local config = require("github_theme.config") local palette = require("github_theme.palette") local highlights = require("github_theme.highlights") local M = { _config = config.merge(), } local function hex_to_rgb(color) local red, green, blue = color:match("^#(%x%x)(%x%x)(%x%x)$") if not red then return nil end return tonumber(red, 16), tonumber(green, 16), tonumber(blue, 16) end local function normalize_color(color, alpha_base) if type(color) ~= "string" or color == "NONE" then return color end local red, green, blue, alpha = color:match("^#(%x%x)(%x%x)(%x%x)(%x%x)$") if not red then return color:upper() end local base_red, base_green, base_blue = hex_to_rgb(alpha_base) local opacity = tonumber(alpha, 16) / 255 local source_red = tonumber(red, 16) local source_green = tonumber(green, 16) local source_blue = tonumber(blue, 16) local function blend(source, base) return math.floor((source * opacity) + (base * (1 - opacity)) + 0.5) end return string.format( "#%02X%02X%02X", blend(source_red, base_red), blend(source_green, base_green), blend(source_blue, base_blue) ) end local function normalize_override(spec) local normalized = {} for key, value in pairs(spec) do if (key == "fg" or key == "bg" or key == "sp") and value == false then normalized[key] = "NONE" else normalized[key] = value end end return normalized end local function apply_highlights(groups, alpha_base) for group, spec in pairs(groups) do if spec.link then vim.api.nvim_set_hl(0, group, spec) else vim.api.nvim_set_hl(0, group, { fg = normalize_color(spec.fg, alpha_base), bg = normalize_color(spec.bg, alpha_base), sp = normalize_color(spec.sp, alpha_base), bold = spec.bold, italic = spec.italic, underline = spec.underline, undercurl = spec.undercurl, underdouble = spec.underdouble, underdotted = spec.underdotted, underdashed = spec.underdashed, strikethrough = spec.strikethrough, reverse = spec.reverse, standout = spec.standout, nocombine = spec.nocombine, default = spec.default, ctermfg = spec.ctermfg, ctermbg = spec.ctermbg, cterm = spec.cterm, force = spec.force, }) end end end local function apply_terminal_colors(palette_values) vim.g.terminal_color_0 = palette_values.ansi_black vim.g.terminal_color_1 = palette_values.ansi_red vim.g.terminal_color_2 = palette_values.ansi_green vim.g.terminal_color_3 = palette_values.ansi_yellow vim.g.terminal_color_4 = palette_values.ansi_blue vim.g.terminal_color_5 = palette_values.ansi_magenta vim.g.terminal_color_6 = palette_values.ansi_cyan vim.g.terminal_color_7 = palette_values.ansi_white vim.g.terminal_color_8 = palette_values.ansi_bright_black vim.g.terminal_color_9 = palette_values.ansi_bright_red vim.g.terminal_color_10 = palette_values.ansi_bright_green vim.g.terminal_color_11 = palette_values.ansi_bright_yellow vim.g.terminal_color_12 = palette_values.ansi_bright_blue vim.g.terminal_color_13 = palette_values.ansi_bright_magenta vim.g.terminal_color_14 = palette_values.ansi_bright_cyan vim.g.terminal_color_15 = palette_values.ansi_bright_white end function M.setup(opts) M._config = config.merge(opts) return M._config end function M.load(variant) local active_config = M._config or config.merge() local theme = palette.get(variant, active_config) local groups = highlights.build(theme.palette, active_config) for group, spec in pairs(active_config.highlights or {}) do groups[group] = vim.tbl_deep_extend("force", groups[group] or {}, normalize_override(spec)) end vim.o.background = theme.is_dark and "dark" or "light" vim.cmd("highlight clear") if vim.fn.exists("syntax_on") == 1 then vim.cmd("syntax reset") end vim.g.colors_name = variant apply_highlights(groups, theme.palette.bg ~= "NONE" and theme.palette.bg or (theme.is_dark and "#0D1117" or "#FFFFFF")) apply_terminal_colors(theme.palette) return theme end return M