I have an insert mode mapping which calls a function to select some text and leave vim in select mode.

inoremap <silent> <C-J> <C-\><C-O>:call MyFunction()<CR>

This works in regular insert mode; and it works when the insert-mode completion popup window is visible and I haven't pressed ctrl-p or ctrl-n.

It doesn't work when the insert-mode completion popup window is visible and I have pressed ctrl-p or ctrl-n. In this case:

  • the cursor moves to the expected location;
  • the literal text :call MyFunction() with a newline is inserted in place of the text I wanted to be selected;
  • vim remains in insert mode instead of switching to select mode.

I believe this is because the C-\ at the start of the RHS is not part of the current completion option, so it has the effect of accepting the completion, which triggers CompleteDone, which executes MyFunction() (I listen for the CompleteDone event and in my listener call MyFunction()), and then the rest of the RHS is taken literally.

completeopt is menuone,noinsert. MyFunction()looks like:

function! MyFunction()
  call setpos("'<", ...)
  call setpos("'>", ...)
  execute "normal! gv\<C-G>"

I tried this variation instead:

inoremap <silent> <C-J> <C-R>=pumvisible() ? '<C-Y>' : MyFunction()<CR>

This works when the completion window is open, both when I have and haven't pressed ctrl-p / ctrl-n; but it doesn't work in regular insert mode (it moves the cursor to the start of the line and switches to normal mode – I suspect because MyFunction() doesn't have an explicit return, and so implicitly returns 0, which takes the cursor to the start of the line).

How can I get the mapping to work all the time?

  • Does :h CTRL-\_CTRL-N do what you want? Jun 14, 2019 at 6:03
  • It puts me into normal mode which isn't quite what I want. Thanks anyway. Jun 14, 2019 at 10:53
  • Well, yes, but then you are always considered to be in normal mode, from which you can call your function, regardless of what mode you have been in before, right? Jun 14, 2019 at 11:02
  • True, but I can't seem to get it to work. What exact map did you have in mind? Jun 14, 2019 at 11:45

1 Answer 1


There are several mistakes in your map:

mistake 1

:h quote= is expression register, it requires an expression. MyFunction() is a function, when it's used in an expression, it's result is returned, not itself. :h :return says that if your function doesn't have an explicit :return, it returns 0. 0 is a normal mode command that move your cursor to column 1. To fix that:

..... <c-r>= ...... : "\<lt>c-\>\<lt>c-o>:call MyFunction\<lt>cr>"<cr>

I will explain "\<lt>cr>" shortly.

mistake 2

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. The <cr> in the end is right because you want to press carriage return in the end of the <c-r>=. <c-y> here works by accident, because when you press <c-y> in command line, it inserts a literal <c-y>, but you can't rely on that, try <cr>, <esc>, they won't insert literal code for you.

Now let's come back to the ugly "\<lt>cr>". Our goal is to return a literal <cr> after MyFunction, literal <cr> is "\<cr>" (check :h string ), in order to stop map command from interpreting <cr> as special keycode, we replace < with it's special keycode <lt>. The same rules applys to <c-\> and <c-o>.

common way

You should use <expr> instead of <c-r> unless there are special reasons ( eg: :h complete() ), because <expr> think that {rhs} is result of an expression, what ever you provided in your <map> is an expression, you don't need to worry about your second mistake inside an expression. I hope i have made my self clear. (my English is poor ~~)

inoremap <expr> <c-j> pumvisible() ? '<c-y>' : '<C-\><C-O>:call MyFunction()<CR>'
  • Thank you very much! That all makes perfect sense and was very well explained (your English is excellent). And it even works ;) Jun 14, 2019 at 10:51

Your Answer

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

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