4

Let's say I've got the word foo in a file, I copy it in register a ("ayiw) and I define the following mapping:

inoremap <expr> <F3> "<C-r>a"

If I hit F3 while in insert mode it will paste the content of register a (foo).

Now, let's say I define the following function, and the following mapping:

function! SomeFunction()
      return "<C-R>a"
endfunction

inoremap <expr> <F3> SomeFunction()

When I hit F3, instead of inserting the a register (foo), it inserts literally <C-R>a.

I found a solution, which involves changing the function and using the unicode for <C-R>.
I think u12 is the unicode for the control character <C-R>, because when you insert it literally (<C-V><C-R>) and you hit ga on it, the output is <^R> 18, Hex 12, Octal 022.

So the following function and mapping works:

function! SomeFunction()
      return "\u12" . 'a'
endfunction

inoremap <expr> <F3> SomeFunction()

When I hit F3 it inserts the content of the a register as expected.

But why do I have to use unicode when the control character is returned by a function instead of being directly passed as an argument to :inoremap?

Edit: After reading Christian Brabandt's answer, I've realised that my solution was too complex.
As he has well explained, no need of unicode, a control character must simply be escaped in a string, so the proper way to write the function would be:

function! SomeFunction()
      return "\<C-R>a"
endfunction

And yet I'm still confused, if I type:

inoremap <expr> <F3> "<C-r>a"

It works as expected. So why do I need to escape <C-r> inside the function but not when it's directly passed as an argument to :inoremap?

For that, I think I have an explanation. The Ex commands which define a mapping like :inoremap, :nnoremap... don't need the control characters to be escaped. For example, you don't write:

nnoremap \<F3> :call SomeFunction\<cr>

but

nnoremap <F3> :call SomeFunction<cr>

Why? Probably because these commands are special, they already interpret correctly <cr> as a carriage return and not as 4 literal characters (same thing for <F3>).

So, going back to my previous function, why do I need to escape <C-r>?
Because, when I hit <F3>, :inoremap evaluates the right-hand-side of the mapping as a call to the function SomeFunction()... and that's it. It doesn't interpret anything after that, it just types the output literally.
The output of SomeFunction() is not interpreted by :inoremap, so this time you have to escape the control character so that Vim (not :inoremap) interprets \<C-r> as Ctrl + r.

1 Answer 1

4

If you want to have Keys returned by mapping expressions, you have to escape them as mentioned in the help :h expr-quote. So your Function needs to return "\<c-r>a" (note the backslash), else you couldn't let the function return the string "<c-r>a"

7
  • 1
    Thank your for your answer. Just another question, if I type: inoremap <expr> <F3> "<C-r>a", it works as expected. I don't have to escape <C-r>, why?
    – saginaw
    Jan 8, 2016 at 19:06
  • 1
    That is interesting and certainly unexpected. That might be a bug. Jan 8, 2016 at 19:08
  • 1
    I may be wrong, but I don't think it's a bug. If you look at the very bottom of :h ins-special-special, they give these 2 examples : inoremap <expr> <Home> col('.') == match(getline('.'), '\S') + 1 ? \ repeat('<C-G>U<Left>', col('.') - 1) : \ (col('.') < match(getline('.'), '\S') ? \ repeat('<C-G>U<Right>', match(getline('.'), '\S') + 0) : \ repeat('<C-G>U<Left>', col('.') - 1 - match(getline('.'), '\S'))) inoremap <expr> <End> repeat('<C-G>U<Right>', col('$') - col('.')). They don't escape <C-G>, neither <Left> nor <Right>.
    – saginaw
    Jan 8, 2016 at 19:45
  • 1
    Worse, they don't use double quotes, but single quotes (which prevents Vim from evaluating anything in the string). My theory: they don't need to be escaped because the Ex commands which define mappings such as :inoremap don't need it, they already know that <CR> for example means "carriage return", you don't need to write \<cr> in a mapping. This is why I don't understand why I need to escape <C-r> when it comes from a function but not when it's on the command line. But I like your answer, from now on, I will always use double quotes and escape to represent a control character.
    – saginaw
    Jan 8, 2016 at 19:45
  • 1
    i know the example very well. I am still not sure, whether this is a bug. I'll ask vim-dev Jan 8, 2016 at 21:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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