Skip to content

Commit ed73819

Browse files
committed
feat: add new option saturation
for #140
1 parent a867351 commit ed73819

File tree

4 files changed

+135
-2
lines changed

4 files changed

+135
-2
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ require("cyberdream").setup({
158158

159159
theme = {
160160
variant = "default", -- use "light" for the light variant. Also accepts "auto" to set dark or light colors based on the current value of `vim.o.background`
161+
saturation = 1, -- accepts a value between 0 and 1. 0 will be fully desaturated (greyscale) and 1 will be the full color (default)
161162
highlights = {
162163
-- Highlight groups to override, adding new groups is also possible
163164
-- See `:h highlight-groups` for a list of highlight groups or run `:hi` to see all groups and their current values

lua/cyberdream/config.lua

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ local M = {}
1616

1717
---@class ThemeConfig
1818
---@field variant? "default" | "light" | "auto"
19+
---@field saturation? number
1920
---@field colors? CyberdreamPalette
2021
---@field highlights? table<string, CyberdreamHighlight>
2122
---@field overrides? CyberdreamOverrideFn
@@ -71,6 +72,7 @@ local default_options = {
7172

7273
theme = {
7374
variant = "default",
75+
saturation = 1,
7476
colors = {},
7577
highlights = {},
7678
},

lua/cyberdream/theme.lua

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local colors = require("cyberdream.colors")
2+
local util = require("cyberdream.util")
23

34
local M = {}
45
function M.setup()
@@ -20,6 +21,9 @@ function M.setup()
2021
end
2122
end
2223

24+
-- Apply user defined saturation
25+
t = util.apply_saturation(t, opts.theme.saturation)
26+
2327
-- Override colors with user defined colors
2428
---@type CyberdreamPalette
2529
t = vim.tbl_deep_extend("force", t, opts.theme.colors)

lua/cyberdream/util.lua

+128-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
local config = require("cyberdream.config")
22
local M = {}
33

4+
--- @alias RGB table {number, number, number}
5+
--- @alias HSL table {number, number, number}
6+
47
--- Notify the user with a message.
58
--- @param message string
69
--- @param level? "info" | "warn" | "error"
@@ -21,6 +24,129 @@ function M.syntax(syntax)
2124
end
2225
end
2326

27+
--- Convert a hex color to an RGB color.
28+
--- @param hex string "#rrggbb"
29+
--- @return RGB
30+
function M.hex_to_rgb(hex)
31+
return {
32+
tonumber(hex:sub(2, 3), 16),
33+
tonumber(hex:sub(4, 5), 16),
34+
tonumber(hex:sub(6, 7), 16),
35+
}
36+
end
37+
38+
--- Convert an RGB color to a hex color.
39+
--- @param rgb RGB
40+
--- @return string
41+
function M.rgb_to_hex(rgb)
42+
return string.format("#%02x%02x%02x", rgb[1], rgb[2], rgb[3])
43+
end
44+
45+
--- Convert an HSL color to RGB.
46+
--- @param HSL HSL
47+
--- @return RGB
48+
function M.hsl_to_rgb(HSL)
49+
local h, s, l = HSL[1] / 360, HSL[2] / 100, HSL[3] / 100
50+
local r, g, b
51+
52+
if s == 0 then
53+
r, g, b = l, l, l
54+
else
55+
local function hue_to_rgb(p, q, t)
56+
if t < 0 then
57+
t = t + 1
58+
end
59+
if t > 1 then
60+
t = t - 1
61+
end
62+
if t < 1 / 6 then
63+
return p + (q - p) * 6 * t
64+
end
65+
if t < 1 / 2 then
66+
return q
67+
end
68+
if t < 2 / 3 then
69+
return p + (q - p) * (2 / 3 - t) * 6
70+
end
71+
return p
72+
end
73+
74+
local q = l < 0.5 and l * (1 + s) or l + s - l * s
75+
local p = 2 * l - q
76+
r = hue_to_rgb(p, q, h + 1 / 3)
77+
g = hue_to_rgb(p, q, h)
78+
b = hue_to_rgb(p, q, h - 1 / 3)
79+
end
80+
81+
return { r * 255, g * 255, b * 255 }
82+
end
83+
84+
--- Convert an RGB color to HSL.
85+
--- @param RGB RGB
86+
--- @return HSL
87+
function M.rgb_to_hsl(RGB)
88+
local r, g, b = RGB[1] / 255, RGB[2] / 255, RGB[3] / 255
89+
local max, min = math.max(r, g, b), math.min(r, g, b)
90+
local h, s, l
91+
92+
l = (max + min) / 2
93+
94+
if max == min then
95+
h, s = 0, 0
96+
else
97+
local d = max - min
98+
s = l > 0.5 and d / (2 - max - min) or d / (max + min)
99+
if max == r then
100+
h = (g - b) / d + (g < b and 6 or 0)
101+
elseif max == g then
102+
h = (b - r) / d + 2
103+
elseif max == b then
104+
h = (r - g) / d + 4
105+
end
106+
h = h / 6
107+
end
108+
109+
return { h * 360, s * 100, l * 100 }
110+
end
111+
112+
--- Desaturate an HSL color based on a float. 0 is fully desaturated, 1 is the original color.
113+
--- @param HSL HSL
114+
--- @param weight number
115+
--- @return HSL
116+
function M.desaturate(HSL, weight)
117+
weight = weight or 0.5
118+
HSL[2] = HSL[2] * weight
119+
return HSL
120+
end
121+
122+
--- Desaturate a hex color based on a float. 0 is fully desaturated, 1 is the original color.
123+
function M.desaturate_hex(hex, weight)
124+
local rgb = M.hex_to_rgb(hex)
125+
local hsl = M.rgb_to_hsl(rgb)
126+
local desaturated_hsl = M.desaturate(hsl, weight)
127+
local desaturated_rgb = M.hsl_to_rgb(desaturated_hsl)
128+
return string.format("#%02x%02x%02x", desaturated_rgb[1], desaturated_rgb[2], desaturated_rgb[3])
129+
end
130+
131+
--- Apply saturation to a table of colors.
132+
--- @param colors CyberdreamColorLight | CyberdreamColorDefault
133+
--- @param weight number
134+
function M.apply_saturation(colors, weight)
135+
if weight >= 1 then
136+
return colors
137+
end
138+
139+
if weight < 0 then
140+
weight = 0
141+
end
142+
143+
local desaturated_colors = {}
144+
for k, v in pairs(colors) do
145+
desaturated_colors[k] = M.desaturate_hex(v, weight)
146+
end
147+
return desaturated_colors
148+
end
149+
24150
--- Load the colorscheme.
25151
--- @param theme table
26152
function M.load(theme)
@@ -43,8 +169,8 @@ end
43169
function M.blend(color1, color2, weight)
44170
weight = weight or 0.5
45171

46-
local rgb1 = { tonumber(color1:sub(2, 3), 16), tonumber(color1:sub(4, 5), 16), tonumber(color1:sub(6, 7), 16) }
47-
local rgb2 = { tonumber(color2:sub(2, 3), 16), tonumber(color2:sub(4, 5), 16), tonumber(color2:sub(6, 7), 16) }
172+
local rgb1 = M.hex_to_rgb(color1)
173+
local rgb2 = M.hex_to_rgb(color2)
48174
local rgb_blended = {}
49175
for i = 1, 3 do
50176
rgb_blended[i] = math.floor(rgb1[i] * weight + rgb2[i] * (1 - weight))

0 commit comments

Comments
 (0)