local spinner_ok, spinner = pcall(require, 'spinner') if spinner_ok then spinner.setup { spinner = {'⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'}, interval = 120, -- spinner frame rate in ms } end 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_ts(), 'StatusLineTreesitter', hi) sl = sl .. statusline_append(statusline_lsp_diagnostics(bufnr, hi), 'StatusLineDiagnostics', hi) sl = sl .. statusline_append(vim.trim(require('lsp-status').status()), 'StatusLineLsp', hi) sl = sl .. statusline_append(statusline_dap(), 'StatusLineDap', hi) sl = sl .. [[ %= ]] -- spacer sl = sl .. statusline_append(statusline_notify(hi), 'StatusLineNotify', hi) if spinner_ok then sl = sl .. statusline_append(spinner.status(bufnr), 'StatusLineJobs', hi) end sl = sl .. statusline_append(require('nvim-lightbulb').get_status_text(), 'StatusLineLightbulb', 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 -- statusline_append -- 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_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_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_ts() local data = require('nvim-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_dap() local dap_ok, dap = pcall(require, 'dap') if not dap_ok 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 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('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', '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()%}'