原文发在语雀上了:https://www.yuque.com/zhoujiping/programming/rust-vim-settings
直接导入的 md ,有些图片没弄到 CSDN 上(暂时不修复这些小 bug 了),所以去语雀上看吧。 CSDN 不支持长代码块滚动条,有些长代码很占篇幅,而语雀可以利用滚动条进行隐藏。此外,语雀上的排版也更美观。
前言
前段时间发现一篇 2021 年用什么 IDE 开发 Rust ?文章,梳理了大部分 IDE。
我最感兴趣的是这张图:https://areweideyet.com/(Rust 的特色口号:Are we xx yet?)
这个网站推荐了一些 Vim / Neovim 的重要插件。
仔细一看,截止 2019-07-15😓 有些 IDE 和插件的介绍也都四五年前了 : (
anyway 想找个深度体验+完整介绍的最新文章没找到。索性自己尝试和记录。
比如图里面罗列的功能出自哪个插件、哪个插件提供的哪个功能最佳,新手肯定非常关心。(只有新手最懂新手bushi)
关于 vim,我有几个踩过的坑需要说明一下:
- spacevim 安装成功之后未报错,但是进入 vim 之后配置没有生效(可能默认不是
~/.vimrc
?),也没找到相关的解决办法,再加上依赖庞大(需要 py、lua、字体之类的),一点也不精简,因此放弃。 - 鉴于 YouCompleteMe 实在难装,一大堆难下载的依赖,那几个 py 三方库依赖非要去 github 下载,放弃。
- rust-analyzer 是最新的 Rust IDE 辅助工具,支持各大编辑器,对 vim 的支持有多种方式。其中 coc.nvim 方式 简单、纯粹且强大,非常棒! _p.s. _coc.nvim _/ coc-snippets / _coc-rust-analyzer 竟然全是国人开发的 👍,还不赶紧支持一下,去点个 ⭐ 也行啊~~
★ 由于 vim 的配置文件在 vim 和 neovim 下不同,这里介绍一下:
vim: ~/.vimrc
neovim: ~/.config/nvim/init.vim
笔者之前用的 vim + vundle 插件管理,后面换成了 neovim + vim-plug。系统环境:腾讯云服务器 ubuntu focal 20.04
注意:
Rust 专用插件不是仅支持我写的功能,而是我觉得这个功能最好用,或者我没找到其他的功能怎么用。
比如 rust-analyzer 文档写了很多功能 (features) ,拿 vscode 举例(毕竟 vscode 最大程度上支持 RA),对其他 IDE 说得不清楚,那么只能去看具体实现的插件的使用说明。
如果有小伙伴补充,欢迎 鼠标选中文字评论 / 在下方留言 ,我加上。
语法增强 rust.vim
官网:https://github.com/rust-lang/rust.vim
官方提供的 vim 插件,主要增强 vim 对 rust 的语法识别。安装之后把以下内容添加到 vim 的配置文件。
" === rust.vim 配置 ===
syntax enable
filetype plugin indent on
" 保存时代码自动格式化
let g:rustfmt_autosave = 1
" 手动调用格式化, Visual 模式下局部格式化,Normal 模式下当前文件内容格式化
" 有时候代码有错误时,rust.vim 不会调用格式化,手动格式化就很方便
vnoremap <leader>ft :RustFmtRange<CR>
nnoremap <leader>ft :RustFmt<CR>
" 设置编译运行 (来自 rust.vim,加命令行参数则使用命令 `:RustRun!`)
nnoremap <M-r> :RustRun<CR>
" 使用 `:verbose nmap <M-t>` 检测 Alt-t是否被占用
" 使用 `:verbose nmap` 则显示所有快捷键绑定信息
nnoremap <M-t> :RustTest<CR>
使用 :h Rust
查看 rust.vim
的说明。支持在 Rust 文件中使用以下 vim 命令:
:RustEmitAsm
:RustEmitIr
:RustExpand
:RustFmt
:RustFmtRange
:RustInfo
:RustInfoToClipboard
:RustInfoToFile
:RustPlay
:RustRun
:RustTest
比较常用的命令::RustRun
对当前项目编译运行到临时文件夹(很方便,但是默认识别不了 Cargo.toml
配置,所以不适合调用 crate 的情况)、:RustRun!
带参数编译运行。
其他方式编译项目:vim 命令 :!cargo run
(推荐这种方式),或者使用 vim 的内置终端 👉 指路介绍
根据语法识别来配置高亮:笔者自己的 color scheme 配置
代码片段 coc-snippets
Always async, never slows you down. 始终保持异步,永不减慢您的速度。
coc 系的插件非常强大。。。有了它,完全享受在 vim 编辑文件的飞速当中。
snippet 相关链接:coc-snippets 官网 | ultisnips 官方 | vim-snippets 官方: UltiSnips | ultisnip 完整案例 | 笔者的不定期更新:coc-snippets 用法
:CocInstall coc-snippets
进行安装(👉 coc.nvim 安装指路):CocCommand snippets.editSnippets
自定义当前打开文件类型的 snippets(若需定义所有类型文件,编辑.config/coc/ultisnips/all.snippets
即可)- 快捷键:
- 使用
Ctrl-j
进行下一个填写; - 使用
Ctrl-k
进行上一个填写; - 在
.vimrc
中添加vmap <m-x> <Plug>(coc-snippets-select)
来实现可视模式下利用Alt-X
使用 ultisnips 的 visual 功能(把选中的内容直接放置在 snippet 内部) - 使用
<tab>
键触发补全、补全确认、snippet 展开和跳转下一个(trigger completion, completion confirm, snippet expand and jump like VSCode),需把以下内容加入配置文件:
- 使用
inoremap <silent><expr> <TAB>
\ pumvisible() ? coc#_select_confirm() :
\ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
\ <SID>check_back_space() ? "\<TAB>" :
\ coc#refresh()
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
let g:coc_snippet_next = '<tab>'
- coc-rust-analyzer 也具有 snippet 功能,但是暂时无法自定义?(RA 加载更慢一些,别担心影响编辑,是异步加载啦),且 snippet 方式等于加强版的补全(支持动态占位符,但不是所有的提示都支持占位符),因此使用专门的 snippet 工具。
- coc-snippets 不仅仅支持 大部分 ultisnips 使用方式,还支持 snipmate 、VSCode snippets 方式。ultisnips 最大亮点:插值、自定义 python 函数。
visual 插入方式:
![visual 功能.gif](https://img-blog.csdnimg.cn/img_convert/91b3904851e7feea2756ef9b5d5eb301.gif#height=284&id=Wr6cw&name=visual 功能.gif&originHeight=284&originWidth=807&originalType=binary&ratio=1&size=213438&status=done&style=none&width=807)
代码 补全 | 检查 | 跳转 利器
RA 官方说明:rust-analyzer: coc-rust-analyzer
笔者的成品:
安装 coc-rust-analyzer
coc.nvim(👉 coc 安装指路)、rustc 和 cargo 都已经安装好之后:
- 终端输入
vim
进入 vim,输入:CocInstall coc-rust-analyzer
自动下载和安装(甚至更新) rust-analyzer 工具,因此无需提前安装 rust-analyzer; - 初次使用时,进入一个 rs 文件之后,vim 会询问是否下载 rust-analyzer,选择 yes 就可以使用了;
- 更多参数和配置见 coc-rust-analyzer、Using-coc-extensions
更新 coc-rust-analyzer
一般来说,在启用 coc-rust-analyzer 并且打开 rust 文件时,会弹出窗口提示更新 coc-rust-analyzer 和 rust-analyzer。
此外还使用以下命令让插件更新:
:CocUpdate
更新 coc-rust-analyzer 插件
:CocCommand rust-analyzer.upgrade
更新 rust-analyzer 程序
手动更新 rust-analyzer
因为 rust-analyzer 更新频繁, coc-rust-analyzer
自动更新机制对访问 github 慢的用户来说不友好,并且每次打开文件都会弹窗提示更新,使用以下方式来不提醒更新,并且手动下载最新的 rust-analyzer :
在 vim 输入 :CocConfig
或者直接编辑 ~/.config/nvim/coc-settings.json
文件,添加
{
"rust-analyzer.updates.prompt": false,
"rust-analyzer.server.path": "/home/ubuntu/.config/coc/extensions/coc-rust-analyzer-data/rust-analyzer"
}
rust-analyzer 下载地址:https://github.com/rust-analyzer/rust-analyzer/releases
ubuntu 系统下载 rust-analyzer-x86_64-unknown-linux-gnu.gz
,解压、添加执行权限、重命名:
gunzip rust-analyzer-x86_64-unknown-linux-gnu.gz
chmod +x rust-analyzer-x86_64-unknown-linux-gnu
mv rust-analyzer-x86_64-unknown-linux-gnu rust-analyzer
受 分享一种安装/更新/切换 rust-analyzer 版本的方法 启发,翻看确认了一下 RA 文档,竟然错过了 rustup 这么好的工具。上述的笨办法以下三步到位:
- 切换到 / 增加 nightly 版本的 Rust,并增加 rust-analyzer-preview 二进制组件支持:
rustup default nightly # rustup default 可以查看默认的 Rust 版本
rustup component add rust-analyzer-preview # 注意 rust-analyzer 只在 Rust 默认版本是 nightly 时生效
- 在 vim 输入
:CocConfig
或者直接编辑~/.config/nvim/coc-settings.json
文件,添加以下配置:
{
"rust-analyzer.updates.prompt": false,
"rust-analyzer.server.path": "~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rust-analyzer"
}
- 使用
rustup update
的时候会自动更新 rustup component,所以更新 Rust 的时候直接更新 RA
功能介绍
默认开启的功能
- 代码诊断检查:
- 自动引入未加载的 crate
一些实用的命令
- 默认开启 diagnostics 来提示有问题的代码;查看全部的 diagnostics 时输入命令
:CocDiagnostics
- 支持以下命令
:CocCommand xx
命令。
rust-analyzer.run
rust-analyzer.ssr
rust-analyzer.upgrade
rust-analyzer.viewHir
rust-analyzer.openDocs
rust-analyzer.joinLines
rust-analyzer.peekTests
rust-analyzer.syntaxTree
rust-analyzer.memoryUsage
rust-analyzer.expandMacro
rust-analyzer.explainError
rust-analyzer.parentModule
rust-analyzer.matchingBrace
rust-analyzer.openCargoToml
rust-analyzer.serverVersion
rust-analyzer.analyzerStatus
rust-analyzer.reloadWorkspace
rust-analyzer.toggleInlayHints
rust-analyzer.echoRunCommandLine
rust-analyzer.reload
例如在 neovim 中默认会设置 行内类型提示 (inlay type hint),也就是![image.png](https://img-blog.csdnimg.cn/img_convert/698a3f2df3b067f2f6c900efba93f3dc.png#height=12&id=wsm8I&margin=[object Object]&name=image.png&originHeight=24&originWidth=230&originalType=binary&ratio=1&size=1437&status=done&style=none&width=115) 三角形后的蓝色部分。
在复制源代码的时候暂时不需要这个提示,就可以在普通模式下输入以下命令来触发。
:CocCommand rust-analyzer.toggleInlayHints
如果想要复制出行内类型的提示,可以修改 Coc 配置文件:
{
"rust-analyzer.inlayHints.chainingHintsSeparator": "// ",
"rust-analyzer.inlayHints.typeHintsSeparator": "// ",
}
在 vim 里面,命令转换成快捷键是非常基础和简单的。配置文件写入以下内容:
" 设置触发/关闭行内类型提示
nnoremap <F4> :CocCommand rust-analyzer.toggleInlayHints<CR>
♥ 各种定义跳转
coc.nvim 支持各式跳转:coc-key-mappings。coc.nvim readme 文档给出例子:
" === coc.nvim 设置 ===
" coc-definition 和 racer 提供的 rust-def 功能是一样的,快捷键冲突,因此只要设置一个就好
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)
这里的:
type-definition 指 一个 变量 / 参数 / 字段 的类型定义;
implementation 指 structs / enums / traits 的 impl block;
references 指 变量使用的地方。
rust-analyzer 不支持 declaration。Rust 貌似没有 delcaration 的概念(笔者暂时不清楚这个问题)。
一般来说 declaration 和 definition 是同时进行,几乎没有区别。 C 语言中可以先 declaration 再 definition,参考 difference between definition and declaration。
拓展:
♥ hover 悬浮文档
.config/nvim/coc-settings.json
配置的相关设置:
{
// rust-doc hover 悬浮文档的相关配置
"rust-analyzer.hoverActions.linksInHover": true,
"hover.floatMaxHeight": 20 ,
"hover.floatMaxWidth": 80,
}
- 设置唤起 hover 的快捷键:
" 设置 hover 悬浮文档
nnoremap <silent> <leader>h :call CocActionAsync('doHover')<CR>
- 使用
<C-f>
和<C-b>
进行翻页,快捷键映射见 coc.nvim 使用 部分 - 使用
<C-w-w>
让光标在 hover 和 编辑窗口跳转,无需映射
neovim 的 floating/popup window 高度设置有 bug:
如果手动设置的 winheight 会导致弹出框高度变成 winheight ,从而覆盖掉 coc-settings.json 的配置。所以暂时不能设置 winheight 。
见 issue:https://github.com/neoclide/coc.nvim/issues/3058、https://github.com/neovim/neovim/pull/13303
![hover doc.gif](https://img-blog.csdnimg.cn/img_convert/b7d6ebca38a3afb08c5e008847aa4ac0.gif#height=895&id=XkSBA&name=hover doc.gif&originHeight=895&originWidth=1090&originalType=binary&ratio=1&size=321767&status=done&style=none&width=1090)
♥ 实用的快捷键
" 设置变量重命名:批量改变变量的名称
nmap <leader>rn <Plug>(coc-rename)
" 设置 hover 悬浮文档
nnoremap <silent> <leader>h :call CocActionAsync('doHover')<CR>
" 设置行内类型提示
nnoremap <F4> :CocCommand rust-analyzer.toggleInlayHints<CR>
" 设置编译运行 (来自 rust.vim,加命令行参数则使用 :RustRun!)
nnoremap <M-r> :RustRun<CR>
" 控制 Coc event 启用,比如需要复制内容的时候,暂时关闭代码诊断干扰
nnoremap <leader>ee :CocEnable<CR>
nnoremap <leader>ed :CocDisable<CR>
" 不保存的情况下进行格式化
" nnoremap <leader>rf :call CocAction('format')<CR>
nmap <leader>ft <Plug>(coc-format)
" 重构:把光标下的变量/trait/类型所有相关的代码提取出来,在左窗口统一修改
nmap <leader>rf <Plug>(coc-refactor)
" 一些诊断信息跳转
nmap <leader>dn <Plug>(coc-diagnostic-next)
nmap <leader>dp <Plug>(coc-diagnostic-prev)
nmap <leader>en <Plug>(coc-diagnostic-next-error)
nmap <leader>ep <Plug>(coc-diagnostic-prev-error)
nmap <leader>fx <Plug>(coc-fix-current)
nmap <leader>fj <Plug>(coc-float-jump)
" nmap <leader>di <Plug>(coc-diagnostic-info)
" nmap <leader>fh <Up><Plug>(coc-float-hide)
" selection:选择函数(内部、全部)
xmap if <Plug>(coc-funcobj-i)
omap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap af <Plug>(coc-funcobj-a)
" 从后向前选择
vmap <leader>rs <Plug>(coc-range-select)
nmap <leader>rs <Plug>(coc-range-select)
笔者关于按键映射的完整设置(写得很乱,仅供参考):
" === vim 基本按键设置 ===
" F2 触发 paste 模式开关
set pastetoggle=<F2>
" F3 触发搜索高亮开关
nnoremap <F3> :set hlsearch!<CR>
" 触发行号
nnoremap <leader>nb :set number!<CR>
" 清除文件内容 delete all
" nnoremap <leader>da :execute "normal! ggVGDI"<CR>
nnoremap <leader>da ggVGD<F2>I
" 跳转缓冲区
nnoremap <leader>bn :bn<CR>
nnoremap <leader>bp :bp<CR>
nnoremap <leader>bd :bd<CR>
nnoremap <leader>bs :buffers<CR>
" 保存、退出
nnoremap <leader>w :w<CR>
nnoremap <leader>q :q<CR>
nnoremap <leader>wq :wq<CR>
nnoremap <leader>wbd :w \| :bd<CR>
" set term=xterm-256color
" set nu! "显示行数
set autoindent "自动缩进
"let g:terminal_key="<C-0>"
let g:terminal_height=10
let g:rustfmt_autosave = 1
let mapleader ="\\"
" === vim-easy-align 按键设置 ===
" Start interactive EasyAlign in visual mode (e.g. vipga)
xmap ga <Plug>(EasyAlign)
" Start interactive EasyAlign for a motion/text object (e.g. gaip)
nmap ga <Plug>(EasyAlign)
" === racer 设置 ===
" 跳转定义等操作时自动保存缓存
set hidden
" 设置 racer 路径
let g:racer_cmd = "/home/ubuntu/.cargo/bin/racer"
" Racer 的补全方式和 (coc-)rust-analyzer 智能补全不太一样,使用的是 vim 的
" Omni completion 补全方式,需要手动触发,快捷键是 <c-n> <c-o>,并不推荐
" vim-racer 的补全功能
" 补全时展示完整的函数定义,比如参数和返回类型
let g:racer_experimental_completer = 1
" 补全时添加括号
let g:racer_insert_paren = 1
" 跳转定义快捷键,十分有用
augroup Racer
autocmd!
autocmd FileType rust nmap <buffer> gd <Plug>(rust-def)
" autocmd FileType rust nmap <buffer> gs <Plug>(rust-def-split)
autocmd FileType rust nmap <buffer> gx <Plug>(rust-def-vertical)
" autocmd FileType rust nmap <buffer> gt <Plug>(rust-def-tab)
autocmd FileType rust nmap <buffer> <leader>gd <Plug>(rust-doc)
autocmd FileType rust nmap <buffer> <leader>gD <Plug>(rust-doc-tab)
augroup END
" === coc.nvim 按键设置 ===
" https://github.com/neoclide/coc.nvim/blob/ec2835fdddb623f22d48e1a58c6c928154b28098/doc/coc.txt#L1060
" GoTo code navigation.
" Rust-analyzer 貌似暂不支持 declaration 和 implementation 跳转
" 关于 definition 和 doc 跳转的部分已经在 Racer.vim 设置了
" nmap <silent> <leader>g= <Plug>(coc-declaration)
nmap <silent> <leader>gy <Plug>(coc-type-definition)
nmap <silent> <leader>gi <Plug>(coc-implementation)
nmap <silent> <leader>gr <Plug>(coc-references)
" 一些实用的设置
" 设置变量重命名:批量改变变量的名称
nmap <leader>rn <Plug>(coc-rename)
" 设置 hover 悬浮文档
nnoremap <silent> <leader>h :call CocActionAsync('doHover')<CR>
" 设置行内类型提示
nnoremap <F4> :CocCommand rust-analyzer.toggleInlayHints<CR>
" 设置编译运行 (来自 rust.vim,加命令行参数则使用 :RustRun!)
nnoremap <M-r> :RustRun<CR>
" 控制 Coc event 启用,比如需要复制内容的时候,暂时关闭代码诊断干扰
nnoremap <leader>ee :CocEnable<CR>
nnoremap <leader>ed :CocDisable<CR>
" 不保存的情况下进行格式化
" nnoremap <leader>rf :call CocAction('format')<CR>
nmap <leader>ft <Plug>(coc-format)
" 重构:把光标下的变量/trait/类型所有相关的代码提取出来,在左窗口统一修改
nmap <leader>rf <Plug>(coc-refactor)
" 一些诊断信息跳转
" nmap <leader>di <Plug>(coc-diagnostic-info)
nmap <leader>dn <Plug>(coc-diagnostic-next)
nmap <leader>dp <Plug>(coc-diagnostic-prev)
nmap <leader>en <Plug>(coc-diagnostic-next-error)
nmap <leader>ep <Plug>(coc-diagnostic-prev-error)
nmap <leader>fx <Plug>(coc-fix-current)
" nmap <leader>fh <Up><Plug>(coc-float-hide)
nmap <leader>fj <Plug>(coc-float-jump)
" selection:选择函数(内部、全部)
xmap if <Plug>(coc-funcobj-i)
omap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap af <Plug>(coc-funcobj-a)
" 从后向前选择
vmap <leader>rs <Plug>(coc-range-select)
nmap <leader>rs <Plug>(coc-range-select)
" 回退上一步选择
vmap <leader>bs <Plug>(coc-range-select-backward)
" rust analyzer 不支持
" vmap <leader>fs <Plug>(coc-format-selected)
" nmap <leader>fs <Plug>(coc-format-selected)
" xmap ic <Plug>(coc-classobj-i)
" omap ic <Plug>(coc-classobj-i)
" xmap ac <Plug>(coc-classobj-a)
" omap ac <Plug>(coc-classobj-a)
" === coc-rust-analyzer 按键设置===
" 它会列出当前所有可执行的方式
nnoremap <leader>rr :CocCommand rust-analyzer.run<CR>
nnoremap <leader>re :CocCommand rust-analyzer.reload<CR>
" nnoremap <leader>sd :CocCommand rust-analyzer.openDocs<CR>
nnoremap <leader>ct :CocCommand rust-analyzer.openCargoToml<CR>
" === coc-snippets 按键设置===
" Use <C-l> for trigger snippet expand.
imap <C-l> <Plug>(coc-snippets-expand)
" Use <m-x> for convert visual selected code to snippet
vmap <m-x> <Plug>(coc-snippets-select)
" 设置 tab > trigger completion, completion confirm, snippet expand and jump like VSCode.
inoremap <silent><expr> <TAB>
\ pumvisible() ? coc#_select_confirm() :
\ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
\ <SID>check_back_space() ? "\<TAB>" :
\ coc#refresh()
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
let g:coc_snippet_next = '<tab>'
" === nerdcommenter ===
" Create default mappings
let g:NERDCreateDefaultMappings = 1
" Add spaces after comment delimiters by default
let g:NERDSpaceDelims = 1
" Use compact syntax for prettified multi-line comments
let g:NERDCompactSexyComs = 1
" Align line-wise comment delimiters flush left instead of following code indentation
let g:NERDDefaultAlign = 'left'
" Set a language to use its alternate delimiters by default
" let g:NERDAltDelims_java = 1
" Add your own custom formats or override the defaults
" let g:NERDCustomDelimiters = { 'rust': { 'left': '/*', 'right': '*/', 'leftAlt': '///','rightAlt': '' } }
let g:NERDCustomDelimiters = { 'rust': { 'left': '//', 'right': '', 'leftAlt': '///','rightAlt': '' } }
" Allow commenting and inverting empty lines (useful when commenting a region)
let g:NERDCommentEmptyLines = 1
" Enable trimming of trailing whitespace when uncommenting
let g:NERDTrimTrailingWhitespace = 1
" Enable NERDCommenterToggle to check all selected lines is commented or not
let g:NERDToggleCheckAllLines = 1
" ban & override the nested comment
" let NERDDefaultNesting = 0
" nnoremap <silent> <leader>cc :call NERDComment('n', 'toggle')<CR>
" Specifies if trailing whitespace should be deleted when uncommenting
let NERDTrimTrailingWhitespace = 1
" === :W :Q 命令 ===
" https://stackoverflow.com/questions/10590165/is-there-a-way-in-vim-to-make-w-to-do-the-same-thing-as-w
" 注意这只会允许单独的 :W 和 :Q ,而不会 :WQ :Wq :wQ
" command! -bang -range=% -complete=file -nargs=* W <line1>,<line2>write<bang> <args>
" command! -bang Q quit<bang>
command! WQ wq
command! Wq wq
command! W w
command! Q q
" command! E e
一些通用的插件
参考:7款优秀Vim插件帮你打造完美IDE
除此之外有些插件虽然很棒,但我不常用,就不再详细介绍了:vim-easy-align、tabular、vim-css-color
vim-plug 安装方式 + github 加速镜像: Plugin 'https://github.com.cnpmjs.org/作者/插件仓库名.git
nerdcommenter
官网:https://github.com/preservim/nerdcommenter
\cc 注释当前行和选中行
\cn 没有发现和\cc有区别
\c<空格> 如果被选区域有部分被注释,则对被选区域执行取消注释操作,其它情况执行反转注释操作
\cm 对被选区域用一对注释符进行注释,前面的注释对每一行都会添加注释
\ci 执行反转注释操作,选中区域注释部分取消注释,非注释部分添加注释
\cs 添加性感的注释,代码开头介绍部分通常使用该注释
\cy 添加注释,并复制被添加注释的部分
\c$ 注释当前光标到改行结尾的内容
\cA 跳转到该行结尾添加注释,并进入编辑模式
\ca 转换注释的方式,比如: /**/和//
\cl \cb 左对齐和左右对其,左右对其主要针对/**/
\cu 取消注释
_注意 _\_
是 _<leader>_
键,使用命令 __:echo mapleader_
来查看具体是哪个键。若显示 _Undefined variable: mapleader_
则说明没有设置,使用命令 _:let mapleader="\\"_
或者在 _.vimrc_
中添加 _let mapleader ="\\"_
,把 _\_
设置成 _<leader>_
键。
autopair
官网:https://github.com/jiangmiao/auto-pairs
针对括号、引号等使用时的补全增强插件,让这些符号环境使用人性化。与 vim-surround 一起使用体验更佳 ~
{'(':')', '[':']', '{':'}',"'":"'",'"':'"', "`":"`", '```':'```', '"""':'"""', "'''":"'''"}
**【更新】**原版本在 2019 年停止开发了。但是有些细节不是很好,比如删除半个括号之后智能匹配不上,经常让光标跳转到下一个括号、过于严格的括号补全。
其 fork 版本:https://github.com/LunarWatcher/auto-pairs 更对我喜好,适度补全。
vim-surround
官网:https://github.com/tpope/vim-surround
增删改 括号、引号、XML 标签 的利器。i
是为了编辑这些环境内的文字,而 s
就是为了编辑双侧环境。
以字符 "Hello world!"
为例,并且都在普通模式下(按 Esc
)
- 增:
- 对光标所在的单词(以空格或者标点符号隔开的内容)增加环境:光标移动在单词的一个字符上,按
ysiw
+目标环境
(ysiw
的记法:you surround in word),如 光标移到H
上,按ysiw)
得到"(Hello) world!"
- 对一整行增加环境:光标移动在某一行,按
yss
+目标环境
,如yss}
、yss<div>
- 对光标所在的单词(以空格或者标点符号隔开的内容)增加环境:光标移动在单词的一个字符上,按
- 删:
- 光标移动在
"Hello world!"
任何一个字符上,输入ds"
就可把"
删除 ,从而得到Hello world!
- 删除的方式从内到外,比如
({ Hello } world!)
删除{}
和()
,只需把光标移到{ Hello }
某个字符上,使用ds{ds(
(或者ds}ds)
之类的)得到Hello world!
- 光标移动在
- 改:修改单词或一行两边的环境:光标移动在
"Hello world!"
任何一个字符上,按cs
+当前环境
+目标环境
即可。例如:- 输入
cs"'
就可把"
改成'
,从而得到'Hello world!'
- 输入
cs"]
就可把"
改成]
,从而得到[Hello world!]
- 输入
cs"[
就可把"
改成[
,从而得到[ Hello world! ]
- 针对 xml tag,输入
cs"<p>
则得到<p>Hello world!</p>
- 输入
注意: _{}_
_[]_
_()_
三种括号在增、改的时候,左右环境是不一样的,左环境会在单词左右两侧增加一个空格再放入环境中,右环境直接把单词放进环境里;但是在删的时候使用左环境或者右环境都可以把环境删除。
相关讨论:What does the “y” stand for in “ysiw”?
git in vim
todo
- 封装 git:https://github.com/tpope/vim-fugitive
- git diff 工具:https://github.com/airblade/vim-gitgutter
- 仿照 emacs 的 magit:https://github.com/TimUntersberger/neogit
- 基于 GitHub 的工作流插件:https://github.com/pwntester/octo.nvim
coc.nvim 作者在 vim 中使用 git 的一些经验:https://zhuanlan.zhihu.com/p/26137257
Rust for Vim
gnvim
未尝试
GUI for neovim, without any web bloat.
为 neovim 打造的 GUI,且无 web 膨胀。
基于 gtk 、使用 Rust 开发的 neovim GUI,因为不基于 electron,所以没有体积膨胀问题。
https://github.com/vhakulinen/gnvim
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZWWP30Vn-1625067464781)(https://github.com/vhakulinen/gnvim/wiki/completionmenu2.png#from=paste&height=374&id=oZOhe&originHeight=748&originWidth=1280&originalType=url&ratio=1&status=done&style=none&width=640)]
minimap.vim
国人开发的代码迷你图:https://github.com/wfxr/minimap.vim、https://github.com/wfxr/code-minimap
需要安装 code-minimap 工具(由 rust 编写的命令行小工具,有二进制版本,解压之后只需要把可执行文件放入系统环境里面),再安装 minimap.vim 插件。
目前至少要 vim8.2 才能顺利安装,默认仓库的版本为 8.1,需要添加私人仓库来更新到最新的 8.2,参考文章 《在 Ubuntu 上安装Vim 8.2》。
进入 vim 使用 :Minimap
开启迷你图;使用 :MinimapClose
关闭迷你图。以及一些写入 vimrc 的参数设置。
顺便介绍一个用 rust 写的跨平台终端命令的 benchmark tool:hyperfine(作者在 repo 上还加入了 py 可视化分析的脚本代码)
colorscheme 配置
highlight
命令 :hi
( :highlight
的简写)可以展示当前所有配色,ctermfg 表示 cterm 下的前景色(字体颜色),ctermbg 表示背景色。参考:vim 语法高亮
命令 :hi 项目
可以查询某个项目的配色。
命令 :hi 项目 ctermfg=Black ctermbg=White
之类的可用于临时预览,确定之后修改配置:重新打开所编辑的文件;或者直接在编辑文件的窗口 :source 修改的配置文件
让配置生效。
笔者关于 highlight 设置如下:
set termguicolors
" 弹出菜单
hi Pmenu ctermbg=LightRed
hi PmenuSbar ctermbg=LightRed
hi PmenuSel ctermbg=LightCyan
hi PmenuThumb ctermbg=LightCyan
" 字调整
hi Keyword ctermfg=Red
hi Function ctermfg=DarkBlue
hi Type ctermfg=Yellow ctermbg=Black cterm=none
hi CocHintSign ctermfg=Brown cterm=underline
hi Comment ctermfg=DarkGray cterm=italic
hi Identifier cterm=bold ctermfg=Blue
" hi Macro ctermfg=Yellow ctermbg=Black cterm=bold
hi Macro ctermfg=Red cterm=bold
" Delimiter
hi Special ctermfg=Magenta
hi String ctermfg=Gray
hi Operator ctermfg=Red cterm=bold
hi LineNr ctermfg=White
" === GUI ===
" 弹出菜单
hi Pmenu guibg=#0A54A0
" hi PmenuSbar guibg=#0A54A0
hi! link PmenuSbar Pmenu
hi PmenuSel guibg=#F69300
" hi PmenuThumb guibg=#F69300
hi! link PmenuThumb PmenuSel
" 字调整
hi Keyword guifg=#FFA89A
hi Function guifg=#58D0F2 guibg=Black
hi Type guifg=#54F685 gui=bold
hi CocHintSign guifg=#f06292 gui=underline
hi Comment guifg=#80cbc4 guibg=none gui=italic
hi Identifier gui=none guifg=#FFFF4D gui=bold
" hi Identifier gui=none guifg=#F6C000
" hi Macro guifg=Yellow guibg=Black gui=bold
hi Macro guifg=#FD3F3F gui=bold
" Delimiter
hi Special guifg=#FFA89A
hi String guifg=#9e9e9e
hi Operator guifg=#f44336 gui=bold
hi LineNr guifg=Grey70
hi Normal guifg=#F3FCFE guibg=Black
hi! link SpecialComment Comment
" hi rustFuncName guifg=Red
hi Folded guibg=#292A00 guifg=#FFFF00
![](https://img-blog.csdnimg.cn/img_convert/e96ef28d35f3b5d39943fb83f38e9be5.png#clientId=u909ee013-9784-4&from=paste&height=476&id=u06ef5860&margin=[object Object]&originHeight=951&originWidth=1022&originalType=binary&ratio=1&size=86217&status=done&style=none&taskId=uc301d3c3-f416-45a1-974c-849c773b678&width=511)
也可修改别人的主题,参考:
statusline
- vim-fugitive 让 vim 集成 git,从而可以让 statusline 显示当前文件所处的 git 分支
- vim-gitgutter 统计 diff 增、改、删 次数
- coc.nvim 、 rust-analyzer 、coc-rust-analyzer 提供四种诊断信息个数统计
- buffer 窗口统计可能不太准确
- BTW:vim-airline 很美观,但是让我的 vim 变得有些笨重 —— 高 CPU、光标移动延迟略高、statusline 过于刷新(每次使用切换模式它都要换一次颜色)
" === statusline (native) ===
" https://stackoverflow.com/questions/5375240/a-more-useful-statusline-in-vim
set statusline=
set statusline+=%1*\[%n/%{NrBufs('loaded')}] " buffernr/loadednr
set statusline+=%2*\ %<%f\ " file+path
set statusline+=%3*\ %{fugitive#head()!=''?''.fugitive#head().'':'\ '}\ " fugitive for branch
set statusline+=%3*%{GitStatus()}\ " gitgutter for diff
set statusline+=%4*\ %{StatusDiagnostic()} " thanks to coc-status
set statusline+=%5*%=\ %Y\ " fileType
set statusline+=%6*\ r:%l/%L\ %3p%%\ " rownumber/total (%)
set statusline+=%7*\ c:%2c\ " colnr
set statusline+=%8*\ %m%r%w\ " Modified? Readonly? Top/bot
hi User1 guifg=#ffffff guibg=none
hi User2 guifg=#ffffff guibg=#2A9A72
hi User3 guifg=#000000 guibg=#F4905C
hi User4 guifg=#ffdad8 guibg=#880c0e
hi User5 guifg=#0A54A0 guibg=none gui=bold
hi User6 guifg=#ffffff guibg=none
hi User7 guifg=#ffffff guibg=none
hi User8 guifg=#ffffff guibg=none gui=reverse
function! NrBufs(buf_type)
" listed / loaded / modified
let key = 'buf' . $buf_type
return len(getbufinfo({key:1}))
endfunction
function! StatusDiagnostic() abort
let info = get(b:, 'coc_diagnostic_info', {})
if empty(info) | return '' | endif
let msgs = []
if get(info, 'error', 0)
call add(msgs, 'E' . info['error'])
endif
if get(info, 'warning', 0)
call add(msgs, 'W' . info['warning'])
endif
if get(info, 'hint', 0)
call add(msgs, 'H' . info['hint'])
endif
if get(info, 'information', 0)
call add(msgs, 'I' . info['information'])
endif
return join(msgs, ' ') . ' ' . get(g:, 'coc_status', '')
endfunction
function! GitStatus()
let [a,m,r] = GitGutterGetHunkSummary()
return printf('+%d ~%d -%d', a, m, r)
endfunction
常用命令
关于注释
Rust 的注释多种多样,分享几个处理注释太多问题的技巧:
- 如果想快速去除掉代码中的注释,删除所有以
//
开头注释的行(其他类型的注释只需修改正则表达式即可,\v
可以让特殊符号不进行转义):
:g/\v^\s{0,}\/\/ .*\n/d
- 折叠以
//
开头注释,包括文档注释:使用 vim 的代码折叠功能
autocmd FileType rust set foldmethod=expr foldexpr=getline(v:lnum)=~'^\\s*//'
结合跳转定义功能,看源码的时候不再让大段注释占据视野:
更完美的解决办法见 关于折叠 ↓
关于折叠
有了前面两个 Rust 语法支持插件,我们可以使用 syntax 的 foldmethod,所以直接设置 autocmd Filetype rust set foldmethod=syntax
即可。
一级折叠(按 zM
折叠到一级):
二级折叠(在一级折叠基础上按 zr
展开到二级):
但是语法折叠无法对注释折叠,加上 vim 不支持多个 foldmethod 同时生效,所以采用快捷键映射:
" === 代码折叠 ===
" autocmd Filetype rust set foldmethod=syntax
" 由于无法同时存在多个 foldmethod,所以可以通过快捷键来设置不同方式的折叠
nnoremap <leader>fs :set foldmethod=syntax<cr>
autocmd FileType rust set foldmethod=expr foldexpr=getline(v:lnum)=~'^\\s*//'
nnoremap <leader>fe :set foldmethod=expr foldexpr=getline(v:lnum)=~'^\\s*//'<cr>
" 更改原先行数在前的折叠样式
" 第一行源代码 ........... 折叠行数 [折叠行数占总行数百分比] +--
" http://gregsexton.org/2011/03/27/improving-the-text-displayed-in-a-vim-fold.html
function! CustomFoldText() abort
"get first non-blank line
let fs = v:foldstart
while getline(fs) =~ '^\s*$' | let fs = nextnonblank(fs + 1)
endwhile
if fs > v:foldend
let line = getline(v:foldstart)
else
let line = substitute(getline(fs), '\t', repeat(' ', &tabstop), 'g')
endif
let w = winwidth(0) - &foldcolumn - (&number ? 8 : 0)
let foldSize = 1 + v:foldend - v:foldstart
let foldSizeStr = " " . foldSize . " lines "
let foldLevelStr = repeat("+-", v:foldlevel)
let lineCount = line("$")
let foldPercentage = printf("[%2.0f%%] ", (foldSize*1.0)/lineCount*100)
let expansionString = repeat(".", w - strwidth(foldSizeStr.line.foldLevelStr.foldPercentage)-1)
return line . " " . expansionString . foldSizeStr . foldPercentage . foldLevelStr
endfunction
set foldtext=CustomFoldText()
hi Folded guibg=#292A00 guifg=#FFFF00
- 默认进入
.rs
文件时,对//
开头的注释进行折叠,而且使用//
进行多行注释保存时,会自动折叠成一行(前提在foldmethod=expr
下) - 修改了 vim 默认的折叠文字样式 (foldtext),看起来更舒服:首行折叠文字位置不变、添加折叠的百分比并进行了同级对齐、
+-
的个数代表所处的折叠级数 - 修改了折叠的颜色样式
- 使用
<leader>fe
启用foldmethod=expr
方式,只对注释折叠 - 使用
<leader>fs
启用foldmethod=syntax
方式,只对语法折叠 - 此外,折叠还能带来批量操作,比如光标移动到折叠成一行的代码上,
dd
命令删除折叠的代码;还可以当作锚点来跳转(使用zj
和zk
)
最终效果:
关于 vim 代码折叠的介绍(foldmethod、快捷键):
- https://yianwillis.github.io/vimcdoc/doc/fold.html
- https://blog.csdn.net/qq_27968607/article/details/60956584
coc.nvim
安装
coc.nvim 是基于 node 的异步插件管理器,coc 系的插件都是用命令 :CocInstall
安装的。终端安装 node:
curl -sL install-node.now.sh/lts | bash
安装 vim 的插件都会用到 vim 通用的 plug 管理器,一般是在配置文件里面加入 Plug(in) 'github | 网址 | 本地 等来源'
内容来安装。coc.nvim 用 vim 插件的方式安装~~(套娃)~~。
推荐使用异步的 vim-plug:👉 vim-plug 安装指路。如果使用 vundle 管理器,把 Plug
替换成 Plugin
。
以下是 vim-plug 安装 coc.nvim 插件方式:
Plug 'neoclide/coc.nvim', {'branch': 'release'}
或者使用加速的下载镜像:
Plug 'https://hub.fastgit.org/neoclide/coc.nvim'
怎么解决从github下载资源慢的问题? - ailx10的回答 - 知乎
https://www.zhihu.com/question/276143842/answer/732220179
使用
- 支持的命令:
:CocAction
:CocCommand
:CocConfig
:CocDiagnostics
:CocDisable
:CocEnable
:CocFix
:CocInfo
:CocInstall
:CocRestart
:CocUpdate
- 使用
:CocConfig
命令;或者编辑~/.config/nvim/coc-settings.json
文件即可。结合 coc-rust-analyer 和 coc-snippet,笔者的配置如下:
{
"coc.preferences.previewMaxHeight": 20,
"dialog.maxHeight": 10 ,
"hover.floatMaxHeight": 10 ,
"hover.floatMaxWidth": 80,
"list.maxPreviewHeight": 20 ,
"notification.maxHeight": 20 ,
"rust-analyzer.diagnostics.enable": false,
"rust-analyzer.diagnostics.enableExperimental": false,
"rust-analyzer.hoverActions.linksInHover": true,
"rust-analyzer.inlayHints.chainingHints": true,
"rust-analyzer.inlayHints.chainingHintsSeparator": "// ", // "‣"
"rust-analyzer.inlayHints.typeHints": true,
"rust-analyzer.inlayHints.typeHintsSeparator": "// ", // "‣"
"rust-analyzer.procMacro.enable": true,
"rust-analyzer.server.path": "/home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rust-analyzer",
"rust-analyzer.updates.prompt": false,
"signature.maxWindowWidth": 20 ,
"snippets.shortcut": "Coc",
"suggest.enablePreselect":true,
"diagnostic.errorSign":"E",
"diagnostic.hintSign":"H",
"diagnostic.infoSign":"I",
"diagnostic.warningSign":"W",
}
- 项目内所有文件中搜索文字:
:CocSearch 被搜索的内容
。借助[ripgrep](https://github.com/BurntSushi/ripgrep)
。参考 coc 文档。 - 自定义 config 参数查询
:h coc-config-suggest
- 弹出框 (popup menu) 或 浮动窗口 (floating window) 设置
<C-f>
和<C-b>
控制上下滚动 (scroll) 翻页:
" 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
![popup menu scroll.gif](https://img-blog.csdnimg.cn/img_convert/225c3093249c21e581d9c7406cbf1b40.gif#height=573&id=FMDza&name=popup menu scroll.gif&originHeight=573&originWidth=916&originalType=binary&ratio=1&size=285619&status=done&style=none&width=916)