È 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}( nnoremapvs 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: 0e 1.
0perché stai cercando una mappatura e non un'abbreviazione, e 1perché 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_savecontiene una chiave chiamata il 'sid'cui valore è l'identificatore corretto.
Pertanto, per rendere più robusto il comando di ripristino precedente, è possibile sostituire map_save.rhscon:
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:
nper la modalità normale o xper 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-be 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 :bufdocomando, 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.