Podrías usar la maparg()
función.
Para probar si el usuario asignó algo <C-c>
en modo normal, escribiría:
if !empty(maparg('<C-c>', 'n'))
Si el usuario asignó algo, para almacenarlo {rhs}
en una variable, escribiría:
let rhs_save = maparg('<C-c>', 'n')
Si desea más información sobre el mapeo, como:
- ¿Es silencioso (
<silent>
argumento)?
- ¿Es local para el búfer actual (
<buffer>
argumento)?
- ¿Es la
{rhs}
evaluación de una expresión ( <expr>
argumento)?
- ¿reasigna el
{rhs}
( nnoremap
vs nmap
)?
- Si el usuario tiene otra asignación que comienza con
<C-c>
, ¿Vim espera a que se escriban más caracteres ( <nowait>
argumento)?
- ...
Entonces, podrías dar un tercer y cuarto argumento: 0
y 1
.
0
porque está buscando un mapeo y no una abreviatura, y 1
porque quiere un diccionario con un máximo de información y no solo el {rhs}
valor:
let map_save = maparg('<C-c>', 'n', 0, 1)
Asumiendo que el usuario no utilizó ningún argumento especial en su mapeo, y que no reasigna el {rhs}
, para restaurarlo, simplemente podría escribir:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
O para estar seguro y restaurar todos los argumentos posibles:
let map_save = maparg('<C-c>', 'n', 0, 1)
" do some stuff which changes the mapping
exe (map_save.noremap ? 'nnoremap' : 'nmap') .
\ (map_save.buffer ? ' <buffer> ' : '') .
\ (map_save.expr ? ' <expr> ' : '') .
\ (map_save.nowait ? ' <nowait> ' : '') .
\ (map_save.silent ? ' <silent> ' : '') .
\ ' <C-c> ' .
\ map_save.rhs
Editar: Lo siento, me acabo de dar cuenta de que no funcionaría como se esperaba si el usuario llama a una función de script local en {rhs}
el mapeo.
Supongamos que el usuario tiene la siguiente asignación dentro de su vimrc
:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
Cuando golpea <C-c>
, muestra el mensaje hello world!
.
Y en su complemento, guarda un diccionario con toda la información, luego cambia temporalmente su mapeo de esta manera:
let map_save = maparg('<C-c>', 'n', 0, 1)
nnoremap <C-c> :<C-U>call <SID>FuncB()<CR>
function! s:FuncB()
echo 'bye all!'
endfunction
Ahora, se mostrará bye all!
. Su complemento funciona y, cuando termina, intenta restaurar el mapeo con el comando anterior.
Probablemente fallará con un mensaje como este:
E117: Unknown function: <SNR>61_FuncA
61
es solo el identificador del script en el que se ejecutaría su comando de mapeo. Podría ser cualquier otro número. Si su complemento es el archivo número 42 del sistema del usuario, lo será 42
.
Dentro de un script, cuando se ejecuta un comando de mapeo, Vim traduce automáticamente la notación <SID>
al código de clave especial <SNR>
, seguido de un número único para el script y un guión bajo. Tiene que hacer esto, porque cuando el usuario golpee <C-c>
, la asignación se ejecutará fuera del script y, por lo tanto, no sabrá en qué script FuncA()
está definido.
El problema es que la asignación original se originó en un script diferente al de su complemento, por lo que aquí la traducción automática es incorrecta. Utiliza el identificador de su script, mientras que debe usar el identificador del usuario vimrc
.
Pero podrías hacer la traducción manualmente. El diccionario map_save
contiene una clave llamada 'sid'
cuyo valor es el identificador correcto.
Entonces, para hacer que el comando de restauración anterior sea más robusto, puede reemplazarlo map_save.rhs
con:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Si el {rhs}
mapeo original contiene <SID>
, debe traducirse correctamente. De lo contrario, no se debe cambiar nada.
Y si desea acortar un poco el código, puede reemplazar las 4 líneas que se ocupan de los argumentos especiales con:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
La map()
función debe convertir cada elemento de la lista ['buffer', 'expr', 'nowait', 'silent']
en el argumento de mapeo correspondiente, pero solo si su clave interna map_save
no es cero. Y join()
debe unir todos los elementos en una cadena.
Entonces, una forma más robusta de guardar y restaurar el mapeo podría ser:
let map_save = maparg('<C-c>', 'n', 0, 1)
" do some stuff which changes the mapping
exe (map_save.noremap ? 'nnoremap' : 'nmap') .
\ join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""')) .
\ map_save.lhs . ' ' .
\ substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Edit2:
Estoy enfrentando el mismo problema que tú, cómo guardar y restaurar una asignación en un complemento de dibujo. Y creo que encontré 2 problemas que la respuesta inicial no vio en el momento en que lo escribí, lo siento.
Primer problema, suponga que el usuario lo utiliza <C-c>
en una asignación global pero también en una asignación local de búfer. Ejemplo:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
En este caso, maparg()
dará prioridad al mapeo local:
:echo maparg('<C-c>', 'n', 0, 1)
---> {'silent': 0, 'noremap': 1, 'lhs': '<C-C>', 'mode': 'n', 'nowait': 0, 'expr': 0, 'sid': 7, 'rhs': ':echo ''local mapping''<CR>', 'buffer': 1}
Lo cual se confirma en :h maparg()
:
The mappings local to the current buffer are checked first,
then the global mappings.
Pero tal vez no esté interesado en el mapeo local del búfer, tal vez quiera el global.
La única forma en que encontré, de manera confiable, obtener la información sobre el mapeo global, es tratar de desasignar temporalmente un mapeo potencial, sombreado y local del búfer usando la misma clave.
Se puede hacer en 4 pasos:
- guardar una asignación (local) de búfer local utilizando la clave
<C-c>
- ejecutar
:silent! nunmap <buffer> <C-c>
para eliminar una asignación local de búfer (potencial)
- guardar el mapeo global (
maparg('<C-c>', 'n', 0, 1)
)
- restaurar la asignación local de búfer
El segundo problema es el siguiente. Supongamos que el usuario no asignó nada <C-c>
, entonces la salida de maparg()
será un diccionario vacío. Y en este caso, el proceso de restauración no consiste en la instalación de un mapeo ( :nnoremap
), sino en la destrucción de un mapeo ( :nunmap
).
Para intentar resolver estos 2 nuevos problemas, puede probar esta función para guardar asignaciones:
fu! Save_mappings(keys, mode, global) abort
let mappings = {}
if a:global
for l:key in a:keys
let buf_local_map = maparg(l:key, a:mode, 0, 1)
sil! exe a:mode.'unmap <buffer> '.l:key
let map_info = maparg(l:key, a:mode, 0, 1)
let mappings[l:key] = !empty(map_info)
\ ? map_info
\ : {
\ 'unmapped' : 1,
\ 'buffer' : 0,
\ 'lhs' : l:key,
\ 'mode' : a:mode,
\ }
call Restore_mappings({l:key : buf_local_map})
endfor
else
for l:key in a:keys
let map_info = maparg(l:key, a:mode, 0, 1)
let mappings[l:key] = !empty(map_info)
\ ? map_info
\ : {
\ 'unmapped' : 1,
\ 'buffer' : 1,
\ 'lhs' : l:key,
\ 'mode' : a:mode,
\ }
endfor
endif
return mappings
endfu
... y este para restaurarlos:
fu! Restore_mappings(mappings) abort
for mapping in values(a:mappings)
if !has_key(mapping, 'unmapped') && !empty(mapping)
exe mapping.mode
\ . (mapping.noremap ? 'noremap ' : 'map ')
\ . (mapping.buffer ? ' <buffer> ' : '')
\ . (mapping.expr ? ' <expr> ' : '')
\ . (mapping.nowait ? ' <nowait> ' : '')
\ . (mapping.silent ? ' <silent> ' : '')
\ . mapping.lhs
\ . ' '
\ . substitute(mapping.rhs, '<SID>', '<SNR>'.mapping.sid.'_', 'g')
elseif has_key(mapping, 'unmapped')
sil! exe mapping.mode.'unmap '
\ .(mapping.buffer ? ' <buffer> ' : '')
\ . mapping.lhs
endif
endfor
endfu
La Save_mappings()
función podría usarse para guardar asignaciones.
Espera 3 argumentos:
- una lista de llaves; ejemplo:
['<C-a>', '<C-b>', '<C-c>']
- un modo; ejemplo:
n
para modo normal o x
para modo visual
- una bandera booleana; si es así
1
, significa que está interesado en los mapeos globales, y si lo está 0
, en los locales
Con él, usted podría ahorrar las asignaciones globales utilizando las teclas C-a
, C-b
y C-c
, en modo normal, dentro de un diccionario:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
Luego, más tarde, cuando desee restaurar las asignaciones, puede llamar Restore_mappings()
y pasar el diccionario que contiene toda la información como argumento:
call Restore_mappings(your_saved_mappings)
Podría haber un tercer problema al guardar / restaurar asignaciones locales de búfer. Porque, entre el momento en que guardamos las asignaciones y el momento en que intentamos restaurarlas, el búfer actual puede haber cambiado.
En este caso, tal vez la Save_mappings()
función podría mejorarse guardando el número del búfer actual ( bufnr('%')
).
Y luego, Restore_mappings()
usaría esta información para restaurar las asignaciones de búfer local en el búfer correcto. Probablemente podríamos usar el :bufdo
comando, prefijar el último con un recuento (que coincida con el número de búfer guardado previamente) y sufijarlo con el comando de mapeo.
Tal vez algo como:
:{original buffer number}bufdo {mapping command}
Tendríamos que verificar primero si el búfer todavía existe, usando la bufexists()
función, porque podría haberse eliminado mientras tanto.