From 3353b099bef8bc5c3880a76eceda4a3e426af927 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Sun, 10 Mar 2024 23:45:38 +0000 Subject: [PATCH] Port custom statusline from vimscript & change colors --- init.lua | 1 + lua/plugins/statusline.lua | 20 ---- lua/statusline.lua | 185 +++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 20 deletions(-) delete mode 100644 lua/plugins/statusline.lua create mode 100644 lua/statusline.lua diff --git a/init.lua b/init.lua index 8bf6da7..ee9f916 100644 --- a/init.lua +++ b/init.lua @@ -3,6 +3,7 @@ require('mappings') require('netrw') require('autocmds') require('build') +require('statusline') local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then diff --git a/lua/plugins/statusline.lua b/lua/plugins/statusline.lua deleted file mode 100644 index dc1e682..0000000 --- a/lua/plugins/statusline.lua +++ /dev/null @@ -1,20 +0,0 @@ -return { - 'ojroques/nvim-hardline', - config = function() - require('hardline').setup({ - sections = { - { class = 'mode', item = require('hardline.parts.mode').get_item }, - -- { class = 'high', item = require('hardline.parts.git').get_item, hide = 100 }, - { class = 'med', item = require('hardline.parts.filename').get_item }, - '%<', - { class = 'med', item = '%=' }, - { class = 'low', item = require('hardline.parts.wordcount').get_item, hide = 100 }, - { class = 'error', item = require('hardline.parts.lsp').get_error }, - { class = 'warning', item = require('hardline.parts.lsp').get_warning }, - { class = 'warning', item = require('hardline.parts.whitespace').get_item }, - { class = 'high', item = require('hardline.parts.filetype').get_item, hide = 60 }, - { class = 'mode', item = require('hardline.parts.line').get_item }, - } - }) - end -} diff --git a/lua/statusline.lua b/lua/statusline.lua new file mode 100644 index 0000000..8001e06 --- /dev/null +++ b/lua/statusline.lua @@ -0,0 +1,185 @@ +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 command = 'highlight ' .. group .. + ' guifg=' .. color.fg .. ' guibg=' .. color.bg + if attrs then + command = command .. ' gui=' .. attrs + end + vim.cmd(command) +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 + +-- 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 .. '# ☰%l/%L ·%2c ' + -- 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, show_lsp) + -- 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 ? "" : " ⛔"}' + -- FIXME: if show_lsp and vim.fn.exists('*coc#status') then + -- -- Display LSP status. + -- line = line .. '%#StatusLineDuskFade#%( %{coc#status()}%)' + -- end + -- 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 .. '# ☰ %l/%L 󰠷 %2c ' + -- 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 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 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, false) + elseif vim.o.filetype == 'man' then + return special('StatusLineDusk', 'Manual', '%f') + end + return generic('StatusLineLight', mode, true) +end + +function 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', false) + elseif vim.o.filetype == 'man' then + line = special('StatusLineDusk', 'Manual', '%f') + else + line = generic('StatusLineDusk', 'Idle', false) + end + -- Escape spaces and double quotes for use in setlocal. + -- FIXME: let l:statusline = substitute(l:statusline, '\([ "]\)', '\\\0', 'g') + 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.require('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.require('statusline').inactive()%} ]] + end +}) + +return statusline