From 86d6e13813b43880c5adc1243149f6967c0b177b Mon Sep 17 00:00:00 2001 From: Andrew Haynes Date: Sun, 10 May 2026 03:12:18 -0400 Subject: [PATCH] Added optimizationsto statusline --- nvim/.config/nvim/lua/DarthMooMancer/ui.lua | 243 ++++++++++++-------- 1 file changed, 152 insertions(+), 91 deletions(-) diff --git a/nvim/.config/nvim/lua/DarthMooMancer/ui.lua b/nvim/.config/nvim/lua/DarthMooMancer/ui.lua index 4d1718b..19725b6 100644 --- a/nvim/.config/nvim/lua/DarthMooMancer/ui.lua +++ b/nvim/.config/nvim/lua/DarthMooMancer/ui.lua @@ -38,7 +38,6 @@ local function setup_statusline_highlights() derive_hl('StatusDiagWarn', { base = 'StatusLine', fg = 'DiagnosticWarn' }) derive_hl('StatusDiagHint', { base = 'StatusLine', fg = 'DiagnosticHint' }) derive_hl('StatusCursor', { base = 'StatusLine', fg = 'Normal' }) - -- derive_mode_hl('StatusPercent', 'Constant') end vim.api.nvim_create_autocmd('ColorScheme', { callback = setup_statusline_highlights, @@ -68,6 +67,9 @@ local mode_hl_map = { --- Git branch (async, cached per buffer, refreshed every 5s) local function update_git_branch() + if vim.bo.buftype ~= '' then + return + end vim.system( { 'git', 'branch', '--show-current' }, { text = true }, @@ -90,6 +92,39 @@ vim.api.nvim_create_autocmd({ 'BufEnter', 'FocusGained' }, { local progress = {} local spinner_frames = { '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' } + +local frame = 0 +--- Clean stale progress messages periodically +local progress_timer = vim.uv.new_timer() +local function start_progress_timer() + if not progress_timer:is_active() then + progress_timer:start(0, 200, function() + local now = vim.loop.now() + for k, v in pairs(progress) do + local ttl = v.done and 2000 or 10000 + if now - v.t > ttl then + progress[k] = nil + end + end + if next(progress) then + frame = (frame % #spinner_frames) + 1 + -- vim.cmd('redrawstatus') + vim.schedule(function() + vim.cmd('redrawstatus') + end) + -- else + else + progress_timer:stop() + vim.schedule(function() + vim.cmd('redrawstatus') + end) + end + -- progress_timer:stop() + -- end + end) + end +end + vim.api.nvim_create_autocmd('LspProgress', { callback = function(ev) local d = ev.data @@ -107,6 +142,7 @@ vim.api.nvim_create_autocmd('LspProgress', { msg = (value.message or 'working...'):gsub('%%', '%%%%'), t = vim.loop.now(), } + start_progress_timer() elseif value.kind == 'report' then local msg_parts = {} if value.message then @@ -127,123 +163,147 @@ vim.api.nvim_create_autocmd('LspProgress', { end end, }) -local frame = 0 ---- Clean stale progress messages periodically -vim.uv.new_timer():start( - 0, - 200, - vim.schedule_wrap(function() - local now = vim.loop.now() - for k, v in pairs(progress) do - local ttl = v.done and 2000 or 10000 - if now - v.t > ttl then - progress[k] = nil - end - end - if next(progress) then - frame = (frame % #spinner_frames) + 1 - end - vim.cmd('redrawstatus') - end) -) +-- local frame = 0 +-- --- Clean stale progress messages periodically +-- vim.uv.new_timer():start( +-- 0, +-- 200, +-- vim.schedule_wrap(function() +-- if next(progress) == nil then +-- return progress_timer:stop() +-- -- end +-- -- else -- no progress +-- -- progress_timer:stop() +-- end +-- local now = vim.loop.now() +-- for k, v in pairs(progress) do +-- local ttl = v.done and 2000 or 10000 +-- if now - v.t > ttl then +-- progress[k] = nil +-- end +-- end +-- if next(progress) then +-- frame = (frame % #spinner_frames) + 1 +-- end +-- vim.cmd('redrawstatus') +-- end) +-- ) --- Build the LSP section of the statusline +vim.api.nvim_create_autocmd({ 'LspAttach', 'LspDetach' }, { + callback = function(args) + -- vim.schedule(function() + local names = {} + for _, c in ipairs(vim.lsp.get_clients({ bufnr = args.buf })) do + table.insert(names, c.name) + end + vim.b[args.buf].lsp_names = #names > 0 + and (' ● ' .. table.concat(names, ', ') .. ' ') + or '' + -- end) + end, +}) + +-- local function lsp_section() +-- -- Only check for progress (dynamic) +-- local latest = nil +-- for _, p in pairs(progress) do +-- -- Simplified check: show latest active or recently done +-- if not latest or p.t > latest.t then +-- latest = p +-- end +-- end +-- +-- if latest and (not latest.done or (vim.loop.now() - latest.t < 2000)) then +-- return '%#StatusLspSpinner# ○ ' .. latest.msg .. ' %*' +-- end +-- +-- -- Use the cached names from the autocmd +-- return '%#StatusLsp#' .. (vim.b.lsp_names or '') .. '%*' +-- end local function lsp_section() - local bufnr = vim.api.nvim_get_current_buf() - local clients = vim.lsp.get_clients({ bufnr = bufnr }) - if #clients == 0 then - return '' - end - -- Show progress spinner if any active for visible clients + -- Only check progress for this buffer's clients local client_ids = {} - for _, c in ipairs(clients) do + for _, c in + ipairs(vim.lsp.get_clients({ bufnr = vim.api.nvim_get_current_buf() })) + do client_ids[c.id] = true end + -- Filter progress by current buffer's clients local latest = nil for key, p in pairs(progress) do local cid = tonumber(key:match('^(%d+):')) - if cid and client_ids[cid] and not p.done then + if cid and client_ids[cid] then if not latest or p.t > latest.t then latest = p end end end - if latest then + if latest and (not latest.done or (vim.loop.now() - latest.t < 2000)) then return '%#StatusLspSpinner# ○ ' .. latest.msg .. ' %*' end - -- Fallback: most recent done entry (lasts 2s for smooth transition) - for key, p in pairs(progress) do - local cid = tonumber(key:match('^(%d+):')) - if cid and client_ids[cid] and p.done then - if not latest or p.t > latest.t then - latest = p - end - end + -- Use the cached names from the autocmd + return '%#StatusLsp#' .. (vim.b.lsp_names or '') .. '%*' +end +--- Diagnostics summary. +local diag_cache = {} +local function update_diag_cache(ev) + local bufnr = ev.buf + local counts = vim.diagnostic.count(bufnr) + local parts = {} + if counts[1] and counts[1] > 0 then + table.insert(parts, '%#StatusDiagError# E' .. counts[1] .. ' %*') end - if latest then - return '%#StatusLspSpinner# ○ ' .. latest.msg .. ' %*' + if counts[2] and counts[2] > 0 then + table.insert(parts, '%#StatusDiagWarn# W' .. counts[2] .. ' %*') end - -- Idle: show client names - local names = {} - for _, c in ipairs(clients) do - table.insert(names, c.name) + if counts[4] and counts[4] > 0 then + table.insert(parts, '%#StatusDiagHint# H' .. counts[4] .. ' %*') end - return '%#StatusLsp# ● ' .. table.concat(names, ', ') .. ' %*' + diag_cache[bufnr] = table.concat(parts) end ---- Diagnostics summary. -local function diag_section() - local diag = vim.diagnostic.get(vim.api.nvim_get_current_buf()) - local parts = {} - local counts = { errors = 0, warnings = 0, hints = 0 } - for _, d in ipairs(diag) do - if d.severity == vim.diagnostic.severity.ERROR then - counts.errors = counts.errors + 1 - elseif d.severity == vim.diagnostic.severity.WARN then - counts.warnings = counts.warnings + 1 - elseif d.severity == vim.diagnostic.severity.HINT then - counts.hints = counts.hints + 1 - end - end - if counts.errors > 0 then - table.insert(parts, '%#StatusDiagError# E' .. counts.errors .. ' %*') - end - if counts.warnings > 0 then - table.insert(parts, '%#StatusDiagWarn# W' .. counts.warnings .. ' %*') - end - if counts.hints > 0 then - table.insert(parts, '%#StatusDiagHint# H' .. counts.hints .. ' %*') - end - return table.concat(parts) -end +vim.api.nvim_create_autocmd( + 'DiagnosticChanged', + { callback = update_diag_cache } +) + --- Main statusline renderer. function _G.__statusline() local m = vim.fn.mode() local mode_hl = mode_hl_map[m] or 'StatusModeNormal' - local mode_txt = mode_map[m] or ' ?? ' - local parts = {} - -- Mode - parts[#parts + 1] = '%#' .. mode_hl .. '#' .. mode_txt .. '%*' - -- Git local git = vim.b.git_branch or '' - if git ~= '' then - parts[#parts + 1] = '%#StatusGit#  ' .. git .. ' %*' - end - -- LSP - parts[#parts + 1] = lsp_section() - -- Right align - parts[#parts + 1] = '%=' - -- Diagnostics - parts[#parts + 1] = diag_section() - -- Cursor position - parts[#parts + 1] = '%#StatusCursor# %l:%-2c %*' - -- Percentage - parts[#parts + 1] = '%#' .. mode_hl .. '# %p%% %*' + local cur_buf = vim.api.nvim_get_current_buf() + + local parts = { + '%#' .. mode_hl .. '#' .. (mode_map[m] or ' ?? ') .. '%*', + git ~= '' and ('%#StatusGit#  ' .. git .. ' %*') or '', + lsp_section(), + '%=', + -- diag_cache[cur_buf] or '', -- Per-buffer cache lookup + diag_cache[cur_buf] or (function() + local parts = {} + local counts = vim.diagnostic.count(cur_buf) + if counts[1] and counts[1] > 0 then + table.insert( + parts, + '%#StatusDiagError# E' .. counts[1] .. ' %*' + ) + end + if counts[2] and counts[2] > 0 then + table.insert(parts, '%#StatusDiagWarn# W' .. counts[2] .. ' %*') + end + if counts[4] and counts[4] > 0 then + table.insert(parts, '%#StatusDiagHint# H' .. counts[4] .. ' %*') + end + return table.concat(parts) + end)(), + '%#StatusCursor# %l:%-2c %*', + '%#' .. mode_hl .. '# %p%% %*', + } return table.concat(parts) end vim.o.statusline = '%!v:lua.__statusline()' -local helpers = require('incline.helpers') -local devicons = require('nvim-web-devicons') require('incline').setup({ window = { padding = 0, @@ -255,7 +315,8 @@ require('incline').setup({ if filename == '' then filename = '[No Name]' end - local ft_icon, ft_color = devicons.get_icon_color(filename) + local ft_icon, ft_color = + require('nvim-web-devicons').get_icon_color(filename) local modified = vim.bo[props.buf].modified return { ft_icon and { @@ -263,7 +324,7 @@ require('incline').setup({ ft_icon, ' ', guibg = ft_color, - guifg = helpers.contrast_color(ft_color), + guifg = require('incline.helpers').contrast_color(ft_color), } or '', ' ', { filename, gui = modified and 'bold,italic' or 'bold' },