local function out(msg) vim.api.nvim_out_write(msg .. "\n") end local function err(msg) vim.api.nvim_err_write(msg .. "\n") end if not vim.api.nvim_get_hl then err("error: nvim_get_hl unavailable; require Neovim 0.9+") vim.cmd("cquit") end local function load_theme() local theme_path = vim.fn.getcwd() .. "/dist/nvim/colors/apex-neon.lua" local ok, load_err = pcall(dofile, theme_path) if not ok then err("error: failed to load theme: " .. tostring(load_err)) err("hint: run 'uv run build.py' to regenerate dist/") vim.cmd("cquit") end end local function has_style(hl) for key, value in pairs(hl) do if key ~= "link" and key ~= "default" then if type(value) ~= "boolean" or value then return true end end end return false end local function get_hl(name) local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = name, link = false }) if not ok then return nil, "error" end return hl, nil end local function audit(groups) local issues = {} local default_links = { Normal = true, NONE = true, } for _, group in ipairs(groups) do local hl, api_err = get_hl(group) if api_err or not hl or next(hl) == nil then table.insert(issues, "missing: " .. group) elseif hl.link and default_links[hl.link] then table.insert(issues, "default-link: " .. group .. " -> " .. hl.link) elseif not hl.link and not has_style(hl) then table.insert(issues, "empty: " .. group) end end return issues end local groups = { -- Pmenu "Pmenu", "PmenuSel", "PmenuSbar", "PmenuThumb", "WildMenu", -- LSP UI "LspReferenceText", "LspReferenceRead", "LspReferenceWrite", "LspSignatureActiveParameter", "LspInlayHint", -- Diagnostics (core + variants) "DiagnosticError", "DiagnosticWarn", "DiagnosticInfo", "DiagnosticHint", "DiagnosticOk", "DiagnosticDeprecated", "DiagnosticUnnecessary", "DiagnosticUnderlineError", "DiagnosticUnderlineWarn", "DiagnosticUnderlineInfo", "DiagnosticUnderlineHint", "DiagnosticUnderlineOk", "DiagnosticVirtualTextError", "DiagnosticVirtualTextWarn", "DiagnosticVirtualTextInfo", "DiagnosticVirtualTextHint", "DiagnosticVirtualTextOk", "DiagnosticVirtualLinesError", "DiagnosticVirtualLinesWarn", "DiagnosticVirtualLinesInfo", "DiagnosticVirtualLinesHint", "DiagnosticVirtualLinesOk", "DiagnosticSignError", "DiagnosticSignWarn", "DiagnosticSignInfo", "DiagnosticSignHint", "DiagnosticSignOk", "DiagnosticFloatingError", "DiagnosticFloatingWarn", "DiagnosticFloatingInfo", "DiagnosticFloatingHint", "DiagnosticFloatingOk", -- Markup (Tree-sitter) "@markup.heading", "@markup.link", "@markup.link.url", "@markup.strong", "@markup.italic", "ApexMarkupStrong", "ApexMarkupItalic", "ApexMarkupLink", -- LSP semantic tokens (types) "@lsp.type.boolean", "@lsp.type.builtinType", "@lsp.type.class", "@lsp.type.comment", "@lsp.type.decorator", "@lsp.type.enum", "@lsp.type.enumMember", "@lsp.type.event", "@lsp.type.function", "@lsp.type.interface", "@lsp.type.keyword", "@lsp.type.macro", "@lsp.type.method", "@lsp.type.modifier", "@lsp.type.namespace", "@lsp.type.number", "@lsp.type.operator", "@lsp.type.parameter", "@lsp.type.property", "@lsp.type.regexp", "@lsp.type.string", "@lsp.type.struct", "@lsp.type.type", "@lsp.type.typeParameter", "@lsp.type.variable", -- LSP semantic tokens (modifiers) "@lsp.mod.deprecated", "@lsp.mod.readonly", "@lsp.mod.static", "@lsp.mod.async", -- LSP semantic tokens (typemods) "@lsp.typemod.function.async", "@lsp.typemod.method.async", "@lsp.typemod.function.deprecated", "@lsp.typemod.method.deprecated", "@lsp.typemod.variable.deprecated", "@lsp.typemod.variable.readonly", "@lsp.typemod.parameter.readonly", "@lsp.typemod.property.readonly", "@lsp.typemod.variable.static", "@lsp.typemod.property.static", } load_theme() local issues = audit(groups) if #issues == 0 then out("nvim audit: ok (" .. tostring(#groups) .. " groups)") vim.cmd("qa") end err("nvim audit: " .. tostring(#issues) .. " issue(s)") for _, issue in ipairs(issues) do err(issue) end vim.cmd("cquit")