这篇文章介绍 Vim 中在文件间跳转的技巧,以及如何通过寄存器实现各种复制粘贴操作。
在文件间跳转
技巧 55:遍历跳转列表
Vim 会记录前后跳转的位置,并提供一些命令让我们能够沿原路返回。
通常来说,动作命令在一个文件内移动,而跳转命令则可以在文件间移动(但是有些移动命令也被归为跳转)。任何改变当前窗口中活动文件的命令,都可以被称为跳转命令。此外,使用 [Count]G
跳转到指定行的命令,也可以被称为跳转。面向句子的动作及面向段落的动作都算跳转。一句话来概括,大范围的动作命令可能会被当成跳转,小范围的动作命令则只能算移动。
以下选了一些跳转命令:
- [count]G:调到指定行
/pattern<CR>
、?pattern<CR>
、n
、N
:跳转到下一个/上一个模式出现之处- %:跳转到匹配括号之处
(
、)
:跳转到上一句/下一句的开头{
、}
:跳转到上一段/下一段的开头H
、M
、L
:跳转到屏幕最上方/正中间/最下方gf
:跳转到光标下的文件名Ctrl-]
:跳转到光标下的定义之处'{mark}
、`{mark}:跳转到位置标记
使用 :jumps
命令,可以查看跳转列表的内容。使用 <Ctrl-o>
命令可以在跳转列表路径上后退,而 <Ctrl-i>
命令则可以在跳转列表上前进。
另外,Vim 可以同时维护多份跳转列表,实际上,每个单独的窗口都有一份自己的跳转列表。
技巧 56:遍历改变列表
每当对文件作出修改后,Vim 都会记录下当时光标所在的位置。Vim 在编辑会话期间维护一张表,里面记载我们对每个缓冲区所做的修改。这个表就是改变列表。使用 :changes
命令可以查看改变列表的内容。
可以使用 g;
和 g,
命令反向或正向遍历改变列表。要想跳转到上次文档被改过的地方,可以使用 g;
之前也讲过,Vim 会自动创建一些标记。'.
总是跳转到上次修改过的位置,而 '^
则跳转到退出插入模式时光标所在位置(另外,使用 gi
命令也是可行的,而且它会自动切换到插入模式)。
Vim 会为编辑会话的每个单独缓冲区维护一个改变列表。
技巧 57:跳转到光标下的文件
Vim 可以将文档中的文件名当成一个超级链接,在选择了正确的配置后,就可以使用 gf
(可以记忆成 go to file
)命令跳转到光标下的文件了。
除了直接打开一个指定的文件名外,也可以省略文件的扩展名。suffixesadd
选项允许指定一个或多个文件扩展名。Vim 使用 gf
命令搜索文件名时会尝试使用这些扩展名。
每次使用 gf 命令时,Vim 都会在跳转列表中增加一条记录。因此可以通过之前的跳转命令进行来回跳转。
path
选项包含一个目录列表,使用 gf
命令时,Vim 会检查 path
目录列表中的每个目录,看该目录是否包含一个匹配光标下文本的文件名。使用 :set path?
可以查看 path
选项的当前值:
.
代表当前文件所在的目录- 空字符串(由两个连着的逗号界定)则代表工作目录
技巧 58:用全局位置标记在文件间快速跳转
之前在学习位置标记时已经讲过,使用 m{letter}
命令设置位置标记时,如果使用小写字母,会创建局部于缓冲区中的标记,而大写字母则创建全局标记。全局标记在两次编辑会话之间仍然保留。
当需要浏览一些文件,然后再快速跳回原处时,全局标记会非常有用。
复制粘贴
技巧 59:用无名寄存器实现删除、复制与粘贴操作
在 Vim 的操作里,剪切、复制与粘贴这三组动作,操作的都是寄存器,而非剪贴板。
调换字符: 使用
xp
命令可以快速调换当前光标下的字符和其之后的一个字符。因为x
命令会删除一个字符,并且把该字符的内容放到无名寄存器中,最后p
命令把无名寄存器的内容粘贴到光标后面调换文本行: 使用
ddp
命令可以快速交换当前光标所在的行和其之后的一行。同样,dd
命令会删除一行,并将该行内容放到无名寄存器中,p
命令把无名寄存器中的内容粘贴到光标后创建文本行的副本:使用
yyp
命令可以创建一行的副本。其原理也是类似。
由于复制(yank)、删除(delete)等命令,默认都是将内容保存到无名寄存器,因此有时候一些操作会不经意覆盖无名寄存器的内容,造成预料之外的结果。为了解决这个问题,需要深入了解 Vim 寄存器的工作原理。
技巧 60:深入理解 Vim 寄存器
Vim 的删除、复制、粘贴操作都可以使用众多寄存器中的某一个。可以使用 "{register}
的方式引用某一个寄存器。如果不指明寄存器,默认使用无名寄存器。
除了普通模式下的命令,Vim 也提供了用于删除、复制、粘贴的Ex命令,其形式分别为::delete {register}
、:yank {register}
、:put {register}
。
以上操作,如果没有指定寄存器,Vim默认使用无名寄存器。无名寄存器用 "
表示,因此可以通过 ""
双引号,显式引用无名寄存器。
当使用 y{motion}
命令时,要复制的文本不仅会拷贝到无名寄存器,而且也会拷贝到复制专用寄存器。复制专用寄存器可以使用数字 0 来引用。注意,复制寄存器只对复制命令有效,x
、s
、c{momtiion}
、d{motion}
命令不会覆盖复制寄存器中的内容。
Vim 提供了一组以 26 个英文字母命名(a-z)的 有名寄存器
。使用小写字母引用 有名寄存器
时,会覆盖寄存器中的原有内容。而如果使用大写字母的话,则将新的内容添加到寄存器原有内容之后。
黑洞寄存器是个有去无会的地方,可以使用 _
引用它。如果想删除一段内容,同时该内容不保存到无名寄存器中,则可以使用 "_d{motion}
命令(其实是将内容保存到黑洞寄存器)。
如果想从 Vim 复制文本到外部程序(反之亦然),则必须使用系统剪贴板。Vim 的加号寄存器与系统剪贴板等效:
- 如果在外部程序中复制了文本,可以使用
"+p
命令或者在插入模式下使用<Ctrl-r>+
命令将其粘贴到Vim内部 - 相反,如果使用
"+
引用寄存器,则相应的文本也会捕获到系统剪贴板。
Vim的寄存器通常被认为是保存文本的容器。但是,通过 "=
引用的表达式寄存器确是个例外。当我们从表达式寄存器中获取内容时,Vim 会跳到命令行模式,并显示提示符 =
,这时可以输入一段 Vim 脚本并执行。
Vim 提供了几组被隐式赋值的寄存器,它们被称作只读寄存器:
"%
:当前文件名"#
:轮换文件名".
:上次插入的文本":
:上次执行的Ex命令"/
:上次查找的模式
可以使用 :reg
命令查看指定所有寄存器或指定寄存器中的内容,在插入模式下,可以使用 <Ctrl-r>
来访问寄存器。
技巧 61:用寄存器中的内容替换高亮选区的文本
在可视模式下使用 p
命令时,Vim 会用我们指定的寄存器内容来替换高亮选区中的文本。但是其背后的步骤也需要注意,在可视模式下使用 p
命令时:
- Vim 是首先将无名寄存器的内容取出并粘贴到高亮选区
- 然后将高亮选区中的内容存入无名寄存器
利用这条技巧,如果需要交换如下 chips 和 fish 两个单词的顺序(假设光标在 chips 上):
1 | I like chips and fish |
diw
:删除单词mm
:设置位置标记mww
:移动到目标单词ve
:选中当前单词p
:使用无名寄存器中的内容替换高亮选区'm
:重新回到高亮选区P
:粘贴新的无名寄存器内容。
技巧 62:把寄存器的内容粘贴出来
普通模式下的粘贴命令,根据要插入文本的性质不同,执行结果也不同。
- p 命令将寄存器中的文本粘贴到光标之后
- P 命令将寄存器的文本粘贴到光标之前
但是光标前后的位置具体在哪,要根据寄存器中的内容决定:
- 面向行的复制或删除操作,将创建面向行的寄存器
- 而面向字符的复制或删除操作,将创建面向字符的寄存器
对于面向行的区域,p
和 P
命令行为就非常直观了。需要注意,这两个命令将光标位置移动被粘贴文本的开头。而 gp
和 gP
命令行为类似,但是将光标位置移动到被粘贴文本的结尾,当复制多行文本时,gp
命令尤为管用。
当粘贴面向字符的区域时,p
和 P
命令使用起来并不直观(非常容易犯差一错误)。可以尝试在插入模式下使用 <Ctrl-r>{register}
的方式来粘贴寄存器中的内容。这种方式,寄存器的文本总是在当前光标之间插入。
技巧 63:与系统剪贴板进行交互
在插入模式下使用系统粘贴命令时,就如同手动输入。如果 autoindent
选项被开启时,这就意味着每当创建新行,都讲保持同级缩进,进而导致空格增多(在自动缩进基础上又保持原有空格)。GVim 能够捕获系统剪贴板粘贴文本的事件,从而可以相应地调整行为。但是在终端运行 Vim 时,这些信息无法获取。
使用 paste 选项允许我们手动通知 Vim 要使用系统粘贴命令了
。paste 选项启用后,Vim 将禁用所有插入模式下的映射项与缩写,并重置很多选项。当使用完 paste
选项后,可以使用 :set paste!
回到普通模式。
为避免切换 paste
选项,也可以使用加号寄存器进行粘贴。