From df9af247b89a0787df4cacf9d26cedad7c037f0f Mon Sep 17 00:00:00 2001 From: robin Date: Sun, 31 Aug 2025 01:03:43 +0200 Subject: [PATCH] feat: winbar support --- lua/lylla/config.lua | 43 +++++++++++++-- lua/lylla/init.lua | 8 ++- lua/lylla/winbar.lua | 125 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 6 deletions(-) create mode 100644 lua/lylla/winbar.lua diff --git a/lua/lylla/config.lua b/lua/lylla/config.lua index 25bf8c2..b8223b1 100644 --- a/lua/lylla/config.lua +++ b/lua/lylla/config.lua @@ -6,6 +6,7 @@ ---@field prefix string ---@field hls table<'normal'|'visual'|'command'|'insert', vim.api.keyset.highlight> ---@field modules any[] +---@field winbar any[] local utils = require("lylla.utils") @@ -43,7 +44,7 @@ M.default = { hls = {}, modules = { component(function() - local prefix = require('lylla.config').get().prefix + local prefix = require("lylla.config").get().prefix local modehl = utils.get_modehl() return { { prefix, modehl }, @@ -90,6 +91,37 @@ M.default = { { "%l:%c" }, { " " }, }, + winbar = { + component(function() + local prefix = require("lylla.config").get().prefix + local modehl = utils.get_modehl() + return { + { prefix, modehl }, + } + end, { + events = { "ModeChanged", "CmdlineEnter" }, + }), + { " " }, + component(function() + return { + utils.getfilepath(), + utils.getfilename(), + { " " }, + } + end, { + events = { + "WinEnter", + "BufEnter", + "BufWritePost", + "FileChangedShellPost", + "Filetype", + }, + }), + { " " }, + component(function() + return { utils.get_searchcount() } + end), + }, } ---@type lylla.config @@ -118,7 +150,7 @@ local function tmerge(tdefault, toverride) tnew[k] = v return tnew end - if type(v) == 'table' then + if type(v) == "table" then tnew[k] = tmerge(v, toverride[k]) return tnew end @@ -132,8 +164,9 @@ end ---@param toverride lylla.config ---@return lylla.config function M.merge(tdefault, toverride) - if vim.fn.has('nvim-0.11.0') == 1 then - toverride = vim.tbl_deep_extend('keep', toverride, { editor = { float = { solid_border = vim.o.winborder == 'solid' } } }) + if vim.fn.has("nvim-0.11.0") == 1 then + toverride = + vim.tbl_deep_extend("keep", toverride, { editor = { float = { solid_border = vim.o.winborder == "solid" } } }) end return tmerge(tdefault, toverride) end @@ -146,7 +179,7 @@ end ---@param cfg lylla.config ---@return lylla.config function M.override(cfg) - return M.merge( M.default, cfg) + return M.merge(M.default, cfg) end ---@param cfg lylla.config diff --git a/lua/lylla/init.lua b/lua/lylla/init.lua index e4d77c1..326d618 100644 --- a/lua/lylla/init.lua +++ b/lua/lylla/init.lua @@ -35,14 +35,16 @@ end function M.init() vim.api.nvim_create_autocmd("WinNew", { - group = vim.api.nvim_create_augroup("lylla:statusline:new", { clear = true }), + group = vim.api.nvim_create_augroup("lylla:win:new", { clear = true }), callback = function() local win = vim.api.nvim_get_current_win() require("lylla.statusline"):new(win):init() + require("lylla.winbar"):new(win):init() end, }) local win = vim.api.nvim_get_current_win() require("lylla.statusline"):new(win):init() + require("lylla.winbar"):new(win):init() vim.api.nvim_create_autocmd("WinClosed", { group = vim.api.nvim_create_augroup("lylla:close", { clear = true }), @@ -51,6 +53,10 @@ function M.init() if stl then stl:close() end + local wbar = require("lylla.winbar").wins[ev.match] + if wbar then + wbar:close() + end end, }) diff --git a/lua/lylla/winbar.lua b/lua/lylla/winbar.lua new file mode 100644 index 0000000..0e7391e --- /dev/null +++ b/lua/lylla/winbar.lua @@ -0,0 +1,125 @@ +local utils = require("lylla.utils") + +---@type lylla.proto +---@diagnostic disable-next-line: missing-fields +local winbar = {} + +winbar.wins = {} + +---@class lylla.proto +---@field new fun(self, win): lylla.proto +function winbar:new(win) + if winbar.wins[win] then + winbar.wins[win]:close() + end + local stl = setmetatable({ + win = win, + modules = vim.deepcopy(require("lylla.config").get().winbar, true), + }, { __index = winbar }) + winbar.wins[win] = stl + return stl +end + +---@class lylla.proto +---@field init fun(self) +function winbar:init() + local err, err_kind + ---@diagnostic disable-next-line: assign-type-mismatch + self.timer, err, err_kind = vim.uv.new_timer() + if not self.timer or err then + vim.api.nvim_echo({ { err_kind }, { "\n\t" }, { err } }, true, { err = true }) + return + end + + local refresh = require("lylla.config").get().refresh_rate + self.timer:start(0, refresh, function() + self:refresh() + end) + + self.refreshau = vim.api.nvim_create_autocmd(require("lylla.config").get().events, { + group = vim.api.nvim_create_augroup("lylla:refresh", { clear = false }), + callback = function(ev) + self:refresh(ev) + end, + }) +end + +---@class lylla.proto +---@field close fun(self) +function winbar:close() + self.timer:stop() + self.timer:close() + vim.api.nvim_del_autocmd(self.refreshau) + winbar.wins[self.win] = nil +end + +---@class lylla.proto +---@field refresh fun(self, ev?: vim.api.keyset.create_autocmd.callback_args) +function winbar:refresh(ev) + vim.schedule(function() + if not vim.api.nvim_win_is_valid(self.win) then + return + end + + local buf = vim.api.nvim_win_get_buf(self.win) + if vim.bo[buf].buftype ~= "" then + return + end + + local ok, result = pcall(vim.api.nvim_win_call, self.win, function() + return self:get(ev) + end) + if not ok then + return + end + + vim.wo[self.win].winbar = result + end) +end + +---@class lylla.proto +---@field fold fun(self, ev?: vim.api.keyset.create_autocmd.callback_args): string +function winbar:fold(ev) + local modules = vim + .iter(ipairs(self.modules)) + :map(function(i, module) + if type(module) == "table" and module._type == "component" then + if module.opts and module.opts.events then + -- refresh from timer + if not ev and module.prev then + return module.prev + end + -- refresh from non-match event + if ev and not vim.tbl_contains(module.opts.events, ev.event) and module.prev then + return module.prev + end + end + module.prev = module.fn() + return module.prev + end + if type(module) == "function" then + module = module() + end + return module + end) + :totable() + modules = utils.flatten(modules, 1) + return vim.iter(modules):fold("", function(str, module) + if type(module) ~= "table" or #module == 0 then + return str + end + local text = module[1] + if #module > 1 then + return str .. "%#" .. module[2] .. "#" .. text .. "%*" + end + return str .. "%*" .. text + end) +end + +---@class lylla.proto +---@field get fun(self, ev?: vim.api.keyset.create_autocmd.callback_args) +function winbar:get(ev) + return self:fold(ev) +end + +return winbar -- 2.51.2