6

I stumbled recently upon a mapping in the Vim Tips Wiki that uses an expr-quote:

nnoremap <silent> <Space> @=(foldlevel('.')?'za':"\<Space>")<CR>

and realized it still worked after using a literal-string instead:

nnoremap <silent> <Space> @=(foldlevel('.')?'za':'<Space>')<CR>

I find examples that use expr-quote over literal-string more often than not. Even the documentation for feedkeys() mentions

To include special keys into {string}, use double-quotes and "\..." notation |expr-quote|.

Is there any particular reason to prefer the "\<xxx>" notation over '<xxx>'?

What is the difference between single and double quoted strings? answers this partially for special characters like \n, but my question is specifically about the usage of special named keys like <CR>, <C-U>, etc.

  • 2
    I had a similar question a couple of years ago. Basically, map commands parse/guess the keynames specifically, therefore, they translate literal <keys> to the right form and you do not need the special form "\<key>" – Christian Brabandt Jun 18 at 10:01
8

Good question. The keycode format with wider general usability is "\<xxx>". In any expression this will be replaced with the underlying numerical representation of the associated key (i.e. the "key code").

Per :h keycodes the other form, <xxx>, is used in the documentation to represent non-printing keys and, more relevant here, can be used to substitute the associated key in mappings.

The mappings-only restriction of <xxx> is arguably the most critical difference between the two forms.

To demonstrate take a look at these two expression commands:

exe "echom 'hi\<space>there'"
exe "echom 'hi<space>there'"

The first will print hi there to the command line. The second will print hi<space>there.

On the other hand if we put the same expressions in expression mappings...

nnoremap <expr> x ":echom 'hi\<space>there'<cr>"
nnoremap <expr> x ":echom 'hi<space>there'<cr>"

...then when invoked both will print hi there. (Note the oft-seen-in-mappings <cr>, without which the preceding command will appear on the command line...followed by a waiting cursor...instead of being executed immediately. Now we recognize that as being another example of the no-backslash form <xxx>.)

As a side note, the "\<xxx>" form is used quite a bit in certain Vim function parameters so it may be illuminating to go to :h eval and search for the string \< to see a number of examples of this usage.

  • 1
    aha, in mappings is key here (no pun intended). Appreciate the reference to :h keycodes. – Antoine Cotten Jun 18 at 11:42
  • @AntoineCotten Sure. Glad it was useful to you. – B Layer Jun 18 at 13:04
3

3 kinds of <xxxx>

"\<xxxx>"
'<xxxx>'
<xxxx>

Let's see "\<xxxx>" first, :h string says:

`\<xxx> Special key named "xxx".  e.g. "\<C-W>" for CTRL-W.`
...

It's an expression, it's a string, a literal string for keycode, let's see it's relation ship with literal terminal keycode on my xterm-256color:

echo "\a" output a, it's the same as terminal literal keycode
echo "\b" output b, it's the same as terminal literal keycode
...
echo "<space>" output , it's the same as terminal literal keycode
echo "\<c-a>" output ^a, it's the same as terminal literal keycode
echo "\<c-b>" output ^b, it's the same as terminal literal keycode
...
echo "\<c-right>" output <80><fd>V, it's not the same as terminal literal keycode
echo "\<c-left>" output <80><fd>U, it's not the same as terminal literal keycode
echo "\<f5>" output <80>k5, it's not the same as terminal literal keycode
echo "\<f6>" output <80>k6, it's not the same as terminal literal keycode
...

So i believe "\<xxxx>" is vim's internal keycode for keys, it's the same as terminal literal keycode if it doesn't starts with 0x80.

Now let's see '<xxxx>', it's the same as "<xxxx>", it's an expression, it's a string, and that's it, there is nothing special about this string.

Now let's see <xxxx>, it's not an expression, it's also not a string, it's nothing by itself, it has to be used with command like map.

Map and all kinds of <xxxx>

Definition of map without <expr> is:

Map the key sequence {lhs} to {rhs} for the modes where the map command applies.

It's key sequence, it works like you are typing it, remember that, it's very important.

:h keycodes says <xxxx> can be used with :h :map command, e.g.

inoremap <down> <esc>

Above command map <down> to <esc> in insert mode, map family command is smart, they interpret <xxxx> style keycode as vim's internal keycode for special keys. Now turn on :h 'showcmd' , let's see another example:

inoremap '<down>' '<esc>'

Type 'down arrow' quickly in insert mode, you should see a single ', and you are back to normal mode, there should be a ' in right bottom of of your screen. Let's break it down: after you hit 'down arrow' in insert mode, the map triggered, it's result is '<esc>', remember that map without <expr> works like you are typing it, so you type ' esc, vim return to normal mode, the last ' won't be discarded, it waits for you to enter a mark lonely in the right bottom.

Another purpose of this example is to show you that map without <expr> knows nothing about expression, when it saw <xxxx>, it knows it should be interpreted as special key code, it doesn't care if it's surrounded by ' or ".

The <c-r>=

Let's see some wrong examples first, assume you want to map <c-x> to <esc> in insert mode:

inoremap <c-x> <c-r>='<esc>'<cr>

It won't work, because map without <expr> works like you are typing it, nothing good will happen if you type <esc> in the middle of a string. Continue:

inoremap <c-x> <c-r>="\<esc>"<cr>

This won't work too, "\" doesn't have chance to do their job, for the same reason as above. In this case you must prevent vim from interpreting <esc> as key code:

inoremap <c-x> <c-r>="\<lt>esc>"<cr>

<lt> is special keycode for <, so after map special keycode interpretation, "\<lt>esc>" becomes "\<esc>", which is literal keycode for esc.

The <expr>

"\<lt>esc>" is super ugly, :h :map-expression is much easier to work with, you provide an expression to map <expr>, it's evaluated result will be used as {rhs} for map, the result is key sequence, the expression is not:

inoremap <expr> <c-x> '<esc>'

It's simple and beautiful. Don't miss the quote, both '<xxxx>' and "<xxxx>" work here. Note that map still interpret <xxxx> as special keycode, this rule won't change, never change, but only for <xxxx> on the command, not for the result of the expression. Let's use another example to explain that. Sometimes you want to use function as an expression:

inoremap <c-x> GetEsc()
function! GetEsc()
  return "<esc>"
endfunction

Result of GetEsc() is "<esc>", you hope that map knows it's a special keycode. it won't work, map recognize <xxxx> as special keycode only if it's typed in the command directly, not for the expression result. The right form is:

inoremap <c-x> GetEsc()
function! GetEsc()
  return "\<esc>"
endfunction
  • 4
    See also my question on vim-dev regarding this and the answer from ZyX – Christian Brabandt Jun 18 at 10:02
  • Vim is such a piece of work. – Antoine Cotten Jun 18 at 12:12
  • @ChristianBrabandt That part is still missing from help, i don't thing i have seen it. – dedowsdi Jun 18 at 12:23
  • There are a few typos in the answer. For example, the part about '<down>, you are mapping '<down> to '<esc>'. Also "map <c-f> to <esc>" should be "map <c-x> to <esc>". – jdhao Jul 16 at 6:21
  • @jdhao Thanks, fixed. – dedowsdi Jul 16 at 6:34

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.