馃 a tiny, customizable statusline for neovim
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 0e0a110a2ce1add94a1055319aa301712e2d206a 184 lines 5.1 kB view raw
1local log = require("lylla.log") 2local utils = require("lylla.utils") 3 4---@class lylla.proto 5---@field wins table<integer, table> 6---@field win integer 7---@field modules any[] 8---@field winbar any[] 9---@field timer uv.uv_timer_t 10---@field refreshau integer 11local statusline = {} 12 13statusline.wins = {} 14 15---@class lylla.proto 16---@field new fun(self, win): lylla.proto 17function statusline:new(win) 18 if statusline.wins[win] then 19 statusline.wins[win]:close() 20 end 21 local stl = setmetatable({ 22 win = win, 23 modules = vim.deepcopy(require("lylla.config").get().modules, true), 24 winbar = vim.deepcopy(require("lylla.config").get().winbar, true), 25 }, { __index = statusline }) 26 statusline.wins[win] = stl 27 return stl 28end 29 30---@class lylla.proto 31---@field init fun(self) 32function statusline:init() 33 local err, err_kind 34 ---@diagnostic disable-next-line: assign-type-mismatch 35 self.timer, err, err_kind = vim.uv.new_timer() 36 if not self.timer or err then 37 vim.api.nvim_echo({ { err_kind }, { "\n\t" }, { err } }, true, { err = true }) 38 return 39 end 40 41 local refresh = require("lylla.config").get().refresh_rate 42 self.timer:start(0, refresh, function() 43 self:refresh() 44 end) 45 46 self.refreshau = vim.api.nvim_create_autocmd(require("lylla.config").get().events, { 47 group = vim.api.nvim_create_augroup("lylla:refresh", { clear = false }), 48 callback = function(ev) 49 self:refresh(ev) 50 end, 51 }) 52end 53 54---@class lylla.proto 55---@field close fun(self) 56function statusline:close() 57 self.timer:stop() 58 self.timer:close() 59 vim.api.nvim_del_autocmd(self.refreshau) 60 statusline.wins[self.win] = nil 61end 62 63local function refreshcomponent(self, fn, ev) 64 do 65 local ok, result = pcall(fn, self, ev) 66 if not ok then 67 log.error("[lylla] error occured on refresh:\n\t" .. result) 68 end 69 end 70end 71 72---@class lylla.proto 73---@field refresh fun(self, ev?: vim.api.keyset.create_autocmd.callback_args) 74function statusline:refresh(ev) 75 vim.schedule(function() 76 if not vim.api.nvim_win_is_valid(self.win) then 77 return 78 end 79 80 refreshcomponent(self, statusline.set, ev) 81 refreshcomponent(self, statusline.setwinbar, ev) 82 end) 83end 84 85---@class lylla.proto 86---@field fold fun(self, ev?: vim.api.keyset.create_autocmd.callback_args, modules: any[]): string 87function statusline:fold(ev, modules) 88 if type(modules) ~= "table" or modules == nil then 89 return "" 90 end 91 92 local lst = vim 93 .iter(ipairs(modules)) 94 :map(function(_, module) 95 if type(module) == "table" and module.fn and type(module.fn) == "function" then 96 if module.opts and module.opts.events then 97 -- refresh from timer 98 if not ev and module.prev then 99 return module.prev 100 end 101 -- refresh from non-match event 102 if ev and not vim.tbl_contains(module.opts.events, ev.event) and module.prev then 103 return module.prev 104 end 105 end 106 do 107 local ok, result = pcall(module.fn) 108 if not ok then 109 error(result) 110 end 111 module.prev = result 112 end 113 return module.prev 114 end 115 if type(module) == "function" then 116 local ok, result = pcall(module) 117 if not ok then 118 error(result) 119 end 120 return result 121 end 122 return module 123 end) 124 :totable() 125 lst = utils.flatten(lst, 1) 126 return vim.iter(lst):fold("", function(str, module) 127 if type(module) == "string" and #module > 0 then 128 return str .. module 129 end 130 if type(module) ~= "table" or #module == 0 then 131 return str 132 end 133 local text = module[1] 134 if text == nil or type(text) ~= "string" or #text == 0 then 135 return str 136 end 137 local hl = module[2] 138 if hl and type(hl) == "string" and #hl > 0 then 139 return str .. "%#" .. hl .. "#" .. text .. "%*" 140 end 141 return str .. "%*" .. text 142 end) 143end 144 145---@class lylla.proto 146---@field get fun(self, ev?: vim.api.keyset.create_autocmd.callback_args) 147function statusline:get(ev) 148 return self:fold(ev, self.modules) 149end 150 151---@class lylla.proto 152---@field getwinbar fun(self, ev?: vim.api.keyset.create_autocmd.callback_args) 153function statusline:getwinbar(ev) 154 return self:fold(ev, self.winbar) 155end 156 157---@class lylla.proto 158---@field setwinbar fun(self, ev?: vim.api.keyset.create_autocmd.callback_args) 159function statusline:setwinbar(ev) 160 local buf = vim.api.nvim_win_get_buf(self.win) 161 if vim.bo[buf].buftype ~= "" then 162 return 163 end 164 165 local ok, result = pcall(vim.api.nvim_win_call, self.win, function() 166 return self:getwinbar(ev) 167 end) 168 assert(ok, string.format("error occured while trying to evaluate winbar:\n\t%s", result)) 169 170 vim.wo[self.win].winbar = result 171end 172 173---@class lylla.proto 174---@field set fun(self, ev?: vim.api.keyset.create_autocmd.callback_args) 175function statusline:set(ev) 176 local ok, result = pcall(vim.api.nvim_win_call, self.win, function() 177 return self:get(ev) 178 end) 179 assert(ok, string.format("error occured while trying to evaluate statusline:\n\t%s", result)) 180 181 vim.wo[self.win].statusline = result 182end 183 184return statusline