tpope / vim-endwise

endwise.vim: Wisely add

Home Page:https://www.vim.org/scripts/script.php?script_id=2386

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Combining with other `<CR>` mappings

gosukiwi opened this issue · comments

Hi, first of all thanks for the hard work in all of your Vim plugins! They are great and I use several of your plugins in my daily vimming.

I wrote a little plugin I use for autocompleting pairs (eg: adding ] after I type [). It does have some functionality to indent when pressing CR.

To make that compatible with vim-endwise (and maybe other similar plugins which use the <CR> mapping) I saved the old mapping and restored it, doing something like this:

function! s:CarriageReturn() abort
  if some_condition
    " ... the plugin will handle the <CR> mapping
  else
    " ... restore previous <CR> behavior
    return "\<CR>\<Plug>(smartpairs-old-cr)"
  endif
endfunction

let s:old_cr_mapping = maparg('<CR>', 'i', 0, 1)
if s:old_cr_mapping != {}
  let s:old_cr = s:old_cr_mapping.rhs
  let s:old_cr = substitute(s:old_cr, '^<CR>', '', 'g')
  let s:old_cr = substitute(s:old_cr, '<SID>', '<SNR>' . s:old_cr_mapping.sid . '_', 'g')
  let s:old_cr = substitute(s:old_cr, '<Plug>', '<SNR>' . s:old_cr_mapping.sid . '_', 'g')
  execute 'imap <buffer> <Plug>(smartpairs-old-cr) ' . s:old_cr
else
  execute 'inoremap <buffer> <Plug>(smartpairs-old-cr) <Nop>'
endif

imap <expr> <buffer> <CR> <SID>CarriageReturn()

When I'm in a file that uses vim-endwise, like a Ruby file, it still works, but when I'm in another file type, like a regular text file, it inserts EndwiseAppend(<SNR>45_CarriageReturn()) whenever I press enter.

I see in the version notes, it includes:

  • Better support for automatically combining with other maps.
  • Better support for manually creating combined maps.

I could try and hack something to make my plugin work, but seeing the patch notes I wonder: What's the preferred way to combine my own mappings with vim-endwise's <CR> mappings?

Since you're using <buffer>, I take it you're triggering on an event like FileType or BufReadPost. What happens when that event triggers a second time? My guess would be <Plug>(smartpairs-old-cr) would end up mapped to <SNR>45_CarriageReturn(), and you'd get <SNR>45_CarriageReturn() inserted directly into the buffer. With that inherent instability in the mix, I don't know that it is even possible to layer in delegating to another map.

If you don't mind hard-coding an Endwise reference, this gets much easier to solve:

function! s:CarriageReturn() abort
  if some_condition
    " ... the plugin will handle the <CR> mapping
  else
    return "\<CR>"
  endif
endfunction

if exists('*EndwiseAppend')
  imap <script><expr><buffer> <CR> EndwiseAppend(<SID>CarriageReturn())
else
  imap <script><expr><buffer> <CR> <SID>CarriageReturn()
endif

Now it's idempotent. You'll get the same result even if the map is defined a second time.

I can maybe offer more specific advice if I see a complete working solution, one that doesn't have the "second time" problem.

Ohh I see! EndwiseAppend works great!

I'd like advice in a more complete solution though :) I'm using the BufEnter event:

function! SmartPairsInitialize() abort
  if get(b:, 'smartpairs_mappings_initialize', 0) == 0
    let b:smartpairs_mappings_initialize = 1
    let b:smartpairs_pairs = has_key(g:smartpairs_pairs, &filetype) ? g:smartpairs_pairs[&filetype] : g:smartpairs_default_pairs
    call s:SetUpMappings()
  end
endfunction

autocmd BufEnter * :call SmartPairsInitialize()

The full source can be seen here. The mappings are defined in s:SetUpMappings().

Thanks for your help :D

I would strongly consider mapping globally. If you're going to map in every single buffer anyways, the only thing a buffer local map adds is extra complexity. That same solution I gave you should work if you drop the <buffer>. I see from the full source you probably can't do that easily for everything, but it should work for <CR> itself.

BufEnter also fires on basically everything, including mundane events like switching window focus. That does make it a popular hammer to use when you can't figure out the "right" way. Since you're keying off the file type, you probably want the FileType event.

Makes sense. Thanks for the advice! 🙏