跳过正文
  1. Posts/

Vim 学习笔记 Day 008:Vim 高频进阶整合,把“会基础编辑”推进到“能稳定日常用”

·4335 字·9 分钟
📖 阅读 --
DogDu
作者
DogDu
工作结束或者累了, 要不休息一会, 看会动漫吧 ~
目录
Vim 14 天 - 这篇文章属于一个选集。
§ 8: 本文

今日主题
#

  • 主主题:Vim 高频进阶整合
  • 副主题:把前 7 天已经学过的基础动作,补成一套更完整的日常编辑闭环

学习目标
#

  • 补齐前 7 天里已经碰到、但还没系统收进去的高频能力:
    • 插入模式高频入口
    • .、撤销、寄存器
    • :global
    • 多文件批处理
  • 建立一个更实用的判断:
    • 重复一小步,用 .
    • 重复一串动作,用宏。
    • 先按条件筛行再执行,用 :global
    • 已知一组文件后统一处理,用 :argdo / :bufdo / :cfdo
  • 为 Day 009 的 Neovim 过渡打底,避免一边补 Vim 高频能力一边换宿主环境。

前置回顾
#

  • Day 001 到 Day 007 已经打下了基础语法:
    • 模式
    • 移动
    • operator + motion
    • 文本对象
    • 搜索 / 替换 / Visual
    • buffer / window / split
    • Ex 命令行与范围
  • 但到这一步,仍然有一批高频能力没有系统收束:
    • 插入模式并不只有 i / a / o
    • 重复修改不只靠手工重做
    • 删除和复制会牵涉寄存器
    • 一部分批量动作应该从单文件推进到多文件

典型场景
#

  • 你刚在一行里完成了一次理想修改,下面几行想重复同样的改法。
  • 你想删一段内容,但不想把刚刚 yank 的文本冲掉。
  • 你在几个文件里要做同一种替换,已经不想一个个打开再手工改。
  • 你只想对“包含 TODO 的行”做处理,而不是整文件盲改。
  • 你正在插入文本,但突然想补一个普通模式动作,不想完全退出插入模式再回来。

最小命令集
#

今天内容比前几天多,但主线只保留最常用的一层。

插入模式高频入口
#

  • I / A
    • 到首个非空白字符前 / 行尾再进入插入
  • O
    • 在上方新开一行并进入插入
  • gi
    • 回到上次离开插入模式的位置
  • s / S
    • 删除一个字符 / 一整行并进入插入
  • 插入模式里 Ctrl-O
    • 临时执行一个普通模式命令
  • 插入模式里 Ctrl-R {register}
    • 插入寄存器内容

重复与撤销
#

  • .
    • 重复上一次修改
  • u
    • 撤销
  • Ctrl-r
    • 重做
  • g- / g+
    • 在时间线上后退 / 前进

最小寄存器心智
#

  • ""
    • 无名寄存器,默认 p / P 用它
  • "0
    • 最近一次 yank
  • "-
    • 小删除寄存器
  • "_
    • 黑洞寄存器,不保留被删内容
  • "+
    • 系统剪贴板
  • :registers
    • 查看寄存器

#

  • qa
    • 开始录制到寄存器 a
  • q
    • 停止录制
  • @a
    • 执行寄存器 a 里的宏
  • @@
    • 重复上一次执行的宏

行级筛选与批处理
#

  • :g/pattern/cmd
    • 对匹配行执行命令
  • :v/pattern/cmd
    • 对不匹配行执行命令
  • :g/pattern/normal ...
    • 对匹配行执行普通模式命令

