🪴 a tiny, customizable statusline for neovim

feat: support hl inheritance and sections

https://github.com/neovim/neovim/issues/35806
https://github.com/neovim/neovim/pull/37153

+75 -24
+75 -24
lua/lylla/utils.lua
··· 52 52 return result 53 53 end 54 54 55 + local sfmt = "%s%%*%s" 56 + local sfmt_inherit = "%s%s" 57 + -- str, hl_name, text 58 + local hlfmt = "%s%%#%s#%s" 59 + local hlfmt_inherit = "%s%%$%s$%s" 60 + 61 + ---@param str string 62 + ---@param text string 63 + ---@param inherit boolean 64 + ---@param hl? string 65 + ---@return string 66 + local function strfmt(str, text, inherit, hl) 67 + if hl then 68 + return string.format(inherit and hlfmt_inherit or hlfmt, str, hl, text) 69 + end 70 + return string.format(inherit and sfmt_inherit or sfmt, str, text) 71 + end 72 + 55 73 function utils.fold(lst) 56 74 vim.validate("lst", lst, "table") 57 75 58 76 lst = utils.flatten(lst, 1) 77 + ---@type string|false 78 + local section = false 59 79 return vim.iter(ipairs(lst)):fold("", function(str, _, module) 80 + local inherit = not not section 60 81 if type(module) == "string" and #module > 0 then 61 - return str .. module 82 + return strfmt(str, module, inherit) 62 83 end 63 - if type(module) ~= "table" or #module == 0 then 84 + if type(module) ~= "table" then 85 + return str 86 + end 87 + if module.section ~= nil and (type(module.section) == "string" or module.section == false) then 88 + section = module.section 89 + if section then 90 + return string.format("%s%%#%s#", str, module.section) 91 + end 64 92 return str 65 93 end 66 94 local text = module[1] ··· 69 97 end 70 98 local hl = module[2] 71 99 if not hl then 72 - return string.format("%s%%*%s", str, text) 100 + return strfmt(str, text, inherit) 73 101 end 74 102 if type(hl) == "string" and #hl > 0 then 75 - return string.format("%s%%#%s#%s%%*", str, hl, text) 103 + return strfmt(str, text, inherit, hl) 76 104 elseif type(hl) == "table" and (hl.fg or hl.bg or hl.link) then 77 - local hl_name = string.format("@lylla.%s", vim.fn.sha256(vim.inspect(hl))) 78 - vim.schedule(function() 79 - vim.api.nvim_set_hl(0, hl_name, hl) 80 - end) 81 - return string.format("%s%%#%s#%s%%*", str, hl_name, text) 105 + inherit = inherit or hl.inherit 106 + hl.inherit = nil 107 + local hl_name = hl.link 108 + if not hl_name then 109 + hl_name = utils.create_hl(hl) 110 + end 111 + return strfmt(str, text, inherit, hl_name) 112 + elseif type(hl) == "table" and hl.inherit then 113 + return strfmt(str, text, true) 82 114 end 83 115 84 - return string.format("%s%%*%s", str, text) 116 + return strfmt(str, text, inherit) 85 117 end) 118 + end 119 + 120 + ---@param hl_name string 121 + ---@return vim.api.keyset.highlight 122 + function utils.reverse_hl(hl_name) 123 + local hl = vim.api.nvim_get_hl(0, { name = hl_name }) 124 + if vim.tbl_isempty(hl) or (not hl.fg and not hl.bg and not hl.link) then 125 + return {} 126 + end 127 + if hl.link then 128 + return utils.reverse_hl(hl.link) 129 + end 130 + local rev = vim.deepcopy(hl) 131 + rev.fg = hl.bg 132 + rev.bg = hl.fg 133 + ---@diagnostic disable-next-line: return-type-mismatch 134 + return rev 135 + end 136 + 137 + ---@param hl vim.api.keyset.highlight 138 + function utils.create_hl(hl) 139 + local hl_name = string.format("@lylla.%s", vim.fn.sha256(vim.inspect(hl))) 140 + vim.schedule(function() 141 + vim.api.nvim_set_hl(0, hl_name, hl) 142 + end) 143 + return hl_name 86 144 end 87 145 88 146 function utils.getfilename() ··· 156 214 ---@return string 157 215 function utils.get_modehl() 158 216 local mode = vim.api.nvim_get_mode().mode 159 - 160 - if string.match(mode, "^n") then 161 - return utils.get_modehl_name("normal") 162 - end 217 + local hl_name = utils.get_modehl_name("normal") 163 218 164 219 if string.match(mode, "^[vVs]") then 165 - return utils.get_modehl_name("visual") 220 + hl_name = utils.get_modehl_name("visual") 221 + elseif string.match(mode, "^c") then 222 + hl_name = utils.get_modehl_name("command") 223 + elseif string.match(mode, "^[irRt]") then 224 + hl_name = utils.get_modehl_name("insert") 166 225 end 167 226 168 - if string.match(mode, "^c") then 169 - return utils.get_modehl_name("command") 170 - end 171 - 172 - if string.match(mode, "^[irRt]") then 173 - return utils.get_modehl_name("insert") 174 - end 175 - 176 - return mode 227 + return hl_name, utils.create_hl(utils.reverse_hl(hl_name)) 177 228 end 178 229 179 230 return utils