馃 a tiny, customizable statusline for neovim
at main 227 lines 6.0 kB view raw
1local utils = {} 2 3--- flatten list so all children have level of depth 4---@param lst table 5---@param maxdepth integer 6function utils.flatten(lst, maxdepth) 7 vim.validate("lst", lst, "table") 8 vim.validate("maxdepth", maxdepth, "number") 9 10 ---@param _t any[] 11 ---@return integer 12 local function _depth(_t) 13 return vim.iter(ipairs(_t)):fold(1, function(maxd, _, v) 14 if type(v) == "table" and vim.islist(v) then 15 local d = 1 + _depth(v) 16 if d > maxd then 17 return d 18 end 19 end 20 return maxd 21 end) 22 end 23 24 local result = {} 25 ---@param _t any[] 26 local function _flatten(_t) 27 local n = #_t 28 for i = 1, n do 29 local v = _t[i] 30 if type(v) ~= "table" or (not vim.islist(v)) or _depth(v) <= maxdepth then 31 table.insert(result, v) 32 else 33 _flatten(v) 34 end 35 end 36 end 37 _flatten(lst) 38 return result 39end 40 41local sfmt = "%s%%*%s" 42local sfmt_inherit = "%s%s" 43-- str, hl_name, text 44local hlfmt = "%s%%#%s#%s" 45local hlfmt_inherit = "%s%%$%s$%s" 46 47---@param str string 48---@param text string 49---@param inherit boolean 50---@param hl? string 51---@return string 52local function strfmt(str, text, inherit, hl) 53 if hl then 54 return string.format(inherit and hlfmt_inherit or hlfmt, str, hl, text) 55 end 56 return string.format(inherit and sfmt_inherit or sfmt, str, text) 57end 58 59function utils.fold(lst) 60 vim.validate("lst", lst, "table") 61 62 lst = utils.flatten(lst, 1) 63 ---@type string|false 64 local section = false 65 return vim.iter(ipairs(lst)):fold("", function(str, _, module) 66 local inherit = not not section 67 if type(module) == "string" and #module > 0 then 68 return strfmt(str, module, inherit) 69 end 70 if type(module) ~= "table" then 71 return str 72 end 73 if module.section ~= nil and (type(module.section) == "string" or module.section == false) then 74 section = module.section 75 if section then 76 return string.format("%s%%#%s#", str, module.section) 77 end 78 return str 79 end 80 local text = module[1] 81 if text == nil or type(text) ~= "string" or #text == 0 then 82 return str 83 end 84 local hl = module[2] 85 if not hl then 86 return strfmt(str, text, inherit) 87 end 88 if type(hl) == "string" and #hl > 0 then 89 return strfmt(str, text, inherit, hl) 90 elseif type(hl) == "table" and (hl.fg or hl.bg or hl.link) then 91 inherit = inherit or hl.inherit 92 hl.inherit = nil 93 local hl_name = hl.link 94 if not hl_name then 95 hl_name = utils.create_hl(hl) 96 end 97 return strfmt(str, text, inherit, hl_name) 98 elseif type(hl) == "table" and hl.inherit then 99 return strfmt(str, text, true) 100 end 101 102 return strfmt(str, text, inherit) 103 end) 104end 105 106---@param hl_name string 107---@return vim.api.keyset.highlight 108function utils.reverse_hl(hl_name) 109 local hl = vim.api.nvim_get_hl(0, { name = hl_name }) 110 if vim.tbl_isempty(hl) or (not hl.fg and not hl.bg and not hl.link) then 111 return {} 112 end 113 if hl.link then 114 return utils.reverse_hl(hl.link) 115 end 116 local rev = vim.deepcopy(hl) 117 rev.fg = hl.bg 118 rev.bg = hl.fg 119 ---@diagnostic disable-next-line: return-type-mismatch 120 return rev 121end 122 123---@param hl vim.api.keyset.highlight 124function utils.create_hl(hl) 125 local hl_name = string.format("@lylla.%s", vim.fn.sha256(vim.inspect(hl))) 126 vim.schedule(function() 127 vim.api.nvim_set_hl(0, hl_name, hl) 128 end) 129 return hl_name 130end 131 132function utils.getfilename() 133 local _, default_file_hl = require("mini.icons").get("default", "file") 134 135 local name = vim.fn.expand("%:t") 136 137 local file_icon_raw, file_icon_hl 138 139 if vim.bo.buftype ~= "" then 140 local filetype = vim.bo.filetype 141 file_icon_raw, file_icon_hl = require("mini.icons").get("filetype", filetype) 142 name = string.format("(%s)", vim.bo.filetype) 143 else 144 file_icon_raw, file_icon_hl = require("mini.icons").get("file", name) 145 end 146 147 return { { name, default_file_hl }, { " " }, { file_icon_raw, file_icon_hl } } 148end 149 150function utils.getfilepath() 151 if vim.bo.buftype ~= "" then 152 return {} 153 end 154 155 local path = vim.fn.expand("%:p:~:.") 156 157 local file_path_list = {} 158 local _ = string.gsub(path, "[^/]+", function(w) 159 table.insert(file_path_list, w) 160 end) 161 162 local filepath = vim.iter(ipairs(file_path_list)):fold("", function(acc, i, fragment) 163 if i == #file_path_list then 164 return acc 165 end 166 acc = acc .. fragment .. "/" 167 return acc 168 end) 169 170 return { filepath, "Directory" } 171end 172 173function utils.get_searchcount() 174 local result = vim.fn.searchcount({ recompute = 1 }) 175 if vim.v.hlsearch ~= 1 then 176 return "" 177 end 178 if vim.tbl_isempty(result) then 179 return "" 180 end 181 local term = vim.fn.getreg("/") 182 local display 183 if result.incomplete == 1 then 184 -- timed out 185 display = "[?/??]" 186 elseif result.incomplete == 2 then 187 -- max count exceeded 188 if result.total > result.maxcount and result.current > result.maxcount then 189 display = string.format("[>%d/>%d]", result.current, result.total) 190 elseif result.total > result.maxcount then 191 display = string.format("[%d/>%d]", result.current, result.total) 192 end 193 end 194 display = display or string.format("[%d/%d]", result.current, result.total) 195 196 return { { string.format("/%s", term), "IncSearch" }, { " " }, { display, "MsgSeparator" } } 197end 198 199---@param mode string 200---@return string 201---@return string 202function utils.get_modehl_name(mode) 203 return "@lylla." .. mode, string.format("@lylla.%s.rev", mode) 204end 205 206---@return string 207---@return string 208function utils.get_modehl() 209 local mode = vim.api.nvim_get_mode().mode 210 local modename = "normal" 211 212 if string.match(mode, "^[vVs]") then 213 modename = "visual" 214 elseif string.match(mode, "^c") then 215 modename = "command" 216 elseif string.match(mode, "^[it]") then 217 modename = "insert" 218 elseif string.match(mode, "^[rR]") then 219 modename = "replace" 220 elseif string.match(mode, "^%ao") then 221 modename = "operator" 222 end 223 224 return utils.get_modehl_name(modename) 225end 226 227return utils