到目前为止,(简化的)插件工作流程如下:
用户调用插件命令
该命令调用预处理功能:
function! s:PreTreatmentFunction(function, ...)
" Do some pretreatment stuff
" Create a mapping to call the TearDown
nnoremap <C-c> :call TeardDown()<CR>
" Call a function depending on the parameter passed to this one
if function == "foo"
call Foo()
else
call Bar()
endif
endfunction
调用另一个函数,该函数更改缓冲区的状态(上一个函数的最后一行中的
Foo()
或Bar()
)用户使用该映射调用拆解函数
拆解功能删除了创建的映射:
function! s:TearDown()
" Do some tear down stuff
" Remove the mapping
unmap <C-c>
endfunction
我对处理映射的方式不满意:如果用户已经将其映射到
所以我的问题是:如何保存
<C-c>
映射到的内容(如果已映射),并在我的拆解函数中恢复它?有内置功能吗?
我虽然了解q4312079请查看
grep
的结果,但感觉并不是真的“干净”。几点注意事项:那,但是他们说使用ftplugin在这里是不可能的:该插件不依赖于文件类型
我可以创建一个变量来让用户选择要使用的键:这可能是我会做的但是我主要对如何执行保存和恢复感兴趣。
我可以聘用当地领导人,但我认为这有点过分,我仍然对保存和恢复事情很感兴趣。
#1 楼
您可以使用maparg()
函数。要测试用户是否在正常模式下将某些内容映射到
<C-c>
,请输入:用户映射了一些内容,以便将
{rhs}
存储在变量中,您可以这样写:if !empty(maparg('<C-c>', 'n'))
如果您想要有关映射的更多信息,例如:
它是沉默的(
<silent>
参数)吗?它是否在当前缓冲区本地(
<buffer>
参数)?{rhs}
是表达式的求值(<expr>
参数)吗?是否重新映射
{rhs}
(nnoremap
与nmap
)?如果用户有另一个以
<C-c>
开头的映射,Vim是否等待输入更多字符(<nowait>
参数)? br /> 然后,您可以给出第三个和第四个参数:
0
和1
。 0
是因为您要查找映射而不是缩写,1
是因为您想要具有最大信息量而不仅仅是{rhs}
值的字典:let rhs_save = maparg('<C-c>', 'n')
假设用户在映射中没有使用任何特殊参数,并且没有重新映射
{rhs}
来还原它,则只需编写以下内容:let map_save = maparg('<C-c>', 'n', 0, 1)
或者可以确定并恢复所有可能的参数:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
编辑:对不起,我只是意识到这行不通如果用户在映射的
{rhs}
中调用脚本本地函数,则按预期进行。假设用户在其
vimrc
内部具有以下映射:>
当他按下
<C-c>
时,它会显示消息hello world!
。 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
现在,它将显示
bye all!
。您的插件完成了一些工作,当结束时,它会尝试使用上一个命令恢复映射。
它可能会失败,并显示以下消息:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
61
只是将在其中执行映射命令的脚本的标识符。可以是任何其他数字。如果您的插件是源于用户系统的第42个文件,则它将为42
。在脚本内,当执行映射命令时,Vim自动将符号
<SID>
转换为特殊键代码<SNR>
,然后是脚本唯一的数字和下划线。它必须这样做,因为当用户点击<C-c>
时,映射将在脚本之外执行,因此它将不知道在哪个脚本中定义了FuncA()
。问题是原始映射的来源与您的插件使用的脚本不同,因此此处的自动翻译是错误的。它使用脚本的标识符,而应使用用户的
vimrc
的标识符。但是您可以手动进行翻译。字典
map_save
包含一个名为'sid'
的键,其值是正确的标识符。因此,为使以前的还原命令更可靠,可以将
map_save.rhs
替换为: br />如果原始映射的{rhs}
包含<SID>
,则应正确翻译。否则,什么都不要更改。如果您想稍微缩短代码,则可以将照顾特殊参数的4行替换为:
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
map()
函数应将列表['buffer', 'expr', 'nowait', 'silent']
中的每个项目转换为相应的映射参数,但前提是map_save
中的键为非零。并且join()
应该将所有项目都连接到一个字符串中。 > Edit2:
我面临与您相同的问题,即如何在图形插件中保存和还原映射。而且我想我发现了两个问题,在我写这篇文章时,最初的答案都没有看到,对此感到抱歉。
第一个问题,假设用户在全局映射中使用
<C-c>
,但在本地缓冲区映射。示例:E117: Unknown function: <SNR>61_FuncA
在这种情况下,
maparg()
将优先使用本地映射:substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
已在
:h maparg()
中得到确认:join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
,但也许您对缓冲区局部映射不感兴趣,也许您想要全局映射。
唯一的方法我发现可靠地获得有关全局映射的信息,是尝试使用相同的键临时取消映射潜在的,阴影的,缓冲区局部的映射。
可以通过4个步骤完成:
使用键
<C-c>
保存(潜在的)缓冲区本地映射执行
:silent! nunmap <buffer> <C-c>
删除(潜在的)缓冲区本地映射保存全局映射(
maparg('<C-c>', 'n', 0, 1)
)还原本地缓冲区映射
第二个问题如下。假设用户没有将任何内容映射到
<C-c>
,那么maparg()
的输出将是一个空字典。在这种情况下,恢复过程不在于安装映射(:nnoremap
),而在于销毁映射(:nunmap
)。要解决这两个新问题,您可以尝试使用此功能来保存映射:
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')
Save_mappings()
函数可用于保存映射。它需要3个参数:
键列表;例如:
['<C-a>', '<C-b>', '<C-c>']
一种模式;例如:
n
(用于普通模式)或x
(用于可视模式)布尔标志;如果是
1
,则表示您对全局映射感兴趣,如果是0
,则表示对本地映射有了它,您可以在正常模式下在字典中使用键
C-a
,C-b
和C-c
保存全局映射:如果要恢复映射,可以调用Restore_mappings()
,将包含所有信息的字典作为参数传递: ,当保存/恢复本地缓冲区映射时。因为在保存映射的那一刻到尝试还原它们的那一刻之间,当前缓冲区可能已更改。在这种情况下,也许可以通过保存当前缓冲区的编号(
Save_mappings()
)。,然后,
bufnr('%')
将使用此信息来还原右侧缓冲区中的本地缓冲区映射。我们可能可以使用Restore_mappings()
命令,为后者加上一个计数(与先前保存的缓冲区号匹配),并在其后加上映射命令。 > nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
我们必须首先使用
:bufdo
函数检查缓冲区是否仍然存在,因为与此同时它可能已被删除。#2 楼
在我的插件中,当我有临时映射时,它们总是在本地缓冲-我真的不在乎保存全局映射,也不在乎涉及它们的复杂事物。因此,我的lh#on#exit().restore_buffer_mapping()
辅助函数-来自lh-vim-lib。最后,将发生以下情况:
评论
太神奇了,这正是我所需要的。谢谢!
–statox♦
16年5月11日在11:51