Vimのコマンドでの引数の補完にカスタム関数を使うというのを撫でてみた。customなら補完候補を改行で連結した文字列を、customlistなら補完候補のlistを返してやる関数を作れば良いだけで、思っていたよりも簡単そう。

補完のために適当なファイル(行ごとに補完したい単語が並べたいわゆる辞書ファイル)を用意してやるというありがちなケースでは、readfile()listが返ってくるので特に簡単だった。例えば各行にメールアドレスが並んでいる$HOME/addressbook.txtというファイルがあるとすると、以下のようなカスタム補完関数で絞り込みつつ補完できるようになる。

function! ListMailAddress(A, L, P)
  let addresses = readfile(expand('$HOME/addressbook.txt'))
  let matches = []

  for address in addresses
    if address =~? '^' . strpart(a:A, 1)
      call add(matches, shellescape(address))
    endif
  endfor

  return matches
endfunction

command! -nargs=1 -complete=customlist,ListMailAddress Mail :execute '! start mailto:' . <args>

第一引数で入力済みの文字列を拾えるので、それで適当に絞り込みをかけるだけ。簡単!shellescape()してるのはメールアドレスの@でアレなことになるからなので、そういうのが無いのならもっと簡単に書ける。第二引数はコマンドラインで入力されたすべての文字列、第三引数がカーソル位置だが、両者の使い道は思いつかなかった……。第二引数は複数のコマンドで補完関数を共有する時とかに使うのかなぁ。

デフォルトのコマンドラインの補完モード(wildmode)は、コマンド・プロンプトの補完と似た感じのシンプルなもの(statuslineに表示される候補を次々と選択していくもの)でちょっと使いづらい感じだったが、色々試して、

set wildmode=longest,list

というbashな感じに落ち着いた。listを入れとくとfun <SNR>の後に<Tab>でスクリプト番号付きの関数が一覧出来たりとか(どうでも良い)。wildmodeの設定はちょっと解りづらかった……。