Clang を使用した非同期で C++ のコード補完を行うVimプラグインをつくった

この記事は Vim Advent Calendar 2012 316日目の記事になります。
ちなみによく Twitter とかで
『2012年と2013年の Vim Advent Calendar が並走するのか』
みたいな発言を見かけますが
Vim Advent Calendar 2012 は11月末で終了します。
ですので、参加されたい方は今のうちに登録しておくとよいと思います。

以前、Vim Advent Calendar で Clang を使用した C++ のコード補完を行うスクリプトを書いたのですが、それをプラグイン化しました。
基本的な動作は前回と変わらないんですが以下のような違いがあります。

  • neocomplete.vim と併用して使用可能
    • 単体でも動作可能
  • 簡単なキャッシング処理を追加
    • 直前の候補であればすぐに結果が表示されます
  • 入力したワードで絞り込みを行う
    • 処理中にキー入力ができ、終了した時にそのワードで絞り込みを行う


単体でも使用する事は可能なのですが、neocomplete.vim と併用して使用できるようにしました。
あと『非同期でコード補完を行う』というコンセプトなので補完処理自体は clang_complete よりも遅いです。

[プラグイン]

NeoBundle "Shougo/vimproc.vim"
NeoBundle "osyo-manga/vim-reunions"
NeoBundle "osyo-manga/vim-marching"

[使い方]

このプラグインは手動で補完を行います。
補完を行いたい位置でオムニ補完()を呼び出すことで非同期で補完処理が実行されます。
この時に補完処理が非同期で行われるため、補完処理中であってもキー入力を行うことは可能です。
また、補完速度によっては補完ウィンドウが表示されるまでに時間がかかる場合があります。
これは 'updatetime' オプションの値に依存する為、'updatetime' の設定が大きい場合は処理が終了していても表示されるまでに時間がかかる可能性があります。
自動補完を行いたい場合は neocomplete.vim を使用する必要があります。
neocomplete.vim を使用する場合は設定が必要になります。
下記の設定例を参考にして下さい。


https://f.cloud.github.com/assets/214488/1320244/ff09818e-334c-11e3-8569-075f31b50984.gif


https://f.cloud.github.com/assets/214488/1320247/0d6e8e5e-334d-11e3-9a62-3b586a247144.gif

[設定例]

" clang コマンドの設定
let g:marching_clang_command = "C:/clang.exe"

" オプションを追加する場合
let g:marching_clang_command_option="-std=c++1y"

" インクルードディレクトリのパスを設定
let g:marching_include_paths = [
\   "C:/MinGW/lib/gcc/mingw32/4.6.2/include/c++"
\   "C:/cpp/boost"
\]

" neocomplete.vim と併用して使用する場合
let g:marching_enable_neocomplete = 1

if !exists('g:neocomplete#force_omni_input_patterns')
  let g:neocomplete#force_omni_input_patterns = {}
endif

let g:neocomplete#force_omni_input_patterns.cpp =
    \ '[^.[:digit:] *\t]\%(\.\|->\)\w*\|\h\w*::\w*'

" 処理のタイミングを制御する
" 環境に合わせて間隔を短くする
" set updatetime=200

" オムニ補完時に補完ワードを挿入したくない場合
imap <buffer> <C-x><C-o> <Plug>(marching_start_omni_complete)

['updatetime' に依存]

このプラグインは CursorHoldI 時に補完の終了のチェックを行っているため 'updatetime' の値に大きく依存します。
'updatetime' の値が大きければそれだけ終了をチェックする間隔が長くなってしまいます。
ですので、なるべく小さい値の方が補完速度は早く感じられます。

[補完ウィンドウが表示されている場合は処理されない]

これは Vim の仕様になるんですが、補完ウィンドウが表示されている間は CursorHoldI が呼ばれません。
その為、補完処理の完了チェックが行われないので補完処理が終了していても補完ウィンドウが更新されるような事はありません。
これは neocomplete.vim で自動補完を使用している場合に注意が必要です。

[キャッシング]

marching.vim では簡単なキャッシングを行っています。
直前の補完であればキャッシングを利用してすぐに結果が表示されます。
また、現在は normal に戻るとキャッシングは削除されます。
このあたりの処理は今後改善していく予定です。
※追記

[clang_complete と比較して]

clang_complete と比べると以下の様な特徴、違いがあります。

  • 補完速度は clang_complete よりも遅い
  • clang_complete とは違いキー入力している間でも非同期で補完処理が行われる
    • clang_complete の場合はキー入力があった場合、補完処理は中断されてしまうが、
    • marching.vim はキー入力中でも補完処理が行われる
  • if_python に依存していない
  • 補完時に表示されるテキストが貧弱
    • 引数などの表示は今後追加していきたい
  • C++ のみに対応


補完速度は clang_complete の方が圧倒的に早いです。
ただ、キャッシングや処理中にも入力可能など clang_complete にはない機能もあるので一概にどちらが上なのかはいえないと思います。


と、いう感じで作ってみました。
とりあえず、最低限の機能だけ実装したので欲しい機能や不具合などあれば Issues に投げてもらえると助かります。