From 2ac05f469c04710585676491ff2c1ecf13acfb9e Mon Sep 17 00:00:00 2001 From: "s0wlz (Matthias Puchstein)" Date: Mon, 12 Jan 2026 23:11:24 +0100 Subject: [PATCH] feat: expand nvim highlights and add audit script --- dist/nvim/colors/apex-aeon.lua | 35 ++++++ dist/nvim/colors/apex-neon.lua | 35 ++++++ scripts/nvim-audit.sh | 18 +++ scripts/nvim_audit.lua | 181 ++++++++++++++++++++++++++++++ templates/nvim/colors/apex.lua.j2 | 35 ++++++ 5 files changed, 304 insertions(+) create mode 100755 scripts/nvim-audit.sh create mode 100644 scripts/nvim_audit.lua diff --git a/dist/nvim/colors/apex-aeon.lua b/dist/nvim/colors/apex-aeon.lua index 595130e..85aa102 100644 --- a/dist/nvim/colors/apex-aeon.lua +++ b/dist/nvim/colors/apex-aeon.lua @@ -82,6 +82,12 @@ function M.load() WildMenu = { fg = p.void, bg = p.tech }, Pmenu = { fg = p.text, bg = p.panel }, PmenuSel = { fg = p.ink, bg = p.razor, bold = true }, -- Red Menu Selection + PmenuKind = { fg = p.dim, bg = p.panel }, + PmenuKindSel = { fg = p.ink, bg = p.razor, bold = true }, + PmenuExtra = { fg = p.dim, bg = p.panel }, + PmenuExtraSel = { fg = p.ink, bg = p.razor, bold = true }, + PmenuMatch = { fg = p.tech, bg = p.panel, bold = true }, + PmenuMatchSel = { fg = p.ink, bg = p.razor, bold = true }, PmenuSbar = { bg = p.panel }, PmenuThumb = { bg = p.stealth }, ErrorMsg = { fg = p.alert }, @@ -149,6 +155,10 @@ function M.load() LspReferenceWrite = { bg = p.panel, bold = true }, LspSignatureActiveParameter = { fg = p.void, bg = p.tech, bold = true }, LspInlayHint = { fg = p.dim, bg = p.panel }, + LspCodeLens = { fg = p.dim }, + LspCodeLensSeparator = { fg = p.stealth }, + LspInfoBorder = { fg = p.border, bg = p.panel }, + LspInfoTitle = { fg = p.dim, bg = p.panel }, -- DIAGNOSTICS ----------------------------------------------------------- DiagnosticError = { fg = p.alert }, @@ -282,10 +292,29 @@ function M.load() ["@text"] = "Normal", ["@text.title"] = "Title", ["@markup.heading"] = "Title", + ["@markup.heading.1"] = "Title", + ["@markup.heading.2"] = "Title", + ["@markup.heading.3"] = "Title", + ["@markup.heading.4"] = "Title", + ["@markup.heading.5"] = "Title", + ["@markup.heading.6"] = "Title", ["@markup.link"] = "ApexMarkupLink", + ["@markup.link.label"] = "ApexMarkupLink", ["@markup.link.url"] = "ApexMarkupLink", ["@markup.strong"] = "ApexMarkupStrong", ["@markup.italic"] = "ApexMarkupItalic", + ["@markup.strikethrough"] = "DiagnosticDeprecated", + ["@markup.underline"] = "Underlined", + ["@markup.raw"] = "String", + ["@markup.raw.block"] = "String", + ["@markup.raw.delimiter"] = "Delimiter", + ["@markup.quote"] = "Comment", + ["@markup.list"] = "Delimiter", + ["@markup.list.checked"] = "String", + ["@markup.list.unchecked"] = "Comment", + ["@markup.math"] = "Constant", + ["@markup.environment"] = "Type", + ["@markup.environment.name"] = "Type", ["@type"] = "Type", ["@type.builtin"] = "Type", ["@type.definition"] = "Type", @@ -320,6 +349,12 @@ function M.load() ["@lsp.type.variable"] = "Identifier", ["@lsp.mod.deprecated"] = "DiagnosticDeprecated", + ["@lsp.mod.abstract"] = "Type", + ["@lsp.mod.declaration"] = "Keyword", + ["@lsp.mod.defaultLibrary"] = "Constant", + ["@lsp.mod.definition"] = "Keyword", + ["@lsp.mod.documentation"] = "Comment", + ["@lsp.mod.modification"] = "Operator", ["@lsp.mod.readonly"] = "Constant", ["@lsp.mod.static"] = "Constant", ["@lsp.mod.async"] = "Keyword", diff --git a/dist/nvim/colors/apex-neon.lua b/dist/nvim/colors/apex-neon.lua index e259231..0d4c606 100644 --- a/dist/nvim/colors/apex-neon.lua +++ b/dist/nvim/colors/apex-neon.lua @@ -82,6 +82,12 @@ function M.load() WildMenu = { fg = p.void, bg = p.tech }, Pmenu = { fg = p.text, bg = p.panel }, PmenuSel = { fg = p.ink, bg = p.razor, bold = true }, -- Red Menu Selection + PmenuKind = { fg = p.dim, bg = p.panel }, + PmenuKindSel = { fg = p.ink, bg = p.razor, bold = true }, + PmenuExtra = { fg = p.dim, bg = p.panel }, + PmenuExtraSel = { fg = p.ink, bg = p.razor, bold = true }, + PmenuMatch = { fg = p.tech, bg = p.panel, bold = true }, + PmenuMatchSel = { fg = p.ink, bg = p.razor, bold = true }, PmenuSbar = { bg = p.panel }, PmenuThumb = { bg = p.stealth }, ErrorMsg = { fg = p.alert }, @@ -149,6 +155,10 @@ function M.load() LspReferenceWrite = { bg = p.panel, bold = true }, LspSignatureActiveParameter = { fg = p.void, bg = p.tech, bold = true }, LspInlayHint = { fg = p.dim, bg = p.panel }, + LspCodeLens = { fg = p.dim }, + LspCodeLensSeparator = { fg = p.stealth }, + LspInfoBorder = { fg = p.border, bg = p.panel }, + LspInfoTitle = { fg = p.dim, bg = p.panel }, -- DIAGNOSTICS ----------------------------------------------------------- DiagnosticError = { fg = p.alert }, @@ -282,10 +292,29 @@ function M.load() ["@text"] = "Normal", ["@text.title"] = "Title", ["@markup.heading"] = "Title", + ["@markup.heading.1"] = "Title", + ["@markup.heading.2"] = "Title", + ["@markup.heading.3"] = "Title", + ["@markup.heading.4"] = "Title", + ["@markup.heading.5"] = "Title", + ["@markup.heading.6"] = "Title", ["@markup.link"] = "ApexMarkupLink", + ["@markup.link.label"] = "ApexMarkupLink", ["@markup.link.url"] = "ApexMarkupLink", ["@markup.strong"] = "ApexMarkupStrong", ["@markup.italic"] = "ApexMarkupItalic", + ["@markup.strikethrough"] = "DiagnosticDeprecated", + ["@markup.underline"] = "Underlined", + ["@markup.raw"] = "String", + ["@markup.raw.block"] = "String", + ["@markup.raw.delimiter"] = "Delimiter", + ["@markup.quote"] = "Comment", + ["@markup.list"] = "Delimiter", + ["@markup.list.checked"] = "String", + ["@markup.list.unchecked"] = "Comment", + ["@markup.math"] = "Constant", + ["@markup.environment"] = "Type", + ["@markup.environment.name"] = "Type", ["@type"] = "Type", ["@type.builtin"] = "Type", ["@type.definition"] = "Type", @@ -320,6 +349,12 @@ function M.load() ["@lsp.type.variable"] = "Identifier", ["@lsp.mod.deprecated"] = "DiagnosticDeprecated", + ["@lsp.mod.abstract"] = "Type", + ["@lsp.mod.declaration"] = "Keyword", + ["@lsp.mod.defaultLibrary"] = "Constant", + ["@lsp.mod.definition"] = "Keyword", + ["@lsp.mod.documentation"] = "Comment", + ["@lsp.mod.modification"] = "Operator", ["@lsp.mod.readonly"] = "Constant", ["@lsp.mod.static"] = "Constant", ["@lsp.mod.async"] = "Keyword", diff --git a/scripts/nvim-audit.sh b/scripts/nvim-audit.sh new file mode 100755 index 0000000..4d07ce8 --- /dev/null +++ b/scripts/nvim-audit.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' + +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +if ! command -v nvim >/dev/null 2>&1; then + echo "error: nvim not found on PATH" >&2 + exit 1 +fi + +if [[ ! -f "${root}/dist/nvim/colors/apex-neon.lua" ]]; then + echo "error: missing dist/nvim/colors/apex-neon.lua; run 'uv run build.py'" >&2 + exit 1 +fi + +cd "$root" +nvim --headless -u NONE -U NONE -c "lua dofile('${root}/scripts/nvim_audit.lua')" diff --git a/scripts/nvim_audit.lua b/scripts/nvim_audit.lua new file mode 100644 index 0000000..8960f9a --- /dev/null +++ b/scripts/nvim_audit.lua @@ -0,0 +1,181 @@ +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") diff --git a/templates/nvim/colors/apex.lua.j2 b/templates/nvim/colors/apex.lua.j2 index b00b1df..b2f39ab 100644 --- a/templates/nvim/colors/apex.lua.j2 +++ b/templates/nvim/colors/apex.lua.j2 @@ -82,6 +82,12 @@ function M.load() WildMenu = { fg = p.void, bg = p.tech }, Pmenu = { fg = p.text, bg = p.panel }, PmenuSel = { fg = p.ink, bg = p.razor, bold = true }, -- Red Menu Selection + PmenuKind = { fg = p.dim, bg = p.panel }, + PmenuKindSel = { fg = p.ink, bg = p.razor, bold = true }, + PmenuExtra = { fg = p.dim, bg = p.panel }, + PmenuExtraSel = { fg = p.ink, bg = p.razor, bold = true }, + PmenuMatch = { fg = p.tech, bg = p.panel, bold = true }, + PmenuMatchSel = { fg = p.ink, bg = p.razor, bold = true }, PmenuSbar = { bg = p.panel }, PmenuThumb = { bg = p.stealth }, ErrorMsg = { fg = p.alert }, @@ -149,6 +155,10 @@ function M.load() LspReferenceWrite = { bg = p.panel, bold = true }, LspSignatureActiveParameter = { fg = p.void, bg = p.tech, bold = true }, LspInlayHint = { fg = p.dim, bg = p.panel }, + LspCodeLens = { fg = p.dim }, + LspCodeLensSeparator = { fg = p.stealth }, + LspInfoBorder = { fg = p.border, bg = p.panel }, + LspInfoTitle = { fg = p.dim, bg = p.panel }, -- DIAGNOSTICS ----------------------------------------------------------- DiagnosticError = { fg = p.alert }, @@ -282,10 +292,29 @@ function M.load() ["@text"] = "Normal", ["@text.title"] = "Title", ["@markup.heading"] = "Title", + ["@markup.heading.1"] = "Title", + ["@markup.heading.2"] = "Title", + ["@markup.heading.3"] = "Title", + ["@markup.heading.4"] = "Title", + ["@markup.heading.5"] = "Title", + ["@markup.heading.6"] = "Title", ["@markup.link"] = "ApexMarkupLink", + ["@markup.link.label"] = "ApexMarkupLink", ["@markup.link.url"] = "ApexMarkupLink", ["@markup.strong"] = "ApexMarkupStrong", ["@markup.italic"] = "ApexMarkupItalic", + ["@markup.strikethrough"] = "DiagnosticDeprecated", + ["@markup.underline"] = "Underlined", + ["@markup.raw"] = "String", + ["@markup.raw.block"] = "String", + ["@markup.raw.delimiter"] = "Delimiter", + ["@markup.quote"] = "Comment", + ["@markup.list"] = "Delimiter", + ["@markup.list.checked"] = "String", + ["@markup.list.unchecked"] = "Comment", + ["@markup.math"] = "Constant", + ["@markup.environment"] = "Type", + ["@markup.environment.name"] = "Type", ["@type"] = "Type", ["@type.builtin"] = "Type", ["@type.definition"] = "Type", @@ -320,6 +349,12 @@ function M.load() ["@lsp.type.variable"] = "Identifier", ["@lsp.mod.deprecated"] = "DiagnosticDeprecated", + ["@lsp.mod.abstract"] = "Type", + ["@lsp.mod.declaration"] = "Keyword", + ["@lsp.mod.defaultLibrary"] = "Constant", + ["@lsp.mod.definition"] = "Keyword", + ["@lsp.mod.documentation"] = "Comment", + ["@lsp.mod.modification"] = "Operator", ["@lsp.mod.readonly"] = "Constant", ["@lsp.mod.static"] = "Constant", ["@lsp.mod.async"] = "Keyword",