
十几年前第一次读Vim用户手册我在上下班路上把User_04.txt这篇“Making small changes”反复翻了好几遍。老实说当时觉得这章太“小”了改一个字符、删一个单词、撤销一下这点东西也值得写一整章后来在真实项目里被daw和da)连续化险为夷我才反应过来——整本手册讲的是同一个道理Vim 的效率从来不靠某个惊天动地的命令而是靠一整套“微小改动”的精准组合。这篇笔记不是什么完整翻译而是我把User_04.txt读薄之后加上自己这些年实操感受的一次复盘。它适合刚刚脱离“只会用 hjkl 移动光标”阶段、想把编辑动作真正变成肌肉记忆的人也适合已经用了几年 Vim、但始终停留在dd和u层面的人——你缺的不是更多命令而是理解这些命令背后那条统一的语法线。我们直接从这一章里最容易被低估的核心概念说起。1. 为什么“微小改动”是整本手册最被低估的一章1.1 这一章的真实定位Vim 编辑哲学的浓缩版User_04.txt表面上讲的是“小改动”替换一个字符、删掉一个单词、改变一行、撤销刚才的手滑。但翻到底你会发现这章其实是 Vim 基本编辑语法的第一次正式亮相后面所有高阶操作都是从这里长出来的。手册在这一章里悄悄做了几件事把“操作符 动作”的语法骨架摆了出来把文本对象word、sentence、paragraph逐个点名把撤销/重做/重复这套时间旅行机制完整讲清。换句话说读完这一章你就不再是“背了一堆零散命令”而是拿到了一张可以推导出无数新命令的地图。很多教程习惯上来就教ciw、caw、da(这种组合技但没说它们从哪里来。如果你不理解“c 是操作符iw 是动作”遇到没见过的场景就只能瞎猜理解了语法遇到新结构比如ci自己就能推出来。1.2 谁最该认真读这篇我给三类人做过 Vim 相关的分享发现他们的需求完全不一样刚入门的用户需要的是“救命指令”怎么退出、怎么保存、怎么撤销。用了几个月的人需要的是“效率指令”少按几次键、少移动几次光标。用了几年的人需要的反而是“语法意识”知道自己每个操作在语法树上处于哪个位置从而自由组合。User_04.txt恰好卡在第二类和第三类之间。它默认你已经会移动光标、知道i和a能进入插入模式然后在此基础上告诉你真正的高效不是更快地进入插入模式而是尽量不进入插入模式。1.3 一个贯穿全章的隐藏语法动词 动作如果你只从这章带走一个概念我建议带走这个Vim 的编辑命令大多数可以拆成“动词”和“动作”两段。动词ddelete删除、cchange改变、yyank复制、vvisual选中。动作w单词、$行尾、0行首、j下一行、t(到左括号前、iw整个单词等。组合起来就是d$ 删除从光标到行尾 d0 删除从光标到行首 dj 删除当前行和下一行 daw 删除一个单词含后面空格这不是死记硬背而是一个可以举一反三的生成规则。理解了这条线后面所有命令都只是往这两个槽位里填不同的值而已。2. 单点修改r 替换、x 删除、以及整个撤销体系的最初形态2.1r命令不进入插入模式也能改字符手册第一个重点就是r。它的作用很简单把光标所在的一个字符替换成你指定的另一个字符。光标停在 f 上按 rf 字符立刻变成 f并且自动回到普通模式为什么这个命令值得写那么多篇幅因为它代表了一种极其重要的思维修改一个字符根本不值得为它进入插入模式、改完再按ESC退出。来回切换模式是有成本的而r把成本压缩到最低一个键开始一个键结束。我见过很多人改错别字时还是i、退格、打字、ESC四步走。用r一步就完了。这一个习惯的改变在一天几十次的小修改场景下节省的时间非常可观。r还可以带计数。比如你想把下面连续的 5 个字符全部替换成-5r- 命令分解5 r -这一招在处理分隔线、临时注释、批量占位符的时候特别实用。注意这里计数是作用在“要被替换的字符数量”上不是作用在动词上——这个细节后面讲d命令时你会再次遇到。2.2x与X删除不是大动作也可以是小修小补x删除光标下的字符X删除光标前面的字符。手册里把它定位成“删除单个字符”的手段用来和后面d命令这种“区域删除”做对比。单字符删除最典型的场景是删逗号、删括号、删多余的空格。比如:foo,bar 光标在逗号上按 x 得到 foobarX则适合你刚发现前一个字符敲错了又想留在普通模式里的场景。它本质上是把退格键的功能搬到了普通模式但比退格更好用因为它不会把光标拉入插入模式撤销时也是一个干净利落的节点。2.3 计数、.重复小操作发挥大威力的关键手册在讲完r和x之后顺势引入了两个概念计数count和.重复上一次修改。3x删除 3 个字符。按一次.重复上一次修改。这里我需要多说一句.命令。它是 Vim 里我最喜欢的键之一因为它的语义是“重复上一次修改”而不是“重复上一次键入”。如果你把 5 个单词各自改成首字母大写正确姿势不是从头到尾手动操作 5 遍而是1. 光标移到第一个单词首字母 2. ~切换大小写 3. 移动到下一个单词 4. 按 . 重复上一次大小写切换这就是“微小改动 × 可重复性”的核心单个操作很小但通过.把它变成流水线。User_04.txt里反复强调的小步修改、随时撤销、随时重复全部围绕这个思路展开。实际操作中我最常用它配合daw删一个单词后跳到下一处按.继续删一路删到底。2.4 退出普通模式的几种方式手册提了ESC但也顺带说了C-[这个替代键。实际使用中很多 Vim 用户会把Caps Lock映射成ESC或者用C-c退出。我的个人习惯是C-[因为手不用离开字母区太远输入中文输入法时也少一些干扰。不过这里有个容易踩的坑C-c在某些配置里和ESC并不完全等价它可能会打断一些映射或者弹出菜单而C-[则更接近原生ESC。如果发现某些插件行为怪怪的可以优先试试C-[。3. 删除命令的语法本质从x到dw、d$、dd3.1 为什么会有dw、d$、dd这么多删除命令User_04.txt从单一的x很快过渡到d系列这里很多人第一次接触“动词 动作”时会被绕晕。其实规则很简单d是操作符它后面跟什么动作就删什么范围。dw 删除从光标到下一个单词开头含空格 d$ 删除从光标到行尾 d0 删除从光标到行首 dgg 删除从光标到文件开头 dG 删除从光标到文件结尾 dd 删除整个当前行dd看起来是特例其实它是d d的省略写法动词d加上动作d表示当前行。类似的还有yy复制当前行、cc改变当前行。3.2 数字与动作3dw和d3w到底哪个对手册在这里给出了一个很好的提示计数既可以用在动作前也可以用在动词前语义几乎等价。3dw 删除三个单词 d3w 删除三个单词两者都是“删除 3 个单词”你愿意怎么按都行。但当动作不是“单词”而是“行”时最常用的还是dd带计数3dd 删除三行这里我提醒一个易混淆点d3w是在一个动作里感知“三”而3dd是在动词层面感知“三”。深层逻辑时3d$是“从光标开始连续删 3 次到行尾”效果和d3$一样但如果你按3dwVim 会直接理解为删除 3 个单词而不是“重复做 3 次删除一个单词”。平时使用几乎感觉不到差异但养成用“动作前计数”的习惯如d3w、c3w语义会更清晰。3.3 删除的内容去哪儿了寄存器与粘贴的伏笔d命令删除的文本不是消失而是被放进了 Vim 的寄存器。这也是为什么删除之后你随时可以用p把它粘贴回来。手册在这里只是轻轻点了一句但我想多说一点实操经验删除是剪切delete不是丢弃。复制是yyank不是“copy”。粘贴是p在光标后粘贴P在光标前粘贴。很多人第一次看到“删掉的内容居然还能贴出来”时都很惊讶这正是 Vim 的寄存器机制在起作用。理解这个机制你后续才能理解为什么dw之后按p能把单词贴到另一个位置——因为文本从未真正消失只是换了个地方存着。3.4 最容易踩的第一个坑dw到底删了什么手册用了一个很小的例子说明dw的行为This is a line with an example. 将光标移到 example 的 e 上按 dw 得到 This is a line with an .注意删掉的不是example这 7 个字母而是example加后面那个空格。当你写dw时动作w的语义是“到下一个单词的开头”所以删除范围自然覆盖了example以及它与下一段文本之间的空格。如果你只想删掉单词本身、保留空格需要的动作是diwdelete inner word这是手册后面讲文本对象时才明显展开的内容。所以很多初学者会在这一步困惑为什么我删一个词会把空格也删掉其实不是 Bug而是d w的组合语义如此。理解了这一点再去看dawdelete a word和diwdelete inner word的差别就会非常顺畅。4. 撤销、重做与重复Vim 的时间旅行机制4.1u、U、C-r三者分工别搞混User_04.txt花了相当篇幅讲撤销因为 Vim 的撤销不是单层而是像一棵树一样可以无限回退如果你配了持久化撤销甚至可以跨会话回退。手册只讲了最基本的三个键u撤销上一次修改。U撤销对当前行所做的全部修改。C-r重做即撤销的反向操作。u和C-r是一对互补命令。修改、u撤销、再C-r重做这个来回切换非常常用。很多人只记得u忘了C-r导致误撤销后只能手动重新敲一遍效率极低。U是一个稍微特殊的命令。它的作用范围是“当前行”只要你没有移动光标到其他行连续按U就会把这一行恢复到你最后一次进入普通模式时的状态。注意它和u的区别u是一步一步往回退U是直接把整行“一键复原”。如果你把一行改得面目全非想整体放弃按U比连续按好几下u更快。4.2 撤销粒度为什么我的u一次撤销一大片这是新手最常见的问题我明明只改了 2 个字符为什么按u却把一大段内容都撤销了因为 Vim 把“一次修改”定义为一组连续的编辑操作。具体规则大致是进入插入模式后直到退出插入模式这期间所有的输入、删除、替换都被视为一次修改。也就是说如果你进入插入模式打了 20 个字符才按ESC那么一次u就会撤销这 20 个字符。手册对这个机制的描述很到位你可以通过“步进式修改”来控制撤销粒度——改一小步、退出插入模式、再改一小步、再退出。这样每段修改都成为独立的撤销节点出问题时回退范围更可控。这在写代码时特别有用。我习惯的做法是一行逻辑没写完先按C-[退出插入模式再重新进入继续写制造两个撤销节点。虽然看起来多按了一次键但换来的是撤销时不会“误伤”之前的正确内容。4.3.命令与撤销的配合重复不是简单的重放., 命令和撤销配合使用时有一个值得注意的行为它的重复是针对“上一次修改”的一次性操作而不是宏。比如你cw改了一个词后按u撤销再按.并不会“重做上一次修改的撤销”而是继续执行“上一次修改”。两者的作用方向经常让人困惑。实操中我建议记住一个简单原则撤销用u重做用C-r重复用.。这三个键的场景完全不同不要指望.能恢复被你撤销的东西。4.4 viminfo 与退出后的撤销被大多数人忽略的福利手册末尾专门提了一个容易忽略的功能Vim 会把撤销历史写入 viminfo 文件所以当你关闭文件再重新打开时之前的撤销记录仍然部分保留。这意味着1. 编辑文件 2. 保存并退出 3. 重新打开 4. 还能按 u 撤销之前的改动很多人不知道这个特性以为退出 Vim 就一切清零了。实际上只要你没有把 viminfo 关掉撤销历史的“主干”还是能恢复的。这一点在误操作后保存退出了文件时特别有用别慌重新打开大概率还能撤销回来。不过要说明的是跨度太长的编辑、经过多次分支撤销的复杂历史viminfo 恢复得不完整这也是正常的。关键时候记得这个机制存在能救命。5. 替换模式与改变操作R、c和它们背后不同的编辑哲学5.1R替换模式覆盖式输入而不是插入式输入R进入替换模式Replace mode在这个模式下你输入的每个字符都会覆盖光标处的已有字符而不是把它们往后挤。光标在 abc 的 a 上按 R输入 xyESC 结果xyc替换模式最适合等宽排版、固定宽度表格、代码注释对齐这类场景——你要做的是“把旧内容逐个换成新内容”而不是“在中间插入并推挤后续文本”。手册提醒了一个细节替换模式和插入模式一样按BS退格键时行为不同。在替换模式下退格会把你替换过的字符恢复成原样而不是简单地往前删。这个行为初看有点反直觉但实际用起来非常顺手——你可以在覆盖过程中随时反悔退回去的东西是原始的旧文本而不是一片空。5.2 改变命令c删除的同时进入插入模式c是这一章里除了d之外最重要的操作符。它的语法和d完全一致区别在于d删除后留在普通模式c删除后直接进入插入模式方便你立刻输入新内容。cw 改变一个单词删除后进入插入模式 c$ 改变从光标到行尾 cc 改变整个当前行进入插入模式从操作习惯上看c适合“替换文本”的场景d适合“删掉不想要、暂时不补新内容”的场景。很多人会觉得d以后再按i输入不也一样吗确实结果可能相同但c把“删除”和“进入插入模式”合并成一次操作减少了一次模式切换连续性更好。举个例子把 foo 改成 bar 光标停在 foo 的 f 上 方案Adw i bar ESC 方案Bcw bar ESC方案B少了一次多余操作而且撤销时的颗粒更干净。5.3c与文本对象组合遇到变量的冲动决定一旦学会c你就会自然地想配合动作使用。这里最常用的几个组合ciw 改变整个单词 caw 改变一个单词含后面的空格 ci 改变双引号内的内容 ci( 改变括号内的内容 ct. 改变直到遇到下一个点号之前的内容这些组合在处理代码时极其高效。例如const name old_value; 光标在引号内按 ci 后输入 new_valueESC你不用手动删引号、不用担心引号被误删因为ci的语义就是把引号内的内容清空并进入插入模式。User_04.txt里虽然没有系统地讲ci但它的文本对象概念已经为这一步埋好了伏笔。5.4r、R、c的边界什么时候用哪个我经常用一个简单的判断标准来区分这三个命令只改一个字符用r。连续覆盖一段固定区域用R。删除并重新输入、长度可能变化用c。用一张小表总结命令行为是否进入插入模式典型场景r替换一个字符否改一个错字R连续覆盖是替换模式对齐、改定宽表c删除区域后输入是改一个单词、括号内内容这个边界不是手册直接划的而是我在日常使用中筛选出来的。你如果能形成类似自己的判断框架命令选择就会下意识变得准确不再纠结。6. 文本对象从“按字符编辑”升级到“按语义编辑”6.1 什么是文本对象word、sentence、paragraph、blockUser_04.txt在讲完dw、d$、dd之后引入了一个真正的进阶概念文本对象text objects。它把文本看作有结构的对象而不是一串没有边界的字符流。w作为动作时是“到下一个单词的开头”但iw作为文本对象时是“当前整个单词”。s作为动作时是句子sentenceis是“当前整个句子”。p是段落paragraphip是“当前整个段落”。(、)、、、、[、{等标点则对应各种围栏区域。文本对象的通用语法是操作符 i/a 文本对象i表示“inner”只处理对象内部内容。a表示“a/an”处理对象及其周围的边界或空格。6.2daw与dw的差别一个空格引发的思考手册专门用例子说明了daw的威力The quick brown fox jumps over the lazy dog. 光标在 fox 的 f 上 daw 得到 The quick brown jumps over the lazy dog.注意daw删掉的“fox”包含它后面的空格结果是两个单词之间只有一个空格读起来自然顺畅。如果只用dw因为 w 动作默认会跳到下一个单词开头行为通常一样但如果对象恰好处于特殊位置比如行尾的单词dw可能删不干净空格、daw则一次到位。更重要的是diw它只删除单词本身不触碰空格。这在需要保留空格的场景例如批量删除某些词、但不破坏排版时特别灵巧daw 删除单词后面的空格适合正常文本 diw 只删除单词适合保留空格、缩进的情况6.3 文本对象与d、c、y、v的搭配文本对象绝不是d的专利。它几乎可以和任何操作符搭配caw 删除一个单词并开始输入 yiw 复制当前单词到寄存器 viw 选中当前单词 da 删除双引号及其中的内容 ci) 修改括号内的内容我最常用的是ci)或者ci处理参数列表和字符串特别快。比如函数调用someFunction(a, b, c) 光标在 a 上按 ci) 后输入 x, y, zESC 得到 someFunction(x, y, z)这类操作本质上就是“把括号内清空再重写”不用手动处理左右括号的收尾稳定性高得多。6.4 绕围栏操作da)为什么不常用但一旦用就回不去文本对象里的a变体除了单词的daw围栏相关的也值得练da( 删除括号及括号内全部内容 di( 只删除括号内内容保留括号 da 删除双引号及内容 di 只删除引号内内容日常编码里我大量使用di(、di来修改函数参数和字符串字面量只有当你确定整个括号都不想要时才用da(把括号一起带走。User_04.txt》里没有展开到这么细但它讲的文本对象语法正是这些命令的推导基础。建议你拿到文本对象概念之后立刻在代码里试一组ci(、da、viw很快就能体会到“按语义编辑”和“按字符编辑”的差别。7. 大小写切换、行合并、缩进微调被忽视的小动作集7.1~切换大小写比你想的更适合批量操作~命令切换光标下字符的大小写光标在 f 上按 ~f 变 F 光标在 F 上按 ~F 变 f和r、.,一样~也支持计数和重复。处理一组不规范命名的变量时配合., 能快速统一大小写风格光标移到第一个需要改的字符 按 ~ 移到下一个位置 按 .这个动作集在边读边改代码时特别好用因为不需要进入插入模式改动范围又小撤销也非常精准。7.2J把多行合并成一行J命令把当前行和下一行合并成一行并保留一个空格作为连接符。line one line two 光标在第一行按 J 得到 line one line twogJ则是不加空格直接合并适合拼接不想有多余空格的文本片段。手册把J归类为“微小改动”但它其实非常适合整理 markdown 列表、折叠长文本、清理错误换行等场景。我之前处理过一份被导出软件强行换行的文本几百行每句话被拦腰截断。处理思路就是反复移动光标按J合并借助j移动和.重复不到一分钟就理顺了。7.3与缩进不是扭来扭去的空格把当前行右缩进一个shiftwidth左缩进。注意它们操作的是整行不是光标位置。光标在代码行上按 该行向右缩进 按 恢复原样这个命令在手动调整缩进层级时非常顺手。如果是按了v进入可视模式再按可以对选中的多行统一缩进。User_04.txt用的是它配合J和~作为一组“格式化小操作”来讲的我觉得这三个命令放到一起练效果最好。7.4 综合小例子5 秒钟整理一段混乱文本把这一节内容串起来举一个实际场景。假设你有一段文本被缩进搞乱了、大小写不统一、还有多余换行hello World foo Bar BAZ qux目标是把它们整理成一行并且每个单词首字母小写。操作路径可以是1. 光标移到第一行首 2. J合并到下一行 3. .重复合并 4. 依次移动每个大写字母按 ~ 切换为小写 5. 按 去掉多余缩进虽然步骤看着多但每一步都是微小操作整体非常快。这里的关键是“用组合而不是宏去处理小规模任务”也是User_04.txt通过大量小例子反复传递的思路。8. 我的实操建议与几个从坑里爬出来的心得8.1 先把d、c、y、p的语法树刻进脑子整篇User_04.txt读下来我最大的收获不是某个具体命令而是“操作符 动作 / 文本对象”这个语法意识。它让我的 Vim 使用从“记住几十个命令”升级成“按规则生成任意命令”。我的建议是别急着去背ciw、da(、di这些组合先在自己常用的文件格式里把d、c、y各配几个动作和文本对象练成条件反射。8.2 练习时故意用“最小命令”而不是“能用的命令”日常工作中我们总倾向于用最顺手的老方法比如改字符就是i然后退格重打。没错这样也能完成但你永远不会进步。我练熟r、x、~、ciw、daw的方式很笨连续两周强制自己遇到任何小改动都用这些命令哪怕一开始慢。两周后手就记住了。之后写代码时“改一个参数名”“删一个单词”“合并两行”都变成下意识动作不再打扰思路。8.3 撤销粒度是大坑早重视早受益很多人用 Vim 久了还是被撤销问题困扰根因通常是“进入插入模式后一口气写太长”。我在前面提过多次的“步进式修改”——写一小段就u退出插入模式再继续——看似多此一举实际是帮你把撤销历史切成好用的小块。等到改错三行内容想局部回退时你会感谢当初这个习惯。8.4 最后一个建议每次只改一个对象然后停下来检查我会刻意遵循“一次只做一个微小改动移动确认再改动”的节奏。这听起来慢但 Vim 的效率从来不是靠手速而是靠精准每次少量修改配合.快速重复配合u快速撤销。持续这样操作错误率会显著下降因为你的每次操作都有明确的边界和可回退的余地。这也是我认为User_04.txt名为“微小改动”、实为整本手册灵魂的原因。它教会你的不是某个命令而是一种编辑态度微小、精确、可重复、随时可反悔。把这个态度带进日常使用Vim 才真正开始变得好用。