Vous pouvez utiliser la maparg()
fonction.
Pour tester si l'utilisateur a mappé quelque chose <C-c>
en mode normal, vous écririez:
if !empty(maparg('<C-c>', 'n'))
Si l'utilisateur a mappé quelque chose, pour stocker le {rhs}
dans une variable, vous écririez:
let rhs_save = maparg('<C-c>', 'n')
Si vous souhaitez plus d'informations sur le mappage, comme:
- est-ce silencieux (
<silent>
argument)?
- est-il local au tampon actuel (
<buffer>
argument)?
- est l'
{rhs}
évaluation d'une expression ( <expr>
argument)?
- remappe-t-il le
{rhs}
( nnoremap
vs nmap
)?
- si l'utilisateur a un autre mappage qui commence par
<C-c>
, Vim attend-il que plus de caractères soient saisis ( <nowait>
argument)?
- ...
Ensuite, vous pourriez donner un troisième et un quatrième argument: 0
et 1
.
0
parce que vous cherchez une cartographie et non une abréviation, et 1
parce que vous voulez un dictionnaire avec un maximum d'informations et pas seulement la {rhs}
valeur:
let map_save = maparg('<C-c>', 'n', 0, 1)
En supposant que l'utilisateur n'a utilisé aucun argument spécial dans son mappage et qu'il ne remappe pas le {rhs}
, pour le restaurer, vous pouvez simplement écrire:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
Ou pour être sûr et restaurer tous les arguments possibles:
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
Edit: Désolé, je viens de réaliser que cela ne fonctionnerait pas comme prévu si l'utilisateur appelle une fonction script locale dans {rhs}
le mappage.
Supposons que l'utilisateur ait le mappage suivant dans son vimrc
:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
Quand il frappe <C-c>
, il affiche le message hello world!
.
Et dans votre plugin, vous enregistrez un dictionnaire avec toutes les informations, puis modifiez temporairement son mappage comme ceci:
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
Maintenant, il s'affichera bye all!
. Votre plugin fonctionne, et une fois terminé, il essaie de restaurer le mappage avec la commande précédente.
Il échouera probablement avec un message ressemblant à ceci:
E117: Unknown function: <SNR>61_FuncA
61
est juste l'identifiant du script dans lequel votre commande de mappage serait exécutée. Ce pourrait être n'importe quel autre numéro. Si votre plugin est le 42ème fichier provenant du système de l'utilisateur, il le sera 42
.
Dans un script, lorsqu'une commande de mappage est exécutée, Vim traduit automatiquement la notation <SID>
en code de clé spéciale <SNR>
, suivi d'un nombre unique pour le script et d'un trait de soulignement. Il doit le faire, car lorsque l'utilisateur frappera <C-c>
, le mappage sera exécuté en dehors du script, et donc il ne saura pas dans quel script FuncA()
est défini.
Le problème est que le mappage d'origine provenait d'un script différent de celui de votre plugin, donc ici la traduction automatique est incorrecte. Il utilise l'identifiant de votre script, alors qu'il devrait utiliser l'identifiant de l'utilisateur vimrc
.
Mais vous pouvez faire la traduction manuellement. Le dictionnaire map_save
contient une clé appelée 'sid'
dont la valeur est l'identifiant correct.
Donc, pour rendre la commande de restauration précédente plus robuste, vous pouvez remplacer map_save.rhs
par:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Si le {rhs}
mappage d'origine contient <SID>
, il doit être correctement traduit. Sinon, rien ne devrait être changé.
Et si vous voulez raccourcir un peu le code, vous pouvez remplacer les 4 lignes qui s'occupent des arguments spéciaux par:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
La map()
fonction doit convertir chaque élément de la liste ['buffer', 'expr', 'nowait', 'silent']
en l'argument de mappage correspondant, mais uniquement si sa clé à l'intérieur map_save
est différente de zéro. Et join()
devrait joindre tous les éléments dans une chaîne.
Ainsi, un moyen plus robuste d'enregistrer et de restaurer le mappage pourrait être:
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:
Je suis confronté au même problème que vous, comment enregistrer et restaurer un mappage dans un plugin de dessin. Et je pense que j'ai trouvé 2 problèmes que la réponse initiale ne voyait pas au moment où je l'ai écrit, désolé.
Premier problème, supposons que l'utilisateur utilise <C-c>
dans un mappage global mais aussi dans un mappage tampon-local. Exemple:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
Dans ce cas, maparg()
donnera la priorité à la cartographie 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}
Ce qui est confirmé dans :h maparg()
:
The mappings local to the current buffer are checked first,
then the global mappings.
Mais peut-être que vous n'êtes pas intéressé par le mappage tampon-local, peut-être que vous voulez le global.
Le seul moyen que j'ai trouvé pour obtenir de manière fiable les informations sur le mappage global, est d'essayer de démapper temporairement un mappage potentiel de tampon local avec la même clé.
Cela pourrait se faire en 4 étapes:
- enregistrer un mappage local (potentiel) du tampon à l'aide de la clé
<C-c>
- exécuter
:silent! nunmap <buffer> <C-c>
pour supprimer un mappage local-tampon (potentiel)
- enregistrer la cartographie globale (
maparg('<C-c>', 'n', 0, 1)
)
- restaurer le mappage tampon-local
Le deuxième problème est le suivant. Supposons que l'utilisateur n'ait rien mappé <C-c>
, la sortie de maparg()
sera un dictionnaire vide. Et dans ce cas, le processus de restauration ne consiste pas à installer un mapping ( :nnoremap
), mais à détruire un mapping ( :nunmap
).
Pour essayer de résoudre ces 2 nouveaux problèmes, vous pouvez essayer cette fonction pour enregistrer les mappages:
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
... et celui-ci pour les restaurer:
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()
fonction pourrait être utilisée pour enregistrer les mappages.
Il attend 3 arguments:
- une liste de clés; exemple:
['<C-a>', '<C-b>', '<C-c>']
- un mode; exemple:
n
pour le mode normal ou x
pour le mode visuel
- un drapeau booléen; si c'est le cas
1
, cela signifie que vous êtes intéressé par les mappages globaux, et si c'est le cas 0
, par les mappages locaux
Avec elle, vous pouvez enregistrer les applications globales à l' aide des touches C-a
, C-b
et C-c
, en mode normal, dans un dictionnaire:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
Ensuite, plus tard, lorsque vous voudrez restaurer les mappages, vous pourrez appeler Restore_mappings()
, en passant le dictionnaire contenant toutes les informations comme argument:
call Restore_mappings(your_saved_mappings)
Il pourrait y avoir un troisième problème lors de l'enregistrement / restauration des mappages locaux de tampon. Parce que, entre le moment où nous avons enregistré les mappages et le moment où nous essayons de les restaurer, le tampon actuel peut avoir changé.
Dans ce cas, la Save_mappings()
fonction pourrait peut-être être améliorée en enregistrant le numéro du tampon actuel ( bufnr('%')
).
Et puis, Restore_mappings()
utiliserait ces informations pour restaurer les mappages de tampon local dans le bon tampon. Nous pourrions probablement utiliser la :bufdo
commande, préfixer ce dernier avec un nombre (correspondant au numéro de tampon précédemment enregistré) et le suffixer avec la commande de mappage.
Peut-être quelque chose comme:
:{original buffer number}bufdo {mapping command}
Il faudrait d'abord vérifier si le tampon existe toujours, en utilisant la bufexists()
fonction, car il aurait pu être supprimé entre-temps.
Dans mes plugins, lorsque j'ai des mappages temporaires, ils sont toujours en tampon local - je ne me soucie vraiment pas de sauvegarder les mappages globaux ni de quoi que ce soit de complexe qui les implique. D'où ma
lh#on#exit().restore_buffer_mapping()
fonction d'aide - de lh-vim-lib .En fin de compte, ce qui se passe est le suivant:
la source