给 VSCodeVim 用户的福音,在 VSCodevim 中实现 Leap 打造最强移动插件

2,050 阅读6分钟

Leap.nvim 是一个在 Vim 和 Neovim 社区非常流行的移动插件,可以让你在 Vim 中快速定位到代码中的任何位置。但是,由于 VSCodeVim 不支持该插件,看到别人使用 leap.nvim 的效果,我也感到十分眼红。 showcase.gif

更令人郁闷的是,VSCodeVim 的维护者似乎也没有打算更新该插件。在对应的 issue 中,大家的反馈已经很久没有得到回应了。

VSCodeVim对leap.nvim的支持问题

于是,我决定自己动手实现该插件。经过一番努力,现在已经可用了,并且在 VSCodeVim 中使用效果非常棒。

vim_leap_section_1.gif

不得不说,由于 VSCodeVim 不支持插件系统,所以插件的开发确实比较麻烦,需要深入了解它的运行机制。VSCodeVim 果然是个阉割版啊。

使用

下面介绍下目前已经支持的功能:

  • 上下搜索
  • 双向搜索
  • 可视化模式
  • 自定义 Leap 标签
  • 自定义标记点显示位置
  • 大小写敏感

接下来将逐一介绍。

上下搜索

这是 Leap 最基本的功能,通过按下 s char1 char2 向下搜索,按下 S char1 char2 向上搜索。

例如,按下 "s o n" 就可以向下搜索文本: vim_leap_section_1.gif

按下 "S o n" 就可以向上搜索文本: vim_leap_section_2.gif

有个小细节:如果匹配点只有一个,则会自动跳转过去: vim_leap_section_4.gif

如果你想要搜索的字符后面是空白符,则可以使用 s char space。例如: vim_leap_section_5.gif

这里想跳转到 "h" 后面,但是 "h" 后面是一个空白符,这时候只需要按下 s h space 就搞定啦。

如果你想执行上一次的搜索,只需要按下 s enter 就可以执行上次的搜索了。搜索的顺序也是按照上一次的顺序来的: vim_leap_section_6.gif

这里第一次搜索的是 s o n,然后想重复执行的时候按下 s enter 搞定。

预览模式

这里要特别说明一下,Leap 有一个预览模式。按下 "s char" 的第一个字符的时候,会提前显示标记点位置,让你先有个心理预期,知道等会可能会跳转的点在哪里。然后当按下第二个搜索字符的时候,就会只剩下符合要求的标记点,然后就可以通过按键的字符来跳转了。

注意:很多同学在使用的时候会错把第一个提示点当成跳转点,发现按下的时候不生效。

支持双向搜索

当然,有些用户可能不想区分搜索方向,也不想按下 S(需要按下 shift,对于像我这样的懒人来说有些麻烦)。因此,为了满足这些用户的需求,还增加了双向搜索功能,只需按下一个 s 就可以搞定啦!

vim_leap_section_11.gif

只需要在 settings.json 中设置这个配置 "vim.leapBidirectionalSearch": true

跳转点的设计也非常巧妙,为了让标记点均匀分布在上下两个方向,我特意设计了下面的算法,默认的 labelsklyuiopnm,qwertzxcvbahdgjf;,双向搜索的跳转点会变成:下一个用 s,上一个用 k,下一个用 l,上一个用 y。这样设计可以保证距离较近的跳转点都是单字符,并且还能保证使用 s 必定跳转到最近的下一个,使用 k 必定跳转到最近的上一个。

支持可视化模式

搜索功能也可以在可视化模式下使用,比如:

vim_leap_section_8.gif

先按下 v 进入可视化模式,然后按下 s e r 来搜索 e r 跳转选中,非常方便。

这里有个小小的遗憾,向上搜索的时候不可以使用 S,因为 SSurround 插件占用了。但是如果开启双向搜索的模式的话就不会有这个烦恼了,因为 s 可以同时上下搜索。

在可视化模式下,不光可以使用 s,还可以使用 xX

vim_leap_section_9.gif

那么 s x 的区别你看出来了吗?区别就是 s 是包含搜索的两个字符的,而 x 是不包含的。

例如,按下 s i n 可以看到是包含 In 的:

image.png

而按下 x i n 可以看到是不包含 In 的:

image.png

支持自定义 Leap 标签

如果您对默认的 labels 不满意,可以通过配置进行修改。

vim.leapLabels = 'sklyuiopnm,qwertzxcvbahdgjf;';

这里是和 easymotionlabels 对齐的,因此如果之前使用过 easymotion的话,你应该会非常熟悉, 其目的就是为了保持操作一致,因为这 2 个插件可以结合起来使用。

支持自定义标记位置

您还可以自定义 Leap 的标记位置。通过配置 "vim.leapShowMarkerPosition": "target",标记将显示在搜索字符的位置,如下动画所示:

vim_leap_section_10.gif

默认情况下,标记将显示在要跳转到的字符后面,但在我的使用体验中,跳转到实际标记更为直观。

支持大小写敏感

您还可以通过配置 "vim.leapCaseSensitive": false 来自定义大小写敏感度。默认情况下,大小写敏感度关闭,这意味着大写和小写字母被视为相同。

聊聊和 leap.nvim 的差异在哪里

由于 VSCodeVim 的底层实现问题,有一些 leap.nvim 的功能无法实现,另外还有一些功能进行了微小的修改以适应与原有功能的配合使用。

不支持在 OperatorPendingMode 使用

也就是说不可以配合 d y p 之类的 operator

这是由于 VSCodeVim 的底层实现问题导致的。但是支持在可视化模式下使用,只需要多按一个 v 即可。

多跳转点的实现方式与原生 leap.nvim 不同

在 leap.nvim 中,如果匹配点过多,则需要使用 spacetag 切换相应的组。这种方法的问题在于,如果匹配了三个组,则需要按两次 space 进行选择,这种情况非常极端,可能不会经常出现。

在我的实现中,参考了 easymotion 的跳转实现方式,从标记点从一个字母开始,如果超过一个字母,则使用两个字母。这样的好处是,无论匹配了多少次,两个字母都可以直接定位标记点。另外一个原因是,这种实现方式与 easymotion 统一,因为有些移动场景使用 easymotion,所以有两套选择方式会很难受。

安装

如果你看到这里,肯定是想尝试一下了。

很遗憾,由于官方还没有合并我的 PR,所以你需要下载我的 vim 版本来安装。

不过也不算麻烦,我已经打包好了,只需要下载下来就可以了:

  1. 下载 vim 插件安装包 github.com/cuixiaorui/…
  2. 执行 code --install-extension vim-1.25.2.vsix --force

需要注意的是,路径必须正确:

image.png

视频教程

当然,如果通过本文你仍然无法弄清如何安装和使用,还有视频教程可以观看:

结尾

好了,如果你对插件的功能有任何意见或建议,请留言给我反馈。

最后,有些同学可能会问:为什么不用 neovim 呢?用 VSCodeVim 不是很低端吗?这其实完全是个人偏好的问题,有人喜欢吃甜的,有人喜欢吃苦的,没有必要在这些没有意义的问题上纠结。这篇文章是送给使用 VSCodeVim 的同学的。

对了 想看代码实现的同学这是 pr 链接:github.com/VSCodeVim/V…