Вы могли бы использовать 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
команду, поставить перед последней префикс счетчиком (совпадающим с ранее сохраненным номером буфера) и добавить к суффиксу команду mapping.
Может быть что-то вроде:
:{original buffer number}bufdo {mapping command}
Мы должны были бы сначала проверить, если буфер все еще существует, используя bufexists()
функцию, потому что он мог бы быть удален за это время.