nvim/plugin/statusline.lua
Kenneth Benzie (Benie) 14709a12a7 Remove unicode from statusline
Some terminals use more characters than others for to display certain
unicode code points, this resulted the statusline to "leak" past the end
of the line causing characters at the next line to be highlighted
incorrectly.
2025-03-05 10:48:56 +00:00

186 lines
7.2 KiB
Lua

local statusline = {}
local theme = {
light_green = { fg = '#262626', bg = '#59946f' },
light_blue = { fg = '#262626', bg = '#5c91bf' },
light_orange = { fg = '#262626', bg = '#b6927b' },
light_red = { fg = '#262626', bg = '#e46876' },
light_grey = { fg = '#262626', bg = '#808080' },
light_violet = { fg = '#262626', bg = '#957fb8' },
dark_white = { fg = '#ffffff', bg = '#121212' },
dark_yellow = { fg = '#c4b28a', bg = '#121212' },
dark_grey = { fg = '#808080', bg = '#121212' },
}
local modes = {}
modes[110] = { name = 'Normal', color = 'light_green' }
modes[105] = { name = 'Insert', color = 'light_blue' }
modes[99] = { name = 'Command', color = 'light_green' }
modes[118] = { name = 'Visual', color = 'light_violet' }
modes[86] = { name = 'V-Line', color = 'light_violet' }
modes[22] = { name = 'V-Block', color = 'light_violet' }
modes[82] = { name = 'Replace', color = 'light_red' }
modes[115] = { name = 'Select', color = 'light_orange' }
modes[83] = { name = 'S-Line', color = 'light_orange' }
modes[19] = { name = 'S-Block', color = 'light_orange' }
modes[116] = { name = 'Terminal', color = 'light_blue' }
modes[33] = { name = 'Shell', color = 'light_grey' }
local function highlight(group, color, attrs)
local args = { group, 'guifg=' .. color.fg, 'guibg=' .. color.bg }
if attrs then
table.insert(args, 'gui=' .. attrs)
end
vim.cmd.highlight(args)
end
-- StatusLineLight is shows the mode and cursor information, it is dynamically
-- changed by statusline#mode(), give it a default.
highlight('StatusLineLight', theme.light_grey)
-- StatusLineDusk is shows additional information which is not always present,
-- give it a muted color.
highlight('StatusLineDusk', theme.light_grey, 'bold')
-- StatusLineDark shows the filename and filetype and takes up most of the
-- statusline, give it a dark background.
highlight('StatusLineDark', theme.dark_white)
-- StatusLineChange shows changes in the file by changing the colour of the
-- filename, give if a dark background.
highlight('StatusLineChange', theme.dark_yellow)
-- StatusLineFade shows the status of completion engines but using colors which
-- fade into the background to avoid grabbing attention.
highlight('StatusLineDuskFade', theme.dark_grey)
-- Get statusline mode and update StatusLineLight.
local function get_mode()
-- Map modes to a human readable name and a color.
local current_mode = modes[vim.fn.char2nr(vim.fn.mode())]
-- Update the StatusLineLight color.
highlight('StatusLineLight', theme[current_mode.color], 'bold')
return current_mode.name
end
-- Display cusor line/total and column
local position = '# %l/%L:%2c '
-- Construct a statusline for special buffer types.
local function special(group, name, title)
-- Display current mode with dynamic highlights.
local line = '%#' .. group .. '# ' .. name .. ' '
-- Display filename with dark highlights.
line = line .. '%#StatusLineDark# ' .. title
-- Display current/total lines and column with dynamic highlights.
line = line .. '%=' .. '%#' .. group .. position
-- Combine the elements into a single string to be evaluated.
return line
end
-- Construct a statusline for generic buffer types.
local function generic(group, name)
-- Display current mode with dynamic highlights.
local line = '%#' .. group .. '# ' .. name .. ' '
-- Display spell or paste if set with dusk highlights in a group to swallow
-- the spaces when empty.
line = line .. '%#StatusLineDusk#%( ' .. '%{&spell ? "Spell " : ""}' ..
'%{&paste ? "Paste " : ""}' .. '%)'
-- Display filename with dark or changed highlights.
if vim.o.modified then
line = line .. '%#StatusLineChange#'
else
line = line .. '%#StatusLineDark#'
end
line = line .. ' %<%f'
-- Display readonly and nomodifiable if set.
line = line
.. '%#StatusLineDark#'
.. '%{&readonly ? " 🔒" : ""}'
.. '%{&modifiable ? "" : " ⛔"}'
-- Display filetype if set.
line = line .. '%=' .. '%#StatusLineDark# %{&filetype} '
-- Display fileencoding if not utf-8 and fileformat if not unix with dusk
-- highlights in a group to swallow spaces when empty.
line = line .. '%#StatusLineDusk#%( ' ..
'%{&fileencoding ==# "utf-8" ? "" : &fileencoding}' ..
'%{&fileformat ==# "unix" ? "" : "[".&fileformat."]"}' .. ' %)'
-- Display current/total lines and column with dynamic highlights.
line = line .. '%#' .. group .. position
-- Combine the elements into a single string to be evaluated.
return line
end
-- Define active statusline, this statusline is dynamic with StatusLineLight
-- being updated based on the current mode and only used for current buffer.
function _G.statusline_active()
local mode = get_mode()
if vim.o.buftype == 'help' then
if mode == 'Normal' then mode = 'Help' end
return special('StatusLineDusk', 'Help', '%F')
elseif vim.o.buftype == 'quickfix' then
-- Quickfix list and location list have the same buftype, the window has a
-- loclist flag, query the window info.
local info = vim.fn.getwininfo(vim.fn.win_getid())[1]
if mode == 'Normal' then
if info.loclist == 1 then
mode = 'Location'
else
mode = 'Quickfix'
end
end
local title = info.variables.quickfix_title
return special('StatusLineLight', mode, title)
elseif vim.o.buftype == 'terminal' then
return special('StatusLineLight', 'Terminal', '%f')
elseif vim.o.previewwindow then
if mode == 'Normal' then mode = 'Preview' end
return generic('StatusLineLight', mode)
elseif vim.o.filetype == 'man' then
return special('StatusLineDusk', 'Manual', '%f')
end
return generic('StatusLineLight', mode)
end
function _G.statusline_inactive()
local mode = modes[vim.fn.char2nr(vim.fn.mode())].name
local line = ''
if vim.o.buftype == 'help' then
line = special('StatusLineDusk', 'Help', '%F')
elseif vim.o.buftype == 'quickfix' then
-- Quickfix list and location list have the same buftype, the window has a
-- loclist flag, query the window info.
local info = vim.fn.getwininfo(vim.fn.win_getid())[1]
if info['loclist'] then mode = 'Location' else mode = 'Quickfix' end
line = special('StatusLineDusk', mode, info.variables.quickfix_title)
elseif vim.o.buftype == 'terminal' then
line = special('StatusLineDusk', 'Terminal', '%f')
elseif vim.o.previewwindow then
line = generic('StatusLineDusk', 'Preview')
elseif vim.o.filetype == 'man' then
line = special('StatusLineDusk', 'Manual', '%f')
else
line = generic('StatusLineDusk', 'Idle')
end
return line
end
-- Setup autocmds to set the statusline per buffer.
local group = vim.api.nvim_create_augroup('statusline', { clear = true })
-- Dynamically update the current buffer mode and color changes using %! to
-- call a function which is always evaluated on statusline update.
vim.api.nvim_create_autocmd({ 'BufEnter', 'WinEnter', 'BufWinEnter' }, {
pattern = '*',
group = group,
callback = function()
vim.cmd.setlocal("statusline=%{%v:lua.statusline_active()%}")
end
})
-- Statically set the statusline when leaving the buffer.
vim.api.nvim_create_autocmd({ 'BufLeave', 'WinLeave' }, {
pattern = '*',
group = group,
callback = function()
vim.cmd.setlocal("statusline=%{%v:lua.statusline_inactive()%}")
end
})
return statusline