vim-users.jp

Hack #14: Insert mode補完 自作編

Posted at 2009/05/21
このエントリーをはてなブックマークに追加

Insert modeの補完を自作することができれば、Vimの可能性が無限大に広がります。ここではInsert modeにおける補完関数の作り方についてレクチャーします。補完関数に求められる仕様は'omnifunc''completefunc'で共通なので、ここで学んだ知識はどちらの補完にも使用できます。

補完関数に求められる仕様:
補完を自作するためには、まず補完関数を作成しなければなりません。補完関数はfindstartとbaseという二つの引数を持ち、Vimから二度呼ばれます。
一度目に呼び出されたとき、カーソルから補完する単語までの位置を決定します。a:findstartは1になり、a:baseは空です。補完できないときは-1を返します。
二度目に呼ばれたとき、補完する単語のリストを返します。a:findstartは0で、a:baseには補完位置からカーソル位置までの文字列が格納されています。a:baseは参考情報として用意されているだけなので、無視してもかまいません。補完する単語が存在しない場合は空リストを返します。
補完する単語は単純な文字列にすることもありますが、Dictionaryにしておくと、追加情報を表示できて便利です。Dictionaryの場合、キーとして次のような情報を持つことができます。
  • word
      補完する単語です。省略不可。
  • abbr
      wordのabbrevation(略称)です。このキーが存在する場合、ポップアップメニューにwordの代わりに表示されます。wordが長すぎる場合に省略表示するために使います。
  • menu
      これを設定すると、abbrの後ろに追加情報として表示されます。補完する単語のファイル名などを設定することが多いです。
  • info
      プレビューウインドウに表示する追加情報です。複数行にするときは\nで区切ります。'completeopt'にpreviewがないと無視されます。大量の情報を表示できますが、プレビューウインドウを開く処理やプレビューウインドウの内容を書き換える処理は重いので注意してください。
  • kind
      補完候補の種類を表す1文字です。主にオムニ補完で使用されます。代表的な物は変数を表す’v'や関数を表す’f'、メンバを表す’m'などです。
  • icase
      これが0以外に設定されている場合、Vimは要素の大文字小文字を区別しません。これはポップアップ表示後の要素の絞り込みに関係します。省略すると0になるので、大文字小文字の違いを区別します。アセンブリ言語やBasic以外では省略し、大文字小文字を区別した方がよいです。しかし、'ignorecase'相当の動作を自作補完関数でも行いたい場合、これを1に設定しなければなりません。
  • dup
      これが0以外に設定されている場合、wordが同じでも補完候補に追加されます。省略すると0になるので、重複は無視します。
  • ちなみに、他のキーは存在しても無視されます。
    補完関数についての詳しい解説は:help complete-functionsを参照してください。
    補完関数のサンプル:
    function! CompleteFiles(findstart, base)
        if a:findstart
            " Get cursor word.
            let cur_text = strpart(getline('.'), 0, col('.') - 1)
    
            return match(cur_text, '\f*$')
        endif
    
        let words = split(expand(a:base . '*'), '\n')
        let list = []
        let cnt = 0
        for word in words
            call add(list, { 'word' : word, 'abbr' : printf('%3d: %s', cnt, word), 'menu' : 'file_complete' })
            let cnt += 1
        endfor
    
        return list
    endfunction
    
    最後にまとめとして、補完関数のサンプルを紹介しておきます。これはカレントディレクトリに存在するファイルを補完するサンプルです。’abbr’や’menu’も使用しています。一番最初にファイル名としてマッチする部分を返し、次に呼び出されたときにファイル名にマッチする補完リストを返します。:setlocal completefunc=CompleteFilesとすると使えます。
    ファイル名補完

    ファイル名補完

    注意:
    補完関数が呼び出されるのは補完を行うキーが押されたときだけです。 Vimは英字を入力したときに、ポップアップの絞り込みを自動で行いますが、補完関数を再度呼び出すことはありません。自動で補完を行うためには、CursorMovedIにautocmdを設定し、カーソルが移動したら自動で補完関数を呼び出す必要があります。自動補完は処理が複雑になるので、この章では解説しません。ちなみに<C-h>を押したときは例外で、補完関数が再度呼び出されます。この動作が気になるようなら、
    inoremap <expr><C-h> pumvisible() ? "\<C-y>\<C-h>" : "\<C-h>"
    と.vimrcで設定した方がよいかもしれません。
    またポップアップメニューを生成する処理は重いため、巨大なリストを返却した場合、Vimの動作が止まってしまうことがあります。その点Vim標準の補完はよく考えられていて、処理が重いときには先頭の候補のみをポップアップメニューに表示します。そしてしばらく待っていると、全ての補完候補が表示されます。自作の補完関数でこのような動作を行うためには、complete_check()でキー入力を監視し、complete_add()で少しずつ要素を追加するようにしてください。
    Shougo

    もどる
    blog comments powered by Disqus