--- Custom statusline using std APIs and no external dependencies local icon = require 'std.icon' local table = require 'std.table' local auto = require 'std.auto' -- Local state/cache local cache = { git_branch = {}, -- per-directory cache lsp_count = 0, } local cached_cwd = assert(vim.uv.cwd()) -- Component functions local function mode_component() local mode = vim.api.nvim_get_mode().mode local mode_icons = { n = icon.normal, -- Ν i = icon.insert, --  v = icon.visual, -- 󰒉 V = icon.visual, ['\22'] = icon.visual, -- ^V c = icon.command, -- 󰘳 R = icon.replace, --  } return '%#ModeMsg#' .. (mode_icons[mode] or mode) .. '%*' end local function lsp_component() local count = cache.lsp_count if count == 0 then return '' end return '%@v:lua.BugabingaStatusline.on_lsp_click@' .. icon.lsp .. ' ' .. count .. '%X' end local registered = {} local function register(fn) table.insert(registered, fn) end local function reset() for i = #registered, 1, -1 do table.remove(registered, i) end end local function plugins_component() local results = table.map(function(fn) return fn() end, registered) local filtered = table.filter(function(c) return c ~= '' end, results) return table.concat(filtered, ' ') end local function file_component() local name = vim.api.nvim_buf_get_name(0) -- An empty name modifies into the working directory, which reads as if the -- buffer were a file in it. A nameless buffer says so instead. if name == '' then return icon.file .. ' [No Name]' end local path = vim.fn.fnamemodify(name, ':~:.') if #path > 40 then path = '...' .. path:sub(-37) end local modified = vim.api.nvim_get_option_value('modified', { buf = 0 }) and ' ' .. icon.modified or '' return icon.file .. ' ' .. path .. modified end local function git_component() local cwd = cached_cwd if not cache.git_branch[cwd] then vim.system({ 'git', 'branch', '--show-current' }, { cwd = cwd, timeout = 2000, }, function(result) if result.code == 0 then local branch = (result.stdout or ''):gsub('\n', ''):sub(1, 15) cache.git_branch[cwd] = icon.branch .. ' ' .. branch else cache.git_branch[cwd] = '' end vim.schedule(function() vim.cmd.redrawstatus() end) end) return '' end return cache.git_branch[cwd] end local function position_component() return '%l:%c/%L' end local function fileinfo_component() local ft = vim.bo.filetype local enc = vim.bo.fileencoding or vim.o.encoding local fmt = vim.bo.fileformat return string.format('%s %s %s', ft, enc, fmt) end -- Main statusline function local function render() local components = { mode_component(), lsp_component(), plugins_component(), file_component(), git_component(), '%=' .. position_component(), fileinfo_component(), } local filtered = table.filter(function(c) return c ~= '' end, components) return table.concat(filtered, ' ') end _G.BugabingaStatusline = { render = render, register = register, reset = reset, plugins_component = plugins_component, git_component = git_component, _get_cache = function() return cache end, _get_cached_cwd = function() return cached_cwd end, on_lsp_click = function() vim.cmd('LspInfo') end, } vim.opt.statusline = '%!v:lua.BugabingaStatusline.render()' auto 'statusline' { { events = 'LspAttach', command = function() cache.lsp_count = #vim.lsp.get_clients() vim.cmd.redrawstatus() end, }, { events = 'LspDetach', command = function() cache.lsp_count = #vim.lsp.get_clients() vim.cmd.redrawstatus() end, }, { events = 'DirChanged', command = function() cached_cwd = assert(vim.uv.cwd()) cache.git_branch = {} vim.cmd.redrawstatus() end, }, { events = { 'ModeChanged', 'BufEnter', 'WinEnter' }, command = function() vim.cmd.redrawstatus() end, }, } return BugabingaStatusline