Skip to content

Commit

Permalink
Remove dependence on terminal colours
Browse files Browse the repository at this point in the history
  • Loading branch information
Dkendal committed Sep 5, 2024
1 parent 8d00546 commit 3f367db
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 73 deletions.
32 changes: 11 additions & 21 deletions lua/nvim-treeclimber.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,30 +71,20 @@ end
function M.setup_highlight()
-- Must run after colorscheme or TermOpen to ensure that terminal_colors are available
local hi = require("nvim-treeclimber.hi")
local term_colors = hi.ansi_colors()
local hi_normal = hi.get_hl("Normal", { follow = true })

hi_normal = hi_normal and hi_normal.bg and hi.HSLUVHighlight:new(hi_normal)
or { bg = term_colors[0], fg = term_colors[1] }
local Normal = hi.get_hl("Normal", { follow = true })
assert(not vim.tbl_isempty(Normal), "hi Normal not found")
local normal = hi.HSLUVHighlight:new(Normal)

if vim.tbl_isempty(hi_normal) then
return
end
local Visual = hi.get_hl("Visual", { follow = true })
assert(not vim.tbl_isempty(Visual), "hi Visual not found")
local visual = hi.HSLUVHighlight:new(Visual)

local bg = hi_normal.bg
local fg = hi_normal.fg

local dim = bg.mix(fg, 20)

vim.api.nvim_set_hl(0, "TreeClimberHighlight", { background = dim.hex })

vim.api.nvim_set_hl(0, "TreeClimberSiblingBoundary", { background = term_colors[5].hex })

vim.api.nvim_set_hl(0, "TreeClimberSibling", { background = term_colors[5].mix(bg, 40).hex, bold = true })

vim.api.nvim_set_hl(0, "TreeClimberParent", { background = bg.mix(fg, 2).hex })

vim.api.nvim_set_hl(0, "TreeClimberParentStart", { background = term_colors[4].mix(bg, 10).hex, bold = true })
vim.api.nvim_set_hl(0, "TreeClimberHighlight", { background = visual.bg.hex })
vim.api.nvim_set_hl(0, "TreeClimberSiblingBoundary", { background = visual.bg.mix(normal.bg, 50).hex })
vim.api.nvim_set_hl(0, "TreeClimberSibling", { background = visual.bg.mix(normal.bg, 50).hex })
vim.api.nvim_set_hl(0, "TreeClimberParent", { background = visual.bg.mix(normal.bg, 50).hex })
vim.api.nvim_set_hl(0, "TreeClimberParentStart", { background = visual.bg.mix(normal.bg, 50).hex })
end

function M.setup_augroups()
Expand Down
39 changes: 11 additions & 28 deletions lua/nvim-treeclimber/hi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ local hsl = require("nvim-treeclimber.vivid.hsl.type")

local M = {}

---@class Highlight
---@field bg number
---@field fg number
---@field ctermbg number
---@field ctermfg number
---@alias Highlight vim.api.keyset.hl_info

---@param name string
---@return vim.api.keyset.hl_info
Expand Down Expand Up @@ -45,14 +41,20 @@ function M.get_hl(name, opts)
return hl
end

---@class HSLUVHighlight
---@field bg? HSLUV
---@field fg? HSLUV
---@field ctermbg? HSLUV
---@field ctermfg? HSLUV

M.HSLUVHighlight = {}

---@param hl Highlight
---@return HSLUVHighlight
function M.HSLUVHighlight:new(hl)
return {
bg = M.base_ten_to_hsluv(hl.bg),
fg = M.base_ten_to_hsluv(hl.fg),
ctermbg = hl.ctermbg,
ctermfg = hl.ctermfg,
bg = hl.bg and M.base_ten_to_hsluv(hl.bg) or nil,
fg = hl.fg and M.base_ten_to_hsluv(hl.fg) or nil,
}
end

Expand Down Expand Up @@ -104,23 +106,4 @@ function M.fg_hsl(name)
return M.hsluv(hl.fg)
end

function M.ansi_colors()
local t = {}

if not vim.g.terminal_color_0 then
error("Terminal colors not found see :help terminal-config")
end