多文件批处理
#

  • :args *.md
    • 建立参数列表
  • :argdo ... | update
    • 对参数列表里的每个文件执行命令
  • :bufdo ... | update
    • 对所有 buffer 执行命令
  • :vimgrep /pattern/ **/*.md
    • 搜索并把结果放进 quickfix
  • :copen
    • 打开 quickfix 窗口
  • :cfdo ... | update
    • 对 quickfix 命中的每个文件执行命令
  • :cdo ...
    • 对 quickfix 的每个命中项执行命令

它是怎么用的
#

插入模式值得补齐一轮高频入口
#

Learn-Vim 的插入模式章节和本地帮助都提醒了一个关键点:

  • 进入插入模式的方法很多
  • 目的不是记住所有入口
  • 而是减少“先进去再挪位置”的浪费

最值得先补齐的是:

  • I
    • 已经确定要去行首真正开始写内容
  • A
    • 已经确定要接在行尾补内容
  • O
    • 需要在上方补一行
  • gi
    • 刚才插入到一半跳开了,现在要回原位继续写

这组命令会把 Day 001 的“少在插入模式里漂移”真正落到动作上。

.、撤销、寄存器,是最小编辑闭环
#

如果把前几天学过的内容连起来看,日常编辑最常见的闭环其实是:

  1. 先用 motion / 文本对象做出一次正确修改
  2. . 重复
  3. 改错了就 u
  4. 需要拿回刚才的文本就看寄存器

这里最实用的判断是:

  • . 适合重复“刚刚那一次修改”
  • 宏适合重复“一串动作”

寄存器里也只先抓最常用的几个:

  • ""
    • 默认复制粘贴来源
  • "0
    • 让你在删改之后还能拿回刚才 yank 的内容
  • "_
    • 让你删除时不污染当前寄存器
  • "+
    • 让 Vim 和系统剪贴板接轨

如果这四个先抓稳,已经足够覆盖大量真实场景。

宏解决的是“重复动作”,不是“重复一次修改”
#

宏的句式很简单:

VIM 代码 · 共 4 行
qa
...动作...
q
@a

但真正该记住的是使用边界:

  • 一次小改动,优先 .
  • 需要跨行、跨多个普通模式动作重复,优先宏。

本地 Learn-Vim 的宏章节和 Vim 帮助都强调了一点:

  • 宏在遇到错误时会停下

所以录宏时,动作最好设计成:

  • 起点清楚
  • 结束条件自然
  • 最后一小步故意会在末尾失败并停住

这会让 99@a 成为一个很实用的习惯,而不是炫技。

:global 是“先筛行,再做事”
#

Day 007 已经建立了 :[range]command 的心智。Day 008 再往前一步,是把“范围”换成“条件”:

VIM 代码 · 共 2 行
:g/pattern/cmd
:v/pattern/cmd

这组命令最容易用在三类场景:

  • 删掉所有包含某模式的行
  • 只保留匹配或不匹配的行
  • 对匹配行执行普通模式命令

例如:

VIM 代码 · 共 4 行
:g/console/d
:v/^$/d
:g/TODO/t $
:g/./normal A;

所以 :global 的价值不是“又多记一个命令”,而是把 Day 005 的搜索能力和 Day 007 的命令行能力真正接起来。

多文件批处理先记一句话:先造列表,再跑命令
#

Day 008 里最容易一下子学乱的是 argdobufdocfdocdo。先别背百科,先记这句判断:

  • 已知一组目标文件:args -> argdo
  • 已经打开了一堆 buffer:bufdo
  • 先搜索,再在结果上处理:vimgrep -> copen -> cfdo / cdo

其中最常用的两组往往是:

VIM 代码 · 共 2 行
:args **/*.md
:argdo %s/old/new/ge | update

VIM 代码 · 共 3 行
:vimgrep /TODO/ **/*.md
:copen
:cfdo %s/TODO/DONE/ge | update

再补一个关键判断:

  • 命令是“按文件跑一次”,优先 cfdo
  • 命令是“按每个命中项跑一次”,再考虑 cdo

所以如果你传的是 :%s/.../.../g 这种整文件替换,通常 cfdocdo 更合适。

常见操作套路
#

套路 1:已经知道改法正确,下面几处直接 .
#

场景:

  • 你刚用 ciwcwA 做完一次正确修改
  • 下面几处只差位置不同,改法相同

做法:

  1. 第一次认真完成修改
  2. 移到下一处
  3. .

这是最该优先养成的重复习惯。

套路 2:正在插入时,临时补一个普通模式动作
#

场景:

  • 你在插入模式里,忽然想居中、跳 mark、删到行尾
  • 但不想彻底退出插入模式

做法:

VIM 代码 · 共 2 行
Ctrl-O zz
Ctrl-O D

这会让插入模式不再像一个完全封闭的房间。

套路 3:删除时不污染你刚才 yank 的内容
#

场景:

  • 你刚 yy 了一行,后面还要 paste
  • 但中间还要删几个词或几行

做法:

VIM 代码 · 共 2 行
"_diw
"_dd

如果你不用黑洞寄存器,很容易把本来想保留的 yank 冲掉。

套路 4:宏处理“跨多步”的重复
#

场景:

  • 每一行都要做同一串动作
  • 单个 . 已经不够

做法:

VIM 代码 · 共 2 行
qa0f,rxjq
99@a

不是要死记这个例子,而是先建立“录一遍,重放多次”的工作流。

套路 5:先把 TODO 聚到一起,再统一处理
#

场景:

  • 文件里散着很多 TODO
  • 想先集中查看,再决定改法

做法:

VIM 代码 · 共 1 行
:g/TODO/t $

这比肉眼扫全文更稳定,也更接近真实代码整理场景。

套路 6:多文件改名,先搜结果,再按文件改
#

场景:

  • 某个变量名或标记散在多个文件里
  • 想先确认命中结果,再统一替换

做法:

VIM 代码 · 共 3 行
:vimgrep /legacy_name/ **/*.md
:copen
:cfdo %s/\<legacy_name\>/new_name/ge | update

