跳到主要内容

宏录制

宏(Macro)是 Vim 中用于录制和回放一系列操作的功能。它可以将重复性的编辑任务自动化,大幅提升效率。

什么是宏

宏是存储在寄存器中的一系列按键操作。你可以:

  1. 录制一系列操作
  2. 将操作保存到寄存器
  3. 随时回放这些操作
  4. 多次重复执行

录制宏

基本步骤

1. q{寄存器}    " 开始录制(如 qa 表示录制到寄存器 a)
2. 执行操作 " 执行你想要录制的操作
3. q " 停止录制

示例:给每行添加序号

原始文本:
apple
banana
cherry

操作步骤:
1. qa " 开始录制到寄存器 a
2. I1. Esc " 在行首插入 "1. "
3. j " 移到下一行
4. q " 停止录制

现在可以用 @a 回放宏

播放宏

基本播放

命令作用
@{寄存器}播放指定寄存器的宏
@@播放上次使用的宏

示例

@a          " 播放寄存器 a 中的宏
@@ " 再次播放
10@a " 播放 10 次

给多行添加序号(完整示例)

原始文本:
apple
banana
cherry
date
elderberry

步骤:
1. 光标在第一行
2. qaI1. Escjq " 录制宏:插入 "1. " 并移到下一行
3. 光标移到第二行
4. 2@a " 对剩余两行执行宏

结果:
1. apple
2. banana
3. cherry
4. date
5. elderberry

宏的高级用法

在可视模式中播放宏

1. 选中多行(可视模式)
2. :normal @a " 对选中的每一行播放宏 a

在范围中播放宏

:5,10normal @a   " 对第 5-10 行播放宏 a
:%normal @a " 对所有行播放宏 a

递归宏

宏可以调用自身,实现递归操作:

1. 清空寄存器 a:let @a = ''
2. 光标在第一行
3. qaI- Escj@aq " 录制递归宏

这个宏会:
- 插入 "- "
- 移到下一行
- 调用自身(@a)

4. @a 启动递归,直到文件末尾
注意

递归宏需要确保有终止条件,否则会无限循环。

编辑宏

宏存储在寄存器中,可以像编辑文本一样编辑宏。

查看宏内容

"ap         " 粘贴寄存器 a 的内容,查看宏的具体按键

修改宏

1. "ap       " 粘贴宏内容
2. 编辑宏内容
3. "ayy " 重新存入寄存器(或用可视模式选择后 "ay)

追加到宏

qa          " 录制新宏到 a,会覆盖原有内容
qA " 追加到寄存器 a(大写 A)

宏的应用场景

场景 1:格式化数据

原始 CSV 数据:
Alice,25,NY
Bob,30,LA
Charlie,35,CHI

目标格式:
Name: Alice, Age: 25, City: NY

宏操作:
qa
^ " 跳到行首
IName: Esc " 插入 "Name: "
2f,i, Age: Esc " 找到逗号,插入 ", Age: "
2f,i, City: Esc " 找到逗号,插入 ", City: "
jq

然后播放:2@a

场景 2:重构代码

# 原始代码
x = 1
y = 2
z = 3

# 目标:改为 print 语句
print("x =", x)
print("y =", y)
print("z =", z)

宏操作:
qa
Iprint("Escf i =", EscA)Escjq

然后播放:2@a

场景 3:生成 HTML 列表

原始文本:
Apple
Banana
Cherry

目标:
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>

宏操作:
qa
I<li>EscA</li>Escjq

然后播放:2@a

场景 4:删除特定模式

删除所有 console.log 语句:

宏操作:
qa
/console.logEnter" 搜索 console.log
dd " 删除该行
q

然后重复播放 @@ 直到没有匹配

宏的技巧

技巧 1:确保光标位置正确

录制宏时,使用绝对定位(如 ^, $, 0)确保每次执行时光标位置一致。

好的做法:
qa^I// Escj " 使用 ^ 确保在行首注释

不好的做法:
qai// Escj " 如果光标不在行首会出错

技巧 2:使用查找移动

qa
f: " 找到冒号
r= " 替换为等号
jq

技巧 3:处理错误

如果宏执行中遇到错误,会停止执行。可以在宏中加入容错处理:

qa
:norm! ^ " 强制跳到行首,即使出错也继续
...
q

技巧 4:批量执行宏

:argdo normal @a    " 在所有参数文件上执行宏
:bufdo normal @a " 在所有缓冲区上执行宏
:windo normal @a " 在所有窗口上执行宏

技巧 5:宏与点命令结合

qa
cwnewTextEsc " 修改单词
q

n " 跳到下一个匹配
. " 重复修改
n. n. n. " 继续重复

或者:
10@a " 如果所有位置都需要相同修改

宏的保存与加载

保存宏到文件

" 将宏保存到 vimrc
let @a = 'I// ^[j' " ^[ 表示 Esc(用 Ctrl+v Esc 输入)

在 vimrc 中定义宏

" 定义宏 a:在行首添加注释
let @a = "I// \<Esc>j"

" 定义宏 b:删除当前行并粘贴到下一行
let @b = "ddp"
注意

在 vimrc 中定义宏时,特殊字符需要转义:

  • \<Esc> 表示 Esc 键
  • \<CR> 表示回车
  • \<Tab> 表示 Tab

宏的调试

逐步执行

1. 先播放一次宏,观察效果
2. 如果出错,用 "ap 查看宏内容
3. 检查每一步的操作
4. 重新录制或编辑宏

常见问题

问题 1:宏执行到一半停止

  • 原因:遇到错误或找不到匹配
  • 解决:检查宏中的查找命令,添加容错

问题 2:宏在不同位置效果不同

  • 原因:光标位置不一致
  • 解决:使用绝对定位(^, $, gg, G)

问题 3:宏修改了不想修改的内容

  • 原因:搜索范围太宽泛
  • 解决:使用更精确的搜索模式

练习

练习 1:基础宏

创建一个文件,包含:
line1
line2
line3
line4
line5

任务:给每行添加 "- " 前缀
1. 录制宏 qaI- Escjq
2. 播放宏 4@a

练习 2:格式化数据

原始数据:
2024-01-01 100
2024-01-02 200
2024-01-03 300

任务:改为
Date: 2024-01-01, Amount: $100

提示:
1. 录制宏添加 "Date: " 和 ", Amount: $"
2. 播放宏处理所有行

练习 3:重构代码

# 原始代码
var1 = 10
var2 = 20
var3 = 30

# 目标:
self.var1 = var1
self.var2 = var2
self.var3 = var3

任务:
1. 录制宏将 "var = " 改为 "self.var = var"
2. 应用到所有行

练习 4:递归宏

原始文本:
item
item
item
item

任务:添加递增序号
1. 1. item
2. 2. item
3. 3. item
4. 4. item

提示:使用递归宏,每次调用自身

宏 vs 其他功能

功能适用场景优势
复杂的多步骤操作可以录制任意操作序列
点命令重复单次修改简单快捷
替换批量文本替换可以处理整个文件
可视模式选择性编辑直观看到选择范围

宏总结

操作命令
开始录制q{寄存器}
停止录制q
播放宏@{寄存器}
重复播放@@
多次播放{数字}@{寄存器}
查看宏"{寄存器}p
编辑宏粘贴、修改、重新存入

下一步

掌握了宏录制后,你已经具备了 Vim 的核心编辑技能。下一章我们将学习配置 Vim,让你的编辑器更加个性化和高效。