Wiki LogoWiki - The Power of Many

W03: 视觉艺术与自动化原语

掌握视觉块操作的工程化应用, 深度解析宏的寄存器本质及其递归逻辑.

1. 可视模式详解

1.1 三种可视模式

v           " 字符可视模式 (Character-wise)
V           " 行可视模式 (Line-wise)
Ctrl + v    " 块可视模式 (Block-wise)

1.2 可视模式操作

o           " 切换到选区另一端
O           " 块模式下切换到同一行另一端
gv          " 重新选择上次的选区
1v          " 选择与上次相同大小的区域

1.3 可视模式下的动词

选中后可使用任何操作符:

d           " 删除选区
y           " 复制选区
c           " 修改选区
>           " 缩进
<           " 反缩进
~           " 切换大小写
u           " 转小写
U           " 转大写
J           " 合并行
:           " 对选区执行 Ex 命令

2. 块模式的极致生产力 (Visual Block)

Ctrl + v 进入的块视觉模式是 Vim 批量修改的核武器.

2.1 列编辑: 批量插入

初始:
  name: Alice
  name: Bob
  name: Charlie

操作: 在每行前添加 "user_"

1. 光标置于第一行 'n' 上
2. Ctrl+v 进入块模式
3. 2j 向下选择 3 行
4. I (大写) 进入插入模式
5. 输入 "user_"
6. Esc

结果:
  user_name: Alice
  user_name: Bob
  user_name: Charlie

原理: Vim 并非实时同步, 而是在按 Esc 的瞬间将指令重放到所有选中行.

2.2 列编辑: 批量追加

初始:
  const a = 1
  const b = 2
  const c = 3

操作: 在每行末尾添加分号

1. Ctrl+v 选择第一列
2. 2j 向下扩展
3. $ 扩展到行尾 (关键!)
4. A (大写) 在末尾追加
5. 输入 ";"
6. Esc

结果:
  const a = 1;
  const b = 2;
  const c = 3;

2.3 列删除

初始:
  # comment1
  # comment2
  # comment3

操作: 删除所有注释符号

1. 光标置于 '#' 上
2. Ctrl+v 进入块模式
3. 2j 向下选择
4. l 扩展选择 '# '
5. d 删除

结果:
  comment1
  comment2
  comment3

2.4 批量替换

" 选中列后
c           " 修改选中的列
r{char}     " 将选中区域替换为字符

3. 自动化内核: 宏 (Macros)

在 Vim 中, 宏只是存储在寄存器中的指令流字符串.

3.1 录制与回放

q{a-z}      " 开始录制到寄存器 (如 qa)
q           " 停止录制
@{a-z}      " 回放宏 (如 @a)
@@          " 重复上次的宏
{n}@{a-z}   " 执行 n 次 (如 10@a)

3.2 健壮的宏设计原则

录制宏时的最佳实践:

1. 开始前重置位置
   - 0 (行首)
   - ^ (首个非空)
   - gg (文件首)

2. 使用可重复的动作
   - 用搜索 /pattern 而非绝对位置
   - 用 f{char} 而非多次 l

3. 结束时定位到下一目标
   - j (下一行)
   - n (下一个搜索匹配)
   - } (下一段)

示例: 为每行添加引号
qa           " 开始录制
0            " 到行首
i"<Esc>      " 插入开头引号
$            " 到行尾
a"<Esc>      " 追加结尾引号
j            " 下一行
q            " 停止录制

3.3 查看宏内容

" 查看寄存器内容
:reg a
:registers a

" 以文本形式编辑
"ap         " 在当前位置粘贴寄存器 a 的内容

3.4 编辑宏

如果录制的宏有错误, 不需要重录:

" 1. 新建空行, 粘贴宏内容
"ap

