diff --git a/README.md b/README.md index 779b901..3d985fb 100644 --- a/README.md +++ b/README.md @@ -51,12 +51,12 @@ require("one_monokai").setup({ ### Available Options -| Option | Description | Type | Note | -| ------------- | -------------------------------- | -------------------------- | ---------------- | -| `transparent` | Enables a transparent background | `boolean` | N/A | -| `colors` | Custom color definitions | `table` | N/A | -| `highlights` | Custom highlight groups | `function(colors): table` | `:h nvim_set_hl` | -| `italics` | Enables italic | `boolean` | N/A | +| Option | Description | Type | Note | +| ------------- | -------------------------------- | ------------------------------- | ---------------- | +| `transparent` | Enables a transparent background | `boolean` | N/A | +| `colors` | Custom color definitions | `table` | N/A | +| `highlights` | Custom highlight groups | `function(colors): table` | `:h nvim_set_hl` | +| `italics` | Enables italic | `boolean` | N/A | ### Default Configuration @@ -91,8 +91,10 @@ colors[""]:lighten(alpha) require("one_monokai").setup({ transparent = true, -- Enable transparent background colors = { - lmao = "#ffffff", -- Define a new color pink = "#ec6075", -- Override a default color + lmao = "#ffffff", -- Define a new color as hexadecimal string + human = 0xFFABCD, -- Define a new color as number + alien = 16755661, -- Why not? }, highlights = function(colors) -- Customize highlight groups @@ -109,7 +111,7 @@ require("one_monokai").setup({ ``` > [!TIP] -> To find the highlight group for an item, place the cursor inside it and run `:Inspect`. Refer to `:h :Inspect` for more information. +> To find the highlight group for an item, place the cursor under it and run `:Inspect`. Refer to `:h :Inspect` for more information. ## :champagne: Plugin Support diff --git a/lua/one_monokai/colors.lua b/lua/one_monokai/colors.lua index ef925c5..aef792e 100644 --- a/lua/one_monokai/colors.lua +++ b/lua/one_monokai/colors.lua @@ -30,10 +30,11 @@ local defaults = { ---@type colors colors = vim.deepcopy(defaults) ----Convert hex value to rgb ----@param color string +---Converts a hex color to an RGB table +---@param color string #Hex color +---@return integer[] #RGB table {r, g, b} local function hex2rgb(color) - color = string.lower(color) + color = color:lower() return { tonumber(color:sub(2, 3), 16), @@ -42,69 +43,79 @@ local function hex2rgb(color) } end ----@param fg string #foreground color ----@param bg string #background color ----@param alpha number #number between 0 and 1. ----@source: https://github.com/folke/tokyonight.nvim/blob/main/lua/tokyonight/util.lua#L9-L37 +---Blends two hex colors together based on the alpha value. +--- +---[View source](https://github.com/folke/tokyonight.nvim/blob/main/lua/tokyonight/util.lua) +---@param fg string #Foreground hex color +---@param bg string #Background hex color +---@param alpha number #Blend factor between 0 (only bg) and 1 (only fg) +---@return string #Hex color of the resulting blended color local function blend(fg, bg, alpha) local bg_rgb = hex2rgb(bg) local fg_rgb = hex2rgb(fg) - local blend_channel = function(i) - local ret = (alpha * fg_rgb[i] + ((1 - alpha) * bg_rgb[i])) + local r = alpha * fg_rgb[1] + (1 - alpha) * bg_rgb[1] + 0.5 + local g = alpha * fg_rgb[2] + (1 - alpha) * bg_rgb[2] + 0.5 + local b = alpha * fg_rgb[3] + (1 - alpha) * bg_rgb[3] + 0.5 - return math.floor(math.min(math.max(0, ret), 255) + 0.5) - end - - return ("#%02x%02x%02x"):format(blend_channel(1), blend_channel(2), blend_channel(3)) + return ("#%02x%02x%02x"):format(r, g, b) end ----@param alpha number #number between 0 and 1 -function string:darken(alpha) - return blend(self, "#000000", alpha) +---Darkens the current hex color +---@param s string +---@param alpha number #Value between 0 and 1 +function string.darken(s, alpha) + return blend(s, "#000000", alpha) end ----@param alpha number #number between 0 and 1 -function string:lighten(alpha) - return blend(self, "#ffffff", alpha) +---Lightens the current hex color +---@param s string +---@param alpha number #Value between 0 and 1 +function string.lighten(s, alpha) + return blend(s, "#ffffff", alpha) end ----Get the hex value of a color ----@param name string #name of the color ----@param value any #value of the color ----@return string? #hex string or `nil` if invalid -local function get_hex_value(name, value) - local logs = require "one_monokai.logs" +---Resolve and retrieve the value of a color +---@param name string #Name of the color +---@param value string|number #Value of the color +---@return string|number? #Hex color or 24-bit RGB value, or default if invalid +local function resolve_color(name, value) + local color_type = type(value) - local type_ok, err = pcall(vim.validate, { - ["colors(" .. name .. ")"] = { value, "string" }, - }) + -- Resolve string first to optimize the common case + if color_type == "string" then + if value:lower() == "none" then + return value + end - if not type_ok then - logs.error(err) + local rgb = vim.api.nvim_get_color_by_name(value) - return defaults[name] + if rgb ~= -1 then + return value + end end - if value:lower() == "none" then + if color_type == "number" and value >= 0 and value <= 0xFFFFFF then return value end - local rgb = vim.api.nvim_get_color_by_name(value) - - if rgb == -1 then - logs.error("colors(%s): %q is not a valid color", name, value) + local logs = require "one_monokai.logs" + local default = defaults[name] - return defaults[name] - end + logs.error( + "colors(%s): expected hex color (#rrggbb) or 24-bit RGB color, got %q. Fallback to %q.", + name, + value, + default + ) - return ("#%06x"):format(rgb) + return default end local config = require "one_monokai.config" -for name, value in pairs(config.colors) do - colors[name] = get_hex_value(name, value) +for name, value in pairs(config.colors or {}) do + colors[name] = resolve_color(name, value) end return colors diff --git a/lua/one_monokai/config.lua b/lua/one_monokai/config.lua index 8cf79f7..f2bbc99 100644 --- a/lua/one_monokai/config.lua +++ b/lua/one_monokai/config.lua @@ -2,12 +2,12 @@ local config = {} ---@class options ---@field transparent boolean #Whether to enable transparent background ----@field colors colors #Custom colors +---@field colors? colors #Custom colors ---@field highlights? fun(colors:colors):groups #Custom highlight groups ---@field italics boolean #Whether to apply italics to certain highlight groups local defaults = { transparent = false, - colors = {}, + colors = nil, ---@deprecated themes = nil, highlights = nil, diff --git a/tests/spec/color_spec.lua b/tests/spec/color_spec.lua index e4b2ced..72add69 100644 --- a/tests/spec/color_spec.lua +++ b/tests/spec/color_spec.lua @@ -6,7 +6,7 @@ describe("Override config with color utility", function() colors = { lmao = "#812873", }, - themes = function(c) + highlights = function(c) return { Normal = { fg = c.lmao:darken(0.5) }, } @@ -25,7 +25,7 @@ describe("Override config with color utility", function() colors = { lmao = "#812873", }, - themes = function(c) + highlights = function(c) return { Normal = { fg = c.lmao:lighten(0.5) }, } diff --git a/tests/spec/config_spec.lua b/tests/spec/config_spec.lua index 6243494..fb88ff8 100644 --- a/tests/spec/config_spec.lua +++ b/tests/spec/config_spec.lua @@ -3,7 +3,9 @@ local one_monokai = require "one_monokai" describe("Config options", function() it("could be indexed without options field", function() - assert.are.same({}, config.colors) + assert.is_false(config.transparent) + assert.is_nil(config.colors) + assert.is_true(config.italics) end) end) @@ -12,6 +14,7 @@ describe("Override config", function() colors = { pink = "#61afef", lmao = "#dedeff", + alien = 0xABCDFF, }, highlights = function(c) return { @@ -35,6 +38,8 @@ describe("Override config", function() assert.equal(expected.colors.pink, colors.pink) ---@diagnostic disable-next-line: undefined-field assert.equal(expected.colors.lmao, colors.lmao) + ---@diagnostic disable-next-line: undefined-field + assert.equal(expected.colors.alien, colors.alien) end) it("should change default highlights", function()