From 024999f6f97630d17850d6f0aef2f12612a05f03 Mon Sep 17 00:00:00 2001 From: Webhooked <9132742+webhooked@users.noreply.github.com> Date: Fri, 25 Jul 2025 11:00:04 +0200 Subject: [PATCH] feat: add contrast foreground config option --- README.md | 43 +++++++++-- lua/kanso/colors.lua | 59 +++++++++++++++- lua/kanso/highlights/plugins.lua | 2 +- lua/kanso/init.lua | 70 ++++++++++++++++-- lua/kanso/themes.lua | 118 ++++++++++++++++--------------- lua/kanso/utils.lua | 6 +- lua/lualine/themes/kanso.lua | 4 +- 7 files changed, 226 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 6a17b24..31b3ee2 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ - 🌈 Extensive support for `TreeSitter` syntax highlighting - πŸ”Œ Compatible with popular plugins out of the box - ⚑ Compilation to lua byte code for fast startup times -- 🎨 Three beautiful theme variants to match your mood and environment +- 🎨 Four beautiful theme variants to match your mood and environment +- πŸ”† Contrast mode for enhanced syntax highlighting visibility - πŸ‘οΈ WCAG 2.1 AA compliant ## πŸ“¦ Installation @@ -93,11 +94,12 @@ require('kanso').setup({ overrides = function(colors) -- add/modify highlights return {} end, - theme = "zen", -- Load "zen" theme + theme = "ink", -- Load "ink" theme background = { -- map the value of 'background' option to a theme - dark = "zen", -- try "ink" ! - light = "pearl" -- try "mist" ! + dark = "ink", -- try "zen" ! + light = "ink" -- try "pearl" or "mist" ! }, + foreground = "default", -- "default" or "contrast" (can also be a table like background) }) -- setup must be called before loading @@ -177,6 +179,39 @@ require("kanso").load("zen") +## 🌟 Foreground Contrast + +Kansō now supports a foreground contrast option that enhances the saturation of syntax highlighting colors while keeping the same background colors. This is useful for improving visibility in certain lighting conditions or personal preference. + +
+πŸ”† Using Contrast Mode + +The `foreground` option can be configured per background mode: + +```lua +require('kanso').setup({ + foreground = { + dark = "default", -- Use default colors in dark mode + light = "contrast" -- Use higher saturation in light mode + }, +}) +``` + +When set to `"contrast"`, syntax highlighting colors will have increased saturation making them stand out more against the background: + +- Zen, Ink, and Mist themes: 20% more vibrant colors +- Pearl theme: 40% more vibrant colors + +This is particularly useful: + +- In bright environments where you need more color distinction +- For users who prefer more vibrant syntax highlighting +- When using the light themes where contrast can be beneficial + +The contrast adjustment only affects syntax highlighting colors (strings, keywords, functions, etc.) and does not change UI elements or background colors. + +
+ ## 🧰 Customization In Kansō, there are _two_ kinds of colors: `PaletteColors` and `ThemeColors`; diff --git a/lua/kanso/colors.lua b/lua/kanso/colors.lua index c5dcc54..26e0559 100644 --- a/lua/kanso/colors.lua +++ b/lua/kanso/colors.lua @@ -57,6 +57,30 @@ local palette = { orange2 = "#b98d7b", aqua = "#8ea4a2", + -- Contrast variants (20% more saturation) + redContrast = "#C93134", + red2Contrast = "#ED5965", + red3Contrast = "#CA675F", + yellowContrast = "#E59F49", + yellow2Contrast = "#EDC272", + yellow3Contrast = "#CAAC7A", + greenContrast = "#8FC055", + green2Contrast = "#7CAF7C", + green3Contrast = "#7F9F6E", + green4Contrast = "#5B9A82", + green5Contrast = "#6BAE97", + blueContrast = "#6EBBD4", + blue2Contrast = "#568B8F", + blue3Contrast = "#7EAABA", + blue4Contrast = "#81AAA9", + violetContrast = "#8A88B0", + violet2Contrast = "#7E91AF", + violet3Contrast = "#8A9FBE", + pinkContrast = "#A08AA2", + orangeContrast = "#BC8A6C", + orange2Contrast = "#BF856B", + aquaContrast = "#81AAA9", + -- Fg and Comments fg = "#C5C9C7", fg2 = "#f2f1ef", @@ -108,6 +132,30 @@ local palette = { pearlTeal2 = "#6693bf", pearlTeal3 = "#5a7785", pearlCyan = "#d7e3d8", + + -- Pearl contrast variants (40% more saturation) + pearlGreenContrast = "#5E8F2F", + pearlGreen2Contrast = "#5B9945", + pearlGreen3Contrast = "#A8DA9B", + pearlPinkContrast = "#C04062", + pearlOrangeContrast = "#E05700", + pearlOrange2Contrast = "#FF7700", + pearlYellowContrast = "#656720", + pearlYellow2Contrast = "#72612B", + pearlYellow3Contrast = "#F28C00", + pearlYellow4Contrast = "#FFD56D", + pearlRedContrast = "#D72436", + pearlRed2Contrast = "#E42D2C", + pearlRed3Contrast = "#F50000", + pearlRed4Contrast = "#E4977B", + pearlAquaContrast = "#3E8366", + pearlAqua2Contrast = "#428F6A", + pearlTeal1Contrast = "#2E96B0", + pearlTeal2Contrast = "#469FD3", + pearlTeal3Contrast = "#3D8077", + pearlBlue4Contrast = "#2A73B1", + pearlBlue5Contrast = "#3E56B8", + pearlViolet4Contrast = "#44418F", } local M = {} @@ -117,7 +165,7 @@ local M = {} --- Defaults to KansoConfig.colors. --- - theme: Use selected theme. Defaults to KansoConfig.theme --- according to the value of 'background' option. ----@param opts? { colors?: table, theme?: string } +---@param opts? { colors?: table, theme?: string, foreground?: "default"|"contrast" } ---@return { theme: ThemeColors, palette: PaletteColors} function M.setup(opts) opts = opts or {} @@ -134,7 +182,14 @@ function M.setup(opts) local updated_palette_colors = vim.tbl_extend("force", palette, override_colors.palette or {}) -- Generate the theme according to the updated palette colors - local theme_colors = require("kanso.themes")[theme](updated_palette_colors) + local kanso_config = require("kanso").config + local bg_mode = vim.o.background + local foreground = opts.foreground + or (type(kanso_config.foreground) == "table" and kanso_config.foreground[bg_mode]) + or kanso_config.foreground + or "default" + ---@cast foreground "default"|"contrast" + local theme_colors = require("kanso.themes")[theme](updated_palette_colors, foreground) -- Add to and/or override theme_colors local theme_overrides = diff --git a/lua/kanso/highlights/plugins.lua b/lua/kanso/highlights/plugins.lua index dc3281d..fd8be2a 100644 --- a/lua/kanso/highlights/plugins.lua +++ b/lua/kanso/highlights/plugins.lua @@ -527,7 +527,7 @@ function M.setup(colors, config) BufferLineBackground = { fg = theme.ui.none, bg = theme.ui.none }, BufferLineBuffer = { fg = theme.ui.none, bg = theme.ui.none }, - BufferLineBufferSelected = { bg = theme.ui.none }, + BufferLineBufferSelected = { bg = theme.ui.none, fg = theme.ui.fg }, BufferLineBufferVisible = { bg = theme.ui.none }, BufferLineCloseButton = { bg = theme.ui.none }, BufferLineCloseButtonSelected = { bg = theme.ui.none }, diff --git a/lua/kanso/init.lua b/lua/kanso/init.lua index 6272db0..a69264c 100644 --- a/lua/kanso/init.lua +++ b/lua/kanso/init.lua @@ -25,12 +25,14 @@ M.config = { return {} end, ---@type { dark: string, light: string } - background = { dark = "ink", light = "pearl" }, + background = { dark = "ink", light = "ink" }, theme = "ink", + ---@type { dark: "default"|"contrast", light: "default"|"contrast" }|"default"|"contrast" + foreground = "default", compile = false, } -local function check_config(config) +local function check_config(_) local err return not err end @@ -60,6 +62,22 @@ function M.load(theme) vim.g.colors_name = "kanso" vim.o.termguicolors = true + -- Setup autocommand to reload theme when background changes + if not M._autocmd_created then + M._autocmd_created = true + vim.api.nvim_create_autocmd("OptionSet", { + pattern = "background", + callback = function() + if vim.g.colors_name == "kanso" then + -- Clear cached modules to force reload + package.loaded["kanso.colors"] = nil + package.loaded["kanso.themes"] = nil + M.load() + end + end, + }) + end + if M.config.compile then if utils.load_compiled(theme) then return @@ -68,7 +86,11 @@ function M.load(theme) M.compile() utils.load_compiled(theme) else - local colors = require("kanso.colors").setup({ theme = theme, colors = M.config.colors }) + local foreground_setting = type(M.config.foreground) == "table" and M.config.foreground[vim.o.background] + or M.config.foreground + ---@cast foreground_setting "default"|"contrast" + local colors = + require("kanso.colors").setup({ theme = theme, colors = M.config.colors, foreground = foreground_setting }) local highlights = require("kanso.highlights").setup(colors, M.config) require("kanso.highlights").highlight(highlights, M.config.terminalColors and colors.theme.term or {}) end @@ -76,9 +98,45 @@ end function M.compile() for theme, _ in pairs(require("kanso.themes")) do - local colors = require("kanso.colors").setup({ theme = theme, colors = M.config.colors }) - local highlights = require("kanso.highlights").setup(colors, M.config) - require("kanso.utils").compile(theme, highlights, M.config.terminalColors and colors.theme.term or {}) + -- Compile both foreground variants if foreground is a table + if type(M.config.foreground) == "table" then + -- Compile for dark mode + local colors_dark = require("kanso.colors").setup({ + theme = theme, + colors = M.config.colors, + foreground = M.config.foreground.dark, + }) + local highlights_dark = require("kanso.highlights").setup(colors_dark, M.config) + require("kanso.utils").compile( + theme .. "_dark_" .. M.config.foreground.dark, + highlights_dark, + M.config.terminalColors and colors_dark.theme.term or {} + ) + + -- Compile for light mode + local colors_light = require("kanso.colors").setup({ + theme = theme, + colors = M.config.colors, + foreground = M.config.foreground.light, + }) + local highlights_light = require("kanso.highlights").setup(colors_light, M.config) + require("kanso.utils").compile( + theme .. "_light_" .. M.config.foreground.light, + highlights_light, + M.config.terminalColors and colors_light.theme.term or {} + ) + else + -- Fallback for backward compatibility + local foreground_str = M.config.foreground + ---@cast foreground_str "default"|"contrast" + local colors = require("kanso.colors").setup({ + theme = theme, + colors = M.config.colors, + foreground = foreground_str, + }) + local highlights = require("kanso.highlights").setup(colors, M.config) + require("kanso.utils").compile(theme, highlights, M.config.terminalColors and colors.theme.term or {}) + end end end diff --git a/lua/kanso/themes.lua b/lua/kanso/themes.lua index 86c8813..8769a28 100644 --- a/lua/kanso/themes.lua +++ b/lua/kanso/themes.lua @@ -1,5 +1,3 @@ -local c = require("kanso.lib.color") - --TODO: --PreProc needs its own color --parameter and field should be different @@ -94,8 +92,9 @@ local c = require("kanso.lib.color") return { ---@param palette PaletteColors + ---@param foreground? "default"|"contrast" ---@return ThemeColors - zen = function(palette) + zen = function(palette, foreground) return { ui = { none = "NONE", @@ -143,25 +142,25 @@ return { }, }, syn = { - string = palette.green3, + string = foreground == "contrast" and palette.green3Contrast or palette.green3, variable = "NONE", - number = palette.pink, - constant = palette.orange, - identifier = palette.violet2, + number = foreground == "contrast" and palette.pinkContrast or palette.pink, + constant = foreground == "contrast" and palette.orangeContrast or palette.orange, + identifier = foreground == "contrast" and palette.violet2Contrast or palette.violet2, parameter = palette.gray3, - fun = palette.blue3, - statement = palette.violet2, - keyword = palette.violet2, + fun = foreground == "contrast" and palette.blue3Contrast or palette.blue3, + statement = foreground == "contrast" and palette.violet2Contrast or palette.violet2, + keyword = foreground == "contrast" and palette.violet2Contrast or palette.violet2, operator = palette.gray3, preproc = palette.gray3, - type = palette.aqua, - regex = palette.red3, + type = foreground == "contrast" and palette.aquaContrast or palette.aqua, + regex = foreground == "contrast" and palette.red3Contrast or palette.red3, deprecated = palette.gray, punct = palette.gray3, comment = palette.gray4, - special1 = palette.yellow3, - special2 = palette.violet2, - special3 = palette.violet2, + special1 = foreground == "contrast" and palette.yellow3Contrast or palette.yellow3, + special2 = foreground == "contrast" and palette.violet2Contrast or palette.violet2, + special3 = foreground == "contrast" and palette.violet2Contrast or palette.violet2, }, diag = { error = palette.red, @@ -205,8 +204,9 @@ return { } end, ---@param palette PaletteColors + ---@param foreground? "default"|"contrast" ---@return ThemeColors - ink = function(palette) + ink = function(palette, foreground) return { ui = { none = "NONE", @@ -254,25 +254,25 @@ return { }, }, syn = { - string = palette.green3, + string = foreground == "contrast" and palette.green3Contrast or palette.green3, variable = "NONE", - number = palette.pink, - constant = palette.orange, - identifier = palette.violet2, + number = foreground == "contrast" and palette.pinkContrast or palette.pink, + constant = foreground == "contrast" and palette.orangeContrast or palette.orange, + identifier = foreground == "contrast" and palette.violet2Contrast or palette.violet2, parameter = palette.gray3, - fun = palette.blue3, - statement = palette.violet2, - keyword = palette.violet2, + fun = foreground == "contrast" and palette.blue3Contrast or palette.blue3, + statement = foreground == "contrast" and palette.violet2Contrast or palette.violet2, + keyword = foreground == "contrast" and palette.violet2Contrast or palette.violet2, operator = palette.gray3, preproc = palette.gray3, - type = palette.aqua, - regex = palette.red3, + type = foreground == "contrast" and palette.aquaContrast or palette.aqua, + regex = foreground == "contrast" and palette.red3Contrast or palette.red3, deprecated = palette.gray, punct = palette.gray3, comment = palette.gray4, - special1 = palette.yellow3, - special2 = palette.violet2, - special3 = palette.violet2, + special1 = foreground == "contrast" and palette.yellow3Contrast or palette.yellow3, + special2 = foreground == "contrast" and palette.violet2Contrast or palette.violet2, + special3 = foreground == "contrast" and palette.violet2Contrast or palette.violet2, }, diag = { error = palette.red, @@ -316,8 +316,9 @@ return { } end, ---@param palette PaletteColors + ---@param foreground? "default"|"contrast" ---@return ThemeColors - pearl = function(palette) + pearl = function(palette, foreground) return { ui = { none = "NONE", @@ -364,25 +365,25 @@ return { }, }, syn = { - string = palette.pearlGreen, + string = foreground == "contrast" and palette.pearlGreenContrast or palette.pearlGreen, variable = "NONE", - number = palette.pearlPink, - constant = palette.pearlOrange, - identifier = palette.pearlViolet4, - parameter = palette.pearlBlue5, - fun = palette.pearlBlue4, - statement = palette.pearlViolet4, - keyword = palette.pearlViolet4, + number = foreground == "contrast" and palette.pearlPinkContrast or palette.pearlPink, + constant = foreground == "contrast" and palette.pearlOrangeContrast or palette.pearlOrange, + identifier = foreground == "contrast" and palette.pearlViolet4Contrast or palette.pearlViolet4, + parameter = foreground == "contrast" and palette.pearlBlue5Contrast or palette.pearlBlue5, + fun = foreground == "contrast" and palette.pearlBlue4Contrast or palette.pearlBlue4, + statement = foreground == "contrast" and palette.pearlViolet4Contrast or palette.pearlViolet4, + keyword = foreground == "contrast" and palette.pearlViolet4Contrast or palette.pearlViolet4, operator = palette.pearlGray3, preproc = palette.pearlGray2, - type = palette.pearlAqua, - regex = palette.pearlYellow2, + type = foreground == "contrast" and palette.pearlAquaContrast or palette.pearlAqua, + regex = foreground == "contrast" and palette.pearlYellow2Contrast or palette.pearlYellow2, deprecated = palette.pearlGray3, comment = palette.pearlGray3, punct = palette.pearlGray3, - special1 = palette.pearlYellow2, - special2 = palette.pearlViolet4, - special3 = palette.pearlViolet4, + special1 = foreground == "contrast" and palette.pearlYellow2Contrast or palette.pearlYellow2, + special2 = foreground == "contrast" and palette.pearlViolet4Contrast or palette.pearlViolet4, + special3 = foreground == "contrast" and palette.pearlViolet4Contrast or palette.pearlViolet4, }, vcs = { added = palette.pearlGreen2, @@ -426,8 +427,9 @@ return { } end, ---@param palette PaletteColors + ---@param foreground? "default"|"contrast" ---@return ThemeColors - mist = function(palette) + mist = function(palette, foreground) return { ui = { none = "NONE", @@ -475,25 +477,25 @@ return { }, }, syn = { - string = palette.green3, + string = foreground == "contrast" and palette.green3Contrast or palette.green3, variable = "NONE", - number = palette.pink, - constant = palette.orange, - identifier = palette.violet2, + number = foreground == "contrast" and palette.pinkContrast or palette.pink, + constant = foreground == "contrast" and palette.orangeContrast or palette.orange, + identifier = foreground == "contrast" and palette.violet2Contrast or palette.violet2, parameter = palette.gray3, - fun = palette.blue3, - statement = palette.violet2, - keyword = palette.violet2, + fun = foreground == "contrast" and palette.blue3Contrast or palette.blue3, + statement = foreground == "contrast" and palette.violet2Contrast or palette.violet2, + keyword = foreground == "contrast" and palette.violet2Contrast or palette.violet2, operator = palette.gray3, preproc = palette.gray3, - type = palette.aqua, - regex = palette.red3, + type = foreground == "contrast" and palette.aquaContrast or palette.aqua, + regex = foreground == "contrast" and palette.red3Contrast or palette.red3, deprecated = palette.gray, punct = palette.gray3, comment = palette.gray4, - special1 = palette.yellow3, - special2 = palette.violet2, - special3 = palette.violet2, + special1 = foreground == "contrast" and palette.yellow3Contrast or palette.yellow3, + special2 = foreground == "contrast" and palette.violet2Contrast or palette.violet2, + special3 = foreground == "contrast" and palette.violet2Contrast or palette.violet2, }, diag = { error = palette.red, @@ -509,9 +511,9 @@ return { text = palette.diffYellow, }, vcs = { - added = palette.autumnGreen, - removed = palette.autumnRed, - changed = palette.autumnYellow, + added = palette.gitGreen, + removed = palette.gitRed, + changed = palette.gitYellow, untracked = palette.gray4, }, term = { diff --git a/lua/kanso/utils.lua b/lua/kanso/utils.lua index 599efa7..1a9e3c4 100644 --- a/lua/kanso/utils.lua +++ b/lua/kanso/utils.lua @@ -1,5 +1,5 @@ local M = {} -local PATH_SEP = vim.loop.os_uname().version:match("Windows") and "\\" or "/" +local PATH_SEP = vim.uv.os_uname().version:match("Windows") and "\\" or "/" local get_compiled_path = function(theme) return table.concat({ vim.fn.stdpath("state"), "kanso", theme .. "_compiled.lua" }, PATH_SEP) @@ -8,14 +8,14 @@ end ---@return string theme function M.get_theme_from_bg_opt() local config = require("kanso").config - return config.theme[vim.o.background] or config.theme.default + return config.background[vim.o.background] or config.theme end ---@param theme string ---@param highlights table ---@param termcolors table function M.compile(theme, highlights, termcolors) - vim.loop.fs_mkdir(vim.fn.stdpath("state") .. PATH_SEP .. "kanso", 448) + vim.uv.fs_mkdir(vim.fn.stdpath("state") .. PATH_SEP .. "kanso", 448) local fname = get_compiled_path(theme) local file, err = io.open(fname, "wb") diff --git a/lua/lualine/themes/kanso.lua b/lua/lualine/themes/kanso.lua index 0f57267..3b33660 100644 --- a/lua/lualine/themes/kanso.lua +++ b/lua/lualine/themes/kanso.lua @@ -3,8 +3,8 @@ local theme = require("kanso.colors").setup().theme local kanso = {} kanso.normal = { - a = { bg = theme.syn.fun, fg = theme.ui.bg }, - b = { bg = theme.ui.none, fg = theme.syn.fun }, + a = { bg = theme.ui.fg, fg = theme.ui.bg }, + b = { bg = theme.ui.none, fg = theme.ui.fg }, c = { bg = theme.ui.none, fg = theme.ui.fg }, }