見出し画像

Vimの補完を他エディタやIDEのような挙動にするようにする

タイトルが分かりづらい。。IntelliJとか、VSCodeだと入力補完は常に最初の1件目が選択状態になっていて、Enterを押すだけで補完が確定していきます。それと同じような挙動にVimもしたいなと思った次第です。

本当はGIFをたくさん用意していたのですが、何故かnoteに投稿できず。。サイズも規定内のはずなんだけどな。

挙動の確認

VSCodeやIntellIJの補完の挙動

・補完ウィンドウが起動すると先頭1件が選択状態になっている。
・そのままEnterを押すと改行ではなく、補完ウィンドウの先頭1件が挿入される。
・補完候補を矢印キーで選択してもEnterが押されるまでは挿入しない

Vimのデフォルトの補完の挙動

画像1

・補完ウィンドウが表示されると選択状態になっている。
・最初の1件目がすぐに挿入されている状態になる。
・補完候補を選択すると挿入されている対象が選択した文字になっていく
・Enterを押すといかなる状態でも改行

Vimでしたいこと

・補完ウィンドウが表示された時に最初の1件目を選択状態にしておきたい
・Enterで補完対象を確定したい
・選んでいる時はまだ挿入したくない

.vimrcにこれを書きます。

set completeopt=menuone,noinsert

このcompleteoptと言うのが補完時の挙動を設定するオプションで、その引数に色々指定することで挙動を変更することができます。menuoneで、対象が1件しかなくても常に補完ウィンドウを表示していて、noinsertで補完ウィンドウを表示時に挿入しない、と言う設定になります。

あとは、これも書きましょう。

" 補完表示時のEnterで改行をしない
inoremap <expr><CR>  pumvisible() ? "<C-y>" : "<CR>"

この設定で補完表示時にEnterを押しても改行せずに確定するようになります。inoremapで挿入モード時のキーマップを宣言していて、pubvisible()関数が補完ウィンドウが表示されているのかどうかを返却します。あとは参考演算時で、補完ウィンドウが表示されている時のEnterは<C-y>にリマップしています。
そもそもVimは確定はEnterではなくCtrl+yなので、補完ウィンドウはデフォルトでCtrl+yで確定の挙動をとることができるのですが、これをEnterにもリマップしている、と言う設定です。

そして最後にこれも書きましょう。

inoremap <expr><C-n> pumvisible() ? "<Down>" : "<C-n>"
inoremap <expr><C-p> pumvisible() ? "<Up>" : "<C-p>"

Vimの補完はCtrl+nで下方向に選択、Ctrl+pで上方向に選択をするのですが、これを使うと選択と同時に対象が挿入されていってしまいます。

で、面白いことに、矢印キーの上と下でも補完対象を選択できるのですが、こちらは選択したものが挿入はされません。矢印キーの場合は、補完ウィンドウ内で選択してからEnterで確定する、と言う挙動をとることができます。

この上のinoremap二つは、補完ウィンドウ表示時のCtrl+nとCtrl+pをそれぞれ矢印キーの<Down>と<Up>をリマップすることで同じ挙動にしています。

まとめると、設定ファイルにこんな感じで書きます。

" 補完表示時のEnterで改行をしない
inoremap <expr><CR>  pumvisible() ? "<C-y>" : "<CR>"

set completeopt=menuone,noinsert
inoremap <expr><C-n> pumvisible() ? "<Down>" : "<C-n>"
inoremap <expr><C-p> pumvisible() ? "<Up>" : "<C-p>"

あとは自動補完系のプラグインを入れてあげれば他のIDEやエディタと同じような感覚で使うことができるかなと思います。

画像2

ただ、基本的に自動補完系のプラグインはこのcompleteoptを上書きしていることが多いので、この設定で設定したように動くかは要確認です。

例えば、僕の使っているcoc.nvimと言うLSPクライアント(簡単に言うと補完とかコードアクション、リネーム、エラー表示などを統合的に使えるようにするもの)を使うと、completeoptの上書きができないようになっています。その場合、coc-config.jsonに下記のように書くと上書きができます。

{
      "suggest.keepCompleteopt": true,
}

ここら辺の調整は使っているプラグインのドキュメントを見るしかないですね。

この記事が気に入ったらサポートをしてみませんか?