local N = require 'bugabinga.nugu.palette' local P = N.tui local gui_palette = function () return N[vim.o.background == 'light' and 'light' or 'dark'] end local set_group_properties = function ( self, properties ) vim.validate( 'properties', properties, 'table' ) vim.validate( 'properties.fg', properties.fg, 'number', true ) vim.validate( 'properties.bg', properties.bg, 'number', true ) vim.validate( 'properties.blend', properties.blend, 'number', true ) vim.validate( 'properties.bold', properties.bold, 'boolean', true ) vim.validate( 'properties.standout', properties.standout, 'boolean', true ) vim.validate( 'properties.underline', properties.underline, 'boolean', true ) vim.validate( 'properties.undercurl', properties.undercurl, 'boolean', true ) vim.validate( 'properties.underdotted', properties.underdotted, 'boolean', true ) vim.validate( 'properties.underdashed', properties.underdashed, 'boolean', true ) vim.validate( 'properties.strikethrough', properties.strikethrough, 'boolean', true ) vim.validate( 'properties.italic', properties.italic, 'boolean', true ) vim.validate( 'properties.reverse', properties.reverse, 'boolean', true ) vim.validate( 'properties.nocombine', properties.nocombine, 'boolean', true ) vim.validate( 'properties.default', properties.default, 'boolean', true ) vim.validate( 'properties.force', properties.force, 'boolean', true ) for key, value in pairs( properties ) do self[key] = value end end local new_group = function () return setmetatable( {}, { __call = set_group_properties, } ) end local add_group = function ( self, key ) if not self.groups[key] then self.groups[key] = new_group() end return self.groups[key] end local link_group = function ( self, key, value ) local group = add_group( self, key ) for name, group_link in pairs( self.groups ) do if group_link == value then group.link = name return group end end end local _ = setmetatable( { groups = {} }, { __index = add_group, __newindex = link_group, } ) -- editor _.Normal { fg = P.content_normal, bg = P.content_backdrop } _.NormalUi { fg = P.ui_normal, bg = P.ui_backdrop } _.NormalFloat { bg = _.NormalUi.bg } _.EndOfBuffer { bg = _.Normal.bg } _.Cursor { fg = P.content_backdrop, bg = P.content_accent } _.CursorColumn { bg = P.ui_unfocus } _.CursorLine { bg = P.ui_unfocus } _.CursorLineNr { fg = P.ui_focus, bg = P.ui_backdrop } _.CursorLineSign = _.CursorLineNr _.ColorColumn { fg = P.ui_important_global, bg = _.Normal.bg } _.Conceal { fg = P.content_focus, bg = _.Normal.bg } _.Directory { fg = _.Normal.fg } _.MatchParen { bg = P.ui_unfocus, bold = true } _.LineNr { fg = P.ui_focus, bg = P.content_backdrop } _.LineNrAbove { fg = P.ui_minor, bg = P.content_backdrop } _.LineNrBelow { fg = P.ui_minor, bg = P.content_backdrop } _.FoldColumn = _.LineNrAbove _.SignColumn = _.LineNrAbove _.NonText { fg = P.content_unfocus } _.Whitespace = _.NonText _.SpecialKey { fg = P.error, bg = P.content_unfocus, bold = true } _.Visual { bg = P.content_unfocus } _.VisualNOS { bg = P.ui_unfocus } _.Search { fg = P.content_backdrop, bg = P.content_focus } _.IncSearch { fg = P.content_backdrop, bg = P.content_unfocus } _.CurSearch { fg = P.content_backdrop, bg = P.content_important_local } _.QuickFixLine = _.PmenuSel _.Folded = _.Conceal -- floats _.FloatBorder { fg = P.ui_accent, bg = _.NormalFloat.bg } _.FloatBorderCorner { fg = P.ui_accent, bg = _.Normal.bg } _.FloatShadow { bg = P.content_unfocus, blend = 80 } _.FloatShadowThrough { bg = P.content_unfocus, blend = 100 } _.FloatTitle { fg = _.FloatBorder.fg, bg = _.FloatBorder.bg, bold = true } -- ui chrome _.StatusLine = _.NormalUi _.StatusLineNC { fg = P.ui_minor, bg = _.StatusLine.bg } _.WinBar { fg = P.ui_focus, bg = _.StatusLine.bg } _.WinBarNC { fg = P.ui_minor, bg = _.StatusLine.bg } _.TabLine = _.StatusLine _.TabLineFill = _.StatusLine _.TabLineSel { fg = P.ui_important_global, bg = _.TabLine.bg, bold = true, underline = true } _.VertSplit { fg = P.ui_important_global } _.Title { fg = P.content_important_global, bold = true, underline = true } _.ModeMsg { bold = true } _.MsgArea = _.NormalUi _.MsgSeparator = _.NormalUi _.MoreMsg = _.NormalUi _.Question { fg = P.ui_important_local, bold = true } _.WildMenu = _.PmenuSel _.Debug { fg = P.ui_normal, bg = P.debug, bold = true } -- menus _.Pmenu = _.NormalFloat _.PmenuSel { fg = P.ui_important_local, bg = _.Pmenu.bg, bold = true, underline = true } _.PmenuSbar { fg = P.ui_minor, bg = _.NormalFloat.bg } _.PmenuThumb { fg = P.ui_important_local, bg = _.NormalFloat.bg } _.PmenuMatch { fg = P.content_focus, bold = true } _.PmenuMatchSel { fg = P.content_focus, bold = true } _.ComplMatchIns { fg = P.content_accent } _.PmenuKind { fg = P.ui_minor } _.PmenuKindSel { fg = P.ui_important_local } -- cmdline _.BugabingaCmdlineCursor { fg = P.ui_important_local, bg = P.ui_unfocus, bold = true } _.CmdlineBorderSearch { fg = P.ui_important_global, bg = _.NormalFloat.bg } _.CmdlineBorderShell { fg = P.content_focus, bg = _.NormalFloat.bg } _.CmdlineBorderHelp { fg = P.info, bg = _.NormalFloat.bg } _.CmdlineBorderLua { fg = P.content_focus, bg = _.NormalFloat.bg } _.CmdlineBorderInput { fg = P.ui_important_local, bg = _.NormalFloat.bg } _.CmdlineBorderCmdline { fg = P.ui_minor, bg = _.NormalFloat.bg } _.CmdlineBorderCornerSearch { fg = _.CmdlineBorderSearch.fg, bg = _.FloatBorderCorner.bg } _.CmdlineBorderCornerShell { fg = _.CmdlineBorderShell.fg, bg = _.FloatBorderCorner.bg } _.CmdlineBorderCornerHelp { fg = _.CmdlineBorderHelp.fg, bg = _.FloatBorderCorner.bg } _.CmdlineBorderCornerLua { fg = _.CmdlineBorderLua.fg, bg = _.FloatBorderCorner.bg } _.CmdlineBorderCornerInput { fg = _.CmdlineBorderInput.fg, bg = _.FloatBorderCorner.bg } _.CmdlineBorderCornerCmdline { fg = _.CmdlineBorderCmdline.fg, bg = _.FloatBorderCorner.bg } _.CmdlineIconSearch { fg = _.CmdlineBorderSearch.fg } _.CmdlineIconShell { fg = _.CmdlineBorderShell.fg } _.CmdlineIconHelp { fg = _.CmdlineBorderHelp.fg } _.CmdlineIconLua { fg = _.CmdlineBorderLua.fg } _.CmdlineIconInput { fg = _.CmdlineBorderInput.fg } _.CmdlineIconCmdline { fg = _.CmdlineBorderCmdline.fg } -- diagnostics _.DiagnosticError { fg = P.error } _.DiagnosticWarn { fg = P.warning } _.DiagnosticInfo { fg = P.info } _.DiagnosticHint { fg = P.ui_important_local } _.DiagnosticOk { fg = P.ui_minor } _.DiagnosticUnnecessary { fg = P.ui_focus } _.DiagnosticDeprecated { fg = P.ui_important_global, strikethrough = true } _.DiagnosticVirtualTextError = _.DiagnosticError _.DiagnosticVirtualTextWarn = _.DiagnosticWarn _.DiagnosticVirtualTextInfo = _.DiagnosticInfo _.DiagnosticVirtualTextHint = _.DiagnosticHint _.DiagnosticVirtualTextOk = _.DiagnosticOk _.DiagnosticUnderlineError { fg = _.DiagnosticError.fg, underdouble = true } _.DiagnosticUnderlineWarn { fg = _.DiagnosticWarn.fg, underline = true } _.DiagnosticUnderlineInfo { fg = _.DiagnosticInfo.fg, underdashed = true } _.DiagnosticUnderlineHint { fg = _.DiagnosticHint.fg, underdotted = true } _.DiagnosticUnderlineOk { fg = _.DiagnosticOk.fg } _.DiagnosticSignError = _.DiagnosticError _.DiagnosticSignWarn = _.DiagnosticWarn _.DiagnosticSignInfo = _.DiagnosticInfo _.DiagnosticSignHint = _.DiagnosticHint _.DiagnosticSignOk = _.DiagnosticOk -- messages _.ErrorMsg { fg = P.error } _.WarningMsg { fg = P.warning, bold = true } _.Added { fg = P.content_focus } _.OkMsg = _.Added _.Removed { fg = P.error } _.Changed { fg = P.content_important_local } _.NvimInternalError { fg = P.error, bg = P.content_backdrop } -- diff _.DiffAdd { fg = P.info } _.DiffDelete { fg = P.error, strikethrough = true } _.DiffChange { fg = P.warning } _.DiffText { fg = P.content_backdrop, bg = P.warning, bold = true } -- spelling _.SpellBad { fg = P.error, undercurl = true } _.SpellCap = _.SpellBad _.SpellLocal = _.SpellBad _.SpellRare = _.SpellBad -- misc _.Comment { fg = P.content_important_global, bold = true, italic = true } _.NotifyBackground = _.NormalUi _.CycleBufferFileName { fg = P.ui_accent, bold = true } _.CycleBufferIcon { fg = P.ui_minor } _.TextYankPost { fg = P.content_backdrop, bg = P.ui_important_local } _.SnippetTabstop { bg = P.content_unfocus, underline = true } _.RedrawDebugClear { fg = P.content_backdrop, bg = P.ui_backdrop } _.RedrawDebugComposed { fg = P.content_backdrop, bg = P.ui_unfocus } _.RedrawDebugRecompose { fg = P.content_backdrop, bg = P.error } -- bugabinga code actions _.BugabingaCodeActionFixAll = _.DiagnosticWarn _.BugabingaCodeActionQuickFix = _.DiagnosticHint _.BugabingaCodeActionRefactor = _.DiagnosticInfo _.BugabingaCodeActionRefactorExtract = _.DiagnosticInfo _.BugabingaCodeActionRefactorMove = _.DiagnosticInfo _.BugabingaCodeActionSource = _.DiagnosticHint _.BugabingaCodeActionSourceImports = _.DiagnosticHint _.BugabingaCodeActionDefault = _.DiagnosticHint -- pivi conversation -- A user message is the one thing worth finding while scrolling, so it alone -- carries a background and a solid bar. Everything else stays quiet, and tool -- work is the quietest. _.PiviUser { bg = P.ui_backdrop } _.PiviUserBar { fg = P.content_accent, bold = true } _.PiviUserLabel { fg = P.content_accent, bold = true } _.PiviAssistantLabel { fg = P.content_focus } -- The output recedes furthest; the outcome beside the name stays scannable. _.PiviTool { fg = P.content_unfocus } _.PiviToolIcon { fg = P.content_focus } _.PiviToolOutcome { fg = P.content_minor } _.PiviError { fg = P.error } _.PiviErrorIcon { fg = P.error, bold = true } -- bugabinga debug viewer _.DbgViewerKind = _.Title _.DbgViewerTime = _.Comment _.DbgViewerMessage = _.Normal _.DbgViewerLocation = _.Comment _.DbgViewerFilter = _.Search _.DbgViewerKindIcon = _.DiagnosticInfo -- lsp _.LspReferenceText { underline = true } _.LspReferenceRead = _.LspReferenceText _.LspReferenceWrite = _.LspReferenceText _.LspInlayHint { fg = P.content_minor, bg = _.Normal.bg } _.LspSignatureActiveParameter = _.PmenuSel -- mini.hipatterns _.MiniHipatternsFixme { fg = P.ui_backdrop, bg = _.DiagnosticError.fg, bold = true, underline = true } _.MiniHipatternsHack { fg = P.ui_backdrop, bg = _.DiagnosticWarn.fg, bold = true, underline = true } _.MiniHipatternsTodo { fg = P.ui_backdrop, bg = _.DiagnosticHint.fg, bold = true, underline = true } _.MiniHipatternsNote { fg = P.ui_backdrop, bg = _.DiagnosticInfo.fg, bold = true, underline = true } -- syntax _.String { fg = P.content_focus, italic = true } _.Constant = _.String _.Character = _.String _.Number = _.String _.Boolean = _.String _.Float = _.String _.Identifier { fg = _.Normal.fg } _.Function { fg = _.Normal.fg } _.FunctionDeclaration { fg = _.Function.fg, underline = true } _.Parameter { fg = P.content_important_local, bold = true } _.MutableVariable = { fg = _.Parameter.fg, underline = true } _.Type { fg = _.Identifier.fg } _.Delimiter { fg = P.content_minor } _.Statement { fg = P.content_minor } _.Conditional = _.Statement _.Repeat = _.Statement _.Label = _.Statement _.Operator = _.Statement _.Keyword = _.Statement _.Exception = _.Statement _.StorageClass = _.Statement _.Structure = _.Statement _.Typedef = _.Statement _.PreProc { fg = P.content_important_global, bold = true } _.Include = _.PreProc _.Define = _.PreProc _.Macro = _.PreProc _.PreCondit = _.PreProc _.Special { fg = P.content_important_global, bold = true } _.SpecialChar = _.Special _.Tag = _.Special _.SpecialComment = _.Special _.Underlined { underline = true } _.Bold { bold = true } _.Italic { italic = true } _.Ignore { fg = _.Normal.bg } _.Error { fg = P.error } _.Todo { fg = P.content_important_global, bold = true, underdouble = true } -- treesitter _['@attribute'] = _.Keyword _['@boolean'] = _.Boolean _['@character'] = _.Character _['@character.special'] = _.SpecialChar _['@comment'] = _.Comment _['@conditional'] = _.Conditional _['@constant'] = _.Constant _['@constant.builtin'] = _.String _['@constant.macro'] = _.Define _['@constructor'] = _.Special _['@debug'] = _.Debug _['@define'] = _.Define _['@exception'] = _.Exception _['@field'] = _.Identifier _['@float'] = _.Float _['@function'] = _.Function _['@function.builtin'] = _.Special _['@function.macro'] = _.Macro _['@include'] = _.Include _['@keyword'] = _.Keyword _['@keyword.return'] { fg = _.Keyword.fg, bg = _.Keyword.bg, underline = true, bold = true } _['@label'] = _.Label _['@macro'] = _.Macro _['@method'] = _.Function _['@namespace'] = _.Function _['@number'] = _.Number _['@operator'] = _.Operator _['@parameter'] = _.Parameter _['@preproc'] = _.PreProc _['@property'] = _.Identifier _['@punctuation'] = _.Delimiter _['@error'] = _.DiagnosticError _['@repeat'] = _.Repeat _['@storageclass'] = _.StorageClass _['@string'] = _.String _['@string.escape'] = _.SpecialChar _['@string.special'] = _.SpecialChar _['@structure'] = _.Structure _['@tag'] = _.Tag _['@text.literal'] = _.Comment _['@text.reference'] = _.Identifier _['@text.title'] = _.Title _['@text.todo'] = _.Todo _['@text.underline'] = _.Underlined _['@type'] = _.Type _['@type.builtin'] = _.Type _['@type.definition'] = _.Typedef _['@variable'] = _.Identifier _['@variable.parameter'] = _.Parameter _['@markup.raw.block'] { fg = P.content_normal } _['@markup.raw.block.markdown'] { fg = P.ui_normal } _['@markup.raw.block.vimdoc'] { fg = P.ui_normal } -- lsp semantic tokens _['@lsp.type.class'] = _['@type'] _['@lsp.type.decorator'] = _['@function'] _['@lsp.type.enum'] = _['@type'] _['@lsp.type.enumMember'] = _['@constant'] _['@lsp.type.function'] = _['@function'] _['@lsp.type.interface'] = _['@type'] _['@lsp.type.macro'] = _['@macro'] _['@lsp.type.method'] = _['@method'] _['@lsp.type.modifier'] = _['@keyword'] _['@lsp.type.namespace'] = _['@namespace'] _['@lsp.type.parameter'] = _['@parameter'] _['@lsp.type.property'] = _['@property'] _['@lsp.type.struct'] = _['@structure'] _['@lsp.type.type'] = _['@type'] _['@lsp.type.typeParameter'] = _['@type'] _['@lsp.type.variable'] = _['@variable'] _['@lsp.typemod.function.declaration'] = _.FunctionDeclaration _['@lsp.typemod.method.declaration'] = _.FunctionDeclaration _['@lsp.typemod.parameter.declaration'] = _.Parameter -- cterm attributes that must be mirrored to the cterm table local cterm_attrs = { bold = true, italic = true, reverse = true, standout = true, underline = true, undercurl = true, underdouble = true, underdotted = true, underdashed = true, strikethrough = true, nocombine = true, } return function () for name, group in pairs( _.groups ) do if group.link then vim.api.nvim_set_hl( 0, name, { link = group.link, default = group.default } ) else local opts = {} local gui = gui_palette() if group.fg then opts.ctermfg = group.fg opts.fg = gui[group.fg] end if group.bg then opts.ctermbg = group.bg opts.bg = gui[group.bg] end if group.fg and ( group.undercurl or group.underdashed or group.underdotted or group.underdouble ) then opts.sp = gui[group.fg] end local ct = {} for attr in pairs( cterm_attrs ) do if group[attr] then ct[attr] = true opts[attr] = true end end if next( ct ) then opts.cterm = ct end if group.blend then opts.blend = group.blend end if group.default then opts.default = group.default end if group.force then opts.force = group.force end vim.api.nvim_set_hl( 0, name, opts ) end end end