for i = 0, 15 do
---@type string
local value = vim.g["terminal_color_" .. i]

if value then
t[i] = hsl(value)
end
end

return t
end

return M
100 changes: 76 additions & 24 deletions lua/nvim-treeclimber/vivid/hsl_like.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
local clamp = require('nvim-treeclimber.math').clamp
local round = require('nvim-treeclimber.math').round

---@class HSLUV
---@field hex string
---@field h number
---@field s number
---@field l number
---@field rotate fun(n: number): HSLUV
---@field ro fun(n: number): HSLUV
---@field saturate fun(n: number): HSLUV
---@field sa fun(n: number): HSLUV
---@field abs_saturate fun(n: number): HSLUV
---@field abs_sa fun(n: number): HSLUV
---@field desaturate fun(n: number): HSLUV
---@field de fun(n: number): HSLUV
---@field abs_desaturate fun(n: number): HSLUV
---@field abs_de fun(n: number): HSLUV
---@field lighten fun(n: number): HSLUV
---@field li fun(n: number): HSLUV
---@field abs_lighten fun(n: number): HSLUV
---@field abs_li fun(n: number): HSLUV
---@field darken fun(n: number): HSLUV
---@field da fun(n: number): HSLUV
---@field abs_darken fun(n: number): HSLUV
---@field abs_da fun(n: number): HSLUV
---@field mix fun(color: HSLUV, n: number): HSLUV
---@field readable fun(): HSLUV
---@field hue fun(n: number): HSLUV
---@field saturation fun(n: number): HSLUV
---@field lightness fun(n: number): HSLUV

--
-- HSL-like colour functions
--
Expand All @@ -23,8 +52,10 @@ end
-- return a new color with the key set to given value
local function make_abs_fn(color, key)
return function(abs_value)
if type(abs_value) ~= "number" then error("Must provide number to HSL modifiers", 0) end
local new_values = {h = color.h, s = color.s, l = color.l}
if type(abs_value) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
local new_values = { h = color.h, s = color.s, l = color.l }
new_values[key] = new_values[key] + abs_value
return new_values
end
Expand All @@ -35,10 +66,12 @@ end
-- return a new color with the key lerped by given value
local function make_lerp_fn(color, key)
return function(percent)
if type(percent) ~= "number" then error("Must provide number to HSL modifiers", 0) end
if type(percent) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end

-- we never modifiy the caller
local new_values = {h = color.h, s = color.s, l = color.l}
local new_values = { h = color.h, s = color.s, l = color.l }
-- we can safely bounds all relative adjustments to 0, 100
-- because you can't 'relatively rotate' hue
local min, max = 0, 100
Expand Down Expand Up @@ -69,15 +102,19 @@ end
-- (color) -> (n) -> {h, s lerp -n, l}
local function op_desaturate(color)
return function(percent)
if type(percent) ~= "number" then error("Must provide number to HSL modifiers", 0) end
if type(percent) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
return make_lerp_fn(color, "s")(-percent)
end
end

-- (color) -> (n) -> {h, s - n, l}
local function op_abs_desaturate(color)
return function(abs_value)
if type(abs_value) ~= "number" then error("Must provide number to HSL modifiers", 0) end
if type(abs_value) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
return make_abs_fn(color, "s")(-abs_value)
end
end
Expand All @@ -95,15 +132,19 @@ end
-- (color) -> (n) -> {h, s, l lerp -n}
local function op_darken(color)
return function(percent)
if type(percent) ~= "number" then error("Must provide number to HSL modifiers", 0) end
if type(percent) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
return make_lerp_fn(color, "l")(-percent)
end
end

-- (color) -> (n) -> {h, s, l - n}
local function op_abs_darken(color)
return function(abs_value)
if type(abs_value) ~= "number" then error("Must provide number to HSL modifiers", 0) end
if type(abs_value) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
return make_abs_fn(color, "l")(-abs_value)
end
end
Expand Down Expand Up @@ -153,34 +194,40 @@ end
-- (color) -> (n) -> {n, s, l}
local function op_hue(color)
return function(hue)
if type(hue) ~= "number" then error("Must provide number to HSL modifiers", 0) end
return {h = hue, s = color.s, l = color.l}
if type(hue) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
return { h = hue, s = color.s, l = color.l }
end
end

