Skip to content
On this page

告别重复:vim 的宏操作

在开发中,我们有时会面临需要重复大量相同的操作的情况,比如下面的代码:

我们需要把所有变量名为 obj 的对象修改为 Obj 并在前面添加 _,最终变成 _Obj,但是我们不能修改为数组的 obj,而且处于谨慎起见,我们不可以同事多光标去修改;

const obj = new Object()
const obj = new Object()
const obj = new Object()
const obj = []
const obj = new Object()
const obj = []
const obj = new Object()

这时,你可能想起 . 命令,在前面我们提到过,它可以重复执行上一个命令;但是对于当前的场景,有好像无法使用 .,这时就要请出终极大杀器 ———— 宏操作(macro)了。

宏操作

宏(macro)即可以把一系列的操作录制成组并暂存起来,然后通过特定的指令重复去触发执行。

命令

  • q + [字母]:开始录制,并把当前一次的录制命名为 [字母];如 qa,则当前录制的宏操作名称为 a,如 qq,宏操作则为 q;录制完后,再输入 q 则退出录制
  • :reg + [字母]:查看录制好的名为 [字母] 的宏操作
  • @ + [字母]:调用名为 [字母] 的宏操作
  • @@:调用最后一次执行的宏操作
  • [数字] + @ + [字母]:以 [数字] 次数重复执行名称为 [字母] 的宏操作
  • q + [大写字母]:在对应名为 [字母] 的宏操作后追加命令;比如我们录制一个宏操作为 a,他的功能是删除每行的第一个单词;则我们首先录制改宏操作:qa^diw;录制完后发现我们删除了第一个单词后,还需要把光标移到下一行,这时我们可以键入 qAj,即在宏操作 a 后面追加个 j 命令,就可以愉快地继续使用宏操作 a 了

注意

在录制宏操作时,名称无论输入的是大写字母还是小写字母,最终都会暂存为小写字母,而往宏操作追加时,则使用名称字母的大写进行追加。

对于多次执行宏操作的时候,当出现无法执行对应操作时,会报错并停止执行;比如,我们使用宏操作进行批量替换特定文本,内容里有 10 个要替换的文本,而我们使用 [数字] + @ + [字母] 的方式让操作执行 20次;当指令执行完第十次后发现已经没有可替换的文本时,vim 会报错并停下;利用这个特性,我们可以在一些重复操作中无心智负担地进行全量执行,比如大概预估要重复执行的次数,然后直接执行一个绝对大于数目的次数,就可简单安全地达到目的。

修改已暂存的宏

录制一个宏操作后 vim 会把录制的宏操作暂存在寄存器中;而修改一个已知的宏操作,其实是指修改寄存器中的内容;则我们的步骤是:获取宏操作的内容、修改该内容、重新储存回寄存器

  • 获取宏操作的内容:
    • " + [字母] + p:粘贴名称为 [字母] 的宏操作;" + [字母] 可以理解为获取该宏操作,而 p 就是粘贴;这时会把对应的宏命令粘贴在我们当前光标所在的位置中;
    • :put + [字母]:与上面的效果一样,这时也会把对应的宏命令粘贴在我们当前光标所在的位置中(注意 put 后有个空格);
  • 修改该内容
  • 重新储存回寄存器:这一步其实是要把新的操作命令组合替代原来的宏操作的命令组合;同样先要输入 " + [字母] 获取到对应宏操作,此时 vim 会等待你接下来存入寄存器中的内容,把该内容作为原来宏操作 [字母] 的对应命令组合;此时我们可以键入 ywyy 等可以向寄存器存入内容的命令(换言之,dc 等命令也可以),把对应的宏操作 [字母] 的命令组合修改为我们新的内容。

比如还是上面提到的追加操作提到的宏命令,我们添加 j 后,发现在删除了第一个单词后,每行前面还有一个空格,所以在光标跳到下一行之前,还要把空格删掉;这时我们可以键入 :put a,此时会粘贴出 ^diwj,然后我们把文本修改为 ^diwxj,然后在 normal mode 把光标移动到 ^ 后(因为我要用 yg_ 来选中,yiw 无法把字母和符号一起选中),输入 "ayg_,这时就修改完成可以再次愉快地继续使用宏操作 a 了

技巧

使用宏操作的过程中,我们有两点需要注意的:

  • 规范好光标的位置
  • 移录光标移动时使用相对位置

这两点其实都是为了确保光标在正确的位置以使宏操作可以按照它本应该的逻辑执行,避免发生意料之外的情况。