站内链接:

操作对象

命令格式

一个基本的 vim 命令格式:<operator> [count] <动作>|<文本对象>

  • operator: 操作符,表示要进行的操作
  • count: 数量,可选值,指定操作应该应用的次数
  • motion:动作,指定光标移动的方向和范围
  • text object: 文本对象,与动作互斥,指定在特定文本块上执行操作,文本对象通常用于比光标移动更精确的文本选择

根据上面的命令介绍给出一些基本的命令实例

  • dd: 删除当前行(operator + motion)
  • 2dd: 删除当前行和下一行(operator + count + motion)
  • viw:在可视模式下选择当前单词,不包括周围的空格

motion

在讲解所有的 vim 命令之前必须先简单的了解下操作对象选择,毕竟没有待操作对象,再多的处理动作都是空中楼阁。例如下面的一些命令:

  • b: 反向移动一个单词,默认的操作对象是当前光标所在位置前后的单词
  • 3b: 反向移动 3 个单词

结合上一节的命令格式,操作对象一般分为两类:动作、文本对象,其中 motion 是一种用于在文本中移动光标的命令。它允许你在文本中跳转到特定的位置或者选择一定范围的文本, 下面是 motion 的常见分类:

  • 上下左右动作, 见h, j, k, l
  • 单词动作, 如w,e,b等,见 help word-motions
  • 行级别动作,如0-行首,^-行内第一个非空白字符,$-行尾
  • 查找字符动作,若f,F,t,T
  • 跳转, 如gg, G, ctrl+b, ctrl+f,H-移动到屏幕底部的行,M-移动到屏幕中间的行,L-移动到屏幕底部的行,见 help jump-motions

motion 命令允许您快速准确地在文件中移动,无需使用鼠标或箭头键,从而提高编辑效率,其一般和操作符相结合,而且同其他命令结合能够产生更加高效复杂的文本命令。

text object

