From bf1b2d50420794408275faf15c68ef9cc6db7728 Mon Sep 17 00:00:00 2001 From: Andrew Haynes Date: Sat, 3 Oct 2026 00:48:06 -0400 Subject: [PATCH] CHORE: Cleaned up the status bar and finished it --- nvim/.config/nvim/lua/DarthMooMancer/ui.lua | 112 +++++++++++++------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/nvim/.config/nvim/lua/DarthMooMancer/ui.lua b/nvim/.config/nvim/lua/DarthMooMancer/ui.lua index 51ae6f7..06186d2 100644 --- a/nvim/.config/nvim/lua/DarthMooMancer/ui.lua +++ b/nvim/.config/nvim/lua/DarthMooMancer/ui.lua @@ -1,4 +1,3 @@ ---- Derive a highlight from an existing scheme group. local function derive_hl(name, opts) local base = opts.base and vim.api.nvim_get_hl(0, { name = opts.base }) or {} @@ -10,7 +9,7 @@ local function derive_hl(name, opts) bold = opts.bold, }) end ---- Derive a mode highlight where bg comes from a syntax group and fg contrasts. + local function derive_mode_hl(name, color_group) local color = vim.api.nvim_get_hl(0, { name = color_group }) local status_bg = vim.api.nvim_get_hl(0, { name = 'StatusLine' }) @@ -21,7 +20,6 @@ local function derive_mode_hl(name, color_group) }) end ---- (Re)build all statusline highlight groups from current scheme. local function setup_statusline_highlights() derive_mode_hl('StatusModeNormal', 'Type') derive_mode_hl('StatusModeInsert', 'String') @@ -29,9 +27,7 @@ local function setup_statusline_highlights() derive_mode_hl('StatusModeCommand', 'PreProc') derive_mode_hl('StatusModeReplace', 'WarningMsg') derive_mode_hl('StatusModeTerminal', 'Special') - derive_hl('StatusGit', { base = 'CursorLine', fg = 'LineNr' }) - -- derive_hl('StatusLsp', { base = 'StatusLine', fg = 'DiagnosticInfo' }) - -- derive_hl('StatusLspSpinner', { base = 'StatusLine', fg = 'Constant' }) + derive_hl('StatusGit', { base = 'CursorLine', fg = 'Normal' }) derive_hl( 'StatusLspWorking', { base = 'StatusLine', fg = 'DiagnosticInfo' } @@ -45,7 +41,7 @@ local function setup_statusline_highlights() derive_hl('StatusDiagWarn', { base = 'StatusLine', fg = 'DiagnosticWarn' }) derive_hl('StatusDiagHint', { base = 'StatusLine', fg = 'DiagnosticHint' }) derive_hl('StatusCursor', { base = 'CursorLine', fg = 'Normal' }) - derive_hl('StatusGitAdded', { base = 'StatusLine', fg = 'MoreMsg' }) + derive_hl('StatusGitAdded', { base = 'StatusLine', fg = 'DiagnosticOk' }) derive_hl( 'StatusGitRemoved', { base = 'StatusLine', fg = 'DiagnosticError' } @@ -57,7 +53,6 @@ vim.api.nvim_create_autocmd('ColorScheme', { }) setup_statusline_highlights() ---- Mode text mapping. local mode_map = { n = ' NORM ', i = ' INS ', @@ -73,6 +68,7 @@ local mode_map = { t = ' TERM ', ['!'] = ' SHELL ', } + local mode_hl_map = { n = 'StatusModeNormal', i = 'StatusModeInsert', @@ -89,45 +85,50 @@ local mode_hl_map = { t = 'StatusModeTerminal', } ---- Git branch (async, cached per buffer, refreshed every 5s) local function refresh_status(buf) local b = vim.b[buf] local left, right = {}, {} if b.git_branch and b.git_branch ~= '' then - left[#left + 1] = '%#StatusGit# ' .. b.git_branch .. ' %*' + left[#left + 1] = '%#StatusGit# ' .. b.git_branch .. ' %*' end local diff = b.git_diff if diff then if diff.added > 0 then - left[#left + 1] = '%#StatusGitAdded# +' .. diff.added .. ' %*' + left[#left + 1] = '%#StatusGitAdded# +' .. diff.added .. '%*' end if diff.removed > 0 then - left[#left + 1] = '%#StatusGitRemoved# -' .. diff.removed .. ' %*' + left[#left + 1] = '%#StatusGitRemoved# -' .. diff.removed .. '%*' end end - if b.lsp_icon then - left[#left + 1] = '%#' .. b.lsp_hl .. '#' .. b.lsp_icon .. '%*' - end if b.recording then right[#right + 1] = '%#StatusRecording# ' .. b.recording .. ' %*' end if b.diag_str then right[#right + 1] = b.diag_str end + if b.lsp_icon and b.lsp_icon ~= '' then + right[#right + 1] = '%#' + .. b.lsp_hl + .. '#' + .. b.lsp_icon + .. (b.lsp_name or '') + .. ' %*' + end b.status_left = #left > 0 and table.concat(left) or '' b.status_right = #right > 0 and table.concat(right) or '' end ---- LSP: one icon, three states. local lsp_icon = { - none = '  ', + none = '', + starting = '', working = ' 󰄬 ', ready = ' 󰄭 ', } local lsp_hl = { none = 'StatusLspNone', + starting = 'StatusLspNone', working = 'StatusLspWorking', ready = 'StatusLspReady', } @@ -138,12 +139,18 @@ local function refresh_lsp(buf) local clients = vim.lsp.get_clients({ bufnr = buf }) if #clients == 0 then state = 'none' + vim.b[buf].lsp_name = '' else + local names = {} for _, client in ipairs(clients) do - if active_progress[client.id] then + names[#names + 1] = client.name + local prog = active_progress[client.id] + if prog == 'working' then state = 'working' - break + elseif prog == 'starting' and state ~= 'working' then + state = 'starting' end + vim.b[buf].lsp_name = table.concat(names, '/') end end vim.b[buf].lsp_icon = lsp_icon[state] @@ -153,15 +160,32 @@ end vim.api.nvim_create_autocmd({ 'LspAttach', 'LspDetach' }, { callback = function(ev) + if ev.event == 'LspAttach' then + local cid = ev.data.client_id + if not active_progress[cid] then + active_progress[cid] = 'starting' + vim.defer_fn(function() + if active_progress[cid] == 'starting' then + active_progress[cid] = nil + if vim.api.nvim_buf_is_valid(ev.buf) then + refresh_lsp(ev.buf) + end + end + end, 500) -- 500ms grace period to wait for LspProgress + end + elseif ev.event == 'LspDetach' then + active_progress[ev.data.client_id] = nil + end refresh_lsp(ev.buf) end, }) vim.api.nvim_create_autocmd('LspProgress', { callback = function(ev) - if ev.match == 'begin' or ev.match == 'report' then - active_progress[ev.data.client_id] = true - elseif ev.match == 'end' then + local kind = ev.data.params.value and ev.data.params.value.kind + if kind == 'begin' or kind == 'report' then + active_progress[ev.data.client_id] = 'working' + elseif kind == 'end' then active_progress[ev.data.client_id] = nil else return @@ -175,32 +199,41 @@ vim.api.nvim_create_autocmd('LspProgress', { end, }) ---- Git: resolved once per buffer, refreshed on save. +local BRANCH_ICON = ' ' + local function refresh_branch(buf) + local file = vim.api.nvim_buf_get_name(buf) + if file == '' or vim.bo[buf].buftype ~= '' then + vim.b[buf].git_branch = '' + return + end + local cwd = vim.fs.root(buf, '.git') or vim.fs.dirname(file) + vim.system( { 'git', 'branch', '--show-current' }, - { text = true }, + { text = true, cwd = cwd }, vim.schedule_wrap(function(out) if not vim.api.nvim_buf_is_valid(buf) then return end - vim.b[buf].git_branch = (out.code == 0 and out.stdout or ''):gsub( - '%s+', - '' - ) + local branch = (out.code == 0 and out.stdout or ''):gsub('%s+', '') + vim.b[buf].git_branch = branch ~= '' and (BRANCH_ICON .. branch) + or '' refresh_status(buf) end) ) end local function refresh_diff(buf) - local file = vim.fn.fnamemodify(vim.fn.bufname(buf), ':p') - if file == '' then + local file = vim.api.nvim_buf_get_name(buf) + if file == '' or vim.bo[buf].buftype ~= '' then + vim.b[buf].git_diff = nil return end + local cwd = vim.fs.root(buf, '.git') or vim.fs.dirname(file) vim.system( { 'git', 'diff', '--numstat', 'HEAD', '--', file }, - { text = true }, + { text = true, cwd = cwd }, vim.schedule_wrap(function(out) if not vim.api.nvim_buf_is_valid(buf) then return @@ -209,10 +242,14 @@ local function refresh_diff(buf) vim.b[buf].git_diff = nil else local added, removed = out.stdout:match('(%d+)%s+(%d+)') - vim.b[buf].git_diff = { - added = tonumber(added) or 0, - removed = tonumber(removed) or 0, - } + if added and removed then + vim.b[buf].git_diff = { + added = tonumber(added) or 0, + removed = tonumber(removed) or 0, + } + else + vim.b[buf].git_diff = nil + end end refresh_status(buf) end) @@ -266,11 +303,10 @@ vim.api.nvim_create_autocmd('BufWritePost', { end, }) ---- Macro: read once when recording starts, not on every redraw. vim.api.nvim_create_autocmd('RecordingEnter', { pattern = '*', callback = function(ev) - vim.b[ev.buf].recording = '● Rec @' .. vim.fn.reg_recording() + vim.b[ev.buf].recording = 'Rec @' .. vim.fn.reg_recording() refresh_status(ev.buf) end, }) @@ -293,7 +329,7 @@ function _G.__statusline() b.status_left or '', '%=', b.status_right or '', - '%#StatusCursor# %l:%-2c %*', + '%#StatusCursor# %l:%c ', '%#' .. hl .. '# %p%% %*', }) end