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