什么是宏
宏让我们可以在 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-
完成替换
可以看到,被选中的每一行都只有第一个 .
被替换了,而不会像普通的可视模式一样选中整行。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。