什么是 winbar
Neovim 0.8.0 就增加了 'winbar'
这一选项。winbar 实际上类似于状态栏(statusline),只不过 winbar 是显示在每一个窗口的顶部。
它的设置格式与状态栏也完全一致。
这里做了一个简单的示例效果图:
" 使用全局状态栏,状态栏只在底部显示,水平分割窗口将不再显示状态栏。
set laststatus=3
" 隐藏顶部标签栏
set showtabline=0
使用 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
这里面其实有很多功能可以去做的,比如:
- 排除 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
- 文件名按正则表达式排除
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
存在的一些问题
- callback 函数内无法获取到触发这一事件的 windows ID,因为说白了,winbar 是一个 local to window 的选项,通过指定 winid 去修改其值才是最保险的。