neovim-confs/lua/plex/lib/color.lua

141 lines
4.1 KiB
Lua
Raw Permalink Normal View History

2023-09-06 00:26:45 +02:00
-- Source: https://github.com/nvim-lualine/lualine.nvim/blob/master/lua/lualine/themes/auto.lua
-- Copyright (c) 2020-2021 shadmansaleh
-- MIT license, see LICENSE for more details.
local M = {}
-- Turns #rrggbb -> { red, green, blue }
function M.rgb_str2num(rgb_color_str)
if rgb_color_str:find('#') == 1 then
rgb_color_str = rgb_color_str:sub(2, #rgb_color_str)
end
local red = tonumber(rgb_color_str:sub(1, 2), 16)
local green = tonumber(rgb_color_str:sub(3, 4), 16)
local blue = tonumber(rgb_color_str:sub(5, 6), 16)
return { red = red, green = green, blue = blue }
end
-- Turns { red, green, blue } -> #rrggbb
function M.rgb_num2str(rgb_color_num)
local rgb_color_str = string.format(
'#%02x%02x%02x',
rgb_color_num.red,
rgb_color_num.green,
rgb_color_num.blue
)
return rgb_color_str
end
-- Returns brightness level of color in range 0 to 1
-- arbitrary value it's basically an weighted average
function M.get_color_brightness(rgb_color)
local color = M.rgb_str2num(rgb_color)
local brightness = (color.red * 2 + color.green * 3 + color.blue) / 6
return brightness / 256
end
-- returns average of colors in range 0 to 1
-- used to determine contrast level
function M.get_color_avg(rgb_color)
local color = M.rgb_str2num(rgb_color)
return (color.red + color.green + color.blue) / 3 / 256
end
-- Clamps the val between left and right
function M.clamp(val, left, right)
if val > right then
return right
end
if val < left then
return left
end
return val
end
-- Changes brightness of rgb_color by percentage
function M.brightness_modifier(rgb_color, parcentage)
local color = M.rgb_str2num(rgb_color)
color.red = M.clamp(color.red + (color.red * parcentage / 100), 0, 255)
color.green = M.clamp(color.green + (color.green * parcentage / 100), 0, 255)
color.blue = M.clamp(color.blue + (color.blue * parcentage / 100), 0, 255)
return M.rgb_num2str(color)
end
-- Changes contrast of rgb_color by amount
function M.contrast_modifier(rgb_color, amount)
local color = M.rgb_str2num(rgb_color)
color.red = M.clamp(color.red + amount, 0, 255)
color.green = M.clamp(color.green + amount, 0, 255)
color.blue = M.clamp(color.blue + amount, 0, 255)
return M.rgb_num2str(color)
end
-- Changes brightness of foreground color to achieve contrast
-- without changing the color
function M.apply_contrast(highlight, threshold)
local hightlight_bg_avg = M.get_color_avg(highlight.bg)
local contrast_threshold_config = M.clamp(threshold, 0, 0.5)
local contranst_change_step = 5
if hightlight_bg_avg > 0.5 then
contranst_change_step = -contranst_change_step
end
-- Don't waste too much time here max 25 iteration should be more than enough
local iteration_count = 1
while
math.abs(M.get_color_avg(highlight.fg) - hightlight_bg_avg)
< contrast_threshold_config
and iteration_count < 25
do
highlight.fg = M.contrast_modifier(highlight.fg, contranst_change_step)
iteration_count = iteration_count + 1
end
end
-- Change brightness of colors
-- Darken if light theme (or) Lighten if dark theme
function M.apply_brightness(color, base_color, brightness_modifier_parameter)
if base_color ~= nil then
if M.get_color_brightness(base_color) > 0.5 then
brightness_modifier_parameter = -brightness_modifier_parameter
end
return M.brightness_modifier(color, brightness_modifier_parameter)
end
end
-- Assorted highlight helpers
--
local has_nvim9 = vim.fn.has('nvim-0.9') == 1
-- Retrieves color value from highlight group names.
-- First present highlight is returned
---@param scope string
---@param highlights table
---@param default string?
---@return string|nil
function M.get_color(scope, highlights, default)
for _, hl_name in ipairs(highlights) do
local hl
if has_nvim9 then
hl = vim.api.nvim_get_hl(0, { name = hl_name })
else
---@diagnostic disable-next-line: deprecated
hl = vim.api.nvim_get_hl_by_name(hl_name, true)
hl.fg, hl.bg, hl.sp = hl.foreground, hl.background, hl.special
end
if hl.reverse then
if scope == 'bg' then
scope = 'fg'
elseif scope == 'fg' then
scope = 'bg'
end
end
if hl[scope] then
return string.format('#%06x', hl[scope])
end
end
return default
end
return M