Day 16:自动补全!coc.nvim

一个好的自动补全工具可以让你工作效率翻倍,你不用再去查文件了,自动补全不仅可以告诉你这里有什麽函数可以用,还会告诉你参数的型态、函数功能的说明,可以说是把文件都写在 vim 里面了。
以前我用的自动补全是 You Complete Me(YCM),现在我选择使用 coc.nvim 原因是他提供更多的补全来源、外挂和设定,而且可以用 nodejs 自制外挂,据说所有纯 JS 写的 VS code 外挂都可以装(这个我没实验过,只是传闻)。关於这两个自动补全外挂的比较碍於篇幅请自行 Google。

安装

coc.nvim 和一般的 vim 外挂一样,都是用 vim-plug 安装就可以了,在 ~/.config/nvim/plugin.vim 中新增以下设定

Plug 'neoclide/coc.nvim', {'branch': 'release'}
so ~/.config/nvim/coc-config.vim

因为 coc 有很多设定,为了避免档案太杂乱我把 coc 相关的设定移到另一个档案,就像我们在 前天 做得一样
接下来建立 ~/.config/nvim/coc-config.vim,不然等等载入设定档 vim 会报错

:!touch ~/.config/nvim/coc-config.vim

:! {cmd} 可以执行外部命令

接下来存档安装

:w | PlugInstall

跑完後,重开 vim,coc 就装好了

lsp 语言服务器协定

在讲 coc 之前必须先讲 Language Server Protocol,简称 lsp,中文是「语言服务器协定」。lsp 做的事是提供自动补全和 go to def,能做到这两个功能的原因是因为 lsp 懂程序码,他知道你写的每个字代表什麽。为什麽 lsp 这麽强呢?因为 lsp 什麽都不懂,他把所有事情丢给 language server 处理,所以只要你有装 language server,那麽 lsp 什麽语言都懂。
这麽神奇的 lsp 就是大名鼎鼎的 vs code 提出的(难怪是最多人用的编辑器),我们深耕 45 年的 vim 当然要跟上,所以 coc.nvim 出现了,他是一个 vim 的 language client,而重点是非常好用!

安装 coc 扩充

刚刚说了 coc 的主要功能是把所有事情丢给别人做,那麽这个「人」设定听起来就很麻烦,所以 coc 有个好主意,用扩充( extension )解决!你只要装好扩充差不多就设定好 lsp 了
coc.nvim 的自动补全选字来源除了目前所有的 buffer(开启的档案)之外,还有 coc 扩充。
coc 扩充安装很简单,在 vim 里面下指令 :CocInstall {extension},那麽这个扩充的名字该去哪里找呢?一个是 coc.nvim 的 GitHub Wiki,另一个是去 npm 搜寻 coc,稍微过滤一下大部分都是 coc.nvim 的扩充。

刚刚讲的安装方法有一个缺点,就是当你今天要搬电脑时你要全部手动再安装一次,这时候就有点麻烦了。所以你可以在 ~/.config/nvim/coc-config.vim 中写下我们第一个 coc 设定

let g:coc_global_extensions = [
\ 'coc-extension-1',
\ 'coc-extension-2'
\ ]

这个变数储存的是 coc 扩充的名字(就是你安装时用的那个),coc 启动如果没安装他就会自己去装了,所以手动安装好扩充後记得在这里写一下,为以後搬电脑做打算
你也可以用 :CocList extensions 列出现在安装的扩充
至於要装什麽扩充,这个就要看你要写什麽程序语言了,自己去上面介绍的两个地方找你需要的,我这里就不多介绍

基本设定

因为 coc 可能是你在写程序时最常用的外挂,所以为了避免有快捷键冲突,coc 预设不会有任何的按键绑定,所以你必须自己写全部的 keymap,在 coc.nvim 的 GitHub README.md 有范例,接下来的设定都是从这里面挑出来的。
以下是我觉得必须的设定,我会把注解翻成中文,有些在范例上标明「可能」、「某些情况」的设定我不会纳进来,当你遇到奇怪问题时再去看看范例和 issue

" 太长的更新间隔会导致明显的延迟并降低使用者体验(预设是 4000 ms = 4s )
set updatetime=300

" 永远显示 signcolumn(行号左边那个,这我不知道怎麽翻),否则每当有诊断出来时整个程序码就会被往右移
if has("nvim-0.5.0") || has("patch-8.1.1564")
  " 新的版本可以把 signcolumn 和行号合并(这个我版本不够没看过,有人知道会长怎样可以下面留言吗?)
  set signcolumn=number
else
  set signcolumn=yes
endif

" 用 tab 键触发自动补全
" 注意:载入设定後记得用命令 `verbose imap <tab>` 确定这没有被其他外挂覆盖掉
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

" 让 enter 键自动完成第一个建议并让 coc 进行格式化(不确定个格式化指的是什麽,我看不太出来)
" enter 可以被重复 keymap(看不懂就算了,意思是你乱搞不会出错)
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
	\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

" 用 \rn 重新命名变数、函数(原文写「符号」)
nmap <leader>rn <Plug>(coc-rename)

" 这个让你可以卷动浮动视窗和跳出式框框(有时候自动补全给你的文件会太长超出萤幕,如果你想要看下面的内容必须设定这个)
if has('nvim-0.4.0') || has('patch-8.2.0750')
  nnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
  nnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
  inoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(1)\<cr>" : "\<Right>"
  inoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(0)\<cr>" : "\<Left>"
  vnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
  vnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
endif

结尾

coc.nvim 的设定真的很多,一眼看上去会觉得很烦,但是认真看完设定好後的 vim 真的会让你过得非常舒服。
明天是我今天没有介绍到的部份,大部份是超难记的快捷键。一样都会有全中文翻译(但是有些我真的没用过,只能硬着头皮翻译了)


<<:  Day_17 iPerf3

>>:  Day14-守护饼乾大作战(一)

Day9_HTML语法6

项目符号和编号 在阅读时,常常会使用条列式的方式呈现内容,让读者更一目了然,此时我们就会使用 <...

基本面 VS 技术面

接触股市的人一定常听到「基本面」与「技术面」这两种面向。 很多人都有相同疑问:我该研究「基本面」还是...

我想用 AJAX,但是...

现在使用者对网页应用程序的要求越来越高,又要好看又要反应快。常见的做法是使用 AJAX 提升页面反应...

Nvidia Docker安装说明(含WSL2)

订阅patreon即可看到更多文章 https://www.patreon.com/wade3c ...

Day19-不能说的秘密(一)

前言 讲完 session 之後,接下来这几天要来讲讲跟密码有关的安全性议题,毕竟如果使用者的密码不...