文本对象指一块特定的文本区域,其不仅可以是单词或句子,还可以是代码或括号内的内容,文本对象允许用户快速选中并对这些区域进行编辑操作,如删除、复制、更改等。下面是文本对象常见分类:

  • 单词: aw, iw
  • 句子:as, is
  • 段落:ap, ip
  • 括号内容: a(, i(

通过对比 motion 和 text object 可以得出

  • motion 命令主要用于光标的移动,其关注从当前位置到另一个位置的移动,其一般和操作命令配合完成文本编辑任务
  • text object 主要用于指定编辑命令的作用范围(结构化块),其关注围绕或包含光标当前位置的文本块,其指定了一个明确的文本区域作为操作的目标

虽然 text object 在使用频率相比 motion 更加小,但是 text objects 从定义上看更加贴近操作对象这个概念,而且作用的选择范围也更加宽泛(段落、句子等)。另外,通过结合 motion 和 text object,在 vim 社区提出了object-motionsobject-select两个概念:

  • 文本对象动作, help object-motions:利用 “motion” 命令和 “text objects” 结合的方式来移动光标或选择文本,例如daw就是opeartor + 文本块
  • 文本对象选择, help object-select:使用 “text objects” 来选择文本区域的操作,特别是在可视模式(Visual Mode)下,例如可视模式下使用iw选择一个单词内的文本

注意,object-select一般在”可视模式”以及”operator”后面生效, 用于选择某一个限定的对象.其中操作符之后的文本作用范围见文档-[非]块对象的说明。下面是一些常见的选择命令:

1
2
3
4
5
6
aW: 选择一个字串, 光标所在的字串
as: 选择一个句子
ap: 选择一个段落
a]: 选择[]之间的内容
a': 选择''之间的内容
at: 选择html标签内的内容

其命令格式一般为operator + a/i + 分隔符文本对象,其中a/i表示:

  • i(inside)–选择分隔符内的文本
  • a(all)–选择包括分隔符在内的文本

操作符

操作符(Operator)是用于对文本进行操作的命令。它们通常用于在文本中执行删除、复制、替换等操作,下面是一些常见的操作符:

  • d:删除选中的文本,类似于剪切操作。
  • c:修改(替换)选中的文本,类似于剪切并进入插入模式。
  • y:复制选中的文本,类似于拷贝操作。
  • >:向右缩进选中的文本。
  • <:向左缩进选中的文本。
  • =:对选中的文本进行自动缩进。
  • g~:反转选中文本的大小写。
  • gu:将选中的文本转换为小写。
  • gU:将选中的文本转换为大写。

关于操作符的详细信息见: help operator。Motion/文本对象 和操作符(Operator)是密切相关的概念。操作符是用于对文本进行操作的命令,例如删除、复制、替换等。而 Motion 是用于在文本中移动光标的命令,用于指定操作符的作用范围。

在 Vim 的操作中,通常先输入一个操作符,然后再输入一个 Motion/text objects 来指定操作符的作用范围。例如,假设你想要删除一行文本,你可以使用 d 操作符(表示删除)后跟一个 Motion 来指定删除的范围:

  • dd:删除当前行。
  • d2j:删除当前行及其下面的两行(总共删除三行)。
  • dG:删除当前行及其后面的所有行(删除到文件末尾)。

基本命令

插入命令

  1. 移动插入命令
1
2
3
4
5
6
7
8
i           " 光标首插入
A " 行尾部插入,该命令非常有用(等同于$a的集合体)
wa " 自定义的命令连用,先移动,之后进行插入操作
o " 新建一行,并进入插入模式(等同于A+<CR>)
O " 上方新建一行,并进入插入模式(等同于ko,或k$a<CR>,千万别学后者)
I " 行首插入
a " 光标尾插入
ea " 词尾插入
  1. 插入选择,进入普通模式,执行一次 action,之后再次回到插入模式, 例如:
1
2
" 删除一行并重新输入(蛮常用的)
cc

移动命令

  1. 屏幕移动
  • 半屏幕:下移:Ctrl + D, 上移:Ctrl+U
  • 整个屏幕:ctrl + B、ctrl + F
  1. 字符移动:操作对象为行, 当前行到行尾的查找
1
2
3
4
f              " 向前移动光标到字符所在位置
F " 向后移动光标到字符所在位置
t " 向前移动光标到字符所在位置的前一个位置, 比f{char}有用
T " 向后移动光标到字符所在位置的后一个位置
  1. 单词或字符串移动

*, 微型的宏命令,选择光标所在的字符串作为匹配对象

1
2
3
4
5
6
7
8
W              " 说明:WROD--所有非空白字符组成的任意长度的串,只要不是空白串
w " 下一个单词的开头
B " 反向移动到上一个字串
b " 反向移动当前单词或者上一个单词
E " 下一个字串的尾部
e " 当前单词或者下一个单词的结尾
gE " 反向移动到上一个字串的尾部, 注意尾部
ge " 反向上一个单词的尾部
  1. 更改光标位置
1
2
3
4
H              " 屏幕开头
zt " 置顶(重要)
zz " 当前光标所在位置移动到屏幕中间,重画屏幕(多用多用多用)
zb " 置底
  1. 括号间跳转:在开、闭括号之间跳转

使用命令:%,其作用对象:()、{}、[],例如:ft{ --> % --> r] -->--> r[ 将{}更改为[],使用到%以及标记命令

更新命令

  1. 普通模式: 一次修改可以是字符、整行、整个文件. 其中一次修改: 最后一次命令 + motion
1
2
3
4
5
x           " 作用于字符
dd " 作用于行对象
>G " 作用于整个文件(缩进+G组合命令)
r " 替换光标下的字符
R " 替换并写入字符串
  1. 插入模式, 每一次修改动作:进入插入模式+...+ESC 结束(包含进入 insert 模式的最后一个命令),注意:如果发生光标移动,则会重置修改状态

  2. Virtual 模式,每一次修改: 进入可视模式+选择对象+…+ESC(如果进入插入模式)

  3. 替换模式,注意使用 r 产生了一个非常棒的方法,利用 r+Enter 键,进行换行操作,只不过会删除当前 cursor 下的字符

1
2
3
4
5
6
7
r        " 当前cursor下的字符
R " 一直更改,直到ESC
" 已退为进,完成离散的更改, 即换一种思维或者思路,推倒重来,
" 例如在一个“+”的前后加上空格, 操作过程
f+ " 查找,此时该命令记录到命令缓存中
dw " 执行update操作, ESC退出
;. " 来重复修改

删除命令

  1. ‘’之间字符

使用 vim 中的文本对象选区功能,涉及到的命令有:i 和 a,其中 i 选定文本对象之间的内容,注意,这里的 i 和 a 并不是动作命令删除’’之间的字符之后进行插入操作:ci'

  1. 行尾空格
1
2
" \s在正则中表示所有的空格,即\s\+$匹配所有末尾的空格
%s/\s\+$//g
  1. 删除并进入输入模式
1
2
3
4
cc       " 删除一行(特殊的语法规则)
C " 删除从光标到行尾的所有字符(等同于c$)
s " 删除当前cursor下的字符,进入insert模式(等同于cl)
S " 删除当前cursor所在的行,进入insert模式(等同于^C、^c$)
  1. 删除 motion
1
2
cw       " 删除一个单词,进入insert模式
daw " aw表示作用对象是当前光标所在的整个单词,例如vaw、caw、gUaw
  1. 删除单词(重要),在插入模式下使用,无需进行插入-选择模式操作就可以达到目的
1
2
3
<C-h>    " 删除前一个字符
<C-w> " 删除前一个单词
<C-u> " 删除到行首

Undo/Redo

把握撤销的力度

  1. 命令
1
2
3
4
u           					" 一直往后撤销
U " 撤销当前行的所有修改,之后就一直循环
ctrl + r 或者 :redo " Redo操作
. " 重复命令

另外,undo/redo 命令前面可以加上 count,例如2 Ctrl + r将重做最近被撤销的两次操作

  1. Granularity

将撤销单元尽可能的切成规整的小块单元,保证撤销的粒度在合理且高效的处理范围内。例如: 输入一长串的字符串(超过一百行),此时发现最后的 50 个字符出错,如果使用 u 命令,会撤销所有输入:

  • 如果停顿(画家开始构思了),构建断点,ESC,之后可以使用 A 重新开始输入
  • 在连续性的多行操作时,将换成 ESC+o
  1. 重置粒度: 类似于’.’范式中一次修改动作的重置,在插入模式下如果使用光标键(上下作用),则断点会发生重置

Case-sensitive

  1. 用于将当前光标或者选中的字符变为大写或小写的命令
1
2
3
4
5
6
7
8
9
10
~           "反转光标下的字符
g~ "反转{motion}跨越文本的大小写, Enter表示字符串
g~~ "切换当前行的大小写
{Visual}~ "切换高亮文本的大小写
gu "将{motion}文本变为小写, 此时使用map来完成, 例如:
" map! <C-F> <Esc>guiw`]a
"在插入模式下, 将光标之前的单词变为小写, 这里用到了"mark-motions"
gU "大写
guu "小写整行
gUU "大写整行

注意:这里的操作对象类似于缩进中的说明, 具体见vim model.

  1. 数学运算
1
2
3
4
<C-a>          " 增加
<C-x> " 减少

插入模式:=6*35

重复和宏

help single-repeat, help multi-repeat

vim 本身对重复性操作进行了优化,记录最近的操作,之后使用极为精短的按键就可以重复之前的工作。注意:对于每一个重复性工作,必须实现认真规划按键动作,从而完成任务。

single-repeat

单次重复,允许用户重复上一次的命令或操作,常见的single repeat命令如下:

  • .:微型的宏结构,用于重复一次完整的修改, 注意不能重复”Ex-命令行”命令,’.’范式表示一次按键移动,一次按键 motion

  • ; and ,:微型的宏结构,用于重复最近一次使用 f, F, t, T 命令的搜索动作,其中;用于重复上一次命令的搜索方向,,则是相反,重复上一次命令的相反搜索方向

  • @::微型的宏结构,在普通模式下通过@+:组合键重复执行上一次的 EX 命令,测试过程如下:

1
2
3
4
首先执行:%normal A kuang 在每一行末尾添加字符串
重复执行:@:
重复插件推荐: vim-repeat
多次执行:[count]@:,此时就变为multiple-repat命令了
  • &:微型的宏结构,重复上一次的替换操作,相当于执行了上一次使用的 :s(substitute)命令,但不包含任何参数

  • n/N:查找模式下的重复按键(n/N)

Ex 命令是一类在命令行模式(Command-line Mode)下执行的命令,它们源自 Vim 的前身——Ex 编辑器,例如:w, :s/old/new/g, :set option等命令,更详细的说明见vim 模式中的介绍。

Multiple Repeat

多次重复命令和单次重复命令的区别就是次数,他们操作的对象主体都是命令或者宏,例如上面的宏命令:

1
2
3
4
录制宏:按下q,按下任意字母,比如c,此时就进入@c记录器了
执行命令:注意,这里输入的命令必须是后续在普通模式下可以执行的命令
结束录制:再次按下q结束录制
重复命令:使用@c重复执行在执行命令阶段输入的命令

对于single-repeat则仅仅需要输入@c即可,对于multiple-repeat则输入3@c就表示执行 3 遍。单次重复适用于快速重做一个操作,而多次重复适合于批量执行相同操作

宏命令

宏,将任意数量的按键操作录制到寄存器,之后进行回放,类此流量回放,自动化测试回放等等。宏的使用实例在上面章节已经介绍,下面是使用宏的基本命令:

1
2
3
4
5
q{register}                  开始录制宏
q 停止录制宏,此时查看寄存器中的内容:reg {register},就会发现刚刚所有的按键操作
@{register} 执行一次已录制的宏
{number}@{register} 执行多次已录制的宏
@@ 重复最近调用的宏
  1. 执行方式
  • 串行执行:一次执行一个宏,然后再执行下一个宏。这种方式通常用于需要按照特定顺序处理文本的情况,每次宏执行完毕后,下一次执行可能依赖于前一次执行的结果,一旦中间发生警告,则会直接中断宏的执行。例如对于需求:在每行的开头添加特定的标记,然后在每行的结尾添加另一个标记,则需要录制宏:行首的添加操作、行尾的添加操作,并且这两个宏是顺序执行的。
  • 并行执行:指一次性执行多个操作的宏,这些操作对每个目标都是相同的,而不依赖于它们执行的顺序,例如对于需求:多个行的开头都添加相同的标记,则需要录制宏:在一行开头添加标记,然后使用 :normal 命令或重复执行宏的方式多次执行
  1. 黄金规则:确保录制一个宏时,保证每一条命令都可以被重复执行,从而高效准确的重复利用宏

  2. 常见错误

  • 在编写代码时,常常会错误的开启宏录制功能,此时状态栏会显示“记录中”,此时尽快退出

缓冲和窗口

vim 中有很多与文件操作和管理有关的术语或功能,比如缓冲区、缓冲区之上的窗口、filetype 和文件编码等,下面就简单的介绍下这些术语或功能。

缓冲区

  1. 缓冲区

缓冲区是 Vim 中的一个核心概念,Vim 为打开的文件内容在内存中的临时存储区,每次打开或新建一个文件都会对应的创建一个文件缓冲区,注意,这个缓冲区是直接加载到内存区域中的(这也是 vim 不能编辑大文件的根源吧?)。缓冲区允许用户对其中的内容进行增删改查操作,但不会立即影响磁盘中真正的文件内容(异常推出时会保存为.swp 临时文件),只有:w成功保存之后才会将数据输入磁盘中。

通过缓冲区是编辑过程中的工作区,让用户可以自由地进行文本编辑和其他操作,而不必担心对原始文件造成即时的或不可逆的更改,而且由于是缓冲区的缘故,vim 才会产生各种各样华丽的操作。正因为是内存中的文件, 所以 vim 对于大文件的操作性非常不好。下面是一些常用的缓冲区命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
" 1. 保存或者重新载入缓冲区
write/wall " 保存
quit/qall " 退出并检查是否改动,如果发生改动则无法正常推出
quit!/qall! " 退出并不检查是否改动
edit! " 重新读取文件,删除刚刚所做的更改
edit %<Tab> " 获取当前活动缓冲区文件的完整路径(相对)
edit %:h<Tab> " 仅仅获取当前活动缓冲区的目录路径

" 2. 缓冲区列表或切换
buffers " 当前所有缓冲区
buffer [N]
[N] buffer " 切换到第N个缓冲区
buffer filename
b filename " 选择缓冲区中的某个文件
bfirst/brewind " 切换到第一个缓冲区
blast " 切换到最后一个缓冲区

" 3. 缓冲区数据清理
bdelete begin-n,end-num " 删除缓存格式
rewind, first " 编辑第一个缓冲文件并重置更改
last " 编辑最后一个缓冲文件并重置更改
all " 整理所有缓冲文件

" 4. 打开vim文件时的所有参数列表,例如vim a.md,则参数列表就是[a.md]
args
  1. swap 文件

前面提到,vim 在编辑文件之后发生异常的时候会文件所在目录下,创建文件名以 .swp.swo.swn 等扩展名结尾的临时的交换文件,这些文件统一被称为 swap 文件,它实际上就是文件缓冲区的磁盘存储部分,在每次编辑或新建文件的时候都相应的在磁盘上创建一个相关临时 swap 文件,用于存储未保存的更改,从而在系统异常的时候进行数据恢复。

缓冲区数据是完全存储在内存中的,它是用户文件编辑操作的直接对象,但是在 vim 后台有进程(猜测,可能是假的,但是应该类似吧)将这些数据定时刷新到 swap 磁盘文件中。所以,从存储位置、存储目的、生命周期三个角度看 buffer 和 swap 是不同的,但是他们两又是前后紧密合作的。

窗口

缓冲区是内存中的文本文件,窗口是缓冲区的视窗,在 vim 中的所有操作都是在 buffer 进行的,自然而然,每一个操作窗口标签页是窗口的集合,他们两的区别如下:

  • “窗口” 被用来查看缓冲区里的内容。你可以用多个窗口观察同一个缓冲区,也可以用多个窗口观察不同的缓冲区。
  • “缓冲区” 是一块内存区域,里面存储着正在编辑的文件(亦或帮助文件、目录列表等)。如果没有把缓冲区里的文件存盘,那么原始文件不会被更改。

另外,vim 支持多窗口,这确保了 vim 可以同一时间内编辑多个文件或者多窗口查看同一个文件,其中每个窗口都有自己的光标信息、折叠状态信息等,这是窗口非常重要的功能。

  1. 切割命令
1
2
3
4
5
6
7
8
9
10
11
sp                      " 水平切割,并在新窗口中载入file
vs " 垂直切割,并在新窗口中载入file
<C-w> s " 水平切割,在新窗口中任然显示当前缓冲区
<C-w> v " 垂直切割,在新窗口中任然显示当前缓冲区

clo/q " 关闭活动窗口
on " 关闭其他窗口(非常有用)

<C-w>= " 使所有窗口等宽、等高
<C-w>_ " 最大化活动窗口的高度
<C-w>| " 最大化活动窗口的宽度
  1. 移动命令 s
1
2
<C-w>w                 " 窗口循环切换
<C-w>h/j/k/l " 左右上下切换

寄存器

分类和命令

寄存器(Registers)是用来存储文本、命令、搜索模式等信息的临时存储空间,通过寄存器可以将命令(宏则是一组)或文本放入其中,后续可以通过类似重放的方式重复的复制或执行这些内容或命令,在 Vim 正常使用过程中这是非常高频的用法:复制黏贴(通过 xterm_clipboard 还可以同系统交互)、命令、搜索和替换、宏录制。Vim 提供 10 类寄存器,大约 48 个寄存器,用以实现复制黏贴功能。

  1. 寄存器分类
  • "":无名寄存器,比如执行删除操作 d、x 命令时,被删除的文本默认会存储到未命名寄存器中,此时使用 p 会立即黏贴该文本
  • "0, ... ,"9:数字个编号寄存器
  • "-:小删除寄存器,用于存储较小的删除操作的内容,通常是少于一行的删除,例如
  • "_:黑洞寄存器寄存器
  • "a 到 "z,"A 到 "Z:26 个命名的寄存器
  • ":、". 和 "%:三个只读寄存器
  • "#:轮换缓冲区寄存器
  • "=:表达式寄存器
  • "*、"+ 和 "~ :选择和拖放寄存器
  • "/:最近搜索模式寄存器
  1. 命令,当使用寄存器的时候,可以通过按键" + 寄存器名来使用寄存器进行数据的录入和输出,下面一些常用的寄存器相关命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
" 1 查看寄存器中的内容
reg "0
reg

" 2 其他命令
"ayiw "复制单词到寄存器中
"ap " 输出register-a中的内容到当前光标处
"_dw " 黑洞寄存器, 相当于真正的删除, 不会有缓存
"% " 当前文件名, 只读, 用法: "%p
"# " 轮换文件名
". " 上次插入的文本
": " 上次执行的ex命令
"/ " 上次查找的模式
"*/+/~ " 获取和保存 GUI 界面选择的文本
  1. 插入模式下的寄存器使用

普通模式下使用寄存器的方法非常简单,通过" + 寄存器名即可实现,那么在插入模式下应该怎么使用寄存器呢?通过<C_r>{register}可以将指定寄存器中的值复制到当前输入位置。另外,还可以通过该方式进行数学运算。

系统剪贴板

寄存器的使用仅能在 vim 的多个 buffer 之间实现数据的复制黏贴,但是脱离某个 vim 独立进程就无法在多个打开的标签之间、vim 和外部程序之间进行数据的复制黏贴。

这里就需要引入 xterm_clipboard 编译项支持,另外 mac 需安装 macvim, 确保能进行 vim 和 GUI 的交互,这样就能基础系统剪贴板进行数据的复制黏贴了

  • */+功能类似,在 x11 系统中,前者存放选中或者高亮的内容,后者存放复制和剪贴的内容
  • "*p 命令可以避免使用 F7 命令的缩进行为(非常棒的方法)
  • 格式: {virtual}"+y, "+y{motion}

其整体流程如下

1
2
3
4
5
6
7
8
9
# 1 vim-->clipboard
"*y 或者 "+y
"+2yy 或者 "+dd

# 2 clipboard ---> vim 避免重复的使用:set paste的按键开销(重要)
"+p 或者 "*p

# 3 Shift + Insert 插入模式下的拷贝
<c-r> + -