local M = {} M.bg = "#000000" M.fg = "#ffffff" M.day_brightness = 0.3 ---@param c string local function hexToRgb(c) c = string.lower(c) return { tonumber(c:sub(2, 3), 16), tonumber(c:sub(4, 5), 16), tonumber(c:sub(6, 7), 16) } end ---@param fg string foreground color ---@param bg string background color ---@param alpha number number between 0 and 1. 0 results in bg, 1 results in fg function M.blend(fg, bg, alpha) bg = hexToRgb(bg) fg = hexToRgb(fg) local blendChannel = function(i) local ret = (alpha * fg[i] + ((1 - alpha) * bg[i])) return math.floor(math.min(math.max(0, ret), 255) + 0.5) end return string.format("#%02x%02x%02x", blendChannel(1), blendChannel(2), blendChannel(3)) end function M.darken(hex, amount, bg) return M.blend(hex, bg or M.bg, math.abs(amount)) end function M.lighten(hex, amount, fg) return M.blend(hex, fg or M.fg, math.abs(amount)) end function M.invert_color(color) local hsluv = require("tokyonight.hsluv") if color ~= "NONE" then local hsl = hsluv.hex_to_hsluv(color) hsl[3] = 100 - hsl[3] if hsl[3] < 40 then hsl[3] = hsl[3] + (100 - hsl[3]) * M.day_brightness end return hsluv.hsluv_to_hex(hsl) end return color end function M.highlight(group, color) local hl = { fg = color.fg, bg = color.bg, sp = color.sp, link = color.link } if color.style and color.style:lower() ~= "none" then for s in string.gmatch(color.style, "([^,]+)") do hl[s] = true end end vim.api.nvim_set_hl(0, group, hl) end --- Delete the autocmds when the theme changes to something else function M.onColorScheme() if vim.g.colors_name ~= "tokyonight" then vim.cmd([[autocmd! TokyoNight]]) vim.cmd([[augroup! TokyoNight]]) end end ---@param config Config function M.autocmds(config) vim.cmd([[augroup TokyoNight]]) vim.cmd([[ autocmd!]]) vim.cmd([[ autocmd ColorScheme * lua require("tokyonight.util").onColorScheme()]]) for _, sidebar in ipairs(config.sidebars) do if sidebar == "terminal" then vim.cmd([[ autocmd TermOpen * setlocal winhighlight=Normal:NormalSB,SignColumn:SignColumnSB]]) else vim.cmd([[ autocmd FileType ]] .. sidebar .. [[ setlocal winhighlight=Normal:NormalSB,SignColumn:SignColumnSB]]) end end vim.cmd([[augroup end]]) end -- Simple string interpolation. -- -- Example template: "${name} is ${value}" -- ---@param str string template string ---@param table table key value pairs to replace in the string function M.template(str, table) return (str:gsub("($%b{})", function(w) return table[w:sub(3, -2)] or w end)) end function M.syntax(syntax) for group, colors in pairs(syntax) do M.highlight(group, colors) end end ---@param colors ColorScheme function M.terminal(colors) -- dark vim.g.terminal_color_0 = colors.black vim.g.terminal_color_8 = colors.terminal_black -- light vim.g.terminal_color_7 = colors.fg_dark vim.g.terminal_color_15 = colors.fg -- colors vim.g.terminal_color_1 = colors.red vim.g.terminal_color_9 = colors.red vim.g.terminal_color_2 = colors.green vim.g.terminal_color_10 = colors.green vim.g.terminal_color_3 = colors.yellow vim.g.terminal_color_11 = colors.yellow vim.g.terminal_color_4 = colors.blue vim.g.terminal_color_12 = colors.blue vim.g.terminal_color_5 = colors.magenta vim.g.terminal_color_13 = colors.magenta vim.g.terminal_color_6 = colors.cyan vim.g.terminal_color_14 = colors.cyan end ---@param colors ColorScheme function M.invert_colors(colors) if type(colors) == "string" then ---@diagnostic disable-next-line: return-type-mismatch return M.invert_color(colors) end for key, value in pairs(colors) do colors[key] = M.invert_colors(value) end end ---@param hls Highlights function M.invert_highlights(hls) for _, hl in pairs(hls) do if hl.fg then hl.fg = M.invert_color(hl.fg) end if hl.bg then hl.bg = M.invert_color(hl.bg) end if hl.sp then hl.sp = M.invert_color(hl.sp) end end end ---@param theme Theme function M.load(theme) -- only needed to clear when not the default colorscheme if vim.g.colors_name then vim.cmd("hi clear") end vim.o.termguicolors = true vim.g.colors_name = "tokyonight" M.syntax(theme.highlights) -- vim.api.nvim_set_hl_ns(M.ns) if theme.config.terminal_colors then M.terminal(theme.colors) end M.autocmds(theme.config) vim.defer_fn(function() M.syntax(theme.defer) end, 100) end return M