2020-01-06 10:22:49 +08:00
|
|
|
" MIT License. Copyright (c) 2013-2020 Bailey Ling Christian Brabandt et al.
|
2013-08-18 01:35:06 +08:00
|
|
|
" vim: et ts=2 sts=2 sw=2
|
2013-08-17 20:50:07 +08:00
|
|
|
|
2016-09-24 08:16:30 +08:00
|
|
|
scriptencoding utf-8
|
|
|
|
|
2017-06-21 21:43:43 +08:00
|
|
|
let s:is_win32term = (has('win32') || has('win64')) &&
|
|
|
|
\ !has('gui_running') &&
|
|
|
|
\ (empty($CONEMUBUILD) || &term !=? 'xterm') &&
|
2020-12-04 16:43:01 +08:00
|
|
|
\ empty($WT_SESSION) &&
|
2017-06-21 21:43:43 +08:00
|
|
|
\ !(exists("+termguicolors") && &termguicolors)
|
2015-03-06 22:42:04 +08:00
|
|
|
|
2013-08-24 21:40:20 +08:00
|
|
|
let s:separators = {}
|
2013-11-01 12:54:10 +08:00
|
|
|
let s:accents = {}
|
2017-08-11 17:26:35 +08:00
|
|
|
let s:hl_groups = {}
|
2013-08-17 20:50:07 +08:00
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! s:gui2cui(rgb, fallback) abort
|
2013-08-21 09:27:00 +08:00
|
|
|
if a:rgb == ''
|
|
|
|
return a:fallback
|
2016-01-28 03:06:22 +08:00
|
|
|
elseif match(a:rgb, '^\%(NONE\|[fb]g\)$') > -1
|
2016-01-28 02:12:54 +08:00
|
|
|
return a:rgb
|
2013-08-21 09:27:00 +08:00
|
|
|
endif
|
2016-01-28 03:06:22 +08:00
|
|
|
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
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! s:group_not_done(list, name) abort
|
2018-11-07 21:25:40 +08:00
|
|
|
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
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! s:get_syn(group, what, mode) abort
|
2017-02-21 03:24:43 +08:00
|
|
|
let color = ''
|
|
|
|
if hlexists(a:group)
|
2020-10-27 04:16:31 +08:00
|
|
|
let color = synIDattr(synIDtrans(hlID(a:group)), a:what, a:mode)
|
2013-09-02 10:57:32 +08:00
|
|
|
endif
|
|
|
|
if empty(color) || color == -1
|
2020-10-27 04:16:31 +08:00
|
|
|
" should always exist
|
|
|
|
let color = synIDattr(synIDtrans(hlID('Normal')), a:what, a:mode)
|
2017-02-21 03:24:43 +08:00
|
|
|
" however, just in case
|
|
|
|
if empty(color) || color == -1
|
|
|
|
let color = 'NONE'
|
|
|
|
endif
|
2013-09-02 10:57:32 +08:00
|
|
|
endif
|
|
|
|
return color
|
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
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, ',') ]
|
2013-09-02 10:57:32 +08:00
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! airline#highlighter#reset_hlcache() abort
|
2017-08-11 17:26:35 +08:00
|
|
|
let s:hl_groups = {}
|
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
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')
|
2017-08-14 14:06:53 +08:00
|
|
|
if get(g:, 'airline_highlighting_cache', 0) && has_key(s:hl_groups, a:group)
|
2018-10-16 18:02:44 +08:00
|
|
|
let res = s:hl_groups[a:group]
|
|
|
|
return reverse ? [ res[1], res[0], res[3], res[2], res[4] ] : res
|
2017-08-11 17:26:35 +08:00
|
|
|
else
|
2020-10-27 04:16:31 +08:00
|
|
|
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
|
2020-10-27 04:16:31 +08:00
|
|
|
let res = s:get_array(guibg, guifg, ctermbg, ctermfg, bold ? ['bold'] : a:000)
|
2019-01-17 21:34:19 +08:00
|
|
|
else
|
2020-10-27 04:16:31 +08:00
|
|
|
let res = s:get_array(guifg, guibg, ctermfg, ctermbg, bold ? ['bold'] : a:000)
|
2017-09-01 17:25:37 +08:00
|
|
|
endif
|
2017-08-11 17:26:35 +08:00
|
|
|
endif
|
|
|
|
let s:hl_groups[a:group] = res
|
|
|
|
return res
|
2013-09-02 10:57:32 +08:00
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
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)
|
2013-09-02 10:57:32 +08:00
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! s:hl_group_exists(group) abort
|
2017-06-21 15:19:51 +08:00
|
|
|
if !hlexists(a:group)
|
|
|
|
return 0
|
|
|
|
elseif empty(synIDattr(hlID(a:group), 'fg'))
|
|
|
|
return 0
|
|
|
|
endif
|
|
|
|
return 1
|
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! airline#highlighter#exec(group, colors) abort
|
2016-01-29 00:27:17 +08:00
|
|
|
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
|
2016-01-29 00:27:17 +08:00
|
|
|
let old_hi = airline#highlighter#get_highlight(a:group)
|
|
|
|
if len(colors) == 4
|
|
|
|
call add(colors, '')
|
|
|
|
endif
|
2020-10-27 04:16:31 +08:00
|
|
|
let new_hi = [colors[0], colors[1], printf('%s', colors[2]), printf('%s', colors[3]), colors[4]]
|
2017-02-21 04:02:36 +08:00
|
|
|
let colors = s:CheckDefined(colors)
|
2017-06-27 04:27:01 +08:00
|
|
|
if old_hi != new_hi || !s:hl_group_exists(a:group)
|
2018-11-13 00:46:08 +08:00
|
|
|
let cmd = printf('hi %s%s', a:group, s:GetHiCmd(colors))
|
2016-01-29 00:27:17 +08:00
|
|
|
exe cmd
|
2017-08-11 17:26:35 +08:00
|
|
|
if has_key(s:hl_groups, a:group)
|
|
|
|
let s:hl_groups[a:group] = colors
|
|
|
|
endif
|
2016-01-29 00:27:17 +08:00
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! s:CheckDefined(colors) abort
|
2017-02-21 04:02:36 +08:00
|
|
|
" 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
|
2017-02-28 15:33:44 +08:00
|
|
|
" 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
|
2017-02-28 15:33:44 +08:00
|
|
|
return a:colors
|
|
|
|
endif
|
|
|
|
|
2017-02-21 04:02:36 +08:00
|
|
|
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
|
2017-02-28 15:33:44 +08:00
|
|
|
let fg = g:airline#highlighter#normal_fg_hi
|
2017-02-21 04:02:36 +08:00
|
|
|
let bg = synIDattr(synIDtrans(hlID('Normal')), 'bg', 'cterm')
|
2017-03-06 05:18:04 +08:00
|
|
|
if bg < 0
|
|
|
|
" in case there is no background color defined for Normal
|
|
|
|
let bg = a:colors[3]
|
|
|
|
endif
|
2017-02-21 04:02:36 +08:00
|
|
|
return a:colors[0:1] + [fg, bg] + [a:colors[4]]
|
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! s:GetHiCmd(list) abort
|
2018-11-13 00:46:08 +08:00
|
|
|
" a:list needs to have 5 items!
|
|
|
|
let res = ''
|
|
|
|
let i = -1
|
2018-11-13 16:06:39 +08:00
|
|
|
while i < 4
|
2018-11-13 00:46:08 +08:00
|
|
|
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
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! s:exec_separator(dict, from, to, inverse, suffix) abort
|
2016-01-29 00:27:17 +08:00
|
|
|
if pumvisible()
|
|
|
|
return
|
|
|
|
endif
|
2018-11-12 04:15:03 +08:00
|
|
|
let group = a:from.'_to_'.a:to.a:suffix
|
2018-03-20 22:30:02 +08:00
|
|
|
let l:from = airline#themes#get_highlight(a:from.a:suffix)
|
|
|
|
let l:to = airline#themes#get_highlight(a:to.a:suffix)
|
2013-08-21 05:27:13 +08:00
|
|
|
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
|
2013-08-18 01:35:06 +08:00
|
|
|
let a:dict[group] = colors
|
|
|
|
call airline#highlighter#exec(group, colors)
|
2013-08-17 20:50:07 +08:00
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! airline#highlighter#load_theme() abort
|
2016-01-29 00:27:17 +08:00
|
|
|
if pumvisible()
|
|
|
|
return
|
|
|
|
endif
|
2013-09-07 21:03:15 +08:00
|
|
|
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'])
|
2016-08-28 20:41:45 +08:00
|
|
|
if getbufvar( bufnr('%'), '&modified' )
|
|
|
|
call airline#highlighter#highlight(['normal', 'modified'])
|
|
|
|
else
|
|
|
|
call airline#highlighter#highlight(['normal'])
|
|
|
|
endif
|
2013-08-24 21:40:20 +08:00
|
|
|
endfunction
|
2013-08-17 20:50:07 +08:00
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! airline#highlighter#add_separator(from, to, inverse) abort
|
2013-08-24 21:40:20 +08:00
|
|
|
let s:separators[a:from.a:to] = [a:from, a:to, a:inverse]
|
2013-09-02 10:57:32 +08:00
|
|
|
call <sid>exec_separator({}, a:from, a:to, a:inverse, '')
|
2013-08-24 21:40:20 +08:00
|
|
|
endfunction
|
2013-08-17 23:12:01 +08:00
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! airline#highlighter#add_accent(accent) abort
|
2013-11-01 12:54:10 +08:00
|
|
|
let s:accents[a:accent] = 1
|
|
|
|
endfunction
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! airline#highlighter#highlight_modified_inactive(bufnr) abort
|
2013-09-07 21:00:10 +08:00
|
|
|
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
|
|
|
|
|
2020-10-27 04:16:31 +08:00
|
|
|
function! airline#highlighter#highlight(modes, ...) abort
|
2016-09-09 00:39:29 +08:00
|
|
|
let bufnr = a:0 ? a:1 : ''
|
2013-09-28 09:36:44 +08:00
|
|
|
let p = g:airline#themes#{g:airline_theme}#palette
|
|
|
|
|
2013-08-24 21:40:20 +08:00
|
|
|
" 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' : ''
|
2018-11-08 19:17:40 +08:00
|
|
|
let airline_grouplist = []
|
|
|
|
let buffers_in_tabpage = sort(tabpagebuflist())
|
|
|
|
if exists("*uniq")
|
|
|
|
let buffers_in_tabpage = uniq(buffers_in_tabpage)
|
|
|
|
endif
|
2018-11-07 21:25:40 +08:00
|
|
|
" 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)
|
2013-08-24 21:40:20 +08:00
|
|
|
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)
|
2013-09-28 09:36:44 +08:00
|
|
|
let mode_colors = kvp[1]
|
2016-09-09 00:39:29 +08:00
|
|
|
let name = kvp[0]
|
|
|
|
if name is# 'airline_c' && !empty(bufnr) && suffix is# '_inactive'
|
|
|
|
let name = 'airline_c'.bufnr
|
|
|
|
endif
|
2018-11-08 19:17:40 +08:00
|
|
|
" do not re-create highlighting for buffers that are no longer visible
|
|
|
|
" in the current tabpage
|
2018-11-08 20:32:20 +08:00
|
|
|
if name =~# 'airline_c\d\+'
|
2018-11-08 19:24:02 +08:00
|
|
|
let bnr = matchstr(name, 'airline_c\zs\d\+') + 0
|
2018-11-08 19:40:46 +08:00
|
|
|
if bnr > 0 && index(buffers_in_tabpage, bnr) == -1
|
2018-11-08 19:17:40 +08:00
|
|
|
continue
|
|
|
|
endif
|
2018-11-13 20:57:15 +08:00
|
|
|
elseif (name =~# '_to_') || (name[0:10] is# 'airline_tab' && !empty(suffix))
|
2018-11-12 12:18:53 +08:00
|
|
|
" group will be redefined below at exec_separator
|
2018-11-13 20:43:55 +08:00
|
|
|
" or is not needed for tabline with '_inactive' suffix
|
|
|
|
" since active flag is 1 for builder)
|
2018-11-12 12:18:53 +08:00
|
|
|
continue
|
2018-11-08 19:17:40 +08:00
|
|
|
endif
|
2018-11-07 21:25:40 +08:00
|
|
|
if s:group_not_done(airline_grouplist, name.suffix)
|
|
|
|
call airline#highlighter#exec(name.suffix, mode_colors)
|
|
|
|
endif
|
2013-09-28 09:36:44 +08:00
|
|
|
|
2020-01-20 19:28:04 +08:00
|
|
|
if !has_key(p, 'accents')
|
2020-01-20 19:32:06 +08:00
|
|
|
" work around a broken installation
|
2020-01-20 19:28:04 +08:00
|
|
|
" shouldn't actually happen, p should always contain accents
|
|
|
|
continue
|
|
|
|
endif
|
|
|
|
|
2013-11-01 12:54:10 +08:00
|
|
|
for accent in keys(s:accents)
|
|
|
|
if !has_key(p.accents, accent)
|
|
|
|
continue
|
|
|
|
endif
|
2013-09-28 09:36:44 +08:00
|
|
|
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
|
2018-11-07 21:25:40 +08:00
|
|
|
if s:group_not_done(airline_grouplist, name.suffix.'_'.accent)
|
|
|
|
call airline#highlighter#exec(name.suffix.'_'.accent, colors)
|
|
|
|
endif
|
2013-09-28 09:36:44 +08:00
|
|
|
endfor
|
2013-08-24 21:40:20 +08:00
|
|
|
endfor
|
2013-08-17 20:50:07 +08:00
|
|
|
|
2018-11-07 21:25:40 +08:00
|
|
|
if empty(s:separators)
|
|
|
|
" nothing to be done
|
|
|
|
continue
|
|
|
|
endif
|
2018-11-12 04:15:03 +08:00
|
|
|
" TODO: optimize this
|
2013-08-24 21:40:20 +08:00
|
|
|
for sep in items(s:separators)
|
2018-11-12 04:15:03 +08:00
|
|
|
" 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)
|
2013-08-24 21:40:20 +08:00
|
|
|
endfor
|
|
|
|
endif
|
|
|
|
endfor
|
2013-08-17 20:50:07 +08:00
|
|
|
endfunction
|