diff options
Diffstat (limited to 'plugin/statusryne.vim')
-rw-r--r-- | plugin/statusryne.vim | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/plugin/statusryne.vim b/plugin/statusryne.vim new file mode 100644 index 0000000..54dfac3 --- /dev/null +++ b/plugin/statusryne.vim @@ -0,0 +1,428 @@ +" Vim Plugin + +if exists("g:statusryne") || &cp + finish +endif + +let s:keepcpo = &cpo +set cpo&vim + +" Statusline {{{ +" Always show statusline. +set laststatus=2 +" Don't additionally show mode underneath statusline. +set noshowmode + +" Mode Dict {{{ +let g:currentmode={ + \ 'n' : 'NORMAL', + \ 'no' : 'N-PENDING', + \ 'v' : 'VISUAL', + \ 'V' : 'V-LINE', + \ '\<C-V>' : 'V Block', + \ 's' : 'SELECT', + \ 'S' : 'S-LINE', + \ '\<C-S>' : 'S-BLOCK', + \ 'i' : 'INSERT', + \ 'R' : 'REPLACE', + \ 'Rv' : 'V-REPLACE', + \ 'c' : 'COMMAND', + \ 'cv' : 'VIM-EX', + \ 'ce' : 'EX', + \ 'r' : 'PROMPT', + \ 'rm' : 'MORE', + \ 'r?' : 'CONFIRM', + \ '!' : 'SHELL', + \ 't' : 'TERMINAL' + \} +" }}} +" (f) Git Info {{{ +let b:git_info = '' + +augroup GetGitBranch + autocmd! + autocmd BufEnter,BufWritePost * let b:git_info = GitInfo() +augroup END + +function! GitInfo() + + let git = '' + let git_cmd = 'git -C ' . expand('%:p:h') + + let branch_cmd = git_cmd . ' rev-parse --abbrev-ref HEAD 2> /dev/null' + let branch = system(branch_cmd) + + " git puts strange characters on branch output. Sanitise output, remove + " non-printable characters, i.e. those in ascii range ~ (tilde) to - + " (minus). + let branch = substitute(branch, '[^ -~]\+', '', '') + + " Get more information if in a git repo. + if branch != '' + let git .= ' ' + let git .= '(' . branch . ')' + + " Could be a new file in a git repo with no name yet. + if expand('%:p') != '' + let stats_cmd = git_cmd . ' diff --numstat ' . expand('%:p' ) + let stats = system(stats_cmd) + + " Could be a non-tracked file. Then there are no stats. + if stats != '' + " Parse. + let stats_pattern = '^\([0-9]*\)\s*\([0-9]*\).*$' + let stats = substitute(stats, stats_pattern, '\1(+) \2(-)', '') + " Truncate. + let stats = stats[0:14] + let git .= ' ' . stats + endif + endif + endif + + return git +endfunction +" }}} +" (f) Colours {{{ +" 'bg' is text colour, 'fg' is the bar colour. +" +hi StatusLine ctermbg=010 +hi StatusLine ctermfg=007 + +hi StatusLineExtra ctermbg=014 +hi StatusLineExtra ctermfg=007 + +hi StatusLineMode ctermfg=015 + +" Automatically change the statusline color depending on mode. +function! ChangeStatuslineColor() + if (mode() =~# '\v(n|no)') + " Normal Mode. + exe 'hi! StatusLineMode ctermbg=010' + elseif (mode() =~# '\v(v|V)') +" Visual Mode. + exe 'hi! StatusLineMode ctermbg=005' + elseif (mode() ==# 'i') +" Insert Mode. + exe 'hi! StatusLineMode ctermbg=004' + else +" Other Mode. + exe 'hi! StatusLineMode ctermbg=010' + endif + + return '' +endfunction +" }}} +" (f) Buffer Statistics {{{ +let b:buf_stats = '' + +augroup GetFileStats + autocmd! + autocmd BufEnter,BufWritePost * let b:buf_stats = FileStats() +augroup END + +function! FileStats() + + let stats = '' + + " If buffer hasn't been written yet, don't get size. + if str2float(getfsize(expand('%:p'))) > 0 + + " Buffer size. + " let bytes = str2float(getfsize(expand('%:p'))) + + " if bytes <= 0 + " return '0' + " endif + + " for size in ["B", "K", "M", "G"] + " if (abs(bytes) < 1000) + " return string(float2nr(round(bytes))) . size + " endif + " let bytes = bytes / 1000 + " endfor + + " Using system utils + let size_cmd = 'du -sh ' . expand('%:p') + let size = system(size_cmd) + " Parse. + let size_pattern = '^\(\S*\).*$' + let size = substitute(size, size_pattern, '\1', '') + + " Word and character count. + let counts_cmd = 'wc -mw ' . expand('%:p') + let counts = system(counts_cmd) + " Parse. + let counts_pattern = '^\s*\([0-9]*\)\s*\([0-9]*\).*$' + let counts = substitute(counts, counts_pattern, '\1(w) \2(c)', '') + + let stats = counts . ' ' . size + + endif + + return stats + +endfunction +" }}} +" (f) Read Only {{{ +let b:readonly_flag = "" + +augroup ReadOnlyStatus + autocmd! + autocmd BufEnter,WinEnter * let b:readonly_flag = ReadOnly() +augroup END + + +function! ReadOnly() + + if &readonly || !&modifiable + return "[READ ONLY]" + else + return "" + +endfunction +" }}} +" (f) File Name {{{ +" Change how much of the filename is displayed based on available terminal. +" space. + +let b:filename = "" + +augroup FileName + autocmd! + autocmd BufEnter,VimResized * let b:filename = FileName() +augroup END + + +function! FileName() + + let fullname = expand("%:p") + + if (fullname == "") + return ' [New]' + endif + + " See how much space is being occupied by the rest of the statusline + " elements. + let remainder = + \ 25 + \ + len(&filetype) + \ + len(&fenc) + \ + len(g:currentmode[mode()]) + \ + len(get(b:, 'git_info', '')) + \ + len(get(b:, 'readonly_flag', '')) + \ + len(get(b:, 'buf_stats', '')) + + " If the full name doesn't fit, then use a shorter one. + " Cases: + " 1) Show full path. + " 2) Show only first character of every directory in path. + " 3) Show only basename. + + if (&columns > len(fullname) + remainder) + + let shortpath = substitute(fullname, $HOME, '~', "") + return ' ' . shortpath + + elseif (&columns > len(pathshorten(fullname)) + remainder) + + let home = pathshorten($HOME . '/') + let shortpath = substitute(pathshorten(fullname), home, '~/', "") + return ' ' . shortpath + + else + return ' ' . expand("%:t") + endif + +endfunction +" }}} + +" Status Line Format String. +set statusline= +set statusline+=%{ChangeStatuslineColor()} +set statusline+=%#StatusLineMode# " Set colour. +set statusline+=\ %{g:currentmode[mode()]} " Get Mode. +set statusline+=\ %* " Default colour. +set statusline+=%{get(b:,'filename','')} " Filename. +set statusline+=%{get(b:,'git_info','')} " Git branch. +set statusline+=%{get(b:,'readonly_flag','')} " Readonly flag. +set statusline+=\ %* " Default colour. + +set statusline+=\ %= " Right Side. +set statusline+=\ %3(%{get(b:,'buf_stats','')}%) " File size. +set statusline+=\ %#StatusLineExtra# " Set colour. +set statusline+=\ %<[%{substitute(&spelllang,'_..','','g')}] " Spell Language. +set statusline+=%{(&filetype!=''?'\ ['.&filetype.']':'')} " FileType. +set statusline+=\ %#StatusLineMode# " Set colour. +set statusline+=\ %3p%% " Percentage. +set statusline+=\ %3l/%-3L:%-3c\ " Line/Column Numbers. +" }}} +" Tab Line {{{ +" Only show tabline if there are two or more tabs. +set showtabline=1 +set tabpagemax=10 +set tabline=%!TabLine() + +" Colours and Configurations {{{ +let g:padding = 2 +let g:mintablabellen = 5 + +hi TabLineSel ctermfg=007 cterm=None +hi TabLineSel ctermbg=010 cterm=None + +hi TabLineNum ctermfg=015 cterm=None +hi TabLineNum ctermbg=014 cterm=None + +hi TabLineBuffer ctermbg=014 +hi TabLineBuffer ctermfg=007 + +hi TabLine cterm=None +hi TabLineFill cterm=None +" }}} +" (f) LabelName {{{ +function! LabelName(n) + " Decide label name for n'th buffer. + + let b:buftype = getbufvar(a:n, "&buftype") + + if b:buftype ==# 'help' + " Show help page name and strip trailing '.txt'. + let label = '[H] ' . fnamemodify(bufname(a:n), ':t:s/.txt$//') + + elseif b:buftype ==# 'quickfix' + let label = '[Q]' + + elseif bufname(a:n) != '' + " Only show basename (with extension) for regular files. + let label = " " . fnamemodify(bufname(a:n), ':t') + + else + let label = "[New]" + + endif + + return label + +endfunction +" }}} +" (f) Maxlen {{{ +function! MaxLen(iterable) + let maxlen = 0 + for item in a:iterable + if len(item) > maxlen + let maxlen = len(item) + endif + endfor + return maxlen +endfunction +" }}} +" (f) TabLine {{{ +function! TabLine() + " Set the format string for the tabline. + + " Explainer {{{ + " The main complexity in the following code arises due to the requirement to + " have equally spaced tab labels. It means that we need to find what will be + " visually displayed first (the chars printed to screen with spacing) to + " find out how long each tab label will be and then go back over the buffer + " list to add formatting strings (i.e. colour). If we did not do this, the + " formatting strings would be included in the calculation of the length of + " the tab labels, even though they don't take up any visual space. + " + " Example: + " The format string + " + " '%1T%#TabLineSel#%#TabLineSel# %#TabLineSel# vimrc %#TabLineBuffer# .tmux.conf %2T%#TabLine# [H] eval %#TabLineFill#%T' + " + " takes up 141 chars, but will only display + " + " ' vimrc .tmux.conf [H] eval ' + " + " taking up 54 chars. + " }}} + " Get maximum length tab label {{{ + + " Get all labels. + let g:tablabels = [] + for t in range(tabpagenr('$')) + let g:tablabel = "" + for bufnum in tabpagebuflist(t + 1) + let g:tablabel .= LabelName(bufnum) + endfor + call add(g:tablabels, g:tablabel) + endfor + + " Find maximal length. + " For equal with tabs, fitted to longest tab label. + let g:maxlabellen = max([g:mintablabellen, MaxLen(g:tablabels)]) + " For full screen width equal width tabs. + " let g:maxlabellen = &columns / tabpagenr('$') + + " }}} + + let tablfmt = '' + + " Iter over tabs. + " Here we set the format strings, for correct colouring, we need to do it in + " the following order: + " '<colour><padding><buflabel>[[ <colour> <buflabel>]]*<padding>' + + for t in range(tabpagenr('$')) + + " New tab label begins here. + let tablfmt .= '%' . (t+1) . 'T' + + " Set highlight. + " #TabLineSel for selected tab, #TabLine otherwise. + let tablfmt .= (t+1 == tabpagenr() ? '%#TabLineSel#' : '%#TabLine#') + + " Get buffer names and statuses. + " Buffer names with formatting strings, colours etc. + let t:labelfmt = '' + " Number of buffers in tab. + let t:bcount = len(tabpagebuflist(t+1)) + " Total amount of whitespace to fill, after considering curent tab label. + let t:remainder = g:maxlabellen - len(g:tablabels[t]) + let t:pad = t:remainder /2 + g:padding + + " Iter over buffers in tab. + for bnum in tabpagebuflist(t+1) + + " Set colour. + if t+1 == tabpagenr() + " If on current buffer in current tab, set bg colour dark. + let bcolour = (bnum == bufnr("%") ? '%#TabLineSel#' : '%#TabLineBuffer#') + else + " If not on current tab, leave default bg colour. + let bcolour = '' + endif + + " Put padding before first buffer name in tab. + if bnum == tabpagebuflist(t+1)[0] + let t:labelfmt .= bcolour . repeat(" ", t:pad) + endif + + let t:labelfmt .= bcolour . LabelName(bnum) + + " Don't add final space to buffer name. + if t:bcount > 1 + let t:labelfmt .= ' ' + endif + let t:bcount -= 1 + + endfor + + let t:labelfmt .= repeat(" ", t:pad) + let tablfmt .= t:labelfmt + + endfor + + " Fill to end. + let tablfmt .= '%#TabLineFill#%T' + + return tablfmt +endfunction +" }}} +" }}} + +let &cpo = s:keepcpo +unlet s:keepcpo |