Vim 快速编辑
涛叔我在Vim 快速移动一文中相对系统地总结了 Vim 的移动操作。本文补上编辑部分。目的只有一个,那就是帮助初学者尽快熟悉 Vim,形成战斗力。
Vim 在启动之后会进入所谓的Normal模式。在 Normal 模式下,用户无法直接输入文本。我想,这可能是 Vim 最令人困惑的地方了。
关于这个 Normal 模式,我在Vim 快速移动一文中也有介绍:
✏️Note对于一段代码,跟它的整个生命周期相比,编码的时间可能连百分之一都不到。我们大部分时间都是阅读或者修改已经写好的代码。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<cr>
(O
(大写的o
,你懂得)这个键位。
好了,光切换到插入模式,我们已经学了四种办法,如下表
快捷键 | 等效键位 | 功能 |
---|---|---|
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
不能完成删除操作,必须还要再提供一个范围。这个范围主要使用移动操作表示,而且是从光标所在字符开始。比如,如果想向右删除一个字符,可以按 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 |
有志于掌握 Vim 的读者应该依照我的移动和编辑编辑两篇文章,多加练习,假以时日,必成大器🐶