Ви можете використовувати maparg()функцію.
Щоб перевірити, чи користувач щось відмітив <C-c>у звичайному режимі, напишете:
if !empty(maparg('<C-c>', 'n'))
Якщо користувач щось відобразив для зберігання {rhs}змінної, ви напишете:
let rhs_save = maparg('<C-c>', 'n')
Якщо ви хочете отримати більше інформації про картографування, наприклад:
- це мовчить (
<silent>аргумент)?
- вона локальна для поточного буфера (
<buffer>аргументу)?
- чи є
{rhs}оцінка виразу ( <expr>аргументу)?
- чи перезаписує
{rhs}( nnoremapпроти nmap)?
- якщо у користувача є інше відображення, яке починається з того
<C-c>, чи чекає Vim, щоб ввести більше символів ( <nowait>аргумент)?
- ...
Тоді ви можете дати третій та четвертий аргументи: 0і 1.
0тому що ви шукаєте відображення, а не абревіатуру, і 1тому, що ви хочете, щоб словник максимум інформації, а не лише {rhs}значення:
let map_save = maparg('<C-c>', 'n', 0, 1)
Якщо припустити, що користувач не використовував жодного спеціального аргументу для свого відображення, і що він не переосмислює його {rhs}, щоб відновити його, ви можете просто написати:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
Або бути впевненим і відновити всі можливі аргументи:
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
Редагувати: Вибачте, я щойно зрозумів, що він не працюватиме так, як очікувалося, якщо користувач викликає функцію локального сценарію в {rhs}розділі відображення.
Припустимо, що користувач має таке відображення всередині свого vimrc:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
Коли він потрапляє <C-c>, він відображає повідомлення hello world!.
І у своєму плагіні ви зберігаєте словник з усією інформацією, а потім тимчасово змінюєте його відображення так:
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
Тепер він відобразиться bye all!. Ваш плагін виконує певну роботу, і коли він закінчиться, він намагається відновити відображення за допомогою попередньої команди.
Ймовірно, це не вдасться з таким виглядом повідомлення:
E117: Unknown function: <SNR>61_FuncA
61- це лише ідентифікатор сценарію, в якому буде виконуватися ваша команда картографування. Це може бути будь-яке інше число. Якщо ваш плагін - це 42-й файл, що базується на системі користувача, він буде 42.
Всередині сценарію, коли виконується команда картографування, Vim автоматично переводить нотацію <SID>в спеціальний код ключа <SNR>, а потім номер, унікальний для сценарію, і підкреслення. Це має зробити це, тому що, коли користувач натисне <C-c>, відображення буде виконуватися поза сценарієм, і, таким чином, він не буде знати, в якому сценарії FuncA()визначено.
Проблема полягає в тому, що оригінальне відображення було розміщено за іншим сценарієм, ніж ваш плагін, тому автоматичний переклад тут неправильний. Він використовує ідентифікатор вашого сценарію, тоді як він повинен використовувати ідентифікатор користувача vimrc.
Але ви могли зробити переклад вручну. Словник map_saveмістить ключ, який називається 'sid'правильним ідентифікатором.
Отже, щоб зробити попередню команду відновлення більш надійною, її можна замінити map_save.rhsна:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Якщо {rhs}оригінальне відображення містило оригінальне відображення <SID>, воно має бути належним чином перекладено. Інакше нічого не слід міняти.
І якщо ви хочете трохи скоротити код, ви можете замінити 4 рядки, які стосуються спеціальних аргументів:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
map()Функція повинна перетворити кожен елемент зі списку ['buffer', 'expr', 'nowait', 'silent']у відповідному відображенні аргумент , але тільки якщо його ключ всередині map_saveненульовий. І join()повинен об'єднати всі елементи в рядок.
Отже, більш надійним способом збереження та відновлення відображення може бути:
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:
Я зіткнувся з тією ж проблемою, що і ви, як зберегти та відновити відображення у плагіні для малювання. І я думаю, що я знайшов 2 питання, на які початкова відповідь не бачив, коли я це писав, вибачте за це.
По-перше, припустимо, що користувач використовує <C-c>глобальне відображення, але також і локальне буферне відображення. Приклад:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
У цьому випадку maparg()буде надано пріоритет локальному картографуванню:
: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}
Що підтверджено в :h maparg():
The mappings local to the current buffer are checked first,
then the global mappings.
Але, можливо, вас не цікавить буферне локальне відображення, можливо, ви хочете глобальне.
Єдиний спосіб, з якого я дізнався надійно отримати інформацію про глобальне відображення, - це спробувати тимчасово зняти карту потенційного, тіньового, локально-буферного відображення за допомогою того самого ключа.
Це можна зробити в 4 етапи:
- збережіть (потенційне) буферне локальне відображення за допомогою ключа
<C-c>
- виконати,
:silent! nunmap <buffer> <C-c>щоб видалити (потенційне) буферне локальне відображення
- зберегти глобальне відображення (
maparg('<C-c>', 'n', 0, 1))
- відновити локальне буферне відображення
Друге питання - наступне. Припустимо, що користувач нічого не зробив на карті <C-c>, тоді вихід maparg()буде порожнім словником. І в цьому випадку процес відновлення полягає не в установці відображення ( :nnoremap), а в знищенні відображення ( :nunmap).
Щоб спробувати вирішити ці 2 нові проблеми, ви можете спробувати цю функцію для збереження відображень:
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
... і цей відновити їх:
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()Функція може бути використана для збереження відображення.
Очікує 3 аргументи:
- список ключів; приклад:
['<C-a>', '<C-b>', '<C-c>']
- режим; приклад:
nдля звичайного або xдля візуального
- булевий прапор; якщо це так
1, це означає, що вас цікавлять глобальні відображення, а якщо вони - 0місцеві
З його допомогою ви можете зберегти глобальні відображення за допомогою клавіш C-a, C-bа C-cв звичайному режимі всередині словника:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
Потім, пізніше, коли ви захочете відновити відображення, ви можете зателефонувати Restore_mappings(), передаючи словник, що містить всю інформацію, як аргумент:
call Restore_mappings(your_saved_mappings)
Під час збереження / відновлення буферно-локальних відображень може виникнути третя проблема. Тому що між моментом, коли ми зберегли відображення, і моментом, коли ми намагаємось відновити їх, поточний буфер, можливо, змінився.
У цьому випадку, можливо, Save_mappings()функцію можна було б покращити, зберігаючи число поточного буфера ( bufnr('%')).
А потім Restore_mappings()використає цю інформацію для відновлення локальних відображень буфера в правильному буфері. Напевно, ми могли б використовувати :bufdoкоманду, префікс останньої з підрахунком (відповідність раніше збереженому номеру буфера) та суфікс із командою відображення.
Можливо, щось на кшталт:
:{original buffer number}bufdo {mapping command}
Слід спочатку перевірити, чи буфер все ще існує, використовуючи bufexists()функцію, оскільки його можна було тим часом видалити.