vimでひかえめな自動保存
Vim Advent Calendar 2013、 67日目の記事になります。
御存知の通り、 webapi-vimの出現により vimによって簡単にwebサービスを読み書きができるようになりました。 さらにunite.vimや vim-metarwを 使用する事で簡単にインターフェイスを構築できます。
しかし、これらのサービスのAPIの応答は、
一般にローカルに保存する場合に比べ圧倒的に時間がかかります。
さらに現状のvimではajaxのようにスクリプトを非同期実行できない。
もしvim-metarwのwriteで毎回送信する場合、
:w
と押すたびに数秒待たされるかもしれない。
かといって手動で送信するのは忘れがち。
つまりアクセスの回数を絞った自動保存機能が欲しい。
試行錯誤編
という事で試行錯誤が始まります。 多分autocmdにそれっぽいトリガーがあるだろうと思ってhelpを読む事数十分。。。 (あまり読みなれてない)
BufUnload Before unloading a buffer. This is when the text in the buffer is going to be freed. This may be after a BufWritePost and before a BufDelete. Also used for all buffers that are loaded when Vim is going to exit. NOTE: When this autocommand is executed, the current buffer "%" may be different from the buffer being unloaded "<afile>". Don't change to another buffer, it will cause problems. When exiting and v:dying is 2 or more this event is not triggered.
多分これっぽいんだけど、なんか後半に良くわからない事が書いてるorz
めげずに<afile>
について調べると、
<afile> When executing autocommands, is replaced with the file name for a file read or write. <abuf> When executing autocommands, is replaced with the currently effective buffer number (for ":r file" and ":so file" it is the current buffer, the file being read/sourced is not in a buffer).
つまりバッファがアンロードされる時の現在のバッファ(%
)が
トリガーが指定されたバッファ(<abuf>
)と違うかもしれないという事か!!(オウム返し)
:bdelete
で消す場合とか:qa
で全部閉じる場合を考えろってことか。
ともかくこれで行ける!?
<abuf>
はきっとexpand()
使うんだろう:
function! s:buffer_infos() let file_name = expand("<afile>") let buffer_number = expand("<abuf>") let buffer_name = bufname(buffer_number) echo "File name : " . file_name echo "Buffer number: " . buffer_number echo "Buffer name : " . buffer_name let lines = getbufline(buffer_number, 1, '$') echo lines endfunction augroup test_trigger autocmd! autocmd BufUnload test.vim call s:save_buffer_to_file() augroup END
多分これでいけるはず!!
:so %
してバッファを閉じるぜ!!!
File name : test.vim Buffer number: 1 Buffer name : []
(´・ω・`)ショボーン
bufname({expr}) *bufname()* ... If the {expr} is a String, but you want to use it as a buffer number, force it to be a Number by adding zero to it: > :echo bufname("3" + 0) If the buffer doesn't exist, or doesn't have a name, an empty string is returned.
これか?
function! s:buffer_infos() let file_name = expand("<afile>") let buffer_number = expand("<abuf>") let buffer_name = bufname(buffer_number + 0) echo "File name : " . file_name echo "Buffer number: " . buffer_number echo "Buffer name : " . buffer_name let lines = getbufline(buffer_number, 1, '$') echo lines endfunction
File name : test.vim Buffer number: 1 Buffer name : test.vim [ "function! s:buffer_infos()", " let file_name = expand("<afile>")", " let buffer_number = expand("<abuf>")", " let buffer_name = bufname(buffer_number)", " echo "File name : " . file_name", " echo "Buffer number: " . buffer_number", " echo "Buffer name : " . buffer_name", " let lines = getbufline(buffer_number, 1, '$')", " echo lines", "endfunction", "", "augroup test_trigger", " autocmd!", " autocmd BufUnload test.vim call s:save_buffer_to_file()", "augroup END", ]
大勝利!!!
別バッファから:bdelete
しても上手く動く
(`・ω・´)キリッ
まとめ
最終的に
function! s:send(lines) " send data to web service endfunction function! s:wrapper() let buffer_number = expand("<abuf>") let lines = getbufline(buffer_number + 0, 1, '$') call s:send(lines) endfunction augroup ModestAutoSave autocmd! autocmd BufUnload * call s:wrapper() augroup END
とすればいい!パターンの部分は適当に。
おわりに
プラグインとして公開しようと思っていたのですが、 autocmdのパターンの扱い(変数が使えない?)がよくわからなかったので無期限延期しました。 結局すごく短かいですし。