Vim 修炼场
CHAPTER 11 · 进阶篇 外

多文件与窗口:buffer 思维与分屏导航

预计阅读 25 分钟(含练习约 1 小时)· 前置:第 3、9 章 · 本章演示 4 个

学习目标

  • 建立 Vim 多文件的三层心智模型:缓冲区(文件在内存的分身)、窗口(取景框)、标签页(桌面)—— 谁装内容、谁管画面,一张表分清
  • 掌握缓冲区流::ls 看清单、:b{n} 按号切、:e 开新档,以及 Ctrl+^ 两文件一键乒乓
  • 学会分屏::sp / :vs 与 Ctrl+w 全家(选窗、轮换、只留此窗、均分),并理解分屏共享同一缓冲区
  • 认识标签页的真实定位(布局工作区,不是文件列表)与 quickfix 清单驱动导航(:vimgrep + :cn)
  • 划清「IDE 管找,vim 管改」的分工:文件跳转、符号跳转、gd 定义跳转交接给 IDE,vim 接手落位后的加工

1. 单文件的尽头:三个概念先分家

前十章的所有功夫都在一个文件里。真实的工作不是这样的:改一个函数,要先看它的定义、再对照调用处、再瞥一眼配置文件、最后回到测试 —— 写代码的一半时间花在文件之间穿梭。鼠标用户穿梭靠点标签、点分屏、点搜索框;Vim 给了一套自己的词汇,而这套词汇最劝退新人的地方是:它把「文件」拆成了三个概念,很多人用了多年都没分清。

一次分清,终身受益:缓冲区(buffer)是文件在内存里的分身 —— 你真正编辑的对象,每个打开的文件对应一个;窗口(window)是取景框 —— 屏幕上的一块玻璃,透过它看某个缓冲区,几块玻璃可以看同一个缓冲区;标签页(tab)是桌面 —— 一整屏取景框的编组,换个桌面换一整套布局。一句话记住:内容住在缓冲区里,窗口和标签页都只是看它的方式 —— 关掉窗口和标签页,文件毫发无伤,缓冲区里随叫随到。

IDE 用户的直觉正好可以翻译过来:VSCode / IDEA 里每打开一个文件也是一个「编辑器实例」,标签栏显示的是你看过哪些 —— Vim 的缓冲区就是这些实例的集合,只是它默认不给你标签栏,你要用命令(或插件)去列出、去切换。这个「默认不给」是哲学不是吝啬:文件一多,标签栏必然溢出,而 :ls + :b 加补全的效率不受文件数影响 —— 先把缓冲区思维建立起来,再谈要不要标签。

Vim 社区里长期并存两大流派,知道流派的存在比站队更重要:缓冲区流派全部文件待在缓冲区里,切换靠 :b 与 Ctrl-^,屏幕永远干净,适合同时开二三十个文件的重度重构;标签页流派每个文件一个 tab,视觉直观、可点击,适合同时只碰三五个文件的日常开发。终端 Vim 用户偏前者,IDE 插件用户偏后者 —— 因为 VSCode / IDEA 的标签栏本来就好用,gt/gT 又直接映射过去。务实的选择是混合:三五个常用文件留在标签栏里当「书签」,大量偶尔一瞥的文件用 :b 随开随切、不开标签,两边各取所长。

2. 缓冲区::ls 看号,:b 按号切

缓冲区流的工作节奏极简::ls 列出所有缓冲区(每行一个号 + 文件名 + 状态字母),:b{n} 按号切换,:e 文件名(edit)打开新档 —— 文件名可以只打前几个字符按 Tab 补全。看一遍完整往返:

演示里藏着一个容易错过的细节::b1 切回 main.js 时,光标还停在你离开时的位置 —— 每个缓冲区各自记着自己的光标、滚动位置,甚至各自的撤销历史。这就是缓冲区流的体验底座:文件之间切换不是「重新打开」,是「回到原地」,心理成本近乎零。两个实用补充:①:b 后面也可以接文件名片段(如 :b util,Tab 补全),比记号更顺手;②:bd(bdelete)把缓冲区从清单里真正请出去 —— 文件不再占位,但注意未保存的修改会拦你(§7)。

看懂 :ls 清单里的状态字母,是缓冲区流的「识字课」:

字母含义说明
%当前缓冲区光标所在的窗口正看着它
#交替缓冲区(上一个)Ctrl-^ 的往返对象,§3 的主角
a活跃正显示在某个窗口里;h 则是隐藏 loaded 未显示
+有未保存修改关它之前 Vim 会拦 —— 见 §7 与陷阱一
-不可修改只读文件之类,:w! 才能强写

