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}
( nnoremap
vs 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: 0
i 1
.
0
ponieważ szukasz odwzorowania, a nie skrótu, i 1
ponieważ 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
61
jest 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_save
zawiera klucz o nazwie, 'sid'
którego wartość jest poprawnym identyfikatorem.
Aby poprzednie polecenie przywracania było bardziej niezawodne, możesz zastąpić map_save.rhs
je:
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_save
jest 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:
n
w trybie normalnym lub x
w 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-b
i 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 :bufdo
komendy, 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ąć.
W moich wtyczkach, gdy mam tymczasowe mapowania, są one zawsze buforowane lokalnie - naprawdę nie dbam o zapisywanie globalnych mapowań ani o nic złożonego, które ich dotyczą. Stąd moja
lh#on#exit().restore_buffer_mapping()
funkcja pomocnika - z lh-vim-lib .W końcu dzieje się tak:
źródło