--============================================================================= -- statusline.lua --- -- Copyright (c) 2019-2024 Wang Shidong & Contributors -- Author: Wang Shidong < wsdjeg@outlook.com > -- URL: https://spacevim.org -- License: GPLv3 --============================================================================= local highlight = require('spacevim.api.vim.highlight') local system = require('spacevim.api.system') local lang = require('spacevim.api.language') local time = require('spacevim.api.time') local JSON = require('spacevim.api.data.json') local layer = require('spacevim.layer') local messletters = require('spacevim.api.messletters') local statusline = require('spacevim.api.vim.statusline') local log = require('spacevim.logger').derive('stl') local M = {} local function index(t, v) for n, m in ipairs(t) do if m == v then return n end end return -1 end -- https://github.com/ryanoasis/powerline-extra-symbols local separators = { arrow = { '', '' }, curve = { '', '' }, slant = { '', '' }, brace = { '', '' }, fire = { '', '' }, ['nil'] = { '', '' }, } local i_separators = { arrow = { '', '' }, curve = { '', '' }, slant = { '', '' }, bar = { '|', '|' }, ['nil'] = { '', '' }, } local lsep = '' local rsep = '' local ilsep = '' local irsep = '' local loaded_modes = {} local colors_template = vim.fn['SpaceVim#mapping#guide#theme#gruvbox#palette']() local section_old_pos = {} local modes = { ['center-cursor'] = { icon = '', icon_asc = '-', desc = 'centered-cursor mode', }, ['hi-characters-for-long-lines'] = { icon = '⑧', icon_asc = '8', desc = 'toggle highlight of characters for long lines', }, ['fill-column-indicator'] = { icon = messletters.circled_letter('f'), icon_asc = 'f', desc = 'fill-column-indicator mode', }, ['syntax-checking'] = { icon = messletters.circled_letter('s'), icon_asc = 's', desc = 'syntax-checking mode', }, ['spell-checking'] = { icon = messletters.circled_letter('S'), icon_asc = 'S', desc = 'spell-checking mode', }, ['paste-mode'] = { icon = messletters.circled_letter('p'), icon_asc = 'p', desc = 'paste mode', }, whitespace = { icon = messletters.circled_letter('w'), icon_asc = 'w', desc = 'whitespace mode', }, wrapline = { icon = messletters.circled_letter('W'), icon_asc = 'W', desc = 'wrap line mode', }, } local major_mode_cache = true if layer.isLoaded('checkers') then table.insert(loaded_modes, 'syntax-checking') end if vim.o.spell then table.insert(loaded_modes, 'spell-checking') end if vim.o.cc == '80' then table.insert(loaded_modes, 'fill-column-indicator') end if index(vim.g.spacevim_statusline_right, 'whitespace') ~= -1 then table.insert(loaded_modes, 'whitespace') end local function winnr(...) if select(1, ...) then if vim.g.spacevim_windows_index_type == 3 then return ' %{ get(w:, "winid", winnr()) } ' else return ' %{ v:lua.require("spacevim.plugin.statusline").winnr(get(w:, "winid", winnr())) } ' end else if vim.g.spacevim_enable_statusline_mode == 1 then return '%{v:lua.require("spacevim.plugin.statusline").mode(mode())} %{ v:lua.require("spacevim.plugin.statusline").winnr(get(w:, "winid", winnr())) } %{v:lua.require("spacevim.plugin.statusline").mode_text(mode())} ' elseif vim.g.spacevim_windows_index_type == 3 then return '%{v:lua.require("spacevim.plugin.statusline").mode(mode())} %{ get(w:, "winid", winnr()) } ' else return '%{v:lua.require("spacevim.plugin.statusline").mode(mode())} %{ v:lua.require("spacevim.plugin.statusline").winnr(get(w:, "winid", winnr())) } ' end end end function M.winnr(id) return messletters.circled_num(id, vim.g.spacevim_windows_index_type) end local function whitespace() local ln = vim.fn.search('\\s\\+$', 'nw') if ln ~= 0 then return ' trailing[' .. ln .. '] ' else return '' end end local function battery_status() if vim.fn.executable('acpi') == 1 then else return '' end end ---@return string # The buffer name local function buffer_name() if vim.b._spacevim_statusline_showbfname == 1 or vim.g.spacevim_enable_statusline_bfpath == 1 then return ' ' .. vim.fn.bufname('%') else return '' end end local function input_method() if vim.fn.executable('fcitx-remote') == 1 then if vim.fn.system('fcitx-remote') == 1 then return ' cn ' else return ' en ' end end return '' end local function syntax_checking() if vim.fn['SpaceVim#lsp#buf_server_ready']() then local counts = require('spacevim.lsp').lsp_diagnostic_count() local errors = counts[1] or 0 local warnings = counts[2] or 0 local infos = counts[3] or 0 local hints = counts[4] or 0 local errors_l = '' if errors > 0 then errors_l = '%#SpaceVim_statusline_error#● ' .. errors end local warnings_l = '' if warnings > 0 then warnings_l = '%#SpaceVim_statusline_warn#● ' .. warnings end local infos_l = '' if infos > 0 then infos_l = '%#SpaceVim_statusline_info#● ' .. infos end local hints_l = '' if hints > 0 then hints_l = '%#SpaceVim_statusline_hint#● ' .. hints end local l = table.concat( vim.tbl_filter(function(t) return t ~= '' end, { errors_l, warnings_l, infos_l, hints_l }), ' ' ) if #l > 0 then return ' ' .. l .. ' ' else return '' end elseif vim.g.spacevim_lint_engine == 'neomake' then if not vim.g.loaded_neomake then return '' end local counts = vim.fn['neomake#statusline#LoclistCounts']() local warnings = counts.W or 0 local errors = counts.E or 0 local l = '' if warnings > 0 then l = '%#SpaceVim_statusline_warn# ● ' .. warnings .. ' ' end if errors > 0 then l = l .. '%#SpaceVim_statusline_error#● ' .. errors end if l ~= '' then return ' ' .. l .. ' ' else return '' end elseif vim.g.spacevim_lint_engine == 'ale' then if not vim.g.ale_enabled then return '' end local counts = vim.fn['ale#statusline#Count'](vim.fn.bufnr('')) local warnings = counts.warning + counts.style_warning local errors = counts.error + counts.style_error local l = '' if warnings > 0 then l = '%#SpaceVim_statusline_warn# ● ' .. warnings .. ' ' end if errors > 0 then l = l .. '%#SpaceVim_statusline_error#● ' .. errors end if l ~= '' then return ' ' .. l .. ' ' else return '' end else if vim.fn.exists(':SyntasticCheck') == 0 then return '' end local l = vim.fn.SyntasticStatuslineFlag() if #l > 0 then return l else return '' end end end local function search_status() end local function search_count() end local function filesize() local size = vim.fn.getfsize(vim.fn.bufname('%')) if size <= 0 then return '' elseif size < 1024 then return size .. ' bytes ' elseif size < 1024 * 1024 then return string.format('%.1f', size / 1024) .. 'k ' elseif size < 1024 * 1024 * 1024 then return string.format('%.1f', size / 1024 / 1024) .. 'm ' else return string.format('%.1f', size / 1024 / 1024 / 1024) .. 'g ' end end local function filename() local name = vim.fn.fnamemodify(vim.fn.bufname('%'), ':t') if name == '' then name = 'No Name' end return "%{ &modified ? ' * ' : ' - '}" .. filesize() .. name .. ' ' end local function fileformat() if vim.g.spacevim_statusline_unicode == 1 then vim.g._spacevim_statusline_fileformat = system.fileformat() else vim.g._spacevim_statusline_fileformat = vim.o.ff end return '%{ " " . g:_spacevim_statusline_fileformat . " ' .. irsep .. ' " . (&fenc!=""?&fenc:&enc) . " "}' end local function major_mode() local alias = lang.get_alias(vim.o.filetype) if alias == '' then return '' else return ' ' .. alias .. ' ' end end local function get_modes() -- same as s:modes() in vim statusline local m if vim.g.spacevim_statusline_unicode == 1 then m = ' ❖ ' else m = ' # ' end for _, mode in ipairs(loaded_modes) do if vim.g.spacevim_statusline_unicode == 1 then m = m .. modes[mode].icon .. ' ' else m = m .. modes[mode].icon_asc .. ' ' end end return m .. ' ' end local function totallines() return ' %L ' end local function percentage() return ' %P ' end local function cursorpos() return [[%{' ' . join(map(getpos('.')[1:2], "printf('%3d', v:val)"), ':') . ' '}]] end local function current_time() return ' ' .. time.current_time() .. ' ' end local function current_date() return ' ' .. time.current_date() .. ' ' end local registed_sections = { winnr = winnr, ['syntax checking'] = syntax_checking, filename = filename, fileformat = fileformat, ['major mode'] = major_mode, ['minor mode lighters'] = get_modes, cursorpos = cursorpos, percentage = percentage, totallines = totallines, time = current_time, date = current_date, whitespace = whitespace, ['battery status'] = battery_status, ['input method'] = input_method, ['search status'] = search_status, ['search count'] = search_count, } local function current_tag() return '%{ v:lua.require("spacevim.plugin.statusline")._current_tag() }' end function M._current_tag() local tag = '' pcall(function() -- current tag should be show only after vimenter -- @fixme this make sure tagbar has been loaded -- because when first run tagbar, it needs long time. -- and also there no syntax highlight when first time open file. if vim.g._spacevim_after_vimenter == 1 and vim.g.spacevim_enable_statusline_tag == 1 and vim.g.loaded_tagbar == 1 then tag = vim.fn['tagbar#currenttag']('%s ', '') end end) return tag end local function active() local lsec = {} for _, section in ipairs(vim.g.spacevim_statusline_left) do if registed_sections[section] then local rst = '' local ok, _ = pcall(function() if type(registed_sections[section]) == 'function' then rst = registed_sections[section]() elseif type(registed_sections[section]) == 'string' then rst = vim.fn[registed_sections[section]]() end end) if not ok then log.debug('failed to call section func:' .. section) end table.insert(lsec, rst) end end local rsec = {} for _, section in ipairs(vim.g.spacevim_statusline_right) do if registed_sections[section] then local rst = '' local ok, _ = pcall(function() if type(registed_sections[section]) == 'function' then rst = registed_sections[section]() elseif type(registed_sections[section]) == 'string' then rst = vim.fn[registed_sections[section]]() end end) if not ok then log.debug('failed to call section func:' .. section) end table.insert(rsec, rst) end end local fname = buffer_name() local tag = current_tag() local winwidth = vim.fn.winwidth(vim.fn.winnr()) if vim.o.laststatus == 3 then winwidth = vim.o.columns end return statusline.build( lsec, rsec, lsep, rsep, fname, tag, 'SpaceVim_statusline_a', 'SpaceVim_statusline_b', 'SpaceVim_statusline_c', 'SpaceVim_statusline_z', winwidth ) end local function inactive() local l = '%#SpaceVim_statusline_ia#' .. winnr(1) .. '%#SpaceVim_statusline_ia_SpaceVim_statusline_b#' .. lsep .. '%#SpaceVim_statusline_b#' local secs = { filename(), ' ' .. vim.o.filetype, get_modes() } local base = 10 for _, sec in ipairs(secs) do local len = statusline.len(sec) base = base + len l = l .. '%{ get(w:, "winwidth", 150) < ' .. base .. ' ? "" : (" ' .. statusline.eval(sec) .. ' ' .. ilsep .. '")}' end if (vim.w.winwidth or 150) > base + 10 then l = l .. table.concat({ '%=', '%{" " . get(g:, "_spacevim_statusline_fileformat", "") . " "}', '%{" " . (&fenc!=""?&fenc:&enc) . " "}', ' %P ', }, irsep) end return l end ---@return string # return a simple statusline with special name local function simple_name(name) return '%#SpaceVim_statusline_ia#' .. winnr(1) .. '%#SpaceVim_statusline_ia_SpaceVim_statusline_b#' .. lsep .. '%#SpaceVim_statusline_b# ' .. name .. ' %#SpaceVim_statusline_b_SpaceVim_statusline_c#' .. lsep .. '%#SpaceVim_statusline_c#' end local special_statusline = { vimfiler = function() return simple_name('VimFiler') end, qf = function() local l = '' local wininfo = vim.fn.getwininfo(vim.api.nvim_get_current_win())[1] if wininfo.quickfix == 1 and wininfo.loclist == 0 then local title = vim.fn.getqflist({ title = 0 }).title if title == ':setqflist()' then title = '' end l = simple_name('QuickFix') .. ' ' .. title elseif wininfo.loclist == 1 then local title = vim.fn.getloclist(vim.fn.winnr(), { title = 0 }).title if title == ':setloclist()' then title = '' end l = simple_name('Location list') .. ' ' .. title end return l end, defx = function() return simple_name('defx') end, ['git-status'] = function() return simple_name('Git status') end, startify = function() pcall(vim.fn['fugitive#detect'], vim.fn.getcwd()) local st = '%#SpaceVim_statusline_ia#' .. winnr(1) .. '%#SpaceVim_statusline_ia_SpaceVim_statusline_b#' .. lsep .. '%#SpaceVim_statusline_b# startify %#SpaceVim_statusline_b_SpaceVim_statusline_c#' .. lsep if index(vim.g.spacevim_statusline_left, 'vcs') ~= -1 and registed_sections.vcs then st = st .. '%#SpaceVim_statusline_c#' if type(registed_sections.vcs) == 'string' then st = st .. vim.fn[registed_sections.vcs]() elseif type(registed_sections.vcs) == 'function' then st = st .. registed_sections.vcs() end st = st .. '%#SpaceVim_statusline_c_SpaceVim_statusline_z#' .. lsep end return st end, NvimTree = function() return simple_name('NvimTree') end, ['neo-tree'] = function() return simple_name('NeoTree') end, Fuzzy = function() end, -- todo ['git-commit'] = function() return simple_name('Git commit') end, ['git-rebase'] = function() return simple_name('Git rebase') end, ['git-blame'] = function() return simple_name('Git blame') end, ['git-log'] = function() return simple_name('Git log') end, ['git-diff'] = function() return simple_name('Git diff') end, ['git-config'] = function() return simple_name('Git config') end, SpaceVimMessageBuffer = function() return simple_name('Message') end, ['gista-list'] = function() return simple_name('Gista') end, terminal = function() end, -- todo vimchat = function() end, -- todo calender = function() return simple_name('Calendar') end, ['vader-result'] = function() return simple_name('Vader result') end, ['gina-status'] = function() return simple_name('Gina status') end, ['gina-commit'] = function() return simple_name('Gina commit') end, nerdtree = function() return simple_name('Nerdtree') end, Mundo = function() return simple_name('Mundo') end, MundoDiff = function() return simple_name('MundoDiff') end, SpaceVimLayerManager = function() return simple_name('LayerManager') end, SpaceVimFindArgv = function() return simple_name('Find') end, SpaceVimGitLogPopup = function() return simple_name('Git log popup') end, ['response.idris'] = function() return simple_name('Idris Response') end, ['markdown.lspdoc'] = function() return simple_name('LSP hover info') end, SpaceVimWinDiskManager = function() return simple_name('WinDisk') end, SpaceVimTodoManager = function() return simple_name('TODO manager') end, SpaceVimTasksInfo = function() return simple_name('Tasks manager') end, SpaceVimGitBranchManager = function() return simple_name('Branch manager') end, SpaceVimGitRemoteManager = function() return simple_name('Remote manager') end, SpaceVimPlugManager = function() return simple_name('PlugManager') end, SpaceVimTabsManager = function() return simple_name('TabsManager') end, fzf = function() end, -- todo denite = function() end, -- todo ['denite-filter'] = function() return '%#SpaceVim_statusline_a_bold#' .. ' Filter ' .. '%#SpaceVim_statusline_a_SpaceVim_statusline_b#' .. lsep end, unite = function() end, -- todo SpaceVimFlyGrep = function() end, -- todo TransientState = function() return '%#SpaceVim_statusline_ia# Transient State %#SpaceVim_statusline_a_SpaceVim_statusline_b#' end, SpaceVimLog = function() return simple_name('SpaceVim Runtime Log') end, SpaceVimTomlViewer = function() return simple_name('Toml Json Viewer') end, vimcalc = function() return simple_name('VimCalc') end, HelpDescribe = function() return simple_name('HelpDescribe') end, SpaceVimRunner = function() return simple_name('Runner') .. ' %{SpaceVim#plugins#runner#status()}' end, SpaceVimREPL = function() return simple_name('REPL') .. ' %{SpaceVim#plugins#repl#status()}' end, VimMailClient = function() end, -- todo SpaceVimQuickFix = function() return simple_name('SpaceVimQuickFix') end, VebuggerShell = function() return simple_name('VebuggerShell') end, VebuggerTerminal = function() return simple_name('VebuggerTerminal') end, } function M.get(...) if special_statusline[vim.o.filetype] then return special_statusline[vim.o.filetype]() end if select(1, ...) then return active() else return inactive() end end function M.def_colors() local name = vim.g.colors_name or 'gruvbox' local t if #vim.g.spacevim_custom_color_palette > 0 then t = vim.g.spacevim_custom_color_palette else local ok = pcall(function() t = vim.fn['SpaceVim#mapping#guide#theme#' .. name .. '#palette']() end) if not ok then t = vim.fn['SpaceVim#mapping#guide#theme#gruvbox#palette']() end end colors_template = t vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a', { fg = t[1][1], bg = t[1][2], ctermfg = t[1][4], ctermbg = t[1][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a_bold', { bold = true, fg = t[1][1], bg = t[1][2], ctermfg = t[1][4], ctermbg = t[1][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_ia', { fg = t[1][1], bg = t[1][2], ctermfg = t[1][4], ctermbg = t[1][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_b', { fg = t[2][1], bg = t[2][2], ctermfg = t[2][4], ctermbg = t[2][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_c', { fg = t[3][1], bg = t[3][2], ctermfg = t[3][4], ctermbg = t[3][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_z', { fg = t[3][1], bg = t[4][1], ctermfg = t[3][3], ctermbg = t[4][2], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_error', { bold = true, fg = '#ffc0b9', bg = t[2][2], ctermfg = 'Black', ctermbg = t[2][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_warn', { bold = true, fg = '#fce094', bg = t[2][2], ctermfg = 'Black', ctermbg = t[2][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_info', { bold = true, fg = '#8cf8f7', bg = t[2][2], ctermfg = 'Black', ctermbg = t[2][3], }) vim.api.nvim_set_hl(0, 'SpaceVim_statusline_hint', { bold = true, fg = '#a6dbff', bg = t[2][2], ctermfg = 'Black', ctermbg = t[2][3], }) highlight.hi_separator('SpaceVim_statusline_a', 'SpaceVim_statusline_b') highlight.hi_separator('SpaceVim_statusline_a_bold', 'SpaceVim_statusline_b') highlight.hi_separator('SpaceVim_statusline_ia', 'SpaceVim_statusline_b') highlight.hi_separator('SpaceVim_statusline_b', 'SpaceVim_statusline_c') highlight.hi_separator('SpaceVim_statusline_b', 'SpaceVim_statusline_z') highlight.hi_separator('SpaceVim_statusline_c', 'SpaceVim_statusline_z') end function M.register_mode(mode) if modes[mode.key] and mode.func then modes[mode.key].func = mode.func log.debug('register major mode function:' .. mode.key) else modes[mode.key] = mode end end local function update_conf() log.debug('write major mode to major_mode.json') local conf = {} for key, _ in pairs(modes) do if index(loaded_modes, key) > -1 then conf[key] = true else conf[key] = false end end if vim.fn.writefile( { JSON.json_encode(conf) }, vim.fn.expand(vim.g.spacevim_data_dir .. 'SpaceVim/major_mode.json') ) == 0 then log.debug('update major_mode.json done') else log.debug('failed to update major_mode.json') end end function M.toggle_mode(name) log.debug('toggle major mode:' .. name) local mode = modes[name] if not mode then log.debug('can not find major mode:' .. name) return end local done if mode.func then if type(mode.func) == 'string' then done = vim.fn[mode.func]() elseif type(mode.func) == 'function' then done = mode.func() end end local idx = index(loaded_modes, name) if idx ~= -1 then table.remove(loaded_modes, idx) else if done == 1 then table.insert(loaded_modes, name) end end vim.opt_local.statusline = M.get(1) if major_mode_cache then update_conf() end end function M.toggle_section(name) if index(vim.g.spacevim_statusline_left, name) == -1 and index(vim.g.spacevim_statusline_right, name) == -1 and not section_old_pos[name] then if name == 'search status' then local temp = vim.g.spacevim_statusline_left table.insert(temp, 2, name) vim.g.spacevim_statusline_left = temp else local temp = vim.g.spacevim_statusline_right table.insert(temp, name) vim.g.spacevim_statusline_right = temp end elseif index(vim.g.spacevim_statusline_right, name) ~= -1 then section_old_pos[name] = { 'r', index(vim.g.spacevim_statusline_right, name) } local temp = vim.g.spacevim_statusline_right table.remove(temp, index(temp, name)) vim.g.spacevim_statusline_right = temp elseif index(vim.g.spacevim_statusline_left, name) ~= -1 then section_old_pos[name] = { 'l', index(vim.g.spacevim_statusline_left, name) } local temp = vim.g.spacevim_statusline_left table.remove(temp, index(temp, name)) vim.g.spacevim_statusline_left = temp elseif section_old_pos[name] then if section_old_pos[name][1] == #'r' then local temp = vim.g.spacevim_statusline_right table.insert(temp, section_old_pos[name][2], name) vim.g.spacevim_statusline_right = temp else local temp = vim.g.spacevim_statusline_left table.insert(temp, section_old_pos[name][2], name) vim.g.spacevim_statusline_left = temp end end vim.opt_local.statusline = M.get(1) end function M.ctrlp_status(str) return statusline.build( { ' Ctrlp ', ' ' .. str .. ' ' }, { ' ' .. vim.fn.getcwd() .. ' ' }, lsep, rsep, '', '', 'SpaceVim_statusline_a', 'SpaceVim_statusline_b', 'SpaceVim_statusline_c', 'SpaceVim_statusline_z', vim.fn.winwidth(vim.fn.winnr()) ) end function M.config() if separators[vim.g.spacevim_statusline_separator] then lsep = separators[vim.g.spacevim_statusline_separator][1] rsep = separators[vim.g.spacevim_statusline_separator][2] end if i_separators[vim.g.spacevim_statusline_iseparator] then ilsep = i_separators[vim.g.spacevim_statusline_iseparator][1] irsep = i_separators[vim.g.spacevim_statusline_iseparator][2] end vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 'm' }, 'call SpaceVim#layers#core#statusline#toggle_section("minor mode lighters")', 'toggle the minor mode lighters', 1 ) vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 'M' }, 'call SpaceVim#layers#core#statusline#toggle_section("major mode")', 'toggle the major mode', 1 ) vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 'b' }, 'call SpaceVim#layers#core#statusline#toggle_section("battery status")', 'toggle the battery status', 1 ) vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 'd' }, 'call SpaceVim#layers#core#statusline#toggle_section("date")', 'toggle the date', 1 ) vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 'i' }, 'call SpaceVim#layers#core#statusline#toggle_section("input method")', 'toggle the input method', 1 ) vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 't' }, 'call SpaceVim#layers#core#statusline#toggle_section("time")', 'toggle the time', 1 ) vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 'p' }, 'call SpaceVim#layers#core#statusline#toggle_section("cursorpos")', 'toggle the cursor position', 1 ) vim.fn['SpaceVim#mapping#space#def']( 'nnoremap', { 't', 'm', 'T' }, 'if &laststatus == 2 | let &laststatus = 0 | else | let &laststatus = 2 | endif', 'toggle the statusline itself', 1 ) local function TagbarStatusline(_, _, fname, _) local name = '' if vim.fn.strwidth(fname) > vim.g.spacevim_sidebar_width - 15 then name = string.sub(fname, vim.g.spacevim_sidebar_width - 20) .. '..' else name = fname end return statusline.build( { winnr(1), ' Tagbar ', ' ' .. name .. ' ' }, {}, lsep, rsep, '', '', 'SpaceVim_statusline_ia', 'SpaceVim_statusline_b', 'SpaceVim_statusline_c', 'SpaceVim_statusline_z', vim.g.spacevim_sidebar_width ) end vim.g.tagbar_status_func = TagbarStatusline vim.g.unite_force_overwrite_statusline = 0 vim.g.ctrlp_status_func = { main = 'SpaceVim#layers#core#statusline#ctrlp', prog = 'SpaceVim#layers#core#statusline#ctrlp_status', } if vim.fn.filereadable(vim.fn.expand(vim.g.spacevim_data_dir .. 'SpaceVim/major_mode.json')) == 1 and major_mode_cache then log.debug('load cache from major_mode.json') local conf = JSON.json_decode( vim.fn.join( vim.fn.readfile(vim.fn.expand(vim.g.spacevim_data_dir .. 'SpaceVim/major_mode.json'), ''), '' ) ) if type(conf) == 'table' then for k, v in pairs(conf) do if v == 1 or v == true then log.debug('cached major mode: ' .. k) M.toggle_mode(k) end end end end end function M.ctrlp(focus, byfname, _, prev, item, next, _) return statusline.build( { ' Ctrlp ', ' ' .. prev .. ' ', ' ' .. item .. ' ', ' ' .. next .. ' ' }, { ' ' .. focus .. ' ', ' ' .. byfname .. ' ', ' ' .. vim.fn.getcwd() .. ' ' }, lsep, rsep, '', '', 'SpaceVim_statusline_a_bold', 'SpaceVim_statusline_b', 'SpaceVim_statusline_c', 'SpaceVim_statusline_z', vim.fn.winwidth(vim.fn.winnr()) ) end function M.jump(i) pcall(function() vim.cmd(i .. 'wincmd w') end) end function M.mode(mode) local t = colors_template local iedit_mode = vim.w.spacevim_iedit_mode or '' if vim.w.spacevim_statusline_mode ~= mode then if mode == 'n' then if iedit_mode == 'n' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a', { bold = true, fg = t[9][1], bg = t[9][2], ctermfg = t[9][3], ctermbg = t[9][4], }) elseif iedit_mode == 'i' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a', { bold = true, fg = t[8][1], bg = t[8][2], ctermfg = t[8][3], ctermbg = t[8][4], }) else vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a', { bold = true, fg = t[1][1], bg = t[1][2], ctermfg = t[1][4], ctermbg = t[1][3], }) end elseif mode == 'i' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a', { bold = true, fg = t[5][1], bg = t[5][2], ctermfg = t[5][3], ctermbg = t[5][4], }) elseif mode == 'R' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a', { bold = true, fg = t[7][1], bg = t[7][2], ctermfg = t[7][3], ctermbg = t[7][4], }) elseif mode == 'v' or mode == 'V' or mode == #'' or mode == 's' or mode == 'S' or mode == #'' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a', { bold = true, fg = t[6][1], bg = t[6][2], ctermfg = t[6][3], ctermbg = t[6][4], }) end highlight.hi_separator('SpaceVim_statusline_a', 'SpaceVim_statusline_b') vim.w.spacevim_statusline_mode = mode end return '' end function M.mode_text(mode) local past_mode = '' if vim.o.paste then past_mode = 'Paste ' .. ilsep .. ' ' end local mode_text = '' local iedit_mode = vim.w.spacevim_iedit_mode or '' if mode == 'n' then if iedit_mode ~= '' then if iedit_mode == 'n' then mode_text = 'IEDIT-NORMAL' elseif iedit_mode == 'i' then mode_text = 'IEDIT-INSERT' end else mode_text = ' NORMAL' end elseif mode == 'i' then mode_text = ' INSERT' elseif mode == 'R' then mode_text = 'REPLACE' elseif mode == 'v' then mode_text = ' VISUAL' elseif mode == 'V' then mode_text = ' V-LINE' elseif mode == '' then mode_text = 'V-BLOCK' elseif mode == 'c' then mode_text = 'COMMAND' elseif mode == 't' then mode_text = ' TERM' elseif mode == 'v' or mode == 'V' or mode == '^V' or mode == 's' or mode == 'S' or mode == '^S' then mode_text = ' VISUAL' end return past_mode .. mode_text end function M.set_variable(var) major_mode_cache = var.major_mode_cache or major_mode_cache end function M.check_section(name) for _, v in ipairs(vim.g.spacevim_statusline_right) do if v == name then return true end end for _, v in ipairs(vim.g.spacevim_statusline_left) do if v == name then return true end end return false end function M.denite_status(argv) local denite_ver ---@type number if vim.fn.exists('*denite#get_status_mode') == 1 then denite_ver = 2 else denite_ver = 3 end if denite_ver == 3 then return vim.fn['denite#get_status'](argv) else return vim.fn['denite#get_status_' .. argv]() end end function M.denite_mode() local t = colors_template local denite_ver ---@type number if vim.fn.exists('*denite#get_status_mode') == 1 then denite_ver = 2 else denite_ver = 3 end if denite_ver == 3 then return 'Denite' else local dmode = vim.fn.split(vim.fn['denite#get_status_mode']())[2] if vim.w.spacevim_statusline_mode ~= dmode then if dmode == 'NORMAL' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a_bold', { bold = true, fg = t[1][1], bg = t[1][2], ctermfg = t[1][4], ctermbg = t[1][3], }) else vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a_bold', { bold = true, fg = t[5][1], bg = t[5][2], ctermfg = t[5][3], ctermbg = t[5][4], }) end highlight.hi_separator('SpaceVim_statusline_a_bold', 'SpaceVim_statusline_b') vim.w.spacevim_statusline_mode = dmode end return dmode end end function M.unite_mode() local t = colors_template local dmode = vim.fn.mode() if vim.w.spacevim_statusline_mode ~= dmode then if dmode == 'n' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a_bold', { bold = true, fg = t[1][1], bg = t[1][2], ctermfg = t[1][4], ctermbg = t[1][3], }) elseif dmode == 'i' then vim.api.nvim_set_hl(0, 'SpaceVim_statusline_a_bold', { bold = true, fg = t[5][1], bg = t[5][2], ctermfg = t[5][3], ctermbg = t[5][4], }) end highlight.hi_separator('SpaceVim_statusline_a_bold', 'SpaceVim_statusline_b') vim.w.spacevim_statusline_mode = dmode end return dmode end function M.register_sections(name, func) if registed_sections[name] then log.info('statusline build-in section ' .. name .. ' has been changed!') end if type(func) ~= 'function' and type(func) ~= 'string' then log.warn('section' .. name .. ' need to be function or string') return end registed_sections[name] = func end function M.remove_section(name) local left = {} local right = {} for _, v in ipairs(vim.g.spacevim_statusline_left) do if v ~= name then table.insert(left, v) end end vim.g.spacevim_statusline_left = left for _, v in ipairs(vim.g.spacevim_statusline_right) do if v ~= name then table.insert(right, v) end end vim.g.spacevim_statusline_right = right vim.opt_local.statusline = M.get(1) end function M.health() end function M.init() local group = vim.api.nvim_create_augroup('spacevim_statusline', { clear = true }) vim.api.nvim_create_autocmd({ 'BufWinEnter', 'WinEnter', 'FileType', 'BufWritePost' }, { group = group, pattern = { '*' }, callback = function(_) vim.opt_local.statusline = M.get(1) end, }) vim.api.nvim_create_autocmd({ 'WinLeave' }, { group = group, pattern = { '*' }, callback = function(_) vim.opt_local.statusline = M.get() end, }) vim.api.nvim_create_autocmd({ 'ColorScheme' }, { group = group, pattern = { '*' }, callback = function(_) M.def_colors() end, }) end function M.rsep() return separators[vim.g.spacevim_statusline_separator] or separators.arrow end return M