今日主题#
- 主主题:
移动:从“硬挪”到“直接到位” - 副主题:
把 h j k l 从主导航降级成兜底导航
学习目标#
- 解决“明明知道怎么动,但移动成本太高”的问题。
- 明确 Vim 里的高效移动不是更快地多按几次,而是更少地按、更直接地到。
- 建立三层移动视角:
- 按字符微调
- 按词和按行快速到位
- 按文件位置跳转
- 为下一天的
operator + motion做准备。
前置回顾#
- Day 001 已经建立一个关键前提:
- 普通模式是主工作模式。
- 插入模式只是短暂停留。
- 既然普通模式是主工作模式,下一步就不是学着“怎么继续打字”,而是学着“怎么先到对的位置”。
- 当前本地环境已确认:
vim 9.2nvim 0.12.0
- 本篇仍以
vim的基础移动模型为主,因为这部分在vim/nvim/ LazyVim 中都通用。
典型场景#
这一篇要解决的是真实编辑里很常见的几种慢:
- 想改一处单词,结果一路按方向键或
h l挪过去。 - 想去行首或行尾,却还在一点点来回蹭。
- 想去文件开头、文件结尾或某一段附近,结果只能靠滚屏和猜位置。
- 明明只是想改“这个词”或“这一行结尾”,却因为定位慢,后续编辑也慢。
如果移动还是“硬挪”,那后面的删除、修改、复制都会显得笨重。
最小命令集#
今天只保留最常用、最值得形成肌肉记忆的那一层。
字符级微调#
h/l- 向左 / 向右移动一个字符
j/k- 向下 / 向上移动一行
行内快速到位#
0- 到本行第一个字符
^- 到本行第一个非空白字符
$- 到本行最后一个字符
按词移动#
w- 到下一个词的开头
e- 到当前词或下一个词的结尾
b- 回到上一个词的开头
ge- 回到上一个词的结尾
行内找字符#
f{char}/F{char}- 在当前行向前 / 向后找到某个字符,并落到它上面
t{char}/T{char}- 在当前行向前 / 向后找到某个字符,但停在它前一个位置
;/,- 重复上一次
f/F/t/T搜索,或反方向重复
- 重复上一次
文件级定位#
gg- 到文件开头
G- 到文件结尾
{count}G- 到指定行,例如
20G
- 到指定行,例如
count#
{count}{motion}- 让一个 motion 一次跨多步,例如
3w、5j、20G
- 让一个 motion 一次跨多步,例如
软换行场景补充#
gj- 按屏幕显示行向下
gk- 按屏幕显示行向上
它是怎么用的#
先改一个判断:高效移动不是“按得快”,而是“少按几次”#
很多人刚开始学移动,会把重点放在:
- 能不能不用方向键
- 能不能把
h j k l按熟
这当然有用,但它只解决了“怎么挪”,还没有解决“为什么还要挪这么多次”。
真正更重要的是:
- 先判断目标在词内、行内,还是文件级位置。
- 选最接近那个尺度的 motion。
- 到位后再做编辑。
所以 h j k l 不是废弃,而是降级成微调工具。
0、^、$ 解决的是“行内定位”问题#
这三个键非常高频,因为你经常会遇到:
- 去行首补点内容
- 去行尾追加点内容
- 跳到代码缩进后的真正开头
最容易混的是:
0是真正的第一个字符,包含行首空格或缩进^是第一个非空白字符$是最后一个字符
写代码时,^ 往往比 0 更常用,因为你通常想落在代码开头,不是落在缩进空格上。
w、e、b、ge 解决的是“按词到位”问题#
这是 Day 002 的真正主力。
当你看到一个目标词时,应该逐渐从:
l l l l l
转成:
wbege
可以这样理解:
w:往前找下一个词头e:往前找词尾b:往回找词头ge:往回找词尾
官方帮助 :help word-motions 也说明了这组命令的核心是“按 word / WORD 移动”,而不是按字符移动。
W / E / B / gE:按“非空白块”移动#
D:\program\Learn-Vim\ch05_moving_in_file.md 很值得补的一个点是:
word- 受标点、连字符等影响更大
WORD- 只按空白分隔,粒度更粗
所以当你面对下面这种内容时:
snake_case-namew往往会在更细的边界停下W会把整块非空白内容看成一个更大的单位
日常结论先记这个就够:
- 普通文本和代码里的常规跳词,先用
w/e/b - 遇到路径、参数串、带符号的片段,补上
W/E/B/gE
count 让移动不只是“一个一个来”#
本地 motion.txt 和 Learn-Vim 都强调了同一件事:
- 大多数 motion 都能接 count
所以不要把它想成少量特殊写法,而要把它想成通用句式:
3w- 往前跳三个词
5j- 向下五行
20G- 直接去第 20 行
这会明显减少“我知道方向对,但还是要连按很多次”的感觉。
f / t / ; / ,:同一行内横向找目标时,比 llll 更值钱#
当目标还在当前行时,很多时候甚至不用上 w。
本地 motion.txt 里:
f{char}- 找到字符并落到它上面
t{char}- 找到字符,但停在它前一格
;- 继续按同方向重复上一次行内搜索
,- 反方向重复
真实场景里很常见:
- 想跳到这行里的
= - 想停在
)前面 - 想在两个引号之间快速来回
这时优先想到:
f=t);,
gg、G、{count}G 解决的是“文件级定位”问题#
只要文件稍微长一点,你就会遇到:
- 回文件顶部看标题或 imports
- 去文件底部追加内容
- 跳到某个大致已知的行号
这时再用滚动或连续 j k 就太慢了。
gg用于直接回开头G用于直接去结尾{count}G用于直接去指定行
这组动作会让你第一次感受到:Vim 不是“更麻烦地移动”,而是“允许你直接去结构位置”。
gj / gk 是给“显示行”准备的,不是替代 j / k#
当一行内容很长、屏幕发生软换行时:
j/k仍然按“真实文本行”移动gj/gk按“屏幕显示行”移动
所以它们不是谁更高级,而是解决不同问题。
如果你在 Markdown、长注释或长 JSON 中经常遇到“明明看起来就在下一屏幕行,但 j 一下跳太多”,就该想到 gj / gk。
常见操作套路#
套路 1:改某个单词,先按词到位,再进入编辑#
错误直觉:
- 一直
l挪过去 - 到附近后再
i或a
更稳的方式:
- 用
w/b到目标词附近 - 用
e或ge精调到词尾附近 - 必要时再用
h/l微调 - 再进入插入或等待下一天的
operator + motion
套路 2:想在行首代码前后动手,先分清 0 和 ^#
如果你要处理的是缩进本身,用 0。
如果你要处理的是这行真正的内容开头,用 ^。
这会显著减少“明明到了行首却还差一点”的感觉。
套路 3:同一行找目标字符,优先 f / t#
场景:
- 你看见目标就在这一行
- 只是横向距离有点远
这时先别下意识按很多次 l,而是优先看:
- 目标字符能不能用
f{char}直接到 - 需不需要用
t{char}停在它前面 - 到了之后用
;/,继续重复
套路 4:跨大段内容时,不要拿 j / k 当主力#
更好的优先级通常是:
- 先看是不是
gg/G/{count}G - 再看是不是
w/b - 最后才是
h j k l
这就是“直接到位”的核心。
套路 5:遇到屏幕软换行,记得切换到 gj / gk#
如果你看见的是“视觉上的下一行”,但编辑器内部其实还是同一长行,那就不要和 j / k 硬扛。
环境差异:vim / nvim / LazyVim#
这些移动在 vim 和 nvim 中的基础语义一致#
本地帮助文件里,Vim 9.2 和 Neovim 0.12.0 的 motion.txt 都保留了相同的移动模型:
h j k l0 ^ $w e b gegg Ggj gk
所以 Day 002 学到的不是“某个发行版技巧”,而是 Vim 系编辑器的共同底层。
到了 LazyVim,这些基础移动不会被替代#
LazyVim 会增强:
- 文件搜索
- buffer 切换
- 项目导航
- LSP 跳转
但进入文件后的细粒度定位,仍然离不开今天这些 motion。
如果 Day 002 不稳,到了 LazyVim 往往会出现一种假熟练:
- 项目能打开
- 文件能跳到
- 但进到文件里改具体内容时还是慢
今日练习(5-10 分钟)#
练习材料#
新建一个临时文件,写入下面内容:
vim motion should reduce wasted movement
longer lines make direct navigation more important
I want to move by word instead of drifting by character
sometimes a wrapped line is still one real line
snake_case-name behaves differently for word and WORD练习任务#
- 用
vim或nvim打开这个文件。 - 只用
w和b,在第一行和第三行之间反复找motion、word、character这些词。 - 在第二行里分别用
0、^、$感受行首、非空白开头、行尾的区别。 - 用
gg回到文件开头,再用G去文件结尾。 - 用
2G、3G、4G分别跳到对应行。 - 在第一行或第三行试一次
3w、2b,感受 count 和 motion 的组合。 - 在第二行找一个明显字符,试一次
f、t、;、,的配合。 - 把光标放到最后一行,比较
w和W的落点差异。 - 如果你的窗口足够窄,制造软换行后分别试
j/k和gj/gk的差异。
完成标准#
- 能明确说出
h j k l是微调,不是主导航。 - 能在真实文本里优先想到
w/b/e/ge。 - 能在同一行目标较远时想到
f/t,而不是一路l。 - 能把
{count}{motion}当成自然句式,而不是例外。 - 能分清
0和^。 - 能用
gg/G/{count}G完成文件级定位。
今日问题与讨论#
我的问题#
问题 1:是不是以后就不该再用 h j k l 了?#
- 简答:
- 不是。它们仍然很重要,但更适合微调,而不是长距离主导航。
- 场景:
- 已经接近目标,只差 1 到 2 个字符。
- 依据:
:help motion.txt把它们作为最基础的字符级与行级移动;高效来自“选对尺度”,不是完全废掉某组命令。
- 当前结论:
h j k l要保留,但要从主力降级成兜底。
- 是否需要后续回看:
是
问题 2:0 和 ^ 到底该优先记哪个?#
- 简答:
- 两个都要记,但写代码时通常先养成
^的习惯。
- 两个都要记,但写代码时通常先养成
- 场景:
- 一行前面有缩进空格,而你只想落到代码开头。
- 依据:
:help left-right-motions对两者给出的定义不同:0到第一字符,^到第一个非空白字符。
- 当前结论:
- 改缩进时想
0,改内容时多想^。
- 改缩进时想
- 是否需要后续回看:
是
问题 3:j / k 和 gj / gk 为什么都需要?#
- 简答:
- 因为它们处理的是两种不同的“行”。
- 场景:
- 长行发生软换行时,视觉上一行不等于真实文本一行。
- 依据:
:help up-down-motions明确区分了 linewise 的j/k和 display lines 的gj/gk。
- 当前结论:
- 普通代码文件常用
j/k,长段文本或软换行场景要想到gj/gk。
- 普通代码文件常用
- 是否需要后续回看:
是
外部高价值问题#
问题 1:w 和 W 到底差在哪?#
- 问题:
- 它们看起来都像“往前跳一个词”,为什么还要分大小写两套?
- 简答:
- 因为
word和WORD的边界规则不同,WORD只按空白分隔,粒度更粗。
- 因为
- 场景:
- 代码里出现
snake_case-name、路径、参数串、带标点的片段。
- 代码里出现
- 依据:
- 本地
motion.txt对word/WORD的定义。 D:\program\Learn-Vim\ch05_moving_in_file.md。
- 本地
- 当前结论:
- 普通文本和代码常规跳词先想小写;遇到符号很多但你只想按整块跳,再补大写。
- 是否需要后续回看:
是
常见误区或易混点#
- 误区 1:不用方向键,就等于移动已经高效
- 不是。连续按很多次
h l仍然是低效移动。
- 不是。连续按很多次
- 误区 2:
w/b只是“可选技巧”- 不是。它们是从字符移动升级到词级移动的核心。
- 误区 3:
0和^差不多- 不差不多。缩进一多,区别会非常明显。
- 误区 4:
gg/G只在超大文件里才有用- 不是。只要超过几屏,就已经比滚动更省力。
- 误区 5:
gj/gk没必要学- 只要你编辑 Markdown、注释、日志或任何长行文本,它们就会变得实用。
扩展内容#
g_- 到行尾最后一个非空白字符,适合某些代码行尾定位。
n|- 直接跳到当前行第
n列,偶尔处理固定列文本时会很直接。
- 直接跳到当前行第
%- 在成对的括号、方括号、花括号之间跳转,后面进入代码编辑时会更常用。
(/)与{/}- 按句子或段落移动,更适合长文本场景。
今日小结#
Day 002 的关键不是“记更多方向命令”,而是建立一个判断:
- 远距离不要硬挪
- 按词、按行、按文件位置直接到位
h j k l负责微调,不负责包办一切
只要这一步建立起来,下一天学 operator + motion 时,很多组合就会自然顺起来。
明日衔接#
下一步建议进入:
Day 003:operator + motion
重点会开始解决:
- 为什么
d、c这种操作离不开移动 - 为什么
dw、de、d$这种组合才是 Vim 的真正编辑节奏 - 为什么 Day 002 的移动不是独立知识,而是后续编辑动作的基础
复习题#
- 为什么说高效移动不是“按得更快”,而是“按得更少”?
0和^的区别是什么?写代码时谁更常用?w、e、b、ge分别更适合解决什么定位问题?gg、G、20G分别适合什么场景?- 在软换行场景里,为什么要区分
j/k和gj/gk?


