Dotfiles/vim/theme/cyberqueer.nvim/lua/cyberdream/util.lua

270 lines
6.9 KiB
Lua

local config = require("cyberdream.config")
local M = {}
--- @alias RGB table {number, number, number}
--- @alias HSL table {number, number, number}
--- Notify the user with a message.
--- @param message string
--- @param level? "info" | "warn" | "error"
--- @param title? string
function M.notify(message, level, title)
level = level or "info"
title = title or "cyberdream.nvim"
local level_int = level == "info" and 2 or level == "warn" and 3 or 4
vim.notify(message, level_int, { title = title })
end
--- Set the syntax highlighting for a group.
--- @param syntax table
function M.syntax(syntax)
for group, colors in pairs(syntax) do
vim.api.nvim_set_hl(0, group, colors)
end
end
--- Convert a hex color to an RGB color.
--- @param hex string "#rrggbb"
--- @return RGB
function M.hex_to_rgb(hex)
return {
tonumber(hex:sub(2, 3), 16),
tonumber(hex:sub(4, 5), 16),
tonumber(hex:sub(6, 7), 16),
}
end
--- Convert an RGB color to a hex color.
--- @param rgb RGB
--- @return string
function M.rgb_to_hex(rgb)
return string.format("#%02x%02x%02x", rgb[1], rgb[2], rgb[3])
end
--- Convert an HSL color to RGB.
--- @param HSL HSL
--- @return RGB
function M.hsl_to_rgb(HSL)
local h, s, l = HSL[1] / 360, HSL[2] / 100, HSL[3] / 100
local r, g, b
if s == 0 then
r, g, b = l, l, l
else
local function hue_to_rgb(p, q, t)
if t < 0 then
t = t + 1
end
if t > 1 then
t = t - 1
end
if t < 1 / 6 then
return p + (q - p) * 6 * t
end
if t < 1 / 2 then
return q
end
if t < 2 / 3 then
return p + (q - p) * (2 / 3 - t) * 6
end
return p
end
local q = l < 0.5 and l * (1 + s) or l + s - l * s
local p = 2 * l - q
r = hue_to_rgb(p, q, h + 1 / 3)
g = hue_to_rgb(p, q, h)
b = hue_to_rgb(p, q, h - 1 / 3)
end
return { r * 255, g * 255, b * 255 }
end
--- Convert an RGB color to HSL.
--- @param RGB RGB
--- @return HSL
function M.rgb_to_hsl(RGB)
local r, g, b = RGB[1] / 255, RGB[2] / 255, RGB[3] / 255
local max, min = math.max(r, g, b), math.min(r, g, b)
local h, s, l
l = (max + min) / 2
if max == min then
h, s = 0, 0
else
local d = max - min
s = l > 0.5 and d / (2 - max - min) or d / (max + min)
if max == r then
h = (g - b) / d + (g < b and 6 or 0)
elseif max == g then
h = (b - r) / d + 2
elseif max == b then
h = (r - g) / d + 4
end
h = h / 6
end
return { h * 360, s * 100, l * 100 }
end
--- Desaturate an HSL color based on a float. 0 is fully desaturated, 1 is the original color.
--- @param HSL HSL
--- @param weight number
--- @return HSL
function M.desaturate(HSL, weight)
weight = weight or 0.5
HSL[2] = HSL[2] * weight
return HSL
end
--- Desaturate a hex color based on a float. 0 is fully desaturated, 1 is the original color.
function M.desaturate_hex(hex, weight)
local rgb = M.hex_to_rgb(hex)
local hsl = M.rgb_to_hsl(rgb)
local desaturated_hsl = M.desaturate(hsl, weight)
local desaturated_rgb = M.hsl_to_rgb(desaturated_hsl)
return string.format("#%02x%02x%02x", desaturated_rgb[1], desaturated_rgb[2], desaturated_rgb[3])
end
--- Apply saturation to a table of colors.
--- @param colors CyberdreamPalette
--- @param weight number
function M.apply_saturation(colors, weight)
if weight >= 1 then
return colors
end
if weight < 0 then
weight = 0
end
local desaturated_colors = {}
for k, v in pairs(colors) do
desaturated_colors[k] = M.desaturate_hex(v, weight)
end
return desaturated_colors
end
--- Load the colorscheme.
--- @param theme table
function M.load(theme)
-- only needed to clear when not the default colorscheme
if vim.g.colors_name then
vim.cmd("hi clear")
end
vim.o.termguicolors = true
vim.g.colors_name = "cyberdream"
M.syntax(theme.highlights)
end
--- Blend two colors together based on a weight.
--- @param color1 string
--- @param color2 string
--- @param weight? number
--- @return string
function M.blend(color1, color2, weight)
weight = weight or 0.5
local rgb1 = M.hex_to_rgb(color1)
local rgb2 = M.hex_to_rgb(color2)
local rgb_blended = {}
for i = 1, 3 do
rgb_blended[i] = math.floor(rgb1[i] * weight + rgb2[i] * (1 - weight))
end
return string.format("#%02x%02x%02x", rgb_blended[1], rgb_blended[2], rgb_blended[3])
end
--- Remove an element from a table.
--- @param table table
--- @param index number
--- @return table
function M.remove(table, index)
local new_table = {}
for i = 1, #table do
if i ~= index then
new_table[#new_table + 1] = table[i]
end
end
return new_table
end
--- Parse a template string with a given table of colors.
--- @param template string
--- @param t table
--- @return string
function M.parse_extra_template(template, t)
for k, v in pairs(t) do
template = template:gsub("%${" .. k .. "}", v)
end
return template
end
--- Override options with a new table of values.
--- @param new_opts Config
--- @return Config
function M.set_options(new_opts)
local opts = vim.g.cyberdream_opts
vim.g.cyberdream_opts = vim.tbl_deep_extend("force", opts, new_opts)
return vim.g.cyberdream_opts
end
--- Apply options to the colorscheme.
--- @param opts Config
function M.apply_options(opts)
-- Update the colorscheme
config.setup(opts)
vim.cmd("colorscheme cyberdream")
end
--- Toggle the theme variant between "default" and "light".
--- @return string new variant
function M.toggle_theme_variant()
local opts = vim.g.cyberdream_opts
-- Handle the "auto" variant without overwriting the value in opts.
if opts.variant == "auto" then
return M.toggle_theme_auto()
end
opts.variant = opts.variant == "default" and "light" or "default"
M.set_options(opts)
M.apply_options(opts)
return opts.variant
end
--- Used for toggling the theme variant when the variant is set to "auto". Uses the 'set background' command to toggle between 'light' and 'dark'.
--- @return string new variant
function M.toggle_theme_auto()
local variant = vim.o.background
if variant == "dark" then
variant = "light"
else
variant = "dark"
end
vim.cmd(":set background=" .. variant)
return variant == "dark" and "default" or "light"
end
--- Toggle theme for lualine
function M.toggle_lualine_theme()
if package.loaded["lualine"] == nil then
return
end
package.loaded["lualine.themes.cyberdream"] = nil
local lualine_opts = require("lualine").get_config()
local lualine_theme = require("lualine.themes.cyberdream")
lualine_opts.options.theme = lualine_theme
require("lualine").setup(lualine_opts)
end
return M