Vim 8.1 懒人配置手册(包含 C/C++、Python、Rust 自动补全,基于 coc.nvim)

先说点废话。

最近装了 WSL2,想着作为 Win10 内置的 Linux 系统,应该比一般的虚拟机要来得平滑一些。毕竟虚拟机还要装 Virtualbox,每次开机还要多点几下,还要等它启动。怕麻烦。。。

可能习惯问题,喜欢在 Linux 下配置开发环境(学习写代码)。总感觉 Windows 上略显磨叽了一些。也许我道行不够。碰到需要编译的东西,一套工具装起来过于繁琐,直接 sudo apt install gcc 不香吗。

可惜 WSL 没有桌面支持,装不上 Vscode。对于工具的选择,我的原则是简单够用就好,Vscode 即是目前我的最爱(非重度编码)。
开箱即用,功能满足基本需求。无非代码高亮、自动补全、查看定义、语法检查、代码格式化,再加个跳转。

于是决定在 Windows 系统上安装 Vscode,借助 Remote WSL 插件“远程”编码。可惜有 BUG,一直不能正常工作。Github 上提了 issue,没人理。无奈转向 Vim。

一开始用的补全插件是 YouCompleteMe,还要编译。虽然敲个命令就能自动执行,但光 Rust 支持就在本地给我搞了将近 1G 的文件,不太能忍。网上查了下,貌似已经很老的机制了。于是转向较新一点的 coc.nvim。据说支持各种 LSP(这个缩写。。。),也不懂,能用就行。

废话结束。

一、效果截图

Rust

Python

C++

二、NERDTree 文件浏览器

vim 用的自带的 8.1 版本,有内置的插件管理。一般的插件安装流程是直接将插件源代码 clone 到 ~/.vim/pack/vendor/start 路径下(没有就创建),再在 vim 中运行 :helptags ~/.vim/pack/vendor/start/someplugin/doc 命令生成帮助文档(这一步可选)。

vim 会自动检测已经下载的插件。vendor 路径下可以有 startopt 两个目录,start 路径下的插件会在 vim 启动时自动加载,opt 路径下的插件则需要通过 :packadd 命令手动加载。

vendor 也可以是其他名称,同位置下也可以有多个相同结构的目录,方便对不同类型的插件分别进行管理。
省事起见,这里所有的插件都放在 ~/.vim/pack/vendor/start 下面。

NERDTree 文件浏览器插件安装:

1
2
cd ~/.vim/pack/vendor/start
git clone https://github.com/scrooloose/nerdtree

~/.vimrc 文件中添加配置:

1
2
3
4
5
6
7
8
" 进入 vim 时自动开启 NERDTree
autocmd VimEnter * NERDTree | wincmd p

" 若关闭某个 buff 后 NERDTree 是仅剩的最后一个 buff,则自动关闭 NERDTree
autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif

" 使用 Ctrl+n 快捷键打开或关闭 NERDTree
nnoremap <C-n> :NERDTreeToggle<CR>

更多配置选项参考 VimAwesome

三、vim-airline 与配色

安装 vim-airline 状态栏美化插件:
git clone https://github.com/vim-airline/vim-airline

关于配色,萝卜青菜各有所爱。懒得去一个一个试。
准备了两套,vim-one 深色和 gruvbox 浅色。

vim-one 插件安装:
git clone https://github.com/rakr/vim-one

添加配置:

1
2
3
4
5
" 深色背景
set bg=dark

" 启用 one 配色
colorscheme one

效果截图:vim-one dark

安装 gruvbox 插件:
git clone https://github.com/morhetz/gruvbox

修改配置文件(注释掉 colorscheme one):

1
2
3
set bg=light
" colorscheme one
autocmd vimenter * ++nested colorscheme gruvbox

效果截图:gruvbox light

更复杂的配置可自行在 VimAwesome 搜索对应的插件,或者进入相应的 Github 主页查看。

四、coco.nvim 代码补全与语法检查

安装 nodejs >= 10.12,官网上写的是通过 curl -sL install-node.now.sh/lts | bash 命令安装。我个人建议使用 nvm 安装最新的 lts 版本。此处不赘述。

安装 coc.nvim 插件:
git clone https://github.com/neoclide/coc.nvim.git

为了得到某种编程语言的补全功能,还需要安装对应语言的 coc 扩展以及代码补全后端(LSP)。
比如 C/C++ 对应的 coc 扩展为 coc-clangd,LSP 为 clangd。两个都需要。

安装 coc 扩展的方法非常简单,进入 vim 后运行 :CocInstall extension_name 命令即可。
比如使用 :CocInstall coc-clangd 命令安装 coc-clangd 扩展。coc 扩展我遇到的都比较小,安装非常迅速,也会单独开一个窗口显示进度信息。

coc 扩展安装完成后,打开对应的源代码文件,比如 vim test.c,vim 就会自动在本地环境中寻找对应的 LSP(C/C++ 语言是 clangd)。

clangd 此时并未安装,vim 就会提示你运行某个命令(在 vim 内部)自动安装该依赖。这里有个坑。
不知道是不是网络的问题,我复制运行了 vim 提供的命令,一直显示下载中,几个小时不见下载完成。。。

好在可以手动安装 clangd,退出 vim 直接运行 sudo apt install clangd 即可。
此时 coc.nvim 对于 C/C++ 的补全支持即安装配置完成。

Rust 和 Python 语言支持

对于 Rust 语言,需要先安装 coc-rust-analyzer 扩展:
:CocInstall coc-rust-analyzer
这一步简单迅速。

安装 rust-srcrustup component add rust-src

接着还必须安装针对 Rust 的 LSP(rust-analyzer)。鉴于安装 clangd 时出现的曲折,我决定手动安装 rust-analyzer。诡异的事情发生了。手动安装的可执行程序不被 coc 识别。
无奈下尝试 vim 中的自动安装居然成功了。。。

方法是用 vim 新建任意一个 rust 源文件(vim test.rs),vim 会自动弹出提示,找不到 rust-analyzer,是否自动安装,选择 Yes 即可。这里的安装过程居然异乎寻常的快。
安装完成后可能不会立即生效,会尝试创建索引。多打开几个文件试试。

至于 Python,安装 coc-pyright
:CocInstall coc-pyright

印象中并没有做其他操作,对于 Python 的支持就自动生效了,也许是安装扩展的时候自动安装了对应的 LSP。

对于其他语言的支持,可参考 Using coc extensions

coc.nvim 示例配置(从官方 Github 上 copy 的,主要是一些快捷键的映射,可根据需求删减。没细看):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
" Set internal encoding of vim, not needed on neovim, since coc.nvim using some
" unicode characters in the file autoload/float.vim
set encoding=utf-8

" TextEdit might fail if hidden is not set.
set hidden

" 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("nvim-0.5.0") || 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 <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config.
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.
if has('nvim')
inoremap <silent><expr> <c-space> coc#refresh()
else
inoremap <silent><expr> <c-@> coc#refresh()
endif

" Make <CR> auto-select the first completion item and notify coc.nvim to
" format on enter, <cr> could be remapped by other vim plugin
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

" Use `[g` and `]g` to navigate diagnostics
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list.
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)

" GoTo code navigation.
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>')
elseif (coc#rpc#ready())
call CocActionAsync('doHover')
else
execute '!' . &keywordprg . " " . expand('<cword>')
endif
endfunction

" Highlight the symbol and its references when holding the cursor.
autocmd CursorHold * silent call CocActionAsync('highlight')

" Symbol renaming.
nmap <leader>rn <Plug>(coc-rename)

" Formatting selected code.
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

" Applying codeAction to the selected region.
" Example: `<leader>aap` for current paragraph
xmap <leader>a <Plug>(coc-codeaction-selected)
nmap <leader>a <Plug>(coc-codeaction-selected)

" Remap keys for applying codeAction to the current buffer.
nmap <leader>ac <Plug>(coc-codeaction)
" Apply AutoFix to problem on the current line.
nmap <leader>qf <Plug>(coc-fix-current)

" Map function and class text objects
" NOTE: Requires 'textDocument.documentSymbol' support from the language server.
xmap if <Plug>(coc-funcobj-i)
omap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap af <Plug>(coc-funcobj-a)
xmap ic <Plug>(coc-classobj-i)
omap ic <Plug>(coc-classobj-i)
xmap ac <Plug>(coc-classobj-a)
omap ac <Plug>(coc-classobj-a)

" Remap <C-f> and <C-b> for scroll float windows/popups.
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

" Use CTRL-S for selections ranges.
" Requires 'textDocument/selectionRange' support of language server.
nmap <silent> <C-s> <Plug>(coc-range-select)
xmap <silent> <C-s> <Plug>(coc-range-select)

" 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', <f-args>)

" 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
" Show all diagnostics.
nnoremap <silent><nowait> <space>a :<C-u>CocList diagnostics<cr>
" Manage extensions.
nnoremap <silent><nowait> <space>e :<C-u>CocList extensions<cr>
" Show commands.
nnoremap <silent><nowait> <space>c :<C-u>CocList commands<cr>
" Find symbol of current document.
nnoremap <silent><nowait> <space>o :<C-u>CocList outline<cr>
" Search workspace symbols.
nnoremap <silent><nowait> <space>s :<C-u>CocList -I symbols<cr>
" Do default action for next item.
nnoremap <silent><nowait> <space>j :<C-u>CocNext<CR>
" Do default action for previous item.
nnoremap <silent><nowait> <space>k :<C-u>CocPrev<CR>
" Resume latest coc list.
nnoremap <silent><nowait> <space>p :<C-u>CocListResume<CR>

五、彩蛋

smile

在 vim 中运行 :smile

效果::smile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
:smile
oooo$$$$$$$$$$$$oooo
oo$$$$$$$$$$$$$$$$$$$$$$$$o
oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o o$ $$ o$
o $ oo o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o $$ $$ $$o$
oo $ $ "$ o$$$$$$$$$ $$$$$$$$$$$$$ $$$$$$$$$o $$$o$$o$
"$$$$$$o$ o$$$$$$$$$ $$$$$$$$$$$ $$$$$$$$$$o $$$$$$$$
$$$$$$$ $$$$$$$$$$$ $$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$
$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$ $$$$$$$$$$$$$$ """$$$
"$$$""""$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ "$$$
$$$ o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ "$$$o
o$$" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$o
$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" "$$$$$$ooooo$$$$o
o$$$oooo$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ o$$$$$$$$$$$$$$$$$
$$$$$$$$"$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$""""""""
"""" $$$$ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$" o$$$
"$$$o """$$$$$$$$$$$$$$$$$$"$$" $$$
$$$o "$$""$$$$$$"""" o$$$
$$$$o o$$$"
"$$$$o o$$$$$$o"$$$$o o$$$$
"$$$$$oo ""$$$$o$$$$$o o$$$$""
""$$$$$oooo "$$$o$$$$$$$$$"""
""$$$$$$$oo $$$$$$$$$$
""""$$$$$$$$$$$
$$$$$$$$$$$$
$$$$$$$$$$"
"$$$""""
Kill Sheep 小游戏

针对 vim 8.2 版本,可在 Windows 系统中安装 gvim 8.2

进入 C:\Users\xxx\vimfiles\pack\vendor\start 路径下(没有就创建),clone 源代码:
git clone https://github.com/vim/killersheep.git

打开 gvim,最大化,运行 :KillKillKill 命令即可进入游戏。
killer sheep