From cb8d9bda7263a59f733f05d02633c0b115e7c94a Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Sat, 21 Mar 2020 17:47:37 -0600 Subject: [PATCH 1/4] Highlight hsluv() functions [HSLuv][1] is a color space that is like HSL, but adjusts the lightness component so that each color within the H-S plane is perceptually uniform for each value of L. `hsluv()` is not a valid function in CSS, but there is a new spec ([CSS Color 4][2]) that introduces `lab()` and `lch()`, so `hsluv()` is an extension to that idea. In order to highlight `hsluv()` functions as colors in Vim: * You will need to configure Sass to recognize `hsluv()` as a function. You can make use of my [`sass-hsluv`][3] library to do this. (There are instructions in the README for how to configure Webpack and other bundlers.) * You will need to install two Vim plugins of mine: [`vim-hsluv`][4] and [`vim-css-hsluv`][5] (the latter adds `hsluv()` to a syntax highlighting group; the former has HSLuv color conversion functions). [1]: https://www.hsluv.org/ [2]: https://www.w3.org/TR/css-color-4/#specifying-lab-lch [3]: https://git.sr.ht/~mcmire/sass-hsluv [4]: https://git.sr.ht/~mcmire/vim-hsluv [5]: https://git.sr.ht/~mcmire/vim-css-hsluv --- after/syntax/sass.vim | 2 +- autoload/css_color.vim | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/after/syntax/sass.vim b/after/syntax/sass.vim index 79f8bc0..3571486 100644 --- a/after/syntax/sass.vim +++ b/after/syntax/sass.vim @@ -1 +1 @@ -call css_color#init('css', 'extended', 'sassCssAttribute,sassComment,sassCssComment') +call css_color#init('css', 'extended', 'sassCssAttribute,sassComment,sassCssComment,sassFunction') diff --git a/autoload/css_color.vim b/autoload/css_color.vim index 1d31847..7d605c6 100644 --- a/autoload/css_color.vim +++ b/autoload/css_color.vim @@ -38,6 +38,12 @@ function! s:hsl2color(h,s,l) return printf( '%02x%02x%02x', rgb[0], rgb[1], rgb[2] ) endfunction +function! s:hsluv2color(h,s,l) + let [h,s,l] = map( [a:h,a:s, a:l], 'str2float(v:val)' ) + let rgb = hsluv#to_rgb([h,s,l]) + return printf( '%02x%02x%02x', rgb[0], rgb[1], rgb[2] ) +endfunction + let s:hex={} for i in range(0, 255) let s:hex[ printf( '%02x', i ) ] = i @@ -141,10 +147,12 @@ function! s:create_syn_match() let hexcolor = submatch(1) let funcname = submatch(2) - if funcname == 'rgb' + if funcname == 'rgb' || funcname == 'rgba' let rgb_color = s:rgb2color(submatch(3),submatch(4),submatch(5)) - elseif funcname == 'hsl' + elseif funcname == 'hsl' || funcname == 'hsla' let rgb_color = s:hsl2color(submatch(3),submatch(4),submatch(5)) + elseif funcname == 'hsluv' + let rgb_color = s:hsluv2color(submatch(3),submatch(4),submatch(5)) elseif strlen(hexcolor) == 6 let rgb_color = tolower(hexcolor) elseif strlen(hexcolor) == 3 @@ -203,9 +211,9 @@ function! s:create_matches() endfunction let s:_hexcolor = '#\(\x\{3}\|\x\{6}\)\>' " submatch 1 -let s:_funcname = '\(rgb\|hsl\)a\?' " submatch 2 +let s:_funcname = '\(rgba\?\|hsla\?\|hsluv\)' " submatch 2 let s:_ws_ = '\s*' -let s:_numval = s:_ws_ . '\(\d\{1,3}%\?\)' " submatch 3,4,5 +let s:_numval = s:_ws_ . '\(\d\{1,3}\%(.\d\+\)\?%\?\)' " 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_ . '[)]' From d2efbbd429eaa654b98fa199c8e2d449156e0cb1 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Sat, 21 Mar 2020 21:27:40 -0600 Subject: [PATCH 2/4] Fix check for existence of hsluv plugin --- autoload/css_color.vim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/autoload/css_color.vim b/autoload/css_color.vim index 7d605c6..0d9270c 100644 --- a/autoload/css_color.vim +++ b/autoload/css_color.vim @@ -44,6 +44,8 @@ function! s:hsluv2color(h,s,l) return printf( '%02x%02x%02x', rgb[0], rgb[1], rgb[2] ) endfunction +let s:supports_hsluv = get(g:, 'loaded_hsluv', 0) + let s:hex={} for i in range(0, 255) let s:hex[ printf( '%02x', i ) ] = i @@ -151,7 +153,7 @@ function! s:create_syn_match() let rgb_color = s:rgb2color(submatch(3),submatch(4),submatch(5)) elseif funcname == 'hsl' || funcname == 'hsla' let rgb_color = s:hsl2color(submatch(3),submatch(4),submatch(5)) - elseif funcname == 'hsluv' + elseif funcname == 'hsluv' && s:supports_hsluv let rgb_color = s:hsluv2color(submatch(3),submatch(4),submatch(5)) elseif strlen(hexcolor) == 6 let rgb_color = tolower(hexcolor) @@ -211,7 +213,7 @@ function! s:create_matches() endfunction let s:_hexcolor = '#\(\x\{3}\|\x\{6}\)\>' " submatch 1 -let s:_funcname = '\(rgba\?\|hsla\?\|hsluv\)' " submatch 2 +let s:_funcname = s:supports_hsluv ? '\(rgba\?\|hsla\?\|hsluv\)' : '\(rgba\?\|hsla\?\)' " submatch 2 let s:_ws_ = '\s*' let s:_numval = s:_ws_ . '\(\d\{1,3}\%(.\d\+\)\?%\?\)' " submatch 3,4,5 let s:_listsep = s:_ws_ . ',' From cf94b8368c17719809b62cd1fdfc0548250bb512 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Sat, 21 Mar 2020 21:28:04 -0600 Subject: [PATCH 3/4] Fix hue so that it doesn't get transformed --- autoload/css_color.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autoload/css_color.vim b/autoload/css_color.vim index 0d9270c..84cd11f 100644 --- a/autoload/css_color.vim +++ b/autoload/css_color.vim @@ -39,7 +39,8 @@ function! s:hsl2color(h,s,l) endfunction function! s:hsluv2color(h,s,l) - let [h,s,l] = map( [a:h,a:s, a:l], 'str2float(v:val)' ) + let h = str2float(a:h) + let [s,l] = map( [a:s, a:l], 'v:val =~ "%$" ? str2float(v:val) : str2float(v:val) * 100.0' ) let rgb = hsluv#to_rgb([h,s,l]) return printf( '%02x%02x%02x', rgb[0], rgb[1], rgb[2] ) endfunction From 533e816a902e7c6421d4e45d5c7b0aed9f4e5d2a Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Sat, 21 Mar 2020 21:28:29 -0600 Subject: [PATCH 4/4] Introduce syntax highlighting for hsluv() functions Originally I was going to introduce this as a separate plugin, but it belongs here. --- after/syntax/css.vim | 10 ++++++++++ after/syntax/sass.vim | 11 +++++++++++ after/syntax/scss.vim | 13 ++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/after/syntax/css.vim b/after/syntax/css.vim index 1b45f23..4bf3454 100644 --- a/after/syntax/css.vim +++ b/after/syntax/css.vim @@ -1 +1,11 @@ call css_color#init('css', 'extended', 'cssMediaBlock,cssFunction,cssDefinition,cssAttrRegion,cssComment') + +syn clear cssFunction + +" Have to override all of these over again because of the clear :( +" Source: +syn region cssFunction contained matchgroup=cssFunctionName start="\<\(var\|calc\)\s*(" end=")" contains=cssCustomProp,cssValue.*,cssFunction,cssColor,cssStringQ,cssStringQQ oneline +syn region cssFunction contained matchgroup=cssFunctionName start="\<\(rgb\|clip\|attr\|counter\|rect\|cubic-bezier\|steps\)\s*(" end=")" oneline contains=cssValueInteger,cssValueNumber,cssValueLength,cssFunctionComma +syn region cssFunction contained matchgroup=cssFunctionName start="\<\(rgba\|hsl\|hsla\|hsluv\|color-stop\|from\|to\)\s*(" end=")" oneline contains=cssColor,cssValueInteger,cssValueNumber,cssValueLength,cssFunctionComma,cssFunction +syn region cssFunction contained matchgroup=cssFunctionName start="\<\(linear-\|radial-\)\=\gradient\s*(" end=")" oneline contains=cssColor,cssValueInteger,cssValueNumber,cssValueLength,cssFunction,cssGradientAttr,cssFunctionComma +syn region cssFunction contained matchgroup=cssFunctionName start="\<\(matrix\(3d\)\=\|scale\(3d\|X\|Y\|Z\)\=\|translate\(3d\|X\|Y\|Z\)\=\|skew\(X\|Y\)\=\|rotate\(3d\|X\|Y\|Z\)\=\|perspective\)\s*(" end=")" oneline contains=cssValueInteger,cssValueNumber,cssValueLength,cssValueAngle,cssFunctionComma diff --git a/after/syntax/sass.vim b/after/syntax/sass.vim index 3571486..5f0a046 100644 --- a/after/syntax/sass.vim +++ b/after/syntax/sass.vim @@ -1 +1,12 @@ call css_color#init('css', 'extended', 'sassCssAttribute,sassComment,sassCssComment,sassFunction') + +syn clear sassFunction + +" Have to override all of these over again because of the clear :( +" Source: +syn match sassFunction "\<\%(rgb\|rgba\|red\|green\|blue\|mix\)\>(\@=" contained +syn match sassFunction "\<\%(hsl\|hsla\|hsluv\|hue\|saturation\|lightness\|adjust-hue\|lighten\|darken\|saturate\|desaturate\|grayscale\|complement\)\>(\@=" contained +syn match sassFunction "\<\%(alpha\|opacity\|rgba\|opacify\|fade-in\|transparentize\|fade-out\)\>(\@=" contained +syn match sassFunction "\<\%(unquote\|quote\)\>(\@=" contained +syn match sassFunction "\<\%(percentage\|round\|ceil\|floor\|abs\)\>(\@=" contained +syn match sassFunction "\<\%(type-of\|unit\|unitless\|comparable\)\>(\@=" contained diff --git a/after/syntax/scss.vim b/after/syntax/scss.vim index 57569b1..3465b8f 100644 --- a/after/syntax/scss.vim +++ b/after/syntax/scss.vim @@ -1 +1,12 @@ -call css_color#init('css', 'extended', 'scssAttribute,scssComment,scssVariableValue,scssMap,scssMapValue,sassCssAttribute,cssComment') +call css_color#init('css', 'extended', 'scssAttribute,scssComment,scssVariableValue,scssMap,scssMapValue,sassCssAttribute,cssComment,sassFunction') + +syn clear sassFunction + +" Have to override all of these over again because of the clear :( +" Source: +syn match sassFunction "\<\%(rgb\|rgba\|red\|green\|blue\|mix\)\>(\@=" contained +syn match sassFunction "\<\%(hsl\|hsla\|hsluv\|hue\|saturation\|lightness\|adjust-hue\|lighten\|darken\|saturate\|desaturate\|grayscale\|complement\)\>(\@=" contained +syn match sassFunction "\<\%(alpha\|opacity\|rgba\|opacify\|fade-in\|transparentize\|fade-out\)\>(\@=" contained +syn match sassFunction "\<\%(unquote\|quote\)\>(\@=" contained +syn match sassFunction "\<\%(percentage\|round\|ceil\|floor\|abs\)\>(\@=" contained +syn match sassFunction "\<\%(type-of\|unit\|unitless\|comparable\)\>(\@=" contained