My completion mappings scheme with coc is the following:

  • <c-@> (ctrl-space): trigger the menu / use the selected item (or the first one)
  • <c-j> and <c-k>: navigate the list (or also trigger the menu)
  • <c-n> and <c-p>: jump between snippets placeholders

Which translates as:

inoremap <expr> <c-@> pumvisible() ? coc#_select_confirm() : coc#refresh()
inoremap <expr> <c-j> pumvisible() ? "\<C-n>" : coc#refresh()
inoremap <expr> <c-k> pumvisible() ? "\<C-p>" : coc#refresh()
let g:coc_snippet_next = <c-n>
let g:coc_snippet_prev = <c-p>

This works pretty well (and I'm glad each key does only one thing and my "tab" and "enter", which are <c-i> and <c-m>, are not remapped).

Unfortunately, when the popup completion menu is shown, the default behavior (navigate the menu) takes over the global variable given by the plugin.

I tried the following (and more) to definitely shut the mapping when the menu is visible, with no success:

inoremap <expr> <c-n> pumvisible() ? "\<c-y>" : ""
inoremap <expr> <c-n> pumvisible() ? "\<nop>" : "\<nop>"
inoremap <expr> <c-n> "\<nop>"
inoremap <c-n> <nop>

Doing so, I noticed <c-n> and <c-p> seem to be affected only by the pumvisible() check for the regular pop menu, and not by the coc pop menu.

It's really driving me nuts since the above mappings, which use the same check, do work as intended.

Also, there's something in the help from coc which could possibly point the the right direction:

    inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
            \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

It uses coc's functions, which are not documented. I guess there's one to jump between placeholders, but I'm not able to find id.

Thanks for your time!

1 Answer 1


Hey not a long time ago I was also looking to have the same setup as yours and ended up with this config. Although I ended up using <c-j> and <c-k> for navigating the completion list and also for snippet jumps.

let g:coc_snippet_next = ''
let g:coc_snippet_prev = ''
inoremap <expr> <c-j>
   \ pumvisible() ? "\<c-n>" :
   \ coc#jumpable() ? "\<c-r>=coc#rpc#request('snippetNext', [])<cr>" :
   \ "\<c-j>"
inoremap <expr> <c-k>
   \ pumvisible() ? "\<c-p>" :
   \ coc#jumpable() ? "\<c-r>=coc#rpc#request('snippetPrev', [])<cr>" :
   \ "\<c-k>"
  • 2
    Well, I ended up using <c-b> and <c-f> for snippet jumps to avoid confusion. Thanks for your solution though, I'll try that out.
    – Biggybi
    Commented Dec 1, 2020 at 16:46

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.