在vim中,<cr> + register和<cr> <cp> +注册的区别是什么.命令?

aut*_*tra 5 vim

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

最好的解决方案是

cw(<C-R><C-P>")<Esc>w.w.ZZ
Run Code Online (Sandbox Code Playgroud)

然后我试着去做

cw(<C-R>")<Esc>w.w.ZZ
Run Code Online (Sandbox Code Playgroud)

但随后文本就变成了

(one) (one)
(one)
Run Code Online (Sandbox Code Playgroud)

代替

(one) (two)
(three)
Run Code Online (Sandbox Code Playgroud)

有人可以帮助我理解为什么.这两个命令的行为有何不同?

Ing*_*kat 5

这是有趣的.不使用CTRL-R CTRL-P(字面插入和修复缩进)的区别特征; 缩进不涉及,文字插入也发生在CTRL-R CTRL-R(但这不起作用,也没有像<BS>这里涉及的任何特殊字符).

而不是CTRL-R CTRL-P,这也适用于CTRL-R CTRL-O; 唯一的共性(在帮助中)是两者都有:

不替换字符!

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

这使Vim不再重复命令

取代目前用这个词(,随后one,其次是)

取代目前用这个词(,插入默认寄存器的寄存器内容,插入).

即第一次重复存储寄存器插入的结果,而第二次实际存储寄存器插入的动作.

当你列出".寄存器内容时,你会看到效果:reg ..


mgi*_*ida 5

由于接受的答案解决了两者之间的区别CTRL-R CTRL-RCTRL-R CTRL-O但没有回答关于为什么.行为如此的问题,并且文档非常无用,因此我对源代码进行了一些挖掘。

控制字符

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

Hello<CTRL-H>World
Run Code Online (Sandbox Code Playgroud)

产量

HellWorld
Run Code Online (Sandbox Code Playgroud)

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

Hello<CTRL-V><CTRL-H>World
Run Code Online (Sandbox Code Playgroud)

给我们

Hello^HWorld
Run Code Online (Sandbox Code Playgroud)

where^H真的只是你得到的角色的代表CTRL-H

控制字符

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

1| Hello^HWorld
Run Code Online (Sandbox Code Playgroud)

如果我们只是将其置于插入模式,我们将度过一段糟糕的时光:

"ay$o
<CTRL-R>a  -->  2| HellWorld
Run Code Online (Sandbox Code Playgroud)

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

:s/<CTRL-V><CTRL-H>/<CTRL-V><CTRL-V>&
"ay$o
<CTRL-R>a  -->  2| Hello^HWorld
Run Code Online (Sandbox Code Playgroud)

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

文字插入

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

插入模式读取带有vgetorpeek. 这包括三部分,我们可以简化为两部分:

  1. 尝试从stuffbuffer获取一个字符。
  2. 如果stuffbuffer 为空,则从用户那里获取一个字符。

当您CTRL-R或 时CTRL-R CTRL-R,这会调用insert_reg. 该函数将寄存器的内容插入到 stuffbuffer 中,因此 Vim 将读取它,就好像它正在被输入一样

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

CTRL-R CTRL-O 和 . 命令

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

但是对于CTRL-R CTRL-O和 来说CTRL-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);
Run Code Online (Sandbox Code Playgroud)

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

这就是您看到不同行为的原因:

1| one two
2| three

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

1| (one) (two)
2| (three)
Run Code Online (Sandbox Code Playgroud)

重复此操作时,先用“二”cw更新"寄存器,然后是“三”,<C-R><C-P>"然后重新读取"寄存器。

如果我们只使用<C-R>"(or <C-R><C-R>",这里没有区别),重复动作只是重复插入“一”。

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

1| (one) (one)
2| (one)
Run Code Online (Sandbox Code Playgroud)

你可以.通过: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 所说,

不替换字符!