dotfiles/vim/.vim/plugin/statusbars/statusline.vim
Akemi Izuko de244f9ea7
Init again
The dotfiles are back
2023-12-23 20:13:47 -07:00

355 lines
13 KiB
VimL

" 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'), '#AFAF00')
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 ==# "\<C-v>"
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/