Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

More accurate and minimal snapshots. #7

Open
wants to merge 5 commits into from

2 participants

Buck Golemon Matt Wozniski
Buck Golemon

I'd really benefit from a critique of this changeset.

In particular, the colors 'fg' and 'bg' were being used too often, which was preventing some reverse and background-only color groups from functioning as intended.

I went on to do a fairly major refactor which allows me to output a more minimal and readable snapshot color scheme. I've started capturing syntax group links because some color schemes use them in their implementation (notably ir_black and zenburn).

I've noticed that my minimized konsole/eterm settings are always blank. Either I've broken it, it was already broken, or it is working but the konsole/eterm colors are never different from the xterm colors.

Future work: (please comment if you have suggestions or concerns)

  • :CSApproxSnapshot file scheme
    Try to do a hard-reset of highlight groups and reload the color scheme before snapshotting, to give a more exact picture of the color scheme.
    Set the default filename as ${CSA-install-dir}/colors/${scheme}-approx.vim
    Set scheme to default to g:colors_name

  • :CSApproxSnapshotCurrent file
    Similar to above, but don't do a hard reset, to capture any manual customizations by the user.
    Set the default filename as ${CSA-install-dir}/colors/${g:colors_name}-${USER}-approx.vim

    I'm not sure this one is necessary. Do you think anyone will use it? I mainly plan this because it's closer to the original behavior of :CSASnapshot.

  • :CSApproxSnapshotAll dir
    Snapshot all color scheme files that can be found into dir
    Set default dir to ${CSA-install-dir}/colors/

  • fall back to ${g:colors_name}-approx.vim
    In a non-gui, pre-7.3 environment, check for on-disk snapshots before giving an error.

Thanks in advance for your time.
--buck

Matt Wozniski
Owner

Do you have a testcase showing a colorscheme that is improved by this change?

Example from the tomorrownight theme https://github.com/werbitt/Tomorrow-Theme/blob/master/Vim/Tomorrow-Night.vim

:hi StatusLine
StatusLine     xxx term=bold,reverse cterm=reverse ctermfg=222 ctermbg=59 gui=reverse guifg=#4d5057 guibg=#f0c674

If you bring up your color charts, you'll see that the ctermfg and ctermbg are swapped, compared to the gui colors, but 'reverse' is still set.
I think the red code above made things correct before the 'translate gui=reverse to cterm' change, but now it's making things incorrect.

Matt Wozniski
Owner

Do you have a testcase showing a colorscheme that is improved by this change?

Look at the CursorLine of the 'murphy' colorscheme.
When loaded with CSApprox we get:

:hi CursorLine
CursorLine     xxx term=underline ctermbg=241 guibg=Grey40

This allows other highlights' foreground colors to show through the cursorline. Note that there is no 'ctermfg' entry. The above code (in red) causes the cursorline to always be the Normal fg color instead, which is quite worse.

Matt Wozniski
Owner

I think I'd prefer to delete the .gitignore file entirely rather than update it... It's not doing anything useful.

It's useful to have an accurate git status.

Matt Wozniski
Owner

For the two refactors of the snapshot code, I'll have to look through them a bit more carefully and see what I think. In general, I'd rather not check in changes just for the sake of making them smaller and more readable - in general, I think that generated code ought to be easy to generate, rather than easy to read. It looks like there are some actual fixes to the snapshotting mixed in here as well, but I don't want to apply those without a testcase showing the change that they cause, and a careful review to make sure that they don't make any of my other testcases worse.

Buck Golemon

Some remarks that may help:

The chief thing I've done is change the layout of the s:Highlights return value. If you can agree to that, the rest flows naturally from there. I think the layout results in more natural, readable code downstream, but it also enables two features that I'm trying to introduce.

First, I'd like to capture color-group links, as these are used in some color schemes. Ignoring them gives incorrect results.

