1. 阅读这篇文章我能学到什么?
你可能想知道其他软件与vim之间,vim与其命令行之间如何进行复制、粘贴、剪切问题,那么就请阅读这篇文章。这篇文章将从Vim寄存器的作用角度解答你使用vim过程中进行复制、粘贴、剪切如何操作的问题,将会非常详细。
——如果您觉得这是一篇不错的博文,希望您能给一个小小的赞,感谢您的支持。
vim有很多寄存器,我们进行的复制粘贴操作实际就是往这些寄存器写或者读取内容的操作,要想更好的使用复制粘贴功能,需要对这些寄存器有基本的了解。这些寄存器各有其功能,以我现在使用的 gvim_8.2.0318_x64_signed 举例(不排除未来会有版本差异),它具有这么几类寄存器:
- 无名寄存器 ":缓存最近一次的内容,也是复制粘贴最常用的寄存器;
- 编号寄存器 0~9:缓存最近操作内容。其中0号寄存器有别其他,它缓存最近一次复制的内容,1~9缓存最近9次删除的内容。
- 命名寄存器 a~z或A~Z:指定名称的寄存器,可以由用户自由选择内容缓存进去。要注意的是大小写虽然对应同一个寄存器,但是功能有差异。
- 只读寄存器 .、:、%:分别缓存上次插入的文本、最近执行的Ex命令、当前文件名。
- 表达式寄存器 =:实际上并不存在这么一个寄存器用来缓存文本,这是方便再使用寄存器的命令中使用表达式的一种方式。该寄存器是可读写的。它缓存的是表达式而不是表达式结果。
- 轮换文件寄存器 #:内容为当前窗口轮换文件的名字(网上一些文章说将其也归类为只读寄存器是错的,这个寄存器是可写的)。
- 选择和拖拽寄存器 *、+、:用于与其他应用之间的内容传递交互,是只读的。
- 最近搜索模式寄存器 /:内容为最近搜索的模式。
- 行内删除寄存器 -:该寄存器保存删除不到一行的内容,除非刻意指定了用其他寄存器。
- 黑洞寄存器 _:将内容放入黑洞寄存器不会留缓存记录。
你可以在vim中输入指令reg
查看它的寄存器:
我们可以看到上面提到的一些寄存器并没有显示出来,但这并不代表它们不存在,比如选择和拖拽寄存器的 + (又称为系统寄存器),它需要你的vim支持 clipboard , ~ 寄存器需要vim支持 dnd 。而命名寄存器 a~z 或 A~Z 是因为使用大写时操作的依然是对应的小写寄存器,而小写寄存器只有在有内容时才会显示,如果未使用则不会显示。黑洞寄存器是实际并没有用于存储内容的寄存器,它表示的含义就是不将内容放入可以缓存的任何一个寄存器,所以也就能理解为什么没有显示该寄存器。
如何查看自己的vim是否支持clipboard和dnd呢?打开cmd,输入vim --version
如果能看到clipboard和dnd前面显示了+则说明支持,如果是-则不支持。不持支的化你可能需要安装支持的版本,或者自己编译vim使其支持,clipboard一般都是支持的,而dnd一般用不到可以不必太在意。
在进一步学习Vim的寄存器之前我们先学习下Vim的几种基本操作:
必备知识:Vim中y
(yank缩写,抽出的意思)键用于复制功能;p
(past缩写,放置的意思)键用于粘贴功能;d
(delete缩写,删除的意思)键用于剪切功能,因为vim的删除是会在缓存备份的,所以实际就是剪切功能。
y
。{n}yy
、{n}Y
、y{n}y
{} 内参数n是可选的,n为从当前行往下数需要复制的行数,当n为1时可省略。ygg
,从当前行复制到文件尾yG
。y^
,从光标位置(不包括光标当前所在的字符)复制到行第一列y0
。从光标位置(包括光标当前所在的字符)复制到行末y$
。p
。d
。{n}dd
、{n}D
、d{n}d
n为从当前行往下数需要剪切的行数,当n为1时可省略。dgg
,从当前行剪切到文件尾dG
。y^
,从光标位置(不包括光标当前所在的字符)剪切到行第一列y0
。从光标位置(包括光标当前所在的字符)剪切到行末y$
。前面我们讲到了Vim的多种寄存器可用于缓存内容,那上面这些复制、粘贴、剪切操作用到了哪些寄存器呢?
当没有指定使用某个寄存器时,Vim都会按默认寄存器操作。比如y指令的复制操作默认是将内容缓存在了 " 无名寄存器种,所以粘贴时默认也是将无名寄存器的内容取出。剪切操作的的默认寄存器是 1~9 编号寄存器,这9个寄存器构成了一个“队列”,1号是队尾存放最新剪切掉的内容,当有更新的内容被剪切时小编号内容往大编号移动,最新内容放1号寄存器,超过9号之后就舍去。
用法示例:
使用yy
复制整行,观察 " 无名寄存器:
yy复制整行
观察 " 寄存器
使用dd
删除10行,观察 1~9 编号寄存器的值:
dd剪切10行文本
观察 1~9 编号寄存器
"ay
。
"ap
。
"+d
。
注意:以上的x值并不是指定任意寄存器都能操作成功,比如复制往只读寄存器里缓存内容。剪切操作会按编号寄存器的顺序从1到9传递缓存内容,不能自己打乱。等等。
当使用y
相关指令且未指定寄存器时,内容会被填充到无名寄存器中。当使用p
相关指令且未指定寄存器时进行粘贴默认取出无名寄存器内容。类似的还有d
、c
、s
、x
等和复制或删除相关的指令,在未指定寄存器情况下默认都是使用无名寄存器。无名寄存器用于缓存最近一次进行的复制或剪切内容,即使这定了其他寄存器,无名寄存器也都会被填充最近一次的复制或剪切内容,除非指定的是黑洞寄存器。
用法示例:
使用yy
复制文本到 a~z 或 A~Z 命名寄存器,观察 " 无名寄存器内容是否也被修改:
使用命令"ay
复制整行到a寄存器,观察 " 寄存器和 a 寄存器值
从上图可以看出 " 寄存器和 a 寄存器值都发生改变缓存了一份复制内容。
这些寄存器用来存放复制和剪切命令的文本。其中 0 号寄存器用于存放最近复制的文本,而 1~9 号用于存放最近剪切的文本(如果文本少于一行时缓存在行内删除寄存器)。每进行一次剪切操作,Vim会把前一次的寄存器 1 中的内容转存到寄存器 2 , 2 又到 3 ,依此类推,到 9 之后就舍弃。也可以指定缓存的寄存器,缓存的内容会被放到指定的寄存器和 1 号寄存器种有
注意:指定寄存器进行剪切时,会先将内容缓存到指定的寄存器,然后又会在 1 号寄存器进行缓存,这是有先后顺序的。比如往 a 寄存器剪切,则内容缓存到 a 寄存器和 1 号寄存器种,但是往 2 号寄存器剪切,内容被缓存到 3 号寄存器和 1 号寄存器,因为缓存 1 号寄存器时编号寄存器内容发生了一次移动。最后,黑洞寄存器依旧是个例外,往黑洞寄存器剪切不会保存内容,即使是 1 号寄存器。
用法示例:
使用"bd
指令剪切一行内容到b寄存器,观察 b 寄存器和 1 寄存器值
从图中可以看出,我们指定寄存器b剪切了一行文本,这行文本的内容总共被缓存到了三个地方, 1 号寄存器、 b 寄存器、 " 无名寄存器。回顾一下前面的无名寄存器,它会自动缓存最近一次的复制或剪切内容,所以就能理解为什么这里进行指定寄存器的剪切操作会缓存到无名寄存器里。
0 号寄存器用于存放最近复制的文本,你可能会发现很不多时候它和 " 无名寄存器的值是相同的,比如对一行文本用yy
进行复制。
用法示例:
对一行文本用yy
指令进行复制,观察 " 无名寄存器和 0 号寄存器值:
继续看,对一行文本用dd
进行剪切,观察 " 无名寄存器和 0 号寄存器值:
通过以上对比可知, " 无名寄存器缓存最近一次复制或剪切的内容, 0 号寄存器缓存最近一次复制的内容,而 1~9 号寄存器用于缓存最近9此的剪切内容。所以 " 无名寄存器的值要么等于 0 号寄存器,要么等于1号寄存器。
编号寄存器Vim是不会对其主动操作的,他们是给使用者在编辑过程中自由使用,灵活的使用他们将会使得你的代码编辑最少的敲打重复内容以及调整代码块的位置。这些寄存器在无内容时使用:reg
指令不会显示。你可能已经注意到了大小写的问题, a 和 A 是否时两个不同的寄存器?我要告诉你他们都是 a 寄存器,但是产生的效果不同。
用法示例:
对一行文本用"ay
指令进行复制,重复两次该操作,观察 a 寄存器值:
可以看到重复两次操作, a 寄存器也只能保存最新一次的内容。
对一行文本用"Ay
指令进行复制,重复两次该操作,观察 a 寄存器值:
可以看到重复两次操作, a 寄存器保存了多次复制的内容。
所以命名寄存器的大小写指的都是小写寄存器进行存储,但是当使用大写时会把内容进行追加,不会清楚之前保存的内容。利用好大写的命名寄存器可以拼接出我们想要的内容。
注意:其他寄存器Vim对其都有默认的操作,将需要内容保存到其他寄存器会很不安全,因为很可能会Vim自动覆盖,而命名寄存器拥有足够的数量且由用户操作,所以命名寄存器会是我们常用的寄存器。
这些寄存器都是只读的,有其特殊含义所以只能由Vim写。 % 被用于存放当前文件的文件名。 : 缓存最近执行过的命令行,需要注意的是只有当命令中至少有一个字符是键入的,该寄存器才会对指令进行缓存,如果命令行完全来自映射并不会缓存这些指令。这个寄存器需要你的Vim支持 cmdline_hist 特性。 . 寄存器被用于存放最近插入的文本,进入插入模式后输入的内容会被缓存进这个寄存器里,但是不会缓存通过粘贴途径放置的文本。
用法示例:
使用echo @%
命令输出 % 寄存器的值。"%p
粘贴出 % 寄存器的值:
可以看到 % 寄存器内的值就是当前文件名
用法示例:
使用:echo "nihao"
命令执行一遍字符串输出,然后使用:@:
重复执行一次最近执行过的命令。使用":p
命令将最近执行的命令内容粘贴出来:
注意Vim的寄存器都可以前面加上@将其当变量使用其值,比如@%和@:。
用法示例:
使用".p
指令粘贴最近一次插入的文本:
插入一段文本后观察 . 寄存器的值:
可以看到 . 寄存器将插入文本过程中输入的文本内容和一些退格和换行等信息也保存了,所以粘贴其内容的时候会是完全一样的文本。
注意 . 寄存器和 . 指令不同,Vim重.指令可以将最近的一些操作重复执行,而 . 寄存器是用来缓存最近插入的文本的。一个是指令一个是寄存器,不要搞混了。
你可以在插入模式按键ctrl r =
将会等待你输入表达式,会在光标处输出表达式的结果(结果自动转换为字符串类型。在普通模式和可视模式下"=
同样可执行表达式,不过表达式的结果只有在插入模式下才会输出在光标处。最近使用的表达式会被写入缓存到表达式寄存器(实际并不是一个寄存器,输入表达式时你可以在命令行按上下键选择最近使用过的多条表达式,默认显示最新的表达式)。
用法示例:
使用ctrl r =
指令在插入模式下计算表达式并输出值:
使用指令:reg
查看表达式内容:
注意:如果你无法修改 = 表达式寄存器的值,那很有可能是因为该寄存器被你的插件占用了,比如在插件Neardtree处于打开状态下,该寄存器就会被该插件一直占用,但是不影响插入模式下输出表达式的计算结果。
这个寄存器也是在没有值时:reg
指令下并不会显示它。它的值为当前窗口轮换文件的名字,你可以简单的理解为“上一次打开的文件的相对路径(这个相对路径不是指相对当前文件,是相对Vim的当前所处目录”,为什么要叫轮换文件寄存器呢?因为可以使用指令ctrl ^
在当前文件和上一次文件之间来回切换。
用法示例:
使用"#p
指令粘贴 # 轮换文件寄存器值:
使用reg
查看 # 轮换文件寄存器值:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ejVpipfI-1585324490702)
~ 寄存器是只读的,它缓存最近一次拖放操作放下的文本。比如你从其他地方鼠标选中一段文本将其直接拖入Vim界面,这时候这些文本就会被缓存到 ~ 寄存器里。需要你的vim支持 dnd 才可使用此寄存器。 + 寄存器就是我们常说的系统寄存器,用于和外界内容的拷进拷出。在MS-Windows上, * 和 + 寄存器是等价的,而在X11系统上有区别。
将最近的搜索模式缓存入该寄存器,实际不止缓存一条内容,它可以缓存最近使用过的搜索模式,普通模式下按/
后可通过鼠标上下键选择。
用法示例:
使用/nihao
指令进行模式搜索后,使用"/p
指令粘贴最近使用过的模式匹配内容:
使用:reg
指令查看 / 最近模糊模式寄存器
在行内进行删除时(删除的内容未达到一行),内容默认保存到 - 行内寄存器下。如果指定缓存在别的寄存器下时,内容只会被缓存到指定的寄存器,不会改变 - 行内寄存器的值。
用法示例:
使用指令"ad"
删除行内一段文本后,使用指令:reg
查看寄存器值变化:
删除的行内内容放入指定寄存器a,且 - 行内寄存器值并未改变。当然 " 无名寄存器的值也会被改变。
将内容指定放入 _ 黑洞寄存器就意味着不放入任何其他寄存器。当你想彻底删除某些内容而不影响其他寄存器时就可以指定其放入 _ 黑洞寄存器。
用法示例:
使用指令"_d
删除一行文本”1010101010“,观察各个寄存器值变化:
可以看到,指定放入 _ 黑洞寄存器的内容不会改变其他任何寄存器的值。