restructured for vim.pack

This commit is contained in:
normanras
2026-04-15 11:46:47 -04:00
parent 578e71442e
commit 1e1f820040
5 changed files with 4 additions and 0 deletions

556
lua/n8n/groups.lua Normal file
View File

@ -0,0 +1,556 @@
local theme = require("n8n.theme")
local M = {}
---@param opts? table
function M.setup(opts)
opts = opts or {}
local c = theme.colors()
local groups = {}
-- ============================================================
-- Core editor highlights
-- ============================================================
groups.Normal = { fg = c.fg, bg = c.bg }
groups.NormalFloat = { fg = c.fg, bg = c.bg_float }
groups.NormalSB = { fg = c.fg_sidebar, bg = c.bg_sidebar }
groups.SignColumn = { fg = c.fg_gutter, bg = c.bg }
groups.FoldColumn = { fg = c.fg_gutter, bg = c.bg }
groups.MsgArea = { fg = c.fg }
groups.MsgSeparator = { fg = c.border }
groups.SpellBad = { sp = c.error, undercurl = true }
groups.SpellCap = { sp = c.warning, undercurl = true }
groups.SpellLocal = { sp = c.info, undercurl = true }
groups.SpellRare = { sp = c.hint, undercurl = true }
-- Cursor and selections
groups.Cursor = { fg = c.bg, bg = c.fg_bright }
groups.lCursor = { link = "Cursor" }
groups.CursorIM = { link = "Cursor" }
groups.TermCursor = { fg = c.bg, bg = c.accent }
groups.TermCursorNC = { fg = c.bg, bg = c.fg_dark }
groups.CursorLine = { bg = c.bg_highlight }
groups.CursorColumn = { bg = c.bg_highlight }
groups.ColorColumn = { bg = c.bg_highlight }
groups.Visual = { bg = c.bg_visual }
groups.VisualNOS = { bg = c.bg_visual }
-- Line numbers
groups.LineNr = { fg = c.fg_gutter }
groups.CursorLineNr = { fg = c.accent, bold = true }
groups.LineNrAbove = { fg = c.fg_gutter }
groups.LineNrBelow = { fg = c.fg_gutter }
-- Search
groups.Search = { fg = c.fg_bright, bg = c.bg_search }
groups.IncSearch = { fg = c.bg, bg = c.accent }
groups.CurSearch = { link = "IncSearch" }
groups.Substitute = { fg = c.bg, bg = c.accent }
-- Popup menu
groups.Pmenu = { fg = c.fg, bg = c.bg_popup }
groups.PmenuSel = { fg = c.fg_bright, bg = c.bg_visual }
groups.PmenuSbar = { bg = c.bg_popup }
groups.PmenuThumb = { bg = c.border }
groups.PmenuKind = { fg = c.accent }
groups.PmenuKindSel = { fg = c.accent, bg = c.bg_visual }
groups.PmenuExtra = { fg = c.fg_dark }
groups.PmenuExtraSel = { fg = c.fg_dark, bg = c.bg_visual }
-- Tabline
groups.TabLine = { fg = c.fg_dark, bg = c.bg_statusline }
groups.TabLineFill = { bg = c.bg_dark }
groups.TabLineSel = { fg = c.fg_bright, bg = c.bg }
-- Statusline
groups.StatusLine = { fg = c.fg, bg = c.bg_statusline }
groups.StatusLineNC = { fg = c.fg_gutter, bg = c.bg_statusline }
-- Window separators
groups.VertSplit = { fg = c.border }
groups.WinSeparator = { fg = c.border }
groups.WinBar = { fg = c.fg, bg = c.bg }
groups.WinBarNC = { fg = c.fg_dark, bg = c.bg }
-- Folds and columns
groups.Folded = { fg = c.fg_dark, bg = c.bg_highlight }
groups.NonText = { fg = c.neutral_700 }
groups.EndOfBuffer = { fg = c.neutral_800 }
groups.Whitespace = { fg = c.neutral_800 }
groups.SpecialKey = { fg = c.neutral_700 }
-- Messages
groups.ErrorMsg = { fg = c.error }
groups.WarningMsg = { fg = c.warning }
groups.MoreMsg = { fg = c.info }
groups.Question = { fg = c.accent }
groups.Title = { fg = c.accent, bold = true }
groups.Directory = { fg = c.func }
groups.Conceal = { fg = c.fg_dark }
groups.MatchParen = { fg = c.accent, bold = true, underline = true }
groups.QuickFixLine = { bg = c.bg_visual }
-- Float border
groups.FloatBorder = { fg = c.border_highlight, bg = c.bg_float }
groups.FloatTitle = { fg = c.accent, bg = c.bg_float, bold = true }
-- ============================================================
-- Standard syntax groups (:h group-name)
-- ============================================================
groups.Comment = { fg = c.comment, italic = true }
groups.Constant = { fg = c.constant }
groups.String = { fg = c.string }
groups.Character = { fg = c.string }
groups.Number = { fg = c.number }
groups.Boolean = { fg = c.boolean }
groups.Float = { fg = c.number }
groups.Identifier = { fg = c.variable }
groups.Function = { fg = c.func }
groups.Statement = { fg = c.keyword }
groups.Conditional = { fg = c.keyword }
groups.Repeat = { fg = c.keyword }
groups.Label = { fg = c.keyword }
groups.Operator = { fg = c.operator }
groups.Keyword = { fg = c.keyword }
groups.Exception = { fg = c.keyword }
groups.PreProc = { fg = c.preproc }
groups.Include = { fg = c.keyword }
groups.Define = { fg = c.keyword }
groups.Macro = { fg = c.preproc }
groups.PreCondit = { fg = c.preproc }
groups.Type = { fg = c.type }
groups.StorageClass = { fg = c.keyword }
groups.Structure = { fg = c.type }
groups.Typedef = { fg = c.type }
groups.Special = { fg = c.special }
groups.SpecialChar = { fg = c.escape }
groups.Tag = { fg = c.tag }
groups.Delimiter = { fg = c.punctuation }
groups.SpecialComment = { fg = c.comment, bold = true }
groups.Debug = { fg = c.warning }
groups.Underlined = { underline = true }
groups.Bold = { bold = true }
groups.Italic = { italic = true }
groups.Ignore = { fg = c.bg }
groups.Error = { fg = c.error }
groups.Todo = { fg = c.bg, bg = c.accent, bold = true }
-- ============================================================
-- Treesitter highlights (@groups)
-- ============================================================
-- Identifiers
groups["@variable"] = { fg = c.variable }
groups["@variable.builtin"] = { fg = c.builtin, italic = true }
groups["@variable.parameter"] = { fg = c.parameter }
groups["@variable.parameter.builtin"] = { fg = c.parameter, italic = true }
groups["@variable.member"] = { fg = c.property }
groups["@constant"] = { fg = c.constant }
groups["@constant.builtin"] = { fg = c.constant, bold = true }
groups["@constant.macro"] = { fg = c.preproc }
groups["@module"] = { fg = c.namespace }
groups["@module.builtin"] = { fg = c.namespace, italic = true }
groups["@label"] = { fg = c.keyword }
-- Literals
groups["@string"] = { fg = c.string }
groups["@string.documentation"] = { fg = c.comment }
groups["@string.regex"] = { fg = c.regex }
groups["@string.escape"] = { fg = c.escape }
groups["@string.special"] = { fg = c.special }
groups["@string.special.symbol"] = { fg = c.special }
groups["@string.special.url"] = { fg = c.info, underline = true }
groups["@string.special.path"] = { fg = c.info }
groups["@character"] = { fg = c.string }
groups["@character.special"] = { fg = c.escape }
groups["@boolean"] = { fg = c.boolean }
groups["@number"] = { fg = c.number }
groups["@number.float"] = { fg = c.number }
-- Types
groups["@type"] = { fg = c.type }
groups["@type.builtin"] = { fg = c.type, italic = true }
groups["@type.definition"] = { fg = c.type }
groups["@type.qualifier"] = { fg = c.keyword }
groups["@attribute"] = { fg = c.attribute }
groups["@attribute.builtin"] = { fg = c.attribute, italic = true }
groups["@property"] = { fg = c.property }
-- Functions
groups["@function"] = { fg = c.func }
groups["@function.builtin"] = { fg = c.builtin }
groups["@function.call"] = { fg = c.func }
groups["@function.macro"] = { fg = c.preproc }
groups["@function.method"] = { fg = c.func }
groups["@function.method.call"] = { fg = c.func }
groups["@constructor"] = { fg = c.type }
groups["@operator"] = { fg = c.operator }
-- Keywords
groups["@keyword"] = { fg = c.keyword }
groups["@keyword.coroutine"] = { fg = c.keyword, italic = true }
groups["@keyword.function"] = { fg = c.keyword }
groups["@keyword.operator"] = { fg = c.operator }
groups["@keyword.import"] = { fg = c.keyword }
groups["@keyword.type"] = { fg = c.keyword }
groups["@keyword.modifier"] = { fg = c.keyword }
groups["@keyword.repeat"] = { fg = c.keyword }
groups["@keyword.return"] = { fg = c.keyword }
groups["@keyword.debug"] = { fg = c.warning }
groups["@keyword.exception"] = { fg = c.keyword }
groups["@keyword.conditional"] = { fg = c.keyword }
groups["@keyword.conditional.ternary"] = { fg = c.operator }
groups["@keyword.directive"] = { fg = c.preproc }
groups["@keyword.directive.define"] = { fg = c.preproc }
-- Punctuation
groups["@punctuation.delimiter"] = { fg = c.punctuation }
groups["@punctuation.bracket"] = { fg = c.punctuation }
groups["@punctuation.special"] = { fg = c.special }
-- Comments
groups["@comment"] = { fg = c.comment, italic = true }
groups["@comment.documentation"] = { fg = c.comment }
groups["@comment.error"] = { fg = c.error }
groups["@comment.warning"] = { fg = c.warning }
groups["@comment.todo"] = { fg = c.bg, bg = c.accent, bold = true }
groups["@comment.note"] = { fg = c.bg, bg = c.info, bold = true }
-- Markup (markdown, html, etc.)
groups["@markup.strong"] = { bold = true }
groups["@markup.italic"] = { italic = true }
groups["@markup.strikethrough"] = { strikethrough = true }
groups["@markup.underline"] = { underline = true }
groups["@markup.heading"] = { fg = c.accent, bold = true }
groups["@markup.heading.1"] = { fg = c.accent, bold = true }
groups["@markup.heading.2"] = { fg = c.func, bold = true }
groups["@markup.heading.3"] = { fg = c.type, bold = true }
groups["@markup.heading.4"] = { fg = c.string, bold = true }
groups["@markup.heading.5"] = { fg = c.constant, bold = true }
groups["@markup.heading.6"] = { fg = c.comment, bold = true }
groups["@markup.quote"] = { fg = c.fg_dark, italic = true }
groups["@markup.math"] = { fg = c.number }
groups["@markup.environment"] = { fg = c.preproc }
groups["@markup.link"] = { fg = c.info, underline = true }
groups["@markup.link.label"] = { fg = c.info }
groups["@markup.link.url"] = { fg = c.info, underline = true }
groups["@markup.raw"] = { fg = c.string }
groups["@markup.raw.block"] = { fg = c.fg }
groups["@markup.list"] = { fg = c.accent }
groups["@markup.list.checked"] = { fg = c.git_add }
groups["@markup.list.unchecked"] = { fg = c.fg_dark }
-- Tags (HTML, JSX, etc.)
groups["@tag"] = { fg = c.tag }
groups["@tag.builtin"] = { fg = c.tag, bold = true }
groups["@tag.attribute"] = { fg = c.attribute }
groups["@tag.delimiter"] = { fg = c.punctuation }
-- ============================================================
-- LSP Semantic Tokens
-- ============================================================
groups["@lsp.type.boolean"] = { link = "@boolean" }
groups["@lsp.type.builtinType"] = { link = "@type.builtin" }
groups["@lsp.type.comment"] = { link = "@comment" }
groups["@lsp.type.decorator"] = { link = "@attribute" }
groups["@lsp.type.deriveHelper"] = { link = "@attribute" }
groups["@lsp.type.enum"] = { link = "@type" }
groups["@lsp.type.enumMember"] = { link = "@constant" }
groups["@lsp.type.escapeSequence"] = { link = "@string.escape" }
groups["@lsp.type.formatSpecifier"] = { link = "@punctuation.special" }
groups["@lsp.type.function"] = { link = "@function" }
groups["@lsp.type.generic"] = { link = "@variable" }
groups["@lsp.type.interface"] = { fg = c.type }
groups["@lsp.type.keyword"] = { link = "@keyword" }
groups["@lsp.type.lifetime"] = { link = "@keyword.modifier" }
groups["@lsp.type.method"] = { link = "@function.method" }
groups["@lsp.type.namespace"] = { link = "@module" }
groups["@lsp.type.number"] = { link = "@number" }
groups["@lsp.type.operator"] = { link = "@operator" }
groups["@lsp.type.parameter"] = { link = "@variable.parameter" }
groups["@lsp.type.property"] = { link = "@property" }
groups["@lsp.type.selfKeyword"] = { fg = c.builtin, italic = true }
groups["@lsp.type.selfTypeKeyword"] = { link = "@type.builtin" }
groups["@lsp.type.string"] = { link = "@string" }
groups["@lsp.type.typeAlias"] = { link = "@type.definition" }
groups["@lsp.type.typeParameter"] = { fg = c.type }
groups["@lsp.type.unresolvedReference"] = { undercurl = true, sp = c.error }
groups["@lsp.type.variable"] = {} -- defer to treesitter
groups["@lsp.typemod.class.defaultLibrary"] = { link = "@type.builtin" }
groups["@lsp.typemod.enum.defaultLibrary"] = { link = "@type.builtin" }
groups["@lsp.typemod.enumMember.defaultLibrary"] = { link = "@constant.builtin" }
groups["@lsp.typemod.function.defaultLibrary"] = { link = "@function.builtin" }
groups["@lsp.typemod.keyword.async"] = { link = "@keyword.coroutine" }
groups["@lsp.typemod.keyword.injected"] = { link = "@keyword" }
groups["@lsp.typemod.macro.defaultLibrary"] = { link = "@function.builtin" }
groups["@lsp.typemod.method.defaultLibrary"] = { link = "@function.builtin" }
groups["@lsp.typemod.operator.injected"] = { link = "@operator" }
groups["@lsp.typemod.string.injected"] = { link = "@string" }
groups["@lsp.typemod.struct.defaultLibrary"] = { link = "@type.builtin" }
groups["@lsp.typemod.type.defaultLibrary"] = { link = "@type.builtin" }
groups["@lsp.typemod.typeAlias.defaultLibrary"] = { link = "@type.builtin" }
groups["@lsp.typemod.variable.callable"] = { link = "@function" }
groups["@lsp.typemod.variable.defaultLibrary"] = { link = "@variable.builtin" }
groups["@lsp.typemod.variable.injected"] = { link = "@variable" }
groups["@lsp.typemod.variable.static"] = { link = "@constant" }
-- ============================================================
-- Diagnostics
-- ============================================================
groups.DiagnosticError = { fg = c.error }
groups.DiagnosticWarn = { fg = c.warning }
groups.DiagnosticInfo = { fg = c.info }
groups.DiagnosticHint = { fg = c.hint }
groups.DiagnosticOk = { fg = c.git_add }
groups.DiagnosticUnderlineError = { undercurl = true, sp = c.error }
groups.DiagnosticUnderlineWarn = { undercurl = true, sp = c.warning }
groups.DiagnosticUnderlineInfo = { undercurl = true, sp = c.info }
groups.DiagnosticUnderlineHint = { undercurl = true, sp = c.hint }
groups.DiagnosticUnderlineOk = { undercurl = true, sp = c.git_add }
groups.DiagnosticVirtualTextError = { fg = c.error, bg = c.danger_bg }
groups.DiagnosticVirtualTextWarn = { fg = c.warning, bg = c.sticky_bg }
groups.DiagnosticVirtualTextInfo = { fg = c.info, bg = c.info_bg }
groups.DiagnosticVirtualTextHint = { fg = c.hint, bg = c.success_bg }
-- ============================================================
-- Diff
-- ============================================================
groups.DiffAdd = { bg = c.diff_add }
groups.DiffChange = { bg = c.diff_change }
groups.DiffDelete = { bg = c.diff_delete }
groups.DiffText = { bg = c.diff_text }
groups.diffAdded = { fg = c.git_add }
groups.diffRemoved = { fg = c.git_delete }
groups.diffChanged = { fg = c.git_change }
groups.diffOldFile = { fg = c.git_delete }
groups.diffNewFile = { fg = c.git_add }
groups.diffFile = { fg = c.info }
groups.diffLine = { fg = c.comment }
groups.diffIndexLine = { fg = c.comment }
-- ============================================================
-- Git Signs
-- ============================================================
groups.GitSignsAdd = { fg = c.git_add }
groups.GitSignsChange = { fg = c.git_change }
groups.GitSignsDelete = { fg = c.git_delete }
groups.GitSignsAddNr = { fg = c.git_add }
groups.GitSignsChangeNr = { fg = c.git_change }
groups.GitSignsDeleteNr = { fg = c.git_delete }
groups.GitSignsAddLn = { bg = c.diff_add }
groups.GitSignsChangeLn = { bg = c.diff_change }
groups.GitSignsDeleteLn = { bg = c.diff_delete }
groups.GitSignsCurrentLineBlame = { fg = c.fg_gutter, italic = true }
-- ============================================================
-- Telescope
-- ============================================================
groups.TelescopeNormal = { fg = c.fg, bg = c.bg_float }
groups.TelescopeBorder = { fg = c.border_highlight, bg = c.bg_float }
groups.TelescopeTitle = { fg = c.accent, bold = true }
groups.TelescopePromptNormal = { fg = c.fg_bright, bg = c.bg_popup }
groups.TelescopePromptBorder = { fg = c.accent, bg = c.bg_popup }
groups.TelescopePromptTitle = { fg = c.bg, bg = c.accent, bold = true }
groups.TelescopePromptPrefix = { fg = c.accent }
groups.TelescopePreviewTitle = { fg = c.bg, bg = c.info, bold = true }
groups.TelescopeResultsTitle = { fg = c.bg, bg = c.hint, bold = true }
groups.TelescopeSelection = { bg = c.bg_visual }
groups.TelescopeSelectionCaret = { fg = c.accent }
groups.TelescopeMatching = { fg = c.accent, bold = true }
-- ============================================================
-- NvimTree / Neo-tree
-- ============================================================
groups.NvimTreeNormal = { fg = c.fg_sidebar, bg = c.bg_sidebar }
groups.NvimTreeNormalNC = { fg = c.fg_sidebar, bg = c.bg_sidebar }
groups.NvimTreeRootFolder = { fg = c.accent, bold = true }
groups.NvimTreeFolderIcon = { fg = c.func }
groups.NvimTreeFolderName = { fg = c.func }
groups.NvimTreeOpenedFolderName = { fg = c.func, bold = true }
groups.NvimTreeGitDirty = { fg = c.git_change }
groups.NvimTreeGitNew = { fg = c.git_add }
groups.NvimTreeGitDeleted = { fg = c.git_delete }
groups.NvimTreeSpecialFile = { fg = c.special, underline = true }
groups.NvimTreeIndentMarker = { fg = c.border }
groups.NvimTreeWinSeparator = { fg = c.border, bg = c.bg_sidebar }
groups.NeoTreeNormal = { fg = c.fg_sidebar, bg = c.bg_sidebar }
groups.NeoTreeNormalNC = { fg = c.fg_sidebar, bg = c.bg_sidebar }
groups.NeoTreeDimText = { fg = c.fg_gutter }
groups.NeoTreeTitleBar = { fg = c.bg, bg = c.accent }
-- ============================================================
-- Indent Blankline
-- ============================================================
groups.IndentBlanklineChar = { fg = c.neutral_800, nocombine = true }
groups.IndentBlanklineContextChar = { fg = c.accent, nocombine = true }
groups.IblIndent = { fg = c.neutral_800, nocombine = true }
groups.IblScope = { fg = c.accent, nocombine = true }
-- ============================================================
-- Which Key
-- ============================================================
groups.WhichKey = { fg = c.accent }
groups.WhichKeyGroup = { fg = c.func }
groups.WhichKeyDesc = { fg = c.fg }
groups.WhichKeySeparator = { fg = c.comment }
groups.WhichKeyValue = { fg = c.fg_dark }
-- ============================================================
-- Dashboard / Alpha
-- ============================================================
groups.DashboardHeader = { fg = c.accent }
groups.DashboardCenter = { fg = c.func }
groups.DashboardShortCut = { fg = c.keyword }
groups.DashboardFooter = { fg = c.comment, italic = true }
-- ============================================================
-- Notify
-- ============================================================
groups.NotifyERRORBorder = { fg = c.error }
groups.NotifyERRORIcon = { fg = c.error }
groups.NotifyERRORTitle = { fg = c.error }
groups.NotifyWARNBorder = { fg = c.warning }
groups.NotifyWARNIcon = { fg = c.warning }
groups.NotifyWARNTitle = { fg = c.warning }
groups.NotifyINFOBorder = { fg = c.info }
groups.NotifyINFOIcon = { fg = c.info }
groups.NotifyINFOTitle = { fg = c.info }
groups.NotifyDEBUGBorder = { fg = c.comment }
groups.NotifyDEBUGIcon = { fg = c.comment }
groups.NotifyDEBUGTitle = { fg = c.comment }
groups.NotifyTRACEBorder = { fg = c.special }
groups.NotifyTRACEIcon = { fg = c.special }
groups.NotifyTRACETitle = { fg = c.special }
-- ============================================================
-- Noice
-- ============================================================
groups.NoiceCmdlinePopup = { fg = c.fg, bg = c.bg_float }
groups.NoiceCmdlinePopupBorder = { fg = c.accent }
groups.NoiceCmdlineIcon = { fg = c.accent }
groups.NoiceConfirm = { fg = c.fg, bg = c.bg_float }
groups.NoiceConfirmBorder = { fg = c.accent }
-- ============================================================
-- Cmp (completion)
-- ============================================================
groups.CmpItemAbbr = { fg = c.fg }
groups.CmpItemAbbrDeprecated = { fg = c.fg_dark, strikethrough = true }
groups.CmpItemAbbrMatch = { fg = c.accent, bold = true }
groups.CmpItemAbbrMatchFuzzy = { fg = c.accent, bold = true }
groups.CmpItemKind = { fg = c.func }
groups.CmpItemMenu = { fg = c.fg_dark }
groups.CmpItemKindClass = { fg = c.type }
groups.CmpItemKindColor = { fg = c.special }
groups.CmpItemKindConstant = { fg = c.constant }
groups.CmpItemKindConstructor = { fg = c.type }
groups.CmpItemKindEnum = { fg = c.type }
groups.CmpItemKindEnumMember = { fg = c.constant }
groups.CmpItemKindEvent = { fg = c.special }
groups.CmpItemKindField = { fg = c.property }
groups.CmpItemKindFile = { fg = c.fg }
groups.CmpItemKindFolder = { fg = c.func }
groups.CmpItemKindFunction = { fg = c.func }
groups.CmpItemKindInterface = { fg = c.type }
groups.CmpItemKindKeyword = { fg = c.keyword }
groups.CmpItemKindMethod = { fg = c.func }
groups.CmpItemKindModule = { fg = c.namespace }
groups.CmpItemKindOperator = { fg = c.operator }
groups.CmpItemKindProperty = { fg = c.property }
groups.CmpItemKindReference = { fg = c.constant }
groups.CmpItemKindSnippet = { fg = c.special }
groups.CmpItemKindStruct = { fg = c.type }
groups.CmpItemKindText = { fg = c.fg }
groups.CmpItemKindTypeParameter = { fg = c.type }
groups.CmpItemKindUnit = { fg = c.constant }
groups.CmpItemKindValue = { fg = c.constant }
groups.CmpItemKindVariable = { fg = c.variable }
-- ============================================================
-- Blink.cmp
-- ============================================================
groups.BlinkCmpMenu = { fg = c.fg, bg = c.bg_popup }
groups.BlinkCmpMenuBorder = { fg = c.border_highlight, bg = c.bg_popup }
groups.BlinkCmpMenuSelection = { bg = c.bg_visual }
groups.BlinkCmpLabel = { fg = c.fg }
groups.BlinkCmpLabelMatch = { fg = c.accent, bold = true }
groups.BlinkCmpKind = { fg = c.func }
-- ============================================================
-- Trouble
-- ============================================================
groups.TroubleNormal = { fg = c.fg, bg = c.bg_sidebar }
groups.TroubleNormalNC = { fg = c.fg_sidebar, bg = c.bg_sidebar }
-- ============================================================
-- Lazy
-- ============================================================
groups.LazyButton = { fg = c.fg, bg = c.bg_popup }
groups.LazyButtonActive = { fg = c.bg, bg = c.accent }
groups.LazyH1 = { fg = c.bg, bg = c.accent, bold = true }
groups.LazySpecial = { fg = c.accent }
groups.LazyProgressDone = { fg = c.accent }
groups.LazyProgressTodo = { fg = c.fg_gutter }
-- ============================================================
-- Mason
-- ============================================================
groups.MasonNormal = { fg = c.fg, bg = c.bg_float }
groups.MasonHeader = { fg = c.bg, bg = c.accent, bold = true }
groups.MasonHighlight = { fg = c.accent }
groups.MasonHighlightBlock = { fg = c.bg, bg = c.accent }
groups.MasonMutedBlock = { fg = c.fg, bg = c.bg_popup }
-- ============================================================
-- Mini plugins
-- ============================================================
groups.MiniStatuslineFilename = { fg = c.fg, bg = c.bg_statusline }
groups.MiniStatuslineDevinfo = { fg = c.fg_dark, bg = c.bg_highlight }
groups.MiniStatuslineModeNormal = { fg = c.bg, bg = c.accent, bold = true }
groups.MiniStatuslineModeInsert = { fg = c.bg, bg = c.hint, bold = true }
groups.MiniStatuslineModeVisual = { fg = c.bg, bg = c.special, bold = true }
groups.MiniStatuslineModeReplace = { fg = c.bg, bg = c.error, bold = true }
groups.MiniStatuslineModeCommand = { fg = c.bg, bg = c.warning, bold = true }
groups.MiniIndentscopeSymbol = { fg = c.accent }
groups.MiniCursorword = { bg = c.bg_visual }
groups.MiniCursorwordCurrent = { bg = c.bg_visual }
-- ============================================================
-- Bufferline
-- ============================================================
groups.BufferLineIndicatorSelected = { fg = c.accent }
groups.BufferLineFill = { bg = c.bg_dark }
-- ============================================================
-- Snacks
-- ============================================================
groups.SnacksDashboardHeader = { fg = c.accent }
groups.SnacksDashboardFooter = { fg = c.comment, italic = true }
groups.SnacksDashboardIcon = { fg = c.func }
groups.SnacksDashboardKey = { fg = c.accent }
groups.SnacksDashboardDesc = { fg = c.fg }
groups.SnacksNotifierInfo = { fg = c.info }
groups.SnacksNotifierWarn = { fg = c.warning }
groups.SnacksNotifierError = { fg = c.error }
return groups
end
return M

