Vim 进阶 - 宏和宏的应用

1,057 阅读5分钟

什么是宏

宏让我们可以在 Vim 中重复进行特定的修改。在 Vim 中,我们可以把任意的按键操作录制并存储到某一个寄存器中,用于之后的回放。

要使用宏,首先要录制一个宏,也就是输入一系列命令,同时也将这一系列命令存储在某个寄存器里。这一系列命令就是我们录制的宏,也是我们之后要重复执行的操作。

输入可能会出错,或是有修改,我们可以直接修改某个宏,也可以把这个宏复制到一个文档里进行修改。

宏的执行有串行也有并行,后面我们会详细说明这两种方式的差异。

在这篇教程中,我们通过实现一个简单的目标来学习宏。

假设我们有这样一段代码:

{
  "foo": "bar.1.1",
  "foo": "bar.1.1",
  "foo": "bar.1.1",
  "foo": "bar.1.1",
  "foo": "bar.1.1",
  "foo": "bar.1.1"
}

我们想把这段代码中每一行的第一个 . 替换成 -,该怎么用宏来实现这样的操作呢?

录制宏

录制一个宏主要使用 q 命令,这个命令既代表开始,也代表结束。

开始录制

使用 q{reg} 命令开始录制一个宏,reg 代表我们要存储这个宏的寄存器,例如,qq 就表示我们要开始录制一个宏,并将这个宏保存在寄存器 q 中。

回到前面提到的小目标,如果我们想替换光标当前行的第一个 .,应该进行的操作是 0f.r-0 可以保证我们后边 f. 找到的是同一个 . -> 每一行的第一个),让我们把这个操作存储到寄存器 q 中:

qq0f.r-

结束录制

这时,我们发现第一行的 . 已经被替换成了 -,宏也被录制到了寄存器 q 中。

随后再按一次 q,就结束了这个录制,回到了普通模式。

宏的执行

@{reg} 可以执行指定寄存器当中的宏,也可以用 @@ 来执行最近执行的上一个宏。

之前我们把宏录制到了寄存器 q 中,现在,我们可以用 j 把光标移动到下一行,然后按 @q

我们执行了之前的宏,现在,第二行的第一个 . 也被正确地替换了。

想要替换下面几行的 .,只需要多执行几次 j@@ 就可以啦。

并行执行

Vim 也可以并行地在多个行上同时执行某个宏。

先把刚刚的操作撤销,把 - 恢复回 .

VG 选中从当前行到末尾的所有行,然后输入 :normal @q,我们就会发现,之前录制的宏在所有选中的行上都同时执行了一遍。

是的,:normal @{reg} 就是并行执行宏的命令,它会指示 Vim 在选中区域的每一行上执行指定的宏。

宏的追加和编辑

追加

在前面串行执行宏的过程中,我们发现每一次执行之前,都要用 j 把光标移动到下一行,这也是一步重复操作,当然也可以录制到宏中。

刚才,我们把宏录制到了寄存器 q 中,这次,可以使用大写的 Q,意思是我们要向寄存器 q 中追加内容。追加的操作:

qQjq

回到刚才要修改的文本,执行一次 @q,可以发现,Vim 在执行完替换之后也将光标向下移动了一行,这说明我们没有破坏或者丢失之前录制的宏,而追加的 j 也生效了。

宏的执行也支持指定次数,例如,执行 5@q 便可以将寄存器 q 中的宏重复执行 5 遍。

但是,我们可能不知道到底还有多少行,怎么办呢?

简单来讲,可以随便输入一个很大的数,比如 22@q,(因为 2@ 对应同一个按键),来让宏尽可能多地执行。

Vim 在串行地执行宏的时候,如果遇到了错误,会停止执行。

在上面的例子中,当 Vim 执行到最后一行(只有一个 })时,因为没有 .,无法完成替换,Vim 也就会在这里停止执行,而不是真的执行 22 遍。

编辑

除了追加之外,还想对宏进行一些其他编辑应该怎么做呢?

前面我们把宏录制到了一个寄存器中,这个寄存器和我们进行复制、删除等操作时的寄存器一样。当我们录制一个宏时,Vim 会把我们录制的一系列操作在寄存器中存储为一段文本。

对宏进行编辑,基本的思路就是把这个寄存器中的文本粘贴出来,编辑,然后存回寄存器。

以刚刚录制到寄存器 q 中的宏为例:

  • "qp 把寄存器 q 中的内容 put 出来

  • 编辑复制出来的文本

  • "qyy 把这一行复制到寄存器 q 中

  • 删除这行文本 dd(因为它现在没有用了)

也可以通过在命令行中直接编辑的方法来进行:

  • 输入 :let @a='

  • <ctrl-r>a 把寄存器 q 中的文本(我们刚刚录制的宏)插入进来

  • 编辑复制出来的文本

  • 补齐缺失的 ' 然后按回车

你可能并不需要宏

回到刚才的目标,这个例子只是为了演示宏的使用,但是如果你深入了解过 Vim 的可视模式的话应该能发现,实现这个目标并不需要使用宏,并不需要进行录制、执行等等的操作。

在 Vim 中按 <ctrl-v> 可以进入「块可视模式」,也就可以对多行文本同时进行编辑,还以刚才的例子为例:

  • f. 找到要修改的字符 .

  • <ctrl-v>jjjjj 选中要修改的行

  • r- 完成替换

可以看到,被选中的每一行都只有第一个 . 被替换了,而不会像普通的可视模式一样选中整行。