diff options
Diffstat (limited to '.vim/lua/internal/statusline.lua')
| -rw-r--r-- | .vim/lua/internal/statusline.lua | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/.vim/lua/internal/statusline.lua b/.vim/lua/internal/statusline.lua new file mode 100644 index 0000000..97f5031 --- /dev/null +++ b/.vim/lua/internal/statusline.lua @@ -0,0 +1,255 @@ +function _G.statusline() + local bufnr = vim.fn.bufnr() or 0 + local hi = statusline_color(vim.fn.mode()) + + local sl = hi + -- sl = sl .. statusline_append([[ ⢷]], 'StatusLineIcon', hi) + + sl = sl .. statusline_append(statusline_lightbulb(), + 'StatusLineLightbulb', hi) + + sl = sl .. statusline_append(statusline_ts(), + 'StatusLineTreesitter', hi) + + sl = sl .. statusline_append(statusline_lsp_diagnostics(bufnr, hi), + 'StatusLineDiagnostics', hi) + + sl = sl .. statusline_append(statusline_lspstatus(), + 'StatusLineLsp', hi) + + sl = sl .. statusline_append(statusline_dap(), + 'StatusLineDap', hi) + + sl = sl .. [[ %= ]] -- spacer + + sl = sl .. statusline_append(statusline_notify(hi), + 'StatusLineNotify', hi) + + sl = sl .. statusline_append(statusline_spinner(bufnr), + 'StatusLineJobs', hi) + + sl = sl .. statusline_append([[ %l:%v --%p%%-- %y]], hi, hi) + + return sl +end + +function _G.statusline_color(mode) + local hi = '%*' + if mode == 'i' then + -- hi = '%#StatusLineInsert#' + elseif mode == 'c' then + -- hi = '%#StatusLineCommand#' + elseif mode == 'v' or mode == 'V' or mode == '' then + hi = '%#StatusLineVisual#' + elseif mode == 'R' or mode == 'Rv' then + hi = '%#StatusLineReplace#' + end + -- return '%{g:actual_curwin==win_getid()?'.. hi ..':%#StatusLineNC#}' + return hi +end +-- does item highlighting and conditionnal spacing +function _G.statusline_append(element, hi, default_hi, opts) + if not element or element == '' then return '' end + opts = opts or { append_space = true } + + if hi ~= nil then hi = '%#' .. hi .. '#' end + if not (default_hi == '%*') then hi = default_hi end + local el = hi .. element .. default_hi + if opts.append_space then el = el .. ' ' end + return el +end +function _G.statusline_combine_hi(outer_name, inner_name) + local outer = vim.api.nvim_get_hl_by_id(vim.api.nvim_get_hl_id_by_name(outer_name), true) + local inner = vim.api.nvim_get_hl_by_id(vim.api.nvim_get_hl_id_by_name(inner_name), true) + local hi = 'auto' .. outer_name .. inner_name + if pcall(vim.api.nvim_get_hl_by_name, hi, true) then return hi end + local gui + gui = inner.bold and 'bold' + gui = inner.italic and 'italic' + gui = inner.underline and 'underline' + vim.api.nvim_set_hl(0, hi, {bg = outer.background, fg = inner.foreground, gui = gui}) + return hi +end + +function _G.statusline_lsp_diagnostics(bufnr, default_hi) + local error_num = vim.diagnostic.get(bufnr, {severity=vim.diagnostic.severity.ERROR}) + local warn_num = vim.diagnostic.get(bufnr, {severity=vim.diagnostic.severity.WARN}) + + local s = '' + if #error_num > 0 then + local errs = vim.fn.sign_getdefined('DiagnosticSignError')[1].text .. #error_num + s = s .. statusline_append(errs, statusline_combine_hi('StatusLineDiagnostics', 'DiagnosticError'), default_hi) + end + if #warn_num > 0 then + local warns = vim.fn.sign_getdefined('DiagnosticSignWarn')[1].text .. #warn_num + s = s .. statusline_append(warns, statusline_combine_hi('StatusLineDiagnostics', 'DiagnosticWarn'), default_hi) + end + return vim.trim(s) +end +function _G.statusline_ts() + local navic = package.loaded['nvim-navic'] + if not navic then return '' end + local data = navic.get_data() + if not data then return '' end + local s = {} + for i = 1, #data do + table.insert(s, string.format('%%#CmpItemKind%s#%s%%* %%#StatusLine#%s%%*', data[i].type, data[i].icon, data[i].name)) + end + return table.concat(s, ' > ') +end +function _G.statusline_lspstatus() + local lst = package.loaded['lsp-status'] + if not lst then return '' end + return vim.trim(lst.status()) +end +function _G.statusline_lightbulb() + local lb = package.loaded['nvim-lightbulb'] + if not lb then return '' end + return lb.get_status_text() +end +function _G.statusline_spinner(bufnr) + local sp = package.loaded.spinner + if not sp then return '' end + return sp.status(bufnr) +end +function _G.statusline_dap() + local dap = package.loaded.dap + if not dap then return '' end + local s = dap.status() + if s == '' then return s end + return '[DAP: ' .. s .. ']' +end + +-- notifications cache +_G.statusline_notifications = {} +_G.statusline_notifications_archive = {} + +function _G.statusline_notify(default_hi) + if #_G.statusline_notifications == 0 then return '' end + local n = _G.statusline_notifications[1] + local timeout = (n.options and n.options.timeout) or 2000 + -- pop message after <timeout> and move to archive + vim.defer_fn(function() + local n = table.remove(_G.statusline_notifications, 1) + table.insert(_G.statusline_notifications_archive, n) + -- make sure archive is never longer than 20 notifications + if #_G.statusline_notifications_archive > 20 then + table.remove(_G.statusline_notifications_archive, 1) + end + end, timeout) + + local s = '' + if n.hi then + s = s .. statusline_append(n.lvl_string .. ' ', statusline_combine_hi('StatusLineNotify', n.hi), default_hi, { append_space = false }) + end + s = s .. statusline_append(n.message, 'StatusLineNotify', default_hi) + return vim.trim(s) +end + +-- out vim.notify implementation +local notify = function(m, l, o) + local lvl_string = l + local hi = nil + if l and type(l) == 'number' then + if l == vim.log.levels.TRACE then + hi = 'deEmph' + elseif l == vim.log.levels.DEBUG then + hi = 'DiagnosticHint' + elseif l == vim.log.levels.INFO then + hi = 'DiagnosticInfo' + elseif l == vim.log.levels.WARN then + hi = 'DiagnosticWarn' + elseif l == vim.log.levels.ERROR then + hi = 'DiagnosticError' + end + -- get level string + lvl_string = vim.lsp.log_levels[l] + end + local display = m + if lvl_string then display = lvl_string .. ' ' .. display end + table.insert(_G.statusline_notifications, { + message = m, + level = l, + options = o, + lvl_string = lvl_string, + hi = hi, + display = display, + }) + + if _G.statusline_enable_notifysend then + local args = {} + if lvl_string then + if lvl_string == 'ERROR' then + table.insert(args, '--category=error') + end + if lvl_string == 'WARN' then + table.insert(args, '--category=warning') + end + end + table.insert(args, 'nvim') + table.insert(args, display) + require('internal.job').jobstart { command = 'notify-send', args = args } + end +end + +-- overwrite vim.notify +vim.notify = function( m, l, o) + if vim.in_fast_event() then + vim.schedule(function() + notify(m, l, o) + end) + else + return notify(m, l, o) + end +end + +vim.keymap.set('n', '<leader>n', function() + local pickers = require('telescope.pickers') + local finders = require('telescope.finders') + local conf = require('telescope.config').values + local actions = require('telescope.actions') + -- local action_state = require('telescope.actions.state') + -- local previewers = require('telescope.previewers') + + local opts = {} + pickers.new(opts, { + prompt_title = "Notifications", + finder = finders.new_dynamic { + fn = function() + return _G.statusline_notifications_archive + end, + entry_maker = function(n) + return { + value = n, + display = n.display, + ordinal = n.message, + } + end, + }, + sorter = conf.generic_sorter(opts), + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + -- noop + -- local sel = action_state.get_selected_entry() + -- vim.notify(sel.value.message, sel.value.level, sel.value.options) + end) + return true + end, + -- previewer = previewers.new_buffer_previewer { + -- define_preview = function(self, entry) + -- vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, {entry.value.display}) + -- end, + -- }, + }):find() +end, {desc='notifications'}) + +-- vim.opt.statusline = '%!luaeval("statusline()")' +vim.opt.statusline = '%{%v:lua.statusline()%}' + +-- WINBAR -- +vim.opt.winbar = [[%h%w%q%f %-m %-r %= %#WinBarCwd#%{%getcwd()%}%*]] -- keep it simple +-- function _G.winbar() +-- return [[%<%F %-m %-r]] +-- end +-- vim.opt.winbar = '%{%v:lua.winbar()%}' |