-- (color) -> (n) -> {h, n, l}
local function op_saturation(color)
return function(saturation)
if type(saturation) ~= "number" then error("Must provide number to HSL modifiers", 0) end
return {h = color.h, s = saturation, l = color.l}
if type(saturation) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
return { h = color.h, s = saturation, l = color.l }
end
end

-- (color) -> (n) -> {h, s, n}
local function op_lightness(color)
return function(lightness)
if type(lightness) ~= "number" then error("Must provide number to HSL modifiers", 0) end
return {h = color.h, s = color.s, l = lightness}
if type(lightness) ~= "number" then
error("Must provide number to HSL modifiers", 0)
end
return { h = color.h, s = color.s, l = lightness }
end
end

-- (color) -> (n) -> {h, s, 0 | 100}
local function op_readable(color)
return function()
if color.l >= 50 then
return {h = color.h, s = color.s, l = 0}
return { h = color.h, s = color.s, l = 0 }
else
return {h = color.h, s = color.s, l = 100}
return { h = color.h, s = color.s, l = 100 }
end
end
end
Expand Down Expand Up @@ -227,7 +274,7 @@ local function decorate_hsl_table(color, to_hex_fn)
if key_name == "h" then return color.h end
if key_name == "s" then return color.s end
if key_name == "l" then return color.l end
if key_name == "hsl" then return {h = color.h, s = color.s, l = color.l} end
if key_name == "hsl" then return { h = color.h, s = color.s, l = color.l } end
if key_name == "hex" then return to_hex_fn(color) end
if key_name == "rgb" then
local hex = to_hex_fn(color)
Expand All @@ -249,9 +296,9 @@ local function decorate_hsl_table(color, to_hex_fn)
end
ops = ops .. " h s l hex hsl"
error("Invalid hsl operation: '"
.. key_name
.. "', valid operations:"
.. ops, 2)
.. key_name
.. "', valid operations:"
.. ops, 2)
end
end,

Expand All @@ -275,6 +322,11 @@ local function decorate_hsl_table(color, to_hex_fn)
})
end

---@param h_or_hex number|string
---@param s? number
---@param l? number
---@param type_fns table
---@return HSLUV
local M = function(h_or_hex, s, l, type_fns)
assert(type_fns, "must provide type_fns")
assert(type_fns.name, "must provide name() type_fn")
Expand All @@ -289,21 +341,21 @@ local M = function(h_or_hex, s, l, type_fns)
if type(hex_str) == "string" then
-- normalise
local hex = "[abcdef0-9][abcdef0-9]"
local pat = "^#("..hex..")("..hex..")("..hex..")$"
local pat = "^#(" .. hex .. ")(" .. hex .. ")(" .. hex .. ")$"
hex_str = string.lower(hex_str)

-- smoke test
assert(string.find(hex_str, pat) ~= nil,
"hex_to_rgb: invalid hex_str: " .. tostring(hex_str))
"hex_to_rgb: invalid hex_str: " .. tostring(hex_str))

hsl = type_fns.from_hex(hex_str)
hsl = type_fns.from_hex(hex_str)
else
if type(h) ~= "number" or
type(s) ~= "number" or
type(l) ~= "number" then
error(type_fns.name() .. " expects (number, number, number) or (string)", 2)
end
hsl = {h = h, s = s, l = l}
hsl = { h = h, s = s, l = l }
end

return decorate_hsl_table(hsl, type_fns.to_hex)
Expand Down
4 changes: 4 additions & 0 deletions lua/nvim-treeclimber/vivid/hsluv/type.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ local type_fns = {
name = function() return "hsluv()" end
}

---@param h_or_hex number|string
---@param s? number
---@param l? number
---@return HSLUV
local M = function(h_or_hex, s, l)
return hsl_like(h_or_hex, s, l, type_fns)
end
Expand Down

0 comments on commit 3f367db

Please sign in to comment.