一、初识
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