// This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // highlight_group.c: code for managing highlight groups #include #include "nvim/api/private/helpers.h" #include "nvim/autocmd.h" #include "nvim/charset.h" #include "nvim/cursor_shape.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/vars.h" #include "nvim/ex_docmd.h" #include "nvim/fold.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/lua/executor.h" #include "nvim/match.h" #include "nvim/option.h" #include "nvim/runtime.h" /// \addtogroup SG_SET /// @{ #define SG_CTERM 2 // cterm has been set #define SG_GUI 4 // gui has been set #define SG_LINK 8 // link has been set /// @} #define MAX_SYN_NAME 200 // builtin |highlight-groups| static garray_T highlight_ga = GA_EMPTY_INIT_VALUE; // arena for object with same lifetime as highlight_ga (aka hl_table) Arena highlight_arena = ARENA_EMPTY; Map(cstr_t, int) highlight_unames = MAP_INIT; /// The "term", "cterm" and "gui" arguments can be any combination of the /// following names, separated by commas (but no spaces!). static char *(hl_name_table[]) = { "bold", "standout", "underline", "undercurl", "underdouble", "underdotted", "underdashed", "italic", "reverse", "inverse", "strikethrough", "nocombine", "NONE" }; static int hl_attr_table[] = { HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_UNDERDOUBLE, HL_UNDERDOTTED, HL_UNDERDASHED, HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 }; /// Structure that stores information about a highlight group. /// The ID of a highlight group is also called group ID. It is the index in /// the highlight_ga array PLUS ONE. typedef struct { char_u *sg_name; ///< highlight group name char *sg_name_u; ///< uppercase of sg_name bool sg_cleared; ///< "hi clear" was used int sg_attr; ///< Screen attr @see ATTR_ENTRY int sg_link; ///< link to this highlight group ID int sg_deflink; ///< default link; restored in highlight_clear() int sg_set; ///< combination of flags in \ref SG_SET sctx_T sg_deflink_sctx; ///< script where the default link was set sctx_T sg_script_ctx; ///< script in which the group was last set // for terminal UIs int sg_cterm; ///< "cterm=" highlighting attr ///< (combination of \ref HlAttrFlags) int sg_cterm_fg; ///< terminal fg color number + 1 int sg_cterm_bg; ///< terminal bg color number + 1 bool sg_cterm_bold; ///< bold attr was set for light color // for RGB UIs int sg_gui; ///< "gui=" highlighting attributes ///< (combination of \ref HlAttrFlags) RgbValue sg_rgb_fg; ///< RGB foreground color RgbValue sg_rgb_bg; ///< RGB background color RgbValue sg_rgb_sp; ///< RGB special color int sg_rgb_fg_idx; ///< RGB foreground color index int sg_rgb_bg_idx; ///< RGB background color index int sg_rgb_sp_idx; ///< RGB special color index int sg_blend; ///< blend level (0-100 inclusive), -1 if unset int sg_parent; ///< parent of @nested.group } HlGroup; enum { kColorIdxNone = -1, kColorIdxHex = -2, kColorIdxFg = -3, kColorIdxBg = -4, }; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "highlight_group.c.generated.h" #endif #define hl_table ((HlGroup *)((highlight_ga.ga_data))) // The default highlight groups. These are compiled-in for fast startup and // they still work when the runtime files can't be found. // // When making changes here, also change runtime/colors/default.vim! static const char *highlight_init_both[] = { "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey", "Cursor guibg=fg guifg=bg", "lCursor guibg=fg guifg=bg", "DiffText cterm=bold ctermbg=Red gui=bold guibg=Red", "ErrorMsg ctermbg=DarkRed ctermfg=White guibg=Red guifg=White", "IncSearch cterm=reverse gui=reverse", "ModeMsg cterm=bold gui=bold", "NonText ctermfg=Blue gui=bold guifg=Blue", "Normal cterm=NONE gui=NONE", "PmenuSbar ctermbg=Grey guibg=Grey", "StatusLine cterm=reverse,bold gui=reverse,bold", "StatusLineNC cterm=reverse gui=reverse", "TabLineFill cterm=reverse gui=reverse", "TabLineSel cterm=bold gui=bold", "TermCursor cterm=reverse gui=reverse", "WinBar cterm=bold gui=bold", "WildMenu ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black", "default link VertSplit Normal", "default link WinSeparator VertSplit", "default link WinBarNC WinBar", "default link EndOfBuffer NonText", "default link LineNrAbove LineNr", "default link LineNrBelow LineNr", "default link QuickFixLine Search", "default link CursorLineSign SignColumn", "default link CursorLineFold FoldColumn", "default link Substitute Search", "default link Whitespace NonText", "default link MsgSeparator StatusLine", "default link NormalFloat Pmenu", "default link FloatBorder WinSeparator", "default FloatShadow blend=80 guibg=Black", "default FloatShadowThrough blend=100 guibg=Black", "RedrawDebugNormal cterm=reverse gui=reverse", "RedrawDebugClear ctermbg=Yellow guibg=Yellow", "RedrawDebugComposed ctermbg=Green guibg=Green", "RedrawDebugRecompose ctermbg=Red guibg=Red", "Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE guifg=White guibg=Red", "Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE guifg=Blue guibg=Yellow", "default link String Constant", "default link Character Constant", "default link Number Constant", "default link Boolean Constant", "default link Float Number", "default link Function Identifier", "default link Conditional Statement", "default link Repeat Statement", "default link Label Statement", "default link Operator Statement", "default link Keyword Statement", "default link Exception Statement", "default link Include PreProc", "default link Define PreProc", "default link Macro PreProc", "default link PreCondit PreProc", "default link StorageClass Type", "default link Structure Type", "default link Typedef Type", "default link Tag Special", "default link SpecialChar Special", "default link Delimiter Special", "default link SpecialComment Special", "default link Debug Special", "default DiagnosticError ctermfg=1 guifg=Red", "default DiagnosticWarn ctermfg=3 guifg=Orange", "default DiagnosticInfo ctermfg=4 guifg=LightBlue", "default DiagnosticHint ctermfg=7 guifg=LightGrey", "default DiagnosticUnderlineError cterm=underline gui=underline guisp=Red", "default DiagnosticUnderlineWarn cterm=underline gui=underline guisp=Orange", "default DiagnosticUnderlineInfo cterm=underline gui=underline guisp=LightBlue", "default DiagnosticUnderlineHint cterm=underline gui=underline guisp=LightGrey", "default link DiagnosticVirtualTextError DiagnosticError", "default link DiagnosticVirtualTextWarn DiagnosticWarn", "default link DiagnosticVirtualTextInfo DiagnosticInfo", "default link DiagnosticVirtualTextHint DiagnosticHint", "default link DiagnosticFloatingError DiagnosticError", "default link DiagnosticFloatingWarn DiagnosticWarn", "default link DiagnosticFloatingInfo DiagnosticInfo", "default link DiagnosticFloatingHint DiagnosticHint", "default link DiagnosticSignError DiagnosticError", "default link DiagnosticSignWarn DiagnosticWarn", "default link DiagnosticSignInfo DiagnosticInfo", "default link DiagnosticSignHint DiagnosticHint", "default link @text.underline Underlined", "default link @todo Todo", "default link @debug Debug", // Miscs "default link @comment Comment", "default link @punctuation Delimiter", // Constants "default link @constant Constant", "default link @constant.builtin Special", "default link @constant.macro Define", "default link @define Define", "default link @macro Macro", "default link @string String", "default link @string.escape SpecialChar", "default link @character Character", "default link @character.special SpecialChar", "default link @number Number", "default link @boolean Boolean", "default link @float Float", // Functions "default link @function Function", "default link @function.builtin Special", "default link @function.macro Macro", "default link @parameter Identifier", "default link @method Function", "default link @field Identifier", "default link @property Identifier", "default link @constructor Special", // Keywords "default link @conditional Conditional", "default link @repeat Repeat", "default link @label Label", "default link @operator Operator", "default link @keyword Keyword", "default link @exception Exception", "default link @type Type", "default link @type.definition Typedef", "default link @storageclass StorageClass", "default link @structure Structure", "default link @include Include", "default link @preproc PreProc", NULL }; // Default colors only used with a light background. static const char *highlight_init_light[] = { "ColorColumn ctermbg=LightRed guibg=LightRed", "CursorColumn ctermbg=LightGrey guibg=Grey90", "CursorLine cterm=underline guibg=Grey90", "CursorLineNr cterm=underline ctermfg=Brown gui=bold guifg=Brown", "DiffAdd ctermbg=LightBlue guibg=LightBlue", "DiffChange ctermbg=LightMagenta guibg=LightMagenta", "DiffDelete ctermfg=Blue ctermbg=LightCyan gui=bold guifg=Blue guibg=LightCyan", "Directory ctermfg=DarkBlue guifg=Blue", "FoldColumn ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue", "Folded ctermbg=Grey ctermfg=DarkBlue guibg=LightGrey guifg=DarkBlue", "LineNr ctermfg=Brown guifg=Brown", "MatchParen ctermbg=Cyan guibg=Cyan", "MoreMsg ctermfg=DarkGreen gui=bold guifg=SeaGreen", "Pmenu ctermbg=LightMagenta ctermfg=Black guibg=LightMagenta", "PmenuSel ctermbg=LightGrey ctermfg=Black guibg=Grey", "PmenuThumb ctermbg=Black guibg=Black", "Question ctermfg=DarkGreen gui=bold guifg=SeaGreen", "Search ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE", "SignColumn ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue", "SpecialKey ctermfg=DarkBlue guifg=Blue", "SpellBad ctermbg=LightRed guisp=Red gui=undercurl", "SpellCap ctermbg=LightBlue guisp=Blue gui=undercurl", "SpellLocal ctermbg=Cyan guisp=DarkCyan gui=undercurl", "SpellRare ctermbg=LightMagenta guisp=Magenta gui=undercurl", "TabLine cterm=underline ctermfg=black ctermbg=LightGrey gui=underline guibg=LightGrey", "Title ctermfg=DarkMagenta gui=bold guifg=Magenta", "Visual guibg=LightGrey", "WarningMsg ctermfg=DarkRed guifg=Red", "Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE gui=NONE guifg=Blue guibg=NONE", "Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE gui=NONE guifg=Magenta guibg=NONE", "Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a5acd guibg=NONE", "Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE gui=NONE guifg=DarkCyan guibg=NONE", "Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE gui=bold guifg=Brown guibg=NONE", "PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a0dad guibg=NONE", "Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE gui=bold guifg=SeaGreen guibg=NONE", "Underlined term=underline cterm=underline ctermfg=DarkMagenta gui=underline guifg=SlateBlue", "Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE gui=NONE guifg=bg guibg=NONE", NULL }; // Default colors only used with a dark background. static const char *highlight_init_dark[] = { "ColorColumn ctermbg=DarkRed guibg=DarkRed", "CursorColumn ctermbg=DarkGrey guibg=Grey40", "CursorLine cterm=underline guibg=Grey40", "CursorLineNr cterm=underline ctermfg=Yellow gui=bold guifg=Yellow", "DiffAdd ctermbg=DarkBlue guibg=DarkBlue", "DiffChange ctermbg=DarkMagenta guibg=DarkMagenta", "DiffDelete ctermfg=Blue ctermbg=DarkCyan gui=bold guifg=Blue guibg=DarkCyan", "Directory ctermfg=LightCyan guifg=Cyan", "FoldColumn ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan", "Folded ctermbg=DarkGrey ctermfg=Cyan guibg=DarkGrey guifg=Cyan", "LineNr ctermfg=Yellow guifg=Yellow", "MatchParen ctermbg=DarkCyan guibg=DarkCyan", "MoreMsg ctermfg=LightGreen gui=bold guifg=SeaGreen", "Pmenu ctermbg=Magenta ctermfg=Black guibg=Magenta", "PmenuSel ctermbg=Black ctermfg=DarkGrey guibg=DarkGrey", "PmenuThumb ctermbg=White guibg=White", "Question ctermfg=LightGreen gui=bold guifg=Green", "Search ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black", "SignColumn ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan", "SpecialKey ctermfg=LightBlue guifg=Cyan", "SpellBad ctermbg=Red guisp=Red gui=undercurl", "SpellCap ctermbg=Blue guisp=Blue gui=undercurl", "SpellLocal ctermbg=Cyan guisp=Cyan gui=undercurl", "SpellRare ctermbg=Magenta guisp=Magenta gui=undercurl", "TabLine cterm=underline ctermfg=white ctermbg=DarkGrey gui=underline guibg=DarkGrey", "Title ctermfg=LightMagenta gui=bold guifg=Magenta", "Visual guibg=DarkGrey", "WarningMsg ctermfg=LightRed guifg=Red", "Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#80a0ff guibg=NONE", "Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE gui=NONE guifg=#ffa0a0 guibg=NONE", "Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE gui=NONE guifg=Orange guibg=NONE", "Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#40ffff guibg=NONE", "Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE gui=bold guifg=#ffff60 guibg=NONE", "PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE gui=NONE guifg=#ff80ff guibg=NONE", "Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE gui=bold guifg=#60ff60 guibg=NONE", "Underlined term=underline cterm=underline ctermfg=LightBlue gui=underline guifg=#80a0ff", "Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE gui=NONE guifg=bg guibg=NONE", NULL }; const char *const highlight_init_cmdline[] = { // XXX When modifying a list modify it in both valid and invalid halves. // TODO(ZyX-I): merge valid and invalid groups via a macros. // NvimInternalError should appear only when highlighter has a bug. "NvimInternalError ctermfg=Red ctermbg=Red guifg=Red guibg=Red", // Highlight groups (links) used by parser: "default link NvimAssignment Operator", "default link NvimPlainAssignment NvimAssignment", "default link NvimAugmentedAssignment NvimAssignment", "default link NvimAssignmentWithAddition NvimAugmentedAssignment", "default link NvimAssignmentWithSubtraction NvimAugmentedAssignment", "default link NvimAssignmentWithConcatenation NvimAugmentedAssignment", "default link NvimOperator Operator", "default link NvimUnaryOperator NvimOperator", "default link NvimUnaryPlus NvimUnaryOperator", "default link NvimUnaryMinus NvimUnaryOperator", "default link NvimNot NvimUnaryOperator", "default link NvimBinaryOperator NvimOperator", "default link NvimComparison NvimBinaryOperator", "default link NvimComparisonModifier NvimComparison", "default link NvimBinaryPlus NvimBinaryOperator", "default link NvimBinaryMinus NvimBinaryOperator", "default link NvimConcat NvimBinaryOperator", "default link NvimConcatOrSubscript NvimConcat", "default link NvimOr NvimBinaryOperator", "default link NvimAnd NvimBinaryOperator", "default link NvimMultiplication NvimBinaryOperator", "default link NvimDivision NvimBinaryOperator", "default link NvimMod NvimBinaryOperator", "default link NvimTernary NvimOperator", "default link NvimTernaryColon NvimTernary", "default link NvimParenthesis Delimiter", "default link NvimLambda NvimParenthesis", "default link NvimNestingParenthesis NvimParenthesis", "default link NvimCallingParenthesis NvimParenthesis", "default link NvimSubscript NvimParenthesis", "default link NvimSubscriptBracket NvimSubscript", "default link NvimSubscriptColon NvimSubscript", "default link NvimCurly NvimSubscript", "default link NvimContainer NvimParenthesis", "default link NvimDict NvimContainer", "default link NvimList NvimContainer", "default link NvimIdentifier Identifier", "default link NvimIdentifierScope NvimIdentifier", "default link NvimIdentifierScopeDelimiter NvimIdentifier", "default link NvimIdentifierName NvimIdentifier", "default link NvimIdentifierKey NvimIdentifier", "default link NvimColon Delimiter", "default link NvimComma Delimiter", "default link NvimArrow Delimiter", "default link NvimRegister SpecialChar", "default link NvimNumber Number", "default link NvimFloat NvimNumber", "default link NvimNumberPrefix Type", "default link NvimOptionSigil Type", "default link NvimOptionName NvimIdentifier", "default link NvimOptionScope NvimIdentifierScope", "default link NvimOptionScopeDelimiter NvimIdentifierScopeDelimiter", "default link NvimEnvironmentSigil NvimOptionSigil", "default link NvimEnvironmentName NvimIdentifier", "default link NvimString String", "default link NvimStringBody NvimString", "default link NvimStringQuote NvimString", "default link NvimStringSpecial SpecialChar", "default link NvimSingleQuote NvimStringQuote", "default link NvimSingleQuotedBody NvimStringBody", "default link NvimSingleQuotedQuote NvimStringSpecial", "default link NvimDoubleQuote NvimStringQuote", "default link NvimDoubleQuotedBody NvimStringBody", "default link NvimDoubleQuotedEscape NvimStringSpecial", "default link NvimFigureBrace NvimInternalError", "default link NvimSingleQuotedUnknownEscape NvimInternalError", "default link NvimSpacing Normal", // NvimInvalid groups: "default link NvimInvalidSingleQuotedUnknownEscape NvimInternalError", "default link NvimInvalid Error", "default link NvimInvalidAssignment NvimInvalid", "default link NvimInvalidPlainAssignment NvimInvalidAssignment", "default link NvimInvalidAugmentedAssignment NvimInvalidAssignment", "default link NvimInvalidAssignmentWithAddition NvimInvalidAugmentedAssignment", "default link NvimInvalidAssignmentWithSubtraction NvimInvalidAugmentedAssignment", "default link NvimInvalidAssignmentWithConcatenation NvimInvalidAugmentedAssignment", "default link NvimInvalidOperator NvimInvalid", "default link NvimInvalidUnaryOperator NvimInvalidOperator", "default link NvimInvalidUnaryPlus NvimInvalidUnaryOperator", "default link NvimInvalidUnaryMinus NvimInvalidUnaryOperator", "default link NvimInvalidNot NvimInvalidUnaryOperator", "default link NvimInvalidBinaryOperator NvimInvalidOperator", "default link NvimInvalidComparison NvimInvalidBinaryOperator", "default link NvimInvalidComparisonModifier NvimInvalidComparison", "default link NvimInvalidBinaryPlus NvimInvalidBinaryOperator", "default link NvimInvalidBinaryMinus NvimInvalidBinaryOperator", "default link NvimInvalidConcat NvimInvalidBinaryOperator", "default link NvimInvalidConcatOrSubscript NvimInvalidConcat", "default link NvimInvalidOr NvimInvalidBinaryOperator", "default link NvimInvalidAnd NvimInvalidBinaryOperator", "default link NvimInvalidMultiplication NvimInvalidBinaryOperator", "default link NvimInvalidDivision NvimInvalidBinaryOperator", "default link NvimInvalidMod NvimInvalidBinaryOperator", "default link NvimInvalidTernary NvimInvalidOperator", "default link NvimInvalidTernaryColon NvimInvalidTernary", "default link NvimInvalidDelimiter NvimInvalid", "default link NvimInvalidParenthesis NvimInvalidDelimiter", "default link NvimInvalidLambda NvimInvalidParenthesis", "default link NvimInvalidNestingParenthesis NvimInvalidParenthesis", "default link NvimInvalidCallingParenthesis NvimInvalidParenthesis", "default link NvimInvalidSubscript NvimInvalidParenthesis", "default link NvimInvalidSubscriptBracket NvimInvalidSubscript", "default link NvimInvalidSubscriptColon NvimInvalidSubscript", "default link NvimInvalidCurly NvimInvalidSubscript", "default link NvimInvalidContainer NvimInvalidParenthesis", "default link NvimInvalidDict NvimInvalidContainer", "default link NvimInvalidList NvimInvalidContainer", "default link NvimInvalidValue NvimInvalid", "default link NvimInvalidIdentifier NvimInvalidValue", "default link NvimInvalidIdentifierScope NvimInvalidIdentifier", "default link NvimInvalidIdentifierScopeDelimiter NvimInvalidIdentifier", "default link NvimInvalidIdentifierName NvimInvalidIdentifier", "default link NvimInvalidIdentifierKey NvimInvalidIdentifier", "default link NvimInvalidColon NvimInvalidDelimiter", "default link NvimInvalidComma NvimInvalidDelimiter", "default link NvimInvalidArrow NvimInvalidDelimiter", "default link NvimInvalidRegister NvimInvalidValue", "default link NvimInvalidNumber NvimInvalidValue", "default link NvimInvalidFloat NvimInvalidNumber", "default link NvimInvalidNumberPrefix NvimInvalidNumber", "default link NvimInvalidOptionSigil NvimInvalidIdentifier", "default link NvimInvalidOptionName NvimInvalidIdentifier", "default link NvimInvalidOptionScope NvimInvalidIdentifierScope", "default link NvimInvalidOptionScopeDelimiter NvimInvalidIdentifierScopeDelimiter", "default link NvimInvalidEnvironmentSigil NvimInvalidOptionSigil", "default link NvimInvalidEnvironmentName NvimInvalidIdentifier", // Invalid string bodies and specials are still highlighted as valid ones to // minimize the red area. "default link NvimInvalidString NvimInvalidValue", "default link NvimInvalidStringBody NvimStringBody", "default link NvimInvalidStringQuote NvimInvalidString", "default link NvimInvalidStringSpecial NvimStringSpecial", "default link NvimInvalidSingleQuote NvimInvalidStringQuote", "default link NvimInvalidSingleQuotedBody NvimInvalidStringBody", "default link NvimInvalidSingleQuotedQuote NvimInvalidStringSpecial", "default link NvimInvalidDoubleQuote NvimInvalidStringQuote", "default link NvimInvalidDoubleQuotedBody NvimInvalidStringBody", "default link NvimInvalidDoubleQuotedEscape NvimInvalidStringSpecial", "default link NvimInvalidDoubleQuotedUnknownEscape NvimInvalidValue", "default link NvimInvalidFigureBrace NvimInvalidDelimiter", "default link NvimInvalidSpacing ErrorMsg", // Not actually invalid, but we show the user that they are doing something // wrong. "default link NvimDoubleQuotedUnknownEscape NvimInvalidValue", NULL, }; /// Returns the number of highlight groups. int highlight_num_groups(void) { return highlight_ga.ga_len; } /// Returns the name of a highlight group. char_u *highlight_group_name(int id) { return hl_table[id].sg_name; } /// Returns the ID of the link to a highlight group. int highlight_link_id(int id) { return hl_table[id].sg_link; } /// Create default links for Nvim* highlight groups used for cmdline coloring void syn_init_cmdline_highlight(bool reset, bool init) { for (size_t i = 0; highlight_init_cmdline[i] != NULL; i++) { do_highlight(highlight_init_cmdline[i], reset, init); } } /// Load colors from a file if "g:colors_name" is set, otherwise load builtin /// colors /// /// @param both include groups where 'bg' doesn't matter /// @param reset clear groups first void init_highlight(bool both, bool reset) { static int had_both = false; // Try finding the color scheme file. Used when a color file was loaded // and 'background' or 't_Co' is changed. char *p = (char *)get_var_value("g:colors_name"); if (p != NULL) { // Value of g:colors_name could be freed in load_colors() and make // p invalid, so copy it. char *copy_p = xstrdup(p); bool okay = load_colors((char_u *)copy_p); xfree(copy_p); if (okay) { return; } } // Didn't use a color file, use the compiled-in colors. if (both) { had_both = true; const char *const *const pp = highlight_init_both; for (size_t i = 0; pp[i] != NULL; i++) { do_highlight(pp[i], reset, true); } } else if (!had_both) { // Don't do anything before the call with both == true from main(). // Not everything has been setup then, and that call will overrule // everything anyway. return; } const char *const *const pp = ((*p_bg == 'l') ? highlight_init_light : highlight_init_dark); for (size_t i = 0; pp[i] != NULL; i++) { do_highlight(pp[i], reset, true); } // Reverse looks ugly, but grey may not work for 8 colors. Thus let it // depend on the number of colors available. // With 8 colors brown is equal to yellow, need to use black for Search fg // to avoid Statement highlighted text disappears. // Clear the attributes, needed when changing the t_Co value. if (t_colors > 8) { do_highlight((*p_bg == 'l' ? "Visual cterm=NONE ctermbg=LightGrey" : "Visual cterm=NONE ctermbg=DarkGrey"), false, true); } else { do_highlight("Visual cterm=reverse ctermbg=NONE", false, true); if (*p_bg == 'l') { do_highlight("Search ctermfg=black", false, true); } } syn_init_cmdline_highlight(false, false); } /// Load color file "name". /// Return OK for success, FAIL for failure. int load_colors(char_u *name) { char_u *buf; int retval = FAIL; static bool recursive = false; // When being called recursively, this is probably because setting // 'background' caused the highlighting to be reloaded. This means it is // working, thus we should return OK. if (recursive) { return OK; } recursive = true; size_t buflen = STRLEN(name) + 12; buf = xmalloc(buflen); apply_autocmds(EVENT_COLORSCHEMEPRE, (char *)name, curbuf->b_fname, false, curbuf); snprintf((char *)buf, buflen, "colors/%s.vim", name); retval = source_runtime((char *)buf, DIP_START + DIP_OPT); if (retval == FAIL) { snprintf((char *)buf, buflen, "colors/%s.lua", name); retval = source_runtime((char *)buf, DIP_START + DIP_OPT); } xfree(buf); if (retval == OK) { apply_autocmds(EVENT_COLORSCHEME, (char *)name, curbuf->b_fname, false, curbuf); } recursive = false; return retval; } static char *(color_names[28]) = { "Black", "DarkBlue", "DarkGreen", "DarkCyan", "DarkRed", "DarkMagenta", "Brown", "DarkYellow", "Gray", "Grey", "LightGray", "LightGrey", "DarkGray", "DarkGrey", "Blue", "LightBlue", "Green", "LightGreen", "Cyan", "LightCyan", "Red", "LightRed", "Magenta", "LightMagenta", "Yellow", "LightYellow", "White", "NONE" }; // indices: // 0, 1, 2, 3, // 4, 5, 6, 7, // 8, 9, 10, 11, // 12, 13, // 14, 15, 16, 17, // 18, 19, 20, 21, 22, // 23, 24, 25, 26, 27 static int color_numbers_16[28] = { 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, -1 }; // for xterm with 88 colors... static int color_numbers_88[28] = { 0, 4, 2, 6, 1, 5, 32, 72, 84, 84, 7, 7, 82, 82, 12, 43, 10, 61, 14, 63, 9, 74, 13, 75, 11, 78, 15, -1 }; // for xterm with 256 colors... static int color_numbers_256[28] = { 0, 4, 2, 6, 1, 5, 130, 3, 248, 248, 7, 7, 242, 242, 12, 81, 10, 121, 14, 159, 9, 224, 13, 225, 11, 229, 15, -1 }; // for terminals with less than 16 colors... static int color_numbers_8[28] = { 0, 4, 2, 6, 1, 5, 3, 3, 7, 7, 7, 7, 0 + 8, 0 + 8, 4 + 8, 4 + 8, 2 + 8, 2 + 8, 6 + 8, 6 + 8, 1 + 8, 1 + 8, 5 + 8, 5 + 8, 3 + 8, 3 + 8, 7 + 8, -1 }; // Lookup the "cterm" value to be used for color with index "idx" in // color_names[]. // "boldp" will be set to kTrue or kFalse for a foreground color when using 8 // colors, otherwise it will be unchanged. int lookup_color(const int idx, const bool foreground, TriState *const boldp) { int color = color_numbers_16[idx]; // Use the _16 table to check if it's a valid color name. if (color < 0) { return -1; } if (t_colors == 8) { // t_Co is 8: use the 8 colors table color = color_numbers_8[idx]; if (foreground) { // set/reset bold attribute to get light foreground // colors (on some terminals, e.g. "linux") if (color & 8) { *boldp = kTrue; } else { *boldp = kFalse; } } color &= 7; // truncate to 8 colors } else if (t_colors == 16) { color = color_numbers_8[idx]; } else if (t_colors == 88) { color = color_numbers_88[idx]; } else if (t_colors >= 256) { color = color_numbers_256[idx]; } return color; } void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id) { int idx = id - 1; // Index is ID minus one. bool is_default = attrs.rgb_ae_attr & HL_DEFAULT; // Return if "default" was used and the group already has settings if (is_default && hl_has_settings(idx, true)) { return; } HlGroup *g = &hl_table[idx]; if (link_id > 0) { g->sg_cleared = false; g->sg_link = link_id; g->sg_script_ctx = current_sctx; g->sg_script_ctx.sc_lnum += SOURCING_LNUM; g->sg_set |= SG_LINK; if (is_default) { g->sg_deflink = link_id; g->sg_deflink_sctx = current_sctx; g->sg_deflink_sctx.sc_lnum += SOURCING_LNUM; } goto update; } g->sg_cleared = false; g->sg_link = 0; g->sg_gui = attrs.rgb_ae_attr; g->sg_rgb_fg = attrs.rgb_fg_color; g->sg_rgb_bg = attrs.rgb_bg_color; g->sg_rgb_sp = attrs.rgb_sp_color; struct { int *dest; RgbValue val; Object name; } cattrs[] = { { &g->sg_rgb_fg_idx, g->sg_rgb_fg, HAS_KEY(dict->fg) ? dict->fg : dict->foreground }, { &g->sg_rgb_bg_idx, g->sg_rgb_bg, HAS_KEY(dict->bg) ? dict->bg : dict->background }, { &g->sg_rgb_sp_idx, g->sg_rgb_sp, HAS_KEY(dict->sp) ? dict->sp : dict->special }, { NULL, -1, NIL }, }; for (int j = 0; cattrs[j].dest; j++) { if (cattrs[j].val < 0) { *cattrs[j].dest = kColorIdxNone; } else if (cattrs[j].name.type == kObjectTypeString && cattrs[j].name.data.string.size) { name_to_color(cattrs[j].name.data.string.data, cattrs[j].dest); } else { *cattrs[j].dest = kColorIdxHex; } } g->sg_cterm = attrs.cterm_ae_attr; g->sg_cterm_bg = attrs.cterm_bg_color; g->sg_cterm_fg = attrs.cterm_fg_color; g->sg_cterm_bold = g->sg_cterm & HL_BOLD; g->sg_blend = attrs.hl_blend; g->sg_script_ctx = current_sctx; g->sg_script_ctx.sc_lnum += SOURCING_LNUM; g->sg_attr = hl_get_syn_attr(0, id, attrs); // 'Normal' is special if (strcmp(g->sg_name_u, "NORMAL") == 0) { cterm_normal_fg_color = g->sg_cterm_fg; cterm_normal_bg_color = g->sg_cterm_bg; normal_fg = g->sg_rgb_fg; normal_bg = g->sg_rgb_bg; normal_sp = g->sg_rgb_sp; ui_default_colors_set(); } else { // a cursor style uses this syn_id, make sure its attribute is updated. if (cursor_mode_uses_syn_id(id)) { ui_mode_info_set(); } } update: if (!updating_screen) { redraw_all_later(UPD_NOT_VALID); } need_highlight_changed = true; } /// Handle ":highlight" command /// /// When using ":highlight clear" this is called recursively for each group with /// forceit and init being both true. /// /// @param[in] line Command arguments. /// @param[in] forceit True when bang is given, allows to link group even if /// it has its own settings. /// @param[in] init True when initializing. void do_highlight(const char *line, const bool forceit, const bool init) FUNC_ATTR_NONNULL_ALL { const char *name_end; const char *linep; const char *key_start; const char *arg_start; int off; int len; int attr; int id; int idx; HlGroup item_before; bool did_change = false; bool dodefault = false; bool doclear = false; bool dolink = false; bool error = false; int color; bool is_normal_group = false; // "Normal" group bool did_highlight_changed = false; // If no argument, list current highlighting. if (ends_excmd((uint8_t)(*line))) { for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) { // TODO(brammool): only call when the group has attributes set highlight_list_one(i); } return; } // Isolate the name. name_end = (const char *)skiptowhite(line); linep = (const char *)skipwhite(name_end); // Check for "default" argument. if (strncmp(line, "default", (size_t)(name_end - line)) == 0) { dodefault = true; line = linep; name_end = (const char *)skiptowhite(line); linep = (const char *)skipwhite(name_end); } // Check for "clear" or "link" argument. if (strncmp(line, "clear", (size_t)(name_end - line)) == 0) { doclear = true; } else if (strncmp(line, "link", (size_t)(name_end - line)) == 0) { dolink = true; } // ":highlight {group-name}": list highlighting for one group. if (!doclear && !dolink && ends_excmd((uint8_t)(*linep))) { id = syn_name2id_len(line, (size_t)(name_end - line)); if (id == 0) { semsg(_("E411: highlight group not found: %s"), line); } else { highlight_list_one(id); } return; } // Handle ":highlight link {from} {to}" command. if (dolink) { const char *from_start = linep; const char *from_end; const char *to_start; const char *to_end; int from_id; int to_id; HlGroup *hlgroup = NULL; from_end = (const char *)skiptowhite(from_start); to_start = (const char *)skipwhite(from_end); to_end = (const char *)skiptowhite(to_start); if (ends_excmd((uint8_t)(*from_start)) || ends_excmd((uint8_t)(*to_start))) { semsg(_("E412: Not enough arguments: \":highlight link %s\""), from_start); return; } if (!ends_excmd(*skipwhite(to_end))) { semsg(_("E413: Too many arguments: \":highlight link %s\""), from_start); return; } from_id = syn_check_group(from_start, (size_t)(from_end - from_start)); if (strncmp(to_start, "NONE", 4) == 0) { to_id = 0; } else { to_id = syn_check_group(to_start, (size_t)(to_end - to_start)); } if (from_id > 0) { hlgroup = &hl_table[from_id - 1]; if (dodefault && (forceit || hlgroup->sg_deflink == 0)) { hlgroup->sg_deflink = to_id; hlgroup->sg_deflink_sctx = current_sctx; hlgroup->sg_deflink_sctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&hlgroup->sg_deflink_sctx); } } if (from_id > 0 && (!init || hlgroup->sg_set == 0)) { // Don't allow a link when there already is some highlighting // for the group, unless '!' is used if (to_id > 0 && !forceit && !init && hl_has_settings(from_id - 1, dodefault)) { if (SOURCING_NAME == NULL && !dodefault) { emsg(_("E414: group has settings, highlight link ignored")); } } else if (hlgroup->sg_link != to_id || hlgroup->sg_script_ctx.sc_sid != current_sctx.sc_sid || hlgroup->sg_cleared) { if (!init) { hlgroup->sg_set |= SG_LINK; } hlgroup->sg_link = to_id; hlgroup->sg_script_ctx = current_sctx; hlgroup->sg_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&hlgroup->sg_script_ctx); hlgroup->sg_cleared = false; redraw_all_later(UPD_SOME_VALID); // Only call highlight changed() once after multiple changes need_highlight_changed = true; } } return; } if (doclear) { // ":highlight clear [group]" command. line = linep; if (ends_excmd((uint8_t)(*line))) { do_unlet(S_LEN("colors_name"), true); restore_cterm_colors(); // Clear all default highlight groups and load the defaults. for (int j = 0; j < highlight_ga.ga_len; j++) { highlight_clear(j); } init_highlight(true, true); highlight_changed(); redraw_all_later(UPD_NOT_VALID); return; } name_end = (const char *)skiptowhite(line); linep = (const char *)skipwhite(name_end); } // Find the group name in the table. If it does not exist yet, add it. id = syn_check_group(line, (size_t)(name_end - line)); if (id == 0) { // Failed (out of memory). return; } idx = id - 1; // Index is ID minus one. // Return if "default" was used and the group already has settings if (dodefault && hl_has_settings(idx, true)) { return; } // Make a copy so we can check if any attribute actually changed item_before = hl_table[idx]; is_normal_group = (strcmp(hl_table[idx].sg_name_u, "NORMAL") == 0); // Clear the highlighting for ":hi clear {group}" and ":hi clear". if (doclear || (forceit && init)) { highlight_clear(idx); if (!doclear) { hl_table[idx].sg_set = 0; } } char key[64]; char arg[512]; if (!doclear) { while (!ends_excmd((uint8_t)(*linep))) { key_start = linep; if (*linep == '=') { semsg(_("E415: unexpected equal sign: %s"), key_start); error = true; break; } // Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg", // "guibg" or "guisp"). while (*linep && !ascii_iswhite(*linep) && *linep != '=') { linep++; } size_t key_len = (size_t)(linep - key_start); if (key_len > sizeof(key) - 1) { emsg(_("E423: Illegal argument")); error = true; break; } memcpy(key, key_start, key_len); key[key_len] = NUL; vim_strup((char_u *)key); linep = (const char *)skipwhite(linep); if (strcmp(key, "NONE") == 0) { if (!init || hl_table[idx].sg_set == 0) { if (!init) { hl_table[idx].sg_set |= SG_CTERM + SG_GUI; } highlight_clear(idx); } continue; } // Check for the equal sign. if (*linep != '=') { semsg(_("E416: missing equal sign: %s"), key_start); error = true; break; } linep++; // Isolate the argument. linep = (const char *)skipwhite(linep); if (*linep == '\'') { // guifg='color name' arg_start = ++linep; linep = strchr(linep, '\''); if (linep == NULL) { semsg(_(e_invarg2), key_start); error = true; break; } } else { arg_start = linep; linep = (const char *)skiptowhite(linep); } if (linep == arg_start) { semsg(_("E417: missing argument: %s"), key_start); error = true; break; } size_t arg_len = (size_t)(linep - arg_start); if (arg_len > sizeof(arg) - 1) { emsg(_("E423: Illegal argument")); error = true; break; } memcpy(arg, arg_start, arg_len); arg[arg_len] = NUL; if (*linep == '\'') { linep++; } // Store the argument. if (strcmp(key, "TERM") == 0 || strcmp(key, "CTERM") == 0 || strcmp(key, "GUI") == 0) { attr = 0; off = 0; int i; while (arg[off] != NUL) { for (i = ARRAY_SIZE(hl_attr_table); --i >= 0;) { len = (int)strlen(hl_name_table[i]); if (STRNICMP(arg + off, hl_name_table[i], len) == 0) { attr |= hl_attr_table[i]; off += len; break; } } if (i < 0) { semsg(_("E418: Illegal value: %s"), arg); error = true; break; } if (arg[off] == ',') { // Another one follows. off++; } } if (error) { break; } if (*key == 'C') { if (!init || !(hl_table[idx].sg_set & SG_CTERM)) { if (!init) { hl_table[idx].sg_set |= SG_CTERM; } hl_table[idx].sg_cterm = attr; hl_table[idx].sg_cterm_bold = false; } } else if (*key == 'G') { if (!init || !(hl_table[idx].sg_set & SG_GUI)) { if (!init) { hl_table[idx].sg_set |= SG_GUI; } hl_table[idx].sg_gui = attr; } } } else if (strcmp(key, "FONT") == 0) { // in non-GUI fonts are simply ignored } else if (strcmp(key, "CTERMFG") == 0 || strcmp(key, "CTERMBG") == 0) { if (!init || !(hl_table[idx].sg_set & SG_CTERM)) { if (!init) { hl_table[idx].sg_set |= SG_CTERM; } // When setting the foreground color, and previously the "bold" // flag was set for a light color, reset it now if (key[5] == 'F' && hl_table[idx].sg_cterm_bold) { hl_table[idx].sg_cterm &= ~HL_BOLD; hl_table[idx].sg_cterm_bold = false; } if (ascii_isdigit(*arg)) { color = atoi(arg); } else if (STRICMP(arg, "fg") == 0) { if (cterm_normal_fg_color) { color = cterm_normal_fg_color - 1; } else { emsg(_("E419: FG color unknown")); error = true; break; } } else if (STRICMP(arg, "bg") == 0) { if (cterm_normal_bg_color > 0) { color = cterm_normal_bg_color - 1; } else { emsg(_("E420: BG color unknown")); error = true; break; } } else { // Reduce calls to STRICMP a bit, it can be slow. off = TOUPPER_ASC(*arg); int i; for (i = ARRAY_SIZE(color_names); --i >= 0;) { if (off == color_names[i][0] && STRICMP(arg + 1, color_names[i] + 1) == 0) { break; } } if (i < 0) { semsg(_("E421: Color name or number not recognized: %s"), key_start); error = true; break; } TriState bold = kNone; color = lookup_color(i, key[5] == 'F', &bold); // set/reset bold attribute to get light foreground // colors (on some terminals, e.g. "linux") if (bold == kTrue) { hl_table[idx].sg_cterm |= HL_BOLD; hl_table[idx].sg_cterm_bold = true; } else if (bold == kFalse) { hl_table[idx].sg_cterm &= ~HL_BOLD; } } // Add one to the argument, to avoid zero. Zero is used for // "NONE", then "color" is -1. if (key[5] == 'F') { hl_table[idx].sg_cterm_fg = color + 1; if (is_normal_group) { cterm_normal_fg_color = color + 1; } } else { hl_table[idx].sg_cterm_bg = color + 1; if (is_normal_group) { cterm_normal_bg_color = color + 1; if (!ui_rgb_attached()) { if (color >= 0) { int dark = -1; if (t_colors < 16) { dark = (color == 0 || color == 4); } else if (color < 16) { // Limit the heuristic to the standard 16 colors dark = (color < 7 || color == 8); } // Set the 'background' option if the value is // wrong. if (dark != -1 && dark != (*p_bg == 'd') && !option_was_set("bg")) { set_option_value_give_err("bg", 0L, (dark ? "dark" : "light"), 0); reset_option_was_set("bg"); } } } } } } } else if (strcmp(key, "GUIFG") == 0) { int *indexp = &hl_table[idx].sg_rgb_fg_idx; if (!init || !(hl_table[idx].sg_set & SG_GUI)) { if (!init) { hl_table[idx].sg_set |= SG_GUI; } RgbValue old_color = hl_table[idx].sg_rgb_fg; int old_idx = hl_table[idx].sg_rgb_fg_idx; if (strcmp(arg, "NONE") != 0) { hl_table[idx].sg_rgb_fg = name_to_color(arg, indexp); } else { hl_table[idx].sg_rgb_fg = -1; hl_table[idx].sg_rgb_fg_idx = kColorIdxNone; } did_change = hl_table[idx].sg_rgb_fg != old_color || hl_table[idx].sg_rgb_fg != old_idx; } if (is_normal_group) { normal_fg = hl_table[idx].sg_rgb_fg; } } else if (strcmp(key, "GUIBG") == 0) { int *indexp = &hl_table[idx].sg_rgb_bg_idx; if (!init || !(hl_table[idx].sg_set & SG_GUI)) { if (!init) { hl_table[idx].sg_set |= SG_GUI; } RgbValue old_color = hl_table[idx].sg_rgb_bg; int old_idx = hl_table[idx].sg_rgb_bg_idx; if (strcmp(arg, "NONE") != 0) { hl_table[idx].sg_rgb_bg = name_to_color(arg, indexp); } else { hl_table[idx].sg_rgb_bg = -1; hl_table[idx].sg_rgb_bg_idx = kColorIdxNone; } did_change = hl_table[idx].sg_rgb_bg != old_color || hl_table[idx].sg_rgb_bg != old_idx; } if (is_normal_group) { normal_bg = hl_table[idx].sg_rgb_bg; } } else if (strcmp(key, "GUISP") == 0) { int *indexp = &hl_table[idx].sg_rgb_sp_idx; if (!init || !(hl_table[idx].sg_set & SG_GUI)) { if (!init) { hl_table[idx].sg_set |= SG_GUI; } RgbValue old_color = hl_table[idx].sg_rgb_sp; int old_idx = hl_table[idx].sg_rgb_sp_idx; if (strcmp(arg, "NONE") != 0) { hl_table[idx].sg_rgb_sp = name_to_color(arg, indexp); } else { hl_table[idx].sg_rgb_sp = -1; } did_change = hl_table[idx].sg_rgb_sp != old_color || hl_table[idx].sg_rgb_sp != old_idx; } if (is_normal_group) { normal_sp = hl_table[idx].sg_rgb_sp; } } else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) { // Ignored for now } else if (strcmp(key, "BLEND") == 0) { if (strcmp(arg, "NONE") != 0) { hl_table[idx].sg_blend = (int)strtol(arg, NULL, 10); } else { hl_table[idx].sg_blend = -1; } } else { semsg(_("E423: Illegal argument: %s"), key_start); error = true; break; } hl_table[idx].sg_cleared = false; // When highlighting has been given for a group, don't link it. if (!init || !(hl_table[idx].sg_set & SG_LINK)) { hl_table[idx].sg_link = 0; } // Continue with next argument. linep = (const char *)skipwhite(linep); } } if (!error && is_normal_group) { // Need to update all groups, because they might be using "bg" and/or // "fg", which have been changed now. highlight_attr_set_all(); if (!ui_has(kUILinegrid) && starting == 0) { // Older UIs assume that we clear the screen after normal group is // changed ui_refresh(); } else { // TUI and newer UIs will repaint the screen themselves. UPD_NOT_VALID // redraw below will still handle usages of guibg=fg etc. ui_default_colors_set(); } did_highlight_changed = true; redraw_all_later(UPD_NOT_VALID); } else { set_hl_attr(idx); } hl_table[idx].sg_script_ctx = current_sctx; hl_table[idx].sg_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&hl_table[idx].sg_script_ctx); // Only call highlight_changed() once, after a sequence of highlight // commands, and only if an attribute actually changed if ((did_change || memcmp(&hl_table[idx], &item_before, sizeof(item_before)) != 0) && !did_highlight_changed) { // Do not trigger a redraw when highlighting is changed while // redrawing. This may happen when evaluating 'statusline' changes the // StatusLine group. if (!updating_screen) { redraw_all_later(UPD_NOT_VALID); } need_highlight_changed = true; } } #if defined(EXITFREE) void free_highlight(void) { ga_clear(&highlight_ga); map_destroy(cstr_t, int)(&highlight_unames); arena_mem_free(arena_finish(&highlight_arena)); } #endif /// Reset the cterm colors to what they were before Vim was started, if /// possible. Otherwise reset them to zero. void restore_cterm_colors(void) { normal_fg = -1; normal_bg = -1; normal_sp = -1; cterm_normal_fg_color = 0; cterm_normal_bg_color = 0; } /// @param check_link if true also check for an existing link. /// /// @return true if highlight group "idx" has any settings. static int hl_has_settings(int idx, bool check_link) { return hl_table[idx].sg_cleared == 0 && (hl_table[idx].sg_attr != 0 || hl_table[idx].sg_cterm_fg != 0 || hl_table[idx].sg_cterm_bg != 0 || hl_table[idx].sg_rgb_fg_idx != kColorIdxNone || hl_table[idx].sg_rgb_bg_idx != kColorIdxNone || hl_table[idx].sg_rgb_sp_idx != kColorIdxNone || (check_link && (hl_table[idx].sg_set & SG_LINK))); } /// Clear highlighting for one group. static void highlight_clear(int idx) { hl_table[idx].sg_cleared = true; hl_table[idx].sg_attr = 0; hl_table[idx].sg_cterm = 0; hl_table[idx].sg_cterm_bold = false; hl_table[idx].sg_cterm_fg = 0; hl_table[idx].sg_cterm_bg = 0; hl_table[idx].sg_gui = 0; hl_table[idx].sg_rgb_fg = -1; hl_table[idx].sg_rgb_bg = -1; hl_table[idx].sg_rgb_sp = -1; hl_table[idx].sg_rgb_fg_idx = kColorIdxNone; hl_table[idx].sg_rgb_bg_idx = kColorIdxNone; hl_table[idx].sg_rgb_sp_idx = kColorIdxNone; hl_table[idx].sg_blend = -1; // Restore default link and context if they exist. Otherwise clears. hl_table[idx].sg_link = hl_table[idx].sg_deflink; // Since we set the default link, set the location to where the default // link was set. hl_table[idx].sg_script_ctx = hl_table[idx].sg_deflink_sctx; } /// \addtogroup LIST_XXX /// @{ #define LIST_ATTR 1 #define LIST_STRING 2 #define LIST_INT 3 /// @} static void highlight_list_one(const int id) { const HlGroup *sgp = &hl_table[id - 1]; // index is ID minus one bool didh = false; if (message_filtered((char *)sgp->sg_name)) { return; } // don't list specialized groups if a parent is used instead if (sgp->sg_parent && sgp->sg_cleared) { return; } didh = highlight_list_arg(id, didh, LIST_ATTR, sgp->sg_cterm, NULL, "cterm"); didh = highlight_list_arg(id, didh, LIST_INT, sgp->sg_cterm_fg, NULL, "ctermfg"); didh = highlight_list_arg(id, didh, LIST_INT, sgp->sg_cterm_bg, NULL, "ctermbg"); didh = highlight_list_arg(id, didh, LIST_ATTR, sgp->sg_gui, NULL, "gui"); char hexbuf[8]; didh = highlight_list_arg(id, didh, LIST_STRING, 0, coloridx_to_name(sgp->sg_rgb_fg_idx, sgp->sg_rgb_fg, hexbuf), "guifg"); didh = highlight_list_arg(id, didh, LIST_STRING, 0, coloridx_to_name(sgp->sg_rgb_bg_idx, sgp->sg_rgb_bg, hexbuf), "guibg"); didh = highlight_list_arg(id, didh, LIST_STRING, 0, coloridx_to_name(sgp->sg_rgb_sp_idx, sgp->sg_rgb_sp, hexbuf), "guisp"); didh = highlight_list_arg(id, didh, LIST_INT, sgp->sg_blend + 1, NULL, "blend"); if (sgp->sg_link && !got_int) { (void)syn_list_header(didh, 0, id, true); didh = true; msg_puts_attr("links to", HL_ATTR(HLF_D)); msg_putchar(' '); msg_outtrans((char *)hl_table[hl_table[id - 1].sg_link - 1].sg_name); } if (!didh) { highlight_list_arg(id, didh, LIST_STRING, 0, "cleared", ""); } if (p_verbose > 0) { last_set_msg(sgp->sg_script_ctx); } } Dictionary get_global_hl_defs(Arena *arena) { Dictionary rv = arena_dict(arena, (size_t)highlight_ga.ga_len); for (int i = 1; i <= highlight_ga.ga_len; i++) { Dictionary attrs = ARRAY_DICT_INIT; HlGroup *h = &hl_table[i - 1]; if (h->sg_attr > 0) { attrs = arena_dict(arena, HLATTRS_DICT_SIZE); hlattrs2dict(&attrs, syn_attr2entry(h->sg_attr), true); } else if (h->sg_link > 0) { attrs = arena_dict(arena, 1); char *link = (char *)hl_table[h->sg_link - 1].sg_name; PUT_C(attrs, "link", STRING_OBJ(cstr_as_string(link))); } PUT_C(rv, (char *)h->sg_name, DICTIONARY_OBJ(attrs)); } return rv; } /// Outputs a highlight when doing ":hi MyHighlight" /// /// @param type one of \ref LIST_XXX /// @param iarg integer argument used if \p type == LIST_INT /// @param sarg string used if \p type == LIST_STRING static bool highlight_list_arg(const int id, bool didh, const int type, int iarg, const char *sarg, const char *const name) { char buf[100]; if (got_int) { return false; } if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0)) { const char *ts = buf; if (type == LIST_INT) { snprintf((char *)buf, sizeof(buf), "%d", iarg - 1); } else if (type == LIST_STRING) { ts = sarg; } else { // type == LIST_ATTR buf[0] = NUL; for (int i = 0; hl_attr_table[i] != 0; i++) { if (iarg & hl_attr_table[i]) { if (buf[0] != NUL) { xstrlcat(buf, ",", 100); } xstrlcat(buf, hl_name_table[i], 100); iarg &= ~hl_attr_table[i]; // don't want "inverse" } } } (void)syn_list_header(didh, vim_strsize((char *)ts) + (int)strlen(name) + 1, id, false); didh = true; if (!got_int) { if (*name != NUL) { msg_puts_attr(name, HL_ATTR(HLF_D)); msg_puts_attr("=", HL_ATTR(HLF_D)); } msg_outtrans((char *)ts); } } return didh; } /// Check whether highlight group has attribute /// /// @param[in] id Highlight group to check. /// @param[in] flag Attribute to check. /// @param[in] modec 'g' for GUI, 'c' for term. /// /// @return "1" if highlight group has attribute, NULL otherwise. const char *highlight_has_attr(const int id, const int flag, const int modec) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { int attr; if (id <= 0 || id > highlight_ga.ga_len) { return NULL; } if (modec == 'g') { attr = hl_table[id - 1].sg_gui; } else { attr = hl_table[id - 1].sg_cterm; } return (attr & flag) ? "1" : NULL; } /// Return color name of the given highlight group /// /// @param[in] id Highlight group to work with. /// @param[in] what What to return: one of "font", "fg", "bg", "sp", "fg#", /// "bg#" or "sp#". /// @param[in] modec 'g' for GUI, 'c' for cterm and 't' for term. /// /// @return color name, possibly in a static buffer. Buffer will be overwritten /// on next highlight_color() call. May return NULL. const char *highlight_color(const int id, const char *const what, const int modec) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { static char name[20]; int n; bool fg = false; bool sp = false; bool font = false; if (id <= 0 || id > highlight_ga.ga_len) { return NULL; } if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g') { fg = true; } else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o' && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't') { font = true; } else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p') { sp = true; } else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g')) { return NULL; } if (modec == 'g') { if (what[2] == '#' && ui_rgb_attached()) { if (fg) { n = hl_table[id - 1].sg_rgb_fg; } else if (sp) { n = hl_table[id - 1].sg_rgb_sp; } else { n = hl_table[id - 1].sg_rgb_bg; } if (n < 0 || n > 0xffffff) { return NULL; } snprintf(name, sizeof(name), "#%06x", n); return name; } if (fg) { return coloridx_to_name(hl_table[id - 1].sg_rgb_fg_idx, hl_table[id - 1].sg_rgb_fg, name); } else if (sp) { return coloridx_to_name(hl_table[id - 1].sg_rgb_sp_idx, hl_table[id - 1].sg_rgb_sp, name); } else { return coloridx_to_name(hl_table[id - 1].sg_rgb_bg_idx, hl_table[id - 1].sg_rgb_bg, name); } } if (font || sp) { return NULL; } if (modec == 'c') { if (fg) { n = hl_table[id - 1].sg_cterm_fg - 1; } else { n = hl_table[id - 1].sg_cterm_bg - 1; } if (n < 0) { return NULL; } snprintf(name, sizeof(name), "%d", n); return name; } // term doesn't have color. return NULL; } /// Output the syntax list header. /// /// @param did_header did header already /// @param outlen length of string that comes /// @param id highlight group id /// @param force_newline always start a new line /// @return true when started a new line. bool syn_list_header(const bool did_header, const int outlen, const int id, bool force_newline) { int endcol = 19; bool newline = true; int name_col = 0; bool adjust = true; if (!did_header) { msg_putchar('\n'); if (got_int) { return true; } msg_outtrans((char *)hl_table[id - 1].sg_name); name_col = msg_col; endcol = 15; } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) { msg_putchar(' '); adjust = false; } else if (msg_col + outlen + 1 >= Columns || force_newline) { msg_putchar('\n'); if (got_int) { return true; } } else { if (msg_col >= endcol) { // wrap around is like starting a new line newline = false; } } if (adjust) { if (msg_col >= endcol) { // output at least one space endcol = msg_col + 1; } msg_advance(endcol); } // Show "xxx" with the attributes. if (!did_header) { if (endcol == Columns - 1 && endcol <= name_col) { msg_putchar(' '); } msg_puts_attr("xxx", syn_id2attr(id)); msg_putchar(' '); } return newline; } /// Set the attribute numbers for a highlight group. /// Called after one of the attributes has changed. /// @param idx corrected highlight index static void set_hl_attr(int idx) { HlAttrs at_en = HLATTRS_INIT; HlGroup *sgp = hl_table + idx; at_en.cterm_ae_attr = (int16_t)sgp->sg_cterm; at_en.cterm_fg_color = sgp->sg_cterm_fg; at_en.cterm_bg_color = sgp->sg_cterm_bg; at_en.rgb_ae_attr = (int16_t)sgp->sg_gui; // FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is // initialized with 0(by garray functions), check for sg_rgb_{f,b}g_name // before setting attr_entry->{f,g}g_color to a other than -1 at_en.rgb_fg_color = sgp->sg_rgb_fg_idx != kColorIdxNone ? sgp->sg_rgb_fg : -1; at_en.rgb_bg_color = sgp->sg_rgb_bg_idx != kColorIdxNone ? sgp->sg_rgb_bg : -1; at_en.rgb_sp_color = sgp->sg_rgb_sp_idx != kColorIdxNone ? sgp->sg_rgb_sp : -1; at_en.hl_blend = sgp->sg_blend; sgp->sg_attr = hl_get_syn_attr(0, idx + 1, at_en); // a cursor style uses this syn_id, make sure its attribute is updated. if (cursor_mode_uses_syn_id(idx + 1)) { ui_mode_info_set(); } } int syn_name2id(const char *name) FUNC_ATTR_NONNULL_ALL { if (name[0] == '@') { // if we look up @aaa.bbb, we have to consider @aaa as well return syn_check_group(name, strlen(name)); } else { return syn_name2id_len(name, strlen(name)); } } /// Lookup a highlight group name and return its ID. /// /// @param highlight name e.g. 'Cursor', 'Normal' /// @return the highlight id, else 0 if \p name does not exist int syn_name2id_len(const char *name, size_t len) FUNC_ATTR_NONNULL_ALL { char name_u[MAX_SYN_NAME + 1]; if (len == 0 || len > MAX_SYN_NAME) { return 0; } // Avoid using stricmp() too much, it's slow on some systems */ // Avoid alloc()/free(), these are slow too. memcpy(name_u, name, len); name_u[len] = '\0'; vim_strup((char_u *)name_u); // map_get(..., int) returns 0 when no key is present, which is // the expected value for missing highlight group. return map_get(cstr_t, int)(&highlight_unames, name_u); } /// Lookup a highlight group name and return its attributes. /// Return zero if not found. int syn_name2attr(const char_u *name) FUNC_ATTR_NONNULL_ALL { int id = syn_name2id((char *)name); if (id != 0) { return syn_id2attr(id); } return 0; } /// Return true if highlight group "name" exists. int highlight_exists(const char *name) { return syn_name2id(name) > 0; } /// Return the name of highlight group "id". /// When not a valid ID return an empty string. char_u *syn_id2name(int id) { if (id <= 0 || id > highlight_ga.ga_len) { return (char_u *)""; } return hl_table[id - 1].sg_name; } /// Find highlight group name in the table and return its ID. /// If it doesn't exist yet, a new entry is created. /// /// @param pp Highlight group name /// @param len length of \p pp /// /// @return 0 for failure else the id of the group int syn_check_group(const char *name, size_t len) { if (len > MAX_SYN_NAME) { emsg(_(e_highlight_group_name_too_long)); return 0; } int id = syn_name2id_len(name, len); if (id == 0) { // doesn't exist yet return syn_add_group(name, len); } return id; } /// Add new highlight group and return its ID. /// /// @param name must be an allocated string, it will be consumed. /// @return 0 for failure, else the allocated group id /// @see syn_check_group static int syn_add_group(const char *name, size_t len) { // Check that the name is ASCII letters, digits and underscore. for (size_t i = 0; i < len; i++) { int c = (uint8_t)name[i]; if (!vim_isprintc(c)) { emsg(_("E669: Unprintable character in group name")); return 0; } else if (!ASCII_ISALNUM(c) && c != '_' && c != '.' && c != '@') { // '.' and '@' are allowed characters for use with treesitter capture names. msg_source(HL_ATTR(HLF_W)); emsg(_(e_highlight_group_name_invalid_char)); return 0; } } int scoped_parent = 0; if (len > 1 && name[0] == '@') { char *delim = xmemrchr(name, '.', len); if (delim) { scoped_parent = syn_check_group(name, (size_t)(delim - name)); } } // First call for this growarray: init growing array. if (highlight_ga.ga_data == NULL) { highlight_ga.ga_itemsize = sizeof(HlGroup); ga_set_growsize(&highlight_ga, 10); // 265 builtin groups, will always be used, plus some space ga_grow(&highlight_ga, 300); } if (highlight_ga.ga_len >= MAX_HL_ID) { emsg(_("E849: Too many highlight and syntax groups")); return 0; } // Append another syntax_highlight entry. HlGroup *hlgp = GA_APPEND_VIA_PTR(HlGroup, &highlight_ga); CLEAR_POINTER(hlgp); hlgp->sg_name = (char_u *)arena_memdupz(&highlight_arena, name, len); hlgp->sg_rgb_bg = -1; hlgp->sg_rgb_fg = -1; hlgp->sg_rgb_sp = -1; hlgp->sg_rgb_bg_idx = kColorIdxNone; hlgp->sg_rgb_fg_idx = kColorIdxNone; hlgp->sg_rgb_sp_idx = kColorIdxNone; hlgp->sg_blend = -1; hlgp->sg_name_u = arena_memdupz(&highlight_arena, name, len); hlgp->sg_parent = scoped_parent; // will get set to false by caller if settings are added hlgp->sg_cleared = true; vim_strup((char_u *)hlgp->sg_name_u); int id = highlight_ga.ga_len; // ID is index plus one map_put(cstr_t, int)(&highlight_unames, hlgp->sg_name_u, id); return id; } /// Translate a group ID to highlight attributes. /// @see syn_attr2entry int syn_id2attr(int hl_id) { return syn_ns_id2attr(-1, hl_id, false); } int syn_ns_id2attr(int ns_id, int hl_id, bool optional) { hl_id = syn_ns_get_final_id(&ns_id, hl_id); HlGroup *sgp = &hl_table[hl_id - 1]; // index is ID minus one int attr = ns_get_hl(&ns_id, hl_id, false, sgp->sg_set); // if a highlight group is optional, don't use the global value if (attr >= 0 || (optional && ns_id > 0)) { return attr; } return sgp->sg_attr; } /// Translate a group ID to the final group ID (following links). int syn_get_final_id(int hl_id) { int id = curwin->w_ns_hl_active; return syn_ns_get_final_id(&id, hl_id); } int syn_ns_get_final_id(int *ns_id, int hl_id) { int count; if (hl_id > highlight_ga.ga_len || hl_id < 1) { return 0; // Can be called from eval!! } // Follow links until there is no more. // Look out for loops! Break after 100 links. for (count = 100; --count >= 0;) { HlGroup *sgp = &hl_table[hl_id - 1]; // index is ID minus one // TODO(bfredl): when using "tmp" attribute (no link) the function might be // called twice. it needs be smart enough to remember attr only to // syn_id2attr time int check = ns_get_hl(ns_id, hl_id, true, sgp->sg_set); if (check == 0) { return hl_id; // how dare! it broke the link! } else if (check > 0) { hl_id = check; continue; } if (sgp->sg_link > 0 && sgp->sg_link <= highlight_ga.ga_len) { hl_id = sgp->sg_link; } else if (sgp->sg_cleared && sgp->sg_parent > 0) { hl_id = sgp->sg_parent; } else { break; } } return hl_id; } /// Refresh the color attributes of all highlight groups. void highlight_attr_set_all(void) { for (int idx = 0; idx < highlight_ga.ga_len; idx++) { HlGroup *sgp = &hl_table[idx]; if (sgp->sg_rgb_bg_idx == kColorIdxFg) { sgp->sg_rgb_bg = normal_fg; } else if (sgp->sg_rgb_bg_idx == kColorIdxBg) { sgp->sg_rgb_bg = normal_bg; } if (sgp->sg_rgb_fg_idx == kColorIdxFg) { sgp->sg_rgb_fg = normal_fg; } else if (sgp->sg_rgb_fg_idx == kColorIdxBg) { sgp->sg_rgb_fg = normal_bg; } if (sgp->sg_rgb_sp_idx == kColorIdxFg) { sgp->sg_rgb_sp = normal_fg; } else if (sgp->sg_rgb_sp_idx == kColorIdxBg) { sgp->sg_rgb_sp = normal_bg; } set_hl_attr(idx); } } // Apply difference between User[1-9] and HLF_S to HLF_SNC. static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int hlf, int *table) FUNC_ATTR_NONNULL_ALL { HlGroup *const hlt = hl_table; if (id_alt == 0) { CLEAR_POINTER(&hlt[hlcnt + i]); hlt[hlcnt + i].sg_cterm = highlight_attr[hlf]; hlt[hlcnt + i].sg_gui = highlight_attr[hlf]; } else { memmove(&hlt[hlcnt + i], &hlt[id_alt - 1], sizeof(HlGroup)); } hlt[hlcnt + i].sg_link = 0; hlt[hlcnt + i].sg_cterm ^= hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm; if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg) { hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg; } if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg) { hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg; } hlt[hlcnt + i].sg_gui ^= hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui; if (hlt[id - 1].sg_rgb_fg != hlt[id_S - 1].sg_rgb_fg) { hlt[hlcnt + i].sg_rgb_fg = hlt[id - 1].sg_rgb_fg; } if (hlt[id - 1].sg_rgb_bg != hlt[id_S - 1].sg_rgb_bg) { hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg; } if (hlt[id - 1].sg_rgb_sp != hlt[id_S - 1].sg_rgb_sp) { hlt[hlcnt + i].sg_rgb_sp = hlt[id - 1].sg_rgb_sp; } highlight_ga.ga_len = hlcnt + i + 1; set_hl_attr(hlcnt + i); // At long last we can apply table[i] = syn_id2attr(hlcnt + i + 1); } /// Translate highlight groups into attributes in highlight_attr[] and set up /// the user highlights User1..9. A set of corresponding highlights to use on /// top of HLF_SNC is computed. Called only when nvim starts and upon first /// screen redraw after any :highlight command. void highlight_changed(void) { int id; char userhl[30]; // use 30 to avoid compiler warning int id_S = -1; int id_SNC = 0; int hlcnt; need_highlight_changed = false; /// Translate builtin highlight groups into attributes for quick lookup. for (int hlf = 0; hlf < HLF_COUNT; hlf++) { id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf])); if (id == 0) { abort(); } int ns_id = -1; int final_id = syn_ns_get_final_id(&ns_id, id); if (hlf == HLF_SNC) { id_SNC = final_id; } else if (hlf == HLF_S) { id_S = final_id; } highlight_attr[hlf] = hl_get_ui_attr(ns_id, hlf, final_id, (hlf == HLF_INACTIVE || hlf == HLF_LC)); if (highlight_attr[hlf] != highlight_attr_last[hlf]) { if (hlf == HLF_MSG) { clear_cmdline = true; HlAttrs attrs = syn_attr2entry(highlight_attr[hlf]); msg_grid.blending = attrs.hl_blend > -1; } ui_call_hl_group_set(cstr_as_string((char *)hlf_names[hlf]), highlight_attr[hlf]); highlight_attr_last[hlf] = highlight_attr[hlf]; } } // sentinel value. used when no highlight namespace is active highlight_attr[HLF_COUNT] = 0; // // Setup the user highlights // // Temporarily utilize 10 more hl entries: // 9 for User1-User9 combined with StatusLineNC // 1 for StatusLine default // Must to be in there simultaneously in case of table overflows in // get_attr_entry() ga_grow(&highlight_ga, 10); hlcnt = highlight_ga.ga_len; if (id_S == -1) { // Make sure id_S is always valid to simplify code below. Use the last entry CLEAR_POINTER(&hl_table[hlcnt + 9]); id_S = hlcnt + 10; } for (int i = 0; i < 9; i++) { snprintf(userhl, sizeof(userhl), "User%d", i + 1); id = syn_name2id(userhl); if (id == 0) { highlight_user[i] = 0; highlight_stlnc[i] = 0; } else { highlight_user[i] = syn_id2attr(id); combine_stl_hlt(id, id_S, id_SNC, hlcnt, i, HLF_SNC, highlight_stlnc); } } highlight_ga.ga_len = hlcnt; } /// Handle command line completion for :highlight command. void set_context_in_highlight_cmd(expand_T *xp, const char *arg) { // Default: expand group names. xp->xp_context = EXPAND_HIGHLIGHT; xp->xp_pattern = (char *)arg; include_link = 2; include_default = 1; // (part of) subcommand already typed if (*arg != NUL) { const char *p = (const char *)skiptowhite(arg); if (*p != NUL) { // Past "default" or group name. include_default = 0; if (strncmp("default", arg, (unsigned)(p - arg)) == 0) { arg = (const char *)skipwhite(p); xp->xp_pattern = (char *)arg; p = (const char *)skiptowhite(arg); } if (*p != NUL) { // past group name include_link = 0; if (arg[1] == 'i' && arg[0] == 'N') { highlight_list(); } if (strncmp("link", arg, (unsigned)(p - arg)) == 0 || strncmp("clear", arg, (unsigned)(p - arg)) == 0) { xp->xp_pattern = skipwhite(p); p = (const char *)skiptowhite(xp->xp_pattern); if (*p != NUL) { // Past first group name. xp->xp_pattern = skipwhite(p); p = (const char *)skiptowhite(xp->xp_pattern); } } if (*p != NUL) { // Past group name(s). xp->xp_context = EXPAND_NOTHING; } } } } } /// List highlighting matches in a nice way. static void highlight_list(void) { int i; for (i = 10; --i >= 0;) { highlight_list_two(i, HL_ATTR(HLF_D)); } for (i = 40; --i >= 0;) { highlight_list_two(99, 0); } } static void highlight_list_two(int cnt, int attr) { msg_puts_attr(&("N \bI \b! \b"[cnt / 11]), attr); msg_clr_eos(); ui_flush(); os_delay(cnt == 99 ? 40L : (uint64_t)cnt * 50L, false); } /// Function given to ExpandGeneric() to obtain the list of group names. const char *get_highlight_name(expand_T *const xp, int idx) FUNC_ATTR_WARN_UNUSED_RESULT { return get_highlight_name_ext(xp, idx, true); } /// Obtain a highlight group name. /// /// @param skip_cleared if true don't return a cleared entry. const char *get_highlight_name_ext(expand_T *xp, int idx, bool skip_cleared) FUNC_ATTR_WARN_UNUSED_RESULT { if (idx < 0) { return NULL; } // Items are never removed from the table, skip the ones that were cleared. if (skip_cleared && idx < highlight_ga.ga_len && hl_table[idx].sg_cleared) { return ""; } if (idx == highlight_ga.ga_len && include_none != 0) { return "none"; } else if (idx == highlight_ga.ga_len + include_none && include_default != 0) { return "default"; } else if (idx == highlight_ga.ga_len + include_none + include_default && include_link != 0) { return "link"; } else if (idx == highlight_ga.ga_len + include_none + include_default + 1 && include_link != 0) { return "clear"; } else if (idx >= highlight_ga.ga_len) { return NULL; } return (const char *)hl_table[idx].sg_name; } color_name_table_T color_name_table[] = { // Colors from rgb.txt { "AliceBlue", RGB_(0xf0, 0xf8, 0xff) }, { "AntiqueWhite", RGB_(0xfa, 0xeb, 0xd7) }, { "AntiqueWhite1", RGB_(0xff, 0xef, 0xdb) }, { "AntiqueWhite2", RGB_(0xee, 0xdf, 0xcc) }, { "AntiqueWhite3", RGB_(0xcd, 0xc0, 0xb0) }, { "AntiqueWhite4", RGB_(0x8b, 0x83, 0x78) }, { "Aqua", RGB_(0x00, 0xff, 0xff) }, { "Aquamarine", RGB_(0x7f, 0xff, 0xd4) }, { "Aquamarine1", RGB_(0x7f, 0xff, 0xd4) }, { "Aquamarine2", RGB_(0x76, 0xee, 0xc6) }, { "Aquamarine3", RGB_(0x66, 0xcd, 0xaa) }, { "Aquamarine4", RGB_(0x45, 0x8b, 0x74) }, { "Azure", RGB_(0xf0, 0xff, 0xff) }, { "Azure1", RGB_(0xf0, 0xff, 0xff) }, { "Azure2", RGB_(0xe0, 0xee, 0xee) }, { "Azure3", RGB_(0xc1, 0xcd, 0xcd) }, { "Azure4", RGB_(0x83, 0x8b, 0x8b) }, { "Beige", RGB_(0xf5, 0xf5, 0xdc) }, { "Bisque", RGB_(0xff, 0xe4, 0xc4) }, { "Bisque1", RGB_(0xff, 0xe4, 0xc4) }, { "Bisque2", RGB_(0xee, 0xd5, 0xb7) }, { "Bisque3", RGB_(0xcd, 0xb7, 0x9e) }, { "Bisque4", RGB_(0x8b, 0x7d, 0x6b) }, { "Black", RGB_(0x00, 0x00, 0x00) }, { "BlanchedAlmond", RGB_(0xff, 0xeb, 0xcd) }, { "Blue", RGB_(0x00, 0x00, 0xff) }, { "Blue1", RGB_(0x0, 0x0, 0xff) }, { "Blue2", RGB_(0x0, 0x0, 0xee) }, { "Blue3", RGB_(0x0, 0x0, 0xcd) }, { "Blue4", RGB_(0x0, 0x0, 0x8b) }, { "BlueViolet", RGB_(0x8a, 0x2b, 0xe2) }, { "Brown", RGB_(0xa5, 0x2a, 0x2a) }, { "Brown1", RGB_(0xff, 0x40, 0x40) }, { "Brown2", RGB_(0xee, 0x3b, 0x3b) }, { "Brown3", RGB_(0xcd, 0x33, 0x33) }, { "Brown4", RGB_(0x8b, 0x23, 0x23) }, { "BurlyWood", RGB_(0xde, 0xb8, 0x87) }, { "Burlywood1", RGB_(0xff, 0xd3, 0x9b) }, { "Burlywood2", RGB_(0xee, 0xc5, 0x91) }, { "Burlywood3", RGB_(0xcd, 0xaa, 0x7d) }, { "Burlywood4", RGB_(0x8b, 0x73, 0x55) }, { "CadetBlue", RGB_(0x5f, 0x9e, 0xa0) }, { "CadetBlue1", RGB_(0x98, 0xf5, 0xff) }, { "CadetBlue2", RGB_(0x8e, 0xe5, 0xee) }, { "CadetBlue3", RGB_(0x7a, 0xc5, 0xcd) }, { "CadetBlue4", RGB_(0x53, 0x86, 0x8b) }, { "ChartReuse", RGB_(0x7f, 0xff, 0x00) }, { "Chartreuse1", RGB_(0x7f, 0xff, 0x0) }, { "Chartreuse2", RGB_(0x76, 0xee, 0x0) }, { "Chartreuse3", RGB_(0x66, 0xcd, 0x0) }, { "Chartreuse4", RGB_(0x45, 0x8b, 0x0) }, { "Chocolate", RGB_(0xd2, 0x69, 0x1e) }, { "Chocolate1", RGB_(0xff, 0x7f, 0x24) }, { "Chocolate2", RGB_(0xee, 0x76, 0x21) }, { "Chocolate3", RGB_(0xcd, 0x66, 0x1d) }, { "Chocolate4", RGB_(0x8b, 0x45, 0x13) }, { "Coral", RGB_(0xff, 0x7f, 0x50) }, { "Coral1", RGB_(0xff, 0x72, 0x56) }, { "Coral2", RGB_(0xee, 0x6a, 0x50) }, { "Coral3", RGB_(0xcd, 0x5b, 0x45) }, { "Coral4", RGB_(0x8b, 0x3e, 0x2f) }, { "CornFlowerBlue", RGB_(0x64, 0x95, 0xed) }, { "Cornsilk", RGB_(0xff, 0xf8, 0xdc) }, { "Cornsilk1", RGB_(0xff, 0xf8, 0xdc) }, { "Cornsilk2", RGB_(0xee, 0xe8, 0xcd) }, { "Cornsilk3", RGB_(0xcd, 0xc8, 0xb1) }, { "Cornsilk4", RGB_(0x8b, 0x88, 0x78) }, { "Crimson", RGB_(0xdc, 0x14, 0x3c) }, { "Cyan", RGB_(0x00, 0xff, 0xff) }, { "Cyan1", RGB_(0x0, 0xff, 0xff) }, { "Cyan2", RGB_(0x0, 0xee, 0xee) }, { "Cyan3", RGB_(0x0, 0xcd, 0xcd) }, { "Cyan4", RGB_(0x0, 0x8b, 0x8b) }, { "DarkBlue", RGB_(0x00, 0x00, 0x8b) }, { "DarkCyan", RGB_(0x00, 0x8b, 0x8b) }, { "DarkGoldenRod", RGB_(0xb8, 0x86, 0x0b) }, { "DarkGoldenrod1", RGB_(0xff, 0xb9, 0xf) }, { "DarkGoldenrod2", RGB_(0xee, 0xad, 0xe) }, { "DarkGoldenrod3", RGB_(0xcd, 0x95, 0xc) }, { "DarkGoldenrod4", RGB_(0x8b, 0x65, 0x8) }, { "DarkGray", RGB_(0xa9, 0xa9, 0xa9) }, { "DarkGreen", RGB_(0x00, 0x64, 0x00) }, { "DarkGrey", RGB_(0xa9, 0xa9, 0xa9) }, { "DarkKhaki", RGB_(0xbd, 0xb7, 0x6b) }, { "DarkMagenta", RGB_(0x8b, 0x00, 0x8b) }, { "DarkOliveGreen", RGB_(0x55, 0x6b, 0x2f) }, { "DarkOliveGreen1", RGB_(0xca, 0xff, 0x70) }, { "DarkOliveGreen2", RGB_(0xbc, 0xee, 0x68) }, { "DarkOliveGreen3", RGB_(0xa2, 0xcd, 0x5a) }, { "DarkOliveGreen4", RGB_(0x6e, 0x8b, 0x3d) }, { "DarkOrange", RGB_(0xff, 0x8c, 0x00) }, { "DarkOrange1", RGB_(0xff, 0x7f, 0x0) }, { "DarkOrange2", RGB_(0xee, 0x76, 0x0) }, { "DarkOrange3", RGB_(0xcd, 0x66, 0x0) }, { "DarkOrange4", RGB_(0x8b, 0x45, 0x0) }, { "DarkOrchid", RGB_(0x99, 0x32, 0xcc) }, { "DarkOrchid1", RGB_(0xbf, 0x3e, 0xff) }, { "DarkOrchid2", RGB_(0xb2, 0x3a, 0xee) }, { "DarkOrchid3", RGB_(0x9a, 0x32, 0xcd) }, { "DarkOrchid4", RGB_(0x68, 0x22, 0x8b) }, { "DarkRed", RGB_(0x8b, 0x00, 0x00) }, { "DarkSalmon", RGB_(0xe9, 0x96, 0x7a) }, { "DarkSeaGreen", RGB_(0x8f, 0xbc, 0x8f) }, { "DarkSeaGreen1", RGB_(0xc1, 0xff, 0xc1) }, { "DarkSeaGreen2", RGB_(0xb4, 0xee, 0xb4) }, { "DarkSeaGreen3", RGB_(0x9b, 0xcd, 0x9b) }, { "DarkSeaGreen4", RGB_(0x69, 0x8b, 0x69) }, { "DarkSlateBlue", RGB_(0x48, 0x3d, 0x8b) }, { "DarkSlateGray", RGB_(0x2f, 0x4f, 0x4f) }, { "DarkSlateGray1", RGB_(0x97, 0xff, 0xff) }, { "DarkSlateGray2", RGB_(0x8d, 0xee, 0xee) }, { "DarkSlateGray3", RGB_(0x79, 0xcd, 0xcd) }, { "DarkSlateGray4", RGB_(0x52, 0x8b, 0x8b) }, { "DarkSlateGrey", RGB_(0x2f, 0x4f, 0x4f) }, { "DarkTurquoise", RGB_(0x00, 0xce, 0xd1) }, { "DarkViolet", RGB_(0x94, 0x00, 0xd3) }, { "DarkYellow", RGB_(0xbb, 0xbb, 0x00) }, { "DeepPink", RGB_(0xff, 0x14, 0x93) }, { "DeepPink1", RGB_(0xff, 0x14, 0x93) }, { "DeepPink2", RGB_(0xee, 0x12, 0x89) }, { "DeepPink3", RGB_(0xcd, 0x10, 0x76) }, { "DeepPink4", RGB_(0x8b, 0xa, 0x50) }, { "DeepSkyBlue", RGB_(0x00, 0xbf, 0xff) }, { "DeepSkyBlue1", RGB_(0x0, 0xbf, 0xff) }, { "DeepSkyBlue2", RGB_(0x0, 0xb2, 0xee) }, { "DeepSkyBlue3", RGB_(0x0, 0x9a, 0xcd) }, { "DeepSkyBlue4", RGB_(0x0, 0x68, 0x8b) }, { "DimGray", RGB_(0x69, 0x69, 0x69) }, { "DimGrey", RGB_(0x69, 0x69, 0x69) }, { "DodgerBlue", RGB_(0x1e, 0x90, 0xff) }, { "DodgerBlue1", RGB_(0x1e, 0x90, 0xff) }, { "DodgerBlue2", RGB_(0x1c, 0x86, 0xee) }, { "DodgerBlue3", RGB_(0x18, 0x74, 0xcd) }, { "DodgerBlue4", RGB_(0x10, 0x4e, 0x8b) }, { "Firebrick", RGB_(0xb2, 0x22, 0x22) }, { "Firebrick1", RGB_(0xff, 0x30, 0x30) }, { "Firebrick2", RGB_(0xee, 0x2c, 0x2c) }, { "Firebrick3", RGB_(0xcd, 0x26, 0x26) }, { "Firebrick4", RGB_(0x8b, 0x1a, 0x1a) }, { "FloralWhite", RGB_(0xff, 0xfa, 0xf0) }, { "ForestGreen", RGB_(0x22, 0x8b, 0x22) }, { "Fuchsia", RGB_(0xff, 0x00, 0xff) }, { "Gainsboro", RGB_(0xdc, 0xdc, 0xdc) }, { "GhostWhite", RGB_(0xf8, 0xf8, 0xff) }, { "Gold", RGB_(0xff, 0xd7, 0x00) }, { "Gold1", RGB_(0xff, 0xd7, 0x0) }, { "Gold2", RGB_(0xee, 0xc9, 0x0) }, { "Gold3", RGB_(0xcd, 0xad, 0x0) }, { "Gold4", RGB_(0x8b, 0x75, 0x0) }, { "GoldenRod", RGB_(0xda, 0xa5, 0x20) }, { "Goldenrod1", RGB_(0xff, 0xc1, 0x25) }, { "Goldenrod2", RGB_(0xee, 0xb4, 0x22) }, { "Goldenrod3", RGB_(0xcd, 0x9b, 0x1d) }, { "Goldenrod4", RGB_(0x8b, 0x69, 0x14) }, { "Gray", RGB_(0x80, 0x80, 0x80) }, { "Gray0", RGB_(0x0, 0x0, 0x0) }, { "Gray1", RGB_(0x3, 0x3, 0x3) }, { "Gray10", RGB_(0x1a, 0x1a, 0x1a) }, { "Gray100", RGB_(0xff, 0xff, 0xff) }, { "Gray11", RGB_(0x1c, 0x1c, 0x1c) }, { "Gray12", RGB_(0x1f, 0x1f, 0x1f) }, { "Gray13", RGB_(0x21, 0x21, 0x21) }, { "Gray14", RGB_(0x24, 0x24, 0x24) }, { "Gray15", RGB_(0x26, 0x26, 0x26) }, { "Gray16", RGB_(0x29, 0x29, 0x29) }, { "Gray17", RGB_(0x2b, 0x2b, 0x2b) }, { "Gray18", RGB_(0x2e, 0x2e, 0x2e) }, { "Gray19", RGB_(0x30, 0x30, 0x30) }, { "Gray2", RGB_(0x5, 0x5, 0x5) }, { "Gray20", RGB_(0x33, 0x33, 0x33) }, { "Gray21", RGB_(0x36, 0x36, 0x36) }, { "Gray22", RGB_(0x38, 0x38, 0x38) }, { "Gray23", RGB_(0x3b, 0x3b, 0x3b) }, { "Gray24", RGB_(0x3d, 0x3d, 0x3d) }, { "Gray25", RGB_(0x40, 0x40, 0x40) }, { "Gray26", RGB_(0x42, 0x42, 0x42) }, { "Gray27", RGB_(0x45, 0x45, 0x45) }, { "Gray28", RGB_(0x47, 0x47, 0x47) }, { "Gray29", RGB_(0x4a, 0x4a, 0x4a) }, { "Gray3", RGB_(0x8, 0x8, 0x8) }, { "Gray30", RGB_(0x4d, 0x4d, 0x4d) }, { "Gray31", RGB_(0x4f, 0x4f, 0x4f) }, { "Gray32", RGB_(0x52, 0x52, 0x52) }, { "Gray33", RGB_(0x54, 0x54, 0x54) }, { "Gray34", RGB_(0x57, 0x57, 0x57) }, { "Gray35", RGB_(0x59, 0x59, 0x59) }, { "Gray36", RGB_(0x5c, 0x5c, 0x5c) }, { "Gray37", RGB_(0x5e, 0x5e, 0x5e) }, { "Gray38", RGB_(0x61, 0x61, 0x61) }, { "Gray39", RGB_(0x63, 0x63, 0x63) }, { "Gray4", RGB_(0xa, 0xa, 0xa) }, { "Gray40", RGB_(0x66, 0x66, 0x66) }, { "Gray41", RGB_(0x69, 0x69, 0x69) }, { "Gray42", RGB_(0x6b, 0x6b, 0x6b) }, { "Gray43", RGB_(0x6e, 0x6e, 0x6e) }, { "Gray44", RGB_(0x70, 0x70, 0x70) }, { "Gray45", RGB_(0x73, 0x73, 0x73) }, { "Gray46", RGB_(0x75, 0x75, 0x75) }, { "Gray47", RGB_(0x78, 0x78, 0x78) }, { "Gray48", RGB_(0x7a, 0x7a, 0x7a) }, { "Gray49", RGB_(0x7d, 0x7d, 0x7d) }, { "Gray5", RGB_(0xd, 0xd, 0xd) }, { "Gray50", RGB_(0x7f, 0x7f, 0x7f) }, { "Gray51", RGB_(0x82, 0x82, 0x82) }, { "Gray52", RGB_(0x85, 0x85, 0x85) }, { "Gray53", RGB_(0x87, 0x87, 0x87) }, { "Gray54", RGB_(0x8a, 0x8a, 0x8a) }, { "Gray55", RGB_(0x8c, 0x8c, 0x8c) }, { "Gray56", RGB_(0x8f, 0x8f, 0x8f) }, { "Gray57", RGB_(0x91, 0x91, 0x91) }, { "Gray58", RGB_(0x94, 0x94, 0x94) }, { "Gray59", RGB_(0x96, 0x96, 0x96) }, { "Gray6", RGB_(0xf, 0xf, 0xf) }, { "Gray60", RGB_(0x99, 0x99, 0x99) }, { "Gray61", RGB_(0x9c, 0x9c, 0x9c) }, { "Gray62", RGB_(0x9e, 0x9e, 0x9e) }, { "Gray63", RGB_(0xa1, 0xa1, 0xa1) }, { "Gray64", RGB_(0xa3, 0xa3, 0xa3) }, { "Gray65", RGB_(0xa6, 0xa6, 0xa6) }, { "Gray66", RGB_(0xa8, 0xa8, 0xa8) }, { "Gray67", RGB_(0xab, 0xab, 0xab) }, { "Gray68", RGB_(0xad, 0xad, 0xad) }, { "Gray69", RGB_(0xb0, 0xb0, 0xb0) }, { "Gray7", RGB_(0x12, 0x12, 0x12) }, { "Gray70", RGB_(0xb3, 0xb3, 0xb3) }, { "Gray71", RGB_(0xb5, 0xb5, 0xb5) }, { "Gray72", RGB_(0xb8, 0xb8, 0xb8) }, { "Gray73", RGB_(0xba, 0xba, 0xba) }, { "Gray74", RGB_(0xbd, 0xbd, 0xbd) }, { "Gray75", RGB_(0xbf, 0xbf, 0xbf) }, { "Gray76", RGB_(0xc2, 0xc2, 0xc2) }, { "Gray77", RGB_(0xc4, 0xc4, 0xc4) }, { "Gray78", RGB_(0xc7, 0xc7, 0xc7) }, { "Gray79", RGB_(0xc9, 0xc9, 0xc9) }, { "Gray8", RGB_(0x14, 0x14, 0x14) }, { "Gray80", RGB_(0xcc, 0xcc, 0xcc) }, { "Gray81", RGB_(0xcf, 0xcf, 0xcf) }, { "Gray82", RGB_(0xd1, 0xd1, 0xd1) }, { "Gray83", RGB_(0xd4, 0xd4, 0xd4) }, { "Gray84", RGB_(0xd6, 0xd6, 0xd6) }, { "Gray85", RGB_(0xd9, 0xd9, 0xd9) }, { "Gray86", RGB_(0xdb, 0xdb, 0xdb) }, { "Gray87", RGB_(0xde, 0xde, 0xde) }, { "Gray88", RGB_(0xe0, 0xe0, 0xe0) }, { "Gray89", RGB_(0xe3, 0xe3, 0xe3) }, { "Gray9", RGB_(0x17, 0x17, 0x17) }, { "Gray90", RGB_(0xe5, 0xe5, 0xe5) }, { "Gray91", RGB_(0xe8, 0xe8, 0xe8) }, { "Gray92", RGB_(0xeb, 0xeb, 0xeb) }, { "Gray93", RGB_(0xed, 0xed, 0xed) }, { "Gray94", RGB_(0xf0, 0xf0, 0xf0) }, { "Gray95", RGB_(0xf2, 0xf2, 0xf2) }, { "Gray96", RGB_(0xf5, 0xf5, 0xf5) }, { "Gray97", RGB_(0xf7, 0xf7, 0xf7) }, { "Gray98", RGB_(0xfa, 0xfa, 0xfa) }, { "Gray99", RGB_(0xfc, 0xfc, 0xfc) }, { "Green", RGB_(0x00, 0x80, 0x00) }, { "Green1", RGB_(0x0, 0xff, 0x0) }, { "Green2", RGB_(0x0, 0xee, 0x0) }, { "Green3", RGB_(0x0, 0xcd, 0x0) }, { "Green4", RGB_(0x0, 0x8b, 0x0) }, { "GreenYellow", RGB_(0xad, 0xff, 0x2f) }, { "Grey", RGB_(0x80, 0x80, 0x80) }, { "Grey0", RGB_(0x0, 0x0, 0x0) }, { "Grey1", RGB_(0x3, 0x3, 0x3) }, { "Grey10", RGB_(0x1a, 0x1a, 0x1a) }, { "Grey100", RGB_(0xff, 0xff, 0xff) }, { "Grey11", RGB_(0x1c, 0x1c, 0x1c) }, { "Grey12", RGB_(0x1f, 0x1f, 0x1f) }, { "Grey13", RGB_(0x21, 0x21, 0x21) }, { "Grey14", RGB_(0x24, 0x24, 0x24) }, { "Grey15", RGB_(0x26, 0x26, 0x26) }, { "Grey16", RGB_(0x29, 0x29, 0x29) }, { "Grey17", RGB_(0x2b, 0x2b, 0x2b) }, { "Grey18", RGB_(0x2e, 0x2e, 0x2e) }, { "Grey19", RGB_(0x30, 0x30, 0x30) }, { "Grey2", RGB_(0x5, 0x5, 0x5) }, { "Grey20", RGB_(0x33, 0x33, 0x33) }, { "Grey21", RGB_(0x36, 0x36, 0x36) }, { "Grey22", RGB_(0x38, 0x38, 0x38) }, { "Grey23", RGB_(0x3b, 0x3b, 0x3b) }, { "Grey24", RGB_(0x3d, 0x3d, 0x3d) }, { "Grey25", RGB_(0x40, 0x40, 0x40) }, { "Grey26", RGB_(0x42, 0x42, 0x42) }, { "Grey27", RGB_(0x45, 0x45, 0x45) }, { "Grey28", RGB_(0x47, 0x47, 0x47) }, { "Grey29", RGB_(0x4a, 0x4a, 0x4a) }, { "Grey3", RGB_(0x8, 0x8, 0x8) }, { "Grey30", RGB_(0x4d, 0x4d, 0x4d) }, { "Grey31", RGB_(0x4f, 0x4f, 0x4f) }, { "Grey32", RGB_(0x52, 0x52, 0x52) }, { "Grey33", RGB_(0x54, 0x54, 0x54) }, { "Grey34", RGB_(0x57, 0x57, 0x57) }, { "Grey35", RGB_(0x59, 0x59, 0x59) }, { "Grey36", RGB_(0x5c, 0x5c, 0x5c) }, { "Grey37", RGB_(0x5e, 0x5e, 0x5e) }, { "Grey38", RGB_(0x61, 0x61, 0x61) }, { "Grey39", RGB_(0x63, 0x63, 0x63) }, { "Grey4", RGB_(0xa, 0xa, 0xa) }, { "Grey40", RGB_(0x66, 0x66, 0x66) }, { "Grey41", RGB_(0x69, 0x69, 0x69) }, { "Grey42", RGB_(0x6b, 0x6b, 0x6b) }, { "Grey43", RGB_(0x6e, 0x6e, 0x6e) }, { "Grey44", RGB_(0x70, 0x70, 0x70) }, { "Grey45", RGB_(0x73, 0x73, 0x73) }, { "Grey46", RGB_(0x75, 0x75, 0x75) }, { "Grey47", RGB_(0x78, 0x78, 0x78) }, { "Grey48", RGB_(0x7a, 0x7a, 0x7a) }, { "Grey49", RGB_(0x7d, 0x7d, 0x7d) }, { "Grey5", RGB_(0xd, 0xd, 0xd) }, { "Grey50", RGB_(0x7f, 0x7f, 0x7f) }, { "Grey51", RGB_(0x82, 0x82, 0x82) }, { "Grey52", RGB_(0x85, 0x85, 0x85) }, { "Grey53", RGB_(0x87, 0x87, 0x87) }, { "Grey54", RGB_(0x8a, 0x8a, 0x8a) }, { "Grey55", RGB_(0x8c, 0x8c, 0x8c) }, { "Grey56", RGB_(0x8f, 0x8f, 0x8f) }, { "Grey57", RGB_(0x91, 0x91, 0x91) }, { "Grey58", RGB_(0x94, 0x94, 0x94) }, { "Grey59", RGB_(0x96, 0x96, 0x96) }, { "Grey6", RGB_(0xf, 0xf, 0xf) }, { "Grey60", RGB_(0x99, 0x99, 0x99) }, { "Grey61", RGB_(0x9c, 0x9c, 0x9c) }, { "Grey62", RGB_(0x9e, 0x9e, 0x9e) }, { "Grey63", RGB_(0xa1, 0xa1, 0xa1) }, { "Grey64", RGB_(0xa3, 0xa3, 0xa3) }, { "Grey65", RGB_(0xa6, 0xa6, 0xa6) }, { "Grey66", RGB_(0xa8, 0xa8, 0xa8) }, { "Grey67", RGB_(0xab, 0xab, 0xab) }, { "Grey68", RGB_(0xad, 0xad, 0xad) }, { "Grey69", RGB_(0xb0, 0xb0, 0xb0) }, { "Grey7", RGB_(0x12, 0x12, 0x12) }, { "Grey70", RGB_(0xb3, 0xb3, 0xb3) }, { "Grey71", RGB_(0xb5, 0xb5, 0xb5) }, { "Grey72", RGB_(0xb8, 0xb8, 0xb8) }, { "Grey73", RGB_(0xba, 0xba, 0xba) }, { "Grey74", RGB_(0xbd, 0xbd, 0xbd) }, { "Grey75", RGB_(0xbf, 0xbf, 0xbf) }, { "Grey76", RGB_(0xc2, 0xc2, 0xc2) }, { "Grey77", RGB_(0xc4, 0xc4, 0xc4) }, { "Grey78", RGB_(0xc7, 0xc7, 0xc7) }, { "Grey79", RGB_(0xc9, 0xc9, 0xc9) }, { "Grey8", RGB_(0x14, 0x14, 0x14) }, { "Grey80", RGB_(0xcc, 0xcc, 0xcc) }, { "Grey81", RGB_(0xcf, 0xcf, 0xcf) }, { "Grey82", RGB_(0xd1, 0xd1, 0xd1) }, { "Grey83", RGB_(0xd4, 0xd4, 0xd4) }, { "Grey84", RGB_(0xd6, 0xd6, 0xd6) }, { "Grey85", RGB_(0xd9, 0xd9, 0xd9) }, { "Grey86", RGB_(0xdb, 0xdb, 0xdb) }, { "Grey87", RGB_(0xde, 0xde, 0xde) }, { "Grey88", RGB_(0xe0, 0xe0, 0xe0) }, { "Grey89", RGB_(0xe3, 0xe3, 0xe3) }, { "Grey9", RGB_(0x17, 0x17, 0x17) }, { "Grey90", RGB_(0xe5, 0xe5, 0xe5) }, { "Grey91", RGB_(0xe8, 0xe8, 0xe8) }, { "Grey92", RGB_(0xeb, 0xeb, 0xeb) }, { "Grey93", RGB_(0xed, 0xed, 0xed) }, { "Grey94", RGB_(0xf0, 0xf0, 0xf0) }, { "Grey95", RGB_(0xf2, 0xf2, 0xf2) }, { "Grey96", RGB_(0xf5, 0xf5, 0xf5) }, { "Grey97", RGB_(0xf7, 0xf7, 0xf7) }, { "Grey98", RGB_(0xfa, 0xfa, 0xfa) }, { "Grey99", RGB_(0xfc, 0xfc, 0xfc) }, { "Honeydew", RGB_(0xf0, 0xff, 0xf0) }, { "Honeydew1", RGB_(0xf0, 0xff, 0xf0) }, { "Honeydew2", RGB_(0xe0, 0xee, 0xe0) }, { "Honeydew3", RGB_(0xc1, 0xcd, 0xc1) }, { "Honeydew4", RGB_(0x83, 0x8b, 0x83) }, { "HotPink", RGB_(0xff, 0x69, 0xb4) }, { "HotPink1", RGB_(0xff, 0x6e, 0xb4) }, { "HotPink2", RGB_(0xee, 0x6a, 0xa7) }, { "HotPink3", RGB_(0xcd, 0x60, 0x90) }, { "HotPink4", RGB_(0x8b, 0x3a, 0x62) }, { "IndianRed", RGB_(0xcd, 0x5c, 0x5c) }, { "IndianRed1", RGB_(0xff, 0x6a, 0x6a) }, { "IndianRed2", RGB_(0xee, 0x63, 0x63) }, { "IndianRed3", RGB_(0xcd, 0x55, 0x55) }, { "IndianRed4", RGB_(0x8b, 0x3a, 0x3a) }, { "Indigo", RGB_(0x4b, 0x00, 0x82) }, { "Ivory", RGB_(0xff, 0xff, 0xf0) }, { "Ivory1", RGB_(0xff, 0xff, 0xf0) }, { "Ivory2", RGB_(0xee, 0xee, 0xe0) }, { "Ivory3", RGB_(0xcd, 0xcd, 0xc1) }, { "Ivory4", RGB_(0x8b, 0x8b, 0x83) }, { "Khaki", RGB_(0xf0, 0xe6, 0x8c) }, { "Khaki1", RGB_(0xff, 0xf6, 0x8f) }, { "Khaki2", RGB_(0xee, 0xe6, 0x85) }, { "Khaki3", RGB_(0xcd, 0xc6, 0x73) }, { "Khaki4", RGB_(0x8b, 0x86, 0x4e) }, { "Lavender", RGB_(0xe6, 0xe6, 0xfa) }, { "LavenderBlush", RGB_(0xff, 0xf0, 0xf5) }, { "LavenderBlush1", RGB_(0xff, 0xf0, 0xf5) }, { "LavenderBlush2", RGB_(0xee, 0xe0, 0xe5) }, { "LavenderBlush3", RGB_(0xcd, 0xc1, 0xc5) }, { "LavenderBlush4", RGB_(0x8b, 0x83, 0x86) }, { "LawnGreen", RGB_(0x7c, 0xfc, 0x00) }, { "LemonChiffon", RGB_(0xff, 0xfa, 0xcd) }, { "LemonChiffon1", RGB_(0xff, 0xfa, 0xcd) }, { "LemonChiffon2", RGB_(0xee, 0xe9, 0xbf) }, { "LemonChiffon3", RGB_(0xcd, 0xc9, 0xa5) }, { "LemonChiffon4", RGB_(0x8b, 0x89, 0x70) }, { "LightBlue", RGB_(0xad, 0xd8, 0xe6) }, { "LightBlue1", RGB_(0xbf, 0xef, 0xff) }, { "LightBlue2", RGB_(0xb2, 0xdf, 0xee) }, { "LightBlue3", RGB_(0x9a, 0xc0, 0xcd) }, { "LightBlue4", RGB_(0x68, 0x83, 0x8b) }, { "LightCoral", RGB_(0xf0, 0x80, 0x80) }, { "LightCyan", RGB_(0xe0, 0xff, 0xff) }, { "LightCyan1", RGB_(0xe0, 0xff, 0xff) }, { "LightCyan2", RGB_(0xd1, 0xee, 0xee) }, { "LightCyan3", RGB_(0xb4, 0xcd, 0xcd) }, { "LightCyan4", RGB_(0x7a, 0x8b, 0x8b) }, { "LightGoldenrod", RGB_(0xee, 0xdd, 0x82) }, { "LightGoldenrod1", RGB_(0xff, 0xec, 0x8b) }, { "LightGoldenrod2", RGB_(0xee, 0xdc, 0x82) }, { "LightGoldenrod3", RGB_(0xcd, 0xbe, 0x70) }, { "LightGoldenrod4", RGB_(0x8b, 0x81, 0x4c) }, { "LightGoldenRodYellow", RGB_(0xfa, 0xfa, 0xd2) }, { "LightGray", RGB_(0xd3, 0xd3, 0xd3) }, { "LightGreen", RGB_(0x90, 0xee, 0x90) }, { "LightGrey", RGB_(0xd3, 0xd3, 0xd3) }, { "LightMagenta", RGB_(0xff, 0xbb, 0xff) }, { "LightPink", RGB_(0xff, 0xb6, 0xc1) }, { "LightPink1", RGB_(0xff, 0xae, 0xb9) }, { "LightPink2", RGB_(0xee, 0xa2, 0xad) }, { "LightPink3", RGB_(0xcd, 0x8c, 0x95) }, { "LightPink4", RGB_(0x8b, 0x5f, 0x65) }, { "LightRed", RGB_(0xff, 0xbb, 0xbb) }, { "LightSalmon", RGB_(0xff, 0xa0, 0x7a) }, { "LightSalmon1", RGB_(0xff, 0xa0, 0x7a) }, { "LightSalmon2", RGB_(0xee, 0x95, 0x72) }, { "LightSalmon3", RGB_(0xcd, 0x81, 0x62) }, { "LightSalmon4", RGB_(0x8b, 0x57, 0x42) }, { "LightSeaGreen", RGB_(0x20, 0xb2, 0xaa) }, { "LightSkyBlue", RGB_(0x87, 0xce, 0xfa) }, { "LightSkyBlue1", RGB_(0xb0, 0xe2, 0xff) }, { "LightSkyBlue2", RGB_(0xa4, 0xd3, 0xee) }, { "LightSkyBlue3", RGB_(0x8d, 0xb6, 0xcd) }, { "LightSkyBlue4", RGB_(0x60, 0x7b, 0x8b) }, { "LightSlateBlue", RGB_(0x84, 0x70, 0xff) }, { "LightSlateGray", RGB_(0x77, 0x88, 0x99) }, { "LightSlateGrey", RGB_(0x77, 0x88, 0x99) }, { "LightSteelBlue", RGB_(0xb0, 0xc4, 0xde) }, { "LightSteelBlue1", RGB_(0xca, 0xe1, 0xff) }, { "LightSteelBlue2", RGB_(0xbc, 0xd2, 0xee) }, { "LightSteelBlue3", RGB_(0xa2, 0xb5, 0xcd) }, { "LightSteelBlue4", RGB_(0x6e, 0x7b, 0x8b) }, { "LightYellow", RGB_(0xff, 0xff, 0xe0) }, { "LightYellow1", RGB_(0xff, 0xff, 0xe0) }, { "LightYellow2", RGB_(0xee, 0xee, 0xd1) }, { "LightYellow3", RGB_(0xcd, 0xcd, 0xb4) }, { "LightYellow4", RGB_(0x8b, 0x8b, 0x7a) }, { "Lime", RGB_(0x00, 0xff, 0x00) }, { "LimeGreen", RGB_(0x32, 0xcd, 0x32) }, { "Linen", RGB_(0xfa, 0xf0, 0xe6) }, { "Magenta", RGB_(0xff, 0x00, 0xff) }, { "Magenta1", RGB_(0xff, 0x0, 0xff) }, { "Magenta2", RGB_(0xee, 0x0, 0xee) }, { "Magenta3", RGB_(0xcd, 0x0, 0xcd) }, { "Magenta4", RGB_(0x8b, 0x0, 0x8b) }, { "Maroon", RGB_(0x80, 0x00, 0x00) }, { "Maroon1", RGB_(0xff, 0x34, 0xb3) }, { "Maroon2", RGB_(0xee, 0x30, 0xa7) }, { "Maroon3", RGB_(0xcd, 0x29, 0x90) }, { "Maroon4", RGB_(0x8b, 0x1c, 0x62) }, { "MediumAquamarine", RGB_(0x66, 0xcd, 0xaa) }, { "MediumBlue", RGB_(0x00, 0x00, 0xcd) }, { "MediumOrchid", RGB_(0xba, 0x55, 0xd3) }, { "MediumOrchid1", RGB_(0xe0, 0x66, 0xff) }, { "MediumOrchid2", RGB_(0xd1, 0x5f, 0xee) }, { "MediumOrchid3", RGB_(0xb4, 0x52, 0xcd) }, { "MediumOrchid4", RGB_(0x7a, 0x37, 0x8b) }, { "MediumPurple", RGB_(0x93, 0x70, 0xdb) }, { "MediumPurple1", RGB_(0xab, 0x82, 0xff) }, { "MediumPurple2", RGB_(0x9f, 0x79, 0xee) }, { "MediumPurple3", RGB_(0x89, 0x68, 0xcd) }, { "MediumPurple4", RGB_(0x5d, 0x47, 0x8b) }, { "MediumSeaGreen", RGB_(0x3c, 0xb3, 0x71) }, { "MediumSlateBlue", RGB_(0x7b, 0x68, 0xee) }, { "MediumSpringGreen", RGB_(0x00, 0xfa, 0x9a) }, { "MediumTurquoise", RGB_(0x48, 0xd1, 0xcc) }, { "MediumVioletRed", RGB_(0xc7, 0x15, 0x85) }, { "MidnightBlue", RGB_(0x19, 0x19, 0x70) }, { "MintCream", RGB_(0xf5, 0xff, 0xfa) }, { "MistyRose", RGB_(0xff, 0xe4, 0xe1) }, { "MistyRose1", RGB_(0xff, 0xe4, 0xe1) }, { "MistyRose2", RGB_(0xee, 0xd5, 0xd2) }, { "MistyRose3", RGB_(0xcd, 0xb7, 0xb5) }, { "MistyRose4", RGB_(0x8b, 0x7d, 0x7b) }, { "Moccasin", RGB_(0xff, 0xe4, 0xb5) }, { "NavajoWhite", RGB_(0xff, 0xde, 0xad) }, { "NavajoWhite1", RGB_(0xff, 0xde, 0xad) }, { "NavajoWhite2", RGB_(0xee, 0xcf, 0xa1) }, { "NavajoWhite3", RGB_(0xcd, 0xb3, 0x8b) }, { "NavajoWhite4", RGB_(0x8b, 0x79, 0x5e) }, { "Navy", RGB_(0x00, 0x00, 0x80) }, { "NavyBlue", RGB_(0x0, 0x0, 0x80) }, { "OldLace", RGB_(0xfd, 0xf5, 0xe6) }, { "Olive", RGB_(0x80, 0x80, 0x00) }, { "OliveDrab", RGB_(0x6b, 0x8e, 0x23) }, { "OliveDrab1", RGB_(0xc0, 0xff, 0x3e) }, { "OliveDrab2", RGB_(0xb3, 0xee, 0x3a) }, { "OliveDrab3", RGB_(0x9a, 0xcd, 0x32) }, { "OliveDrab4", RGB_(0x69, 0x8b, 0x22) }, { "Orange", RGB_(0xff, 0xa5, 0x00) }, { "Orange1", RGB_(0xff, 0xa5, 0x0) }, { "Orange2", RGB_(0xee, 0x9a, 0x0) }, { "Orange3", RGB_(0xcd, 0x85, 0x0) }, { "Orange4", RGB_(0x8b, 0x5a, 0x0) }, { "OrangeRed", RGB_(0xff, 0x45, 0x00) }, { "OrangeRed1", RGB_(0xff, 0x45, 0x0) }, { "OrangeRed2", RGB_(0xee, 0x40, 0x0) }, { "OrangeRed3", RGB_(0xcd, 0x37, 0x0) }, { "OrangeRed4", RGB_(0x8b, 0x25, 0x0) }, { "Orchid", RGB_(0xda, 0x70, 0xd6) }, { "Orchid1", RGB_(0xff, 0x83, 0xfa) }, { "Orchid2", RGB_(0xee, 0x7a, 0xe9) }, { "Orchid3", RGB_(0xcd, 0x69, 0xc9) }, { "Orchid4", RGB_(0x8b, 0x47, 0x89) }, { "PaleGoldenRod", RGB_(0xee, 0xe8, 0xaa) }, { "PaleGreen", RGB_(0x98, 0xfb, 0x98) }, { "PaleGreen1", RGB_(0x9a, 0xff, 0x9a) }, { "PaleGreen2", RGB_(0x90, 0xee, 0x90) }, { "PaleGreen3", RGB_(0x7c, 0xcd, 0x7c) }, { "PaleGreen4", RGB_(0x54, 0x8b, 0x54) }, { "PaleTurquoise", RGB_(0xaf, 0xee, 0xee) }, { "PaleTurquoise1", RGB_(0xbb, 0xff, 0xff) }, { "PaleTurquoise2", RGB_(0xae, 0xee, 0xee) }, { "PaleTurquoise3", RGB_(0x96, 0xcd, 0xcd) }, { "PaleTurquoise4", RGB_(0x66, 0x8b, 0x8b) }, { "PaleVioletRed", RGB_(0xdb, 0x70, 0x93) }, { "PaleVioletRed1", RGB_(0xff, 0x82, 0xab) }, { "PaleVioletRed2", RGB_(0xee, 0x79, 0x9f) }, { "PaleVioletRed3", RGB_(0xcd, 0x68, 0x89) }, { "PaleVioletRed4", RGB_(0x8b, 0x47, 0x5d) }, { "PapayaWhip", RGB_(0xff, 0xef, 0xd5) }, { "PeachPuff", RGB_(0xff, 0xda, 0xb9) }, { "PeachPuff1", RGB_(0xff, 0xda, 0xb9) }, { "PeachPuff2", RGB_(0xee, 0xcb, 0xad) }, { "PeachPuff3", RGB_(0xcd, 0xaf, 0x95) }, { "PeachPuff4", RGB_(0x8b, 0x77, 0x65) }, { "Peru", RGB_(0xcd, 0x85, 0x3f) }, { "Pink", RGB_(0xff, 0xc0, 0xcb) }, { "Pink1", RGB_(0xff, 0xb5, 0xc5) }, { "Pink2", RGB_(0xee, 0xa9, 0xb8) }, { "Pink3", RGB_(0xcd, 0x91, 0x9e) }, { "Pink4", RGB_(0x8b, 0x63, 0x6c) }, { "Plum", RGB_(0xdd, 0xa0, 0xdd) }, { "Plum1", RGB_(0xff, 0xbb, 0xff) }, { "Plum2", RGB_(0xee, 0xae, 0xee) }, { "Plum3", RGB_(0xcd, 0x96, 0xcd) }, { "Plum4", RGB_(0x8b, 0x66, 0x8b) }, { "PowderBlue", RGB_(0xb0, 0xe0, 0xe6) }, { "Purple", RGB_(0x80, 0x00, 0x80) }, { "Purple1", RGB_(0x9b, 0x30, 0xff) }, { "Purple2", RGB_(0x91, 0x2c, 0xee) }, { "Purple3", RGB_(0x7d, 0x26, 0xcd) }, { "Purple4", RGB_(0x55, 0x1a, 0x8b) }, { "RebeccaPurple", RGB_(0x66, 0x33, 0x99) }, { "Red", RGB_(0xff, 0x00, 0x00) }, { "Red1", RGB_(0xff, 0x0, 0x0) }, { "Red2", RGB_(0xee, 0x0, 0x0) }, { "Red3", RGB_(0xcd, 0x0, 0x0) }, { "Red4", RGB_(0x8b, 0x0, 0x0) }, { "RosyBrown", RGB_(0xbc, 0x8f, 0x8f) }, { "RosyBrown1", RGB_(0xff, 0xc1, 0xc1) }, { "RosyBrown2", RGB_(0xee, 0xb4, 0xb4) }, { "RosyBrown3", RGB_(0xcd, 0x9b, 0x9b) }, { "RosyBrown4", RGB_(0x8b, 0x69, 0x69) }, { "RoyalBlue", RGB_(0x41, 0x69, 0xe1) }, { "RoyalBlue1", RGB_(0x48, 0x76, 0xff) }, { "RoyalBlue2", RGB_(0x43, 0x6e, 0xee) }, { "RoyalBlue3", RGB_(0x3a, 0x5f, 0xcd) }, { "RoyalBlue4", RGB_(0x27, 0x40, 0x8b) }, { "SaddleBrown", RGB_(0x8b, 0x45, 0x13) }, { "Salmon", RGB_(0xfa, 0x80, 0x72) }, { "Salmon1", RGB_(0xff, 0x8c, 0x69) }, { "Salmon2", RGB_(0xee, 0x82, 0x62) }, { "Salmon3", RGB_(0xcd, 0x70, 0x54) }, { "Salmon4", RGB_(0x8b, 0x4c, 0x39) }, { "SandyBrown", RGB_(0xf4, 0xa4, 0x60) }, { "SeaGreen", RGB_(0x2e, 0x8b, 0x57) }, { "SeaGreen1", RGB_(0x54, 0xff, 0x9f) }, { "SeaGreen2", RGB_(0x4e, 0xee, 0x94) }, { "SeaGreen3", RGB_(0x43, 0xcd, 0x80) }, { "SeaGreen4", RGB_(0x2e, 0x8b, 0x57) }, { "SeaShell", RGB_(0xff, 0xf5, 0xee) }, { "Seashell1", RGB_(0xff, 0xf5, 0xee) }, { "Seashell2", RGB_(0xee, 0xe5, 0xde) }, { "Seashell3", RGB_(0xcd, 0xc5, 0xbf) }, { "Seashell4", RGB_(0x8b, 0x86, 0x82) }, { "Sienna", RGB_(0xa0, 0x52, 0x2d) }, { "Sienna1", RGB_(0xff, 0x82, 0x47) }, { "Sienna2", RGB_(0xee, 0x79, 0x42) }, { "Sienna3", RGB_(0xcd, 0x68, 0x39) }, { "Sienna4", RGB_(0x8b, 0x47, 0x26) }, { "Silver", RGB_(0xc0, 0xc0, 0xc0) }, { "SkyBlue", RGB_(0x87, 0xce, 0xeb) }, { "SkyBlue1", RGB_(0x87, 0xce, 0xff) }, { "SkyBlue2", RGB_(0x7e, 0xc0, 0xee) }, { "SkyBlue3", RGB_(0x6c, 0xa6, 0xcd) }, { "SkyBlue4", RGB_(0x4a, 0x70, 0x8b) }, { "SlateBlue", RGB_(0x6a, 0x5a, 0xcd) }, { "SlateBlue1", RGB_(0x83, 0x6f, 0xff) }, { "SlateBlue2", RGB_(0x7a, 0x67, 0xee) }, { "SlateBlue3", RGB_(0x69, 0x59, 0xcd) }, { "SlateBlue4", RGB_(0x47, 0x3c, 0x8b) }, { "SlateGray", RGB_(0x70, 0x80, 0x90) }, { "SlateGray1", RGB_(0xc6, 0xe2, 0xff) }, { "SlateGray2", RGB_(0xb9, 0xd3, 0xee) }, { "SlateGray3", RGB_(0x9f, 0xb6, 0xcd) }, { "SlateGray4", RGB_(0x6c, 0x7b, 0x8b) }, { "SlateGrey", RGB_(0x70, 0x80, 0x90) }, { "Snow", RGB_(0xff, 0xfa, 0xfa) }, { "Snow1", RGB_(0xff, 0xfa, 0xfa) }, { "Snow2", RGB_(0xee, 0xe9, 0xe9) }, { "Snow3", RGB_(0xcd, 0xc9, 0xc9) }, { "Snow4", RGB_(0x8b, 0x89, 0x89) }, { "SpringGreen", RGB_(0x00, 0xff, 0x7f) }, { "SpringGreen1", RGB_(0x0, 0xff, 0x7f) }, { "SpringGreen2", RGB_(0x0, 0xee, 0x76) }, { "SpringGreen3", RGB_(0x0, 0xcd, 0x66) }, { "SpringGreen4", RGB_(0x0, 0x8b, 0x45) }, { "SteelBlue", RGB_(0x46, 0x82, 0xb4) }, { "SteelBlue1", RGB_(0x63, 0xb8, 0xff) }, { "SteelBlue2", RGB_(0x5c, 0xac, 0xee) }, { "SteelBlue3", RGB_(0x4f, 0x94, 0xcd) }, { "SteelBlue4", RGB_(0x36, 0x64, 0x8b) }, { "Tan", RGB_(0xd2, 0xb4, 0x8c) }, { "Tan1", RGB_(0xff, 0xa5, 0x4f) }, { "Tan2", RGB_(0xee, 0x9a, 0x49) }, { "Tan3", RGB_(0xcd, 0x85, 0x3f) }, { "Tan4", RGB_(0x8b, 0x5a, 0x2b) }, { "Teal", RGB_(0x00, 0x80, 0x80) }, { "Thistle", RGB_(0xd8, 0xbf, 0xd8) }, { "Thistle1", RGB_(0xff, 0xe1, 0xff) }, { "Thistle2", RGB_(0xee, 0xd2, 0xee) }, { "Thistle3", RGB_(0xcd, 0xb5, 0xcd) }, { "Thistle4", RGB_(0x8b, 0x7b, 0x8b) }, { "Tomato", RGB_(0xff, 0x63, 0x47) }, { "Tomato1", RGB_(0xff, 0x63, 0x47) }, { "Tomato2", RGB_(0xee, 0x5c, 0x42) }, { "Tomato3", RGB_(0xcd, 0x4f, 0x39) }, { "Tomato4", RGB_(0x8b, 0x36, 0x26) }, { "Turquoise", RGB_(0x40, 0xe0, 0xd0) }, { "Turquoise1", RGB_(0x0, 0xf5, 0xff) }, { "Turquoise2", RGB_(0x0, 0xe5, 0xee) }, { "Turquoise3", RGB_(0x0, 0xc5, 0xcd) }, { "Turquoise4", RGB_(0x0, 0x86, 0x8b) }, { "Violet", RGB_(0xee, 0x82, 0xee) }, { "VioletRed", RGB_(0xd0, 0x20, 0x90) }, { "VioletRed1", RGB_(0xff, 0x3e, 0x96) }, { "VioletRed2", RGB_(0xee, 0x3a, 0x8c) }, { "VioletRed3", RGB_(0xcd, 0x32, 0x78) }, { "VioletRed4", RGB_(0x8b, 0x22, 0x52) }, { "WebGray", RGB_(0x80, 0x80, 0x80) }, { "WebGreen", RGB_(0x0, 0x80, 0x0) }, { "WebGrey", RGB_(0x80, 0x80, 0x80) }, { "WebMaroon", RGB_(0x80, 0x0, 0x0) }, { "WebPurple", RGB_(0x80, 0x0, 0x80) }, { "Wheat", RGB_(0xf5, 0xde, 0xb3) }, { "Wheat1", RGB_(0xff, 0xe7, 0xba) }, { "Wheat2", RGB_(0xee, 0xd8, 0xae) }, { "Wheat3", RGB_(0xcd, 0xba, 0x96) }, { "Wheat4", RGB_(0x8b, 0x7e, 0x66) }, { "White", RGB_(0xff, 0xff, 0xff) }, { "WhiteSmoke", RGB_(0xf5, 0xf5, 0xf5) }, { "X11Gray", RGB_(0xbe, 0xbe, 0xbe) }, { "X11Green", RGB_(0x0, 0xff, 0x0) }, { "X11Grey", RGB_(0xbe, 0xbe, 0xbe) }, { "X11Maroon", RGB_(0xb0, 0x30, 0x60) }, { "X11Purple", RGB_(0xa0, 0x20, 0xf0) }, { "Yellow", RGB_(0xff, 0xff, 0x00) }, { "Yellow1", RGB_(0xff, 0xff, 0x0) }, { "Yellow2", RGB_(0xee, 0xee, 0x0) }, { "Yellow3", RGB_(0xcd, 0xcd, 0x0) }, { "Yellow4", RGB_(0x8b, 0x8b, 0x0) }, { "YellowGreen", RGB_(0x9a, 0xcd, 0x32) }, { NULL, 0 }, }; /// Translate to RgbValue if \p name is an hex value (e.g. #XXXXXX), /// else look into color_name_table to translate a color name to its /// hex value /// /// @param[in] name string value to convert to RGB /// @param[out] idx index in color table or special value /// return the hex value or -1 if could not find a correct value RgbValue name_to_color(const char *name, int *idx) { if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2]) && isxdigit(name[3]) && isxdigit(name[4]) && isxdigit(name[5]) && isxdigit(name[6]) && name[7] == NUL) { // rgb hex string *idx = kColorIdxHex; return (RgbValue)strtol((char *)(name + 1), NULL, 16); } else if (!STRICMP(name, "bg") || !STRICMP(name, "background")) { *idx = kColorIdxBg; return normal_bg; } else if (!STRICMP(name, "fg") || !STRICMP(name, "foreground")) { *idx = kColorIdxFg; return normal_fg; } int lo = 0; int hi = ARRAY_SIZE(color_name_table) - 1; // don't count NULL element while (lo < hi) { int m = (lo + hi) / 2; int cmp = STRICMP(name, color_name_table[m].name); if (cmp < 0) { hi = m; } else if (cmp > 0) { lo = m + 1; } else { // found match *idx = m; return color_name_table[m].color; break; } } *idx = kColorIdxNone; return -1; } const char *coloridx_to_name(int idx, int val, char hexbuf[8]) { if (idx >= 0) { return color_name_table[idx].name; } switch (idx) { case kColorIdxNone: return NULL; case kColorIdxFg: return "fg"; case kColorIdxBg: return "bg"; case kColorIdxHex: snprintf(hexbuf, 7 + 1, "#%06x", val); return hexbuf; default: abort(); } } int name_to_ctermcolor(const char *name) { int i; int off = TOUPPER_ASC(*name); for (i = ARRAY_SIZE(color_names); --i >= 0;) { if (off == color_names[i][0] && STRICMP(name + 1, color_names[i] + 1) == 0) { break; } } if (i < 0) { return -1; } TriState bold = kNone; return lookup_color(i, false, &bold); }