Secondly, I'm planning a test suite, of sorts. I'd like to add a CSApproxSnapshotAll command that will capture all known color schemes under the CSApprox/colors directory (by default). If those results are deterministic (i.e. sorted) then git diff will suss out any functional changes that have been made. Another implication is that these snapshot color schemes will be added to the project, so I feel that making them small / readable is a good side effect. The reorganization of s:Highlights makes these optimizations fairly trivial.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
1  .gitignore
... ...
@@ -1,2 +1,3 @@
1 1
 tags
2 2
 *~
  3
+.*.sw[n-z]
354  plugin/CSApprox.vim
@@ -89,56 +89,82 @@ function! s:NeedRedirFallback()
89 89
   return g:CSApprox_redirfallback
90 90
 endfunction
91 91
 
92  
-" {>2} Collect and store the highlights
93  
-" Get a dictionary containing information for every highlight group not merely
94  
-" linked to another group.  Return value is a dictionary, with highlight group
95  
-" numbers for keys and values that are dictionaries with four keys each,
96  
-" 'name', 'term', 'cterm', and 'gui'.  'name' holds the group name, and each
97  
-" of the others holds highlight information for that particular mode.
  92
+" {>2} Collect and store the highlights Get a dictionary containing
  93
+" information for every highlight group.  Return value is a dictionary mapping
  94
+" highlight group names to dictionaries with five keys each:
  95
+" [name|id|links|term|cterm|gui].
  96
+"   "name" is the highlight-group's name. 
  97
+"   "id" is the numeric id, suitable for passing to the synID* functions.
  98
+"   "links" holds the list of group names which are to be linked to this one.
  99
+"   "term", "cterm" and "gui" contain the highlight attributes as dictionaries.
  100
+"     Their keys are [fg|bg|extra|sp].
  101
+"     "extra" is a list of the non-color highlight information, such as 'bold'.
  102
+"     "sp" will be unset except under 'gui'
98 103
 function! s:Highlights(modes)
99  
-  let rv = {}
  104
+  let rv = {} "return value
  105
+  let id2name = {}
  106
+  let name2link = {}
100 107
 
101  
-  let i = 0
  108
+  let id = 0
102 109
   while 1
103  
-    let i += 1
  110
+    let id += 1
104 111
 
105  
-    " Only interested in groups that exist and aren't linked
106  
-    if synIDtrans(i) == 0
  112
+    " Only interested in groups that exist
  113
+    if synIDtrans(id) == 0
107 114
       break
108 115
     endif
109 116
 
110  
-    " Handle vim bug allowing groups with name == "" to be created
111  
-    if synIDtrans(i) != i || len(synIDattr(i, "name")) == 0
  117
+    " Handle vim bug allowing groups to be created without a name
  118
+    if synIDattr(id, "name") == ""
112 119
       continue
113 120
     endif
114 121
 
115  
-    let rv[i] = {}
116  
-    let rv[i].name = synIDattr(i, "name")
  122
+    " Handle linked highlight groups
  123
+    let name = synIDattr(id, "name")
  124
+    if synIDtrans(id) != id
  125
+      "save it for later. links can be out-of-order. see zellner.
  126
+      let name2link[name] = synIDtrans(id)
  127
+      continue
  128
+    endif
117 129
 
118  
-    for where in a:modes
119  
-      let rv[i][where]  = {}
120  
-      for attr in s:PossibleAttributes()
121  
-        let rv[i][where][attr] = synIDattr(i, attr, where)
122  
-      endfor
  130
+    let highlight = {'name':name, 'id':id, 'links':[]}
  131
+    for mode in a:modes
  132
+      let highlight[mode] = {}
  133
+
  134
+      let attrs = s:PossibleAttributes()
  135
+      call filter(attrs, 'synIDattr(id, v:val, mode) == 1')
  136
+      let highlight[mode].extra = attrs
123 137
 
124 138
       for attr in [ "fg", "bg" ]
125  
-        let rv[i][where][attr] = synIDattr(i, attr.'#', where)
  139
+        let color = synIDattr(id, attr.'#', mode)
  140
+        if color == -1
  141
+          let highlight[mode][attr] = ''
  142
+        else
  143
+          let highlight[mode][attr] = color
  144
+        endif
126 145
       endfor
127 146
 
