Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New features, bugfixes, better testing #187

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3e7d1de
overflow check
adamhotep May 26, 2023
7d597ee
support for decimals and spaced color values
adamhotep May 26, 2023
583e8c2
awk is faster and more broadly installed than perl, support neovim an…
adamhotep May 27, 2023
a696232
more comprehensive tests
adamhotep May 28, 2023
b54bcf5
support overflow/wraparound values, stricter adherence to formats, ad…
adamhotep May 28, 2023
993a0a5
bench script didn't work with -o, split it up per-file and added a "t…
adamhotep May 28, 2023
928bee7
better comment for pctvet
adamhotep May 28, 2023
caaf911
removed hack to avoid `white-space` since it's already avoided by isk…
adamhotep May 29, 2023
9ba1cc7
bench: run `bc` just once, exit cleanly unless the syntax was never run
adamhotep May 29, 2023
8bfd21e
consistent test order for FP section
adamhotep May 29, 2023
342554c
HTML: fix broken CSS syntax within HTML attributes, add legacy HTML3 …
adamhotep May 29, 2023
42f7c03
HTML: tests for legacy HTML3 colors, etc
adamhotep May 29, 2023
5dda713
commented "solution" to coloring the `tan()` function
adamhotep May 29, 2023
1db0b4d
address the concern in ap/vim-css-color#127 by canonicalizing the path
adamhotep May 29, 2023
a6846bf
fix ap/vim-css-color#140
adamhotep May 30, 2023
e31df59
html3 colors don't support color functions. Just names and 3/6-digit hex
adamhotep Jun 1, 2023
ebde02e
svg in html
adamhotep Aug 27, 2023
dbb7b15
upstream merge (manual)
adamhotep Aug 27, 2023
a24b250
upstream merge (manual)
adamhotep Aug 27, 2023
4743366
svg in html
adamhotep Aug 27, 2023
7046f10
Merge branch 'master' into master
adamhotep Aug 27, 2023
dd89390
svg comment tests
adamhotep Aug 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion after/syntax/html.vim
Original file line number Diff line number Diff line change
@@ -1,2 +1,42 @@
" default html syntax should already be including the css syntax
call css_color#init('none', 'none', 'htmlCommentPart,htmlString')
" but tag style attributes don't properly apply CSS syntax (as of vim 9.0.1378).
" Correct the bug by replacing htmlCssDefinition with a new htmlCssContent: {{{
syn keyword htmlCssArg contained containedin=htmlTag nextgroup=htmlCssEq style
syn match htmlCssEq contained +=+ nextgroup=htmlCssQuote
syn match htmlCssQuote contained +["']+ nextgroup=htmlCssContent
syn region htmlCssContent contained start=+\%("\)\@<=.+ end=+"+ keepend contains=cssTagName,cssAttributeSelector,cssClassName,cssIdentifier,cssAtRule,cssAttrRegion,css.*Prop,cssComment,cssValue.*,cssColor,cssURL,cssImportant,cssCustomProp,cssError,cssStringQ,cssFunction,cssUnicodeEscape,cssVendor,cssHacks,cssNoise
syn region htmlCssContent contained start=+\%('\)\@<=.+ end=+'+ keepend contains=cssTagName,cssAttributeSelector,cssClassName,cssIdentifier,cssAtRule,cssAttrRegion,css.*Prop,cssComment,cssValue.*,cssColor,cssURL,cssImportant,cssCustomProp,cssError,cssStringQ,cssFunction,cssUnicodeEscape,cssVendor,cssHacks,cssNoise

hi def link htmlCssArg htmlArg
hi def link htmlCssEq htmlTag
hi def link htmlCssQuote htmlString
" end bugfix }}}

call css_color#init('css', 'extended', 'htmlCssContent,htmlCommentPart')

" SVG in HTML
"syn keyword htmlTagName contained svg text textPath tspan
syn include @htmlSvgColors after/syntax/svg.vim
syn region htmlSvg start=+<\s*svg\>+ end=+<\s*/svg\s*>+ keepend contains=@htmlXml,htmlTagName,@htmlSvgColors

" Legacy HTML 3-style color declarations (depcecated) {{{
" Search https://www.w3.org/TR/html4/index/attributes.html for `%Color;`
syn region htmlTag start=+<\s*body\s+ end=+>+ fold contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,@htmlPreproc,@htmlArgCluster,htmlTagBodyColors
syn keyword htmlTagBodyColors contained nextgroup=htmlLegacyColor text bgcolor link alink vlink
syn region htmlTag start=+<\s*\%(table\|t[rdh]\)\s+ end=+>+ fold contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,@htmlPreproc,@htmlArgCluster,htmlBgColors
syn keyword htmlBgColors contained nextgroup=htmlLegacyColor bgcolor
syn region htmlTag start=+<\s*\%(base\)\?font\s+ end=+>+ fold contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,@htmlPreproc,@htmlArgCluster,htmlFgColors
syn keyword htmlFgColors contained nextgroup=htmlLegacyColor color
" The spec only supports named colors & hash-prefixed RGB hex with 3 or 6 chars.
" (Both FF & Chrome use IE's crazy "flex hex" formula to convert anything else to hex:
" https://scrappy-do.blogspot.com/2004/08/little-rant-about-microsoft-internet.html -- we're NOT doing that.)
" BUG: I should have been able to specify this as +="[^"]\+"+ and +="[^"]\+"+ and set what
" matches with the args to css_color#init(), but that doesn't seem to work (overridden?)
syn match htmlLegacyColor contained +=\(['"]\)\%(#\x\{3\}\%(\x\{3\}\)\?\|[A-Za-z]\+\)\1+ contains=cssColor

hi def link htmlTagBodyColors htmlArg
hi def link htmlBgColors htmlArg
hi def link htmlFgColors htmlArg

call css_color#init('hex', 'extended', 'htmlLegacyColor')
" end legacy HTML-3 color attributes }}}
10 changes: 9 additions & 1 deletion after/syntax/svg.vim
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
call css_color#init('rgba', 'basic', 'xmlComment,xmlCommentPart,xmlString')
syn region xmlTag start=+<\s*\%(circle\|ellipse\|line\|path\|poly\%(gon\|line\)\|rect\|text\%(path\)\?\|tref\|tspan\)\s+ end=+>+ fold contains=xmlTagName,xmlAttrib,xmlEqual,xmlString,@xmlStartTagHook,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,@htmlPreproc,@htmlArgCluster,svgAttrib
syn keyword svgAttrib contained containedin=xmlTag nextgroup=svgColor fill color stroke sop-color flood-color lighting-color
syn match svgColor contained +="[^"]\+"+
syn match svgColor contained +='[^']\+'+

hi def link svgAttrib Type
hi def link svgColor String

call css_color#init('css', 'extended', 'svgColor')
119 changes: 102 additions & 17 deletions autoload/css_color.vim
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,60 @@ if ! ( v:version >= 700 && has('syntax') && ( has('gui_running') || has('nvim')
finish
endif

let s:_invalid = -9999 " used after bounding/wrapping, so this is safe

" Add open-parens as a keyword char to avoid coloring function names like tan().
" This is ... not advised; it's unclear what it might break
"syn iskeyword @,40,48-57,_,192-255,-

function! s:bound(n, min, max)
let n = a:n
if n < a:min | let n = a:min
elseif n > a:max | let n = a:max | endif
return str2nr( string(n + 0.5) )
endfunction

function! s:rgb2hex(r, g, b)
let [r,g,b] = map( [a:r,a:g,a:b], 's:bound(v:val, 0, 255)' )
return printf( '%02x%02x%02x', r, g, b )
endfunction

function! s:rgb2color(r,g,b)
" Convert 80% -> 204, 100% -> 255, etc.
let rgb = map( [a:r,a:g,a:b], 'v:val =~ "%$" ? ( 255 * v:val ) / 100 : v:val' )
return printf( '%02x%02x%02x', rgb[0], rgb[1], rgb[2] )
" Convert 35.6% -> 90.78, 80% -> 204, 100% -> 255, etc.
let [r,g,b] = map( [a:r,a:g,a:b], 'v:val =~ "%$" ? str2float(v:val) * 2.55 : str2float(v:val)' )
return s:rgb2hex(r, g, b)
endfunction

" Vimscript modulo can't handle decimals. Fix that.
function! s:modulo(a, b)
let num = str2nr( string(a:a) )
let extra = a:a - num
return str2nr(a:a - extra) % a:b + extra
endfunction

function! s:angle2deg(angle, units)
let deg = str2float(a:angle)
" angles: https://developer.mozilla.org/en-US/docs/Web/CSS/angle
if a:units == "rad"
let deg = deg * 57.29577951308232 " deg = rad * 180 / pi, 360deg == 6.2832rad
elseif a:units == "grad"
let deg = deg * 0.9 " 360deg = 400grad
elseif a:units == "turn"
let deg = deg * 360.0 " 360deg = 1turn
elseif a:units != "" && a:units != "deg"
return s:_invalid " percent is invalid here
endif
let deg = s:modulo(deg, 360)
if deg < 0 | let deg = deg + 360 | endif
return deg
endfunction

function! s:hsl2color(h,s,l)
" Convert 80% -> 0.8, 100% -> 1.0, etc.
let [s,l] = map( [a:s, a:l], 'v:val =~ "%$" ? v:val / 100.0 : v:val + 0.0' )
function! s:hsl2rgb(h,u,s,l)
let [s,l] = map( [a:s, a:l], 'str2nr(v:val) >= 1 ? 1.0 : str2float(v:val)' )
" algorithm transcoded to vim from http://www.w3.org/TR/css3-color/#hsl-color
let hh = ( a:h % 360 ) / 360.0
let hh = s:angle2deg(a:h, a:u)
if hh == s:_invalid | return [hh,hh,hh] | endif
let hh = hh / 360.0
let m2 = l <= 0.5 ? l * ( s + 1 ) : l + s - l * s
let m1 = l * 2 - m2
let rgb = []
Expand All @@ -32,12 +75,49 @@ function! s:hsl2color(h,s,l)
\ h * 2 < 1 ? m2 :
\ h * 3 < 2 ? m1 + ( m2 - m1 ) * ( 2/3.0 - h ) * 6 :
\ m1
if v > 1.0 | return '' | endif
if v > 1.0 | return [s:_invalid, s:_invalid, s:_invalid] | endif
let rgb += [ float2nr( 255 * v ) ]
endfor
return printf( '%02x%02x%02x', rgb[0], rgb[1], rgb[2] )
return rgb
endfunction

" vet hsl and hwb values
function! s:pctvet(h,s,l)
" hue cannot be a percent, others must be percents (except for sass & scss)
if a:h =~ "%$" || b:current_syntax !~ "s[ac]ss$" && (a:s !~ "%$" || a:l !~ "%$")
return [s:_invalid, s:_invalid, s:_invalid]
endif
let [s,l] = map( [a:s, a:l], 'v:val >= 100 ? 1.0 : v:val / 100.0' )
return [a:h, s, l]
endfunction

function! s:hsl2color(h,u,s,l)
let [h,s,l] = s:pctvet(a:h, a:s, a:l) " convert saturation & luminance % -> num
if h == s:_invalid | return '' | endif
let [r,g,b] = s:hsl2rgb(h, a:u, s, l)
if r == s:_invalid | return '' | endif
return s:rgb2hex(r, g, b)
endfunction

function! s:hwb2color(h,u,w,b)
let [h,w,b] = s:pctvet(a:h, a:w, a:b) " convert whiteness & blackness % -> num
if h == s:_invalid | return '' | endif
" algorithm transcoded to vim from https://drafts.csswg.org/css-color/#hwb-to-rgb
if w + b >= 1
let gray = w / (w + b)
let [r,g,b] = [gray,gray,gray]
else
let [r,g,b] = map( s:hsl2rgb(a:h, a:u, 1.0, 0.5), 'v:val * (1 - w - b) + w' )
endif
return s:rgb2hex(r, g, b)
endfunction

" TODO (probably not): new "device-independent colors":
" lch(), oklch(), lab(), oklab(), and color().
" These look hard and I don't see reference algorithms to convert to sRGB.
" https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
" https://drafts.csswg.org/css-color/#lab-colors

let s:_1_3 = 1.0/3
let s:_16_116 = 16.0/116.0
let s:cos16 = cos(16*(180/atan2(0,-1)))
Expand Down Expand Up @@ -170,14 +250,17 @@ function! s:create_syn_match()
let hex = submatch(1)
let funcname = submatch(2)

if funcname =~ 'rgb' && submatch(4) != '' | return '' | endif " rgb() doesn't support units

let rgb_color
\ = funcname == 'rgb' ? s:rgb2color(submatch(3),submatch(4),submatch(5))
\ : funcname == 'hsl' ? s:hsl2color(submatch(3),submatch(4),submatch(5))
\ = funcname =~ '^rgb' ? s:rgb2color(submatch(3),submatch(5),submatch(6))
\ : funcname =~ '^hsl' ? s:hsl2color(submatch(3),submatch(4),submatch(5),submatch(6))
\ : funcname == 'hwb' ? s:hwb2color(submatch(3),submatch(4),submatch(5),submatch(6))
\ : strlen(hex) >= 6 ? tolower(hex[0:5])
\ : strlen(hex) >= 3 ? tolower(hex[0].hex[0].hex[1].hex[1].hex[2].hex[2])
\ : ''

if rgb_color == '' | throw 'css_color: create_syn_match invoked on bad match data' | endif
if rgb_color == '' | return '' | endif
let s:pattern_color[pattern] = rgb_color
endif

Expand Down Expand Up @@ -229,12 +312,14 @@ endfunction

let s:_hexcolor = '#\(\x\{3}\%(\>\|\x\{3}\>\)\)' " submatch 1
let s:_rgbacolor = '#\(\x\{3}\%(\>\|\x\%(\>\|\x\{2}\%(\>\|\x\{2}\>\)\)\)\)' " submatch 1
let s:_funcname = '\(rgb\|hsl\)a\?' " submatch 2
let s:_funcname = '\(rgb\a\?\|hsla\?\|hwb\)' " submatch 2
let s:_consistent = '\%(\%(\s\+[0-9.%]\+\)\{2}\s*\%(\/\s*[-0-9.%]\+\)\?[)]\|\%(\s*,\s*[-0-9.%]\+\)\{2,3}[)]\)\@=' " lookahead: 1 2 3 or 1 2 3/4 or 1,2,3 or 1,2,3,4 after 1
let s:_ws_ = '\s*'
let s:_numval = s:_ws_ . '\(\d\{1,3}%\?\)' " submatch 3,4,5
let s:_listsep = s:_ws_ . ','
let s:_otherargs_ = '\%(,[^)]*\)\?'
let s:_funcexpr = s:_funcname . '[(]' . s:_numval . s:_listsep . s:_numval . s:_listsep . s:_numval . s:_ws_ . s:_otherargs_ . '[)]'
let s:_numval = '\(-\?\d\{1,3}\%(\.\d*\)\?%\?\)' " submatch 3,5,6
let s:_units = '\(deg\|g\?rad\|turn\)\?' " submatch 4
let s:_listsep = s:_ws_ . '[,[:space:]]\+'
let s:_otherargs_ = s:_ws_ . '\%([,\/][^)]*\)\?' " ignore alpha
let s:_funcexpr = s:_funcname . '[(]' . s:_ws_ . s:_numval . s:_units . s:_consistent . s:_listsep . s:_numval . s:_listsep . s:_numval . s:_otherargs_ . '[)]'
let s:_csscolor = s:_rgbacolor . '\|' . s:_funcexpr
" N.B. sloppy heuristic constants for performance reasons:
" a) start somewhere left of screen in case of partially visible colorref
Expand Down
2 changes: 1 addition & 1 deletion syntax/colornames/basic.vim
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ syn case ignore
syn keyword BG000000 black contained containedin=@colorableGroup
syn keyword BGc0c0c0 silver contained containedin=@colorableGroup
syn keyword BG808080 gray contained containedin=@colorableGroup
syn match BGffffff "\c\<white\(-\)\@!\>" contained containedin=@colorableGroup
syn keyword BGffffff white contained containedin=@colorableGroup
syn keyword BG800000 maroon contained containedin=@colorableGroup
syn keyword BGff0000 red contained containedin=@colorableGroup
syn keyword BG800080 purple contained containedin=@colorableGroup
Expand Down
17 changes: 13 additions & 4 deletions tests/bench
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
#!/bin/sh
set -e
s=startuptime.txt
vim --startuptime $s -o -c qa "$@"
perl -lane'$sum += $F[1] if m!/\.vim/after/syntax/css\.vim$!; END {print $sum}' $s
rm $s
this=$(realpath "$0" 2>/dev/null || readlink -f "$0")
[ $# = 0 ] && cd "${this%/*}" && set -- *.* # default to all files with a dot
target="${this%/tests/*}/after/syntax/css.vim"
[ $# -gt 1 ] && multi=1 || multi=
for sample in "$@"; do
vim --startuptime $s -c qa "$sample"
run=$(awk -v t="$target" 'index($0, t) {sum += $2} END {print sum}' "$s")
rm $s
echo "$run${multi:+\t$sample}"
total="${total:-0} + ${run:-0}"
done
# if multi, show the sum total. otherwise, return true only if we had a run.
[ -n "$multi" ] && echo "$(echo "$total" |bc -ql)\t(total)" || [ -n "$run" ]
22 changes: 22 additions & 0 deletions tests/example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<html><head><style type="text/css">
/* This section is small because we want to focus on HTML style attributes.
See example.css or suite.css for better tests for this section. */
.red { color: #faa !important; white-space:nowrap }
</style>
</head><body text="white" bgcolor="#777" link="cyan" alink="#0f0">

<!-- TODO: eat green #f00d, make gold, get a tan -->

<p class="red red-room" style="color:red; white-space:nowrap">#faa</p>

<p class='blue seeing-red' style='color:red' data-red='red'>#ff0000</p>

<!-- We don't color bgcolor here because <font> doesn't support it. -->
<p>Text that is <font color="#600" bgcolor="#aaffff">red</font>.</p>

<p>
Here's a <a href="example.html">visited link</a>
and an <a href="https://127.123.45.43:21">unvisited link</a>.
</p>

</body></html>
2 changes: 1 addition & 1 deletion tests/example.sass
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ s
!color1 = #359
!color2 = #335599
!color3 = rgba(144, 0, 0, .5)
!color4 = hsl(0, 100%, 50%)
!color4 = hsl(0, 100, 50)

/*
* #123, #456
Expand Down
2 changes: 1 addition & 1 deletion tests/example.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ s { background: hsl(0, 100%, 50%) }
$color1: #359;
$color2: #335599;
$color3: rgba(144, 0, 0, .5);
$color4: hsl(0, 100%, 50%);
$color4: hsl(0, 100, 50);

/*
* #123, #456
Expand Down
14 changes: 14 additions & 0 deletions tests/example.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading