Rewrite of CSApproxSnapshot
Now it's much less hacky, and looks much more like a well-designed feature. I doubt it's perfect, but it seems to work well in every test case I have, as long as it's run from gvim. I've discovered that it doesn't work when run from terminal vim, and it seems unlikely that it ever will - it's capable of spitting out the right cterm colors in that case, but can't reproduce the proper gui colors.
This commit is contained in:
parent
147d3c9f71
commit
7e4ffb4b2a
@ -190,11 +190,14 @@ function! s:Highlights()
|
|||||||
|
|
||||||
for where in [ "term", "cterm", "gui" ]
|
for where in [ "term", "cterm", "gui" ]
|
||||||
let rv[i][where] = {}
|
let rv[i][where] = {}
|
||||||
for attr in [ "fg", "bg", "sp", "bold", "italic",
|
for attr in [ "bold", "italic", "reverse", "underline", "undercurl" ]
|
||||||
\ "reverse", "underline", "undercurl" ]
|
|
||||||
let rv[i][where][attr] = synIDattr(i, attr, where)
|
let rv[i][where][attr] = synIDattr(i, attr, where)
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
|
for attr in [ "fg", "bg", "sp" ]
|
||||||
|
let rv[i][where][attr] = synIDattr(i, attr.'#', where)
|
||||||
|
endfor
|
||||||
|
|
||||||
if s:NeedRedirFallback()
|
if s:NeedRedirFallback()
|
||||||
redir => temp
|
redir => temp
|
||||||
exe 'sil hi ' . rv[i].name
|
exe 'sil hi ' . rv[i].name
|
||||||
@ -210,6 +213,12 @@ function! s:Highlights()
|
|||||||
endif
|
endif
|
||||||
let rv[i][where]["sp"] = temp
|
let rv[i][where]["sp"] = temp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
for attr in [ "fg", "bg", "sp" ]
|
||||||
|
if rv[i][where][attr] == -1
|
||||||
|
let rv[i][where][attr] = ''
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
endfor
|
endfor
|
||||||
endwhile
|
endwhile
|
||||||
|
|
||||||
@ -360,6 +369,19 @@ function! s:attr_map(attr)
|
|||||||
return rv
|
return rv
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" {>2} Normalize the GUI settings of a highlight group
|
||||||
|
" If the Normal group is cleared, set it to gvim's default, black on white
|
||||||
|
" Though this would be a really weird thing for a scheme to do... *shrug*
|
||||||
|
function! s:FixupGuiInfo(highlights)
|
||||||
|
if a:highlights[s:hlid_normal].gui.bg == ''
|
||||||
|
let a:highlights[s:hlid_normal].gui.bg = 'white'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:highlights[s:hlid_normal].gui.fg == ''
|
||||||
|
let a:highlights[s:hlid_normal].gui.fg = 'black'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
" {>2} Map gui settings to cterm settings
|
" {>2} Map gui settings to cterm settings
|
||||||
" Given information about a highlight group, replace the cterm settings with
|
" Given information about a highlight group, replace the cterm settings with
|
||||||
" the mapped gui settings, applying any attribute overrides along the way. In
|
" the mapped gui settings, applying any attribute overrides along the way. In
|
||||||
@ -371,58 +393,56 @@ endfunction
|
|||||||
" ensure that the 'sp' attribute is never set for cterm, since no terminal can
|
" ensure that the 'sp' attribute is never set for cterm, since no terminal can
|
||||||
" handle that particular highlight. If the user wants to display the guisp
|
" handle that particular highlight. If the user wants to display the guisp
|
||||||
" color, he should map it to either 'fg' or 'bg' using g:CSApprox_attr_map.
|
" color, he should map it to either 'fg' or 'bg' using g:CSApprox_attr_map.
|
||||||
function! s:FixupCtermInfo(hl)
|
function! s:FixupCtermInfo(highlights)
|
||||||
let hl = a:hl
|
for hl in values(a:highlights)
|
||||||
|
|
||||||
" Find attributes to be set in the terminal
|
" Find attributes to be set in the terminal
|
||||||
for attr in [ "bold", "italic", "reverse", "underline", "undercurl" ]
|
for attr in [ "bold", "italic", "reverse", "underline", "undercurl" ]
|
||||||
let hl.cterm[attr] = ''
|
let hl.cterm[attr] = ''
|
||||||
if hl.gui[attr] == 1
|
if hl.gui[attr] == 1
|
||||||
if s:attr_map(attr) != ''
|
if s:attr_map(attr) != ''
|
||||||
let hl.cterm[ s:attr_map(attr) ] = 1
|
let hl.cterm[ s:attr_map(attr) ] = 1
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endfor
|
||||||
endfor
|
|
||||||
|
for color in [ "bg", "fg" ]
|
||||||
|
let eff_color = color
|
||||||
|
if hl.cterm['reverse']
|
||||||
|
let eff_color = (color == 'bg' ? 'fg' : 'bg')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let hl.cterm[color] = get(hl.gui, s:attr_map(eff_color), '')
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if hl.gui['sp'] != '' && s:attr_map('sp') != ''
|
||||||
|
let hl.cterm[s:attr_map('sp')] = hl.gui['sp']
|
||||||
|
endif
|
||||||
|
|
||||||
|
if hl.cterm['reverse'] && hl.cterm.bg == ''
|
||||||
|
let hl.cterm.bg = 'fg'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if hl.cterm['reverse'] && hl.cterm.fg == ''
|
||||||
|
let hl.cterm.fg = 'bg'
|
||||||
|
endif
|
||||||
|
|
||||||
for color in [ "bg", "fg" ]
|
|
||||||
let eff_color = color
|
|
||||||
if hl.cterm['reverse']
|
if hl.cterm['reverse']
|
||||||
let eff_color = (color == 'bg' ? 'fg' : 'bg')
|
let hl.cterm.reverse = ''
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let hl.cterm[color] = get(hl.gui, s:attr_map(eff_color), '')
|
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
if hl.gui['sp'] != '' && s:attr_map('sp') != ''
|
|
||||||
let hl.cterm[s:attr_map('sp')] = hl.gui['sp']
|
|
||||||
endif
|
|
||||||
|
|
||||||
if hl.cterm['reverse'] && hl.cterm.bg == ''
|
|
||||||
let hl.cterm.bg = 'fg'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if hl.cterm['reverse'] && hl.cterm.fg == ''
|
|
||||||
let hl.cterm.fg = 'bg'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if hl.cterm['reverse']
|
|
||||||
let hl.cterm.reverse = ''
|
|
||||||
endif
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" {>2} Set cterm colors for a highlight group
|
" {>2} Set cterm colors for a highlight group
|
||||||
" Given the information for a single highlight group (ie, the value of
|
" Given the information for a single highlight group (ie, the value of
|
||||||
" one of the items in s:Highlights()), uses s:FixupCtermInfo to parse the
|
" one of the items in s:Highlights() already normalized with s:FixupCtermInfo
|
||||||
" structure and normalize it for use on a cterm, then handles matching the
|
" and s:FixupGuiInfo), handle matching the gvim colors to the closest cterm
|
||||||
" gvim colors to the closest cterm colors by calling the approximator
|
" colors by calling the appropriate approximator as specified with the
|
||||||
" specified with g:CSApprox_approximator_function and sets the colors and
|
" g:CSApprox_approximator_function variable and set the colors and attributes
|
||||||
" attributes appropriately to match the gui. The final colors are saved in
|
" appropriately to match the gui.
|
||||||
" s:highlights for use by CSApproxSnapshot.
|
|
||||||
function! s:SetCtermFromGui(hl)
|
function! s:SetCtermFromGui(hl)
|
||||||
let hl = a:hl
|
let hl = a:hl
|
||||||
|
|
||||||
call s:FixupCtermInfo(hl)
|
|
||||||
|
|
||||||
" Set up the default approximator function, if needed
|
" Set up the default approximator function, if needed
|
||||||
if !exists("g:CSApprox_approximator_function")
|
if !exists("g:CSApprox_approximator_function")
|
||||||
let g:CSApprox_approximator_function=function("s:ApproximatePerComponent")
|
let g:CSApprox_approximator_function=function("s:ApproximatePerComponent")
|
||||||
@ -482,10 +502,8 @@ endfunction
|
|||||||
|
|
||||||
" {>1} Top-level control
|
" {>1} Top-level control
|
||||||
|
|
||||||
" {>2} Variable storing highlights between runs
|
" Cache the highlight ID of the normal group; it's used often and won't change
|
||||||
" This allows us to remember what the highlights looked like when we last ran,
|
let s:hlid_normal = hlID('Normal')
|
||||||
" which can be used by CSApproxSnapshot to post-process the results.
|
|
||||||
let s:highlights = {}
|
|
||||||
|
|
||||||
" {>2} Builtin cterm color names above 15
|
" {>2} Builtin cterm color names above 15
|
||||||
" Vim defines some color name to high color mappings internally (see
|
" Vim defines some color name to high color mappings internally (see
|
||||||
@ -530,9 +548,9 @@ let s:presets_256 += [229] " LightYellow
|
|||||||
" to ensure that the Normal group is the first group we set. If it weren't,
|
" to ensure that the Normal group is the first group we set. If it weren't,
|
||||||
" we could get E419 or E420 if a later color used guibg=bg or the likes.
|
" we could get E419 or E420 if a later color used guibg=bg or the likes.
|
||||||
function! s:SortNormalFirst(num1, num2)
|
function! s:SortNormalFirst(num1, num2)
|
||||||
if a:num1 == hlID('Normal') && a:num1 != a:num2
|
if a:num1 == s:hlid_normal && a:num1 != a:num2
|
||||||
return -1
|
return -1
|
||||||
elseif a:num2 == hlID('Normal') && a:num1 != a:num2
|
elseif a:num2 == s:hlid_normal && a:num1 != a:num2
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
@ -610,15 +628,8 @@ function! s:CSApproxImpl()
|
|||||||
" Get the current highlight colors
|
" Get the current highlight colors
|
||||||
let highlights = s:Highlights()
|
let highlights = s:Highlights()
|
||||||
|
|
||||||
" If the Normal group is cleared, set it to gvim's default, black on white
|
call s:FixupGuiInfo(highlights)
|
||||||
" Though this would be a really weird thing for a scheme to do... *shrug*
|
call s:FixupCtermInfo(highlights)
|
||||||
if highlights[hlID('Normal')].gui.bg == ''
|
|
||||||
let highlights[hlID('Normal')].gui.bg = 'white'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if highlights[hlID('Normal')].gui.fg == ''
|
|
||||||
let highlights[hlID('Normal')].gui.fg = 'black'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let hinums = keys(highlights)
|
let hinums = keys(highlights)
|
||||||
|
|
||||||
@ -647,9 +658,6 @@ function! s:CSApproxImpl()
|
|||||||
for hlid in hinums
|
for hlid in hinums
|
||||||
call s:SetCtermFromGui(highlights[hlid])
|
call s:SetCtermFromGui(highlights[hlid])
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
" and finally, store the new highlights for use in CSApproxSnapshot()
|
|
||||||
let s:highlights = copy(highlights)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" {>2} Write out the current colors to an 88/256 color colorscheme file.
|
" {>2} Write out the current colors to an 88/256 color colorscheme file.
|
||||||
@ -671,6 +679,19 @@ function! s:CSApproxSnapshot(file, overwrite)
|
|||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" Sigh... This is basically a bug, but one that I have no chance of fixing.
|
||||||
|
" Vim decides that Pmenu should be highlighted in 'LightMagenta' in terminal
|
||||||
|
" vim and as 'Magenta' in gvim... And I can't ask it what color it actually
|
||||||
|
" *wants*. As far as I can see, there's no way for me to learn that
|
||||||
|
" I should output 'Magenta' when 'LightMagenta' is provided by vim for the
|
||||||
|
" terminal.
|
||||||
|
if !has('gui_running')
|
||||||
|
echohl WarningMsg
|
||||||
|
echomsg "Warning: The written colorscheme may have incorrect colors"
|
||||||
|
echomsg " when CSApproxSnapshot is used in terminal vim!"
|
||||||
|
echohl None
|
||||||
|
endif
|
||||||
|
|
||||||
let save_t_Co = &t_Co
|
let save_t_Co = &t_Co
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -688,13 +709,15 @@ function! s:CSApproxSnapshot(file, overwrite)
|
|||||||
|
|
||||||
let lines += [ 'if 0' ]
|
let lines += [ 'if 0' ]
|
||||||
for &t_Co in [ 256, 88 ]
|
for &t_Co in [ 256, 88 ]
|
||||||
|
let highlights = s:Highlights()
|
||||||
|
call s:FixupGuiInfo(highlights)
|
||||||
let lines += [ 'elseif has("gui_running") || &t_Co == ' . &t_Co ]
|
let lines += [ 'elseif has("gui_running") || &t_Co == ' . &t_Co ]
|
||||||
for hlnum in sort(keys(s:highlights), "s:SortNormalFirst")
|
for hlnum in sort(keys(highlights), "s:SortNormalFirst")
|
||||||
let hl = s:highlights[hlnum]
|
let hl = highlights[hlnum]
|
||||||
let line = ' highlight ' . hl.name
|
let line = ' highlight ' . hl.name
|
||||||
for type in [ 'term', 'cterm', 'gui' ]
|
for type in [ 'term', 'cterm', 'gui' ]
|
||||||
let attrs = [ 'bold', 'italic', 'underline', 'undercurl' ]
|
let attrs = [ 'reverse', 'bold', 'italic', 'underline', 'undercurl' ]
|
||||||
call filter(attrs, 'hl.cterm[v:val] == 1')
|
call filter(attrs, 'hl[type][v:val] == 1')
|
||||||
let line .= ' ' . type . '=' . (empty(attrs) ? 'NONE' : join(attrs, ','))
|
let line .= ' ' . type . '=' . (empty(attrs) ? 'NONE' : join(attrs, ','))
|
||||||
if type != 'term'
|
if type != 'term'
|
||||||
let line .= ' ' . type . 'bg=' . (len(hl[type].bg) ? hl[type].bg : 'bg')
|
let line .= ' ' . type . 'bg=' . (len(hl[type].bg) ? hl[type].bg : 'bg')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user