Vim Macro 101
引言
在我学习 Vim 的过程中,最具有启发意义的一句话是:
Vim 其实是一门“编程语言”
很早之前我就接触过 Vim,但是当时 Vim 的按键组合对我来说很难记,再加上 Vim 的界面实在太过于复古,于是我就转向了比较现代的文本编辑器。但当我学完 Missing semester 这门课程的时候,我对 Vim 的看法有了改观:它远远不止是一个文本编辑器,各种 Vim 的命令的排列组合更像是在写代码,背后都是有逻辑的!
这似乎和这篇博客要讨论的主题没有关系。但其实不是这样的,认识到 Vim 是一门编程语言是一件重要的事情。程序员经常通过编程来避免重复操作,不同人对编程语言的偏好各不相同。如果把 Vim 看成一门编程语言,那么它应该也可以做到类似的事情,今天要研究的就是——如何使用 Vim 来避免重复操作。
下面假定你对 Vim 有一定的了解 : )
什么是 Vim 里面的宏
在 Vim 里面,我们可以用 .
重复上一次的“更改”。但如果我们想要重复一系列地更改呢?答案是:用 Vim 的宏就可以。通过使用宏,我们可以录制一系列的操作,并把他们存放在指定的寄存器里面,后续就可以重复执行。如果你检查寄存器里面的内容的话,你会发现:宏不过就是一连串的字符序列。
基本指南
怎么录制一个宏
步骤:
- 在 normal 模式下,按
q<register>
.- 这里的意思是:先按
q
然后选择一个寄存器register
来存放待会录制的宏 - 可以选用的寄存器
regitser
包括:0-9
,a-z
和"
- 这里的意思是:先按
- 开始录制宏,如果上一步没有问题的话,此时你应该会看到左下角显示
recording @<register>
。从此刻起,你所有的操作都会被记录下来 - 再次按下
q
退出录制
怎么查看宏的内容
前面提到,Vim 会把我们录制的宏存放在指定的寄存器里面。查看宏的内容很简单,用一个简单的 :reg
命令就行:
:reg <register>
里面你会看到一些奇怪的字符,比如:
^[
是<ESC>
键<80>kb
是BAKESPACE
键
怎么执行宏
在一个文件里面执行宏
@<register>
: 执行存放在<register>
这个寄存器里面的宏@@
:执行我们上一次调用的宏- 如果想要多次执行的话,在命令的前面先输入
[COUNT]
表示要执行多少次。- e.g.
100@@
的意思是:执行上一次调用的宏 100 次
- e.g.
自己计算 [COUNT]
的值应该是多大太枯燥了,好在当我们设置一个很大的值的时候,超过的部分会被 Vim 忽略 :)
在多个文件里面执行同一个宏
当然,如果只能在一个文件里面重复执行宏的话,能解决的问题还比较局限。一个很经典的场景是我们想要对一堆文件执行一样的操作,我们总不可能一个个地处理文件。这绝对违反了 DRY(Don’t Repeat Yourself)原则
Vim 允许我们同时打开多个文件然后一个个编辑。不仅如此,它还支持我们在所有打开的文件上执行指定的宏。
比如,我们想要编辑当前目录下的所有 txt
文件,只要在命令行输入 vim *.txt
就可以打开所有文件(每个文件对应一个 buffer,整体可以看成是一个 buffer 列表)。在这个模式下我们可以一个个文件地编辑,编辑完毕之后按 :wn
保存当前文件的更改并跳转到下一个文件。但我们也能一次性对这个文件列表里的所有文件进行更改:
- 先用第一个文件录制宏,录制完成之后,在 normal 模式下输入
:edit!
撤销对第一个文件的更改(不然后续批处理文件的时候第一个文件会被修改两次) - 在 normal 模式下,输入命令
:bufdo execute "normal @<register>" | update
.- 关于
bufdo
的说明可以在 Vim 里面输入:h bufdo
查看。可以理解为对所有的 buffer 执行指定的操作 - 这里的
normal @<register>
的意思就是在 normal 模式下执行@<register>
里面的宏
- 关于
更多的细节可以看 这里
怎么修改已经录制好的宏
简单情况
设想你在录制一个很长的宏,突然录到一半不小心按下了 q
键结束了录制。重新录制肯定很繁琐,Vim 允许我们直接在某个录制好了的宏后面继续追加操作。办法就是用 q<REGISTER>
,这里的 <REGISTER>
表示 A-Z
中的一个字母。比如之前录制到一半的宏在 a
,那么追加的时候就要用 A
复杂情况
如果要编辑的位置是在宏的中间呢?从头开始录制宏肯定不是一个好的选择。前面提到过,宏的本质上只是存储在寄存器里面的字符序列。我们只需要修改寄存器里的内容就行,具体操作如下:
- 在 normal 模式下,按下
G
跳转到当前文件的最后一行(其实别的行也可以,只是跳转到最后一行我们编辑宏的时候比较不会受到干扰),然后输入:put <register>
命令,对应寄存器里面的内容就会被粘贴在下一行 - 接下来直接修改这个内容就行
- 编辑完成之后(确保光标还在这一行),按下
:d <register>
就可以把当前行的内容存回原来的寄存器
下面是一个简单的例子,我录制了一个宏放在寄存器 y
里面,功能是:在当前行的末尾追加 world
,现在我想要修改这个宏,改成追加 hello world
总结
这只是对 Vim 的宏的一个简单介绍,它只是 Vim 强大功能的冰山一角,当你掌握更多 Vim 的其他操作的时候(比如搜索与替换,快速定位到某个位置),把他们结合起来 Vim 将会变得很强大。如果这篇博客可以让你对 Vim 产生兴趣那就再好不过。希望本篇博客对你有所帮助😉