🦁

Vim 本体の自動補完設定試用

に公開

Vim 本体の自動補完が充実してきたので VimComplete が Deprecate になりました。
本体の自動補完に移行すべく以下のような設定で試しています。
まだ本格使用は辛いかな。
でも、まだ進化しそうなのが楽しみです。

2025-09-29 更新: yegappan/lsp での自動補完はやめるように変更。

環境

  • Windows11
  • gVim 9.1.1806

良いところ

  • 補完プラグインが不要

イマイチなところ

自分が使えこなせていないだけの可能性もあり。

  • ポップアップの補完候補を選択しても挿入はされないみたいなので <C-l> で挿入している。
    これに慣れないので VimComplete に戻りそう。
    lsp の自動補完は補完候補の選択で挿入されるのでますます…。
    <C-n>, <C-p><Down>, <Up> を割り当てていたからだった。
  • lsp の補完はなんだか気になる動きをする。
    • lsp を使う filetype では , ( などで lexima が動かない場合がある。
    • vsnip の展開の際に入力した文字列が消されず残る(場合がある?)
      yegappan/lsp の補完でなく本体の補完で omnifunc を使うようにしたら良さそう。
  • lsp を使わない filetype では snippet が補完候補に表示されない。
  • 設定によってはバグっぽい動作がまだある。
    • completefuzzycolletct=keyword としたら意図しない文字列の挿入がされたっぽい [9.1.1782]
  • VimComplete に比べると遅く感じる。収集する候補が多くなっている設定なのかも。

使用プラグイン

それぞれのインストール方法などは書きません。使える状態になっているものとして以下記述します。

使用lsp

自動補完の設定

  • 自動補完の開始は 0.2 秒後に
  • complete の変更
    • t 削除: 自分の環境ではタグ補完で固まるようだったので
    • b^5: 「バッファリスト内の、現在読み込まれている別のバッファから検索」ということなので関係ないものがありそうだからマッチ数を減らしてみる。ヘルプを開いていると日本語がわんさか出てくるみたい。
    • k 追加: plantuml, autohotkey のファイルタイプで dictionary を指定しているので、そこから補完。
    • o 追加: lsp を使えるように omnifunc で補完。
vimrc
set autocomplete
set autocompletedelay=200
set complete=.,k,w,b^5,u,i,o
set completefuzzycollect=keyword
set completeopt-=preview completeopt+=menuone completeopt+=fuzzy completeopt+=popup

" 補完候補が表示されていたら選択して挿入。補完候補が出ていないときの動作はお好みで。
inoremap <expr> <C-n> pumvisible() ? '<C-n>' : '<Cmd>normal! gj<CR>'
inoremap <expr> <C-p> pumvisible() ? '<C-p>' : '<Cmd>normal! gk<CR>'

filetype ごとの設定

autohotkey

https://github.com/fincs/SciTE4AutoHotkey/ の source/ahk2.standard.api と source/ahk.keys.api を結合したものを dictionary へ。
https://github.com/AutoHotkey/AutoHotkeyDocs/tree/v2 をダウンロードして syntaxgen\CreateAhk2.ahk, syntaxgen\CreateKeys.ahk で再生成してみたけど変わっていなかった。

~/_vim/after/ftplugin/autohotkey.vim
setlocal dictionary=~/path/to/autohotkey.txt

plantuml

plantuml.jar -language で出力した内容を dictionary へ

~/_vim/after/ftplugin/plantuml.vim
setlocal dictionary=~/path/to/plantuml.txt

yegappan/lsp の設定

lsp を使う場合は yegappan/lsp の自動補完を使て vsnip を使えるように。

lsp.vim
function s:lspSet() abort
  let lspOpts = #{
        \ autoComplete: v:false,
        \ autoPopulateDiags: v:false,
        \ condensedCompletionMenu: v:true,
        \ completionKinds: v:true,
        \ snippetSupport: v:true,
        \ vsnipSupport: v:true,
        \}
  call LspOptionsSet(lspOpts)

  let lspServers = [
        \ #{name: 'deno',
        \   filetype: ['typescript'],
        \   path: 'deno',
        \   args: ['lsp'],
        \ },
        \ #{name: 'gopls',
        \   filetype: 'go',
        \   path: fnamemodify('~/bin/gopls.exe', ':p')->substitute('\', '/', 'g'),
        \   args: ['serve'],
        \   syncInit: v:true,
        \ },
        \ #{name: 'taplo',
        \   filetype: 'toml',
        \   path: 'taplo',
        \   args: ['lsp', 'stdio'],
        \ },
        \]
  call LspAddServer(lspServers)
