首发于我的个人博客(https://www.niuiic.top)
本文介绍 vim 自动补全方案。主要采用更强大的 coc.nvim 插件来替代 YCM。
自动补全对于任何一个试图取代 IDE 的编辑器的重要性不言而喻。想要将 vim 打造为最契合自己的 IDE,无论如何都不能少了强大的自动补全功能。
coc.nvim 是针对 neovim 开发的的功能非常强大,完全可以替代 YCM,带来更加优越的补全体验。包括语义补全、片段补全、定义跳转、文档查阅、静态检查等等。
同时 coc.nvim 也是一个全新的插件平台,除了其原生插件外,理论上也支持所有纯 JS 实现的 vscode 插件。拥有 coc.nvim,就拥有了一个异步插件平台。
coc.nvim 需要nodejs
支持。安装nodejs
后,用插件管理器安装 coc.nvim 即可。具体可参考其github 主页。
coc.nvim 的补全可以采用安装插件或者配置 lsp 实现。
以 rust 语言为例,可以直接使用:CocInstall
安装coc-rust-analyzer
插件(会自动安装rust-analyzer
)。也可以在安装rust-analyzer
后在 coc.nvim 的配置文件中配置。使用:CocConfig
打开配置文件,写入
{
"languageserver": {
"rust": {
"command": "rust-analyzer",
"filetypes": ["rust"],
"rootPatterns": ["Cargo.toml"]
}
}
}
注意command
必须保证可用。
关于coc插件以及lsp配置的具体内容可以参考coc.nvim wiki。
到此,rust语言的自动补全已经配置完成,静态检查也同步配置完成。但仅仅如此还不可以使用。coc.nvim的自动配置在项目工程中才能起作用。如单独编写一个main.rs
,则不会有语义提示。必须以cargo new demo
新建一个工程,插件检测到Cargo.toml
后才会启动语义的自动补全。当然也有可以直接在单文件中提示的特例,如markdown语言,本身就不存在工程的概念。
安装coc-actions
插件。
再在coc-snippets
、coc-ultisnips
中选择一个或全选即可。注意需要同步安装honza/vim-snippets
、SirVer/ultisnips
。
coc.nvim默认的补全源来自当前打开的所有buffer、插件或lsp等。此外也可以自定义补全源。具体可参见coc.nvim wiki
下面以补全markdown中的latex语法为例,展示如何自定义补全源。
创建目录~/.config/nvim/autoload/coc/source
。这里以linux系统为例,其他系统的位置可以自行参考wiki。
创建latex.vim
,写入
function! coc#source#latex#init() abort
return {
\'triggerCharacters': ['\'],
\'filetypes' : ['markdown'],
\}
endfunction
function! coc#source#latex#complete(opt, cb) abort
let items = ['kappa', 'theta', 'dot{}', 'ddot{}', 'bar{}', 'hat{}', 'exp', 'sin', 'cos', 'tan', 'sec', 'csc', 'vec{}', 'cot', 'arcsin', 'arccos', 'arctan', 'sinh', 'cosh', 'tanh', 'coth', 'sh', 'ch', 'th', 'max', 'min', 'partial', 'nabla', 'prime', 'backprime', 'infty', 'eth', 'hbar', 'sqrt{}', 'sqrt[]{}', 'pm', 'mp', 'times', 'div', 'cdot', 'odot', 'bigodot' , '{ \}', 'in', 'not', 'ni', 'cap', 'Cap', 'bigcap', 'cup', 'Cup', 'bigcup', 'subset', 'supset', 'supseteq', 'subseteq', 'subseteqq', 'supseteqq', 'subsetneq', 'supsetneq', 'supsetneqq', 'subsetneqq', 'sim', 'approx', 'leq', 'geq', 'parallel', 'nparallel', 'perp', 'angle', 'Box', 'bigtriangleup', 'bigtriangledown', 'forall', 'therefore', 'because', 'overline{}', 'Rightarrow', 'Leftarrow', 'rightarrow', 'leftarrow', 'leftrightarrow', 'nRightarrow', 'nLeftarrow', 'nleftarrow', 'nrightarrow', 'nleftrightarrow', 'overleftarrow{}', 'overrightarrow{}', 'overset{}', 'underline{}', 'sum', 'prod', 'lim', 'limits', 'int', 'iint', 'oint', 'iiint', 'frac{}{}', 'tfrac{}{}', 'dfrac{}{}', '\begin{matrix}\end{matrix}', '\begin{vmatrix}\end{vmatrix}', '\begin{bmatrix}\end{bmatrix}', '\begin{Bmatrix}\end{Bmatrix}', '\begin{pmatrix}\end{pmatrix}','\begin{cases}\end{cases}', '\begin{aligned}\end{aligned}', '\begin{array}\end{array}', 'alpha', 'psi', 'Delta', 'delta', 'beta', 'lambda', 'rho', 'varepsilon', 'Gamma', 'chi', 'mu', 'sigma', 'Lambda', 'tau', 'varphi', 'varPhi', 'phi', 'Phi', 'eta', 'omega', 'varrho', 'Pi', 'pi', 'gamma', 'xi', 'Psi', 'Sigma', 'varnothing', 'iiiint']
call a:cb(items)
endfunction
简单分析一下。配置的主体框架按照wiki给出的例子照猫画虎即可。其中triggerCharacters
表示触发字符,意思就是说当输入该字符时启动补全。filetypes
表示该补全源作用的文件类型。更多选项参见wiki。
coc.nvim提供的其他功能还有很多,包括定义跳转、文档查询等等。感兴趣的可以自行研究。以下附上我的coc.nvim配置。仅供参考。其中vim-which-key
的部分如果没有安装该插件就不必配置。
" coc.nvim
inoremap pumvisible() ? "\" : "\"
inoremap pumvisible() ? "\" : "\"
inoremap pumvisible() ? "\" : "\u\"
inoremap pumvisible() ? coc#_select_confirm() : "\u\"
inoremap pumvisible() ? coc#_select_confirm() : "\u\\=coc#on_enter()\"
autocmd! CompleteDone * if pumvisible() == 0 | pclose | endif
" Some servers have issues with backup files, see #649.
set nobackup
set nowritebackup
" Give more space for displaying messages.
set cmdheight=2
" Having longer updatetime (default is 4000 ms = 4 s) leads to noticeable
" delays and poor user experience.
set updatetime=300
" Don't pass messages to |ins-completion-menu|.
set shortmess+=c
" Always show the signcolumn, otherwise it would shift the text each time
" diagnostics appear/become resolved.
if has("patch-8.1.1564")
" Recently vim can merge signcolumn and number column into one
set signcolumn=number
else
set signcolumn=yes
endif
" Use tab for trigger completion with characters ahead and navigate.
" NOTE: Use command ':verbose imap ' to make sure tab is not mapped by
" other plugin before putting this into your config.
inoremap
\ pumvisible() ? "\" :
\ check_back_space() ? "\" :
\ coc#refresh()
inoremap pumvisible() ? "\" : "\"
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
" Use to trigger completion.
if has('nvim')
inoremap coc#refresh()
else
inoremap coc#refresh()
endif
" Use to confirm completion, `u` means break undo chain at current
" position. Coc only does snippet and additional edit on confirm.
" could be remapped by other vim plugin, try `:verbose imap `.
if exists('*complete_info')
inoremap complete_info()["selected"] != "-1" ? "\" : "\u\"
else
inoremap pumvisible() ? "\" : "\u\"
endif
" GoTo code navigation.
nmap gy (coc-type-definition)
nmap gi (coc-implementation)
nmap gr (coc-references)
nmap gd (coc-definition)
let g:which_key_map1.g = {
\ 'name': '+coc.goto',
\ 'y' : 'go to type definition',
\ 'i' : 'go to implementation',
\ 'r' : 'go to references',
\ 'd' : 'go to definition',
\ }
" Use K to show documentation in preview window.
nnoremap K :call show_documentation()
function! s:show_documentation()
if (index(['vim','help'], &filetype) >= 0)
execute 'h '.expand('')
else
call CocActionAsync('doHover')
endif
endfunction
" Highlight the symbol and its references when holding the cursor.
autocmd CursorHold * silent call CocActionAsync('highlight')
" Symbol renaming.
nmap cr (coc-rename)
" Formatting selected code.
nmap cm (coc-format-selected)
xmap cm (coc-format-selected)
let g:which_key_map1.c = {
\ 'name' : '+coc',
\ 'f' : 'automatically fix errors in current line',
\ 'm' : 'format selected code',
\ 'r' : 'rename symbol',
\ }
augroup mygroup
autocmd!
" Setup formatexpr specified filetype(s).
autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
" Update signature help on jump placeholder.
autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
augroup end
" Apply AutoFix to problem on the current line.
nmap cf (coc-fix-current)
" Add `:Format` command to format current buffer.
command! -nargs=0 Format :call CocAction('format')
" Add `:Fold` command to fold current buffer.
command! -nargs=? Fold :call CocAction('fold', )
" Add `:OR` command for organize imports of the current buffer.
command! -nargs=0 OR :call CocAction('runCommand', 'editor.action.organizeImport')
" 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','')}
" Mappings for CoCList
" open CocList
nnoremap ct :CocList
" Show all diagnostics.
nnoremap ca :CocList diagnostics
" Manage extensions.
nnoremap ce :CocList extensions
" Show commands.
nnoremap cc :CocList commands
" Find symbol of current document.
nnoremap co :CocList outline
" Search workspace symbols.
nnoremap cs :CocList -I symbols
" Do default action for next item.
nnoremap cj :CocNext
" Do default action for previous item.
nnoremap cz :CocPrev
" Resume latest coc list.
nnoremap cp :CocListResume
let g:which_key_map2.c = {
\ 'name' : '+coc',
\ 't' : 'open coc list',
\ 'a' : 'show all diagnostics',
\ 'e' : 'manage extensions',
\ 'c' : 'show commands',
\ 'o' : 'find symbol of current document',
\ 's' : 'search workspace symbols',
\ 'j' : 'do default action for next item',
\ 'z' : 'do default action for previous item',
\ 'p' : 'resume latest coc list',
\ }