local M = {} local hsluv = require("catppuccin.utils.hsluv") ---@param hex_str string hexadecimal value of a color local hex_to_rgb = function(hex_str) local hex = "[abcdef0-9][abcdef0-9]" local pat = "^#(" .. hex .. ")(" .. hex .. ")(" .. hex .. ")$" hex_str = string.lower(hex_str) assert(string.find(hex_str, pat) ~= nil, "hex_to_rgb: invalid hex_str: " .. tostring(hex_str)) local red, green, blue = string.match(hex_str, pat) return { tonumber(red, 16), tonumber(green, 16), tonumber(blue, 16) } end ---@param fg string forecrust color ---@param bg string background color ---@param alpha number number between 0 and 1. 0 results in bg, 1 results in fg function M.blend(fg, bg, alpha) bg = hex_to_rgb(bg) fg = hex_to_rgb(fg) local blendChannel = function(i) local ret = (alpha * fg[i] + ((1 - alpha) * bg[i])) return math.floor(math.min(math.max(0, ret), 255) + 0.5) end return string.format("#%02X%02X%02X", blendChannel(1), blendChannel(2), blendChannel(3)) end function M.darken(hex, amount, bg) return M.blend(hex, bg or M.bg, math.abs(amount)) end function M.lighten(hex, amount, fg) return M.blend(hex, fg or M.fg, math.abs(amount)) end function M.brighten(color, percentage) local hsl = hsluv.hex_to_hsluv(color) local larpSpace = 100 - hsl[3] if percentage < 0 then larpSpace = hsl[3] end hsl[3] = hsl[3] + larpSpace * percentage return hsluv.hsluv_to_hex(hsl) end function M.invertColor(color) if color ~= "NONE" then local hsl = hsluv.hex_to_hsluv(color) hsl[3] = 100 - hsl[3] if hsl[3] < 40 then hsl[3] = hsl[3] + (100 - hsl[3]) * M.day_brightness end return hsluv.hsluv_to_hex(hsl) end return color end function M.string_to_color(colors, value, default) if not value or value == "" then return default end -- If the value is a hex color code then return it local hex = "[abcdef0-9][abcdef0-9]" local pat = "^#" .. hex .. hex .. hex .. "$" if string.match(value, pat) then return value end local acceptable_colors = { "black", "red", "green", "blue", "magenta", "cyan", "text", "orange", "pink" } for _, ac in ipairs(acceptable_colors) do if string.match(value, ac) then return colors[value] end end -- Did not match anything to return default return default end function M.color_is_bright(r, g, b) -- Counting the perceptive luminance - human eye favors green color local luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255 if luminance > 0.5 then return true -- Bright colors, black font else return false -- Dark colors, text font end end function M.hex2rgb(hex) return tonumber("0x" .. hex:sub(1, 2)), tonumber("0x" .. hex:sub(3, 4)), tonumber("0x" .. hex:sub(5, 6)) end function M.assert_brightness(color) local hex = color:gsub("#", "") local r = M.hex2rgb(string.sub(hex, 1, 2)) local g = M.hex2rgb(string.sub(hex, 3, 4)) local b = M.hex2rgb(string.sub(hex, 5, 6)) if M.color_is_bright(tonumber(r), tonumber(g), tonumber(b)) == true then return true -- bright end return false -- dull end function M.vary_color(palettes, default) local flvr = vim.g.catppuccin_flavour if palettes[flvr] ~= nil then return palettes[flvr] end return default end return M