Neovim 快捷键:不用鼠标的移动与跳转
这是 Neovim 的第二部分,专门讨论普通模式下的移动。目标不是背下一张很长的按键表,而是建立一条可靠的路线:到达目标 → 阅读或修改 → 回到原处。
本文默认使用 Linux,并且只介绍 Neovim/Vim 内置的行为。先按 Esc 回到普通模式;下文的按键都在普通模式执行。<C-d> 表示同时按下 Ctrl 和 d。
先记住:移动有不同的“距离”
在长文件里,按 j 很多次通常不是问题的解法。先判断目标离自己多远,再选合适的工具:
| 距离或目标 | 优先按键 | 用途 |
|---|---|---|
| 当前行附近 | h、j、k、l |
左、下、上、右 |
| 一个单词 | w、b、e |
下个词首、上个词首、词尾 |
| 当前行的端点 | 0、^、$ |
行首、首个非空白字符、行尾 |
| 文件中的某个词 | /关键词、n、N |
搜索、下一个、上一个匹配 |
| 文件另一处 | gg、G、{数字}G |
文件开头、结尾、指定行 |
| 看过后返回 | <C-o>、 ``、'' |
跳转历史、精确返回、按行返回 |
| 改过后返回 | `.、g; |
最近一次修改、较早的修改位置 |
数字可以放在多数移动命令前。例如 5j 向下五行,3w 向后移动三个单词,20G 到第 20 行。先把这套“距离感”用熟,比记更多命令更重要。
让光标和屏幕各司其职
j、k 移动的是光标;滚动屏幕时,最好不要每一行都带着光标走。
| 按键 | 作用 | 常见场景 |
|---|---|---|
<C-d> / <C-u> |
向下 / 向上滚动半屏,光标随之移动 | 连续阅读函数或调用链 |
<C-f> / <C-b> |
向下 / 向上翻整屏 | 快速略过大段内容 |
<C-e> / <C-y> |
屏幕向下 / 向上滚动一行,光标不动 | 想看相邻上下文,又不离开当前编辑点 |
H / M / L |
光标跳到当前屏幕的顶部 / 中间 / 底部 | 在已看见的代码中快速换一个阅读落点 |
zz |
让当前行置于屏幕中央 | 到达目标后开始阅读,最常用 |
zt / zb |
让当前行置顶 / 置底 | 需要为下方 / 上方内容留出空间 |
H、M、L 移动的是光标,依据的是当前看得见的屏幕区域;zt、zz、zb 则固定光标,并调整屏幕的位置。一个很顺手的习惯是:搜索或跳转到目标后按 zz。光标不会贴着屏幕边缘,阅读代码的上下文也更完整。
在一行和一个代码块中跳
单词、字符与行内查找
w 到下一个单词开头,b 回到上一个单词开头,e 到当前或下一个单词结尾。它们适合编辑标识符、参数和短语。
已知目标字符在当前行时,f{字符} 比搜索整份文件更快:f, 跳到下一个逗号,F, 反向跳到上一个逗号;t, 则停在逗号前一个字符,T, 是反向版本。按 ; 重复上一次 f/t 查找,按 , 反向重复。
例如在下面一行中,光标在 formatInvoice 的开头,输入 f( 能到第一个左括号;输入 t, 能停在第一个逗号前,方便继续操作。
const text = formatInvoice(invoice, locale, options)
括号、段落与文件边界
% 在成对的 ()、[]、{} 之间跳转。在嵌套的函数或对象中,这是理解范围最快的内置命令之一:站在 { 上按 %,立刻看到代码块的结尾;再按一次就回来。
{ 和 } 在段落之间向前、向后跳。在有空行分隔的说明文字、注释或函数块中很有用。gg 到文件开头,G 到文件末尾,{数字}G 到指定行;例如 120G。
[[ 与 ]] 会在文件的“章节”或代码块边界间移动。它们对有明确结构的文件特别方便,但具体识别方式会受文件类型和缩进习惯影响;不确定时,用 / 搜索函数名更可靠。
搜索:最通用的文件内跳转
输入 /renderInvoice 再按回车,跳到下一个匹配;?renderInvoice 则向上搜索。随后:
| 按键 | 作用 |
|---|---|
n / N |
同方向 / 反方向的下一个匹配 |
* / # |
搜索光标下的完整单词,并向后 / 向前跳 |
g* / g# |
搜索光标下的文本,可匹配单词的一部分 |
:noh |
清除搜索高亮,不会改变当前位置 |
搜索本身是一种跳转。搜索一个函数名、看完实现后,可以用 <C-o> 回到搜索之前的位置;不需要重新猜测自己从哪里来。
标记:给重要位置命名
跳转历史会变化;当某个位置之后还要多次回来时,用标记(mark)更稳妥。ma 表示把当前位置记为小写标记 a。
| 按键 | 去向 |
|---|---|
ma |
在当前位置设置标记 a |
`a |
精确跳到标记 a,保留列位置 |
'a |
跳到标记 a 所在行的首个非空白字符 |
:marks |
查看已有标记 |
小写标记只在当前文件有效。大写标记可以跨文件:例如在 api.ts 中用 mA 记住入口,再在任何文件输入 `A 回来。常用做法是:阅读一个复杂函数时用 ma 标出入口,跳去检查几个调用点,最后用 `a 精确回到刚才的光标列。
跳转历史:去了哪里,就能怎么回来
Neovim 会记录许多会跨越较大距离的移动,例如搜索、gg、G、使用标记和跳到定义。这个记录叫作跳转列表(jumplist)。
| 按键 | 作用 |
|---|---|
<C-o> |
跳到较旧的位置,也就是“后退” |
<C-i> |
跳到较新的位置,也就是“前进” |
:jumps |
查看跳转列表 |
`` |
回到上一次跳转前的精确位置 |
'' |
回到上一次跳转前的位置所在行 |
这里有两套互补的返回方式:
- 刚做完一次跳转,想立刻原路回去,用
``;它保留列位置。 - 已经跳了好几次,想沿着来路逐步回退,用
<C-o>;如果退过头了,用<C-i>前进。
'' 和 `` 的区别只在落点:前者落到目标行的首个非空白字符,后者回到原来的列。编辑代码时通常优先使用反引号版本。
修改历史:回到“刚才改过的地方”
跳转列表回答的是“我去过哪里”,修改列表(changelist)回答的是“我改过哪里”。两者不要混用。
| 按键 | 作用 |
|---|---|
`. |
精确跳到最近一次修改的位置 |
'. |
跳到最近一次修改所在行的首个非空白字符 |
g; |
前往更早的一次修改位置 |
g, |
前往更晚的一次修改位置 |
:changes |
查看修改列表 |
例如你在文件开头改完一个类型定义,随后 G 去文件末尾阅读。此时输入 `.,就能回到刚才改动的精确位置。若今天修了多个地方,用 g; 连续回溯;看完后用 g, 沿反方向前进。
注意 `. 与 . 很像,但含义完全不同:`. 是跳转到最近修改处,. 是重复上一次修改操作。前者用于定位,后者用于编辑。
一个完整的工作路线
假设你正在阅读一个很长的 invoice.ts,要确认 renderInvoice 的实现,并修改其中一处格式化逻辑。
- 按
/renderInvoice<Enter>搜索函数名;到达后按zz,把函数放到屏幕中央。 - 在函数体的
{上按%,先确认这个函数在哪里结束;再按%回到开头。 - 输入
ma,为这个阅读起点建立一个临时标记。 - 用
<C-d>向下阅读半屏;遇到同名字段时,按*、n、N在各个匹配处切换。 - 修改某一行后,如果又跳到别处,按
`.回到这次修改;想回到最初阅读点,则按`a。 - 最后若要检查搜索之前的位置,按
<C-o>;若只需要撤回刚刚那一次跳转,则按``。
这条路线的关键是:临时目标用搜索,固定锚点用标记,来回路径用跳转列表,修改点用修改列表。
五分钟练习
新建一个临时 TypeScript 文件,粘贴下面的内容。不要追求一次按对;每一步都观察状态栏和光标位置的变化。
export function renderInvoice(invoice: Invoice, locale: string) {
const amount = formatAmount(invoice.total, locale)
const title = `Invoice: ${invoice.id}`
return `${title} — ${amount}`
}
export function formatAmount(amount: number, locale: string) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'CNY',
}).format(amount)
}
export function sendInvoice(invoice: Invoice) {
return renderInvoice(invoice, 'zh-CN')
}
- 用
/formatAmount<Enter>找到函数定义,按zz。 - 在
new Intl.NumberFormat(...)的左括号上按%,观察跳到哪里,再按%返回。 - 在
currency: 'CNY'一行按ma;随后gg到文件开头,再用`a回来。 - 将
CNY改成另一种货币,随后G到文件结尾,再按`.回到改动处。 - 用
g;回顾更早的修改位置,再用g,回到较新的位置。 - 输入
:jumps和:changes,亲眼比较两份历史记录。
速查表
| 目的 | 按键 |
|---|---|
| 半屏阅读 | <C-d> / <C-u> |
| 跳到当前屏幕顶部 / 中间 / 底部 | H / M / L |
| 当前行居中 / 置顶 / 置底 | zz / zt / zb |
| 搜索与继续搜索 | /文本、n、N |
| 搜索光标下单词 | * / # |
| 成对括号间跳转 | % |
| 文件开头 / 结尾 / 指定行 | gg / G / {数字}G |
| 行内找字符并重复 | f{字符}、;、, |
| 设置 / 精确跳到标记 | ma / `a |
| 跳转历史后退 / 前进 | <C-o> / <C-i> |
| 回到上次跳转前 | `` |
| 回到最近修改处 | `. |
| 在修改历史中后退 / 前进 | g; / g, |
| 查看跳转 / 修改历史 | :jumps / :changes |
快捷键忘记时不必离开编辑器:在 Neovim 中输入 :help {命令},例如 :help jumplist、:help changelist、:help g;,可以直接查看内置说明。