宏
什么是宏?
宏(英语:Macro)是一种批量处理的称谓。 计算机科学里的宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。对于编译语言,宏展开在编译时发生,进行宏展开的工具常被称为宏展开器。
通过上面的定义,可以知道宏相当于是将重复的步骤封装成了一个函数,然后通过这个函数,可以进行更简化的处理,而在Vim中宏是一种把一系列的按键操作过程录制并保存下来,然后在必要时刻可以选择快速调用之前录制的宏操作,目的也是为了简化大量重复的操作。
Vim中的宏命令
如何开启录制宏操作
- 通过
q+[字母]的方式触发录制模式,比如按下qa,此时在Vscode下方会显示正在录制的标记:
- 该标记的可以这样理解:
Recording代表正在录制宏操作@a表示正在录制的宏操作的唯一标记为a,如果之前按下的组合键是qq那么此时此处就会显示@q
- 注意点:实际上不管是用小写字母录制宏还是以大写字母录制宏,最后都会转为小写,比如
qa和qA都是录制唯一标记为a的宏,在触发录制的时候下方显示的内容都是Recording @a,当然qa和qA实际上是有些不同的地方的,后面会讲到。
录制宏操作与停止录制
- 在开启录制之后,后面的操作都会被宏录制下来,直到再次输入
q为止,此时按下的q代表停止录制
寄存器是什么?作用呢?
寄存器是Vim用来暂时存放文本的地方,如果在vim中进行了y(复制)、d(删除)、c(修改)一类的操作,文本则会被存储到寄存器中。
而录制了一个新的宏后,Vim会将该操作宏放在寄存器中,例如 qa 等同于录制一个存储在寄存器 a 中的宏。
如何查看录制好的宏操作
:reg:通过:reg可以常看录制的宏操作,并可以进行搜索
下面是如果我要看标记为
g的操作宏,这个时候就可以输入g,列表下方也会快速检索出对应的结果,可以看到这里我录制的操作为ggVGd
:reg [字母](:reg后面有一个空格):如果要查看指定的宏操作可以在该命令后再加上字母(唯一标识符),这样就可以看到录制的宏操作具体会触发哪些按键了,比如如果要看查看标记为g的操作宏,那么这个时候就可以输入:reg g,右侧会弹出对应的提示(参考下图)
如何调用录制的宏操作(播放宏操作)
- 调用(播放)指定的宏:
@+[字母] - 调用(播放)最后一次执行的宏:
@@ - 重复执行(播放)宏:
[数字]+@+[字母](数字代表了需要重复执行的次数)
如何给已录制的宏追加操作
通过q+[大写字母]:在对应的字母后面追加操作命令,比如当前的录制的宏qa对应的操作为dw,如果需要追加光标移动到行末的操作,这个时候就可以使用qA进入追加操作录制模式,给原有的宏追加操作g_,追加操作完成后记得按下q结束这次追加操作的宏录制,这就追加操作的基本流程。
追加操作小案例
比如现在有这样一段代码(|表示的是光标的位置):
let |a = 'a';
let b = 'b';
let c = 'c';
let d = 'd';
let e = 'e';
let f = 'f';
let g = 'g';
let h = 'h';
let i = 'i';
let j = 'j';
现在的需求是需要给所有声明的变量以及值前面加上_,如果是通过宏的操作来解决就可以这样写:
- 首先录制宏,按下
qa开启录制 - 接下来就进行操作就可以了,输入
v+gb+I+_+ctrl+[+qv:进入可视化模式gb:选中光标所在的单词相同的且未被选中的第一个单词I:再选中的内容前进行插入_:这次需要添加的_服号ctrl+[:退出输入模式
- 现在通过
10+@+a调用下刚才设置的宏,发现并不是想要的结果
- 给之前录制的宏追加操作,首先开启追加宏录制
qA,输入j跳转到下一行,按下q结束追加宏录制,现在看看效果:
宏的安全机制
对于多次执行宏操作的时候,如果出现无法执行对应操作时,比如检索不到对应的字符串的时候,会报错并停止执行。
运用这个特性,可以做一些事情,比如在批量替换字符串的情况下,文本中有多个要替换的内容,但是当前不知道具体有多少个需要替换的字符串,这个时候可以通过配合/检索并替换的操作来录制一个宏,然后通过[数字]+ @ + [字母]的方式,重复执行该宏操作,如果执行的次数超过了当前需要替换的字符串,此时Vim会因为检索不到对应的字符串报错停止替换操作,所以可以利用这个特性,我们可以在一些重复操作中无心智负担地进行全量执行,比如大概预估要重复执行的次数,然后直接执行一个绝对大于数目的次数,就可简单安全地达到目的。
如何获取已暂存的宏?
- 方法1:
"+[字母]+p:粘贴名称为[字母]的宏操作"+[字母]:读取已暂存的宏操作p:粘贴
- 方法2:
:put+[字母],效果与方法1一样,注意:put后面需要加上空格
如何修改已暂存的宏?
录制了一个新的宏后,Vim会将该操作宏放在寄存器中,而若需要修改暂存的宏,主要需要做3步:
- 获取宏操作的内容
- 修改宏操作的内容
- 将修改后的内容重新放回寄存器中
对应的操作如下:
- 通过上文中获取已暂存的宏的方法将暂存的宏操作给打印出来
- 修改打印出来的宏操作
- 前文中提到过,寄存器的概念,操作宏实际上就是存放在寄存器中的宏,而要将东西放入到寄存器,前文中也提到过了,在vim中进行了y(复制)、d(删除)、c(修改)一类的操作,文本会被存储到寄存器中,而如果要将修改后的宏操作重新放回去也是如此,按下
"+[字母]此时 Vim 会等待你接下来存入寄存器中的内容,该内容会覆盖掉原有寄存器[字母]中的内容,所以这个时候将此处修改后的内容进行复制、删除等等操作都可以实现,比较常见的就是yy、yw、dw、dd、cc等等
小案例
比如现在我需要删除当行内容后移动到下一行,已经录制的名为a的宏对应的操作内容为dd,如果还需要移动到下一行,我们可以选择上面追加宏操作的方式,也可以用修改已暂存的宏的方式,下面通过修改已暂存的宏的方式来试试看:
- 获取操作宏的内容:通过
"ap,打印出dd - 修改宏操作的内容:修改
dd为ddj - 将修改后的内容重新放回寄存器中:输入
"a,然后在ddj那行输入dd删除改行的内容,这样就可以把ddj这个新的宏操作替换到寄存器a中了 - 通过
@a测试下是否可行
该方式存在的问题
注:该问题存在于Vscode的Vim插件中,终端上的Vim不会有这个问题。
如果宏中带有功能组合键,比如从输入模式返回normal模式的时候,会输入<C-[>,此时而此前进入输入模式的时候按下了i,这个时候打印出来的宏中必定会前后分别带有i和<C-[>,问题就出在这里,i会把后面的所有内容都识别为要输入的字符串,最后看到的替换后执行的宏对应的效果就是下图了:
对于该问题目前没有好的解决方案,推荐的做法就是重新录制宏。
宏的使用技巧
使用过程中,可以注意两个点:
- 规范好光标的位置
- 使用相对位置的操作符,比如
e、w、f、t、文本对象等等,此外还少注意少用hkjl这些相当于是绝对位置,不能确保光标的所在位置,不能应对一些通用的情况。