3. Ctrl-^:两文件乒乓

多文件编辑的最高频形态其实是就两个文件:一个接口一个实现、一个模板一个数据、一个测试一个源码。这种「对照抄代码」的场景,Vim 给了专用键:Ctrl+^(Ctrl 加数字 6,也叫 Ctrl-6),在当前缓冲区与交替缓冲区(# 号那个,也就是你上一个待过的文件)之间一键往返 —— 演示 1 的后三步就是它:切过去、切回来、再切过去,比 :b{n} 省一半按键,而且不用记号。

命令行形态是 :b#,与按键等价。要留意「上一个」是动态的:如果你从 A 切到 B 又切到 C,此刻 Ctrl-^ 在 C 与 B 之间乒乓(A 变成了更早的历史)—— 三文件以上的往返,老实 :ls 看号或 :b 名字 补全。一个 IDE 翻译:VSCode 的 Ctrl+Tab、IDEA 的 Cmd+e(最近文件)是同类思想,IDE 插件环境下两边任选,手感都顺。

4. 窗口::sp / :vs 与 Ctrl-w 全家

窗口解决「想同时看两处」:上下分屏 :sp(split),左右分屏 :vs(vsplit)。分屏后光标留在原来的窗口,焦点(哪个窗口接收按键)靠 Ctrl+w 前缀调动 —— 它是窗口世界的「名字空间前缀」,像 " 之于寄存器、g 之于扩展命令:

这个演示最重要的画面不在按键里,而在 gg 那一步:在下窗口加的字,上窗口同步出现 —— 因为两个窗口透过两块玻璃看的是同一个缓冲区。想两侧看不同文件?分屏后在下窗口 :e 另一个文件,或直接 :sp 另一个文件 一步到位。窗口键位表(都以 Ctrl-w 开头):

按键作用按键作用
h j k l按方向选窗w / W轮换焦点(正 / 反)
o只留当前窗口c关当前一扇窗(= :q)
s / v再分一扇(水平 / 垂直)_ / |当前窗纵向 / 横向最大化
=所有窗口恢复均分+ - > <微调窗口尺寸

经验法则两条:①分屏是临时脚手架 —— 对照时 :sp 立起来,用完 Ctrl+w o 一键拆干净,别让屏幕长期挂着五六扇窗(焦点迷路是分屏最大的痛);②分屏数量以两到三扇为限,要同时看更多,该上的是标签页或 IDE 的多显示器,不是第八扇窗。

值得专门练熟三个分屏场景。一是接口与实现对照:上窗看类型定义或函数签名,下窗写实现 —— :sp 文件名 一步开两个文件,签名里的参数名抬头可见,不用来回切。二是长文件头尾对照:同一个文件 :sp 分两扇,上窗看函数开头的变量声明,下窗改函数尾部的逻辑 —— 这正是「同一缓冲区两块玻璃」设计的最大红利,普通编辑器要靠迷你地图凑合。三是改一处、验一处:左窗改测试,右窗跑代码,或左窗改模板、右窗看数据。三个场景的共同点是「眼睛在两处之间高频往返」—— 凡是要回头看的,就该并排放,而不是靠记忆。

5. 标签页:一桌多屏,不是文件列表

标签页(tab)在 Vim 里的语义与浏览器不同,这点必须先讲清:浏览器的 tab ≈ 一个文件,而 Vim 的 tab ≈ 一整桌窗口布局 —— 每个标签页里可以有自己的一组分屏。它真正的主场是「工作区切换」:桌一是「前端调试布局」(左边组件右边样式),桌二是「写文档布局」(单窗全屏),gt 一键换桌。当然,每桌放一个文件的简单用法也完全成立:

键位速记:gt / gT 下一个 / 上一个标签页(循环),{n}gt 直达第 n 个,:tabs 看清单,:tabe 文件 新开,:tabc 关闭,:tabo 只留当前。与缓冲区的分工一句话:缓冲区是「开着哪些文件」(内容层),标签页是「怎么摆着看」(布局层) —— 关掉标签页文件还在缓冲区(演示最后强调的),反过来关缓冲区它在所有窗口里消失。日常多文件主力是缓冲区 + Ctrl-^;标签页留给「几套布局来回切」的场景;把二十个文件堆成二十个标签页当文件列表用,是最常见的用法错位(陷阱三)。

6. quickfix:清单驱动的导航

最后一层导航不按「文件」组织,按「问题」组织。quickfix 是 Vim 内置的问题清单:任何「一组文件位置」—— 搜索结果、编译错误、替换预览 —— 都可以装进这份清单,然后 :cn(next)逐条跳转。装东西最常用的是 :vimgrep:

完整工作流四步::vimgrep /TODO/ *.js 收清单 →(可选):copen 打开清单窗(分隔在底部的可导航列表)→ :cn / :cp 逐条消化 → :cclose 收窗。清单窗本身是个特殊缓冲区:里面 jk 移动、Enter 跳到光标那条,按 Enter 后焦点自动回代码窗 —— 想看清单就 :copen,想跳就 :cn,两套入口随意混用。除搜索外,它的另一大来源是编译输出(:make 后错误自动进清单,:cn 逐个错误跳),所以老 Vim 用户修编译错误从不看日志翻行号 —— 全在 quickfix 里跳。IDE 对照:VSCode / IDEA 的 Problems 面板、搜索结果的逐条跳转(F8 / Enter),就是图形化的 quickfix;在 IDE 插件里 :vimgrep 可用,但全局搜索交给 IDE 原生(Cmd+Shift+f)通常更快 —— 这正是 §8 分工哲学的又一例。

quickfix 与第 10 章的宏是天作之合。清单里几十条同类的活(几十个 TODO 要加同一种标记、几十处旧 API 调用要同款改造),逐条「改 + :cn」未免枯燥 —— 录一个「加工 + :cn」结尾的宏(比如 qa 加工 Esc 然后命令行 :cn 回车 q),然后 30@a:宏每执行一轮就改一条、自动跳下一条,清单消化变成了连发。注意这正好满足宏的三纪律:结尾自动推进(靠 :cn)、全程相对导航(quickfix 记着位置,不依赖光标绝对坐标)、连发前先试一发 —— 第 10 章的设计原则在跨文件场景里原样生效。

7. 保存与会话:批量收尾

多文件之后,保存也要批量版::w 存当前,:wa(write all)存全部,:wqa(或 :xa)存全部并退出,:qa 全部退出。有一条护栏必须知道:有未保存修改(清单里的 + 号)的缓冲区,会拦住 :q / :qa —— Vim 提示你确认,这是防止半天工作一键蒸发;真想丢弃,用带感叹号的 :qa!(全部不保存退出)或 :e!(重读文件、丢弃本文件修改)—— 感叹号是「我知道我在干什么」的显式声明。

顺带一个影响体验的选项:隐藏缓冲区(set hidden)。默认情况下,带着未保存修改的缓冲区不许切换(必须先 :w 或 :q)—— 老派但烦人;开了 hidden 就能随便切,修改跟着缓冲区走,退出时统一收尾。终端 Vim 推荐开;IDE 插件则各有默认(VSCodeVim 跟随 VSCode 的自动保存体系,IdeaVim 通常也放行),体感上「切换不被保存卡住」在 IDE 里基本是默认事实 —— 这也是 IDE 与终端 Vim 少有的、IDE 更体贴的地方。纪律一句话:改完就 :w(或交给 IDE 自动保存),别让 + 号积少成多。

8. IDE 分工:「找到」靠 IDE,「改」靠 Vim

在 IDE 里用 Vim,最重要的战略判断是分清两件事:定位(去哪)与编辑(改什么)。定位这块,IDE 的语义引擎不可替代 —— 文件名跳转 Cmd+p、符号跳转 Cmd+Shift+o、定义跳转 Cmd+b(Vim 键 gd,IdeaVim 亦可)、引用查找、调用层级 —— 这些都基于代码索引,vim 的 :vimgrep 纯文本搜索比不了。把它们交给 IDE,一个键都不用抢。

而定位之后的加工,才是前十章功夫的主场:跳到定义后 ciw 改名、da( 拆参数、宏批量收拾、:s 区域替换 —— IDE 的编辑器在这些操作上完全比不过 vim 层。组合起来的节奏是:Cmd+p 到文件 → Cmd+Shift+o 到函数 → gd / Cmd+b 看定义 → vim 键加工 → Cmd+e(IDEA 最近文件)/ Ctrl+^ 回来继续。判断某个动作归谁管,只问一句:它需要「理解代码」吗?需要就是 IDE 的;只是「按键与文本」就是 vim 的。想通这一点,IDE 与 vim 不再打架,而是流水线上的两站。

9. 决策表:跨文件场景用哪个

场景首选备注
就两个文件来回对照Ctrl+^不用记号,一键乒乓
开着的文件多了,来回切:ls + :b 名字(Tab 补全)缓冲区流,数量不敏感
想同时看两处(同文件或两文件):sp / :vs两三扇为限,Ctrl+w o 收场
几套窗口布局来回切(调试 / 写文档)标签页 :tabe + gttab 是布局不是文件
按内容找一批位置逐个处理:vimgrep + :cnIDE 里全局搜索 + 结果跳转同构
按语义找(定义 / 引用 / 文件 / 符号)IDE:Cmd+p / gd / Cmd+bvim 不抢这滩活(§8)
收尾保存:wa / :wqa+ 号缓冲区会拦 :qa,见陷阱一

10. 每日训练计划(30 分钟 × 2 天)

天时间盒内容通过标准
第 1 天0–10 分钟重放演示 1–2,读 §1–§4;开两个真实文件练 :ls / :b / Ctrl-^ 二十个来回Ctrl-^ 不假思索
10–30 分钟练习 1 + 练习 2:b 补全与 Ctrl-w 选窗不看备忘
第 2 天0–10 分钟重放演示 3–4,读 §5–§9;给项目跑一遍 :vimgrep /TODO/ 消化三条:cn 节奏成型
10–30 分钟练习 3 + 练习 4(盲测)10 题对 7 题,本章毕业

11. 如果本章只记住三件事

  1. 内容住在缓冲区里:窗口和标签页只是取景框 —— 关掉它们文件无恙;:ls 看号、:b 切换,多文件主力是缓冲区流 + Ctrl+^ 乒乓;
  2. 分屏共享同一缓冲区::sp 两块玻璃看一处,改一动二;Ctrl+w 前缀管所有窗口事(w 选窗、o 清屏、= 均分);
  3. 找到靠 IDE,改靠 vim:文件 / 符号 / 定义跳转交接给 IDE,落位后的加工全用 vim 键 —— 分工不是妥协,是流水线。

至此「进阶篇」全部收官。下一章把整套武功装回 IDE:VSCodeVim 与 IdeaVim 的推荐配置全文、特色命令(gd、surround、多光标)、键位冲突的仲裁原则。

练习

练习 1:缓冲区点名(10 分钟)

在 IDE 里打开一个多文件项目,任选 5 个文件依次 :e 打开;然后:①:ls 认一遍号与状态字母(找到 %、#、a);②只用 :b{n} 按指定顺序访问 5 个文件(如 3→1→5→2→4),每个文件里 G 再 gg,体会「光标原地记忆」;③挑两个文件用 Ctrl+^ 乒乓 10 个来回;④:b ut+Tab 体验名字补全。通过线:切文件全程不碰鼠标、不看标签栏。

练习 2:分屏施工(10 分钟)

①:sp 上下分屏,Ctrl+w j 到下窗,G 看文件尾;②在下窗改一行,Ctrl+w w 回上窗验证同步出现;③:vs 再分一扇,数清焦点在哪;Ctrl+w h/l 左右走;④Ctrl+w _ 纵向最大化,再 Ctrl+w = 均分;⑤Ctrl+w o 一键清屏;⑥:q 关窗与 :qa 全关各试一次。通过线:每次焦点移动都能提前说出会落在哪扇窗。

练习 3:quickfix 消化(10 分钟)

在项目根目录:①:vimgrep /TODO/ **/* 把待办收进清单;②:copen 打开清单窗,看一眼分布;③:cclose 收起,只靠 :cn 逐条跳,每条做一个小加工(行尾加 [ok] 之类),连做 5 条;④:cp 回跳一次验证方向;:cfirst、:clast 各跳一次。通过线:全程不碰鼠标也不看清单窗,仅凭 :cn 的落点就知道自己到了哪。

练习 4:盲测毕业考(10 分钟)

10 题先说答案再看:①列出所有缓冲区 ②切到 3 号缓冲区 ③打开 config.yml ④当前与上一个文件间往返 ⑤水平 / 垂直分屏 ⑥焦点移到下窗口 ⑦只保留当前窗口 ⑧下一个标签页 / 直达第 2 个 ⑨把所有 TODO 收进清单并跳到第一条 ⑩保存全部并退出。答案::ls / :b3 / :e config.yml(Tab 补全)/ Ctrl-^ / :sp 与 :vs / Ctrl-w j / Ctrl-w o / gt 与 2gt / :vimgrep /TODO/ **/* 然后 :cn / :wqa。10 对 7 毕业。

常见陷阱

🕳 带 + 号的缓冲区被 :qa 拦下 / 被 :qa! 蒸发 :ls 清单里的 + 号 = 未保存修改。:qa 遇到它会被 Vim 拦下提示 —— 这是护栏,别嫌烦;而 :qa! 是显式声明「全丢弃」,半天工作真会蒸发。纪律:改完随手 :w,收尾用 :wa / :wqa;在 IDE 里把自动保存开成习惯,这问题从根上消失。
🕳 分屏多了,焦点迷路 屏幕挂了四五扇窗,打字突然「不进编辑区」—— 九成是焦点不在你以为的那扇窗。两招根治:①迷路就 Ctrl+w w 按到回来(两扇窗时就是乒乓);②用完立刻 Ctrl+w o 清到一扇。预防:分屏不超过三扇,临时脚手架用完就拆。
🕳 把标签页当文件列表,开二十个 Vim 的 tab 是「布局桌面」不是「文件抽屉」:堆二十个标签,gt 按到手指抽筋,还占掉一整条屏幕。多文件切换的正确工具是缓冲区(:ls / :b / Ctrl-^,数量不敏感);标签页只留给「几套布局来回切」。IDE 用户特别容易犯这条 —— 浏览器/VSCode 的习惯翻译不过来,记住:内容在缓冲区,tab 只是摆法。
🕳 Ctrl-^ 的「上一个」被顶掉了 交替缓冲区(#)是动态的:A → B → C 之后,Ctrl-^ 在 C、B 之间乒乓,回不到 A —— 有人以为坏了,其实是对象换了。两个以上文件的往返别赌 Ctrl-^,:ls 看号或 :b 名字 补全,确定性第一;真需要「最近访问的历史」,IDE 的 Cmd+e(IDEA)/ Ctrl+Tab(VSCode)是更长的列表。

VSCode / IDEA 差异

VSCode(VSCodeVim)

  • :ls / :b / :e 可用,与 VSCode 已打开的编辑器联动;未保存切换不受限(跟随 VSCode 的脏文件体系),+ 号对应标签栏的圆点
  • :sp / :vs 与 Ctrl+w 系列:分屏由 VSCode 编辑器组实现;也可用原生 Cmd+\ 分屏、Cmd+1/2 选组
  • 标签页:VSCodeVim 的 gt/gT 映射到 VSCode 标签栏(Cmd+Option+←/→ 同义);:tabe 开新标签
  • quickfix 对照::vimgrep 可用,但全局搜索优先 Cmd+Shift+f,问题导航用 F8/Shift+F8;定位三件 Cmd+p / Cmd+Shift+o / gd(= Cmd+b 定义,第 12 章展开)

IntelliJ IDEA(IdeaVim)

  • IdeaVim 的 :ls / :b 与 IDEA 打开的编辑器联动;:e 相对项目根解析路径;未保存切换默认放行(hidden 语义)
  • :sp / :vs 与 Ctrl+w 接 IDEA 的分屏(Split Right / Down);关窗 Ctrl+w c 与原生 Cmd+W 并存,留意误关
  • 标签页即 IDEA 编辑器标签:gt/gT 循环、{n}gt 直达;「最近文件」Cmd+e 是 IDEA 招牌,比 Ctrl-^ 覆盖更长的历史
  • quickfix 对照::vimgrep / :cn 可用;日常优先 Find in Files(Cmd+Shift+f)与 Problems 面板;定义跳转 Cmd+b(vim 键 gd 等价)

本章速记

按键 / 命令作用按键 / 命令作用
:ls缓冲区清单(% 当前 # 上一个 + 未存):b{n} / :b 名字按号 / 按名切缓冲区
Ctrl+^当前 ↔ 上一个 一键乒乓:e 文件打开文件(Tab 补全)
:sp / :vs上下 / 左右分屏Ctrl+w w/hjkl轮换 / 方向选窗
Ctrl+w o / c只留此窗 / 关一扇Ctrl+w _ / =纵向最大 / 全部均分
gt / gT / {n}gt标签页切换 / 直达:tabe / :tabc新开 / 关闭标签页
:vimgrep /词/ **/* + :cn收清单逐条跳:wa / :wqa / :qa!全存 / 存并退 / 弃改退

一句话心法:内容在缓冲区(:ls :b Ctrl-^),窗口标签只是取景(sp/vs + Ctrl-w),找到靠 IDE,改靠 vim,收尾 :wa。