È possibile utilizzare la maparg()
funzione.
Per verificare se l'utente ha mappato qualcosa <C-c>
in modalità normale, scrivere:
if !empty(maparg('<C-c>', 'n'))
Se l'utente ha mappato qualcosa, per archiviare {rhs}
in una variabile, dovresti scrivere:
let rhs_save = maparg('<C-c>', 'n')
Se vuoi maggiori informazioni sulla mappatura, come:
- è silenzioso (
<silent>
argomento)?
- è locale al buffer corrente (
<buffer>
argomento)?
- è la
{rhs}
valutazione di un'espressione ( <expr>
argomento)?
- rimappa il
{rhs}
( nnoremap
vs nmap
)?
- se l'utente ha un'altra mappatura che inizia con
<C-c>
, Vim attende che vengano digitati più caratteri ( <nowait>
argomento)?
- ...
Quindi, potresti dare un terzo e un quarto argomento: 0
e 1
.
0
perché stai cercando una mappatura e non un'abbreviazione, e 1
perché vuoi un dizionario con un massimo di informazioni e non solo il {rhs}
valore:
let map_save = maparg('<C-c>', 'n', 0, 1)
Supponendo che l'utente non abbia usato alcun argomento speciale nella sua mappatura e che non rimappa {rhs}
, per ripristinarlo, potresti semplicemente scrivere:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
O per essere sicuri e ripristinare tutti i possibili argomenti:
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
Modifica: mi dispiace, ho appena realizzato che non funzionerebbe come previsto se l'utente chiama una funzione script-local nella {rhs}
mappa.
Supponiamo che l'utente abbia la seguente mappatura all'interno della sua vimrc
:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
Quando colpisce <C-c>
, visualizza il messaggio hello world!
.
E nel tuo plugin, salvi un dizionario con tutte le informazioni, quindi modifichi temporaneamente la sua mappatura in questo modo:
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
Ora verrà visualizzato bye all!
. Il tuo plugin funziona un po ', e quando è finito, prova a ripristinare la mappatura con il comando precedente.
Probabilmente fallirà con un messaggio simile al seguente:
E117: Unknown function: <SNR>61_FuncA
61
è solo l'identificatore dello script in cui verrà eseguito il comando di mappatura. Potrebbe essere qualsiasi altro numero. Se il plug-in è il 42 ° file proveniente dal sistema dell'utente, lo sarà 42
.
All'interno di uno script, quando viene eseguito un comando di mappatura, Vim traduce automaticamente la notazione <SID>
nello speciale codice chiave <SNR>
, seguito da un numero univoco per lo script e da un carattere di sottolineatura. Deve farlo, perché quando l'utente colpirà <C-c>
, la mappatura verrà eseguita al di fuori dello script, e quindi non saprà in quale script FuncA()
è definito.
Il problema è che la mappatura originale è stata fornita in uno script diverso rispetto al tuo plugin, quindi qui la traduzione automatica è sbagliata. Utilizza l'identificatore del tuo script, mentre dovrebbe usare l'identificatore dell'utente vimrc
.
Ma potresti fare la traduzione manualmente. Il dizionario map_save
contiene una chiave chiamata il 'sid'
cui valore è l'identificatore corretto.
Pertanto, per rendere più robusto il comando di ripristino precedente, è possibile sostituire map_save.rhs
con:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Se il {rhs}
contenuto del mapping originale è contenuto <SID>
, deve essere tradotto correttamente. Altrimenti, nulla dovrebbe essere cambiato.
E se vuoi abbreviare un po 'il codice, potresti sostituire le 4 righe che si occupano degli argomenti speciali con:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
La map()
funzione dovrebbe convertire ciascun elemento dall'elenco ['buffer', 'expr', 'nowait', 'silent']
nel corrispondente argomento di mappatura, ma solo se la sua chiave interna map_save
è diversa da zero. E join()
dovrebbe unire tutti gli elementi in una stringa.
Pertanto, un modo più efficace per salvare e ripristinare la mappatura potrebbe essere:
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:
Sto affrontando lo stesso problema, come salvare e ripristinare una mappatura in un plug-in di disegno. E penso di aver trovato 2 problemi che la risposta iniziale non ha visto al momento in cui l'ho scritta, mi dispiace per quello.
Primo problema, supponiamo che l'utente usi <C-c>
in una mappatura globale ma anche in una mappatura buffer-locale. Esempio:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
In questo caso, maparg()
darà priorità alla mappatura locale:
: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}
Che è confermato in :h maparg()
:
The mappings local to the current buffer are checked first,
then the global mappings.
Ma forse non sei interessato al mapping buffer-local, forse vuoi quello globale.
L'unico modo in cui ho scoperto, in modo affidabile, di ottenere le informazioni sulla mappatura globale, è cercare di annullare la mappatura temporanea di una potenziale mappatura buffer-local usando una stessa chiave.
Potrebbe essere fatto in 4 passaggi:
- salva una (potenziale) mappatura buffer-locale usando la chiave
<C-c>
- eseguire
:silent! nunmap <buffer> <C-c>
per eliminare una (potenziale) mappatura buffer-locale
- salva la mappatura globale (
maparg('<C-c>', 'n', 0, 1)
)
- ripristinare la mappatura buffer-locale
Il secondo problema è il seguente. Supponiamo che l'utente non abbia mappato nulla <C-c>
, quindi l'output di maparg()
sarà un dizionario vuoto. E in questo caso, il processo di ripristino non consiste nell'installazione di un mapping ( :nnoremap
), ma nella distruzione di un mapping ( :nunmap
).
Per provare a risolvere questi 2 nuovi problemi, puoi provare questa funzione per salvare i mapping:
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
... e questo per ripristinarli:
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()
funzione potrebbe essere utilizzata per salvare i mapping.
Si aspetta 3 argomenti:
- un elenco di chiavi; esempio:
['<C-a>', '<C-b>', '<C-c>']
- una modalità; esempio:
n
per la modalità normale o x
per la modalità visiva
- una bandiera booleana; se lo è
1
, significa che sei interessato ai mapping globali e, se lo è 0
, a quelli locali
Con esso, si potrebbe risparmiare le mappature globali utilizzando i tasti C-a
, C-b
e C-c
, in modalità normale, all'interno di un dizionario:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
Quindi, in seguito, quando vorrai ripristinare i mapping, puoi chiamare Restore_mappings()
, passando il dizionario contenente tutte le informazioni come argomento:
call Restore_mappings(your_saved_mappings)
Potrebbe esserci un terzo problema, durante il salvataggio / ripristino delle mappature buffer-local. Perché, tra il momento in cui abbiamo salvato i mapping e il momento in cui proviamo a ripristinarli, il buffer corrente potrebbe essere cambiato.
In questo caso, forse la Save_mappings()
funzione potrebbe essere migliorata salvando il numero del buffer corrente ( bufnr('%')
).
Quindi, Restore_mappings()
utilizzare queste informazioni per ripristinare i mapping buffer-local nel buffer corretto. Probabilmente potremmo usare il :bufdo
comando, aggiungere il prefisso a quest'ultimo con un conteggio (corrispondente al numero di buffer precedentemente salvato) e suffissarlo con il comando mapping.
Forse qualcosa del tipo:
:{original buffer number}bufdo {mapping command}
Dovremmo prima verificare se il buffer esiste ancora, usando la bufexists()
funzione, perché potrebbe essere stato eliminato nel frattempo.