Vim 快速编辑
涛叔Vim在启动之后会进入所谓的Normal模式。在Normal模式下,用户无法直接输入文本。我想,这可能是Vim最令人困惑的地方了。
关于这个Normal模式,我在Vim 快速移动一文中也有介绍:
对于一段代码,跟它的整个生命周期相比,编码的时间可能连百分之一都不到。我们大部分时间都是阅读或者修改已经写好的代码。Vim的作者有鉴于这种事实,引入了所谓的 Normal 模式。在 Normal 模式下,你不能输入内容,但是可以高效地移动和修改。
因为输入内容用的相对较少,所以Vim要求在输入前需要先切换到Insert模式。一旦进入Insert模式,大家就可以正常输入内容。完成输入后需要按Esc返回Normal模式。
那么如何进入Insert模式呢?
最常用的就是按字母i,显然是单词insert的第一个字母。 大家可以试一下,按i切入Insert模式后,光标会停在当前字母的前面。也就是说,如果你的光标停在了insert的s上,那按i之后,光标会停在n和s之间,新输入的内容也会实插入到s之前。
如果Vim只支持i,我们就会遇到一些麻烦。比如,我们想给一行的结尾加一个分号。我们只能是先按$跳到最后一个字母,再按i切换到Insert模式,再按→把光标移动到最后一个字母的后面,再输入;,再按Esc回到Normal模式。
这么小的改动居然得用方向键。能忍吗。为此,Vim还提供了字母a,大家可以理解成append,也就是追加的意思。同样是切换到Insert模式,a会让光标停在当前字母后面。所以,前面的改动可以依次键入a;Esc就可以了。
所以,在一行的开头插入内容需按^i,在结尾插入内容需按a,然后输入内容,最后按Esc返回Normal模式。因为这两种操作比较常用,Vim给他们单独分配了快捷键,i对应I,a对应A。怎么样,是不是很有规律。
除了简单的插入内容,我们还经常需要新起一行输入内内容。到现在你可以依次按A,跳到行尾并切换到插入模式,再按回车新起一行,然后输入你想要的内容。按两次有点麻烦,Vim为大家提供了o来实现这个效果。这个o好像没有对应的单词。大家不妨理解成open new line😜
o是在当前行下面新起一行。细心的朋友肯定会问如何在当前行之上新起一行呢?如果我们只会o,那我们只能先按一下k稳到上一行,然后再按o。可如果光标就在第一行呢?我们只能先按I再按回车了。同样因为常用,Vim为I
好了,光切换到插入模式,我们已经学了四种办法,如下表
快捷键 | 等效键位 | 功能 |
---|---|---|
i | 之前追加 | |
a | i→ | 之后追加 |
I | ^i | 行首插入 |
A | $a | 行尾插入 |
o | I |
下起一行 |
O | A |
上起一行 |
每当完成修改后,一定要返回Normal模式。有同学喜欢「一键到底」,这不是一个好习惯。为什么呢?一个原因是在Insert模式下,我们无发像Normal那样灵活移动;另一个原因是不能灵活的撤销之前的改动。
跟其他编织器一样,Vim也提供undo和redo功能(分别对应u和r),但是这些操作是以「原子改动」为单位的。什么是「原子改动」呢?简单来说,从Normal模式切换到Insert模式、输入改动内容、再返回Normal模式,这一整个过程叫做一次「原子改动」。如果大家一直在Insert模式下输入内容,不管输入多少,只要回到Normal模式再按一下u,就会全部撤销。非常不灵活。
所以,Vim鼓励大家多想少改,一次只改一点,步步为营。每改完一点,就按一次Esc返回Normal模式。大家可以跟 git 类比一下,把每次切到Insert模式、改动、返回Normal模式当成一次 commit。这样撤销的时候会非常灵活。
在极少数情况下,我在希望在Insert模式快速移动光标。简单的做法是使用方向键,但更地道的方法是使用ctrl+o。在Insert模式下按ctrl+o vim会临时切换到Normal式,然后可以按wf^$等实现快速移动。Vim命令执行完之后会自动切换到Insert模式。也算是一种小优化。
以上都是说先切换到Insert模式再进行修改的。切来切去多麻烦。有没有更快的方法呢?有!
首先你可以直接在Normal模式执行删除操作。删除的主要命令是d(可以理解为delete)。单纯一个d不能完成删除操作,必须还要再提供一个范围。这个范围主要使用移动操作表示(如果你对移动不大熟悉可以先看我的素人Vim之快速移动一文),而且是从光标所在字符开始。比如,如果想向右删除一个字符,可以按dl,如果想删三个字符可以按d3l,给大家整理一个表格
命令 | 范围 | 功能 |
---|---|---|
dl | l | 向右删除一个字符 |
d3l | 3l | 向右删除三个字符 |
de | e | 向右删除到单词的结尾 |
df; | f; | 向右删除到第一个分号 |
d$ | $ | 向右删除到当前行的结尾 |
d^ | ^ | 向左删除到当前行的开头 |
dG | G | 从当前行删除到最后一行 |
dgg | gg | 从当前行删除到第一行 |
命令+范围,大家要记住这个范式。Vim还有很多其他功能也遵守这样的范式。
为了进一步简化删除操作,Vim还提供了一组简化的快捷键
功能 | 快捷键 |
---|---|
dl | x |
dh | X |
d$ | D |
删除整行 | dd |
到这里,删除已经学的差不多了。记住d+范围可以解决大部分问题。
我们为什么要删除呢?除了极少数纯删除操作外,我们一般都是为了修改而执行删除操作的。删是为了更好的改。先删后改,是不有点麻烦呢?能不能删改一体化?能!
简单来说就是把刚才的d换成c(可以理解成change)就可以了。也是命令+范围,c会删除相同范围的内容并切换到Insert模式,删除之后可以立即输入新内容。因为c跟d是完全对应的,我就不在这里重复罗列了。但c还有一些简化操作,不得不提
功能 | 快捷键 | 功能 |
---|---|---|
cl | s | 修改当前字符 |
cc | S | 修改整行 |
还有一种情况是我们只想改一个数字,比如把0改成1我们可以按s1Esc,需要按一次Esc返回Normal模式。Vim对这种情况也提供了一个快捷键叫r(可以理解成replace),原来的s1Esc可以简化成r1。
最后说一下复制跟粘贴。
复制使用y(yank),同样遵循命令+范围的范式,跟dc完全对应(复制整行用yy),不作赘述。
粘贴则使用p(paste),比较简单。与之对应的是P,也是粘贴,但会粘贴到光标的左侧和上方,大家可以试一下。
最后给大家整一个表格,到此,基本把编辑相关的操作讲完了。
命令 | 助记词 | 整行操作 |
---|---|---|
d | delete | dd |
c | change | cc |
y | yank | yy |
p | page | |
u | undo | |
ctrl+r | redo |