vim-vimlint 作った

この記事は Vim Advent Calendar 2012 357日目の記事になります.356日目は id:leafcage さんによる 'nobuflisted' なバッファの作り方 - cafegale(LeafCage備忘録) でした.

vim-vimlint を作りはじめたのはだいぶ前で更新も止まっているのですが, 記事を書いていなかったので紹介します. いまだにドキュメントまともに書いていません. すいません.

概要

vim-vimlintvim script の文法チェックを行うプログラムです.
以下のような実行時ではないと検出できないエラーを検出します.

  • 初期化されていない変数の参照
  • 初期化されているが参照されない変数
  • build-in 関数の使用法誤り (引数の数チェック)
  • 使用されない関数の引数

これにより, 関数の引数に a: を付け忘れて参照していたり, エラールートなど実装したけど通したことがないルートのバグを事前に検出することができます.

例えば以下のようなバグを検出しました.

インストール

NeoBundle を使う場合, 以下のように vimrc に記述してください.

NeoBundle 'syngan/vim-vimlint', {
    \ 'depends' : 'ynkdir/vim-vimlparser',
    \ 'autoload' : {
    \ 'functions' : 'vimlint#vimlint'}}

簡単な使い方

" 任意のファイル
:call vimlint#vimlint(filename)

" 指定されたディレクトリ配下の .vim ファイル
:call vimlint#vimlint(directory)

上記のように実行すると, echo でチェック結果を出力します. 出力先はオプションで変更します.

" ファイル outputfilename に出力する場合
:call vimlint#vimlint(filename, {'output': 'outputfilename'})

" リストで結果を取得する場合
:echo vimlint#vimlint(filename, {'output': []})

出力

echo 出力は以下の形式です.

'%f:%l:%c:%m'

%m は以下の形式です.

$ERRNO: $(ERRMSG) 

$ERRNO は

  • EVPxxx の形式は vim-vimlparser によるエラーメッセージ. このメッセージが出力された場合には vim-vimlparser の解析が停止しているのでそれ以上の処理はできなくなります.
  • EVLxxx または Exx の形式は vim-vimlint によるエラーメッセージです.

詳細は vim-vimlint/vimlint.txt at master · syngan/vim-vimlint · GitHub を参照してください.

実装について

プラグインvim-vimlparser により解析されたデータを基にしています. したがって, vim-vimlparse が構文解析に失敗すると, 本プラグインは動作しません. コマンドまわりで停止することがあり, 特に test/spec 系のソースではエラーになってしまうことが多いです.

また, どちらも pure vim script で書かれていて, とても遅いです.

vim-vimlint でチェックしている内容は vim-vimlint/test at master · syngan/vim-vimlint · GitHub を見てもらうと一応確認できます. lint と名前をつけたので基本的にあやしいものはエラーに倒す方針で実装しています.
例えば以下のようなコードは判定できず未使用変数のエラーになります.

function! g:open(...)
  ....
  let path = printf('gitlab://%s', join(base + args, '/'))
  let opener = 'edit'
  execute opener . '`=path`'
endfunction
dbakker/vim-lint

vim script の文法チェックを行うプログラムには他に GitHub - dbakker/vim-lint: Check your .vimrc for errors があります. ざっくり簡単な比較を行うと, 以下のような感じです.
vimlparser のように構文解析しているわけではないので未使用変数などのエラーは検出できていないように感じます.

  syngan/vim-vimlint dbakker/vim-lint
言語 vim script python
実行速度 ×
検出精度

連携プラグイン

おすすめの連携プラグインは, vim-watchdogs

vimproc がインストールされていれば, 保存時に非同期で文法チェックしてくれます. watchdogs 便利.
ここで注意ですが, watchdogs で vimlint を使う場合 NeoBundleLazy にしていると動作しないので, Lazy にしないことをお勧めします.

  • vimlparser も Lazy だと動作しません (2013/11/25 追記)

終わりに

以下のことをやりたいと思っていますが, 手が回っていません.

  • ドキュメント
  • エラーを抑止する設定
    • unused argument などは無視して良いことが多い
    • オプションを追加するか, ソース上にコメントを追加する形にするか.
  • PR お待ちしています.

lint を保存毎に実施する必要はないと思いますが, メジャーバージョンアップ時などに思い出して使ってもらえると幸いでございます.

さーて明日の VAC さんは?

明日以降の VAC は決まっていないようですね. まだ #vimconf2013 が終わってない人がたくさんいますよね.