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!