↑↓←→
、i
、<ESC>
、:wq
,就可以覆盖大部分使用场景。那为什么还需要再深入学习 vim 呢?vimtutor
,打开一个教程文本文件,尝试某个快捷键或命令。vimtutor
即可打开,mac 系统下是中文文档这里顺便再推荐一些可视化学习资源: 数据结构与算法:Data Structure Visualization、Visualgo 正则表达式:regexper Git:Learn Git Branching(强烈推荐)、Visualizing Git
:
可以执行命令i
进入插入模式,此时可以输入文本;按下 <ESC>
退出插入模式ii
退出插入模式,这样左手不需要移动到最左上角去按下 <ESC>
。在标准模式下执行:imap ii <Esc>
i
的场景:如果想要输入连续的两个 i
,必须在按下第一个 i
之后稍等一会儿,再按第二个 i
。不过英文中很少有单词包含连续的两个 i
,所以影响可以忽略。:<command>
:
后输入命令,按回车执行。如 :set number
会显示行号。:q
/ ZZ
:q
/ :quit
:退出 vim,不作任何改动:q!
:退出 vim,丢弃已有的改动:wq
:保存更改(write)并退出(quit)vimZZ
:等同于 :wq
,这个快捷键输入比 :wq
更快,注意是大写 Z
:w
/ :w <filename>
:w
:保存更改:w <filename>
:保存到一个新的文件h
/ j
/ k
/ l
h
、j
、k
、l
而不是 ←
、↓
、→
、↑
,这能够避免将手指移出键盘热区再移回来。如果有必要的话,甚至可以禁用方向键,来强制自己使用 h
、j
、k
、l
:map <Left> <Nop>
map <Right> <Nop>
map <Up> <Nop>
map <Down> <Nop>
gg
/ G
gg
:前往第一行1G
:同 gg
G
:前往最后一行w
/ e
w
:向右移动一个单词,光标将落在下一个单词的首字符e
:向右移动一个单词,光标将落在当前一个单词的最后一个字符↓ 光标在这里
Hello, world!
↑ 按下 w
↑ 按下 e
Hello, world!
↑ 按两下 w
↑ 按两下 e
W
/ E
,区别在于这两个快捷键将「空格」作为单词的分隔符。示例:↓ 光标在这里
Hello, world!
↑ 按下 W
↑ 按下 E
Hello, world!
↑ 按两下 E
↑ 按两下 W 会移动到下一行
b
b
向左移动到前一个单词的首字符,相当于是 w
的逆操作。b
取 backwards 首字母,「单词」的定义同 w
。2b
向左移动两个单词,nb
向左移动 n 个单词。B
向左移动一个单词,将「空格」作为单词的分隔符(同 W
、E
)。单词移动类快捷键速记:web。
ge
ge
移动到前一个单词的末尾,gE
将空格作为单词的分隔符。0
/ $
0
:前往第一个字符,可以理解成是第 0 列$
:前往最后一个字符x
/ X
x
:删除当前字符,等同于 <Delete>
X
:删除前一个字符dw
w
,单词后面的任意多个空格将被删除。dW
,删除下一个空格前的单词。dd
a
i
在当前位置前面插入(insert),a
在当前位置后面插入(append)。I
/ A
o
/ O
u
/ <Ctrl> + r
u
:撤销(undo)<Ctrl> + r
:重做(redo)n<key>
n
前缀来重复 n 次:nh
/ nj
/ nk
/ nl
。5h
向左移动 5 个字符,5j
向下移动 5 行。nb
。2b
向左移动两个单词。nG
。1G
可以前往第一行,就是这个原理。如果希望在 vim 中显示行号,可以在标准模式下执行 set number
命令,也可以将这条命令写到 vim 的配置文件中。nx
。2x
删除两个字符,2X
向左删除两个字符。nw
/ ne
。2w
/ 2e
向右移动两个单词,等同于按两次 w
/ e
,示例: ↓ 光标在这里
Hello, world!
↑ 按下 2w
↑ 按下 2e
dnw
/ ndw
。d2w
/ 2dw
删除光标后的两个单词。类似的还有 dnW
,删除后面第 n 个空格之前的单词。dnd
/ ndd
。d2d
/ 2dd
都可以删除光标开始的两行。nu
。2u
撤销前两步操作,等同于按两次 u
。n<Ctrl> + r
。2<Ctrl> + r
重做被撤销的两步操作,等同于按两次 <Ctrl> + r
。d<range>
d
可以和任意光标移动的操作符结合,来删除一个范围的内容。$
是个例外)d
可以向任意方向进行删除,都符合上述约定。vimtutor
尝试一下这些命令,就可以理解上述“范围”的含义:dw
:删除下一个单词,不会删除 w
跳转到的那个字符db
:删除前一个单词,不会删除光标一开始指向的那个字符d0
:删除当前位置到行开头的所有内容,不会删除光标一开始指向的那个字符dG
:删除当前行到文件末尾的所有内容,包含当前行在内也会被删除dgg
:删除当前行到文件开头的所有内容,包含当前行在内也会被删除,d1G
可以达到相同的效果$
是一个例外,d$
会删除当前位置到行末尾的所有内容,包含行末尾在内的字符也都会被删除。3G
会跳到第 3 行,那么 d3G
将删除当前行到第 3 行的所有内容,包括第 3 行;j
下移一行,那么 dj
将删除当前行和下一行,d2j
将删除当前行开始的 3 行内容;dh
、dl
分别等价于 x
、X
…… 理解之后,你就可以做到举一反三了。d
和数字 n
可以组合在一起使用。d
表示删除元素,n
表示后面的命令重复 n 次。这两个命令以不同顺序组合也能达到相同的效果,比如 d2w
和 2dw
都是删除后两个单词。但我个人认为,这两个命令在语义上有区别:d2w
表示删除 2w
范围的内容,而 2dw
表示 dw
命令重复 2 次。在 vim 术语中,将 d
后 面的操作称为[number]
与motion
,其中number
是可选的。 比如d2w
中,2
就是number
,w
是motion
。 本文为了便于理解,统称其为range
。
部分快捷键见「进阶」一节
x
向右、X
向左p
向下、P
向上o
向下、O
向上f
向右、F
向左w
将特殊字符作为独立单词,W
只将空格作为单词分隔符e
/ E
、b
/ B
同理a
在当前位置后面插入、A
在当前行末尾插入i
在当前位置前插入、I
在当前行开始插入d
删除一个范围、D
删除到行末尾c
删除一个范围、C
删除到行末尾,并进入编辑模式s
删除当前字符,并进入编辑模式;S
删除当前整行,并进入编辑模式r
替换一个字符、R
连续替换多个字符直到按下 <Esc>
v
进入可视模式v
进入可视模式(visual mode),然后移动光标以选择文本:y
可以复制选中的文本d
可以删除选中的文本,按下 p
放置(粘贴)这些文本,这就实现了剪切功能r
r
:再按下任意键,替换(replace)当前字符,等同于 x
+ i
。示例: ↓ 光标在这里
Helle, world!
# 先按 r,再按 o
Hello, world!
↑ 光标在这里
R
R
:替换连续的多个字符,按下 <Esc>
可以退出替换模式。c
c
取 change 的首字母,这个命令的便捷之处在于将「删除操作」和「进入编辑模式」合二为一,可以少按一个键。cw
:更改下一个单词,等同于 dw
+ i
c2w
:更改后两个单词,等同于 d2w
+ i
c$
:更改从当前位置到行结束的所有内容,等同于 d$
+ i
d
一样,c
也可以和任意光标移动的操作符结合,来更改 一个范围的内容。yy
yy
复制当前行,p
粘贴到目标位置。nyy
复制当前行向下的多行。p
/ P
p
粘贴到目标位置。dd
删除某一行后,也可以按下 p
,将删除掉的内容放置到当前光标位置下一行。注意这里是「放置」而不是「粘贴」,因为 dd
将被删除的行保存到了缓冲区,而 p
其实是将缓冲区的内容放置到当前位置,所以 p
取 put 的首字母,而非 paste。yy
将当前行保存到缓冲区,但不删除。这样 yy
+ p
就可以实现“复制-粘贴”的操作。P
粘贴到上一行。f<target>
ft
移动到下一个 t
出现的位置,f2
移动到下一个 2
出现的位置。f
取 forward 的首字母。F
类似于 f
,向前移动到前一个指定字符。t
类似于 f
,只不过光标会移动到下一个指定字符之前;T
类似于 F
,只不过光标会移动到前一个指定字符之后。t
取 until 的含义。 ↓ 光标在这里
Hello, world!
↑ fo
↑ fr
↑ Fh
↑ to
↑ Th
s
s
等同于 x
+ i
。S
S
等同于 dd
+ o
。D
D
等同于 d$
。C
C
等同于 c$
,或者 d$
+ a
,或者 D
+ a
。yw
y
取 yank(复制)的首字母。yw
复制下一个单词,p
可以将其粘贴(put)到指定位置。y
和 c
、d
一样,可以和任意光标移动的操作符结合,来复制一个范围的内容。比如 y$
将复制当前位置到行末尾的全部内容,yh
将复制光标前面的字符,yG
复制光标所在行到最后一行的所有内容。yy
复制当前行,可以和 dd
一起理解 —— dd
删除一整行,快捷键重复表示操作的是一整行,不管光标位置在哪里。第二个 y
和 d
并没有语义上的含义。zt
zt
把当前行置于屏幕顶端。z
字取其象形意义,模拟一张纸的折叠变形。t
取 top 的首字母。zz
将当前行置于屏幕中央。zb
将当前行置于屏幕底端,b
取 bottom 的首字母。/<pattern>
/
从光标所在位置向后查找关键字,n
/ N
查找下一个 / 上一个匹配的位置。?
向前查找,不过很少使用。如果想向前查找的话,使用 /
+ N
就可以了。q/
、q?
可以列出 /
、?
的查找历史,上下选择,按 i
编辑,回车执行,:q
退出。<pattern>
可以是正则表达式,比如 /vim$
查找位于行尾的 vim
。查找特殊字符时需要转义,比如 /vim\$
查找 vim$
。\c
表示大小写不敏感查找,\C
表示大小写敏感,比如 /foo\c
会查找 foo
、Foo
等。默认是大小写敏感,可以执行 :set ignorecase
或写入配置文件设置大小写不敏感为默认的查找模式。set ic // 等价于 set ignorecase
set hls is // 高亮匹配项
nohlsearch // 移除匹配项的高亮显示
*
↓ 光标在这里
Hello, world!
*
,将查找 Hello
这个单词,并且要求 Hello
出现位置的前后均为空白字符或标点符号,即查找完整独立的单词。%
%
在匹配的括号之间跳转。需要将光标放在 {}[]()
上,然后按 %
。 如果光标所在的位置不是 {}[]()
,那么会向右查找第一个 {}[]()
。<Ctrl> + o
/ i
<Ctrl> + o
将光标跳转到前一个位置,<Ctrl> + i
跳转到后一个位置。h
/ j
/ k
/ l
/ w
等移动将不会记录在「跳转表」中,只有通过 gg
/ nG
/ 查找时的 n
/ N
等命令执行的跳转操作,才可以通过 <Ctrl> + o
/ <Ctrl> + i
来回跳转。补充: 在 VS Code 中,向前一个 / 后一个位置跳转的快捷键是 <Ctrl> + [
/<Ctrl> + ]
。在 Intellij 等 Jetbrains 系列软件中,向前一个 / 后一个位置跳转的快捷键是 <Command> + [
/<Command> + ]
。如果不是,可以在Preferences
中搜索back
,然后在KeyMap -> Main menu -> Navigate -> Back
中设置。
:{range}s/{old}/{new}/{flag}
:s
(substitute)命令用来查找和替换文本。语法如下::{range}s/{old}/{new}/{flag}
range
内查找字符串 old
并替换为 bar
,flag
说明了替换模式,如只替换首次出现、或全部替换。:s/foo/bar/g
%
,如 :%s/foo/bar/g
n,m
,如 :5,12s/foo/bar/g
表示 5.,+n
,如 :.,+2s/foo/bar/g
表示当前行与之后 2 行:%s/foo/bar
g
:全局替换,替换每次出现(global),如 :%s/foo/bar/g
i
:忽略大小写c
:交互式替换,每次替换前需要用户确认(confirm),如 :%s/foo/bar/gc
表示查找全文的所有 foo
并替换为 bar
,每次替换前都需要确认:replace with bar (y/n/a/q/l/^E/^Y)?
y
表示替换n
表示不替换a
表示替换后续所有q
表示退出查找模式l
表示替换当前位置并退出查找模式^E
、^Y
用于向上、向下滚动屏幕,^
表示 <Ctrl>
键:!<command>
:!pwd
,这等同于在 shell 中执行 pwd
。:<prefix> + <Ctrl> + d
:
,再按下 <Ctrl> + d
,将展示所有可以在 vim 中使用的命令。:w
,再按下 <Ctrl> + d
,将展示所有可以在 vim 中使用的、以 w
开头的命令。~/.vimrc
,其内容是若干行可在 vim 中执行的命令,会在每次打开 vim 时自动执行。示例:set number # 显示行号
set ignorecase # 大小写不敏感查找
set ic // 等价于 set ignorecase
set smartcase # 如果有一个大写字母,则切换到大小写敏感查找
set hls is // 高亮匹配项
nohlsearch // 移除匹配项的高亮显示
快捷键 | 作用 |
---|---|
^ | 移动到当前行第一个非空字符 |
<Space> | 向右移动一个字符,等同于 l |
<Alt> + ← , <Alt> + → | 向左 / 向右移动一个单词,等同于 w / b |
:n<enter> | 跳到指定行,等同于 nG |
ngg | 跳到指定行,等同于 nG |
H | 光标移动到屏幕最上方(head) |
M | 光标移动到屏幕中央(middle) |
L | 光标移动到屏幕最下方(last) |
快捷键 | 作用 |
---|---|
向上 / 向下滚动一行 | <Ctrl> + y / <Ctrl> + e |
向上 / 向下滚动一页 | <Ctrl> + f / <Ctrl> + b (forward,backward) |
向上 / 向下滚动半页 | <Ctrl> + d / <Ctrl> + u |
这些命令在大部分 Unix 软件中都可以使用,比如 man
、less
、tmux
(需要先进入滚动模式)
快捷键 | 作用 |
---|---|
ddp | 上下两行交换,实际上就是 dd + p |
J | 将当前行和下一行用空格连成一行 |
Jx | 将当前行和下一行直接连成一行,相当于在下一行的行首按 <Backspace> |
快捷键 | 作用 |
---|---|
:help | 查看帮助文档 |
:help :{command} | 查看一个具体命令的帮助文档,如 :help :q 查看 :q 的帮助文档 |
^y$ | 复制一行 |
ggyG | 复制整个文件 |
q: | 查看历史命令,上下选择,按 i 编辑,回车执行,:q 退出 |
:<command>
执行,也可以写入配置文件。set number # 显示行号
set ignorecase # 大小写不敏感查找
set smartcase # 如果有一个大写字母,则切换到大小写敏感查找
imap ii <Esc> # 在插入模式下,映射 ii 到 <Esc>
# 在标准模式下,禁用方向键
map <Left> <Nop>
map <Right> <Nop>
map <Up> <Nop>
map <Down> <Nop>
set paste # 进入粘贴模式,这可以避免粘贴多行代码时被自动缩进
set nopaste # 粘贴完之后,执行这条命令退出粘贴模式