vim-airline/autoload/airline/highlighter.vim

320 lines
11 KiB
VimL
Raw Normal View History

2020-01-06 10:22:49 +08:00
" MIT License. Copyright (c) 2013-2020 Bailey Ling Christian Brabandt et al.
" vim: et ts=2 sts=2 sw=2
2013-08-17 20:50:07 +08:00
scriptencoding utf-8
let s:is_win32term = (has('win32') || has('win64')) &&
\ !has('gui_running') &&
\ (empty($CONEMUBUILD) || &term !=? 'xterm') &&
\ empty($WT_SESSION) &&
\ !(exists("+termguicolors") && &termguicolors)
let s:separators = {}
let s:accents = {}
let s:hl_groups = {}
2013-08-17 20:50:07 +08:00
function! s:gui2cui(rgb, fallback) abort
2013-08-21 09:27:00 +08:00
if a:rgb == ''
return a:fallback
elseif match(a:rgb, '^\%(NONE\|[fb]g\)$') > -1
return a:rgb
2013-08-21 09:27:00 +08:00
endif
let rgb = map(split(a:rgb[1:], '..\zs'), '0 + ("0x".v:val)')
return airline#msdos#round_msdos_colors(rgb)
2013-08-21 09:27:00 +08:00
endfunction
function! s:group_not_done(list, name) abort
if index(a:list, a:name) == -1
call add(a:list, a:name)
return 1
else
if &vbs
echomsg printf("airline: group: %s already done, skipping", a:name)
endif
return 0
endif
endfu
function! s:get_syn(group, what, mode) abort
let color = ''
if hlexists(a:group)
let color = synIDattr(synIDtrans(hlID(a:group)), a:what, a:mode)
endif
if empty(color) || color == -1
" should always exist
let color = synIDattr(synIDtrans(hlID('Normal')), a:what, a:mode)
" however, just in case
if empty(color) || color == -1
let color = 'NONE'
endif
endif
return color
endfunction
function! s:get_array(guifg, guibg, ctermfg, ctermbg, opts) abort
return [ a:guifg, a:guibg, a:ctermfg, a:ctermbg, empty(a:opts) ? '' : join(a:opts, ',') ]
endfunction
function! airline#highlighter#reset_hlcache() abort
let s:hl_groups = {}
endfunction
function! airline#highlighter#get_highlight(group, ...) abort
" only check for the cterm reverse attribute
" TODO: do we need to check all modes (gui, term, as well)?
let reverse = synIDattr(synIDtrans(hlID(a:group)), 'reverse', 'cterm')
if get(g:, 'airline_highlighting_cache', 0) && has_key(s:hl_groups, a:group)
let res = s:hl_groups[a:group]
return reverse ? [ res[1], res[0], res[3], res[2], res[4] ] : res
else
let ctermfg = s:get_syn(a:group, 'fg', 'cterm')
let ctermbg = s:get_syn(a:group, 'bg', 'cterm')
let guifg = s:get_syn(a:group, 'fg', 'gui')
let guibg = s:get_syn(a:group, 'bg', 'gui')
2017-09-01 17:25:37 +08:00
let bold = synIDattr(synIDtrans(hlID(a:group)), 'bold')
2019-01-17 21:34:19 +08:00
if reverse
let res = s:get_array(guibg, guifg, ctermbg, ctermfg, bold ? ['bold'] : a:000)
2019-01-17 21:34:19 +08:00
else
let res = s:get_array(guifg, guibg, ctermfg, ctermbg, bold ? ['bold'] : a:000)
2017-09-01 17:25:37 +08:00
endif
endif
let s:hl_groups[a:group] = res
return res
endfunction
function! airline#highlighter#get_highlight2(fg, bg, ...) abort
let guifg = s:get_syn(a:fg[0], a:fg[1], 'gui')
let guibg = s:get_syn(a:bg[0], a:bg[1], 'gui')
let ctermfg = s:get_syn(a:fg[0], a:fg[1], 'cterm')
let ctermbg = s:get_syn(a:bg[0], a:bg[1], 'cterm')
return s:get_array(guifg, guibg, ctermfg, ctermbg, a:000)
endfunction
function! s:hl_group_exists(group) abort
if !hlexists(a:group)
return 0
elseif empty(synIDattr(hlID(a:group), 'fg'))
return 0
endif
return 1
endfunction
function! airline#highlighter#exec(group, colors) abort
if pumvisible()
return
endif
2013-08-17 20:50:07 +08:00
let colors = a:colors
if s:is_win32term
2013-08-21 09:27:00 +08:00
let colors[2] = s:gui2cui(get(colors, 0, ''), get(colors, 2, ''))
let colors[3] = s:gui2cui(get(colors, 1, ''), get(colors, 3, ''))
2013-08-17 20:50:07 +08:00
endif
let old_hi = airline#highlighter#get_highlight(a:group)
if len(colors) == 4
call add(colors, '')
endif
let new_hi = [colors[0], colors[1], printf('%s', colors[2]), printf('%s', colors[3]), colors[4]]
let colors = s:CheckDefined(colors)
if old_hi != new_hi || !s:hl_group_exists(a:group)
let cmd = printf('hi %s%s', a:group, s:GetHiCmd(colors))
exe cmd
if has_key(s:hl_groups, a:group)
let s:hl_groups[a:group] = colors
endif
endif
endfunction
function! s:CheckDefined(colors) abort
" Checks, whether the definition of the colors is valid and is not empty or NONE
" e.g. if the colors would expand to this:
" hi airline_c ctermfg=NONE ctermbg=NONE
" that means to clear that highlighting group, therefore, fallback to Normal
" highlighting group for the cterm values
" This only works, if the Normal highlighting group is actually defined, so
" return early, if it has been cleared
if !exists("g:airline#highlighter#normal_fg_hi")
let g:airline#highlighter#normal_fg_hi = synIDattr(synIDtrans(hlID('Normal')), 'fg', 'cterm')
endif
2017-03-14 01:50:19 +08:00
if empty(g:airline#highlighter#normal_fg_hi) || g:airline#highlighter#normal_fg_hi < 0
return a:colors
endif
for val in a:colors
if !empty(val) && val !=# 'NONE'
return a:colors
endif
endfor
" this adds the bold attribute to the term argument of the :hi command,
" but at least this makes sure, the group will be defined
let fg = g:airline#highlighter#normal_fg_hi
let bg = synIDattr(synIDtrans(hlID('Normal')), 'bg', 'cterm')
if bg < 0
" in case there is no background color defined for Normal
let bg = a:colors[3]
endif
return a:colors[0:1] + [fg, bg] + [a:colors[4]]
endfunction
function! s:GetHiCmd(list) abort
" a:list needs to have 5 items!
let res = ''
let i = -1
while i < 4
let i += 1
let item = get(a:list, i, '')
if item is ''
continue
endif
if i == 0
let res .= ' guifg='.item
elseif i == 1
let res .= ' guibg='.item
elseif i == 2
let res .= ' ctermfg='.item
elseif i == 3
let res .= ' ctermbg='.item
elseif i == 4
let res .= printf(' gui=%s cterm=%s term=%s', item, item, item)
endif
endwhile
return res
2013-08-17 20:50:07 +08:00
endfunction
function! s:exec_separator(dict, from, to, inverse, suffix) abort
if pumvisible()
return
endif
let group = a:from.'_to_'.a:to.a:suffix
let l:from = airline#themes#get_highlight(a:from.a:suffix)
let l:to = airline#themes#get_highlight(a:to.a:suffix)
if a:inverse
let colors = [ l:from[1], l:to[1], l:from[3], l:to[3] ]
else
let colors = [ l:to[1], l:from[1], l:to[3], l:from[3] ]
endif
let a:dict[group] = colors
call airline#highlighter#exec(group, colors)
2013-08-17 20:50:07 +08:00
endfunction
function! airline#highlighter#load_theme() abort
if pumvisible()
return
endif
for winnr in filter(range(1, winnr('$')), 'v:val != winnr()')
call airline#highlighter#highlight_modified_inactive(winbufnr(winnr))
endfor
Fixed bug where highlighting on inactive windows wouldn't refresh. This seems to be an omission/regression from #afb75adc, where inactive highlight updating was accidentally removed when fixing another bug. Solution: Add back the deleted statement. closes #1339 Repro steps: 1. Install some theme that depends on the background color (Soares/base16.nvim has a bunch) 2. `set background=dark` in your vimrc, and `colorscheme` one of the aforementioned schemes. 3. Open a split window. Note the colors on the inactive window's airline. 4. `set background=light` manually. note the colors on the inactive window's airline. Note how they have not updated. (In particular, airline_c_inactive has updated, but all the other inactive groups have not.) 5. Enter the inactive window. Exit the inactive window. Observe that the colors are now correct (showing that it is in fact a problem with the airline load_theme code, and not with the theme). It seems strange that the code as written only expects airline_c_inactive to have styling; perhaps there is some norm that themes are supposed to handle inactive windows in a particular way? For the record, my theme dis omething like this: ``` let s:IA1 = s:airlist('similar1', 'similar2') let s:IA2 = s:airlist('similar1', 'similar2') let s:IA3 = s:airlist('similar1', 'similar2') let g:airline#themes#{s:palette}#palette.inactive = airline#themes#generate_color_map(s:IA1, s:IA2, s:IA3) let g:airline#themes#{s:palette}#palette.inactive.airline_warning = s:airlist('base', 'contrast3') let g:airline#themes#{s:palette}#palette.inactive.airline_error = s:airlist('base', 'antibase') ```
2016-11-27 05:22:46 +08:00
call airline#highlighter#highlight(['inactive'])
if getbufvar( bufnr('%'), '&modified' )
call airline#highlighter#highlight(['normal', 'modified'])
else
call airline#highlighter#highlight(['normal'])
endif
endfunction
2013-08-17 20:50:07 +08:00
function! airline#highlighter#add_separator(from, to, inverse) abort
let s:separators[a:from.a:to] = [a:from, a:to, a:inverse]
call <sid>exec_separator({}, a:from, a:to, a:inverse, '')
endfunction
function! airline#highlighter#add_accent(accent) abort
let s:accents[a:accent] = 1
endfunction
function! airline#highlighter#highlight_modified_inactive(bufnr) abort
if getbufvar(a:bufnr, '&modified')
let colors = exists('g:airline#themes#{g:airline_theme}#palette.inactive_modified.airline_c')
\ ? g:airline#themes#{g:airline_theme}#palette.inactive_modified.airline_c : []
else
let colors = exists('g:airline#themes#{g:airline_theme}#palette.inactive.airline_c')
\ ? g:airline#themes#{g:airline_theme}#palette.inactive.airline_c : []
endif
if !empty(colors)
call airline#highlighter#exec('airline_c'.(a:bufnr).'_inactive', colors)
endif
endfunction
function! airline#highlighter#highlight(modes, ...) abort
let bufnr = a:0 ? a:1 : ''
let p = g:airline#themes#{g:airline_theme}#palette
" draw the base mode, followed by any overrides
let mapped = map(a:modes, 'v:val == a:modes[0] ? v:val : a:modes[0]."_".v:val')
let suffix = a:modes[0] == 'inactive' ? '_inactive' : ''
let airline_grouplist = []
let buffers_in_tabpage = sort(tabpagebuflist())
if exists("*uniq")
let buffers_in_tabpage = uniq(buffers_in_tabpage)
endif
" mapped might be something like ['normal', 'normal_modified']
" if a group is in both modes available, only define the second
" that is how this was done previously overwrite the previous definition
for mode in reverse(mapped)
if exists('g:airline#themes#{g:airline_theme}#palette[mode]')
let dict = g:airline#themes#{g:airline_theme}#palette[mode]
for kvp in items(dict)
let mode_colors = kvp[1]
let name = kvp[0]
if name is# 'airline_c' && !empty(bufnr) && suffix is# '_inactive'
let name = 'airline_c'.bufnr
endif
" do not re-create highlighting for buffers that are no longer visible
" in the current tabpage
if name =~# 'airline_c\d\+'
2018-11-08 19:24:02 +08:00
let bnr = matchstr(name, 'airline_c\zs\d\+') + 0
if bnr > 0 && index(buffers_in_tabpage, bnr) == -1
continue
endif
elseif (name =~# '_to_') || (name[0:10] is# 'airline_tab' && !empty(suffix))
" group will be redefined below at exec_separator
" or is not needed for tabline with '_inactive' suffix
" since active flag is 1 for builder)
continue
endif
if s:group_not_done(airline_grouplist, name.suffix)
call airline#highlighter#exec(name.suffix, mode_colors)
endif
if !has_key(p, 'accents')
" work around a broken installation
" shouldn't actually happen, p should always contain accents
continue
endif
for accent in keys(s:accents)
if !has_key(p.accents, accent)
continue
endif
let colors = copy(mode_colors)
if p.accents[accent][0] != ''
let colors[0] = p.accents[accent][0]
endif
if p.accents[accent][2] != ''
let colors[2] = p.accents[accent][2]
endif
if len(colors) >= 5
let colors[4] = get(p.accents[accent], 4, '')
else
call add(colors, get(p.accents[accent], 4, ''))
endif
if s:group_not_done(airline_grouplist, name.suffix.'_'.accent)
call airline#highlighter#exec(name.suffix.'_'.accent, colors)
endif
endfor
endfor
2013-08-17 20:50:07 +08:00
if empty(s:separators)
" nothing to be done
continue
endif
" TODO: optimize this
for sep in items(s:separators)
" we cannot check, that the group already exists, else the separators
" might not be correctly defined. But perhaps we can skip above groups
" that match the '_to_' name, because they would be redefined here...
call <sid>exec_separator(dict, sep[1][0], sep[1][1], sep[1][2], suffix)
endfor
endif
endfor
2013-08-17 20:50:07 +08:00
endfunction