aboutsummaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authorakianonymus <anonymus.aki@gmail.com>2023-02-27 14:30:10 +0530
committerakianonymus <anonymus.aki@gmail.com>2023-02-27 16:01:48 +0530
commitdde3084106a70b9a79d48f426f6d6fec6fd203f7 (patch)
treef1b06f0921e9eaf98bcc94f4d86d9f4d7226cb54 /lua
parentfix: virtualtext on nonfocused window update | #41 (diff)
Separate parsers into individual files
Diffstat (limited to 'lua')
-rw-r--r--lua/colorizer/color.lua394
-rw-r--r--lua/colorizer/matcher.lua23
-rw-r--r--lua/colorizer/parser/argb_hex.lua58
-rw-r--r--lua/colorizer/parser/hsl.lua110
-rw-r--r--lua/colorizer/parser/names.lua84
-rw-r--r--lua/colorizer/parser/rgb.lua114
-rw-r--r--lua/colorizer/parser/rgba_hex.lua68
7 files changed, 448 insertions, 403 deletions
diff --git a/lua/colorizer/color.lua b/lua/colorizer/color.lua
index 370131b..29af64d 100644
--- a/lua/colorizer/color.lua
+++ b/lua/colorizer/color.lua
@@ -1,66 +1,7 @@
----Helper functions to parse different colour formats
+---Helper color functions
--@module colorizer.color
-local api = vim.api
-
-local bit = require "bit"
-local floor, min, max = math.floor, math.min, math.max
-local band, rshift, lshift, tohex = bit.band, bit.rshift, bit.lshift, bit.tohex
-
-local Trie = require "colorizer.trie"
-
-local utils = require "colorizer.utils"
-local byte_is_alphanumeric = utils.byte_is_alphanumeric
-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 color = {}
-local ARGB_MINIMUM_LENGTH = #"0xAARRGGBB" - 1
----parse for 0xaarrggbb and return rgb hex.
--- a format used in android apps
----@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 hex value ended
----@return string|nil: rgb hex value
-function color.argb_hex_parser(line, i)
- if #line < i + ARGB_MINIMUM_LENGTH then
- return
- end
-
- local j = i + 2
-
- local n = j + 8
- local alpha
- local v = 0
- while j <= min(n, #line) do
- local b = line:byte(j)
- if not byte_is_hex(b) then
- break
- end
- if j - i <= 3 then
- alpha = parse_hex(b) + lshift(alpha or 0, 4)
- else
- v = parse_hex(b) + lshift(v, 4)
- end
- j = j + 1
- end
- if #line >= j and byte_is_alphanumeric(line:byte(j)) then
- return
- end
- local length = j - i
- if length ~= 10 then
- return
- end
- alpha = tonumber(alpha) / 255
- local r = floor(band(rshift(v, 16), 0xFF) * alpha)
- local g = floor(band(rshift(v, 8), 0xFF) * alpha)
- local b = floor(band(v, 0xFF) * alpha)
- local rgb_hex = string.format("%02x%02x%02x", r, g, b)
- return length, rgb_hex
-end
-
--- Converts an HSL color value to RGB.
---@param h number: Hue
---@param s number: Saturation
@@ -86,107 +27,6 @@ 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() 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
----@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, 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*(,?)%s*(%d+)%%(%s?)%s*(,?)%s*(%d+)%%%s*(/?,?)%s*([.%d]*)([%%]?)%s*%)()"
-
- if opts.prefix == "hsl" then
- min_len = CSS_HSL_FN_MINIMUM_LENGTH
- end
-
- if #line < i + min_len then
- return
- end
-
- local h, deg, turn, ssep1, csep1, s, ssep2, csep2, l, sep3, a, percent_sign, 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
-
- -- the text after hue should be either deg or empty
- if not ((deg == "") or (deg == "deg") or (turn == "turn")) then
- return
- 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 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
-
- h = tonumber(h) or 1
- -- single turn is 360
- if turn == "turn" then
- h = 360 * h
- end
-
- -- if hue angle if greater than 360, then calculate the hue within 360
- if h > 360 then
- 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
- s = 100
- end
- l = tonumber(l)
- if l > 100 then
- 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
- end
- local rgb_hex = string.format("%02x%02x%02x", r * a, g * a, b * a)
- return match_end - 1, rgb_hex
-end
-
---Convert hsl colour values to rgb.
-- Source: https://gist.github.com/mjackson/5311256
---@param p number
@@ -229,236 +69,4 @@ function color.is_bright(r, g, b)
end
end
-local COLOR_MAP
-local COLOR_TRIE
-local COLOR_NAME_MINLEN, COLOR_NAME_MAXLEN
-local COLOR_NAME_SETTINGS = { lowercase = true, strip_digits = false }
-local TAILWIND_ENABLED = false
---- Grab all the colour values from `vim.api.nvim_get_color_map` and create a lookup table.
--- COLOR_MAP is used to store the colour values
----@param line string: Line to parse
----@param i number: Index of line from where to start parsing
----@param opts table: Currently contains whether tailwind is enabled or not
-function color.name_parser(line, i, opts)
- --- Setup the COLOR_MAP and COLOR_TRIE
- if not COLOR_TRIE or opts.tailwind ~= TAILWIND_ENABLED then
- COLOR_MAP = {}
- COLOR_TRIE = Trie()
- for k, v in pairs(api.nvim_get_color_map()) do
- if not (COLOR_NAME_SETTINGS.strip_digits and k:match "%d+$") then
- COLOR_NAME_MINLEN = COLOR_NAME_MINLEN and min(#k, COLOR_NAME_MINLEN) or #k
- COLOR_NAME_MAXLEN = COLOR_NAME_MAXLEN and max(#k, COLOR_NAME_MAXLEN) or #k
- local rgb_hex = tohex(v, 6)
- COLOR_MAP[k] = rgb_hex
- COLOR_TRIE:insert(k)
- if COLOR_NAME_SETTINGS.lowercase then
- local lowercase = k:lower()
- COLOR_MAP[lowercase] = rgb_hex
- COLOR_TRIE:insert(lowercase)
- end
- end
- end
- if opts and opts.tailwind then
- if opts.tailwind == true or opts.tailwind == "normal" or opts.tailwind == "both" then
- local tailwind = require "colorizer.tailwind_colors"
- -- setup tailwind colors
- for k, v in pairs(tailwind.colors) do
- for _, pre in ipairs(tailwind.prefixes) do
- local name = pre .. "-" .. k
- COLOR_NAME_MINLEN = COLOR_NAME_MINLEN and min(#name, COLOR_NAME_MINLEN) or #name
- COLOR_NAME_MAXLEN = COLOR_NAME_MAXLEN and max(#name, COLOR_NAME_MAXLEN) or #name
- COLOR_MAP[name] = v
- COLOR_TRIE:insert(name)
- end
- end
- end
- end
- TAILWIND_ENABLED = opts.tailwind
- end
-
- if #line < i + COLOR_NAME_MINLEN - 1 then
- return
- end
-
- if i > 1 and byte_is_valid_colorchar(line:byte(i - 1)) then
- return
- end
-
- local prefix = COLOR_TRIE:longest_prefix(line, i)
- if prefix then
- -- Check if there is a letter here so as to disallow matching here.
- -- Take the Blue out of Blueberry
- -- Line end or non-letter.
- local next_byte_index = i + #prefix
- if #line >= next_byte_index and byte_is_valid_colorchar(line:byte(next_byte_index)) then
- return
- end
- return #prefix, COLOR_MAP[prefix]
- 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() 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 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
-
- 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
-
----parse for #rrggbbaa and return rgb hex.
--- a format used in android apps
----@param line string: line to parse
----@param i number: index of line from where to start parsing
----@param opts table: Containing minlen, maxlen, valid_lengths
----@return number|nil: index of line where the hex value ended
----@return string|nil: rgb hex value
-function color.rgba_hex_parser(line, i, opts)
- local minlen, maxlen, valid_lengths = opts.minlen, opts.maxlen, opts.valid_lengths
- local j = i + 1
- if #line < j + minlen - 1 then
- return
- end
-
- if i > 1 and byte_is_alphanumeric(line:byte(i - 1)) then
- return
- end
-
- local n = j + maxlen
- local alpha
- local v = 0
-
- while j <= min(n, #line) do
- local b = line:byte(j)
- if not byte_is_hex(b) then
- break
- end
- if j - i >= 7 then
- alpha = parse_hex(b) + lshift(alpha or 0, 4)
- else
- v = parse_hex(b) + lshift(v, 4)
- end
- j = j + 1
- end
-
- if #line >= j and byte_is_alphanumeric(line:byte(j)) then
- return
- end
-
- local length = j - i
- if length ~= 4 and length ~= 7 and length ~= 9 then
- return
- end
-
- if alpha then
- alpha = tonumber(alpha) / 255
- local r = floor(band(rshift(v, 16), 0xFF) * alpha)
- local g = floor(band(rshift(v, 8), 0xFF) * alpha)
- local b = floor(band(v, 0xFF) * alpha)
- local rgb_hex = string.format("%02x%02x%02x", r, g, b)
- return 9, rgb_hex
- end
- return (valid_lengths[length - 1] and length), line:sub(i + 1, i + length - 1)
-end
-
return color
diff --git a/lua/colorizer/matcher.lua b/lua/colorizer/matcher.lua
index ccd72a2..1f3eede 100644
--- a/lua/colorizer/matcher.lua
+++ b/lua/colorizer/matcher.lua
@@ -3,21 +3,24 @@
local Trie = require "colorizer.trie"
local min, max = math.min, math.max
-local color = require "colorizer.color"
-local color_name_parser = color.name_parser
-local rgba_hex_parser = color.rgba_hex_parser
+local color_name_parser = require "colorizer.parser.names"
-local sass = require "colorizer.sass"
-local sass_name_parser = sass.name_parser
+local rgb_function_parser = require "colorizer.parser.rgb"
+local hsl_function_parser = require "colorizer.parser.hsl"
+
+local argb_hex_parser = require "colorizer.parser.argb_hex"
+local rgba_hex_parser = require "colorizer.parser.rgba_hex"
+
+local sass_name_parser = require("colorizer.sass").name_parser
local B_HASH, DOLLAR_HASH = ("#"):byte(), ("$"):byte()
local parser = {
- ["_0x"] = color.argb_hex_parser,
- ["_rgb"] = color.rgb_function_parser,
- ["_rgba"] = color.rgb_function_parser,
- ["_hsl"] = color.hsl_function_parser,
- ["_hsla"] = color.hsl_function_parser,
+ ["_0x"] = argb_hex_parser,
+ ["_rgb"] = rgb_function_parser,
+ ["_rgba"] = rgb_function_parser,
+ ["_hsl"] = hsl_function_parser,
+ ["_hsla"] = hsl_function_parser,
}
local matcher = {}
diff --git a/lua/colorizer/parser/argb_hex.lua b/lua/colorizer/parser/argb_hex.lua
new file mode 100644
index 0000000..f664dc3
--- /dev/null
+++ b/lua/colorizer/parser/argb_hex.lua
@@ -0,0 +1,58 @@
+---Helper function to parse argb
+
+local bit = require "bit"
+local floor, min = math.floor, math.min
+local band, rshift, lshift = bit.band, bit.rshift, bit.lshift
+
+local utils = require "colorizer.utils"
+local byte_is_alphanumeric = utils.byte_is_alphanumeric
+local byte_is_hex = utils.byte_is_hex
+local parse_hex = utils.parse_hex
+
+local parser = {}
+
+local ARGB_MINIMUM_LENGTH = #"0xAARRGGBB" - 1
+---parse for 0xaarrggbb and return rgb hex.
+-- a format used in android apps
+---@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 hex value ended
+---@return string|nil: rgb hex value
+function parser.argb_hex_parser(line, i)
+ if #line < i + ARGB_MINIMUM_LENGTH then
+ return
+ end
+
+ local j = i + 2
+
+ local n = j + 8
+ local alpha
+ local v = 0
+ while j <= min(n, #line) do
+ local b = line:byte(j)
+ if not byte_is_hex(b) then
+ break
+ end
+ if j - i <= 3 then
+ alpha = parse_hex(b) + lshift(alpha or 0, 4)
+ else
+ v = parse_hex(b) + lshift(v, 4)
+ end
+ j = j + 1
+ end
+ if #line >= j and byte_is_alphanumeric(line:byte(j)) then
+ return
+ end
+ local length = j - i
+ if length ~= 10 then
+ return
+ end
+ alpha = tonumber(alpha) / 255
+ local r = floor(band(rshift(v, 16), 0xFF) * alpha)
+ local g = floor(band(rshift(v, 8), 0xFF) * alpha)
+ local b = floor(band(v, 0xFF) * alpha)
+ local rgb_hex = string.format("%02x%02x%02x", r, g, b)
+ return length, rgb_hex
+end
+
+return parser.argb_hex_parser
diff --git a/lua/colorizer/parser/hsl.lua b/lua/colorizer/parser/hsl.lua
new file mode 100644
index 0000000..cb6a19d
--- /dev/null
+++ b/lua/colorizer/parser/hsl.lua
@@ -0,0 +1,110 @@
+---Helper function to parse argb
+local count = require("colorizer.utils").count
+local floor = math.floor
+
+local hsl_to_rgb = require("colorizer.color").hsl_to_rgb
+
+local parser = {}
+
+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() 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
+---@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 parser.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*(,?)%s*(%d+)%%(%s?)%s*(,?)%s*(%d+)%%%s*(/?,?)%s*([.%d]*)([%%]?)%s*%)()"
+
+ if opts.prefix == "hsl" then
+ min_len = CSS_HSL_FN_MINIMUM_LENGTH
+ end
+
+ if #line < i + min_len then
+ return
+ end
+
+ local h, deg, turn, ssep1, csep1, s, ssep2, csep2, l, sep3, a, percent_sign, 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
+
+ -- the text after hue should be either deg or empty
+ if not ((deg == "") or (deg == "deg") or (turn == "turn")) then
+ return
+ 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 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
+
+ h = tonumber(h) or 1
+ -- single turn is 360
+ if turn == "turn" then
+ h = 360 * h
+ end
+
+ -- if hue angle if greater than 360, then calculate the hue within 360
+ if h > 360 then
+ 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
+ s = 100
+ end
+ l = tonumber(l)
+ if l > 100 then
+ l = 100
+ end
+
+ local r, g, b = hsl_to_rgb(h / 360, s / 100, l / 100)
+ if r == nil or g == nil or b == nil then
+ return
+ end
+ local rgb_hex = string.format("%02x%02x%02x", r * a, g * a, b * a)
+ return match_end - 1, rgb_hex
+end
+
+return parser.hsl_function_parser
diff --git a/lua/colorizer/parser/names.lua b/lua/colorizer/parser/names.lua
new file mode 100644
index 0000000..6fc7043
--- /dev/null
+++ b/lua/colorizer/parser/names.lua
@@ -0,0 +1,84 @@
+---Helper function to parse argb
+local api = vim.api
+
+local bit = require "bit"
+local tohex = bit.tohex
+
+local min, max = math.min, math.max
+
+local Trie = require "colorizer.trie"
+
+local utils = require "colorizer.utils"
+local byte_is_valid_colorchar = utils.byte_is_valid_colorchar
+
+local parser = {}
+
+local COLOR_MAP
+local COLOR_TRIE
+local COLOR_NAME_MINLEN, COLOR_NAME_MAXLEN
+local COLOR_NAME_SETTINGS = { lowercase = true, strip_digits = false }
+local TAILWIND_ENABLED = false
+--- Grab all the colour values from `vim.api.nvim_get_color_map` and create a lookup table.
+-- COLOR_MAP is used to store the colour values
+---@param line string: Line to parse
+---@param i number: Index of line from where to start parsing
+---@param opts table: Currently contains whether tailwind is enabled or not
+function parser.name_parser(line, i, opts)
+ --- Setup the COLOR_MAP and COLOR_TRIE
+ if not COLOR_TRIE or opts.tailwind ~= TAILWIND_ENABLED then
+ COLOR_MAP = {}
+ COLOR_TRIE = Trie()
+ for k, v in pairs(api.nvim_get_color_map()) do
+ if not (COLOR_NAME_SETTINGS.strip_digits and k:match "%d+$") then
+ COLOR_NAME_MINLEN = COLOR_NAME_MINLEN and min(#k, COLOR_NAME_MINLEN) or #k
+ COLOR_NAME_MAXLEN = COLOR_NAME_MAXLEN and max(#k, COLOR_NAME_MAXLEN) or #k
+ local rgb_hex = tohex(v, 6)
+ COLOR_MAP[k] = rgb_hex
+ COLOR_TRIE:insert(k)
+ if COLOR_NAME_SETTINGS.lowercase then
+ local lowercase = k:lower()
+ COLOR_MAP[lowercase] = rgb_hex
+ COLOR_TRIE:insert(lowercase)
+ end
+ end
+ end
+ if opts and opts.tailwind then
+ if opts.tailwind == true or opts.tailwind == "normal" or opts.tailwind == "both" then
+ local tailwind = require "colorizer.tailwind_colors"
+ -- setup tailwind colors
+ for k, v in pairs(tailwind.colors) do
+ for _, pre in ipairs(tailwind.prefixes) do
+ local name = pre .. "-" .. k
+ COLOR_NAME_MINLEN = COLOR_NAME_MINLEN and min(#name, COLOR_NAME_MINLEN) or #name
+ COLOR_NAME_MAXLEN = COLOR_NAME_MAXLEN and max(#name, COLOR_NAME_MAXLEN) or #name
+ COLOR_MAP[name] = v
+ COLOR_TRIE:insert(name)
+ end
+ end
+ end
+ end
+ TAILWIND_ENABLED = opts.tailwind
+ end
+
+ if #line < i + COLOR_NAME_MINLEN - 1 then
+ return
+ end
+
+ if i > 1 and byte_is_valid_colorchar(line:byte(i - 1)) then
+ return
+ end
+
+ local prefix = COLOR_TRIE:longest_prefix(line, i)
+ if prefix then
+ -- Check if there is a letter here so as to disallow matching here.
+ -- Take the Blue out of Blueberry
+ -- Line end or non-letter.
+ local next_byte_index = i + #prefix
+ if #line >= next_byte_index and byte_is_valid_colorchar(line:byte(next_byte_index)) then
+ return
+ end
+ return #prefix, COLOR_MAP[prefix]
+ end
+end
+
+return parser.name_parser
diff --git a/lua/colorizer/parser/rgb.lua b/lua/colorizer/parser/rgb.lua
new file mode 100644
index 0000000..2786a60
--- /dev/null
+++ b/lua/colorizer/parser/rgb.lua
@@ -0,0 +1,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
diff --git a/lua/colorizer/parser/rgba_hex.lua b/lua/colorizer/parser/rgba_hex.lua
new file mode 100644
index 0000000..0f16fbe
--- /dev/null
+++ b/lua/colorizer/parser/rgba_hex.lua
@@ -0,0 +1,68 @@
+---Helper function to parse argb
+local bit = require "bit"
+local floor, min = math.floor, math.min
+local band, rshift, lshift = bit.band, bit.rshift, bit.lshift
+
+local utils = require "colorizer.utils"
+local byte_is_alphanumeric = utils.byte_is_alphanumeric
+local byte_is_hex = utils.byte_is_hex
+local parse_hex = utils.parse_hex
+
+local parser = {}
+
+---parse for #rrggbbaa and return rgb hex.
+-- a format used in android apps
+---@param line string: line to parse
+---@param i number: index of line from where to start parsing
+---@param opts table: Containing minlen, maxlen, valid_lengths
+---@return number|nil: index of line where the hex value ended
+---@return string|nil: rgb hex value
+function parser.rgba_hex_parser(line, i, opts)
+ local minlen, maxlen, valid_lengths = opts.minlen, opts.maxlen, opts.valid_lengths
+ local j = i + 1
+ if #line < j + minlen - 1 then
+ return
+ end
+
+ if i > 1 and byte_is_alphanumeric(line:byte(i - 1)) then
+ return
+ end
+
+ local n = j + maxlen
+ local alpha
+ local v = 0
+
+ while j <= min(n, #line) do
+ local b = line:byte(j)
+ if not byte_is_hex(b) then
+ break
+ end
+ if j - i >= 7 then
+ alpha = parse_hex(b) + lshift(alpha or 0, 4)
+ else
+ v = parse_hex(b) + lshift(v, 4)
+ end
+ j = j + 1
+ end
+
+ if #line >= j and byte_is_alphanumeric(line:byte(j)) then
+ return
+ end
+
+ local length = j - i
+ if length ~= 4 and length ~= 7 and length ~= 9 then
+ return
+ end
+
+ if alpha then
+ alpha = tonumber(alpha) / 255
+ local r = floor(band(rshift(v, 16), 0xFF) * alpha)
+ local g = floor(band(rshift(v, 8), 0xFF) * alpha)
+ local b = floor(band(v, 0xFF) * alpha)
+ local rgb_hex = string.format("%02x%02x%02x", r, g, b)
+ return 9, rgb_hex
+ end
+ return (valid_lengths[length - 1] and length), line:sub(i + 1, i + length - 1)
+end
+
+return parser.rgba_hex_parser