128  
-      if where == "gui"
129  
-        let rv[i][where]["sp"] = s:SynGuiSp(i, rv[i].name)
130  
-      else
131  
-        let rv[i][where]["sp"] = -1
  147
+      if mode == "gui"
  148
+        let color = s:SynGuiSp(id, name)
  149
+        if color == -1
  150
+          let highlight[mode]["sp"] = ''
  151
+        else
  152
+          let highlight[mode]["sp"] = color
  153
+        endif
132 154
       endif
133 155
 
134  
-      for attr in [ "fg", "bg", "sp" ]
135  
-        if rv[i][where][attr] == -1
136  
-          let rv[i][where][attr] = ''
137  
-        endif
138  
-      endfor
  156
+      " Link everything up!
  157
+      let rv[name] = highlight
  158
+      let id2name[id] = name
139 159
     endfor
  160
+
140 161
   endwhile
141 162
 
  163
+  "record all the links we've seen
  164
+  for [name, link] in items(name2link)
  165
+    call add(rv[id2name[link]].links, name)
  166
+  endfor
  167
+
142 168
   return rv
143 169
 endfunction
144 170
 
@@ -156,7 +182,7 @@ endfunction
156 182
 " {>3} Implementation for retrieving guisp with redir hack
157 183
 function! s:SynGuiSpRedir(name)
158 184
   redir => temp
159  
-  exe 'sil hi ' . a:name
  185
+  exe 'sil hi' a:name
160 186
   redir END
161 187
   let temp = matchstr(temp, 'guisp=\zs.*')
162 188
   if len(temp) == 0 || temp[0] =~ '\s'
@@ -287,7 +313,9 @@ endfunction
287 313
 
288 314
 " {>2} List of all possible attributes
289 315
 function! s:PossibleAttributes()
290  
-  return [ "bold", "italic", "reverse", "underline", "undercurl" ]
  316
+  " inverse is exactly equivalent to reverse: they'll both be set or unset
  317
+  " the rest of these are distinct
  318
+  return [ "bold", "italic", "reverse", "standout", "underline", "undercurl" ]
291 319
 endfunction
292 320
 
293 321
 " {>2} Attribute overrides
@@ -302,9 +330,7 @@ endfunction
302 330
 " can look up, to string values, representing the attribute mapped to or an
303 331
 " empty string to disable the given attribute entirely.
304 332
 function! s:attr_map(attr)
305  
-  let rv = get(g:CSApprox_attr_map, a:attr, a:attr)
306  
-
307  
-  return rv
  333
+  return get(g:CSApprox_attr_map, a:attr, a:attr)
308 334
 endfunction
309 335
 
310 336
 function! s:NormalizeAttrMap(map)
@@ -349,71 +375,59 @@ endfunction
349 375
 
350 376
 " {>2} Normalize the GUI settings of a highlight group
351 377
 " If the Normal group is cleared, set it to gvim's default, black on white
352  
-" Though this would be a really weird thing for a scheme to do... *shrug*
  378
+" Although this is a really weird thing for a scheme to do, the 'default'
  379
+" colorscheme does this.
353 380
 function! s:FixupGuiInfo(highlights)
354  
-  if a:highlights[s:hlid_normal].gui.bg == ''
355  
-    let a:highlights[s:hlid_normal].gui.bg = 'white'
  381
+  if a:highlights['Normal'].gui.bg == ''
  382
+    let a:highlights['Normal'].gui.bg = 'white'
356 383
   endif
357 384
 
358  
-  if a:highlights[s:hlid_normal].gui.fg == ''
359  
-    let a:highlights[s:hlid_normal].gui.fg = 'black'
  385
+  if a:highlights['Normal'].gui.fg == ''
  386
+    let a:highlights['Normal'].gui.fg = 'black'
360 387
   endif
361 388
 endfunction
362 389
 
363 390
 " {>2} Map gui settings to cterm settings
364 391
 " Given information about a highlight group, replace the cterm settings with
365 392
 " the mapped gui settings, applying any attribute overrides along the way.  In
