Vim 快速移动
涛叔很多人听说 Vim 就想试试。可一看到罗列出来的快捷键,就打退堂鼓🥁。这是人之常情。错不在于退缩的人,而在于写 Vim 教程的人。
Vim 快捷键虽多,但有内在的规律。我们记快捷键是为了什么?就是为了提高编缉的效率。那 Vim 针对效率提供了哪些功能呢?本质上我们要记住的是这些功能。那些快捷键不过是这些功能的一种表达方式罢了。
这就像我们小时候背英语作文。我们要背一篇作文,不能只关注一句话里的语法和单词,更要关注文章的结构跟内容。我之前都是先用中文理解内容,在脑子里有个中文版的大纲;再一句一句地翻成英文;最后反复背诵,熟能生巧。所以要理解着背,不能死记硬背。
本文就试着给大家带来一种通过理解来背诵快捷键的思路。今天只讲光标移动部分。如果你已经掌握了移动的技巧,可以看快速编辑部分。
写程序的同学应该都清楚,典型的线上系统基本都是读多写少。代码也是一样。对于一段代码,跟它的整个生命周期相比,编码的时间可能连百分之一都不到。我们大部分时间都是阅读或者修改已经写好的代码。Vim 的作者有鉴于这种事实,引入了所谓的 Normal 模式。在 Normal 模式下,你不能输入内容,但是可以高效地移动和修改。这是 Vim 跟常见的编缉器最大的不同点。这也是 Vim 最令初学者难以理解,最让初学者望而却步的特性。
那怎么移动呢?无外乎上下左右。我们现在键盘都有这四个键。有人说 Vim 在诞生的年代,那个时候的键盘没有像现在这样的方向键,所以选用了hjkl
四个键来移动光标。我不认同这个观点。
首先,上下左右是最最基础的移动操作,自然也是最最常用的移动操作。既然常用,我们就应该着力优化这几个操作。怎么优化呢?一般人的右手比左手要灵活,所以这个活得让右手来干。另外,对于标准键盘,右手的姆指之外的四个指头默认依次放到jkl;
键上。因为上下左右使用最频繁,我们肯定不希望频繁移动手指,所以最简单的做法就是使用jkl;
来控制方向。因为你的右手默认就压在这四个键上,不用移动手指就能按到。但是,分号要用小姆指才能按到。小姆指跟其他三个指头相比又不那么灵活,所以最终选取了hjkl
来控制方向,分别表示左下上右四个方向。因为食指非常灵活,同时控制h
和j
,使用起来比小指要方便一点。
至于为什么用jk
表示上下用hl
表示左右,我就不清楚了。我隐约觉着上下移动要比左右移动更常用,所以把最方便的jk
用来控制上下了。
好了,我们可以控制光标上下左右随便移动了。如果 Vim 只支持hjkl
,你一定会发狂。因为hjkl
一次只能移动一个字符或者一行。如果要在几十上百行的文件来回移动,指头都按断了🤦♂️
显然,我们需要效率更高的移动方式。最简单的方法就是避免重复。为此 Vim 引入了数字+命令的方式来加快移动速度。比如,j
表示向下移动一行,3j
表示向下移动三行, 100j
表示向下移动一百行。hjkl
每个命令都可以跟数字搭配。其实,Vim 下很多命令都可以跟数字搭配。先按好你想要的数字(右下角会显示),再按具体的命令,Vim会 自动重复执行。
有了数字+命令这一法宝,我们基本可以畅通无阻。此法快则快矣,却有一个致命的问题。如果你要移动的行数和列数很大,你应该怎么确定这个数字呢?不管是猜测还是数数,都不会提高移动的效率。我们需要继续优化。
Vim 针对左右移动和上下移动分别作了若干优化。我们先说左右移动。
假设我们有这么一段文本,我们的光标在字world
的d
这个字母,我们想稳动到右边的 a
上。
hello world this is a demo.
^
最简单的做法就是不断按l
向右移,一直到a
为止。如果你火眼金眼,一下字就看出来 d
跟a
之间隔着十一个字母,你可以按11l
一步到位。显然,大家都是凡人。那能不能让 Vim 帮我们数呢? 当然是可以的。我们可以通过按fa
来告诉 Vim 一直向右数数,直到发现字母a
为止。然后执行11l
(这个11
可以认为是 Vim 自己数的)。是不省事多了。我猜这里的f
对应find
这个单词。应该一下就记住了吧。
有的时候,我们需要光标停在字母a
的前面,而非字母a
上(也就是说,在移动的时候对数字减一),我们可以按ta
。这里的t
跟前面的f
几乎是一样的,但会少数一个字符。我猜这个t
对应till
,也就until
的意思。
有向右查,就肯定支持向左查。保持对称,这是 Vim 命令的另一内在规律。向左也很容易记忆,分别是F
和T
。一看就明白,我就不做缀述了。但有一点,Vim 有好多命令都有大小写形式,大家在学习的时候要注意总结。
让我们回到原来的例子。
hello world this is a demo.
^
如果我们想让光标移到单词is
的第一个字母,可以按fi
。你会发现光标只会停在this
的i
上。这个时候你得重复按fi
才能跳到is上
。什么,重复按怎么能有效率呢?优化!为此,Vim 提供了重复上次查找的命令。你在按了fi
之后发现还没到,可以直接按;
,相当于再按了一次fi
。重复一次觉不出来,如果要重复好多次,就会显著加快移动。同样的,Vim 保持对称,为我们提供了,
命令,功能跟;
相同,但方向相反。;
和,
对F
和T
同样有效,大家不妨练习一下。
熟悉了f
相关的命令,我在在左右方向上的移动效率就会有一个巨大的提升。我们可以通过查找诸如空格、括号、逗号、分号等特征字符完成快速移动。但是,我们还有提升的空间。
让我们再一次回到前面的例子。
hello world this is a demo.
^
为了能进一步加速,我们必须从文本内容的结构入手了。我们知道,西方拼音文字都是以单词为书写单位,单词之间以空格隔开。我们自然就想到能不能一个单词一个单词地移动。
如果使用f
,稳动到this
需要按ft
,再移动到is
需要按fi
,再移动到a
需要按 fa
。每次都要找到单词的第一个字母,然后配合f
移动。单词的首字母又不尽相同,效率肯定上不去。那能不能让 Vim 帮我们找单词的首字母呢?答案是肯定的。我们需要用 w
。每按一次w
,Vim 就会跳到右边单词的首字母。所以,如果要逐个单词移动,我们可以不断按w。记住,Vim 的对称原则。如果想跳到左边的单词,则需要按b
。w
可以理解成word
,b
呢可以理解成back
。使用w
和b
可以不用考虑单词具体的首字母,效率自然比使用f
命令族要高。
跟移动到右边单词开头对应的则是稳动到尾(这也是一种对称),需要按e
, 可以理解为 end
。如果是想向左跳,则需要按ge
。可能是跳到左边单词结尾这种用法不太常用,所以就用了g
修饰e
来表示。
wbege
这几个命令也可以配合数字使用,请大家自行练习。
最后需要说的左右移动命令就是跳转到一行的开始和结尾了。理论上,如果想跳到结尾,你可以一直按l
, 也可以一直按e
,但都要按很多次,而且次数不定。这显然没有效率可言。于是,Vim 用$
表示跳到一行的结尾。如果你学过正则,一定不会陌生。同样的,为了对称,跳到行首用^
,也是正则的元字符。
Vim 还支持直接跳转到指定列。如果你们相移动到第五列,我们可以执行5|
。一般用于根据报错信息准确定位的场景,不是特别常用。
好了,基本上左右方向上的移动都说完了。现在我们再说上下方向。
左右是列移动动,对应上下是行移动。左右有单词移动,一个单词可以看成多列的集合。上下也有对应的一屏。一屏可以看成多行的集合,一屏近似跟一个单词对应。左右移动对应上下移动。一行的首尾对应的文件的第一行和最后一行。你会发现上下移动跟左右移动惊人的相似。
总结一个表格就是这样子,有一种内在的对称。
左右移动 | 键位映射 | 上下移动 | 键位映射 |
---|---|---|---|
向右查找 | f/t | 向下查找 | / |
向左查找 | F/T | 向上查找 | ? |
重复向右查找 | ; | 重复向下查找 | n |
重复向左查找 | , | 重复向上查找 | N |
跳到右单词 | w | 跳到下一屏 | ctrl+f |
跳到左单词 | b | 跳到上一屏 | ctrl+b |
跳到单词开头 | b | 跳到屏幕第一行 | H |
跳到单词结尾 | e | 跳到屏幕最末行 | L |
一行的开头 | ^ | 第一行 | gg |
一行的结束 | $ | 最末行 | G |
向右 | l | 向下 | j |
向左 | h | 向上 | k |
跳转到指定列 | 数字+| | 跳转到指定行 | 数字+gg |
以上就是常用的移动命令。因为上下跟左右是对称的,只要稍加练习应该很快就能记住。
从l
到w
到f
再到$
,单次移动的距离依次增大。但是,我们要注意,移动距离越大的命令,停下的位置就越固定,相对而言也就越不灵活。最灵活的是hjkl
,因为一次只能移动一行或一列。我们在移动的时候应该尽量先使用移动距离大的命令,再使用移动距离小的命令,最后使用hjkl
进行微调。如果你在日常中需要频繁地重复多次按某个键来移动光标,你一定要想想 Vim 有没有提供相关的优化键位。记住,不要重复!