Combining vim-closer with pumvisible

Reading time: 2 minutes

I’ve been using vim-closer for a while as a lightweight parenthesis/bracket closing plugin. I like it because it only fires when I hit enter, and it’s pretty lightweight and non-invasive.

Recently, I switched my code-completion setup to coc.nvim, but was frustrated that Go’s gopls preselect puts vim’s completion pop-up menu into the “selected” state, which takes over the behavior of the enter key to accept the selection (c.f. menu completion state 2). Here’s an example:

preselect true

If preselect is on at the end of a line like in the picture above, hitting enter doesn’t give a new line – it only accepts the completion suggestion. To get a newline in this situation, I have to hit enter twice. And preselection happens for a lot of simple keywords I can type just fine without completion, like nil or basic types in struct definitions:

preselect struct

There are examples for remapping the <CR> key to always accept the text if the pop-up is visible. Here is one of them:

inoremap <expr> <CR> pumvisible() ? "\<C-Y>" : "\<CR>"

I wanted the opposite: stop the match on <CR> and put in the newline:

inoremap <expr> <CR> pumvisible() ? "\<C-E>\<CR>" : "\<CR>"

But when I tried to remap the <CR> key this way, everything went kablooey. Literally. My editor froze until I hit CTRL-C, and ‘pumvisible() ? ...’ was spammed hundreds of times into my buffer.

The problem was that vim-closer remaps <CR> on a per-buffer basis – trying to extend any existing mapping – and that fails badly with the expr mapping for pumvisible. From suggestions on an issue from vim-endwise, I figured out a solution.

I moved the expression logic into a function that gets called from the mapping using a <C-R>=...<CR> sequence (a.k.a. the expression register):

function! HandleCRKey() abort
  return pumvisible() ? "\<C-E>\n" : "\n"
endfunction

inoremap <silent> <CR> <C-R>=HandleCRKey()<CR>

Because this doesn’t use an expr mapping, vim-closer can extend the mapping correctly when loading a buffer and I get both completion mapping the way I want and the bracket closing I like.

I hope this helps anyone else trying to combine pumvisible expressions with <CR> mappings.

•      •      •

If you enjoyed this or have feedback, please let me know by or