diff --git a/nvim/.config/nvim/lua/DarthMooMancer/statusline.lua b/nvim/.config/nvim/lua/DarthMooMancer/statusline.lua index 3808f5a..a38d129 100644 --- a/nvim/.config/nvim/lua/DarthMooMancer/statusline.lua +++ b/nvim/.config/nvim/lua/DarthMooMancer/statusline.lua @@ -1,203 +1,186 @@ -local has_devicons, devicons = pcall(require, 'nvim-web-devicons') -local uv, api, b = vim.uv or vim.loop, vim.api, vim.b -local SEV = vim.diagnostic.severity - -local function setup_highlights() - local bg = api.nvim_get_hl(0, { name = 'StatusLine' }).bg or 'none' - - local function set(name, link, bold) - local hl = api.nvim_get_hl(0, { name = link, link = false }) - api.nvim_set_hl(0, name, { fg = hl.fg, bg = bg, bold = bold or false }) - end - - set('StatusLineFilename', 'Normal', true) - set('StatusLineMod', 'WarningMsg', true) - set('StatusLineRO', 'ErrorMsg', true) - set('StatusDiagError', 'DiagnosticError', true) - set('StatusDiagWarn', 'DiagnosticWarn', false) - set('StatusDiagHint', 'DiagnosticHint', false) - set('StatusLspSpinner', 'DiagnosticWarn', true) - set('StatusLspLoading', 'DiagnosticInfo', false) - set('StatusLspReady', 'Comment', false) +local ok, D = pcall(require, 'nvim-web-devicons') +local a, u, S = vim.api, vim.uv or vim.loop, vim.diagnostic.severity +local C = a.nvim_get_current_buf +local R = function() + vim.cmd.redrawstatus() end - -api.nvim_create_autocmd({ 'ColorScheme', 'FocusGained', 'VimEnter' }, { - callback = function() - setup_highlights() - vim.cmd('redrawstatus') - end, -}) -setup_highlights() - -local function update_file_info(buf) - local path = api.nvim_buf_get_name(buf) - if path == '' then - b[buf].stl_file_info = ' %#StatusLineFilename#[No Name]%*' - return +local M = '%#StatusLineMod#%m%*%#StatusLineRO#%r%* %=' +local FR = { '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' } +local N, SPIN, LOAD = #FR, '%#StatusLspSpinner#', '%* %#StatusLspLoading#' +local c, T, JOB, TMR, IDX = {}, {}, nil, nil, 1 +local function HI() + local bg = a.nvim_get_hl(0, { name = 'StatusLine' }).bg or 'none' + for _, t in ipairs({ + { 'StatusLineFilename', 'Normal', true }, + { 'StatusLineMod', 'WarningMsg', true }, + { 'StatusLineRO', 'ErrorMsg', true }, + { 'StatusDiagError', 'DiagnosticError', true }, + { 'StatusDiagWarn', 'DiagnosticWarn', false }, + { 'StatusDiagHint', 'DiagnosticHint', false }, + { 'StatusLspSpinner', 'DiagnosticWarn', true }, + { 'StatusLspLoading', 'DiagnosticInfo', false }, + { 'StatusLspReady', 'Comment', false }, + }) do + local h = a.nvim_get_hl(0, { name = t[2], link = false }) + a.nvim_set_hl(0, t[1], { fg = h.fg, bg = bg, bold = t[3] }) end - - local fname = path:match('([^/\\]+)$') or path - local icon = '' - if has_devicons then - local ic, hl = devicons.get_icon( - fname, - path:match('%.([^./\\]+)$'), - { default = true } - ) - if ic then - icon = '%#' .. hl .. '#' .. ic .. ' %*' +end +local function snap(bb) + local p = a.nvim_buf_get_name(bb) + local nm = ' %#StatusLineFilename#' + if p == '' then + nm = nm .. '[No Name]%*' + else + local f = p:match('([^/\\]+)$') or p + if ok then + local i, hl = D.get_icon(f, p:match('%.([^./\\]+)$'), { default = true }) + if i then + nm = nm .. '%#' .. hl .. '#' .. i .. ' %*' + end end + nm = nm .. f .. '%*' end - b[buf].stl_file_info = ' ' - .. icon - .. '%#StatusLineFilename#' - .. fname - .. '%*' + local x = vim.diagnostic.count(bb) + local e, w, h = x[S.ERROR] or 0, x[S.WARN] or 0, x[S.HINT] or 0 + local dg = '' + if e + w + h > 0 then + dg = (e > 0 and ('%#StatusDiagError#E' .. e .. '%* ') or '') + .. (w > 0 and ('%#StatusDiagWarn#W' .. w .. '%* ') or '') + .. (h > 0 and ('%#StatusDiagHint#H' .. h .. '%* ') or '') + end + local rd, cs = '', vim.lsp.get_clients({ bufnr = bb }) + if #cs > 0 then + local nm2 = {} + for i = 1, #cs do + nm2[i] = cs[i].name + end + rd = '%#StatusLspReady#󰄭 ' .. table.concat(nm2, '/') .. '%* ' + end + return nm .. M .. dg, rd end - -local function update_lsp_clients(buf) - local clients = vim.lsp.get_clients({ bufnr = buf }) - if #clients == 0 then - b[buf].stl_lsp_ready = '' - return +local function touch(bb, redraw) + local v = c[bb] + if v then + v.d = true end - - local names = {} - for i = 1, #clients do - names[i] = clients[i].name + if redraw then + R() end - b[buf].stl_lsp_ready = '%#StatusLspReady#󰄭 ' - .. table.concat(names, '/') - .. '%* ' end - -local active_tokens = {} -local spinner_frames = - { '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' } -local current_job, spinner_timer = nil, nil - -local function sync_spinner() - current_job = nil - for _, tokens in pairs(active_tokens) do - for _, msg in pairs(tokens) do - current_job = msg +local function SYNC() + JOB = nil + for _, t in pairs(T) do + for _, m in pairs(t) do + JOB = m break end - if current_job then + if JOB then break end end - - if current_job and not spinner_timer then - spinner_timer = uv.new_timer() - spinner_timer:start( + if JOB and not TMR then + IDX = math.floor(u.now() / 100) % N + 1 + TMR = u.new_timer() + TMR:start( 0, 100, vim.schedule_wrap(function() - if current_job then - vim.cmd('redrawstatus') - elseif spinner_timer then - spinner_timer:stop() - spinner_timer:close() - spinner_timer = nil + if JOB then + IDX = IDX % N + 1 + R() + elseif TMR then + TMR:stop() + TMR:close() + TMR = nil end end) ) - elseif not current_job and spinner_timer then - spinner_timer:stop() - spinner_timer:close() - spinner_timer = nil - vim.cmd('redrawstatus') + elseif not JOB and TMR then + TMR:stop() + TMR:close() + TMR = nil + R() end end - -local group = api.nvim_create_augroup('MinimalStatusline', { clear = true }) - -api.nvim_create_autocmd({ 'BufEnter', 'BufFilePost' }, { - group = group, - callback = function(ev) - update_file_info(ev.buf) - update_lsp_clients(ev.buf) - end, -}) - -api.nvim_create_autocmd('DiagnosticChanged', { - group = group, - callback = function(ev) - if ev.buf == api.nvim_get_current_buf() then - vim.cmd('redrawstatus') - end - end, -}) - -api.nvim_create_autocmd({ 'LspAttach', 'LspDetach' }, { - group = group, - callback = function(ev) - if ev.event == 'LspDetach' then - active_tokens[ev.data.client_id] = nil - sync_spinner() - end - update_lsp_clients(ev.buf) - vim.cmd('redrawstatus') - end, -}) - -api.nvim_create_autocmd('LspProgress', { - group = group, - callback = function(ev) - local val = ev.data.params.value - if type(val) ~= 'table' then - return - end - - local client_id = ev.data.client_id - local token = ev.data.params.token or 'default' - active_tokens[client_id] = active_tokens[client_id] or {} - - if - val.kind == 'end' - or (val.kind == 'report' and val.percentage == 100) - then - active_tokens[client_id][token] = nil - else - local msg = (val.title and val.title ~= '' and val.title) - or val.message - or 'Loading...' - if val.title and val.message and val.message ~= '' then - msg = val.title .. ' ' .. val.message +local G = a.nvim_create_augroup('STL5', { clear = true }) +for _, s in ipairs({ + { + { 'BufEnter', 'BufFilePost' }, + function(e) + touch(e.buf, true) + end, + }, + { + 'DiagnosticChanged', + function(e) + touch(e.buf, e.buf == C()) + end, + }, + { + { 'LspAttach', 'LspDetach' }, + function(e) + if e.event == 'LspDetach' then + T[e.data.client_id] = nil + SYNC() end - active_tokens[client_id][token] = msg - end - - sync_spinner() - end, -}) - -function MinimalStatusline() - local cur_buf = api.nvim_get_current_buf() - local vars = b[cur_buf] - - local c = vim.diagnostic.count(cur_buf) - local e, w, h = c[SEV.ERROR] or 0, c[SEV.WARN] or 0, c[SEV.HINT] or 0 - local diags = '' - if e > 0 or w > 0 or h > 0 then - diags = (e > 0 and ('%#StatusDiagError#E' .. e .. '%* ') or '') - .. (w > 0 and ('%#StatusDiagWarn#W' .. w .. '%* ') or '') - .. (h > 0 and ('%#StatusDiagHint#H' .. h .. '%*') or '') - end - - local right = current_job - and ('%#StatusLspSpinner#' .. spinner_frames[(math.floor( - uv.now() / 100 - ) % 10) + 1] .. '%* %#StatusLspLoading#' .. current_job .. '%* ') - or (vars.stl_lsp_ready or '') - - return (vars.stl_file_info or '') - .. '%#StatusLineMod#%m%*%#StatusLineRO#%r%* %=' - .. diags - .. '%=' - .. right + touch(e.buf, true) + end, + }, + { + 'LspProgress', + function(e) + local v = e.data.params.value + if type(v) ~= 'table' then + return + end + local id, tk = e.data.client_id, e.data.params.token or 'default' + T[id] = T[id] or {} + if v.kind == 'end' or (v.kind == 'report' and v.percentage == 100) then + T[id][tk] = nil + else + local m = (v.title and v.title ~= '' and v.title) or v.message or 'Loading...' + if v.title and v.message and v.message ~= '' then + m = v.title .. ' ' .. v.message + end + T[id][tk] = m + end + SYNC() + end, + }, + { + 'BufUnload', + function(e) + c[e.buf] = nil + end, + }, + { + 'ColorScheme', + function() + HI() + R() + end, + }, + { 'FocusGained', R }, +}) do + a.nvim_create_autocmd(s[1], { group = G, callback = s[2] }) end - -vim.opt.laststatus = 3 -vim.opt.statusline = '%!v:lua.MinimalStatusline()' +HI() +local function Status() + local bb = C() + local v = c[bb] + if not v or v.d then + if not v then + v = {} + c[bb] = v + end + v.h, v.r = snap(bb) + v.stl = v.h .. v.r + v.d = nil + end + if JOB then + return v.h .. SPIN .. FR[IDX] .. LOAD .. JOB .. '%* ' + end + return v.stl +end +_G.Status = Status +vim.opt.statusline = '%!v:lua.Status()' diff --git a/nvim/.config/nvim/stylua.toml b/nvim/.config/nvim/stylua.toml index c6015eb..4178ea5 100644 --- a/nvim/.config/nvim/stylua.toml +++ b/nvim/.config/nvim/stylua.toml @@ -1,5 +1,5 @@ -column_width = 80 +column_width = 120 line_endings = "Unix" indent_type = "Tabs" -indent_width = 4 +indent_width = 2 quote_style = "AutoPreferSingle"