一、初识
Vim 主要有 4 种模式:
Normal 模式:默认进入的模式,也是最常用的模式。
Insert 模式:插入模式,像正常的文本编辑器一样输入。
Command 模式:命令模式,在底部输入命令。
Visual 模式:可视模式,对文本进行选择。
Normal 模式:基本移动
kjhl:分别对应上下左右
gg:跳到第一行
{n}gg:跳到第 n 行
G:跳到最后一行
<Ctrl-u>/<Ctrl-b>:向上翻半页/一页(当前屏幕显示的行数就是一页)
<Ctrl-d>/<Ctrl-f>:向下翻半页/一页(当前屏幕显示的行数就是一页)
zz/zt/zb:光标行设置为 屏幕居中/屏幕第一行/屏幕最后一行
进入 Insert 模式
Normal 模式下通过特定命令进入 Insert 模式:
i:代表 “insert”,当前光标之前开始输入a:代表 “append”,当前光标之后开始输入o:下方插入新的一行,然后开始输入s:删除当前光标的字符,然后开始输入I:在本行的开头开始输入A:在本行的末尾开始输入O:上方插入新的一行,然后开始输入S:删除当前行,然后开始输入
Tips:大写字母和小写字母的操作存在关联,可以一起记忆。
进入 Command 模式
Normal 模式下输入: 进入 Command 模式
:w:保存当前文件:q:退出:q!:放弃当前更改,强制退出:wq:保存当前更改,然后退出:h {command}:显示关于命令的帮助
<Esc>:回到 Normal 模式
Tips:使用 :h {command} 进入到帮助文档之后,可以直接输入 :q 退出帮助文档
进入 Visual 模式
Normal 模式下按 v 进入可视模式
进入可视模式后可以用 Normal 模式下的移动命令选择文本
可视模式下 x/y:剪切/复制;回到 Normal 模式下 p:粘贴
Normal 模式下按 v 进入可视模式,一次选中一整行,在需要选中多行时很方便
<Esc> 回到 Normal 模式
二、移动与编辑
基于单词的移动
除了简单的 kjhl 移动之外,vim 还支持更高级的移动
w:代表 “word”,跳转到下一处单词的开头
b:代表 “back”,跳转到上一处单词的开头
e:代表 “end”,跳转到下一处单词的结尾
ge:e 的反向版本,跳转到上一处单词的结尾
wbe 版本以空格和各种符号为分隔符,大写版本 WBE 对应单词时连续的非空字符也就是只以空格为分隔符
Tips:这里的下/上一处单词的并不是下/上一个单词,而是下一处位置

基于搜索的移动
行内搜索:
-
f{char}/t{char}:跳转到本行下一个char字符出现处/出现前 -
;/,:快速向前/向后重复上一次f/t查找的char;如果使用;/,之前没有进行过f/t则默认查找当前光标指向的字符 -
F{char}/T{char}:往前搜索而非往后
文件中搜索:
/{pattern}:跳转到本文件中下一个pattern出现的地方?{pattern}:跳转到本文件中上一个pattern出现的地方pattern:可以是正则表达式-
*:等价于/{pattern},其中pattern是当前光标下的单词 n/N:快速重复对//?中的字符或单词进行查找,n是正向,N是反向
基于标记的移动
m{makr}:把当前位置标记为mark- ``{mark}
:跳转到名为mark` 的标记位置
mark 是 a-z 的字符
常用场景:当需要临时离开当前光标处,做一些事情后再快速地回来
内置标记:
- ` `` `:上次跳转前的位置
- ``.`:上次修改的位置
- ``^`:上次插入的位置
其他实用的跳转
^/$:跳转到本行的开始/结尾%:跳转到匹配的配对符(括号等)处
Operator+Motion=Action
{operator}{motion}:一次编辑动作
常见操作符:
c:代表 “change”,修改,删除内容并进入插入模式d:代表 “delete”,删除y:代表 “yank”,复制v:代表 “visual”,选中文本,进入可视模式
大部分操作符连续按两次 (cc/dd/yy):将其作用在光标所在的行上
“操作符+移动” 是非常重要的操作罗技,它允许你组合出各种动作
重要操作:. 命令
.:重复上一次修改u:撤销上一次修改<Ctrl-r>:重做上一次撤销
. 命令非常适合用于需要多次重复某一个修改动作的场景,省去了重复输入命令,提高效率
批量操作:数字+动作
{count}{action}:重复 count 次 action 动作
动作可以是移动动作或是编辑动作
4j:向下移动 4 行3dw:删除 3 个单词2yy:复制 2 行4p:粘贴 4 次
数字+动作,是一种重要的批量操作方式,命令直观,语义明确
.命令可以直观地看到每一次的变化,在合适的时候停止- 数字+动作则需要预先知道动作的次数
技巧:使用相对行号确定移动范围
当涉及行操作时,使用相对行号能够更直观地确定范围
:set relativenumber:开启相对行号
:set norelativenumber:关闭相对行号
小结
- 掌握进阶的移动与编辑命令
- (重要)掌握
{operator}{motion}的操作哲学 - 掌握用
.命令重复上一次修改 - (重要)掌握使用
{count}{action}进行批量操作
三、文本对象操作
文本对象操作
textobjects:语义化的文本片段
格式:i/a + 对象
常见的对象:
w/W,s,p:单词、句子、段落(/),[/],{/},</``>,’/”`:配对符定义的对象
i 代表 “inner”,对象内部;a 代表 “a”,表示一个对象额外包括周围的空格或配对符

