vim.opt.termguicolors = true vim.opt.runtimepath:prepend(vim.fn.getcwd()) vim.cmd("syntax on") local theme = require("github_theme") local variants = { "github_light_default", "github_light_high_contrast", "github_light_colorblind", "github_dark_default", "github_dark_high_contrast", "github_dark_colorblind", "github_dark_dimmed", } local function fail(message) error(message, 0) end local function assert_equal(actual, expected, message) if actual ~= expected then fail(("%s\nexpected: %s\nactual: %s"):format(message, tostring(expected), tostring(actual))) end end local function assert_true(value, message) if not value then fail(message) end end local function highlight_id(name) return vim.fn.hlID(name) end local function highlight_attr(name, attr) local value = vim.fn.synIDattr(highlight_id(name), attr) if value == nil then return "" end return tostring(value) end local function highlight_hex(name, attr) local suffix = attr == "fg" and "fg#" or attr == "bg" and "bg#" or "sp#" return string.upper(highlight_attr(name, suffix)) end local function final_syntax_name(line, col) local id = vim.fn.synID(line, col, 1) return vim.fn.synIDattr(vim.fn.synIDtrans(id), "name") end local function assert_group(name, variant) assert_true(highlight_id(name) ~= 0, ("%s missing group %s"):format(variant, name)) end for _, variant in ipairs(variants) do theme.setup({}) vim.cmd.colorscheme(variant) assert_equal(vim.g.colors_name, variant, ("colors_name mismatch for %s"):format(variant)) assert_group("Normal", variant) assert_group("NormalFloat", variant) assert_group("Comment", variant) assert_group("String", variant) assert_group("Function", variant) assert_group("Type", variant) assert_group("Visual", variant) assert_group("DiagnosticError", variant) assert_group("DiffAdd", variant) assert_true(type(vim.g.terminal_color_0) == "string" and vim.g.terminal_color_0 ~= "", ("%s missing terminal colors"):format(variant)) end theme.setup({}) vim.cmd.colorscheme("github_light_high_contrast") assert_equal(highlight_hex("Visual", "fg"), "#FFFFFF", "light high contrast Visual fg should preserve upstream selection foreground") vim.cmd.colorscheme("github_dark_high_contrast") assert_equal(highlight_hex("Visual", "fg"), "#0A0C10", "dark high contrast Visual fg should preserve upstream selection foreground") theme.setup({ transparent = true }) vim.cmd.colorscheme("github_dark_default") assert_equal(highlight_hex("Normal", "bg"), "", "transparent Normal background should be empty") assert_equal(highlight_hex("NormalFloat", "bg"), "", "transparent NormalFloat background should be empty") assert_equal(highlight_hex("SignColumn", "bg"), "", "transparent SignColumn background should be empty") theme.setup({ styles = { comments = { italic = true }, keywords = { bold = true }, functions = { underline = true }, types = { italic = true }, }, }) vim.cmd.colorscheme("github_dark_default") assert_equal(highlight_attr("Comment", "italic"), "1", "Comment should be italic when enabled") assert_equal(highlight_attr("Keyword", "bold"), "1", "Keyword should be bold when enabled") assert_equal(highlight_attr("Function", "underline"), "1", "Function should be underlined when enabled") assert_equal(highlight_attr("Type", "italic"), "1", "Type should be italic when enabled") theme.setup({ colors = { comment = "#123456", }, }) vim.cmd.colorscheme("github_dark_default") assert_equal(highlight_hex("Comment", "fg"), "#123456", "palette color override should win") theme.setup({ colors = { comment = "#123456", }, highlights = { Comment = { fg = "#654321", italic = true, }, }, }) vim.cmd.colorscheme("github_dark_default") assert_equal(highlight_hex("Comment", "fg"), "#654321", "highlight override should win over palette override") assert_equal(highlight_attr("Comment", "italic"), "1", "highlight override should apply styles") theme.setup({ highlights = { Comment = { italic = false, }, }, }) vim.cmd.colorscheme("github_dark_default") assert_equal(highlight_attr("Comment", "italic"), "", "highlight overrides should allow disabling styles") theme.setup({}) vim.cmd.colorscheme("github_dark_default") local dark_fg = highlight_hex("Normal", "fg") vim.cmd.colorscheme("github_dark_default") assert_equal(highlight_hex("Normal", "fg"), dark_fg, "reloading the same theme should be stable") vim.cmd.colorscheme("github_light_default") assert_equal(vim.o.background, "light", "switching to a light theme should update background") assert_true(highlight_hex("Normal", "fg") ~= "", "Normal fg should stay defined after switching variants") theme.setup({}) local markdown_theme = theme.load("github_dark_default") vim.cmd("enew!") vim.api.nvim_buf_set_lines(0, 0, -1, false, { "# Heading", "", "> quoted", "- item", "See [Docs](https://example.com) and `code`.", }) vim.bo.filetype = "markdown" vim.cmd("set syntax=markdown") vim.cmd("syntax sync fromstart") assert_equal(highlight_hex("markdownCode", "fg"), markdown_theme.palette.inline_raw, "markdown inline code should use the inline raw color") assert_equal(highlight_hex("markdownCodeDelimiter", "fg"), markdown_theme.palette.inline_raw, "markdown code delimiters should use the inline raw color") assert_equal(highlight_hex("markdownBlockquote", "fg"), markdown_theme.palette.quote, "markdown blockquotes should use the quote color") assert_equal(highlight_hex("markdownListMarker", "fg"), markdown_theme.palette.type, "markdown list markers should use the list color") assert_equal(highlight_hex("markdownLinkText", "fg"), markdown_theme.palette.link, "markdown link text should use the link color") assert_equal(highlight_hex("markdownUrl", "fg"), markdown_theme.palette.link, "markdown URLs should use the link color") assert_equal(final_syntax_name(5, 38), "markdownCode", "markdown inline code text should resolve to markdownCode") theme.setup({}) local typescript_theme = theme.load("github_dark_default") vim.cmd("enew!") vim.api.nvim_buf_set_lines(0, 0, -1, false, { "interface User { name: string }", "const data = Promise.resolve(value)", "const field = user.name", "function greet(name: string) { return name }", }) vim.bo.filetype = "typescript" vim.cmd("set syntax=typescript") vim.cmd("syntax sync fromstart") assert_equal(highlight_hex("typescriptInterfaceName", "fg"), typescript_theme.palette.type, "typescript interface names should use the type color") assert_equal(highlight_hex("typescriptVariable", "fg"), typescript_theme.palette.keyword, "typescript declaration keywords should use the keyword color") assert_equal(highlight_hex("typescriptMember", "fg"), typescript_theme.palette.property, "typescript members should use the property color") assert_equal(highlight_hex("typescriptCall", "fg"), typescript_theme.palette.variable, "typescript parameter regions should use the variable color") assert_equal(highlight_hex("typescriptBraces", "fg"), typescript_theme.palette.fg_muted, "typescript braces should use the muted punctuation color") assert_equal(highlight_hex("typescriptTypeReference", "fg"), typescript_theme.palette.type, "typescript type references should use the type color") assert_equal(highlight_hex("typescriptGlobal", "fg"), typescript_theme.palette.support, "typescript globals should use the support color") assert_equal(highlight_hex("typescriptDOMFormProp", "fg"), typescript_theme.palette.property, "legacy DOM property matches should use the property color") assert_equal(highlight_hex("typescriptBOMWindowProp", "fg"), typescript_theme.palette.variable_other, "legacy window property matches should stay neutral") assert_equal(final_syntax_name(1, 11), "typescriptInterfaceName", "typescript interface names should resolve to typescriptInterfaceName") assert_equal(final_syntax_name(1, 18), "typescriptMember", "typescript object type members should resolve to typescriptMember") assert_equal(final_syntax_name(2, 1), "typescriptVariable", "const should resolve to typescriptVariable") assert_equal(final_syntax_name(2, 14), "typescriptGlobal", "Promise should resolve to typescriptGlobal") assert_equal(final_syntax_name(3, 20), "typescriptDOMFormProp", "legacy DOM property names should resolve to typescriptDOMFormProp") assert_equal(final_syntax_name(4, 16), "typescriptCall", "function parameter names should resolve to typescriptCall")