duochrome gym

tuesday, 7 january 2020

vim-colors-duochrome had ended my distraction free colorscheme search and become the only vim colorscheme i use for coding and writing. This duochromatic light colorscheme begged for a properly tweaked dark colorscheme counterpart and diff configuration replacement for the vim-quantum and vim-one colorschemes used for such.

Tweaking the colorscheme was rote enough given enough iterations to find colours i could live with. The real effort consumed during this process was maintaining the theme.vim plugin with the various hex colour palette changes for dynamic colour column, window borders, statusline, indent highlighting, cursorline and other dynamic context decorations – the traditional way for augmenting a colorscheme, with external context related highlight commands.

colour optimization

or rather, code optimization. Moving the context rules from the theme and user interface control .vimrc plugins to the colorscheme plugin itself (rendering it an non-standard colorscheme file) reduced the vim configuration significantly by removing colour values, highlight commands and the associated display control logic with..

if !exists('g:duochrome_cursorline') | let g:duochrome_cursorline = 0 | endif if !exists('g:duochrome_insert') | let g:duochrome_insert = 0 | endif if !exists('g:duochrome_markdown') | let g:duochrome_markdown = 0 | endif if !exists('g:duochrome_relative') | let g:duochrome_relative = 0 | endif if !exists('g:duochrome_ruler') | let g:duochrome_ruler = 0 | endif if !exists('g:duochrome_split') | let g:duochrome_split = 0 | endif if !has('gui_running') | let g:duochrome_cursorline = 1 | endif

where,

global variable 0 1 2
duochrome_cursorline dfm highlight underline
duochrome_insert normal mode insert mode  
duochrome_markdown code markdown  
duochrome_relative line number relative number  
duochrome_ruler column off cursor column fixed column
duochrome_split single window split windows  

Context toggles of the global variables in the .vimrc file (actually, the vim-duochrome plugin) can now be magically interpreted by the colorscheme..

cursorline

highlighting is differentiated for code, markdown and diff, whether in normal or insert mode..

if empty($DISPLAY) call s:h('CursorLine', { 'cterm': 'underline' }) elseif g:duochrome_insert && g:duochrome_markdown if g:duochrome_cursorline == 2 call s:h('CursorLine', { 'fg': s:high_contrast, 'gui': 'underline' }) else call s:h('CursorLine', { 'fg': s:high_contrast, 'bg': g:duochrome_cursorline ? s:cursor_line : s:bg }) endif elseif g:duochrome_cursorline == 2 call s:h('CursorLine', { 'gui': 'underline' }) else call s:h('CursorLine', { 'bg': g:duochrome_cursorline ? s:cursor_line : s:bg }) endif

Note: s:h() is a function (borrowed from vim-hemisu) that sets the vim highlight command. Refer to the plugin source.

line numbering

to show current line number only or relative line numbers only..

if g:duochrome_relative call s:h('CursorLineNr', { 'fg': s:bg }) call s:h('LineNr', { 'fg': s:blue }) else call s:h('CursorLineNr', { 'fg': g:duochrome_insert ? s:bg : s:blue }) call s:h('LineNr', { 'fg': s:bg }) endif

diff mode

if &diff call s:h('DiffAdd', { 'bg': s:statusline, 'fg': s:green }) call s:h('DiffDelete', { 'bg': s:statusline, 'fg': s:red }) call s:h('DiffChange', { 'bg': s:statusline, 'fg': s:yellow }) call s:h('DiffText', { 'bg': s:statusline, 'fg': s:constant }) else call s:h('DiffAdd', { 'fg': s:green }) call s:h('DiffDelete', { 'fg': s:red }) call s:h('DiffChange', { 'fg': s:yellow }) call s:h('DiffText', { 'fg': s:constant }) endif

statusline

highlight becomes a visual window separator as well when there are split windows..

call s:h('StatusLine', { 'bg': s:statusline, 'fg': s:norm_subtle }) call s:h('User1', { 'bg': g:duochrome_split ? s:statusline : s:bg, 'fg': s:norm_subtle }) call s:h('User2', { 'bg': g:duochrome_split ? s:statusline : s:bg, 'fg': s:norm_very_subtle }) call s:h('User3', { 'bg': g:duochrome_split ? s:statusline : s:bg, 'fg': s:red }) call s:h('StatusLineNC', { 'bg': g:duochrome_split ? s:statusline : s:bg })

column ruler

call s:h('ColorColumn', { 'bg': g:duochrome_ruler == 1 ? s:column : s:guide })

code coupling

the remainder of the vim-duochrome plugin contains the theme and user interface rules (autocmds) for dynamically setting the colorscheme and statusline based on the context or manual keymap toggle applied as per my personal distraction free workflow..

DuoChrome

The beauty of this approach is, while coupling the colorscheme to the plugin logic (a defiance of colorscheme norms), the preservation of session state information permits toggling between light and dark background themes with a single vim command (versus the former approach requiring external highlight initialization and keeping track of what context highlight is at play).

Toggling a display attribute simply requires a background refresh and any other display attributes are handled accordingly simplifying the plugin logic enormously. Hence, the binding of the theme.vim, ui.vim and duochrome.vim plugins into a single plugin creating a dynamic colorscheme (as opposed to the traditional static colorscheme).

At the same time, runtime initialization of the global variables to sane defaults, still allows this colorscheme to be used simply as a traditional static vim colorscheme. In this case, a user need only copy the colorscheme file to their vim colors folder (versus loading the complete plugin and its dependencies).

»»  gotchas

comment ?