0%

vim(2)

管理文件

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
2
3
4
search for your target
it only takes a moment
to get where you want
#删除taskes到to的内容

可以直接使用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脚本表达式并按 执行,如果返回的是字符串(或者可被强制转换成字符串的数据),Vim将会使用它。

其他寄存器
寄存器 内容
“% 当前文件名
“# 轮换文件名
“. 上次插入的文本
“: 上次执行的Ex命令
“/ 上次查找的模式

用寄存器中的内容替换高亮选区的文本

选区之后使用p会将被替代的内容置入无名寄存器。

交换两个词
  1. de 删除单词
  2. mm标记位置
  3. ww移动到被置换的单词
  4. ve选中单词
  5. p替换
  6. `m返回之前的单词位置
  7. ·p将前面的单词置换

把寄存器的内容粘贴出来

普通模式下的粘贴命令,根据要插入文本的性质不同,执行结果也不同。确定要粘贴的文本区域是面向行的还是面向字符的,将有助于制定不同的策略。

粘贴面向字符的区域
  1. p在光标后粘贴
  2. P在光标前粘贴
  3. <C-r>在插入模式下粘贴
粘贴面向行的区域

当要粘贴的内容来自于面向行的寄存器时,p会在当前行下方粘贴,·P在当前行上方粘贴。


与系统剪贴板进行交互

可能会带来许多问题,鉴于我们不是在vim中进行操作,所以建议直接使用系统粘贴快捷键。



### 宏 #### 宏的读取执行
把命令序列录制成宏

q可以开启录制,也可以控制进行停止录制。

  1. qa将宏录制到寄存器a
  2. 一系列操作
  3. q结束录制
    可以通过:reg a查询a中的内容
通过执行宏来回放命令序列

通过@a可以重新执行之前的宏


规范光标位置、直达目标以及中止宏

黄金法则:在录制一个宏时,要确保每条命令都可被重复执行。

规范光标位置

应该把光标移到下一处查找匹配项(n),或者当前行的行首(0),又或是当前文件的首行(gg)。如果每次总是从确定的位置开始执行的话,那么命中正确的目标会变得更容易。

用可重复的动作命令直达目标

面向单词的动作命令,如 w 、b 、e 和 ge ,与面向字符的动作命令 h 和 l 相比,更具灵活性。如果录制“动作命令 0 ,后跟 e ”,当每次执行该宏时,我们都能预料得到一致的结果,光标会移到当前行第一个词的最后一个字符上。只要该行包含至少一个词,无论该词包含多少个字符,都能够到达目标。

我推荐用查找命令定位,或者用文本对象。总之,请用好Vim提供的所有动作命令,尽量使你的宏兼具灵活性与可重复性。还有一点别忘了,在录制宏的过程中,禁止使用鼠标。

当动作命令失败时,宏将中止执行

Vim的动作命令可能会执行失败。例如,如果光标位于文件的首行,运行 k 命令将什么也不会发生。若光标位于文件的末行,按下 j 也会出现同样的情况。

如果宏执行动作命令失败了,Vim将中止执行宏的其余命令。


加次数回放宏

对于重复次数不多的工作,点范式是一种高效的编辑策略,但它不能指定执行的次数。为了克服该限制,可以录制一个廉价的、一次性的宏,然后再加次数进行回放。


在连续的文本行上重复修改

对于多行范围内的重复性改动,可以先录制一个宏,然后再在每一行上回放,这将会极大减轻我们的工作量。该功能可用串行或者并行两种执行宏的方式实现。

例如把下面的文本

1
2
3
4
1. one
2. two
3. three
4. four

变成

1
2
3
4
1) One
2) Two
3) Three
4) Four

步骤如下:

  1. qa将宏录制到寄存器a
  2. 0f.这样可以保证无论从哪行开始都可以准确的移动到第一个.上,增强复用性
  3. r)w~将.换成)移动到首单词首字母并将其转换为大写
  4. j移动到下一行,这样多次执行宏就可以一直向下一行进行
  5. q结束录制
以串行方式执行宏

宏录制好了以后我们使用3@a就可以完成任务了,但是如果文件中包含注释就会带来新的问题

1
2
3
4
5
1. one
2. two
// break up the monotony
3. three
4. four

我们可以用并行的方式解决这个问题

以并行方式执行宏

之前说过一种在连续文本上执行.命令的方法,此处也可以使用相同的技术。

  1. qa开始录制
  2. 0f.r)w~
  3. q
  4. jVG选中要执行宏的文本
  5. :normal @a执行宏

给宏追加命令

如果发现录制完宏后漏了步骤可以使用qA 来在上次录制后追加命令


在一组文件中执行宏


用迭代求值的方式给列表编号

如果宏在每次执行时都能插入一个可变的数值,这将会很有用处。在本节中,将学习一种技术,它会在录制宏时使某个数字递增,这样一来,就可以在连续的文本上插入数字1到5。
使用let i = 1可以创建一个名为i的变量,如果想把它插入到文档只需在插入模式下运行<C-r>=i<CR>,例如想把下面的文档

1
2
3
4
5
artridge in a pear tree
turtle doves
French hens
calling birds
golden rings

转换为

1
2
3
4
5
1) partridge in a pear tree
2) turtle doves
3) French hens
4) calling birds
5) golden rings

可以按照如下步骤进行:

  1. :let i = 1定义变量i
  2. qa开始记录宏
  3. i<C-r>=i<CR>) <C-[>插入变量,添加文本
  4. :let i += 1<CR>q增加变量值,结束录制
  5. VG:normal@a执行宏

编辑宏的内容

假设我们将宏存在了寄存器a中,我们可以使用:put a或者ap命令来将其粘贴到文档中,然后就可以像编辑文档一样编辑宏了,编辑结束后将宏放回寄存器最简单的方法就是"add但是这样会导致宏多一个^j,所以最安全的方法还是将宏复制进寄存器后删除。