diff options
Diffstat (limited to 'lua/colorizer/utils.lua')
-rw-r--r-- | lua/colorizer/utils.lua | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/lua/colorizer/utils.lua b/lua/colorizer/utils.lua new file mode 100644 index 0000000..0cb09ee --- /dev/null +++ b/lua/colorizer/utils.lua @@ -0,0 +1,106 @@ +---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 +for i = 0, 255 do + local v = 0 + -- Digit is bit 1 + if i >= b "0" and i <= b "9" then + v = bor(v, lshift(1, 0)) + v = bor(v, lshift(1, 2)) + v = bor(v, lshift(i - b "0", 4)) + end + local lowercase = bor(i, 0x20) + -- Alpha is bit 2 + if lowercase >= b "a" and lowercase <= b "z" then + v = bor(v, lshift(1, 1)) + if lowercase <= b "f" then + v = bor(v, lshift(1, 2)) + v = bor(v, lshift(lowercase - b "a" + 10, 4)) + end + 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 + +--- Obvious. +---@param v string +---@return number|nil +local function percent_or_hex(v) + if v:sub(-1, -1) == "%" 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, +} |