Vim 使用总结

2023-09-17
7 min read

因为工作比较忙,很久没有更新博客了,今天水一篇

2023 年 8 月 3 日,Vim 创始人 Bram Moolenaar 离世,时隔年余,他和好友相聚于天堂,愿天堂有他们喜欢的项目

命令速查

  1. VIM 常用快捷键汇总:https://vim.rtorr.com/
  2. code block 跳转快捷键:https://vim.fandom.com/wiki/Jumping_to_the_start_and_end_of_a_code_block
  3. vim -U NONE -N gargantuan.txt,打开大文件
  4. vertical resize 70,设置列宽度;only,仅保留当前窗口;Ve 显示目录;}} {{ 连续文本块跳转
  5. 显示当前 buffer 文件的路径:1 Ctrl-G

对编辑器的诉求

随着使用 Vim 的时间愈久,还在使用的 Vim 插件慢慢就只剩下几个小巧简单的。对我而言,编码所使用的编辑器需要满足如下几个功能,插件的选择,也会围绕这几个功能展开。使用下面 Vim 插件的配置有个前提,就是你主要依赖大脑记忆项目结构,插件只是辅助工具

  1. 脱离鼠标编辑,这是 Vimer 的必备技能
  2. 打开文件要快。终端的 Vim 不需要 GUI,所以响应速度够快,对于大一些的文件可以在不载入 .vimrc 配置的时候加速打开过程(vim -u NONE -N /path/to/file)。更大的文件,可以尝试命令 less 或者 more 进行查看
  3. 支持正则表达式的关键字和文件路径搜索:Universal CtagsGNU GlobalPygments
  4. 简单的包管理:plug.vim
  5. 简单的界面:nerdtreeairlinevim-colors-solarizedvim-markdown
  6. 快速的跳转:vim-easymotiona.vimvim-markbar
  7. 简洁的代码格式化工具:neoformat。系统工具依赖:clang-format(c/c++/python 等)、cmakelang(CMake file)、verible(HDL, e.g. verilog, VHDL)

功能实现

搜索

Universal ctags

Universal Ctags (abbreviated as u-ctags) is a maintained implementation of ctags. ctags generates an index (or tag) file of language objects found in source files for programming languages.

可以使用源码安装,或者 apt、brew 等系统工具进行安装(snap install universal-ctags),tags 工具这里不做介绍。为了区别旧的 ctags 工具,安装完 universal ctags 后,我会将其命令修改为 utags

Global&Pygments

GNU Global 为源文件构建索引,所以可以实现快速的函数、单词和文件查找,且 Global 默认支持正则表达式。Global 的安装和使用细节可以参考官网,这里只介绍我常用的功能

安装完 Global 后,系统会多出两个命令,gtags 和 global。gtags 命令用于给项目源文件创建索引,为减少索引文件对项目的影响,可以将索引文件置于系统目录,或者将索引文件写到 .gitignore 中;另一个命令是 global,global 接受正则字符串,并搜索 gtags 创建的索引文件。使用 gtags 为指定项目创建索引的方式可以参考下面:

# Linux, ~/.bashrc
alias tags_update="find . -regextype posix-egrep -iregex '.*\.(H|HH|HPP|HXX|H\+\+|INC|DEF|C|CC|CPP|CXX|PY)$' -type f > global_file_list.bak && gtags -f global_file_list.bak -i && utags -R --languages=C,C++,Python"

# Macos, ~/.zshrc
alias tags_update="find -E . -iregex '.*\.(H|HH|HPP|HXX|H\+\+|INC|DEF|C|CC|CPP|CXX|PY|V)$' -type f > global_file_list.bak && gtags -f global_file_list.bak -i && utags -R --languages=C,C++,Python,Verilog"

新增需要解析的文件后缀,可以修改上面小括号中的内容

gtags 命令支持配置文件,将 global 源码目录下的 gtags.conf 文件拷贝到 ~/.globalrc,修改 ~/.globalrc 文件可以调整 gtags 的功能。例如 gtags 默认解析的语言不包含 tcl 和 python,修改配置文件中的 langmap,可以新增 tcl/python 的解析

builtin-parser:\
:langmap=c\:.c.h.i,yacc\:.y,asm\:.s.S,java\:.java,cpp\:.c++.cc.hh.cpp.cxx.hxx.hpp.C.H,php\:.php.php3.phtml,Tcl\:.tcl.tk.wish.itcl:

gtags 默认使用内置(build-in)的解析器解析源文件,但内置的解析器支持的语言有限,此时可以考虑使用 pygments 实现更多语言的解析

  1. 安装 pygments:pip3 install pygments
  2. 设置环境变量:export GTAGSLABEL=pygments,Linux 可以将环境变量写入 ~/.bashrc,Mac 可以写入 ~/.zshrc
  3. 验证:gtags --explain

拷贝如下文件到 Vim 配置目录,给 Vim 添加 Gtags 搜索命令:

# locate -b gtags.vim # 确认 gtags 配置到位置
# /usr/share/vim/addons/plugin/gtags.vim

cp /usr/share/vim/addons/plugin/gtags.vim ~/.vim/plugin/
cp /usr/share/vim/addons/plugin/gtags-cscope.vim ~/.vim/plugin/

完成上述任务,且确定当前目录下包含 Gloabl 的索引文件(GTAGS、GPATH 等),进入 Vim 命令模式即可进行搜索,例如:Gtags -gi hell.*ord。Gtags 支持的 flag 不多,但已经足够使用,细节请参考官网教程。下面给出一些使用示例:

Gtags -g hello\(\w     # 使用 grep like 正则表达式搜索 tag
Gtags -gi hello\(\w    # 使用正则表达式搜索 tag,-i 表示忽略大小写
Gtags -Pi tim.*ser     # 使用正则表达式搜索源文件名
gtags -r initia.*      # 使用正则表达式搜索函数的引用(reference)
gtags -f DIR2/fileC.c  # 显示指定文件中包含的 tags

为减少开发时字符的输入量,可以在 vimrc 中添加如下自定义命令。Vim 添加下面的配置后,命令模式输入 Gp 就相当于输入了 Gtags -Pi

command -nargs=* Gf Gtags -gi <args>
command -nargs=* Gp Gtags -Pi <args>

Quckfix&Cfilter

当项目比较大的时候,Gtags 输出到 quickfix 窗口的内容会比较多,可以使用 Cfilter 命令过滤。因为 Cfilter 是 Vim 8.0 后新增的自定义命令,所以需要手动开启。在 .vimrc 文件中添加如下配置即可引入 Cfilter 命令

packadd cfilter

Cfilter 使用示例:

Cfilter  /pat/   # 筛选满足搜索模式的条目
Cfilter! /pat/   # 筛选不满足搜索模式的条目
colder           # 前一个 quickfix
cnewer           # 后一个 quickfix
Lfilter          # 应用于 location list (quickfix 的 buffer 局部版本)
# lolder / lnewer 前/后一个 location list

正则搜索

https://regexr.com/ / VIM 搜索默认支持正则表达式 / VIM 搜索默认考虑大小写,搜索字符串最后输入\c可以促使 VIM 不检查大小写

特性 示例
匹配一个字符(2) . \.
匹配一组字符(3) [f-g]a. [^f-g]a.
元字符(4) \d \D \w \W 附表参考
重复次数(5) + / * ? 换行符 [\r]?\n
重复区间(5) \d{3,}\.\d{2} <[Bb]>.*<\/[Bb]> <[Bb]>.*?<\/[Bb]>
位置(边界)匹配(6) \b \B ^ $ 附表参考
子表达式(7) (&nbsp;){2,} `(19 20)\d{2}`
引用子表达式(8) h([1-6]).*?h\1
环视 / 消耗(9) .+(?=:) 条件(10)、常用正则(11) \d{5}(?(?=-)-\d{4})

跳转

Vim Marks

'< \& '>  start/end of visual selection
'[ \& ']  start/end of last change or yank
'.  position of where last change was made
'^  position of cursor when last Vim last left insert mode - This is how gi command works
''  position before last jump (Super useful!). See h ''

Ctrl-O to jump back to the previous (older) location.
Ctrl-I (same as Tab) to jump forward to the next (newer) location

Vim 跳转,我主要使用 Vim 内置的 Marks,结合 Vim 插件 vim-markbar 可以快速查看已经标记的内容。其他 Marks 相关命令示例:

# 命令模式
marks        # 显示所有 marks
delmarks A-Z # 删除全局文件 mark
delmarks a-z # 删除文件内部 mark

Vim Marks 大写字符是跨项目的,即默认情况下,项目 Z 中标记的 A 在项目 Y 中也能看下,如果在项目 Y 中也设置了标记 A,那么项目 Z 中的 A 将被覆盖。为了避免这类问题,我使用的方法比较简单,将不同项目的 viminfo 文件保存在不同的文件中(默认的 viminfo 路径是空 set viminfo=,可以通过命令设置位置 set viminfofile=/path/to/file),每次切换项目的时候重新读入(rviminfo path/to/viminfo),退出项目时手动保存(wviminf path/to/viminfo

jumps

Vim 的跳转列表也是一个非常不错的工具,命令模式输入 ju[mps] 可以查看跳转列表历史,确认前进或者后退的数值后,可以直接跳转到对应的位置,例如:17 CTRL-O13 Tab

vim-easymotion

有些时候我们需要快速跳转到当前文件中的某个位置,使用 Vim 内置的方法可以考虑先跳转到某一行(100 Shift-G)然后跳到对应的行位置。利用 Vim 插件 vim-easymotion,可以快速跳转到指定的位置,使用方法请参考 github

vim-bookmarks

阅读代码时经常需要在不同文件中跳转,大型仓库使用 vim mark,容易忘记标记的意义。可以考虑使用 vim-bookmarks 辅助记忆,vim-bookmarks 插件支持为不同目录中的文件设置书签功能,如此可以通过书签记忆代码结构

Buffer&Jumplist

Buffer 参考这里

:ls        # show all buffer, files / buffers
:b3        # open buffer 3
:bd3       # del buffer 3
:1,32bd    # del buffer from 1 to 32
:3,$bd     # del buffer from 3 to last, using vim range commands

格式化

clang-format&neoformat

我不喜欢编辑器自动格式化文件,所以我使用 Vim 插件 neoformat 并设置了快捷键触发格式化功能

默认格式化工具我使用的是 clang-format,其他 clang-format 还不支持的语言,可以考虑其他工具,例如:cmakelang(cmake)、verible(HDL, e.g. verilog, VHDL 等)。下面示例为 neoformat 添加自定义的 verilog 格式化方法

首先安装 veribble 工具,并确认系统中可以找到 verible-verilog-format 命令。随后在 neoformat 插件目录中(autoload/neoformat/formatters)新增 verilog.vim 文件,并写入如下内容:

function! neoformat#formatters#verilog#enabled() abort
    return ['verible']
endfunction

function! neoformat#formatters#verilog#verible() abort
    return {
        \ 'exe': 'verible-verilog-format',
        \ }
endfunction

界面

  1. 布局:nerdtree、airline
  2. 常见代码高亮插件:vim-colors-solarized
  3. 特殊文件语法高亮
    1. liberty:https://github.com/tarikgraba/vim-liberty.git

.vimrc 示例

VIM 示例可以参考这里:https://boardmix.cn/app/editor/jTD6en79Nmf3ciWxHYr3vA