vim + coc.nvim + (ccls) + cmake で C/C++ 補完を整える
背景
ale だといまいち...
vim ale で clangd で C++ コンパイルオプションがうまく渡らないっぽいメモ
Vimの非同期文法チェッカALEにプロジェクト固有の情報を教える
coc.nvim + ccls がよさそうでしたので coc.nvim + ccls にします!
ccls はでもちょっと微妙かも... coc デフォの clangd で十分そうでした.
設定
NeoVimでC/C++を書くときはcoc.nvim + cclsが良さげ
Vimにcoc.nvimを入れたら便利すぎて感動したっていう話
ありがとうございます.
yarn install なんちゃらが必要と言われたら,
:CocInstall coc#util#install()
とするといけます.
C++ lsp 関連はとりま clangd 入れます.
:CocInstall coc-clangd
ccls はおこのみで...
coc + clangd のデフォ? 設定だと, auto の型推論もだしてくれたりで良き良きでした 😊
coc.nvim 用の追加設定
lua でもいいのですが, lua にするほどでもないので, init.vim で設定します.
~/.config/nvim/init.vim
(正確には $XDG_CONFIG_HOME/nvim/init.nvim
)
を編集します!
設定サンプルは
を参照ください.
処理ステータスを表示する
最初のころは処理ステータスが見えていたほうがきちんと動いているか確認できてよいと思います.
" Add (Neo)Vim's native statusline support
" NOTE: Please see `:h coc-status` for integrations with external plugins that
" provide custom statusline: lightline.vim, vim-airline
set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}
こんな感じで表示されるようになります.
tab 補間
" Use tab for trigger completion with characters ahead and navigate
" NOTE: There's always complete item selected by default, you may want to enable
" no select by `"suggest.noselect": true` in your configuration file
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config
inoremap <silent><expr> <TAB>
\ coc#pum#visible() ? coc#pum#next(1) :
\ CheckBackspace() ? "\<Tab>" :
\ coc#refresh()
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"
" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
function! CheckBackspace() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
コメントにあるように, nvim 設定の最初のほうに書いておかないと他の tab 設定とかちあうようですので注意です! なるべく nvim 設定の最初のほうに書いておきましょう.
また, これだと候補がでたときに tab すると二番目の候補が選択されてしまします.
たとえば ParseUSD と入力して tab 押すと, 候補二番目の ascii:ParseUnr...
で補完されてしまいます.
(第一候補は implicitly に選択されている)
vim ale などで, 入力中に tab 押したら最初のマッチで補完するのになれている方は, これもコメントにあるように, coc-config.json(or :CocConfig
で開く) で suggest.noselect
を設定しておきましょう(ちょっとわかりずらいパラメータ名ネ)
{
suggest.noselect": true
}
また, Enter すると関数などの場合は関数の引数も fill してくれて便利です.
clang-format をかける
vim で clang-format 使っている方は :ClangFormat
でフォーマットしているかと思います.
" Add `:Format` command to format current buffer
command! -nargs=0 Format :call CocActionAsync('format')
で :Format
で(言語非依存で)同等のことができます.
範囲指定してフォーマットは,
" Formatting selected code
xmap <leader>f <Plug>(coc-format-selected)
nmap <leader>f <Plug>(coc-format-selected)
のようにして, v
で選択後, leader(デフォルトではバックスラッシュキー) + f
でフォーマットできます!
インタラクティブに関数引数の hint
一応デフォルト設定でこんな感じで引数の hint 出してくれます.
ただ, プロジェクト(compile_commands.json かなにかの設定がよくに?)によってはうまく出してくれないときもあるようです.
関数のヒント(ドキュメント表示)
" Use K to show documentation in preview window
nnoremap <silent> K :call ShowDocumentation()<CR>
function! ShowDocumentation()
if CocAction('hasProvider', 'hover')
call CocActionAsync('doHover')
else
call feedkeys('K', 'in')
endif
endfunction
これで関数にカーソルおいて K
キーで hint が表示されます.
ただ, 著者環境では C++ プロジェクトによってはうまく hint が表示されないときや, 大きめのプロジェクトだと hint 取得に時間かかったりしました(5 秒くらい)
色を変える
Terminal のテーマカラーによっては見ずらいときがあります. higlight で調整しましょう.
cmake
cmake の compile_commands.json では, コマンドは一行で -I
などは分離されていません. ale の c.vim ではコマンド文字列を分離していろいろ処理してくれるようですが
それでもうまくいかないときがあります.
cland だと cmake 出力の compile_commands.json でもある程度うまくいくようです.
ccls で compile_flags.txt と組み合わせである程度うまくやってくれるかもですが, それでもうまくいかなかったら
↑の参考 URL にあるように,
bear を使って compile_commands.json 生成するのがいいかもしれません.
C++ 設定
インデント
coc 自体はインデント処理はしません.
vim で C/C++ 系ファイルでインデントさせないようにする
を参考に,
set indentexpr=
set noautoindent
set nocindent
set nosmartindent
au! BufNewFile,BufRead,BufEnter *.c setl ts=2 sw=2 expandtab nocindent noautoindent nosmartindent
au! BufNewFile,BufRead,BufEnter *.cc setl ts=2 sw=2 expandtab nocindent noautoindent nosmartindent
au! BufNewFile,BufRead,BufEnter *.cpp setl ts=2 sw=2 expandtab nocindent noautoindent nosmartindent
au! BufNewFile,BufRead,BufEnter *.h setl ts=2 sw=2 expandtab nocindent noautoindent nosmartindent
au! BufNewFile,BufRead,BufEnter *.hh setl ts=2 sw=2 expandtab nocindent noautoindent nosmartindent
au! BufNewFile,BufRead,BufEnter *.hpp setl ts=2 sw=2 expandtab nocindent noautoindent nosmartindent
あたりでインデント設定します.
↑は vim のを流用なので, nvim だともうちょっといい設定方法があるかもしれません.
make コマンド(ビルドコマンド)呼び出し
vim と同様でよいでしょうか. 著者は ctrl-m
で makeprog を呼び出すようにしています.
map <C-m> :make<CR>
vim makeprog で ninja と make を自動で切り替えるメモ
makeshift も nvim でも使えるかもです!
トラブルシューティング
補完がうまくいかない?...
筆者環境では, ccls 利用だと, デフォルト?では補完(tab)するといろいろな候補が出てしまいました(たとえば class Bora のインスタンス変数に対して補完したら Bora のメンバー関数だけなどが候補に出てほしい).
いい感じにするにはいろいろ設定が必要そうです.
とりあえずは ccls ではなくて coc + clangd で整えてみるのがいいかもしれません.
インデックスが生成されない...?
ccls で gl.h(OpenGL) など含んだプロジェクトだと, /usr/include
のヘッダを全部インデックス化するからかうまくインデックスが生成されないように見えました. ccls 利用の場合, 一度オフラインで ccls
動作させてうまくいっているか確認してみるとよさそうです
Reference や Hint がおそい...
↑にあるように gl.h などでインクルードが多いプロジェクトだと, Reference の探索が遅い(5 秒くらいかかる)です. 依存関係減らせば探索早くなるのでしょうか...
何かしらキャッシュみたいな機能はあると思うのですが...
TODO
- Ale, Visuial Studio intellisense のようにいい感じに補完する設定を探す
- インデックスがきちんと生成されているか確認する方法を探す.
Discussion