130
lua/n8n/init.lua Normal file
View File

@ -0,0 +1,130 @@
local M = {}
---@class N8nConfig
M.config = {
transparent = false, -- enable transparent background
terminal_colors = true, -- set terminal colors
dim_inactive = false, -- dim inactive windows
styles = {
comments = { italic = true },
keywords = {},
functions = {},
strings = {},
variables = {},
},
---@type table<string, vim.api.keyset.highlight>
on_highlights = function(highlights, colors) end,
---@type fun(colors: table): table
on_colors = function(colors) return colors end,
}
---@param opts? N8nConfig
function M.setup(opts)
M.config = vim.tbl_deep_extend("force", M.config, opts or {})
end
function M.load()
if vim.g.colors_name then
vim.cmd("hi clear")
end
if vim.fn.exists("syntax_on") then
vim.cmd("syntax reset")
end
vim.o.termguicolors = true
vim.g.colors_name = "n8n"
vim.o.background = "dark"
local theme = require("n8n.theme")
local groups_mod = require("n8n.groups")
local c = theme.colors()
-- Let user modify colors
if type(M.config.on_colors) == "function" then
local custom = M.config.on_colors(c)
if custom then
c = vim.tbl_deep_extend("force", c, custom)
end
end
-- Handle transparent mode
if M.config.transparent then
c.bg = "NONE"
c.bg_sidebar = "NONE"
c.bg_float = "NONE"
end
local groups = groups_mod.setup({ colors = c })
-- Apply style overrides
if M.config.styles.comments then
groups.Comment = vim.tbl_extend("force", groups.Comment or {}, M.config.styles.comments)
groups["@comment"] = vim.tbl_extend("force", groups["@comment"] or {}, M.config.styles.comments)
end
if M.config.styles.keywords then
for _, key in ipairs({ "Keyword", "Statement", "Conditional", "Repeat", "@keyword" }) do
if groups[key] then
groups[key] = vim.tbl_extend("force", groups[key], M.config.styles.keywords)
end
end
end
if M.config.styles.functions then
for _, key in ipairs({ "Function", "@function", "@function.call" }) do
if groups[key] then
groups[key] = vim.tbl_extend("force", groups[key], M.config.styles.functions)
end
end
end
if M.config.styles.strings then
for _, key in ipairs({ "String", "@string" }) do
if groups[key] then
groups[key] = vim.tbl_extend("force", groups[key], M.config.styles.strings)
end
end
end
if M.config.styles.variables then
for _, key in ipairs({ "Identifier", "@variable" }) do
if groups[key] then
groups[key] = vim.tbl_extend("force", groups[key], M.config.styles.variables)
end
end
end
-- Dim inactive windows
if M.config.dim_inactive then
groups.NormalNC = { fg = c.fg_dark, bg = c.bg_dark }
end
-- Let user modify highlights
if type(M.config.on_highlights) == "function" then
M.config.on_highlights(groups, c)
end
-- Apply all highlight groups
for group, hl in pairs(groups) do
vim.api.nvim_set_hl(0, group, hl)
end
-- Set terminal colors
if M.config.terminal_colors then
local t = theme.colors().terminal
vim.g.terminal_color_0 = t.black
vim.g.terminal_color_1 = t.red
vim.g.terminal_color_2 = t.green
vim.g.terminal_color_3 = t.yellow
vim.g.terminal_color_4 = t.blue
vim.g.terminal_color_5 = t.magenta
vim.g.terminal_color_6 = t.cyan
vim.g.terminal_color_7 = t.white
vim.g.terminal_color_8 = t.bright_black
vim.g.terminal_color_9 = t.bright_red
vim.g.terminal_color_10 = t.bright_green
vim.g.terminal_color_11 = t.bright_yellow
vim.g.terminal_color_12 = t.bright_blue
vim.g.terminal_color_13 = t.bright_magenta
vim.g.terminal_color_14 = t.bright_cyan
vim.g.terminal_color_15 = t.bright_white
end
end
return M

