CHORE: Cleaned up the status bar and finished it
This commit is contained in:
@@ -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,7 +85,6 @@ 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 = {}, {}
|
||||
@@ -106,28 +101,34 @@ local function refresh_status(buf)
|
||||
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+)')
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user