在 vim 中,<c-r>使用 <c-r><c-p>. 命令 +寄存器和 +寄存器有什么区别?

  • 本文关键字:寄存器 c-r 区别 使用 vim c-p 命令 vim
  • 更新时间 :
  • 英文 :


我很难理解这个vimgolf挑战的解决方案。

建议的最佳解决方案是

cw(<C-R><C-P>")<Esc>w.w.ZZ

然后我试着做

cw(<C-R>")<Esc>w.w.ZZ

但随后文本变成

(one) (one)
(one)

而不是

(one) (two)
(three)

有人能帮我理解为什么吗。这两个命令的行为不同?

这很有趣。没有使用CTRL-R CTRL-P的区别特征(按字面插入和固定缩进);indent不涉及,文本插入也发生在CTRL-R CTRL-R中(但这不起作用,这里也不涉及任何像<BS>这样的特殊字符)。

代替CTRL-R CTRL-p,这也适用于CTRL-R CTRL-O;(在帮助中)唯一的共同点是两者都有:

不替换字符!

我不知道这与通过.重复有什么关系(你必须仔细阅读源代码或询问vim_dev邮件列表)。基本上,它会导致<C-R><C-O>命令本身进入.寄存器,而不是您发出命令时寄存器中的文字文本。这意味着,当您使用.重复该操作时,您将在重复时获得指定寄存器中的任何内容,而不仅仅是再次插入相同的文本。

这使Vim不再作为重复该命令

将当前单词替换为(one)

将当前字替换为(,插入默认寄存器的寄存器内容,插入)

也就是说,第一次重复存储寄存器插入的结果,而第二次实际存储的是寄存器插入的动作。

当您通过:reg .列出".寄存器内容时,您也会看到效果。

由于已接受的答案解决了CTRL-R CTRL-RCTRL-R CTRL-O之间的差异,但没有回答为什么.会这样做的问题,而且文档非常没有帮助,所以我仔细研究了一下源代码。

控制字符

当编辑器遇到控制字符(如CTRL-H)时,它不会插入该字符,而是执行命令(在本例中为退格)。所以在插入模式下,

Hello<CTRL-H>World

产生

HellWorld

但是,如果控制字符前面有CTRL-V,则文字控制字符将作为文本插入。因此,

Hello<CTRL-V><CTRL-H>World

给我们

Hello^HWorld

其中CCD_ 18实际上只是用CCD_。

控制字符

所以,如果你想从寄存器中直接插入文本,你怎么能只使用CTRL-R呢?好吧,CTRL-R插入的文本就好像它是打字的一样。但这意味着我们可以使用CTRL-V来欺骗Vim模拟CTRL-R CTRL-R!假设我们要插入的文本在第1行:

1| Hello^HWorld

如果我们只是把它放在插入模式,我们会有一个糟糕的时间:

"ay$o
<CTRL-R>a  -->  2| HellWorld

相反,让我们首先插入^V:

:s/<CTRL-V><CTRL-H>/<CTRL-V><CTRL-V>&
"ay$o
<CTRL-R>a  -->  2| Hello^HWorld

这给了我们Hello^HWorld,就像我们想要的一样。

文字插入

现在您基本上知道了CTRL-R CTRL-R是如何工作的——它在每个字符之前插入^V,确保每个字符都是按字面意思插入的,而不是按类型插入的。

插入模式使用vgetorpeek读取字符。这有三个部分,我们可以将其简化为两部分:

  1. 尝试从stuffbuffer中获取一个字符
  2. 如果stuffbuffer为空,请从用户处获取一个字符

当您使用CTRL-RCTRL-R CTRL-R时,这将调用insert_reg。该函数将寄存器的内容插入stuffbuffer,因此Vim将在中读取它,就好像它被键入一样。

CTRL-R CTRL-R的情况下,我们将CTRL-V插入stuffbuffer中的每个特殊字符之前(除了制表符**)。实际上,这与单独使用正则表达式和CTRL-R没有什么不同——只是更方便。

CTRL-R CTRL-O和。命令

故事的寓意是,当您使用CTRL-R [CTRL-R]时,.命令只会看到您键入的文本流。

CTRL-R CTRL-OCTRL-R CTRL-P的情况完全不同,它们显然是在Bram修复了.无法正确重复鼠标粘贴的错误时添加的。我们不使用insert_reg,而是调用do_put,它直接将寄存器的内容放入文本中,不传递Go,不解释键序列。

一个结果(Bram所要做的)是,即使使用CTRL-R CTRL-R也没有按字面插入的选项卡,却使用CTRL-R CTRL-O按字面插入。在家里用可见的空格试试。我想这就是help中神秘的"不替换字符!"行的意思。

但更有趣的副作用是,寄存器的值不会显示在重做缓冲区中——就像我们从未键入过一样。相反,Bram手动调用AppendCharToRedobuff,这样.就会重复使用CTRL-R CTRL-O

/* Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r */
AppendCharToRedobuff(Ctrl('R'));
AppendCharToRedobuff(fix_indent ? Ctrl('P') : Ctrl('O'));
AppendCharToRedobuff(regname == 0 ? '"' : regname);

老实说,这似乎是一个懒惰的解决方案,甚至可能是一个bug。但结果是,您可以使用CTRL-R CTRL-O来拉入寄存器,并在每次重复时获取寄存器的内容。

这就是为什么你会看到不同的行为:

1| one two
2| three
cw(<C-R><C-P>")<Esc>w.w.
1| (one) (two)
2| (three)

当重复此操作时,cw"寄存器更新为"二",然后更新为"三",<C-R><C-P>"随之出现并重新读取"寄存器。

如果我们只使用<C-R>"(或<C-R><C-R>",在这里没有区别),重复操作只会重复插入"一"。

cw(<C-R>")<Esc>w.w.ZZ
1| (one) (one)
2| (one)

您可以在每个版本之后使用:reg .来查看.寄存器中的差异,尽管我不知道.寄存器与.操作的确切对应方式。


**这解释了其他一些奇怪的事情。如果在插入模式下键入<CTRL-V><Tab>,即使您有:set expandtab,也会得到一个选项卡,因为<CTRL-V>强制使用文字Tab字符。

但是,如果将Something<CTRL-V><Tab>Something拉入寄存器,然后尝试使用<CTRL-R><CTRL-R>插入,则选项卡将扩展为空格,就像只使用<CTRL-R>一样。这可以通过stuffescaped函数来解释,无论出于何种原因,该函数都不会在选项卡之前插入<CTRL-V>

由于<CTRL-R><CTRL-O>不需要<CTRL-V>(事实上,它会将这些字符作为文字^V字符插入!),所以选项卡保持不变——或者正如Bram所说,

不替换字符!