移动·行与文件:大范围跳跃
学习目标
- 建立行间与文件级的移动能力:不再用滚轮「逛」到目的地,而是报地址直达
- 掌握相对行号思维:5j / 3k 一步跳 N 行
- 掌握文件三键:gg(开头)、G(结尾)、{n}G / :n(直达第 n 行)
- 掌握结构级移动:段落 { }、配对符 % —— 按代码的结构跳,不按行号跳
- 会用书签 ma + 'a / `a 和跳转表 Ctrl+o / Ctrl+i 走回头路
- 了解窗口地标 H M L 与滚动键 Ctrl+d/u、zz 的分工
1. 行内自由之后,新的痛
第 2 章毕业时,你在一行之内已经两键直达任何位置。但真实代码是几百行的文件:光标在第 30 行,你想去第 55 行看看那个函数,再回 30 行继续写 —— 熟悉的剧本上演:右手摸向鼠标,滚轮哗哗滚,眼睛扫过中间二十几行不知所云,到了地方改两笔,又哗哗滚回来。这趟旅程里你的眼睛当了一次「人肉传送带」,而这正是 Vim 诞生的年代里 Ken Thompson 要解决的核心问题之一:光标移动不应该消耗注意力。
先分清两种动作:「滚动」和「到达」。滚动是浏览 —— 你想看看中间有什么,适合鼠标滚轮和 Ctrl+d/u;到达是通勤 —— 你已经知道要去哪,只是要走过去,适合本章的主角们。90% 的日常移动是「到达」,而多数人把它们全办成了「滚动」,痛就痛在这。本章给你三件套:报行号(5j、42G)、认结构({ }、%)、走回头路(书签、跳转表)。
还有一条贯穿全章的伏笔:这些移动键不仅是「去」的门票,它们同时是编辑语言的名词 —— 第 4、5 章你已经见过 dt, 和 diw,本章的 % 也能当名词(d% 删整个块)。移动学得越透,后面动词的射程就越远。
2. 相对行号:把 j/k 变成传送门
j/k 一次一行,去五格之外就得连按五次 —— 问题不在按键,在于你得自己数。解法是让编辑器替你数:相对行号(relative line numbers)。开启后,当前行显示真实行号,其余行显示「离当前行几步」。想去哪行,读一下它头上的数字,报数,走人:
看演示时注意行号列的变化:每跳一步,所有行号都重算一次 —— 因为「相对」的参照物是你自己。这就是它的哲学:位置不是文件的属性,是你和目标的距离。配合计数前缀,2j、4k 变成「报地址」:眼睛看目标、读距离、手指报数,全程不用心算「55 减 30 等于几」。
两个实用建议:①绝对行号 + 相对行号混用是主流配置(当前行给绝对号,方便和报错信息、同事口头引用对齐;其他行给相对距离,方便跳)—— 播放器里演示的就是这种,Vim 里叫 set number relativenumber,IDE 的开启方法见本章 IDE 备注;②距离超过一屏就别数了 —— 相对行号只服务「看得见的距离」,更远的目标交给下一节的文件三键。
3. 文件三键:gg、G 与 {n}G
超出视野的距离,思路从「数步数」切换到「报门牌」:gg 直奔文件第一行,大写 G 直奔最后一行,{n}G 精确直达第 n 行(命令行版是 :n 再回车,效果相同):
gg 的来历顺带一提:goto —— g 是「扩展前缀」,g_、gU、gJ 都是它带的词,这个家族你已经很熟了。{n}G 的最高频场景是跟着报错跳:编译器说第 42 行有错、测试输出指向第 118 行 —— 眼睛读到数字,手上报 42G,两秒内人到现场,这是 Vim 用户的标志性动作。另有两个顺手键记一眼:当前行之上/之下第一个非空行用 - / +(少用但偶尔顺手),行内定位交给第 2 章。
注意 G 落地时默认落在该行第一个非空白字符上(受 startofline 选项影响,默认开)—— 所以跳过去通常正好落在代码上而不是缩进空格里,很贴心。而 gg 同理会落在第一行首个非空白字符(演示里第一行顶格,所以是第 0 列)。
顺带一个和 IDE 的对照:两个 IDE 都有「转到行」对话框(VSCode 的 Ctrl+g,IDEA 的 Cmd+l),功能上与 {n}G 等价 —— 区别在交互节奏:对话框要等弹窗、要按回车,Vim 的版本是盲打的,眼睛全程不用离开代码。这也是本教程反复出现的主题:同一个功能,Vim 的形态永远更贴着手指。日常跟着编译报错、测试栈帧跳行时,把 120G 练成肌肉记忆,比每次开「转到行」快出一截。
4. 段落移动:{ 与 }
报行号适合「我知道门牌」,但更多时候你知道的是结构:「下一个函数」「上一段配置」。} 跳到下一段、{ 跳回上一段 —— Vim 对「段落」的定义和第 4 章的 ip 完全一致:空行分隔的一坨连续文本:
两个细节:①落点是分段的空行本身,不是下一段的第一个字符 —— 想直接进段内干活,补一个 j 或 w 就好,不必较劲;②{ } 同样吃计数,2} 跳过一段。代码文件几乎都用空行分隔逻辑块,所以这对键的实际体验是「按函数/逻辑块翻页」—— 调试时快速浏览文件结构,比滚轮高效一个量级,而且它跳的是语义边界,不会停在半截逻辑中间让你分神。
同族还有一对句子键 ( )(按英文句号分句)。在代码里句子边界几乎没有意义(分号不是句号),写 Markdown 或文案时才偶尔有用,知道有这对键即可,不必练。真正值得练的结构键是下面这位。
5. %:配对符任意门
把光标放到 (、{、[(或它们的闭括号)上,按 % —— 直达配对的另一半。多深、多远、跨多少行都无所谓:
% 的日常用法有三层。第一层,看结构:光标在函数的 { 上按 %,一眼看到函数结尾在哪行,再按一次弹回来 —— 「这个函数多长」两键就有答案。第二层,配对检查:改完一堆括号,从最外层 % 一下,落点符合预期说明配对没坏;落点诡异说明有括号漏了或多了,这是比肉眼数括号可靠得多的自检。第三层,当名词:d% 从光标删到配对符(含两端)—— 想删掉整个 if 块、整层包装?光标放到 { 上,d%,完事。它和第 4 章的 da{ 是近亲:区别是 % 要求光标先站在括号上,而对象只要求在块内 —— 现场哪个顺手用哪个。
6. 书签:m、' 与 `
「到达」解决了一半,另一半是回来。场景:你在第 200 行改代码,需要去文件头查一个常量的定义 —— 查完怎么回 200 行?再 200G 一次?行号还可能已经变了。正确工具是书签(mark):出发前钉个钉子,回来时一键召回。
语法:m{字母} 设书签(如 ma),'{字母} 跳到书签所在行首,`{字母} 连行带列精确还原。设书签时屏幕毫无提示 —— 这是它被低估的原因之一,人们不信任看不见的操作,但 m 是 Vim 里最可靠的静默操作之一。命名建议:用有含义的字母,mb(begin)、me(end)、mt(todo)比随手 ma 三天后还记得住。
两个进阶知识点先混个脸熟:①小写 a–z 是本文件书签,大写 A–Z 跨文件且持久(重启也在);②还有一对系统自动维护的特殊书签:''(两个单引号)跳到上次跳转出发的地方 —— 在两处来回横跳时它是零成本往返门,试试 G 之后按 ''。
书签最经典的用工场景是「对照改码」:接口定义处设 mi(interface)、调用密集区设 mc(calls),写实现时 'i 看一眼签名、'c 回战场 —— 两三个字母就是你的私人分屏。再比如 code review:从头部意见区设 mr,一路往下改,改完 'r 回去对清单,不多不少正好够用。
7. 窗口地标 H M L 与滚动家族
H(High)、M(Middle)、L(Low)分别跳到可见窗口的第一行、正中、最后一行。注意它们的坐标系是屏幕而不是文件 —— 不管文件滚到哪,三键永远落在你眼前这屏的三颗地标上:
使用频率上 H M L 属于二线键(有 {n}G 和相对行号在,垂直直达很少缺工具),但两个场景很好用:①翻页/搜索后先按 M 定锚再观察四周;②配合 d 家族吃射程 —— dH 删到窗口顶、dL 删到窗口底(「这一屏的下半部分不要了」的裸奔说法,第 7 章可视化模式会给更稳的替代)。
滚动家族一句话扫清(演示器窗口固定,自己到 IDE 里感受):Ctrl+d / Ctrl+u 向下/向上滚半页(最常用的浏览键,手指不用离开主键区);zz 把当前行滚到屏幕正中,zt 顶到最上,zb 压到最下 —— z 家族不移动光标,只挪屏幕。高频组合:长行/长函数里改完一处 zz 把战场居中;% 跳到块尾后 zz 把结局拉到眼前。至于整页的 Ctrl+f / Ctrl+b,和 PageUp/PageDown 同义,交给个人口味。
8. 跳转表:Ctrl-o 与 Ctrl-i
书签要手动设钉,适合「我知道会回来」的地方;更多时候你只是逛着逛着想原路返回 —— 这需要自动记录的历史。Vim 维护着一张跳转表(jumplist):每次大跳(gg、G、{n}G、%、'a、搜索命中……)都会登记一条。Ctrl+o 沿表后退,Ctrl+i 前进 —— 和浏览器的后退/前进是同一个思想:
把它和书签分工记住:书签是「存档点」,跳转表是「浏览历史」。两三步之内回得来,用 Ctrl+o 连按;要固定往返于两个工作点,用 ma 更稳(跳转表会被后续跳转冲,书签不会)。跳转表在 IDE 里还有个重量级队友:第 12 章会讲 gd(跳到定义)—— 跳过去看一眼源码,Ctrl+o 回来,这对组合是「查证-回岗」工作流的地基,而地基本章已经打好。另外注意:小步移动(j、w、f)不进跳转表 —— 历史只记大跳,不会被碎步刷屏,这个设计体会一下会很佩服。
9. 移动篇毕业:去哪儿,用什么
两章移动课到此收官,把全部工具压进一张决策表 —— 以后每当你伸手去摸鼠标,先扫一眼这张表:
| 目的地 | 按键 | 一句话备注 |
|---|---|---|
| 同一行内某处 | fx / w / $ … | 第 2 章:两键到达 |
| 邻近几行 | 3j / 2k | 配相对行号,读数字报数 |
| 已知行号 | 42G 或 :42 | 报错、测试输出指路专用 |
| 文件头 / 尾 | gg / G | 两端书挡 |
| 下一段 / 上一段 | } / { | 按逻辑块翻,落在空行上 |
| 配对符另一半 | % | 光标先站上括号;还能 d% |
| 屏幕顶 / 中 / 底 | H / M / L | 坐标系是屏幕,不是文件 |
| 回来(临时) | Ctrl+o | 浏览历史后退,Ctrl+i 前进 |
| 回来(固定) | 'a / `a | 先 ma 设钉;` 连列一起还原 |
| 只是想看看 | Ctrl+d / Ctrl+u | 浏览才滚动,到达别滚动 |
最后给一个自测标准,达标就算移动篇毕业:任何一次光标移动超过 5 行,你的手都没有离开主键区;任何一次「去而复返」,你都有意识地选了 Ctrl-o 或书签而不是重新找。做到这两条,第 5 章的语法在你手上就有了飞毛腿 —— 编辑语言的名词库,至此齐装满员。
10. 每日训练计划(30 分钟 × 3 天)
| 天 | 时间盒 | 内容 | 通过标准 |
|---|---|---|---|
| 第 1 天 | 0–10 分钟 | 开相对行号;重放演示 1–2,读 §1–§3;靶场里 10 组「读数字 → 数字 j/k」 | 不再连按 j 超过两次 |
| 10–30 分钟 | 练习 1:报数跳 | 10 组 8 组一步命中 | |
| 第 2 天 | 0–10 分钟 | 重放演示 3–5,读 §4–§6;真实文件里 }{{} 和 % 各巡一圈 | d% 删块一次成功 |
| 10–30 分钟 | 练习 2 + 练习 3 | 书签巡逻三轮不出错 | |
| 第 3 天 | 0–10 分钟 | 重放演示 6–7,读 §7–§9;把决策表抄进便签贴屏幕边 | 能默写决策表 8 成 |
| 10–30 分钟 | 练习 4:盲测毕业考 | 10 题对 7 题,移动篇毕业 |
11. 如果本章只记住三件事
- 到达别滚动:知道去哪就报地址 —— 3j(相对行号)、42G(行号)、}(下一段)、%(配对符);滚轮和 Ctrl+d/u 只留给「随便看看」;
- 回来有专门工具:临时回程连按 Ctrl+o,固定往返设书签 ma —— 别用重新找的方式回去;
- 移动键都是名词:今天学的 % 明天就是 d% 的射程 —— 移动词每多一个,动词的火力就翻一倍,这是「编辑语言」的复利。
移动篇两章到此完成,你的光标已经能在文件里飞行。下一章进入全站核心:给「东西」起名字 —— 文本对象。
练习
练习 1:报数跳(10 分钟)
靶场开好相对行号,光标放文件中部。心里选一个目标行 → 瞄一眼它头上的相对数字 → 数字+j 或 k 一步命中。10 组。然后升级:目标定在当前窗口外(看不见的行),改用 行号G 或 :行号(先开绝对行号或用状态栏行号)。通过线:10 组里 8 组不用按第二次。
练习 2:书签巡逻(10 分钟)
在一个 100 行以上的真实文件里:ma 在文件头附近设点、mb 中部、mc 尾部。然后按 'c → 'a → `b(注意第三个用反引号,感受连列还原)循环巡逻五轮。再玩 G + Ctrl+o:跳到文件尾,连按 Ctrl+o 一路退回出发地,再用 Ctrl+i 前进回去。体会「存档点」和「历史」的手感差异。
练习 3:% 往返工坊(10 分钟)
找一段嵌套两层以上的代码:①光标 f( 送上一个内层括号,% 往返 10 次;②光标放到函数的 { 上,% 看结尾、% 弹回,5 组;③d% 删掉一个 if 块,u 悔回;4j 挪到另一层再 d%,u。通过线:能说出 d% 和 da{ 对光标位置要求的区别(前者要求站在括号上,后者只要求在块内)。
练习 4:盲测毕业考(10 分钟)
对真实代码,10 个任务先说按键再看答案:①去文件第一行 ②去最后一行 ③去第 42 行(说出两种按键)④去下一段 ⑤回上一段 ⑥光标在 { 上,看这个块在哪结束 ⑦删掉光标所在的整个 if 块(括号要求?)⑧设书签并一键回岗 ⑨把当前行滚到屏幕中央 ⑩沿历史后退三步。答案:gg / G / 42G 或 :42 / } / { / % / d%(光标需在 { 上;在块内则用 da{)/ ma…'a / zz / Ctrl-o 连按三次。10 对 7 毕业。
常见陷阱
VSCode / IDEA 差异
VSCode(VSCodeVim)
- 相对行号:设置项
editor.lineNumbers改为relative(设置界面搜 "Line Numbers");当前行会自动显示绝对号,正好是推荐的混用形态 - Ctrl+d:VSCode 原生是「添加下一个匹配为多光标」;装 VSCodeVim 后默认接管为半页滚动,多光标用 gb(第 7 章)。若想还原原生行为,在 Keyboard Shortcuts 里自己仲裁
- %、HML、zz、书签、Ctrl+o/i 跳转表:VSCodeVim 全部原生支持,照 Vim 语义用
- VSCode 自己也有「后退/前进」导航(Go 菜单),但它与 Vim 跳转表历史不互通 —— 用 Vim 键就认 Vim 的表,别混着按
IntelliJ IDEA(IdeaVim)
- 相对行号:在
~/.ideavimrc加set relativenumber(与已有的set number同时开即混用形态);IDEA 编辑器设置里也有原生 Relative line numbers 选项 —— 建议用 IdeaVim 的一侧,行为和 Vim 文档一致 - Ctrl+d/u:mac 上 IDEA 的 Cmd+d 是复制当前行(与 Vim 无关);Ctrl+d 由 IdeaVim 接管为半页滚动。若个别键不生效,是
sethandler仲裁问题,第 12 章配置篇统一处理 - 书签:IDEA 自带书签(F11)与 Vim 的 m 书签互不相通,选一套用即可;IdeaVim 的 A–Z 大写书签同样支持跨文件
- Ctrl+o 在 IDEA 里原生是「回到上一个编辑位置」—— IdeaVim 激活后走 Vim 跳转表语义,覆盖之;想用原生的可从菜单 Navigate › Back 进入
本章速记
| 按键 | 作用 | 按键 | 作用 |
|---|---|---|---|
| 3j / 4k | 按相对行号跳 N 行 | % / d% | 配对符往返 / 删整块 |
| gg / G | 文件第一行 / 最后一行 | ma + 'a | 设书签 / 跳回(行) |
| 42G / :42 | 直达第 42 行(两种) | `a / '' | 书签(带列)/ 上次位置 |
| } / { | 下一段 / 上一段(空行分界) | Ctrl+o / Ctrl+i | 跳转表后退 / 前进 |
| H / M / L | 窗口顶 / 中 / 底 | Ctrl+d/u / zz | 半页滚动 / 当前行居中 |
一句话心法:到达报地址(行号、段落、配对符),回来靠钉子(书签)和历史(Ctrl-o)—— 滚动只留给浏览。