aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakianonymus <anonymus.aki@gmail.com>2023-02-26 23:12:48 +0530
committerakianonymus <anonymus.aki@gmail.com>2023-02-26 23:14:44 +0530
commitebb03999a8cffcd927e36d54062d9d01e868992b (patch)
tree406b26a8ec2b0d6832c7f17423b0ecb92bfe58ea
parentfix: hsl: for multiple spaces in between (diff)
feat: Support modern rgb/rgba syntax
https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb
-rw-r--r--lua/colorizer/color.lua126
-rw-r--r--lua/colorizer/matcher.lua2
-rw-r--r--lua/colorizer/utils.lua17
-rw-r--r--test/expectation.txt7
4 files changed, 86 insertions, 66 deletions
diff --git a/lua/colorizer/color.lua b/lua/colorizer/color.lua
index fe3e15b..370131b 100644
--- a/lua/colorizer/color.lua
+++ b/lua/colorizer/color.lua
@@ -14,7 +14,6 @@ local byte_is_hex = utils.byte_is_hex
local byte_is_valid_colorchar = utils.byte_is_valid_colorchar
local count = utils.count
local parse_hex = utils.parse_hex
-local percent_or_hex = utils.percent_or_hex
local color = {}
@@ -298,76 +297,111 @@ function color.name_parser(line, i, opts)
end
end
+local CSS_RGBA_FN_MINIMUM_LENGTH = #"rgba(0,0,0)" - 1
local CSS_RGB_FN_MINIMUM_LENGTH = #"rgb(0,0,0)" - 1
----Parse for rgb() css function and return rgb hex.
+---Parse for rgb() rgba() css function and return rgb hex.
+-- For more info: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb
---@param line string: Line to parse
---@param i number: Index of line from where to start parsing
----@return number|nil: Index of line where the rgb function ended
+---@param opts table: Values passed from matchers like prefix
+---@return number|nil: Index of line where the rgb/rgba function ended
---@return string|nil: rgb hex value
-function color.rgb_function_parser(line, i)
- if #line < i + CSS_RGB_FN_MINIMUM_LENGTH then
- return
- end
- local r, g, b, match_end = line:sub(i):match "^rgb%(%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*(%d+%%?)%s*%)()"
- if not match_end then
- r, g, b, match_end = line:sub(i):match "^rgb%(%s*(%d+%%?)%s+(%d+%%?)%s+(%d+%%?)%s*%)()"
- if not match_end then
- return
- end
- end
- r = percent_or_hex(r)
- if not r then
- return
+function color.rgb_function_parser(line, i, opts)
+ local min_len = CSS_RGBA_FN_MINIMUM_LENGTH
+ local min_commas, min_spaces, min_percent = 2, 2, 3
+ local pattern = "^"
+ .. opts.prefix
+ .. "%(%s*([.%d]+)([%%]?)(%s?)%s*(,?)%s*([.%d]+)([%%]?)(%s?)%s*(,?)%s*([.%d]+)([%%]?)%s*(/?,?)%s*([.%d]*)([%%]?)%s*%)()"
+
+ if opts.prefix == "rgb" then
+ min_len = CSS_RGB_FN_MINIMUM_LENGTH
end
- g = percent_or_hex(g)
- if not g then
+
+ if #line < i + min_len then
return
end
- b = percent_or_hex(b)
- if not b then
+
+ local r, unit1, ssep1, csep1, g, unit2, ssep2, csep2, b, unit3, sep3, a, unit_a, match_end =
+ line:sub(i):match(pattern)
+ if not match_end then
return
end
- local rgb_hex = string.format("%02x%02x%02x", r, g, b)
- return match_end - 1, rgb_hex
-end
-local CSS_RGBA_FN_MINIMUM_LENGTH = #"rgba(0,0,0,0)" - 1
----Parse for rgba() css function and return rgb hex.
--- Todo consider removing the regexes here
--- Todo this might not be the best approach to alpha channel.
--- Things like pumblend might be useful here.
----@param line string: Line to parse
----@param i number: Index of line from where to start parsing
----@return number|nil: Index of line where the rgba function ended
----@return string|nil: rgb hex value
-function color.rgba_function_parser(line, i)
- if #line < i + CSS_RGBA_FN_MINIMUM_LENGTH then
- return
+ if a == "" then
+ a = nil
+ else
+ min_commas = min_commas + 1
end
- local r, g, b, a, match_end =
- line:sub(i):match "^rgba%(%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*([.%d]+)%s*%)()"
- if not match_end then
- r, g, b, a, match_end = line:sub(i):match "^rgba%(%s*(%d+%%?)%s+(%d+%%?)%s+(%d+%%?)%s+([.%d]+)%s*%)()"
- if not match_end then
+
+ local units = ("%s%s%s"):format(unit1, unit2, unit3)
+ if units:match "%%" then
+ if not ((count(units, "%%")) == min_percent) then
return
end
end
- a = tonumber(a)
- if not a or a > 1 then
+
+ local c_seps = ("%s%s%s"):format(csep1, csep2, sep3)
+ local s_seps = ("%s%s"):format(ssep1, ssep2)
+ -- comma separator syntax
+ if c_seps:match "," then
+ if not (count(c_seps, ",") == min_commas) then
+ return
+ end
+ -- space separator syntax with decimal or percentage alpha
+ elseif count(s_seps, "%s") >= min_spaces then
+ if a then
+ if not (c_seps == "/") then
+ return
+ end
+ end
+ else
return
end
- r = percent_or_hex(r)
+
+ if not a then
+ a = 1
+ else
+ a = tonumber(a)
+ -- if percentage, then convert to decimal
+ if unit_a == "%" then
+ a = a / 100
+ end
+ -- although alpha doesn't support larger values than 1, css anyways renders it at 1
+ if a > 1 then
+ a = 1
+ end
+ end
+
+ r = tonumber(r)
if not r then
return
end
- g = percent_or_hex(g)
+ g = tonumber(g)
if not g then
return
end
- b = percent_or_hex(b)
+ b = tonumber(b)
if not b then
return
end
+
+ if unit1 == "%" then
+ r = r / 100 * 255
+ g = g / 100 * 255
+ b = b / 100 * 255
+ else
+ -- although r,g,b doesn't support larger values than 255, css anyways renders it at 255
+ if r > 255 then
+ r = 255
+ end
+ if g > 255 then
+ g = 255
+ end
+ if b > 255 then
+ b = 255
+ end
+ end
+
local rgb_hex = string.format("%02x%02x%02x", r * a, g * a, b * a)
return match_end - 1, rgb_hex
end
diff --git a/lua/colorizer/matcher.lua b/lua/colorizer/matcher.lua
index 21d7b4f..ccd72a2 100644
--- a/lua/colorizer/matcher.lua
+++ b/lua/colorizer/matcher.lua
@@ -15,7 +15,7 @@ local B_HASH, DOLLAR_HASH = ("#"):byte(), ("$"):byte()
local parser = {
["_0x"] = color.argb_hex_parser,
["_rgb"] = color.rgb_function_parser,
- ["_rgba"] = color.rgba_function_parser,
+ ["_rgba"] = color.rgb_function_parser,
["_hsl"] = color.hsl_function_parser,
["_hsla"] = color.hsl_function_parser,
}
diff --git a/lua/colorizer/utils.lua b/lua/colorizer/utils.lua
index 724b46e..ae590cd 100644
--- a/lua/colorizer/utils.lua
+++ b/lua/colorizer/utils.lua
@@ -122,25 +122,10 @@ function utils.parse_hex(byte)
return rshift(BYTE_CATEGORY[byte], 4)
end
-local b_percent = string.byte "%"
---- Obvious.
----@param v string
----@return number|nil
-function utils.percent_or_hex(v)
- if v:byte(-1) == b_percent then
- return tonumber(v:sub(1, -2)) / 100 * 255
- end
- local x = tonumber(v)
- if x > 255 then
- return
- end
- return x
-end
-
--- Watch a file for changes and execute callback
---@param path string: File path
---@param callback function: Callback to execute
----@param ... array: params for callback
+---@param ... table: params for callback
---@return function|nil
function utils.watch_file(path, callback, ...)
if not path or type(callback) ~= "function" then
diff --git a/test/expectation.txt b/test/expectation.txt
index e3cc609..6150778 100644
--- a/test/expectation.txt
+++ b/test/expectation.txt
@@ -18,8 +18,10 @@ White
#def #deadbeef
-rgb(0,0,0) rgb(10, 100 , 100)
-rgba(200,30,0,1) rgba(200,30,0,0.5)
+rgb( 31 12.90 50 /0.5) rgb( 10, 100 , 100, 0.3)
+rgb(30% 20% 50%) rgb(0,0,0) rgb(255 122 127 / 80%)
+rgb(255 122 127 / .2) rgba(200,30,0,1) rgba(200,30,0,0.5)
+
hsl(300 50% 50%) hsl(300 50% 50% / 1) hsl(100 80% 50% / 0.4)
hsl(990 80% 50% / 0.4) hsl(720 80% 50% / 0.4)
hsl(1turn 80% 50% / 0.4) hsl(0.4turn 80% 50% / 0.4) hsl(1.4turn 80% 50% / 0.4)
@@ -38,7 +40,6 @@ Blueberry Gray1000 BlueGree BlueGray
#define
#def0
matcher#add
-rgb(10,256,100)
rgb (10,255,100)
rgb(10, 1 00 , 100)
hsl(300 50% 50% 1)