repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/statusline.lua
Raw--- 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