366  
-" particular, this gives special treatment to the 'reverse' attribute and the
367  
-" 'guisp' attribute.  In particular, if the 'reverse' attribute is set for
368  
-" gvim, we unset it for the terminal and instead set ctermfg to match guibg
369  
-" and vice versa, since terminals can consider a 'reverse' flag to mean using
370  
-" default-bg-on-default-fg instead of current-bg-on-current-fg.  We also
371  
-" ensure that the 'sp' attribute is never set for cterm, since no terminal can
372  
-" handle that particular highlight.  If the user wants to display the guisp
373  
-" color, he should map it to either 'fg' or 'bg' using g:CSApprox_attr_map.
  393
+" particular, this gives special treatment to the 'guisp' attribute.  In
  394
+" particular, we ensure that the 'sp' attribute is never set for cterm, since
  395
+" no terminal can handle that particular highlight.  If the user wants to
  396
+" display the guisp color, he should map it to either 'fg' or 'bg' using
  397
+" g:CSApprox_attr_map.
374 398
 function! s:FixupCtermInfo(highlights)
375 399
   for hl in values(a:highlights)
376  
-
377  
-    if !has_key(hl, 'cterm')
378  
-      let hl["cterm"] = {}
379  
-    endif
  400
+    let hl.cterm = {}
380 401
 
381 402
     " Find attributes to be set in the terminal
382  
-    for attr in s:PossibleAttributes()
383  
-      let hl.cterm[attr] = ''
384  
-      if hl.gui[attr] == 1
385  
-        if s:attr_map(attr) != ''
386  
-          let hl.cterm[ s:attr_map(attr) ] = 1
387  
-        endif
388  
-      endif
389  
-    endfor
  403
+    let hl.cterm.extra = copy(hl.gui.extra)
  404
+    call map(hl.cterm.extra, 's:attr_map(v:val)')
390 405
 
391  
-    for color in [ "bg", "fg" ]
392  
-      let eff_color = color
393  
-      if hl.cterm['reverse']
394  
-        let eff_color = (color == 'bg' ? 'fg' : 'bg')
395  
-      endif
396  
-
397  
-      let hl.cterm[color] = get(hl.gui, s:attr_map(eff_color), '')
  406
+    for mode in [ "bg", "fg" ]
  407
+      let hl.cterm[s:attr_map(mode)] = hl.gui[mode]
398 408
     endfor
399 409
 
400  
-    if hl.gui['sp'] != '' && s:attr_map('sp') != ''
401  
-      let hl.cterm[s:attr_map('sp')] = hl.gui['sp']
  410
+    if strlen(hl.gui.sp) && s:attr_map('sp') != 'sp'
  411
+      let hl.cterm[s:attr_map('sp')] = hl.gui.sp
402 412
     endif
403 413
 
404  
-    if exists("g:CSApprox_fake_reverse") && g:CSApprox_fake_reverse
405  
-      if hl.cterm['reverse'] && hl.cterm.bg == ''
406  
-        let hl.cterm.bg = 'fg'
407  
-      endif
  414
+    if exists("g:CSApprox_fake_reverse") 
  415
+        \&& g:CSApprox_fake_reverse 
  416
+        \&& index(hl.cterm.extra, 'reverse') != -1
  417
+      "manually swap the colors
  418
+      call filter(hl.cterm.extra, 'v:val != "reverse"')
408 419
 
409  
-      if hl.cterm['reverse'] && hl.cterm.fg == ''
410  
-        let hl.cterm.fg = 'bg'
  420
+      if hl.cterm.bg == ''
  421
+        let hl.cterm.bg = 'bg'
411 422
       endif
412 423
 
413  
-      if hl.cterm['reverse']
414  
-        let hl.cterm.reverse = ''
  424
+      if hl.cterm.fg == ''
  425
+        let hl.cterm.fg = 'fg'
415 426
       endif
  427
+
  428
+      let [hl.cterm.fg, hl.cterm.bg] = [hl.cterm.bg, hl.cterm.fg]
416 429
     endif
  430
+
417 431
   endfor
418 432
 endfunction
