代替YCM,当前vim最强自动补全方案

首发于我的个人博客(https://www.niuiic.top)


本文介绍 vim 自动补全方案。主要采用更强大的 coc.nvim 插件来替代 YCM。

vim 自动补全

前言

自动补全对于任何一个试图取代 IDE 的编辑器的重要性不言而喻。想要将 vim 打造为最契合自己的 IDE,无论如何都不能少了强大的自动补全功能。

coc.nvim 介绍

coc.nvim 是针对 neovim 开发的的功能非常强大,完全可以替代 YCM,带来更加优越的补全体验。包括语义补全、片段补全、定义跳转、文档查阅、静态检查等等。

同时 coc.nvim 也是一个全新的插件平台,除了其原生插件外,理论上也支持所有纯 JS 实现的 vscode 插件。拥有 coc.nvim,就拥有了一个异步插件平台。

coc.nvim 安装

coc.nvim 需要nodejs支持。安装nodejs后,用插件管理器安装 coc.nvim 即可。具体可参考其github 主页。

使用 coc.nvim 进行补全

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-snippetscoc-ultisnips中选择一个或全选即可。注意需要同步安装honza/vim-snippetsSirVer/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',
			\ }

你可能感兴趣的:(vim,vim)