Vimにソースコードの構文エラーを検出させたい(ただしRubyに限る)

Vimmerであるところの諸兄が、あのすばらしいVimテクニックバイブル 〜作業効率をカイゼンする150の技を片手にご機嫌の年越しと相成ったであろうことは想像に難くない。無論私とてそのクチであり同じ穴の狢というやつである。微妙に日本語の使い方を間違っている気もする。

それはともかく、"1-13 autocmdを使用して自動的に処理を実行する"で紹介されている、"保存時に構文チェックを実行する"技が簡単に導入できる上になかなかどうして便利そうなので早速我が.vimrcにも書いてみた次第である。

保存時に構文チェック

" ~/.vimrc
augroup rbsyntaxcheck
  autocmd!
  autocmd BufWrite *.rb w !ruby -c
augroup END

構文エラーを含む*.rbファイルを保存すると、ウィンドウの下の方に…

Good.

しかし問題があって…

構文に問題が無い場合もなにか言ってくるのである。

つまり、構文エラーの有無にかかわらず、ファイルを保存するたびにEnterキーを一回余計に叩かなければならない。これは非常に面倒だ。

理想としては、問題が無いときは黙っていて、なにか失敗した場合にだけ文句を言ってきて欲しい。つまり、シンタックスチェックの出力をQuickFixに追い出して、必要に応じて:cwして見る、というやり方にしたい。

:make を使う

ところで、同書籍6-7で、:compilerと:makeを使ってコンパイルないしシンタックスチェックを行う方法が紹介されている。この場合、:makeの出力はQuickFixに流れるので、まさに望んでいる通りの処理である。

そういえばだいぶ昔に書いた vimでrubyプログラミング - idesaku blog で、:makeを使う方法にふれた。少なくともRubyに関しては、あれを併用すればいいのではなかろうか。

そういうわけで、設定してみた。

事前にvim-rubyをインストールしておく。Vimプラグインの管理にはpathogenやvundleを使うのが今風であるが、いまどきunite.vimと連携できないプラグインなんて…という風潮もあるのでneobundle.vimを使うといいと思う。

まず、~/.vim/after/ftplugin/ruby.vimに、次の一行を書き加える。

" ~/.vim/after/ftplugin/ruby.vim
compiler ruby

これで、filetypeがrubyであるファイルを開いている状態で :make すると ruby -w コマンドが走るようになる。

そして、.vimrcのautocmd設定部分を書き換えて次のようにする。ファイルパターンは*.rbだけでもいいのだが、ついでにRakeにも対応させよう*1

" ~/.vimrc
augroup rbsyntaxcheck
  autocmd!
  autocmd BufWritePost *.rb,*.rake,Rakefile silent make -c % | redraw!
augroup END

redraw! についてはGitHub - kchmck/vim-coffee-script: CoffeeScript support for vimを参考にした。よくわかっていないのだが、これを付けないと画面表示がガタガタになる。

QuickFixを自動的に開く

最後に、:cwを自分で叩くのも面倒なので、これもautocmdに任せることにする。:makeしたら勝手に:cwするよう設定するのである*2

" ~/.vimrc
augroup quickfixopen
  autocmd!
  autocmd QuickfixCmdPost make cw
augroup END

これで、ファイル保存時に構文エラーがある場合のみQuickFixウィンドウが表示され、エラーが解消され次第勝手に閉じるようになる。また、QuickFixウィンドウ上のエラーメッセージ行上でEnterキーを叩けばエラー箇所までカーソルが跳ぶようにもなる。

もっといいやり方があるのかもしれないが、自分のVim力ではこのくらいが限界。特に、せっかくvim-rubyが適切にfiletypeを判別してくれているのに、autocmd側でも似たような設定(*.rbとか)を書かねばならないのが、なんかなぁ。

追記1

ftpluginでより賢く対処できることを id:thinca さんに教えていただいた。詳しくは本記事のコメント参照なのだが、autocmdを~/.vimrcではなく~/.vim/after/ftplugin/ruby.vimに書けよ、という話。

最終的にこうなった。

" ~/.vim/after/ftplugin/ruby.vim
compiler ruby
augroup rbsyntaxcheck
  autocmd! BufWritePost <buffer> silent make! -c "%" | redraw!
augroup END
" ~/.vimrc
augroup quickfixopen
  autocmd!
  autocmd QuickfixCmdPost make cw
augroup END

Awesome!*3

追記2

自分の環境で上記の設定を行うと、なぜか *.haml や *.erb を編集している場合も ruby -c が起動してしまい、まったく見当違いな文法エラーを警告してくるという非常に困った動作をしていたのだが、原因がわかった。

vim-hamlのftplugin/haml.vimと、vim-rubyのftplugin/eruby.vimが、内部でftplugin/ruby.vimを読み込んでいた。

" vim-haml/ftplugin/haml.vim 某所
runtime! ftplugin/ruby.vim ftplugin/ruby_*.vim ftplugin/ruby/*.vim

そのため、それぞれfiletypeはhamlだのerubyだのと言っておきながら、内部的にはruby用のcompiler設定を行ってしまっていたらしい。

そこで、こうなった。

" ~/.vim/after/ftplugin/ruby.vim

" filetypeが*本当に*"ruby"のときだけ処理を続ける
if &filetype != "ruby"
  finish
endif

compiler ruby
augroup rbsyntaxcheck
  autocmd! BufWritePost <buffer> silent make! -c "%" | redraw!
augroup END
" ~/.vimrc
augroup quickfixopen
  autocmd!
  autocmd QuickfixCmdPost make cw
augroup END

ruby.vimだというのに &filetype != "ruby" などという判定をせねばならんとは…

Vimテクニックバイブル 〜作業効率をカイゼンする150の技Vimテクニックバイブル 〜作業効率をカイゼンする150の技
Vimサポーターズ

技術評論社 2011-09-23
売り上げランキング : 38199

Amazonで詳しく見る
by G-Tools

*1:https://github.com/vim-ruby/vim-ruby/blob/master/ftdetect/ruby.vim が参考になる。*.rbやRakefileはまだしも、まさかGuardfileや.pryrcまで見ているとは。

*2:QuickfixCmdPostにはgrep系も設定しておくと便利。 autocmd QuickfixCmdPost make,grep,vimgrep,grepadd cw

*3:redraw!は私の環境では外せなかった…原因がMacのTerminal.app、tmux、MacVimのどこにあるのかわからない。