我很难理解这个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)
有人可以帮助我理解为什么.这两个命令的行为有何不同?
这是有趣的.不使用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 ..
由于接受的答案解决了两者之间的区别CTRL-R CTRL-R,CTRL-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. 这包括三部分,我们可以简化为两部分:
当您CTRL-R或 时CTRL-R CTRL-R,这会调用insert_reg. 该函数将寄存器的内容插入到 stuffbuffer 中,因此 Vim 将读取它,就好像它正在被输入一样。
在 的情况下CTRL-R CTRL-R,我们在每个特殊字符(除了 Tab** 之外)之前插入CTRL-V到 stuffbuffer 中。所以真的,这与单独使用我们的正则表达式没有什么不同——只是更方便。CTRL-R
故事的寓意是,当您使用 时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 所说,
不替换字符!