举例:
文本对象提供了为文本赋予结构化的含义,允许我们以一个语义对象作为操作单元
[count]{operator}{textobjects}
diw:删除一个单词ci(:修改小括号内部yi{:复制大括号内部
通过组合 operator 和 textobjects,可以对不同的语义对象实施不同的操作,不仅十分灵活,而且语义明确,容易记忆
配合 . 命令或者 [count] 可以简单地完成多次对特定语义对象的操作
textobjects VS motion
{operator}{motion} 与 {operator}{textobjects}
解耦了操作与操作的对象,大大提高了操作效率
motion是能够移动光标的命令,可以独立使用(如wbe)- 文本对象只能跟在
operator后面,不能独立使用(如iw) motion通过光标的移动确定operator的作用范围,范围更加灵活但不够明确textobjects则是显式地指定操作的对象,范围明确
扩展
{operator}{motion} 与 {operator}{textobjects}
有些插件可以通过自定义 operator、motion、textobjects 进行扩展,实现更强大的操作
- vim-easymotion:扩展
motion,更强大的跳转功能 - vim-surround:定义了添加配对符(括号、引号等)的
operator - vim-commentary:定义了添加注释的
operator - targets.vim:扩展
textobjects,定义了新的文本对象,如函数参数等
操作符与命令补充
gu{textobjects}/gU{textobjects}/g~{textobjects}:操作符,转小写/转大写/翻转大小写J:join,连接两行<Ctrl-a>/<Ctrl-x>:增加数字/减少数字g<Ctrl-A>:创建递增序列</>:连按两下进行左/右缩进
建议:让你的命令更模块化
尽量使你的命令更模块化,具有清晰的含义与作用范围,以便于与 . 等命令协同
例如:daw 比 dw 具有更清晰的语义,也更模块化
练习技巧:用 v 先可视化修改的范围
一开始不熟练时,可能不确定 motion 或 textobjects 具体覆盖了哪些部分文本,可以先用 v{motion}/v{textobjects} 将范围选中,再执行 c/d/y 等操作
但是,当熟练掌握后,尽可能直接使用完整的命令进行操作,因为相比于 viwd,diw 更加模块化,也更容易进行重复操作
小结
了解常用的文本对象
(重要)掌握 {operator}{textobjects} 的操作哲学
尽量使你的命令模块化,语义清晰,易于重复
四、寄存器与宏
寄存器
Vim 提供了许多寄存器用于存放内容,可以理解为剪切板
一个字符对应一个寄存器(如 a-z,0-9)
特别的寄存器:
":双引号,默认寄存器,平时复制、删除的内容都放在里面%:当前文件名.:上一次插入的内容::上一次执行的内容
通过 :reg {register} 查看对应寄存器中的内容
通过 :h registers 查看寄存器的帮助文档
指定寄存器
在复制/删除/粘贴等操作前加上 "{register} 就可以指定本次操作所用的寄存器
只要设计寄存器操作的都可以这样指定
"ayy:将这一行复制到a寄存器中"bdiw:将单词删除,保存到b寄存器中"cp:将c寄存器中的内容粘贴出来
常见用途:将想要持久保存的文本放到特定寄存器中,随时进行粘贴,避免被覆盖
寄存器字符大写:代表添加(append)而非覆盖。
宏
宏(Macro):录制一系列键盘操作,并允许我们重放这些操作
操作序列存储在指定的寄存器中
q{register}:开始录制宏,存放在寄存器register中- 录制过程中按
q退出录制 @{register}:重放寄存器register中的操作@@:重放上一次宏操作
常见用法:q{register} 录制一段操作,@{register} 重放,然后一直 @@ 重放这段操作
注意:
.命令对宏不生效,.命令只记录上一次修改,而宏可能包含多次修改
建议:让你的宏对连续重放友好
- 让你的光标移动更加 general
- 假设你要在多个特定的位置进行特定的操作,一个好的习惯是在宏录制的最后,跳转到下一个需要编辑的位置 即,宏包括【编辑动作】+【跳转到下一个需要编辑的动作】 这样一来,连续重放就可以实现对所有需要编辑的位置进行编辑操作
通过大写的寄存器,在宏的后面添加命令
如果宏是重放友好的,允许我们使用 [count]@{register} 直接重放 count 次
小结
- 了解寄存器的概念
- 了解常用的内置寄存器
- (重要)掌握使用宏进行批量操作
五、命令模式
前面的教程大多集中在 Normal 模式
命令模式提供了除了 Normal 模式的编辑方式
命令模式的操作对象以”行“为基本单位
normal 和 global 命令提供强大的批量行操作
Ex 命令格式
:[range] {excommand} [args]
range:作用的范围,缺省默认本行excommand:特殊的命令,适用于 Command 模式args:后续的参数,依命令而定
一些 Ex Command ([x] 为寄存器,是可选项):
:[range] delete [x]:删除range中的行(到寄存器x),delete可简写为d:[range] yank [x]:复制range中的行(到寄存器x),yank可简写为y:[range] print:将range中的行打印出来,print可简写为p
range 与 address:指定范围
range 由一个或两个 address 构成,即 {address},{address}
address 可以是:
{lineno}:行号,如3代表第三行(O 代表第一行上面的虚拟行)$:最后一行.:光标所在行/{pattern}/:下一个pattern所在的行
address 可以做加减法,.+3 代表光标往下第三行,$-3 代表倒数第 4 行
aaddress 组合成 range
address 组合出 range(可以混用):
1, 3:文件的 1-3 行., .+4:当前-当前往下 4 行(共 5 行)$-3, $:文件的最后 4 行
%:特殊的 range,代表当前文件的所有行
'< /'>:可视模式中选中范围的开头和结尾(可视模式下直接按 : 可以直接设置)
例子:
1, 3 delete:删除 1~3 行., .+4 yank:复制当前~当前往下 4 行$-3, $ print:打印文件的最后 4 行
行的复制、移动、粘贴
:[range] copy {address}:把range中的行复制到address后面:[range] move {address}:把range中的行移动到address后面:[address] put [x]:把寄存器x的内容粘贴到address后面
0 作为虚拟行的 address,可以用来将内容插入第一行
Ex 命令
删除、拷贝、打印:
:[range] delete [x]:[range] yank [x]:[range] print
复制、移动、粘贴:
:[range] copy {address}:[range] move {address}:[address] put [x]
Ex 命令和 Normal 模式下的编辑操作有区别?
- 命令模式下的编辑操作以”行“为单位
- 命令模式下的编辑操作无需移动光标
批量操作:normal 命令
格式::[range] normal {commands}
含义:对 range 中的所有行执行 Normal 模式下的命令 commands
- 将
range设置为%,可以对整个文件的所有行执行 -
:[range] normal .:配合.命令,效果拔群 常用做法:先做一次修改操作,再用 normal 命令在指定的行上完成操作 .命令只能记录一次修改,用宏可以实现记录多个操作:[range] normal @{register}常用做法:先把想要的操作录制成宏,再用 normal 命令在指定的行上重放 宏
举例:1, 4 normal I#
批量操作:global 命令
格式::[range] global/{pattern}/[cmd]
含义:对 range 中包含 pattern 的所有行执行 Command 模式下的 Ex 命令
[cmd]:Ex 命令,缺省默认是打印(print)
注意:normal 命令也是 Ex 命令
:[range] global/{pattern}/normal {commands}:对 range 中所有带 pattern 的行,执行 Normal 模式下的命令 commands
举例::% global /TODO/delete:删除所有带 TODO 的行
替换命令
:[range]s/{pattern}/{string}/[flags]
将 pattern 替换为 string,默认只替换第一个匹配
flags:
g:替换每一行的所有匹配i:忽视大小写c:替换前进行确认n:计数而不是替换
:%s/Vim//gn:统计文件中所有 Vim 出现的次数(此时替换为什么无所谓,加了 n 就不会执行替换操作)
小结
- 了解常见的 Ex 命令
- 了解
address和range的概念 - (重要)掌握如何使用 normal 命令批量运行 Normal 模式的命令
- (重要)掌握如何使用 global 命令批量运行 Command 模式的 Ex 命令

推荐资料:官方文档:vimtutor,《practical vim》
参考:https://www.bilibili.com/video/BV1s4421A7he/?spm_id_from=333.337.search-card.all.click&vd_source=e168f5e534dbfee9b7d558d35e4ee09e