1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
---Helper function to parse argb
local count = require("colorizer.utils").count
local parser = {}
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() 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
---@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 parser.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
if #line < i + min_len then
return
end
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
if a == "" then
a = nil
else
min_commas = min_commas + 1
end
local units = ("%s%s%s"):format(unit1, unit2, unit3)
if units:match "%%" then
if not ((count(units, "%%")) == min_percent) then
return
end
end
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
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 = tonumber(g)
if not g then
return
end
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
return parser.rgb_function_parser
|