151
lua/n8n/palette.lua Normal file
View File

@ -0,0 +1,151 @@
---@class N8nPalette
local M = {}
-- n8n Design System palette
-- Extracted from the official n8n dark theme CSS custom properties
-- Neutrals (the backbone of n8n's dark UI)
M.neutral_white = "#ffffff"
M.neutral_50 = "#fcfcfc"
M.neutral_100 = "#f9f9f9"
M.neutral_125 = "#f5f5f5"
M.neutral_150 = "#ededed"
M.neutral_200 = "#e0e0e0"
M.neutral_250 = "#cccccc"
M.neutral_300 = "#adadad"
M.neutral_400 = "#949494"
M.neutral_500 = "#828282"
M.neutral_600 = "#757575"
M.neutral_700 = "#4d4d4d"
M.neutral_750 = "#424242"
M.neutral_800 = "#3d3d3d"
M.neutral_850 = "#2b2b2b"
M.neutral_900 = "#212121"
M.neutral_950 = "#171717"
M.neutral_black = "#000000"
-- Orange (n8n's brand accent in dark mode)
M.orange_50 = "#fff6f5"
M.orange_100 = "#ffe8e6"
M.orange_150 = "#ffdfdb"
M.orange_200 = "#ffc9c2"
M.orange_250 = "#ff9c8f"
M.orange_300 = "#ff6f5c"
M.orange_400 = "#ff4b33"
M.orange_500 = "#ff1e00"
M.orange_600 = "#cc1800"
M.orange_700 = "#991200"
M.orange_800 = "#660c00"
M.orange_900 = "#330600"
M.orange_950 = "#1a0300"
-- Purple (used for pinned nodes, code syntax, accents)
M.purple_50 = "#f8f7fc"
M.purple_100 = "#edecf8"
M.purple_200 = "#e6e4f6"
M.purple_300 = "#c3bee9"
M.purple_400 = "#a098dc"
M.purple_500 = "#7d72cf"
M.purple_600 = "#5a4cc2"
M.purple_700 = "#4438a3"
M.purple_800 = "#3b308d"
M.purple_900 = "#302772"
M.purple_950 = "#211b50"
-- Green (success states, boolean/number syntax)
M.green_50 = "#ebfaf1"
M.green_100 = "#d6f5e3"
M.green_200 = "#adebc7"
M.green_300 = "#85e0ac"
M.green_400 = "#5cd693"
M.green_500 = "#33cc78"
M.green_600 = "#29a360"
M.green_700 = "#1f7a48"
M.green_800 = "#19663d"
M.green_900 = "#145231"
M.green_950 = "#0a291a"
-- Mint (chat user backgrounds, alternative green)
M.mint_500 = "#16e975"
M.mint_600 = "#13cd67"
M.mint_700 = "#0d8c46"
-- Red (danger, errors, diagnostics)
M.red_50 = "#fef1f2"
M.red_100 = "#fcdadd"
M.red_200 = "#faccd0"
M.red_250 = "#f7abb1"
M.red_300 = "#f5949c"
M.red_400 = "#f16a75"
M.red_500 = "#ee4452"
M.red_600 = "#ea1f30"
M.red_700 = "#c41221"
M.red_800 = "#ad101d"
M.red_900 = "#7e0c15"
M.red_950 = "#4f070d"
-- Blue (info states, links, selections)
M.blue_50 = "#eaf2fb"
M.blue_100 = "#ddebf8"
M.blue_200 = "#b2d1f0"
M.blue_300 = "#7fb3e6"
M.blue_400 = "#4891db"
M.blue_500 = "#2878c8"
M.blue_600 = "#236bb3"
M.blue_700 = "#1b5288"
M.blue_800 = "#13385e"
M.blue_900 = "#081a2b"
-- Yellow (warnings, sticky notes)
M.yellow_100 = "#fff5d6"
M.yellow_200 = "#ffe48a"
M.yellow_300 = "#ffdb66"
M.yellow_400 = "#ffcf33"
M.yellow_500 = "#ffc400"
M.yellow_600 = "#cc9c00"
M.yellow_700 = "#a37d00"
M.yellow_800 = "#705600"
M.yellow_900 = "#332700"
-- Gold (alternative warm accent)
M.gold_50 = "#fdf9f1"
M.gold_100 = "#f7e3c4"
M.gold_200 = "#f4d8ae"
M.gold_300 = "#efc381"
M.gold_400 = "#e6a23d"
M.gold_500 = "#d48a1c"
M.gold_600 = "#b57617"
M.gold_700 = "#905e13"
M.gold_800 = "#63410d"
M.gold_900 = "#2d1d06"
-- Slate (alternative neutral with blue tint)
M.slate_100 = "#e4e3e8"
M.slate_200 = "#c8c7d1"
M.slate_300 = "#adabba"
M.slate_400 = "#928fa3"
M.slate_500 = "#76738c"
M.slate_600 = "#5f5c70"
M.slate_700 = "#474554"
M.slate_800 = "#2f2e38"
M.slate_900 = "#18171c"
-- n8n brand pink (logo, marketing)
M.brand_pink = "#EA4B71"
M.brand_dark = "#101330"
-- Assistant/AI highlight gradient stops
M.highlight_1 = "#8c90f2"
M.highlight_2 = "#a977f0"
M.highlight_3 = "#f0778b"
-- Node icon accent colors (from the canvas)
M.icon_blue = "#898fff"
M.icon_light_blue = "#58abff"
M.icon_dark_blue = "#7ba7ff"
M.icon_pink_red = "#f85d82"
-- Special
M.none = "NONE"
return M

122
lua/n8n/theme.lua Normal file
View File

@ -0,0 +1,122 @@
local palette = require("n8n.palette")
---@class N8nTheme
local M = {}
function M.colors()
return {
-- Editor backgrounds (mirroring n8n's layered dark surfaces)
bg = palette.neutral_950, -- #171717 canvas background
bg_dark = palette.neutral_black, -- #000000 deepest bg
bg_float = palette.neutral_900, -- #212121 floating panels
bg_popup = palette.neutral_850, -- #2b2b2b popup menus
bg_sidebar = palette.neutral_900, -- #212121 sidebar/tree
bg_statusline = palette.neutral_900, -- #212121 statusline
bg_visual = palette.neutral_750, -- #424242 visual selection
bg_highlight = palette.neutral_850, -- #2b2b2b cursorline
bg_search = palette.yellow_900, -- #332700 search highlight bg
-- Foregrounds
fg = palette.neutral_200, -- #e0e0e0 primary text
fg_bright = palette.neutral_white, -- #ffffff bright text
fg_dark = palette.neutral_400, -- #949494 muted text
fg_gutter = palette.neutral_600, -- #757575 gutter/line numbers
fg_sidebar = palette.neutral_300, -- #adadad sidebar text
-- Borders (n8n uses white alpha overlays on dark)
border = palette.neutral_700, -- #4d4d4d default border
border_highlight = palette.neutral_600, -- #757575 active border
-- Brand accent (n8n orange in dark mode)
accent = palette.orange_300, -- #ff6f5c brand accent
accent_hover = palette.orange_400, -- #ff4b33 hover state
accent_active = palette.orange_500, -- #ff1e00 active/pressed
-- Syntax colors (derived from n8n's code editor + JSON viewer)
keyword = palette.orange_300, -- #ff6f5c keywords (brand color)
string = palette.purple_400, -- #a098dc strings
func = palette.blue_300, -- #7fb3e6 functions
variable = palette.neutral_200, -- #e0e0e0 variables
constant = palette.gold_400, -- #e6a23d constants
number = palette.green_600, -- #29a360 numbers
boolean = palette.green_600, -- #29a360 booleans
type = palette.purple_300, -- #c3bee9 types
operator = palette.orange_250, -- #ff9c8f operators
property = palette.blue_400, -- #4891db properties/fields
parameter = palette.gold_300, -- #efc381 parameters
comment = palette.neutral_500, -- #828282 comments
punctuation = palette.neutral_400, -- #949494 punctuation
tag = palette.orange_300, -- #ff6f5c HTML/XML tags
attribute = palette.purple_400, -- #a098dc attributes
namespace = palette.slate_300, -- #adabba namespaces
preproc = palette.brand_pink, -- #EA4B71 preprocessor
special = palette.highlight_2, -- #a977f0 special symbols
regex = palette.mint_500, -- #16e975 regex
escape = palette.mint_600, -- #13cd67 escape sequences
builtin = palette.blue_300, -- #7fb3e6 built-in functions
-- JSON viewer colors (directly from n8n's JSON display)
json_key = palette.neutral_125, -- #f5f5f5 JSON keys
json_string = palette.purple_400, -- #a098dc JSON string values
json_number = palette.green_600, -- #29a360 JSON numbers
json_boolean = palette.green_600, -- #29a360 JSON booleans
json_null = palette.red_400, -- #f16a75 JSON null
json_bracket = palette.neutral_700, -- #4d4d4d brackets
-- Diagnostics
error = palette.red_600, -- #ea1f30
warning = palette.yellow_500, -- #ffc400
info = palette.blue_500, -- #2878c8
hint = palette.green_500, -- #33cc78
-- Diff
diff_add = palette.green_950, -- #0a291a
diff_change = palette.blue_900, -- #081a2b
diff_delete = palette.red_950, -- #4f070d
diff_text = palette.blue_800, -- #13385e
-- Git signs
git_add = palette.green_500, -- #33cc78
git_change = palette.blue_400, -- #4891db
git_delete = palette.red_500, -- #ee4452
-- Raw neutrals (used in groups for subtle UI elements)
neutral_700 = palette.neutral_700, -- #4d4d4d
neutral_800 = palette.neutral_800, -- #3d3d3d
-- n8n-specific semantic colors
node_bg = palette.neutral_850, -- node card background
node_border = palette.purple_500, -- pinned node border
sticky_bg = palette.yellow_900, -- sticky note background
sticky_border = palette.yellow_800, -- sticky note border
sticky_text = palette.neutral_125, -- sticky note text
success_bg = palette.green_950, -- success state bg
success_fg = palette.green_50, -- success state text
danger_bg = palette.red_950, -- danger state bg
danger_fg = palette.red_50, -- danger state text
info_bg = palette.blue_900, -- info state bg
info_fg = palette.blue_50, -- info state text
-- Terminal colors
terminal = {
black = palette.neutral_950,
red = palette.red_500,
green = palette.green_500,
yellow = palette.yellow_500,
blue = palette.blue_400,
magenta = palette.purple_500,
cyan = palette.mint_500,
white = palette.neutral_200,
bright_black = palette.neutral_600,
bright_red = palette.red_400,
bright_green = palette.green_400,
bright_yellow = palette.yellow_300,
bright_blue = palette.blue_300,
bright_magenta = palette.purple_400,
bright_cyan = palette.mint_600,
bright_white = palette.neutral_white,
},
}
end
return M