419 433
 
@@ -438,10 +452,10 @@ function! s:SetCtermFromGui(hl)
438 452
   endif
439 453
 
440 454
   " Clear existing highlights
441  
-  exe 'hi ' . hl.name . ' cterm=NONE ctermbg=NONE ctermfg=NONE'
  455
+  exe 'hi' hl.name 'cterm=NONE ctermbg=NONE ctermfg=NONE'
442 456
 
443  
-  for which in [ 'bg', 'fg' ]
444  
-    let val = hl.cterm[which]
  457
+  for mode in [ 'bg', 'fg' ]
  458
+    let val = hl.cterm[mode]
445 459
 
446 460
     " Skip unset colors
447 461
     if val == -1 || val == ""
@@ -450,7 +464,7 @@ function! s:SetCtermFromGui(hl)
450 464
 
451 465
     " Try translating anything but 'fg', 'bg', #rrggbb, and rrggbb from an
452 466
     " rgb.txt color to a #rrggbb color
453  
-    if val !~? '^[fb]g$' && val !~ '^#\=\x\{6}$'
  467
+    if val !~? '^[fb]g$' && val !~ '^#\?\x\{6}$'
454 468
       try
455 469
         " First see if it is in our preset-by-vim rgb list
456 470
         let val = s:rgb_presets[tolower(val)]
@@ -472,35 +486,36 @@ function! s:SetCtermFromGui(hl)
472 486
     endif
473 487
 
474 488
     if val =~? '^[fb]g$'
475  
-      exe 'hi ' . hl.name . ' cterm' . which . '=' . val
476  
-      let hl.cterm[which] = val
477  
-    elseif val =~ '^#\=\x\{6}$'
  489
+      exe 'hi' hl.name 'cterm' . mode . '=' . val
  490
+      let hl.cterm[mode] = val
  491
+    elseif val =~ '^#\?\x\{6}$'
478 492
       let val = substitute(val, '^#', '', '')
479 493
       let r = str2nr(val[0:1], 16)
480 494
       let g = str2nr(val[2:3], 16)
481 495
       let b = str2nr(val[4:5], 16)
482  
-      let hl.cterm[which] = g:CSApprox_approximator_function(r, g, b)
483  
-      exe 'hi ' . hl.name . ' cterm' . which . '=' . hl.cterm[which]
  496
+      let hl.cterm[mode] = g:CSApprox_approximator_function(r, g, b)
  497
+      exe 'hi' hl.name 'cterm' . mode . '=' . hl.cterm[mode]
  498
+    elseif val == ''
  499
+      " do nothing
484 500
     else
485 501
       throw "Internal error handling color: " . val
486 502
     endif
487 503
   endfor
488 504
 
489  
-  " Finally, set the attributes
490  
-  let attrs = s:PossibleAttributes()
491  
-  call filter(attrs, 'hl.cterm[v:val] == 1')
  505
+  " Link the links
  506
+  for link in hl.links
  507
+    exe 'hi! link' link hl.name
  508
+  endfor
492 509
 
493  
-  if !empty(attrs)
494  
-    exe 'hi ' . hl.name . ' cterm=' . join(attrs, ',')
  510
+  " Finally, set the attributes
  511
+  if !empty(hl.cterm.extra)
  512
+    exe 'hi' hl.name 'cterm=' . join(hl.cterm.extra, ',')
495 513
   endif
496 514
 endfunction
497 515
 
498 516
 
499 517
 " {>1} Top-level control
500 518
 
501  
-" Cache the highlight ID of the normal group; it's used often and won't change
502  
-let s:hlid_normal = hlID('Normal')
503  
-
504 519
 " {>2} Builtin cterm color names above 15
505 520
 " Vim defines some color name to high color mappings internally (see
506 521
 " syntax.c:do_highlight).  Since we don't want to overwrite a colorscheme that
@@ -687,7 +702,7 @@ function! s:CSApproxImpl()
687 702
   " Get the current highlight colors
688 703
   let highlights = s:Highlights(["gui"])
689 704
 
690  
-  let hinums = keys(highlights)
  705
