Vim スクリプトでは try-catch が使えて非常に便利。
try echo 'start' throw 'error!' echo 'end' catch /error!/ echomsg 'error occurred.' endtry
start error occurred.
この try-catch、一般的な Vim のエラーが発生した場合も catch してくれる。
unlet! var try echo 'start' echo var echoerr 'hoo' echo 'end' catch echomsg 'error occurred:' . v:exception endtry
start error occurred:Vim(echo):E121: Undefined variable: var
なんて便利!かと思いきや、ここに大きな落とし穴がある。
それは、普通に実行していれば多少エラーが出ても実行される場合も try-catch があるとそこで止まってしまう、ということ。
例えば、新しいバッファを作ってカスタマイズのために FileType を設定するようなプラグインを書くとすると、
function! s:new_buf() new set filetype=plug endfunction function! s:start() try if !s:buf_exists() call s:new_buf() endif call s:load_contents() catch endtry endfunction
この場合、set filetype=plug で FileType イベントが発生し、任意のコードが走る。そのなかのどこかで何かしらエラーが発生した場合、それ以降のコードが実行されず結果ただ真っ白なバッファが開かれることになってしまう。これは残念すぎる。
ちなみに try-catch がなければエラーこそ表示されるものの処理は先に進んで s:load_contents() が呼ばれる。
これを避けようと思ったら
- try-catch を一切使わない
- 予期しないエラーが発生しそうな箇所では逐一 try-catch で囲う
- なんとかしてロールバックして(この場合newしたバッファを閉じる)エラーを報告する
ということになると思うが、1 は try-catch は通常の処理時のエラーの処理をするのに便利だから使いたいし、かと言って 2 は面倒すぎる。3 もかなりむずい。
さて困った、どうしよう。と言うのが実は ref.vim の現状だったりする。と言うわけで今のところ FileType イベント中にエラー出ると残念なことになるのでよろしく。解決も難しそうだし仕様になるかもね…。