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

时间:2014-02-18 16:09:18

标签: 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..."到其他地方执行正常模式移动的方式非常好。

谢谢!

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:2)

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

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>删除了使用从Visual切换到Command模式时自动输入的范围。另请注意,:vmap使用gv来恢复视觉选择。