+  let names = keys(highlights)
691 706
 
692 707
   " Make sure that the script is not already 256 color by checking to make
693 708
   " sure that no groups are set to a value above 256, unless the color they're
@@ -696,14 +711,14 @@ function! s:CSApproxImpl()
696 711
   "
697 712
   " XXX: s:inhibit_hicolor_test allows this test to be skipped for snapshots
698 713
   if !exists("s:inhibit_hicolor_test") || !s:inhibit_hicolor_test
699  
-    for hlid in hinums
  714
+    for name in names
700 715
       for type in [ 'bg', 'fg' ]
701  
-        let color = synIDattr(hlid, type, 'cterm')
  716
+        let color = synIDattr(highlights[name].id, type, 'cterm')
702 717
 
703 718
         if color > 15 && index(s:presets_{&t_Co}, str2nr(color)) < 0
704 719
           " The value is set above 15, and wasn't set by vim.
705 720
           if &verbose >= 2
706  
-            echomsg 'CSApprox: Exiting - high' type 'color found for' highlights[hlid].name
  721
+            echomsg 'CSApprox: Exiting - high' type 'color found for' name
707 722
           endif
708 723
           return
709 724
         endif
@@ -715,11 +730,11 @@ function! s:CSApproxImpl()
715 730
   call s:FixupCtermInfo(highlights)
716 731
 
717 732
   " We need to set the Normal group first so 'bg' and 'fg' work as colors
718  
-  call insert(hinums, remove(hinums, index(hinums, string(s:hlid_normal))))
  733
+  call insert(names, remove(names, index(names, 'Normal')))
719 734
 
720 735
   " then set each color's cterm attributes to match gui
721  
-  for hlid in hinums
722  
-    call s:SetCtermFromGui(highlights[hlid])
  736
+  for name in names
  737
+    call s:SetCtermFromGui(highlights[name])
723 738
   endfor
724 739
 endfunction
725 740
 
@@ -764,6 +779,7 @@ function! s:CSApproxSnapshot(file, overwrite)
764 779
     let save_CSApprox_eterm = g:CSApprox_eterm
765 780
   endif
766 781
 
  782
+  " TODO: it seems like we don't really need this, since we re-use CSApprox
767 783
   " Needed just like in CSApprox()
768 784
   if exists("g:colors_name")
769 785
     let colors_name = g:colors_name
@@ -781,18 +797,26 @@ function! s:CSApproxSnapshot(file, overwrite)
781 797
     let lines += [ '" This scheme was created by CSApproxSnapshot' ]
782 798
     let lines += [ '" on ' . strftime("%a, %d %b %Y") ]
783 799
     let lines += [ '' ]
784  
-    let lines += [ 'hi clear' ]
785  
-    let lines += [ 'if exists("syntax_on")' ]
786  
-    let lines += [ '    syntax reset' ]
787  
-    let lines += [ 'endif' ]
  800
+    let lines += [ 'syntax on' ]
  801
+    let lines += [ 'let syntax_cmd="skip"' ]
  802
+    let lines += [ 'highlight clear' ]
788 803
     let lines += [ '' ]
789  
-    let lines += [ 'if v:version < 700' ]
790  
-    let lines += [ '    let g:colors_name = expand("<sfile>:t:r")' ]
791  
-    let lines += [ '    command! -nargs=+ CSAHi exe "hi" substitute(substitute(<q-args>, "undercurl", "underline", "g"), "guisp\\S\\+", "", "g")' ]
792  
-    let lines += [ 'else' ]
793  
-    let lines += [ '    let g:colors_name = expand("<sfile>:t:r")' ]
794  
-    let lines += [ '    command! -nargs=+ CSAHi exe "hi" <q-args>' ]
795  
-    let lines += [ 'endif' ]
  804
+    let lines += [ 'let g:colors_name = expand("<sfile>:t:r")' ]
  805
+    let lines += [ 'function! s:CSAhi(group, ...)' ]
  806
+    let lines += [ '    exe "hi clear" a:group' ]
  807
+    let lines += [ '    let hi = join(a:000, " ")' ]
  808
+    let lines += [ '    if v:version < 700' ]
  809
+    let lines += [ '        let hi = substitute(substitute(hi, "undercurl", "underline", "g"), "guisp=\\S\\+", "", "g")' ]
  810
+    let lines += [ '    endif' ]
  811
+    let lines += [ '    exe "hi" a:group hi' ]
  812
+    let lines += [ 'endfunction' ]
  813
+    let lines += [ 'command! -nargs=+ CSAhi call s:CSAhi(<f-args>)' ]
  814
+    let lines += [ '' ]
  815
+    let lines += [ 'function! s:CSAlink(from, to)' ]
  816
+    let lines += [ '    exe "hi clear" a:from' ]
  817
+    let lines += [ '    exe "hi! link" a:from a:to' ]
  818
+    let lines += [ 'endfunction' ]
  819
+    let lines += [ 'command! -nargs=+ CSAlink call s:CSAlink(<f-args>)' ]
796 820
     let lines += [ '' ]
797 821
     let lines += [ 'function! s:old_kde()' ]
798 822
     let lines += [ '  " Konsole only used its own palette up til KDE 4.2.0' ]
@@ -807,8 +831,8 @@ function! s:CSApproxSnapshot(file, overwrite)
807 831
     let lines += [ '' ]
808 832
 
809 833
 
810  
-    let lines += [ 'if 0' ]
811  
-    for round in [ 'konsole', 'eterm', 'xterm', 'urxvt' ]
  834
+    let xterm_colors = {}
  835
+    for round in [ 'xterm', 'konsole', 'eterm', 'urxvt' ]
812 836
       sil! unlet g:CSApprox_eterm
813 837
       sil! unlet g:CSApprox_konsole
814 838
 
@@ -824,54 +848,84 @@ function! s:CSApproxSnapshot(file, overwrite)
824 848
         set t_Co=256
825 849
       endif
826 850
 
  851
+      if round == 'xterm'
  852
+        let lines += [ 'if has("gui_running") || &t_Co == ' . &t_Co ]
  853
+      elseif round == 'konsole'
  854
+        let lines += [ '' ]
  855
+        let lines += [ '    if &term =~# "^xterm" || &term =~# "^screen"' ]
  856
+        let lines += [ '        " that''s an ambiguous terminal setting' ]
  857
+        let lines += [ '        if (exists("g:CSApprox_konsole") && g:CSApprox_konsole) || (&term =~? "^konsole" && s:old_kde())' ]
  858
+      elseif round == 'eterm'
  859
+        let lines += [ '        elseif (exists("g:CSApprox_eterm") && g:CSApprox_eterm) || &term =~? "^eterm"']
  860
+      elseif round == 'urxvt'
  861
+        let lines += [ '        endif' ]
  862
+        let lines += [ '    endif' ]
  863
+        let lines += [ '' ]
  864
+        let lines += [ 'elseif &t_Co == ' . &t_Co ]
  865
+      endif
  866
+
827 867
       call s:CSApprox()
828 868
 
829 869
       let highlights = s:Highlights(["term", "cterm", "gui"])
830 870
       call s:FixupGuiInfo(highlights)
831 871
 
