最近翻看了一下 《Vim使用技巧》 这本书,然后就发现我对 Vim 快捷键的了解很不深入。不过即使如此,我日常使用 Vim 写代码的效率也高于使用其他编辑器了,足见 Vim 模式之奇。

实用的命令

普通模式

  • 通过g加移动命令可以在屏幕行而不是实际行中移动。
  • <C-a><C-x>可以对数字进行加减,如果数字开头是0则会被认为是八进制。

该命令和大部分命令一样可以用数字在前修饰表示重复,比如加100100<C-a>

  • dawdiw效果类似,但是daw使用更多(caw等同理),因为可以去除多余的空格。但在使用的时候还是看情况是否包括两边。
  • 行内查找既可以用t也可以用f,目的只是查找时明显使用f更加符合直觉,但是在删除到指定位置的使用场景时,dt保留查找字符的特点可以让我们输入一些在文本中多用于分割的字符用于定位,而不是费劲去看分号前面时什么字母。
  • %可以跳转到成对匹配的符号。

插入模式

  • 有趣但是没啥大用的技巧,<C-v>后接数字可以通过编码输入字符,如果数字以u打头,就是十六进制,<C-k>后接两个字符可以得到二合字母表示的字符。这个技巧在命令行模式中也存在。
  • 可以使用<C-h> <C-w> <C-u>在插入模式中像终端一样删除,该技巧在命令行模式也成立。
  • 使用<C-r>加寄存器名实现在插入模式下快速粘贴。

特殊的插入-普通模式(<C-o>):即执行一次普通模式命令然后马上进入插入模式。

可视模式

  • 在按v进入可视模式之后,通过ai加上' " )等成对匹配的符号,可以直接选中那对符号之间的部分(如果是a则包括那对符号)。
  • 在普通模式下按下gv可以选中上次高亮的部分。
  • 在可视模式下按下o可以将光标切换到另外一段(比较常见的技巧,只是我之前不知道)。
  • 在块可视模式中可以对多行进行插入操作,这样可以不依赖插件实现快速注释和快速取消注释。

命令行模式

  • 命令行命令的格式一般为[range]+[command]+[args]([address]),作用范围和参数可选。
  • !后的命令由外部shell执行,可以结合读入到缓冲区(read r),从缓冲区写入(write w)达到一些很好的效果,如得到当前工作目录中的所有文件r !ls ./
  • !前有一个范围时,情况就会有所不同,shell执行的外部命令的输出会被写回到缓冲区。可以利用这个特性实现对文本的排序%!sort -n
  • %表示当前编辑的文件路径,%:h可以去掉当前文件路径的文件名,非常适合编辑同时编辑多个相对工作目录层级很深的文件时使用。当然,这个也是可以映射的(这里更像宏展开,我也不是很懂vimscript):
cnoremap <expr> %% getcmdtype() == ':' ? expand('%:h').'/' : '%%'
  • 在表示范围时,%表示整个文件。
  • :加行号实现跳转,这个方法其实实用性不高,不如在普通模式下使用行号加’G’。
  • 一些特殊标记:'m '< '>分别表示位置标记为m的行,高亮选区的起始行和结束行。
  • 在命令行中用复制(copy t)、移动(move m)很多时候会更快。
  • normal命令可以实现在指定范围执行普通模式命令,在每次执行完之后自动退出插入模式。
  • Vim 的命令行与shell不同,上下翻历史用的不是<M-p> <M-n>而是<C-p> <C-n>(老版本没有该特性需要自己绑定cnoremap <C-p> <Up> cnoremap <C-n> <Down>
  • 配置了路径之后可以使用 Vim 内建的find命令,如:
:set path+={dirname/**}
:find {filename}

其他技巧

  • 清屏

    • Vim 中也可以利用<C-l>进行清屏,这个技巧在通过查找跳转时相当有用,因为高亮有时十分烦人。也有一劳永逸的方法,就是set nohlsearch直接关闭查找高亮。
  • 启动时

    • 在配置文件中加入如下代码可以在打开文件时光标处于上次的更新位置:
    autocmd BufReadPost * if line("'\"'") > 1 && line("'\'") <= line("$") | exe "normal! g'\"" | endif
    
  • 代码保存

    • 如果使用的是 Vim ,想要以超级用户权限保存文件,可以在使用命令w !sudo tee % > /dev/null,即将缓冲区通过tee命令输入到当前文件中,并将标准输出抛弃。可以绑定为:cmap w!! w !sudo tee % > /dev/null。如果使用的是 NeoVim ,则很遗憾不能使用这个小技巧,可以使用插件 Suda.vim
    • 如果想要保存到一个不存在的目录,可以利用外部命令加上%:h的特性,如:
    :!mkdir -p %:h
    :w
    
  • 缓冲区

    • 多缓冲区编辑时用:bprevious :bnext命令切换文件比较麻烦可以绑定为:
    nnoremap <silent> [b :bprevious<CR>
    nnoremap <silent> ]b :bnext<CR>
    nnoremap <silent> [B :bfirst<CR>
    nnoremap <silent> ]B :blast<CR>
    
    • 在缓冲区进入轮换,即:ls时文件名前有井号时,才可以使用<C-^>快速切换。
    • :argdo:bufdo命令可以对多缓冲区进行操作。
  • 标签页和窗口

    • 相比与使用多缓冲区,使用标签页和窗口更加直观且易于操作,可以达到类似于使用虚拟桌面的效果。
    • :sp[lit] {file}水平分隔窗口,:vs[plit] {file}垂直分割,这两个用的比较多;而对于同一个文件的分屏<C-w>s<C-w>v就可能用得比较少了。
    • 在窗口间切换的命令,前缀全部为<C-w>,加上方向hjkl就是按方向的切换,加上w就是循环切换。
    • :tabe[dit] {filename}在新标签页打开,<C-w>T把当前窗口移到新标签页,tabc[lose]关闭当前标签页及其全部窗口,tabo[nly]只保持当前标签页。
    • 普通模式下{N}gt切换到标号为N的标签页,如果没有N则是切换到上一个,gT是切换到下一个。
  • 设置标记

    • 可以通过m{a-zA-Z}标记光标所在位置,小写是当前缓冲区可见,大写是全局可见。
    • 通过'{mark}跳转到标记的那一行第一个非空白字符, `{mark}跳转到标记的准确位置。

提高编辑效率的思路

  • 注意一些成对的命令的使用选择,如正向还是反向、到目标位置还是到目标位置之前,虽然每次不会节约太多时间,但毕竟积少成多。
  • 多构造能够通过.来重复的编辑,这需要我们注意每次编辑后光标的位置,如果使用宏也是相同的道理。
  • 能够重复就别用次数(为了撤销时能够当作整体):例如d3w2dw
  • 在适当的时候回到普通模式,让每一次的编辑更在逻辑上更连贯(同样是方便撤销和重复)。