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
|
---Helper utils
--@module utils
local bit, ffi = require "bit", require "ffi"
local band, bor, rshift, lshift = bit.band, bit.bor, bit.rshift, bit.lshift
-- -- TODO use rgb as the return value from the matcher functions
-- -- instead of the rgb_hex. Can be the highlight key as well
-- -- when you shift it left 8 bits. Use the lower 8 bits for
-- -- indicating which highlight mode to use.
-- ffi.cdef [[
-- typedef struct { uint8_t r, g, b; } colorizer_rgb;
-- ]]
-- local rgb_t = ffi.typeof 'colorizer_rgb'
-- Create a lookup table where the bottom 4 bits are used to indicate the
-- category and the top 4 bits are the hex value of the ASCII byte.
local BYTE_CATEGORY = ffi.new "uint8_t[256]"
local CATEGORY_DIGIT = lshift(1, 0)
local CATEGORY_ALPHA = lshift(1, 1)
local CATEGORY_HEX = lshift(1, 2)
local CATEGORY_ALPHANUM = bor(CATEGORY_ALPHA, CATEGORY_DIGIT)
-- do not run the loop multiple times
local b = string.byte
local byte_values = { ["0"] = b "0", ["9"] = b "9", ["a"] = b "a", ["f"] = b "f", ["z"] = b "z" }
local extra_char = { [b "-"] = true }
for i = 0, 255 do
local v = 0
local lowercase = bor(i, 0x20)
-- Digit is bit 1
if i >= byte_values["0"] and i <= byte_values["9"] then
v = bor(v, lshift(1, 0))
v = bor(v, lshift(1, 2))
v = bor(v, lshift(i - byte_values["0"], 4))
elseif lowercase >= byte_values["a"] and lowercase <= byte_values["z"] then
-- Alpha is bit 2
v = bor(v, lshift(1, 1))
if lowercase <= byte_values["f"] then
v = bor(v, lshift(1, 2))
v = bor(v, lshift(lowercase - byte_values["a"] + 10, 4))
end
elseif extra_char[i] then
v = i
end
BYTE_CATEGORY[i] = v
end
---Obvious.
---@param byte number
---@return boolean
local function byte_is_alphanumeric(byte)
local category = BYTE_CATEGORY[byte]
return band(category, CATEGORY_ALPHANUM) ~= 0
end
---Obvious.
---@param byte number
---@return boolean
local function byte_is_hex(byte)
return band(BYTE_CATEGORY[byte], CATEGORY_HEX) ~= 0
end
---Merge two tables.
--
-- todo: Remove this and use `vim.tbl_deep_extend`
---@return table
local function merge(...)
local res = {}
for i = 1, select("#", ...) do
local o = select(i, ...)
if type(o) ~= "table" then
return {}
end
for k, v in pairs(o) do
res[k] = v
end
end
return res
end
--- Obvious.
---@param byte number
---@return number
local function parse_hex(byte)
return rshift(BYTE_CATEGORY[byte], 4)
end
local b_percent = string.byte "%"
--- Obvious.
---@param v string
---@return number|nil
local function 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
--- @export
return {
byte_is_alphanumeric = byte_is_alphanumeric,
byte_is_hex = byte_is_hex,
merge = merge,
parse_hex = parse_hex,
percent_or_hex = percent_or_hex,
}
|