Vim技巧
这是最近看《Vim实用技巧》的记录,以后如果有Vim方面的技巧会继续追加。
- 插入模式下使用方向键相当于使用
Esc + hjkl + i
,会改变.
或u
等按键的行为。 - 经常使用
Esc
能够帮助理清思路和控制回退粒度。 - 针对文本对象的操作威力强劲,试试
daw
、ci"
或者yapp
。定义文本对象时,除了一些显而易见的分隔符之外还有wWspt
,另外bB
分别与)}
等价。 - 操作的效率和可重复性都需要关注。
- 如果光标不在数字上,键入
[n]<C-a>
或[n]<C-x>
会先自动跳转到当前行的下一个数字再执行。 - Vim默认将0开头的数字解释成八进制,此时使用
<C-a>
结果可能出乎预料,可以考虑设置nrformats
参数。 d3w
和dw..
各有千秋。前一种形式键入少,撤销连贯,后一种形式不需要数数,撤销粒度细。- Vim除了几个常用模式之外还有很多小模式,比如在键入
dw
时在两次按键中间短暂存在”操作符待决模式”。 - 单词写错之后,删除整个单词重写能够有效降低再次犯错的概率。另外键入
start
可能比键入art
更快。 - 在插入模式下使用
能够进入"插入-普通模式",允许我们执行一次普通模式命令。 - 把
Caps
映射成Ctrl
键非常有用,够不着Esc
可以使用<C-[>
替代。不过如果一年有300天每天有10个小时手是放在键盘上的,为什么不买个HHKB呢? - 在插入模式下可以使用
<C-r>{register}
插入对应寄存器内的数据,这种插入是相当于从键盘上一个一个键入的,如果开了自动补全功能可能出现奇怪的结果。使用<C-r><C-p>{register}
则按原义插入,建议插入多行时还是先退回到普通模式。如果需要粘贴从其他程序内复制来的文本,可以:set paste
保证粘贴结果(也可以使用"+p
来避免切换paste)。 - 使用
gR
或gr
进入”虚拟替换模式”,该模式会将制表符当做一组空格处理。其实更建议启用expandtab
,只使用空格。 ga
显示当前字符的编码,<C-v>
按编码插入字符。- 为什么要使用
<C-g>
从可视模式切换到选择模式呢? gv
可以重新选定上次选定的文本范围,不过如果上次选定的文本被删了结果可能就有点奇怪。在可视模式下o
可以切换选区的活动端。<C-v>5j$Aa
和:.,.+5 norm Aa
都可以在光标所在行及其后五行的行尾加上字符a
。- 行内跳转使用
f;,
可能比hl
效果好,实际上可以只在光标距离目标只有一两个字符的时候使用hl
。尽量选择目标附近的非常见字符,如使用fxh
而不是fe;;;
。 - 将光标处于一对圆括号的
(
上时,将这对圆括号改成方括号的一种方法是:%r]``r[
。 `.
跳转到最后修改的位置,g;
则可以依次向更早的修改的位置跳转。gi
则使用`^
恢复退出插入模式时的光标位置并切换到插入模式,是个好用的功能。- 配合
path
和suffixesadd
参数,可以很方便的使用gf
打开当前文件中引用的文件,就像超链接一样。:find
可以在path
中搜索指定文件并打开;:edit
可以打开指定文件,使用:e!
放弃所有修改将文件重新加载到缓冲区是一个很常用的功能。 "_
为黑洞寄存器。与其小心翼翼保护无名寄存器,不如将内容保存到指定寄存器。使用y
时,内容不但会覆盖到无名寄存器,同时会保存到复制专用寄存器"0
。"+
寄存器与系统粘贴板等效,可以使用该寄存器完成Vim与粘贴板互通(使用:version
查看xterm_clipboard
确定该功能在编译时是否开启)。使用小写字母引用有名寄存器,会覆盖该寄存器原有内容,使用大写字母则追加。- 在可视模式时,使用
p
可以使用指定寄存器的内容来替换高亮文本,同时将高亮文本覆盖到无名寄存器中。 - 使用
vim -u NONE -N
启动Vim时不加载vimrc
并禁用插件,使用于原生Vim。 H/M/L
可以将光标移动到屏幕的顶部/中部/下部。zt/zb/zz
则将光标所在行滚动到屏幕的顶部/中部/下部。- 粘贴多行文本时,使用
gp
会在粘贴后将光标移动到粘贴内容的结尾。 10;.
和;10.
显然都是不好用的,但是qq;.q
之后再10@q
是好用的。另外,f
只在当前行查询,如果不想数需要执行多少次,可以试试22@q
,因为2
和@
在同一个键上。- 使用
norm
可以在多行并行执行宏,一行上出错不会中止其他行上的执行。具体采用并行还是串行需要根据情况。 - Vim的寄存器不过是一些保存文本的容器。如果需要在宏中追加命令,只需要使用大写字母引用宏进行录制。可以将宏导出到文本里并进行修改(使用
<C-v>
输入Esc
等),然后使用0"ay$
之类的命令导入到宏寄存器,不使用"add
的原因是防止引入拖尾字符^J
,从文本中导入宏要特别注意键盘编码。另外还可以通过Vim脚本修改宏。 - 给全文本加上行号的按键序列为:
gg:let i=1<CR>qaI<C-r>=i<CR>)<Esc>:let i += 1<CR>qjVG:norm @a<CR>
。可见norm
的并行也不是完全意义上的并行。 - Vim的magic搜索模式半途而废,只为部分一般意义上的正则特殊符号赋予特殊含义。方括号本身具有特殊含义、圆括号匹配原义字符需要加
\
才能转义具有特殊含义、花括号的闭括号可以省略转义而圆括号则不行,这些看起来特别混乱。可以使用\v
开启very magic
模式,此时除了_
、字母和数字之外的所有字符都当做具有特殊含义的字符(像#
这样暂时没有特殊含义的当然还是直接匹配),以下三组效果一样:#\([0-9a-fA-F]\{6}\|[0-9a-fA-F]\{3}\)
和\v#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})
和\v#(\x{6}|\x{3})
;或者使用\V
开启原义模式,此时只有\
具有特殊含义。 - 在Vim中,
<
和>
相当于\b
,用来界定单词边界;\_s
相当于\s
,用以表示空白字符;zs
(zone start)和ze
(zone end)相当于环视断言,提供了只匹配查找模式所得到的一部分内容的功能;在圆括号前面的%
相当于?
,使圆括号只分组不捕获。即使在原义模式下,正向查找的/
和反向查找的?
也需要转义,否则会被当做查找域的结束符:如/abc/e<CR>
中的/e
是一种标志位,使得光标移动到每个匹配的结尾。 - 执行替换命令时,可以设定
/n
标志位,只统计匹配的数量而不实际执行替换操作。替换域中的特殊字符除了\t
、\1
等,还有&
(插入匹配模式所有内容)、~
(使用上一次s命令的替换域内容)、\={vim script}
(执行vim表达式,并将结果作为替换域内容,其实@{register}
也是一个Vim命令)。 - 将替换命令的查找域留空时Vim将会重用上次的查找模式,这消除了查找和替换之间的耦合性,方便查找模式的测试,也可以利用
*
等命令减少查找模式的输入,缺点是该命令历史记录缺失,不方便重用(必要的时候在查找域中输入<C-r>/
来填充)。另外,使用q/
进入查找历史列表可以很方便的修改查找模式。 :&
相当于重新执行上一次替换命令,但是不包括标志位,如果想保留标志位,可以使用:&&
。g&
则相当于%s//~/&
,在整个文件范围内重复上一次替换命令,带标志位。grep
原来是从:g/re/p
演化来的。:v
和:g!
是对匹配模式取反。g/{/ .+1,/}/-1 >
可以将每对花括号的内容增加一级缩进(实际上如果存在嵌套这个命令就不够看了)。书中认为这是global
命令的广义形式:g/{start}/ .,{finish} [cmd]
,但是我觉得将.+1,/}/-1 >
理解为一个EX命令会更准确,g
命令本来就是先标记,后执行,多生产一个概念没什么好处。:args
和argdo
配合使用可以很方便的在多个缓冲区执行命令。如果执行改变缓冲区的命令,需要启用hidden
选项。:w !sudo tee % > /dev/null
命令可以让我们使用sudo权限保存文件。- 像这种技巧如果能凑个整,比如100条,就会显得特别高大上,我没这么丧心病狂,先凑个四十条吧:Vim不太适合编辑汉字文档。