Eric's Blog 时光荏苒,岁月如梭

Neovim 状态栏及标签栏点击事件

2024-12-28
Eric Wong

什么是 tablineat

熟悉 Vim 或者 Neovim 的用户对于其状态栏(statusline)和标签栏(tabline)应该也不陌生,对于这两个 UI 组件上面的点击事件, 早期是只有 tabline 上面支持点击操控 Vim 的标签页。

很早以前,就有用户想在 vim-airline 插件的标签栏实现 Buffer 切换的功能, 但是似乎直到现在,Vim 都未增加该功能。

2016 年,Neovim 增加了 tablineat 特性,使得用户可以在自定义状态栏和标签栏时, 指定某个区域设定对应的点击事件回调函数,以此实现监控状态栏和标签栏的点击事件。可以使用 has('tablineat') 检测当前 Neovim 是否支持该特性。

以下内容摘自 :h statusline

@ N   Start of execute function label. Use %X or %T to end the label,
      e.g.: %10@[email protected]%X.  Clicking this label runs the
      specified function: in the example when clicking once using left
      mouse button on "foo.c", a `SwitchBuffer(10, 1, 'l', '    ')`
      expression will be run.  The specified function receives the
      following arguments in order:
      1. minwid field value or zero if no N was specified
      2. number of mouse clicks to detect multiple clicks
      3. mouse button used: "l", "r" or "m" for left, right or middle
         button respectively; one should not rely on third argument
         being only "l", "r" or "m": any other non-empty string value
         that contains only ASCII lower case letters may be expected
         for other mouse buttons
      4. modifiers pressed: string which contains "s" if shift
         modifier was pressed, "c" for control, "a" for alt and "m"
         for meta; currently if modifier is not pressed string
         contains space instead, but one should not rely on presence
         of spaces or specific order of modifiers: use |stridx()| to
         test whether some modifier is present; string is guaranteed
         to contain only ASCII letters and spaces, one letter per
         modifier; "?" modifier may also be present, but its presence
         is a bug that denotes that new mouse button recognition was
         added without modifying code that reacts on mouse clicks on
         this label.
      Use |getmousepos()|.winid in the specified function to get the
      corresponding window id of the clicked item.

测试标签栏点击事件

按照前面的帮助文档描述的内容,可以使用格式 %N@function_name@text%X 来指定区域监控点击事件, 回调函数的名称为两个 @ 标记之间的字符串,%@ 之间的数字作为第一个参数。

写一个测试函数,看一看点击事件的具体执行效果:

function! OnClick(a, b, c, d) abort
  echom a:a
  echom a:b
  echom a:c
  echom '>' . a:d . '<'
endfunction

set tabline=xxxxxxx%1@OnClick@11111%X%2@OnClick@22222%X

将以上文件保存为 vim 文件并执行 :so % 后,状态栏变成了 xxxxxxx1111122222, 鼠标左键单击 11111 区域,看到如下输出。

1
1
l
>    <

上述四行分别对应函数的四个参数:

  • 第一个参数是 %@ 之间的数字
  • 第二个参数是鼠标点击的次数
  • 第三个参数是鼠标键位, 可以是左键(l)、右键(r)或者中键(m
  • 第四个参数对应的时按下的组合键,Ctrl 键(c)、Shift 键(s)、Alt 键(a)、Meta 键(m
  • 最后一个参数是对应的 shift/alt/ctrl

多次点击存在的问题

在使用前面的测试脚本测试的过程中,发现第二个参数返回的是点击的次数,其结果不是完全可预期的。为了更加方便测试,将测试的脚本修改如下:

function! OnClick(a, b, c, d) abort
  echom '点击次数:' .. a:b
endfunction

set tabline=xxxxxxx%1@OnClick@11111%X%2@OnClick@22222%X

多次点击后,其结果如下:

点击次数:1
点击次数:2
点击次数:3
点击次数:4
点击次数:1
点击次数:2
点击次数:3
点击次数:4
点击次数:1
点击次数:2
点击次数:1
点击次数:2
点击次数:3
点击次数:4
点击次数:1
点击次数:2

上面的输出可以看到,当连续点击时,回调函数会在每次点击时被调用。并且点击次数会增加, 当间隔时间超过 mousetime 时,点击次数计数归零, 间隔时间可以查阅 :h mousetime, 默认为 500 毫秒。


版权声明:本文为原创文章,遵循 署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)版权协议,转载请附上原文出处链接和本声明。


延生阅读

分享到:

评论

目前只支持使用邮件参与评论。