" Very minital statusline for vim " Supports vim 8.0 and up and neovim 0.4 and likely earlier versions " Always show set laststatus=2 " ======================================================== " # Statusline highlights " ====================================================={{{ augroup statusbars_colorscheme_matching au! autocmd ColorScheme * call ReloadStatlnColors() augroup END " Function taken from vim airline " https://github.com/vim-airline/vim-airline/blob/master/autoload/airline/highlighter.vim#L17 function! GuiColors(rgb, fallback) if a:rgb[0] !~ '#' return a:fallback endif return a:rgb endfunction " Also set as active tabline hue let g:StatlnPrimaryColor = '#000000' " \ GuiColors(synIDattr(synIDtrans(hlID('String')), 'fg', 'gui'), '#000000') " Updates statusline colors function! ReloadStatlnColors() call SetGlobalPrimaryColor() let g:StatlnPrimaryFG = GuiColors(synIDattr(synIDtrans(hlID('Normal')), 'bg', 'gui'), '#222222') \ | let g:StatlnSubtle = GuiColors(synIDattr(synIDtrans(hlID('Normal')), 'fg', 'gui'), '#DAB997') \ | let g:StatlnSubtleBG = GuiColors(synIDattr(synIDtrans(hlID('Visual')), 'bg', 'gui'), '#4E4E4E') \ | let g:StatlnIdle = GuiColors(synIDattr(synIDtrans(hlID('Search')), 'bg', 'gui'), '#FFAF00') \ | let g:StatlnIdleBG = GuiColors(synIDattr(synIDtrans(hlID('Normal')), 'bg', 'gui'), '#222222') " Colored accent highlight changing based on the mode " Statusline: Left and right corners " TabLine: Active tab execute 'highlight StatlnPrimaryHL' \ . ' guifg=' . g:StatlnPrimaryFG \ . ' guibg=' . g:StatlnPrimaryColor \ . ' term=bold cterm=bold gui=bold' highlight! link TabLineActiveHL StatlnPrimaryHL " Primary highlight transitions for powerline seperators " Statusline: Left/right corners to adjacent " Tabline: Active <-> Idle tabs execute 'highlight StatlnPrimaryToSubtleHL guifg=' . g:StatlnSubtleBG . ' guibg=' . g:StatlnPrimaryColor highlight! link TabLineIdleToActiveHL StatlnPrimaryToSubtleHL execute 'highlight StatlnSubtleToPrimaryHL guifg=' . g:StatlnPrimaryColor . ' guibg=' . g:StatlnSubtleBG highlight! link TabLineActiveToIdleHL StatlnSubtleToPrimaryHL " Small Statusline: Center -> blank right side " TabLine: Active tab -> blank right side execute 'highlight TabLineActiveToBGHL guifg=' . g:StatlnPrimaryColor . ' guibg=' . g:StatlnIdleBG execute 'highlight StatlnPrimaryToIdleHL guifg=' . g:StatlnIdleBG . ' guibg=' . g:StatlnPrimaryColor " Secondary highlight " Statusline: Adjacent to corners " Tabline: Inactive (idle) tabs execute 'highlight StatlnSubtleHL guifg=' . g:StatlnSubtle . ' guibg=' . g:StatlnSubtleBG highlight! link TabLineIdleHL StatlnSubtleHL " Secondary highlight transitions for powerline seperators " StatusLine: Into/from the middle gap " Small StatusLine: Blank left side -> center " Tabline: Inactive tab -> blank right side execute 'highlight StatlnSubtleToIdleHL guifg=' . g:StatlnIdleBG . ' guibg=' . g:StatlnSubtleBG execute 'highlight StatlnIdleToPrimaryHL guifg=' . g:StatlnPrimaryColor . ' guibg=' . g:StatlnIdleBG execute 'highlight StatlnIdleToSubtleHL guifg=' . g:StatlnSubtleBG . ' guibg=' . g:StatlnIdleBG highlight! link TabLineIdleToBGHL StatlnIdleToSubtleHL " Tertiary highlight " StatusLine: Background of statusline and inactive buffers execute 'highlight StatlnIdleHL guifg=' . g:StatlnIdle ' guibg=' . g:StatlnIdleBG execute 'highlight StatlnIdleInverseHL guifg=' . g:StatlnIdleBG ' guibg=' . g:StatlnIdle endfunction " Sets primary color highlight for statusline and tabline, based on the mode " Updates the name of the mode in the statusline function! SetGlobalPrimaryColor() let l:mode = mode() " Returns vim's current mode if l:mode ==# 'n' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('String')), 'fg', 'gui'), '#b8bb26') let g:mode_str = 'NORMAL' " Light green elseif l:mode ==# 'i' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Function')), 'fg', 'gui'), '#83ADAD') let g:mode_str = 'INSERT' " Light blue elseif l:mode ==# 'R' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Error')), 'bg', 'gui'), '#D75F5F') let g:mode_str = 'REPLACE' " Light red elseif l:mode ==# 'v' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Keyword')), 'fg', 'gui'), '#D485AD') let g:mode_str = 'VISUAL' " Pink/light purple elseif l:mode ==# 'V' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Keyword')), 'fg', 'gui'), '#D485AD') let g:mode_str = "V-LINE" " Pink/light purple elseif l:mode ==# "\" let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Keyword')), 'fg', 'gui'), '#D485AD') let g:mode_str = "V-BLOCK" " Pink/light purple elseif l:mode ==# 's' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Special')), 'fg', 'gui'), '#85AD85') let g:mode_str = 'SELECT' " Turquoise elseif l:mode ==# 'c' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Special')), 'fg', 'gui'), '#85AD85') let g:mode_str = 'COMMAND' " Turquoise elseif l:mode ==# '!' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Special')), 'fg', 'gui'), '#85AD85') let g:mode_str = 'SHELL' " Turquoise elseif l:mode ==# 't' let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Special')), 'fg', 'gui'), '#85AD85') let g:mode_str = 'TERM' " Turquoise else let g:StatlnPrimaryColor = GuiColors(synIDattr(synIDtrans(hlID('Special')), 'fg', 'gui'), '#85AD85') let g:mode_str = 'UNKNOWN' " Turquoise endif endfunction " }}} " ======================================================== " # Statusline helper functions " ====================================================={{{ " Returns the current git branch, or an empty string function! StatlnGitBranch() let l:branch = system('git branch --show-current') if l:branch !~ ' ' return '  ' else return '' endif endfunction " Modified buffer indicator function! StatlnModified() let l:is_modified = getbufinfo(bufnr('%'))[0].changed if l:is_modified && &readonly let l:modified_marker = '[!]' " Ah! You modified a read-only buffer elseif l:is_modified let l:modified_marker = '[+]' elseif &readonly let l:modified_marker = '[-]' else let l:modified_marker = '' " No indicator for unmodified normal buffer endif return l:modified_marker endfunction " Set the primary status/tabline color and the mode string function! StatlnMode() call SetGlobalPrimaryColor() call ReloadStatlnColors() " Redraws tabline and updates the global mode color " Required to synchronize tabline and statusline properly set tabline=%!TabLine() return g:mode_str . ' ' endfunction " Upper estimate for the length of the active stausline, not inluding the " middle gap function! EstStatlnLength() let l:mode_len = 11 let l:buff_len = len(fnamemodify(bufname("%"), ':t')) + 7 let l:file_type_len = len(&filetype) + 6 let l:line_metrics_len = len(string(line('$'))) * 2 + 12 return l:mode_len + l:buff_len + l:file_type_len + l:line_metrics_len endfunction " }}} " ======================================================== " # Build and reload Statusline " ====================================================={{{ " Statusline for active window " " Switches to a compact version for narrow windows function! ActiveStatusline() " Update statusline on all events let l:track_mode='%{strpart(StatlnMode(), 0, 0)}' " Compact statusline ============================================ " Current buffer's name centered with mode-specific background color let l:left='%#StatlnIdleHL#' . '%{StatlnSmall("margin_left")}' \ . '%#StatlnIdleToPrimaryHL#' . '%{StatlnSmall("seperator")}' let l:buff='%#StatlnPrimaryHL#' . '%{StatlnSmall("file_name")}' \ . '%#StatlnPrimaryToIdleHL#' . '%{StatlnSmall("seperator")}' let l:right='%#StatlnIdleHL#' . '%{StatlnSmall("margin_right")}' let l:small_line = l:left . l:buff . l:right " Left side ===================================================== " Current mode bold and with a mode-specific background color let l:mode='%#StatlnPrimaryHL#' . '%{StatlnFull("mode")}' \ . '%#StatlnPrimaryToSubtleHL#' . '%{StatlnFull("seperator")}' " Current buffer's name and an indicator if it was modified let l:buff='%#StatlnSubtleHL#' . '%{StatlnFull("file_name")}' \ . '%#StatlnSubtleToIdleHL#' . '%{StatlnFull("seperator")}' let l:left_side = l:mode . l:buff . '%#StatlnIdleHL#' " Right side ==================================================== let l:trans_from_gap='%#StatlnIdleToSubtleHL#' . '%{StatlnFull("seperator")}' " File type in [] let l:file_type='%#StatlnSubtleHL#' . '%{StatlnFull("file_type")}' \ . '%#StatlnSubtleToPrimaryHL#' . '%{StatlnFull("seperator")}' " Scroll percentage, column, line / total lines, with mode-background color let l:line_metrics='%#StatlnPrimaryHL#%{StatlnFull("line_metrics")}' let l:right_side='%=' . l:trans_from_gap . l:file_type . l:line_metrics let l:full_line = l:left_side . l:right_side " Return all. Only one line with render at a time return l:track_mode . l:small_line . l:full_line endfunction " Returns component for the compact statusline " " Returns empty strings if the window is wide enough for a full sized " statusline function! StatlnFull(part) let l:is_small_window = winwidth(0) <= EstStatlnLength() - 18 if !l:is_small_window if 'mode' ==# a:part return ' ' . StatlnMode() elseif 'seperator' ==# a:part return '' elseif 'file_name' ==# a:part let l:file_name = fnamemodify(bufname('%'), ':t') " Blank buffer if len(l:file_name) == 0 let l:file_name = '[No Name]' endif return ' ' . l:file_name . ' ' . StatlnModified() elseif 'file_type' ==# a:part " Blank buffer if len(&filetype) == 0 return '' endif return '[' . &filetype . ']' elseif 'line_metrics' ==# a:part let l:total = line('$') let l:current = line('.') let l:frac = ' ' . l:current . '/' . l:total . ' ' let l:col = printf('%2S', col('.')) let l:percent = float2nr(l:current * 100 / l:total) . '% ☰ ' return l:percent . l:col . l:frac else echom 'Error: a:part for the full statusline doesn''t match any part' return '' endif else " Part indicated shouldn't render, since the compact statusline should " be rendering instead return '' endif endfunction " Returns component for full sized statusline " " Returns empty strings if the window is too narrow for a full sized " statusline function! StatlnSmall(part) let l:is_small_window = winwidth(0) <= EstStatlnLength() - 18 if l:is_small_window if 'margin_left' ==# a:part return repeat('—', 7) . ' ' elseif 'margin_right' ==# a:part let l:len = winwidth(0) \ - strchars(StatlnSmall('margin_left')) \ - strchars(StatlnSmall('file_name')) \ - 3 "Unclear where this magical constant appears return ' ' . repeat('—', l:len - 1) elseif 'seperator' ==# a:part return '' elseif 'file_name' ==# a:part return ' ' . fnamemodify(bufname("%"), ':t') . ' ' . StatlnModified() else echom 'Error: a:part for the compact statusline doesn''t match any part' return '' endif else " Part shouldn't render since the window is wide enough for the full " statusline to render instead return '' endif endfunction " Status line for all windows except the focused window " " Transparent background with em-dash margins around the buffer's name function! IdleStatusline() call ReloadStatlnColors() set fillchars=stlnc:— " All empty space filled with em-dashes " Left padding to align file name with active stl. " Same background as editor makes it very minimalist return '%#StatlnIdleHL#—————————— %t %{StatlnModified()} ' endfunction augroup SetStatusLine autocmd! au BufEnter,WinEnter * let &l:stl = ActiveStatusline() au BufLeave,WinLeave * let &l:stl = IdleStatusline() " Updates status/tabline when entering command prompt au CmdlineEnter * redraw augroup end " }}} " Further reading: " https://shapeshed.com/vim-statuslines/ " https://www.reddit.com/r/vim/comments/ld8h2j/i_made_a_status_line_from_scratch_no_plugins_used/