VIM:映射正常/可视模式运动



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

function! s:Skip(distance, direction)
execute "normal! ".string(a:distance).a:direction
endfunction

其中a:distance是整数,a:direction是类似于'h''l'的东西。 这作为普通模式映射工作正常,但是,我想将这些运动扩展到可视模式。

问题是在可视模式下运行的execute "normal! etc..."命令不起作用(即不会像在正常模式下选择原始光标位置和最终光标位置之间的文本那样执行光标移动)。 一种解决方法可能是:退出可视模式,删除标记,执行skip()然后从新的光标位置直观地选择标记。 我不关心这个解决方案,不仅因为它需要一个标记,而且它也没有"感觉"像是将正常模式运动转换为视觉模式运动的正确方法。

有什么建议吗? 我应该指出,我有许多像skip()这样的函数可以执行execute "normal! movement..."因此最好有一个一般规则,而不是一次性的零碎解决方案(如果是这种情况,例如标记)。 将我执行正常模式移动的方式从execute "normal! etc..."更改为其他方式是完全可以的。

谢谢!

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

function! s:Skip(distance, direction, isVisual)
execute "normal! ".(a:isVisual ? 'gv': '').a:distance.a:direction
endfunction

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

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

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>

我使用一个字母的代码(nvo)来表示模式,而不是isVisual;只是不同的样式。 就像@Ingo Karkat的答案之后的评论一样,<C-U>删除了使用自动输入的范围:从视觉模式切换到命令模式。 另请注意,:vmap使用gv来还原视觉对象选择。

最新更新