管理文件
vim允许同时在多个文件上工作。
用缓冲区列表管理打开的文件
在一次编辑会话中,可以打开多个文件。用Vim的缓冲区列表可以对这些文件进行管理。
此章内容基本只能用于原生vim,编辑器已经提供了很好的文件管理功能,所以略过此处。
用动作命令在文档中移动
让手指保持在本位行上
使用hjkl可以进行左下上右的移动
区分实际行与屏幕行
有时编辑器为了展示一行的完整内容会在屏幕上换行展示,而上面提到的命令是换实际行下面的表格对相关命令进行了总结
| 命令 | 光标动作 |
|---|---|
j |
向下移动一个实际行 |
gj |
向下移动一个屏幕行 |
k |
向上移动一个实际行 |
gk |
向上移动一个屏幕行 |
0 |
移动到实际行的行首 |
g0 |
移动到屏幕行的行首 |
^ |
移动到实际行的第一个非空白字符 |
g^ |
移动到屏幕行的第一个非空白字符 |
$ |
移动到实际行的行尾 |
g$ |
移动到屏幕行的行尾 |
基于单词移动
| 命令 | 动作 |
|---|---|
w |
正向移动到下一单词开头 |
b |
正向移动到当前单词/上一单词开头 |
e |
正向移动到当前单词/下一单词的结尾 |
ge |
正向移动到上一单词结尾 |
理解单词和字符串
我们经常提到单词,但迄今为止,我们都一直未定义过究竟什么是一个单词。Vim 对此有两种不同的定义,并且分别用“单词”(word)和“字串”(WORD)对其进行区分。我们之前遇到过的每个面向单词的动作命令,都有一个面向字串的命令与其对应,这当中包括 W 、B 、E 和 gE 。
一个单词由字母、数字、下画线,或其他非空白字符的序列组成,单词间以空白字符分隔(参见 :h word )。字串的定义则更简单,它由非空白字符序列组成,字串间以空白字符分隔
对字符进行查找
| 命令 | 用途 |
|---|---|
f{char} |
正向移动到下一个{char}所在处 |
F{char} |
反向移动到下一个{char}所在处 |
t{char} |
正向移动到下一个{char}所在处所在的前一个字符上 |
T{char} |
反向移动到下一个{char}所在处所在的后一个字符上 |
; |
重复上次的字符查找命令 |
, |
反转方向查找上次的字符查找命令 |
通过查找进行移动
可以通过/{char}去跳转到其他行的字符,比如:
1 | search for your target |
可以直接使用d/ge完成
用精确的文本对象选择选区
文本对象允许操作括号、被引用的文本、XML标签以及其他文本中的常见结构。
Vim 的文本对象由两个字符组成,第一个字符永远是i或是a。一般以i开头的文本对象会选择分隔符内部的文本,而以a开头的文本对象会选择包括分隔符在内的整个文本。为了便于记忆,可以把i想成“inside”,而把a想成“around”或“all”。
| 文本对象 | 区域 | 文本对象 | 区域 |
|---|---|---|---|
a)或ab |
一对圆括号 | i)或ib |
圆括号内部 |
a}或aB |
- | i}或iB |
- |
a] |
- | i] |
- |
a> |
- | i] |
- |
a' |
- | i] |
- |
a |
- | i |
- |
a |
- | i |
- |
at |
- | it |
- |
用文本对象执行操作
文本对象自身并不是动作命令,不能用它们在文档中移动。但是却可以在可视模式及操作符待决模式中使用文本对象。记住:每当在命令语法里看到{motion}时,也可以在这个地方使用文本对象,常见的例子包括d{motion} 、c{motion} 和 y{motion},更多命令看第二章表。
删除周边,修改内部
范围文本对象
| 文本对象 | 选择范围 |
|---|---|
| iw | 当前单词 |
| aw | 当前单词及一个空格 |
| iW | 当前字符串 |
| aW | 当当前字符串及一个空格 |
| is | 当前句子 |
| as | 当前句子及一个空格 |
| ip | 当前段落 |
| ap | 当前段落及一个空行 |
上面这些命令对中文的支持都非常不好,因为vim评判单词,字符串,等的标准是英文的符号和空格
一般来说,d{motion}命令和aw 、as 和 ap配合起来使用比较好,而c{motion}命令和iw及类似的文本对象一起用效果会更好。
设置位置标记,以便快速跳回
Vim 的位置标记允许我们快速跳转到文档中感兴趣的地方。可以手动设置位置标记,不过 Vim 也会自动记录某些感兴趣的位置点。
m{a-zA-z}命令会用选定的字母标记当前光标所在的位置。小写位置标记只在每个缓冲区局部可见,大写标记则全局可见。
普通模式提供了两个命令来跳转到一个位置标记上:'{mark}命令跳到位置标记所在行,`{mark}命令则把光标移动到设置此位置标记时光标所在之处。
自动位置标记
| 位置标记 | 跳转到 |
|---|---|
| `` | 当前文件中上次跳转动作之前的位置 |
| `. | 上次修改的地方 |
| `^ | 上次插入的地方 |
| `[ | 上次修改或复制的起始位置 |
| `] | 上次修改或复制的结束位置 |
| `< | 上次高亮选区的起始位置 |
| `> | 上次高亮选区的结束位置 |
在匹配括号间跳转
%命令允许在一组开、闭括号间跳转,它可作用于()、{}以及[]。
如果想把cities = %w{London Berlin New\ York}改为cities = [London Berlin New\ York],可以这么做,dt{ -> % -> r] -> `` -> r[
在文件间跳转
本章在编译器中无法使用,故不过多介绍
复制与粘贴
用无名寄存器实现删除、复制与粘贴操作
通常情况下,在讨论剪切、复制与粘贴这3组操作时,指的都是操作系统剪贴板。不过,在Vim的术语里,我们操作的是寄存器,而并非剪贴板。
调换字符
在想调换的一个字符上使用xp命令,x可以将第一个字符剪切下来,并放到无名寄存器中,p命令可以把无名寄存器中的内容粘贴到光标后面。
调换文本行
ddp可以调换文本行,原理同上
创建文本行的副本
yyp可以实现
深入理解Vim寄存器
Vim不使用单一的剪贴板进行剪切、复制与粘贴操作,而是为这些操作提供了多组寄存器。当使用删除、复制与粘贴命令时,可以明确指定它们中的某一个进行操作。
引用一个寄存器
Vim的删除、复制与粘贴命令都会用到众多寄存器中的某一个。可以通过给命令加"{register}前缀的方法指定要用的寄存器。若不指名,Vim将默认使用无名寄存器。
Vim术语对照表
剪切(cut)、复制(copy)与粘贴(paste)这些都是众所周知的术语,而且大多数桌面软件和操作系统都支持这3类操作。Vim当然也提供这些功能,只不过使用的是另外的术语delete、yank与put 。
Vim的put命令与粘贴操作完全相同。幸运的是,两词均以字母p开头,因此即使术语不同,也不会影响记忆。
Vim的yank命令也等同于复制操作。但由于历史原因,当时c命令已经被用于修改(change)操作了,因此Vi的作者们被迫选择了另一个名字yank。由于那时y键还可用,因此它就成了复制操作的命令。
Vim的delete命令也与标准剪切操作的作用一致。也就是说,该命令会先把指定文本复制到寄存器后再从文档中删掉。能够理解这一点,是避开类似 糟糕!我弄丢了复制内容 所遇到的常见陷阱的关键。
你也许好奇,Vim中真正删除文本的操作是什么。也就是说,我们怎样才能删除文本而不把其内容复制到任何寄存器?答案是使用名为“黑洞”的特殊寄存器,顾名思义,放到这里的文本真的是有去无回了。用下画线符号可以引用黑洞寄存器。因此,"_d{motion}会执行真正的删除操作。
无名寄存器(“”)
""可以指定使用无名寄存器,例如""p完全等于p。
复制专用寄存器(“0)
当使用y{motion}命令时,要复制的文本也会被拷贝到复制专用寄存器中,可用0引用,它不会被x,s,c,d覆盖
有名寄存器(“a - “z)
遇到将一段或多段文本粘贴到多处的情况,有名寄存器就会大显神通。
黑洞寄存器
当想彻底删除的时候可以使用"_来引用黑洞寄存器,这时不会覆盖掉无名寄存器的内容。
系统剪切板("+)与选择专用寄存器("*)
如果想要把vim外部的内容粘贴到vim内,或者想将vim中的内容粘贴到外部可以使用
表达式寄存器(“=)
Vim的寄存器通常被认为是保存一段文本的容器。然而,通过=号引用的表达式寄存器却是个例外。当从表达式寄存器获取内容时,Vim将跳到命令行模式,并显示提示符“=”。这时,可以输入一段Vim脚本表达式并按
其他寄存器
| 寄存器 | 内容 |
|---|---|
| “% | 当前文件名 |
| “# | 轮换文件名 |
| “. | 上次插入的文本 |
| “: | 上次执行的Ex命令 |
| “/ | 上次查找的模式 |
用寄存器中的内容替换高亮选区的文本
选区之后使用p会将被替代的内容置入无名寄存器。
交换两个词
de删除单词mm标记位置ww移动到被置换的单词ve选中单词p替换`m返回之前的单词位置- ·
p将前面的单词置换
把寄存器的内容粘贴出来
普通模式下的粘贴命令,根据要插入文本的性质不同,执行结果也不同。确定要粘贴的文本区域是面向行的还是面向字符的,将有助于制定不同的策略。
粘贴面向字符的区域
p在光标后粘贴P在光标前粘贴<C-r>在插入模式下粘贴
粘贴面向行的区域
当要粘贴的内容来自于面向行的寄存器时,p会在当前行下方粘贴,·P在当前行上方粘贴。
与系统剪贴板进行交互
可能会带来许多问题,鉴于我们不是在vim中进行操作,所以建议直接使用系统粘贴快捷键。
### 宏 #### 宏的读取执行
把命令序列录制成宏
q可以开启录制,也可以控制进行停止录制。
qa将宏录制到寄存器a- 一系列操作
q结束录制
可以通过:reg a查询a中的内容
通过执行宏来回放命令序列
通过@a可以重新执行之前的宏
规范光标位置、直达目标以及中止宏
黄金法则:在录制一个宏时,要确保每条命令都可被重复执行。
规范光标位置
应该把光标移到下一处查找匹配项(n),或者当前行的行首(0),又或是当前文件的首行(gg)。如果每次总是从确定的位置开始执行的话,那么命中正确的目标会变得更容易。
用可重复的动作命令直达目标
面向单词的动作命令,如 w 、b 、e 和 ge ,与面向字符的动作命令 h 和 l 相比,更具灵活性。如果录制“动作命令 0 ,后跟 e ”,当每次执行该宏时,我们都能预料得到一致的结果,光标会移到当前行第一个词的最后一个字符上。只要该行包含至少一个词,无论该词包含多少个字符,都能够到达目标。
我推荐用查找命令定位,或者用文本对象。总之,请用好Vim提供的所有动作命令,尽量使你的宏兼具灵活性与可重复性。还有一点别忘了,在录制宏的过程中,禁止使用鼠标。
当动作命令失败时,宏将中止执行
Vim的动作命令可能会执行失败。例如,如果光标位于文件的首行,运行 k 命令将什么也不会发生。若光标位于文件的末行,按下 j 也会出现同样的情况。
如果宏执行动作命令失败了,Vim将中止执行宏的其余命令。
加次数回放宏
对于重复次数不多的工作,点范式是一种高效的编辑策略,但它不能指定执行的次数。为了克服该限制,可以录制一个廉价的、一次性的宏,然后再加次数进行回放。
在连续的文本行上重复修改
对于多行范围内的重复性改动,可以先录制一个宏,然后再在每一行上回放,这将会极大减轻我们的工作量。该功能可用串行或者并行两种执行宏的方式实现。
例如把下面的文本
1 | 1. one |
变成
1 | 1) One |
步骤如下:
qa将宏录制到寄存器a0f.这样可以保证无论从哪行开始都可以准确的移动到第一个.上,增强复用性r)w~将.换成)移动到首单词首字母并将其转换为大写j移动到下一行,这样多次执行宏就可以一直向下一行进行q结束录制
以串行方式执行宏
宏录制好了以后我们使用3@a就可以完成任务了,但是如果文件中包含注释就会带来新的问题
1 | 1. one |
我们可以用并行的方式解决这个问题
以并行方式执行宏
之前说过一种在连续文本上执行.命令的方法,此处也可以使用相同的技术。
qa开始录制0f.r)w~qjVG选中要执行宏的文本:normal @a执行宏
给宏追加命令
如果发现录制完宏后漏了步骤可以使用qA 来在上次录制后追加命令
在一组文件中执行宏
略
用迭代求值的方式给列表编号
如果宏在每次执行时都能插入一个可变的数值,这将会很有用处。在本节中,将学习一种技术,它会在录制宏时使某个数字递增,这样一来,就可以在连续的文本上插入数字1到5。
使用let i = 1可以创建一个名为i的变量,如果想把它插入到文档只需在插入模式下运行<C-r>=i<CR>,例如想把下面的文档
1 | artridge in a pear tree |
转换为
1 | 1) partridge in a pear tree |
可以按照如下步骤进行:
:let i = 1定义变量iqa开始记录宏i<C-r>=i<CR>) <C-[>插入变量,添加文本:let i += 1<CR>q增加变量值,结束录制VG:normal@a执行宏
编辑宏的内容
假设我们将宏存在了寄存器a中,我们可以使用:put a或者ap命令来将其粘贴到文档中,然后就可以像编辑文档一样编辑宏了,编辑结束后将宏放回寄存器最简单的方法就是"add但是这样会导致宏多一个^j,所以最安全的方法还是将宏复制进寄存器后删除。