Jetbrains到期?试试 coc.nvim 征服 vim/neovim 补全[视频]

Jetbrains到期?试试 coc.nvim 征服 vim/neovim 补全[视频]

coc.nvim vim/neovim 补全插件https://www.zhihu.com/video/1199413416475308032

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)

参考

《vim as a go ide》

往期文章推荐:


编辑于 2022-10-30 09:42