星期一, 3月 29, 2010

latex 半自動 WYSIWYM

之前寫過的 iwatch 可以讓我寫 latex 的時候不用一直手動 make,然後只要編譯完用 foxit 顯示文件就可以了,但是這樣的效果差強人意,因為 foxit 沒辦法自動 reload,我只好每次 make 完就 kill 然後重開一個 foxit,心血來潮之下找到了 xpdf,他可以開一個 remote xpdf 像是一個 server ,然後 xpdf -remote preview -reload 就可以讓這個remote server 重新讀取 pdf!!
這樣的組合真是太完美了,搭配 iwatch,可以用我寫的 script:
#!/bin/bash
REMOTE=preview
TEX=sample.tex
PDF=$(basename $TEX .tex).pdf
xpdf -remote $REMOTE $PDF &                                                                                    
id=$!
while ./iwatch -e modify $TEX
do
    make
    xpdf -remote $REMOTE -reload &
    id=$!
done

這樣每次儲存以後,會自動編譯,然後在現有 xpdf 更新畫面!在我的桌面上執行起來像這樣:下面是 vim 上面是 xpdf,因為用 xmonad 剛好可以分成上下來顯示。

星期二, 3月 23, 2010

git diff 自訂 hunk header (function line, function name...)

GNU diff 有一個參數是 -F RE,  --show-function-line=RE 可以在 diff 的時候用來顯示內容屬於哪個區塊,提供除了檔案行數以外的位置辨認。
對於 C,  C++, HTML, java.... 一些常見的語言有內建的辨識語法來抓出 function name,但如果是自訂格式的檔案的話就比需要自己寫,詳情可以參考 man gitattribues,這邊大概紀錄一下作法..

先設定指定的類別用的語法, ~/.gitconfig :
[diff "are"]
    xfuncname = "^#[0-9]+$"
然後在 project 的根目錄或是有放那些檔案的目錄下加一個 .gitattributes (跟 .gitignore 一樣, 有與上層繼承的關係),裡面寫:
*.are diff=are
這樣就可以了, git diff 的一個區段結果會長這樣:

@@ -6,4 +6,4 @@ #103
 3
 4
 5
-6
+7
會找出最近一個符合的字串放在行數後面,這樣如果只看 diff 的話也會比較清楚這個 patch 到底做了什麼。不過要記得,如果 match 到的字串有在 diff 的上下文(context)出現,就不會顯示在 header,所以 header 上的提示不一定是正確的(當然 context number 可以用 -U 設定,不過如果 > 0 就是有可能有這種情況)。

星期六, 3月 13, 2010

inotify - 讓 kernel 幫你監控檔案

自從 Linux Kernel 2.6.13,linux 就提供了 inotify 的 API 讓使用者以 event 的方式監控檔案。這顯然比傳統 busy checking 的方式有效率多了,除了用的是 kernel space 的 memory 以外幾乎沒有理由不用這麼好用的機制了吧!
inotify 提供監控的事件可以在 manual 裡找到 (man inotify) 在這邊就不贅述。使用上其實也很簡單,首先呼叫 inotify_init() 取得一個 file descriptor,將來只要讀這個 fd (block/non-block) 就可以取得 event,可以視為一個 event queue,然後把想要監控的檔案、訊息透過 inotify_add_watch 就可以加入監控的列表。接下來只要讀取剛剛取得的 fd 就可以了。需要注意的地方是,如果監控的目標是 directory,那 read 用的 buffer 以及 size 必須包含檔案名稱的大小然後一起 read,不然會有 EINVAL 的錯誤。

以前就聽過看過這東西,這次會翻出來是因為我正在用 latex 寫一篇文章但每次都要 compile/make 實在很麻煩(雖然說 vim 可以設 key binding 來直接 make 可是還是懶了點)於是就寫了一個等某個 inotify event 的小程式,有一個叫做 inotify-tools 的工具包裡面有 inotifywait 但是他只能針對某個存在的 file 進行監控,而 vim 在寫檔時會移動/刪除原本的檔案,造成監控中斷,所以我只好另外寫了這個 tool 對於目前的 WD 內特定的 filename 的某些特定 event 做等待。也就是說我監控的對象是這個 directory 但是我只 care 某個特定檔案發生的某些 event。

以下是我寫的 iwatch, 以 MIT License 釋出。
http://moon.cse.yzu.edu.tw/~s961449/iwatch.c


應用在我上面提到的自動編譯 latex, 可以用這個  bash script:
#!/bin/bash
id=0
while iwatch -e modify proposal.tex
do
kill -KILL $id
make
acroread proposal.pdf &
id=$!
done
執行這個 script 會監控目標 .tex 發現更變以後自動重新 make, 然後打開 pdf viewer,這邊是用 acroread,也可以用 foxit (比較快)。

星期四, 12月 17, 2009

vim plugin: autocomplpop (acp)

vim 內建的 omni c complete function 其實算是堪用,但不方便的就是每次都要自己按 ^P, ^N 或是 ^X^O 等組合才會跳出來讓你選。這兩天在 Vim taiwan 的 mailing list 看到 acp 這個 plugin,試用了以後愛不釋手,安裝方法跟其他vim plugin 沒兩樣:
到這邊下載最新版的 autocomplpop: http://www.vim.org/scripts/script.php?script_id=1879
然後解壓縮在 ~/.vim 就可以了:
unzip -d ~/.vim vim-autocomplpop.zip
這樣就算是安裝好了,開 vim 也會自動執行。
autocomplpop 簡單的說就是你每輸入一個超過長度的word(預設2個字元) 他就開始用 keyword/omni 找可能的補全單字然後顯示在pmenu,多說無益,試過才知道!

不過剛裝好的時候有點不習慣,因為他預設的搜尋範圍不包括 include 近來的檔案,所以以前慣用的 ^N, ^P (或是 ^X^i) 就只能用 ^X^I 呼叫出來,要讓 acp 也搜尋include 的檔案的話只要在 ~/.vimrc 加入下面的設定:(vim 預設 .,w,b,u,t,i ; acp 預設 .,w,b,k)
let g:acp_completeOption = '.,w,b,u,t,i,k'
每個選項的功用可以參考 :help complete
這樣邊打字就也會邊出現 api 的 auto complete popup,挺實用的!
------------------
另外這個也是在 mailing list 上看到的(其實是包含在acp 的help file裡,只是大家沒注意到):
acp 也提供 snipMate 一個接口,讓 snipMate 的補全也變成 menu 的樣式讓你選,啟動的方法只要在 ~/.vim/plugin/snipMate.vim 加入

  fun! GetSnipsInCurrentScope()
    let snips = {}
    for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
      call extend(snips, get(s:snippets, scope, {}), 'keep')
      call extend(snips, get(s:multi_snips, scope, {}), 'keep')
    endfor
    return snips
  endf
然後在 ~/.vimrc:
let g:acp_behaviorSnipmateLength=1
這樣輸入大寫字母的時候他就會去找 snipMate 的 template 看有沒有符合的項目並整理到menu 顯示,有興趣的人可以試看看。

星期三, 12月 16, 2009

load balance in difference internet interfaces

如果你有兩張網卡都是連上外部網路的話,可以透過 ip route 來做 load balance,方法很簡單,基本上就是把 default route 改成 multipath route。當然在這之前需要先把 ip route 設好讓一個 IP (TCP/UDP)連線只經由該連線存在的 interface 送出。

當然這只是很簡單的提供 load balance 的機制.. 有時候並不是那麼有用,不過將就點用吧 XD

其實設定上也很簡單,network split 的部份我就不再重複紀錄了,跟我之前寫過的這篇 差不多。
balance 的部份就是把default route 分成兩個 channel 依照 weight 決定連線走哪一條。步驟大概是這樣:

ip route del default #把目前 defualt route 刪掉
ip route add default scope global nexthop via [gw1] dev [if1] weight [weight1] \
nexthop via [gw2] dev [if2] weight [weight2]
假如我要從兩個 ISP 出去, 一個ip 是 A 另一個 B,分別透過 eth0 跟 eth1 連線,而 A 的連線速度比較快,可能是 B 的兩倍,那麼我可以這樣設定:(gateway 可以用 route -n 看)
ip route del default
ip route add default scope global nexthop via gw1 dev eth0 weight 2 \
nexthop via gw2 dev eth1 weight 1

這樣就設定好了,如果看 ip route 的話會看到下面這樣的結果

default
    nexthop via gw1  dev eth0 weight 2
    nexthop via gw2  dev eth0 weight 1
觀察流量的話也可以大略用 iptraf 看一下各個network interface 上面的流量。