aboutsummaryrefslogtreecommitdiff
path: root/lua/colorizer/matcher_utils.lua
blob: 11e56f6dda9b2f2db05ec47fe26241038b4dc13d (plain)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
---Helper functions for colorizer to enable required parsers
--@module colorizer.matcher_utils
local Trie = require "colorizer.trie"
local min, max = math.min, math.max

local color_utils = require "colorizer.color_utils"
local color_name_parser = color_utils.color_name_parser
local rgba_hex_parser = color_utils.rgba_hex_parser

local parser = {}
parser["_0x"] = color_utils.argb_hex_parser
parser["_rgb"] = color_utils.rgb_function_parser
parser["_rgba"] = color_utils.rgba_function_parser
parser["_hsl"] = color_utils.hsl_function_parser
parser["_hsla"] = color_utils.hsla_function_parser

---Form a trie stuct with the given prefixes
---@param matchers table: List of prefixes, {"rgb", "hsl"}
---@param matchers_trie table: Table containing information regarding non-trie based parsers
---@return function: function which will just parse the line for enabled parsers
local function compile_matcher(matchers, matchers_trie)
  local trie = Trie(matchers_trie)

  local b_hash = ("#"):byte()
  local function parse_fn(line, i)
    -- prefix #
    if matchers.rgba_hex_parser then
      if line:byte(i) == b_hash then
        return rgba_hex_parser(line, i, matchers.rgba_hex_parser)
      end
    end

    -- Prefix 0x, rgba, rgb, hsla, hsl
    local prefix = trie:longest_prefix(line, i)
    if prefix then
      local fn = "_" .. prefix
      if parser[fn] then
        return parser[fn](line, i, matchers[fn])
      end
    end

    -- Colour names
    if matchers.color_name_parser then
      return color_name_parser(line, i, matchers.color_name_parser)
    end
  end
  return parse_fn
end

local MATCHER_CACHE = {}
---Parse the given options and return a function with enabled parsers.
--if no parsers enabled then return false
--Do not try make the function again if it is present in the cache
---@param options table: options created in `colorizer.setup`
---@return function|boolean: function which will just parse the line for enabled parsers
local function make_matcher(options)
  local enable_names = options.css or options.names
  local enable_tailwind = options.tailwind
  local enable_RGB = options.css or options.RGB
  local enable_RRGGBB = options.css or options.RRGGBB
  local enable_RRGGBBAA = options.css or options.RRGGBBAA
  local enable_AARRGGBB = options.AARRGGBB
  local enable_rgb = options.css or options.css_fns or options.rgb_fn
  local enable_hsl = options.css or options.css_fns or options.hsl_fn

  local matcher_key = 0
    + (enable_names and 1 or 0)
    + (enable_RGB and 1 or 1)
    + (enable_RRGGBB and 1 or 2)
    + (enable_RRGGBBAA and 1 or 3)
    + (enable_AARRGGBB and 1 or 4)
    + (enable_rgb and 1 or 5)
    + (enable_hsl and 1 or 6)
    + (enable_tailwind == "normal" and 1 or 7)
    + (enable_tailwind == "lsp" and 1 or 8)
    + (enable_tailwind == "both" and 1 or 9)

  if matcher_key == 0 then
    return false
  end

  local loop_parse_fn = MATCHER_CACHE[matcher_key]
  if loop_parse_fn then
    return loop_parse_fn
  end

  local matchers = {}
  local matchers_prefix = {}
  matchers.max_prefix_length = 0

  if enable_names then
    matchers.color_name_parser = { tailwind = options.tailwind }
  end

  local valid_lengths = { [3] = enable_RGB, [6] = enable_RRGGBB, [8] = enable_RRGGBBAA }
  local minlen, maxlen
  for k, v in pairs(valid_lengths) do
    if v then
      minlen = minlen and min(k, minlen) or k
      maxlen = maxlen and max(k, maxlen) or k
    end
  end

  if minlen then
    matchers.rgba_hex_parser = {}
    matchers.rgba_hex_parser.valid_lengths = valid_lengths
    matchers.rgba_hex_parser.maxlen = maxlen
    matchers.rgba_hex_parser.minlen = minlen
  end

  if enable_AARRGGBB then
    table.insert(matchers_prefix, "0x")
  end

  -- do not mess with the sequence, hsla before hsl, etc
  if enable_rgb and enable_hsl then
    table.insert(matchers_prefix, "hsla")
    table.insert(matchers_prefix, "rgba")
    table.insert(matchers_prefix, "rgb")
    table.insert(matchers_prefix, "hsl")
  elseif enable_rgb then
    table.insert(matchers_prefix, "rgba")
    table.insert(matchers_prefix, "rgb")
  elseif enable_hsl then
    table.insert(matchers_prefix, "hsla")
    table.insert(matchers_prefix, "hsl")
  end

  loop_parse_fn = compile_matcher(matchers, matchers_prefix)
  MATCHER_CACHE[matcher_key] = loop_parse_fn

  return loop_parse_fn
end

--- @export
return {
  make_matcher = make_matcher,
}