Vim の complete-functions でハマった
久しぶりに Vim の complete-functions を書いていたんですが、知らなかった仕様にはまったので覚書。
さて、Vim でオレオレコード補完処理を行いたい場合は 'completefunc' や 'omnifunc' などのオプションにコード補完関数を設定して実現します。
function! Complete(findstart, base) if a:findstart return 補完を開始する列の位置 endif return 補完の候補 endfunction set omnifunc=Complete
雑に書くと上のような感じです。
実際に
1回目は『補完を開始する列の位置』を返し、2回目の呼び出しで『補完の候補』を返します。
詳しくは :help complete-functions を参照してください。
[ハマりポイント]
結論からいうと1回目と2回目の呼び出しでは getline(".") の値が異なります。
具体的に言うと 1回目に返した列位置からカーソルの列位置間のテキストが 2回目に呼び出された時には削られます。
どういうことかというと、動作を確認するために次のような補完関数を設定しておきます。
function! Complete(findstart, base) echom printf("%d 回目" , a:findstart ? 1 : 2) echom "line : " . getline(".") if a:findstart return 1 endif return [] endfunction set omnifunc=Complete
この時に
homu " ここで <C-x><C-o>
すると
1 回目 line : homu 2 回目 line : h
というような結果が出力されます。
こんな感じで1回目と2回目の呼び出しでは getline(".") の値が異なっている事がわかると思います。
また、この影響のためか、補完を呼び出す前と呼び出したあとでは b:changedtick の値が変わっています。
ちなみに
以前、marching.vim でオムニ補完を書いていたときはこんな仕様にはまらなかったんだけど気づかなかっただけなのかなぁ…。