Ви можете використовувати 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()
функцію, оскільки його можна було тим часом видалити.