endfunction
autocmd vimrc User LspSetup call s:lspSet()

function s:LspHas(feature)
  return !lsp#buffer#CurbufGetServer(a:feature)->empty()
endfunction

function s:lspKeymap() abort
  if s:LspHas("hover")
    setl keywordprg=:LspHover
  endif
  if s:LspHas("declaration")
    nnoremap <buffer> gd :LspGotoDeclaration<CR>
    nnoremap <buffer> gD :LspPeekDeclaration<CR>
  endif
  nnoremap <buffer> <Space>al <Cmd>LspDiagShow<CR>
  nnoremap <buffer> <C-]> <Cmd>LspGotoDefinition<CR>
  nnoremap <buffer> <Space>ar <Cmd>LspRename<CR>
  nnoremap <buffer> <Space>aR <Cmd>LspReferences<CR>

  " submode
  call submode#enter_with('lsp', 'n', 'br', '<Space>aj', '<Cmd>LspDiagNext<CR>')
  call submode#enter_with('lsp', 'n', 'br', '<Space>an', '<Cmd>LspDiagNext<CR>')
  call submode#enter_with('lsp', 'n', 'br', '<Space>ak', '<Cmd>LspDiagPrev<CR>')
  call submode#enter_with('lsp', 'n', 'br', '<Space>ap', '<Cmd>LspDiagPrev<CR>')
  call submode#map('lsp', 'n', 'brs', 'j', '<Cmd>LspDiagNext<CR>')
  call submode#map('lsp', 'n', 'brs', 'n', '<Cmd>LspDiagNext<CR>')
  call submode#map('lsp', 'n', 'brs', 'k', '<Cmd>LspDiagPrev<CR>')
  call submode#map('lsp', 'n', 'brs', 'p', '<Cmd>LspDiagPrev<CR>')
endfunction
autocmd vimrc User LspAttached call s:lspKeymap()

vsnip の設定

vsnip.vim
imap <silent><expr> <Tab>
      \ pumvisible() ? '<Down>' :
      \ vsnip#jumpable(1)  ? '<Plug>(vsnip-jump-next)' :
      \ '<Tab>'
smap <silent><expr> <Tab>  vsnip#jumpable(1)  ? '<Plug>(vsnip-jump-next)' : '<Tab>'
imap <silent><expr> <S-Tab>
      \ pumvisible() ? '<Up>' :
      \ vsnip#jumpable(-1)  ? '<Plug>(vsnip-jump-prev)' :
      \ '<C-h>'
smap <expr> <S-Tab> vsnip#jumpable(-1) ? '<Plug>(vsnip-jump-prev)' : '<S-Tab>'
imap <silent><expr> <C-j>
      \ pumvisible() ? '<C-n>' :
      \ '<C-j>'
imap <silent><expr> <C-k>
      \ pumvisible() ? '<C-p>' :
      \ '<Cmd>normal! D<CR>'
" vsnip の展開候補を選択している状態なら <C-y> で展開される
" <C-l> が押しやすいと感じているのでこちらで
imap <silent><expr> <C-l>
      \ pumvisible() ? '<C-y>' :
      \ vsnip#expandable() ? '<Plug>(vsnip-expand)' :
      \ vsnip#jumpable(1) ? '<Plug>(vsnip-jump-next)' :
      \ ''

" 各環境に従って変更
let g:vsnip_snippet_dirs = [
      \ expand('~/vimfiles/plug/vsnip'),
      \ expand('~/_vim/path/to/friendly-snippets/snippets'),
      \]
GitHubで編集を提案

Discussion