1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * Highlighting stuff. 12 */ 13 14 #include "vim.h" 15 16 #define SG_TERM 1 // term has been set 17 #define SG_CTERM 2 // cterm has been set 18 #define SG_GUI 4 // gui has been set 19 #define SG_LINK 8 // link has been set 20 21 /* 22 * The "term", "cterm" and "gui" arguments can be any combination of the 23 * following names, separated by commas (but no spaces!). 24 */ 25 static char *(hl_name_table[]) = 26 {"bold", "standout", "underline", "undercurl", 27 "italic", "reverse", "inverse", "nocombine", "strikethrough", "NONE"}; 28 static int hl_attr_table[] = 29 {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_NOCOMBINE, HL_STRIKETHROUGH, 0}; 30 #define ATTR_COMBINE(attr_a, attr_b) ((((attr_b) & HL_NOCOMBINE) ? attr_b : (attr_a)) | (attr_b)) 31 32 /* 33 * Structure that stores information about a highlight group. 34 * The ID of a highlight group is also called group ID. It is the index in 35 * the highlight_ga array PLUS ONE. 36 */ 37 typedef struct 38 { 39 char_u *sg_name; // highlight group name 40 char_u *sg_name_u; // uppercase of sg_name 41 int sg_cleared; // "hi clear" was used 42 // for normal terminals 43 int sg_term; // "term=" highlighting attributes 44 char_u *sg_start; // terminal string for start highl 45 char_u *sg_stop; // terminal string for stop highl 46 int sg_term_attr; // Screen attr for term mode 47 // for color terminals 48 int sg_cterm; // "cterm=" highlighting attr 49 int sg_cterm_bold; // bold attr was set for light color 50 int sg_cterm_fg; // terminal fg color number + 1 51 int sg_cterm_bg; // terminal bg color number + 1 52 int sg_cterm_ul; // terminal ul color number + 1 53 int sg_cterm_attr; // Screen attr for color term mode 54 // for when using the GUI 55 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 56 guicolor_T sg_gui_fg; // GUI foreground color handle 57 guicolor_T sg_gui_bg; // GUI background color handle 58 guicolor_T sg_gui_sp; // GUI special color handle 59 #endif 60 #ifdef FEAT_GUI 61 GuiFont sg_font; // GUI font handle 62 #ifdef FEAT_XFONTSET 63 GuiFontset sg_fontset; // GUI fontset handle 64 #endif 65 char_u *sg_font_name; // GUI font or fontset name 66 int sg_gui_attr; // Screen attr for GUI mode 67 #endif 68 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 69 // Store the sp color name for the GUI or synIDattr() 70 int sg_gui; // "gui=" highlighting attributes 71 char_u *sg_gui_fg_name;// GUI foreground color name 72 char_u *sg_gui_bg_name;// GUI background color name 73 char_u *sg_gui_sp_name;// GUI special color name 74 #endif 75 int sg_link; // link to this highlight group ID 76 int sg_deflink; // default link; restored in highlight_clear() 77 int sg_set; // combination of SG_* flags 78 #ifdef FEAT_EVAL 79 sctx_T sg_deflink_sctx; // script where the default link was set 80 sctx_T sg_script_ctx; // script in which the group was last set 81 #endif 82 } hl_group_T; 83 84 // highlight groups for 'highlight' option 85 static garray_T highlight_ga; 86 #define HL_TABLE() ((hl_group_T *)((highlight_ga.ga_data))) 87 88 /* 89 * An attribute number is the index in attr_table plus ATTR_OFF. 90 */ 91 #define ATTR_OFF (HL_ALL + 1) 92 93 static void syn_unadd_group(void); 94 static void set_hl_attr(int idx); 95 static void highlight_list_one(int id); 96 static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg, char *name); 97 static int syn_add_group(char_u *name); 98 static int hl_has_settings(int idx, int check_link); 99 static void highlight_clear(int idx); 100 101 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 102 static void gui_do_one_color(int idx, int do_menu, int do_tooltip); 103 #endif 104 #ifdef FEAT_GUI 105 static int set_group_colors(char_u *name, guicolor_T *fgp, guicolor_T *bgp, int do_menu, int use_norm, int do_tooltip); 106 static void hl_do_font(int idx, char_u *arg, int do_normal, int do_menu, int do_tooltip, int free_font); 107 #endif 108 109 /* 110 * The default highlight groups. These are compiled-in for fast startup and 111 * they still work when the runtime files can't be found. 112 * When making changes here, also change runtime/colors/default.vim! 113 * The #ifdefs are needed to reduce the amount of static data. Helps to make 114 * the 16 bit DOS (museum) version compile. 115 */ 116 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 117 # define CENT(a, b) b 118 #else 119 # define CENT(a, b) a 120 #endif 121 static char *(highlight_init_both[]) = { 122 CENT("ErrorMsg term=standout ctermbg=DarkRed ctermfg=White", 123 "ErrorMsg term=standout ctermbg=DarkRed ctermfg=White guibg=Red guifg=White"), 124 CENT("IncSearch term=reverse cterm=reverse", 125 "IncSearch term=reverse cterm=reverse gui=reverse"), 126 CENT("ModeMsg term=bold cterm=bold", 127 "ModeMsg term=bold cterm=bold gui=bold"), 128 CENT("NonText term=bold ctermfg=Blue", 129 "NonText term=bold ctermfg=Blue gui=bold guifg=Blue"), 130 CENT("StatusLine term=reverse,bold cterm=reverse,bold", 131 "StatusLine term=reverse,bold cterm=reverse,bold gui=reverse,bold"), 132 CENT("StatusLineNC term=reverse cterm=reverse", 133 "StatusLineNC term=reverse cterm=reverse gui=reverse"), 134 "default link EndOfBuffer NonText", 135 CENT("VertSplit term=reverse cterm=reverse", 136 "VertSplit term=reverse cterm=reverse gui=reverse"), 137 #ifdef FEAT_CLIPBOARD 138 CENT("VisualNOS term=underline,bold cterm=underline,bold", 139 "VisualNOS term=underline,bold cterm=underline,bold gui=underline,bold"), 140 #endif 141 #ifdef FEAT_DIFF 142 CENT("DiffText term=reverse cterm=bold ctermbg=Red", 143 "DiffText term=reverse cterm=bold ctermbg=Red gui=bold guibg=Red"), 144 #endif 145 CENT("PmenuSbar ctermbg=Grey", 146 "PmenuSbar ctermbg=Grey guibg=Grey"), 147 CENT("TabLineSel term=bold cterm=bold", 148 "TabLineSel term=bold cterm=bold gui=bold"), 149 CENT("TabLineFill term=reverse cterm=reverse", 150 "TabLineFill term=reverse cterm=reverse gui=reverse"), 151 #ifdef FEAT_GUI 152 "Cursor guibg=fg guifg=bg", 153 "lCursor guibg=fg guifg=bg", // should be different, but what? 154 #endif 155 "default link QuickFixLine Search", 156 CENT("Normal cterm=NONE", "Normal gui=NONE"), 157 NULL 158 }; 159 160 // Default colors only used with a light background. 161 static char *(highlight_init_light[]) = { 162 CENT("Directory term=bold ctermfg=DarkBlue", 163 "Directory term=bold ctermfg=DarkBlue guifg=Blue"), 164 CENT("LineNr term=underline ctermfg=Brown", 165 "LineNr term=underline ctermfg=Brown guifg=Brown"), 166 CENT("CursorLineNr term=bold cterm=underline ctermfg=Brown", 167 "CursorLineNr term=bold cterm=underline ctermfg=Brown gui=bold guifg=Brown"), 168 CENT("MoreMsg term=bold ctermfg=DarkGreen", 169 "MoreMsg term=bold ctermfg=DarkGreen gui=bold guifg=SeaGreen"), 170 CENT("Question term=standout ctermfg=DarkGreen", 171 "Question term=standout ctermfg=DarkGreen gui=bold guifg=SeaGreen"), 172 CENT("Search term=reverse ctermbg=Yellow ctermfg=NONE", 173 "Search term=reverse ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE"), 174 #ifdef FEAT_SPELL 175 CENT("SpellBad term=reverse ctermbg=LightRed", 176 "SpellBad term=reverse ctermbg=LightRed guisp=Red gui=undercurl"), 177 CENT("SpellCap term=reverse ctermbg=LightBlue", 178 "SpellCap term=reverse ctermbg=LightBlue guisp=Blue gui=undercurl"), 179 CENT("SpellRare term=reverse ctermbg=LightMagenta", 180 "SpellRare term=reverse ctermbg=LightMagenta guisp=Magenta gui=undercurl"), 181 CENT("SpellLocal term=underline ctermbg=Cyan", 182 "SpellLocal term=underline ctermbg=Cyan guisp=DarkCyan gui=undercurl"), 183 #endif 184 CENT("PmenuThumb ctermbg=Black", 185 "PmenuThumb ctermbg=Black guibg=Black"), 186 CENT("Pmenu ctermbg=LightMagenta ctermfg=Black", 187 "Pmenu ctermbg=LightMagenta ctermfg=Black guibg=LightMagenta"), 188 CENT("PmenuSel ctermbg=LightGrey ctermfg=Black", 189 "PmenuSel ctermbg=LightGrey ctermfg=Black guibg=Grey"), 190 CENT("SpecialKey term=bold ctermfg=DarkBlue", 191 "SpecialKey term=bold ctermfg=DarkBlue guifg=Blue"), 192 CENT("Title term=bold ctermfg=DarkMagenta", 193 "Title term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta"), 194 CENT("WarningMsg term=standout ctermfg=DarkRed", 195 "WarningMsg term=standout ctermfg=DarkRed guifg=Red"), 196 #ifdef FEAT_WILDMENU 197 CENT("WildMenu term=standout ctermbg=Yellow ctermfg=Black", 198 "WildMenu term=standout ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"), 199 #endif 200 #ifdef FEAT_FOLDING 201 CENT("Folded term=standout ctermbg=Grey ctermfg=DarkBlue", 202 "Folded term=standout ctermbg=Grey ctermfg=DarkBlue guibg=LightGrey guifg=DarkBlue"), 203 CENT("FoldColumn term=standout ctermbg=Grey ctermfg=DarkBlue", 204 "FoldColumn term=standout ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue"), 205 #endif 206 #ifdef FEAT_SIGNS 207 CENT("SignColumn term=standout ctermbg=Grey ctermfg=DarkBlue", 208 "SignColumn term=standout ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue"), 209 #endif 210 CENT("Visual term=reverse", 211 "Visual term=reverse guibg=LightGrey"), 212 #ifdef FEAT_DIFF 213 CENT("DiffAdd term=bold ctermbg=LightBlue", 214 "DiffAdd term=bold ctermbg=LightBlue guibg=LightBlue"), 215 CENT("DiffChange term=bold ctermbg=LightMagenta", 216 "DiffChange term=bold ctermbg=LightMagenta guibg=LightMagenta"), 217 CENT("DiffDelete term=bold ctermfg=Blue ctermbg=LightCyan", 218 "DiffDelete term=bold ctermfg=Blue ctermbg=LightCyan gui=bold guifg=Blue guibg=LightCyan"), 219 #endif 220 CENT("TabLine term=underline cterm=underline ctermfg=black ctermbg=LightGrey", 221 "TabLine term=underline cterm=underline ctermfg=black ctermbg=LightGrey gui=underline guibg=LightGrey"), 222 #ifdef FEAT_SYN_HL 223 CENT("CursorColumn term=reverse ctermbg=LightGrey", 224 "CursorColumn term=reverse ctermbg=LightGrey guibg=Grey90"), 225 CENT("CursorLine term=underline cterm=underline", 226 "CursorLine term=underline cterm=underline guibg=Grey90"), 227 CENT("ColorColumn term=reverse ctermbg=LightRed", 228 "ColorColumn term=reverse ctermbg=LightRed guibg=LightRed"), 229 #endif 230 #ifdef FEAT_CONCEAL 231 CENT("Conceal ctermbg=DarkGrey ctermfg=LightGrey", 232 "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey"), 233 #endif 234 CENT("MatchParen term=reverse ctermbg=Cyan", 235 "MatchParen term=reverse ctermbg=Cyan guibg=Cyan"), 236 #ifdef FEAT_TERMINAL 237 CENT("StatusLineTerm term=reverse,bold cterm=bold ctermfg=White ctermbg=DarkGreen", 238 "StatusLineTerm term=reverse,bold cterm=bold ctermfg=White ctermbg=DarkGreen gui=bold guifg=bg guibg=DarkGreen"), 239 CENT("StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen", 240 "StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen guifg=bg guibg=DarkGreen"), 241 #endif 242 #ifdef FEAT_MENU 243 CENT("ToolbarLine term=underline ctermbg=LightGrey", 244 "ToolbarLine term=underline ctermbg=LightGrey guibg=LightGrey"), 245 CENT("ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey", 246 "ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey gui=bold guifg=White guibg=Grey40"), 247 #endif 248 NULL 249 }; 250 251 // Default colors only used with a dark background. 252 static char *(highlight_init_dark[]) = { 253 CENT("Directory term=bold ctermfg=LightCyan", 254 "Directory term=bold ctermfg=LightCyan guifg=Cyan"), 255 CENT("LineNr term=underline ctermfg=Yellow", 256 "LineNr term=underline ctermfg=Yellow guifg=Yellow"), 257 CENT("CursorLineNr term=bold cterm=underline ctermfg=Yellow", 258 "CursorLineNr term=bold cterm=underline ctermfg=Yellow gui=bold guifg=Yellow"), 259 CENT("MoreMsg term=bold ctermfg=LightGreen", 260 "MoreMsg term=bold ctermfg=LightGreen gui=bold guifg=SeaGreen"), 261 CENT("Question term=standout ctermfg=LightGreen", 262 "Question term=standout ctermfg=LightGreen gui=bold guifg=Green"), 263 CENT("Search term=reverse ctermbg=Yellow ctermfg=Black", 264 "Search term=reverse ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"), 265 CENT("SpecialKey term=bold ctermfg=LightBlue", 266 "SpecialKey term=bold ctermfg=LightBlue guifg=Cyan"), 267 #ifdef FEAT_SPELL 268 CENT("SpellBad term=reverse ctermbg=Red", 269 "SpellBad term=reverse ctermbg=Red guisp=Red gui=undercurl"), 270 CENT("SpellCap term=reverse ctermbg=Blue", 271 "SpellCap term=reverse ctermbg=Blue guisp=Blue gui=undercurl"), 272 CENT("SpellRare term=reverse ctermbg=Magenta", 273 "SpellRare term=reverse ctermbg=Magenta guisp=Magenta gui=undercurl"), 274 CENT("SpellLocal term=underline ctermbg=Cyan", 275 "SpellLocal term=underline ctermbg=Cyan guisp=Cyan gui=undercurl"), 276 #endif 277 CENT("PmenuThumb ctermbg=White", 278 "PmenuThumb ctermbg=White guibg=White"), 279 CENT("Pmenu ctermbg=Magenta ctermfg=Black", 280 "Pmenu ctermbg=Magenta ctermfg=Black guibg=Magenta"), 281 CENT("PmenuSel ctermbg=Black ctermfg=DarkGrey", 282 "PmenuSel ctermbg=Black ctermfg=DarkGrey guibg=DarkGrey"), 283 CENT("Title term=bold ctermfg=LightMagenta", 284 "Title term=bold ctermfg=LightMagenta gui=bold guifg=Magenta"), 285 CENT("WarningMsg term=standout ctermfg=LightRed", 286 "WarningMsg term=standout ctermfg=LightRed guifg=Red"), 287 #ifdef FEAT_WILDMENU 288 CENT("WildMenu term=standout ctermbg=Yellow ctermfg=Black", 289 "WildMenu term=standout ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"), 290 #endif 291 #ifdef FEAT_FOLDING 292 CENT("Folded term=standout ctermbg=DarkGrey ctermfg=Cyan", 293 "Folded term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=DarkGrey guifg=Cyan"), 294 CENT("FoldColumn term=standout ctermbg=DarkGrey ctermfg=Cyan", 295 "FoldColumn term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan"), 296 #endif 297 #ifdef FEAT_SIGNS 298 CENT("SignColumn term=standout ctermbg=DarkGrey ctermfg=Cyan", 299 "SignColumn term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan"), 300 #endif 301 CENT("Visual term=reverse", 302 "Visual term=reverse guibg=DarkGrey"), 303 #ifdef FEAT_DIFF 304 CENT("DiffAdd term=bold ctermbg=DarkBlue", 305 "DiffAdd term=bold ctermbg=DarkBlue guibg=DarkBlue"), 306 CENT("DiffChange term=bold ctermbg=DarkMagenta", 307 "DiffChange term=bold ctermbg=DarkMagenta guibg=DarkMagenta"), 308 CENT("DiffDelete term=bold ctermfg=Blue ctermbg=DarkCyan", 309 "DiffDelete term=bold ctermfg=Blue ctermbg=DarkCyan gui=bold guifg=Blue guibg=DarkCyan"), 310 #endif 311 CENT("TabLine term=underline cterm=underline ctermfg=white ctermbg=DarkGrey", 312 "TabLine term=underline cterm=underline ctermfg=white ctermbg=DarkGrey gui=underline guibg=DarkGrey"), 313 #ifdef FEAT_SYN_HL 314 CENT("CursorColumn term=reverse ctermbg=DarkGrey", 315 "CursorColumn term=reverse ctermbg=DarkGrey guibg=Grey40"), 316 CENT("CursorLine term=underline cterm=underline", 317 "CursorLine term=underline cterm=underline guibg=Grey40"), 318 CENT("ColorColumn term=reverse ctermbg=DarkRed", 319 "ColorColumn term=reverse ctermbg=DarkRed guibg=DarkRed"), 320 #endif 321 CENT("MatchParen term=reverse ctermbg=DarkCyan", 322 "MatchParen term=reverse ctermbg=DarkCyan guibg=DarkCyan"), 323 #ifdef FEAT_CONCEAL 324 CENT("Conceal ctermbg=DarkGrey ctermfg=LightGrey", 325 "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey"), 326 #endif 327 #ifdef FEAT_TERMINAL 328 CENT("StatusLineTerm term=reverse,bold cterm=bold ctermfg=Black ctermbg=LightGreen", 329 "StatusLineTerm term=reverse,bold cterm=bold ctermfg=Black ctermbg=LightGreen gui=bold guifg=bg guibg=LightGreen"), 330 CENT("StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen", 331 "StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen guifg=bg guibg=LightGreen"), 332 #endif 333 #ifdef FEAT_MENU 334 CENT("ToolbarLine term=underline ctermbg=DarkGrey", 335 "ToolbarLine term=underline ctermbg=DarkGrey guibg=Grey50"), 336 CENT("ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey", 337 "ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey gui=bold guifg=Black guibg=LightGrey"), 338 #endif 339 NULL 340 }; 341 342 /* 343 * Returns the number of highlight groups. 344 */ 345 int 346 highlight_num_groups(void) 347 { 348 return highlight_ga.ga_len; 349 } 350 351 /* 352 * Returns the name of a highlight group. 353 */ 354 char_u * 355 highlight_group_name(int id) 356 { 357 return HL_TABLE()[id].sg_name; 358 } 359 360 /* 361 * Returns the ID of the link to a highlight group. 362 */ 363 int 364 highlight_link_id(int id) 365 { 366 return HL_TABLE()[id].sg_link; 367 } 368 369 void 370 init_highlight( 371 int both, // include groups where 'bg' doesn't matter 372 int reset) // clear group first 373 { 374 int i; 375 char **pp; 376 static int had_both = FALSE; 377 #ifdef FEAT_EVAL 378 char_u *p; 379 380 /* 381 * Try finding the color scheme file. Used when a color file was loaded 382 * and 'background' or 't_Co' is changed. 383 */ 384 p = get_var_value((char_u *)"g:colors_name"); 385 if (p != NULL) 386 { 387 // The value of g:colors_name could be freed when sourcing the script, 388 // making "p" invalid, so copy it. 389 char_u *copy_p = vim_strsave(p); 390 int r; 391 392 if (copy_p != NULL) 393 { 394 r = load_colors(copy_p); 395 vim_free(copy_p); 396 if (r == OK) 397 return; 398 } 399 } 400 401 #endif 402 403 /* 404 * Didn't use a color file, use the compiled-in colors. 405 */ 406 if (both) 407 { 408 had_both = TRUE; 409 pp = highlight_init_both; 410 for (i = 0; pp[i] != NULL; ++i) 411 do_highlight((char_u *)pp[i], reset, TRUE); 412 } 413 else if (!had_both) 414 // Don't do anything before the call with both == TRUE from main(). 415 // Not everything has been setup then, and that call will overrule 416 // everything anyway. 417 return; 418 419 if (*p_bg == 'l') 420 pp = highlight_init_light; 421 else 422 pp = highlight_init_dark; 423 for (i = 0; pp[i] != NULL; ++i) 424 do_highlight((char_u *)pp[i], reset, TRUE); 425 426 // Reverse looks ugly, but grey may not work for 8 colors. Thus let it 427 // depend on the number of colors available. 428 // With 8 colors brown is equal to yellow, need to use black for Search fg 429 // to avoid Statement highlighted text disappears. 430 // Clear the attributes, needed when changing the t_Co value. 431 if (t_colors > 8) 432 do_highlight((char_u *)(*p_bg == 'l' 433 ? "Visual cterm=NONE ctermbg=LightGrey" 434 : "Visual cterm=NONE ctermbg=DarkGrey"), FALSE, TRUE); 435 else 436 { 437 do_highlight((char_u *)"Visual cterm=reverse ctermbg=NONE", 438 FALSE, TRUE); 439 if (*p_bg == 'l') 440 do_highlight((char_u *)"Search ctermfg=black", FALSE, TRUE); 441 } 442 443 #ifdef FEAT_SYN_HL 444 /* 445 * If syntax highlighting is enabled load the highlighting for it. 446 */ 447 if (get_var_value((char_u *)"g:syntax_on") != NULL) 448 { 449 static int recursive = 0; 450 451 if (recursive >= 5) 452 emsg(_("E679: recursive loop loading syncolor.vim")); 453 else 454 { 455 ++recursive; 456 (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL); 457 --recursive; 458 } 459 } 460 #endif 461 } 462 463 /* 464 * Load color file "name". 465 * Return OK for success, FAIL for failure. 466 */ 467 int 468 load_colors(char_u *name) 469 { 470 char_u *buf; 471 int retval = FAIL; 472 static int recursive = FALSE; 473 474 // When being called recursively, this is probably because setting 475 // 'background' caused the highlighting to be reloaded. This means it is 476 // working, thus we should return OK. 477 if (recursive) 478 return OK; 479 480 recursive = TRUE; 481 buf = alloc(STRLEN(name) + 12); 482 if (buf != NULL) 483 { 484 apply_autocmds(EVENT_COLORSCHEMEPRE, name, 485 curbuf->b_fname, FALSE, curbuf); 486 sprintf((char *)buf, "colors/%s.vim", name); 487 retval = source_runtime(buf, DIP_START + DIP_OPT); 488 vim_free(buf); 489 apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf); 490 } 491 recursive = FALSE; 492 493 return retval; 494 } 495 496 static char *(color_names[28]) = { 497 "Black", "DarkBlue", "DarkGreen", "DarkCyan", 498 "DarkRed", "DarkMagenta", "Brown", "DarkYellow", 499 "Gray", "Grey", "LightGray", "LightGrey", 500 "DarkGray", "DarkGrey", 501 "Blue", "LightBlue", "Green", "LightGreen", 502 "Cyan", "LightCyan", "Red", "LightRed", "Magenta", 503 "LightMagenta", "Yellow", "LightYellow", "White", "NONE"}; 504 // indices: 505 // 0, 1, 2, 3, 506 // 4, 5, 6, 7, 507 // 8, 9, 10, 11, 508 // 12, 13, 509 // 14, 15, 16, 17, 510 // 18, 19, 20, 21, 22, 511 // 23, 24, 25, 26, 27 512 static int color_numbers_16[28] = {0, 1, 2, 3, 513 4, 5, 6, 6, 514 7, 7, 7, 7, 515 8, 8, 516 9, 9, 10, 10, 517 11, 11, 12, 12, 13, 518 13, 14, 14, 15, -1}; 519 // for xterm with 88 colors... 520 static int color_numbers_88[28] = {0, 4, 2, 6, 521 1, 5, 32, 72, 522 84, 84, 7, 7, 523 82, 82, 524 12, 43, 10, 61, 525 14, 63, 9, 74, 13, 526 75, 11, 78, 15, -1}; 527 // for xterm with 256 colors... 528 static int color_numbers_256[28] = {0, 4, 2, 6, 529 1, 5, 130, 3, 530 248, 248, 7, 7, 531 242, 242, 532 12, 81, 10, 121, 533 14, 159, 9, 224, 13, 534 225, 11, 229, 15, -1}; 535 // for terminals with less than 16 colors... 536 static int color_numbers_8[28] = {0, 4, 2, 6, 537 1, 5, 3, 3, 538 7, 7, 7, 7, 539 0+8, 0+8, 540 4+8, 4+8, 2+8, 2+8, 541 6+8, 6+8, 1+8, 1+8, 5+8, 542 5+8, 3+8, 3+8, 7+8, -1}; 543 544 /* 545 * Lookup the "cterm" value to be used for color with index "idx" in 546 * color_names[]. 547 * "boldp" will be set to TRUE or FALSE for a foreground color when using 8 548 * colors, otherwise it will be unchanged. 549 */ 550 int 551 lookup_color(int idx, int foreground, int *boldp) 552 { 553 int color = color_numbers_16[idx]; 554 char_u *p; 555 556 // Use the _16 table to check if it's a valid color name. 557 if (color < 0) 558 return -1; 559 560 if (t_colors == 8) 561 { 562 // t_Co is 8: use the 8 colors table 563 #if defined(__QNXNTO__) 564 // On qnx, the 8 & 16 color arrays are the same 565 if (STRNCMP(T_NAME, "qansi", 5) == 0) 566 color = color_numbers_16[idx]; 567 else 568 #endif 569 color = color_numbers_8[idx]; 570 if (foreground) 571 { 572 // set/reset bold attribute to get light foreground 573 // colors (on some terminals, e.g. "linux") 574 if (color & 8) 575 *boldp = TRUE; 576 else 577 *boldp = FALSE; 578 } 579 color &= 7; // truncate to 8 colors 580 } 581 else if (t_colors == 16 || t_colors == 88 582 || t_colors >= 256) 583 { 584 /* 585 * Guess: if the termcap entry ends in 'm', it is 586 * probably an xterm-like terminal. Use the changed 587 * order for colors. 588 */ 589 if (*T_CAF != NUL) 590 p = T_CAF; 591 else 592 p = T_CSF; 593 if (*p != NUL && (t_colors > 256 594 || *(p + STRLEN(p) - 1) == 'm')) 595 { 596 if (t_colors == 88) 597 color = color_numbers_88[idx]; 598 else if (t_colors >= 256) 599 color = color_numbers_256[idx]; 600 else 601 color = color_numbers_8[idx]; 602 } 603 #ifdef FEAT_TERMRESPONSE 604 if (t_colors >= 256 && color == 15 && is_mac_terminal) 605 // Terminal.app has a bug: 15 is light grey. Use white 606 // from the color cube instead. 607 color = 231; 608 #endif 609 } 610 return color; 611 } 612 613 /* 614 * Handle the ":highlight .." command. 615 * When using ":hi clear" this is called recursively for each group with 616 * "forceit" and "init" both TRUE. 617 */ 618 void 619 do_highlight( 620 char_u *line, 621 int forceit, 622 int init) // TRUE when called for initializing 623 { 624 char_u *name_end; 625 char_u *p; 626 char_u *linep; 627 char_u *key_start; 628 char_u *arg_start; 629 char_u *key = NULL, *arg = NULL; 630 long i; 631 int off; 632 int len; 633 int attr; 634 int id; 635 int idx; 636 hl_group_T item_before; 637 int did_change = FALSE; 638 int dodefault = FALSE; 639 int doclear = FALSE; 640 int dolink = FALSE; 641 int error = FALSE; 642 int color; 643 int is_normal_group = FALSE; // "Normal" group 644 #ifdef FEAT_TERMINAL 645 int is_terminal_group = FALSE; // "Terminal" group 646 #endif 647 #ifdef FEAT_GUI_X11 648 int is_menu_group = FALSE; // "Menu" group 649 int is_scrollbar_group = FALSE; // "Scrollbar" group 650 int is_tooltip_group = FALSE; // "Tooltip" group 651 int do_colors = FALSE; // need to update colors? 652 #else 653 # define is_menu_group 0 654 # define is_tooltip_group 0 655 #endif 656 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 657 int did_highlight_changed = FALSE; 658 #endif 659 660 /* 661 * If no argument, list current highlighting. 662 */ 663 if (!init && ends_excmd2(line - 1, line)) 664 { 665 for (i = 1; i <= highlight_ga.ga_len && !got_int; ++i) 666 // TODO: only call when the group has attributes set 667 highlight_list_one((int)i); 668 return; 669 } 670 671 /* 672 * Isolate the name. 673 */ 674 name_end = skiptowhite(line); 675 linep = skipwhite(name_end); 676 677 /* 678 * Check for "default" argument. 679 */ 680 if (STRNCMP(line, "default", name_end - line) == 0) 681 { 682 dodefault = TRUE; 683 line = linep; 684 name_end = skiptowhite(line); 685 linep = skipwhite(name_end); 686 } 687 688 /* 689 * Check for "clear" or "link" argument. 690 */ 691 if (STRNCMP(line, "clear", name_end - line) == 0) 692 doclear = TRUE; 693 if (STRNCMP(line, "link", name_end - line) == 0) 694 dolink = TRUE; 695 696 /* 697 * ":highlight {group-name}": list highlighting for one group. 698 */ 699 if (!doclear && !dolink && ends_excmd2(line, linep)) 700 { 701 id = syn_namen2id(line, (int)(name_end - line)); 702 if (id == 0) 703 semsg(_("E411: highlight group not found: %s"), line); 704 else 705 highlight_list_one(id); 706 return; 707 } 708 709 /* 710 * Handle ":highlight link {from} {to}" command. 711 */ 712 if (dolink) 713 { 714 char_u *from_start = linep; 715 char_u *from_end; 716 char_u *to_start; 717 char_u *to_end; 718 int from_id; 719 int to_id; 720 hl_group_T *hlgroup = NULL; 721 722 from_end = skiptowhite(from_start); 723 to_start = skipwhite(from_end); 724 to_end = skiptowhite(to_start); 725 726 if (ends_excmd2(line, from_start) || ends_excmd2(line, to_start)) 727 { 728 semsg(_("E412: Not enough arguments: \":highlight link %s\""), 729 from_start); 730 return; 731 } 732 733 if (!ends_excmd2(line, skipwhite(to_end))) 734 { 735 semsg(_("E413: Too many arguments: \":highlight link %s\""), 736 from_start); 737 return; 738 } 739 740 from_id = syn_check_group(from_start, (int)(from_end - from_start)); 741 if (STRNCMP(to_start, "NONE", 4) == 0) 742 to_id = 0; 743 else 744 to_id = syn_check_group(to_start, (int)(to_end - to_start)); 745 746 if (from_id > 0) 747 { 748 hlgroup = &HL_TABLE()[from_id - 1]; 749 if (dodefault && (forceit || hlgroup->sg_deflink == 0)) 750 { 751 hlgroup->sg_deflink = to_id; 752 #ifdef FEAT_EVAL 753 hlgroup->sg_deflink_sctx = current_sctx; 754 hlgroup->sg_deflink_sctx.sc_lnum += SOURCING_LNUM; 755 #endif 756 } 757 } 758 759 if (from_id > 0 && (!init || hlgroup->sg_set == 0)) 760 { 761 /* 762 * Don't allow a link when there already is some highlighting 763 * for the group, unless '!' is used 764 */ 765 if (to_id > 0 && !forceit && !init 766 && hl_has_settings(from_id - 1, dodefault)) 767 { 768 if (SOURCING_NAME == NULL && !dodefault) 769 emsg(_("E414: group has settings, highlight link ignored")); 770 } 771 else if (hlgroup->sg_link != to_id 772 #ifdef FEAT_EVAL 773 || hlgroup->sg_script_ctx.sc_sid != current_sctx.sc_sid 774 #endif 775 || hlgroup->sg_cleared) 776 { 777 if (!init) 778 hlgroup->sg_set |= SG_LINK; 779 hlgroup->sg_link = to_id; 780 #ifdef FEAT_EVAL 781 hlgroup->sg_script_ctx = current_sctx; 782 hlgroup->sg_script_ctx.sc_lnum += SOURCING_LNUM; 783 #endif 784 hlgroup->sg_cleared = FALSE; 785 redraw_all_later(SOME_VALID); 786 787 // Only call highlight_changed() once after multiple changes. 788 need_highlight_changed = TRUE; 789 } 790 } 791 792 return; 793 } 794 795 if (doclear) 796 { 797 /* 798 * ":highlight clear [group]" command. 799 */ 800 if (ends_excmd2(line, linep)) 801 { 802 #ifdef FEAT_GUI 803 // First, we do not destroy the old values, but allocate the new 804 // ones and update the display. THEN we destroy the old values. 805 // If we destroy the old values first, then the old values 806 // (such as GuiFont's or GuiFontset's) will still be displayed but 807 // invalid because they were free'd. 808 if (gui.in_use) 809 { 810 # ifdef FEAT_BEVAL_TIP 811 gui_init_tooltip_font(); 812 # endif 813 # if defined(FEAT_MENU) && (defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MOTIF)) 814 gui_init_menu_font(); 815 # endif 816 } 817 # if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_X11) 818 gui_mch_def_colors(); 819 # endif 820 # ifdef FEAT_GUI_X11 821 # ifdef FEAT_MENU 822 823 // This only needs to be done when there is no Menu highlight 824 // group defined by default, which IS currently the case. 825 gui_mch_new_menu_colors(); 826 # endif 827 if (gui.in_use) 828 { 829 gui_new_scrollbar_colors(); 830 # ifdef FEAT_BEVAL_GUI 831 gui_mch_new_tooltip_colors(); 832 # endif 833 # ifdef FEAT_MENU 834 gui_mch_new_menu_font(); 835 # endif 836 } 837 # endif 838 839 // Ok, we're done allocating the new default graphics items. 840 // The screen should already be refreshed at this point. 841 // It is now Ok to clear out the old data. 842 #endif 843 #ifdef FEAT_EVAL 844 do_unlet((char_u *)"g:colors_name", TRUE); 845 #endif 846 restore_cterm_colors(); 847 848 /* 849 * Clear all default highlight groups and load the defaults. 850 */ 851 for (idx = 0; idx < highlight_ga.ga_len; ++idx) 852 highlight_clear(idx); 853 init_highlight(TRUE, TRUE); 854 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 855 if (USE_24BIT) 856 highlight_gui_started(); 857 else 858 #endif 859 highlight_changed(); 860 redraw_later_clear(); 861 return; 862 } 863 line = linep; 864 name_end = skiptowhite(line); 865 linep = skipwhite(name_end); 866 } 867 868 /* 869 * Find the group name in the table. If it does not exist yet, add it. 870 */ 871 id = syn_check_group(line, (int)(name_end - line)); 872 if (id == 0) // failed (out of memory) 873 return; 874 idx = id - 1; // index is ID minus one 875 876 // Return if "default" was used and the group already has settings. 877 if (dodefault && hl_has_settings(idx, TRUE)) 878 return; 879 880 // Make a copy so we can check if any attribute actually changed. 881 item_before = HL_TABLE()[idx]; 882 883 if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0) 884 is_normal_group = TRUE; 885 #ifdef FEAT_TERMINAL 886 else if (STRCMP(HL_TABLE()[idx].sg_name_u, "TERMINAL") == 0) 887 is_terminal_group = TRUE; 888 #endif 889 #ifdef FEAT_GUI_X11 890 else if (STRCMP(HL_TABLE()[idx].sg_name_u, "MENU") == 0) 891 is_menu_group = TRUE; 892 else if (STRCMP(HL_TABLE()[idx].sg_name_u, "SCROLLBAR") == 0) 893 is_scrollbar_group = TRUE; 894 else if (STRCMP(HL_TABLE()[idx].sg_name_u, "TOOLTIP") == 0) 895 is_tooltip_group = TRUE; 896 #endif 897 898 // Clear the highlighting for ":hi clear {group}" and ":hi clear". 899 if (doclear || (forceit && init)) 900 { 901 highlight_clear(idx); 902 if (!doclear) 903 HL_TABLE()[idx].sg_set = 0; 904 } 905 906 if (!doclear) 907 while (!ends_excmd2(line, linep)) 908 { 909 key_start = linep; 910 if (*linep == '=') 911 { 912 semsg(_("E415: unexpected equal sign: %s"), key_start); 913 error = TRUE; 914 break; 915 } 916 917 /* 918 * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or 919 * "guibg"). 920 */ 921 while (*linep && !VIM_ISWHITE(*linep) && *linep != '=') 922 ++linep; 923 vim_free(key); 924 key = vim_strnsave_up(key_start, linep - key_start); 925 if (key == NULL) 926 { 927 error = TRUE; 928 break; 929 } 930 linep = skipwhite(linep); 931 932 if (STRCMP(key, "NONE") == 0) 933 { 934 if (!init || HL_TABLE()[idx].sg_set == 0) 935 { 936 if (!init) 937 HL_TABLE()[idx].sg_set |= SG_TERM+SG_CTERM+SG_GUI; 938 highlight_clear(idx); 939 } 940 continue; 941 } 942 943 /* 944 * Check for the equal sign. 945 */ 946 if (*linep != '=') 947 { 948 semsg(_("E416: missing equal sign: %s"), key_start); 949 error = TRUE; 950 break; 951 } 952 ++linep; 953 954 /* 955 * Isolate the argument. 956 */ 957 linep = skipwhite(linep); 958 if (*linep == '\'') // guifg='color name' 959 { 960 arg_start = ++linep; 961 linep = vim_strchr(linep, '\''); 962 if (linep == NULL) 963 { 964 semsg(_(e_invarg2), key_start); 965 error = TRUE; 966 break; 967 } 968 } 969 else 970 { 971 arg_start = linep; 972 linep = skiptowhite(linep); 973 } 974 if (linep == arg_start) 975 { 976 semsg(_("E417: missing argument: %s"), key_start); 977 error = TRUE; 978 break; 979 } 980 vim_free(arg); 981 arg = vim_strnsave(arg_start, linep - arg_start); 982 if (arg == NULL) 983 { 984 error = TRUE; 985 break; 986 } 987 if (*linep == '\'') 988 ++linep; 989 990 /* 991 * Store the argument. 992 */ 993 if ( STRCMP(key, "TERM") == 0 994 || STRCMP(key, "CTERM") == 0 995 || STRCMP(key, "GUI") == 0) 996 { 997 attr = 0; 998 off = 0; 999 while (arg[off] != NUL) 1000 { 1001 for (i = sizeof(hl_attr_table) / sizeof(int); --i >= 0; ) 1002 { 1003 len = (int)STRLEN(hl_name_table[i]); 1004 if (STRNICMP(arg + off, hl_name_table[i], len) == 0) 1005 { 1006 attr |= hl_attr_table[i]; 1007 off += len; 1008 break; 1009 } 1010 } 1011 if (i < 0) 1012 { 1013 semsg(_("E418: Illegal value: %s"), arg); 1014 error = TRUE; 1015 break; 1016 } 1017 if (arg[off] == ',') // another one follows 1018 ++off; 1019 } 1020 if (error) 1021 break; 1022 if (*key == 'T') 1023 { 1024 if (!init || !(HL_TABLE()[idx].sg_set & SG_TERM)) 1025 { 1026 if (!init) 1027 HL_TABLE()[idx].sg_set |= SG_TERM; 1028 HL_TABLE()[idx].sg_term = attr; 1029 } 1030 } 1031 else if (*key == 'C') 1032 { 1033 if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) 1034 { 1035 if (!init) 1036 HL_TABLE()[idx].sg_set |= SG_CTERM; 1037 HL_TABLE()[idx].sg_cterm = attr; 1038 HL_TABLE()[idx].sg_cterm_bold = FALSE; 1039 } 1040 } 1041 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 1042 else 1043 { 1044 if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) 1045 { 1046 if (!init) 1047 HL_TABLE()[idx].sg_set |= SG_GUI; 1048 HL_TABLE()[idx].sg_gui = attr; 1049 } 1050 } 1051 #endif 1052 } 1053 else if (STRCMP(key, "FONT") == 0) 1054 { 1055 // in non-GUI fonts are simply ignored 1056 #ifdef FEAT_GUI 1057 if (HL_TABLE()[idx].sg_font_name != NULL 1058 && STRCMP(HL_TABLE()[idx].sg_font_name, arg) == 0) 1059 { 1060 // Font name didn't change, ignore. 1061 } 1062 else if (!gui.shell_created) 1063 { 1064 // GUI not started yet, always accept the name. 1065 vim_free(HL_TABLE()[idx].sg_font_name); 1066 HL_TABLE()[idx].sg_font_name = vim_strsave(arg); 1067 did_change = TRUE; 1068 } 1069 else 1070 { 1071 GuiFont temp_sg_font = HL_TABLE()[idx].sg_font; 1072 # ifdef FEAT_XFONTSET 1073 GuiFontset temp_sg_fontset = HL_TABLE()[idx].sg_fontset; 1074 # endif 1075 // First, save the current font/fontset. 1076 // Then try to allocate the font/fontset. 1077 // If the allocation fails, HL_TABLE()[idx].sg_font OR 1078 // sg_fontset will be set to NOFONT or NOFONTSET respectively. 1079 1080 HL_TABLE()[idx].sg_font = NOFONT; 1081 # ifdef FEAT_XFONTSET 1082 HL_TABLE()[idx].sg_fontset = NOFONTSET; 1083 # endif 1084 hl_do_font(idx, arg, is_normal_group, is_menu_group, 1085 is_tooltip_group, FALSE); 1086 1087 # ifdef FEAT_XFONTSET 1088 if (HL_TABLE()[idx].sg_fontset != NOFONTSET) 1089 { 1090 // New fontset was accepted. Free the old one, if there 1091 // was one. 1092 gui_mch_free_fontset(temp_sg_fontset); 1093 vim_free(HL_TABLE()[idx].sg_font_name); 1094 HL_TABLE()[idx].sg_font_name = vim_strsave(arg); 1095 did_change = TRUE; 1096 } 1097 else 1098 HL_TABLE()[idx].sg_fontset = temp_sg_fontset; 1099 # endif 1100 if (HL_TABLE()[idx].sg_font != NOFONT) 1101 { 1102 // New font was accepted. Free the old one, if there was 1103 // one. 1104 gui_mch_free_font(temp_sg_font); 1105 vim_free(HL_TABLE()[idx].sg_font_name); 1106 HL_TABLE()[idx].sg_font_name = vim_strsave(arg); 1107 did_change = TRUE; 1108 } 1109 else 1110 HL_TABLE()[idx].sg_font = temp_sg_font; 1111 } 1112 #endif 1113 } 1114 else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0 1115 || STRCMP(key, "CTERMUL") == 0) 1116 { 1117 if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) 1118 { 1119 if (!init) 1120 HL_TABLE()[idx].sg_set |= SG_CTERM; 1121 1122 // When setting the foreground color, and previously the "bold" 1123 // flag was set for a light color, reset it now 1124 if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold) 1125 { 1126 HL_TABLE()[idx].sg_cterm &= ~HL_BOLD; 1127 HL_TABLE()[idx].sg_cterm_bold = FALSE; 1128 } 1129 1130 if (VIM_ISDIGIT(*arg)) 1131 color = atoi((char *)arg); 1132 else if (STRICMP(arg, "fg") == 0) 1133 { 1134 if (cterm_normal_fg_color) 1135 color = cterm_normal_fg_color - 1; 1136 else 1137 { 1138 emsg(_("E419: FG color unknown")); 1139 error = TRUE; 1140 break; 1141 } 1142 } 1143 else if (STRICMP(arg, "bg") == 0) 1144 { 1145 if (cterm_normal_bg_color > 0) 1146 color = cterm_normal_bg_color - 1; 1147 else 1148 { 1149 emsg(_("E420: BG color unknown")); 1150 error = TRUE; 1151 break; 1152 } 1153 } 1154 else if (STRICMP(arg, "ul") == 0) 1155 { 1156 if (cterm_normal_ul_color > 0) 1157 color = cterm_normal_ul_color - 1; 1158 else 1159 { 1160 emsg(_("E453: UL color unknown")); 1161 error = TRUE; 1162 break; 1163 } 1164 } 1165 else 1166 { 1167 int bold = MAYBE; 1168 1169 // reduce calls to STRICMP a bit, it can be slow 1170 off = TOUPPER_ASC(*arg); 1171 for (i = (sizeof(color_names) / sizeof(char *)); --i >= 0; ) 1172 if (off == color_names[i][0] 1173 && STRICMP(arg + 1, color_names[i] + 1) == 0) 1174 break; 1175 if (i < 0) 1176 { 1177 semsg(_("E421: Color name or number not recognized: %s"), key_start); 1178 error = TRUE; 1179 break; 1180 } 1181 1182 color = lookup_color(i, key[5] == 'F', &bold); 1183 1184 // set/reset bold attribute to get light foreground 1185 // colors (on some terminals, e.g. "linux") 1186 if (bold == TRUE) 1187 { 1188 HL_TABLE()[idx].sg_cterm |= HL_BOLD; 1189 HL_TABLE()[idx].sg_cterm_bold = TRUE; 1190 } 1191 else if (bold == FALSE) 1192 HL_TABLE()[idx].sg_cterm &= ~HL_BOLD; 1193 } 1194 1195 // Add one to the argument, to avoid zero. Zero is used for 1196 // "NONE", then "color" is -1. 1197 if (key[5] == 'F') 1198 { 1199 HL_TABLE()[idx].sg_cterm_fg = color + 1; 1200 if (is_normal_group) 1201 { 1202 cterm_normal_fg_color = color + 1; 1203 cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD); 1204 #ifdef FEAT_GUI 1205 // Don't do this if the GUI is used. 1206 if (!gui.in_use && !gui.starting) 1207 #endif 1208 { 1209 must_redraw = CLEAR; 1210 if (termcap_active && color >= 0) 1211 term_fg_color(color); 1212 } 1213 } 1214 } 1215 else if (key[5] == 'B') 1216 { 1217 HL_TABLE()[idx].sg_cterm_bg = color + 1; 1218 if (is_normal_group) 1219 { 1220 cterm_normal_bg_color = color + 1; 1221 #ifdef FEAT_GUI 1222 // Don't mess with 'background' if the GUI is used. 1223 if (!gui.in_use && !gui.starting) 1224 #endif 1225 { 1226 must_redraw = CLEAR; 1227 if (color >= 0) 1228 { 1229 int dark = -1; 1230 1231 if (termcap_active) 1232 term_bg_color(color); 1233 if (t_colors < 16) 1234 dark = (color == 0 || color == 4); 1235 // Limit the heuristic to the standard 16 colors 1236 else if (color < 16) 1237 dark = (color < 7 || color == 8); 1238 // Set the 'background' option if the value is 1239 // wrong. 1240 if (dark != -1 1241 && dark != (*p_bg == 'd') 1242 && !option_was_set((char_u *)"bg")) 1243 { 1244 set_option_value((char_u *)"bg", 0L, 1245 (char_u *)(dark ? "dark" : "light"), 0); 1246 reset_option_was_set((char_u *)"bg"); 1247 } 1248 } 1249 } 1250 } 1251 } 1252 else // ctermul 1253 { 1254 HL_TABLE()[idx].sg_cterm_ul = color + 1; 1255 if (is_normal_group) 1256 { 1257 cterm_normal_ul_color = color + 1; 1258 #ifdef FEAT_GUI 1259 // Don't do this if the GUI is used. 1260 if (!gui.in_use && !gui.starting) 1261 #endif 1262 { 1263 must_redraw = CLEAR; 1264 if (termcap_active && color >= 0) 1265 term_ul_color(color); 1266 } 1267 } 1268 } 1269 } 1270 } 1271 else if (STRCMP(key, "GUIFG") == 0) 1272 { 1273 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 1274 char_u **namep = &HL_TABLE()[idx].sg_gui_fg_name; 1275 1276 if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) 1277 { 1278 if (!init) 1279 HL_TABLE()[idx].sg_set |= SG_GUI; 1280 1281 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1282 // In GUI guifg colors are only used when recognized 1283 i = color_name2handle(arg); 1284 if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT) 1285 { 1286 HL_TABLE()[idx].sg_gui_fg = i; 1287 # endif 1288 if (*namep == NULL || STRCMP(*namep, arg) != 0) 1289 { 1290 vim_free(*namep); 1291 if (STRCMP(arg, "NONE") != 0) 1292 *namep = vim_strsave(arg); 1293 else 1294 *namep = NULL; 1295 did_change = TRUE; 1296 } 1297 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1298 # ifdef FEAT_GUI_X11 1299 if (is_menu_group && gui.menu_fg_pixel != i) 1300 { 1301 gui.menu_fg_pixel = i; 1302 do_colors = TRUE; 1303 } 1304 if (is_scrollbar_group && gui.scroll_fg_pixel != i) 1305 { 1306 gui.scroll_fg_pixel = i; 1307 do_colors = TRUE; 1308 } 1309 # ifdef FEAT_BEVAL_GUI 1310 if (is_tooltip_group && gui.tooltip_fg_pixel != i) 1311 { 1312 gui.tooltip_fg_pixel = i; 1313 do_colors = TRUE; 1314 } 1315 # endif 1316 # endif 1317 } 1318 # endif 1319 } 1320 #endif 1321 } 1322 else if (STRCMP(key, "GUIBG") == 0) 1323 { 1324 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 1325 char_u **namep = &HL_TABLE()[idx].sg_gui_bg_name; 1326 1327 if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) 1328 { 1329 if (!init) 1330 HL_TABLE()[idx].sg_set |= SG_GUI; 1331 1332 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1333 // In GUI guifg colors are only used when recognized 1334 i = color_name2handle(arg); 1335 if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT) 1336 { 1337 HL_TABLE()[idx].sg_gui_bg = i; 1338 # endif 1339 if (*namep == NULL || STRCMP(*namep, arg) != 0) 1340 { 1341 vim_free(*namep); 1342 if (STRCMP(arg, "NONE") != 0) 1343 *namep = vim_strsave(arg); 1344 else 1345 *namep = NULL; 1346 did_change = TRUE; 1347 } 1348 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1349 # ifdef FEAT_GUI_X11 1350 if (is_menu_group && gui.menu_bg_pixel != i) 1351 { 1352 gui.menu_bg_pixel = i; 1353 do_colors = TRUE; 1354 } 1355 if (is_scrollbar_group && gui.scroll_bg_pixel != i) 1356 { 1357 gui.scroll_bg_pixel = i; 1358 do_colors = TRUE; 1359 } 1360 # ifdef FEAT_BEVAL_GUI 1361 if (is_tooltip_group && gui.tooltip_bg_pixel != i) 1362 { 1363 gui.tooltip_bg_pixel = i; 1364 do_colors = TRUE; 1365 } 1366 # endif 1367 # endif 1368 } 1369 # endif 1370 } 1371 #endif 1372 } 1373 else if (STRCMP(key, "GUISP") == 0) 1374 { 1375 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 1376 char_u **namep = &HL_TABLE()[idx].sg_gui_sp_name; 1377 1378 if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) 1379 { 1380 if (!init) 1381 HL_TABLE()[idx].sg_set |= SG_GUI; 1382 1383 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1384 // In GUI guisp colors are only used when recognized 1385 i = color_name2handle(arg); 1386 if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT) 1387 { 1388 HL_TABLE()[idx].sg_gui_sp = i; 1389 # endif 1390 if (*namep == NULL || STRCMP(*namep, arg) != 0) 1391 { 1392 vim_free(*namep); 1393 if (STRCMP(arg, "NONE") != 0) 1394 *namep = vim_strsave(arg); 1395 else 1396 *namep = NULL; 1397 did_change = TRUE; 1398 } 1399 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1400 } 1401 # endif 1402 } 1403 #endif 1404 } 1405 else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0) 1406 { 1407 char_u buf[100]; 1408 char_u *tname; 1409 1410 if (!init) 1411 HL_TABLE()[idx].sg_set |= SG_TERM; 1412 1413 /* 1414 * The "start" and "stop" arguments can be a literal escape 1415 * sequence, or a comma separated list of terminal codes. 1416 */ 1417 if (STRNCMP(arg, "t_", 2) == 0) 1418 { 1419 off = 0; 1420 buf[0] = 0; 1421 while (arg[off] != NUL) 1422 { 1423 // Isolate one termcap name 1424 for (len = 0; arg[off + len] && 1425 arg[off + len] != ','; ++len) 1426 ; 1427 tname = vim_strnsave(arg + off, len); 1428 if (tname == NULL) // out of memory 1429 { 1430 error = TRUE; 1431 break; 1432 } 1433 // lookup the escape sequence for the item 1434 p = get_term_code(tname); 1435 vim_free(tname); 1436 if (p == NULL) // ignore non-existing things 1437 p = (char_u *)""; 1438 1439 // Append it to the already found stuff 1440 if ((int)(STRLEN(buf) + STRLEN(p)) >= 99) 1441 { 1442 semsg(_("E422: terminal code too long: %s"), arg); 1443 error = TRUE; 1444 break; 1445 } 1446 STRCAT(buf, p); 1447 1448 // Advance to the next item 1449 off += len; 1450 if (arg[off] == ',') // another one follows 1451 ++off; 1452 } 1453 } 1454 else 1455 { 1456 /* 1457 * Copy characters from arg[] to buf[], translating <> codes. 1458 */ 1459 for (p = arg, off = 0; off < 100 - 6 && *p; ) 1460 { 1461 len = trans_special(&p, buf + off, FSK_SIMPLIFY, NULL); 1462 if (len > 0) // recognized special char 1463 off += len; 1464 else // copy as normal char 1465 buf[off++] = *p++; 1466 } 1467 buf[off] = NUL; 1468 } 1469 if (error) 1470 break; 1471 1472 if (STRCMP(buf, "NONE") == 0) // resetting the value 1473 p = NULL; 1474 else 1475 p = vim_strsave(buf); 1476 if (key[2] == 'A') 1477 { 1478 vim_free(HL_TABLE()[idx].sg_start); 1479 HL_TABLE()[idx].sg_start = p; 1480 } 1481 else 1482 { 1483 vim_free(HL_TABLE()[idx].sg_stop); 1484 HL_TABLE()[idx].sg_stop = p; 1485 } 1486 } 1487 else 1488 { 1489 semsg(_("E423: Illegal argument: %s"), key_start); 1490 error = TRUE; 1491 break; 1492 } 1493 HL_TABLE()[idx].sg_cleared = FALSE; 1494 1495 /* 1496 * When highlighting has been given for a group, don't link it. 1497 */ 1498 if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK)) 1499 HL_TABLE()[idx].sg_link = 0; 1500 1501 /* 1502 * Continue with next argument. 1503 */ 1504 linep = skipwhite(linep); 1505 } 1506 1507 /* 1508 * If there is an error, and it's a new entry, remove it from the table. 1509 */ 1510 if (error && idx == highlight_ga.ga_len) 1511 syn_unadd_group(); 1512 else 1513 { 1514 if (is_normal_group) 1515 { 1516 HL_TABLE()[idx].sg_term_attr = 0; 1517 HL_TABLE()[idx].sg_cterm_attr = 0; 1518 #ifdef FEAT_GUI 1519 HL_TABLE()[idx].sg_gui_attr = 0; 1520 /* 1521 * Need to update all groups, because they might be using "bg" 1522 * and/or "fg", which have been changed now. 1523 */ 1524 #endif 1525 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1526 if (USE_24BIT) 1527 { 1528 highlight_gui_started(); 1529 did_highlight_changed = TRUE; 1530 redraw_all_later(NOT_VALID); 1531 } 1532 #endif 1533 #ifdef FEAT_VTP 1534 control_console_color_rgb(); 1535 #endif 1536 } 1537 #ifdef FEAT_TERMINAL 1538 else if (is_terminal_group) 1539 set_terminal_default_colors( 1540 HL_TABLE()[idx].sg_cterm_fg, HL_TABLE()[idx].sg_cterm_bg); 1541 #endif 1542 #ifdef FEAT_GUI_X11 1543 # ifdef FEAT_MENU 1544 else if (is_menu_group) 1545 { 1546 if (gui.in_use && do_colors) 1547 gui_mch_new_menu_colors(); 1548 } 1549 # endif 1550 else if (is_scrollbar_group) 1551 { 1552 if (gui.in_use && do_colors) 1553 gui_new_scrollbar_colors(); 1554 else 1555 set_hl_attr(idx); 1556 } 1557 # ifdef FEAT_BEVAL_GUI 1558 else if (is_tooltip_group) 1559 { 1560 if (gui.in_use && do_colors) 1561 gui_mch_new_tooltip_colors(); 1562 } 1563 # endif 1564 #endif 1565 else 1566 set_hl_attr(idx); 1567 #ifdef FEAT_EVAL 1568 HL_TABLE()[idx].sg_script_ctx = current_sctx; 1569 HL_TABLE()[idx].sg_script_ctx.sc_lnum += SOURCING_LNUM; 1570 #endif 1571 } 1572 1573 vim_free(key); 1574 vim_free(arg); 1575 1576 // Only call highlight_changed() once, after a sequence of highlight 1577 // commands, and only if an attribute actually changed. 1578 if ((did_change 1579 || memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0) 1580 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1581 && !did_highlight_changed 1582 #endif 1583 ) 1584 { 1585 // Do not trigger a redraw when highlighting is changed while 1586 // redrawing. This may happen when evaluating 'statusline' changes the 1587 // StatusLine group. 1588 if (!updating_screen) 1589 redraw_all_later(NOT_VALID); 1590 need_highlight_changed = TRUE; 1591 } 1592 } 1593 1594 #if defined(EXITFREE) || defined(PROTO) 1595 void 1596 free_highlight(void) 1597 { 1598 int i; 1599 1600 for (i = 0; i < highlight_ga.ga_len; ++i) 1601 { 1602 highlight_clear(i); 1603 vim_free(HL_TABLE()[i].sg_name); 1604 vim_free(HL_TABLE()[i].sg_name_u); 1605 } 1606 ga_clear(&highlight_ga); 1607 } 1608 #endif 1609 1610 /* 1611 * Reset the cterm colors to what they were before Vim was started, if 1612 * possible. Otherwise reset them to zero. 1613 */ 1614 void 1615 restore_cterm_colors(void) 1616 { 1617 #if defined(MSWIN) && !defined(FEAT_GUI_MSWIN) 1618 // Since t_me has been set, this probably means that the user 1619 // wants to use this as default colors. Need to reset default 1620 // background/foreground colors. 1621 mch_set_normal_colors(); 1622 #else 1623 # ifdef VIMDLL 1624 if (!gui.in_use) 1625 { 1626 mch_set_normal_colors(); 1627 return; 1628 } 1629 # endif 1630 cterm_normal_fg_color = 0; 1631 cterm_normal_fg_bold = 0; 1632 cterm_normal_bg_color = 0; 1633 # ifdef FEAT_TERMGUICOLORS 1634 cterm_normal_fg_gui_color = INVALCOLOR; 1635 cterm_normal_bg_gui_color = INVALCOLOR; 1636 cterm_normal_ul_gui_color = INVALCOLOR; 1637 # endif 1638 #endif 1639 } 1640 1641 /* 1642 * Return TRUE if highlight group "idx" has any settings. 1643 * When "check_link" is TRUE also check for an existing link. 1644 */ 1645 static int 1646 hl_has_settings(int idx, int check_link) 1647 { 1648 return HL_TABLE()[idx].sg_cleared == 0 1649 && ( HL_TABLE()[idx].sg_term_attr != 0 1650 || HL_TABLE()[idx].sg_cterm_attr != 0 1651 || HL_TABLE()[idx].sg_cterm_fg != 0 1652 || HL_TABLE()[idx].sg_cterm_bg != 0 1653 #ifdef FEAT_GUI 1654 || HL_TABLE()[idx].sg_gui_attr != 0 1655 || HL_TABLE()[idx].sg_gui_fg_name != NULL 1656 || HL_TABLE()[idx].sg_gui_bg_name != NULL 1657 || HL_TABLE()[idx].sg_gui_sp_name != NULL 1658 || HL_TABLE()[idx].sg_font_name != NULL 1659 #endif 1660 || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK))); 1661 } 1662 1663 /* 1664 * Clear highlighting for one group. 1665 */ 1666 static void 1667 highlight_clear(int idx) 1668 { 1669 HL_TABLE()[idx].sg_cleared = TRUE; 1670 1671 HL_TABLE()[idx].sg_term = 0; 1672 VIM_CLEAR(HL_TABLE()[idx].sg_start); 1673 VIM_CLEAR(HL_TABLE()[idx].sg_stop); 1674 HL_TABLE()[idx].sg_term_attr = 0; 1675 HL_TABLE()[idx].sg_cterm = 0; 1676 HL_TABLE()[idx].sg_cterm_bold = FALSE; 1677 HL_TABLE()[idx].sg_cterm_fg = 0; 1678 HL_TABLE()[idx].sg_cterm_bg = 0; 1679 HL_TABLE()[idx].sg_cterm_attr = 0; 1680 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 1681 HL_TABLE()[idx].sg_gui = 0; 1682 VIM_CLEAR(HL_TABLE()[idx].sg_gui_fg_name); 1683 VIM_CLEAR(HL_TABLE()[idx].sg_gui_bg_name); 1684 VIM_CLEAR(HL_TABLE()[idx].sg_gui_sp_name); 1685 #endif 1686 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 1687 HL_TABLE()[idx].sg_gui_fg = INVALCOLOR; 1688 HL_TABLE()[idx].sg_gui_bg = INVALCOLOR; 1689 HL_TABLE()[idx].sg_gui_sp = INVALCOLOR; 1690 #endif 1691 #ifdef FEAT_GUI 1692 gui_mch_free_font(HL_TABLE()[idx].sg_font); 1693 HL_TABLE()[idx].sg_font = NOFONT; 1694 # ifdef FEAT_XFONTSET 1695 gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset); 1696 HL_TABLE()[idx].sg_fontset = NOFONTSET; 1697 # endif 1698 VIM_CLEAR(HL_TABLE()[idx].sg_font_name); 1699 HL_TABLE()[idx].sg_gui_attr = 0; 1700 #endif 1701 // Restore default link and context if they exist. Otherwise clears. 1702 HL_TABLE()[idx].sg_link = HL_TABLE()[idx].sg_deflink; 1703 #ifdef FEAT_EVAL 1704 // Since we set the default link, set the location to where the default 1705 // link was set. 1706 HL_TABLE()[idx].sg_script_ctx = HL_TABLE()[idx].sg_deflink_sctx; 1707 #endif 1708 } 1709 1710 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO) 1711 /* 1712 * Set the normal foreground and background colors according to the "Normal" 1713 * highlighting group. For X11 also set "Menu", "Scrollbar", and 1714 * "Tooltip" colors. 1715 */ 1716 void 1717 set_normal_colors(void) 1718 { 1719 # ifdef FEAT_GUI 1720 # ifdef FEAT_TERMGUICOLORS 1721 if (gui.in_use) 1722 # endif 1723 { 1724 if (set_group_colors((char_u *)"Normal", 1725 &gui.norm_pixel, &gui.back_pixel, 1726 FALSE, TRUE, FALSE)) 1727 { 1728 gui_mch_new_colors(); 1729 must_redraw = CLEAR; 1730 } 1731 # ifdef FEAT_GUI_X11 1732 if (set_group_colors((char_u *)"Menu", 1733 &gui.menu_fg_pixel, &gui.menu_bg_pixel, 1734 TRUE, FALSE, FALSE)) 1735 { 1736 # ifdef FEAT_MENU 1737 gui_mch_new_menu_colors(); 1738 # endif 1739 must_redraw = CLEAR; 1740 } 1741 # ifdef FEAT_BEVAL_GUI 1742 if (set_group_colors((char_u *)"Tooltip", 1743 &gui.tooltip_fg_pixel, &gui.tooltip_bg_pixel, 1744 FALSE, FALSE, TRUE)) 1745 { 1746 # ifdef FEAT_TOOLBAR 1747 gui_mch_new_tooltip_colors(); 1748 # endif 1749 must_redraw = CLEAR; 1750 } 1751 # endif 1752 if (set_group_colors((char_u *)"Scrollbar", 1753 &gui.scroll_fg_pixel, &gui.scroll_bg_pixel, 1754 FALSE, FALSE, FALSE)) 1755 { 1756 gui_new_scrollbar_colors(); 1757 must_redraw = CLEAR; 1758 } 1759 # endif 1760 } 1761 # endif 1762 # ifdef FEAT_TERMGUICOLORS 1763 # ifdef FEAT_GUI 1764 else 1765 # endif 1766 { 1767 int idx; 1768 1769 idx = syn_name2id((char_u *)"Normal") - 1; 1770 if (idx >= 0) 1771 { 1772 gui_do_one_color(idx, FALSE, FALSE); 1773 1774 // If the normal fg or bg color changed a complete redraw is 1775 // required. 1776 if (cterm_normal_fg_gui_color != HL_TABLE()[idx].sg_gui_fg 1777 || cterm_normal_bg_gui_color != HL_TABLE()[idx].sg_gui_bg) 1778 { 1779 // if the GUI color is INVALCOLOR then we use the default cterm 1780 // color 1781 cterm_normal_fg_gui_color = HL_TABLE()[idx].sg_gui_fg; 1782 cterm_normal_bg_gui_color = HL_TABLE()[idx].sg_gui_bg; 1783 must_redraw = CLEAR; 1784 } 1785 } 1786 } 1787 # endif 1788 } 1789 #endif 1790 1791 #if defined(FEAT_GUI) || defined(PROTO) 1792 /* 1793 * Set the colors for "Normal", "Menu", "Tooltip" or "Scrollbar". 1794 */ 1795 static int 1796 set_group_colors( 1797 char_u *name, 1798 guicolor_T *fgp, 1799 guicolor_T *bgp, 1800 int do_menu, 1801 int use_norm, 1802 int do_tooltip) 1803 { 1804 int idx; 1805 1806 idx = syn_name2id(name) - 1; 1807 if (idx >= 0) 1808 { 1809 gui_do_one_color(idx, do_menu, do_tooltip); 1810 1811 if (HL_TABLE()[idx].sg_gui_fg != INVALCOLOR) 1812 *fgp = HL_TABLE()[idx].sg_gui_fg; 1813 else if (use_norm) 1814 *fgp = gui.def_norm_pixel; 1815 if (HL_TABLE()[idx].sg_gui_bg != INVALCOLOR) 1816 *bgp = HL_TABLE()[idx].sg_gui_bg; 1817 else if (use_norm) 1818 *bgp = gui.def_back_pixel; 1819 return TRUE; 1820 } 1821 return FALSE; 1822 } 1823 1824 /* 1825 * Get the font of the "Normal" group. 1826 * Returns "" when it's not found or not set. 1827 */ 1828 char_u * 1829 hl_get_font_name(void) 1830 { 1831 int id; 1832 char_u *s; 1833 1834 id = syn_name2id((char_u *)"Normal"); 1835 if (id > 0) 1836 { 1837 s = HL_TABLE()[id - 1].sg_font_name; 1838 if (s != NULL) 1839 return s; 1840 } 1841 return (char_u *)""; 1842 } 1843 1844 /* 1845 * Set font for "Normal" group. Called by gui_mch_init_font() when a font has 1846 * actually chosen to be used. 1847 */ 1848 void 1849 hl_set_font_name(char_u *font_name) 1850 { 1851 int id; 1852 1853 id = syn_name2id((char_u *)"Normal"); 1854 if (id > 0) 1855 { 1856 vim_free(HL_TABLE()[id - 1].sg_font_name); 1857 HL_TABLE()[id - 1].sg_font_name = vim_strsave(font_name); 1858 } 1859 } 1860 1861 /* 1862 * Set background color for "Normal" group. Called by gui_set_bg_color() 1863 * when the color is known. 1864 */ 1865 void 1866 hl_set_bg_color_name( 1867 char_u *name) // must have been allocated 1868 { 1869 int id; 1870 1871 if (name != NULL) 1872 { 1873 id = syn_name2id((char_u *)"Normal"); 1874 if (id > 0) 1875 { 1876 vim_free(HL_TABLE()[id - 1].sg_gui_bg_name); 1877 HL_TABLE()[id - 1].sg_gui_bg_name = name; 1878 } 1879 } 1880 } 1881 1882 /* 1883 * Set foreground color for "Normal" group. Called by gui_set_fg_color() 1884 * when the color is known. 1885 */ 1886 void 1887 hl_set_fg_color_name( 1888 char_u *name) // must have been allocated 1889 { 1890 int id; 1891 1892 if (name != NULL) 1893 { 1894 id = syn_name2id((char_u *)"Normal"); 1895 if (id > 0) 1896 { 1897 vim_free(HL_TABLE()[id - 1].sg_gui_fg_name); 1898 HL_TABLE()[id - 1].sg_gui_fg_name = name; 1899 } 1900 } 1901 } 1902 1903 /* 1904 * Return the handle for a font name. 1905 * Returns NOFONT when failed. 1906 */ 1907 static GuiFont 1908 font_name2handle(char_u *name) 1909 { 1910 if (STRCMP(name, "NONE") == 0) 1911 return NOFONT; 1912 1913 return gui_mch_get_font(name, TRUE); 1914 } 1915 1916 # ifdef FEAT_XFONTSET 1917 /* 1918 * Return the handle for a fontset name. 1919 * Returns NOFONTSET when failed. 1920 */ 1921 static GuiFontset 1922 fontset_name2handle(char_u *name, int fixed_width) 1923 { 1924 if (STRCMP(name, "NONE") == 0) 1925 return NOFONTSET; 1926 1927 return gui_mch_get_fontset(name, TRUE, fixed_width); 1928 } 1929 # endif 1930 1931 /* 1932 * Get the font or fontset for one highlight group. 1933 */ 1934 static void 1935 hl_do_font( 1936 int idx, 1937 char_u *arg, 1938 int do_normal, // set normal font 1939 int do_menu UNUSED, // set menu font 1940 int do_tooltip UNUSED, // set tooltip font 1941 int free_font) // free current font/fontset 1942 { 1943 # ifdef FEAT_XFONTSET 1944 // If 'guifontset' is not empty, first try using the name as a 1945 // fontset. If that doesn't work, use it as a font name. 1946 if (*p_guifontset != NUL 1947 # ifdef FONTSET_ALWAYS 1948 || do_menu 1949 # endif 1950 # ifdef FEAT_BEVAL_TIP 1951 // In Athena & Motif, the Tooltip highlight group is always a fontset 1952 || do_tooltip 1953 # endif 1954 ) 1955 { 1956 if (free_font) 1957 gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset); 1958 HL_TABLE()[idx].sg_fontset = fontset_name2handle(arg, 0 1959 # ifdef FONTSET_ALWAYS 1960 || do_menu 1961 # endif 1962 # ifdef FEAT_BEVAL_TIP 1963 || do_tooltip 1964 # endif 1965 ); 1966 } 1967 if (HL_TABLE()[idx].sg_fontset != NOFONTSET) 1968 { 1969 // If it worked and it's the Normal group, use it as the normal 1970 // fontset. Same for the Menu group. 1971 if (do_normal) 1972 gui_init_font(arg, TRUE); 1973 # if (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) && defined(FEAT_MENU) 1974 if (do_menu) 1975 { 1976 # ifdef FONTSET_ALWAYS 1977 gui.menu_fontset = HL_TABLE()[idx].sg_fontset; 1978 # else 1979 // YIKES! This is a bug waiting to crash the program 1980 gui.menu_font = HL_TABLE()[idx].sg_fontset; 1981 # endif 1982 gui_mch_new_menu_font(); 1983 } 1984 # ifdef FEAT_BEVAL_GUI 1985 if (do_tooltip) 1986 { 1987 // The Athena widget set cannot currently handle switching between 1988 // displaying a single font and a fontset. 1989 // If the XtNinternational resource is set to True at widget 1990 // creation, then a fontset is always used, otherwise an 1991 // XFontStruct is used. 1992 gui.tooltip_fontset = (XFontSet)HL_TABLE()[idx].sg_fontset; 1993 gui_mch_new_tooltip_font(); 1994 } 1995 # endif 1996 # endif 1997 } 1998 else 1999 # endif 2000 { 2001 if (free_font) 2002 gui_mch_free_font(HL_TABLE()[idx].sg_font); 2003 HL_TABLE()[idx].sg_font = font_name2handle(arg); 2004 // If it worked and it's the Normal group, use it as the 2005 // normal font. Same for the Menu group. 2006 if (HL_TABLE()[idx].sg_font != NOFONT) 2007 { 2008 if (do_normal) 2009 gui_init_font(arg, FALSE); 2010 #ifndef FONTSET_ALWAYS 2011 # if (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) && defined(FEAT_MENU) 2012 if (do_menu) 2013 { 2014 gui.menu_font = HL_TABLE()[idx].sg_font; 2015 gui_mch_new_menu_font(); 2016 } 2017 # endif 2018 #endif 2019 } 2020 } 2021 } 2022 2023 #endif // FEAT_GUI 2024 2025 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO) 2026 /* 2027 * Return the handle for a color name. 2028 * Returns INVALCOLOR when failed. 2029 */ 2030 guicolor_T 2031 color_name2handle(char_u *name) 2032 { 2033 if (STRCMP(name, "NONE") == 0) 2034 return INVALCOLOR; 2035 2036 if (STRICMP(name, "fg") == 0 || STRICMP(name, "foreground") == 0) 2037 { 2038 #if defined(FEAT_TERMGUICOLORS) && defined(FEAT_GUI) 2039 if (gui.in_use) 2040 #endif 2041 #ifdef FEAT_GUI 2042 return gui.norm_pixel; 2043 #endif 2044 #ifdef FEAT_TERMGUICOLORS 2045 if (cterm_normal_fg_gui_color != INVALCOLOR) 2046 return cterm_normal_fg_gui_color; 2047 // Guess that the foreground is black or white. 2048 return GUI_GET_COLOR((char_u *)(*p_bg == 'l' ? "black" : "white")); 2049 #endif 2050 } 2051 if (STRICMP(name, "bg") == 0 || STRICMP(name, "background") == 0) 2052 { 2053 #if defined(FEAT_TERMGUICOLORS) && defined(FEAT_GUI) 2054 if (gui.in_use) 2055 #endif 2056 #ifdef FEAT_GUI 2057 return gui.back_pixel; 2058 #endif 2059 #ifdef FEAT_TERMGUICOLORS 2060 if (cterm_normal_bg_gui_color != INVALCOLOR) 2061 return cterm_normal_bg_gui_color; 2062 // Guess that the background is white or black. 2063 return GUI_GET_COLOR((char_u *)(*p_bg == 'l' ? "white" : "black")); 2064 #endif 2065 } 2066 2067 return GUI_GET_COLOR(name); 2068 } 2069 #endif 2070 2071 /* 2072 * Table with the specifications for an attribute number. 2073 * Note that this table is used by ALL buffers. This is required because the 2074 * GUI can redraw at any time for any buffer. 2075 */ 2076 static garray_T term_attr_table = {0, 0, 0, 0, NULL}; 2077 2078 #define TERM_ATTR_ENTRY(idx) ((attrentry_T *)term_attr_table.ga_data)[idx] 2079 2080 static garray_T cterm_attr_table = {0, 0, 0, 0, NULL}; 2081 2082 #define CTERM_ATTR_ENTRY(idx) ((attrentry_T *)cterm_attr_table.ga_data)[idx] 2083 2084 #ifdef FEAT_GUI 2085 static garray_T gui_attr_table = {0, 0, 0, 0, NULL}; 2086 2087 #define GUI_ATTR_ENTRY(idx) ((attrentry_T *)gui_attr_table.ga_data)[idx] 2088 #endif 2089 2090 /* 2091 * Return the attr number for a set of colors and font. 2092 * Add a new entry to the term_attr_table, cterm_attr_table or gui_attr_table 2093 * if the combination is new. 2094 * Return 0 for error (no more room). 2095 */ 2096 static int 2097 get_attr_entry(garray_T *table, attrentry_T *aep) 2098 { 2099 int i; 2100 attrentry_T *taep; 2101 static int recursive = FALSE; 2102 2103 /* 2104 * Init the table, in case it wasn't done yet. 2105 */ 2106 table->ga_itemsize = sizeof(attrentry_T); 2107 table->ga_growsize = 7; 2108 2109 /* 2110 * Try to find an entry with the same specifications. 2111 */ 2112 for (i = 0; i < table->ga_len; ++i) 2113 { 2114 taep = &(((attrentry_T *)table->ga_data)[i]); 2115 if ( aep->ae_attr == taep->ae_attr 2116 && ( 2117 #ifdef FEAT_GUI 2118 (table == &gui_attr_table 2119 && (aep->ae_u.gui.fg_color == taep->ae_u.gui.fg_color 2120 && aep->ae_u.gui.bg_color 2121 == taep->ae_u.gui.bg_color 2122 && aep->ae_u.gui.sp_color 2123 == taep->ae_u.gui.sp_color 2124 && aep->ae_u.gui.font == taep->ae_u.gui.font 2125 # ifdef FEAT_XFONTSET 2126 && aep->ae_u.gui.fontset == taep->ae_u.gui.fontset 2127 # endif 2128 )) 2129 || 2130 #endif 2131 (table == &term_attr_table 2132 && (aep->ae_u.term.start == NULL) 2133 == (taep->ae_u.term.start == NULL) 2134 && (aep->ae_u.term.start == NULL 2135 || STRCMP(aep->ae_u.term.start, 2136 taep->ae_u.term.start) == 0) 2137 && (aep->ae_u.term.stop == NULL) 2138 == (taep->ae_u.term.stop == NULL) 2139 && (aep->ae_u.term.stop == NULL 2140 || STRCMP(aep->ae_u.term.stop, 2141 taep->ae_u.term.stop) == 0)) 2142 || (table == &cterm_attr_table 2143 && aep->ae_u.cterm.fg_color 2144 == taep->ae_u.cterm.fg_color 2145 && aep->ae_u.cterm.bg_color 2146 == taep->ae_u.cterm.bg_color 2147 && aep->ae_u.cterm.ul_color 2148 == taep->ae_u.cterm.ul_color 2149 #ifdef FEAT_TERMGUICOLORS 2150 && aep->ae_u.cterm.fg_rgb 2151 == taep->ae_u.cterm.fg_rgb 2152 && aep->ae_u.cterm.bg_rgb 2153 == taep->ae_u.cterm.bg_rgb 2154 && aep->ae_u.cterm.ul_rgb 2155 == taep->ae_u.cterm.ul_rgb 2156 #endif 2157 ))) 2158 2159 return i + ATTR_OFF; 2160 } 2161 2162 if (table->ga_len + ATTR_OFF > MAX_TYPENR) 2163 { 2164 /* 2165 * Running out of attribute entries! remove all attributes, and 2166 * compute new ones for all groups. 2167 * When called recursively, we are really out of numbers. 2168 */ 2169 if (recursive) 2170 { 2171 emsg(_("E424: Too many different highlighting attributes in use")); 2172 return 0; 2173 } 2174 recursive = TRUE; 2175 2176 clear_hl_tables(); 2177 2178 must_redraw = CLEAR; 2179 2180 for (i = 0; i < highlight_ga.ga_len; ++i) 2181 set_hl_attr(i); 2182 2183 recursive = FALSE; 2184 } 2185 2186 /* 2187 * This is a new combination of colors and font, add an entry. 2188 */ 2189 if (ga_grow(table, 1) == FAIL) 2190 return 0; 2191 2192 taep = &(((attrentry_T *)table->ga_data)[table->ga_len]); 2193 CLEAR_POINTER(taep); 2194 taep->ae_attr = aep->ae_attr; 2195 #ifdef FEAT_GUI 2196 if (table == &gui_attr_table) 2197 { 2198 taep->ae_u.gui.fg_color = aep->ae_u.gui.fg_color; 2199 taep->ae_u.gui.bg_color = aep->ae_u.gui.bg_color; 2200 taep->ae_u.gui.sp_color = aep->ae_u.gui.sp_color; 2201 taep->ae_u.gui.font = aep->ae_u.gui.font; 2202 # ifdef FEAT_XFONTSET 2203 taep->ae_u.gui.fontset = aep->ae_u.gui.fontset; 2204 # endif 2205 } 2206 #endif 2207 if (table == &term_attr_table) 2208 { 2209 if (aep->ae_u.term.start == NULL) 2210 taep->ae_u.term.start = NULL; 2211 else 2212 taep->ae_u.term.start = vim_strsave(aep->ae_u.term.start); 2213 if (aep->ae_u.term.stop == NULL) 2214 taep->ae_u.term.stop = NULL; 2215 else 2216 taep->ae_u.term.stop = vim_strsave(aep->ae_u.term.stop); 2217 } 2218 else if (table == &cterm_attr_table) 2219 { 2220 taep->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color; 2221 taep->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color; 2222 taep->ae_u.cterm.ul_color = aep->ae_u.cterm.ul_color; 2223 #ifdef FEAT_TERMGUICOLORS 2224 taep->ae_u.cterm.fg_rgb = aep->ae_u.cterm.fg_rgb; 2225 taep->ae_u.cterm.bg_rgb = aep->ae_u.cterm.bg_rgb; 2226 taep->ae_u.cterm.ul_rgb = aep->ae_u.cterm.ul_rgb; 2227 #endif 2228 } 2229 ++table->ga_len; 2230 return (table->ga_len - 1 + ATTR_OFF); 2231 } 2232 2233 #if defined(FEAT_TERMINAL) || defined(PROTO) 2234 /* 2235 * Get an attribute index for a cterm entry. 2236 * Uses an existing entry when possible or adds one when needed. 2237 */ 2238 int 2239 get_cterm_attr_idx(int attr, int fg, int bg) 2240 { 2241 attrentry_T at_en; 2242 2243 CLEAR_FIELD(at_en); 2244 #ifdef FEAT_TERMGUICOLORS 2245 at_en.ae_u.cterm.fg_rgb = INVALCOLOR; 2246 at_en.ae_u.cterm.bg_rgb = INVALCOLOR; 2247 at_en.ae_u.cterm.ul_rgb = INVALCOLOR; 2248 #endif 2249 at_en.ae_attr = attr; 2250 at_en.ae_u.cterm.fg_color = fg; 2251 at_en.ae_u.cterm.bg_color = bg; 2252 at_en.ae_u.cterm.ul_color = 0; 2253 return get_attr_entry(&cterm_attr_table, &at_en); 2254 } 2255 #endif 2256 2257 #if (defined(FEAT_TERMINAL) && defined(FEAT_TERMGUICOLORS)) || defined(PROTO) 2258 /* 2259 * Get an attribute index for a 'termguicolors' entry. 2260 * Uses an existing entry when possible or adds one when needed. 2261 */ 2262 int 2263 get_tgc_attr_idx(int attr, guicolor_T fg, guicolor_T bg) 2264 { 2265 attrentry_T at_en; 2266 2267 CLEAR_FIELD(at_en); 2268 at_en.ae_attr = attr; 2269 if (fg == INVALCOLOR && bg == INVALCOLOR) 2270 { 2271 // If both GUI colors are not set fall back to the cterm colors. Helps 2272 // if the GUI only has an attribute, such as undercurl. 2273 at_en.ae_u.cterm.fg_rgb = CTERMCOLOR; 2274 at_en.ae_u.cterm.bg_rgb = CTERMCOLOR; 2275 } 2276 else 2277 { 2278 at_en.ae_u.cterm.fg_rgb = fg; 2279 at_en.ae_u.cterm.bg_rgb = bg; 2280 } 2281 at_en.ae_u.cterm.ul_rgb = INVALCOLOR; 2282 return get_attr_entry(&cterm_attr_table, &at_en); 2283 } 2284 #endif 2285 2286 #if (defined(FEAT_TERMINAL) && defined(FEAT_GUI)) || defined(PROTO) 2287 /* 2288 * Get an attribute index for a cterm entry. 2289 * Uses an existing entry when possible or adds one when needed. 2290 */ 2291 int 2292 get_gui_attr_idx(int attr, guicolor_T fg, guicolor_T bg) 2293 { 2294 attrentry_T at_en; 2295 2296 CLEAR_FIELD(at_en); 2297 at_en.ae_attr = attr; 2298 at_en.ae_u.gui.fg_color = fg; 2299 at_en.ae_u.gui.bg_color = bg; 2300 return get_attr_entry(&gui_attr_table, &at_en); 2301 } 2302 #endif 2303 2304 /* 2305 * Clear all highlight tables. 2306 */ 2307 void 2308 clear_hl_tables(void) 2309 { 2310 int i; 2311 attrentry_T *taep; 2312 2313 #ifdef FEAT_GUI 2314 ga_clear(&gui_attr_table); 2315 #endif 2316 for (i = 0; i < term_attr_table.ga_len; ++i) 2317 { 2318 taep = &(((attrentry_T *)term_attr_table.ga_data)[i]); 2319 vim_free(taep->ae_u.term.start); 2320 vim_free(taep->ae_u.term.stop); 2321 } 2322 ga_clear(&term_attr_table); 2323 ga_clear(&cterm_attr_table); 2324 } 2325 2326 /* 2327 * Combine special attributes (e.g., for spelling) with other attributes 2328 * (e.g., for syntax highlighting). 2329 * "prim_attr" overrules "char_attr". 2330 * This creates a new group when required. 2331 * Since we expect there to be few spelling mistakes we don't cache the 2332 * result. 2333 * Return the resulting attributes. 2334 */ 2335 int 2336 hl_combine_attr(int char_attr, int prim_attr) 2337 { 2338 attrentry_T *char_aep = NULL; 2339 attrentry_T *spell_aep; 2340 attrentry_T new_en; 2341 2342 if (char_attr == 0) 2343 return prim_attr; 2344 if (char_attr <= HL_ALL && prim_attr <= HL_ALL) 2345 return ATTR_COMBINE(char_attr, prim_attr); 2346 #ifdef FEAT_GUI 2347 if (gui.in_use) 2348 { 2349 if (char_attr > HL_ALL) 2350 char_aep = syn_gui_attr2entry(char_attr); 2351 if (char_aep != NULL) 2352 new_en = *char_aep; 2353 else 2354 { 2355 CLEAR_FIELD(new_en); 2356 new_en.ae_u.gui.fg_color = INVALCOLOR; 2357 new_en.ae_u.gui.bg_color = INVALCOLOR; 2358 new_en.ae_u.gui.sp_color = INVALCOLOR; 2359 if (char_attr <= HL_ALL) 2360 new_en.ae_attr = char_attr; 2361 } 2362 2363 if (prim_attr <= HL_ALL) 2364 new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr); 2365 else 2366 { 2367 spell_aep = syn_gui_attr2entry(prim_attr); 2368 if (spell_aep != NULL) 2369 { 2370 new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, 2371 spell_aep->ae_attr); 2372 if (spell_aep->ae_u.gui.fg_color != INVALCOLOR) 2373 new_en.ae_u.gui.fg_color = spell_aep->ae_u.gui.fg_color; 2374 if (spell_aep->ae_u.gui.bg_color != INVALCOLOR) 2375 new_en.ae_u.gui.bg_color = spell_aep->ae_u.gui.bg_color; 2376 if (spell_aep->ae_u.gui.sp_color != INVALCOLOR) 2377 new_en.ae_u.gui.sp_color = spell_aep->ae_u.gui.sp_color; 2378 if (spell_aep->ae_u.gui.font != NOFONT) 2379 new_en.ae_u.gui.font = spell_aep->ae_u.gui.font; 2380 # ifdef FEAT_XFONTSET 2381 if (spell_aep->ae_u.gui.fontset != NOFONTSET) 2382 new_en.ae_u.gui.fontset = spell_aep->ae_u.gui.fontset; 2383 # endif 2384 } 2385 } 2386 return get_attr_entry(&gui_attr_table, &new_en); 2387 } 2388 #endif 2389 2390 if (IS_CTERM) 2391 { 2392 if (char_attr > HL_ALL) 2393 char_aep = syn_cterm_attr2entry(char_attr); 2394 if (char_aep != NULL) 2395 new_en = *char_aep; 2396 else 2397 { 2398 CLEAR_FIELD(new_en); 2399 #ifdef FEAT_TERMGUICOLORS 2400 new_en.ae_u.cterm.bg_rgb = INVALCOLOR; 2401 new_en.ae_u.cterm.fg_rgb = INVALCOLOR; 2402 new_en.ae_u.cterm.ul_rgb = INVALCOLOR; 2403 #endif 2404 if (char_attr <= HL_ALL) 2405 new_en.ae_attr = char_attr; 2406 } 2407 2408 if (prim_attr <= HL_ALL) 2409 new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr); 2410 else 2411 { 2412 spell_aep = syn_cterm_attr2entry(prim_attr); 2413 if (spell_aep != NULL) 2414 { 2415 new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, 2416 spell_aep->ae_attr); 2417 if (spell_aep->ae_u.cterm.fg_color > 0) 2418 new_en.ae_u.cterm.fg_color = spell_aep->ae_u.cterm.fg_color; 2419 if (spell_aep->ae_u.cterm.bg_color > 0) 2420 new_en.ae_u.cterm.bg_color = spell_aep->ae_u.cterm.bg_color; 2421 if (spell_aep->ae_u.cterm.ul_color > 0) 2422 new_en.ae_u.cterm.ul_color = spell_aep->ae_u.cterm.ul_color; 2423 #ifdef FEAT_TERMGUICOLORS 2424 // If both fg and bg are not set fall back to cterm colors. 2425 // Helps for SpellBad which uses undercurl in the GUI. 2426 if (COLOR_INVALID(spell_aep->ae_u.cterm.fg_rgb) 2427 && COLOR_INVALID(spell_aep->ae_u.cterm.bg_rgb)) 2428 { 2429 if (spell_aep->ae_u.cterm.fg_color > 0) 2430 new_en.ae_u.cterm.fg_rgb = CTERMCOLOR; 2431 if (spell_aep->ae_u.cterm.bg_color > 0) 2432 new_en.ae_u.cterm.bg_rgb = CTERMCOLOR; 2433 } 2434 else 2435 { 2436 if (spell_aep->ae_u.cterm.fg_rgb != INVALCOLOR) 2437 new_en.ae_u.cterm.fg_rgb = spell_aep->ae_u.cterm.fg_rgb; 2438 if (spell_aep->ae_u.cterm.bg_rgb != INVALCOLOR) 2439 new_en.ae_u.cterm.bg_rgb = spell_aep->ae_u.cterm.bg_rgb; 2440 } 2441 if (spell_aep->ae_u.cterm.ul_rgb != INVALCOLOR) 2442 new_en.ae_u.cterm.ul_rgb = spell_aep->ae_u.cterm.ul_rgb; 2443 #endif 2444 } 2445 } 2446 return get_attr_entry(&cterm_attr_table, &new_en); 2447 } 2448 2449 if (char_attr > HL_ALL) 2450 char_aep = syn_term_attr2entry(char_attr); 2451 if (char_aep != NULL) 2452 new_en = *char_aep; 2453 else 2454 { 2455 CLEAR_FIELD(new_en); 2456 if (char_attr <= HL_ALL) 2457 new_en.ae_attr = char_attr; 2458 } 2459 2460 if (prim_attr <= HL_ALL) 2461 new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr); 2462 else 2463 { 2464 spell_aep = syn_term_attr2entry(prim_attr); 2465 if (spell_aep != NULL) 2466 { 2467 new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, spell_aep->ae_attr); 2468 if (spell_aep->ae_u.term.start != NULL) 2469 { 2470 new_en.ae_u.term.start = spell_aep->ae_u.term.start; 2471 new_en.ae_u.term.stop = spell_aep->ae_u.term.stop; 2472 } 2473 } 2474 } 2475 return get_attr_entry(&term_attr_table, &new_en); 2476 } 2477 2478 #ifdef FEAT_GUI 2479 attrentry_T * 2480 syn_gui_attr2entry(int attr) 2481 { 2482 attr -= ATTR_OFF; 2483 if (attr >= gui_attr_table.ga_len) // did ":syntax clear" 2484 return NULL; 2485 return &(GUI_ATTR_ENTRY(attr)); 2486 } 2487 #endif 2488 2489 /* 2490 * Get the highlight attributes (HL_BOLD etc.) from an attribute nr. 2491 * Only to be used when "attr" > HL_ALL. 2492 */ 2493 int 2494 syn_attr2attr(int attr) 2495 { 2496 attrentry_T *aep; 2497 2498 #ifdef FEAT_GUI 2499 if (gui.in_use) 2500 aep = syn_gui_attr2entry(attr); 2501 else 2502 #endif 2503 if (IS_CTERM) 2504 aep = syn_cterm_attr2entry(attr); 2505 else 2506 aep = syn_term_attr2entry(attr); 2507 2508 if (aep == NULL) // highlighting not set 2509 return 0; 2510 return aep->ae_attr; 2511 } 2512 2513 2514 attrentry_T * 2515 syn_term_attr2entry(int attr) 2516 { 2517 attr -= ATTR_OFF; 2518 if (attr >= term_attr_table.ga_len) // did ":syntax clear" 2519 return NULL; 2520 return &(TERM_ATTR_ENTRY(attr)); 2521 } 2522 2523 attrentry_T * 2524 syn_cterm_attr2entry(int attr) 2525 { 2526 attr -= ATTR_OFF; 2527 if (attr >= cterm_attr_table.ga_len) // did ":syntax clear" 2528 return NULL; 2529 return &(CTERM_ATTR_ENTRY(attr)); 2530 } 2531 2532 #define LIST_ATTR 1 2533 #define LIST_STRING 2 2534 #define LIST_INT 3 2535 2536 static void 2537 highlight_list_one(int id) 2538 { 2539 hl_group_T *sgp; 2540 int didh = FALSE; 2541 2542 sgp = &HL_TABLE()[id - 1]; // index is ID minus one 2543 2544 if (message_filtered(sgp->sg_name)) 2545 return; 2546 2547 didh = highlight_list_arg(id, didh, LIST_ATTR, 2548 sgp->sg_term, NULL, "term"); 2549 didh = highlight_list_arg(id, didh, LIST_STRING, 2550 0, sgp->sg_start, "start"); 2551 didh = highlight_list_arg(id, didh, LIST_STRING, 2552 0, sgp->sg_stop, "stop"); 2553 2554 didh = highlight_list_arg(id, didh, LIST_ATTR, 2555 sgp->sg_cterm, NULL, "cterm"); 2556 didh = highlight_list_arg(id, didh, LIST_INT, 2557 sgp->sg_cterm_fg, NULL, "ctermfg"); 2558 didh = highlight_list_arg(id, didh, LIST_INT, 2559 sgp->sg_cterm_bg, NULL, "ctermbg"); 2560 didh = highlight_list_arg(id, didh, LIST_INT, 2561 sgp->sg_cterm_ul, NULL, "ctermul"); 2562 2563 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 2564 didh = highlight_list_arg(id, didh, LIST_ATTR, 2565 sgp->sg_gui, NULL, "gui"); 2566 didh = highlight_list_arg(id, didh, LIST_STRING, 2567 0, sgp->sg_gui_fg_name, "guifg"); 2568 didh = highlight_list_arg(id, didh, LIST_STRING, 2569 0, sgp->sg_gui_bg_name, "guibg"); 2570 didh = highlight_list_arg(id, didh, LIST_STRING, 2571 0, sgp->sg_gui_sp_name, "guisp"); 2572 #endif 2573 #ifdef FEAT_GUI 2574 didh = highlight_list_arg(id, didh, LIST_STRING, 2575 0, sgp->sg_font_name, "font"); 2576 #endif 2577 2578 if (sgp->sg_link && !got_int) 2579 { 2580 (void)syn_list_header(didh, 9999, id); 2581 didh = TRUE; 2582 msg_puts_attr("links to", HL_ATTR(HLF_D)); 2583 msg_putchar(' '); 2584 msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name); 2585 } 2586 2587 if (!didh) 2588 highlight_list_arg(id, didh, LIST_STRING, 0, (char_u *)"cleared", ""); 2589 #ifdef FEAT_EVAL 2590 if (p_verbose > 0) 2591 last_set_msg(sgp->sg_script_ctx); 2592 #endif 2593 } 2594 2595 static int 2596 highlight_list_arg( 2597 int id, 2598 int didh, 2599 int type, 2600 int iarg, 2601 char_u *sarg, 2602 char *name) 2603 { 2604 char_u buf[100]; 2605 char_u *ts; 2606 int i; 2607 2608 if (got_int) 2609 return FALSE; 2610 if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0)) 2611 { 2612 ts = buf; 2613 if (type == LIST_INT) 2614 sprintf((char *)buf, "%d", iarg - 1); 2615 else if (type == LIST_STRING) 2616 ts = sarg; 2617 else // type == LIST_ATTR 2618 { 2619 buf[0] = NUL; 2620 for (i = 0; hl_attr_table[i] != 0; ++i) 2621 { 2622 if (iarg & hl_attr_table[i]) 2623 { 2624 if (buf[0] != NUL) 2625 vim_strcat(buf, (char_u *)",", 100); 2626 vim_strcat(buf, (char_u *)hl_name_table[i], 100); 2627 iarg &= ~hl_attr_table[i]; // don't want "inverse" 2628 } 2629 } 2630 } 2631 2632 (void)syn_list_header(didh, 2633 (int)(vim_strsize(ts) + STRLEN(name) + 1), id); 2634 didh = TRUE; 2635 if (!got_int) 2636 { 2637 if (*name != NUL) 2638 { 2639 msg_puts_attr(name, HL_ATTR(HLF_D)); 2640 msg_puts_attr("=", HL_ATTR(HLF_D)); 2641 } 2642 msg_outtrans(ts); 2643 } 2644 } 2645 return didh; 2646 } 2647 2648 #if (((defined(FEAT_EVAL) || defined(FEAT_PRINTER))) && defined(FEAT_SYN_HL)) || defined(PROTO) 2649 /* 2650 * Return "1" if highlight group "id" has attribute "flag". 2651 * Return NULL otherwise. 2652 */ 2653 char_u * 2654 highlight_has_attr( 2655 int id, 2656 int flag, 2657 int modec) // 'g' for GUI, 'c' for cterm, 't' for term 2658 { 2659 int attr; 2660 2661 if (id <= 0 || id > highlight_ga.ga_len) 2662 return NULL; 2663 2664 #if defined(FEAT_GUI) || defined(FEAT_EVAL) 2665 if (modec == 'g') 2666 attr = HL_TABLE()[id - 1].sg_gui; 2667 else 2668 #endif 2669 if (modec == 'c') 2670 attr = HL_TABLE()[id - 1].sg_cterm; 2671 else 2672 attr = HL_TABLE()[id - 1].sg_term; 2673 2674 if (attr & flag) 2675 return (char_u *)"1"; 2676 return NULL; 2677 } 2678 #endif 2679 2680 #if (defined(FEAT_SYN_HL) && defined(FEAT_EVAL)) || defined(PROTO) 2681 /* 2682 * Return color name of highlight group "id". 2683 */ 2684 char_u * 2685 highlight_color( 2686 int id, 2687 char_u *what, // "font", "fg", "bg", "sp", "ul", "fg#", "bg#" or "sp#" 2688 int modec) // 'g' for GUI, 'c' for cterm, 't' for term 2689 { 2690 static char_u name[20]; 2691 int n; 2692 int fg = FALSE; 2693 int sp = FALSE; 2694 int ul = FALSE; 2695 int font = FALSE; 2696 2697 if (id <= 0 || id > highlight_ga.ga_len) 2698 return NULL; 2699 2700 if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g') 2701 fg = TRUE; 2702 else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o' 2703 && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't') 2704 font = TRUE; 2705 else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p') 2706 sp = TRUE; 2707 else if (TOLOWER_ASC(what[0]) == 'u' && TOLOWER_ASC(what[1]) == 'l') 2708 ul = TRUE; 2709 else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g')) 2710 return NULL; 2711 if (modec == 'g') 2712 { 2713 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 2714 # ifdef FEAT_GUI 2715 // return font name 2716 if (font) 2717 return HL_TABLE()[id - 1].sg_font_name; 2718 # endif 2719 2720 // return #RRGGBB form (only possible when GUI is running) 2721 if ((USE_24BIT) && what[2] == '#') 2722 { 2723 guicolor_T color; 2724 long_u rgb; 2725 static char_u buf[10]; 2726 2727 if (fg) 2728 color = HL_TABLE()[id - 1].sg_gui_fg; 2729 else if (sp) 2730 color = HL_TABLE()[id - 1].sg_gui_sp; 2731 else 2732 color = HL_TABLE()[id - 1].sg_gui_bg; 2733 if (color == INVALCOLOR) 2734 return NULL; 2735 rgb = (long_u)GUI_MCH_GET_RGB(color); 2736 sprintf((char *)buf, "#%02x%02x%02x", 2737 (unsigned)(rgb >> 16), 2738 (unsigned)(rgb >> 8) & 255, 2739 (unsigned)rgb & 255); 2740 return buf; 2741 } 2742 # endif 2743 if (fg) 2744 return (HL_TABLE()[id - 1].sg_gui_fg_name); 2745 if (sp) 2746 return (HL_TABLE()[id - 1].sg_gui_sp_name); 2747 return (HL_TABLE()[id - 1].sg_gui_bg_name); 2748 } 2749 if (font || sp) 2750 return NULL; 2751 if (modec == 'c') 2752 { 2753 if (fg) 2754 n = HL_TABLE()[id - 1].sg_cterm_fg - 1; 2755 else if (ul) 2756 n = HL_TABLE()[id - 1].sg_cterm_ul - 1; 2757 else 2758 n = HL_TABLE()[id - 1].sg_cterm_bg - 1; 2759 if (n < 0) 2760 return NULL; 2761 sprintf((char *)name, "%d", n); 2762 return name; 2763 } 2764 // term doesn't have color 2765 return NULL; 2766 } 2767 #endif 2768 2769 #if (defined(FEAT_SYN_HL) \ 2770 && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)) \ 2771 && defined(FEAT_PRINTER)) || defined(PROTO) 2772 /* 2773 * Return color name of highlight group "id" as RGB value. 2774 */ 2775 long_u 2776 highlight_gui_color_rgb( 2777 int id, 2778 int fg) // TRUE = fg, FALSE = bg 2779 { 2780 guicolor_T color; 2781 2782 if (id <= 0 || id > highlight_ga.ga_len) 2783 return 0L; 2784 2785 if (fg) 2786 color = HL_TABLE()[id - 1].sg_gui_fg; 2787 else 2788 color = HL_TABLE()[id - 1].sg_gui_bg; 2789 2790 if (color == INVALCOLOR) 2791 return 0L; 2792 2793 return GUI_MCH_GET_RGB(color); 2794 } 2795 #endif 2796 2797 /* 2798 * Output the syntax list header. 2799 * Return TRUE when started a new line. 2800 */ 2801 int 2802 syn_list_header( 2803 int did_header, // did header already 2804 int outlen, // length of string that comes 2805 int id) // highlight group id 2806 { 2807 int endcol = 19; 2808 int newline = TRUE; 2809 int name_col = 0; 2810 2811 if (!did_header) 2812 { 2813 msg_putchar('\n'); 2814 if (got_int) 2815 return TRUE; 2816 msg_outtrans(HL_TABLE()[id - 1].sg_name); 2817 name_col = msg_col; 2818 endcol = 15; 2819 } 2820 else if (msg_col + outlen + 1 >= Columns) 2821 { 2822 msg_putchar('\n'); 2823 if (got_int) 2824 return TRUE; 2825 } 2826 else 2827 { 2828 if (msg_col >= endcol) // wrap around is like starting a new line 2829 newline = FALSE; 2830 } 2831 2832 if (msg_col >= endcol) // output at least one space 2833 endcol = msg_col + 1; 2834 if (Columns <= endcol) // avoid hang for tiny window 2835 endcol = Columns - 1; 2836 2837 msg_advance(endcol); 2838 2839 // Show "xxx" with the attributes. 2840 if (!did_header) 2841 { 2842 if (endcol == Columns - 1 && endcol <= name_col) 2843 msg_putchar(' '); 2844 msg_puts_attr("xxx", syn_id2attr(id)); 2845 msg_putchar(' '); 2846 } 2847 2848 return newline; 2849 } 2850 2851 /* 2852 * Set the attribute numbers for a highlight group. 2853 * Called after one of the attributes has changed. 2854 */ 2855 static void 2856 set_hl_attr( 2857 int idx) // index in array 2858 { 2859 attrentry_T at_en; 2860 hl_group_T *sgp = HL_TABLE() + idx; 2861 2862 // The "Normal" group doesn't need an attribute number 2863 if (sgp->sg_name_u != NULL && STRCMP(sgp->sg_name_u, "NORMAL") == 0) 2864 return; 2865 2866 #ifdef FEAT_GUI 2867 /* 2868 * For the GUI mode: If there are other than "normal" highlighting 2869 * attributes, need to allocate an attr number. 2870 */ 2871 if (sgp->sg_gui_fg == INVALCOLOR 2872 && sgp->sg_gui_bg == INVALCOLOR 2873 && sgp->sg_gui_sp == INVALCOLOR 2874 && sgp->sg_font == NOFONT 2875 # ifdef FEAT_XFONTSET 2876 && sgp->sg_fontset == NOFONTSET 2877 # endif 2878 ) 2879 { 2880 sgp->sg_gui_attr = sgp->sg_gui; 2881 } 2882 else 2883 { 2884 at_en.ae_attr = sgp->sg_gui; 2885 at_en.ae_u.gui.fg_color = sgp->sg_gui_fg; 2886 at_en.ae_u.gui.bg_color = sgp->sg_gui_bg; 2887 at_en.ae_u.gui.sp_color = sgp->sg_gui_sp; 2888 at_en.ae_u.gui.font = sgp->sg_font; 2889 # ifdef FEAT_XFONTSET 2890 at_en.ae_u.gui.fontset = sgp->sg_fontset; 2891 # endif 2892 sgp->sg_gui_attr = get_attr_entry(&gui_attr_table, &at_en); 2893 } 2894 #endif 2895 /* 2896 * For the term mode: If there are other than "normal" highlighting 2897 * attributes, need to allocate an attr number. 2898 */ 2899 if (sgp->sg_start == NULL && sgp->sg_stop == NULL) 2900 sgp->sg_term_attr = sgp->sg_term; 2901 else 2902 { 2903 at_en.ae_attr = sgp->sg_term; 2904 at_en.ae_u.term.start = sgp->sg_start; 2905 at_en.ae_u.term.stop = sgp->sg_stop; 2906 sgp->sg_term_attr = get_attr_entry(&term_attr_table, &at_en); 2907 } 2908 2909 /* 2910 * For the color term mode: If there are other than "normal" 2911 * highlighting attributes, need to allocate an attr number. 2912 */ 2913 if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0 && sgp->sg_cterm_ul == 0 2914 # ifdef FEAT_TERMGUICOLORS 2915 && sgp->sg_gui_fg == INVALCOLOR 2916 && sgp->sg_gui_bg == INVALCOLOR 2917 && sgp->sg_gui_sp == INVALCOLOR 2918 # endif 2919 ) 2920 sgp->sg_cterm_attr = sgp->sg_cterm; 2921 else 2922 { 2923 at_en.ae_attr = sgp->sg_cterm; 2924 at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg; 2925 at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg; 2926 at_en.ae_u.cterm.ul_color = sgp->sg_cterm_ul; 2927 # ifdef FEAT_TERMGUICOLORS 2928 # ifdef MSWIN 2929 # ifdef VIMDLL 2930 // Only when not using the GUI. 2931 if (!gui.in_use && !gui.starting) 2932 # endif 2933 { 2934 int id; 2935 guicolor_T fg, bg; 2936 2937 id = syn_name2id((char_u *)"Normal"); 2938 if (id > 0) 2939 { 2940 syn_id2colors(id, &fg, &bg); 2941 if (sgp->sg_gui_fg == INVALCOLOR) 2942 sgp->sg_gui_fg = fg; 2943 if (sgp->sg_gui_bg == INVALCOLOR) 2944 sgp->sg_gui_bg = bg; 2945 } 2946 2947 } 2948 # endif 2949 at_en.ae_u.cterm.fg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_fg); 2950 at_en.ae_u.cterm.bg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_bg); 2951 // Only use the underline/undercurl color when used, it may clear the 2952 // background color if not supported. 2953 if (sgp->sg_cterm & (HL_UNDERLINE | HL_UNDERCURL)) 2954 at_en.ae_u.cterm.ul_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_sp); 2955 else 2956 at_en.ae_u.cterm.ul_rgb = INVALCOLOR; 2957 if (at_en.ae_u.cterm.fg_rgb == INVALCOLOR 2958 && at_en.ae_u.cterm.bg_rgb == INVALCOLOR) 2959 { 2960 // If both fg and bg are invalid fall back to the cterm colors. 2961 // Helps when the GUI only uses an attribute, e.g. undercurl. 2962 at_en.ae_u.cterm.fg_rgb = CTERMCOLOR; 2963 at_en.ae_u.cterm.bg_rgb = CTERMCOLOR; 2964 } 2965 # endif 2966 sgp->sg_cterm_attr = get_attr_entry(&cterm_attr_table, &at_en); 2967 } 2968 } 2969 2970 /* 2971 * Lookup a highlight group name and return its ID. 2972 * If it is not found, 0 is returned. 2973 */ 2974 int 2975 syn_name2id(char_u *name) 2976 { 2977 int i; 2978 char_u name_u[200]; 2979 2980 // Avoid using stricmp() too much, it's slow on some systems 2981 // Avoid alloc()/free(), these are slow too. ID names over 200 chars 2982 // don't deserve to be found! 2983 vim_strncpy(name_u, name, 199); 2984 vim_strup(name_u); 2985 for (i = highlight_ga.ga_len; --i >= 0; ) 2986 if (HL_TABLE()[i].sg_name_u != NULL 2987 && STRCMP(name_u, HL_TABLE()[i].sg_name_u) == 0) 2988 break; 2989 return i + 1; 2990 } 2991 2992 /* 2993 * Lookup a highlight group name and return its attributes. 2994 * Return zero if not found. 2995 */ 2996 int 2997 syn_name2attr(char_u *name) 2998 { 2999 int id = syn_name2id(name); 3000 3001 if (id != 0) 3002 return syn_id2attr(id); 3003 return 0; 3004 } 3005 3006 #if defined(FEAT_EVAL) || defined(PROTO) 3007 /* 3008 * Return TRUE if highlight group "name" exists. 3009 */ 3010 int 3011 highlight_exists(char_u *name) 3012 { 3013 return (syn_name2id(name) > 0); 3014 } 3015 3016 # if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) 3017 /* 3018 * Return the name of highlight group "id". 3019 * When not a valid ID return an empty string. 3020 */ 3021 char_u * 3022 syn_id2name(int id) 3023 { 3024 if (id <= 0 || id > highlight_ga.ga_len) 3025 return (char_u *)""; 3026 return HL_TABLE()[id - 1].sg_name; 3027 } 3028 # endif 3029 #endif 3030 3031 /* 3032 * Like syn_name2id(), but take a pointer + length argument. 3033 */ 3034 int 3035 syn_namen2id(char_u *linep, int len) 3036 { 3037 char_u *name; 3038 int id = 0; 3039 3040 name = vim_strnsave(linep, len); 3041 if (name != NULL) 3042 { 3043 id = syn_name2id(name); 3044 vim_free(name); 3045 } 3046 return id; 3047 } 3048 3049 /* 3050 * Find highlight group name in the table and return its ID. 3051 * The argument is a pointer to the name and the length of the name. 3052 * If it doesn't exist yet, a new entry is created. 3053 * Return 0 for failure. 3054 */ 3055 int 3056 syn_check_group(char_u *pp, int len) 3057 { 3058 int id; 3059 char_u *name; 3060 3061 name = vim_strnsave(pp, len); 3062 if (name == NULL) 3063 return 0; 3064 3065 id = syn_name2id(name); 3066 if (id == 0) // doesn't exist yet 3067 id = syn_add_group(name); 3068 else 3069 vim_free(name); 3070 return id; 3071 } 3072 3073 /* 3074 * Add new highlight group and return its ID. 3075 * "name" must be an allocated string, it will be consumed. 3076 * Return 0 for failure. 3077 */ 3078 static int 3079 syn_add_group(char_u *name) 3080 { 3081 char_u *p; 3082 char_u *name_up; 3083 3084 // Check that the name is ASCII letters, digits and underscore. 3085 for (p = name; *p != NUL; ++p) 3086 { 3087 if (!vim_isprintc(*p)) 3088 { 3089 emsg(_("E669: Unprintable character in group name")); 3090 vim_free(name); 3091 return 0; 3092 } 3093 else if (!ASCII_ISALNUM(*p) && *p != '_') 3094 { 3095 // This is an error, but since there previously was no check only 3096 // give a warning. 3097 msg_source(HL_ATTR(HLF_W)); 3098 msg(_("W18: Invalid character in group name")); 3099 break; 3100 } 3101 } 3102 3103 /* 3104 * First call for this growarray: init growing array. 3105 */ 3106 if (highlight_ga.ga_data == NULL) 3107 { 3108 highlight_ga.ga_itemsize = sizeof(hl_group_T); 3109 highlight_ga.ga_growsize = 10; 3110 } 3111 3112 if (highlight_ga.ga_len >= MAX_HL_ID) 3113 { 3114 emsg(_("E849: Too many highlight and syntax groups")); 3115 vim_free(name); 3116 return 0; 3117 } 3118 3119 /* 3120 * Make room for at least one other syntax_highlight entry. 3121 */ 3122 if (ga_grow(&highlight_ga, 1) == FAIL) 3123 { 3124 vim_free(name); 3125 return 0; 3126 } 3127 3128 name_up = vim_strsave_up(name); 3129 if (name_up == NULL) 3130 { 3131 vim_free(name); 3132 return 0; 3133 } 3134 3135 CLEAR_POINTER(&(HL_TABLE()[highlight_ga.ga_len])); 3136 HL_TABLE()[highlight_ga.ga_len].sg_name = name; 3137 HL_TABLE()[highlight_ga.ga_len].sg_name_u = name_up; 3138 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 3139 HL_TABLE()[highlight_ga.ga_len].sg_gui_bg = INVALCOLOR; 3140 HL_TABLE()[highlight_ga.ga_len].sg_gui_fg = INVALCOLOR; 3141 HL_TABLE()[highlight_ga.ga_len].sg_gui_sp = INVALCOLOR; 3142 #endif 3143 ++highlight_ga.ga_len; 3144 3145 return highlight_ga.ga_len; // ID is index plus one 3146 } 3147 3148 /* 3149 * When, just after calling syn_add_group(), an error is discovered, this 3150 * function deletes the new name. 3151 */ 3152 static void 3153 syn_unadd_group(void) 3154 { 3155 --highlight_ga.ga_len; 3156 vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name); 3157 vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u); 3158 } 3159 3160 /* 3161 * Translate a group ID to highlight attributes. 3162 */ 3163 int 3164 syn_id2attr(int hl_id) 3165 { 3166 int attr; 3167 hl_group_T *sgp; 3168 3169 hl_id = syn_get_final_id(hl_id); 3170 sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one 3171 3172 #ifdef FEAT_GUI 3173 /* 3174 * Only use GUI attr when the GUI is being used. 3175 */ 3176 if (gui.in_use) 3177 attr = sgp->sg_gui_attr; 3178 else 3179 #endif 3180 if (IS_CTERM) 3181 attr = sgp->sg_cterm_attr; 3182 else 3183 attr = sgp->sg_term_attr; 3184 3185 return attr; 3186 } 3187 3188 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO) 3189 /* 3190 * Get the GUI colors and attributes for a group ID. 3191 * NOTE: the colors will be INVALCOLOR when not set, the color otherwise. 3192 */ 3193 int 3194 syn_id2colors(int hl_id, guicolor_T *fgp, guicolor_T *bgp) 3195 { 3196 hl_group_T *sgp; 3197 3198 hl_id = syn_get_final_id(hl_id); 3199 sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one 3200 3201 *fgp = sgp->sg_gui_fg; 3202 *bgp = sgp->sg_gui_bg; 3203 return sgp->sg_gui; 3204 } 3205 #endif 3206 3207 #if (defined(MSWIN) \ 3208 && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) \ 3209 && defined(FEAT_TERMGUICOLORS)) \ 3210 || defined(FEAT_TERMINAL) || defined(PROTO) 3211 void 3212 syn_id2cterm_bg(int hl_id, int *fgp, int *bgp) 3213 { 3214 hl_group_T *sgp; 3215 3216 hl_id = syn_get_final_id(hl_id); 3217 sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one 3218 *fgp = sgp->sg_cterm_fg - 1; 3219 *bgp = sgp->sg_cterm_bg - 1; 3220 } 3221 #endif 3222 3223 /* 3224 * Translate a group ID to the final group ID (following links). 3225 */ 3226 int 3227 syn_get_final_id(int hl_id) 3228 { 3229 int count; 3230 hl_group_T *sgp; 3231 3232 if (hl_id > highlight_ga.ga_len || hl_id < 1) 3233 return 0; // Can be called from eval!! 3234 3235 /* 3236 * Follow links until there is no more. 3237 * Look out for loops! Break after 100 links. 3238 */ 3239 for (count = 100; --count >= 0; ) 3240 { 3241 sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one 3242 if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) 3243 break; 3244 hl_id = sgp->sg_link; 3245 } 3246 3247 return hl_id; 3248 } 3249 3250 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO) 3251 /* 3252 * Call this function just after the GUI has started. 3253 * Also called when 'termguicolors' was set, gui.in_use will be FALSE then. 3254 * It finds the font and color handles for the highlighting groups. 3255 */ 3256 void 3257 highlight_gui_started(void) 3258 { 3259 int idx; 3260 3261 // First get the colors from the "Normal" and "Menu" group, if set 3262 if (USE_24BIT) 3263 set_normal_colors(); 3264 3265 for (idx = 0; idx < highlight_ga.ga_len; ++idx) 3266 gui_do_one_color(idx, FALSE, FALSE); 3267 3268 highlight_changed(); 3269 } 3270 3271 static void 3272 gui_do_one_color( 3273 int idx, 3274 int do_menu UNUSED, // TRUE: might set the menu font 3275 int do_tooltip UNUSED) // TRUE: might set the tooltip font 3276 { 3277 int didit = FALSE; 3278 3279 # ifdef FEAT_GUI 3280 # ifdef FEAT_TERMGUICOLORS 3281 if (gui.in_use) 3282 # endif 3283 if (HL_TABLE()[idx].sg_font_name != NULL) 3284 { 3285 hl_do_font(idx, HL_TABLE()[idx].sg_font_name, FALSE, do_menu, 3286 do_tooltip, TRUE); 3287 didit = TRUE; 3288 } 3289 # endif 3290 if (HL_TABLE()[idx].sg_gui_fg_name != NULL) 3291 { 3292 HL_TABLE()[idx].sg_gui_fg = 3293 color_name2handle(HL_TABLE()[idx].sg_gui_fg_name); 3294 didit = TRUE; 3295 } 3296 if (HL_TABLE()[idx].sg_gui_bg_name != NULL) 3297 { 3298 HL_TABLE()[idx].sg_gui_bg = 3299 color_name2handle(HL_TABLE()[idx].sg_gui_bg_name); 3300 didit = TRUE; 3301 } 3302 if (HL_TABLE()[idx].sg_gui_sp_name != NULL) 3303 { 3304 HL_TABLE()[idx].sg_gui_sp = 3305 color_name2handle(HL_TABLE()[idx].sg_gui_sp_name); 3306 didit = TRUE; 3307 } 3308 if (didit) // need to get a new attr number 3309 set_hl_attr(idx); 3310 } 3311 #endif 3312 3313 #if defined(USER_HIGHLIGHT) && defined(FEAT_STL_OPT) 3314 /* 3315 * Apply difference between User[1-9] and HLF_S to HLF_SNC, HLF_ST or HLF_STNC. 3316 */ 3317 static void 3318 combine_stl_hlt( 3319 int id, 3320 int id_S, 3321 int id_alt, 3322 int hlcnt, 3323 int i, 3324 int hlf, 3325 int *table) 3326 { 3327 hl_group_T *hlt = HL_TABLE(); 3328 3329 if (id_alt == 0) 3330 { 3331 CLEAR_POINTER(&hlt[hlcnt + i]); 3332 hlt[hlcnt + i].sg_term = highlight_attr[hlf]; 3333 hlt[hlcnt + i].sg_cterm = highlight_attr[hlf]; 3334 # if defined(FEAT_GUI) || defined(FEAT_EVAL) 3335 hlt[hlcnt + i].sg_gui = highlight_attr[hlf]; 3336 # endif 3337 } 3338 else 3339 mch_memmove(&hlt[hlcnt + i], 3340 &hlt[id_alt - 1], 3341 sizeof(hl_group_T)); 3342 hlt[hlcnt + i].sg_link = 0; 3343 3344 hlt[hlcnt + i].sg_term ^= 3345 hlt[id - 1].sg_term ^ hlt[id_S - 1].sg_term; 3346 if (hlt[id - 1].sg_start != hlt[id_S - 1].sg_start) 3347 hlt[hlcnt + i].sg_start = hlt[id - 1].sg_start; 3348 if (hlt[id - 1].sg_stop != hlt[id_S - 1].sg_stop) 3349 hlt[hlcnt + i].sg_stop = hlt[id - 1].sg_stop; 3350 hlt[hlcnt + i].sg_cterm ^= 3351 hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm; 3352 if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg) 3353 hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg; 3354 if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg) 3355 hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg; 3356 # if defined(FEAT_GUI) || defined(FEAT_EVAL) 3357 hlt[hlcnt + i].sg_gui ^= 3358 hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui; 3359 # endif 3360 # ifdef FEAT_GUI 3361 if (hlt[id - 1].sg_gui_fg != hlt[id_S - 1].sg_gui_fg) 3362 hlt[hlcnt + i].sg_gui_fg = hlt[id - 1].sg_gui_fg; 3363 if (hlt[id - 1].sg_gui_bg != hlt[id_S - 1].sg_gui_bg) 3364 hlt[hlcnt + i].sg_gui_bg = hlt[id - 1].sg_gui_bg; 3365 if (hlt[id - 1].sg_gui_sp != hlt[id_S - 1].sg_gui_sp) 3366 hlt[hlcnt + i].sg_gui_sp = hlt[id - 1].sg_gui_sp; 3367 if (hlt[id - 1].sg_font != hlt[id_S - 1].sg_font) 3368 hlt[hlcnt + i].sg_font = hlt[id - 1].sg_font; 3369 # ifdef FEAT_XFONTSET 3370 if (hlt[id - 1].sg_fontset != hlt[id_S - 1].sg_fontset) 3371 hlt[hlcnt + i].sg_fontset = hlt[id - 1].sg_fontset; 3372 # endif 3373 # endif 3374 highlight_ga.ga_len = hlcnt + i + 1; 3375 set_hl_attr(hlcnt + i); // At long last we can apply 3376 table[i] = syn_id2attr(hlcnt + i + 1); 3377 } 3378 #endif 3379 3380 /* 3381 * Translate the 'highlight' option into attributes in highlight_attr[] and 3382 * set up the user highlights User1..9. If FEAT_STL_OPT is in use, a set of 3383 * corresponding highlights to use on top of HLF_SNC is computed. 3384 * Called only when the 'highlight' option has been changed and upon first 3385 * screen redraw after any :highlight command. 3386 * Return FAIL when an invalid flag is found in 'highlight'. OK otherwise. 3387 */ 3388 int 3389 highlight_changed(void) 3390 { 3391 int hlf; 3392 int i; 3393 char_u *p; 3394 int attr; 3395 char_u *end; 3396 int id; 3397 #ifdef USER_HIGHLIGHT 3398 char_u userhl[30]; // use 30 to avoid compiler warning 3399 # ifdef FEAT_STL_OPT 3400 int id_S = -1; 3401 int id_SNC = 0; 3402 # ifdef FEAT_TERMINAL 3403 int id_ST = 0; 3404 int id_STNC = 0; 3405 # endif 3406 int hlcnt; 3407 # endif 3408 #endif 3409 static int hl_flags[HLF_COUNT] = HL_FLAGS; 3410 3411 need_highlight_changed = FALSE; 3412 3413 /* 3414 * Clear all attributes. 3415 */ 3416 for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf) 3417 highlight_attr[hlf] = 0; 3418 3419 /* 3420 * First set all attributes to their default value. 3421 * Then use the attributes from the 'highlight' option. 3422 */ 3423 for (i = 0; i < 2; ++i) 3424 { 3425 if (i) 3426 p = p_hl; 3427 else 3428 p = get_highlight_default(); 3429 if (p == NULL) // just in case 3430 continue; 3431 3432 while (*p) 3433 { 3434 for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf) 3435 if (hl_flags[hlf] == *p) 3436 break; 3437 ++p; 3438 if (hlf == (int)HLF_COUNT || *p == NUL) 3439 return FAIL; 3440 3441 /* 3442 * Allow several hl_flags to be combined, like "bu" for 3443 * bold-underlined. 3444 */ 3445 attr = 0; 3446 for ( ; *p && *p != ','; ++p) // parse up to comma 3447 { 3448 if (VIM_ISWHITE(*p)) // ignore white space 3449 continue; 3450 3451 if (attr > HL_ALL) // Combination with ':' is not allowed. 3452 return FAIL; 3453 3454 switch (*p) 3455 { 3456 case 'b': attr |= HL_BOLD; 3457 break; 3458 case 'i': attr |= HL_ITALIC; 3459 break; 3460 case '-': 3461 case 'n': // no highlighting 3462 break; 3463 case 'r': attr |= HL_INVERSE; 3464 break; 3465 case 's': attr |= HL_STANDOUT; 3466 break; 3467 case 'u': attr |= HL_UNDERLINE; 3468 break; 3469 case 'c': attr |= HL_UNDERCURL; 3470 break; 3471 case 't': attr |= HL_STRIKETHROUGH; 3472 break; 3473 case ':': ++p; // highlight group name 3474 if (attr || *p == NUL) // no combinations 3475 return FAIL; 3476 end = vim_strchr(p, ','); 3477 if (end == NULL) 3478 end = p + STRLEN(p); 3479 id = syn_check_group(p, (int)(end - p)); 3480 if (id == 0) 3481 return FAIL; 3482 attr = syn_id2attr(id); 3483 p = end - 1; 3484 #if defined(FEAT_STL_OPT) && defined(USER_HIGHLIGHT) 3485 if (hlf == (int)HLF_SNC) 3486 id_SNC = syn_get_final_id(id); 3487 # ifdef FEAT_TERMINAL 3488 else if (hlf == (int)HLF_ST) 3489 id_ST = syn_get_final_id(id); 3490 else if (hlf == (int)HLF_STNC) 3491 id_STNC = syn_get_final_id(id); 3492 # endif 3493 else if (hlf == (int)HLF_S) 3494 id_S = syn_get_final_id(id); 3495 #endif 3496 break; 3497 default: return FAIL; 3498 } 3499 } 3500 highlight_attr[hlf] = attr; 3501 3502 p = skip_to_option_part(p); // skip comma and spaces 3503 } 3504 } 3505 3506 #ifdef USER_HIGHLIGHT 3507 /* 3508 * Setup the user highlights 3509 * 3510 * Temporarily utilize 28 more hl entries: 3511 * 9 for User1-User9 combined with StatusLineNC 3512 * 9 for User1-User9 combined with StatusLineTerm 3513 * 9 for User1-User9 combined with StatusLineTermNC 3514 * 1 for StatusLine default 3515 * Have to be in there simultaneously in case of table overflows in 3516 * get_attr_entry() 3517 */ 3518 # ifdef FEAT_STL_OPT 3519 if (ga_grow(&highlight_ga, 28) == FAIL) 3520 return FAIL; 3521 hlcnt = highlight_ga.ga_len; 3522 if (id_S == -1) 3523 { 3524 // Make sure id_S is always valid to simplify code below. Use the last 3525 // entry. 3526 CLEAR_POINTER(&HL_TABLE()[hlcnt + 27]); 3527 HL_TABLE()[hlcnt + 18].sg_term = highlight_attr[HLF_S]; 3528 id_S = hlcnt + 19; 3529 } 3530 # endif 3531 for (i = 0; i < 9; i++) 3532 { 3533 sprintf((char *)userhl, "User%d", i + 1); 3534 id = syn_name2id(userhl); 3535 if (id == 0) 3536 { 3537 highlight_user[i] = 0; 3538 # ifdef FEAT_STL_OPT 3539 highlight_stlnc[i] = 0; 3540 # ifdef FEAT_TERMINAL 3541 highlight_stlterm[i] = 0; 3542 highlight_stltermnc[i] = 0; 3543 # endif 3544 # endif 3545 } 3546 else 3547 { 3548 highlight_user[i] = syn_id2attr(id); 3549 # ifdef FEAT_STL_OPT 3550 combine_stl_hlt(id, id_S, id_SNC, hlcnt, i, 3551 HLF_SNC, highlight_stlnc); 3552 # ifdef FEAT_TERMINAL 3553 combine_stl_hlt(id, id_S, id_ST, hlcnt + 9, i, 3554 HLF_ST, highlight_stlterm); 3555 combine_stl_hlt(id, id_S, id_STNC, hlcnt + 18, i, 3556 HLF_STNC, highlight_stltermnc); 3557 # endif 3558 # endif 3559 } 3560 } 3561 # ifdef FEAT_STL_OPT 3562 highlight_ga.ga_len = hlcnt; 3563 # endif 3564 3565 #endif // USER_HIGHLIGHT 3566 3567 return OK; 3568 } 3569 3570 static void highlight_list(void); 3571 static void highlight_list_two(int cnt, int attr); 3572 3573 /* 3574 * Handle command line completion for :highlight command. 3575 */ 3576 void 3577 set_context_in_highlight_cmd(expand_T *xp, char_u *arg) 3578 { 3579 char_u *p; 3580 3581 // Default: expand group names 3582 xp->xp_context = EXPAND_HIGHLIGHT; 3583 xp->xp_pattern = arg; 3584 include_link = 2; 3585 include_default = 1; 3586 3587 // (part of) subcommand already typed 3588 if (*arg != NUL) 3589 { 3590 p = skiptowhite(arg); 3591 if (*p != NUL) // past "default" or group name 3592 { 3593 include_default = 0; 3594 if (STRNCMP("default", arg, p - arg) == 0) 3595 { 3596 arg = skipwhite(p); 3597 xp->xp_pattern = arg; 3598 p = skiptowhite(arg); 3599 } 3600 if (*p != NUL) // past group name 3601 { 3602 include_link = 0; 3603 if (arg[1] == 'i' && arg[0] == 'N') 3604 highlight_list(); 3605 if (STRNCMP("link", arg, p - arg) == 0 3606 || STRNCMP("clear", arg, p - arg) == 0) 3607 { 3608 xp->xp_pattern = skipwhite(p); 3609 p = skiptowhite(xp->xp_pattern); 3610 if (*p != NUL) // past first group name 3611 { 3612 xp->xp_pattern = skipwhite(p); 3613 p = skiptowhite(xp->xp_pattern); 3614 } 3615 } 3616 if (*p != NUL) // past group name(s) 3617 xp->xp_context = EXPAND_NOTHING; 3618 } 3619 } 3620 } 3621 } 3622 3623 /* 3624 * List highlighting matches in a nice way. 3625 */ 3626 static void 3627 highlight_list(void) 3628 { 3629 int i; 3630 3631 for (i = 10; --i >= 0; ) 3632 highlight_list_two(i, HL_ATTR(HLF_D)); 3633 for (i = 40; --i >= 0; ) 3634 highlight_list_two(99, 0); 3635 } 3636 3637 static void 3638 highlight_list_two(int cnt, int attr) 3639 { 3640 msg_puts_attr(&("N \bI \b! \b"[cnt / 11]), attr); 3641 msg_clr_eos(); 3642 out_flush(); 3643 ui_delay(cnt == 99 ? 40L : (long)cnt * 50L, FALSE); 3644 } 3645 3646 /* 3647 * Function given to ExpandGeneric() to obtain the list of group names. 3648 */ 3649 char_u * 3650 get_highlight_name(expand_T *xp UNUSED, int idx) 3651 { 3652 return get_highlight_name_ext(xp, idx, TRUE); 3653 } 3654 3655 /* 3656 * Obtain a highlight group name. 3657 * When "skip_cleared" is TRUE don't return a cleared entry. 3658 */ 3659 char_u * 3660 get_highlight_name_ext(expand_T *xp UNUSED, int idx, int skip_cleared) 3661 { 3662 if (idx < 0) 3663 return NULL; 3664 3665 // Items are never removed from the table, skip the ones that were 3666 // cleared. 3667 if (skip_cleared && idx < highlight_ga.ga_len && HL_TABLE()[idx].sg_cleared) 3668 return (char_u *)""; 3669 3670 if (idx == highlight_ga.ga_len && include_none != 0) 3671 return (char_u *)"none"; 3672 if (idx == highlight_ga.ga_len + include_none && include_default != 0) 3673 return (char_u *)"default"; 3674 if (idx == highlight_ga.ga_len + include_none + include_default 3675 && include_link != 0) 3676 return (char_u *)"link"; 3677 if (idx == highlight_ga.ga_len + include_none + include_default + 1 3678 && include_link != 0) 3679 return (char_u *)"clear"; 3680 if (idx >= highlight_ga.ga_len) 3681 return NULL; 3682 return HL_TABLE()[idx].sg_name; 3683 } 3684 3685 #if defined(FEAT_GUI) || defined(PROTO) 3686 /* 3687 * Free all the highlight group fonts. 3688 * Used when quitting for systems which need it. 3689 */ 3690 void 3691 free_highlight_fonts(void) 3692 { 3693 int idx; 3694 3695 for (idx = 0; idx < highlight_ga.ga_len; ++idx) 3696 { 3697 gui_mch_free_font(HL_TABLE()[idx].sg_font); 3698 HL_TABLE()[idx].sg_font = NOFONT; 3699 # ifdef FEAT_XFONTSET 3700 gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset); 3701 HL_TABLE()[idx].sg_fontset = NOFONTSET; 3702 # endif 3703 } 3704 3705 gui_mch_free_font(gui.norm_font); 3706 # ifdef FEAT_XFONTSET 3707 gui_mch_free_fontset(gui.fontset); 3708 # endif 3709 # ifndef FEAT_GUI_GTK 3710 gui_mch_free_font(gui.bold_font); 3711 gui_mch_free_font(gui.ital_font); 3712 gui_mch_free_font(gui.boldital_font); 3713 # endif 3714 } 3715 #endif 3716