" 2. 编辑文本 (这就是宏的指令序列)
" 例如: 0i"^[$a"^[j
"        └──────┴───┴────┴──┴─ 这些是按键序列

" 3. 选中修改后的文本
0v$

" 4. 复制回寄存器
"ay

" 注意: ^[ 代表 Esc, 输入方式是 Ctrl+v 然后 Esc

3.5 寄存器追加

qA          " 大写字母表示追加到已有宏
...         " 追加的操作
q           " 停止

4. 递归宏

这是大规模文本转换的终极方案.

4.1 原理

在宏的末尾调用自己:

qa          " 开始录制
...         " 操作内容
@a          " 调用自己 (此时 a 还在录制中)
q           " 停止录制

@a          " 执行 - 会无限循环直到遇到错误

4.2 安全终止

递归宏在以下情况自动停止:

  • 搜索失败 (如 /pattern 没有找到)
  • 移动失败 (如 j 在最后一行)
  • 任何操作出错
" 示例: 处理所有匹配行直到结束
qa          " 开始录制
/TODO<CR>   " 搜索 TODO
dd          " 删除该行
@a          " 递归调用
q           " 停止

@a          " 执行 - 删除所有含 TODO 的行

4.3 对范围执行宏

:5,10 normal @a     " 对第 5-10 行执行宏 a
:'<,'>normal @a     " 对可视选区执行宏
:%normal @a         " 对所有行执行宏
:g/pattern/normal @a " 对匹配行执行宏

5. 宏的高级进阶 (Macro Pro Tips)

5.1 并行执行宏

虽然递归宏很酷, 但在多行上并行执行通常更稳健, 因为某一行报错不会影响其他行.

" 对可视选区选中的每一行执行宏 a
:'<,'>normal @a

" 对整个项目所有 Go 文件执行宏
:argdo %normal @a

5.2 插件增强: tpope/vim-repeat

原生 Vim 的 . 只能重复内置命令. 安装 vim-repeat 后, 很多插件操作 (如 surround) 也可以被 . 重复.

重要的是, 它也允许你在编写插件或自定义映射时, 通过简单的一行代码让其支持 . 重复.

5.3 宏与寄存器的可视化管理

如果你的宏逻辑非常复杂, 推荐使用 tada/vim-macro 或类似的 UI 插件来查看和管理寄存器中的指令序列.


6. 实战案例

5.1 CSV 转 JSON

初始:
name,age,city
Alice,25,NYC
Bob,30,LA

目标:
{"name": "Alice", "age": "25", "city": "NYC"},
{"name": "Bob", "age": "30", "city": "LA"},
" 假设光标在数据第一行
qa                          " 开始录制
0                           " 行首
i{"name": "<Esc>            " 插入
f,                          " 找逗号
s", "age": "<Esc>           " 替换逗号
f,                          " 找下一个逗号
s", "city": "<Esc>          " 替换
$                           " 行尾
a"},<Esc>                   " 追加
j                           " 下一行
q                           " 停止

@a                          " 执行
@@                          " 重复

5.2 批量重命名变量

初始:
let userName = "Alice";
console.log(userName);
return userName;

目标:
let user_name = "Alice";
console.log(user_name);
return user_name;
" 使用宏 + 搜索
/userName<CR>       " 搜索
qa                  " 录制
ciwuser_name<Esc>   " 修改单词
n                   " 下一个匹配
q                   " 停止

10@a                " 执行 10 次
" 或者使用 :%s/userName/user_name/g

7. 本周实战任务

6.1 块编辑

  1. 为 50 行代码批量添加 // 注释前缀
  2. 为多行字符串添加首尾引号
  3. 对齐多行赋值语句的等号

6.2 宏录制

  1. 录制一个宏: 将 var 替换为 const
  2. 练习编辑宏: 粘贴、修改、重新存储
  3. 使用 :normal @a 对指定范围执行宏

6.3 递归宏

  1. 录制递归宏删除所有空行
  2. 使用递归宏处理多层嵌套结构

8. 思考题

  1. 块模式的 IA 与普通模式有何不同?
  2. 为什么宏要以 0 开始、j 结束?
  3. 如何修改一个录制错误的宏?
  4. 递归宏如何安全终止?
  5. 什么场景更适合用宏而非替换命令?

可视块和宏是 Vim 批量处理的两大支柱. 掌握它们, 你就拥有了文本自动化的能力.

On this page