这条路线比“打开一个改一个”更接近真正的日常工作流。

环境差异:vim / nvim / LazyVim
#

Vim 和 Neovim 的底层语法一致
#

今天这批内容基本都属于共同底层:

  • . / u / Ctrl-r
  • 寄存器
  • :global
  • :argdo / :bufdo / :cdo

本地确认环境是:

  • Vim 9.2
  • Neovim 0.12.0

这些语法在两边都继续成立。

Neovim 不会替代这些能力,只会把它们接进更现代的宿主环境
#

到了 Day 009,真正变化的重点会是:

  • :terminal
  • 剪贴板 provider
  • stdpath() 和配置入口
  • :checkhealth

但如果 Day 008 这层没补齐,你会很容易把 Neovim 学成“会按框架快捷键,不会做基础批量编辑”。

LazyVim 只是给这些能力更快的入口
#

后面进到 LazyVim:

  • 文件搜索会更快
  • 项目搜索入口会更快
  • LSP 入口会更快

但最后真正落到文本处理时,很多动作仍然会回到:

  • .
  • 寄存器
  • :global
  • quickfix 列表

今日练习(5-10 分钟)
#

练习材料
#

新建两个临时文件。

demo-a.txt

TXT 代码 · 共 10 行
name = foo
name = foo
name = foo

# TODO: first
# TODO: second

apple
apple
banana

demo-b.txt

TXT 代码 · 共 3 行
name = foo
# TODO: third
apple

练习任务 A:把一次修改练成 .
#

  1. demo-a.txt 第一行把 foo 改成 bar
  2. . 把下面两行同样改掉。
  3. 撤销两次,再用 Ctrl-r 重做一次。

练习任务 B:补一轮寄存器和插入模式入口
#

  1. apple 这几行上试一次:
VIM 代码 · 共 1 行
"ayiw
  1. 到另一处进入插入模式后,用:
VIM 代码 · 共 1 行
Ctrl-R a
  1. 再试一次:
VIM 代码 · 共 1 行
gi
  1. 最后试一次不污染寄存器的删除:
VIM 代码 · 共 1 行
"_dd

练习任务 C:录一个最小宏
#

  1. 录一个宏,把一行行尾补上 ;,再跳到下一行:
VIM 代码 · 共 1 行
qaA;<Esc>jq
  1. 在相邻两行执行:
VIM 代码 · 共 1 行
2@a

练习任务 D:练一次 :global 和多文件批处理
#

  1. demo-a.txt 里执行:
VIM 代码 · 共 1 行
:g/TODO/t $
  1. 建一个参数列表:
VIM 代码 · 共 1 行
:args demo-a.txt demo-b.txt
  1. 对两个文件统一替换:
VIM 代码 · 共 1 行
:argdo %s/\<foo\>/done/ge | update

完成标准
#

  • 能说出 .、宏、:globalargdo 分别解决什么问题。
  • 能分清 "0"_"+ 的基本用途。
  • 能在需要时想到 giCtrl-OCtrl-R {register}

今日问题与讨论
#

我的问题
#

  • 暂无。本节先把高频进阶能力收束起来,后续问答直接补到这里。

