Added optimizationsto statusline

This commit is contained in:
Andrew Haynes
2026-05-10 03:12:18 -04:00
parent 9fefc102c9
commit 86d6e13813
+152 -91
View File
@@ -38,7 +38,6 @@ local function setup_statusline_highlights()
derive_hl('StatusDiagWarn', { base = 'StatusLine', fg = 'DiagnosticWarn' }) derive_hl('StatusDiagWarn', { base = 'StatusLine', fg = 'DiagnosticWarn' })
derive_hl('StatusDiagHint', { base = 'StatusLine', fg = 'DiagnosticHint' }) derive_hl('StatusDiagHint', { base = 'StatusLine', fg = 'DiagnosticHint' })
derive_hl('StatusCursor', { base = 'StatusLine', fg = 'Normal' }) derive_hl('StatusCursor', { base = 'StatusLine', fg = 'Normal' })
-- derive_mode_hl('StatusPercent', 'Constant')
end end
vim.api.nvim_create_autocmd('ColorScheme', { vim.api.nvim_create_autocmd('ColorScheme', {
callback = setup_statusline_highlights, callback = setup_statusline_highlights,
@@ -68,6 +67,9 @@ local mode_hl_map = {
--- Git branch (async, cached per buffer, refreshed every 5s) --- Git branch (async, cached per buffer, refreshed every 5s)
local function update_git_branch() local function update_git_branch()
if vim.bo.buftype ~= '' then
return
end
vim.system( vim.system(
{ 'git', 'branch', '--show-current' }, { 'git', 'branch', '--show-current' },
{ text = true }, { text = true },
@@ -90,6 +92,39 @@ vim.api.nvim_create_autocmd({ 'BufEnter', 'FocusGained' }, {
local progress = {} local progress = {}
local spinner_frames = 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', { vim.api.nvim_create_autocmd('LspProgress', {
callback = function(ev) callback = function(ev)
local d = ev.data local d = ev.data
@@ -107,6 +142,7 @@ vim.api.nvim_create_autocmd('LspProgress', {
msg = (value.message or 'working...'):gsub('%%', '%%%%'), msg = (value.message or 'working...'):gsub('%%', '%%%%'),
t = vim.loop.now(), t = vim.loop.now(),
} }
start_progress_timer()
elseif value.kind == 'report' then elseif value.kind == 'report' then
local msg_parts = {} local msg_parts = {}
if value.message then if value.message then
@@ -127,123 +163,147 @@ vim.api.nvim_create_autocmd('LspProgress', {
end end
end, end,
}) })
local frame = 0 -- local frame = 0
--- Clean stale progress messages periodically -- --- Clean stale progress messages periodically
vim.uv.new_timer():start( -- vim.uv.new_timer():start(
0, -- 0,
200, -- 200,
vim.schedule_wrap(function() -- vim.schedule_wrap(function()
local now = vim.loop.now() -- if next(progress) == nil then
for k, v in pairs(progress) do -- return progress_timer:stop()
local ttl = v.done and 2000 or 10000 -- -- end
if now - v.t > ttl then -- -- else -- no progress
progress[k] = nil -- -- progress_timer:stop()
end -- end
end -- local now = vim.loop.now()
if next(progress) then -- for k, v in pairs(progress) do
frame = (frame % #spinner_frames) + 1 -- local ttl = v.done and 2000 or 10000
end -- if now - v.t > ttl then
vim.cmd('redrawstatus') -- progress[k] = nil
end) -- end
) -- end
-- if next(progress) then
-- frame = (frame % #spinner_frames) + 1
-- end
-- vim.cmd('redrawstatus')
-- end)
-- )
--- Build the LSP section of the statusline --- 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 function lsp_section()
local bufnr = vim.api.nvim_get_current_buf() -- Only check progress for this buffer's clients
local clients = vim.lsp.get_clients({ bufnr = bufnr })
if #clients == 0 then
return ''
end
-- Show progress spinner if any active for visible clients
local client_ids = {} 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 client_ids[c.id] = true
end end
-- Filter progress by current buffer's clients
local latest = nil local latest = nil
for key, p in pairs(progress) do for key, p in pairs(progress) do
local cid = tonumber(key:match('^(%d+):')) 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 if not latest or p.t > latest.t then
latest = p latest = p
end end
end end
end end
if latest then if latest and (not latest.done or (vim.loop.now() - latest.t < 2000)) then
return '%#StatusLspSpinner# ○ ' .. latest.msg .. ' %*' return '%#StatusLspSpinner# ○ ' .. latest.msg .. ' %*'
end end
-- Fallback: most recent done entry (lasts 2s for smooth transition) -- Use the cached names from the autocmd
for key, p in pairs(progress) do return '%#StatusLsp#' .. (vim.b.lsp_names or '') .. '%*'
local cid = tonumber(key:match('^(%d+):')) end
if cid and client_ids[cid] and p.done then --- Diagnostics summary.
if not latest or p.t > latest.t then local diag_cache = {}
latest = p local function update_diag_cache(ev)
end local bufnr = ev.buf
end local counts = vim.diagnostic.count(bufnr)
local parts = {}
if counts[1] and counts[1] > 0 then
table.insert(parts, '%#StatusDiagError# E' .. counts[1] .. ' %*')
end end
if latest then if counts[2] and counts[2] > 0 then
return '%#StatusLspSpinner# ○ ' .. latest.msg .. ' %*' table.insert(parts, '%#StatusDiagWarn# W' .. counts[2] .. ' %*')
end end
-- Idle: show client names if counts[4] and counts[4] > 0 then
local names = {} table.insert(parts, '%#StatusDiagHint# H' .. counts[4] .. ' %*')
for _, c in ipairs(clients) do
table.insert(names, c.name)
end end
return '%#StatusLsp# ● ' .. table.concat(names, ', ') .. ' %*' diag_cache[bufnr] = table.concat(parts)
end end
--- Diagnostics summary. vim.api.nvim_create_autocmd(
local function diag_section() 'DiagnosticChanged',
local diag = vim.diagnostic.get(vim.api.nvim_get_current_buf()) { callback = update_diag_cache }
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
--- Main statusline renderer. --- Main statusline renderer.
function _G.__statusline() function _G.__statusline()
local m = vim.fn.mode() local m = vim.fn.mode()
local mode_hl = mode_hl_map[m] or 'StatusModeNormal' 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 '' local git = vim.b.git_branch or ''
if git ~= '' then local cur_buf = vim.api.nvim_get_current_buf()
parts[#parts + 1] = '%#StatusGit#  ' .. git .. ' %*'
end local parts = {
-- LSP '%#' .. mode_hl .. '#' .. (mode_map[m] or ' ?? ') .. '%*',
parts[#parts + 1] = lsp_section() git ~= '' and ('%#StatusGit#  ' .. git .. ' %*') or '',
-- Right align lsp_section(),
parts[#parts + 1] = '%=' '%=',
-- Diagnostics -- diag_cache[cur_buf] or '', -- Per-buffer cache lookup
parts[#parts + 1] = diag_section() diag_cache[cur_buf] or (function()
-- Cursor position local parts = {}
parts[#parts + 1] = '%#StatusCursor# %l:%-2c %*' local counts = vim.diagnostic.count(cur_buf)
-- Percentage if counts[1] and counts[1] > 0 then
parts[#parts + 1] = '%#' .. mode_hl .. '# %p%% %*' 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) return table.concat(parts)
end end
vim.o.statusline = '%!v:lua.__statusline()' vim.o.statusline = '%!v:lua.__statusline()'
local helpers = require('incline.helpers')
local devicons = require('nvim-web-devicons')
require('incline').setup({ require('incline').setup({
window = { window = {
padding = 0, padding = 0,
@@ -255,7 +315,8 @@ require('incline').setup({
if filename == '' then if filename == '' then
filename = '[No Name]' filename = '[No Name]'
end 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 local modified = vim.bo[props.buf].modified
return { return {
ft_icon and { ft_icon and {
@@ -263,7 +324,7 @@ require('incline').setup({
ft_icon, ft_icon,
' ', ' ',
guibg = ft_color, guibg = ft_color,
guifg = helpers.contrast_color(ft_color), guifg = require('incline.helpers').contrast_color(ft_color),
} or '', } or '',
' ', ' ',
{ filename, gui = modified and 'bold,italic' or 'bold' }, { filename, gui = modified and 'bold,italic' or 'bold' },