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