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

Neovim winbar 设置

2025-01-14
Eric Wong

什么是 winbar

Neovim 0.8.0 就增加了 'winbar' 这一选项。winbar 实际上类似于状态栏(statusline),只不过 winbar 是显示在每一个窗口的顶部。 它的设置格式与状态栏也完全一致。

这里做了一个简单的示例效果图:

" 使用全局状态栏,状态栏只在底部显示,水平分割窗口将不再显示状态栏。
set laststatus=3
" 隐藏顶部标签栏
set showtabline=0

winbar

使用 lua 设置 winbar

前面也提到了 Neovim 实际上早就增加了 winbar,我是因为习惯了现有的状态栏和标签栏,不太像改变操作习惯。 最近正好想尝试使用一下 winbar 特性,因为之前写过自定义的标签栏、状态栏,因此配置起来还算顺手。

详细代码可以看我的 Github 仓库:wsdjeg/winbar.nvim

实现的逻辑也比较简单,监控指定的 Neovim 事件,在 callback 函数内调用 redraw_winbar 函数。

local augroup = vim.api.nvim_create_augroup('winbar.nvim', {
  clear = true,
})
vim.api.nvim_create_autocmd({ 'BufWinEnter' }, {
  group = augroup,
  pattern = '*',
  callback = function(e)
    redraw_winbar()
  end,
})

我看过 fgheng/winbar.nvim 插件的代码,最后一次更新时间是 2022 年七月,在他的插件里 setup 函数直接这样写:

function M.setup(opts)
    config.set_options(opts)
    local winbar = require('winbar.winbar')

    winbar.init()
    if opts.enabled == true then
        vim.api.nvim_create_autocmd({ 'DirChanged', 'CursorMoved', 'BufWinEnter', 'BufFilePost', 'InsertEnter', 'BufWritePost' }, {
            callback = function()
                winbar.show_winbar()
            end
        })
    end
end

这会存在一个非常严重问题,就是如果使用者不小心调用了两次甚至多次 setup 函数,那么就会发现,实际上定义了多个重复的 autocmd。 因此不管是使用 Lua 来创建 autocmd 还是早期 Vim 下使用 Vim Script 创建 autocmd,都建议使用 augroup。

redraw_winbar 函数实现

简单到极致的实现:

local function redraw_winbar()
  local file_name = vim.fn.expand('%:t')

  if file_name == '' then
    return
  end

  local value = '%#SpaceVim_winbar#' .. file_name .. ' %#SpaceVim_winbar_Normal#' .. default_conf.winbar_seperator .. '%#Normal#'

  vim.api.nvim_set_option_value('winbar', value, { scope = 'local' })
end

这里面其实有很多功能可以去做的,比如:

  1. 排除 filetype
local file_name = vim.fn.expand('%:t')
local ft = vim.filetype.match({ filename = file_name })
for _, v in ipairs(excluded_filetypes) do
  if v == ft then
    return
  end
end
  1. 文件名按正则表达式排除
local excluded_regex = [[\.txt$]]
local re = vim.regex(excluded_regex)
local file_name = vim.fn.expand('%:t')
for _, v in ipairs(excluded_filetypes) do
  if re:match(file_name) then
    return
  end
end

存在的一些问题

  1. callback 函数内无法获取到触发这一事件的 windows ID,因为说白了,winbar 是一个 local to window 的选项,通过指定 winid 去修改其值才是最保险的。

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


延生阅读

分享到:

评论

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