Skip to content

重复与撤销:点命令、宏与寄存器

Vim 高效的秘密不仅在于单次操作快,更在于重复操作极其简单。本章将介绍 Vim 最强大的效率工具:点命令、宏和寄存器。

点命令:一键重复

.(点命令)是 Vim 中最强大的单个命令——它重复上一次的编辑操作。

基础用法

javascript
const foo = 1;
const bar = 2;
const baz = 3;

想把所有 const 改成 let

  1. 移动到第一个 const
  2. ciwlet<Esc> → 修改为 let
  3. 移动到下一个 const
  4. . → 重复上次修改
  5. 移动到下一个
  6. . → 再次重复

三行只需要一次完整输入,后面全是 .

什么算"一次编辑操作"

点命令重复的是"从进入 Insert 模式到退出"的整个过程:

  • ciw + 输入内容 + <Esc> → 整体算一次操作
  • dd → 一次删除操作
  • >> → 一次缩进操作

设计可重复的操作

点命令的威力取决于你如何设计操作。

不好的设计

javascript
const value = oldValue;

想把 oldValue 改成 newValue

  1. f" 跳到 o
  2. dwi → 删除词,进入 Insert
  3. 输入 new
  4. <Esc>

这样 . 只能重复"输入 new",不实用。

好的设计

  1. 光标在 oldValue
  2. ciw → 删除整个词,进入 Insert
  3. 输入 newValue
  4. <Esc>

现在 . 可以重复"把当前词改成 newValue"。

实战:批量添加分号

javascript
const a = 1
const b = 2
const c = 3

想在每行末尾添加分号:

  1. A;<Esc> → 到行尾添加分号
  2. j. → 下一行,重复
  3. j. → 下一行,重复

A 是"在行尾进入 Insert 模式",配合 . 可以批量在行尾添加内容。

撤销与重做

命令效果
u撤销(undo)
Ctrl+R重做(redo)
U撤销整行修改

撤销粒度

Vim 的撤销粒度是"一次编辑操作":

  • 在 Insert 模式输入 100 个字符,u 会撤销全部
  • 每次从 Normal 进入 Insert 再退出,算一个撤销点

如果你在 Insert 模式下想创建撤销点,按 Ctrl+G u

输入一些内容 Ctrl+G u 输入更多内容

这样 u 只会撤销"输入更多内容"。

撤销分支

Vim 维护完整的撤销历史树,而非线性历史。但在 VSCode Vim 中,这个功能有限。了解 uCtrl+R 足够日常使用。

寄存器:智能剪贴板

Vim 有多个"寄存器",可以理解为多个剪贴板。

默认寄存器

ydc 的内容默认存入 " 寄存器。p" 寄存器粘贴。

命名寄存器

"a"z 是命名寄存器,你可以指定存储位置:

操作效果
"ayy复制当前行到寄存器 a
"ap从寄存器 a 粘贴
"bdiw删除词并存入寄存器 b

数字寄存器

"0"9 自动保存最近的内容:

  • "0:最近一次 yank(y 命令)的内容
  • "1 - "9:最近 9 次删除的内容

这解决了一个常见问题:

  1. 你复制了一些内容(yy
  2. 你删除了一些内容(dd
  3. 你想粘贴之前复制的内容
  4. p 粘贴的是刚删除的内容!

解决方案:"0p → 粘贴最近复制的内容(而非删除的)。

系统剪贴板

如果配置了 vim.useSystemClipboard: true,y/p 直接使用系统剪贴板。

如果没有,可以用 "+ 寄存器手动访问系统剪贴板:

操作效果
"+yy复制到系统剪贴板
"+p从系统剪贴板粘贴

查看寄存器

使用 :reg 命令查看所有寄存器内容。在 VSCode Vim 中,这个命令显示最近几个寄存器的内容。

宏:录制与回放

宏是"录制操作序列,然后回放"的功能。它比点命令更强大——可以录制多个命令的组合。

基础用法

命令效果
q{a-z}开始录制到寄存器
q停止录制
@{a-z}回放宏
@@重复上次宏

实战:批量格式化

javascript
name: "John"
age: "30"
city: "NYC"

想把每行改成:

javascript
"name": "John",
"age": "30",
"city": "NYC",
  1. 光标在第一行
  2. qa → 开始录制到寄存器 a
  3. I"<Esc> → 行首添加引号
  4. f:i"<Esc> → 冒号前添加引号
  5. A,<Esc> → 行尾添加逗号
  6. j → 移动到下一行
  7. q → 停止录制
  8. 2@a → 执行宏 2 次

整个操作只需设计一次,然后批量应用。

宏的设计原则

原则 1:让宏自包含

宏应该从一个明确的位置开始,结束在下一个同样的位置。比如:

  • 开始:行首
  • 结束:下一行行首

这样连续执行不会出错。

原则 2:使用相对定位

不要使用"第 5 个字符"这样的绝对定位,而是用 f{char}w$ 等相对定位。

原则 3:先测试再批量执行

录制后,先用 @a 执行一次,确认正确,再用 100@a 批量执行。

宏的常见模式

模式 1:行处理

qa0...操作...j q

从行首开始,操作完移动到下一行,方便连续执行。

模式 2:搜索处理

qa/pattern<CR>...操作...q

搜索找到目标,操作,然后可以用 n@a 或直接 @a(如果宏里包含了搜索)。

模式 3:数字递增

这在 VSCode Vim 中支持有限,但基本思路是:

qa...操作...<C-a>...q

Ctrl+A 让数字 +1。

组合使用

点命令、寄存器、宏可以组合使用:

场景:复制函数到多个位置

  1. "ayip → 复制函数到寄存器 a
  2. 移动到位置 1
  3. "ap → 粘贴
  4. 移动到位置 2
  5. "ap → 粘贴

场景:宏中使用寄存器

  1. 先复制一些内容到寄存器 a
  2. 录制宏时使用 "ap 粘贴
  3. 宏中的粘贴内容是固定的,不受当前剪贴板影响

效率对比

任务:在 10 个 console.log 后添加分号

传统方式:

  • 手动定位 10 次
  • 手动输入分号 10 次
  • 时间:约 60 秒

Vim 方式(使用 A; + .):

  • A;<Esc> 一次
  • /console<CR> + . 重复 9 次
  • 时间:约 10 秒

Vim 方式(使用宏):

  • 录制 qaA;<Esc>/console<CR>q
  • 9@a
  • 时间:约 5 秒

练习

  1. 点命令练习

    • 创建 5 行相似的变量声明
    • ciw + . 批量修改变量名
  2. 寄存器练习

    • 复制一段代码到寄存器 a("ayip
    • 删除另一段代码
    • "ap 粘贴寄存器 a 的内容
  3. 宏练习

    • 创建 5 行需要格式化的数据
    • 录制宏处理第一行
    • 4@a 处理剩余行

本章收获

  • ✅ 掌握点命令(.)的使用
  • ✅ 理解撤销与重做机制
  • ✅ 学会使用寄存器系统
  • ✅ 能够录制和回放宏

效率提升

  • 点命令让重复编辑效率提升 5-10 倍
  • 宏让批量操作效率提升 10-50 倍
  • 正确使用寄存器避免内容丢失,节省 无数时间
重复与撤销:点命令、宏与寄存器 has loaded