🐙

Neovim: winbar 上のクリックに反応させる

に公開

Neovim v0.8 で入っていたという winbar の存在を今更認識し、これを使えば最近課題感を感じていた terminal buffer の切り替えを自分好みにできそうだったので使ってみました。

動作確認は Neovim v0.11.3 で行いました。

winbar とは

window bar の略で各 window の上部に表示される部分のこと。
winbar 変数に何かしらの値が設定されると表示されます。

たとえば以下のようにすると現在開いているファイルのパスが winbar に表示されます

lua vim.o.winbar = '%f'

file

クリックに反応させる

表示させた部分はクリックに反応させることができます。

以下のように書くと winbar に [Hello] と表示され、その部分をクリックすると現在開いている buffer に文字が挿入されます

sample.lua
function _G.my_winbar_click_handler(id, clicks, button, mods)
 local comment = ("-- id: %s, num clicks %d,  (button: %s), mods %s"):format(id, clicks, button, mods)
 vim.api.nvim_buf_set_lines(0, -1, -1, false, { comment })
end

vim.o.winbar = "%123@v:lua.my_winbar_click_handler@[Hello]%T"

click

%{int}@v:lua.some_function@{display string}%T の形式で書くと、{display string} がクリックされたときに some_function が呼び出されます。
関数は4つの引数を取り、第1引数には {int} で指定した整数値が渡されます。第2引数にはクリック数、第3引数にはクリックされたボタンの種類 (l, r, m の3種。それぞれ左クリック、右クリック、中クリック)、第4引数には修飾キー(ctrl, alt, etc)の名前が渡されます。
%T はクリック可能領域の終端を表します。%T の代わりに %X も使うことができます。
tabbar 等では %X%T で違いがあるようですが、winbar においては今のところ差はないように思います。

ref

buffer の切り替え

もう少し実用的な例として以下では buffer の切り替えを行えるようにしています。
クリックされたら buffer number が関数に渡るようにして vim.api.nvim_set_current_buf で buffer の切り替えを行っています。

switch_buffer.lua
local bufnrs = {}
for i = 1, 5 do
  local bufnr = vim.api.nvim_create_buf(false, true)
  table.insert(bufnrs, bufnr)
  vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Buffer ' .. bufnr })
end

local winid = vim.api.nvim_open_win(bufnrs[1], true, {
  split = 'below',
  height = math.floor(vim.o.lines * 0.4),
  style = 'minimal',
})

local function set_winbar(winid, bufnrs)
  local winbar_text_format = '%%%d@v:lua.my_winbar_click_handler@[Buffer %d]%%T'
  local winbar_text = ''
  for i, bufnr in ipairs(bufnrs) do
    winbar_text = winbar_text .. string.format(winbar_text_format, bufnr, bufnr)
    if i < #bufnrs then
      winbar_text = winbar_text .. ' | '
    end
  end

  vim.api.nvim_set_option_value('winbar', winbar_text, {
    win = winid,
  })
end

function _G.my_winbar_click_handler(minwid, clicks, button, mods)
  vim.api.nvim_set_current_buf(minwid)
  set_winbar(winid, bufnrs)
end

set_winbar(winid, bufnrs)

switch buffer

上記の例は普通の buffer ですが、私はこれを toggleterm で作られた terminal buffer の切り替えに使用しています。素の toggleterm でも HEAD では winbar 対応されていますがクリックすると新しい window で開きます。一方、私の使い方としては window そのままで buffer の切り替えを行いたかったため、toggleterm の custom terminal を使いつつ winbar で切り替えが行えるようにしました。

switch terminal buffer

https://github.com/goropikari/tabterm.nvim

上記のように特定の条件を満たす buffer を winbar に表示して切替可能にするといった用途には結構便利だと思いました。

GitHubで編集を提案

Discussion