¿Cómo activar la derecha de un mapa?
Digamos que tengo una función como esta:
function! Foo()
echom 'foo'
endfunction
Y un mapa como este:
nmap gf :<C-U>call Foo()<CR>0v$
Cuando escribo gf, veo un fooeco y la línea actual está resaltada. Hasta aquí todo bien.
Quiero poder ejecutar los rhs del mapa sin usar lhs. Dado que el rhs se procesa como si estuviera escrito, probé esto:
let rhs = maparg('gf', 'n')
execute 'normal!' rhs
Pero no parece hacer nada. También probé:
call feedkeys(rhs, 'xt')
Pero eso tampoco funcionó.
(Mi motivación es querer anular un mapeo estableciendo un nuevo rhs que llama a una función que puede volver a los rhs originales cuando sea necesario).
¿Cómo puedo invocar los rhs originales?
¡Gracias!
Respuestas
(Mi motivación es querer anular un mapeo estableciendo un nuevo rhs que llama a una función que puede volver a los rhs originales cuando sea necesario).
Primero, guarde toda la información sobre el mapeo original a través de maparg(). Para hacerlo, debe pasar los argumentos booleanos opcionales {abbr}y {dict}:
let s:gf_mapsave = maparg('gf', 'n', v:false, v:true)
Luego, en su nuevo mapeo, que anula el original, haga lo que quiera. Y cuando necesite invocar el mapeo original, use mapset()para restaurarlo temporalmente:
call mapset('n', v:false, s:gf_mapsave)
Alimente el lhs en el búfer typeahead:
call feedkeys('gf', 'xt')
Y restaure su mapeo principal:
nno gf :call Override()<cr>
Como ejemplo:
fu Foo()
echom 'foo'
endfu
nno gf :<c-u>call Foo()<cr>
let s:gf_mapsave = maparg('gf', 'n', v:false, v:true)
nno gf :call Override()<cr>
fu Override()
try
echom 'working'
not_working
" fall back
catch
call mapset('n', v:false, s:gf_mapsave)
call feedkeys('gf', 'xt')
nno gf :call Override()<cr>
endtry
endfu
Esto requiere el parche 8.2.0807 .
Para obtener más información, consulte:
- : h maparg ()
- : h mapset ()
En un complemento, tengo una lh#bracket#enrich_imap()función que uso para ejecutar alguna acción si se determina que una condición es verdadera y, de lo contrario, desencadenar el mapeo anterior / comportamiento esperado predeterminado.
Por ejemplo, lo uso de la siguiente manera:
call lh#brackets#enrich_imap('<cr>',
\ {'condition': 'getline(".")[col(".")-2:col(".")-1]=="{}"',
\ 'action': 'lh#brackets#_add_newline_between_brackets()'},
\ 0
\ )
Internamente, utilizo maparg()para buscar el mapeo anterior, si lo hubiera. Luego, me ocupo de algunas funciones portátiles antiguas para manejar correctamente las llamadas a funciones locales de scripts y para construir la asignación adecuada.
Las funciones principales son
" from lh-vim-lib
function! lh#mapping#_build_rhs(mapping_definition) abort
call lh#assert#value(a:mapping_definition)
\.has_key('rhs')
" Inject the right SNR instead of "<sid>"
let rhs = substitute(a:mapping_definition.rhs, '\c<SID>', "\<SNR>".get(a:mapping_definition, 'sid', 'SID_EXPECTED').'_', 'g')
return rhs
endfunction
function! lh#mapping#_switch(trigger, cases) abort
return lh#mapping#_switch_int(a:trigger, a:cases)
endfunction
function! lh#mapping#_switch_int(trigger, cases) abort
for c in a:cases
if eval(c.condition)
return eval(c.action)
endif
endfor
return lh#mapping#reinterpret_escaped_char(eval(a:trigger))
endfunction
function! lh#mapping#reinterpret_escaped_char(seq) abort
let seq = escape(a:seq, '"\')
exe 'return "' .
\ substitute( seq, '\\\\<\(.\{-}\)\\\\>', '"."\\<\1>"."', 'g' ) . '"'
endfunction
-------
" from lh-brackets
function! lh#brackets#enrich_imap(trigger, case, isLocal, ...) abort
" - Some keys, like '<bs>', cannot be used to code the default.
" - Double "string(" because those chars are correctly interpreted with
" lh#mapping#reinterpret_escaped_char(eval()), which requires nested strings...
if a:0 == 0
let previous = maparg(a:trigger, 'i', 0, 1)
if !empty(previous) && previous.expr
" If not an expression, I do know yet how to forward a non expr mapping
" from an expr mapping definition
let default = lh#mapping#_build_rhs(previous)
else
let default = string(a:trigger)
endif
else
let default = string(a:1)
endif
let sCase='lh#mapping#_switch('.string(default).', '.string([a:case]).')'
call s:DefineImap(a:trigger, sCase, a:isLocal)
endfunction
function! s:DefineImap(trigger, inserter, isLocal) abort
if exists('*IMAP') && a:trigger !~? '<bs>\|<cr>\|<up>\|<down>\|<left>\|<right>'
if a:isLocal
call IMAP(a:trigger, "\<c-r>=".a:inserter."\<cr>", &ft)
else
call IMAP(a:trigger, "\<c-r>=".a:inserter."\<cr>", '')
endif
else
call s:DefineMap('inore', a:trigger, (a:inserter), a:isLocal, 1)
endif
endfunction
function! s:DefineMap(mode, trigger, action, isLocal, isExpr) abort
" The actual definition does much more as mappings from the plugin can be activated or deactivated
let crt_mapping = {}
let crt_mapping.lhs = escape(a:trigger, '|') " need to escape bar
let crt_mapping.mode = a:mode
let crt_mapping.rhs = a:action
let crt_mapping.buffer = a:isLocal ? '<buffer> ' : ''
let crt_mapping.expr = a:isExpr ? '<expr> ' : ''
call s:Map(crt_mapping)
endfunction
function! s:Map(m) abort
" Nowadays there exists a vimscript function that does the same; we no longer need :exe
let cmd = a:m.mode.'map <silent> ' . a:m.expr . a:m.buffer . a:m.lhs .' '.a:m.rhs
call s:Verbose(cmd)
exe cmd
endfunction