Możesz użyć tej maparg()funkcji.
Aby sprawdzić, czy użytkownik zmapował coś <C-c>w trybie normalnym, napiszesz:
if !empty(maparg('<C-c>', 'n'))
Jeśli użytkownik coś zmapował, aby zapisać {rhs}w zmiennej, napiszesz:
let rhs_save = maparg('<C-c>', 'n')
Jeśli chcesz uzyskać więcej informacji o mapowaniu, na przykład:
- czy to milczy (
<silent>argument)?
- czy jest lokalny dla bieżącego bufora (
<buffer>argumentu)?
- jest
{rhs}ocena wyrażenia ( <expr>argumentu)?
- czy odwzorowuje
{rhs}( nnoremapvs nmap)?
- jeśli użytkownik ma inne mapowanie, które zaczyna się od
<C-c>, czy Vim czeka na wpisanie większej liczby znaków ( <nowait>argument)?
- ...
Następnie możesz podać trzeci i czwarty argument: 0i 1.
0ponieważ szukasz odwzorowania, a nie skrótu, i 1ponieważ potrzebujesz słownika zawierającego maksimum informacji, a nie tylko {rhs}wartość:
let map_save = maparg('<C-c>', 'n', 0, 1)
Zakładając, że użytkownik nie użył żadnego specjalnego argumentu w swoim mapowaniu i że nie odwzorowuje on {rhs}, aby go przywrócić, możesz po prostu napisać:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
Lub, aby mieć pewność i przywrócić wszystkie możliwe argumenty:
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
Edycja: Przepraszam, właśnie zdałem sobie sprawę, że nie zadziałałoby zgodnie z oczekiwaniami, jeśli użytkownik wywoła funkcję lokalną dla skryptu w {rhs}odwzorowaniu.
Załóżmy, że użytkownik ma następujące mapowanie vimrc:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
Kiedy uderza <C-c>, wyświetla komunikat hello world!.
A we wtyczce zapisujesz słownik ze wszystkimi informacjami, a następnie tymczasowo zmieniasz jego mapowanie w następujący sposób:
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
Teraz wyświetli się bye all!. Twoja wtyczka działa trochę, a kiedy się skończy, próbuje przywrócić mapowanie za pomocą poprzedniego polecenia.
Prawdopodobnie zakończy się niepowodzeniem z komunikatem wyglądającym tak:
E117: Unknown function: <SNR>61_FuncA
61jest tylko identyfikatorem skryptu, w którym zostanie wykonane polecenie mapowania. Może to być dowolny inny numer. Jeśli wtyczka jest 42 plikiem pochodzącym z systemu użytkownika, to tak będzie 42.
Wewnątrz skryptu, gdy wykonywane jest polecenie mapowania, Vim automatycznie tłumaczy notację <SID>na specjalny kod klucza <SNR>, po którym następuje unikalna dla skryptu liczba i podkreślenie. Musi to zrobić, ponieważ gdy użytkownik uderzy <C-c>, mapowanie zostanie wykonane poza skryptem, a zatem nie będzie wiedział, w którym skrypcie FuncA()jest zdefiniowany.
Problem polega na tym, że oryginalne mapowanie pochodziło z innego skryptu niż wtyczka, więc tutaj automatyczne tłumaczenie jest nieprawidłowe. Używa identyfikatora twojego skryptu, podczas gdy powinien używać identyfikatora użytkownika vimrc.
Ale możesz wykonać tłumaczenie ręcznie. Słownik map_savezawiera klucz o nazwie, 'sid'którego wartość jest poprawnym identyfikatorem.
Aby poprzednie polecenie przywracania było bardziej niezawodne, możesz zastąpić map_save.rhsje:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Jeśli {rhs}oryginalne mapowanie zawierało <SID>, należy je odpowiednio przetłumaczyć. W przeciwnym razie nic nie powinno zostać zmienione.
A jeśli chcesz nieco skrócić kod, możesz zastąpić 4 wiersze, które zajmują się specjalnymi argumentami:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
map()Funkcja powinna przekształcić każdą pozycję z listy ['buffer', 'expr', 'nowait', 'silent']do odpowiedniego odwzorowania argumentu, ale tylko wtedy, gdy klucz wewnątrz map_savejest niezerowe. I join()powinien połączyć wszystkie elementy w ciąg.
Bardziej niezawodnym sposobem zapisywania i przywracania mapowania może być:
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')
Edycja2:
Mam do czynienia z tym samym problemem co Ty, jak zapisać i przywrócić mapowanie we wtyczce do rysowania. I myślę, że znalazłem 2 problemy, których początkowa odpowiedź nie widziała w chwili, gdy ją pisałem, przepraszam za to.
Pierwszy problem, załóżmy, że użytkownik używa <C-c>w mapowaniu globalnym, ale także w mapowaniu lokalnym bufora. Przykład:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
W takim przypadku maparg()pierwszeństwo będzie miało mapowanie lokalne:
: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}
Co potwierdza :h maparg():
The mappings local to the current buffer are checked first,
then the global mappings.
Ale może nie interesuje Cię mapowanie lokalne bufora, może chcesz globalne.
Jedynym sposobem, w jaki udało mi się rzetelnie uzyskać informacje o mapowaniu globalnym, jest próba tymczasowego odwzorowania potencjalnego, cieniowania, mapowania lokalnego bufora przy użyciu tego samego klucza.
Można to zrobić w 4 krokach:
- zapisz (potencjalne) lokalne mapowanie bufora za pomocą klucza
<C-c>
- wykonaj,
:silent! nunmap <buffer> <C-c>aby usunąć (potencjalne) lokalne mapowanie bufora
- zapisz globalne mapowanie (
maparg('<C-c>', 'n', 0, 1))
- przywrócić lokalne mapowanie bufora
Drugi problem jest następujący. Załóżmy, że użytkownik niczego nie zamapował <C-c>, a wynikiem maparg()będzie pusty słownik. W tym przypadku proces przywracania nie polega na instalacji mapowania ( :nnoremap), ale na zniszczeniu mapowania ( :nunmap).
Aby spróbować rozwiązać te 2 nowe problemy, możesz wypróbować tę funkcję, aby zapisać mapowania:
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
... i ten, aby je przywrócić:
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
Save_mappings()Funkcja może być używany do zapisywania mapowania.
Oczekuje 3 argumentów:
- lista kluczy; przykład:
['<C-a>', '<C-b>', '<C-c>']
- tryb; przykład:
nw trybie normalnym lub xw trybie wizualnym
- flaga logiczna; jeśli tak
1, oznacza to, że interesują Cię mapowania globalne, a jeśli tak 0, to lokalne
Dzięki niemu można zaoszczędzić globalnych mapowania za pomocą klawiszy C-a, C-bi C-c, w trybie normalnym, wewnątrz słownika:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
Następnie, gdy będziesz chciał przywrócić mapowania, możesz zadzwonić Restore_mappings(), przekazując słownik zawierający wszystkie informacje jako argument:
call Restore_mappings(your_saved_mappings)
Może występować trzeci problem podczas zapisywania / przywracania lokalnych map buforów. Ponieważ między chwilą zapisania mapowań a chwilą próby ich przywrócenia bieżący bufor mógł ulec zmianie.
W takim przypadku Save_mappings()funkcja może być poprawiona poprzez zapisanie numeru bieżącego bufora ( bufnr('%')).
Następnie Restore_mappings()użyłby tych informacji do przywrócenia mapowań lokalnych buforów we właściwym buforze. Prawdopodobnie moglibyśmy użyć tej :bufdokomendy, poprzedzić ją drugą liczbą (odpowiadającą wcześniej zapisanemu numerowi bufora) i dodać do niej komendę mapowania.
Może coś takiego:
:{original buffer number}bufdo {mapping command}
Musielibyśmy najpierw sprawdzić, czy bufor nadal istnieje, używając bufexists()funkcji, ponieważ można go w międzyczasie usunąć.