In vim, what is the difference between <c-r>+register and <c-r><c-p>+register with the . command?
vim
Solution
Since the accepted answer addresses the difference between `CTRL-R CTRL-R` and `CTRL-R CTRL-O` but doesn't answer the question as to why `.` behaves as it does, and the documentation is pretty unhelpful, I dug through the source a bit.
Control characters
When the editor encounters a control character, like `CTRL-H`, instead of inserting that character it executes the command (in this case, backspace). So in insert mode,
Hello<CTRL-H>World
yields
HellWorld
However, if the control character is preceded by `CTRL-V`, the literal control character is inserted as text. Thus,
Hello<CTRL-V><CTRL-H>World
gives us
Hello^HWorld
where `^H` is really just a representation of the character you get with `CTRL-H`.
Controlling the characters
So if you wanted to insert text from a register literally, how could you do it using only `CTRL-R`? Well, `CTRL-R` inserts text as if it were typed. But that means we can just use `CTRL-V` to trick Vim into simulating `CTRL-R CTRL-R`! Let's say the text we want to insert is on line 1:
1| Hello^HWorld
If we just put that in insert mode, we'll have a bad time:
"ay$o
<CTRL-R>a --> 2| HellWorld
Instead, let's first insert ^V:
:s/<CTRL-V><CTRL-H>/<CTRL-V><CTRL-V>&
"ay$o
<CTRL-R>a --> 2| Hello^HWorld
This gives us `Hello^HWorld`, just like we wanted.
Literal insertion
Now you basically know how `CTRL-R CTRL-R` works -- it inserts `^V` before each character, ensuring that every character is inserted literally instead of as if it were typed.
Insert mode reads characters with `vgetorpeek`. This has three parts, which we can simplify into two:
- Try to get a character from the stuffbuffer.
- If the stuffbuffer is empty, get a character from the user.
When you `CTRL-R` or `CTRL-R CTRL-R`, this calls `insert_reg`. That function inserts the contents of the register into the stuffbuffer, so Vim will read it in as if it's being typed.
In the case of `CTRL-R CTRL-R` , we insert `CTRL-V` into the stuffbuffer before every special character (aside from Tab**). So really, this is no different from using our regular expression and `CTRL-R` alone -- just way more convenient.
CTRL-R CTRL-O and the . command
Moral of the story, when you use `CTRL-R [CTRL-R]`, the `.` command just sees a stream of text you typed.
But the story is completely different for `CTRL-R CTRL-O` and `CTRL-R CTRL-P`, which were apparently added when Bram fixed a bug where pasting with the mouse wasn't repeated properly by `.`. Instead of using `insert_reg`, we call `do_put`, which directly puts the content of the register into the text, do not pass Go, do not interpret key sequences.
One consequence (what Bram was going for) was that Tabs, which even with `CTRL-R CTRL-R` weren't inserted literally, get inserted literally with `CTRL-R CTRL-O`. Try it at home with visible whitespace. I think this is what the cryptic "Does not replace characters!" line in :help means.
But the more interesting side effect is that the value of the register doesn't show up in the redo buffer -- like we never typed it in. Instead, Bram manually calls `AppendCharToRedobuff` so that `.` will repeat using `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);
Honestly, this seems like a lazy solution, maybe even a bug. But as a result, you can use `CTRL-R CTRL-O` to pull in registers and grab the contents of the register each time you repeat.
This is why you're seeing different behavior:
1| one two
2| three
cw(<C-R><C-P>")<Esc>w.w.
1| (one) (two)
2| (three)
When this is repeated, `cw` updates the `"` register with "two", then "three", and `<C-R><C-P>"` comes along and re-reads the `"` register.
If we just use `<C-R>"` (or `<C-R><C-R>"`, it makes no difference here), repeating the action just repeats the insertion of "one".
cw(<C-R>")<Esc>w.w.ZZ
1| (one) (one)
2| (one)
You can see the difference in the `.` register by using `:reg .` after each version, although I don't know exactly how the `.` register corresponds to the `.` action.
** This explains something else that's weird. If you type `<CTRL-V><Tab>` in insert mode, you'll get a tab even if you have `:set expandtab`, because `<CTRL-V>` forces the literal `Tab` character.
However, if you yank `Something<CTRL-V><Tab>Something` into a register and then try to insert it with `<CTRL-R><CTRL-R>`, the tab expands to spaces, just like if you had only used `<CTRL-R>`. This is explained by the `stuffescaped` function which, for whatever reason, doesn't insert `<CTRL-V>` before a tab.
Since `<CTRL-R><CTRL-O>` doesn't need `<CTRL-V>` (and in fact will insert those as literal `^V` characters!) the tabs stay intact -- or as Bram says,
Does not replace characters!
Problem
I struggle to understand the solution to this vimgolf challenge. The best proposed solution is ``` cw(<C-R><C-P>")<Esc>w.w.ZZ ``` Then I tried to do ``` cw(<C-R>")<Esc>w.w.ZZ ``` But then the text becomes ``` (one) (one) (one) ``` instead of ``` (one) (two) (three) ``` Can someone help me to understand why . behaves differently with those two commands?