vim:映射正常/视觉模式移动

vim:映射正常/视觉模式移动,vim,Vim,我有在正常模式下移动光标的功能,例如: function! s:Skip(distance, direction) execute "normal! ".string(a:distance).a:direction endfunction 其中,a:distance是一个整数,a:direction类似于'h'或'l'。这可以很好地作为法线模式映射,但是,我想将这些运动扩展到视觉模式 问题在于,在视觉模式下运行的执行“normal!etc…”命令不起作用(即不执行光标移动,就像在正常模

我有在正常模式下移动光标的功能,例如:

function! s:Skip(distance, direction)
    execute "normal! ".string(a:distance).a:direction
endfunction
其中,
a:distance
是一个整数,
a:direction
类似于
'h'
'l'
。这可以很好地作为法线模式映射,但是,我想将这些运动扩展到视觉模式

问题在于,在视觉模式下运行的
执行“normal!etc…”
命令不起作用(即不执行光标移动,就像在正常模式下在原始和最终光标位置之间选择文本一样)。一种解决方法是:退出视觉模式,放下一个标记,执行
skip()
,然后从新光标位置视觉选择标记。我不喜欢这个解决方案,不仅因为它需要一个标记,而且它“感觉”不像是将正常模式运动转换为视觉模式运动的正确方法

有什么建议吗?我应该指出,我有很多函数,比如
skip()
,它们执行
执行“正常!移动…”
,因此最好有一个通用规则,而不是一次性的零碎解决方案(如果是这样的话,比如标记)。将我执行正常模式移动的方式从
执行“normal!etc…”更改为其他方式完全可以


谢谢

将当前模式传递到功能中(例如,通过
isVisual
标志);您的映射知道模式,或者您可以查询
mode()
。然后,对于视觉模式,通常使用
gv
重新选择当前选择(当您从映射触发功能时,选择丢失)


这将在视觉模式映射后保留(扩展)选择。请注意,
gv
还将光标恢复到一个选择边界(通常是结束);您可能需要考虑/切换到另一侧(使用
o
)。

将当前模式传递到功能中(例如,通过
isVisual
标志);您的映射知道模式,或者您可以查询
mode()
。然后,对于视觉模式,通常使用
gv
重新选择当前选择(当您从映射触发功能时,选择丢失)

这将在视觉模式映射后保留(扩展)选择。请注意,
gv
还将光标恢复到一个选择边界(通常是结束);您可能需要解释/切换到另一边(使用
o
)。

有关@Ingo Karkat答案中方法的“实时”示例,请查看matchit.vim(在标准vim发行版的宏/目录中):

nnoremap%:调用匹配包装器(“”,1,'n')
nnoremap g%:调用匹配包装器(“”,0,'n'))
vnoremap%:调用匹配包装(“”,1,'v')m'gv``
vnoremap g%:调用匹配包装(“”,0,'v')m'gv``
onoremap%v:调用匹配_包装(“”,1,'o'))
onoremap g%v:调用匹配_包装器(“”,0,'o'))
我使用单字母代码(
n
v
o
)来表示模式,而不是
isVisual
;只是一种不同的风格。在@Ingo Karkat回答后的评论中,
删除了使用:从视觉模式切换到命令模式时自动输入的范围。另请注意,
:vmap
s使用
gv
恢复视觉选择。

有关@Ingo Karkat答案中方法的“实时”示例,请查看matchit.vim(在标准vim发行版的宏/目录中):

nnoremap%:调用匹配包装器(“”,1,'n')
nnoremap g%:调用匹配包装器(“”,0,'n'))
vnoremap%:调用匹配包装(“”,1,'v')m'gv``
vnoremap g%:调用匹配包装(“”,0,'v')m'gv``
onoremap%v:调用匹配_包装(“”,1,'o'))
onoremap g%v:调用匹配_包装器(“”,0,'o'))

我使用单字母代码(
n
v
o
)来表示模式,而不是
isVisual
;只是一种不同的风格。在@Ingo Karkat回答后的评论中,
删除了使用:从视觉模式切换到命令模式时自动输入的范围。还请注意,
:vmap
s使用
gv
来恢复视觉选择。

小提示:您不需要
字符串(a:距离)
;Vim会自动为您将数字转换为字符串。我不明白在视觉模式下调用函数时您想要实现什么。调用例如
4l
后,光标向左移动4次,是否希望保留选择范围?这意味着新光标位置位于选择区域的“中间”位置?或者您只想更改视觉选择区域4个字符?(取决于当前光标位置,选择区域的开始或结束)我想我想要后者。也就是说,如果
skip()
执行“normal!4l”
,那么在视觉模式下它应该相当于
4l
(即,它将光标向左移动4个字符,这样您就可以选择4个字符,并将光标保留在第4个字符上)小提示:您不需要
字符串(a:距离)
;Vim会自动为您将数字转换为字符串。我不明白在视觉模式下调用函数时您想要实现什么。调用例如
4l
后,光标向左移动4次,是否希望保留选择范围?这意味着新光标位置位于选择区域的“中间”位置?或者您只想更改视觉选择区域4个字符?(取决于当前光标位置,选择区域的开始或结束)我想我想要后者。也就是说,如果
skip()
execute“normal!4l”
,那么在视觉模式下,它应该相当于
4l
(也就是说,它将光标向左移动4个字符,这样您就可以选择4个字符,并将光标保留在第4个字符上)。也许我没有这样做,但甚至类似这样做
function! s:Skip(distance, direction, isVisual)
    execute "normal! ".(a:isVisual ? 'gv': '').a:distance.a:direction
endfunction
nnoremap <silent> %  :<C-U>call <SID>Match_wrapper('',1,'n') <CR>
nnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'n') <CR>
vnoremap <silent> %  :<C-U>call <SID>Match_wrapper('',1,'v') <CR>m'gv``
vnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'v') <CR>m'gv``
onoremap <silent> %  v:<C-U>call <SID>Match_wrapper('',1,'o') <CR>
onoremap <silent> g% v:<C-U>call <SID>Match_wrapper('',0,'o') <CR>