Jetbrains到期?试试 coc.nvim 征服 vim/neovim 补全[视频]
hi,大家好,最近貌似很多 jetbrains 的授权到期了,趁机介绍一个强大的vim/neovim LSP 补全插件 coc.nvim,感谢 @赵启明 大佬(知乎上可以关注下)开发的这款非常好用的补全插件。 最近写 go(vim-go) 切到了coc.nvim来进行代码补全,体验了一下感觉很不错,支持二级提示, 速度也很快。打算写一个入门介绍,使用 vim8/neovim 的朋友们可以体验一下,视频里会进行一些简单的演示。
安装
coc 官方文档 已经比较详细了,这里还是简单的介绍下安装方式,因为插件是 nodejs 编写的,如果没有安装 nodejs 的话需要先安装 nodejs。
# 安装 nodejs,执行命令
curl -sL install-node.now.sh/lts | bash
# 安装 coc.nvim,这里推荐使用插件管理器 vim-plug。最近用 vim-go 编写 go 代码,编辑你的vimrc
call plug#begin('~/.vim/plugged')
Plug 'fatih/vim-go'
Plug 'neoclide/coc.nvim', {'branch': 'release'}
call plug#end()
重启 vim 之后执行 :PlugInstall
就安装完成了,过程比较简单。vim-go 插件需要安装 go 工具,执行 :GoInstallBinaries
。(go 工具可能需要网络代理才能装上) 进入 vim 之后如果执行 :CocInfo
可以正常输出版本的话说明安装完成。
如果你使用的 dein 等插件管理器可以参考wiki:Install coc.nvim。
配置
配置比较多可能会令很多人望而却步,不过官方给了一个 vimrc 示例,你可以无脑直接粘贴到你的 vimrc里边,需要自定义配置的时候你再去学习它们的含义。 或者参考我正在用的这个配置 coc.vim。
" if hidden is not set, TextEdit might fail.
set hidden
" Some servers have issues with backup files, see #649
set nobackup
set nowritebackup
" Better display for messages
set cmdheight=2
" You will have bad experience for diagnostic messages when it's default 4000.
set updatetime=300
" don't give |ins-completion-menu| messages.
set shortmess+=c
" always show signcolumns
set signcolumn=yes
" Use tab for trigger completion with characters ahead and navigate.
" Use command ':verbose imap <tab>' to make sure tab is not mapped by other plugin.
inoremap <silent><expr> <TAB>
\ pumvisible() ? "\<C-n>" :
\ <SID>check_back_space() ? "\<TAB>" :
\ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
" Use <c-space> to trigger completion.
inoremap <silent><expr> <c-space> coc#refresh()
" Use <cr> to confirm completion, `<C-g>u` means break undo chain at current position.
" Coc only does snippet and additional edit on confirm.
inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
" Or use `complete_info` if your vim support it, like:
" inoremap <expr> <cr> complete_info()["selected"] != "-1" ? "\<C-y>" : "\<C-g>u\<CR>"
" Use `[g` and `]g` to navigate diagnostics
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)
" Remap keys for gotos
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
" Use K to show documentation in preview window
nnoremap <silent> K :call <SID>show_documentation()<CR>
function! s:show_documentation()
if (index(['vim','help'], &filetype) >= 0)
execute 'h '.expand('<cword>')
else
call CocAction('doHover')
endif
endfunction
" Highlight symbol under cursor on CursorHold
autocmd CursorHold * silent call CocActionAsync('highlight')
" Remap for rename current word
nmap <leader>rn <Plug>(coc-rename)
" Remap for format selected region
xmap <leader>f <Plug>(coc-format-selected)
nmap <leader>f <Plug>(coc-format-selected)
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
" Remap for do codeAction of selected region, ex: `<leader>aap` for current paragraph
xmap <leader>a <Plug>(coc-codeaction-selected)
nmap <leader>a <Plug>(coc-codeaction-selected)
" Remap for do codeAction of current line
nmap <leader>ac <Plug>(coc-codeaction)
" Fix autofix problem of current line
nmap <leader>qf <Plug>(coc-fix-current)
" Create mappings for function text object, requires document symbols feature of languageserver.
xmap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap if <Plug>(coc-funcobj-i)
omap af <Plug>(coc-funcobj-a)
" Use <TAB> for select selections ranges, needs server support, like: coc-tsserver, coc-python
nmap <silent> <TAB> <Plug>(coc-range-select)
xmap <silent> <TAB> <Plug>(coc-range-select)
" Use `:Format` to format current buffer
command! -nargs=0 Format :call CocAction('format')
" Use `:Fold` to fold current buffer
command! -nargs=? Fold :call CocAction('fold', <f-args>)
" use `:OR` for organize import of current buffer
command! -nargs=0 OR :call CocAction('runCommand', 'editor.action.organizeImport')
" Add status line support, for integration with other plugin, checkout `:h coc-status`
set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}
" Using CocList
" Show all diagnostics
nnoremap <silent> <space>a :<C-u>CocList diagnostics<cr>
" Manage extensions
nnoremap <silent> <space>e :<C-u>CocList extensions<cr>
" Show commands
nnoremap <silent> <space>c :<C-u>CocList commands<cr>
" Find symbol of current document
nnoremap <silent> <space>o :<C-u>CocList outline<cr>
" Search workspace symbols
nnoremap <silent> <space>s :<C-u>CocList -I symbols<cr>
" Do default action for next item.
nnoremap <silent> <space>j :<C-u>CocNext<CR>
" Do default action for previous item.
nnoremap <silent> <space>k :<C-u>CocPrev<CR>
" Resume latest coc list
nnoremap <silent> <space>p :<C-u>CocListResume<CR>
如何配置 go 补全
进入 vim 之后执行 :CocConfig
然后可以设置 go 的 language server:(实际上是在编辑 coc-settings.json 文件)
{
"languageserver": {
"golang": {
"command": "gopls",
"rootPatterns": ["go.mod", ".vim/", ".git/", ".hg/"],
"filetypes": ["go"]
}
}
}
编辑完成保存退出 vim 就可以啦。尝试进入一个 go 工程文件体验一下吧,视频里我会进行一些常用的演示。 对于 go 微服务后台开发来说,补全/跳转/错误提示/名称重构基本就够用了,还有一些 vim-go 笔者常用的一些命令辅助提升开发效率。
# 最近一直在开发机服务器上直接用 neovim+vim-go 写 golang,具有完备开发功能(vim-go借助各种go工具实现)
# https://github.com/fatih/vim-go
# https://github.com/fatih/vim-go-tutorial # vim-go 官方教程,最好过一遍
let g:go_def_mode='godef' # 有时候 gopls 有问题可以用 godef 跳转,默认用 gopls
# 如何生成 interface 接口定义
type S struct{} # cursor 放在 S 上执行 :GoImpl io.Reader
# 跳转到接口的实现 https://github.com/fatih/vim-go/issues/820
:GoDef (或ctrl+]) 跳转到定义,但是如果是接口实现只能跳转到 interface 定义而非 struct 实现。
:GoCallees 从函数调用处跳转到接口的真正实现,而不是接口定义 (在方法调用点使用 -> struct 方法实现列表)
:GoCallers 找到当前函数被调用的地点
:GoImplements 跳转到该函数实现的接口定义处 (struct 方法定义 -> interface 定义)
# 常用的方便命令(命令模式Tab补全), 参考 https://github.com/fatih/vim-go/blob/master/doc/vim-go.txt
:GoFmt 格式化,你可以配置 vim-go 直接保存自动执行格式化或者直接执行 GoImports
:GoRun, GoTest, GoTestFunc 运行代码和单测
:GoMetaLinter 执行 lint,可以配置 .gometalinter.json 忽略一些 lint 错误。https://github.com/PegasusWang/linux_config/blob/master/golang/gometalinter.json
:GoRename 快速重构
:GoImpl 为 struct 生成接口函数定义(光标放到struct定义上使用)。如果一个 interface 有很多需要实现的函数,比较方便
:GoAddTags GoRemoveTags json 快速给 struct field 增加 json tag,支持 visual 模式多选。默认 tag 名是下划线命名
:GoKeyify 把无名称初始化的 struct literals 转成包含字段名的初始化方式
:GoIfErr 生成 if err 返回值(或者用 snippets)
:GoChannelPeers 寻找可能的 channel 发送和接收点
:GoFillStruct 给一个 struct 填充默认值
笔者用了几个月开发体验还是不错的,在自己的开发机上和本地 macos 开发体验完全一致。如果你想体验其他编程语言的补全,可以试试安装对应的插件,比如 CocInstall coc-python
。
如果您觉得插件不错,可以给开源项目捐赠点咖啡钱,支持一下优秀的开源项目和无私的开发者们,感谢你们的付出让社区变得越来越好。
vim-go和coc.nvim 冲突问题
这里补全我建议用 coc 的,禁用 vim-go 的。可以设置 vim-go 配置 let g:go_gopls_enabled = 0。
写go代码的时候,主要会用到 coc.nvim 的以下快捷键:分别是 gd (跳转到定义); gy (跳转到类型定义); gi (查找接口实现); gr (查找变量被使用的地方,比直接grep更精确)
" 以下是 coc.nvim 官方示例定义的快捷键
" 跳转到变量定义。normal 模式下在一个变量名上按一下 gd 即可跳转到定义位置,然后ctrl-o 可以快速返回原位置
nmap <silent> gd <Plug>(coc-definition)
" 跳转到值的类型定义,或者跳转到函数的返回值类型。在你想要快速查找一个类型的结构的时候非常有用
nmap <silent> gy <Plug>(coc-type-definition)
" 跳转到 interface 接口的对应实现。比如查看go里一个 interface 被哪些 struct 实现了
nmap <silent> gi <Plug>(coc-implementation)
" 打开当前变量、函数等被引用的列表。比如看一个 函数 在哪些地方使用了
nmap <silent> gr <Plug>(coc-references)
参考
往期文章推荐: