aboutsummaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua')
-rw-r--r--lua/colorizer/color.lua111
-rw-r--r--lua/colorizer/matcher.lua8
2 files changed, 73 insertions, 46 deletions
diff --git a/lua/colorizer/color.lua b/lua/colorizer/color.lua
index 9cfac2a..37f8f30 100644
--- a/lua/colorizer/color.lua
+++ b/lua/colorizer/color.lua
@@ -86,76 +86,99 @@ function color.hsl_to_rgb(h, s, l)
255 * color.hue_to_rgb(p, q, h - 1 / 3)
end
+local CSS_HSLA_FN_MINIMUM_LENGTH = #"hsla(0,0%,0%)" - 1
local CSS_HSL_FN_MINIMUM_LENGTH = #"hsl(0,0%,0%)" - 1
----Parse for hsl() css function and return rgb hex.
+---Parse for hsl() hsla() css function and return rgb hex.
+-- For more info: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl
---@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 hsl function ended
+---@param opts table: Values passed from matchers like prefix
+---@return number|nil: Index of line where the hsla/hsl function ended
---@return string|nil: rgb hex value
-function color.hsl_function_parser(line, i)
- if #line < i + CSS_HSL_FN_MINIMUM_LENGTH then
- return
- end
- local h, s, l, match_end = line:sub(i):match "^hsl%(%s*(%d+)%s*,%s*(%d+)%%%s*,%s*(%d+)%%%s*%)()"
- if not match_end then
- h, s, l, match_end = line:sub(i):match "^hsl%(%s*(%d+)%s+(%d+)%%%s+(%d+)%%%s*%)()"
- if not match_end then
- return
- end
+function color.hsl_function_parser(line, i, opts)
+ local min_len = CSS_HSLA_FN_MINIMUM_LENGTH
+ local min_commas, min_spaces = 2, 2
+ local pattern = "^"
+ .. opts.prefix
+ .. "%(%s*([.%d]+)([deg]*)([turn]*)(,?)(%s?)%s*(%d+)%%(,?)(%s?)%s*(%d+)%%%s*(/?,?)%s*([.%d]*)([%%]?)%s*%)()"
+
+ if opts.prefix == "hsl" then
+ min_len = CSS_HSL_FN_MINIMUM_LENGTH
end
- h = tonumber(h)
- if h > 360 then
+
+ if #line < i + min_len then
return
end
- s = tonumber(s)
- if s > 100 then
+
+ local h, deg, turn, csep1, ssep1, s, csep2, ssep2, l, sep3, a, percent_sign, match_end = line:sub(i):match(pattern)
+ if not match_end then
return
end
- l = tonumber(l)
- if l > 100 then
- return
+ if a == "" then
+ a = nil
+ else
+ min_commas = min_commas + 1
end
- local r, g, b = color.hsl_to_rgb(h / 360, s / 100, l / 100)
- if r == nil or g == nil or b == nil then
+
+ -- the text after hue should be either deg or empty
+ if not ((deg == "") or (deg == "deg") or (turn == "turn")) then
return
end
- local rgb_hex = string.format("%02x%02x%02x", r, g, b)
- return match_end - 1, rgb_hex
-end
-local CSS_HSLA_FN_MINIMUM_LENGTH = #"hsla(0,0%,0%,0)" - 1
----Parse for hsl() css function and return rgb hex.
----@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 hsla function ended
----@return string|nil: rgb hex value
-function color.hsla_function_parser(line, i)
- if #line < i + CSS_HSLA_FN_MINIMUM_LENGTH 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 (#c_seps:match ",*" == min_commas) then
+ return
+ end
+ -- space separator syntax with decimal or percentage alpha
+ elseif #s_seps:match "%s*" >= min_spaces then
+ if a then
+ if not (c_seps == "/") then
+ return
+ end
+ end
+ else
return
end
- local h, s, l, a, match_end = line:sub(i):match "^hsla%(%s*(%d+)%s*,%s*(%d+)%%%s*,%s*(%d+)%%%s*,%s*([.%d]+)%s*%)()"
- if not match_end then
- h, s, l, a, match_end = line:sub(i):match "^hsla%(%s*(%d+)%s+(%d+)%%%s+(%d+)%%%s+([.%d]+)%s*%)()"
- if not match_end then
- return
+
+ if not a then
+ a = 1
+ else
+ a = tonumber(a)
+ -- if percentage, then convert to decimal
+ if percent_sign == "%" 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
- a = tonumber(a)
- if not a or a > 1 then
- return
+
+ h = tonumber(h) or 1
+ -- single turn is 360
+ if turn == "turn" then
+ h = 360 * h
end
- h = tonumber(h)
+
+ -- if hue angle if greater than 360, then calculate the hue within 360
if h > 360 then
- return
+ local turns = h / 360
+ h = 360 * (turns - floor(turns))
end
+
+ -- if saturation or luminance percentage is greater than 100 then reset it to 100
s = tonumber(s)
if s > 100 then
- return
+ s = 100
end
l = tonumber(l)
if l > 100 then
- return
+ l = 100
end
+
local r, g, b = color.hsl_to_rgb(h / 360, s / 100, l / 100)
if r == nil or g == nil or b == nil then
return
diff --git a/lua/colorizer/matcher.lua b/lua/colorizer/matcher.lua
index dba67c0..d55a673 100644
--- a/lua/colorizer/matcher.lua
+++ b/lua/colorizer/matcher.lua
@@ -17,7 +17,7 @@ local parser = {
["_rgb"] = color.rgb_function_parser,
["_rgba"] = color.rgba_function_parser,
["_hsl"] = color.hsl_function_parser,
- ["_hsla"] = color.hsla_function_parser,
+ ["_hsla"] = color.hsl_function_parser,
}
local matcher = {}
@@ -49,7 +49,7 @@ function matcher.compile(matchers, matchers_trie)
if prefix then
local fn = "_" .. prefix
if parser[fn] then
- return parser[fn](line, i, matchers[fn])
+ return parser[fn](line, i, matchers[prefix])
end
end
@@ -145,6 +145,10 @@ function matcher.make(options)
table.insert(matchers_prefix, "hsl")
end
+ for _, value in ipairs(matchers_prefix) do
+ matchers[value] = { prefix = value }
+ end
+
loop_parse_fn = matcher.compile(matchers, matchers_prefix)
MATCHER_CACHE[matcher_key] = loop_parse_fn