外部高价值问题
#

问题 1:什么时候该用 .,什么时候该录宏?
#

  • 问题:
    • 两者都能“重复”,边界到底在哪里?
  • 简答:
    • . 重复的是上一次修改;宏重复的是一整串动作。
  • 场景:
    • 改同一种词,优先 .
    • 跨行、跨多步、还要带跳转时,优先宏。
  • 依据:
    • Learn-Vim 的点命令与宏章节。
    • 本地 repeat.txt 和宏执行行为。
  • 当前结论:
    • 先试 .,不够再上宏,是更稳的顺序。
  • 是否需要后续回看:

问题 2:为什么有了搜索和范围,还要学 :global
#

  • 问题:
    • Day 005 和 Day 007 已经学了 /:%s:[range]command,为什么还要补 :g
  • 简答:
    • 因为 :global 解决的是“按条件筛行后批量执行”,它不是简单替换。
  • 场景:
    • 删除所有包含某模式的行。
    • 复制所有 TODO 到文末。
    • 对所有匹配行执行 :normal
  • 依据:
    • D:\program\Learn-Vim\ch13_the_global_command.md
    • 本地 cmdline.txt
  • 当前结论:
    • :global 是搜索能力和 Ex 批量能力之间的桥。
  • 是否需要后续回看:

问题 3:为什么 cfdocdo 更适合配合 :%s
#

  • 问题:
    • quickfix 里不是已经有所有命中项了吗?为什么不直接 cdo
  • 简答:
    • 因为 :%s 是整文件命令,按文件执行一次通常就够了;cdo 会对每个命中项都跑一次。
  • 场景:
    • 一个文件里命中十次,但你只想在这个文件里整体替换一次。
  • 依据:
    • D:\program\Learn-Vim\ch21_multiple_file_operations.md
    • 本地 cmdline.txtediting.txt
  • 当前结论:
    • 文件级命令优先 cfdo,逐项命令再考虑 cdo
  • 是否需要后续回看:

常见误区或易混点
#

  • 误区 1:一遇到重复就录宏。
    • 先判断 . 能不能解决。
  • 误区 2:删除和复制永远只看默认寄存器。
    • "_"0 很多时候能避免手感被打断。
  • 误区 3:把 :global 当成“另一个替换命令”。
    • 它更像“按条件筛行,再执行别的命令”。
  • 误区 4:多文件替换时,一上来就 bufdo
    • 先判断目标文件集合是“已知列表”“已打开 buffer”还是“搜索结果”。
  • 误区 5:插入模式里只会 Esc 退出。
    • giCtrl-OCtrl-R {register} 其实非常高频。

扩展内容
#

  • "-
    • 小删除寄存器,适合理解“短删”和整行删除的差别。
  • "=
    • 表达式寄存器,后面需要时再展开。
  • 递归宏、追加宏
    • 属于有价值但不是今天主线必练的内容。
  • :windo:tabdo:ldo
    • 多文件 / 多窗口批处理的兄弟命令,先知道有这层即可。
  • :put _
    • 可以插空行,配合 :global 有一些很巧的用法。

今日小结
#

  • Day 008 不是开新体系,而是把前 7 天已经学过的能力补成闭环。
  • 到这一步,最关键的不是多记了多少命令,而是会开始做更清楚的判断:
    • 一次修改还是重复动作?
    • 单文件还是多文件?
    • 按范围还是按条件?
  • 这层补齐后,再进入 Neovim,会更像“切到现代宿主环境”,而不是一边补 Vim 基础一边换编辑器。

明日衔接
#

  • 下一天进入 Neovim 的定位 + 终端 / 剪贴板 / 配置 / health
  • 到那时会开始回答一个更实际的问题:
    • 为什么前 8 天学的 Vim 语法几乎都还能继续用,但日常主力往往会落到 nvim

复习题
#

  1. . 和宏各自适合解决什么问题?
  2. "0"_"+ 分别最适合什么场景?
  3. :g/pattern/cmd 的核心思路是什么?
  4. :argdo:bufdo:cfdo 大致分别适合什么入口场景?
  5. 为什么 Day 008 要放在 Neovim 之前,而不是之后?
Vim 14 天 - 这篇文章属于一个选集。
§ 8: 本文