xref: /vim-8.2.3635/src/highlight.c (revision 32aa1020)
1f9cc9f20SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2f9cc9f20SBram Moolenaar  *
3f9cc9f20SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4f9cc9f20SBram Moolenaar  *
5f9cc9f20SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6f9cc9f20SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7f9cc9f20SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8f9cc9f20SBram Moolenaar  */
9f9cc9f20SBram Moolenaar 
10f9cc9f20SBram Moolenaar /*
1129b7d7a9SBram Moolenaar  * Highlighting stuff.
1229b7d7a9SBram Moolenaar  * Includes highlighting matches.
13f9cc9f20SBram Moolenaar  */
14f9cc9f20SBram Moolenaar 
15f9cc9f20SBram Moolenaar #include "vim.h"
16f9cc9f20SBram Moolenaar 
17f9cc9f20SBram Moolenaar #define SG_TERM		1	// term has been set
18f9cc9f20SBram Moolenaar #define SG_CTERM	2	// cterm has been set
19f9cc9f20SBram Moolenaar #define SG_GUI		4	// gui has been set
20f9cc9f20SBram Moolenaar #define SG_LINK		8	// link has been set
21f9cc9f20SBram Moolenaar 
22f9cc9f20SBram Moolenaar /*
23f9cc9f20SBram Moolenaar  * The "term", "cterm" and "gui" arguments can be any combination of the
24f9cc9f20SBram Moolenaar  * following names, separated by commas (but no spaces!).
25f9cc9f20SBram Moolenaar  */
26f9cc9f20SBram Moolenaar static char *(hl_name_table[]) =
27f9cc9f20SBram Moolenaar     {"bold", "standout", "underline", "undercurl",
28f9cc9f20SBram Moolenaar       "italic", "reverse", "inverse", "nocombine", "strikethrough", "NONE"};
29f9cc9f20SBram Moolenaar static int hl_attr_table[] =
30f9cc9f20SBram Moolenaar     {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_NOCOMBINE, HL_STRIKETHROUGH, 0};
31f9cc9f20SBram Moolenaar #define ATTR_COMBINE(attr_a, attr_b) ((((attr_b) & HL_NOCOMBINE) ? attr_b : (attr_a)) | (attr_b))
32f9cc9f20SBram Moolenaar 
332ac6e82aSBram Moolenaar /*
342ac6e82aSBram Moolenaar  * Structure that stores information about a highlight group.
352ac6e82aSBram Moolenaar  * The ID of a highlight group is also called group ID.  It is the index in
362ac6e82aSBram Moolenaar  * the highlight_ga array PLUS ONE.
372ac6e82aSBram Moolenaar  */
382ac6e82aSBram Moolenaar typedef struct
392ac6e82aSBram Moolenaar {
402ac6e82aSBram Moolenaar     char_u	*sg_name;	// highlight group name
412ac6e82aSBram Moolenaar     char_u	*sg_name_u;	// uppercase of sg_name
422ac6e82aSBram Moolenaar     int		sg_cleared;	// "hi clear" was used
432ac6e82aSBram Moolenaar // for normal terminals
442ac6e82aSBram Moolenaar     int		sg_term;	// "term=" highlighting attributes
452ac6e82aSBram Moolenaar     char_u	*sg_start;	// terminal string for start highl
462ac6e82aSBram Moolenaar     char_u	*sg_stop;	// terminal string for stop highl
472ac6e82aSBram Moolenaar     int		sg_term_attr;	// Screen attr for term mode
482ac6e82aSBram Moolenaar // for color terminals
492ac6e82aSBram Moolenaar     int		sg_cterm;	// "cterm=" highlighting attr
502ac6e82aSBram Moolenaar     int		sg_cterm_bold;	// bold attr was set for light color
512ac6e82aSBram Moolenaar     int		sg_cterm_fg;	// terminal fg color number + 1
522ac6e82aSBram Moolenaar     int		sg_cterm_bg;	// terminal bg color number + 1
532ac6e82aSBram Moolenaar     int		sg_cterm_attr;	// Screen attr for color term mode
542ac6e82aSBram Moolenaar // for when using the GUI
552ac6e82aSBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
562ac6e82aSBram Moolenaar     guicolor_T	sg_gui_fg;	// GUI foreground color handle
572ac6e82aSBram Moolenaar     guicolor_T	sg_gui_bg;	// GUI background color handle
582ac6e82aSBram Moolenaar #endif
592ac6e82aSBram Moolenaar #ifdef FEAT_GUI
602ac6e82aSBram Moolenaar     guicolor_T	sg_gui_sp;	// GUI special color handle
612ac6e82aSBram Moolenaar     GuiFont	sg_font;	// GUI font handle
622ac6e82aSBram Moolenaar #ifdef FEAT_XFONTSET
632ac6e82aSBram Moolenaar     GuiFontset	sg_fontset;	// GUI fontset handle
642ac6e82aSBram Moolenaar #endif
652ac6e82aSBram Moolenaar     char_u	*sg_font_name;  // GUI font or fontset name
662ac6e82aSBram Moolenaar     int		sg_gui_attr;    // Screen attr for GUI mode
672ac6e82aSBram Moolenaar #endif
682ac6e82aSBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
692ac6e82aSBram Moolenaar // Store the sp color name for the GUI or synIDattr()
702ac6e82aSBram Moolenaar     int		sg_gui;		// "gui=" highlighting attributes
712ac6e82aSBram Moolenaar     char_u	*sg_gui_fg_name;// GUI foreground color name
722ac6e82aSBram Moolenaar     char_u	*sg_gui_bg_name;// GUI background color name
732ac6e82aSBram Moolenaar     char_u	*sg_gui_sp_name;// GUI special color name
742ac6e82aSBram Moolenaar #endif
752ac6e82aSBram Moolenaar     int		sg_link;	// link to this highlight group ID
762ac6e82aSBram Moolenaar     int		sg_set;		// combination of SG_* flags
772ac6e82aSBram Moolenaar #ifdef FEAT_EVAL
782ac6e82aSBram Moolenaar     sctx_T	sg_script_ctx;	// script in which the group was last set
792ac6e82aSBram Moolenaar #endif
802ac6e82aSBram Moolenaar } hl_group_T;
812ac6e82aSBram Moolenaar 
822ac6e82aSBram Moolenaar // highlight groups for 'highlight' option
832ac6e82aSBram Moolenaar static garray_T highlight_ga;
842ac6e82aSBram Moolenaar #define HL_TABLE()	((hl_group_T *)((highlight_ga.ga_data)))
852ac6e82aSBram Moolenaar 
862ac6e82aSBram Moolenaar /*
872ac6e82aSBram Moolenaar  * An attribute number is the index in attr_table plus ATTR_OFF.
882ac6e82aSBram Moolenaar  */
892ac6e82aSBram Moolenaar #define ATTR_OFF (HL_ALL + 1)
902ac6e82aSBram Moolenaar 
91f9cc9f20SBram Moolenaar static void syn_unadd_group(void);
92f9cc9f20SBram Moolenaar static void set_hl_attr(int idx);
93f9cc9f20SBram Moolenaar static void highlight_list_one(int id);
94f9cc9f20SBram Moolenaar static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg, char *name);
95f9cc9f20SBram Moolenaar static int syn_add_group(char_u *name);
96f9cc9f20SBram Moolenaar static int hl_has_settings(int idx, int check_link);
97f9cc9f20SBram Moolenaar static void highlight_clear(int idx);
98f9cc9f20SBram Moolenaar 
99f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
100f9cc9f20SBram Moolenaar static void gui_do_one_color(int idx, int do_menu, int do_tooltip);
101f9cc9f20SBram Moolenaar #endif
102f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
103f9cc9f20SBram Moolenaar static int  set_group_colors(char_u *name, guicolor_T *fgp, guicolor_T *bgp, int do_menu, int use_norm, int do_tooltip);
104f9cc9f20SBram Moolenaar static void hl_do_font(int idx, char_u *arg, int do_normal, int do_menu, int do_tooltip, int free_font);
105f9cc9f20SBram Moolenaar #endif
106f9cc9f20SBram Moolenaar 
107f9cc9f20SBram Moolenaar /*
108f9cc9f20SBram Moolenaar  * The default highlight groups.  These are compiled-in for fast startup and
109f9cc9f20SBram Moolenaar  * they still work when the runtime files can't be found.
110f9cc9f20SBram Moolenaar  * When making changes here, also change runtime/colors/default.vim!
111f9cc9f20SBram Moolenaar  * The #ifdefs are needed to reduce the amount of static data.  Helps to make
112f9cc9f20SBram Moolenaar  * the 16 bit DOS (museum) version compile.
113f9cc9f20SBram Moolenaar  */
114f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
115f9cc9f20SBram Moolenaar # define CENT(a, b) b
116f9cc9f20SBram Moolenaar #else
117f9cc9f20SBram Moolenaar # define CENT(a, b) a
118f9cc9f20SBram Moolenaar #endif
119f9cc9f20SBram Moolenaar static char *(highlight_init_both[]) = {
120f9cc9f20SBram Moolenaar     CENT("ErrorMsg term=standout ctermbg=DarkRed ctermfg=White",
121f9cc9f20SBram Moolenaar 	 "ErrorMsg term=standout ctermbg=DarkRed ctermfg=White guibg=Red guifg=White"),
122f9cc9f20SBram Moolenaar     CENT("IncSearch term=reverse cterm=reverse",
123f9cc9f20SBram Moolenaar 	 "IncSearch term=reverse cterm=reverse gui=reverse"),
124f9cc9f20SBram Moolenaar     CENT("ModeMsg term=bold cterm=bold",
125f9cc9f20SBram Moolenaar 	 "ModeMsg term=bold cterm=bold gui=bold"),
126f9cc9f20SBram Moolenaar     CENT("NonText term=bold ctermfg=Blue",
127f9cc9f20SBram Moolenaar 	 "NonText term=bold ctermfg=Blue gui=bold guifg=Blue"),
128f9cc9f20SBram Moolenaar     CENT("StatusLine term=reverse,bold cterm=reverse,bold",
129f9cc9f20SBram Moolenaar 	 "StatusLine term=reverse,bold cterm=reverse,bold gui=reverse,bold"),
130f9cc9f20SBram Moolenaar     CENT("StatusLineNC term=reverse cterm=reverse",
131f9cc9f20SBram Moolenaar 	 "StatusLineNC term=reverse cterm=reverse gui=reverse"),
132f9cc9f20SBram Moolenaar     "default link EndOfBuffer NonText",
133f9cc9f20SBram Moolenaar     CENT("VertSplit term=reverse cterm=reverse",
134f9cc9f20SBram Moolenaar 	 "VertSplit term=reverse cterm=reverse gui=reverse"),
135f9cc9f20SBram Moolenaar #ifdef FEAT_CLIPBOARD
136f9cc9f20SBram Moolenaar     CENT("VisualNOS term=underline,bold cterm=underline,bold",
137f9cc9f20SBram Moolenaar 	 "VisualNOS term=underline,bold cterm=underline,bold gui=underline,bold"),
138f9cc9f20SBram Moolenaar #endif
139f9cc9f20SBram Moolenaar #ifdef FEAT_DIFF
140f9cc9f20SBram Moolenaar     CENT("DiffText term=reverse cterm=bold ctermbg=Red",
141f9cc9f20SBram Moolenaar 	 "DiffText term=reverse cterm=bold ctermbg=Red gui=bold guibg=Red"),
142f9cc9f20SBram Moolenaar #endif
143f9cc9f20SBram Moolenaar     CENT("PmenuSbar ctermbg=Grey",
144f9cc9f20SBram Moolenaar 	 "PmenuSbar ctermbg=Grey guibg=Grey"),
145f9cc9f20SBram Moolenaar     CENT("TabLineSel term=bold cterm=bold",
146f9cc9f20SBram Moolenaar 	 "TabLineSel term=bold cterm=bold gui=bold"),
147f9cc9f20SBram Moolenaar     CENT("TabLineFill term=reverse cterm=reverse",
148f9cc9f20SBram Moolenaar 	 "TabLineFill term=reverse cterm=reverse gui=reverse"),
149f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
150f9cc9f20SBram Moolenaar     "Cursor guibg=fg guifg=bg",
151f9cc9f20SBram Moolenaar     "lCursor guibg=fg guifg=bg", // should be different, but what?
152f9cc9f20SBram Moolenaar #endif
153f9cc9f20SBram Moolenaar     "default link QuickFixLine Search",
154f9cc9f20SBram Moolenaar     CENT("Normal cterm=NONE", "Normal gui=NONE"),
155f9cc9f20SBram Moolenaar     NULL
156f9cc9f20SBram Moolenaar };
157f9cc9f20SBram Moolenaar 
1581f164b19SBram Moolenaar // Default colors only used with a light background.
159f9cc9f20SBram Moolenaar static char *(highlight_init_light[]) = {
160f9cc9f20SBram Moolenaar     CENT("Directory term=bold ctermfg=DarkBlue",
161f9cc9f20SBram Moolenaar 	 "Directory term=bold ctermfg=DarkBlue guifg=Blue"),
162f9cc9f20SBram Moolenaar     CENT("LineNr term=underline ctermfg=Brown",
163f9cc9f20SBram Moolenaar 	 "LineNr term=underline ctermfg=Brown guifg=Brown"),
164017ba07fSBram Moolenaar     CENT("CursorLineNr term=bold cterm=underline ctermfg=Brown",
165017ba07fSBram Moolenaar 	 "CursorLineNr term=bold cterm=underline ctermfg=Brown gui=bold guifg=Brown"),
166f9cc9f20SBram Moolenaar     CENT("MoreMsg term=bold ctermfg=DarkGreen",
167f9cc9f20SBram Moolenaar 	 "MoreMsg term=bold ctermfg=DarkGreen gui=bold guifg=SeaGreen"),
168f9cc9f20SBram Moolenaar     CENT("Question term=standout ctermfg=DarkGreen",
169f9cc9f20SBram Moolenaar 	 "Question term=standout ctermfg=DarkGreen gui=bold guifg=SeaGreen"),
170f9cc9f20SBram Moolenaar     CENT("Search term=reverse ctermbg=Yellow ctermfg=NONE",
171f9cc9f20SBram Moolenaar 	 "Search term=reverse ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE"),
172f9cc9f20SBram Moolenaar #ifdef FEAT_SPELL
173f9cc9f20SBram Moolenaar     CENT("SpellBad term=reverse ctermbg=LightRed",
174f9cc9f20SBram Moolenaar 	 "SpellBad term=reverse ctermbg=LightRed guisp=Red gui=undercurl"),
175f9cc9f20SBram Moolenaar     CENT("SpellCap term=reverse ctermbg=LightBlue",
176f9cc9f20SBram Moolenaar 	 "SpellCap term=reverse ctermbg=LightBlue guisp=Blue gui=undercurl"),
177f9cc9f20SBram Moolenaar     CENT("SpellRare term=reverse ctermbg=LightMagenta",
178f9cc9f20SBram Moolenaar 	 "SpellRare term=reverse ctermbg=LightMagenta guisp=Magenta gui=undercurl"),
179f9cc9f20SBram Moolenaar     CENT("SpellLocal term=underline ctermbg=Cyan",
180f9cc9f20SBram Moolenaar 	 "SpellLocal term=underline ctermbg=Cyan guisp=DarkCyan gui=undercurl"),
181f9cc9f20SBram Moolenaar #endif
182f9cc9f20SBram Moolenaar     CENT("PmenuThumb ctermbg=Black",
183f9cc9f20SBram Moolenaar 	 "PmenuThumb ctermbg=Black guibg=Black"),
184f9cc9f20SBram Moolenaar     CENT("Pmenu ctermbg=LightMagenta ctermfg=Black",
185f9cc9f20SBram Moolenaar 	 "Pmenu ctermbg=LightMagenta ctermfg=Black guibg=LightMagenta"),
186f9cc9f20SBram Moolenaar     CENT("PmenuSel ctermbg=LightGrey ctermfg=Black",
187f9cc9f20SBram Moolenaar 	 "PmenuSel ctermbg=LightGrey ctermfg=Black guibg=Grey"),
188f9cc9f20SBram Moolenaar     CENT("SpecialKey term=bold ctermfg=DarkBlue",
189f9cc9f20SBram Moolenaar 	 "SpecialKey term=bold ctermfg=DarkBlue guifg=Blue"),
190f9cc9f20SBram Moolenaar     CENT("Title term=bold ctermfg=DarkMagenta",
191f9cc9f20SBram Moolenaar 	 "Title term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta"),
192f9cc9f20SBram Moolenaar     CENT("WarningMsg term=standout ctermfg=DarkRed",
193f9cc9f20SBram Moolenaar 	 "WarningMsg term=standout ctermfg=DarkRed guifg=Red"),
194f9cc9f20SBram Moolenaar #ifdef FEAT_WILDMENU
195f9cc9f20SBram Moolenaar     CENT("WildMenu term=standout ctermbg=Yellow ctermfg=Black",
196f9cc9f20SBram Moolenaar 	 "WildMenu term=standout ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"),
197f9cc9f20SBram Moolenaar #endif
198f9cc9f20SBram Moolenaar #ifdef FEAT_FOLDING
199f9cc9f20SBram Moolenaar     CENT("Folded term=standout ctermbg=Grey ctermfg=DarkBlue",
200f9cc9f20SBram Moolenaar 	 "Folded term=standout ctermbg=Grey ctermfg=DarkBlue guibg=LightGrey guifg=DarkBlue"),
201f9cc9f20SBram Moolenaar     CENT("FoldColumn term=standout ctermbg=Grey ctermfg=DarkBlue",
202f9cc9f20SBram Moolenaar 	 "FoldColumn term=standout ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue"),
203f9cc9f20SBram Moolenaar #endif
204f9cc9f20SBram Moolenaar #ifdef FEAT_SIGNS
205f9cc9f20SBram Moolenaar     CENT("SignColumn term=standout ctermbg=Grey ctermfg=DarkBlue",
206f9cc9f20SBram Moolenaar 	 "SignColumn term=standout ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue"),
207f9cc9f20SBram Moolenaar #endif
208f9cc9f20SBram Moolenaar     CENT("Visual term=reverse",
209f9cc9f20SBram Moolenaar 	 "Visual term=reverse guibg=LightGrey"),
210f9cc9f20SBram Moolenaar #ifdef FEAT_DIFF
211f9cc9f20SBram Moolenaar     CENT("DiffAdd term=bold ctermbg=LightBlue",
212f9cc9f20SBram Moolenaar 	 "DiffAdd term=bold ctermbg=LightBlue guibg=LightBlue"),
213f9cc9f20SBram Moolenaar     CENT("DiffChange term=bold ctermbg=LightMagenta",
214f9cc9f20SBram Moolenaar 	 "DiffChange term=bold ctermbg=LightMagenta guibg=LightMagenta"),
215f9cc9f20SBram Moolenaar     CENT("DiffDelete term=bold ctermfg=Blue ctermbg=LightCyan",
216f9cc9f20SBram Moolenaar 	 "DiffDelete term=bold ctermfg=Blue ctermbg=LightCyan gui=bold guifg=Blue guibg=LightCyan"),
217f9cc9f20SBram Moolenaar #endif
218f9cc9f20SBram Moolenaar     CENT("TabLine term=underline cterm=underline ctermfg=black ctermbg=LightGrey",
219f9cc9f20SBram Moolenaar 	 "TabLine term=underline cterm=underline ctermfg=black ctermbg=LightGrey gui=underline guibg=LightGrey"),
220f9cc9f20SBram Moolenaar #ifdef FEAT_SYN_HL
221f9cc9f20SBram Moolenaar     CENT("CursorColumn term=reverse ctermbg=LightGrey",
222f9cc9f20SBram Moolenaar 	 "CursorColumn term=reverse ctermbg=LightGrey guibg=Grey90"),
223f9cc9f20SBram Moolenaar     CENT("CursorLine term=underline cterm=underline",
224f9cc9f20SBram Moolenaar 	 "CursorLine term=underline cterm=underline guibg=Grey90"),
225f9cc9f20SBram Moolenaar     CENT("ColorColumn term=reverse ctermbg=LightRed",
226f9cc9f20SBram Moolenaar 	 "ColorColumn term=reverse ctermbg=LightRed guibg=LightRed"),
227f9cc9f20SBram Moolenaar #endif
228f9cc9f20SBram Moolenaar #ifdef FEAT_CONCEAL
229f9cc9f20SBram Moolenaar     CENT("Conceal ctermbg=DarkGrey ctermfg=LightGrey",
230f9cc9f20SBram Moolenaar 	 "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey"),
231f9cc9f20SBram Moolenaar #endif
232f9cc9f20SBram Moolenaar     CENT("MatchParen term=reverse ctermbg=Cyan",
233f9cc9f20SBram Moolenaar 	 "MatchParen term=reverse ctermbg=Cyan guibg=Cyan"),
234f9cc9f20SBram Moolenaar #ifdef FEAT_TERMINAL
235f9cc9f20SBram Moolenaar     CENT("StatusLineTerm term=reverse,bold cterm=bold ctermfg=White ctermbg=DarkGreen",
236f9cc9f20SBram Moolenaar 	 "StatusLineTerm term=reverse,bold cterm=bold ctermfg=White ctermbg=DarkGreen gui=bold guifg=bg guibg=DarkGreen"),
237f9cc9f20SBram Moolenaar     CENT("StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen",
238f9cc9f20SBram Moolenaar 	 "StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen guifg=bg guibg=DarkGreen"),
239f9cc9f20SBram Moolenaar #endif
240f9cc9f20SBram Moolenaar #ifdef FEAT_MENU
241f9cc9f20SBram Moolenaar     CENT("ToolbarLine term=underline ctermbg=LightGrey",
242f9cc9f20SBram Moolenaar 	 "ToolbarLine term=underline ctermbg=LightGrey guibg=LightGrey"),
243f9cc9f20SBram Moolenaar     CENT("ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey",
244f9cc9f20SBram Moolenaar 	 "ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey gui=bold guifg=White guibg=Grey40"),
245f9cc9f20SBram Moolenaar #endif
246f9cc9f20SBram Moolenaar     NULL
247f9cc9f20SBram Moolenaar };
248f9cc9f20SBram Moolenaar 
2491f164b19SBram Moolenaar // Default colors only used with a dark background.
250f9cc9f20SBram Moolenaar static char *(highlight_init_dark[]) = {
251f9cc9f20SBram Moolenaar     CENT("Directory term=bold ctermfg=LightCyan",
252f9cc9f20SBram Moolenaar 	 "Directory term=bold ctermfg=LightCyan guifg=Cyan"),
253f9cc9f20SBram Moolenaar     CENT("LineNr term=underline ctermfg=Yellow",
254f9cc9f20SBram Moolenaar 	 "LineNr term=underline ctermfg=Yellow guifg=Yellow"),
255017ba07fSBram Moolenaar     CENT("CursorLineNr term=bold cterm=underline ctermfg=Yellow",
256017ba07fSBram Moolenaar 	 "CursorLineNr term=bold cterm=underline ctermfg=Yellow gui=bold guifg=Yellow"),
257f9cc9f20SBram Moolenaar     CENT("MoreMsg term=bold ctermfg=LightGreen",
258f9cc9f20SBram Moolenaar 	 "MoreMsg term=bold ctermfg=LightGreen gui=bold guifg=SeaGreen"),
259f9cc9f20SBram Moolenaar     CENT("Question term=standout ctermfg=LightGreen",
260f9cc9f20SBram Moolenaar 	 "Question term=standout ctermfg=LightGreen gui=bold guifg=Green"),
261f9cc9f20SBram Moolenaar     CENT("Search term=reverse ctermbg=Yellow ctermfg=Black",
262f9cc9f20SBram Moolenaar 	 "Search term=reverse ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"),
263f9cc9f20SBram Moolenaar     CENT("SpecialKey term=bold ctermfg=LightBlue",
264f9cc9f20SBram Moolenaar 	 "SpecialKey term=bold ctermfg=LightBlue guifg=Cyan"),
265f9cc9f20SBram Moolenaar #ifdef FEAT_SPELL
266f9cc9f20SBram Moolenaar     CENT("SpellBad term=reverse ctermbg=Red",
267f9cc9f20SBram Moolenaar 	 "SpellBad term=reverse ctermbg=Red guisp=Red gui=undercurl"),
268f9cc9f20SBram Moolenaar     CENT("SpellCap term=reverse ctermbg=Blue",
269f9cc9f20SBram Moolenaar 	 "SpellCap term=reverse ctermbg=Blue guisp=Blue gui=undercurl"),
270f9cc9f20SBram Moolenaar     CENT("SpellRare term=reverse ctermbg=Magenta",
271f9cc9f20SBram Moolenaar 	 "SpellRare term=reverse ctermbg=Magenta guisp=Magenta gui=undercurl"),
272f9cc9f20SBram Moolenaar     CENT("SpellLocal term=underline ctermbg=Cyan",
273f9cc9f20SBram Moolenaar 	 "SpellLocal term=underline ctermbg=Cyan guisp=Cyan gui=undercurl"),
274f9cc9f20SBram Moolenaar #endif
275f9cc9f20SBram Moolenaar     CENT("PmenuThumb ctermbg=White",
276f9cc9f20SBram Moolenaar 	 "PmenuThumb ctermbg=White guibg=White"),
277f9cc9f20SBram Moolenaar     CENT("Pmenu ctermbg=Magenta ctermfg=Black",
278f9cc9f20SBram Moolenaar 	 "Pmenu ctermbg=Magenta ctermfg=Black guibg=Magenta"),
279f9cc9f20SBram Moolenaar     CENT("PmenuSel ctermbg=Black ctermfg=DarkGrey",
280f9cc9f20SBram Moolenaar 	 "PmenuSel ctermbg=Black ctermfg=DarkGrey guibg=DarkGrey"),
281f9cc9f20SBram Moolenaar     CENT("Title term=bold ctermfg=LightMagenta",
282f9cc9f20SBram Moolenaar 	 "Title term=bold ctermfg=LightMagenta gui=bold guifg=Magenta"),
283f9cc9f20SBram Moolenaar     CENT("WarningMsg term=standout ctermfg=LightRed",
284f9cc9f20SBram Moolenaar 	 "WarningMsg term=standout ctermfg=LightRed guifg=Red"),
285f9cc9f20SBram Moolenaar #ifdef FEAT_WILDMENU
286f9cc9f20SBram Moolenaar     CENT("WildMenu term=standout ctermbg=Yellow ctermfg=Black",
287f9cc9f20SBram Moolenaar 	 "WildMenu term=standout ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"),
288f9cc9f20SBram Moolenaar #endif
289f9cc9f20SBram Moolenaar #ifdef FEAT_FOLDING
290f9cc9f20SBram Moolenaar     CENT("Folded term=standout ctermbg=DarkGrey ctermfg=Cyan",
291f9cc9f20SBram Moolenaar 	 "Folded term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=DarkGrey guifg=Cyan"),
292f9cc9f20SBram Moolenaar     CENT("FoldColumn term=standout ctermbg=DarkGrey ctermfg=Cyan",
293f9cc9f20SBram Moolenaar 	 "FoldColumn term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan"),
294f9cc9f20SBram Moolenaar #endif
295f9cc9f20SBram Moolenaar #ifdef FEAT_SIGNS
296f9cc9f20SBram Moolenaar     CENT("SignColumn term=standout ctermbg=DarkGrey ctermfg=Cyan",
297f9cc9f20SBram Moolenaar 	 "SignColumn term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan"),
298f9cc9f20SBram Moolenaar #endif
299f9cc9f20SBram Moolenaar     CENT("Visual term=reverse",
300f9cc9f20SBram Moolenaar 	 "Visual term=reverse guibg=DarkGrey"),
301f9cc9f20SBram Moolenaar #ifdef FEAT_DIFF
302f9cc9f20SBram Moolenaar     CENT("DiffAdd term=bold ctermbg=DarkBlue",
303f9cc9f20SBram Moolenaar 	 "DiffAdd term=bold ctermbg=DarkBlue guibg=DarkBlue"),
304f9cc9f20SBram Moolenaar     CENT("DiffChange term=bold ctermbg=DarkMagenta",
305f9cc9f20SBram Moolenaar 	 "DiffChange term=bold ctermbg=DarkMagenta guibg=DarkMagenta"),
306f9cc9f20SBram Moolenaar     CENT("DiffDelete term=bold ctermfg=Blue ctermbg=DarkCyan",
307f9cc9f20SBram Moolenaar 	 "DiffDelete term=bold ctermfg=Blue ctermbg=DarkCyan gui=bold guifg=Blue guibg=DarkCyan"),
308f9cc9f20SBram Moolenaar #endif
309f9cc9f20SBram Moolenaar     CENT("TabLine term=underline cterm=underline ctermfg=white ctermbg=DarkGrey",
310f9cc9f20SBram Moolenaar 	 "TabLine term=underline cterm=underline ctermfg=white ctermbg=DarkGrey gui=underline guibg=DarkGrey"),
311f9cc9f20SBram Moolenaar #ifdef FEAT_SYN_HL
312f9cc9f20SBram Moolenaar     CENT("CursorColumn term=reverse ctermbg=DarkGrey",
313f9cc9f20SBram Moolenaar 	 "CursorColumn term=reverse ctermbg=DarkGrey guibg=Grey40"),
314f9cc9f20SBram Moolenaar     CENT("CursorLine term=underline cterm=underline",
315f9cc9f20SBram Moolenaar 	 "CursorLine term=underline cterm=underline guibg=Grey40"),
316f9cc9f20SBram Moolenaar     CENT("ColorColumn term=reverse ctermbg=DarkRed",
317f9cc9f20SBram Moolenaar 	 "ColorColumn term=reverse ctermbg=DarkRed guibg=DarkRed"),
318f9cc9f20SBram Moolenaar #endif
319f9cc9f20SBram Moolenaar     CENT("MatchParen term=reverse ctermbg=DarkCyan",
320f9cc9f20SBram Moolenaar 	 "MatchParen term=reverse ctermbg=DarkCyan guibg=DarkCyan"),
321f9cc9f20SBram Moolenaar #ifdef FEAT_CONCEAL
322f9cc9f20SBram Moolenaar     CENT("Conceal ctermbg=DarkGrey ctermfg=LightGrey",
323f9cc9f20SBram Moolenaar 	 "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey"),
324f9cc9f20SBram Moolenaar #endif
325f9cc9f20SBram Moolenaar #ifdef FEAT_TERMINAL
326f9cc9f20SBram Moolenaar     CENT("StatusLineTerm term=reverse,bold cterm=bold ctermfg=Black ctermbg=LightGreen",
327f9cc9f20SBram Moolenaar 	 "StatusLineTerm term=reverse,bold cterm=bold ctermfg=Black ctermbg=LightGreen gui=bold guifg=bg guibg=LightGreen"),
328f9cc9f20SBram Moolenaar     CENT("StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen",
329f9cc9f20SBram Moolenaar 	 "StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen guifg=bg guibg=LightGreen"),
330f9cc9f20SBram Moolenaar #endif
331f9cc9f20SBram Moolenaar #ifdef FEAT_MENU
332f9cc9f20SBram Moolenaar     CENT("ToolbarLine term=underline ctermbg=DarkGrey",
333f9cc9f20SBram Moolenaar 	 "ToolbarLine term=underline ctermbg=DarkGrey guibg=Grey50"),
334f9cc9f20SBram Moolenaar     CENT("ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey",
335f9cc9f20SBram Moolenaar 	 "ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey gui=bold guifg=Black guibg=LightGrey"),
336f9cc9f20SBram Moolenaar #endif
337f9cc9f20SBram Moolenaar     NULL
338f9cc9f20SBram Moolenaar };
339f9cc9f20SBram Moolenaar 
3402ac6e82aSBram Moolenaar /*
3412ac6e82aSBram Moolenaar  * Returns the number of highlight groups.
3422ac6e82aSBram Moolenaar  */
3432ac6e82aSBram Moolenaar     int
3442ac6e82aSBram Moolenaar highlight_num_groups(void)
3452ac6e82aSBram Moolenaar {
3462ac6e82aSBram Moolenaar     return highlight_ga.ga_len;
3472ac6e82aSBram Moolenaar }
3482ac6e82aSBram Moolenaar 
3492ac6e82aSBram Moolenaar /*
3502ac6e82aSBram Moolenaar  * Returns the name of a highlight group.
3512ac6e82aSBram Moolenaar  */
3522ac6e82aSBram Moolenaar     char_u *
3532ac6e82aSBram Moolenaar highlight_group_name(int id)
3542ac6e82aSBram Moolenaar {
3552ac6e82aSBram Moolenaar     return HL_TABLE()[id].sg_name;
3562ac6e82aSBram Moolenaar }
3572ac6e82aSBram Moolenaar 
3582ac6e82aSBram Moolenaar /*
3592ac6e82aSBram Moolenaar  * Returns the ID of the link to a highlight group.
3602ac6e82aSBram Moolenaar  */
3612ac6e82aSBram Moolenaar     int
3622ac6e82aSBram Moolenaar highlight_link_id(int id)
3632ac6e82aSBram Moolenaar {
3642ac6e82aSBram Moolenaar     return HL_TABLE()[id].sg_link;
3652ac6e82aSBram Moolenaar }
3662ac6e82aSBram Moolenaar 
367f9cc9f20SBram Moolenaar     void
368f9cc9f20SBram Moolenaar init_highlight(
369f9cc9f20SBram Moolenaar     int		both,	    // include groups where 'bg' doesn't matter
370f9cc9f20SBram Moolenaar     int		reset)	    // clear group first
371f9cc9f20SBram Moolenaar {
372f9cc9f20SBram Moolenaar     int		i;
373f9cc9f20SBram Moolenaar     char	**pp;
374f9cc9f20SBram Moolenaar     static int	had_both = FALSE;
375f9cc9f20SBram Moolenaar #ifdef FEAT_EVAL
376f9cc9f20SBram Moolenaar     char_u	*p;
377f9cc9f20SBram Moolenaar 
378f9cc9f20SBram Moolenaar     /*
379f9cc9f20SBram Moolenaar      * Try finding the color scheme file.  Used when a color file was loaded
380f9cc9f20SBram Moolenaar      * and 'background' or 't_Co' is changed.
381f9cc9f20SBram Moolenaar      */
382f9cc9f20SBram Moolenaar     p = get_var_value((char_u *)"g:colors_name");
383f9cc9f20SBram Moolenaar     if (p != NULL)
384f9cc9f20SBram Moolenaar     {
385f9cc9f20SBram Moolenaar 	// The value of g:colors_name could be freed when sourcing the script,
386f9cc9f20SBram Moolenaar 	// making "p" invalid, so copy it.
387f9cc9f20SBram Moolenaar 	char_u *copy_p = vim_strsave(p);
388f9cc9f20SBram Moolenaar 	int    r;
389f9cc9f20SBram Moolenaar 
390f9cc9f20SBram Moolenaar 	if (copy_p != NULL)
391f9cc9f20SBram Moolenaar 	{
392f9cc9f20SBram Moolenaar 	    r = load_colors(copy_p);
393f9cc9f20SBram Moolenaar 	    vim_free(copy_p);
394f9cc9f20SBram Moolenaar 	    if (r == OK)
395f9cc9f20SBram Moolenaar 		return;
396f9cc9f20SBram Moolenaar 	}
397f9cc9f20SBram Moolenaar     }
398f9cc9f20SBram Moolenaar 
399f9cc9f20SBram Moolenaar #endif
400f9cc9f20SBram Moolenaar 
401f9cc9f20SBram Moolenaar     /*
402f9cc9f20SBram Moolenaar      * Didn't use a color file, use the compiled-in colors.
403f9cc9f20SBram Moolenaar      */
404f9cc9f20SBram Moolenaar     if (both)
405f9cc9f20SBram Moolenaar     {
406f9cc9f20SBram Moolenaar 	had_both = TRUE;
407f9cc9f20SBram Moolenaar 	pp = highlight_init_both;
408f9cc9f20SBram Moolenaar 	for (i = 0; pp[i] != NULL; ++i)
409f9cc9f20SBram Moolenaar 	    do_highlight((char_u *)pp[i], reset, TRUE);
410f9cc9f20SBram Moolenaar     }
411f9cc9f20SBram Moolenaar     else if (!had_both)
412f9cc9f20SBram Moolenaar 	// Don't do anything before the call with both == TRUE from main().
413f9cc9f20SBram Moolenaar 	// Not everything has been setup then, and that call will overrule
414f9cc9f20SBram Moolenaar 	// everything anyway.
415f9cc9f20SBram Moolenaar 	return;
416f9cc9f20SBram Moolenaar 
417f9cc9f20SBram Moolenaar     if (*p_bg == 'l')
418f9cc9f20SBram Moolenaar 	pp = highlight_init_light;
419f9cc9f20SBram Moolenaar     else
420f9cc9f20SBram Moolenaar 	pp = highlight_init_dark;
421f9cc9f20SBram Moolenaar     for (i = 0; pp[i] != NULL; ++i)
422f9cc9f20SBram Moolenaar 	do_highlight((char_u *)pp[i], reset, TRUE);
423f9cc9f20SBram Moolenaar 
424f9cc9f20SBram Moolenaar     // Reverse looks ugly, but grey may not work for 8 colors.  Thus let it
425f9cc9f20SBram Moolenaar     // depend on the number of colors available.
426f9cc9f20SBram Moolenaar     // With 8 colors brown is equal to yellow, need to use black for Search fg
427f9cc9f20SBram Moolenaar     // to avoid Statement highlighted text disappears.
428f9cc9f20SBram Moolenaar     // Clear the attributes, needed when changing the t_Co value.
429f9cc9f20SBram Moolenaar     if (t_colors > 8)
430f9cc9f20SBram Moolenaar 	do_highlight((char_u *)(*p_bg == 'l'
431f9cc9f20SBram Moolenaar 		    ? "Visual cterm=NONE ctermbg=LightGrey"
432f9cc9f20SBram Moolenaar 		    : "Visual cterm=NONE ctermbg=DarkGrey"), FALSE, TRUE);
433f9cc9f20SBram Moolenaar     else
434f9cc9f20SBram Moolenaar     {
435f9cc9f20SBram Moolenaar 	do_highlight((char_u *)"Visual cterm=reverse ctermbg=NONE",
436f9cc9f20SBram Moolenaar 								 FALSE, TRUE);
437f9cc9f20SBram Moolenaar 	if (*p_bg == 'l')
438f9cc9f20SBram Moolenaar 	    do_highlight((char_u *)"Search ctermfg=black", FALSE, TRUE);
439f9cc9f20SBram Moolenaar     }
440f9cc9f20SBram Moolenaar 
441f9cc9f20SBram Moolenaar #ifdef FEAT_SYN_HL
442f9cc9f20SBram Moolenaar     /*
443f9cc9f20SBram Moolenaar      * If syntax highlighting is enabled load the highlighting for it.
444f9cc9f20SBram Moolenaar      */
445f9cc9f20SBram Moolenaar     if (get_var_value((char_u *)"g:syntax_on") != NULL)
446f9cc9f20SBram Moolenaar     {
447f9cc9f20SBram Moolenaar 	static int	recursive = 0;
448f9cc9f20SBram Moolenaar 
449f9cc9f20SBram Moolenaar 	if (recursive >= 5)
450f9cc9f20SBram Moolenaar 	    emsg(_("E679: recursive loop loading syncolor.vim"));
451f9cc9f20SBram Moolenaar 	else
452f9cc9f20SBram Moolenaar 	{
453f9cc9f20SBram Moolenaar 	    ++recursive;
454f9cc9f20SBram Moolenaar 	    (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL);
455f9cc9f20SBram Moolenaar 	    --recursive;
456f9cc9f20SBram Moolenaar 	}
457f9cc9f20SBram Moolenaar     }
458f9cc9f20SBram Moolenaar #endif
459f9cc9f20SBram Moolenaar }
460f9cc9f20SBram Moolenaar 
461f9cc9f20SBram Moolenaar /*
462f9cc9f20SBram Moolenaar  * Load color file "name".
463f9cc9f20SBram Moolenaar  * Return OK for success, FAIL for failure.
464f9cc9f20SBram Moolenaar  */
465f9cc9f20SBram Moolenaar     int
466f9cc9f20SBram Moolenaar load_colors(char_u *name)
467f9cc9f20SBram Moolenaar {
468f9cc9f20SBram Moolenaar     char_u	*buf;
469f9cc9f20SBram Moolenaar     int		retval = FAIL;
470f9cc9f20SBram Moolenaar     static int	recursive = FALSE;
471f9cc9f20SBram Moolenaar 
472f9cc9f20SBram Moolenaar     // When being called recursively, this is probably because setting
473f9cc9f20SBram Moolenaar     // 'background' caused the highlighting to be reloaded.  This means it is
474f9cc9f20SBram Moolenaar     // working, thus we should return OK.
475f9cc9f20SBram Moolenaar     if (recursive)
476f9cc9f20SBram Moolenaar 	return OK;
477f9cc9f20SBram Moolenaar 
478f9cc9f20SBram Moolenaar     recursive = TRUE;
479f9cc9f20SBram Moolenaar     buf = alloc(STRLEN(name) + 12);
480f9cc9f20SBram Moolenaar     if (buf != NULL)
481f9cc9f20SBram Moolenaar     {
482f9cc9f20SBram Moolenaar 	apply_autocmds(EVENT_COLORSCHEMEPRE, name,
483f9cc9f20SBram Moolenaar 					       curbuf->b_fname, FALSE, curbuf);
484f9cc9f20SBram Moolenaar 	sprintf((char *)buf, "colors/%s.vim", name);
485f9cc9f20SBram Moolenaar 	retval = source_runtime(buf, DIP_START + DIP_OPT);
486f9cc9f20SBram Moolenaar 	vim_free(buf);
487f9cc9f20SBram Moolenaar 	apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf);
488f9cc9f20SBram Moolenaar     }
489f9cc9f20SBram Moolenaar     recursive = FALSE;
490f9cc9f20SBram Moolenaar 
491f9cc9f20SBram Moolenaar     return retval;
492f9cc9f20SBram Moolenaar }
493f9cc9f20SBram Moolenaar 
494f9cc9f20SBram Moolenaar static char *(color_names[28]) = {
495f9cc9f20SBram Moolenaar 	    "Black", "DarkBlue", "DarkGreen", "DarkCyan",
496f9cc9f20SBram Moolenaar 	    "DarkRed", "DarkMagenta", "Brown", "DarkYellow",
497f9cc9f20SBram Moolenaar 	    "Gray", "Grey", "LightGray", "LightGrey",
498f9cc9f20SBram Moolenaar 	    "DarkGray", "DarkGrey",
499f9cc9f20SBram Moolenaar 	    "Blue", "LightBlue", "Green", "LightGreen",
500f9cc9f20SBram Moolenaar 	    "Cyan", "LightCyan", "Red", "LightRed", "Magenta",
501f9cc9f20SBram Moolenaar 	    "LightMagenta", "Yellow", "LightYellow", "White", "NONE"};
502f9cc9f20SBram Moolenaar 	    // indices:
503f9cc9f20SBram Moolenaar 	    // 0, 1, 2, 3,
504f9cc9f20SBram Moolenaar 	    // 4, 5, 6, 7,
505f9cc9f20SBram Moolenaar 	    // 8, 9, 10, 11,
506f9cc9f20SBram Moolenaar 	    // 12, 13,
507f9cc9f20SBram Moolenaar 	    // 14, 15, 16, 17,
508f9cc9f20SBram Moolenaar 	    // 18, 19, 20, 21, 22,
509f9cc9f20SBram Moolenaar 	    // 23, 24, 25, 26, 27
510f9cc9f20SBram Moolenaar static int color_numbers_16[28] = {0, 1, 2, 3,
511f9cc9f20SBram Moolenaar 				 4, 5, 6, 6,
512f9cc9f20SBram Moolenaar 				 7, 7, 7, 7,
513f9cc9f20SBram Moolenaar 				 8, 8,
514f9cc9f20SBram Moolenaar 				 9, 9, 10, 10,
515f9cc9f20SBram Moolenaar 				 11, 11, 12, 12, 13,
516f9cc9f20SBram Moolenaar 				 13, 14, 14, 15, -1};
517f9cc9f20SBram Moolenaar // for xterm with 88 colors...
518f9cc9f20SBram Moolenaar static int color_numbers_88[28] = {0, 4, 2, 6,
519f9cc9f20SBram Moolenaar 				 1, 5, 32, 72,
520f9cc9f20SBram Moolenaar 				 84, 84, 7, 7,
521f9cc9f20SBram Moolenaar 				 82, 82,
522f9cc9f20SBram Moolenaar 				 12, 43, 10, 61,
523f9cc9f20SBram Moolenaar 				 14, 63, 9, 74, 13,
524f9cc9f20SBram Moolenaar 				 75, 11, 78, 15, -1};
525f9cc9f20SBram Moolenaar // for xterm with 256 colors...
526f9cc9f20SBram Moolenaar static int color_numbers_256[28] = {0, 4, 2, 6,
527f9cc9f20SBram Moolenaar 				 1, 5, 130, 130,
528f9cc9f20SBram Moolenaar 				 248, 248, 7, 7,
529f9cc9f20SBram Moolenaar 				 242, 242,
530f9cc9f20SBram Moolenaar 				 12, 81, 10, 121,
531f9cc9f20SBram Moolenaar 				 14, 159, 9, 224, 13,
532f9cc9f20SBram Moolenaar 				 225, 11, 229, 15, -1};
533f9cc9f20SBram Moolenaar // for terminals with less than 16 colors...
534f9cc9f20SBram Moolenaar static int color_numbers_8[28] = {0, 4, 2, 6,
535f9cc9f20SBram Moolenaar 				 1, 5, 3, 3,
536f9cc9f20SBram Moolenaar 				 7, 7, 7, 7,
537f9cc9f20SBram Moolenaar 				 0+8, 0+8,
538f9cc9f20SBram Moolenaar 				 4+8, 4+8, 2+8, 2+8,
539f9cc9f20SBram Moolenaar 				 6+8, 6+8, 1+8, 1+8, 5+8,
540f9cc9f20SBram Moolenaar 				 5+8, 3+8, 3+8, 7+8, -1};
541f9cc9f20SBram Moolenaar 
542f9cc9f20SBram Moolenaar /*
543f9cc9f20SBram Moolenaar  * Lookup the "cterm" value to be used for color with index "idx" in
544f9cc9f20SBram Moolenaar  * color_names[].
545f9cc9f20SBram Moolenaar  * "boldp" will be set to TRUE or FALSE for a foreground color when using 8
546f9cc9f20SBram Moolenaar  * colors, otherwise it will be unchanged.
547f9cc9f20SBram Moolenaar  */
548f9cc9f20SBram Moolenaar     int
549f9cc9f20SBram Moolenaar lookup_color(int idx, int foreground, int *boldp)
550f9cc9f20SBram Moolenaar {
551f9cc9f20SBram Moolenaar     int		color = color_numbers_16[idx];
552f9cc9f20SBram Moolenaar     char_u	*p;
553f9cc9f20SBram Moolenaar 
554f9cc9f20SBram Moolenaar     // Use the _16 table to check if it's a valid color name.
555f9cc9f20SBram Moolenaar     if (color < 0)
556f9cc9f20SBram Moolenaar 	return -1;
557f9cc9f20SBram Moolenaar 
558f9cc9f20SBram Moolenaar     if (t_colors == 8)
559f9cc9f20SBram Moolenaar     {
560f9cc9f20SBram Moolenaar 	// t_Co is 8: use the 8 colors table
561f9cc9f20SBram Moolenaar #if defined(__QNXNTO__)
562f9cc9f20SBram Moolenaar 	color = color_numbers_8_qansi[idx];
563f9cc9f20SBram Moolenaar #else
564f9cc9f20SBram Moolenaar 	color = color_numbers_8[idx];
565f9cc9f20SBram Moolenaar #endif
566f9cc9f20SBram Moolenaar 	if (foreground)
567f9cc9f20SBram Moolenaar 	{
568f9cc9f20SBram Moolenaar 	    // set/reset bold attribute to get light foreground
569f9cc9f20SBram Moolenaar 	    // colors (on some terminals, e.g. "linux")
570f9cc9f20SBram Moolenaar 	    if (color & 8)
571f9cc9f20SBram Moolenaar 		*boldp = TRUE;
572f9cc9f20SBram Moolenaar 	    else
573f9cc9f20SBram Moolenaar 		*boldp = FALSE;
574f9cc9f20SBram Moolenaar 	}
575f9cc9f20SBram Moolenaar 	color &= 7;	// truncate to 8 colors
576f9cc9f20SBram Moolenaar     }
577f9cc9f20SBram Moolenaar     else if (t_colors == 16 || t_colors == 88
578f9cc9f20SBram Moolenaar 					   || t_colors >= 256)
579f9cc9f20SBram Moolenaar     {
580f9cc9f20SBram Moolenaar 	/*
581f9cc9f20SBram Moolenaar 	 * Guess: if the termcap entry ends in 'm', it is
582f9cc9f20SBram Moolenaar 	 * probably an xterm-like terminal.  Use the changed
583f9cc9f20SBram Moolenaar 	 * order for colors.
584f9cc9f20SBram Moolenaar 	 */
585f9cc9f20SBram Moolenaar 	if (*T_CAF != NUL)
586f9cc9f20SBram Moolenaar 	    p = T_CAF;
587f9cc9f20SBram Moolenaar 	else
588f9cc9f20SBram Moolenaar 	    p = T_CSF;
589f9cc9f20SBram Moolenaar 	if (*p != NUL && (t_colors > 256
590f9cc9f20SBram Moolenaar 			      || *(p + STRLEN(p) - 1) == 'm'))
591f9cc9f20SBram Moolenaar 	{
592f9cc9f20SBram Moolenaar 	    if (t_colors == 88)
593f9cc9f20SBram Moolenaar 		color = color_numbers_88[idx];
594f9cc9f20SBram Moolenaar 	    else if (t_colors >= 256)
595f9cc9f20SBram Moolenaar 		color = color_numbers_256[idx];
596f9cc9f20SBram Moolenaar 	    else
597f9cc9f20SBram Moolenaar 		color = color_numbers_8[idx];
598f9cc9f20SBram Moolenaar 	}
599f9cc9f20SBram Moolenaar #ifdef FEAT_TERMRESPONSE
600f9cc9f20SBram Moolenaar 	if (t_colors >= 256 && color == 15 && is_mac_terminal)
601f9cc9f20SBram Moolenaar 	    // Terminal.app has a bug: 15 is light grey. Use white
602f9cc9f20SBram Moolenaar 	    // from the color cube instead.
603f9cc9f20SBram Moolenaar 	    color = 231;
604f9cc9f20SBram Moolenaar #endif
605f9cc9f20SBram Moolenaar     }
606f9cc9f20SBram Moolenaar     return color;
607f9cc9f20SBram Moolenaar }
608f9cc9f20SBram Moolenaar 
609f9cc9f20SBram Moolenaar /*
610f9cc9f20SBram Moolenaar  * Handle the ":highlight .." command.
611f9cc9f20SBram Moolenaar  * When using ":hi clear" this is called recursively for each group with
612f9cc9f20SBram Moolenaar  * "forceit" and "init" both TRUE.
613f9cc9f20SBram Moolenaar  */
614f9cc9f20SBram Moolenaar     void
615f9cc9f20SBram Moolenaar do_highlight(
616f9cc9f20SBram Moolenaar     char_u	*line,
617f9cc9f20SBram Moolenaar     int		forceit,
618f9cc9f20SBram Moolenaar     int		init)	    // TRUE when called for initializing
619f9cc9f20SBram Moolenaar {
620f9cc9f20SBram Moolenaar     char_u	*name_end;
621f9cc9f20SBram Moolenaar     char_u	*p;
622f9cc9f20SBram Moolenaar     char_u	*linep;
623f9cc9f20SBram Moolenaar     char_u	*key_start;
624f9cc9f20SBram Moolenaar     char_u	*arg_start;
625f9cc9f20SBram Moolenaar     char_u	*key = NULL, *arg = NULL;
626f9cc9f20SBram Moolenaar     long	i;
627f9cc9f20SBram Moolenaar     int		off;
628f9cc9f20SBram Moolenaar     int		len;
629f9cc9f20SBram Moolenaar     int		attr;
630f9cc9f20SBram Moolenaar     int		id;
631f9cc9f20SBram Moolenaar     int		idx;
632f9cc9f20SBram Moolenaar     hl_group_T	item_before;
633f9cc9f20SBram Moolenaar     int		did_change = FALSE;
634f9cc9f20SBram Moolenaar     int		dodefault = FALSE;
635f9cc9f20SBram Moolenaar     int		doclear = FALSE;
636f9cc9f20SBram Moolenaar     int		dolink = FALSE;
637f9cc9f20SBram Moolenaar     int		error = FALSE;
638f9cc9f20SBram Moolenaar     int		color;
639f9cc9f20SBram Moolenaar     int		is_normal_group = FALSE;	// "Normal" group
640f9cc9f20SBram Moolenaar #ifdef FEAT_TERMINAL
641f9cc9f20SBram Moolenaar     int		is_terminal_group = FALSE;	// "Terminal" group
642f9cc9f20SBram Moolenaar #endif
643f9cc9f20SBram Moolenaar #ifdef FEAT_GUI_X11
644f9cc9f20SBram Moolenaar     int		is_menu_group = FALSE;		// "Menu" group
645f9cc9f20SBram Moolenaar     int		is_scrollbar_group = FALSE;	// "Scrollbar" group
646f9cc9f20SBram Moolenaar     int		is_tooltip_group = FALSE;	// "Tooltip" group
647f9cc9f20SBram Moolenaar     int		do_colors = FALSE;		// need to update colors?
648f9cc9f20SBram Moolenaar #else
649f9cc9f20SBram Moolenaar # define is_menu_group 0
650f9cc9f20SBram Moolenaar # define is_tooltip_group 0
651f9cc9f20SBram Moolenaar #endif
652f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
653f9cc9f20SBram Moolenaar     int		did_highlight_changed = FALSE;
654f9cc9f20SBram Moolenaar #endif
655f9cc9f20SBram Moolenaar 
656f9cc9f20SBram Moolenaar     /*
657f9cc9f20SBram Moolenaar      * If no argument, list current highlighting.
658f9cc9f20SBram Moolenaar      */
659f9cc9f20SBram Moolenaar     if (ends_excmd(*line))
660f9cc9f20SBram Moolenaar     {
661f9cc9f20SBram Moolenaar 	for (i = 1; i <= highlight_ga.ga_len && !got_int; ++i)
662f9cc9f20SBram Moolenaar 	    // TODO: only call when the group has attributes set
663f9cc9f20SBram Moolenaar 	    highlight_list_one((int)i);
664f9cc9f20SBram Moolenaar 	return;
665f9cc9f20SBram Moolenaar     }
666f9cc9f20SBram Moolenaar 
667f9cc9f20SBram Moolenaar     /*
668f9cc9f20SBram Moolenaar      * Isolate the name.
669f9cc9f20SBram Moolenaar      */
670f9cc9f20SBram Moolenaar     name_end = skiptowhite(line);
671f9cc9f20SBram Moolenaar     linep = skipwhite(name_end);
672f9cc9f20SBram Moolenaar 
673f9cc9f20SBram Moolenaar     /*
674f9cc9f20SBram Moolenaar      * Check for "default" argument.
675f9cc9f20SBram Moolenaar      */
676f9cc9f20SBram Moolenaar     if (STRNCMP(line, "default", name_end - line) == 0)
677f9cc9f20SBram Moolenaar     {
678f9cc9f20SBram Moolenaar 	dodefault = TRUE;
679f9cc9f20SBram Moolenaar 	line = linep;
680f9cc9f20SBram Moolenaar 	name_end = skiptowhite(line);
681f9cc9f20SBram Moolenaar 	linep = skipwhite(name_end);
682f9cc9f20SBram Moolenaar     }
683f9cc9f20SBram Moolenaar 
684f9cc9f20SBram Moolenaar     /*
685f9cc9f20SBram Moolenaar      * Check for "clear" or "link" argument.
686f9cc9f20SBram Moolenaar      */
687f9cc9f20SBram Moolenaar     if (STRNCMP(line, "clear", name_end - line) == 0)
688f9cc9f20SBram Moolenaar 	doclear = TRUE;
689f9cc9f20SBram Moolenaar     if (STRNCMP(line, "link", name_end - line) == 0)
690f9cc9f20SBram Moolenaar 	dolink = TRUE;
691f9cc9f20SBram Moolenaar 
692f9cc9f20SBram Moolenaar     /*
693f9cc9f20SBram Moolenaar      * ":highlight {group-name}": list highlighting for one group.
694f9cc9f20SBram Moolenaar      */
695f9cc9f20SBram Moolenaar     if (!doclear && !dolink && ends_excmd(*linep))
696f9cc9f20SBram Moolenaar     {
697f9cc9f20SBram Moolenaar 	id = syn_namen2id(line, (int)(name_end - line));
698f9cc9f20SBram Moolenaar 	if (id == 0)
699f9cc9f20SBram Moolenaar 	    semsg(_("E411: highlight group not found: %s"), line);
700f9cc9f20SBram Moolenaar 	else
701f9cc9f20SBram Moolenaar 	    highlight_list_one(id);
702f9cc9f20SBram Moolenaar 	return;
703f9cc9f20SBram Moolenaar     }
704f9cc9f20SBram Moolenaar 
705f9cc9f20SBram Moolenaar     /*
706f9cc9f20SBram Moolenaar      * Handle ":highlight link {from} {to}" command.
707f9cc9f20SBram Moolenaar      */
708f9cc9f20SBram Moolenaar     if (dolink)
709f9cc9f20SBram Moolenaar     {
710f9cc9f20SBram Moolenaar 	char_u	    *from_start = linep;
711f9cc9f20SBram Moolenaar 	char_u	    *from_end;
712f9cc9f20SBram Moolenaar 	char_u	    *to_start;
713f9cc9f20SBram Moolenaar 	char_u	    *to_end;
714f9cc9f20SBram Moolenaar 	int	    from_id;
715f9cc9f20SBram Moolenaar 	int	    to_id;
716f9cc9f20SBram Moolenaar 
717f9cc9f20SBram Moolenaar 	from_end = skiptowhite(from_start);
718f9cc9f20SBram Moolenaar 	to_start = skipwhite(from_end);
719f9cc9f20SBram Moolenaar 	to_end	 = skiptowhite(to_start);
720f9cc9f20SBram Moolenaar 
721f9cc9f20SBram Moolenaar 	if (ends_excmd(*from_start) || ends_excmd(*to_start))
722f9cc9f20SBram Moolenaar 	{
723f9cc9f20SBram Moolenaar 	    semsg(_("E412: Not enough arguments: \":highlight link %s\""),
724f9cc9f20SBram Moolenaar 								  from_start);
725f9cc9f20SBram Moolenaar 	    return;
726f9cc9f20SBram Moolenaar 	}
727f9cc9f20SBram Moolenaar 
728f9cc9f20SBram Moolenaar 	if (!ends_excmd(*skipwhite(to_end)))
729f9cc9f20SBram Moolenaar 	{
730f9cc9f20SBram Moolenaar 	    semsg(_("E413: Too many arguments: \":highlight link %s\""), from_start);
731f9cc9f20SBram Moolenaar 	    return;
732f9cc9f20SBram Moolenaar 	}
733f9cc9f20SBram Moolenaar 
734f9cc9f20SBram Moolenaar 	from_id = syn_check_group(from_start, (int)(from_end - from_start));
735f9cc9f20SBram Moolenaar 	if (STRNCMP(to_start, "NONE", 4) == 0)
736f9cc9f20SBram Moolenaar 	    to_id = 0;
737f9cc9f20SBram Moolenaar 	else
738f9cc9f20SBram Moolenaar 	    to_id = syn_check_group(to_start, (int)(to_end - to_start));
739f9cc9f20SBram Moolenaar 
740f9cc9f20SBram Moolenaar 	if (from_id > 0 && (!init || HL_TABLE()[from_id - 1].sg_set == 0))
741f9cc9f20SBram Moolenaar 	{
742f9cc9f20SBram Moolenaar 	    /*
743f9cc9f20SBram Moolenaar 	     * Don't allow a link when there already is some highlighting
744f9cc9f20SBram Moolenaar 	     * for the group, unless '!' is used
745f9cc9f20SBram Moolenaar 	     */
746f9cc9f20SBram Moolenaar 	    if (to_id > 0 && !forceit && !init
747f9cc9f20SBram Moolenaar 				   && hl_has_settings(from_id - 1, dodefault))
748f9cc9f20SBram Moolenaar 	    {
749f9cc9f20SBram Moolenaar 		if (sourcing_name == NULL && !dodefault)
750f9cc9f20SBram Moolenaar 		    emsg(_("E414: group has settings, highlight link ignored"));
751f9cc9f20SBram Moolenaar 	    }
752f9cc9f20SBram Moolenaar 	    else if (HL_TABLE()[from_id - 1].sg_link != to_id
753f9cc9f20SBram Moolenaar #ifdef FEAT_EVAL
754f9cc9f20SBram Moolenaar 		    || HL_TABLE()[from_id - 1].sg_script_ctx.sc_sid
755f9cc9f20SBram Moolenaar 							 != current_sctx.sc_sid
756f9cc9f20SBram Moolenaar #endif
757f9cc9f20SBram Moolenaar 		    || HL_TABLE()[from_id - 1].sg_cleared)
758f9cc9f20SBram Moolenaar 	    {
759f9cc9f20SBram Moolenaar 		if (!init)
760f9cc9f20SBram Moolenaar 		    HL_TABLE()[from_id - 1].sg_set |= SG_LINK;
761f9cc9f20SBram Moolenaar 		HL_TABLE()[from_id - 1].sg_link = to_id;
762f9cc9f20SBram Moolenaar #ifdef FEAT_EVAL
763f9cc9f20SBram Moolenaar 		HL_TABLE()[from_id - 1].sg_script_ctx = current_sctx;
764f9cc9f20SBram Moolenaar 		HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += sourcing_lnum;
765f9cc9f20SBram Moolenaar #endif
766f9cc9f20SBram Moolenaar 		HL_TABLE()[from_id - 1].sg_cleared = FALSE;
767f9cc9f20SBram Moolenaar 		redraw_all_later(SOME_VALID);
768f9cc9f20SBram Moolenaar 
769f9cc9f20SBram Moolenaar 		// Only call highlight_changed() once after multiple changes.
770f9cc9f20SBram Moolenaar 		need_highlight_changed = TRUE;
771f9cc9f20SBram Moolenaar 	    }
772f9cc9f20SBram Moolenaar 	}
773f9cc9f20SBram Moolenaar 
774f9cc9f20SBram Moolenaar 	return;
775f9cc9f20SBram Moolenaar     }
776f9cc9f20SBram Moolenaar 
777f9cc9f20SBram Moolenaar     if (doclear)
778f9cc9f20SBram Moolenaar     {
779f9cc9f20SBram Moolenaar 	/*
780f9cc9f20SBram Moolenaar 	 * ":highlight clear [group]" command.
781f9cc9f20SBram Moolenaar 	 */
782f9cc9f20SBram Moolenaar 	line = linep;
783f9cc9f20SBram Moolenaar 	if (ends_excmd(*line))
784f9cc9f20SBram Moolenaar 	{
785f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
786f9cc9f20SBram Moolenaar 	    // First, we do not destroy the old values, but allocate the new
787f9cc9f20SBram Moolenaar 	    // ones and update the display. THEN we destroy the old values.
788f9cc9f20SBram Moolenaar 	    // If we destroy the old values first, then the old values
789f9cc9f20SBram Moolenaar 	    // (such as GuiFont's or GuiFontset's) will still be displayed but
790f9cc9f20SBram Moolenaar 	    // invalid because they were free'd.
791f9cc9f20SBram Moolenaar 	    if (gui.in_use)
792f9cc9f20SBram Moolenaar 	    {
793f9cc9f20SBram Moolenaar # ifdef FEAT_BEVAL_TIP
794f9cc9f20SBram Moolenaar 		gui_init_tooltip_font();
795f9cc9f20SBram Moolenaar # endif
796f9cc9f20SBram Moolenaar # if defined(FEAT_MENU) && (defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MOTIF))
797f9cc9f20SBram Moolenaar 		gui_init_menu_font();
798f9cc9f20SBram Moolenaar # endif
799f9cc9f20SBram Moolenaar 	    }
800f9cc9f20SBram Moolenaar # if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_X11)
801f9cc9f20SBram Moolenaar 	    gui_mch_def_colors();
802f9cc9f20SBram Moolenaar # endif
803f9cc9f20SBram Moolenaar # ifdef FEAT_GUI_X11
804f9cc9f20SBram Moolenaar #  ifdef FEAT_MENU
805f9cc9f20SBram Moolenaar 
806f9cc9f20SBram Moolenaar 	    // This only needs to be done when there is no Menu highlight
807f9cc9f20SBram Moolenaar 	    // group defined by default, which IS currently the case.
808f9cc9f20SBram Moolenaar 	    gui_mch_new_menu_colors();
809f9cc9f20SBram Moolenaar #  endif
810f9cc9f20SBram Moolenaar 	    if (gui.in_use)
811f9cc9f20SBram Moolenaar 	    {
812f9cc9f20SBram Moolenaar 		gui_new_scrollbar_colors();
813f9cc9f20SBram Moolenaar #  ifdef FEAT_BEVAL_GUI
814f9cc9f20SBram Moolenaar 		gui_mch_new_tooltip_colors();
815f9cc9f20SBram Moolenaar #  endif
816f9cc9f20SBram Moolenaar #  ifdef FEAT_MENU
817f9cc9f20SBram Moolenaar 		gui_mch_new_menu_font();
818f9cc9f20SBram Moolenaar #  endif
819f9cc9f20SBram Moolenaar 	    }
820f9cc9f20SBram Moolenaar # endif
821f9cc9f20SBram Moolenaar 
822f9cc9f20SBram Moolenaar 	    // Ok, we're done allocating the new default graphics items.
823f9cc9f20SBram Moolenaar 	    // The screen should already be refreshed at this point.
824f9cc9f20SBram Moolenaar 	    // It is now Ok to clear out the old data.
825f9cc9f20SBram Moolenaar #endif
826f9cc9f20SBram Moolenaar #ifdef FEAT_EVAL
827f9cc9f20SBram Moolenaar 	    do_unlet((char_u *)"colors_name", TRUE);
828f9cc9f20SBram Moolenaar #endif
829f9cc9f20SBram Moolenaar 	    restore_cterm_colors();
830f9cc9f20SBram Moolenaar 
831f9cc9f20SBram Moolenaar 	    /*
832f9cc9f20SBram Moolenaar 	     * Clear all default highlight groups and load the defaults.
833f9cc9f20SBram Moolenaar 	     */
834f9cc9f20SBram Moolenaar 	    for (idx = 0; idx < highlight_ga.ga_len; ++idx)
835f9cc9f20SBram Moolenaar 		highlight_clear(idx);
836f9cc9f20SBram Moolenaar 	    init_highlight(TRUE, TRUE);
837f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
838f9cc9f20SBram Moolenaar 	    if (USE_24BIT)
839f9cc9f20SBram Moolenaar 		highlight_gui_started();
840f9cc9f20SBram Moolenaar 	    else
841f9cc9f20SBram Moolenaar #endif
842f9cc9f20SBram Moolenaar 		highlight_changed();
843f9cc9f20SBram Moolenaar 	    redraw_later_clear();
844f9cc9f20SBram Moolenaar 	    return;
845f9cc9f20SBram Moolenaar 	}
846f9cc9f20SBram Moolenaar 	name_end = skiptowhite(line);
847f9cc9f20SBram Moolenaar 	linep = skipwhite(name_end);
848f9cc9f20SBram Moolenaar     }
849f9cc9f20SBram Moolenaar 
850f9cc9f20SBram Moolenaar     /*
851f9cc9f20SBram Moolenaar      * Find the group name in the table.  If it does not exist yet, add it.
852f9cc9f20SBram Moolenaar      */
853f9cc9f20SBram Moolenaar     id = syn_check_group(line, (int)(name_end - line));
854f9cc9f20SBram Moolenaar     if (id == 0)			// failed (out of memory)
855f9cc9f20SBram Moolenaar 	return;
856f9cc9f20SBram Moolenaar     idx = id - 1;			// index is ID minus one
857f9cc9f20SBram Moolenaar 
858f9cc9f20SBram Moolenaar     // Return if "default" was used and the group already has settings.
859f9cc9f20SBram Moolenaar     if (dodefault && hl_has_settings(idx, TRUE))
860f9cc9f20SBram Moolenaar 	return;
861f9cc9f20SBram Moolenaar 
862f9cc9f20SBram Moolenaar     // Make a copy so we can check if any attribute actually changed.
863f9cc9f20SBram Moolenaar     item_before = HL_TABLE()[idx];
864f9cc9f20SBram Moolenaar 
865f9cc9f20SBram Moolenaar     if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
866f9cc9f20SBram Moolenaar 	is_normal_group = TRUE;
867f9cc9f20SBram Moolenaar #ifdef FEAT_TERMINAL
868f9cc9f20SBram Moolenaar     else if (STRCMP(HL_TABLE()[idx].sg_name_u, "TERMINAL") == 0)
869f9cc9f20SBram Moolenaar 	is_terminal_group = TRUE;
870f9cc9f20SBram Moolenaar #endif
871f9cc9f20SBram Moolenaar #ifdef FEAT_GUI_X11
872f9cc9f20SBram Moolenaar     else if (STRCMP(HL_TABLE()[idx].sg_name_u, "MENU") == 0)
873f9cc9f20SBram Moolenaar 	is_menu_group = TRUE;
874f9cc9f20SBram Moolenaar     else if (STRCMP(HL_TABLE()[idx].sg_name_u, "SCROLLBAR") == 0)
875f9cc9f20SBram Moolenaar 	is_scrollbar_group = TRUE;
876f9cc9f20SBram Moolenaar     else if (STRCMP(HL_TABLE()[idx].sg_name_u, "TOOLTIP") == 0)
877f9cc9f20SBram Moolenaar 	is_tooltip_group = TRUE;
878f9cc9f20SBram Moolenaar #endif
879f9cc9f20SBram Moolenaar 
880f9cc9f20SBram Moolenaar     // Clear the highlighting for ":hi clear {group}" and ":hi clear".
881f9cc9f20SBram Moolenaar     if (doclear || (forceit && init))
882f9cc9f20SBram Moolenaar     {
883f9cc9f20SBram Moolenaar 	highlight_clear(idx);
884f9cc9f20SBram Moolenaar 	if (!doclear)
885f9cc9f20SBram Moolenaar 	    HL_TABLE()[idx].sg_set = 0;
886f9cc9f20SBram Moolenaar     }
887f9cc9f20SBram Moolenaar 
888f9cc9f20SBram Moolenaar     if (!doclear)
889f9cc9f20SBram Moolenaar       while (!ends_excmd(*linep))
890f9cc9f20SBram Moolenaar       {
891f9cc9f20SBram Moolenaar 	key_start = linep;
892f9cc9f20SBram Moolenaar 	if (*linep == '=')
893f9cc9f20SBram Moolenaar 	{
894f9cc9f20SBram Moolenaar 	    semsg(_("E415: unexpected equal sign: %s"), key_start);
895f9cc9f20SBram Moolenaar 	    error = TRUE;
896f9cc9f20SBram Moolenaar 	    break;
897f9cc9f20SBram Moolenaar 	}
898f9cc9f20SBram Moolenaar 
899f9cc9f20SBram Moolenaar 	/*
900f9cc9f20SBram Moolenaar 	 * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or
901f9cc9f20SBram Moolenaar 	 * "guibg").
902f9cc9f20SBram Moolenaar 	 */
903f9cc9f20SBram Moolenaar 	while (*linep && !VIM_ISWHITE(*linep) && *linep != '=')
904f9cc9f20SBram Moolenaar 	    ++linep;
905f9cc9f20SBram Moolenaar 	vim_free(key);
906f9cc9f20SBram Moolenaar 	key = vim_strnsave_up(key_start, (int)(linep - key_start));
907f9cc9f20SBram Moolenaar 	if (key == NULL)
908f9cc9f20SBram Moolenaar 	{
909f9cc9f20SBram Moolenaar 	    error = TRUE;
910f9cc9f20SBram Moolenaar 	    break;
911f9cc9f20SBram Moolenaar 	}
912f9cc9f20SBram Moolenaar 	linep = skipwhite(linep);
913f9cc9f20SBram Moolenaar 
914f9cc9f20SBram Moolenaar 	if (STRCMP(key, "NONE") == 0)
915f9cc9f20SBram Moolenaar 	{
916f9cc9f20SBram Moolenaar 	    if (!init || HL_TABLE()[idx].sg_set == 0)
917f9cc9f20SBram Moolenaar 	    {
918f9cc9f20SBram Moolenaar 		if (!init)
919f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_set |= SG_TERM+SG_CTERM+SG_GUI;
920f9cc9f20SBram Moolenaar 		highlight_clear(idx);
921f9cc9f20SBram Moolenaar 	    }
922f9cc9f20SBram Moolenaar 	    continue;
923f9cc9f20SBram Moolenaar 	}
924f9cc9f20SBram Moolenaar 
925f9cc9f20SBram Moolenaar 	/*
926f9cc9f20SBram Moolenaar 	 * Check for the equal sign.
927f9cc9f20SBram Moolenaar 	 */
928f9cc9f20SBram Moolenaar 	if (*linep != '=')
929f9cc9f20SBram Moolenaar 	{
930f9cc9f20SBram Moolenaar 	    semsg(_("E416: missing equal sign: %s"), key_start);
931f9cc9f20SBram Moolenaar 	    error = TRUE;
932f9cc9f20SBram Moolenaar 	    break;
933f9cc9f20SBram Moolenaar 	}
934f9cc9f20SBram Moolenaar 	++linep;
935f9cc9f20SBram Moolenaar 
936f9cc9f20SBram Moolenaar 	/*
937f9cc9f20SBram Moolenaar 	 * Isolate the argument.
938f9cc9f20SBram Moolenaar 	 */
939f9cc9f20SBram Moolenaar 	linep = skipwhite(linep);
940f9cc9f20SBram Moolenaar 	if (*linep == '\'')		// guifg='color name'
941f9cc9f20SBram Moolenaar 	{
942f9cc9f20SBram Moolenaar 	    arg_start = ++linep;
943f9cc9f20SBram Moolenaar 	    linep = vim_strchr(linep, '\'');
944f9cc9f20SBram Moolenaar 	    if (linep == NULL)
945f9cc9f20SBram Moolenaar 	    {
946f9cc9f20SBram Moolenaar 		semsg(_(e_invarg2), key_start);
947f9cc9f20SBram Moolenaar 		error = TRUE;
948f9cc9f20SBram Moolenaar 		break;
949f9cc9f20SBram Moolenaar 	    }
950f9cc9f20SBram Moolenaar 	}
951f9cc9f20SBram Moolenaar 	else
952f9cc9f20SBram Moolenaar 	{
953f9cc9f20SBram Moolenaar 	    arg_start = linep;
954f9cc9f20SBram Moolenaar 	    linep = skiptowhite(linep);
955f9cc9f20SBram Moolenaar 	}
956f9cc9f20SBram Moolenaar 	if (linep == arg_start)
957f9cc9f20SBram Moolenaar 	{
958f9cc9f20SBram Moolenaar 	    semsg(_("E417: missing argument: %s"), key_start);
959f9cc9f20SBram Moolenaar 	    error = TRUE;
960f9cc9f20SBram Moolenaar 	    break;
961f9cc9f20SBram Moolenaar 	}
962f9cc9f20SBram Moolenaar 	vim_free(arg);
963f9cc9f20SBram Moolenaar 	arg = vim_strnsave(arg_start, (int)(linep - arg_start));
964f9cc9f20SBram Moolenaar 	if (arg == NULL)
965f9cc9f20SBram Moolenaar 	{
966f9cc9f20SBram Moolenaar 	    error = TRUE;
967f9cc9f20SBram Moolenaar 	    break;
968f9cc9f20SBram Moolenaar 	}
969f9cc9f20SBram Moolenaar 	if (*linep == '\'')
970f9cc9f20SBram Moolenaar 	    ++linep;
971f9cc9f20SBram Moolenaar 
972f9cc9f20SBram Moolenaar 	/*
973f9cc9f20SBram Moolenaar 	 * Store the argument.
974f9cc9f20SBram Moolenaar 	 */
975f9cc9f20SBram Moolenaar 	if (  STRCMP(key, "TERM") == 0
976f9cc9f20SBram Moolenaar 		|| STRCMP(key, "CTERM") == 0
977f9cc9f20SBram Moolenaar 		|| STRCMP(key, "GUI") == 0)
978f9cc9f20SBram Moolenaar 	{
979f9cc9f20SBram Moolenaar 	    attr = 0;
980f9cc9f20SBram Moolenaar 	    off = 0;
981f9cc9f20SBram Moolenaar 	    while (arg[off] != NUL)
982f9cc9f20SBram Moolenaar 	    {
983f9cc9f20SBram Moolenaar 		for (i = sizeof(hl_attr_table) / sizeof(int); --i >= 0; )
984f9cc9f20SBram Moolenaar 		{
985f9cc9f20SBram Moolenaar 		    len = (int)STRLEN(hl_name_table[i]);
986f9cc9f20SBram Moolenaar 		    if (STRNICMP(arg + off, hl_name_table[i], len) == 0)
987f9cc9f20SBram Moolenaar 		    {
988f9cc9f20SBram Moolenaar 			attr |= hl_attr_table[i];
989f9cc9f20SBram Moolenaar 			off += len;
990f9cc9f20SBram Moolenaar 			break;
991f9cc9f20SBram Moolenaar 		    }
992f9cc9f20SBram Moolenaar 		}
993f9cc9f20SBram Moolenaar 		if (i < 0)
994f9cc9f20SBram Moolenaar 		{
995f9cc9f20SBram Moolenaar 		    semsg(_("E418: Illegal value: %s"), arg);
996f9cc9f20SBram Moolenaar 		    error = TRUE;
997f9cc9f20SBram Moolenaar 		    break;
998f9cc9f20SBram Moolenaar 		}
999f9cc9f20SBram Moolenaar 		if (arg[off] == ',')		// another one follows
1000f9cc9f20SBram Moolenaar 		    ++off;
1001f9cc9f20SBram Moolenaar 	    }
1002f9cc9f20SBram Moolenaar 	    if (error)
1003f9cc9f20SBram Moolenaar 		break;
1004f9cc9f20SBram Moolenaar 	    if (*key == 'T')
1005f9cc9f20SBram Moolenaar 	    {
1006f9cc9f20SBram Moolenaar 		if (!init || !(HL_TABLE()[idx].sg_set & SG_TERM))
1007f9cc9f20SBram Moolenaar 		{
1008f9cc9f20SBram Moolenaar 		    if (!init)
1009f9cc9f20SBram Moolenaar 			HL_TABLE()[idx].sg_set |= SG_TERM;
1010f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_term = attr;
1011f9cc9f20SBram Moolenaar 		}
1012f9cc9f20SBram Moolenaar 	    }
1013f9cc9f20SBram Moolenaar 	    else if (*key == 'C')
1014f9cc9f20SBram Moolenaar 	    {
1015f9cc9f20SBram Moolenaar 		if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
1016f9cc9f20SBram Moolenaar 		{
1017f9cc9f20SBram Moolenaar 		    if (!init)
1018f9cc9f20SBram Moolenaar 			HL_TABLE()[idx].sg_set |= SG_CTERM;
1019f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_cterm = attr;
1020f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_cterm_bold = FALSE;
1021f9cc9f20SBram Moolenaar 		}
1022f9cc9f20SBram Moolenaar 	    }
1023f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
1024f9cc9f20SBram Moolenaar 	    else
1025f9cc9f20SBram Moolenaar 	    {
1026f9cc9f20SBram Moolenaar 		if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
1027f9cc9f20SBram Moolenaar 		{
1028f9cc9f20SBram Moolenaar 		    if (!init)
1029f9cc9f20SBram Moolenaar 			HL_TABLE()[idx].sg_set |= SG_GUI;
1030f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_gui = attr;
1031f9cc9f20SBram Moolenaar 		}
1032f9cc9f20SBram Moolenaar 	    }
1033f9cc9f20SBram Moolenaar #endif
1034f9cc9f20SBram Moolenaar 	}
1035f9cc9f20SBram Moolenaar 	else if (STRCMP(key, "FONT") == 0)
1036f9cc9f20SBram Moolenaar 	{
1037f9cc9f20SBram Moolenaar 	    // in non-GUI fonts are simply ignored
1038f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
1039f9cc9f20SBram Moolenaar 	    if (HL_TABLE()[idx].sg_font_name != NULL
1040f9cc9f20SBram Moolenaar 			     && STRCMP(HL_TABLE()[idx].sg_font_name, arg) == 0)
1041f9cc9f20SBram Moolenaar 	    {
1042f9cc9f20SBram Moolenaar 		// Font name didn't change, ignore.
1043f9cc9f20SBram Moolenaar 	    }
1044f9cc9f20SBram Moolenaar 	    else if (!gui.shell_created)
1045f9cc9f20SBram Moolenaar 	    {
1046f9cc9f20SBram Moolenaar 		// GUI not started yet, always accept the name.
1047f9cc9f20SBram Moolenaar 		vim_free(HL_TABLE()[idx].sg_font_name);
1048f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
1049f9cc9f20SBram Moolenaar 		did_change = TRUE;
1050f9cc9f20SBram Moolenaar 	    }
1051f9cc9f20SBram Moolenaar 	    else
1052f9cc9f20SBram Moolenaar 	    {
1053f9cc9f20SBram Moolenaar 		GuiFont temp_sg_font = HL_TABLE()[idx].sg_font;
1054f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
1055f9cc9f20SBram Moolenaar 		GuiFontset temp_sg_fontset = HL_TABLE()[idx].sg_fontset;
1056f9cc9f20SBram Moolenaar # endif
1057f9cc9f20SBram Moolenaar 		// First, save the current font/fontset.
1058f9cc9f20SBram Moolenaar 		// Then try to allocate the font/fontset.
1059f9cc9f20SBram Moolenaar 		// If the allocation fails, HL_TABLE()[idx].sg_font OR
1060f9cc9f20SBram Moolenaar 		// sg_fontset will be set to NOFONT or NOFONTSET respectively.
1061f9cc9f20SBram Moolenaar 
1062f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_font = NOFONT;
1063f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
1064f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_fontset = NOFONTSET;
1065f9cc9f20SBram Moolenaar # endif
1066f9cc9f20SBram Moolenaar 		hl_do_font(idx, arg, is_normal_group, is_menu_group,
1067f9cc9f20SBram Moolenaar 						     is_tooltip_group, FALSE);
1068f9cc9f20SBram Moolenaar 
1069f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
1070f9cc9f20SBram Moolenaar 		if (HL_TABLE()[idx].sg_fontset != NOFONTSET)
1071f9cc9f20SBram Moolenaar 		{
1072f9cc9f20SBram Moolenaar 		    // New fontset was accepted. Free the old one, if there
1073f9cc9f20SBram Moolenaar 		    // was one.
1074f9cc9f20SBram Moolenaar 		    gui_mch_free_fontset(temp_sg_fontset);
1075f9cc9f20SBram Moolenaar 		    vim_free(HL_TABLE()[idx].sg_font_name);
1076f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
1077f9cc9f20SBram Moolenaar 		    did_change = TRUE;
1078f9cc9f20SBram Moolenaar 		}
1079f9cc9f20SBram Moolenaar 		else
1080f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_fontset = temp_sg_fontset;
1081f9cc9f20SBram Moolenaar # endif
1082f9cc9f20SBram Moolenaar 		if (HL_TABLE()[idx].sg_font != NOFONT)
1083f9cc9f20SBram Moolenaar 		{
1084f9cc9f20SBram Moolenaar 		    // New font was accepted. Free the old one, if there was
1085f9cc9f20SBram Moolenaar 		    // one.
1086f9cc9f20SBram Moolenaar 		    gui_mch_free_font(temp_sg_font);
1087f9cc9f20SBram Moolenaar 		    vim_free(HL_TABLE()[idx].sg_font_name);
1088f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
1089f9cc9f20SBram Moolenaar 		    did_change = TRUE;
1090f9cc9f20SBram Moolenaar 		}
1091f9cc9f20SBram Moolenaar 		else
1092f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_font = temp_sg_font;
1093f9cc9f20SBram Moolenaar 	    }
1094f9cc9f20SBram Moolenaar #endif
1095f9cc9f20SBram Moolenaar 	}
1096f9cc9f20SBram Moolenaar 	else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0)
1097f9cc9f20SBram Moolenaar 	{
1098f9cc9f20SBram Moolenaar 	  if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
1099f9cc9f20SBram Moolenaar 	  {
1100f9cc9f20SBram Moolenaar 	    if (!init)
1101f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_set |= SG_CTERM;
1102f9cc9f20SBram Moolenaar 
1103f9cc9f20SBram Moolenaar 	    // When setting the foreground color, and previously the "bold"
1104f9cc9f20SBram Moolenaar 	    // flag was set for a light color, reset it now
1105f9cc9f20SBram Moolenaar 	    if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold)
1106f9cc9f20SBram Moolenaar 	    {
1107f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
1108f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_cterm_bold = FALSE;
1109f9cc9f20SBram Moolenaar 	    }
1110f9cc9f20SBram Moolenaar 
1111f9cc9f20SBram Moolenaar 	    if (VIM_ISDIGIT(*arg))
1112f9cc9f20SBram Moolenaar 		color = atoi((char *)arg);
1113f9cc9f20SBram Moolenaar 	    else if (STRICMP(arg, "fg") == 0)
1114f9cc9f20SBram Moolenaar 	    {
1115f9cc9f20SBram Moolenaar 		if (cterm_normal_fg_color)
1116f9cc9f20SBram Moolenaar 		    color = cterm_normal_fg_color - 1;
1117f9cc9f20SBram Moolenaar 		else
1118f9cc9f20SBram Moolenaar 		{
1119f9cc9f20SBram Moolenaar 		    emsg(_("E419: FG color unknown"));
1120f9cc9f20SBram Moolenaar 		    error = TRUE;
1121f9cc9f20SBram Moolenaar 		    break;
1122f9cc9f20SBram Moolenaar 		}
1123f9cc9f20SBram Moolenaar 	    }
1124f9cc9f20SBram Moolenaar 	    else if (STRICMP(arg, "bg") == 0)
1125f9cc9f20SBram Moolenaar 	    {
1126f9cc9f20SBram Moolenaar 		if (cterm_normal_bg_color > 0)
1127f9cc9f20SBram Moolenaar 		    color = cterm_normal_bg_color - 1;
1128f9cc9f20SBram Moolenaar 		else
1129f9cc9f20SBram Moolenaar 		{
1130f9cc9f20SBram Moolenaar 		    emsg(_("E420: BG color unknown"));
1131f9cc9f20SBram Moolenaar 		    error = TRUE;
1132f9cc9f20SBram Moolenaar 		    break;
1133f9cc9f20SBram Moolenaar 		}
1134f9cc9f20SBram Moolenaar 	    }
1135f9cc9f20SBram Moolenaar 	    else
1136f9cc9f20SBram Moolenaar 	    {
1137f9cc9f20SBram Moolenaar 		int bold = MAYBE;
1138f9cc9f20SBram Moolenaar 
1139f9cc9f20SBram Moolenaar #if defined(__QNXNTO__)
1140f9cc9f20SBram Moolenaar 		static int *color_numbers_8_qansi = color_numbers_8;
1141f9cc9f20SBram Moolenaar 		// On qnx, the 8 & 16 color arrays are the same
1142f9cc9f20SBram Moolenaar 		if (STRNCMP(T_NAME, "qansi", 5) == 0)
1143f9cc9f20SBram Moolenaar 		    color_numbers_8_qansi = color_numbers_16;
1144f9cc9f20SBram Moolenaar #endif
1145f9cc9f20SBram Moolenaar 
1146f9cc9f20SBram Moolenaar 		// reduce calls to STRICMP a bit, it can be slow
1147f9cc9f20SBram Moolenaar 		off = TOUPPER_ASC(*arg);
1148f9cc9f20SBram Moolenaar 		for (i = (sizeof(color_names) / sizeof(char *)); --i >= 0; )
1149f9cc9f20SBram Moolenaar 		    if (off == color_names[i][0]
1150f9cc9f20SBram Moolenaar 				 && STRICMP(arg + 1, color_names[i] + 1) == 0)
1151f9cc9f20SBram Moolenaar 			break;
1152f9cc9f20SBram Moolenaar 		if (i < 0)
1153f9cc9f20SBram Moolenaar 		{
1154f9cc9f20SBram Moolenaar 		    semsg(_("E421: Color name or number not recognized: %s"), key_start);
1155f9cc9f20SBram Moolenaar 		    error = TRUE;
1156f9cc9f20SBram Moolenaar 		    break;
1157f9cc9f20SBram Moolenaar 		}
1158f9cc9f20SBram Moolenaar 
1159f9cc9f20SBram Moolenaar 		color = lookup_color(i, key[5] == 'F', &bold);
1160f9cc9f20SBram Moolenaar 
1161f9cc9f20SBram Moolenaar 		// set/reset bold attribute to get light foreground
1162f9cc9f20SBram Moolenaar 		// colors (on some terminals, e.g. "linux")
1163f9cc9f20SBram Moolenaar 		if (bold == TRUE)
1164f9cc9f20SBram Moolenaar 		{
1165f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_cterm |= HL_BOLD;
1166f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_cterm_bold = TRUE;
1167f9cc9f20SBram Moolenaar 		}
1168f9cc9f20SBram Moolenaar 		else if (bold == FALSE)
1169f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
1170f9cc9f20SBram Moolenaar 	    }
1171f9cc9f20SBram Moolenaar 
1172f9cc9f20SBram Moolenaar 	    // Add one to the argument, to avoid zero.  Zero is used for
1173f9cc9f20SBram Moolenaar 	    // "NONE", then "color" is -1.
1174f9cc9f20SBram Moolenaar 	    if (key[5] == 'F')
1175f9cc9f20SBram Moolenaar 	    {
1176f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_cterm_fg = color + 1;
1177f9cc9f20SBram Moolenaar 		if (is_normal_group)
1178f9cc9f20SBram Moolenaar 		{
1179f9cc9f20SBram Moolenaar 		    cterm_normal_fg_color = color + 1;
1180f9cc9f20SBram Moolenaar 		    cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
1181f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
1182f9cc9f20SBram Moolenaar 		    // Don't do this if the GUI is used.
1183f9cc9f20SBram Moolenaar 		    if (!gui.in_use && !gui.starting)
1184f9cc9f20SBram Moolenaar #endif
1185f9cc9f20SBram Moolenaar 		    {
1186f9cc9f20SBram Moolenaar 			must_redraw = CLEAR;
1187f9cc9f20SBram Moolenaar 			if (termcap_active && color >= 0)
1188f9cc9f20SBram Moolenaar 			    term_fg_color(color);
1189f9cc9f20SBram Moolenaar 		    }
1190f9cc9f20SBram Moolenaar 		}
1191f9cc9f20SBram Moolenaar 	    }
1192f9cc9f20SBram Moolenaar 	    else
1193f9cc9f20SBram Moolenaar 	    {
1194f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_cterm_bg = color + 1;
1195f9cc9f20SBram Moolenaar 		if (is_normal_group)
1196f9cc9f20SBram Moolenaar 		{
1197f9cc9f20SBram Moolenaar 		    cterm_normal_bg_color = color + 1;
1198f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
1199f9cc9f20SBram Moolenaar 		    // Don't mess with 'background' if the GUI is used.
1200f9cc9f20SBram Moolenaar 		    if (!gui.in_use && !gui.starting)
1201f9cc9f20SBram Moolenaar #endif
1202f9cc9f20SBram Moolenaar 		    {
1203f9cc9f20SBram Moolenaar 			must_redraw = CLEAR;
1204f9cc9f20SBram Moolenaar 			if (color >= 0)
1205f9cc9f20SBram Moolenaar 			{
1206f9cc9f20SBram Moolenaar 			    int dark = -1;
1207f9cc9f20SBram Moolenaar 
1208f9cc9f20SBram Moolenaar 			    if (termcap_active)
1209f9cc9f20SBram Moolenaar 				term_bg_color(color);
1210f9cc9f20SBram Moolenaar 			    if (t_colors < 16)
1211f9cc9f20SBram Moolenaar 				dark = (color == 0 || color == 4);
1212f9cc9f20SBram Moolenaar 			    // Limit the heuristic to the standard 16 colors
1213f9cc9f20SBram Moolenaar 			    else if (color < 16)
1214f9cc9f20SBram Moolenaar 				dark = (color < 7 || color == 8);
1215f9cc9f20SBram Moolenaar 			    // Set the 'background' option if the value is
1216f9cc9f20SBram Moolenaar 			    // wrong.
1217f9cc9f20SBram Moolenaar 			    if (dark != -1
1218f9cc9f20SBram Moolenaar 				    && dark != (*p_bg == 'd')
1219f9cc9f20SBram Moolenaar 				    && !option_was_set((char_u *)"bg"))
1220f9cc9f20SBram Moolenaar 			    {
1221f9cc9f20SBram Moolenaar 				set_option_value((char_u *)"bg", 0L,
1222f9cc9f20SBram Moolenaar 				       (char_u *)(dark ? "dark" : "light"), 0);
1223f9cc9f20SBram Moolenaar 				reset_option_was_set((char_u *)"bg");
1224f9cc9f20SBram Moolenaar 			    }
1225f9cc9f20SBram Moolenaar 			}
1226f9cc9f20SBram Moolenaar 		    }
1227f9cc9f20SBram Moolenaar 		}
1228f9cc9f20SBram Moolenaar 	    }
1229f9cc9f20SBram Moolenaar 	  }
1230f9cc9f20SBram Moolenaar 	}
1231f9cc9f20SBram Moolenaar 	else if (STRCMP(key, "GUIFG") == 0)
1232f9cc9f20SBram Moolenaar 	{
1233f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
1234f9cc9f20SBram Moolenaar 	    char_u **namep = &HL_TABLE()[idx].sg_gui_fg_name;
1235f9cc9f20SBram Moolenaar 
1236f9cc9f20SBram Moolenaar 	    if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
1237f9cc9f20SBram Moolenaar 	    {
1238f9cc9f20SBram Moolenaar 		if (!init)
1239f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_set |= SG_GUI;
1240f9cc9f20SBram Moolenaar 
1241f9cc9f20SBram Moolenaar # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
1242f9cc9f20SBram Moolenaar 		// In GUI guifg colors are only used when recognized
1243f9cc9f20SBram Moolenaar 		i = color_name2handle(arg);
1244f9cc9f20SBram Moolenaar 		if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
1245f9cc9f20SBram Moolenaar 		{
1246f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_gui_fg = i;
1247f9cc9f20SBram Moolenaar # endif
1248f9cc9f20SBram Moolenaar 		    if (*namep == NULL || STRCMP(*namep, arg) != 0)
1249f9cc9f20SBram Moolenaar 		    {
1250f9cc9f20SBram Moolenaar 			vim_free(*namep);
1251f9cc9f20SBram Moolenaar 			if (STRCMP(arg, "NONE") != 0)
1252f9cc9f20SBram Moolenaar 			    *namep = vim_strsave(arg);
1253f9cc9f20SBram Moolenaar 			else
1254f9cc9f20SBram Moolenaar 			    *namep = NULL;
1255f9cc9f20SBram Moolenaar 			did_change = TRUE;
1256f9cc9f20SBram Moolenaar 		    }
1257f9cc9f20SBram Moolenaar # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
1258f9cc9f20SBram Moolenaar #  ifdef FEAT_GUI_X11
1259f9cc9f20SBram Moolenaar 		    if (is_menu_group && gui.menu_fg_pixel != i)
1260f9cc9f20SBram Moolenaar 		    {
1261f9cc9f20SBram Moolenaar 			gui.menu_fg_pixel = i;
1262f9cc9f20SBram Moolenaar 			do_colors = TRUE;
1263f9cc9f20SBram Moolenaar 		    }
1264f9cc9f20SBram Moolenaar 		    if (is_scrollbar_group && gui.scroll_fg_pixel != i)
1265f9cc9f20SBram Moolenaar 		    {
1266f9cc9f20SBram Moolenaar 			gui.scroll_fg_pixel = i;
1267f9cc9f20SBram Moolenaar 			do_colors = TRUE;
1268f9cc9f20SBram Moolenaar 		    }
1269f9cc9f20SBram Moolenaar #   ifdef FEAT_BEVAL_GUI
1270f9cc9f20SBram Moolenaar 		    if (is_tooltip_group && gui.tooltip_fg_pixel != i)
1271f9cc9f20SBram Moolenaar 		    {
1272f9cc9f20SBram Moolenaar 			gui.tooltip_fg_pixel = i;
1273f9cc9f20SBram Moolenaar 			do_colors = TRUE;
1274f9cc9f20SBram Moolenaar 		    }
1275f9cc9f20SBram Moolenaar #   endif
1276f9cc9f20SBram Moolenaar #  endif
1277f9cc9f20SBram Moolenaar 		}
1278f9cc9f20SBram Moolenaar # endif
1279f9cc9f20SBram Moolenaar 	    }
1280f9cc9f20SBram Moolenaar #endif
1281f9cc9f20SBram Moolenaar 	}
1282f9cc9f20SBram Moolenaar 	else if (STRCMP(key, "GUIBG") == 0)
1283f9cc9f20SBram Moolenaar 	{
1284f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
1285f9cc9f20SBram Moolenaar 	    char_u **namep = &HL_TABLE()[idx].sg_gui_bg_name;
1286f9cc9f20SBram Moolenaar 
1287f9cc9f20SBram Moolenaar 	    if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
1288f9cc9f20SBram Moolenaar 	    {
1289f9cc9f20SBram Moolenaar 		if (!init)
1290f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_set |= SG_GUI;
1291f9cc9f20SBram Moolenaar 
1292f9cc9f20SBram Moolenaar # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
1293f9cc9f20SBram Moolenaar 		// In GUI guifg colors are only used when recognized
1294f9cc9f20SBram Moolenaar 		i = color_name2handle(arg);
1295f9cc9f20SBram Moolenaar 		if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
1296f9cc9f20SBram Moolenaar 		{
1297f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_gui_bg = i;
1298f9cc9f20SBram Moolenaar # endif
1299f9cc9f20SBram Moolenaar 		    if (*namep == NULL || STRCMP(*namep, arg) != 0)
1300f9cc9f20SBram Moolenaar 		    {
1301f9cc9f20SBram Moolenaar 			vim_free(*namep);
1302f9cc9f20SBram Moolenaar 			if (STRCMP(arg, "NONE") != 0)
1303f9cc9f20SBram Moolenaar 			    *namep = vim_strsave(arg);
1304f9cc9f20SBram Moolenaar 			else
1305f9cc9f20SBram Moolenaar 			    *namep = NULL;
1306f9cc9f20SBram Moolenaar 			did_change = TRUE;
1307f9cc9f20SBram Moolenaar 		    }
1308f9cc9f20SBram Moolenaar # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
1309f9cc9f20SBram Moolenaar #  ifdef FEAT_GUI_X11
1310f9cc9f20SBram Moolenaar 		    if (is_menu_group && gui.menu_bg_pixel != i)
1311f9cc9f20SBram Moolenaar 		    {
1312f9cc9f20SBram Moolenaar 			gui.menu_bg_pixel = i;
1313f9cc9f20SBram Moolenaar 			do_colors = TRUE;
1314f9cc9f20SBram Moolenaar 		    }
1315f9cc9f20SBram Moolenaar 		    if (is_scrollbar_group && gui.scroll_bg_pixel != i)
1316f9cc9f20SBram Moolenaar 		    {
1317f9cc9f20SBram Moolenaar 			gui.scroll_bg_pixel = i;
1318f9cc9f20SBram Moolenaar 			do_colors = TRUE;
1319f9cc9f20SBram Moolenaar 		    }
1320f9cc9f20SBram Moolenaar #   ifdef FEAT_BEVAL_GUI
1321f9cc9f20SBram Moolenaar 		    if (is_tooltip_group && gui.tooltip_bg_pixel != i)
1322f9cc9f20SBram Moolenaar 		    {
1323f9cc9f20SBram Moolenaar 			gui.tooltip_bg_pixel = i;
1324f9cc9f20SBram Moolenaar 			do_colors = TRUE;
1325f9cc9f20SBram Moolenaar 		    }
1326f9cc9f20SBram Moolenaar #   endif
1327f9cc9f20SBram Moolenaar #  endif
1328f9cc9f20SBram Moolenaar 		}
1329f9cc9f20SBram Moolenaar # endif
1330f9cc9f20SBram Moolenaar 	    }
1331f9cc9f20SBram Moolenaar #endif
1332f9cc9f20SBram Moolenaar 	}
1333f9cc9f20SBram Moolenaar 	else if (STRCMP(key, "GUISP") == 0)
1334f9cc9f20SBram Moolenaar 	{
1335f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
1336f9cc9f20SBram Moolenaar 	    char_u **namep = &HL_TABLE()[idx].sg_gui_sp_name;
1337f9cc9f20SBram Moolenaar 
1338f9cc9f20SBram Moolenaar 	    if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
1339f9cc9f20SBram Moolenaar 	    {
1340f9cc9f20SBram Moolenaar 		if (!init)
1341f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_set |= SG_GUI;
1342f9cc9f20SBram Moolenaar 
1343f9cc9f20SBram Moolenaar # ifdef FEAT_GUI
1344f9cc9f20SBram Moolenaar 		i = color_name2handle(arg);
1345f9cc9f20SBram Moolenaar 		if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !gui.in_use)
1346f9cc9f20SBram Moolenaar 		{
1347f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_gui_sp = i;
1348f9cc9f20SBram Moolenaar # endif
1349f9cc9f20SBram Moolenaar 		    if (*namep == NULL || STRCMP(*namep, arg) != 0)
1350f9cc9f20SBram Moolenaar 		    {
1351f9cc9f20SBram Moolenaar 			vim_free(*namep);
1352f9cc9f20SBram Moolenaar 			if (STRCMP(arg, "NONE") != 0)
1353f9cc9f20SBram Moolenaar 			    *namep = vim_strsave(arg);
1354f9cc9f20SBram Moolenaar 			else
1355f9cc9f20SBram Moolenaar 			    *namep = NULL;
1356f9cc9f20SBram Moolenaar 			did_change = TRUE;
1357f9cc9f20SBram Moolenaar 		    }
1358f9cc9f20SBram Moolenaar # ifdef FEAT_GUI
1359f9cc9f20SBram Moolenaar 		}
1360f9cc9f20SBram Moolenaar # endif
1361f9cc9f20SBram Moolenaar 	    }
1362f9cc9f20SBram Moolenaar #endif
1363f9cc9f20SBram Moolenaar 	}
1364f9cc9f20SBram Moolenaar 	else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0)
1365f9cc9f20SBram Moolenaar 	{
1366f9cc9f20SBram Moolenaar 	    char_u	buf[100];
1367f9cc9f20SBram Moolenaar 	    char_u	*tname;
1368f9cc9f20SBram Moolenaar 
1369f9cc9f20SBram Moolenaar 	    if (!init)
1370f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_set |= SG_TERM;
1371f9cc9f20SBram Moolenaar 
1372f9cc9f20SBram Moolenaar 	    /*
1373f9cc9f20SBram Moolenaar 	     * The "start" and "stop"  arguments can be a literal escape
1374f9cc9f20SBram Moolenaar 	     * sequence, or a comma separated list of terminal codes.
1375f9cc9f20SBram Moolenaar 	     */
1376f9cc9f20SBram Moolenaar 	    if (STRNCMP(arg, "t_", 2) == 0)
1377f9cc9f20SBram Moolenaar 	    {
1378f9cc9f20SBram Moolenaar 		off = 0;
1379f9cc9f20SBram Moolenaar 		buf[0] = 0;
1380f9cc9f20SBram Moolenaar 		while (arg[off] != NUL)
1381f9cc9f20SBram Moolenaar 		{
1382f9cc9f20SBram Moolenaar 		    // Isolate one termcap name
1383f9cc9f20SBram Moolenaar 		    for (len = 0; arg[off + len] &&
1384f9cc9f20SBram Moolenaar 						 arg[off + len] != ','; ++len)
1385f9cc9f20SBram Moolenaar 			;
1386f9cc9f20SBram Moolenaar 		    tname = vim_strnsave(arg + off, len);
1387f9cc9f20SBram Moolenaar 		    if (tname == NULL)		// out of memory
1388f9cc9f20SBram Moolenaar 		    {
1389f9cc9f20SBram Moolenaar 			error = TRUE;
1390f9cc9f20SBram Moolenaar 			break;
1391f9cc9f20SBram Moolenaar 		    }
1392f9cc9f20SBram Moolenaar 		    // lookup the escape sequence for the item
1393f9cc9f20SBram Moolenaar 		    p = get_term_code(tname);
1394f9cc9f20SBram Moolenaar 		    vim_free(tname);
1395f9cc9f20SBram Moolenaar 		    if (p == NULL)	    // ignore non-existing things
1396f9cc9f20SBram Moolenaar 			p = (char_u *)"";
1397f9cc9f20SBram Moolenaar 
1398f9cc9f20SBram Moolenaar 		    // Append it to the already found stuff
1399f9cc9f20SBram Moolenaar 		    if ((int)(STRLEN(buf) + STRLEN(p)) >= 99)
1400f9cc9f20SBram Moolenaar 		    {
1401f9cc9f20SBram Moolenaar 			semsg(_("E422: terminal code too long: %s"), arg);
1402f9cc9f20SBram Moolenaar 			error = TRUE;
1403f9cc9f20SBram Moolenaar 			break;
1404f9cc9f20SBram Moolenaar 		    }
1405f9cc9f20SBram Moolenaar 		    STRCAT(buf, p);
1406f9cc9f20SBram Moolenaar 
1407f9cc9f20SBram Moolenaar 		    // Advance to the next item
1408f9cc9f20SBram Moolenaar 		    off += len;
1409f9cc9f20SBram Moolenaar 		    if (arg[off] == ',')	    // another one follows
1410f9cc9f20SBram Moolenaar 			++off;
1411f9cc9f20SBram Moolenaar 		}
1412f9cc9f20SBram Moolenaar 	    }
1413f9cc9f20SBram Moolenaar 	    else
1414f9cc9f20SBram Moolenaar 	    {
1415f9cc9f20SBram Moolenaar 		/*
1416f9cc9f20SBram Moolenaar 		 * Copy characters from arg[] to buf[], translating <> codes.
1417f9cc9f20SBram Moolenaar 		 */
1418f9cc9f20SBram Moolenaar 		for (p = arg, off = 0; off < 100 - 6 && *p; )
1419f9cc9f20SBram Moolenaar 		{
1420459fd785SBram Moolenaar 		    len = trans_special(&p, buf + off, FALSE, FALSE,
1421459fd785SBram Moolenaar 								   TRUE, NULL);
1422f9cc9f20SBram Moolenaar 		    if (len > 0)	    // recognized special char
1423f9cc9f20SBram Moolenaar 			off += len;
1424f9cc9f20SBram Moolenaar 		    else		    // copy as normal char
1425f9cc9f20SBram Moolenaar 			buf[off++] = *p++;
1426f9cc9f20SBram Moolenaar 		}
1427f9cc9f20SBram Moolenaar 		buf[off] = NUL;
1428f9cc9f20SBram Moolenaar 	    }
1429f9cc9f20SBram Moolenaar 	    if (error)
1430f9cc9f20SBram Moolenaar 		break;
1431f9cc9f20SBram Moolenaar 
1432f9cc9f20SBram Moolenaar 	    if (STRCMP(buf, "NONE") == 0)	// resetting the value
1433f9cc9f20SBram Moolenaar 		p = NULL;
1434f9cc9f20SBram Moolenaar 	    else
1435f9cc9f20SBram Moolenaar 		p = vim_strsave(buf);
1436f9cc9f20SBram Moolenaar 	    if (key[2] == 'A')
1437f9cc9f20SBram Moolenaar 	    {
1438f9cc9f20SBram Moolenaar 		vim_free(HL_TABLE()[idx].sg_start);
1439f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_start = p;
1440f9cc9f20SBram Moolenaar 	    }
1441f9cc9f20SBram Moolenaar 	    else
1442f9cc9f20SBram Moolenaar 	    {
1443f9cc9f20SBram Moolenaar 		vim_free(HL_TABLE()[idx].sg_stop);
1444f9cc9f20SBram Moolenaar 		HL_TABLE()[idx].sg_stop = p;
1445f9cc9f20SBram Moolenaar 	    }
1446f9cc9f20SBram Moolenaar 	}
1447f9cc9f20SBram Moolenaar 	else
1448f9cc9f20SBram Moolenaar 	{
1449f9cc9f20SBram Moolenaar 	    semsg(_("E423: Illegal argument: %s"), key_start);
1450f9cc9f20SBram Moolenaar 	    error = TRUE;
1451f9cc9f20SBram Moolenaar 	    break;
1452f9cc9f20SBram Moolenaar 	}
1453f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_cleared = FALSE;
1454f9cc9f20SBram Moolenaar 
1455f9cc9f20SBram Moolenaar 	/*
1456f9cc9f20SBram Moolenaar 	 * When highlighting has been given for a group, don't link it.
1457f9cc9f20SBram Moolenaar 	 */
1458f9cc9f20SBram Moolenaar 	if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK))
1459f9cc9f20SBram Moolenaar 	    HL_TABLE()[idx].sg_link = 0;
1460f9cc9f20SBram Moolenaar 
1461f9cc9f20SBram Moolenaar 	/*
1462f9cc9f20SBram Moolenaar 	 * Continue with next argument.
1463f9cc9f20SBram Moolenaar 	 */
1464f9cc9f20SBram Moolenaar 	linep = skipwhite(linep);
1465f9cc9f20SBram Moolenaar       }
1466f9cc9f20SBram Moolenaar 
1467f9cc9f20SBram Moolenaar     /*
1468f9cc9f20SBram Moolenaar      * If there is an error, and it's a new entry, remove it from the table.
1469f9cc9f20SBram Moolenaar      */
1470f9cc9f20SBram Moolenaar     if (error && idx == highlight_ga.ga_len)
1471f9cc9f20SBram Moolenaar 	syn_unadd_group();
1472f9cc9f20SBram Moolenaar     else
1473f9cc9f20SBram Moolenaar     {
1474f9cc9f20SBram Moolenaar 	if (is_normal_group)
1475f9cc9f20SBram Moolenaar 	{
1476f9cc9f20SBram Moolenaar 	    HL_TABLE()[idx].sg_term_attr = 0;
1477f9cc9f20SBram Moolenaar 	    HL_TABLE()[idx].sg_cterm_attr = 0;
1478f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
1479f9cc9f20SBram Moolenaar 	    HL_TABLE()[idx].sg_gui_attr = 0;
1480f9cc9f20SBram Moolenaar 	    /*
1481f9cc9f20SBram Moolenaar 	     * Need to update all groups, because they might be using "bg"
1482f9cc9f20SBram Moolenaar 	     * and/or "fg", which have been changed now.
1483f9cc9f20SBram Moolenaar 	     */
1484f9cc9f20SBram Moolenaar #endif
1485f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
1486f9cc9f20SBram Moolenaar 	    if (USE_24BIT)
1487f9cc9f20SBram Moolenaar 	    {
1488f9cc9f20SBram Moolenaar 		highlight_gui_started();
1489f9cc9f20SBram Moolenaar 		did_highlight_changed = TRUE;
1490f9cc9f20SBram Moolenaar 		redraw_all_later(NOT_VALID);
1491f9cc9f20SBram Moolenaar 	    }
1492f9cc9f20SBram Moolenaar #endif
1493f9cc9f20SBram Moolenaar 	}
1494f9cc9f20SBram Moolenaar #ifdef FEAT_TERMINAL
1495f9cc9f20SBram Moolenaar 	else if (is_terminal_group)
1496f9cc9f20SBram Moolenaar 	    set_terminal_default_colors(
1497f9cc9f20SBram Moolenaar 		    HL_TABLE()[idx].sg_cterm_fg, HL_TABLE()[idx].sg_cterm_bg);
1498f9cc9f20SBram Moolenaar #endif
1499f9cc9f20SBram Moolenaar #ifdef FEAT_GUI_X11
1500f9cc9f20SBram Moolenaar # ifdef FEAT_MENU
1501f9cc9f20SBram Moolenaar 	else if (is_menu_group)
1502f9cc9f20SBram Moolenaar 	{
1503f9cc9f20SBram Moolenaar 	    if (gui.in_use && do_colors)
1504f9cc9f20SBram Moolenaar 		gui_mch_new_menu_colors();
1505f9cc9f20SBram Moolenaar 	}
1506f9cc9f20SBram Moolenaar # endif
1507f9cc9f20SBram Moolenaar 	else if (is_scrollbar_group)
1508f9cc9f20SBram Moolenaar 	{
1509f9cc9f20SBram Moolenaar 	    if (gui.in_use && do_colors)
1510f9cc9f20SBram Moolenaar 		gui_new_scrollbar_colors();
1511f9cc9f20SBram Moolenaar 	    else
1512f9cc9f20SBram Moolenaar 		set_hl_attr(idx);
1513f9cc9f20SBram Moolenaar 	}
1514f9cc9f20SBram Moolenaar # ifdef FEAT_BEVAL_GUI
1515f9cc9f20SBram Moolenaar 	else if (is_tooltip_group)
1516f9cc9f20SBram Moolenaar 	{
1517f9cc9f20SBram Moolenaar 	    if (gui.in_use && do_colors)
1518f9cc9f20SBram Moolenaar 		gui_mch_new_tooltip_colors();
1519f9cc9f20SBram Moolenaar 	}
1520f9cc9f20SBram Moolenaar # endif
1521f9cc9f20SBram Moolenaar #endif
1522f9cc9f20SBram Moolenaar 	else
1523f9cc9f20SBram Moolenaar 	    set_hl_attr(idx);
1524f9cc9f20SBram Moolenaar #ifdef FEAT_EVAL
1525f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_script_ctx = current_sctx;
1526f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
1527f9cc9f20SBram Moolenaar #endif
1528f9cc9f20SBram Moolenaar     }
1529f9cc9f20SBram Moolenaar 
1530f9cc9f20SBram Moolenaar     vim_free(key);
1531f9cc9f20SBram Moolenaar     vim_free(arg);
1532f9cc9f20SBram Moolenaar 
1533f9cc9f20SBram Moolenaar     // Only call highlight_changed() once, after a sequence of highlight
1534f9cc9f20SBram Moolenaar     // commands, and only if an attribute actually changed.
1535f9cc9f20SBram Moolenaar     if ((did_change
1536f9cc9f20SBram Moolenaar 	   || memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0)
1537f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
1538f9cc9f20SBram Moolenaar 	    && !did_highlight_changed
1539f9cc9f20SBram Moolenaar #endif
1540f9cc9f20SBram Moolenaar        )
1541f9cc9f20SBram Moolenaar     {
1542f9cc9f20SBram Moolenaar 	// Do not trigger a redraw when highlighting is changed while
1543f9cc9f20SBram Moolenaar 	// redrawing.  This may happen when evaluating 'statusline' changes the
1544f9cc9f20SBram Moolenaar 	// StatusLine group.
1545f9cc9f20SBram Moolenaar 	if (!updating_screen)
1546f9cc9f20SBram Moolenaar 	    redraw_all_later(NOT_VALID);
1547f9cc9f20SBram Moolenaar 	need_highlight_changed = TRUE;
1548f9cc9f20SBram Moolenaar     }
1549f9cc9f20SBram Moolenaar }
1550f9cc9f20SBram Moolenaar 
1551f9cc9f20SBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
1552f9cc9f20SBram Moolenaar     void
1553f9cc9f20SBram Moolenaar free_highlight(void)
1554f9cc9f20SBram Moolenaar {
1555f9cc9f20SBram Moolenaar     int	    i;
1556f9cc9f20SBram Moolenaar 
1557f9cc9f20SBram Moolenaar     for (i = 0; i < highlight_ga.ga_len; ++i)
1558f9cc9f20SBram Moolenaar     {
1559f9cc9f20SBram Moolenaar 	highlight_clear(i);
1560f9cc9f20SBram Moolenaar 	vim_free(HL_TABLE()[i].sg_name);
1561f9cc9f20SBram Moolenaar 	vim_free(HL_TABLE()[i].sg_name_u);
1562f9cc9f20SBram Moolenaar     }
1563f9cc9f20SBram Moolenaar     ga_clear(&highlight_ga);
1564f9cc9f20SBram Moolenaar }
1565f9cc9f20SBram Moolenaar #endif
1566f9cc9f20SBram Moolenaar 
1567f9cc9f20SBram Moolenaar /*
1568f9cc9f20SBram Moolenaar  * Reset the cterm colors to what they were before Vim was started, if
1569f9cc9f20SBram Moolenaar  * possible.  Otherwise reset them to zero.
1570f9cc9f20SBram Moolenaar  */
1571f9cc9f20SBram Moolenaar     void
1572f9cc9f20SBram Moolenaar restore_cterm_colors(void)
1573f9cc9f20SBram Moolenaar {
1574f9cc9f20SBram Moolenaar #if defined(MSWIN) && !defined(FEAT_GUI_MSWIN)
1575f9cc9f20SBram Moolenaar     // Since t_me has been set, this probably means that the user
1576f9cc9f20SBram Moolenaar     // wants to use this as default colors.  Need to reset default
1577f9cc9f20SBram Moolenaar     // background/foreground colors.
1578f9cc9f20SBram Moolenaar     mch_set_normal_colors();
1579f9cc9f20SBram Moolenaar #else
1580f9cc9f20SBram Moolenaar # ifdef VIMDLL
1581f9cc9f20SBram Moolenaar     if (!gui.in_use)
1582f9cc9f20SBram Moolenaar     {
1583f9cc9f20SBram Moolenaar 	mch_set_normal_colors();
1584f9cc9f20SBram Moolenaar 	return;
1585f9cc9f20SBram Moolenaar     }
1586f9cc9f20SBram Moolenaar # endif
1587f9cc9f20SBram Moolenaar     cterm_normal_fg_color = 0;
1588f9cc9f20SBram Moolenaar     cterm_normal_fg_bold = 0;
1589f9cc9f20SBram Moolenaar     cterm_normal_bg_color = 0;
1590f9cc9f20SBram Moolenaar # ifdef FEAT_TERMGUICOLORS
1591f9cc9f20SBram Moolenaar     cterm_normal_fg_gui_color = INVALCOLOR;
1592f9cc9f20SBram Moolenaar     cterm_normal_bg_gui_color = INVALCOLOR;
1593f9cc9f20SBram Moolenaar # endif
1594f9cc9f20SBram Moolenaar #endif
1595f9cc9f20SBram Moolenaar }
1596f9cc9f20SBram Moolenaar 
1597f9cc9f20SBram Moolenaar /*
1598f9cc9f20SBram Moolenaar  * Return TRUE if highlight group "idx" has any settings.
1599f9cc9f20SBram Moolenaar  * When "check_link" is TRUE also check for an existing link.
1600f9cc9f20SBram Moolenaar  */
1601f9cc9f20SBram Moolenaar     static int
1602f9cc9f20SBram Moolenaar hl_has_settings(int idx, int check_link)
1603f9cc9f20SBram Moolenaar {
1604f9cc9f20SBram Moolenaar     return (   HL_TABLE()[idx].sg_term_attr != 0
1605f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_cterm_attr != 0
1606f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_cterm_fg != 0
1607f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_cterm_bg != 0
1608f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
1609f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_gui_attr != 0
1610f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_gui_fg_name != NULL
1611f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_gui_bg_name != NULL
1612f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_gui_sp_name != NULL
1613f9cc9f20SBram Moolenaar 	    || HL_TABLE()[idx].sg_font_name != NULL
1614f9cc9f20SBram Moolenaar #endif
1615f9cc9f20SBram Moolenaar 	    || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)));
1616f9cc9f20SBram Moolenaar }
1617f9cc9f20SBram Moolenaar 
1618f9cc9f20SBram Moolenaar /*
1619f9cc9f20SBram Moolenaar  * Clear highlighting for one group.
1620f9cc9f20SBram Moolenaar  */
1621f9cc9f20SBram Moolenaar     static void
1622f9cc9f20SBram Moolenaar highlight_clear(int idx)
1623f9cc9f20SBram Moolenaar {
1624f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_cleared = TRUE;
1625f9cc9f20SBram Moolenaar 
1626f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_term = 0;
1627f9cc9f20SBram Moolenaar     VIM_CLEAR(HL_TABLE()[idx].sg_start);
1628f9cc9f20SBram Moolenaar     VIM_CLEAR(HL_TABLE()[idx].sg_stop);
1629f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_term_attr = 0;
1630f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_cterm = 0;
1631f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_cterm_bold = FALSE;
1632f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_cterm_fg = 0;
1633f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_cterm_bg = 0;
1634f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_cterm_attr = 0;
1635f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
1636f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_gui = 0;
1637f9cc9f20SBram Moolenaar     VIM_CLEAR(HL_TABLE()[idx].sg_gui_fg_name);
1638f9cc9f20SBram Moolenaar     VIM_CLEAR(HL_TABLE()[idx].sg_gui_bg_name);
1639f9cc9f20SBram Moolenaar     VIM_CLEAR(HL_TABLE()[idx].sg_gui_sp_name);
1640f9cc9f20SBram Moolenaar #endif
1641f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
1642f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_gui_fg = INVALCOLOR;
1643f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_gui_bg = INVALCOLOR;
1644f9cc9f20SBram Moolenaar #endif
1645f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
1646f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_gui_sp = INVALCOLOR;
1647f9cc9f20SBram Moolenaar     gui_mch_free_font(HL_TABLE()[idx].sg_font);
1648f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_font = NOFONT;
1649f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
1650f9cc9f20SBram Moolenaar     gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset);
1651f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_fontset = NOFONTSET;
1652f9cc9f20SBram Moolenaar # endif
1653f9cc9f20SBram Moolenaar     VIM_CLEAR(HL_TABLE()[idx].sg_font_name);
1654f9cc9f20SBram Moolenaar     HL_TABLE()[idx].sg_gui_attr = 0;
1655f9cc9f20SBram Moolenaar #endif
1656f9cc9f20SBram Moolenaar #ifdef FEAT_EVAL
1657f9cc9f20SBram Moolenaar     // Clear the script ID only when there is no link, since that is not
1658f9cc9f20SBram Moolenaar     // cleared.
1659f9cc9f20SBram Moolenaar     if (HL_TABLE()[idx].sg_link == 0)
1660f9cc9f20SBram Moolenaar     {
1661f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_script_ctx.sc_sid = 0;
1662f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_script_ctx.sc_lnum = 0;
1663f9cc9f20SBram Moolenaar     }
1664f9cc9f20SBram Moolenaar #endif
1665f9cc9f20SBram Moolenaar }
1666f9cc9f20SBram Moolenaar 
1667f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
1668f9cc9f20SBram Moolenaar /*
1669f9cc9f20SBram Moolenaar  * Set the normal foreground and background colors according to the "Normal"
1670f9cc9f20SBram Moolenaar  * highlighting group.  For X11 also set "Menu", "Scrollbar", and
1671f9cc9f20SBram Moolenaar  * "Tooltip" colors.
1672f9cc9f20SBram Moolenaar  */
1673f9cc9f20SBram Moolenaar     void
1674f9cc9f20SBram Moolenaar set_normal_colors(void)
1675f9cc9f20SBram Moolenaar {
1676f9cc9f20SBram Moolenaar # ifdef FEAT_GUI
1677f9cc9f20SBram Moolenaar #  ifdef FEAT_TERMGUICOLORS
1678f9cc9f20SBram Moolenaar     if (gui.in_use)
1679f9cc9f20SBram Moolenaar #  endif
1680f9cc9f20SBram Moolenaar     {
1681f9cc9f20SBram Moolenaar 	if (set_group_colors((char_u *)"Normal",
1682f9cc9f20SBram Moolenaar 				 &gui.norm_pixel, &gui.back_pixel,
1683f9cc9f20SBram Moolenaar 				 FALSE, TRUE, FALSE))
1684f9cc9f20SBram Moolenaar 	{
1685f9cc9f20SBram Moolenaar 	    gui_mch_new_colors();
1686f9cc9f20SBram Moolenaar 	    must_redraw = CLEAR;
1687f9cc9f20SBram Moolenaar 	}
1688f9cc9f20SBram Moolenaar #  ifdef FEAT_GUI_X11
1689f9cc9f20SBram Moolenaar 	if (set_group_colors((char_u *)"Menu",
1690f9cc9f20SBram Moolenaar 			     &gui.menu_fg_pixel, &gui.menu_bg_pixel,
1691f9cc9f20SBram Moolenaar 			     TRUE, FALSE, FALSE))
1692f9cc9f20SBram Moolenaar 	{
1693f9cc9f20SBram Moolenaar #   ifdef FEAT_MENU
1694f9cc9f20SBram Moolenaar 	    gui_mch_new_menu_colors();
1695f9cc9f20SBram Moolenaar #   endif
1696f9cc9f20SBram Moolenaar 	    must_redraw = CLEAR;
1697f9cc9f20SBram Moolenaar 	}
1698f9cc9f20SBram Moolenaar #   ifdef FEAT_BEVAL_GUI
1699f9cc9f20SBram Moolenaar 	if (set_group_colors((char_u *)"Tooltip",
1700f9cc9f20SBram Moolenaar 			     &gui.tooltip_fg_pixel, &gui.tooltip_bg_pixel,
1701f9cc9f20SBram Moolenaar 			     FALSE, FALSE, TRUE))
1702f9cc9f20SBram Moolenaar 	{
1703f9cc9f20SBram Moolenaar #    ifdef FEAT_TOOLBAR
1704f9cc9f20SBram Moolenaar 	    gui_mch_new_tooltip_colors();
1705f9cc9f20SBram Moolenaar #    endif
1706f9cc9f20SBram Moolenaar 	    must_redraw = CLEAR;
1707f9cc9f20SBram Moolenaar 	}
1708f9cc9f20SBram Moolenaar #   endif
1709f9cc9f20SBram Moolenaar 	if (set_group_colors((char_u *)"Scrollbar",
1710f9cc9f20SBram Moolenaar 			&gui.scroll_fg_pixel, &gui.scroll_bg_pixel,
1711f9cc9f20SBram Moolenaar 			FALSE, FALSE, FALSE))
1712f9cc9f20SBram Moolenaar 	{
1713f9cc9f20SBram Moolenaar 	    gui_new_scrollbar_colors();
1714f9cc9f20SBram Moolenaar 	    must_redraw = CLEAR;
1715f9cc9f20SBram Moolenaar 	}
1716f9cc9f20SBram Moolenaar #  endif
1717f9cc9f20SBram Moolenaar     }
1718f9cc9f20SBram Moolenaar # endif
1719f9cc9f20SBram Moolenaar # ifdef FEAT_TERMGUICOLORS
1720f9cc9f20SBram Moolenaar #  ifdef FEAT_GUI
1721f9cc9f20SBram Moolenaar     else
1722f9cc9f20SBram Moolenaar #  endif
1723f9cc9f20SBram Moolenaar     {
1724f9cc9f20SBram Moolenaar 	int		idx;
1725f9cc9f20SBram Moolenaar 
1726f9cc9f20SBram Moolenaar 	idx = syn_name2id((char_u *)"Normal") - 1;
1727f9cc9f20SBram Moolenaar 	if (idx >= 0)
1728f9cc9f20SBram Moolenaar 	{
1729f9cc9f20SBram Moolenaar 	    gui_do_one_color(idx, FALSE, FALSE);
1730f9cc9f20SBram Moolenaar 
1731f9cc9f20SBram Moolenaar 	    // If the normal fg or bg color changed a complete redraw is
1732f9cc9f20SBram Moolenaar 	    // required.
1733f9cc9f20SBram Moolenaar 	    if (cterm_normal_fg_gui_color != HL_TABLE()[idx].sg_gui_fg
1734f9cc9f20SBram Moolenaar 		    || cterm_normal_bg_gui_color != HL_TABLE()[idx].sg_gui_bg)
1735f9cc9f20SBram Moolenaar 	    {
1736f9cc9f20SBram Moolenaar 		// if the GUI color is INVALCOLOR then we use the default cterm
1737f9cc9f20SBram Moolenaar 		// color
1738f9cc9f20SBram Moolenaar 		cterm_normal_fg_gui_color = HL_TABLE()[idx].sg_gui_fg;
1739f9cc9f20SBram Moolenaar 		cterm_normal_bg_gui_color = HL_TABLE()[idx].sg_gui_bg;
1740f9cc9f20SBram Moolenaar 		must_redraw = CLEAR;
1741f9cc9f20SBram Moolenaar 	    }
1742f9cc9f20SBram Moolenaar 	}
1743f9cc9f20SBram Moolenaar     }
1744f9cc9f20SBram Moolenaar # endif
1745f9cc9f20SBram Moolenaar }
1746f9cc9f20SBram Moolenaar #endif
1747f9cc9f20SBram Moolenaar 
1748f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(PROTO)
1749f9cc9f20SBram Moolenaar /*
1750f9cc9f20SBram Moolenaar  * Set the colors for "Normal", "Menu", "Tooltip" or "Scrollbar".
1751f9cc9f20SBram Moolenaar  */
1752f9cc9f20SBram Moolenaar     static int
1753f9cc9f20SBram Moolenaar set_group_colors(
1754f9cc9f20SBram Moolenaar     char_u	*name,
1755f9cc9f20SBram Moolenaar     guicolor_T	*fgp,
1756f9cc9f20SBram Moolenaar     guicolor_T	*bgp,
1757f9cc9f20SBram Moolenaar     int		do_menu,
1758f9cc9f20SBram Moolenaar     int		use_norm,
1759f9cc9f20SBram Moolenaar     int		do_tooltip)
1760f9cc9f20SBram Moolenaar {
1761f9cc9f20SBram Moolenaar     int		idx;
1762f9cc9f20SBram Moolenaar 
1763f9cc9f20SBram Moolenaar     idx = syn_name2id(name) - 1;
1764f9cc9f20SBram Moolenaar     if (idx >= 0)
1765f9cc9f20SBram Moolenaar     {
1766f9cc9f20SBram Moolenaar 	gui_do_one_color(idx, do_menu, do_tooltip);
1767f9cc9f20SBram Moolenaar 
1768f9cc9f20SBram Moolenaar 	if (HL_TABLE()[idx].sg_gui_fg != INVALCOLOR)
1769f9cc9f20SBram Moolenaar 	    *fgp = HL_TABLE()[idx].sg_gui_fg;
1770f9cc9f20SBram Moolenaar 	else if (use_norm)
1771f9cc9f20SBram Moolenaar 	    *fgp = gui.def_norm_pixel;
1772f9cc9f20SBram Moolenaar 	if (HL_TABLE()[idx].sg_gui_bg != INVALCOLOR)
1773f9cc9f20SBram Moolenaar 	    *bgp = HL_TABLE()[idx].sg_gui_bg;
1774f9cc9f20SBram Moolenaar 	else if (use_norm)
1775f9cc9f20SBram Moolenaar 	    *bgp = gui.def_back_pixel;
1776f9cc9f20SBram Moolenaar 	return TRUE;
1777f9cc9f20SBram Moolenaar     }
1778f9cc9f20SBram Moolenaar     return FALSE;
1779f9cc9f20SBram Moolenaar }
1780f9cc9f20SBram Moolenaar 
1781f9cc9f20SBram Moolenaar /*
1782f9cc9f20SBram Moolenaar  * Get the font of the "Normal" group.
1783f9cc9f20SBram Moolenaar  * Returns "" when it's not found or not set.
1784f9cc9f20SBram Moolenaar  */
1785f9cc9f20SBram Moolenaar     char_u *
1786f9cc9f20SBram Moolenaar hl_get_font_name(void)
1787f9cc9f20SBram Moolenaar {
1788f9cc9f20SBram Moolenaar     int		id;
1789f9cc9f20SBram Moolenaar     char_u	*s;
1790f9cc9f20SBram Moolenaar 
1791f9cc9f20SBram Moolenaar     id = syn_name2id((char_u *)"Normal");
1792f9cc9f20SBram Moolenaar     if (id > 0)
1793f9cc9f20SBram Moolenaar     {
1794f9cc9f20SBram Moolenaar 	s = HL_TABLE()[id - 1].sg_font_name;
1795f9cc9f20SBram Moolenaar 	if (s != NULL)
1796f9cc9f20SBram Moolenaar 	    return s;
1797f9cc9f20SBram Moolenaar     }
1798f9cc9f20SBram Moolenaar     return (char_u *)"";
1799f9cc9f20SBram Moolenaar }
1800f9cc9f20SBram Moolenaar 
1801f9cc9f20SBram Moolenaar /*
1802f9cc9f20SBram Moolenaar  * Set font for "Normal" group.  Called by gui_mch_init_font() when a font has
1803f9cc9f20SBram Moolenaar  * actually chosen to be used.
1804f9cc9f20SBram Moolenaar  */
1805f9cc9f20SBram Moolenaar     void
1806f9cc9f20SBram Moolenaar hl_set_font_name(char_u *font_name)
1807f9cc9f20SBram Moolenaar {
1808f9cc9f20SBram Moolenaar     int	    id;
1809f9cc9f20SBram Moolenaar 
1810f9cc9f20SBram Moolenaar     id = syn_name2id((char_u *)"Normal");
1811f9cc9f20SBram Moolenaar     if (id > 0)
1812f9cc9f20SBram Moolenaar     {
1813f9cc9f20SBram Moolenaar 	vim_free(HL_TABLE()[id - 1].sg_font_name);
1814f9cc9f20SBram Moolenaar 	HL_TABLE()[id - 1].sg_font_name = vim_strsave(font_name);
1815f9cc9f20SBram Moolenaar     }
1816f9cc9f20SBram Moolenaar }
1817f9cc9f20SBram Moolenaar 
1818f9cc9f20SBram Moolenaar /*
1819f9cc9f20SBram Moolenaar  * Set background color for "Normal" group.  Called by gui_set_bg_color()
1820f9cc9f20SBram Moolenaar  * when the color is known.
1821f9cc9f20SBram Moolenaar  */
1822f9cc9f20SBram Moolenaar     void
1823f9cc9f20SBram Moolenaar hl_set_bg_color_name(
1824f9cc9f20SBram Moolenaar     char_u  *name)	    // must have been allocated
1825f9cc9f20SBram Moolenaar {
1826f9cc9f20SBram Moolenaar     int	    id;
1827f9cc9f20SBram Moolenaar 
1828f9cc9f20SBram Moolenaar     if (name != NULL)
1829f9cc9f20SBram Moolenaar     {
1830f9cc9f20SBram Moolenaar 	id = syn_name2id((char_u *)"Normal");
1831f9cc9f20SBram Moolenaar 	if (id > 0)
1832f9cc9f20SBram Moolenaar 	{
1833f9cc9f20SBram Moolenaar 	    vim_free(HL_TABLE()[id - 1].sg_gui_bg_name);
1834f9cc9f20SBram Moolenaar 	    HL_TABLE()[id - 1].sg_gui_bg_name = name;
1835f9cc9f20SBram Moolenaar 	}
1836f9cc9f20SBram Moolenaar     }
1837f9cc9f20SBram Moolenaar }
1838f9cc9f20SBram Moolenaar 
1839f9cc9f20SBram Moolenaar /*
1840f9cc9f20SBram Moolenaar  * Set foreground color for "Normal" group.  Called by gui_set_fg_color()
1841f9cc9f20SBram Moolenaar  * when the color is known.
1842f9cc9f20SBram Moolenaar  */
1843f9cc9f20SBram Moolenaar     void
1844f9cc9f20SBram Moolenaar hl_set_fg_color_name(
1845f9cc9f20SBram Moolenaar     char_u  *name)	    // must have been allocated
1846f9cc9f20SBram Moolenaar {
1847f9cc9f20SBram Moolenaar     int	    id;
1848f9cc9f20SBram Moolenaar 
1849f9cc9f20SBram Moolenaar     if (name != NULL)
1850f9cc9f20SBram Moolenaar     {
1851f9cc9f20SBram Moolenaar 	id = syn_name2id((char_u *)"Normal");
1852f9cc9f20SBram Moolenaar 	if (id > 0)
1853f9cc9f20SBram Moolenaar 	{
1854f9cc9f20SBram Moolenaar 	    vim_free(HL_TABLE()[id - 1].sg_gui_fg_name);
1855f9cc9f20SBram Moolenaar 	    HL_TABLE()[id - 1].sg_gui_fg_name = name;
1856f9cc9f20SBram Moolenaar 	}
1857f9cc9f20SBram Moolenaar     }
1858f9cc9f20SBram Moolenaar }
1859f9cc9f20SBram Moolenaar 
1860f9cc9f20SBram Moolenaar /*
1861f9cc9f20SBram Moolenaar  * Return the handle for a font name.
1862f9cc9f20SBram Moolenaar  * Returns NOFONT when failed.
1863f9cc9f20SBram Moolenaar  */
1864f9cc9f20SBram Moolenaar     static GuiFont
1865f9cc9f20SBram Moolenaar font_name2handle(char_u *name)
1866f9cc9f20SBram Moolenaar {
1867f9cc9f20SBram Moolenaar     if (STRCMP(name, "NONE") == 0)
1868f9cc9f20SBram Moolenaar 	return NOFONT;
1869f9cc9f20SBram Moolenaar 
1870f9cc9f20SBram Moolenaar     return gui_mch_get_font(name, TRUE);
1871f9cc9f20SBram Moolenaar }
1872f9cc9f20SBram Moolenaar 
1873f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
1874f9cc9f20SBram Moolenaar /*
1875f9cc9f20SBram Moolenaar  * Return the handle for a fontset name.
1876f9cc9f20SBram Moolenaar  * Returns NOFONTSET when failed.
1877f9cc9f20SBram Moolenaar  */
1878f9cc9f20SBram Moolenaar     static GuiFontset
1879f9cc9f20SBram Moolenaar fontset_name2handle(char_u *name, int fixed_width)
1880f9cc9f20SBram Moolenaar {
1881f9cc9f20SBram Moolenaar     if (STRCMP(name, "NONE") == 0)
1882f9cc9f20SBram Moolenaar 	return NOFONTSET;
1883f9cc9f20SBram Moolenaar 
1884f9cc9f20SBram Moolenaar     return gui_mch_get_fontset(name, TRUE, fixed_width);
1885f9cc9f20SBram Moolenaar }
1886f9cc9f20SBram Moolenaar # endif
1887f9cc9f20SBram Moolenaar 
1888f9cc9f20SBram Moolenaar /*
1889f9cc9f20SBram Moolenaar  * Get the font or fontset for one highlight group.
1890f9cc9f20SBram Moolenaar  */
1891f9cc9f20SBram Moolenaar     static void
1892f9cc9f20SBram Moolenaar hl_do_font(
1893f9cc9f20SBram Moolenaar     int		idx,
1894f9cc9f20SBram Moolenaar     char_u	*arg,
1895f9cc9f20SBram Moolenaar     int		do_normal,		// set normal font
1896f9cc9f20SBram Moolenaar     int		do_menu UNUSED,		// set menu font
1897f9cc9f20SBram Moolenaar     int		do_tooltip UNUSED,	// set tooltip font
1898f9cc9f20SBram Moolenaar     int		free_font)		// free current font/fontset
1899f9cc9f20SBram Moolenaar {
1900f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
1901f9cc9f20SBram Moolenaar     // If 'guifontset' is not empty, first try using the name as a
1902f9cc9f20SBram Moolenaar     // fontset.  If that doesn't work, use it as a font name.
1903f9cc9f20SBram Moolenaar     if (*p_guifontset != NUL
1904f9cc9f20SBram Moolenaar #  ifdef FONTSET_ALWAYS
1905f9cc9f20SBram Moolenaar 	|| do_menu
1906f9cc9f20SBram Moolenaar #  endif
1907f9cc9f20SBram Moolenaar #  ifdef FEAT_BEVAL_TIP
1908f9cc9f20SBram Moolenaar 	// In Athena & Motif, the Tooltip highlight group is always a fontset
1909f9cc9f20SBram Moolenaar 	|| do_tooltip
1910f9cc9f20SBram Moolenaar #  endif
1911f9cc9f20SBram Moolenaar 	    )
1912f9cc9f20SBram Moolenaar     {
1913f9cc9f20SBram Moolenaar 	if (free_font)
1914f9cc9f20SBram Moolenaar 	    gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset);
1915f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_fontset = fontset_name2handle(arg, 0
1916f9cc9f20SBram Moolenaar #  ifdef FONTSET_ALWAYS
1917f9cc9f20SBram Moolenaar 		|| do_menu
1918f9cc9f20SBram Moolenaar #  endif
1919f9cc9f20SBram Moolenaar #  ifdef FEAT_BEVAL_TIP
1920f9cc9f20SBram Moolenaar 		|| do_tooltip
1921f9cc9f20SBram Moolenaar #  endif
1922f9cc9f20SBram Moolenaar 		);
1923f9cc9f20SBram Moolenaar     }
1924f9cc9f20SBram Moolenaar     if (HL_TABLE()[idx].sg_fontset != NOFONTSET)
1925f9cc9f20SBram Moolenaar     {
1926f9cc9f20SBram Moolenaar 	// If it worked and it's the Normal group, use it as the normal
1927f9cc9f20SBram Moolenaar 	// fontset.  Same for the Menu group.
1928f9cc9f20SBram Moolenaar 	if (do_normal)
1929f9cc9f20SBram Moolenaar 	    gui_init_font(arg, TRUE);
1930f9cc9f20SBram Moolenaar #   if (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) && defined(FEAT_MENU)
1931f9cc9f20SBram Moolenaar 	if (do_menu)
1932f9cc9f20SBram Moolenaar 	{
1933f9cc9f20SBram Moolenaar #    ifdef FONTSET_ALWAYS
1934f9cc9f20SBram Moolenaar 	    gui.menu_fontset = HL_TABLE()[idx].sg_fontset;
1935f9cc9f20SBram Moolenaar #    else
1936f9cc9f20SBram Moolenaar 	    // YIKES!  This is a bug waiting to crash the program
1937f9cc9f20SBram Moolenaar 	    gui.menu_font = HL_TABLE()[idx].sg_fontset;
1938f9cc9f20SBram Moolenaar #    endif
1939f9cc9f20SBram Moolenaar 	    gui_mch_new_menu_font();
1940f9cc9f20SBram Moolenaar 	}
1941f9cc9f20SBram Moolenaar #    ifdef FEAT_BEVAL_GUI
1942f9cc9f20SBram Moolenaar 	if (do_tooltip)
1943f9cc9f20SBram Moolenaar 	{
1944f9cc9f20SBram Moolenaar 	    // The Athena widget set cannot currently handle switching between
1945f9cc9f20SBram Moolenaar 	    // displaying a single font and a fontset.
1946f9cc9f20SBram Moolenaar 	    // If the XtNinternational resource is set to True at widget
1947f9cc9f20SBram Moolenaar 	    // creation, then a fontset is always used, otherwise an
1948f9cc9f20SBram Moolenaar 	    // XFontStruct is used.
1949f9cc9f20SBram Moolenaar 	    gui.tooltip_fontset = (XFontSet)HL_TABLE()[idx].sg_fontset;
1950f9cc9f20SBram Moolenaar 	    gui_mch_new_tooltip_font();
1951f9cc9f20SBram Moolenaar 	}
1952f9cc9f20SBram Moolenaar #    endif
1953f9cc9f20SBram Moolenaar #   endif
1954f9cc9f20SBram Moolenaar     }
1955f9cc9f20SBram Moolenaar     else
1956f9cc9f20SBram Moolenaar # endif
1957f9cc9f20SBram Moolenaar     {
1958f9cc9f20SBram Moolenaar 	if (free_font)
1959f9cc9f20SBram Moolenaar 	    gui_mch_free_font(HL_TABLE()[idx].sg_font);
1960f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_font = font_name2handle(arg);
1961f9cc9f20SBram Moolenaar 	// If it worked and it's the Normal group, use it as the
1962f9cc9f20SBram Moolenaar 	// normal font.  Same for the Menu group.
1963f9cc9f20SBram Moolenaar 	if (HL_TABLE()[idx].sg_font != NOFONT)
1964f9cc9f20SBram Moolenaar 	{
1965f9cc9f20SBram Moolenaar 	    if (do_normal)
1966f9cc9f20SBram Moolenaar 		gui_init_font(arg, FALSE);
1967f9cc9f20SBram Moolenaar #ifndef FONTSET_ALWAYS
1968f9cc9f20SBram Moolenaar # if (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) && defined(FEAT_MENU)
1969f9cc9f20SBram Moolenaar 	    if (do_menu)
1970f9cc9f20SBram Moolenaar 	    {
1971f9cc9f20SBram Moolenaar 		gui.menu_font = HL_TABLE()[idx].sg_font;
1972f9cc9f20SBram Moolenaar 		gui_mch_new_menu_font();
1973f9cc9f20SBram Moolenaar 	    }
1974f9cc9f20SBram Moolenaar # endif
1975f9cc9f20SBram Moolenaar #endif
1976f9cc9f20SBram Moolenaar 	}
1977f9cc9f20SBram Moolenaar     }
1978f9cc9f20SBram Moolenaar }
1979f9cc9f20SBram Moolenaar 
1980f9cc9f20SBram Moolenaar #endif // FEAT_GUI
1981f9cc9f20SBram Moolenaar 
1982f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
1983f9cc9f20SBram Moolenaar /*
1984f9cc9f20SBram Moolenaar  * Return the handle for a color name.
1985f9cc9f20SBram Moolenaar  * Returns INVALCOLOR when failed.
1986f9cc9f20SBram Moolenaar  */
1987f9cc9f20SBram Moolenaar     guicolor_T
1988f9cc9f20SBram Moolenaar color_name2handle(char_u *name)
1989f9cc9f20SBram Moolenaar {
1990f9cc9f20SBram Moolenaar     if (STRCMP(name, "NONE") == 0)
1991f9cc9f20SBram Moolenaar 	return INVALCOLOR;
1992f9cc9f20SBram Moolenaar 
1993f9cc9f20SBram Moolenaar     if (STRICMP(name, "fg") == 0 || STRICMP(name, "foreground") == 0)
1994f9cc9f20SBram Moolenaar     {
1995f9cc9f20SBram Moolenaar #if defined(FEAT_TERMGUICOLORS) && defined(FEAT_GUI)
1996f9cc9f20SBram Moolenaar 	if (gui.in_use)
1997f9cc9f20SBram Moolenaar #endif
1998f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
1999f9cc9f20SBram Moolenaar 	    return gui.norm_pixel;
2000f9cc9f20SBram Moolenaar #endif
2001f9cc9f20SBram Moolenaar #ifdef FEAT_TERMGUICOLORS
2002f9cc9f20SBram Moolenaar 	if (cterm_normal_fg_gui_color != INVALCOLOR)
2003f9cc9f20SBram Moolenaar 	    return cterm_normal_fg_gui_color;
2004f9cc9f20SBram Moolenaar 	// Guess that the foreground is black or white.
2005f9cc9f20SBram Moolenaar 	return GUI_GET_COLOR((char_u *)(*p_bg == 'l' ? "black" : "white"));
2006f9cc9f20SBram Moolenaar #endif
2007f9cc9f20SBram Moolenaar     }
2008f9cc9f20SBram Moolenaar     if (STRICMP(name, "bg") == 0 || STRICMP(name, "background") == 0)
2009f9cc9f20SBram Moolenaar     {
2010f9cc9f20SBram Moolenaar #if defined(FEAT_TERMGUICOLORS) && defined(FEAT_GUI)
2011f9cc9f20SBram Moolenaar 	if (gui.in_use)
2012f9cc9f20SBram Moolenaar #endif
2013f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2014f9cc9f20SBram Moolenaar 	    return gui.back_pixel;
2015f9cc9f20SBram Moolenaar #endif
2016f9cc9f20SBram Moolenaar #ifdef FEAT_TERMGUICOLORS
2017f9cc9f20SBram Moolenaar 	if (cterm_normal_bg_gui_color != INVALCOLOR)
2018f9cc9f20SBram Moolenaar 	    return cterm_normal_bg_gui_color;
2019f9cc9f20SBram Moolenaar 	// Guess that the background is white or black.
2020f9cc9f20SBram Moolenaar 	return GUI_GET_COLOR((char_u *)(*p_bg == 'l' ? "white" : "black"));
2021f9cc9f20SBram Moolenaar #endif
2022f9cc9f20SBram Moolenaar     }
2023f9cc9f20SBram Moolenaar 
2024f9cc9f20SBram Moolenaar     return GUI_GET_COLOR(name);
2025f9cc9f20SBram Moolenaar }
2026f9cc9f20SBram Moolenaar #endif
2027f9cc9f20SBram Moolenaar 
2028f9cc9f20SBram Moolenaar /*
2029f9cc9f20SBram Moolenaar  * Table with the specifications for an attribute number.
2030f9cc9f20SBram Moolenaar  * Note that this table is used by ALL buffers.  This is required because the
2031f9cc9f20SBram Moolenaar  * GUI can redraw at any time for any buffer.
2032f9cc9f20SBram Moolenaar  */
2033f9cc9f20SBram Moolenaar static garray_T	term_attr_table = {0, 0, 0, 0, NULL};
2034f9cc9f20SBram Moolenaar 
2035f9cc9f20SBram Moolenaar #define TERM_ATTR_ENTRY(idx) ((attrentry_T *)term_attr_table.ga_data)[idx]
2036f9cc9f20SBram Moolenaar 
2037f9cc9f20SBram Moolenaar static garray_T	cterm_attr_table = {0, 0, 0, 0, NULL};
2038f9cc9f20SBram Moolenaar 
2039f9cc9f20SBram Moolenaar #define CTERM_ATTR_ENTRY(idx) ((attrentry_T *)cterm_attr_table.ga_data)[idx]
2040f9cc9f20SBram Moolenaar 
2041f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2042f9cc9f20SBram Moolenaar static garray_T	gui_attr_table = {0, 0, 0, 0, NULL};
2043f9cc9f20SBram Moolenaar 
2044f9cc9f20SBram Moolenaar #define GUI_ATTR_ENTRY(idx) ((attrentry_T *)gui_attr_table.ga_data)[idx]
2045f9cc9f20SBram Moolenaar #endif
2046f9cc9f20SBram Moolenaar 
2047f9cc9f20SBram Moolenaar /*
2048f9cc9f20SBram Moolenaar  * Return the attr number for a set of colors and font.
2049f9cc9f20SBram Moolenaar  * Add a new entry to the term_attr_table, cterm_attr_table or gui_attr_table
2050f9cc9f20SBram Moolenaar  * if the combination is new.
2051f9cc9f20SBram Moolenaar  * Return 0 for error (no more room).
2052f9cc9f20SBram Moolenaar  */
2053f9cc9f20SBram Moolenaar     static int
2054f9cc9f20SBram Moolenaar get_attr_entry(garray_T *table, attrentry_T *aep)
2055f9cc9f20SBram Moolenaar {
2056f9cc9f20SBram Moolenaar     int		i;
2057f9cc9f20SBram Moolenaar     attrentry_T	*taep;
2058f9cc9f20SBram Moolenaar     static int	recursive = FALSE;
2059f9cc9f20SBram Moolenaar 
2060f9cc9f20SBram Moolenaar     /*
2061f9cc9f20SBram Moolenaar      * Init the table, in case it wasn't done yet.
2062f9cc9f20SBram Moolenaar      */
2063f9cc9f20SBram Moolenaar     table->ga_itemsize = sizeof(attrentry_T);
2064f9cc9f20SBram Moolenaar     table->ga_growsize = 7;
2065f9cc9f20SBram Moolenaar 
2066f9cc9f20SBram Moolenaar     /*
2067f9cc9f20SBram Moolenaar      * Try to find an entry with the same specifications.
2068f9cc9f20SBram Moolenaar      */
2069f9cc9f20SBram Moolenaar     for (i = 0; i < table->ga_len; ++i)
2070f9cc9f20SBram Moolenaar     {
2071f9cc9f20SBram Moolenaar 	taep = &(((attrentry_T *)table->ga_data)[i]);
2072f9cc9f20SBram Moolenaar 	if (	   aep->ae_attr == taep->ae_attr
2073f9cc9f20SBram Moolenaar 		&& (
2074f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2075f9cc9f20SBram Moolenaar 		       (table == &gui_attr_table
2076f9cc9f20SBram Moolenaar 			&& (aep->ae_u.gui.fg_color == taep->ae_u.gui.fg_color
2077f9cc9f20SBram Moolenaar 			    && aep->ae_u.gui.bg_color
2078f9cc9f20SBram Moolenaar 						    == taep->ae_u.gui.bg_color
2079f9cc9f20SBram Moolenaar 			    && aep->ae_u.gui.sp_color
2080f9cc9f20SBram Moolenaar 						    == taep->ae_u.gui.sp_color
2081f9cc9f20SBram Moolenaar 			    && aep->ae_u.gui.font == taep->ae_u.gui.font
2082f9cc9f20SBram Moolenaar #  ifdef FEAT_XFONTSET
2083f9cc9f20SBram Moolenaar 			    && aep->ae_u.gui.fontset == taep->ae_u.gui.fontset
2084f9cc9f20SBram Moolenaar #  endif
2085f9cc9f20SBram Moolenaar 			    ))
2086f9cc9f20SBram Moolenaar 		    ||
2087f9cc9f20SBram Moolenaar #endif
2088f9cc9f20SBram Moolenaar 		       (table == &term_attr_table
2089f9cc9f20SBram Moolenaar 			&& (aep->ae_u.term.start == NULL)
2090f9cc9f20SBram Moolenaar 					    == (taep->ae_u.term.start == NULL)
2091f9cc9f20SBram Moolenaar 			&& (aep->ae_u.term.start == NULL
2092f9cc9f20SBram Moolenaar 			    || STRCMP(aep->ae_u.term.start,
2093f9cc9f20SBram Moolenaar 						  taep->ae_u.term.start) == 0)
2094f9cc9f20SBram Moolenaar 			&& (aep->ae_u.term.stop == NULL)
2095f9cc9f20SBram Moolenaar 					     == (taep->ae_u.term.stop == NULL)
2096f9cc9f20SBram Moolenaar 			&& (aep->ae_u.term.stop == NULL
2097f9cc9f20SBram Moolenaar 			    || STRCMP(aep->ae_u.term.stop,
2098f9cc9f20SBram Moolenaar 						  taep->ae_u.term.stop) == 0))
2099f9cc9f20SBram Moolenaar 		    || (table == &cterm_attr_table
2100f9cc9f20SBram Moolenaar 			    && aep->ae_u.cterm.fg_color
2101f9cc9f20SBram Moolenaar 						  == taep->ae_u.cterm.fg_color
2102f9cc9f20SBram Moolenaar 			    && aep->ae_u.cterm.bg_color
2103f9cc9f20SBram Moolenaar 						  == taep->ae_u.cterm.bg_color
2104f9cc9f20SBram Moolenaar #ifdef FEAT_TERMGUICOLORS
2105f9cc9f20SBram Moolenaar 			    && aep->ae_u.cterm.fg_rgb
2106f9cc9f20SBram Moolenaar 						    == taep->ae_u.cterm.fg_rgb
2107f9cc9f20SBram Moolenaar 			    && aep->ae_u.cterm.bg_rgb
2108f9cc9f20SBram Moolenaar 						    == taep->ae_u.cterm.bg_rgb
2109f9cc9f20SBram Moolenaar #endif
2110f9cc9f20SBram Moolenaar 		       )))
2111f9cc9f20SBram Moolenaar 
2112f9cc9f20SBram Moolenaar 	return i + ATTR_OFF;
2113f9cc9f20SBram Moolenaar     }
2114f9cc9f20SBram Moolenaar 
2115f9cc9f20SBram Moolenaar     if (table->ga_len + ATTR_OFF > MAX_TYPENR)
2116f9cc9f20SBram Moolenaar     {
2117f9cc9f20SBram Moolenaar 	/*
2118f9cc9f20SBram Moolenaar 	 * Running out of attribute entries!  remove all attributes, and
2119f9cc9f20SBram Moolenaar 	 * compute new ones for all groups.
2120f9cc9f20SBram Moolenaar 	 * When called recursively, we are really out of numbers.
2121f9cc9f20SBram Moolenaar 	 */
2122f9cc9f20SBram Moolenaar 	if (recursive)
2123f9cc9f20SBram Moolenaar 	{
2124f9cc9f20SBram Moolenaar 	    emsg(_("E424: Too many different highlighting attributes in use"));
2125f9cc9f20SBram Moolenaar 	    return 0;
2126f9cc9f20SBram Moolenaar 	}
2127f9cc9f20SBram Moolenaar 	recursive = TRUE;
2128f9cc9f20SBram Moolenaar 
2129f9cc9f20SBram Moolenaar 	clear_hl_tables();
2130f9cc9f20SBram Moolenaar 
2131f9cc9f20SBram Moolenaar 	must_redraw = CLEAR;
2132f9cc9f20SBram Moolenaar 
2133f9cc9f20SBram Moolenaar 	for (i = 0; i < highlight_ga.ga_len; ++i)
2134f9cc9f20SBram Moolenaar 	    set_hl_attr(i);
2135f9cc9f20SBram Moolenaar 
2136f9cc9f20SBram Moolenaar 	recursive = FALSE;
2137f9cc9f20SBram Moolenaar     }
2138f9cc9f20SBram Moolenaar 
2139f9cc9f20SBram Moolenaar     /*
2140f9cc9f20SBram Moolenaar      * This is a new combination of colors and font, add an entry.
2141f9cc9f20SBram Moolenaar      */
2142f9cc9f20SBram Moolenaar     if (ga_grow(table, 1) == FAIL)
2143f9cc9f20SBram Moolenaar 	return 0;
2144f9cc9f20SBram Moolenaar 
2145f9cc9f20SBram Moolenaar     taep = &(((attrentry_T *)table->ga_data)[table->ga_len]);
2146f9cc9f20SBram Moolenaar     vim_memset(taep, 0, sizeof(attrentry_T));
2147f9cc9f20SBram Moolenaar     taep->ae_attr = aep->ae_attr;
2148f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2149f9cc9f20SBram Moolenaar     if (table == &gui_attr_table)
2150f9cc9f20SBram Moolenaar     {
2151f9cc9f20SBram Moolenaar 	taep->ae_u.gui.fg_color = aep->ae_u.gui.fg_color;
2152f9cc9f20SBram Moolenaar 	taep->ae_u.gui.bg_color = aep->ae_u.gui.bg_color;
2153f9cc9f20SBram Moolenaar 	taep->ae_u.gui.sp_color = aep->ae_u.gui.sp_color;
2154f9cc9f20SBram Moolenaar 	taep->ae_u.gui.font = aep->ae_u.gui.font;
2155f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
2156f9cc9f20SBram Moolenaar 	taep->ae_u.gui.fontset = aep->ae_u.gui.fontset;
2157f9cc9f20SBram Moolenaar # endif
2158f9cc9f20SBram Moolenaar     }
2159f9cc9f20SBram Moolenaar #endif
2160f9cc9f20SBram Moolenaar     if (table == &term_attr_table)
2161f9cc9f20SBram Moolenaar     {
2162f9cc9f20SBram Moolenaar 	if (aep->ae_u.term.start == NULL)
2163f9cc9f20SBram Moolenaar 	    taep->ae_u.term.start = NULL;
2164f9cc9f20SBram Moolenaar 	else
2165f9cc9f20SBram Moolenaar 	    taep->ae_u.term.start = vim_strsave(aep->ae_u.term.start);
2166f9cc9f20SBram Moolenaar 	if (aep->ae_u.term.stop == NULL)
2167f9cc9f20SBram Moolenaar 	    taep->ae_u.term.stop = NULL;
2168f9cc9f20SBram Moolenaar 	else
2169f9cc9f20SBram Moolenaar 	    taep->ae_u.term.stop = vim_strsave(aep->ae_u.term.stop);
2170f9cc9f20SBram Moolenaar     }
2171f9cc9f20SBram Moolenaar     else if (table == &cterm_attr_table)
2172f9cc9f20SBram Moolenaar     {
2173f9cc9f20SBram Moolenaar 	taep->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color;
2174f9cc9f20SBram Moolenaar 	taep->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
2175f9cc9f20SBram Moolenaar #ifdef FEAT_TERMGUICOLORS
2176f9cc9f20SBram Moolenaar 	taep->ae_u.cterm.fg_rgb = aep->ae_u.cterm.fg_rgb;
2177f9cc9f20SBram Moolenaar 	taep->ae_u.cterm.bg_rgb = aep->ae_u.cterm.bg_rgb;
2178f9cc9f20SBram Moolenaar #endif
2179f9cc9f20SBram Moolenaar     }
2180f9cc9f20SBram Moolenaar     ++table->ga_len;
2181f9cc9f20SBram Moolenaar     return (table->ga_len - 1 + ATTR_OFF);
2182f9cc9f20SBram Moolenaar }
2183f9cc9f20SBram Moolenaar 
2184f9cc9f20SBram Moolenaar #if defined(FEAT_TERMINAL) || defined(PROTO)
2185f9cc9f20SBram Moolenaar /*
2186f9cc9f20SBram Moolenaar  * Get an attribute index for a cterm entry.
2187f9cc9f20SBram Moolenaar  * Uses an existing entry when possible or adds one when needed.
2188f9cc9f20SBram Moolenaar  */
2189f9cc9f20SBram Moolenaar     int
2190f9cc9f20SBram Moolenaar get_cterm_attr_idx(int attr, int fg, int bg)
2191f9cc9f20SBram Moolenaar {
2192f9cc9f20SBram Moolenaar     attrentry_T		at_en;
2193f9cc9f20SBram Moolenaar 
2194f9cc9f20SBram Moolenaar     vim_memset(&at_en, 0, sizeof(attrentry_T));
2195f9cc9f20SBram Moolenaar #ifdef FEAT_TERMGUICOLORS
2196f9cc9f20SBram Moolenaar     at_en.ae_u.cterm.fg_rgb = INVALCOLOR;
2197f9cc9f20SBram Moolenaar     at_en.ae_u.cterm.bg_rgb = INVALCOLOR;
2198f9cc9f20SBram Moolenaar #endif
2199f9cc9f20SBram Moolenaar     at_en.ae_attr = attr;
2200f9cc9f20SBram Moolenaar     at_en.ae_u.cterm.fg_color = fg;
2201f9cc9f20SBram Moolenaar     at_en.ae_u.cterm.bg_color = bg;
2202f9cc9f20SBram Moolenaar     return get_attr_entry(&cterm_attr_table, &at_en);
2203f9cc9f20SBram Moolenaar }
2204f9cc9f20SBram Moolenaar #endif
2205f9cc9f20SBram Moolenaar 
2206f9cc9f20SBram Moolenaar #if (defined(FEAT_TERMINAL) && defined(FEAT_TERMGUICOLORS)) || defined(PROTO)
2207f9cc9f20SBram Moolenaar /*
2208f9cc9f20SBram Moolenaar  * Get an attribute index for a 'termguicolors' entry.
2209f9cc9f20SBram Moolenaar  * Uses an existing entry when possible or adds one when needed.
2210f9cc9f20SBram Moolenaar  */
2211f9cc9f20SBram Moolenaar     int
2212f9cc9f20SBram Moolenaar get_tgc_attr_idx(int attr, guicolor_T fg, guicolor_T bg)
2213f9cc9f20SBram Moolenaar {
2214f9cc9f20SBram Moolenaar     attrentry_T		at_en;
2215f9cc9f20SBram Moolenaar 
2216f9cc9f20SBram Moolenaar     vim_memset(&at_en, 0, sizeof(attrentry_T));
2217f9cc9f20SBram Moolenaar     at_en.ae_attr = attr;
2218f9cc9f20SBram Moolenaar     if (fg == INVALCOLOR && bg == INVALCOLOR)
2219f9cc9f20SBram Moolenaar     {
2220f9cc9f20SBram Moolenaar 	// If both GUI colors are not set fall back to the cterm colors.  Helps
2221f9cc9f20SBram Moolenaar 	// if the GUI only has an attribute, such as undercurl.
2222f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.fg_rgb = CTERMCOLOR;
2223f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.bg_rgb = CTERMCOLOR;
2224f9cc9f20SBram Moolenaar     }
2225f9cc9f20SBram Moolenaar     else
2226f9cc9f20SBram Moolenaar     {
2227f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.fg_rgb = fg;
2228f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.bg_rgb = bg;
2229f9cc9f20SBram Moolenaar     }
2230f9cc9f20SBram Moolenaar     return get_attr_entry(&cterm_attr_table, &at_en);
2231f9cc9f20SBram Moolenaar }
2232f9cc9f20SBram Moolenaar #endif
2233f9cc9f20SBram Moolenaar 
2234f9cc9f20SBram Moolenaar #if (defined(FEAT_TERMINAL) && defined(FEAT_GUI)) || defined(PROTO)
2235f9cc9f20SBram Moolenaar /*
2236f9cc9f20SBram Moolenaar  * Get an attribute index for a cterm entry.
2237f9cc9f20SBram Moolenaar  * Uses an existing entry when possible or adds one when needed.
2238f9cc9f20SBram Moolenaar  */
2239f9cc9f20SBram Moolenaar     int
2240f9cc9f20SBram Moolenaar get_gui_attr_idx(int attr, guicolor_T fg, guicolor_T bg)
2241f9cc9f20SBram Moolenaar {
2242f9cc9f20SBram Moolenaar     attrentry_T		at_en;
2243f9cc9f20SBram Moolenaar 
2244f9cc9f20SBram Moolenaar     vim_memset(&at_en, 0, sizeof(attrentry_T));
2245f9cc9f20SBram Moolenaar     at_en.ae_attr = attr;
2246f9cc9f20SBram Moolenaar     at_en.ae_u.gui.fg_color = fg;
2247f9cc9f20SBram Moolenaar     at_en.ae_u.gui.bg_color = bg;
2248f9cc9f20SBram Moolenaar     return get_attr_entry(&gui_attr_table, &at_en);
2249f9cc9f20SBram Moolenaar }
2250f9cc9f20SBram Moolenaar #endif
2251f9cc9f20SBram Moolenaar 
2252f9cc9f20SBram Moolenaar /*
2253f9cc9f20SBram Moolenaar  * Clear all highlight tables.
2254f9cc9f20SBram Moolenaar  */
2255f9cc9f20SBram Moolenaar     void
2256f9cc9f20SBram Moolenaar clear_hl_tables(void)
2257f9cc9f20SBram Moolenaar {
2258f9cc9f20SBram Moolenaar     int		i;
2259f9cc9f20SBram Moolenaar     attrentry_T	*taep;
2260f9cc9f20SBram Moolenaar 
2261f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2262f9cc9f20SBram Moolenaar     ga_clear(&gui_attr_table);
2263f9cc9f20SBram Moolenaar #endif
2264f9cc9f20SBram Moolenaar     for (i = 0; i < term_attr_table.ga_len; ++i)
2265f9cc9f20SBram Moolenaar     {
2266f9cc9f20SBram Moolenaar 	taep = &(((attrentry_T *)term_attr_table.ga_data)[i]);
2267f9cc9f20SBram Moolenaar 	vim_free(taep->ae_u.term.start);
2268f9cc9f20SBram Moolenaar 	vim_free(taep->ae_u.term.stop);
2269f9cc9f20SBram Moolenaar     }
2270f9cc9f20SBram Moolenaar     ga_clear(&term_attr_table);
2271f9cc9f20SBram Moolenaar     ga_clear(&cterm_attr_table);
2272f9cc9f20SBram Moolenaar }
2273f9cc9f20SBram Moolenaar 
2274f9cc9f20SBram Moolenaar /*
2275f9cc9f20SBram Moolenaar  * Combine special attributes (e.g., for spelling) with other attributes
2276f9cc9f20SBram Moolenaar  * (e.g., for syntax highlighting).
2277f9cc9f20SBram Moolenaar  * "prim_attr" overrules "char_attr".
2278f9cc9f20SBram Moolenaar  * This creates a new group when required.
2279f9cc9f20SBram Moolenaar  * Since we expect there to be few spelling mistakes we don't cache the
2280f9cc9f20SBram Moolenaar  * result.
2281f9cc9f20SBram Moolenaar  * Return the resulting attributes.
2282f9cc9f20SBram Moolenaar  */
2283f9cc9f20SBram Moolenaar     int
2284f9cc9f20SBram Moolenaar hl_combine_attr(int char_attr, int prim_attr)
2285f9cc9f20SBram Moolenaar {
2286f9cc9f20SBram Moolenaar     attrentry_T *char_aep = NULL;
2287f9cc9f20SBram Moolenaar     attrentry_T *spell_aep;
2288f9cc9f20SBram Moolenaar     attrentry_T new_en;
2289f9cc9f20SBram Moolenaar 
2290f9cc9f20SBram Moolenaar     if (char_attr == 0)
2291f9cc9f20SBram Moolenaar 	return prim_attr;
2292f9cc9f20SBram Moolenaar     if (char_attr <= HL_ALL && prim_attr <= HL_ALL)
2293f9cc9f20SBram Moolenaar 	return ATTR_COMBINE(char_attr, prim_attr);
2294f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2295f9cc9f20SBram Moolenaar     if (gui.in_use)
2296f9cc9f20SBram Moolenaar     {
2297f9cc9f20SBram Moolenaar 	if (char_attr > HL_ALL)
2298f9cc9f20SBram Moolenaar 	    char_aep = syn_gui_attr2entry(char_attr);
2299f9cc9f20SBram Moolenaar 	if (char_aep != NULL)
2300f9cc9f20SBram Moolenaar 	    new_en = *char_aep;
2301f9cc9f20SBram Moolenaar 	else
2302f9cc9f20SBram Moolenaar 	{
2303f9cc9f20SBram Moolenaar 	    vim_memset(&new_en, 0, sizeof(new_en));
2304f9cc9f20SBram Moolenaar 	    new_en.ae_u.gui.fg_color = INVALCOLOR;
2305f9cc9f20SBram Moolenaar 	    new_en.ae_u.gui.bg_color = INVALCOLOR;
2306f9cc9f20SBram Moolenaar 	    new_en.ae_u.gui.sp_color = INVALCOLOR;
2307f9cc9f20SBram Moolenaar 	    if (char_attr <= HL_ALL)
2308f9cc9f20SBram Moolenaar 		new_en.ae_attr = char_attr;
2309f9cc9f20SBram Moolenaar 	}
2310f9cc9f20SBram Moolenaar 
2311f9cc9f20SBram Moolenaar 	if (prim_attr <= HL_ALL)
2312f9cc9f20SBram Moolenaar 	    new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr);
2313f9cc9f20SBram Moolenaar 	else
2314f9cc9f20SBram Moolenaar 	{
2315f9cc9f20SBram Moolenaar 	    spell_aep = syn_gui_attr2entry(prim_attr);
2316f9cc9f20SBram Moolenaar 	    if (spell_aep != NULL)
2317f9cc9f20SBram Moolenaar 	    {
2318f9cc9f20SBram Moolenaar 		new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr,
2319f9cc9f20SBram Moolenaar 							   spell_aep->ae_attr);
2320f9cc9f20SBram Moolenaar 		if (spell_aep->ae_u.gui.fg_color != INVALCOLOR)
2321f9cc9f20SBram Moolenaar 		    new_en.ae_u.gui.fg_color = spell_aep->ae_u.gui.fg_color;
2322f9cc9f20SBram Moolenaar 		if (spell_aep->ae_u.gui.bg_color != INVALCOLOR)
2323f9cc9f20SBram Moolenaar 		    new_en.ae_u.gui.bg_color = spell_aep->ae_u.gui.bg_color;
2324f9cc9f20SBram Moolenaar 		if (spell_aep->ae_u.gui.sp_color != INVALCOLOR)
2325f9cc9f20SBram Moolenaar 		    new_en.ae_u.gui.sp_color = spell_aep->ae_u.gui.sp_color;
2326f9cc9f20SBram Moolenaar 		if (spell_aep->ae_u.gui.font != NOFONT)
2327f9cc9f20SBram Moolenaar 		    new_en.ae_u.gui.font = spell_aep->ae_u.gui.font;
2328f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
2329f9cc9f20SBram Moolenaar 		if (spell_aep->ae_u.gui.fontset != NOFONTSET)
2330f9cc9f20SBram Moolenaar 		    new_en.ae_u.gui.fontset = spell_aep->ae_u.gui.fontset;
2331f9cc9f20SBram Moolenaar # endif
2332f9cc9f20SBram Moolenaar 	    }
2333f9cc9f20SBram Moolenaar 	}
2334f9cc9f20SBram Moolenaar 	return get_attr_entry(&gui_attr_table, &new_en);
2335f9cc9f20SBram Moolenaar     }
2336f9cc9f20SBram Moolenaar #endif
2337f9cc9f20SBram Moolenaar 
2338f9cc9f20SBram Moolenaar     if (IS_CTERM)
2339f9cc9f20SBram Moolenaar     {
2340f9cc9f20SBram Moolenaar 	if (char_attr > HL_ALL)
2341f9cc9f20SBram Moolenaar 	    char_aep = syn_cterm_attr2entry(char_attr);
2342f9cc9f20SBram Moolenaar 	if (char_aep != NULL)
2343f9cc9f20SBram Moolenaar 	    new_en = *char_aep;
2344f9cc9f20SBram Moolenaar 	else
2345f9cc9f20SBram Moolenaar 	{
2346f9cc9f20SBram Moolenaar 	    vim_memset(&new_en, 0, sizeof(new_en));
2347f9cc9f20SBram Moolenaar #ifdef FEAT_TERMGUICOLORS
2348f9cc9f20SBram Moolenaar 	    new_en.ae_u.cterm.bg_rgb = INVALCOLOR;
2349f9cc9f20SBram Moolenaar 	    new_en.ae_u.cterm.fg_rgb = INVALCOLOR;
2350f9cc9f20SBram Moolenaar #endif
2351f9cc9f20SBram Moolenaar 	    if (char_attr <= HL_ALL)
2352f9cc9f20SBram Moolenaar 		new_en.ae_attr = char_attr;
2353f9cc9f20SBram Moolenaar 	}
2354f9cc9f20SBram Moolenaar 
2355f9cc9f20SBram Moolenaar 	if (prim_attr <= HL_ALL)
2356f9cc9f20SBram Moolenaar 		new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr);
2357f9cc9f20SBram Moolenaar 	else
2358f9cc9f20SBram Moolenaar 	{
2359f9cc9f20SBram Moolenaar 	    spell_aep = syn_cterm_attr2entry(prim_attr);
2360f9cc9f20SBram Moolenaar 	    if (spell_aep != NULL)
2361f9cc9f20SBram Moolenaar 	    {
2362f9cc9f20SBram Moolenaar 		new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr,
2363f9cc9f20SBram Moolenaar 							   spell_aep->ae_attr);
2364f9cc9f20SBram Moolenaar 		if (spell_aep->ae_u.cterm.fg_color > 0)
2365f9cc9f20SBram Moolenaar 		    new_en.ae_u.cterm.fg_color = spell_aep->ae_u.cterm.fg_color;
2366f9cc9f20SBram Moolenaar 		if (spell_aep->ae_u.cterm.bg_color > 0)
2367f9cc9f20SBram Moolenaar 		    new_en.ae_u.cterm.bg_color = spell_aep->ae_u.cterm.bg_color;
2368f9cc9f20SBram Moolenaar #ifdef FEAT_TERMGUICOLORS
2369f9cc9f20SBram Moolenaar 		// If both fg and bg are not set fall back to cterm colors.
2370f9cc9f20SBram Moolenaar 		// Helps for SpellBad which uses undercurl in the GUI.
2371f9cc9f20SBram Moolenaar 		if (COLOR_INVALID(spell_aep->ae_u.cterm.fg_rgb)
2372f9cc9f20SBram Moolenaar 			&& COLOR_INVALID(spell_aep->ae_u.cterm.bg_rgb))
2373f9cc9f20SBram Moolenaar 		{
2374f9cc9f20SBram Moolenaar 		    if (spell_aep->ae_u.cterm.fg_color > 0)
2375f9cc9f20SBram Moolenaar 			new_en.ae_u.cterm.fg_rgb = CTERMCOLOR;
2376f9cc9f20SBram Moolenaar 		    if (spell_aep->ae_u.cterm.bg_color > 0)
2377f9cc9f20SBram Moolenaar 			new_en.ae_u.cterm.bg_rgb = CTERMCOLOR;
2378f9cc9f20SBram Moolenaar 		}
2379f9cc9f20SBram Moolenaar 		else
2380f9cc9f20SBram Moolenaar 		{
2381f9cc9f20SBram Moolenaar 		    if (spell_aep->ae_u.cterm.fg_rgb != INVALCOLOR)
2382f9cc9f20SBram Moolenaar 			new_en.ae_u.cterm.fg_rgb = spell_aep->ae_u.cterm.fg_rgb;
2383f9cc9f20SBram Moolenaar 		    if (spell_aep->ae_u.cterm.bg_rgb != INVALCOLOR)
2384f9cc9f20SBram Moolenaar 			new_en.ae_u.cterm.bg_rgb = spell_aep->ae_u.cterm.bg_rgb;
2385f9cc9f20SBram Moolenaar 		}
2386f9cc9f20SBram Moolenaar #endif
2387f9cc9f20SBram Moolenaar 	    }
2388f9cc9f20SBram Moolenaar 	}
2389f9cc9f20SBram Moolenaar 	return get_attr_entry(&cterm_attr_table, &new_en);
2390f9cc9f20SBram Moolenaar     }
2391f9cc9f20SBram Moolenaar 
2392f9cc9f20SBram Moolenaar     if (char_attr > HL_ALL)
2393f9cc9f20SBram Moolenaar 	char_aep = syn_term_attr2entry(char_attr);
2394f9cc9f20SBram Moolenaar     if (char_aep != NULL)
2395f9cc9f20SBram Moolenaar 	new_en = *char_aep;
2396f9cc9f20SBram Moolenaar     else
2397f9cc9f20SBram Moolenaar     {
2398f9cc9f20SBram Moolenaar 	vim_memset(&new_en, 0, sizeof(new_en));
2399f9cc9f20SBram Moolenaar 	if (char_attr <= HL_ALL)
2400f9cc9f20SBram Moolenaar 	    new_en.ae_attr = char_attr;
2401f9cc9f20SBram Moolenaar     }
2402f9cc9f20SBram Moolenaar 
2403f9cc9f20SBram Moolenaar     if (prim_attr <= HL_ALL)
2404f9cc9f20SBram Moolenaar 	new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr);
2405f9cc9f20SBram Moolenaar     else
2406f9cc9f20SBram Moolenaar     {
2407f9cc9f20SBram Moolenaar 	spell_aep = syn_term_attr2entry(prim_attr);
2408f9cc9f20SBram Moolenaar 	if (spell_aep != NULL)
2409f9cc9f20SBram Moolenaar 	{
2410f9cc9f20SBram Moolenaar 	    new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, spell_aep->ae_attr);
2411f9cc9f20SBram Moolenaar 	    if (spell_aep->ae_u.term.start != NULL)
2412f9cc9f20SBram Moolenaar 	    {
2413f9cc9f20SBram Moolenaar 		new_en.ae_u.term.start = spell_aep->ae_u.term.start;
2414f9cc9f20SBram Moolenaar 		new_en.ae_u.term.stop = spell_aep->ae_u.term.stop;
2415f9cc9f20SBram Moolenaar 	    }
2416f9cc9f20SBram Moolenaar 	}
2417f9cc9f20SBram Moolenaar     }
2418f9cc9f20SBram Moolenaar     return get_attr_entry(&term_attr_table, &new_en);
2419f9cc9f20SBram Moolenaar }
2420f9cc9f20SBram Moolenaar 
2421f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2422f9cc9f20SBram Moolenaar     attrentry_T *
2423f9cc9f20SBram Moolenaar syn_gui_attr2entry(int attr)
2424f9cc9f20SBram Moolenaar {
2425f9cc9f20SBram Moolenaar     attr -= ATTR_OFF;
2426f9cc9f20SBram Moolenaar     if (attr >= gui_attr_table.ga_len)	    // did ":syntax clear"
2427f9cc9f20SBram Moolenaar 	return NULL;
2428f9cc9f20SBram Moolenaar     return &(GUI_ATTR_ENTRY(attr));
2429f9cc9f20SBram Moolenaar }
2430f9cc9f20SBram Moolenaar #endif
2431f9cc9f20SBram Moolenaar 
2432f9cc9f20SBram Moolenaar /*
2433f9cc9f20SBram Moolenaar  * Get the highlight attributes (HL_BOLD etc.) from an attribute nr.
2434f9cc9f20SBram Moolenaar  * Only to be used when "attr" > HL_ALL.
2435f9cc9f20SBram Moolenaar  */
2436f9cc9f20SBram Moolenaar     int
2437f9cc9f20SBram Moolenaar syn_attr2attr(int attr)
2438f9cc9f20SBram Moolenaar {
2439f9cc9f20SBram Moolenaar     attrentry_T	*aep;
2440f9cc9f20SBram Moolenaar 
2441f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2442f9cc9f20SBram Moolenaar     if (gui.in_use)
2443f9cc9f20SBram Moolenaar 	aep = syn_gui_attr2entry(attr);
2444f9cc9f20SBram Moolenaar     else
2445f9cc9f20SBram Moolenaar #endif
2446f9cc9f20SBram Moolenaar 	if (IS_CTERM)
2447f9cc9f20SBram Moolenaar 	    aep = syn_cterm_attr2entry(attr);
2448f9cc9f20SBram Moolenaar 	else
2449f9cc9f20SBram Moolenaar 	    aep = syn_term_attr2entry(attr);
2450f9cc9f20SBram Moolenaar 
2451f9cc9f20SBram Moolenaar     if (aep == NULL)	    // highlighting not set
2452f9cc9f20SBram Moolenaar 	return 0;
2453f9cc9f20SBram Moolenaar     return aep->ae_attr;
2454f9cc9f20SBram Moolenaar }
2455f9cc9f20SBram Moolenaar 
2456f9cc9f20SBram Moolenaar 
2457f9cc9f20SBram Moolenaar     attrentry_T *
2458f9cc9f20SBram Moolenaar syn_term_attr2entry(int attr)
2459f9cc9f20SBram Moolenaar {
2460f9cc9f20SBram Moolenaar     attr -= ATTR_OFF;
2461f9cc9f20SBram Moolenaar     if (attr >= term_attr_table.ga_len)	    // did ":syntax clear"
2462f9cc9f20SBram Moolenaar 	return NULL;
2463f9cc9f20SBram Moolenaar     return &(TERM_ATTR_ENTRY(attr));
2464f9cc9f20SBram Moolenaar }
2465f9cc9f20SBram Moolenaar 
2466f9cc9f20SBram Moolenaar     attrentry_T *
2467f9cc9f20SBram Moolenaar syn_cterm_attr2entry(int attr)
2468f9cc9f20SBram Moolenaar {
2469f9cc9f20SBram Moolenaar     attr -= ATTR_OFF;
2470f9cc9f20SBram Moolenaar     if (attr >= cterm_attr_table.ga_len)	// did ":syntax clear"
2471f9cc9f20SBram Moolenaar 	return NULL;
2472f9cc9f20SBram Moolenaar     return &(CTERM_ATTR_ENTRY(attr));
2473f9cc9f20SBram Moolenaar }
2474f9cc9f20SBram Moolenaar 
2475f9cc9f20SBram Moolenaar #define LIST_ATTR   1
2476f9cc9f20SBram Moolenaar #define LIST_STRING 2
2477f9cc9f20SBram Moolenaar #define LIST_INT    3
2478f9cc9f20SBram Moolenaar 
2479f9cc9f20SBram Moolenaar     static void
2480f9cc9f20SBram Moolenaar highlight_list_one(int id)
2481f9cc9f20SBram Moolenaar {
2482f9cc9f20SBram Moolenaar     hl_group_T	    *sgp;
2483f9cc9f20SBram Moolenaar     int		    didh = FALSE;
2484f9cc9f20SBram Moolenaar 
2485f9cc9f20SBram Moolenaar     sgp = &HL_TABLE()[id - 1];	    // index is ID minus one
2486f9cc9f20SBram Moolenaar 
2487f9cc9f20SBram Moolenaar     if (message_filtered(sgp->sg_name))
2488f9cc9f20SBram Moolenaar 	return;
2489f9cc9f20SBram Moolenaar 
2490f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_ATTR,
2491f9cc9f20SBram Moolenaar 				    sgp->sg_term, NULL, "term");
2492f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_STRING,
2493f9cc9f20SBram Moolenaar 				    0, sgp->sg_start, "start");
2494f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_STRING,
2495f9cc9f20SBram Moolenaar 				    0, sgp->sg_stop, "stop");
2496f9cc9f20SBram Moolenaar 
2497f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_ATTR,
2498f9cc9f20SBram Moolenaar 				    sgp->sg_cterm, NULL, "cterm");
2499f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_INT,
2500f9cc9f20SBram Moolenaar 				    sgp->sg_cterm_fg, NULL, "ctermfg");
2501f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_INT,
2502f9cc9f20SBram Moolenaar 				    sgp->sg_cterm_bg, NULL, "ctermbg");
2503f9cc9f20SBram Moolenaar 
2504f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
2505f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_ATTR,
2506f9cc9f20SBram Moolenaar 				    sgp->sg_gui, NULL, "gui");
2507f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_STRING,
2508f9cc9f20SBram Moolenaar 				    0, sgp->sg_gui_fg_name, "guifg");
2509f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_STRING,
2510f9cc9f20SBram Moolenaar 				    0, sgp->sg_gui_bg_name, "guibg");
2511f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_STRING,
2512f9cc9f20SBram Moolenaar 				    0, sgp->sg_gui_sp_name, "guisp");
2513f9cc9f20SBram Moolenaar #endif
2514f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2515f9cc9f20SBram Moolenaar     didh = highlight_list_arg(id, didh, LIST_STRING,
2516f9cc9f20SBram Moolenaar 				    0, sgp->sg_font_name, "font");
2517f9cc9f20SBram Moolenaar #endif
2518f9cc9f20SBram Moolenaar 
2519f9cc9f20SBram Moolenaar     if (sgp->sg_link && !got_int)
2520f9cc9f20SBram Moolenaar     {
2521f9cc9f20SBram Moolenaar 	(void)syn_list_header(didh, 9999, id);
2522f9cc9f20SBram Moolenaar 	didh = TRUE;
2523f9cc9f20SBram Moolenaar 	msg_puts_attr("links to", HL_ATTR(HLF_D));
2524f9cc9f20SBram Moolenaar 	msg_putchar(' ');
2525f9cc9f20SBram Moolenaar 	msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
2526f9cc9f20SBram Moolenaar     }
2527f9cc9f20SBram Moolenaar 
2528f9cc9f20SBram Moolenaar     if (!didh)
2529f9cc9f20SBram Moolenaar 	highlight_list_arg(id, didh, LIST_STRING, 0, (char_u *)"cleared", "");
2530f9cc9f20SBram Moolenaar #ifdef FEAT_EVAL
2531f9cc9f20SBram Moolenaar     if (p_verbose > 0)
2532f9cc9f20SBram Moolenaar 	last_set_msg(sgp->sg_script_ctx);
2533f9cc9f20SBram Moolenaar #endif
2534f9cc9f20SBram Moolenaar }
2535f9cc9f20SBram Moolenaar 
2536f9cc9f20SBram Moolenaar     static int
2537f9cc9f20SBram Moolenaar highlight_list_arg(
2538f9cc9f20SBram Moolenaar     int		id,
2539f9cc9f20SBram Moolenaar     int		didh,
2540f9cc9f20SBram Moolenaar     int		type,
2541f9cc9f20SBram Moolenaar     int		iarg,
2542f9cc9f20SBram Moolenaar     char_u	*sarg,
2543f9cc9f20SBram Moolenaar     char	*name)
2544f9cc9f20SBram Moolenaar {
2545f9cc9f20SBram Moolenaar     char_u	buf[100];
2546f9cc9f20SBram Moolenaar     char_u	*ts;
2547f9cc9f20SBram Moolenaar     int		i;
2548f9cc9f20SBram Moolenaar 
2549f9cc9f20SBram Moolenaar     if (got_int)
2550f9cc9f20SBram Moolenaar 	return FALSE;
2551f9cc9f20SBram Moolenaar     if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0))
2552f9cc9f20SBram Moolenaar     {
2553f9cc9f20SBram Moolenaar 	ts = buf;
2554f9cc9f20SBram Moolenaar 	if (type == LIST_INT)
2555f9cc9f20SBram Moolenaar 	    sprintf((char *)buf, "%d", iarg - 1);
2556f9cc9f20SBram Moolenaar 	else if (type == LIST_STRING)
2557f9cc9f20SBram Moolenaar 	    ts = sarg;
2558f9cc9f20SBram Moolenaar 	else // type == LIST_ATTR
2559f9cc9f20SBram Moolenaar 	{
2560f9cc9f20SBram Moolenaar 	    buf[0] = NUL;
2561f9cc9f20SBram Moolenaar 	    for (i = 0; hl_attr_table[i] != 0; ++i)
2562f9cc9f20SBram Moolenaar 	    {
2563f9cc9f20SBram Moolenaar 		if (iarg & hl_attr_table[i])
2564f9cc9f20SBram Moolenaar 		{
2565f9cc9f20SBram Moolenaar 		    if (buf[0] != NUL)
2566f9cc9f20SBram Moolenaar 			vim_strcat(buf, (char_u *)",", 100);
2567f9cc9f20SBram Moolenaar 		    vim_strcat(buf, (char_u *)hl_name_table[i], 100);
2568f9cc9f20SBram Moolenaar 		    iarg &= ~hl_attr_table[i];	    // don't want "inverse"
2569f9cc9f20SBram Moolenaar 		}
2570f9cc9f20SBram Moolenaar 	    }
2571f9cc9f20SBram Moolenaar 	}
2572f9cc9f20SBram Moolenaar 
2573f9cc9f20SBram Moolenaar 	(void)syn_list_header(didh,
2574f9cc9f20SBram Moolenaar 			       (int)(vim_strsize(ts) + STRLEN(name) + 1), id);
2575f9cc9f20SBram Moolenaar 	didh = TRUE;
2576f9cc9f20SBram Moolenaar 	if (!got_int)
2577f9cc9f20SBram Moolenaar 	{
2578f9cc9f20SBram Moolenaar 	    if (*name != NUL)
2579f9cc9f20SBram Moolenaar 	    {
2580f9cc9f20SBram Moolenaar 		msg_puts_attr(name, HL_ATTR(HLF_D));
2581f9cc9f20SBram Moolenaar 		msg_puts_attr("=", HL_ATTR(HLF_D));
2582f9cc9f20SBram Moolenaar 	    }
2583f9cc9f20SBram Moolenaar 	    msg_outtrans(ts);
2584f9cc9f20SBram Moolenaar 	}
2585f9cc9f20SBram Moolenaar     }
2586f9cc9f20SBram Moolenaar     return didh;
2587f9cc9f20SBram Moolenaar }
2588f9cc9f20SBram Moolenaar 
2589f9cc9f20SBram Moolenaar #if (((defined(FEAT_EVAL) || defined(FEAT_PRINTER))) && defined(FEAT_SYN_HL)) || defined(PROTO)
2590f9cc9f20SBram Moolenaar /*
2591f9cc9f20SBram Moolenaar  * Return "1" if highlight group "id" has attribute "flag".
2592f9cc9f20SBram Moolenaar  * Return NULL otherwise.
2593f9cc9f20SBram Moolenaar  */
2594f9cc9f20SBram Moolenaar     char_u *
2595f9cc9f20SBram Moolenaar highlight_has_attr(
2596f9cc9f20SBram Moolenaar     int		id,
2597f9cc9f20SBram Moolenaar     int		flag,
2598f9cc9f20SBram Moolenaar     int		modec)	// 'g' for GUI, 'c' for cterm, 't' for term
2599f9cc9f20SBram Moolenaar {
2600f9cc9f20SBram Moolenaar     int		attr;
2601f9cc9f20SBram Moolenaar 
2602f9cc9f20SBram Moolenaar     if (id <= 0 || id > highlight_ga.ga_len)
2603f9cc9f20SBram Moolenaar 	return NULL;
2604f9cc9f20SBram Moolenaar 
2605f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_EVAL)
2606f9cc9f20SBram Moolenaar     if (modec == 'g')
2607f9cc9f20SBram Moolenaar 	attr = HL_TABLE()[id - 1].sg_gui;
2608f9cc9f20SBram Moolenaar     else
2609f9cc9f20SBram Moolenaar #endif
2610f9cc9f20SBram Moolenaar 	 if (modec == 'c')
2611f9cc9f20SBram Moolenaar 	attr = HL_TABLE()[id - 1].sg_cterm;
2612f9cc9f20SBram Moolenaar     else
2613f9cc9f20SBram Moolenaar 	attr = HL_TABLE()[id - 1].sg_term;
2614f9cc9f20SBram Moolenaar 
2615f9cc9f20SBram Moolenaar     if (attr & flag)
2616f9cc9f20SBram Moolenaar 	return (char_u *)"1";
2617f9cc9f20SBram Moolenaar     return NULL;
2618f9cc9f20SBram Moolenaar }
2619f9cc9f20SBram Moolenaar #endif
2620f9cc9f20SBram Moolenaar 
2621f9cc9f20SBram Moolenaar #if (defined(FEAT_SYN_HL) && defined(FEAT_EVAL)) || defined(PROTO)
2622f9cc9f20SBram Moolenaar /*
2623f9cc9f20SBram Moolenaar  * Return color name of highlight group "id".
2624f9cc9f20SBram Moolenaar  */
2625f9cc9f20SBram Moolenaar     char_u *
2626f9cc9f20SBram Moolenaar highlight_color(
2627f9cc9f20SBram Moolenaar     int		id,
2628f9cc9f20SBram Moolenaar     char_u	*what,	// "font", "fg", "bg", "sp", "fg#", "bg#" or "sp#"
2629f9cc9f20SBram Moolenaar     int		modec)	// 'g' for GUI, 'c' for cterm, 't' for term
2630f9cc9f20SBram Moolenaar {
2631f9cc9f20SBram Moolenaar     static char_u	name[20];
2632f9cc9f20SBram Moolenaar     int			n;
2633f9cc9f20SBram Moolenaar     int			fg = FALSE;
2634f9cc9f20SBram Moolenaar     int			sp = FALSE;
2635f9cc9f20SBram Moolenaar     int			font = FALSE;
2636f9cc9f20SBram Moolenaar 
2637f9cc9f20SBram Moolenaar     if (id <= 0 || id > highlight_ga.ga_len)
2638f9cc9f20SBram Moolenaar 	return NULL;
2639f9cc9f20SBram Moolenaar 
2640f9cc9f20SBram Moolenaar     if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g')
2641f9cc9f20SBram Moolenaar 	fg = TRUE;
2642f9cc9f20SBram Moolenaar     else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o'
2643f9cc9f20SBram Moolenaar 	     && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't')
2644f9cc9f20SBram Moolenaar 	font = TRUE;
2645f9cc9f20SBram Moolenaar     else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p')
2646f9cc9f20SBram Moolenaar 	sp = TRUE;
2647f9cc9f20SBram Moolenaar     else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g'))
2648f9cc9f20SBram Moolenaar 	return NULL;
2649f9cc9f20SBram Moolenaar     if (modec == 'g')
2650f9cc9f20SBram Moolenaar     {
2651f9cc9f20SBram Moolenaar # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
2652f9cc9f20SBram Moolenaar #  ifdef FEAT_GUI
2653f9cc9f20SBram Moolenaar 	// return font name
2654f9cc9f20SBram Moolenaar 	if (font)
2655f9cc9f20SBram Moolenaar 	    return HL_TABLE()[id - 1].sg_font_name;
2656f9cc9f20SBram Moolenaar #  endif
2657f9cc9f20SBram Moolenaar 
2658f9cc9f20SBram Moolenaar 	// return #RRGGBB form (only possible when GUI is running)
2659f9cc9f20SBram Moolenaar 	if ((USE_24BIT) && what[2] == '#')
2660f9cc9f20SBram Moolenaar 	{
2661f9cc9f20SBram Moolenaar 	    guicolor_T		color;
2662f9cc9f20SBram Moolenaar 	    long_u		rgb;
2663f9cc9f20SBram Moolenaar 	    static char_u	buf[10];
2664f9cc9f20SBram Moolenaar 
2665f9cc9f20SBram Moolenaar 	    if (fg)
2666f9cc9f20SBram Moolenaar 		color = HL_TABLE()[id - 1].sg_gui_fg;
2667f9cc9f20SBram Moolenaar 	    else if (sp)
2668f9cc9f20SBram Moolenaar #  ifdef FEAT_GUI
2669f9cc9f20SBram Moolenaar 		color = HL_TABLE()[id - 1].sg_gui_sp;
2670f9cc9f20SBram Moolenaar #  else
2671f9cc9f20SBram Moolenaar 		color = INVALCOLOR;
2672f9cc9f20SBram Moolenaar #  endif
2673f9cc9f20SBram Moolenaar 	    else
2674f9cc9f20SBram Moolenaar 		color = HL_TABLE()[id - 1].sg_gui_bg;
2675f9cc9f20SBram Moolenaar 	    if (color == INVALCOLOR)
2676f9cc9f20SBram Moolenaar 		return NULL;
2677f9cc9f20SBram Moolenaar 	    rgb = (long_u)GUI_MCH_GET_RGB(color);
2678f9cc9f20SBram Moolenaar 	    sprintf((char *)buf, "#%02x%02x%02x",
2679f9cc9f20SBram Moolenaar 				      (unsigned)(rgb >> 16),
2680f9cc9f20SBram Moolenaar 				      (unsigned)(rgb >> 8) & 255,
2681f9cc9f20SBram Moolenaar 				      (unsigned)rgb & 255);
2682f9cc9f20SBram Moolenaar 	    return buf;
2683f9cc9f20SBram Moolenaar 	}
2684f9cc9f20SBram Moolenaar # endif
2685f9cc9f20SBram Moolenaar 	if (fg)
2686f9cc9f20SBram Moolenaar 	    return (HL_TABLE()[id - 1].sg_gui_fg_name);
2687f9cc9f20SBram Moolenaar 	if (sp)
2688f9cc9f20SBram Moolenaar 	    return (HL_TABLE()[id - 1].sg_gui_sp_name);
2689f9cc9f20SBram Moolenaar 	return (HL_TABLE()[id - 1].sg_gui_bg_name);
2690f9cc9f20SBram Moolenaar     }
2691f9cc9f20SBram Moolenaar     if (font || sp)
2692f9cc9f20SBram Moolenaar 	return NULL;
2693f9cc9f20SBram Moolenaar     if (modec == 'c')
2694f9cc9f20SBram Moolenaar     {
2695f9cc9f20SBram Moolenaar 	if (fg)
2696f9cc9f20SBram Moolenaar 	    n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
2697f9cc9f20SBram Moolenaar 	else
2698f9cc9f20SBram Moolenaar 	    n = HL_TABLE()[id - 1].sg_cterm_bg - 1;
2699f9cc9f20SBram Moolenaar 	if (n < 0)
2700f9cc9f20SBram Moolenaar 	    return NULL;
2701f9cc9f20SBram Moolenaar 	sprintf((char *)name, "%d", n);
2702f9cc9f20SBram Moolenaar 	return name;
2703f9cc9f20SBram Moolenaar     }
2704f9cc9f20SBram Moolenaar     // term doesn't have color
2705f9cc9f20SBram Moolenaar     return NULL;
2706f9cc9f20SBram Moolenaar }
2707f9cc9f20SBram Moolenaar #endif
2708f9cc9f20SBram Moolenaar 
2709f9cc9f20SBram Moolenaar #if (defined(FEAT_SYN_HL) \
2710f9cc9f20SBram Moolenaar 	    && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)) \
2711f9cc9f20SBram Moolenaar 	&& defined(FEAT_PRINTER)) || defined(PROTO)
2712f9cc9f20SBram Moolenaar /*
2713f9cc9f20SBram Moolenaar  * Return color name of highlight group "id" as RGB value.
2714f9cc9f20SBram Moolenaar  */
2715f9cc9f20SBram Moolenaar     long_u
2716f9cc9f20SBram Moolenaar highlight_gui_color_rgb(
2717f9cc9f20SBram Moolenaar     int		id,
2718f9cc9f20SBram Moolenaar     int		fg)	// TRUE = fg, FALSE = bg
2719f9cc9f20SBram Moolenaar {
2720f9cc9f20SBram Moolenaar     guicolor_T	color;
2721f9cc9f20SBram Moolenaar 
2722f9cc9f20SBram Moolenaar     if (id <= 0 || id > highlight_ga.ga_len)
2723f9cc9f20SBram Moolenaar 	return 0L;
2724f9cc9f20SBram Moolenaar 
2725f9cc9f20SBram Moolenaar     if (fg)
2726f9cc9f20SBram Moolenaar 	color = HL_TABLE()[id - 1].sg_gui_fg;
2727f9cc9f20SBram Moolenaar     else
2728f9cc9f20SBram Moolenaar 	color = HL_TABLE()[id - 1].sg_gui_bg;
2729f9cc9f20SBram Moolenaar 
2730f9cc9f20SBram Moolenaar     if (color == INVALCOLOR)
2731f9cc9f20SBram Moolenaar 	return 0L;
2732f9cc9f20SBram Moolenaar 
2733f9cc9f20SBram Moolenaar     return GUI_MCH_GET_RGB(color);
2734f9cc9f20SBram Moolenaar }
2735f9cc9f20SBram Moolenaar #endif
2736f9cc9f20SBram Moolenaar 
2737f9cc9f20SBram Moolenaar /*
2738f9cc9f20SBram Moolenaar  * Output the syntax list header.
2739f9cc9f20SBram Moolenaar  * Return TRUE when started a new line.
2740f9cc9f20SBram Moolenaar  */
2741f9cc9f20SBram Moolenaar     int
2742f9cc9f20SBram Moolenaar syn_list_header(
2743f9cc9f20SBram Moolenaar     int	    did_header,		// did header already
2744f9cc9f20SBram Moolenaar     int	    outlen,		// length of string that comes
2745f9cc9f20SBram Moolenaar     int	    id)			// highlight group id
2746f9cc9f20SBram Moolenaar {
2747f9cc9f20SBram Moolenaar     int	    endcol = 19;
2748f9cc9f20SBram Moolenaar     int	    newline = TRUE;
2749f9cc9f20SBram Moolenaar     int	    name_col = 0;
2750f9cc9f20SBram Moolenaar 
2751f9cc9f20SBram Moolenaar     if (!did_header)
2752f9cc9f20SBram Moolenaar     {
2753f9cc9f20SBram Moolenaar 	msg_putchar('\n');
2754f9cc9f20SBram Moolenaar 	if (got_int)
2755f9cc9f20SBram Moolenaar 	    return TRUE;
2756f9cc9f20SBram Moolenaar 	msg_outtrans(HL_TABLE()[id - 1].sg_name);
2757f9cc9f20SBram Moolenaar 	name_col = msg_col;
2758f9cc9f20SBram Moolenaar 	endcol = 15;
2759f9cc9f20SBram Moolenaar     }
2760f9cc9f20SBram Moolenaar     else if (msg_col + outlen + 1 >= Columns)
2761f9cc9f20SBram Moolenaar     {
2762f9cc9f20SBram Moolenaar 	msg_putchar('\n');
2763f9cc9f20SBram Moolenaar 	if (got_int)
2764f9cc9f20SBram Moolenaar 	    return TRUE;
2765f9cc9f20SBram Moolenaar     }
2766f9cc9f20SBram Moolenaar     else
2767f9cc9f20SBram Moolenaar     {
2768f9cc9f20SBram Moolenaar 	if (msg_col >= endcol)	// wrap around is like starting a new line
2769f9cc9f20SBram Moolenaar 	    newline = FALSE;
2770f9cc9f20SBram Moolenaar     }
2771f9cc9f20SBram Moolenaar 
2772f9cc9f20SBram Moolenaar     if (msg_col >= endcol)	// output at least one space
2773f9cc9f20SBram Moolenaar 	endcol = msg_col + 1;
2774f9cc9f20SBram Moolenaar     if (Columns <= endcol)	// avoid hang for tiny window
2775f9cc9f20SBram Moolenaar 	endcol = Columns - 1;
2776f9cc9f20SBram Moolenaar 
2777f9cc9f20SBram Moolenaar     msg_advance(endcol);
2778f9cc9f20SBram Moolenaar 
2779f9cc9f20SBram Moolenaar     // Show "xxx" with the attributes.
2780f9cc9f20SBram Moolenaar     if (!did_header)
2781f9cc9f20SBram Moolenaar     {
2782f9cc9f20SBram Moolenaar 	if (endcol == Columns - 1 && endcol <= name_col)
2783f9cc9f20SBram Moolenaar 	    msg_putchar(' ');
2784f9cc9f20SBram Moolenaar 	msg_puts_attr("xxx", syn_id2attr(id));
2785f9cc9f20SBram Moolenaar 	msg_putchar(' ');
2786f9cc9f20SBram Moolenaar     }
2787f9cc9f20SBram Moolenaar 
2788f9cc9f20SBram Moolenaar     return newline;
2789f9cc9f20SBram Moolenaar }
2790f9cc9f20SBram Moolenaar 
2791f9cc9f20SBram Moolenaar /*
2792f9cc9f20SBram Moolenaar  * Set the attribute numbers for a highlight group.
2793f9cc9f20SBram Moolenaar  * Called after one of the attributes has changed.
2794f9cc9f20SBram Moolenaar  */
2795f9cc9f20SBram Moolenaar     static void
2796f9cc9f20SBram Moolenaar set_hl_attr(
2797f9cc9f20SBram Moolenaar     int		idx)	    // index in array
2798f9cc9f20SBram Moolenaar {
2799f9cc9f20SBram Moolenaar     attrentry_T	    at_en;
2800f9cc9f20SBram Moolenaar     hl_group_T	    *sgp = HL_TABLE() + idx;
2801f9cc9f20SBram Moolenaar 
2802f9cc9f20SBram Moolenaar     // The "Normal" group doesn't need an attribute number
2803f9cc9f20SBram Moolenaar     if (sgp->sg_name_u != NULL && STRCMP(sgp->sg_name_u, "NORMAL") == 0)
2804f9cc9f20SBram Moolenaar 	return;
2805f9cc9f20SBram Moolenaar 
2806f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
2807f9cc9f20SBram Moolenaar     /*
2808f9cc9f20SBram Moolenaar      * For the GUI mode: If there are other than "normal" highlighting
2809f9cc9f20SBram Moolenaar      * attributes, need to allocate an attr number.
2810f9cc9f20SBram Moolenaar      */
2811f9cc9f20SBram Moolenaar     if (sgp->sg_gui_fg == INVALCOLOR
2812f9cc9f20SBram Moolenaar 	    && sgp->sg_gui_bg == INVALCOLOR
2813f9cc9f20SBram Moolenaar 	    && sgp->sg_gui_sp == INVALCOLOR
2814f9cc9f20SBram Moolenaar 	    && sgp->sg_font == NOFONT
2815f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
2816f9cc9f20SBram Moolenaar 	    && sgp->sg_fontset == NOFONTSET
2817f9cc9f20SBram Moolenaar # endif
2818f9cc9f20SBram Moolenaar 	    )
2819f9cc9f20SBram Moolenaar     {
2820f9cc9f20SBram Moolenaar 	sgp->sg_gui_attr = sgp->sg_gui;
2821f9cc9f20SBram Moolenaar     }
2822f9cc9f20SBram Moolenaar     else
2823f9cc9f20SBram Moolenaar     {
2824f9cc9f20SBram Moolenaar 	at_en.ae_attr = sgp->sg_gui;
2825f9cc9f20SBram Moolenaar 	at_en.ae_u.gui.fg_color = sgp->sg_gui_fg;
2826f9cc9f20SBram Moolenaar 	at_en.ae_u.gui.bg_color = sgp->sg_gui_bg;
2827f9cc9f20SBram Moolenaar 	at_en.ae_u.gui.sp_color = sgp->sg_gui_sp;
2828f9cc9f20SBram Moolenaar 	at_en.ae_u.gui.font = sgp->sg_font;
2829f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
2830f9cc9f20SBram Moolenaar 	at_en.ae_u.gui.fontset = sgp->sg_fontset;
2831f9cc9f20SBram Moolenaar # endif
2832f9cc9f20SBram Moolenaar 	sgp->sg_gui_attr = get_attr_entry(&gui_attr_table, &at_en);
2833f9cc9f20SBram Moolenaar     }
2834f9cc9f20SBram Moolenaar #endif
2835f9cc9f20SBram Moolenaar     /*
2836f9cc9f20SBram Moolenaar      * For the term mode: If there are other than "normal" highlighting
2837f9cc9f20SBram Moolenaar      * attributes, need to allocate an attr number.
2838f9cc9f20SBram Moolenaar      */
2839f9cc9f20SBram Moolenaar     if (sgp->sg_start == NULL && sgp->sg_stop == NULL)
2840f9cc9f20SBram Moolenaar 	sgp->sg_term_attr = sgp->sg_term;
2841f9cc9f20SBram Moolenaar     else
2842f9cc9f20SBram Moolenaar     {
2843f9cc9f20SBram Moolenaar 	at_en.ae_attr = sgp->sg_term;
2844f9cc9f20SBram Moolenaar 	at_en.ae_u.term.start = sgp->sg_start;
2845f9cc9f20SBram Moolenaar 	at_en.ae_u.term.stop = sgp->sg_stop;
2846f9cc9f20SBram Moolenaar 	sgp->sg_term_attr = get_attr_entry(&term_attr_table, &at_en);
2847f9cc9f20SBram Moolenaar     }
2848f9cc9f20SBram Moolenaar 
2849f9cc9f20SBram Moolenaar     /*
2850f9cc9f20SBram Moolenaar      * For the color term mode: If there are other than "normal"
2851f9cc9f20SBram Moolenaar      * highlighting attributes, need to allocate an attr number.
2852f9cc9f20SBram Moolenaar      */
2853f9cc9f20SBram Moolenaar     if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0
2854f9cc9f20SBram Moolenaar # ifdef FEAT_TERMGUICOLORS
2855f9cc9f20SBram Moolenaar 	    && sgp->sg_gui_fg == INVALCOLOR
2856f9cc9f20SBram Moolenaar 	    && sgp->sg_gui_bg == INVALCOLOR
2857f9cc9f20SBram Moolenaar # endif
2858f9cc9f20SBram Moolenaar 	    )
2859f9cc9f20SBram Moolenaar 	sgp->sg_cterm_attr = sgp->sg_cterm;
2860f9cc9f20SBram Moolenaar     else
2861f9cc9f20SBram Moolenaar     {
2862f9cc9f20SBram Moolenaar 	at_en.ae_attr = sgp->sg_cterm;
2863f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg;
2864f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg;
2865f9cc9f20SBram Moolenaar # ifdef FEAT_TERMGUICOLORS
2866f9cc9f20SBram Moolenaar #  ifdef MSWIN
2867f9cc9f20SBram Moolenaar #   ifdef VIMDLL
2868f9cc9f20SBram Moolenaar 	// Only when not using the GUI.
2869f9cc9f20SBram Moolenaar 	if (!gui.in_use && !gui.starting)
2870f9cc9f20SBram Moolenaar #   endif
2871f9cc9f20SBram Moolenaar 	{
2872f9cc9f20SBram Moolenaar 	    int id;
2873f9cc9f20SBram Moolenaar 	    guicolor_T fg, bg;
2874f9cc9f20SBram Moolenaar 
2875f9cc9f20SBram Moolenaar 	    id = syn_name2id((char_u *)"Normal");
2876f9cc9f20SBram Moolenaar 	    if (id > 0)
2877f9cc9f20SBram Moolenaar 	    {
2878f9cc9f20SBram Moolenaar 		syn_id2colors(id, &fg, &bg);
2879f9cc9f20SBram Moolenaar 		if (sgp->sg_gui_fg == INVALCOLOR)
2880f9cc9f20SBram Moolenaar 		    sgp->sg_gui_fg = fg;
2881f9cc9f20SBram Moolenaar 		if (sgp->sg_gui_bg == INVALCOLOR)
2882f9cc9f20SBram Moolenaar 		    sgp->sg_gui_bg = bg;
2883f9cc9f20SBram Moolenaar 	    }
2884f9cc9f20SBram Moolenaar 
2885f9cc9f20SBram Moolenaar 	}
2886f9cc9f20SBram Moolenaar #  endif
2887f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.fg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_fg);
2888f9cc9f20SBram Moolenaar 	at_en.ae_u.cterm.bg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_bg);
2889f9cc9f20SBram Moolenaar 	if (at_en.ae_u.cterm.fg_rgb == INVALCOLOR
2890f9cc9f20SBram Moolenaar 		&& at_en.ae_u.cterm.bg_rgb == INVALCOLOR)
2891f9cc9f20SBram Moolenaar 	{
2892f9cc9f20SBram Moolenaar 	    // If both fg and bg are invalid fall back to the cterm colors.
2893f9cc9f20SBram Moolenaar 	    // Helps when the GUI only uses an attribute, e.g. undercurl.
2894f9cc9f20SBram Moolenaar 	    at_en.ae_u.cterm.fg_rgb = CTERMCOLOR;
2895f9cc9f20SBram Moolenaar 	    at_en.ae_u.cterm.bg_rgb = CTERMCOLOR;
2896f9cc9f20SBram Moolenaar 	}
2897f9cc9f20SBram Moolenaar # endif
2898f9cc9f20SBram Moolenaar 	sgp->sg_cterm_attr = get_attr_entry(&cterm_attr_table, &at_en);
2899f9cc9f20SBram Moolenaar     }
2900f9cc9f20SBram Moolenaar }
2901f9cc9f20SBram Moolenaar 
2902f9cc9f20SBram Moolenaar /*
2903f9cc9f20SBram Moolenaar  * Lookup a highlight group name and return its ID.
2904f9cc9f20SBram Moolenaar  * If it is not found, 0 is returned.
2905f9cc9f20SBram Moolenaar  */
2906f9cc9f20SBram Moolenaar     int
2907f9cc9f20SBram Moolenaar syn_name2id(char_u *name)
2908f9cc9f20SBram Moolenaar {
2909f9cc9f20SBram Moolenaar     int		i;
2910f9cc9f20SBram Moolenaar     char_u	name_u[200];
2911f9cc9f20SBram Moolenaar 
2912f9cc9f20SBram Moolenaar     // Avoid using stricmp() too much, it's slow on some systems
2913f9cc9f20SBram Moolenaar     // Avoid alloc()/free(), these are slow too.  ID names over 200 chars
2914f9cc9f20SBram Moolenaar     // don't deserve to be found!
2915f9cc9f20SBram Moolenaar     vim_strncpy(name_u, name, 199);
2916f9cc9f20SBram Moolenaar     vim_strup(name_u);
2917f9cc9f20SBram Moolenaar     for (i = highlight_ga.ga_len; --i >= 0; )
2918f9cc9f20SBram Moolenaar 	if (HL_TABLE()[i].sg_name_u != NULL
2919f9cc9f20SBram Moolenaar 		&& STRCMP(name_u, HL_TABLE()[i].sg_name_u) == 0)
2920f9cc9f20SBram Moolenaar 	    break;
2921f9cc9f20SBram Moolenaar     return i + 1;
2922f9cc9f20SBram Moolenaar }
2923f9cc9f20SBram Moolenaar 
2924f9cc9f20SBram Moolenaar /*
2925f9cc9f20SBram Moolenaar  * Lookup a highlight group name and return its attributes.
2926f9cc9f20SBram Moolenaar  * Return zero if not found.
2927f9cc9f20SBram Moolenaar  */
2928f9cc9f20SBram Moolenaar     int
2929f9cc9f20SBram Moolenaar syn_name2attr(char_u *name)
2930f9cc9f20SBram Moolenaar {
2931f9cc9f20SBram Moolenaar     int id = syn_name2id(name);
2932f9cc9f20SBram Moolenaar 
2933f9cc9f20SBram Moolenaar     if (id != 0)
2934f9cc9f20SBram Moolenaar 	return syn_id2attr(id);
2935f9cc9f20SBram Moolenaar     return 0;
2936f9cc9f20SBram Moolenaar }
2937f9cc9f20SBram Moolenaar 
2938f9cc9f20SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
2939f9cc9f20SBram Moolenaar /*
2940f9cc9f20SBram Moolenaar  * Return TRUE if highlight group "name" exists.
2941f9cc9f20SBram Moolenaar  */
2942f9cc9f20SBram Moolenaar     int
2943f9cc9f20SBram Moolenaar highlight_exists(char_u *name)
2944f9cc9f20SBram Moolenaar {
2945f9cc9f20SBram Moolenaar     return (syn_name2id(name) > 0);
2946f9cc9f20SBram Moolenaar }
2947f9cc9f20SBram Moolenaar 
2948f9cc9f20SBram Moolenaar # if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
2949f9cc9f20SBram Moolenaar /*
2950f9cc9f20SBram Moolenaar  * Return the name of highlight group "id".
2951f9cc9f20SBram Moolenaar  * When not a valid ID return an empty string.
2952f9cc9f20SBram Moolenaar  */
2953f9cc9f20SBram Moolenaar     char_u *
2954f9cc9f20SBram Moolenaar syn_id2name(int id)
2955f9cc9f20SBram Moolenaar {
2956f9cc9f20SBram Moolenaar     if (id <= 0 || id > highlight_ga.ga_len)
2957f9cc9f20SBram Moolenaar 	return (char_u *)"";
2958f9cc9f20SBram Moolenaar     return HL_TABLE()[id - 1].sg_name;
2959f9cc9f20SBram Moolenaar }
2960f9cc9f20SBram Moolenaar # endif
2961f9cc9f20SBram Moolenaar #endif
2962f9cc9f20SBram Moolenaar 
2963f9cc9f20SBram Moolenaar /*
2964f9cc9f20SBram Moolenaar  * Like syn_name2id(), but take a pointer + length argument.
2965f9cc9f20SBram Moolenaar  */
2966f9cc9f20SBram Moolenaar     int
2967f9cc9f20SBram Moolenaar syn_namen2id(char_u *linep, int len)
2968f9cc9f20SBram Moolenaar {
2969f9cc9f20SBram Moolenaar     char_u  *name;
2970f9cc9f20SBram Moolenaar     int	    id = 0;
2971f9cc9f20SBram Moolenaar 
2972f9cc9f20SBram Moolenaar     name = vim_strnsave(linep, len);
2973f9cc9f20SBram Moolenaar     if (name != NULL)
2974f9cc9f20SBram Moolenaar     {
2975f9cc9f20SBram Moolenaar 	id = syn_name2id(name);
2976f9cc9f20SBram Moolenaar 	vim_free(name);
2977f9cc9f20SBram Moolenaar     }
2978f9cc9f20SBram Moolenaar     return id;
2979f9cc9f20SBram Moolenaar }
2980f9cc9f20SBram Moolenaar 
2981f9cc9f20SBram Moolenaar /*
2982f9cc9f20SBram Moolenaar  * Find highlight group name in the table and return its ID.
2983f9cc9f20SBram Moolenaar  * The argument is a pointer to the name and the length of the name.
2984f9cc9f20SBram Moolenaar  * If it doesn't exist yet, a new entry is created.
2985f9cc9f20SBram Moolenaar  * Return 0 for failure.
2986f9cc9f20SBram Moolenaar  */
2987f9cc9f20SBram Moolenaar     int
2988f9cc9f20SBram Moolenaar syn_check_group(char_u *pp, int len)
2989f9cc9f20SBram Moolenaar {
2990f9cc9f20SBram Moolenaar     int	    id;
2991f9cc9f20SBram Moolenaar     char_u  *name;
2992f9cc9f20SBram Moolenaar 
2993f9cc9f20SBram Moolenaar     name = vim_strnsave(pp, len);
2994f9cc9f20SBram Moolenaar     if (name == NULL)
2995f9cc9f20SBram Moolenaar 	return 0;
2996f9cc9f20SBram Moolenaar 
2997f9cc9f20SBram Moolenaar     id = syn_name2id(name);
2998f9cc9f20SBram Moolenaar     if (id == 0)			// doesn't exist yet
2999f9cc9f20SBram Moolenaar 	id = syn_add_group(name);
3000f9cc9f20SBram Moolenaar     else
3001f9cc9f20SBram Moolenaar 	vim_free(name);
3002f9cc9f20SBram Moolenaar     return id;
3003f9cc9f20SBram Moolenaar }
3004f9cc9f20SBram Moolenaar 
3005f9cc9f20SBram Moolenaar /*
3006f9cc9f20SBram Moolenaar  * Add new highlight group and return its ID.
3007f9cc9f20SBram Moolenaar  * "name" must be an allocated string, it will be consumed.
3008f9cc9f20SBram Moolenaar  * Return 0 for failure.
3009f9cc9f20SBram Moolenaar  */
3010f9cc9f20SBram Moolenaar     static int
3011f9cc9f20SBram Moolenaar syn_add_group(char_u *name)
3012f9cc9f20SBram Moolenaar {
3013f9cc9f20SBram Moolenaar     char_u	*p;
30146f10c70bSBram Moolenaar     char_u	*name_up;
3015f9cc9f20SBram Moolenaar 
3016f9cc9f20SBram Moolenaar     // Check that the name is ASCII letters, digits and underscore.
3017f9cc9f20SBram Moolenaar     for (p = name; *p != NUL; ++p)
3018f9cc9f20SBram Moolenaar     {
3019f9cc9f20SBram Moolenaar 	if (!vim_isprintc(*p))
3020f9cc9f20SBram Moolenaar 	{
3021f9cc9f20SBram Moolenaar 	    emsg(_("E669: Unprintable character in group name"));
3022f9cc9f20SBram Moolenaar 	    vim_free(name);
3023f9cc9f20SBram Moolenaar 	    return 0;
3024f9cc9f20SBram Moolenaar 	}
3025f9cc9f20SBram Moolenaar 	else if (!ASCII_ISALNUM(*p) && *p != '_')
3026f9cc9f20SBram Moolenaar 	{
3027f9cc9f20SBram Moolenaar 	    // This is an error, but since there previously was no check only
3028f9cc9f20SBram Moolenaar 	    // give a warning.
3029f9cc9f20SBram Moolenaar 	    msg_source(HL_ATTR(HLF_W));
3030f9cc9f20SBram Moolenaar 	    msg(_("W18: Invalid character in group name"));
3031f9cc9f20SBram Moolenaar 	    break;
3032f9cc9f20SBram Moolenaar 	}
3033f9cc9f20SBram Moolenaar     }
3034f9cc9f20SBram Moolenaar 
3035f9cc9f20SBram Moolenaar     /*
3036f9cc9f20SBram Moolenaar      * First call for this growarray: init growing array.
3037f9cc9f20SBram Moolenaar      */
3038f9cc9f20SBram Moolenaar     if (highlight_ga.ga_data == NULL)
3039f9cc9f20SBram Moolenaar     {
3040f9cc9f20SBram Moolenaar 	highlight_ga.ga_itemsize = sizeof(hl_group_T);
3041f9cc9f20SBram Moolenaar 	highlight_ga.ga_growsize = 10;
3042f9cc9f20SBram Moolenaar     }
3043f9cc9f20SBram Moolenaar 
3044f9cc9f20SBram Moolenaar     if (highlight_ga.ga_len >= MAX_HL_ID)
3045f9cc9f20SBram Moolenaar     {
3046f9cc9f20SBram Moolenaar 	emsg(_("E849: Too many highlight and syntax groups"));
3047f9cc9f20SBram Moolenaar 	vim_free(name);
3048f9cc9f20SBram Moolenaar 	return 0;
3049f9cc9f20SBram Moolenaar     }
3050f9cc9f20SBram Moolenaar 
3051f9cc9f20SBram Moolenaar     /*
3052f9cc9f20SBram Moolenaar      * Make room for at least one other syntax_highlight entry.
3053f9cc9f20SBram Moolenaar      */
3054f9cc9f20SBram Moolenaar     if (ga_grow(&highlight_ga, 1) == FAIL)
3055f9cc9f20SBram Moolenaar     {
3056f9cc9f20SBram Moolenaar 	vim_free(name);
3057f9cc9f20SBram Moolenaar 	return 0;
3058f9cc9f20SBram Moolenaar     }
3059f9cc9f20SBram Moolenaar 
30606f10c70bSBram Moolenaar     name_up = vim_strsave_up(name);
30616f10c70bSBram Moolenaar     if (name_up == NULL)
30626f10c70bSBram Moolenaar     {
30636f10c70bSBram Moolenaar 	vim_free(name);
30646f10c70bSBram Moolenaar 	return 0;
30656f10c70bSBram Moolenaar     }
30666f10c70bSBram Moolenaar 
3067f9cc9f20SBram Moolenaar     vim_memset(&(HL_TABLE()[highlight_ga.ga_len]), 0, sizeof(hl_group_T));
3068f9cc9f20SBram Moolenaar     HL_TABLE()[highlight_ga.ga_len].sg_name = name;
30696f10c70bSBram Moolenaar     HL_TABLE()[highlight_ga.ga_len].sg_name_u = name_up;
3070f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
3071f9cc9f20SBram Moolenaar     HL_TABLE()[highlight_ga.ga_len].sg_gui_bg = INVALCOLOR;
3072f9cc9f20SBram Moolenaar     HL_TABLE()[highlight_ga.ga_len].sg_gui_fg = INVALCOLOR;
3073f9cc9f20SBram Moolenaar # ifdef FEAT_GUI
3074f9cc9f20SBram Moolenaar     HL_TABLE()[highlight_ga.ga_len].sg_gui_sp = INVALCOLOR;
3075f9cc9f20SBram Moolenaar # endif
3076f9cc9f20SBram Moolenaar #endif
3077f9cc9f20SBram Moolenaar     ++highlight_ga.ga_len;
3078f9cc9f20SBram Moolenaar 
3079f9cc9f20SBram Moolenaar     return highlight_ga.ga_len;		    // ID is index plus one
3080f9cc9f20SBram Moolenaar }
3081f9cc9f20SBram Moolenaar 
3082f9cc9f20SBram Moolenaar /*
3083f9cc9f20SBram Moolenaar  * When, just after calling syn_add_group(), an error is discovered, this
3084f9cc9f20SBram Moolenaar  * function deletes the new name.
3085f9cc9f20SBram Moolenaar  */
3086f9cc9f20SBram Moolenaar     static void
3087f9cc9f20SBram Moolenaar syn_unadd_group(void)
3088f9cc9f20SBram Moolenaar {
3089f9cc9f20SBram Moolenaar     --highlight_ga.ga_len;
3090f9cc9f20SBram Moolenaar     vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name);
3091f9cc9f20SBram Moolenaar     vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
3092f9cc9f20SBram Moolenaar }
3093f9cc9f20SBram Moolenaar 
3094f9cc9f20SBram Moolenaar /*
3095f9cc9f20SBram Moolenaar  * Translate a group ID to highlight attributes.
3096f9cc9f20SBram Moolenaar  */
3097f9cc9f20SBram Moolenaar     int
3098f9cc9f20SBram Moolenaar syn_id2attr(int hl_id)
3099f9cc9f20SBram Moolenaar {
3100f9cc9f20SBram Moolenaar     int		attr;
3101f9cc9f20SBram Moolenaar     hl_group_T	*sgp;
3102f9cc9f20SBram Moolenaar 
3103f9cc9f20SBram Moolenaar     hl_id = syn_get_final_id(hl_id);
3104f9cc9f20SBram Moolenaar     sgp = &HL_TABLE()[hl_id - 1];	    // index is ID minus one
3105f9cc9f20SBram Moolenaar 
3106f9cc9f20SBram Moolenaar #ifdef FEAT_GUI
3107f9cc9f20SBram Moolenaar     /*
3108f9cc9f20SBram Moolenaar      * Only use GUI attr when the GUI is being used.
3109f9cc9f20SBram Moolenaar      */
3110f9cc9f20SBram Moolenaar     if (gui.in_use)
3111f9cc9f20SBram Moolenaar 	attr = sgp->sg_gui_attr;
3112f9cc9f20SBram Moolenaar     else
3113f9cc9f20SBram Moolenaar #endif
3114f9cc9f20SBram Moolenaar 	if (IS_CTERM)
3115f9cc9f20SBram Moolenaar 	    attr = sgp->sg_cterm_attr;
3116f9cc9f20SBram Moolenaar 	else
3117f9cc9f20SBram Moolenaar 	    attr = sgp->sg_term_attr;
3118f9cc9f20SBram Moolenaar 
3119f9cc9f20SBram Moolenaar     return attr;
3120f9cc9f20SBram Moolenaar }
3121f9cc9f20SBram Moolenaar 
3122f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
3123f9cc9f20SBram Moolenaar /*
3124f9cc9f20SBram Moolenaar  * Get the GUI colors and attributes for a group ID.
3125f9cc9f20SBram Moolenaar  * NOTE: the colors will be INVALCOLOR when not set, the color otherwise.
3126f9cc9f20SBram Moolenaar  */
3127f9cc9f20SBram Moolenaar     int
3128f9cc9f20SBram Moolenaar syn_id2colors(int hl_id, guicolor_T *fgp, guicolor_T *bgp)
3129f9cc9f20SBram Moolenaar {
3130f9cc9f20SBram Moolenaar     hl_group_T	*sgp;
3131f9cc9f20SBram Moolenaar 
3132f9cc9f20SBram Moolenaar     hl_id = syn_get_final_id(hl_id);
3133f9cc9f20SBram Moolenaar     sgp = &HL_TABLE()[hl_id - 1];	    // index is ID minus one
3134f9cc9f20SBram Moolenaar 
3135f9cc9f20SBram Moolenaar     *fgp = sgp->sg_gui_fg;
3136f9cc9f20SBram Moolenaar     *bgp = sgp->sg_gui_bg;
3137f9cc9f20SBram Moolenaar     return sgp->sg_gui;
3138f9cc9f20SBram Moolenaar }
3139f9cc9f20SBram Moolenaar #endif
3140f9cc9f20SBram Moolenaar 
3141f9cc9f20SBram Moolenaar #if (defined(MSWIN) \
3142f9cc9f20SBram Moolenaar 	&& (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) \
3143f9cc9f20SBram Moolenaar 	&& defined(FEAT_TERMGUICOLORS)) || defined(PROTO)
3144f9cc9f20SBram Moolenaar     void
3145f9cc9f20SBram Moolenaar syn_id2cterm_bg(int hl_id, int *fgp, int *bgp)
3146f9cc9f20SBram Moolenaar {
3147f9cc9f20SBram Moolenaar     hl_group_T	*sgp;
3148f9cc9f20SBram Moolenaar 
3149f9cc9f20SBram Moolenaar     hl_id = syn_get_final_id(hl_id);
3150f9cc9f20SBram Moolenaar     sgp = &HL_TABLE()[hl_id - 1];	    // index is ID minus one
3151f9cc9f20SBram Moolenaar     *fgp = sgp->sg_cterm_fg - 1;
3152f9cc9f20SBram Moolenaar     *bgp = sgp->sg_cterm_bg - 1;
3153f9cc9f20SBram Moolenaar }
3154f9cc9f20SBram Moolenaar #endif
3155f9cc9f20SBram Moolenaar 
3156f9cc9f20SBram Moolenaar /*
3157f9cc9f20SBram Moolenaar  * Translate a group ID to the final group ID (following links).
3158f9cc9f20SBram Moolenaar  */
3159f9cc9f20SBram Moolenaar     int
3160f9cc9f20SBram Moolenaar syn_get_final_id(int hl_id)
3161f9cc9f20SBram Moolenaar {
3162f9cc9f20SBram Moolenaar     int		count;
3163f9cc9f20SBram Moolenaar     hl_group_T	*sgp;
3164f9cc9f20SBram Moolenaar 
3165f9cc9f20SBram Moolenaar     if (hl_id > highlight_ga.ga_len || hl_id < 1)
3166f9cc9f20SBram Moolenaar 	return 0;			// Can be called from eval!!
3167f9cc9f20SBram Moolenaar 
3168f9cc9f20SBram Moolenaar     /*
3169f9cc9f20SBram Moolenaar      * Follow links until there is no more.
3170f9cc9f20SBram Moolenaar      * Look out for loops!  Break after 100 links.
3171f9cc9f20SBram Moolenaar      */
3172f9cc9f20SBram Moolenaar     for (count = 100; --count >= 0; )
3173f9cc9f20SBram Moolenaar     {
3174f9cc9f20SBram Moolenaar 	sgp = &HL_TABLE()[hl_id - 1];	    // index is ID minus one
3175f9cc9f20SBram Moolenaar 	if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len)
3176f9cc9f20SBram Moolenaar 	    break;
3177f9cc9f20SBram Moolenaar 	hl_id = sgp->sg_link;
3178f9cc9f20SBram Moolenaar     }
3179f9cc9f20SBram Moolenaar 
3180f9cc9f20SBram Moolenaar     return hl_id;
3181f9cc9f20SBram Moolenaar }
3182f9cc9f20SBram Moolenaar 
3183f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
3184f9cc9f20SBram Moolenaar /*
3185f9cc9f20SBram Moolenaar  * Call this function just after the GUI has started.
3186f9cc9f20SBram Moolenaar  * Also called when 'termguicolors' was set, gui.in_use will be FALSE then.
3187f9cc9f20SBram Moolenaar  * It finds the font and color handles for the highlighting groups.
3188f9cc9f20SBram Moolenaar  */
3189f9cc9f20SBram Moolenaar     void
3190f9cc9f20SBram Moolenaar highlight_gui_started(void)
3191f9cc9f20SBram Moolenaar {
3192f9cc9f20SBram Moolenaar     int	    idx;
3193f9cc9f20SBram Moolenaar 
3194f9cc9f20SBram Moolenaar     // First get the colors from the "Normal" and "Menu" group, if set
3195f9cc9f20SBram Moolenaar     if (USE_24BIT)
3196f9cc9f20SBram Moolenaar 	set_normal_colors();
3197f9cc9f20SBram Moolenaar 
3198f9cc9f20SBram Moolenaar     for (idx = 0; idx < highlight_ga.ga_len; ++idx)
3199f9cc9f20SBram Moolenaar 	gui_do_one_color(idx, FALSE, FALSE);
3200f9cc9f20SBram Moolenaar 
3201f9cc9f20SBram Moolenaar     highlight_changed();
3202f9cc9f20SBram Moolenaar }
3203f9cc9f20SBram Moolenaar 
3204f9cc9f20SBram Moolenaar     static void
3205f9cc9f20SBram Moolenaar gui_do_one_color(
3206f9cc9f20SBram Moolenaar     int		idx,
3207f9cc9f20SBram Moolenaar     int		do_menu UNUSED,	   // TRUE: might set the menu font
3208f9cc9f20SBram Moolenaar     int		do_tooltip UNUSED) // TRUE: might set the tooltip font
3209f9cc9f20SBram Moolenaar {
3210f9cc9f20SBram Moolenaar     int		didit = FALSE;
3211f9cc9f20SBram Moolenaar 
3212f9cc9f20SBram Moolenaar # ifdef FEAT_GUI
3213f9cc9f20SBram Moolenaar #  ifdef FEAT_TERMGUICOLORS
3214f9cc9f20SBram Moolenaar     if (gui.in_use)
3215f9cc9f20SBram Moolenaar #  endif
3216f9cc9f20SBram Moolenaar 	if (HL_TABLE()[idx].sg_font_name != NULL)
3217f9cc9f20SBram Moolenaar 	{
3218f9cc9f20SBram Moolenaar 	    hl_do_font(idx, HL_TABLE()[idx].sg_font_name, FALSE, do_menu,
3219f9cc9f20SBram Moolenaar 							    do_tooltip, TRUE);
3220f9cc9f20SBram Moolenaar 	    didit = TRUE;
3221f9cc9f20SBram Moolenaar 	}
3222f9cc9f20SBram Moolenaar # endif
3223f9cc9f20SBram Moolenaar     if (HL_TABLE()[idx].sg_gui_fg_name != NULL)
3224f9cc9f20SBram Moolenaar     {
3225f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_gui_fg =
3226f9cc9f20SBram Moolenaar 			    color_name2handle(HL_TABLE()[idx].sg_gui_fg_name);
3227f9cc9f20SBram Moolenaar 	didit = TRUE;
3228f9cc9f20SBram Moolenaar     }
3229f9cc9f20SBram Moolenaar     if (HL_TABLE()[idx].sg_gui_bg_name != NULL)
3230f9cc9f20SBram Moolenaar     {
3231f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_gui_bg =
3232f9cc9f20SBram Moolenaar 			    color_name2handle(HL_TABLE()[idx].sg_gui_bg_name);
3233f9cc9f20SBram Moolenaar 	didit = TRUE;
3234f9cc9f20SBram Moolenaar     }
3235f9cc9f20SBram Moolenaar # ifdef FEAT_GUI
3236f9cc9f20SBram Moolenaar     if (HL_TABLE()[idx].sg_gui_sp_name != NULL)
3237f9cc9f20SBram Moolenaar     {
3238f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_gui_sp =
3239f9cc9f20SBram Moolenaar 			    color_name2handle(HL_TABLE()[idx].sg_gui_sp_name);
3240f9cc9f20SBram Moolenaar 	didit = TRUE;
3241f9cc9f20SBram Moolenaar     }
3242f9cc9f20SBram Moolenaar # endif
3243f9cc9f20SBram Moolenaar     if (didit)	// need to get a new attr number
3244f9cc9f20SBram Moolenaar 	set_hl_attr(idx);
3245f9cc9f20SBram Moolenaar }
3246f9cc9f20SBram Moolenaar #endif
3247f9cc9f20SBram Moolenaar 
3248f9cc9f20SBram Moolenaar #if defined(USER_HIGHLIGHT) && defined(FEAT_STL_OPT)
3249f9cc9f20SBram Moolenaar /*
3250f9cc9f20SBram Moolenaar  * Apply difference between User[1-9] and HLF_S to HLF_SNC, HLF_ST or HLF_STNC.
3251f9cc9f20SBram Moolenaar  */
3252f9cc9f20SBram Moolenaar     static void
3253f9cc9f20SBram Moolenaar combine_stl_hlt(
3254f9cc9f20SBram Moolenaar 	int id,
3255f9cc9f20SBram Moolenaar 	int id_S,
3256f9cc9f20SBram Moolenaar 	int id_alt,
3257f9cc9f20SBram Moolenaar 	int hlcnt,
3258f9cc9f20SBram Moolenaar 	int i,
3259f9cc9f20SBram Moolenaar 	int hlf,
3260f9cc9f20SBram Moolenaar 	int *table)
3261f9cc9f20SBram Moolenaar {
3262f9cc9f20SBram Moolenaar     hl_group_T *hlt = HL_TABLE();
3263f9cc9f20SBram Moolenaar 
3264f9cc9f20SBram Moolenaar     if (id_alt == 0)
3265f9cc9f20SBram Moolenaar     {
3266f9cc9f20SBram Moolenaar 	vim_memset(&hlt[hlcnt + i], 0, sizeof(hl_group_T));
3267f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_term = highlight_attr[hlf];
3268f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_cterm = highlight_attr[hlf];
3269f9cc9f20SBram Moolenaar #  if defined(FEAT_GUI) || defined(FEAT_EVAL)
3270f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_gui = highlight_attr[hlf];
3271f9cc9f20SBram Moolenaar #  endif
3272f9cc9f20SBram Moolenaar     }
3273f9cc9f20SBram Moolenaar     else
3274f9cc9f20SBram Moolenaar 	mch_memmove(&hlt[hlcnt + i],
3275f9cc9f20SBram Moolenaar 		    &hlt[id_alt - 1],
3276f9cc9f20SBram Moolenaar 		    sizeof(hl_group_T));
3277f9cc9f20SBram Moolenaar     hlt[hlcnt + i].sg_link = 0;
3278f9cc9f20SBram Moolenaar 
3279f9cc9f20SBram Moolenaar     hlt[hlcnt + i].sg_term ^=
3280f9cc9f20SBram Moolenaar 	hlt[id - 1].sg_term ^ hlt[id_S - 1].sg_term;
3281f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_start != hlt[id_S - 1].sg_start)
3282f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_start = hlt[id - 1].sg_start;
3283f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_stop != hlt[id_S - 1].sg_stop)
3284f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_stop = hlt[id - 1].sg_stop;
3285f9cc9f20SBram Moolenaar     hlt[hlcnt + i].sg_cterm ^=
3286f9cc9f20SBram Moolenaar 	hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm;
3287f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg)
3288f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg;
3289f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg)
3290f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg;
3291f9cc9f20SBram Moolenaar #  if defined(FEAT_GUI) || defined(FEAT_EVAL)
3292f9cc9f20SBram Moolenaar     hlt[hlcnt + i].sg_gui ^=
3293f9cc9f20SBram Moolenaar 	hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui;
3294f9cc9f20SBram Moolenaar #  endif
3295f9cc9f20SBram Moolenaar #  ifdef FEAT_GUI
3296f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_gui_fg != hlt[id_S - 1].sg_gui_fg)
3297f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_gui_fg = hlt[id - 1].sg_gui_fg;
3298f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_gui_bg != hlt[id_S - 1].sg_gui_bg)
3299f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_gui_bg = hlt[id - 1].sg_gui_bg;
3300f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_gui_sp != hlt[id_S - 1].sg_gui_sp)
3301f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_gui_sp = hlt[id - 1].sg_gui_sp;
3302f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_font != hlt[id_S - 1].sg_font)
3303f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_font = hlt[id - 1].sg_font;
3304f9cc9f20SBram Moolenaar #   ifdef FEAT_XFONTSET
3305f9cc9f20SBram Moolenaar     if (hlt[id - 1].sg_fontset != hlt[id_S - 1].sg_fontset)
3306f9cc9f20SBram Moolenaar 	hlt[hlcnt + i].sg_fontset = hlt[id - 1].sg_fontset;
3307f9cc9f20SBram Moolenaar #   endif
3308f9cc9f20SBram Moolenaar #  endif
3309f9cc9f20SBram Moolenaar     highlight_ga.ga_len = hlcnt + i + 1;
3310f9cc9f20SBram Moolenaar     set_hl_attr(hlcnt + i);	// At long last we can apply
3311f9cc9f20SBram Moolenaar     table[i] = syn_id2attr(hlcnt + i + 1);
3312f9cc9f20SBram Moolenaar }
3313f9cc9f20SBram Moolenaar #endif
3314f9cc9f20SBram Moolenaar 
3315f9cc9f20SBram Moolenaar /*
3316f9cc9f20SBram Moolenaar  * Translate the 'highlight' option into attributes in highlight_attr[] and
3317f9cc9f20SBram Moolenaar  * set up the user highlights User1..9.  If FEAT_STL_OPT is in use, a set of
3318f9cc9f20SBram Moolenaar  * corresponding highlights to use on top of HLF_SNC is computed.
3319f9cc9f20SBram Moolenaar  * Called only when the 'highlight' option has been changed and upon first
3320f9cc9f20SBram Moolenaar  * screen redraw after any :highlight command.
3321f9cc9f20SBram Moolenaar  * Return FAIL when an invalid flag is found in 'highlight'.  OK otherwise.
3322f9cc9f20SBram Moolenaar  */
3323f9cc9f20SBram Moolenaar     int
3324f9cc9f20SBram Moolenaar highlight_changed(void)
3325f9cc9f20SBram Moolenaar {
3326f9cc9f20SBram Moolenaar     int		hlf;
3327f9cc9f20SBram Moolenaar     int		i;
3328f9cc9f20SBram Moolenaar     char_u	*p;
3329f9cc9f20SBram Moolenaar     int		attr;
3330f9cc9f20SBram Moolenaar     char_u	*end;
3331f9cc9f20SBram Moolenaar     int		id;
3332f9cc9f20SBram Moolenaar #ifdef USER_HIGHLIGHT
3333f9cc9f20SBram Moolenaar     char_u      userhl[30];  // use 30 to avoid compiler warning
3334f9cc9f20SBram Moolenaar # ifdef FEAT_STL_OPT
3335f9cc9f20SBram Moolenaar     int		id_S = -1;
3336f9cc9f20SBram Moolenaar     int		id_SNC = 0;
3337f9cc9f20SBram Moolenaar #  ifdef FEAT_TERMINAL
3338f9cc9f20SBram Moolenaar     int		id_ST = 0;
3339f9cc9f20SBram Moolenaar     int		id_STNC = 0;
3340f9cc9f20SBram Moolenaar #  endif
3341f9cc9f20SBram Moolenaar     int		hlcnt;
3342f9cc9f20SBram Moolenaar # endif
3343f9cc9f20SBram Moolenaar #endif
3344f9cc9f20SBram Moolenaar     static int	hl_flags[HLF_COUNT] = HL_FLAGS;
3345f9cc9f20SBram Moolenaar 
3346f9cc9f20SBram Moolenaar     need_highlight_changed = FALSE;
3347f9cc9f20SBram Moolenaar 
3348f9cc9f20SBram Moolenaar     /*
3349f9cc9f20SBram Moolenaar      * Clear all attributes.
3350f9cc9f20SBram Moolenaar      */
3351f9cc9f20SBram Moolenaar     for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
3352f9cc9f20SBram Moolenaar 	highlight_attr[hlf] = 0;
3353f9cc9f20SBram Moolenaar 
3354f9cc9f20SBram Moolenaar     /*
3355f9cc9f20SBram Moolenaar      * First set all attributes to their default value.
3356f9cc9f20SBram Moolenaar      * Then use the attributes from the 'highlight' option.
3357f9cc9f20SBram Moolenaar      */
3358f9cc9f20SBram Moolenaar     for (i = 0; i < 2; ++i)
3359f9cc9f20SBram Moolenaar     {
3360f9cc9f20SBram Moolenaar 	if (i)
3361f9cc9f20SBram Moolenaar 	    p = p_hl;
3362f9cc9f20SBram Moolenaar 	else
3363f9cc9f20SBram Moolenaar 	    p = get_highlight_default();
3364f9cc9f20SBram Moolenaar 	if (p == NULL)	    // just in case
3365f9cc9f20SBram Moolenaar 	    continue;
3366f9cc9f20SBram Moolenaar 
3367f9cc9f20SBram Moolenaar 	while (*p)
3368f9cc9f20SBram Moolenaar 	{
3369f9cc9f20SBram Moolenaar 	    for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
3370f9cc9f20SBram Moolenaar 		if (hl_flags[hlf] == *p)
3371f9cc9f20SBram Moolenaar 		    break;
3372f9cc9f20SBram Moolenaar 	    ++p;
3373f9cc9f20SBram Moolenaar 	    if (hlf == (int)HLF_COUNT || *p == NUL)
3374f9cc9f20SBram Moolenaar 		return FAIL;
3375f9cc9f20SBram Moolenaar 
3376f9cc9f20SBram Moolenaar 	    /*
3377f9cc9f20SBram Moolenaar 	     * Allow several hl_flags to be combined, like "bu" for
3378f9cc9f20SBram Moolenaar 	     * bold-underlined.
3379f9cc9f20SBram Moolenaar 	     */
3380f9cc9f20SBram Moolenaar 	    attr = 0;
3381f9cc9f20SBram Moolenaar 	    for ( ; *p && *p != ','; ++p)	    // parse upto comma
3382f9cc9f20SBram Moolenaar 	    {
3383f9cc9f20SBram Moolenaar 		if (VIM_ISWHITE(*p))		    // ignore white space
3384f9cc9f20SBram Moolenaar 		    continue;
3385f9cc9f20SBram Moolenaar 
3386f9cc9f20SBram Moolenaar 		if (attr > HL_ALL)  // Combination with ':' is not allowed.
3387f9cc9f20SBram Moolenaar 		    return FAIL;
3388f9cc9f20SBram Moolenaar 
3389f9cc9f20SBram Moolenaar 		switch (*p)
3390f9cc9f20SBram Moolenaar 		{
3391f9cc9f20SBram Moolenaar 		    case 'b':	attr |= HL_BOLD;
3392f9cc9f20SBram Moolenaar 				break;
3393f9cc9f20SBram Moolenaar 		    case 'i':	attr |= HL_ITALIC;
3394f9cc9f20SBram Moolenaar 				break;
3395f9cc9f20SBram Moolenaar 		    case '-':
3396f9cc9f20SBram Moolenaar 		    case 'n':			    // no highlighting
3397f9cc9f20SBram Moolenaar 				break;
3398f9cc9f20SBram Moolenaar 		    case 'r':	attr |= HL_INVERSE;
3399f9cc9f20SBram Moolenaar 				break;
3400f9cc9f20SBram Moolenaar 		    case 's':	attr |= HL_STANDOUT;
3401f9cc9f20SBram Moolenaar 				break;
3402f9cc9f20SBram Moolenaar 		    case 'u':	attr |= HL_UNDERLINE;
3403f9cc9f20SBram Moolenaar 				break;
3404f9cc9f20SBram Moolenaar 		    case 'c':	attr |= HL_UNDERCURL;
3405f9cc9f20SBram Moolenaar 				break;
3406f9cc9f20SBram Moolenaar 		    case 't':	attr |= HL_STRIKETHROUGH;
3407f9cc9f20SBram Moolenaar 				break;
3408f9cc9f20SBram Moolenaar 		    case ':':	++p;		    // highlight group name
3409f9cc9f20SBram Moolenaar 				if (attr || *p == NUL)	 // no combinations
3410f9cc9f20SBram Moolenaar 				    return FAIL;
3411f9cc9f20SBram Moolenaar 				end = vim_strchr(p, ',');
3412f9cc9f20SBram Moolenaar 				if (end == NULL)
3413f9cc9f20SBram Moolenaar 				    end = p + STRLEN(p);
3414f9cc9f20SBram Moolenaar 				id = syn_check_group(p, (int)(end - p));
3415f9cc9f20SBram Moolenaar 				if (id == 0)
3416f9cc9f20SBram Moolenaar 				    return FAIL;
3417f9cc9f20SBram Moolenaar 				attr = syn_id2attr(id);
3418f9cc9f20SBram Moolenaar 				p = end - 1;
3419f9cc9f20SBram Moolenaar #if defined(FEAT_STL_OPT) && defined(USER_HIGHLIGHT)
3420f9cc9f20SBram Moolenaar 				if (hlf == (int)HLF_SNC)
3421f9cc9f20SBram Moolenaar 				    id_SNC = syn_get_final_id(id);
3422f9cc9f20SBram Moolenaar # ifdef FEAT_TERMINAL
3423f9cc9f20SBram Moolenaar 				else if (hlf == (int)HLF_ST)
3424f9cc9f20SBram Moolenaar 				    id_ST = syn_get_final_id(id);
3425f9cc9f20SBram Moolenaar 				else if (hlf == (int)HLF_STNC)
3426f9cc9f20SBram Moolenaar 				    id_STNC = syn_get_final_id(id);
3427f9cc9f20SBram Moolenaar # endif
3428f9cc9f20SBram Moolenaar 				else if (hlf == (int)HLF_S)
3429f9cc9f20SBram Moolenaar 				    id_S = syn_get_final_id(id);
3430f9cc9f20SBram Moolenaar #endif
3431f9cc9f20SBram Moolenaar 				break;
3432f9cc9f20SBram Moolenaar 		    default:	return FAIL;
3433f9cc9f20SBram Moolenaar 		}
3434f9cc9f20SBram Moolenaar 	    }
3435f9cc9f20SBram Moolenaar 	    highlight_attr[hlf] = attr;
3436f9cc9f20SBram Moolenaar 
3437f9cc9f20SBram Moolenaar 	    p = skip_to_option_part(p);	    // skip comma and spaces
3438f9cc9f20SBram Moolenaar 	}
3439f9cc9f20SBram Moolenaar     }
3440f9cc9f20SBram Moolenaar 
3441f9cc9f20SBram Moolenaar #ifdef USER_HIGHLIGHT
3442f9cc9f20SBram Moolenaar     /*
3443f9cc9f20SBram Moolenaar      * Setup the user highlights
3444f9cc9f20SBram Moolenaar      *
3445f9cc9f20SBram Moolenaar      * Temporarily utilize 28 more hl entries:
3446f9cc9f20SBram Moolenaar      * 9 for User1-User9 combined with StatusLineNC
3447f9cc9f20SBram Moolenaar      * 9 for User1-User9 combined with StatusLineTerm
3448f9cc9f20SBram Moolenaar      * 9 for User1-User9 combined with StatusLineTermNC
3449f9cc9f20SBram Moolenaar      * 1 for StatusLine default
3450f9cc9f20SBram Moolenaar      * Have to be in there simultaneously in case of table overflows in
3451f9cc9f20SBram Moolenaar      * get_attr_entry()
3452f9cc9f20SBram Moolenaar      */
3453f9cc9f20SBram Moolenaar # ifdef FEAT_STL_OPT
3454f9cc9f20SBram Moolenaar     if (ga_grow(&highlight_ga, 28) == FAIL)
3455f9cc9f20SBram Moolenaar 	return FAIL;
3456f9cc9f20SBram Moolenaar     hlcnt = highlight_ga.ga_len;
3457f9cc9f20SBram Moolenaar     if (id_S == -1)
3458f9cc9f20SBram Moolenaar     {
3459f9cc9f20SBram Moolenaar 	// Make sure id_S is always valid to simplify code below. Use the last
3460f9cc9f20SBram Moolenaar 	// entry.
3461f9cc9f20SBram Moolenaar 	vim_memset(&HL_TABLE()[hlcnt + 27], 0, sizeof(hl_group_T));
3462f9cc9f20SBram Moolenaar 	HL_TABLE()[hlcnt + 18].sg_term = highlight_attr[HLF_S];
3463f9cc9f20SBram Moolenaar 	id_S = hlcnt + 19;
3464f9cc9f20SBram Moolenaar     }
3465f9cc9f20SBram Moolenaar # endif
3466f9cc9f20SBram Moolenaar     for (i = 0; i < 9; i++)
3467f9cc9f20SBram Moolenaar     {
3468f9cc9f20SBram Moolenaar 	sprintf((char *)userhl, "User%d", i + 1);
3469f9cc9f20SBram Moolenaar 	id = syn_name2id(userhl);
3470f9cc9f20SBram Moolenaar 	if (id == 0)
3471f9cc9f20SBram Moolenaar 	{
3472f9cc9f20SBram Moolenaar 	    highlight_user[i] = 0;
3473f9cc9f20SBram Moolenaar # ifdef FEAT_STL_OPT
3474f9cc9f20SBram Moolenaar 	    highlight_stlnc[i] = 0;
3475f9cc9f20SBram Moolenaar #  ifdef FEAT_TERMINAL
3476f9cc9f20SBram Moolenaar 	    highlight_stlterm[i] = 0;
3477f9cc9f20SBram Moolenaar 	    highlight_stltermnc[i] = 0;
3478f9cc9f20SBram Moolenaar #  endif
3479f9cc9f20SBram Moolenaar # endif
3480f9cc9f20SBram Moolenaar 	}
3481f9cc9f20SBram Moolenaar 	else
3482f9cc9f20SBram Moolenaar 	{
3483f9cc9f20SBram Moolenaar 	    highlight_user[i] = syn_id2attr(id);
3484f9cc9f20SBram Moolenaar # ifdef FEAT_STL_OPT
3485f9cc9f20SBram Moolenaar 	    combine_stl_hlt(id, id_S, id_SNC, hlcnt, i,
3486f9cc9f20SBram Moolenaar 						     HLF_SNC, highlight_stlnc);
3487f9cc9f20SBram Moolenaar #  ifdef FEAT_TERMINAL
3488f9cc9f20SBram Moolenaar 	    combine_stl_hlt(id, id_S, id_ST, hlcnt + 9, i,
3489f9cc9f20SBram Moolenaar 						    HLF_ST, highlight_stlterm);
3490f9cc9f20SBram Moolenaar 	    combine_stl_hlt(id, id_S, id_STNC, hlcnt + 18, i,
3491f9cc9f20SBram Moolenaar 						HLF_STNC, highlight_stltermnc);
3492f9cc9f20SBram Moolenaar #  endif
3493f9cc9f20SBram Moolenaar # endif
3494f9cc9f20SBram Moolenaar 	}
3495f9cc9f20SBram Moolenaar     }
3496f9cc9f20SBram Moolenaar # ifdef FEAT_STL_OPT
3497f9cc9f20SBram Moolenaar     highlight_ga.ga_len = hlcnt;
3498f9cc9f20SBram Moolenaar # endif
3499f9cc9f20SBram Moolenaar 
3500f9cc9f20SBram Moolenaar #endif // USER_HIGHLIGHT
3501f9cc9f20SBram Moolenaar 
3502f9cc9f20SBram Moolenaar     return OK;
3503f9cc9f20SBram Moolenaar }
3504f9cc9f20SBram Moolenaar 
3505f9cc9f20SBram Moolenaar static void highlight_list(void);
3506f9cc9f20SBram Moolenaar static void highlight_list_two(int cnt, int attr);
3507f9cc9f20SBram Moolenaar 
3508f9cc9f20SBram Moolenaar /*
3509f9cc9f20SBram Moolenaar  * Handle command line completion for :highlight command.
3510f9cc9f20SBram Moolenaar  */
3511f9cc9f20SBram Moolenaar     void
3512f9cc9f20SBram Moolenaar set_context_in_highlight_cmd(expand_T *xp, char_u *arg)
3513f9cc9f20SBram Moolenaar {
3514f9cc9f20SBram Moolenaar     char_u	*p;
3515f9cc9f20SBram Moolenaar 
3516f9cc9f20SBram Moolenaar     // Default: expand group names
3517f9cc9f20SBram Moolenaar     xp->xp_context = EXPAND_HIGHLIGHT;
3518f9cc9f20SBram Moolenaar     xp->xp_pattern = arg;
3519f9cc9f20SBram Moolenaar     include_link = 2;
3520f9cc9f20SBram Moolenaar     include_default = 1;
3521f9cc9f20SBram Moolenaar 
3522f9cc9f20SBram Moolenaar     // (part of) subcommand already typed
3523f9cc9f20SBram Moolenaar     if (*arg != NUL)
3524f9cc9f20SBram Moolenaar     {
3525f9cc9f20SBram Moolenaar 	p = skiptowhite(arg);
3526f9cc9f20SBram Moolenaar 	if (*p != NUL)			// past "default" or group name
3527f9cc9f20SBram Moolenaar 	{
3528f9cc9f20SBram Moolenaar 	    include_default = 0;
3529f9cc9f20SBram Moolenaar 	    if (STRNCMP("default", arg, p - arg) == 0)
3530f9cc9f20SBram Moolenaar 	    {
3531f9cc9f20SBram Moolenaar 		arg = skipwhite(p);
3532f9cc9f20SBram Moolenaar 		xp->xp_pattern = arg;
3533f9cc9f20SBram Moolenaar 		p = skiptowhite(arg);
3534f9cc9f20SBram Moolenaar 	    }
3535f9cc9f20SBram Moolenaar 	    if (*p != NUL)			// past group name
3536f9cc9f20SBram Moolenaar 	    {
3537f9cc9f20SBram Moolenaar 		include_link = 0;
3538f9cc9f20SBram Moolenaar 		if (arg[1] == 'i' && arg[0] == 'N')
3539f9cc9f20SBram Moolenaar 		    highlight_list();
3540f9cc9f20SBram Moolenaar 		if (STRNCMP("link", arg, p - arg) == 0
3541f9cc9f20SBram Moolenaar 			|| STRNCMP("clear", arg, p - arg) == 0)
3542f9cc9f20SBram Moolenaar 		{
3543f9cc9f20SBram Moolenaar 		    xp->xp_pattern = skipwhite(p);
3544f9cc9f20SBram Moolenaar 		    p = skiptowhite(xp->xp_pattern);
3545f9cc9f20SBram Moolenaar 		    if (*p != NUL)		// past first group name
3546f9cc9f20SBram Moolenaar 		    {
3547f9cc9f20SBram Moolenaar 			xp->xp_pattern = skipwhite(p);
3548f9cc9f20SBram Moolenaar 			p = skiptowhite(xp->xp_pattern);
3549f9cc9f20SBram Moolenaar 		    }
3550f9cc9f20SBram Moolenaar 		}
3551f9cc9f20SBram Moolenaar 		if (*p != NUL)			// past group name(s)
3552f9cc9f20SBram Moolenaar 		    xp->xp_context = EXPAND_NOTHING;
3553f9cc9f20SBram Moolenaar 	    }
3554f9cc9f20SBram Moolenaar 	}
3555f9cc9f20SBram Moolenaar     }
3556f9cc9f20SBram Moolenaar }
3557f9cc9f20SBram Moolenaar 
3558f9cc9f20SBram Moolenaar /*
3559f9cc9f20SBram Moolenaar  * List highlighting matches in a nice way.
3560f9cc9f20SBram Moolenaar  */
3561f9cc9f20SBram Moolenaar     static void
3562f9cc9f20SBram Moolenaar highlight_list(void)
3563f9cc9f20SBram Moolenaar {
3564f9cc9f20SBram Moolenaar     int		i;
3565f9cc9f20SBram Moolenaar 
3566f9cc9f20SBram Moolenaar     for (i = 10; --i >= 0; )
3567f9cc9f20SBram Moolenaar 	highlight_list_two(i, HL_ATTR(HLF_D));
3568f9cc9f20SBram Moolenaar     for (i = 40; --i >= 0; )
3569f9cc9f20SBram Moolenaar 	highlight_list_two(99, 0);
3570f9cc9f20SBram Moolenaar }
3571f9cc9f20SBram Moolenaar 
3572f9cc9f20SBram Moolenaar     static void
3573f9cc9f20SBram Moolenaar highlight_list_two(int cnt, int attr)
3574f9cc9f20SBram Moolenaar {
3575f9cc9f20SBram Moolenaar     msg_puts_attr(&("N \bI \b!  \b"[cnt / 11]), attr);
3576f9cc9f20SBram Moolenaar     msg_clr_eos();
3577f9cc9f20SBram Moolenaar     out_flush();
3578f9cc9f20SBram Moolenaar     ui_delay(cnt == 99 ? 40L : (long)cnt * 50L, FALSE);
3579f9cc9f20SBram Moolenaar }
3580f9cc9f20SBram Moolenaar 
3581f9cc9f20SBram Moolenaar /*
3582f9cc9f20SBram Moolenaar  * Function given to ExpandGeneric() to obtain the list of group names.
3583f9cc9f20SBram Moolenaar  */
3584f9cc9f20SBram Moolenaar     char_u *
3585f9cc9f20SBram Moolenaar get_highlight_name(expand_T *xp UNUSED, int idx)
3586f9cc9f20SBram Moolenaar {
3587f9cc9f20SBram Moolenaar     return get_highlight_name_ext(xp, idx, TRUE);
3588f9cc9f20SBram Moolenaar }
3589f9cc9f20SBram Moolenaar 
3590f9cc9f20SBram Moolenaar /*
3591f9cc9f20SBram Moolenaar  * Obtain a highlight group name.
3592f9cc9f20SBram Moolenaar  * When "skip_cleared" is TRUE don't return a cleared entry.
3593f9cc9f20SBram Moolenaar  */
3594f9cc9f20SBram Moolenaar     char_u *
3595f9cc9f20SBram Moolenaar get_highlight_name_ext(expand_T *xp UNUSED, int idx, int skip_cleared)
3596f9cc9f20SBram Moolenaar {
3597f9cc9f20SBram Moolenaar     if (idx < 0)
3598f9cc9f20SBram Moolenaar 	return NULL;
3599f9cc9f20SBram Moolenaar 
3600f9cc9f20SBram Moolenaar     // Items are never removed from the table, skip the ones that were
3601f9cc9f20SBram Moolenaar     // cleared.
3602f9cc9f20SBram Moolenaar     if (skip_cleared && idx < highlight_ga.ga_len && HL_TABLE()[idx].sg_cleared)
3603f9cc9f20SBram Moolenaar 	return (char_u *)"";
3604f9cc9f20SBram Moolenaar 
3605f9cc9f20SBram Moolenaar     if (idx == highlight_ga.ga_len && include_none != 0)
3606f9cc9f20SBram Moolenaar 	return (char_u *)"none";
3607f9cc9f20SBram Moolenaar     if (idx == highlight_ga.ga_len + include_none && include_default != 0)
3608f9cc9f20SBram Moolenaar 	return (char_u *)"default";
3609f9cc9f20SBram Moolenaar     if (idx == highlight_ga.ga_len + include_none + include_default
3610f9cc9f20SBram Moolenaar 							 && include_link != 0)
3611f9cc9f20SBram Moolenaar 	return (char_u *)"link";
3612f9cc9f20SBram Moolenaar     if (idx == highlight_ga.ga_len + include_none + include_default + 1
3613f9cc9f20SBram Moolenaar 							 && include_link != 0)
3614f9cc9f20SBram Moolenaar 	return (char_u *)"clear";
3615f9cc9f20SBram Moolenaar     if (idx >= highlight_ga.ga_len)
3616f9cc9f20SBram Moolenaar 	return NULL;
3617f9cc9f20SBram Moolenaar     return HL_TABLE()[idx].sg_name;
3618f9cc9f20SBram Moolenaar }
3619f9cc9f20SBram Moolenaar 
3620f9cc9f20SBram Moolenaar #if defined(FEAT_GUI) || defined(PROTO)
3621f9cc9f20SBram Moolenaar /*
3622f9cc9f20SBram Moolenaar  * Free all the highlight group fonts.
3623f9cc9f20SBram Moolenaar  * Used when quitting for systems which need it.
3624f9cc9f20SBram Moolenaar  */
3625f9cc9f20SBram Moolenaar     void
3626f9cc9f20SBram Moolenaar free_highlight_fonts(void)
3627f9cc9f20SBram Moolenaar {
3628f9cc9f20SBram Moolenaar     int	    idx;
3629f9cc9f20SBram Moolenaar 
3630f9cc9f20SBram Moolenaar     for (idx = 0; idx < highlight_ga.ga_len; ++idx)
3631f9cc9f20SBram Moolenaar     {
3632f9cc9f20SBram Moolenaar 	gui_mch_free_font(HL_TABLE()[idx].sg_font);
3633f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_font = NOFONT;
3634f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
3635f9cc9f20SBram Moolenaar 	gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset);
3636f9cc9f20SBram Moolenaar 	HL_TABLE()[idx].sg_fontset = NOFONTSET;
3637f9cc9f20SBram Moolenaar # endif
3638f9cc9f20SBram Moolenaar     }
3639f9cc9f20SBram Moolenaar 
3640f9cc9f20SBram Moolenaar     gui_mch_free_font(gui.norm_font);
3641f9cc9f20SBram Moolenaar # ifdef FEAT_XFONTSET
3642f9cc9f20SBram Moolenaar     gui_mch_free_fontset(gui.fontset);
3643f9cc9f20SBram Moolenaar # endif
3644f9cc9f20SBram Moolenaar # ifndef FEAT_GUI_GTK
3645f9cc9f20SBram Moolenaar     gui_mch_free_font(gui.bold_font);
3646f9cc9f20SBram Moolenaar     gui_mch_free_font(gui.ital_font);
3647f9cc9f20SBram Moolenaar     gui_mch_free_font(gui.boldital_font);
3648f9cc9f20SBram Moolenaar # endif
3649f9cc9f20SBram Moolenaar }
3650f9cc9f20SBram Moolenaar #endif
365129b7d7a9SBram Moolenaar 
365229b7d7a9SBram Moolenaar 
365329b7d7a9SBram Moolenaar #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
3654bbca7732SBram Moolenaar 
3655bbca7732SBram Moolenaar # define SEARCH_HL_PRIORITY 0
3656bbca7732SBram Moolenaar 
365729b7d7a9SBram Moolenaar /*
365829b7d7a9SBram Moolenaar  * Add match to the match list of window 'wp'.  The pattern 'pat' will be
365929b7d7a9SBram Moolenaar  * highlighted with the group 'grp' with priority 'prio'.
366029b7d7a9SBram Moolenaar  * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
366129b7d7a9SBram Moolenaar  * If no particular ID is desired, -1 must be specified for 'id'.
366229b7d7a9SBram Moolenaar  * Return ID of added match, -1 on failure.
366329b7d7a9SBram Moolenaar  */
36647dfb016dSBram Moolenaar     static int
366529b7d7a9SBram Moolenaar match_add(
366629b7d7a9SBram Moolenaar     win_T	*wp,
366729b7d7a9SBram Moolenaar     char_u	*grp,
366829b7d7a9SBram Moolenaar     char_u	*pat,
366929b7d7a9SBram Moolenaar     int		prio,
367029b7d7a9SBram Moolenaar     int		id,
367129b7d7a9SBram Moolenaar     list_T	*pos_list,
36721f164b19SBram Moolenaar     char_u      *conceal_char UNUSED) // pointer to conceal replacement char
367329b7d7a9SBram Moolenaar {
367429b7d7a9SBram Moolenaar     matchitem_T	*cur;
367529b7d7a9SBram Moolenaar     matchitem_T	*prev;
367629b7d7a9SBram Moolenaar     matchitem_T	*m;
367729b7d7a9SBram Moolenaar     int		hlg_id;
367829b7d7a9SBram Moolenaar     regprog_T	*regprog = NULL;
367929b7d7a9SBram Moolenaar     int		rtype = SOME_VALID;
368029b7d7a9SBram Moolenaar 
368129b7d7a9SBram Moolenaar     if (*grp == NUL || (pat != NULL && *pat == NUL))
368229b7d7a9SBram Moolenaar 	return -1;
368329b7d7a9SBram Moolenaar     if (id < -1 || id == 0)
368429b7d7a9SBram Moolenaar     {
3685*32aa1020SBram Moolenaar 	semsg(_("E799: Invalid ID: %d (must be greater than or equal to 1)"),
3686*32aa1020SBram Moolenaar 									   id);
368729b7d7a9SBram Moolenaar 	return -1;
368829b7d7a9SBram Moolenaar     }
368929b7d7a9SBram Moolenaar     if (id != -1)
369029b7d7a9SBram Moolenaar     {
369129b7d7a9SBram Moolenaar 	cur = wp->w_match_head;
369229b7d7a9SBram Moolenaar 	while (cur != NULL)
369329b7d7a9SBram Moolenaar 	{
369429b7d7a9SBram Moolenaar 	    if (cur->id == id)
369529b7d7a9SBram Moolenaar 	    {
369629b7d7a9SBram Moolenaar 		semsg(_("E801: ID already taken: %d"), id);
369729b7d7a9SBram Moolenaar 		return -1;
369829b7d7a9SBram Moolenaar 	    }
369929b7d7a9SBram Moolenaar 	    cur = cur->next;
370029b7d7a9SBram Moolenaar 	}
370129b7d7a9SBram Moolenaar     }
370229b7d7a9SBram Moolenaar     if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0)
370329b7d7a9SBram Moolenaar     {
370429b7d7a9SBram Moolenaar 	semsg(_(e_nogroup), grp);
370529b7d7a9SBram Moolenaar 	return -1;
370629b7d7a9SBram Moolenaar     }
370729b7d7a9SBram Moolenaar     if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
370829b7d7a9SBram Moolenaar     {
370929b7d7a9SBram Moolenaar 	semsg(_(e_invarg2), pat);
371029b7d7a9SBram Moolenaar 	return -1;
371129b7d7a9SBram Moolenaar     }
371229b7d7a9SBram Moolenaar 
37131f164b19SBram Moolenaar     // Find available match ID.
371429b7d7a9SBram Moolenaar     while (id == -1)
371529b7d7a9SBram Moolenaar     {
371629b7d7a9SBram Moolenaar 	cur = wp->w_match_head;
371729b7d7a9SBram Moolenaar 	while (cur != NULL && cur->id != wp->w_next_match_id)
371829b7d7a9SBram Moolenaar 	    cur = cur->next;
371929b7d7a9SBram Moolenaar 	if (cur == NULL)
372029b7d7a9SBram Moolenaar 	    id = wp->w_next_match_id;
372129b7d7a9SBram Moolenaar 	wp->w_next_match_id++;
372229b7d7a9SBram Moolenaar     }
372329b7d7a9SBram Moolenaar 
37241f164b19SBram Moolenaar     // Build new match.
372529b7d7a9SBram Moolenaar     m = ALLOC_CLEAR_ONE(matchitem_T);
372629b7d7a9SBram Moolenaar     m->id = id;
372729b7d7a9SBram Moolenaar     m->priority = prio;
372829b7d7a9SBram Moolenaar     m->pattern = pat == NULL ? NULL : vim_strsave(pat);
372929b7d7a9SBram Moolenaar     m->hlg_id = hlg_id;
373029b7d7a9SBram Moolenaar     m->match.regprog = regprog;
373129b7d7a9SBram Moolenaar     m->match.rmm_ic = FALSE;
373229b7d7a9SBram Moolenaar     m->match.rmm_maxcol = 0;
373329b7d7a9SBram Moolenaar # if defined(FEAT_CONCEAL)
373429b7d7a9SBram Moolenaar     m->conceal_char = 0;
373529b7d7a9SBram Moolenaar     if (conceal_char != NULL)
373629b7d7a9SBram Moolenaar 	m->conceal_char = (*mb_ptr2char)(conceal_char);
373729b7d7a9SBram Moolenaar # endif
373829b7d7a9SBram Moolenaar 
37391f164b19SBram Moolenaar     // Set up position matches
374029b7d7a9SBram Moolenaar     if (pos_list != NULL)
374129b7d7a9SBram Moolenaar     {
374229b7d7a9SBram Moolenaar 	linenr_T	toplnum = 0;
374329b7d7a9SBram Moolenaar 	linenr_T	botlnum = 0;
374429b7d7a9SBram Moolenaar 	listitem_T	*li;
374529b7d7a9SBram Moolenaar 	int		i;
374629b7d7a9SBram Moolenaar 
374729b7d7a9SBram Moolenaar 	for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
374829b7d7a9SBram Moolenaar 							i++, li = li->li_next)
374929b7d7a9SBram Moolenaar 	{
375029b7d7a9SBram Moolenaar 	    linenr_T	lnum = 0;
375129b7d7a9SBram Moolenaar 	    colnr_T	col = 0;
375229b7d7a9SBram Moolenaar 	    int		len = 1;
375329b7d7a9SBram Moolenaar 	    list_T	*subl;
375429b7d7a9SBram Moolenaar 	    listitem_T	*subli;
375529b7d7a9SBram Moolenaar 	    int		error = FALSE;
375629b7d7a9SBram Moolenaar 
375729b7d7a9SBram Moolenaar 	    if (li->li_tv.v_type == VAR_LIST)
375829b7d7a9SBram Moolenaar 	    {
375929b7d7a9SBram Moolenaar 		subl = li->li_tv.vval.v_list;
376029b7d7a9SBram Moolenaar 		if (subl == NULL)
376129b7d7a9SBram Moolenaar 		    goto fail;
376229b7d7a9SBram Moolenaar 		subli = subl->lv_first;
376329b7d7a9SBram Moolenaar 		if (subli == NULL)
376429b7d7a9SBram Moolenaar 		    goto fail;
376529b7d7a9SBram Moolenaar 		lnum = tv_get_number_chk(&subli->li_tv, &error);
376629b7d7a9SBram Moolenaar 		if (error == TRUE)
376729b7d7a9SBram Moolenaar 		    goto fail;
376829b7d7a9SBram Moolenaar 		if (lnum == 0)
376929b7d7a9SBram Moolenaar 		{
377029b7d7a9SBram Moolenaar 		    --i;
377129b7d7a9SBram Moolenaar 		    continue;
377229b7d7a9SBram Moolenaar 		}
377329b7d7a9SBram Moolenaar 		m->pos.pos[i].lnum = lnum;
377429b7d7a9SBram Moolenaar 		subli = subli->li_next;
377529b7d7a9SBram Moolenaar 		if (subli != NULL)
377629b7d7a9SBram Moolenaar 		{
377729b7d7a9SBram Moolenaar 		    col = tv_get_number_chk(&subli->li_tv, &error);
377829b7d7a9SBram Moolenaar 		    if (error == TRUE)
377929b7d7a9SBram Moolenaar 			goto fail;
378029b7d7a9SBram Moolenaar 		    subli = subli->li_next;
378129b7d7a9SBram Moolenaar 		    if (subli != NULL)
378229b7d7a9SBram Moolenaar 		    {
378329b7d7a9SBram Moolenaar 			len = tv_get_number_chk(&subli->li_tv, &error);
378429b7d7a9SBram Moolenaar 			if (error == TRUE)
378529b7d7a9SBram Moolenaar 			    goto fail;
378629b7d7a9SBram Moolenaar 		    }
378729b7d7a9SBram Moolenaar 		}
378829b7d7a9SBram Moolenaar 		m->pos.pos[i].col = col;
378929b7d7a9SBram Moolenaar 		m->pos.pos[i].len = len;
379029b7d7a9SBram Moolenaar 	    }
379129b7d7a9SBram Moolenaar 	    else if (li->li_tv.v_type == VAR_NUMBER)
379229b7d7a9SBram Moolenaar 	    {
379329b7d7a9SBram Moolenaar 		if (li->li_tv.vval.v_number == 0)
379429b7d7a9SBram Moolenaar 		{
379529b7d7a9SBram Moolenaar 		    --i;
379629b7d7a9SBram Moolenaar 		    continue;
379729b7d7a9SBram Moolenaar 		}
379829b7d7a9SBram Moolenaar 		m->pos.pos[i].lnum = li->li_tv.vval.v_number;
379929b7d7a9SBram Moolenaar 		m->pos.pos[i].col = 0;
380029b7d7a9SBram Moolenaar 		m->pos.pos[i].len = 0;
380129b7d7a9SBram Moolenaar 	    }
380229b7d7a9SBram Moolenaar 	    else
380329b7d7a9SBram Moolenaar 	    {
380429b7d7a9SBram Moolenaar 		emsg(_("List or number required"));
380529b7d7a9SBram Moolenaar 		goto fail;
380629b7d7a9SBram Moolenaar 	    }
380729b7d7a9SBram Moolenaar 	    if (toplnum == 0 || lnum < toplnum)
380829b7d7a9SBram Moolenaar 		toplnum = lnum;
380929b7d7a9SBram Moolenaar 	    if (botlnum == 0 || lnum >= botlnum)
381029b7d7a9SBram Moolenaar 		botlnum = lnum + 1;
381129b7d7a9SBram Moolenaar 	}
381229b7d7a9SBram Moolenaar 
38131f164b19SBram Moolenaar 	// Calculate top and bottom lines for redrawing area
381429b7d7a9SBram Moolenaar 	if (toplnum != 0)
381529b7d7a9SBram Moolenaar 	{
381629b7d7a9SBram Moolenaar 	    if (wp->w_buffer->b_mod_set)
381729b7d7a9SBram Moolenaar 	    {
381829b7d7a9SBram Moolenaar 		if (wp->w_buffer->b_mod_top > toplnum)
381929b7d7a9SBram Moolenaar 		    wp->w_buffer->b_mod_top = toplnum;
382029b7d7a9SBram Moolenaar 		if (wp->w_buffer->b_mod_bot < botlnum)
382129b7d7a9SBram Moolenaar 		    wp->w_buffer->b_mod_bot = botlnum;
382229b7d7a9SBram Moolenaar 	    }
382329b7d7a9SBram Moolenaar 	    else
382429b7d7a9SBram Moolenaar 	    {
382529b7d7a9SBram Moolenaar 		wp->w_buffer->b_mod_set = TRUE;
382629b7d7a9SBram Moolenaar 		wp->w_buffer->b_mod_top = toplnum;
382729b7d7a9SBram Moolenaar 		wp->w_buffer->b_mod_bot = botlnum;
382829b7d7a9SBram Moolenaar 		wp->w_buffer->b_mod_xlines = 0;
382929b7d7a9SBram Moolenaar 	    }
383029b7d7a9SBram Moolenaar 	    m->pos.toplnum = toplnum;
383129b7d7a9SBram Moolenaar 	    m->pos.botlnum = botlnum;
383229b7d7a9SBram Moolenaar 	    rtype = VALID;
383329b7d7a9SBram Moolenaar 	}
383429b7d7a9SBram Moolenaar     }
383529b7d7a9SBram Moolenaar 
38361f164b19SBram Moolenaar     // Insert new match.  The match list is in ascending order with regard to
38371f164b19SBram Moolenaar     // the match priorities.
383829b7d7a9SBram Moolenaar     cur = wp->w_match_head;
383929b7d7a9SBram Moolenaar     prev = cur;
384029b7d7a9SBram Moolenaar     while (cur != NULL && prio >= cur->priority)
384129b7d7a9SBram Moolenaar     {
384229b7d7a9SBram Moolenaar 	prev = cur;
384329b7d7a9SBram Moolenaar 	cur = cur->next;
384429b7d7a9SBram Moolenaar     }
384529b7d7a9SBram Moolenaar     if (cur == prev)
384629b7d7a9SBram Moolenaar 	wp->w_match_head = m;
384729b7d7a9SBram Moolenaar     else
384829b7d7a9SBram Moolenaar 	prev->next = m;
384929b7d7a9SBram Moolenaar     m->next = cur;
385029b7d7a9SBram Moolenaar 
38514ef18dccSBram Moolenaar     redraw_win_later(wp, rtype);
385229b7d7a9SBram Moolenaar     return id;
385329b7d7a9SBram Moolenaar 
385429b7d7a9SBram Moolenaar fail:
385529b7d7a9SBram Moolenaar     vim_free(m);
385629b7d7a9SBram Moolenaar     return -1;
385729b7d7a9SBram Moolenaar }
385829b7d7a9SBram Moolenaar 
385929b7d7a9SBram Moolenaar /*
386029b7d7a9SBram Moolenaar  * Delete match with ID 'id' in the match list of window 'wp'.
386129b7d7a9SBram Moolenaar  * Print error messages if 'perr' is TRUE.
386229b7d7a9SBram Moolenaar  */
38637dfb016dSBram Moolenaar     static int
386429b7d7a9SBram Moolenaar match_delete(win_T *wp, int id, int perr)
386529b7d7a9SBram Moolenaar {
386629b7d7a9SBram Moolenaar     matchitem_T	*cur = wp->w_match_head;
386729b7d7a9SBram Moolenaar     matchitem_T	*prev = cur;
386829b7d7a9SBram Moolenaar     int		rtype = SOME_VALID;
386929b7d7a9SBram Moolenaar 
387029b7d7a9SBram Moolenaar     if (id < 1)
387129b7d7a9SBram Moolenaar     {
387229b7d7a9SBram Moolenaar 	if (perr == TRUE)
387329b7d7a9SBram Moolenaar 	    semsg(_("E802: Invalid ID: %d (must be greater than or equal to 1)"),
387429b7d7a9SBram Moolenaar 									  id);
387529b7d7a9SBram Moolenaar 	return -1;
387629b7d7a9SBram Moolenaar     }
387729b7d7a9SBram Moolenaar     while (cur != NULL && cur->id != id)
387829b7d7a9SBram Moolenaar     {
387929b7d7a9SBram Moolenaar 	prev = cur;
388029b7d7a9SBram Moolenaar 	cur = cur->next;
388129b7d7a9SBram Moolenaar     }
388229b7d7a9SBram Moolenaar     if (cur == NULL)
388329b7d7a9SBram Moolenaar     {
388429b7d7a9SBram Moolenaar 	if (perr == TRUE)
388529b7d7a9SBram Moolenaar 	    semsg(_("E803: ID not found: %d"), id);
388629b7d7a9SBram Moolenaar 	return -1;
388729b7d7a9SBram Moolenaar     }
388829b7d7a9SBram Moolenaar     if (cur == prev)
388929b7d7a9SBram Moolenaar 	wp->w_match_head = cur->next;
389029b7d7a9SBram Moolenaar     else
389129b7d7a9SBram Moolenaar 	prev->next = cur->next;
389229b7d7a9SBram Moolenaar     vim_regfree(cur->match.regprog);
389329b7d7a9SBram Moolenaar     vim_free(cur->pattern);
389429b7d7a9SBram Moolenaar     if (cur->pos.toplnum != 0)
389529b7d7a9SBram Moolenaar     {
389629b7d7a9SBram Moolenaar 	if (wp->w_buffer->b_mod_set)
389729b7d7a9SBram Moolenaar 	{
389829b7d7a9SBram Moolenaar 	    if (wp->w_buffer->b_mod_top > cur->pos.toplnum)
389929b7d7a9SBram Moolenaar 		wp->w_buffer->b_mod_top = cur->pos.toplnum;
390029b7d7a9SBram Moolenaar 	    if (wp->w_buffer->b_mod_bot < cur->pos.botlnum)
390129b7d7a9SBram Moolenaar 		wp->w_buffer->b_mod_bot = cur->pos.botlnum;
390229b7d7a9SBram Moolenaar 	}
390329b7d7a9SBram Moolenaar 	else
390429b7d7a9SBram Moolenaar 	{
390529b7d7a9SBram Moolenaar 	    wp->w_buffer->b_mod_set = TRUE;
390629b7d7a9SBram Moolenaar 	    wp->w_buffer->b_mod_top = cur->pos.toplnum;
390729b7d7a9SBram Moolenaar 	    wp->w_buffer->b_mod_bot = cur->pos.botlnum;
390829b7d7a9SBram Moolenaar 	    wp->w_buffer->b_mod_xlines = 0;
390929b7d7a9SBram Moolenaar 	}
391029b7d7a9SBram Moolenaar 	rtype = VALID;
391129b7d7a9SBram Moolenaar     }
391229b7d7a9SBram Moolenaar     vim_free(cur);
391306029a85SBram Moolenaar     redraw_win_later(wp, rtype);
391429b7d7a9SBram Moolenaar     return 0;
391529b7d7a9SBram Moolenaar }
391629b7d7a9SBram Moolenaar 
391729b7d7a9SBram Moolenaar /*
391829b7d7a9SBram Moolenaar  * Delete all matches in the match list of window 'wp'.
391929b7d7a9SBram Moolenaar  */
392029b7d7a9SBram Moolenaar     void
392129b7d7a9SBram Moolenaar clear_matches(win_T *wp)
392229b7d7a9SBram Moolenaar {
392329b7d7a9SBram Moolenaar     matchitem_T *m;
392429b7d7a9SBram Moolenaar 
392529b7d7a9SBram Moolenaar     while (wp->w_match_head != NULL)
392629b7d7a9SBram Moolenaar     {
392729b7d7a9SBram Moolenaar 	m = wp->w_match_head->next;
392829b7d7a9SBram Moolenaar 	vim_regfree(wp->w_match_head->match.regprog);
392929b7d7a9SBram Moolenaar 	vim_free(wp->w_match_head->pattern);
393029b7d7a9SBram Moolenaar 	vim_free(wp->w_match_head);
393129b7d7a9SBram Moolenaar 	wp->w_match_head = m;
393229b7d7a9SBram Moolenaar     }
39334ef18dccSBram Moolenaar     redraw_win_later(wp, SOME_VALID);
393429b7d7a9SBram Moolenaar }
393529b7d7a9SBram Moolenaar 
393629b7d7a9SBram Moolenaar /*
393729b7d7a9SBram Moolenaar  * Get match from ID 'id' in window 'wp'.
393829b7d7a9SBram Moolenaar  * Return NULL if match not found.
393929b7d7a9SBram Moolenaar  */
39407dfb016dSBram Moolenaar     static matchitem_T *
394129b7d7a9SBram Moolenaar get_match(win_T *wp, int id)
394229b7d7a9SBram Moolenaar {
394329b7d7a9SBram Moolenaar     matchitem_T *cur = wp->w_match_head;
394429b7d7a9SBram Moolenaar 
394529b7d7a9SBram Moolenaar     while (cur != NULL && cur->id != id)
394629b7d7a9SBram Moolenaar 	cur = cur->next;
394729b7d7a9SBram Moolenaar     return cur;
394829b7d7a9SBram Moolenaar }
3949bbca7732SBram Moolenaar 
3950bbca7732SBram Moolenaar /*
3951bbca7732SBram Moolenaar  * Init for calling prepare_search_hl().
3952bbca7732SBram Moolenaar  */
3953bbca7732SBram Moolenaar     void
3954bbca7732SBram Moolenaar init_search_hl(win_T *wp, match_T *search_hl)
3955bbca7732SBram Moolenaar {
3956bbca7732SBram Moolenaar     matchitem_T *cur;
3957bbca7732SBram Moolenaar 
39581f164b19SBram Moolenaar     // Setup for match and 'hlsearch' highlighting.  Disable any previous
39591f164b19SBram Moolenaar     // match
3960bbca7732SBram Moolenaar     cur = wp->w_match_head;
3961bbca7732SBram Moolenaar     while (cur != NULL)
3962bbca7732SBram Moolenaar     {
3963bbca7732SBram Moolenaar 	cur->hl.rm = cur->match;
3964bbca7732SBram Moolenaar 	if (cur->hlg_id == 0)
3965bbca7732SBram Moolenaar 	    cur->hl.attr = 0;
3966bbca7732SBram Moolenaar 	else
3967bbca7732SBram Moolenaar 	    cur->hl.attr = syn_id2attr(cur->hlg_id);
3968bbca7732SBram Moolenaar 	cur->hl.buf = wp->w_buffer;
3969bbca7732SBram Moolenaar 	cur->hl.lnum = 0;
3970bbca7732SBram Moolenaar 	cur->hl.first_lnum = 0;
3971bbca7732SBram Moolenaar # ifdef FEAT_RELTIME
39721f164b19SBram Moolenaar 	// Set the time limit to 'redrawtime'.
3973bbca7732SBram Moolenaar 	profile_setlimit(p_rdt, &(cur->hl.tm));
3974c61a48d2SBram Moolenaar # endif
3975bbca7732SBram Moolenaar 	cur = cur->next;
3976bbca7732SBram Moolenaar     }
3977bbca7732SBram Moolenaar     search_hl->buf = wp->w_buffer;
3978bbca7732SBram Moolenaar     search_hl->lnum = 0;
3979bbca7732SBram Moolenaar     search_hl->first_lnum = 0;
39801f164b19SBram Moolenaar     // time limit is set at the toplevel, for all windows
3981bbca7732SBram Moolenaar }
3982bbca7732SBram Moolenaar 
3983bbca7732SBram Moolenaar /*
3984bbca7732SBram Moolenaar  * If there is a match fill "shl" and return one.
3985bbca7732SBram Moolenaar  * Return zero otherwise.
3986bbca7732SBram Moolenaar  */
3987bbca7732SBram Moolenaar     static int
3988bbca7732SBram Moolenaar next_search_hl_pos(
39891f164b19SBram Moolenaar     match_T	    *shl,	// points to a match
3990bbca7732SBram Moolenaar     linenr_T	    lnum,
39911f164b19SBram Moolenaar     posmatch_T	    *posmatch,	// match positions
39921f164b19SBram Moolenaar     colnr_T	    mincol)	// minimal column for a match
3993bbca7732SBram Moolenaar {
3994bbca7732SBram Moolenaar     int	    i;
3995bbca7732SBram Moolenaar     int	    found = -1;
3996bbca7732SBram Moolenaar 
3997bbca7732SBram Moolenaar     for (i = posmatch->cur; i < MAXPOSMATCH; i++)
3998bbca7732SBram Moolenaar     {
3999bbca7732SBram Moolenaar 	llpos_T	*pos = &posmatch->pos[i];
4000bbca7732SBram Moolenaar 
4001bbca7732SBram Moolenaar 	if (pos->lnum == 0)
4002bbca7732SBram Moolenaar 	    break;
4003bbca7732SBram Moolenaar 	if (pos->len == 0 && pos->col < mincol)
4004bbca7732SBram Moolenaar 	    continue;
4005bbca7732SBram Moolenaar 	if (pos->lnum == lnum)
4006bbca7732SBram Moolenaar 	{
4007bbca7732SBram Moolenaar 	    if (found >= 0)
4008bbca7732SBram Moolenaar 	    {
40091f164b19SBram Moolenaar 		// if this match comes before the one at "found" then swap
40101f164b19SBram Moolenaar 		// them
4011bbca7732SBram Moolenaar 		if (pos->col < posmatch->pos[found].col)
4012bbca7732SBram Moolenaar 		{
4013bbca7732SBram Moolenaar 		    llpos_T	tmp = *pos;
4014bbca7732SBram Moolenaar 
4015bbca7732SBram Moolenaar 		    *pos = posmatch->pos[found];
4016bbca7732SBram Moolenaar 		    posmatch->pos[found] = tmp;
4017bbca7732SBram Moolenaar 		}
4018bbca7732SBram Moolenaar 	    }
4019bbca7732SBram Moolenaar 	    else
4020bbca7732SBram Moolenaar 		found = i;
4021bbca7732SBram Moolenaar 	}
4022bbca7732SBram Moolenaar     }
4023bbca7732SBram Moolenaar     posmatch->cur = 0;
4024bbca7732SBram Moolenaar     if (found >= 0)
4025bbca7732SBram Moolenaar     {
4026bbca7732SBram Moolenaar 	colnr_T	start = posmatch->pos[found].col == 0
4027bbca7732SBram Moolenaar 					    ? 0 : posmatch->pos[found].col - 1;
4028bbca7732SBram Moolenaar 	colnr_T	end = posmatch->pos[found].col == 0
4029bbca7732SBram Moolenaar 				   ? MAXCOL : start + posmatch->pos[found].len;
4030bbca7732SBram Moolenaar 
4031bbca7732SBram Moolenaar 	shl->lnum = lnum;
4032bbca7732SBram Moolenaar 	shl->rm.startpos[0].lnum = 0;
4033bbca7732SBram Moolenaar 	shl->rm.startpos[0].col = start;
4034bbca7732SBram Moolenaar 	shl->rm.endpos[0].lnum = 0;
4035bbca7732SBram Moolenaar 	shl->rm.endpos[0].col = end;
4036bbca7732SBram Moolenaar 	shl->is_addpos = TRUE;
4037bbca7732SBram Moolenaar 	posmatch->cur = found + 1;
4038bbca7732SBram Moolenaar 	return 1;
4039bbca7732SBram Moolenaar     }
4040bbca7732SBram Moolenaar     return 0;
4041bbca7732SBram Moolenaar }
4042bbca7732SBram Moolenaar 
4043bbca7732SBram Moolenaar /*
4044bbca7732SBram Moolenaar  * Search for a next 'hlsearch' or match.
4045bbca7732SBram Moolenaar  * Uses shl->buf.
4046bbca7732SBram Moolenaar  * Sets shl->lnum and shl->rm contents.
4047bbca7732SBram Moolenaar  * Note: Assumes a previous match is always before "lnum", unless
4048bbca7732SBram Moolenaar  * shl->lnum is zero.
4049bbca7732SBram Moolenaar  * Careful: Any pointers for buffer lines will become invalid.
4050bbca7732SBram Moolenaar  */
4051bbca7732SBram Moolenaar     static void
4052bbca7732SBram Moolenaar next_search_hl(
4053bbca7732SBram Moolenaar     win_T	    *win,
4054bbca7732SBram Moolenaar     match_T	    *search_hl,
4055bbca7732SBram Moolenaar     match_T	    *shl,	// points to search_hl or a match
4056bbca7732SBram Moolenaar     linenr_T	    lnum,
4057bbca7732SBram Moolenaar     colnr_T	    mincol,	// minimal column for a match
4058bbca7732SBram Moolenaar     matchitem_T	    *cur)	// to retrieve match positions if any
4059bbca7732SBram Moolenaar {
4060bbca7732SBram Moolenaar     linenr_T	l;
4061bbca7732SBram Moolenaar     colnr_T	matchcol;
4062bbca7732SBram Moolenaar     long	nmatched;
4063bbca7732SBram Moolenaar     int		save_called_emsg = called_emsg;
4064bbca7732SBram Moolenaar 
4065bbca7732SBram Moolenaar     // for :{range}s/pat only highlight inside the range
4066bbca7732SBram Moolenaar     if (lnum < search_first_line || lnum > search_last_line)
4067bbca7732SBram Moolenaar     {
4068bbca7732SBram Moolenaar 	shl->lnum = 0;
4069bbca7732SBram Moolenaar 	return;
4070bbca7732SBram Moolenaar     }
4071bbca7732SBram Moolenaar 
4072bbca7732SBram Moolenaar     if (shl->lnum != 0)
4073bbca7732SBram Moolenaar     {
40741f164b19SBram Moolenaar 	// Check for three situations:
40751f164b19SBram Moolenaar 	// 1. If the "lnum" is below a previous match, start a new search.
40761f164b19SBram Moolenaar 	// 2. If the previous match includes "mincol", use it.
40771f164b19SBram Moolenaar 	// 3. Continue after the previous match.
4078bbca7732SBram Moolenaar 	l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
4079bbca7732SBram Moolenaar 	if (lnum > l)
4080bbca7732SBram Moolenaar 	    shl->lnum = 0;
4081bbca7732SBram Moolenaar 	else if (lnum < l || shl->rm.endpos[0].col > mincol)
4082bbca7732SBram Moolenaar 	    return;
4083bbca7732SBram Moolenaar     }
4084bbca7732SBram Moolenaar 
4085bbca7732SBram Moolenaar     /*
4086bbca7732SBram Moolenaar      * Repeat searching for a match until one is found that includes "mincol"
4087bbca7732SBram Moolenaar      * or none is found in this line.
4088bbca7732SBram Moolenaar      */
4089bbca7732SBram Moolenaar     called_emsg = FALSE;
4090bbca7732SBram Moolenaar     for (;;)
4091bbca7732SBram Moolenaar     {
4092bbca7732SBram Moolenaar # ifdef FEAT_RELTIME
40931f164b19SBram Moolenaar 	// Stop searching after passing the time limit.
4094bbca7732SBram Moolenaar 	if (profile_passed_limit(&(shl->tm)))
4095bbca7732SBram Moolenaar 	{
40961f164b19SBram Moolenaar 	    shl->lnum = 0;		// no match found in time
4097bbca7732SBram Moolenaar 	    break;
4098bbca7732SBram Moolenaar 	}
4099bbca7732SBram Moolenaar # endif
41001f164b19SBram Moolenaar 	// Three situations:
41011f164b19SBram Moolenaar 	// 1. No useful previous match: search from start of line.
41021f164b19SBram Moolenaar 	// 2. Not Vi compatible or empty match: continue at next character.
41031f164b19SBram Moolenaar 	//    Break the loop if this is beyond the end of the line.
41041f164b19SBram Moolenaar 	// 3. Vi compatible searching: continue at end of previous match.
4105bbca7732SBram Moolenaar 	if (shl->lnum == 0)
4106bbca7732SBram Moolenaar 	    matchcol = 0;
4107bbca7732SBram Moolenaar 	else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
4108bbca7732SBram Moolenaar 		|| (shl->rm.endpos[0].lnum == 0
4109bbca7732SBram Moolenaar 		    && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
4110bbca7732SBram Moolenaar 	{
4111bbca7732SBram Moolenaar 	    char_u	*ml;
4112bbca7732SBram Moolenaar 
4113bbca7732SBram Moolenaar 	    matchcol = shl->rm.startpos[0].col;
4114bbca7732SBram Moolenaar 	    ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
4115bbca7732SBram Moolenaar 	    if (*ml == NUL)
4116bbca7732SBram Moolenaar 	    {
4117bbca7732SBram Moolenaar 		++matchcol;
4118bbca7732SBram Moolenaar 		shl->lnum = 0;
4119bbca7732SBram Moolenaar 		break;
4120bbca7732SBram Moolenaar 	    }
4121bbca7732SBram Moolenaar 	    if (has_mbyte)
4122bbca7732SBram Moolenaar 		matchcol += mb_ptr2len(ml);
4123bbca7732SBram Moolenaar 	    else
4124bbca7732SBram Moolenaar 		++matchcol;
4125bbca7732SBram Moolenaar 	}
4126bbca7732SBram Moolenaar 	else
4127bbca7732SBram Moolenaar 	    matchcol = shl->rm.endpos[0].col;
4128bbca7732SBram Moolenaar 
4129bbca7732SBram Moolenaar 	shl->lnum = lnum;
4130bbca7732SBram Moolenaar 	if (shl->rm.regprog != NULL)
4131bbca7732SBram Moolenaar 	{
41321f164b19SBram Moolenaar 	    // Remember whether shl->rm is using a copy of the regprog in
41331f164b19SBram Moolenaar 	    // cur->match.
4134bbca7732SBram Moolenaar 	    int regprog_is_copy = (shl != search_hl && cur != NULL
4135bbca7732SBram Moolenaar 				&& shl == &cur->hl
4136bbca7732SBram Moolenaar 				&& cur->match.regprog == cur->hl.rm.regprog);
4137bbca7732SBram Moolenaar 	    int timed_out = FALSE;
4138bbca7732SBram Moolenaar 
4139bbca7732SBram Moolenaar 	    nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
4140bbca7732SBram Moolenaar 		    matchcol,
4141bbca7732SBram Moolenaar #ifdef FEAT_RELTIME
4142bbca7732SBram Moolenaar 		    &(shl->tm), &timed_out
4143bbca7732SBram Moolenaar #else
4144bbca7732SBram Moolenaar 		    NULL, NULL
4145bbca7732SBram Moolenaar #endif
4146bbca7732SBram Moolenaar 		    );
41471f164b19SBram Moolenaar 	    // Copy the regprog, in case it got freed and recompiled.
4148bbca7732SBram Moolenaar 	    if (regprog_is_copy)
4149bbca7732SBram Moolenaar 		cur->match.regprog = cur->hl.rm.regprog;
4150bbca7732SBram Moolenaar 
4151bbca7732SBram Moolenaar 	    if (called_emsg || got_int || timed_out)
4152bbca7732SBram Moolenaar 	    {
41531f164b19SBram Moolenaar 		// Error while handling regexp: stop using this regexp.
4154bbca7732SBram Moolenaar 		if (shl == search_hl)
4155bbca7732SBram Moolenaar 		{
41561f164b19SBram Moolenaar 		    // don't free regprog in the match list, it's a copy
4157bbca7732SBram Moolenaar 		    vim_regfree(shl->rm.regprog);
4158bbca7732SBram Moolenaar 		    set_no_hlsearch(TRUE);
4159bbca7732SBram Moolenaar 		}
4160bbca7732SBram Moolenaar 		shl->rm.regprog = NULL;
4161bbca7732SBram Moolenaar 		shl->lnum = 0;
41621f164b19SBram Moolenaar 		got_int = FALSE;  // avoid the "Type :quit to exit Vim" message
4163bbca7732SBram Moolenaar 		break;
4164bbca7732SBram Moolenaar 	    }
4165bbca7732SBram Moolenaar 	}
4166bbca7732SBram Moolenaar 	else if (cur != NULL)
4167bbca7732SBram Moolenaar 	    nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
4168bbca7732SBram Moolenaar 	else
4169bbca7732SBram Moolenaar 	    nmatched = 0;
4170bbca7732SBram Moolenaar 	if (nmatched == 0)
4171bbca7732SBram Moolenaar 	{
41721f164b19SBram Moolenaar 	    shl->lnum = 0;		// no match found
4173bbca7732SBram Moolenaar 	    break;
4174bbca7732SBram Moolenaar 	}
4175bbca7732SBram Moolenaar 	if (shl->rm.startpos[0].lnum > 0
4176bbca7732SBram Moolenaar 		|| shl->rm.startpos[0].col >= mincol
4177bbca7732SBram Moolenaar 		|| nmatched > 1
4178bbca7732SBram Moolenaar 		|| shl->rm.endpos[0].col > mincol)
4179bbca7732SBram Moolenaar 	{
4180bbca7732SBram Moolenaar 	    shl->lnum += shl->rm.startpos[0].lnum;
41811f164b19SBram Moolenaar 	    break;			// useful match found
4182bbca7732SBram Moolenaar 	}
4183bbca7732SBram Moolenaar     }
4184bbca7732SBram Moolenaar 
4185bbca7732SBram Moolenaar     // Restore called_emsg for assert_fails().
4186bbca7732SBram Moolenaar     called_emsg = save_called_emsg;
4187bbca7732SBram Moolenaar }
4188bbca7732SBram Moolenaar 
4189bbca7732SBram Moolenaar /*
4190bbca7732SBram Moolenaar  * Advance to the match in window "wp" line "lnum" or past it.
4191bbca7732SBram Moolenaar  */
4192bbca7732SBram Moolenaar     void
4193bbca7732SBram Moolenaar prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum)
4194bbca7732SBram Moolenaar {
41951f164b19SBram Moolenaar     matchitem_T *cur;		// points to the match list
41961f164b19SBram Moolenaar     match_T	*shl;		// points to search_hl or a match
41971f164b19SBram Moolenaar     int		shl_flag;	// flag to indicate whether search_hl
41981f164b19SBram Moolenaar 				// has been processed or not
41991f164b19SBram Moolenaar     int		pos_inprogress;	// marks that position match search is
42001f164b19SBram Moolenaar 				// in progress
4201bbca7732SBram Moolenaar     int		n;
4202bbca7732SBram Moolenaar 
42031f164b19SBram Moolenaar     // When using a multi-line pattern, start searching at the top
42041f164b19SBram Moolenaar     // of the window or just after a closed fold.
42051f164b19SBram Moolenaar     // Do this both for search_hl and the match list.
4206bbca7732SBram Moolenaar     cur = wp->w_match_head;
4207bbca7732SBram Moolenaar     shl_flag = WIN_IS_POPUP(wp);  // skip search_hl in a popup window
4208bbca7732SBram Moolenaar     while (cur != NULL || shl_flag == FALSE)
4209bbca7732SBram Moolenaar     {
4210bbca7732SBram Moolenaar 	if (shl_flag == FALSE)
4211bbca7732SBram Moolenaar 	{
4212bbca7732SBram Moolenaar 	    shl = search_hl;
4213bbca7732SBram Moolenaar 	    shl_flag = TRUE;
4214bbca7732SBram Moolenaar 	}
4215bbca7732SBram Moolenaar 	else
4216bbca7732SBram Moolenaar 	    shl = &cur->hl;
4217bbca7732SBram Moolenaar 	if (shl->rm.regprog != NULL
4218bbca7732SBram Moolenaar 		&& shl->lnum == 0
4219bbca7732SBram Moolenaar 		&& re_multiline(shl->rm.regprog))
4220bbca7732SBram Moolenaar 	{
4221bbca7732SBram Moolenaar 	    if (shl->first_lnum == 0)
4222bbca7732SBram Moolenaar 	    {
4223bbca7732SBram Moolenaar # ifdef FEAT_FOLDING
4224bbca7732SBram Moolenaar 		for (shl->first_lnum = lnum;
4225bbca7732SBram Moolenaar 			   shl->first_lnum > wp->w_topline; --shl->first_lnum)
4226bbca7732SBram Moolenaar 		    if (hasFoldingWin(wp, shl->first_lnum - 1,
4227bbca7732SBram Moolenaar 						      NULL, NULL, TRUE, NULL))
4228bbca7732SBram Moolenaar 			break;
4229bbca7732SBram Moolenaar # else
4230bbca7732SBram Moolenaar 		shl->first_lnum = wp->w_topline;
4231bbca7732SBram Moolenaar # endif
4232bbca7732SBram Moolenaar 	    }
4233bbca7732SBram Moolenaar 	    if (cur != NULL)
4234bbca7732SBram Moolenaar 		cur->pos.cur = 0;
4235bbca7732SBram Moolenaar 	    pos_inprogress = TRUE;
4236bbca7732SBram Moolenaar 	    n = 0;
4237bbca7732SBram Moolenaar 	    while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
4238bbca7732SBram Moolenaar 					  || (cur != NULL && pos_inprogress)))
4239bbca7732SBram Moolenaar 	    {
4240bbca7732SBram Moolenaar 		next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n,
4241bbca7732SBram Moolenaar 					       shl == search_hl ? NULL : cur);
4242bbca7732SBram Moolenaar 		pos_inprogress = cur == NULL || cur->pos.cur == 0
4243bbca7732SBram Moolenaar 							      ? FALSE : TRUE;
4244bbca7732SBram Moolenaar 		if (shl->lnum != 0)
4245bbca7732SBram Moolenaar 		{
4246bbca7732SBram Moolenaar 		    shl->first_lnum = shl->lnum
4247bbca7732SBram Moolenaar 				    + shl->rm.endpos[0].lnum
4248bbca7732SBram Moolenaar 				    - shl->rm.startpos[0].lnum;
4249bbca7732SBram Moolenaar 		    n = shl->rm.endpos[0].col;
4250bbca7732SBram Moolenaar 		}
4251bbca7732SBram Moolenaar 		else
4252bbca7732SBram Moolenaar 		{
4253bbca7732SBram Moolenaar 		    ++shl->first_lnum;
4254bbca7732SBram Moolenaar 		    n = 0;
4255bbca7732SBram Moolenaar 		}
4256bbca7732SBram Moolenaar 	    }
4257bbca7732SBram Moolenaar 	}
4258bbca7732SBram Moolenaar 	if (shl != search_hl && cur != NULL)
4259bbca7732SBram Moolenaar 	    cur = cur->next;
4260bbca7732SBram Moolenaar     }
4261bbca7732SBram Moolenaar }
4262bbca7732SBram Moolenaar 
4263bbca7732SBram Moolenaar /*
4264bbca7732SBram Moolenaar  * Prepare for 'hlsearch' and match highlighting in one window line.
4265bbca7732SBram Moolenaar  * Return TRUE if there is such highlighting and set "search_attr" to the
4266bbca7732SBram Moolenaar  * current highlight attribute.
4267bbca7732SBram Moolenaar  */
4268bbca7732SBram Moolenaar     int
4269bbca7732SBram Moolenaar prepare_search_hl_line(
4270bbca7732SBram Moolenaar 	win_T	    *wp,
4271bbca7732SBram Moolenaar 	linenr_T    lnum,
4272bbca7732SBram Moolenaar 	colnr_T	    mincol,
4273bbca7732SBram Moolenaar 	char_u	    **line,
4274bbca7732SBram Moolenaar 	match_T	    *search_hl,
4275bbca7732SBram Moolenaar 	int	    *search_attr)
4276bbca7732SBram Moolenaar {
4277bbca7732SBram Moolenaar     matchitem_T *cur;			// points to the match list
4278bbca7732SBram Moolenaar     match_T	*shl;			// points to search_hl or a match
4279bbca7732SBram Moolenaar     int		shl_flag;		// flag to indicate whether search_hl
4280bbca7732SBram Moolenaar 					// has been processed or not
4281bbca7732SBram Moolenaar     int		area_highlighting = FALSE;
4282bbca7732SBram Moolenaar 
4283bbca7732SBram Moolenaar     /*
4284bbca7732SBram Moolenaar      * Handle highlighting the last used search pattern and matches.
4285bbca7732SBram Moolenaar      * Do this for both search_hl and the match list.
4286bbca7732SBram Moolenaar      * Do not use search_hl in a popup window.
4287bbca7732SBram Moolenaar      */
4288bbca7732SBram Moolenaar     cur = wp->w_match_head;
4289bbca7732SBram Moolenaar     shl_flag = WIN_IS_POPUP(wp);
4290bbca7732SBram Moolenaar     while (cur != NULL || shl_flag == FALSE)
4291bbca7732SBram Moolenaar     {
4292bbca7732SBram Moolenaar 	if (shl_flag == FALSE)
4293bbca7732SBram Moolenaar 	{
4294bbca7732SBram Moolenaar 	    shl = search_hl;
4295bbca7732SBram Moolenaar 	    shl_flag = TRUE;
4296bbca7732SBram Moolenaar 	}
4297bbca7732SBram Moolenaar 	else
4298bbca7732SBram Moolenaar 	    shl = &cur->hl;
4299bbca7732SBram Moolenaar 	shl->startcol = MAXCOL;
4300bbca7732SBram Moolenaar 	shl->endcol = MAXCOL;
4301bbca7732SBram Moolenaar 	shl->attr_cur = 0;
4302bbca7732SBram Moolenaar 	shl->is_addpos = FALSE;
4303bbca7732SBram Moolenaar 	if (cur != NULL)
4304bbca7732SBram Moolenaar 	    cur->pos.cur = 0;
4305bbca7732SBram Moolenaar 	next_search_hl(wp, search_hl, shl, lnum, mincol,
4306bbca7732SBram Moolenaar 						shl == search_hl ? NULL : cur);
4307bbca7732SBram Moolenaar 
4308bbca7732SBram Moolenaar 	// Need to get the line again, a multi-line regexp may have made it
4309bbca7732SBram Moolenaar 	// invalid.
4310bbca7732SBram Moolenaar 	*line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4311bbca7732SBram Moolenaar 
4312bbca7732SBram Moolenaar 	if (shl->lnum != 0 && shl->lnum <= lnum)
4313bbca7732SBram Moolenaar 	{
4314bbca7732SBram Moolenaar 	    if (shl->lnum == lnum)
4315bbca7732SBram Moolenaar 		shl->startcol = shl->rm.startpos[0].col;
4316bbca7732SBram Moolenaar 	    else
4317bbca7732SBram Moolenaar 		shl->startcol = 0;
4318bbca7732SBram Moolenaar 	    if (lnum == shl->lnum + shl->rm.endpos[0].lnum
4319bbca7732SBram Moolenaar 						- shl->rm.startpos[0].lnum)
4320bbca7732SBram Moolenaar 		shl->endcol = shl->rm.endpos[0].col;
4321bbca7732SBram Moolenaar 	    else
4322bbca7732SBram Moolenaar 		shl->endcol = MAXCOL;
4323bbca7732SBram Moolenaar 	    // Highlight one character for an empty match.
4324bbca7732SBram Moolenaar 	    if (shl->startcol == shl->endcol)
4325bbca7732SBram Moolenaar 	    {
4326bbca7732SBram Moolenaar 		if (has_mbyte && (*line)[shl->endcol] != NUL)
4327bbca7732SBram Moolenaar 		    shl->endcol += (*mb_ptr2len)((*line) + shl->endcol);
4328bbca7732SBram Moolenaar 		else
4329bbca7732SBram Moolenaar 		    ++shl->endcol;
4330bbca7732SBram Moolenaar 	    }
43311f164b19SBram Moolenaar 	    if ((long)shl->startcol < mincol)  // match at leftcol
4332bbca7732SBram Moolenaar 	    {
4333bbca7732SBram Moolenaar 		shl->attr_cur = shl->attr;
4334bbca7732SBram Moolenaar 		*search_attr = shl->attr;
4335bbca7732SBram Moolenaar 	    }
4336bbca7732SBram Moolenaar 	    area_highlighting = TRUE;
4337bbca7732SBram Moolenaar 	}
4338bbca7732SBram Moolenaar 	if (shl != search_hl && cur != NULL)
4339bbca7732SBram Moolenaar 	    cur = cur->next;
4340bbca7732SBram Moolenaar     }
4341bbca7732SBram Moolenaar     return area_highlighting;
4342bbca7732SBram Moolenaar }
4343bbca7732SBram Moolenaar 
4344bbca7732SBram Moolenaar /*
4345bbca7732SBram Moolenaar  * For a position in a line: Check for start/end of 'hlsearch' and other
4346bbca7732SBram Moolenaar  * matches.
4347bbca7732SBram Moolenaar  * After end, check for start/end of next match.
4348bbca7732SBram Moolenaar  * When another match, have to check for start again.
4349bbca7732SBram Moolenaar  * Watch out for matching an empty string!
4350*32aa1020SBram Moolenaar  * Return the updated search_attr.
4351bbca7732SBram Moolenaar  */
4352bbca7732SBram Moolenaar     int
4353bbca7732SBram Moolenaar update_search_hl(
4354bbca7732SBram Moolenaar 	win_T	    *wp,
4355bbca7732SBram Moolenaar 	linenr_T    lnum,
4356bbca7732SBram Moolenaar 	colnr_T	    col,
4357bbca7732SBram Moolenaar 	char_u	    **line,
4358bbca7732SBram Moolenaar 	match_T	    *search_hl,
43591f164b19SBram Moolenaar 	int	    *has_match_conc UNUSED,
43601f164b19SBram Moolenaar 	int	    *match_conc UNUSED,
4361bbca7732SBram Moolenaar 	int	    did_line_attr,
4362bbca7732SBram Moolenaar 	int	    lcs_eol_one)
4363bbca7732SBram Moolenaar {
4364bbca7732SBram Moolenaar     matchitem_T *cur;		    // points to the match list
4365bbca7732SBram Moolenaar     match_T	*shl;		    // points to search_hl or a match
4366bbca7732SBram Moolenaar     int		shl_flag;	    // flag to indicate whether search_hl
4367bbca7732SBram Moolenaar 				    // has been processed or not
4368bbca7732SBram Moolenaar     int		pos_inprogress;	    // marks that position match search is in
4369bbca7732SBram Moolenaar 				    // progress
4370bbca7732SBram Moolenaar     int		search_attr = 0;
4371bbca7732SBram Moolenaar 
4372bbca7732SBram Moolenaar 
4373bbca7732SBram Moolenaar     // Do this for 'search_hl' and the match list (ordered by priority).
4374bbca7732SBram Moolenaar     cur = wp->w_match_head;
4375bbca7732SBram Moolenaar     shl_flag = WIN_IS_POPUP(wp);
4376bbca7732SBram Moolenaar     while (cur != NULL || shl_flag == FALSE)
4377bbca7732SBram Moolenaar     {
4378bbca7732SBram Moolenaar 	if (shl_flag == FALSE
4379bbca7732SBram Moolenaar 		&& ((cur != NULL
4380bbca7732SBram Moolenaar 			&& cur->priority > SEARCH_HL_PRIORITY)
4381bbca7732SBram Moolenaar 		    || cur == NULL))
4382bbca7732SBram Moolenaar 	{
4383bbca7732SBram Moolenaar 	    shl = search_hl;
4384bbca7732SBram Moolenaar 	    shl_flag = TRUE;
4385bbca7732SBram Moolenaar 	}
4386bbca7732SBram Moolenaar 	else
4387bbca7732SBram Moolenaar 	    shl = &cur->hl;
4388bbca7732SBram Moolenaar 	if (cur != NULL)
4389bbca7732SBram Moolenaar 	    cur->pos.cur = 0;
4390bbca7732SBram Moolenaar 	pos_inprogress = TRUE;
4391bbca7732SBram Moolenaar 	while (shl->rm.regprog != NULL || (cur != NULL && pos_inprogress))
4392bbca7732SBram Moolenaar 	{
4393bbca7732SBram Moolenaar 	    if (shl->startcol != MAXCOL
4394bbca7732SBram Moolenaar 		    && col >= shl->startcol
4395bbca7732SBram Moolenaar 		    && col < shl->endcol)
4396bbca7732SBram Moolenaar 	    {
43971614a149SBram Moolenaar 		int next_col = col + mb_ptr2len(*line + col);
4398bbca7732SBram Moolenaar 
4399bbca7732SBram Moolenaar 		if (shl->endcol < next_col)
4400bbca7732SBram Moolenaar 		    shl->endcol = next_col;
4401bbca7732SBram Moolenaar 		shl->attr_cur = shl->attr;
4402bbca7732SBram Moolenaar # ifdef FEAT_CONCEAL
4403bbca7732SBram Moolenaar 		// Match with the "Conceal" group results in hiding
4404bbca7732SBram Moolenaar 		// the match.
4405bbca7732SBram Moolenaar 		if (cur != NULL
4406bbca7732SBram Moolenaar 			&& shl != search_hl
4407bbca7732SBram Moolenaar 			&& syn_name2id((char_u *)"Conceal") == cur->hlg_id)
4408bbca7732SBram Moolenaar 		{
4409bbca7732SBram Moolenaar 		    *has_match_conc = col == shl->startcol ? 2 : 1;
4410bbca7732SBram Moolenaar 		    *match_conc = cur->conceal_char;
4411bbca7732SBram Moolenaar 		}
4412bbca7732SBram Moolenaar 		else
4413bbca7732SBram Moolenaar 		    *has_match_conc = *match_conc = 0;
4414bbca7732SBram Moolenaar # endif
4415bbca7732SBram Moolenaar 	    }
4416bbca7732SBram Moolenaar 	    else if (col == shl->endcol)
4417bbca7732SBram Moolenaar 	    {
4418bbca7732SBram Moolenaar 		shl->attr_cur = 0;
4419bbca7732SBram Moolenaar 		next_search_hl(wp, search_hl, shl, lnum, col,
4420bbca7732SBram Moolenaar 					       shl == search_hl ? NULL : cur);
4421bbca7732SBram Moolenaar 		pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
4422bbca7732SBram Moolenaar 
4423bbca7732SBram Moolenaar 		// Need to get the line again, a multi-line regexp may have
4424bbca7732SBram Moolenaar 		// made it invalid.
4425bbca7732SBram Moolenaar 		*line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4426bbca7732SBram Moolenaar 
4427bbca7732SBram Moolenaar 		if (shl->lnum == lnum)
4428bbca7732SBram Moolenaar 		{
4429bbca7732SBram Moolenaar 		    shl->startcol = shl->rm.startpos[0].col;
4430bbca7732SBram Moolenaar 		    if (shl->rm.endpos[0].lnum == 0)
4431bbca7732SBram Moolenaar 			shl->endcol = shl->rm.endpos[0].col;
4432bbca7732SBram Moolenaar 		    else
4433bbca7732SBram Moolenaar 			shl->endcol = MAXCOL;
4434bbca7732SBram Moolenaar 
4435bbca7732SBram Moolenaar 		    if (shl->startcol == shl->endcol)
4436bbca7732SBram Moolenaar 		    {
44371f164b19SBram Moolenaar 			// highlight empty match, try again after
44381f164b19SBram Moolenaar 			// it
4439bbca7732SBram Moolenaar 			if (has_mbyte)
4440bbca7732SBram Moolenaar 			    shl->endcol += (*mb_ptr2len)(*line + shl->endcol);
4441bbca7732SBram Moolenaar 			else
4442bbca7732SBram Moolenaar 			    ++shl->endcol;
4443bbca7732SBram Moolenaar 		    }
4444bbca7732SBram Moolenaar 
44451f164b19SBram Moolenaar 		    // Loop to check if the match starts at the
44461f164b19SBram Moolenaar 		    // current position
4447bbca7732SBram Moolenaar 		    continue;
4448bbca7732SBram Moolenaar 		}
4449bbca7732SBram Moolenaar 	    }
4450bbca7732SBram Moolenaar 	    break;
4451bbca7732SBram Moolenaar 	}
4452bbca7732SBram Moolenaar 	if (shl != search_hl && cur != NULL)
4453bbca7732SBram Moolenaar 	    cur = cur->next;
4454bbca7732SBram Moolenaar     }
4455bbca7732SBram Moolenaar 
4456bbca7732SBram Moolenaar     // Use attributes from match with highest priority among 'search_hl' and
4457bbca7732SBram Moolenaar     // the match list.
4458bbca7732SBram Moolenaar     cur = wp->w_match_head;
4459bbca7732SBram Moolenaar     shl_flag = WIN_IS_POPUP(wp);
4460bbca7732SBram Moolenaar     while (cur != NULL || shl_flag == FALSE)
4461bbca7732SBram Moolenaar     {
4462bbca7732SBram Moolenaar 	if (shl_flag == FALSE
4463bbca7732SBram Moolenaar 		&& ((cur != NULL
4464bbca7732SBram Moolenaar 			&& cur->priority > SEARCH_HL_PRIORITY)
4465bbca7732SBram Moolenaar 		    || cur == NULL))
4466bbca7732SBram Moolenaar 	{
4467bbca7732SBram Moolenaar 	    shl = search_hl;
4468bbca7732SBram Moolenaar 	    shl_flag = TRUE;
4469bbca7732SBram Moolenaar 	}
4470bbca7732SBram Moolenaar 	else
4471bbca7732SBram Moolenaar 	    shl = &cur->hl;
4472bbca7732SBram Moolenaar 	if (shl->attr_cur != 0)
4473bbca7732SBram Moolenaar 	    search_attr = shl->attr_cur;
4474bbca7732SBram Moolenaar 	if (shl != search_hl && cur != NULL)
4475bbca7732SBram Moolenaar 	    cur = cur->next;
4476bbca7732SBram Moolenaar     }
44771f164b19SBram Moolenaar     // Only highlight one character after the last column.
4478bbca7732SBram Moolenaar     if (*(*line + col) == NUL && (did_line_attr >= 1
4479bbca7732SBram Moolenaar 				       || (wp->w_p_list && lcs_eol_one == -1)))
4480bbca7732SBram Moolenaar 	search_attr = 0;
4481bbca7732SBram Moolenaar     return search_attr;
4482bbca7732SBram Moolenaar }
4483bbca7732SBram Moolenaar 
4484bbca7732SBram Moolenaar     int
4485bbca7732SBram Moolenaar get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol)
4486bbca7732SBram Moolenaar {
4487bbca7732SBram Moolenaar     long	prevcol = curcol;
4488bbca7732SBram Moolenaar     int		prevcol_hl_flag = FALSE;
4489bbca7732SBram Moolenaar     matchitem_T *cur;			// points to the match list
4490bbca7732SBram Moolenaar 
4491bbca7732SBram Moolenaar     // we're not really at that column when skipping some text
4492bbca7732SBram Moolenaar     if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
4493bbca7732SBram Moolenaar 	++prevcol;
4494bbca7732SBram Moolenaar 
4495bbca7732SBram Moolenaar     if (!search_hl->is_addpos && prevcol == (long)search_hl->startcol)
4496bbca7732SBram Moolenaar 	prevcol_hl_flag = TRUE;
4497bbca7732SBram Moolenaar     else
4498bbca7732SBram Moolenaar     {
4499bbca7732SBram Moolenaar 	cur = wp->w_match_head;
4500bbca7732SBram Moolenaar 	while (cur != NULL)
4501bbca7732SBram Moolenaar 	{
4502bbca7732SBram Moolenaar 	    if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
4503bbca7732SBram Moolenaar 	    {
4504bbca7732SBram Moolenaar 		prevcol_hl_flag = TRUE;
4505bbca7732SBram Moolenaar 		break;
4506bbca7732SBram Moolenaar 	    }
4507bbca7732SBram Moolenaar 	    cur = cur->next;
4508bbca7732SBram Moolenaar 	}
4509bbca7732SBram Moolenaar     }
4510bbca7732SBram Moolenaar     return prevcol_hl_flag;
4511bbca7732SBram Moolenaar }
4512bbca7732SBram Moolenaar 
4513bbca7732SBram Moolenaar /*
4514bbca7732SBram Moolenaar  * Get highlighting for the char after the text in "char_attr" from 'hlsearch'
4515bbca7732SBram Moolenaar  * or match highlighting.
4516bbca7732SBram Moolenaar  */
4517bbca7732SBram Moolenaar     void
4518bbca7732SBram Moolenaar get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr)
4519bbca7732SBram Moolenaar {
4520bbca7732SBram Moolenaar     matchitem_T *cur;			// points to the match list
4521bbca7732SBram Moolenaar     match_T	*shl;			// points to search_hl or a match
4522bbca7732SBram Moolenaar     int		shl_flag;		// flag to indicate whether search_hl
4523bbca7732SBram Moolenaar 					// has been processed or not
4524bbca7732SBram Moolenaar 
4525bbca7732SBram Moolenaar     cur = wp->w_match_head;
4526bbca7732SBram Moolenaar     shl_flag = WIN_IS_POPUP(wp);
4527bbca7732SBram Moolenaar     while (cur != NULL || shl_flag == FALSE)
4528bbca7732SBram Moolenaar     {
4529bbca7732SBram Moolenaar 	if (shl_flag == FALSE
4530bbca7732SBram Moolenaar 		&& ((cur != NULL
4531bbca7732SBram Moolenaar 			&& cur->priority > SEARCH_HL_PRIORITY)
4532bbca7732SBram Moolenaar 		    || cur == NULL))
4533bbca7732SBram Moolenaar 	{
4534bbca7732SBram Moolenaar 	    shl = search_hl;
4535bbca7732SBram Moolenaar 	    shl_flag = TRUE;
4536bbca7732SBram Moolenaar 	}
4537bbca7732SBram Moolenaar 	else
4538bbca7732SBram Moolenaar 	    shl = &cur->hl;
4539bbca7732SBram Moolenaar 	if (col - 1 == (long)shl->startcol
4540bbca7732SBram Moolenaar 		&& (shl == search_hl || !shl->is_addpos))
4541bbca7732SBram Moolenaar 	    *char_attr = shl->attr;
4542bbca7732SBram Moolenaar 	if (shl != search_hl && cur != NULL)
4543bbca7732SBram Moolenaar 	    cur = cur->next;
4544bbca7732SBram Moolenaar     }
4545bbca7732SBram Moolenaar }
4546bbca7732SBram Moolenaar 
4547bbca7732SBram Moolenaar #endif // FEAT_SEARCH_EXTRA
454829b7d7a9SBram Moolenaar 
4549c61a48d2SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
4550c61a48d2SBram Moolenaar # ifdef FEAT_SEARCH_EXTRA
455129b7d7a9SBram Moolenaar     static int
455229b7d7a9SBram Moolenaar matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
455329b7d7a9SBram Moolenaar {
455429b7d7a9SBram Moolenaar     dictitem_T *di;
455529b7d7a9SBram Moolenaar 
455629b7d7a9SBram Moolenaar     if (tv->v_type != VAR_DICT)
455729b7d7a9SBram Moolenaar     {
455829b7d7a9SBram Moolenaar 	emsg(_(e_dictreq));
455929b7d7a9SBram Moolenaar 	return FAIL;
456029b7d7a9SBram Moolenaar     }
456129b7d7a9SBram Moolenaar 
456229b7d7a9SBram Moolenaar     if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
456329b7d7a9SBram Moolenaar 	*conceal_char = dict_get_string(tv->vval.v_dict,
456429b7d7a9SBram Moolenaar 						   (char_u *)"conceal", FALSE);
456529b7d7a9SBram Moolenaar 
456629b7d7a9SBram Moolenaar     if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
456729b7d7a9SBram Moolenaar     {
456829b7d7a9SBram Moolenaar 	*win = find_win_by_nr_or_id(&di->di_tv);
456929b7d7a9SBram Moolenaar 	if (*win == NULL)
457029b7d7a9SBram Moolenaar 	{
457129b7d7a9SBram Moolenaar 	    emsg(_(e_invalwindow));
457229b7d7a9SBram Moolenaar 	    return FAIL;
457329b7d7a9SBram Moolenaar 	}
457429b7d7a9SBram Moolenaar     }
457529b7d7a9SBram Moolenaar 
457629b7d7a9SBram Moolenaar     return OK;
457729b7d7a9SBram Moolenaar }
457829b7d7a9SBram Moolenaar #endif
457929b7d7a9SBram Moolenaar 
458029b7d7a9SBram Moolenaar /*
45817dfb016dSBram Moolenaar  * "clearmatches()" function
45827dfb016dSBram Moolenaar  */
45837dfb016dSBram Moolenaar     void
45847dfb016dSBram Moolenaar f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
45857dfb016dSBram Moolenaar {
45867dfb016dSBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
45877dfb016dSBram Moolenaar     win_T   *win = get_optional_window(argvars, 0);
45887dfb016dSBram Moolenaar 
45897dfb016dSBram Moolenaar     if (win != NULL)
45907dfb016dSBram Moolenaar 	clear_matches(win);
45917dfb016dSBram Moolenaar #endif
45927dfb016dSBram Moolenaar }
45937dfb016dSBram Moolenaar 
45947dfb016dSBram Moolenaar /*
459529b7d7a9SBram Moolenaar  * "getmatches()" function
459629b7d7a9SBram Moolenaar  */
459729b7d7a9SBram Moolenaar     void
459829b7d7a9SBram Moolenaar f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
459929b7d7a9SBram Moolenaar {
460029b7d7a9SBram Moolenaar # ifdef FEAT_SEARCH_EXTRA
460129b7d7a9SBram Moolenaar     dict_T	*dict;
460229b7d7a9SBram Moolenaar     matchitem_T	*cur;
460329b7d7a9SBram Moolenaar     int		i;
460429b7d7a9SBram Moolenaar     win_T	*win = get_optional_window(argvars, 0);
460529b7d7a9SBram Moolenaar 
460629b7d7a9SBram Moolenaar     if (rettv_list_alloc(rettv) == FAIL || win == NULL)
460729b7d7a9SBram Moolenaar 	return;
460829b7d7a9SBram Moolenaar 
460929b7d7a9SBram Moolenaar     cur = win->w_match_head;
461029b7d7a9SBram Moolenaar     while (cur != NULL)
461129b7d7a9SBram Moolenaar     {
461229b7d7a9SBram Moolenaar 	dict = dict_alloc();
461329b7d7a9SBram Moolenaar 	if (dict == NULL)
461429b7d7a9SBram Moolenaar 	    return;
461529b7d7a9SBram Moolenaar 	if (cur->match.regprog == NULL)
461629b7d7a9SBram Moolenaar 	{
46171f164b19SBram Moolenaar 	    // match added with matchaddpos()
461829b7d7a9SBram Moolenaar 	    for (i = 0; i < MAXPOSMATCH; ++i)
461929b7d7a9SBram Moolenaar 	    {
462029b7d7a9SBram Moolenaar 		llpos_T	*llpos;
462129b7d7a9SBram Moolenaar 		char	buf[30];  // use 30 to avoid compiler warning
462229b7d7a9SBram Moolenaar 		list_T	*l;
462329b7d7a9SBram Moolenaar 
462429b7d7a9SBram Moolenaar 		llpos = &cur->pos.pos[i];
462529b7d7a9SBram Moolenaar 		if (llpos->lnum == 0)
462629b7d7a9SBram Moolenaar 		    break;
462729b7d7a9SBram Moolenaar 		l = list_alloc();
462829b7d7a9SBram Moolenaar 		if (l == NULL)
462929b7d7a9SBram Moolenaar 		    break;
463029b7d7a9SBram Moolenaar 		list_append_number(l, (varnumber_T)llpos->lnum);
463129b7d7a9SBram Moolenaar 		if (llpos->col > 0)
463229b7d7a9SBram Moolenaar 		{
463329b7d7a9SBram Moolenaar 		    list_append_number(l, (varnumber_T)llpos->col);
463429b7d7a9SBram Moolenaar 		    list_append_number(l, (varnumber_T)llpos->len);
463529b7d7a9SBram Moolenaar 		}
463629b7d7a9SBram Moolenaar 		sprintf(buf, "pos%d", i + 1);
463729b7d7a9SBram Moolenaar 		dict_add_list(dict, buf, l);
463829b7d7a9SBram Moolenaar 	    }
463929b7d7a9SBram Moolenaar 	}
464029b7d7a9SBram Moolenaar 	else
464129b7d7a9SBram Moolenaar 	{
464229b7d7a9SBram Moolenaar 	    dict_add_string(dict, "pattern", cur->pattern);
464329b7d7a9SBram Moolenaar 	}
464429b7d7a9SBram Moolenaar 	dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
464529b7d7a9SBram Moolenaar 	dict_add_number(dict, "priority", (long)cur->priority);
464629b7d7a9SBram Moolenaar 	dict_add_number(dict, "id", (long)cur->id);
464729b7d7a9SBram Moolenaar #  if defined(FEAT_CONCEAL)
464829b7d7a9SBram Moolenaar 	if (cur->conceal_char)
464929b7d7a9SBram Moolenaar 	{
465029b7d7a9SBram Moolenaar 	    char_u buf[MB_MAXBYTES + 1];
465129b7d7a9SBram Moolenaar 
465229b7d7a9SBram Moolenaar 	    buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
465329b7d7a9SBram Moolenaar 	    dict_add_string(dict, "conceal", (char_u *)&buf);
465429b7d7a9SBram Moolenaar 	}
465529b7d7a9SBram Moolenaar #  endif
465629b7d7a9SBram Moolenaar 	list_append_dict(rettv->vval.v_list, dict);
465729b7d7a9SBram Moolenaar 	cur = cur->next;
465829b7d7a9SBram Moolenaar     }
465929b7d7a9SBram Moolenaar # endif
466029b7d7a9SBram Moolenaar }
466129b7d7a9SBram Moolenaar 
466229b7d7a9SBram Moolenaar /*
46637dfb016dSBram Moolenaar  * "setmatches()" function
46647dfb016dSBram Moolenaar  */
46657dfb016dSBram Moolenaar     void
46667dfb016dSBram Moolenaar f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
46677dfb016dSBram Moolenaar {
46687dfb016dSBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
46697dfb016dSBram Moolenaar     list_T	*l;
46707dfb016dSBram Moolenaar     listitem_T	*li;
46717dfb016dSBram Moolenaar     dict_T	*d;
46727dfb016dSBram Moolenaar     list_T	*s = NULL;
46737dfb016dSBram Moolenaar     win_T	*win = get_optional_window(argvars, 1);
46747dfb016dSBram Moolenaar 
46757dfb016dSBram Moolenaar     rettv->vval.v_number = -1;
46767dfb016dSBram Moolenaar     if (argvars[0].v_type != VAR_LIST)
46777dfb016dSBram Moolenaar     {
46787dfb016dSBram Moolenaar 	emsg(_(e_listreq));
46797dfb016dSBram Moolenaar 	return;
46807dfb016dSBram Moolenaar     }
46817dfb016dSBram Moolenaar     if (win == NULL)
46827dfb016dSBram Moolenaar 	return;
46837dfb016dSBram Moolenaar 
46847dfb016dSBram Moolenaar     if ((l = argvars[0].vval.v_list) != NULL)
46857dfb016dSBram Moolenaar     {
46861f164b19SBram Moolenaar 	// To some extent make sure that we are dealing with a list from
46871f164b19SBram Moolenaar 	// "getmatches()".
46887dfb016dSBram Moolenaar 	li = l->lv_first;
46897dfb016dSBram Moolenaar 	while (li != NULL)
46907dfb016dSBram Moolenaar 	{
46917dfb016dSBram Moolenaar 	    if (li->li_tv.v_type != VAR_DICT
46927dfb016dSBram Moolenaar 		    || (d = li->li_tv.vval.v_dict) == NULL)
46937dfb016dSBram Moolenaar 	    {
46947dfb016dSBram Moolenaar 		emsg(_(e_invarg));
46957dfb016dSBram Moolenaar 		return;
46967dfb016dSBram Moolenaar 	    }
46977dfb016dSBram Moolenaar 	    if (!(dict_find(d, (char_u *)"group", -1) != NULL
46987dfb016dSBram Moolenaar 			&& (dict_find(d, (char_u *)"pattern", -1) != NULL
46997dfb016dSBram Moolenaar 			    || dict_find(d, (char_u *)"pos1", -1) != NULL)
47007dfb016dSBram Moolenaar 			&& dict_find(d, (char_u *)"priority", -1) != NULL
47017dfb016dSBram Moolenaar 			&& dict_find(d, (char_u *)"id", -1) != NULL))
47027dfb016dSBram Moolenaar 	    {
47037dfb016dSBram Moolenaar 		emsg(_(e_invarg));
47047dfb016dSBram Moolenaar 		return;
47057dfb016dSBram Moolenaar 	    }
47067dfb016dSBram Moolenaar 	    li = li->li_next;
47077dfb016dSBram Moolenaar 	}
47087dfb016dSBram Moolenaar 
47097dfb016dSBram Moolenaar 	clear_matches(win);
47107dfb016dSBram Moolenaar 	li = l->lv_first;
47117dfb016dSBram Moolenaar 	while (li != NULL)
47127dfb016dSBram Moolenaar 	{
47137dfb016dSBram Moolenaar 	    int		i = 0;
47147dfb016dSBram Moolenaar 	    char	buf[30];  // use 30 to avoid compiler warning
47157dfb016dSBram Moolenaar 	    dictitem_T  *di;
47167dfb016dSBram Moolenaar 	    char_u	*group;
47177dfb016dSBram Moolenaar 	    int		priority;
47187dfb016dSBram Moolenaar 	    int		id;
47197dfb016dSBram Moolenaar 	    char_u	*conceal;
47207dfb016dSBram Moolenaar 
47217dfb016dSBram Moolenaar 	    d = li->li_tv.vval.v_dict;
47227dfb016dSBram Moolenaar 	    if (dict_find(d, (char_u *)"pattern", -1) == NULL)
47237dfb016dSBram Moolenaar 	    {
47247dfb016dSBram Moolenaar 		if (s == NULL)
47257dfb016dSBram Moolenaar 		{
47267dfb016dSBram Moolenaar 		    s = list_alloc();
47277dfb016dSBram Moolenaar 		    if (s == NULL)
47287dfb016dSBram Moolenaar 			return;
47297dfb016dSBram Moolenaar 		}
47307dfb016dSBram Moolenaar 
47311f164b19SBram Moolenaar 		// match from matchaddpos()
47327dfb016dSBram Moolenaar 		for (i = 1; i < 9; i++)
47337dfb016dSBram Moolenaar 		{
47347dfb016dSBram Moolenaar 		    sprintf((char *)buf, (char *)"pos%d", i);
47357dfb016dSBram Moolenaar 		    if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
47367dfb016dSBram Moolenaar 		    {
47377dfb016dSBram Moolenaar 			if (di->di_tv.v_type != VAR_LIST)
47387dfb016dSBram Moolenaar 			    return;
47397dfb016dSBram Moolenaar 
47407dfb016dSBram Moolenaar 			list_append_tv(s, &di->di_tv);
47417dfb016dSBram Moolenaar 			s->lv_refcount++;
47427dfb016dSBram Moolenaar 		    }
47437dfb016dSBram Moolenaar 		    else
47447dfb016dSBram Moolenaar 			break;
47457dfb016dSBram Moolenaar 		}
47467dfb016dSBram Moolenaar 	    }
47477dfb016dSBram Moolenaar 
47487dfb016dSBram Moolenaar 	    group = dict_get_string(d, (char_u *)"group", TRUE);
47497dfb016dSBram Moolenaar 	    priority = (int)dict_get_number(d, (char_u *)"priority");
47507dfb016dSBram Moolenaar 	    id = (int)dict_get_number(d, (char_u *)"id");
47517dfb016dSBram Moolenaar 	    conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
47527dfb016dSBram Moolenaar 			      ? dict_get_string(d, (char_u *)"conceal", TRUE)
47537dfb016dSBram Moolenaar 			      : NULL;
47547dfb016dSBram Moolenaar 	    if (i == 0)
47557dfb016dSBram Moolenaar 	    {
47567dfb016dSBram Moolenaar 		match_add(win, group,
47577dfb016dSBram Moolenaar 		    dict_get_string(d, (char_u *)"pattern", FALSE),
47587dfb016dSBram Moolenaar 		    priority, id, NULL, conceal);
47597dfb016dSBram Moolenaar 	    }
47607dfb016dSBram Moolenaar 	    else
47617dfb016dSBram Moolenaar 	    {
47627dfb016dSBram Moolenaar 		match_add(win, group, NULL, priority, id, s, conceal);
47637dfb016dSBram Moolenaar 		list_unref(s);
47647dfb016dSBram Moolenaar 		s = NULL;
47657dfb016dSBram Moolenaar 	    }
47667dfb016dSBram Moolenaar 	    vim_free(group);
47677dfb016dSBram Moolenaar 	    vim_free(conceal);
47687dfb016dSBram Moolenaar 
47697dfb016dSBram Moolenaar 	    li = li->li_next;
47707dfb016dSBram Moolenaar 	}
47717dfb016dSBram Moolenaar 	rettv->vval.v_number = 0;
47727dfb016dSBram Moolenaar     }
47737dfb016dSBram Moolenaar #endif
47747dfb016dSBram Moolenaar }
47757dfb016dSBram Moolenaar 
47767dfb016dSBram Moolenaar /*
477729b7d7a9SBram Moolenaar  * "matchadd()" function
477829b7d7a9SBram Moolenaar  */
477929b7d7a9SBram Moolenaar     void
478029b7d7a9SBram Moolenaar f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
478129b7d7a9SBram Moolenaar {
478229b7d7a9SBram Moolenaar # ifdef FEAT_SEARCH_EXTRA
478329b7d7a9SBram Moolenaar     char_u	buf[NUMBUFLEN];
47841f164b19SBram Moolenaar     char_u	*grp = tv_get_string_buf_chk(&argvars[0], buf);	// group
47851f164b19SBram Moolenaar     char_u	*pat = tv_get_string_buf_chk(&argvars[1], buf);	// pattern
47861f164b19SBram Moolenaar     int		prio = 10;	// default priority
478729b7d7a9SBram Moolenaar     int		id = -1;
478829b7d7a9SBram Moolenaar     int		error = FALSE;
478929b7d7a9SBram Moolenaar     char_u	*conceal_char = NULL;
479029b7d7a9SBram Moolenaar     win_T	*win = curwin;
479129b7d7a9SBram Moolenaar 
479229b7d7a9SBram Moolenaar     rettv->vval.v_number = -1;
479329b7d7a9SBram Moolenaar 
479429b7d7a9SBram Moolenaar     if (grp == NULL || pat == NULL)
479529b7d7a9SBram Moolenaar 	return;
479629b7d7a9SBram Moolenaar     if (argvars[2].v_type != VAR_UNKNOWN)
479729b7d7a9SBram Moolenaar     {
479829b7d7a9SBram Moolenaar 	prio = (int)tv_get_number_chk(&argvars[2], &error);
479929b7d7a9SBram Moolenaar 	if (argvars[3].v_type != VAR_UNKNOWN)
480029b7d7a9SBram Moolenaar 	{
480129b7d7a9SBram Moolenaar 	    id = (int)tv_get_number_chk(&argvars[3], &error);
480229b7d7a9SBram Moolenaar 	    if (argvars[4].v_type != VAR_UNKNOWN
480329b7d7a9SBram Moolenaar 		&& matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
480429b7d7a9SBram Moolenaar 		return;
480529b7d7a9SBram Moolenaar 	}
480629b7d7a9SBram Moolenaar     }
480729b7d7a9SBram Moolenaar     if (error == TRUE)
480829b7d7a9SBram Moolenaar 	return;
480929b7d7a9SBram Moolenaar     if (id >= 1 && id <= 3)
481029b7d7a9SBram Moolenaar     {
481129b7d7a9SBram Moolenaar 	semsg(_("E798: ID is reserved for \":match\": %d"), id);
481229b7d7a9SBram Moolenaar 	return;
481329b7d7a9SBram Moolenaar     }
481429b7d7a9SBram Moolenaar 
481529b7d7a9SBram Moolenaar     rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
481629b7d7a9SBram Moolenaar 								conceal_char);
481729b7d7a9SBram Moolenaar # endif
481829b7d7a9SBram Moolenaar }
481929b7d7a9SBram Moolenaar 
482029b7d7a9SBram Moolenaar /*
482129b7d7a9SBram Moolenaar  * "matchaddpos()" function
482229b7d7a9SBram Moolenaar  */
482329b7d7a9SBram Moolenaar     void
482429b7d7a9SBram Moolenaar f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
482529b7d7a9SBram Moolenaar {
482629b7d7a9SBram Moolenaar # ifdef FEAT_SEARCH_EXTRA
482729b7d7a9SBram Moolenaar     char_u	buf[NUMBUFLEN];
482829b7d7a9SBram Moolenaar     char_u	*group;
482929b7d7a9SBram Moolenaar     int		prio = 10;
483029b7d7a9SBram Moolenaar     int		id = -1;
483129b7d7a9SBram Moolenaar     int		error = FALSE;
483229b7d7a9SBram Moolenaar     list_T	*l;
483329b7d7a9SBram Moolenaar     char_u	*conceal_char = NULL;
483429b7d7a9SBram Moolenaar     win_T	*win = curwin;
483529b7d7a9SBram Moolenaar 
483629b7d7a9SBram Moolenaar     rettv->vval.v_number = -1;
483729b7d7a9SBram Moolenaar 
483829b7d7a9SBram Moolenaar     group = tv_get_string_buf_chk(&argvars[0], buf);
483929b7d7a9SBram Moolenaar     if (group == NULL)
484029b7d7a9SBram Moolenaar 	return;
484129b7d7a9SBram Moolenaar 
484229b7d7a9SBram Moolenaar     if (argvars[1].v_type != VAR_LIST)
484329b7d7a9SBram Moolenaar     {
484429b7d7a9SBram Moolenaar 	semsg(_(e_listarg), "matchaddpos()");
484529b7d7a9SBram Moolenaar 	return;
484629b7d7a9SBram Moolenaar     }
484729b7d7a9SBram Moolenaar     l = argvars[1].vval.v_list;
484829b7d7a9SBram Moolenaar     if (l == NULL)
484929b7d7a9SBram Moolenaar 	return;
485029b7d7a9SBram Moolenaar 
485129b7d7a9SBram Moolenaar     if (argvars[2].v_type != VAR_UNKNOWN)
485229b7d7a9SBram Moolenaar     {
485329b7d7a9SBram Moolenaar 	prio = (int)tv_get_number_chk(&argvars[2], &error);
485429b7d7a9SBram Moolenaar 	if (argvars[3].v_type != VAR_UNKNOWN)
485529b7d7a9SBram Moolenaar 	{
485629b7d7a9SBram Moolenaar 	    id = (int)tv_get_number_chk(&argvars[3], &error);
485729b7d7a9SBram Moolenaar 
485829b7d7a9SBram Moolenaar 	    if (argvars[4].v_type != VAR_UNKNOWN
485929b7d7a9SBram Moolenaar 		&& matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
486029b7d7a9SBram Moolenaar 		return;
486129b7d7a9SBram Moolenaar 	}
486229b7d7a9SBram Moolenaar     }
486329b7d7a9SBram Moolenaar     if (error == TRUE)
486429b7d7a9SBram Moolenaar 	return;
486529b7d7a9SBram Moolenaar 
48661f164b19SBram Moolenaar     // id == 3 is ok because matchaddpos() is supposed to substitute :3match
486729b7d7a9SBram Moolenaar     if (id == 1 || id == 2)
486829b7d7a9SBram Moolenaar     {
486929b7d7a9SBram Moolenaar 	semsg(_("E798: ID is reserved for \":match\": %d"), id);
487029b7d7a9SBram Moolenaar 	return;
487129b7d7a9SBram Moolenaar     }
487229b7d7a9SBram Moolenaar 
487329b7d7a9SBram Moolenaar     rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
487429b7d7a9SBram Moolenaar 								conceal_char);
487529b7d7a9SBram Moolenaar # endif
487629b7d7a9SBram Moolenaar }
487729b7d7a9SBram Moolenaar 
487829b7d7a9SBram Moolenaar /*
487929b7d7a9SBram Moolenaar  * "matcharg()" function
488029b7d7a9SBram Moolenaar  */
488129b7d7a9SBram Moolenaar     void
488229b7d7a9SBram Moolenaar f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
488329b7d7a9SBram Moolenaar {
488429b7d7a9SBram Moolenaar     if (rettv_list_alloc(rettv) == OK)
488529b7d7a9SBram Moolenaar     {
488629b7d7a9SBram Moolenaar # ifdef FEAT_SEARCH_EXTRA
488729b7d7a9SBram Moolenaar 	int	    id = (int)tv_get_number(&argvars[0]);
488829b7d7a9SBram Moolenaar 	matchitem_T *m;
488929b7d7a9SBram Moolenaar 
489029b7d7a9SBram Moolenaar 	if (id >= 1 && id <= 3)
489129b7d7a9SBram Moolenaar 	{
489229b7d7a9SBram Moolenaar 	    if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
489329b7d7a9SBram Moolenaar 	    {
489429b7d7a9SBram Moolenaar 		list_append_string(rettv->vval.v_list,
489529b7d7a9SBram Moolenaar 						syn_id2name(m->hlg_id), -1);
489629b7d7a9SBram Moolenaar 		list_append_string(rettv->vval.v_list, m->pattern, -1);
489729b7d7a9SBram Moolenaar 	    }
489829b7d7a9SBram Moolenaar 	    else
489929b7d7a9SBram Moolenaar 	    {
490029b7d7a9SBram Moolenaar 		list_append_string(rettv->vval.v_list, NULL, -1);
490129b7d7a9SBram Moolenaar 		list_append_string(rettv->vval.v_list, NULL, -1);
490229b7d7a9SBram Moolenaar 	    }
490329b7d7a9SBram Moolenaar 	}
490429b7d7a9SBram Moolenaar # endif
490529b7d7a9SBram Moolenaar     }
490629b7d7a9SBram Moolenaar }
490729b7d7a9SBram Moolenaar 
490829b7d7a9SBram Moolenaar /*
490929b7d7a9SBram Moolenaar  * "matchdelete()" function
491029b7d7a9SBram Moolenaar  */
491129b7d7a9SBram Moolenaar     void
491229b7d7a9SBram Moolenaar f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
491329b7d7a9SBram Moolenaar {
491429b7d7a9SBram Moolenaar # ifdef FEAT_SEARCH_EXTRA
491529b7d7a9SBram Moolenaar     win_T   *win = get_optional_window(argvars, 1);
491629b7d7a9SBram Moolenaar 
491729b7d7a9SBram Moolenaar     if (win == NULL)
491829b7d7a9SBram Moolenaar 	rettv->vval.v_number = -1;
491929b7d7a9SBram Moolenaar     else
492029b7d7a9SBram Moolenaar 	rettv->vval.v_number = match_delete(win,
492129b7d7a9SBram Moolenaar 				       (int)tv_get_number(&argvars[0]), TRUE);
492229b7d7a9SBram Moolenaar # endif
492329b7d7a9SBram Moolenaar }
4924c61a48d2SBram Moolenaar #endif
49257dfb016dSBram Moolenaar 
49267dfb016dSBram Moolenaar #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
49277dfb016dSBram Moolenaar /*
49287dfb016dSBram Moolenaar  * ":[N]match {group} {pattern}"
49297dfb016dSBram Moolenaar  * Sets nextcmd to the start of the next command, if any.  Also called when
49307dfb016dSBram Moolenaar  * skipping commands to find the next command.
49317dfb016dSBram Moolenaar  */
49327dfb016dSBram Moolenaar     void
49337dfb016dSBram Moolenaar ex_match(exarg_T *eap)
49347dfb016dSBram Moolenaar {
49357dfb016dSBram Moolenaar     char_u	*p;
49367dfb016dSBram Moolenaar     char_u	*g = NULL;
49377dfb016dSBram Moolenaar     char_u	*end;
49387dfb016dSBram Moolenaar     int		c;
49397dfb016dSBram Moolenaar     int		id;
49407dfb016dSBram Moolenaar 
49417dfb016dSBram Moolenaar     if (eap->line2 <= 3)
49427dfb016dSBram Moolenaar 	id = eap->line2;
49437dfb016dSBram Moolenaar     else
49447dfb016dSBram Moolenaar     {
49457dfb016dSBram Moolenaar 	emsg(_(e_invcmd));
49467dfb016dSBram Moolenaar 	return;
49477dfb016dSBram Moolenaar     }
49487dfb016dSBram Moolenaar 
49491f164b19SBram Moolenaar     // First clear any old pattern.
49507dfb016dSBram Moolenaar     if (!eap->skip)
49517dfb016dSBram Moolenaar 	match_delete(curwin, id, FALSE);
49527dfb016dSBram Moolenaar 
49537dfb016dSBram Moolenaar     if (ends_excmd(*eap->arg))
49547dfb016dSBram Moolenaar 	end = eap->arg;
49557dfb016dSBram Moolenaar     else if ((STRNICMP(eap->arg, "none", 4) == 0
49567dfb016dSBram Moolenaar 		&& (VIM_ISWHITE(eap->arg[4]) || ends_excmd(eap->arg[4]))))
49577dfb016dSBram Moolenaar 	end = eap->arg + 4;
49587dfb016dSBram Moolenaar     else
49597dfb016dSBram Moolenaar     {
49607dfb016dSBram Moolenaar 	p = skiptowhite(eap->arg);
49617dfb016dSBram Moolenaar 	if (!eap->skip)
49627dfb016dSBram Moolenaar 	    g = vim_strnsave(eap->arg, (int)(p - eap->arg));
49637dfb016dSBram Moolenaar 	p = skipwhite(p);
49647dfb016dSBram Moolenaar 	if (*p == NUL)
49657dfb016dSBram Moolenaar 	{
49661f164b19SBram Moolenaar 	    // There must be two arguments.
49677dfb016dSBram Moolenaar 	    vim_free(g);
49687dfb016dSBram Moolenaar 	    semsg(_(e_invarg2), eap->arg);
49697dfb016dSBram Moolenaar 	    return;
49707dfb016dSBram Moolenaar 	}
49717dfb016dSBram Moolenaar 	end = skip_regexp(p + 1, *p, TRUE, NULL);
49727dfb016dSBram Moolenaar 	if (!eap->skip)
49737dfb016dSBram Moolenaar 	{
49747dfb016dSBram Moolenaar 	    if (*end != NUL && !ends_excmd(*skipwhite(end + 1)))
49757dfb016dSBram Moolenaar 	    {
49767dfb016dSBram Moolenaar 		vim_free(g);
49777dfb016dSBram Moolenaar 		eap->errmsg = e_trailing;
49787dfb016dSBram Moolenaar 		return;
49797dfb016dSBram Moolenaar 	    }
49807dfb016dSBram Moolenaar 	    if (*end != *p)
49817dfb016dSBram Moolenaar 	    {
49827dfb016dSBram Moolenaar 		vim_free(g);
49837dfb016dSBram Moolenaar 		semsg(_(e_invarg2), p);
49847dfb016dSBram Moolenaar 		return;
49857dfb016dSBram Moolenaar 	    }
49867dfb016dSBram Moolenaar 
49877dfb016dSBram Moolenaar 	    c = *end;
49887dfb016dSBram Moolenaar 	    *end = NUL;
49897dfb016dSBram Moolenaar 	    match_add(curwin, g, p + 1, 10, id, NULL, NULL);
49907dfb016dSBram Moolenaar 	    vim_free(g);
49917dfb016dSBram Moolenaar 	    *end = c;
49927dfb016dSBram Moolenaar 	}
49937dfb016dSBram Moolenaar     }
49947dfb016dSBram Moolenaar     eap->nextcmd = find_nextcmd(end);
49957dfb016dSBram Moolenaar }
49967dfb016dSBram Moolenaar #endif
4997