832  
-      if round == 'konsole' || round == 'eterm'
833  
-        if round == 'konsole'
834  
-          let term_matches_round = '(&term =~? "^konsole" && s:old_kde())'
835  
-        else
836  
-          let term_matches_round = '&term =~? "^' . round . '"'
837  
-        endif
838  
-
839  
-        let lines += [ 'elseif has("gui_running") || (&t_Co == ' . &t_Co
840  
-                   \ . ' && (&term ==# "xterm" || &term =~# "^screen")'
841  
-                   \ . ' && exists("g:CSApprox_' . round . '")'
842  
-                   \ . ' && g:CSApprox_' . round . ')'
843  
-                   \ . ' || ' . term_matches_round ]
844  
-      else
845  
-        let lines += [ 'elseif has("gui_running") || &t_Co == ' . &t_Co ]
846  
-      endif
847  
-
848  
-      let hinums = keys(highlights)
849  
-
850  
-      call insert(hinums, remove(hinums, index(hinums, string(s:hlid_normal))))
851  
-
852  
-      for hlnum in hinums
853  
-        let hl = highlights[hlnum]
854  
-        let line = '    CSAHi ' . hl.name
855  
-        for type in [ 'term', 'cterm', 'gui' ]
856  
-          let attrs = s:PossibleAttributes()
857  
-          call filter(attrs, 'hl[type][v:val] == 1')
858  
-          let line .= ' ' . type . '=' . (empty(attrs) ? 'NONE' : join(attrs, ','))
859  
-          if type != 'term'
860  
-            let line .= ' ' . type . 'bg=' . (len(hl[type].bg) ? hl[type].bg : 'bg')
861  
-            let line .= ' ' . type . 'fg=' . (len(hl[type].fg) ? hl[type].fg : 'fg')
862  
-            if type == 'gui' && hl.gui.sp !~ '^\s*$'
863  
-              let line .= ' ' . type . 'sp=' . hl[type].sp
  872
+      " Sort the color groups, for readability
  873
+      let names = sort(keys(highlights))
  874
+      " We need to set the Normal group first so 'bg' and 'fg' work as colors
  875
+      call insert(names, remove(names, index(names, 'Normal')))
  876
+
  877
+      for name in names
  878
+        let hl = highlights[name]
  879
+        let line = ''
  880
+        for mode in [ 'term', 'cterm', 'gui' ]
  881
+          if !empty(hl[mode].extra)
  882
+            let line .= ' ' . mode . '=' . join(hl[mode].extra, ',')
  883
+          endif
  884
+          if mode != 'term'
  885
+            if hl[mode].bg != ''
  886
+              let line .= ' ' . mode . 'bg=' . hl[mode].bg
  887
+            endif
  888
+            if hl[mode].fg != ''
  889
+              let line .= ' ' . mode . 'fg=' . hl[mode].fg
  890
+            endif
  891
+            if mode == 'gui' && hl.gui.sp !~ '^\s*$'
  892
+              let line .= ' ' . mode . 'sp=' . hl[mode].sp
864 893
             endif
865 894
           endif
866 895
         endfor
867  
-        let lines += [ line ]
  896
+        if line == ''
  897
+          continue
  898
+        else
  899
+          let line = '    CSAhi ' . name . line
  900
+        endif
  901
+        if round == 'xterm'
  902
+          " Record what we set in the xterm round
  903
+          let xterm_colors[line] = 1
  904
+        endif
  905
+        if round == 'xterm' || round == 'urxvt'
  906
+          let lines += [ line ]
  907
+          " Write out links for accuracy, in sorted order for readability
  908
+          " Some color schemes set links (see zenburn, ir_black)
  909
+          for link in sort(hl.links)
  910
+            let lines += [ '      CSAlink ' . link . ' ' . hl.name ]
  911
+          endfor
  912
+        elseif round == 'konsole' || round == 'eterm'
  913
+          " only need to output this if it wasn't set in the xterm round
  914
+          if !has_key(xterm_colors, line)
  915
+            let lines += [ '    ' . line ]
  916
+          endif
  917
+        else
  918
+          throw "Internal error snapshotting: " . round
  919
+        endif
868 920
       endfor
869 921
     endfor
870 922
     let lines += [ 'endif' ]
871 923
     let lines += [ '' ]
872  
-    let lines += [ 'if 1' ]
873  
-    let lines += [ '    delcommand CSAHi' ]
874  
-    let lines += [ 'endif' ]
  924
+    let lines += [ 'delcommand CSAlink' ]
  925
+    let lines += [ 'delfunction s:CSAlink' ]
  926
+    let lines += [ 'delcommand CSAhi' ]
  927
+    let lines += [ 'delfunction s:CSAhi' ]
  928
+    let lines += [ 'let syntax_cmd="on"' ]
875 929
     call writefile(lines, file)
876 930
   finally
877 931
     let &t_Co = save_t_Co
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.