1

I used to store macros in insert mode as <c-r><c-r>q, but that fails if the macro contains a special character such as <C-Right>

If I record a macro as

qq<C-Right>q.

the result of <c-r><c-r>q in insert mode is :

<80>ýV

the result of "qp in normal mode is :

<80><fd>V

If I copy the result back to a new register "ay$ , only the "qp approach works. The first character in the newly copied register of the <c-r><c-r>q approach is <c2>, I have no idea what <c2> is, it's echo result is 0.

So my question is what's the difference between these two methods?

2

what's the difference between these two methods?

p inserts the content of a register as it is, regardless of the encoding, but CTRL-R CTRL-R encodes sequences of bytes before inserting them.

Explanation

Special key combinations, such as Ctrl+, are translated into terminal keycodes like ^[[1;5C, then into vim keycodes like <C-Right>, and finally into a sequence of bytes starting with 0x80 like <80><fd>V (<80> is 0x80) [1] [2] [3] [4] [5]. This is a special case where the vim keycode is different than the terminal keycode [6].

After assigning the register q like this:

let @q="\<C-Right>"

the sequence of bytes is what's actually saved:

:registers q
Type Name Content
  c  "q   <80><fd>V
Press ENTER or type command to continue

If I went to insert mode and put this sequence by hand as Unicode code points [7] [8] [9] (V is 0x56 here)

  • Ctrl+V u0080 for <80>
  • Ctrl+V u00fd for <fd>
  • Ctrl+V u0056 for V

This is what I would get:

<80>ýV

which is the same result as the one I would get if I pressed

Ctrl+r Ctrl+r q in insert mode.

I have no idea what <c2> is

If the cursor is moved on the opening angle bracket < in the previous output:

<80>ýV

and then press g8 in normal mode, this is the output I'd get [10][11]:

c2 80

These are the hexadecimal numbers for the two-byte UTF-8 character under the cursor; so the <c2> is the first byte of the two.

As a final note, what follows is the output of "qp in normal mode:

<80><fd>V

If I again move the cursor on the first < and press g8 the output would be different:

80

because that's not a UTF-8 character but just a binary one.

Thanks to all the Vi and Vim community (including you) who made this answer possible. I hope this answer is useful.

| improve this answer | |
  • 1
    Very well explained! Great answer. – dedowsdi Dec 21 '19 at 23:33
  • Thank you @dedowsdi – Jair López Dec 21 '19 at 23:43
2

There are several ways to insert the content of a registers. I'm going to briefly discuss some that are inserted when in :h Insert-mode:

  • :h i_CTRL-R : Insert the content of a register. Unlike, :h p or :h P i.e. "qp, how the texts are inserted will be affected by options like :h textwidth, :h formatoptions or :h autoindent.
  • :h i_CTRL-R_CTRL-R : Works like using a single CTRL-R, but the text is inserted literally, not as if typed. So, if you record hitting a backspace, e.g. type^Hing, would insert typing when inserted with single CTRL-R but will insert type^Hing when inserted with double CTRL-R. (^H is CTRL-H, used for <BS> in terminal emulators, i.e. they emit same code <U+0008). Still is affected by auto-indent options.
  • :h i_CTRL-R_CTRL-O : Insert text literally and isn't affected by auto-indent.
  • :h i_CTRL-R_CTRL-P : Insert the contents of a register literally and fix the indent.

Now, when you pressed <Ctrl-Right> after starting the recording, your terminal emulator emits some keycodes. I don't exactly know what they might be and most probably they even differ from computer to computer. So, it's a wildcard why the characters <80> <fd> (both hexadecimal values) and most confusingly why V is there! I have no answer to these. The only thing I have advanced on your observations is that both ý and <fd> are basically same character, i.e. they both have same HEX values which is 00FD. Double CTRL-R, i.e. i_CTRL-R_CTRL-R, inserts literal characters. That's why it inserted the literal value of <fd> and not the HEX value which is saved in its :h digraph.

So, to wrap it up:

  • Check out the documentations to know about various ways to insert content of a register and differences among them.
  • <fd> and ý are same character, former is HEX value and latter is ASCII value.
  • No idea why there is a literal V in the <C-Right> :h key-codes recording
  • No idea how to make sense of these nonsensical key-codes. And I suppose, in order to not have to think about these key-codes, vim provides us sensible :h key-codes for mappings and such.

Edit

You can't use the literal string that you got when you inserted it with :h i_CTRL-R_CTRL-R to use as a recording. Because the literal string that the extended ASCII key-code spews out is not within one of :h key-codes. For example, if you want to insert <C-Right> into a register and use it, you need to do it in the following way:

:let @q = "\<C-Right>"

The backslash and double-quote is necessary to evaluate to special characters, see :h string and :h literal-string.

In other words, the weird character that the HEX value of <fd> evaluates to in extended ASCII chart is not going to be converted to special characters or key-codes in :h key-codes.

| improve this answer | |
  • I know <c-r><c-r> insert literal content, i should've mensioned it. The question is why can't you copy literal macro text back to reqister, and use it as a macro, while the normal "qp approach works, help p only says "put the text ..... ". – dedowsdi Apr 7 '19 at 10:54
  • I edited my answer. Check if it helps – klaus Apr 7 '19 at 11:20
  • I'm not sure, i just tried let @q = "<c-v><C-Right>" , then @q, vim works, neovim failed. I also tried let @q = "\<C-Right>", both vim and neovim works. – dedowsdi Apr 7 '19 at 11:49
  • <c-v><C-Right> is "<C-Right>" in neovim, "^[[1;5C" in vim. – dedowsdi Apr 7 '19 at 11:54
  • 1
    Yes, you can because it is keycode, not a special key-code. The confusions are arising due to my misuse of terms. The special characters provided in :h key-codes can be used as literal or non-literal strings, e.g. '<C-Right>' or "\<C-Right>". Now, when you're using <80><fd> directly, it is being used as you expect. But if you copy <80>ý, it's not gonna work because ý would not work as <fd>, it will be another usual ASCII character. So, basically, you can use direct codes like <fd> but not their ASCII values like ý in a macro. And you can use special keys like <C-Right> – klaus Apr 7 '19 at 12:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.