patch 9.2.0093: Not possible to have window-local highlighting groups
Commit:
https://github.com/vim/vim/commit/98174caabb5dc5a5aeda2fb328c922fe9a670be4
Author: Foxe Chen <
chen...@gmail.com>
Date: Mon Mar 2 19:36:07 2026 +0000
patch 9.2.0093: Not possible to have window-local highlighting groups
Problem: Not possible to have window-local highlighting groups
(Hima)
Solution: Port Neovims 'winhighlight' option to Vim (Foxe Chen).
fixes: #3576
closes: #19493
Signed-off-by: Foxe Chen <
chen...@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/ci/hlgroups.ignore b/ci/hlgroups.ignore
index a046eb127..681b12087 100644
--- a/ci/hlgroups.ignore
+++ b/ci/hlgroups.ignore
@@ -67,3 +67,4 @@ Visual
VisualNOS
WarningMsg
WildMenu
+WinColor
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 6986fde86..327494d68 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4810,6 +4810,9 @@ A jump table for the options with a short description can be found at |Q_op|.
|hl-PmenuBorder| j popup menu border characters
|hl-PmenuShadow| H popup menu shadow
|hl-PreInsert| I text inserted when "preinsert" is in 'completeopt'
+ |hl-Normal| ( Window color (supersedes 'wincolor' option)
+
+ Note that the "(" occasion is not set by default.
The display modes are:
r reverse (termcap entry "mr" and "me")
@@ -10246,8 +10249,19 @@ A jump table for the options with a short description can be found at |Q_op|.
*'wincolor'* *'wcr'*
'wincolor' 'wcr' string (default empty)
local to window
+ DEPRECATED: Use 'winhighlight' if possible, this option uses
+ 'winhighlight' internally by setting it to: >vim
+ set winhighlight=!(:HighlightGroup
+< If this option is set and 'winhighlight' is changed, then it will not
+ update the option value. For example, if 'wincolor' is set to "A" and
+ then 'winhighlight' is to an empty value, then 'wincolor' will still
+ remain as "A". Additionally, the existing value in 'winhighlight' will
+ be discarded when this option is set.
+
Highlight group name to use for this window instead of the Normal
- color |hl-Normal|.
+ color |hl-Normal|. For other |highlight-groups|, see 'winhighlight'.
+ Note that it is not recommended to set this and 'winhighlight' at the
+ same time.
*'window'* *'wi'*
'window' 'wi' number (default screen height - 1)
@@ -10306,6 +10320,35 @@ A jump table for the options with a short description can be found at |Q_op|.
'winheight' applies to the current window. Use 'winminheight' to set
the minimal height for other windows.
+ *'winhighlight'* *'whl'*
+'winhighlight' 'whl' string (default empty)
+ local to window
+ Window-local highlight group mappings. Comma-delimited list of
+ highlight |group-name| pairs "{hl-from}:{hl-to},..." where each
+ {hl-from} is a |highlight-groups| item to be overridden by {hl-to}
+ group in the window. If {hl-from} is "Normal", then it will always
+ map to the "(" (window color) value in 'highlight'.
+
+ If a highlight group name starts with "!", then it is assumed to map
+ to a value in 'highlight'. For example, this will override the
+ visual mode setting: >vim
+ set winhighlight=!v:SomeHighlightGroup
+< This will map the occasion "v" to occasion "l" >vim
+ set winhighlight=!v:!l
+<
+ Highlights of vertical separators are determined by the window to the
+ left of the separator. The 'tabline' highlight of a tabpage is
+ decided by the last-focused window of the tabpage. Highlights of
+ the popupmenu are determined by the current window. Highlights in the
+ message area cannot be overridden.
+
+ When handling highlight group links, if a highlight group (which may
+ be a link as well) is overridden by 'winhighlight', then all highlight
+ groups that link to it will be affected. For example, if highlight
+ group C links to B which links to A, then >vim
+ set winhighlight=B:SomeHighlightGroup
+< will make SomeHighlightGroup override groups B and C, but not A.
+
*'winminheight'* *'wmh'*
'winminheight' 'wmh' number (default 1)
global
diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt
index 021410eb2..e968a2107 100644
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -1,4 +1,4 @@
-*popup.txt* For Vim version 9.2. Last change: 2026 Feb 18
+*popup.txt* For Vim version 9.2. Last change: 2026 Mar 02
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -773,6 +773,8 @@ The second argument of |popup_create()| is a dictionary with options:
the popup window.
highlight Highlight group name to use for the text, stored in
the 'wincolor' option.
+ highlights Highlight group overrides, stored in the
+ 'winhighlight' option (same format).
opacity Opacity of the popup, a value between 0 and 100:
0 is fully transparent (background text fully visible)
100 is fully opaque (default, no transparency)
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 2d4cf57e7..e7b2068b0 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -1,4 +1,4 @@
-*quickref.txt* For Vim version 9.2. Last change: 2026 Mar 01
+*quickref.txt* For Vim version 9.2. Last change: 2026 Mar 02
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1017,6 +1017,7 @@ Short explanation of each option: *option-list*
'wildoptions' 'wop' specifies how command line completion is done
'winaltkeys' 'wak' when the windows system handles ALT keys
'wincolor' 'wcr' window-local highlighting
+'winhighlight' 'whl' window-local highlighting mappings
'window' 'wi' nr of lines to scroll for CTRL-F and CTRL-B
'winfixbuf' 'wfb' keep window focused on a single buffer
'winfixheight' 'wfh' keep window height when opening/closing windows
diff --git a/runtime/doc/tags b/runtime/doc/tags
index e4478f0d7..a881c0acf 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -1335,6 +1335,7 @@ $quote eval.txt /*$quote*
'wfw' options.txt /*'wfw'*
'wh' options.txt /*'wh'*
'whichwrap' options.txt /*'whichwrap'*
+'whl' options.txt /*'whl'*
'wi' options.txt /*'wi'*
'wic' options.txt /*'wic'*
'wig' options.txt /*'wig'*
@@ -1353,6 +1354,7 @@ $quote eval.txt /*$quote*
'winfixheight' options.txt /*'winfixheight'*
'winfixwidth' options.txt /*'winfixwidth'*
'winheight' options.txt /*'winheight'*
+'winhighlight' options.txt /*'winhighlight'*
'winminheight' options.txt /*'winminheight'*
'winminwidth' options.txt /*'winminwidth'*
'winptydll' options.txt /*'winptydll'*
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 85a6c8032..120c1960d 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.2. Last change: 2026 Mar 01
+*version9.txt* For Vim version 9.2. Last change: 2026 Mar 02
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52613,6 +52613,7 @@ Options: ~
'statuslineopt' Extra options for the 'statusline', e.g. use the
"maxheight" suboption to use several lines.
+'winhighlight' Window-local highlight group mappings.
==============================================================================
PATCHES *patches-9.3* *bug-fixes-9.3*
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 28d91abc5..705195d0e 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: The Vim Project <
https://github.com/vim/vim>
-" Last Change: 2026 Mar 01
+" Last Change: 2026 Mar 02
" Former Maintainer: Bram Moolenaar <
Br...@vim.org>
" If there already is an option window, jump to that one.
@@ -445,6 +445,9 @@ call <SID>BinOptionG("hls", &hls)
call <SID>AddOption("wincolor", gettext("highlight group to use for the window"))
call append("$", " " .. s:local_to_window)
call <SID>OptionL("wcr")
+call <SID>AddOption("winhighlight", gettext("highlight group mappings for the window"))
+call append("$", " " .. s:local_to_window)
+call <SID>OptionL("whl")
if has("termguicolors")
call <SID>AddOption("termguicolors", gettext("use GUI colors for the terminal"))
call <SID>BinOptionG("tgc", &tgc)
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 4c96b6e7a..a81f82bd5 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -2,7 +2,7 @@
" Language: Vim script
" Maintainer: Hirohito Higashi <h.east.727 ATMARK
gmail.com>
" Doug Kearns <
dougk...@gmail.com>
-" Last Change: 2026 Mar 01
+" Last Change: 2026 Mar 02
" Former Maintainer: Charles E. Campbell
" DO NOT CHANGE DIRECTLY.
@@ -72,7 +72,7 @@ syn keyword vimOption contained mmd maxmapdepth mm maxmem mmp maxmempattern mmt
syn keyword vimOption contained popt printoptions prompt pb pumborder ph pumheight pmw pummaxwidth pw pumwidth pythondll pythonhome pythonthreedll pythonthreehome pyx pyxversion qftf quickfixtextfunc qe quoteescape ro readonly rdt redrawtime re regexpengine rnu relativenumber remap rop renderoptions report rs restorescreen ri revins rl rightleft rlc rightleftcmd rubydll ru ruler ruf rulerformat rtp runtimepath scr scroll scb scrollbind scf scrollfocus sj scrolljump so scrolloff sbo scrollopt sect sections secure sel selection slm selectmode ssop sessionoptions sh shell shcf shellcmdflag sp shellpipe shq shellquote srr shellredir ssl shellslash stmp shelltemp st shelltype sxe shellxescape sxq shellxquote sr shiftround sw shiftwidth shm shortmess sn shortname sbr showbreak skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained sc showcmd sloc showcmdloc sft showfulltag sm showmatch smd showmode stal showtabline stpl showtabpanel ss sidescroll siso sidescrolloff scl signcolumn scs smartcase si smartindent sta smarttab sms smoothscroll sts softtabstop spell spc spellcapcheck spf spellfile spl spelllang spo spelloptions sps spellsuggest sb splitbelow spk splitkeep spr splitright sol startofline stl statusline stlo statuslineopt su suffixes sua suffixesadd swf swapfile sws swapsync swb switchbuf smc synmaxcol syn syntax tcl tabclose tal tabline tpm tabpagemax tpl tabpanel tplo tabpanelopt ts tabstop tbs tagbsearch tc tagcase tfu tagfunc tl taglength tr tagrelative tag tags tgst tagstack tcldll term tbidi termbidi tenc termencoding tgc termguicolors twk termwinkey skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained twsl termwinscroll tws termwinsize twt termwintype terse ta textauto tx textmode tw textwidth tsr thesaurus tsrfu thesaurusfunc top tildeop to timeout tm timeoutlen title titlelen titleold titlestring tb toolbar tbis toolbariconsize ttimeout ttm ttimeoutlen tbi ttybuiltin tf ttyfast ttym ttymouse tsl ttyscroll tty ttytype udir undodir udf undofile ul undolevels ur undoreload uc updatecount ut updatetime vsts varsofttabstop vts vartabstop vbs verbose vfile verbosefile vdir viewdir vop viewoptions vi viminfo vif viminfofile ve virtualedit vb visualbell warn wiv weirdinvert ww whichwrap wc wildchar wcm wildcharm wig wildignore wic wildignorecase wmnu wildmenu wim wildmode wop wildoptions wak winaltkeys wcr wincolor wi window wfb winfixbuf skipwhite nextgroup=vimSetEqual,vimSetMod
-syn keyword vimOption contained wfh winfixheight wfw winfixwidth wh winheight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes skipwhite nextgroup=vimSetEqual,vimSetMod
+syn keyword vimOption contained wfh winfixheight wfw winfixwidth wh winheight whl winhighlight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes skipwhite nextgroup=vimSetEqual,vimSetMod
" vimOptions: These are the turn-off setting variants {{{2
" GEN_SYN_VIM: vimOption turn-off, START_STR='syn keyword vimOption contained', END_STR=''
@@ -111,7 +111,7 @@ syn keyword vimOptionVarName contained mfd maxfuncdepth mmd maxmapdepth mm maxme
syn keyword vimOptionVarName contained pmbfn printmbfont popt printoptions prompt pb pumborder ph pumheight pmw pummaxwidth pw pumwidth pythondll pythonhome pythonthreedll pythonthreehome pyx pyxversion qftf quickfixtextfunc qe quoteescape ro readonly rdt redrawtime re regexpengine rnu relativenumber remap rop renderoptions report rs restorescreen ri revins rl rightleft rlc rightleftcmd rubydll ru ruler ruf rulerformat rtp runtimepath scr scroll scb scrollbind scf scrollfocus sj scrolljump so scrolloff sbo scrollopt sect sections secure sel selection slm selectmode ssop sessionoptions sh shell shcf shellcmdflag sp shellpipe shq shellquote srr shellredir ssl shellslash stmp shelltemp st shelltype sxe shellxescape sxq shellxquote sr shiftround sw shiftwidth shm shortmess
syn keyword vimOptionVarName contained sn shortname sbr showbreak sc showcmd sloc showcmdloc sft showfulltag sm showmatch smd showmode stal showtabline stpl showtabpanel ss sidescroll siso sidescrolloff scl signcolumn scs smartcase si smartindent sta smarttab sms smoothscroll sts softtabstop spell spc spellcapcheck spf spellfile spl spelllang spo spelloptions sps spellsuggest sb splitbelow spk splitkeep spr splitright sol startofline stl statusline stlo statuslineopt su suffixes sua suffixesadd swf swapfile sws swapsync swb switchbuf smc synmaxcol syn syntax tcl tabclose tal tabline tpm tabpagemax tpl tabpanel tplo tabpanelopt ts tabstop tbs tagbsearch tc tagcase tfu tagfunc tl taglength tr tagrelative tag tags tgst tagstack tcldll term tbidi termbidi tenc termencoding
syn keyword vimOptionVarName contained tgc termguicolors twk termwinkey twsl termwinscroll tws termwinsize twt termwintype terse ta textauto tx textmode tw textwidth tsr thesaurus tsrfu thesaurusfunc top tildeop to timeout tm timeoutlen title titlelen titleold titlestring tb toolbar tbis toolbariconsize ttimeout ttm ttimeoutlen tbi ttybuiltin tf ttyfast ttym ttymouse tsl ttyscroll tty ttytype udir undodir udf undofile ul undolevels ur undoreload uc updatecount ut updatetime vsts varsofttabstop vts vartabstop vbs verbose vfile verbosefile vdir viewdir vop viewoptions vi viminfo vif viminfofile ve virtualedit vb visualbell warn wiv weirdinvert ww whichwrap wc wildchar wcm wildcharm wig wildignore wic wildignorecase wmnu wildmenu wim wildmode wop wildoptions wak winaltkeys
-syn keyword vimOptionVarName contained wcr wincolor wi window wfb winfixbuf wfh winfixheight wfw winfixwidth wh winheight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes
+syn keyword vimOptionVarName contained wcr wincolor wi window wfb winfixbuf wfh winfixheight wfw winfixwidth wh winheight whl winhighlight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes
" GEN_SYN_VIM: vimOption term output code variable, START_STR='syn keyword vimOptionVarName contained', END_STR=''
syn keyword vimOptionVarName contained t_AB t_AF t_AU t_AL t_al t_bc t_BE t_BD t_cd t_ce t_Ce t_CF t_cl t_cm t_Co t_CS t_Cs t_cs t_CV t_da t_db t_DL t_dl t_ds t_Ds t_EC t_EI t_fs t_fd t_fe t_GP t_IE t_IS t_ke t_ks t_le t_mb t_md t_me t_mr t_ms t_nd t_op t_RF t_RB t_RC t_RI t_Ri t_RK t_RS t_RT t_RV t_Sb t_SC t_se t_Sf t_SH t_SI t_Si t_so t_SR t_sr t_ST t_Te t_te t_TE t_ti t_TI t_Ts t_ts t_u7 t_ue t_us t_Us t_ut t_vb t_ve t_vi t_VS t_vs t_WP t_WS t_XM t_xn t_xs t_ZH t_ZR t_8f t_8b t_8u t_xo
syn keyword vimOptionVarName contained t_F1 t_F2 t_F3 t_F4 t_F5 t_F6 t_F7 t_F8 t_F9 t_k1 t_K1 t_k2 t_k3 t_K3 t_k4 t_K4 t_k5 t_K5 t_k6 t_K6 t_k7 t_K7 t_k8 t_K8 t_k9 t_K9 t_KA t_kb t_kB t_KB t_KC t_kd t_kD t_KD t_KE t_KF t_KG t_kh t_KH t_kI t_KI t_KJ t_KK t_kl t_KL t_kN t_kP t_kr t_ku
diff --git a/src/drawline.c b/src/drawline.c
index 2758e882e..4597d8d3c 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -127,7 +127,6 @@ typedef struct {
int win_attr; // background for the whole window, except
// margins and "~" lines.
- int wcr_attr; // attributes from 'wincolor'
#ifdef FEAT_SYN_HL
int cul_attr; // set when 'cursorline' active
#endif
@@ -261,9 +260,9 @@ handle_foldcolumn(win_T *wp, winlinevars_T *wlv)
wlv->c_extra = NUL;
wlv->c_final = NUL;
if (use_cursor_line_highlight(wp, wlv->lnum))
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_CLF));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_CLF));
else
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_FC));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_FC));
}
#endif
@@ -293,9 +292,9 @@ get_sign_display_info(
else
{
if (use_cursor_line_highlight(wp, wlv->lnum))
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_CLS));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_CLS));
else
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_SC));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_SC));
wlv->n_extra = 2;
}
@@ -467,7 +466,7 @@ handle_lnum_col(
wlv->c_final = NUL;
}
wlv->n_extra = number_width(wp) + 1;
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_N));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_N));
#ifdef FEAT_SYN_HL
// When 'cursorline' is set highlight the line number of
// the current line differently.
@@ -481,16 +480,16 @@ handle_lnum_col(
&& (wlv->row == lnum_row
|| (wlv->row > lnum_row
&& (wp->w_p_culopt_flags & CULOPT_LINE))))
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_CLN));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_CLN));
#endif
if (wp->w_p_rnu && wlv->lnum < wp->w_cursor.lnum
&& HL_ATTR(HLF_LNA) != 0)
// Use LineNrAbove
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_LNA));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_LNA));
if (wp->w_p_rnu && wlv->lnum > wp->w_cursor.lnum
&& HL_ATTR(HLF_LNB) != 0)
// Use LineNrBelow
- wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_LNB));
+ wlv->char_attr = hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_LNB));
}
#ifdef FEAT_SIGNS
if (num_attr)
@@ -608,7 +607,7 @@ handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv)
// required when 'linebreak' is also set.
if (wlv->tocol == wlv->vcol)
wlv->tocol = wlv->vcol_sbr;
- // combine 'showbreak' with 'wincolor'
+ // combine 'showbreak' with HLF_WIN
wlv->char_attr = hl_combine_attr(wlv->win_attr, HL_ATTR(HLF_AT));
# ifdef FEAT_SYN_HL
// combine 'showbreak' with 'cursorline'
@@ -1676,10 +1675,9 @@ win_line(
}
}
- wlv.wcr_attr = get_wcr_attr(wp);
- if (wlv.wcr_attr != 0)
+ if (get_win_attr(wp) != 0)
{
- wlv.win_attr = wlv.wcr_attr;
+ wlv.win_attr = get_win_attr(wp);
area_highlighting = TRUE;
}
@@ -1993,7 +1991,7 @@ win_line(
wlv.c_extra = cmdwin_type;
wlv.c_final = NUL;
wlv.char_attr =
- hl_combine_attr(wlv.wcr_attr, HL_ATTR(HLF_AT));
+ hl_combine_attr(get_win_attr(wp), HL_ATTR(HLF_AT));
}
}
#ifdef FEAT_FOLDING
@@ -2655,7 +2653,7 @@ win_line(
#endif
}
- // combine attribute with 'wincolor'
+ // combine attribute with HLF_WIN
if (wlv.win_attr != 0)
{
if (wlv.char_attr == 0)
@@ -4303,7 +4301,7 @@ win_line(
{
#ifdef FEAT_CONCEAL
wlv.col -= wlv.boguscols;
- // Apply 'cursorline' and 'wincolor' highlight.
+ // Apply 'cursorline' and HLF_WIN highlight.
if (wlv.boguscols != 0 && (
# ifdef LINE_ATTR
wlv.line_attr != 0 ||
diff --git a/src/drawscreen.c b/src/drawscreen.c
index aff03cb87..8ce8826c1 100644
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -100,6 +100,7 @@ update_screen(int type_arg)
#ifdef FEAT_PROP_POPUP
int did_redraw_window = FALSE;
#endif
+ bool override_success;
// Don't do anything if the screen structures are (not yet) valid.
if (!screen_valid(TRUE))
@@ -319,6 +320,8 @@ update_screen(int type_arg)
#endif
FOR_ALL_WINDOWS(wp)
{
+ override_success = push_highlight_overrides(wp->w_hl, wp->w_hl_len);
+
if (wp->w_redr_type != 0)
{
cursor_off();
@@ -353,6 +356,10 @@ update_screen(int type_arg)
cursor_off();
win_redr_status(wp, TRUE); // any popup menu will be redrawn below
}
+
+ if (override_success)
+ pop_highlight_overrides();
+
}
#if defined(FEAT_SEARCH_EXTRA)
end_search_hl();
@@ -624,6 +631,7 @@ redraw_custom_statusline(win_T *wp)
void
showruler(int always)
{
+ bool override_success;
if (!always && !redrawing())
return;
if (pum_visible())
@@ -632,12 +640,15 @@ showruler(int always)
curwin->w_redr_status = TRUE;
return;
}
+ override_success = push_highlight_overrides(curwin->w_hl, curwin->w_hl_len);
#if defined(FEAT_STL_OPT)
if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
redraw_custom_statusline(curwin);
else
#endif
win_redr_ruler(curwin, always, FALSE);
+ if (override_success)
+ pop_highlight_overrides();
if (need_maketitle
#ifdef FEAT_STL_OPT
@@ -3379,7 +3390,12 @@ redraw_statuslines(void)
FOR_ALL_WINDOWS(wp)
if (wp->w_redr_status)
+ {
+ bool ret = push_highlight_overrides(wp->w_hl, wp->w_hl_len);
win_redr_status(wp, FALSE);
+ if (ret)
+ pop_highlight_overrides();
+ }
if (redraw_tabline)
draw_tabline();
diff --git a/src/highlight.c b/src/highlight.c
index f4d6867aa..5ce3ea107 100644
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -181,6 +181,28 @@ typedef struct
#endif
} hl_group_T;
+typedef struct hl_overrides_S hl_overrides_T;
+struct hl_overrides_S
+{
+ hl_override_T *arr;
+ int len;
+ hl_overrides_T *next; // Used to handle recursive calls
+
+ int attr[HLF_COUNT]; // highlight_attr[] before being updated.
+};
+
+static hl_overrides_T *overrides = NULL;
+
+// Synced with highlight_attr, each is the highlight group id for each attr. If
+// an element is 0, then there is no attr for it. If an element is -1, then it
+// means it was set to itself.
+static int highlight_ids[HLF_COUNT];
+
+// Same as highlight_attr[] but is not modified by highlight group overrides
+static int highlight_attr_raw[HLF_COUNT];
+
+static int hl_flags[HLF_COUNT] = HL_FLAGS;
+
// highlight groups for 'highlight' option
static garray_T highlight_ga;
#define HL_TABLE() ((hl_group_T *)((highlight_ga.ga_data)))
@@ -3766,6 +3788,20 @@ set_hl_attr(
}
}
+/*
+ * Check if highlight id is overridden, and return the overriding highlight id.
+ * Otherwise return the original id if no override.
+ */
+ static int
+syn_override(int id)
+{
+ if (overrides != NULL && overrides->arr != NULL)
+ for (int k = 0; k < overrides->len; k++)
+ if (overrides->arr[k].from == id)
+ return overrides->arr[k].to;
+ return id;
+}
+
/*
* Lookup a highlight group name and return its ID.
* If it is not found, 0 is returned.
@@ -4041,13 +4077,20 @@ syn_get_final_id(int hl_id)
// Look out for loops! Break after 100 links.
for (count = 100; --count >= 0; )
{
+ int tmp = hl_id;
+
sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len)
break;
+
+ // This is to handle highlight groups that are overridden but are in the
+ // middle of a link chain.
+ hl_id = syn_override(hl_id);
+ if (tmp != hl_id)
+ continue;
hl_id = sgp->sg_link;
}
-
- return hl_id;
+ return syn_override(hl_id);
}
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
@@ -4211,18 +4254,22 @@ highlight_changed(void)
int hlcnt;
# endif
#endif
- static int hl_flags[HLF_COUNT] = HL_FLAGS;
+ win_T *wp;
need_highlight_changed = FALSE;
#ifdef FEAT_TERMINAL
term_update_colors_all();
- term_update_wincolor_all();
+ term_update_hlfwin_all();
#endif
// Clear all attributes.
for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
+ {
highlight_attr[hlf] = 0;
+ highlight_attr_raw[hlf] = 0;
+ highlight_ids[hlf] = 0;
+ }
// First set all attributes to their default value.
// Then use the attributes from the 'highlight' option.
@@ -4309,11 +4356,20 @@ highlight_changed(void)
}
}
highlight_attr[hlf] = attr;
+ highlight_attr_raw[hlf] = attr;
+ highlight_ids[hlf] = id;
p = skip_to_option_part(p); // skip comma and spaces
}
}
+ FOR_ALL_WINDOWS(wp)
+ wp->w_hlfwin_id = hlf_get_id(wp, HLF_WIN);
+
+#ifdef FEAT_TERMINAL
+ term_update_hlfwin_all();
+#endif
+
#ifdef USER_HIGHLIGHT
// Setup the user highlights
//
@@ -4948,7 +5004,7 @@ highlight_get_info(int hl_idx, int resolve_link)
if (dict_add_number(dict, "id", hlgid) == FAIL)
goto error;
- if (sgp->sg_link && resolve_link)
+ if (resolve_link)
{
// resolve the highlight group link recursively
while (sgp->sg_link)
@@ -5399,3 +5455,351 @@ f_hlset(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 0;
}
#endif
+
+/*
+ * If "old" is in the override stack, then update it to "new". Does not free
+ * "old".
+ */
+ void
+update_highlight_overrides(hl_override_T *old, hl_override_T *new, int newlen)
+{
+ if (old == NULL)
+ return;
+
+ for (hl_overrides_T *set = overrides; set != NULL; set = set->next)
+ {
+ if (set->arr == old)
+ {
+ set->arr = new;
+ set->len = newlen;
+ break;
+ }
+ }
+}
+
+/*
+ * Update highlight_attr[] array. If "update_ids" is true, then update
+ * highlight_ids[] array instead.
+ */
+ static void
+set_highlight_attr(hl_override_T *arr, int len, bool update_ids)
+{
+ for (int i = 0; i < len; i++)
+ {
+ hl_override_T *override = arr + i;
+ int hlf = -1, attr;
+
+ if (override->from <= 0)
+ // Directly map to highlight_attr
+ hlf = -override->from;
+ else
+ {
+ for (int k = 0; k < HLF_COUNT; k++)
+ if (override->from == highlight_ids[k])
+ {
+ hlf = k;
+ break;
+ }
+
+ if (hlf == -1)
+ continue;
+ }
+
+ if (update_ids)
+ {
+ if (override->to <= 0)
+ {
+ if (hlf == -override->to)
+ highlight_ids[hlf] = -1;
+ else
+ highlight_ids[hlf] = highlight_ids[-override->to];
+ }
+ else
+ highlight_ids[hlf] = override->to;
+ }
+ else
+ {
+ if (override->to <= 0)
+ // Directly use highlight_attr[]
+ attr = highlight_attr[-override->to];
+ else
+ attr = syn_id2attr(override->to);
+
+ highlight_attr[hlf] = attr;
+ }
+ }
+}
+
+/*
+ * Set the current highlight override to "arr". Returns true if successful
+ */
+ bool
+push_highlight_overrides(hl_override_T *arr, int len)
+{
+ // Don't want to do anything if "arr" is NULL or if "arr" is already the
+ // current override.
+ if (arr == NULL || (overrides != NULL && overrides->arr == arr))
+ return false;
+
+ hl_overrides_T *set;
+
+ set = ALLOC_ONE(hl_overrides_T);
+ if (set == NULL)
+ return false;
+
+ set->arr = arr;
+ set->len = len;
+
+ // Push to front of list
+ set->next = overrides;
+ overrides = set;
+
+ // Save current highlight_attr[], so it can be restored later after this
+ // override is popped.
+ memcpy(set->attr, highlight_attr, sizeof(highlight_attr));
+
+ // Reset highlight_attr[] to default values, as we don't want changes from
+ // other overrides.
+ memcpy(highlight_attr, highlight_attr_raw, sizeof(highlight_attr));
+
+ // Update highlight_attr[] array
+ set_highlight_attr(arr, len, false);
+
+ return true;
+}
+
+/*
+ * Pop the current highlight override (if any) from the stack. This should
+ * always be paired with a *successful* push.
+ */
+ void
+pop_highlight_overrides(void)
+{
+ hl_overrides_T *set = overrides;
+
+ if (overrides == NULL)
+ return;
+
+ overrides = set->next;
+
+ // Set highlight_attr[] to state before override was pushed.
+ memcpy(highlight_attr, set->attr, sizeof(highlight_attr));
+ vim_free(set);
+}
+
+/*
+ * Parse the 'winhighlight' option and return array. Returns NULL on failure or
+ * if empty option. If failure, then errmsg is set.
+ */
+ static hl_override_T *
+parse_winhighlight(char_u *opt, int *len, char **errmsg)
+{
+ char_u *p = opt;
+ hl_override_T *arr;
+ int i = 0;
+ int num = 1;
+
+ if (*p == NUL)
+ return NULL;
+
+ // Get number of overrides first so we can allocate array
+ while ((p = vim_strchr(p, ',')) != NULL)
+ {
+ p++;
+ num++;
+ }
+
+ arr = ALLOC_MULT(hl_override_T, num);
+ if (arr == NULL)
+ {
+ *errmsg = e_out_of_memory;
+ return NULL;
+ }
+
+ p = opt;
+
+ while (true)
+ {
+ hl_override_T *override = arr + i++;
+ char_u *fromname = p, *toname;
+ char_u *tmp;
+ char_u **names[2] = {&fromname, &toname};
+ int fromlen, tolen;
+ int *lens[2] = {&fromlen, &tolen};
+ int fromid, toid;
+ int *ids[2] = {&fromid, &toid};
+
+ p = vim_strchr(p, ':');
+
+ if (p == NULL)
+ goto fail;
+
+ fromlen = p - fromname; // Get hl for "from"
+ p++; // Skip colon ':'
+ if (*p == NUL)
+ goto fail;
+
+ toname = p;
+ tmp = vim_strchr(p, ',');
+
+ // Get hl for "to", must check for no trailing comma in case last
+ // element.
+ if (tmp == NULL)
+ tolen = (int)STRLEN(p);
+ else
+ {
+ tolen = tmp - toname;
+ p = ++tmp;
+ }
+
+ for (int k = 0; k < 2; k++)
+ {
+ char_u *name = *names[k];
+ int nlen = *lens[k];
+
+ if (*name == '!')
+ {
+ // If starts with "!", then it maps directly to a 'highlight'
+ // occasion.
+ int hlf;
+
+ if (nlen != 2)
+ goto fail;
+
+ for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
+ if (hl_flags[hlf] == name[1])
+ break;
+
+ if (hlf >= HLF_COUNT)
+ goto fail;
+
+ *ids[k] = -hlf;
+ }
+ else
+ {
+ // Otherwise get the highlight group id.
+ if (syn_check_group(name, nlen) == 0)
+ goto fail;
+
+ *ids[k] = syn_namen2id(name, nlen);
+ if (*ids[k] == 0)
+ goto fail;
+
+ // Always map "Normal" group to HLF_WIN
+ if (ids[k] == &fromid &&
+ STRCMP(HL_TABLE()[*ids[k] - 1].sg_name_u, "NORMAL") == 0)
+ *ids[k] = -HLF_WIN;
+ }
+ }
+
+ // If fromid == toid, leave it be, this is so that we know HLF_WIN has
+ // been set (even to itself e.g. "Normal"), and therefore know to use
+ // its attr instead.
+ override->from = fromid;
+ override->to = toid;
+
+ if (tmp == NULL)
+ break;
+ }
+
+ *len = num;
+ return arr;
+fail:
+ vim_free(arr);
+ *errmsg = e_invalid_argument;
+ return NULL;
+}
+
+/*
+ * Update w_hl for "wp" using given option value. Returns error
+ * message on failure, otherwise NULL.
+ */
+ char *
+update_winhighlight(win_T *wp, char_u *opt)
+{
+ char *err = NULL;
+ hl_override_T *arr;
+ int num = 1;
+
+ arr = parse_winhighlight(opt, &num, &err);
+
+ if (arr == NULL && err != NULL)
+ return err;
+
+ update_highlight_overrides(wp->w_hl, arr, num);
+
+ vim_free(wp->w_hl);
+ wp->w_hl = arr;
+ wp->w_hl_len = num;
+
+ wp->w_hlfwin_id = hlf_get_id(wp, HLF_WIN);
+
+#ifdef FEAT_TERMINAL
+ term_update_hlfwin(wp);
+#endif
+
+#ifdef FEAT_TERMINAL
+ // May be NULL (such as in after_copy_winopt())
+ if (wp->w_buffer != NULL)
+ {
+ // Make sure terminal highlighting is updated
+ bool ret = push_highlight_overrides(wp->w_hl, wp->w_hl_len);
+
+ if (wp->w_buffer->b_term != NULL)
+ term_init_default_colors(wp->w_buffer->b_term);
+ if (ret)
+ pop_highlight_overrides();
+ }
+#endif
+
+ return NULL;
+}
+
+/*
+ * Get id that the hlf attr is using in window "wp", otherwise zero. Note that
+ * -1 may be returned if the hlf was set to itself.
+ */
+ int
+hlf_get_id(win_T *wp, int hlf)
+{
+ int id;
+ static int prev[HLF_COUNT];
+
+ if (wp->w_hl == NULL)
+ return highlight_ids[hlf];
+
+ memcpy(prev, highlight_ids, sizeof(highlight_ids));
+ set_highlight_attr(wp->w_hl, wp->w_hl_len, true);
+ id = highlight_ids[hlf];
+ memcpy(highlight_ids, prev, sizeof(highlight_ids));
+
+ return id;
+}
+
+/*
+ * Update 'winhighlight' using a 'wincolor' style option value. Returns error
+ * message on failure otherwise NULL. Does not update the actual 'wincolor'
+ * value, but does update the 'winhighlight' value.
+ */
+ char *
+update_wincolor(win_T *wp, char_u *opt)
+{
+ char_u *str = *opt == NUL ? "" : alloc(sizeof("!(:") + STRLEN(opt));
+ char *errmsg;
+
+ if (str == NULL)
+ return e_out_of_memory;
+
+ if (*opt != NUL)
+ sprintf((char *)str, "!(:%s", opt);
+
+ errmsg = update_winhighlight(wp, str);
+
+ if (errmsg == NULL)
+ set_string_option_direct_in_win(wp, (char_u *)"winhighlight", -1,
+ str, OPT_FREE|OPT_LOCAL, 0);
+
+ if (*opt != NUL)
+ free(str);
+ return errmsg;
+}
diff --git a/src/match.c b/src/match.c
index ff7e8d9f3..912abfd74 100644
--- a/src/match.c
+++ b/src/match.c
@@ -323,6 +323,9 @@ init_search_hl(win_T *wp, match_T *search_hl)
cur->mit_hl.first_lnum = 0;
cur = cur->mit_next;
}
+ // Must update this every time since highlight group override can change it.
+ search_hl->attr = HL_ATTR(HLF_L);
+
search_hl->buf = wp->w_buffer;
search_hl->lnum = 0;
search_hl->first_lnum = 0;
diff --git a/src/option.c b/src/option.c
index e4a94e1c6..8de0d9c68 100644
--- a/src/option.c
+++ b/src/option.c
@@ -4401,7 +4401,7 @@ did_set_termguicolors(optset_T *args UNUSED)
# ifdef FEAT_TERMINAL
term_update_colors_all();
term_update_palette_all();
- term_update_wincolor_all();
+ term_update_hlfwin_all();
# endif
p_tgc_set = TRUE;
@@ -6860,6 +6860,8 @@ get_varp(struct vimoption *p)
case PV_COCU: return (char_u *)&(curwin->w_p_cocu);
case PV_COLE: return (char_u *)&(curwin->w_p_cole);
#endif
+ case PV_WHL: return (char_u *)&(curwin->w_p_whl);
+
#ifdef FEAT_TERMINAL
case PV_TWK: return (char_u *)&(curwin->w_p_twk);
case PV_TWS: return (char_u *)&(curwin->w_p_tws);
@@ -7041,6 +7043,11 @@ win_copy_options(win_T *wp_from, win_T *wp_to)
void
after_copy_winopt(win_T *wp)
{
+ char *errmsg = update_winhighlight(wp, wp->w_p_whl);
+
+ if (errmsg != NULL)
+ emsg(_(errmsg));
+
// Set w_leftcol or w_skipcol to zero.
if (wp->w_p_wrap)
wp->w_leftcol = 0;
@@ -7170,6 +7177,7 @@ copy_winopt(winopt_T *from, winopt_T *to)
to->wo_fde_flags = from->wo_fde_flags;
to->wo_fdt_flags = from->wo_fdt_flags;
#endif
+ to->wo_whl = copy_option_val(from->wo_whl);
#ifdef FEAT_EVAL
// Copy the script context so that we know where the value was last set.
@@ -7236,6 +7244,7 @@ check_winopt(winopt_T *wop UNUSED)
check_string_option(&wop->wo_lcs);
check_string_option(&wop->wo_fcs);
check_string_option(&wop->wo_ve);
+ check_string_option(&wop->wo_whl);
}
/*
@@ -7285,6 +7294,7 @@ clear_winopt(winopt_T *wop UNUSED)
clear_string_option(&wop->wo_lcs);
clear_string_option(&wop->wo_fcs);
clear_string_option(&wop->wo_ve);
+ clear_string_option(&wop->wo_whl);
}
#ifdef FEAT_EVAL
diff --git a/src/option.h b/src/option.h
index 46b8daf09..fddc3905c 100644
--- a/src/option.h
+++ b/src/option.h
@@ -1389,6 +1389,7 @@ enum
, WV_WFB
, WV_WFH
, WV_WFW
+ , WV_WHL
, WV_WRAP
#ifdef FEAT_SIGNS
, WV_SCL
diff --git a/src/optiondefs.h b/src/optiondefs.h
index 650943480..2a2b1c0da 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -228,6 +228,7 @@
#define PV_WFB OPT_WIN(WV_WFB)
#define PV_WFH OPT_WIN(WV_WFH)
#define PV_WFW OPT_WIN(WV_WFW)
+#define PV_WHL OPT_WIN(WV_WHL)
#define PV_WRAP OPT_WIN(WV_WRAP)
#define PV_CRBIND OPT_WIN(WV_CRBIND)
#ifdef FEAT_CONCEAL
@@ -2979,6 +2980,9 @@ static struct vimoption options[] =
(char_u *)&p_wh, PV_NONE,
did_set_winheight_helpheight, NULL,
{(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"winhighlight", "whl", P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP|P_COLON,
+ (char_u *)VAR_WIN, PV_WHL, did_set_winhighlight, expand_set_winhighlight,
+ {(char_u *)"", (char_u *)NULL} SCTX_INIT},
{"winminheight", "wmh", P_NUM|P_VI_DEF,
(char_u *)&p_wmh, PV_NONE, did_set_winminheight, NULL,
{(char_u *)1L, (char_u *)0L} SCTX_INIT},
diff --git a/src/optionstr.c b/src/optionstr.c
index d4287b46c..7fb8bf548 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -503,7 +503,6 @@ set_string_option_direct(
#endif
}
-#if defined(FEAT_PROP_POPUP) || (defined(FEAT_DIFF) && defined(FEAT_FOLDING))
/*
* Like set_string_option_direct(), but for a window-local option in "wp".
* Blocks autocommands to avoid the old curwin becoming invalid.
@@ -527,7 +526,6 @@ set_string_option_direct_in_win(
curbuf = curwin->w_buffer;
unblock_autocmds();
}
-#endif
#if defined(FEAT_PROP_POPUP)
/*
@@ -2815,6 +2813,63 @@ did_set_highlight(optset_T *args UNUSED)
return NULL;
}
+ static int
+expand_hl_occasions(
+ optexpand_T *args,
+ int *numMatches,
+ char_u ***matches,
+ char_u prefix)
+{
+ char_u *p;
+ static char_u hl_flags[HLF_COUNT] = HL_FLAGS;
+ size_t i;
+ int count = 0;
+
+ *matches = ALLOC_MULT(char_u *, HLF_COUNT + 1);
+ if (*matches == NULL)
+ return FAIL;
+
+ // We still want to return the full option if it's requested.
+ if (args->oe_include_orig_val)
+ {
+ p = vim_strsave(args->oe_opt_value);
+ if (p == NULL)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ (*matches)[count++] = p;
+ }
+
+ for (i = 0; i < HLF_COUNT; i++)
+ {
+ p = alloc((prefix == NUL ? 1 : 2) + 1);
+ if (p == NULL)
+ {
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ else
+ break;
+ }
+ if (prefix == NUL)
+ sprintf((char *)p, "%c", hl_flags[i]);
+ else
+ sprintf((char *)p, "%c%c", prefix, hl_flags[i]);
+ (*matches)[count++] = p;
+ }
+
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ *numMatches = count;
+ return OK;
+}
+
/*
* Expand 'highlight' option.
*/
@@ -2823,7 +2878,6 @@ expand_set_highlight(optexpand_T *args, int *numMatches, char_u ***matches)
{
char_u *p;
expand_T *xp = args->oe_xp;
- static char_u hl_flags[HLF_COUNT] = HL_FLAGS;
size_t i;
int count = 0;
@@ -2838,49 +2892,9 @@ expand_set_highlight(optexpand_T *args, int *numMatches, char_u ***matches)
}
if (*xp->xp_pattern == NUL)
- {
// At beginning of a comma-separated list. Return the specific list of
// supported occasions.
- *matches = ALLOC_MULT(char_u *, HLF_COUNT + 1);
- if (*matches == NULL)
- return FAIL;
-
- // We still want to return the full option if it's requested.
- if (args->oe_include_orig_val)
- {
- p = vim_strsave(args->oe_opt_value);
- if (p == NULL)
- {
- VIM_CLEAR(*matches);
- return FAIL;
- }
- (*matches)[count++] = p;
- }
-
- for (i = 0; i < HLF_COUNT; i++)
- {
- p = vim_strnsave(&hl_flags[i], 1);
- if (p == NULL)
- {
- if (count == 0)
- {
- VIM_CLEAR(*matches);
- return FAIL;
- }
- else
- break;
- }
- (*matches)[count++] = p;
- }
-
- if (count == 0)
- {
- VIM_CLEAR(*matches);
- return FAIL;
- }
- *numMatches = count;
- return OK;
- }
+ return expand_hl_occasions(args, numMatches, matches, NUL);
// We are after the initial character (which indicates the occasion). We
// already made sure we are not matching after a ':' above, so now we want
@@ -4928,12 +4942,48 @@ expand_set_winaltkeys(optexpand_T *args, int *numMatches, char_u ***matches)
char *
did_set_wincolor(optset_T *args UNUSED)
{
-#ifdef FEAT_TERMINAL
- term_update_wincolor(curwin);
-#endif
+ update_wincolor(curwin, args->os_newval.string);
return NULL;
}
+/*
+ * The 'winhighlight' option is changed
+ */
+ char *
+did_set_winhighlight(optset_T *args)
+{
+ return update_winhighlight(curwin, args->os_newval.string);
+}
+
+/*
+ * Expand 'winhighlight' option.
+ */
+ int
+expand_set_winhighlight(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ expand_T *xp = args->oe_xp;
+
+ if ((xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
+ || xp->xp_pattern == args->oe_set_arg || *(xp->xp_pattern-1) == ',')
+ {
+ // After a ':' or after a ',', or at the start, so expand highlight
+ // group name.
+
+ // If starts with !, then expand 'highlight' occasions.
+ if (*xp->xp_pattern == '!')
+ return expand_hl_occasions(args, numMatches, matches, '!');
+ else
+ return expand_set_opt_generic(
+ args,
+ get_highlight_name,
+ numMatches,
+ matches);
+ }
+
+ VIM_CLEAR(*matches);
+ return FAIL;
+}
+
int
expand_set_wincolor(optexpand_T *args, int *numMatches, char_u ***matches)
{
diff --git a/src/popupmenu.c b/src/popupmenu.c
index d316ba99e..b8c72d44f 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -905,6 +905,10 @@ pum_redraw(void)
int last_isabbr = FALSE;
int orig_attr = -1;
int scroll_range = pum_size - pum_height;
+ bool override_success;
+
+ // Use current window for highlight overrides when using 'winhighlight'
+ override_success = push_highlight_overrides(curwin->w_hl, curwin->w_hl_len);
hlf_T hlfsNorm[3];
hlf_T hlfsSel[3];
@@ -1042,6 +1046,9 @@ pum_redraw(void)
#ifdef FEAT_PROP_POPUP
screen_zindex = 0;
#endif
+
+ if (override_success)
+ pop_highlight_overrides();
}
#if defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX)
diff --git a/src/popupwin.c b/src/popupwin.c
index 399ab67ac..7cd39b071 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -826,11 +826,25 @@ apply_general_options(win_T *wp, dict_T *dict)
str = dict_get_string(dict, "highlight", FALSE);
if (str != NULL)
{
- set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
- str, OPT_FREE|OPT_LOCAL, 0);
-#ifdef FEAT_TERMINAL
- term_update_wincolor(wp);
-#endif
+ char *errmsg = update_wincolor(wp, str);
+
+ if (errmsg == NULL)
+ set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
+ str, OPT_FREE|OPT_LOCAL, 0);
+ else
+ emsg(_(errmsg));
+ }
+
+ str = dict_get_string(dict, "highlights", FALSE);
+ if (str != NULL)
+ {
+ char *errmsg = update_winhighlight(wp, str);
+
+ if (errmsg == NULL)
+ set_string_option_direct_in_win(wp, (char_u *)"winhighlight", -1,
+ str, OPT_FREE|OPT_LOCAL, 0);
+ else
+ emsg(_(errmsg));
}
if (set_padding_border(dict, wp->w_popup_padding, "padding", 999) == FAIL ||
@@ -1894,11 +1908,18 @@ parse_popup_option(win_T *wp, int is_preview)
{
if (wp != NULL)
{
+ char *errmsg;
int c = *p;
*p = NUL;
- set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
- s + 10, OPT_FREE|OPT_LOCAL, 0);
+
+ errmsg = update_wincolor(wp, s + 10);
+ if (errmsg == NULL)
+ set_string_option_direct_in_win(wp, (char_u *)"wincolor",
+ -1, s + 10, OPT_FREE|OPT_LOCAL, 0);
+ else
+ emsg(_(errmsg));
+
*p = c;
}
}
@@ -2218,9 +2239,14 @@ popup_update_color(win_T *wp, create_type_T type)
{
char *hiname = type == TYPE_MESSAGE_WIN
? "MessageWindow" : "PopupNotification";
- set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
- (char_u *)hiname,
- OPT_FREE|OPT_LOCAL, 0);
+ char *errmsg;
+
+ errmsg = update_wincolor(wp, (char_u *)hiname);
+ if (errmsg == NULL)
+ set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
+ (char_u *)hiname, OPT_FREE|OPT_LOCAL, 0);
+ else
+ emsg(_(errmsg));
}
/*
@@ -3681,7 +3707,8 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
(wp->w_popup_flags & POPF_OPACITY) ? 100 - wp->w_popup_blend : 100);
dict_add_number(dict, "cursorline",
(wp->w_popup_flags & POPF_CURSORLINE) != 0);
- dict_add_string(dict, "highlight", wp->w_p_wcr);
+ dict_add_string(dict, "highlight", syn_id2name(hlf_get_id(wp, HLF_WIN)));
+ dict_add_string(dict, "highlights", wp->w_p_whl);
if (wp->w_scrollbar_highlight != NULL)
dict_add_string(dict, "scrollbarhighlight",
wp->w_scrollbar_highlight);
@@ -4494,7 +4521,7 @@ draw_opacity_padding_cell(
if (enc_utf8)
ScreenLinesUC[off] = 0;
int popup_attr_val =
- get_wcr_attr(screen_opacity_popup);
+ get_win_attr(screen_opacity_popup);
int blend = screen_opacity_popup->w_popup_blend;
ScreenAttrs[off] = hl_blend_attr(ScreenAttrs[off],
popup_attr_val, blend, TRUE);
@@ -4525,7 +4552,7 @@ draw_opacity_padding_cell(
ScreenAttrs[off] = saved_screenattrs[save_off];
int popup_attr_val =
- get_wcr_attr(screen_opacity_popup);
+ get_win_attr(screen_opacity_popup);
int blend = screen_opacity_popup->w_popup_blend;
ScreenAttrs[base_off] = hl_blend_attr(
ScreenAttrs[base_off],
@@ -4547,7 +4574,7 @@ draw_opacity_padding_cell(
ScreenAttrs[off] = saved_screenattrs[save_off];
if (enc_utf8 && ScreenLinesUC != NULL)
ScreenLinesUC[off] = 0;
- int popup_attr_val = get_wcr_attr(screen_opacity_popup);
+ int popup_attr_val = get_win_attr(screen_opacity_popup);
int blend = screen_opacity_popup->w_popup_blend;
ScreenAttrs[off] = hl_blend_attr(ScreenAttrs[off],
popup_attr_val, blend, TRUE);
@@ -4567,7 +4594,7 @@ draw_opacity_padding_cell(
ScreenLinesUC[base_off] = saved_screenlinesuc[base_save_off];
ScreenLinesUC[off] = saved_screenlinesuc[save_off];
- int popup_attr_val = get_wcr_attr(screen_opacity_popup);
+ int popup_attr_val = get_win_attr(screen_opacity_popup);
int blend = screen_opacity_popup->w_popup_blend;
ScreenAttrs[base_off] = hl_blend_attr(ScreenAttrs[base_off],
popup_attr_val, blend, TRUE);
@@ -4597,7 +4624,7 @@ draw_opacity_padding_cell(
ScreenLinesUC[off] = 0;
}
- int popup_attr_val = get_wcr_attr(screen_opacity_popup);
+ int popup_attr_val = get_win_attr(screen_opacity_popup);
int blend = screen_opacity_popup->w_popup_blend;
ScreenAttrs[off] = hl_blend_attr(ScreenAttrs[off],
popup_attr_val, blend, TRUE);
@@ -4658,6 +4685,7 @@ update_popups(void (*win_update)(win_T *wp))
int sb_thumb_height = 0;
int attr_scroll = 0;
int attr_thumb = 0;
+ bool override_success;
// hide the cursor until redrawing is done.
cursor_off();
@@ -4690,6 +4718,8 @@ update_popups(void (*win_update)(win_T *wp))
int title_len = 0;
int title_wincol;
+ override_success = push_highlight_overrides(wp->w_hl, wp->w_hl_len);
+
// This drawing uses the zindex of the popup window, so that it's on
// top of the text but doesn't draw when another popup with higher
// zindex is on top of the character.
@@ -4858,7 +4888,7 @@ update_popups(void (*win_update)(win_T *wp))
total_width = popup_width(wp) - wp->w_popup_rightoff;
total_height = popup_height(wp);
- popup_attr = get_wcr_attr(wp);
+ popup_attr = get_win_attr(wp);
if (wp->w_winrow + total_height > cmdline_row)
wp->w_popup_flags |= POPF_ON_CMDLINE;
@@ -5225,6 +5255,9 @@ update_popups(void (*win_update)(win_T *wp))
// if this was the message window popup may start the timer now
may_start_message_win_timer(wp);
#endif
+
+ if (override_success)
+ pop_highlight_overrides();
}
#ifdef FEAT_PROP_POPUP
diff --git a/src/proto/
highlight.pro b/src/proto/
highlight.pro
index 908765c21..a7691c88f 100644
--- a/src/proto/
highlight.pro
+++ b/src/proto/
highlight.pro
@@ -48,4 +48,10 @@ int expand_highlight_group(char_u *pat, expand_T *xp, regmatch_T *rmp, char_u **
void free_highlight_fonts(void);
void f_hlget(typval_T *argvars, typval_T *rettv);
void f_hlset(typval_T *argvars, typval_T *rettv);
+void update_highlight_overrides(hl_override_T *old, hl_override_T *new, int newlen);
+bool push_highlight_overrides(hl_override_T *arr, int len);
+void pop_highlight_overrides(void);
+char *update_winhighlight(win_T *wp, char_u *opt);
+int hlf_get_id(win_T *wp, int hlf);
+char *update_wincolor(win_T *wp, char_u *opt);
/* vim: set ft=c : */
diff --git a/src/proto/
optionstr.pro b/src/proto/
optionstr.pro
index 7e55d3b19..e4e39e759 100644
--- a/src/proto/
optionstr.pro
+++ b/src/proto/
optionstr.pro
@@ -207,6 +207,8 @@ int expand_set_wildoptions(optexpand_T *args, int *numMatches, char_u ***matches
char *did_set_winaltkeys(optset_T *args);
int expand_set_winaltkeys(optexpand_T *args, int *numMatches, char_u ***matches);
char *did_set_wincolor(optset_T *args);
+char *did_set_winhighlight(optset_T *args);
+int expand_set_winhighlight(optexpand_T *args, int *numMatches, char_u ***matches);
int expand_set_wincolor(optexpand_T *args, int *numMatches, char_u ***matches);
char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char_u *value, char *errbuf, size_t errbuflen, int opt_flags, set_op_T op, int *value_checked);
int check_ff_value(char_u *p);
diff --git a/src/proto/
screen.pro b/src/proto/
screen.pro
index cf7cd95f4..2dce88691 100644
--- a/src/proto/
screen.pro
+++ b/src/proto/
screen.pro
@@ -1,7 +1,7 @@
/* screen.c */
int conceal_cursor_line(win_T *wp);
void conceal_check_cursor_line(int was_concealed);
-int get_wcr_attr(win_T *wp);
+int get_win_attr(win_T *wp);
void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl);
int compute_foldcolumn(win_T *wp, int col);
size_t fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
diff --git a/src/proto/
terminal.pro b/src/proto/
terminal.pro
index dfa59cced..5ae6b4ca6 100644
--- a/src/proto/
terminal.pro
+++ b/src/proto/
terminal.pro
@@ -35,9 +35,10 @@ int term_is_finished(buf_T *buf);
int term_show_buffer(buf_T *buf);
void term_change_in_curbuf(void);
int term_get_attr(win_T *wp, linenr_T lnum, int col);
-void term_reset_wincolor(win_T *wp);
-void term_update_wincolor(win_T *wp);
-void term_update_wincolor_all(void);
+void term_reset_hlfwin(win_T *wp);
+void term_update_hlfwin(win_T *wp);
+void term_update_hlfwin_all(void);
+void term_init_default_colors(term_T *term);
void term_update_palette_all(void);
void term_update_colors_all(void);
char_u *term_get_status_text(term_T *term);
diff --git a/src/screen.c b/src/screen.c
index 716715558..316b18b20 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -111,26 +111,31 @@ conceal_check_cursor_line(int was_concealed)
#endif
/*
- * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
- * window then get the "Pmenu" highlight attribute.
+ * Get HLF_WIN attribute for window "wp". If not set and "wp" is a popup window
+ * then get the "Pmenu" highlight attribute.
*/
int
-get_wcr_attr(win_T *wp)
+get_win_attr(win_T *wp)
{
- int wcr_attr = 0;
+ int win_attr = wp->w_hlfwin_id;
- if (*wp->w_p_wcr != NUL)
- wcr_attr = syn_name2attr(wp->w_p_wcr);
+ if (win_attr != 0)
+ {
+ if (win_attr != -1)
+ win_attr = syn_id2attr(win_attr);
+ else
+ win_attr = 0;
+ }
#ifdef FEAT_PROP_POPUP
else if (WIN_IS_POPUP(wp))
{
if (wp->w_popup_flags & POPF_INFO)
- wcr_attr = HL_ATTR(HLF_PSI); // PmenuSel
+ win_attr = HL_ATTR(HLF_PSI); // PmenuSel
else
- wcr_attr = HL_ATTR(HLF_PNI); // Pmenu
+ win_attr = HL_ATTR(HLF_PNI); // Pmenu
}
#endif
- return wcr_attr;
+ return win_attr;
}
/*
@@ -184,9 +189,9 @@ win_draw_end(
{
int n = 0;
int attr = HL_ATTR(hl);
- int wcr_attr = get_wcr_attr(wp);
+ int win_attr = get_win_attr(wp);
- attr = hl_combine_attr(wcr_attr, attr);
+ attr = hl_combine_attr(win_attr, attr);
if (draw_margin)
{
@@ -196,19 +201,19 @@ win_draw_end(
if (fdc > 0)
// draw the fold column
n = screen_fill_end(wp, ' ', ' ', n, fdc,
- row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)));
+ row, endrow, hl_combine_attr(win_attr, HL_ATTR(HLF_FC)));
#endif
#ifdef FEAT_SIGNS
if (signcolumn_on(wp))
// draw the sign column
n = screen_fill_end(wp, ' ', ' ', n, 2,
- row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)));
+ row, endrow, hl_combine_attr(win_attr, HL_ATTR(HLF_SC)));
#endif
if ((wp->w_p_nu || wp->w_p_rnu)
&& vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
// draw the number column
n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1,
- row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)));
+ row, endrow, hl_combine_attr(win_attr, HL_ATTR(HLF_N)));
}
#ifdef FEAT_RIGHTLEFT
@@ -658,7 +663,7 @@ screen_line(
// Wide char doesn't fit at the edge. Replace with a
// blended space so opacity is still applied.
int char_attr = ScreenAttrs[off_from];
- int popup_attr = get_wcr_attr(screen_opacity_popup);
+ int popup_attr = get_win_attr(screen_opacity_popup);
int combined = hl_combine_attr(popup_attr, char_attr);
int blend = screen_opacity_popup->w_popup_blend;
ScreenLines[off_to] = ' ';
@@ -687,7 +692,7 @@ screen_line(
// attribute (e.g. match highlight) so that its background
// color is preserved on blank cells.
int char_attr = ScreenAttrs[off_from];
- int popup_attr = get_wcr_attr(screen_opacity_popup);
+ int popup_attr = get_win_attr(screen_opacity_popup);
int combined = hl_combine_attr(popup_attr, char_attr);
int blend = screen_opacity_popup->w_popup_blend;
ScreenAttrs[off_to] = hl_blend_attr(ScreenAttrs[off_to],
@@ -712,7 +717,7 @@ screen_line(
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0))
{
int char_attr = ScreenAttrs[off_from];
- int popup_attr = get_wcr_attr(screen_opacity_popup);
+ int popup_attr = get_win_attr(screen_opacity_popup);
int combined = hl_combine_attr(popup_attr, char_attr);
int blend = screen_opacity_popup->w_popup_blend;
ScreenLines[off_to] = ' ';
@@ -869,7 +874,7 @@ skip_opacity:
&& screen_opacity_popup->w_popup_blend > 0)
{
int char_attr = ScreenAttrs[off_from];
- int popup_attr = get_wcr_attr(screen_opacity_popup);
+ int popup_attr = get_win_attr(screen_opacity_popup);
int blend = screen_opacity_popup->w_popup_blend;
// Combine popup window color with the character's own
// attribute (e.g. syntax highlighting) so that the
@@ -1747,7 +1752,6 @@ start_search_hl(void)
end_search_hl(); // just in case it wasn't called before
last_pat_prog(&screen_search_hl.rm);
- screen_search_hl.attr = HL_ATTR(HLF_L);
}
/*
@@ -2499,7 +2503,7 @@ screen_fill(
goto skip_opacity_fill;
}
- int popup_attr = get_wcr_attr(screen_opacity_popup);
+ int popup_attr = get_win_attr(screen_opacity_popup);
int blend = screen_opacity_popup->w_popup_blend;
// Blend both foreground and background for padding area
ScreenAttrs[off] = hl_blend_attr(ScreenAttrs[off],
@@ -4559,9 +4563,9 @@ draw_tabline(void)
int modified;
int c;
int len;
- int attr_sel = HL_ATTR(HLF_TPS);
- int attr_nosel = HL_ATTR(HLF_TP);
- int attr_fill = HL_ATTR(HLF_TPF);
+ int attr_sel;
+ int attr_nosel;
+ int attr_fill;
char_u *p;
int room;
int use_sep_chars = (t_colors < 8
@@ -4572,6 +4576,7 @@ draw_tabline(void)
&& !p_tgc
#endif
);
+ bool override_success;
#if defined(FEAT_TABPANEL)
col = firstwin->w_wincol;
@@ -4609,13 +4614,21 @@ draw_tabline(void)
if (tabwidth < 6)
tabwidth = 6;
- attr = attr_nosel;
tabcount = 0;
for (tp = first_tabpage; tp != NULL && col < Columns - 4;
tp = tp->tp_next)
{
scol = col;
+ override_success = push_highlight_overrides(
+ tp->tp_curwin->w_hl, tp->tp_curwin->w_hl_len);
+
+ // Update them each time since highlight override might change them.
+ attr_sel = HL_ATTR(HLF_TPS);
+ attr_nosel = HL_ATTR(HLF_TP);
+ attr_fill = HL_ATTR(HLF_TPF);
+ attr = attr_nosel;
+
if (tp->tp_topframe == topframe)
attr = attr_sel;
if (use_sep_chars && col > 0)
@@ -4697,6 +4710,9 @@ draw_tabline(void)
++tabcount;
while (scol < col)
TabPageIdxs[scol++] = tabcount;
+
+ if (override_success)
+ pop_highlight_overrides();
}
if (use_sep_chars)
diff --git a/src/structs.h b/src/structs.h
index 1fdc2ee1b..b0b559e8a 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -368,6 +368,8 @@ typedef struct
sctx_T wo_script_ctx[WV_COUNT]; // SCTXs for window-local options
# define w_p_script_ctx w_onebuf_opt.wo_script_ctx
#endif
+ char_u *wo_whl;
+#define w_p_whl w_onebuf_opt.wo_whl // 'winhighlight'
} winopt_T;
/*
@@ -3949,6 +3951,17 @@ typedef struct
int truncrl;
} fill_chars_T;
+/*
+ * Represents current highlight overrides (used by 'winhighlight' option). The
+ * highlight group with ID "from" will be overridden by the highlight group with
+ * ID "to"
+ */
+typedef struct
+{
+ int from; // If zero or negative then it is hlf_T enum
+ int to; // Same thing as "from"
+} hl_override_T;
+
/*
* Structure which contains all information that belongs to a window
*
@@ -4207,7 +4220,7 @@ struct window_S
// column being used
#endif
#ifdef FEAT_TERMINAL
- termcellcolor_T w_term_wincolor; // cache for term color of 'wincolor'
+ termcellcolor_T w_term_hlfwin; // cache for term color of HLF_WIN
#endif
/*
@@ -4362,6 +4375,11 @@ struct window_S
#ifdef FEAT_RUBY
void *w_ruby_ref;
#endif
+
+ hl_override_T *w_hl;
+ int w_hl_len;
+ int w_hlfwin_id; // Cached HLF_WIN highlight group id, zero if none,
+ // or -1 if it was set to itself.
};
/*
diff --git a/src/terminal.c b/src/terminal.c
index 02ca5d6d9..cea79dac6 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -2184,10 +2184,6 @@ may_move_terminal_to_buffer(term_T *term, int redraw)
<= term->tl_scrollback_scrolled)
update_snapshot(term);
- // Obtain the current background color.
- vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm),
- &term->tl_default_color.fg, &term->
tl_default_color.bg);
-
if (redraw)
{
win_T *wp = NULL;
@@ -2607,8 +2603,8 @@ term_get_highlight_id(term_T *term, win_T *wp)
{
char_u *name;
- if (wp != NULL && *wp->w_p_wcr != NUL)
- name = wp->w_p_wcr;
+ if (wp != NULL && wp->w_hlfwin_id != 0)
+ name = syn_id2name(wp->w_hlfwin_id);
else if (term->tl_highlight_name != NULL)
name = term->tl_highlight_name;
else
@@ -3179,12 +3175,12 @@ cell2attr(
if (is_default_fg || is_default_bg)
{
- if (wp != NULL && *wp->w_p_wcr != NUL)
+ if (wp != NULL && wp->w_hlfwin_id != 0)
{
if (is_default_fg)
- fg = &wp->w_term_wincolor.fg;
+ fg = &wp->w_term_hlfwin.fg;
if (is_default_bg)
- bg = &wp->
w_term_wincolor.bg;
+ bg = &wp->
w_term_hlfwin.bg;
}
else
{
@@ -4352,25 +4348,23 @@ get_vterm_color_from_synid(int id, VTermColor *fg, VTermColor *bg)
}
void
-term_reset_wincolor(win_T *wp)
+term_reset_hlfwin(win_T *wp)
{
- wp->w_term_wincolor.fg.type = VTERM_COLOR_INVALID | VTERM_COLOR_DEFAULT_FG;
- wp->w_term_wincolor.bg.type = VTERM_COLOR_INVALID | VTERM_COLOR_DEFAULT_BG;
+ wp->w_term_hlfwin.fg.type = VTERM_COLOR_INVALID | VTERM_COLOR_DEFAULT_FG;
+ wp->w_term_hlfwin.bg.type = VTERM_COLOR_INVALID | VTERM_COLOR_DEFAULT_BG;
}
/*
- * Cache the color of 'wincolor'.
+ * Cache the color of HLF_WIN.
*/
void
-term_update_wincolor(win_T *wp)
+term_update_hlfwin(win_T *wp)
{
- int id = 0;
+ int id = wp->w_hlfwin_id;
- if (*wp->w_p_wcr != NUL)
- id = syn_name2id(wp->w_p_wcr);
- if (id == 0 || !get_vterm_color_from_synid(id, &wp->w_term_wincolor.fg,
- &wp->
w_term_wincolor.bg))
- term_reset_wincolor(wp);
+ if (id == 0 || !get_vterm_color_from_synid(id == -1 ? 0 : id,
+ &wp->w_term_hlfwin.fg, &wp->
w_term_hlfwin.bg))
+ term_reset_hlfwin(wp);
}
/*
@@ -4378,20 +4372,20 @@ term_update_wincolor(win_T *wp)
* or when any highlight is changed.
*/
void
-term_update_wincolor_all(void)
+term_update_hlfwin_all(void)
{
win_T *wp = NULL;
int did_curwin = FALSE;
while (for_all_windows_and_curwin(&wp, &did_curwin))
- term_update_wincolor(wp);
+ term_update_hlfwin(wp);
}
/*
* Initialize term->tl_default_color from the environment.
*/
- static void
-init_default_colors(term_T *term)
+ void
+term_init_default_colors(term_T *term)
{
VTermColor *fg, *bg;
int fgval, bgval;
@@ -4960,7 +4954,7 @@ create_vterm(term_T *term, int rows, int cols)
// TODO: depends on 'encoding'.
vterm_set_utf8(vterm, 1);
- init_default_colors(term);
+ term_init_default_colors(term);
vterm_state_set_default_colors(
state,
@@ -5066,7 +5060,7 @@ term_update_colors_all(void)
{
if (term->tl_vterm == NULL)
continue;
- init_default_colors(term);
+ term_init_default_colors(term);
vterm_state_set_default_colors(
vterm_obtain_state(term->tl_vterm),
&term->tl_default_color.fg,
@@ -5821,7 +5815,7 @@ term_load_dump(typval_T *argvars, typval_T *rettv, int do_diff)
VTermPos cursor_pos1;
VTermPos cursor_pos2;
- init_default_colors(term);
+ term_init_default_colors(term);
rettv->vval.v_number = buf->b_fnum;
diff --git a/src/testdir/dumps/Test_winhighlight_1.dump b/src/testdir/dumps/Test_winhighlight_1.dump
new file mode 100644
index 000000000..aa2760bd9
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_1.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+>F+0#ffffff16#e000002|o|u|r| @32||+1#0000000#ffffff0|F+8&&|o|u|r| @32
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|C|u|r|s|o|r|L|i|n|e|:|E|r@1|o|r|M|s|g| @41
diff --git a/src/testdir/dumps/Test_winhighlight_10.dump b/src/testdir/dumps/Test_winhighlight_10.dump
new file mode 100644
index 000000000..7b42eba43
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_10.dump
@@ -0,0 +1,8 @@
+| +0#ffffff16#e000002|2+0#e000e06&|++0#ffffff16&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@37|X+8#0000001#e0e0e08
+> +8#0000000#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|:+0#0000000&|t|a|b|n| |3| @49|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_11.dump b/src/testdir/dumps/Test_winhighlight_11.dump
new file mode 100644
index 000000000..3534418ac
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_11.dump
@@ -0,0 +1,8 @@
+| +8#0000001#e0e0e08|2+8#e000e06&|++8#0000001&| |[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@37|X+8#0000001#e0e0e08
+> +8#0000000#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|:+0#0000000&|t|a|b|n| |3| @49|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_12.dump b/src/testdir/dumps/Test_winhighlight_12.dump
new file mode 100644
index 000000000..12c31ec11
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_12.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|w+8#0000000#ffffff0|N|e|x>t|w|N|e|x|t|F|o|u|r| @22||+1&&|w+8&&|N|e|x|t|w|N|e|x|t|F|o|u|r| @22
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+0#ffffff16#e000002|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|5| @11|A|l@1| |[+1#0000000#ffffff0|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|5| @11|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|S|t|a|t|u|s|L|i|n|e|:|E|r@1|o|r|M|s|g| @41
diff --git a/src/testdir/dumps/Test_winhighlight_13.dump b/src/testdir/dumps/Test_winhighlight_13.dump
new file mode 100644
index 000000000..ae3e7d3a1
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_13.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|w+0#0000000#ffffff0|N|e|x|t|w|N|e|x|t|F|o|u|r| @22||+1&&|w+8&&|N|e|x|t|w|N|e|x|t|F|o|u|r| @22
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S+8&&|i>x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+0#ffffff16#e000002|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|3| @11|A|l@1| |[+1#0000000#ffffff0|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|5| @11|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|S|t|a|t|u|s|L|i|n|e|:|E|r@1|o|r|M|s|g| @41
diff --git a/src/testdir/dumps/Test_winhighlight_13a.dump b/src/testdir/dumps/Test_winhighlight_13a.dump
new file mode 100644
index 000000000..4a20d4647
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_13a.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|w+0#0000000#ffffff0|N|e|x|t|w|N|e|x|t|F|o|u|r| @22||+1&&|w+8&&|N|e|x|t|w|N|e|x|t|F|o|u|r| @22
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S+8&&|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+0#ffffff16#e000002|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|3| @11|A|l@1| |[+1#0000000#ffffff0|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|5| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_winhighlight_14.dump b/src/testdir/dumps/Test_winhighlight_14.dump
new file mode 100644
index 000000000..1ea869d65
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_14.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|w+0#0000000#ffffff0|N|e|x|t|w|N|e|x|t|F|o|u|r| @22||+1&&|w+8&&|N|e|x>t|w|N|e|x|t|F|o|u|r| @22
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S+8&&|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|3| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|5| @11|A|l@1
+|:+0&&|w|i|n|c|m|d| |l| @65
diff --git a/src/testdir/dumps/Test_winhighlight_15.dump b/src/testdir/dumps/Test_winhighlight_15.dump
new file mode 100644
index 000000000..a90302a86
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_15.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|w+0#0000000#ffffff0|N|e|x|t|w|N|e|x|t|F|o|u|r| @22||+1&&|w+8#ffffff16#e000002|N|e|x>t|w|N|e|x|t|F|o|u|r| @22
+|F+0#0000000#ffffff0|i|v|e| @32||+1&&|F+0#ffffff16#e000002|i|v|e| @32
+|S+8#0000000#ffffff0|i|x| @33||+1&&|S+0#ffffff16#e000002|i|x| @33
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13#e000002| @35
+|~+0&#ffffff0| @35||+1#0000000&|~+0#4040ff13#e000002| @35
+|[+1#0000000#ffffff0|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|3| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|5| @11|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|N|o|r|m|a|l|:|E|r@1|o|r|M|s|g| @45
diff --git a/src/testdir/dumps/Test_winhighlight_2.dump b/src/testdir/dumps/Test_winhighlight_2.dump
new file mode 100644
index 000000000..b84ef7053
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_2.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|F+0#ffffff16#e000002|o|u|r| @32||+1#0000000#ffffff0>F+8&&|o|u|r| @32
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+|:+0&&|w|i|n|c|m|d| |l| @65
diff --git a/src/testdir/dumps/Test_winhighlight_3.dump b/src/testdir/dumps/Test_winhighlight_3.dump
new file mode 100644
index 000000000..636db41a2
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_3.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+>F+8#0000000#ffffff0|o|u|r| @32||+1&&|F+8&&|o|u|r| @32
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=| @60
diff --git a/src/testdir/dumps/Test_winhighlight_6.dump b/src/testdir/dumps/Test_winhighlight_6.dump
new file mode 100644
index 000000000..f5753e118
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_6.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|F+8#0000000#ffffff0|o|u|r| @32||+1&&>F+8&&|o|u|r| @32
+|F+0&&|i|v|e| @32||+1&&|F+0&&|i|v|e| @32
+|S|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|V|e|r|t|S|p|l|i|t|:|E|r@1|o|r|M|s|g| @42
diff --git a/src/testdir/dumps/Test_winhighlight_7.dump b/src/testdir/dumps/Test_winhighlight_7.dump
new file mode 100644
index 000000000..3967f03ef
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_7.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+>F+8#0000000#ffffff0|o|u|r| @32||+0#ffffff16#e000002|F+8#0000000#ffffff0|o|u|r| @32
+|F+0&&|i|v|e| @32||+0#ffffff16#e000002|F+0#0000000#ffffff0|i|v|e| @32
+|S|i|x| @33||+0#ffffff16#e000002|S+0#0000000#ffffff0|i|x| @33
+|~+0#4040ff13&| @35||+0#ffffff16#e000002|~+0#4040ff13#ffffff0| @35
+|~| @35||+0#ffffff16#e000002|~+0#4040ff13#ffffff0| @35
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|V|e|r|t|S|p|l|i|t|:|E|r@1|o|r|M|s|g| @42
diff --git a/src/testdir/dumps/Test_winhighlight_8.dump b/src/testdir/dumps/Test_winhighlight_8.dump
new file mode 100644
index 000000000..69568fc95
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_8.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|w+8#0000000#ffffff0|N|e|x|t>F|o|u|r| @27||+1&&|w+8&&|N|e|x|t|F|o|u|r| @27
+|w+0#0000001#e0e0e08|N|e|x|t| @9| +0#0000000#0000001| +0&#ffffff0@20||+1&&|F+0&&|i|v|e| @32
+|w+0#0000001#ffd7ff255|a+0#ffffff16#e000002|l@1| @10| +0#0000000#a8a8a8255| +0&#ffffff0@20||+1&&|S+0&&|i|x| @33
+|w+0#0000001#ffd7ff255|h+0#ffffff16#e000002|i|l|e| @9| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@20||+1#0000000&|~+0#4040ff13&| @35
+|w+0#0000001#ffd7ff255|i+0#ffffff16#e000002|n|c|m|d| @8| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@20||+1#0000000&|~+0#4040ff13&| @35
+|w+0#0000001#ffd7ff255|i+0#ffffff16#e000002|n|d|o| @9| +0#0000000#a8a8a8255| +3&#ffffff0@2|1|,|1| @11|A|l@1| |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+|-+2&&@1| |C|o|m@1|a|n|d|-|l|i|n|e| |c|o|m|p|l|e|t|i|o|n| |(|^|V|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |1|5| +0#0000000&@25
diff --git a/src/testdir/dumps/Test_winhighlight_9.dump b/src/testdir/dumps/Test_winhighlight_9.dump
new file mode 100644
index 000000000..174531af7
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_9.dump
@@ -0,0 +1,8 @@
+| +2&#ffffff0|2+2#e000e06&|++2#0000000&| |[|N|o| |N|a|m|e|]| | +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +1#0000000#ffffff0@37|X+8#0000001#e0e0e08
+|w+8#0000000#ffffff0|N|e|x|t|w|N|e|x|t|F|o|u|r| @22||+1&&|w+8&&|N|e|x|t>w|N|e|x|t|F|o|u|r| @22
+|F+0&&|i|v|e| @32| +0#0000001#e0e0e08|w|N|e|x|t| @9| +0#0000000#0000001| +0&#ffffff0@20
+|S|i|x| @33| +0#0000001#ffd7ff255|w|a|l@1| @10| +0#0000000#a8a8a8255| +0&#ffffff0@20
+|~+0#4040ff13&| @35| +0#0000001#ffd7ff255|w|h|i|l|e| @9| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@20
+|~| @35| +0#0000001#ffd7ff255|w|i|n|c|m|d| @8| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@20
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|5| @11|A|l@1| +0#0000001#ffd7ff255|w|i|n|d|o| @9| +0#0000000#a8a8a8255| +3&#ffffff0@2|1|,|1| @11|A|l@1
+|-+2&&@1| |C|o|m@1|a|n|d|-|l|i|n|e| |c|o|m|p|l|e|t|i|o|n| |(|^|V|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |1|5| +0#0000000&@25
diff --git a/src/testdir/dumps/Test_winhighlight_copy_1.dump b/src/testdir/dumps/Test_winhighlight_copy_1.dump
new file mode 100644
index 000000000..1e61b6f82
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_copy_1.dump
@@ -0,0 +1,20 @@
+> +0#ffffff16#e000002@36||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+3#0000000&|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1| |[+1&&|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1
+|:+0&&|v|s|p|l|i|t| @67
diff --git a/src/testdir/dumps/Test_winhighlight_hlsearch_1.dump b/src/testdir/dumps/Test_winhighlight_hlsearch_1.dump
new file mode 100644
index 000000000..65f370758
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_hlsearch_1.dump
@@ -0,0 +1,20 @@
+|F+0&#ffffff0|o|u|r| @32||+1&&|F+0&&|o|u|r| @32
+|F|i+0#ffffff16#ff404010|v+0#0000000#ffffff0|e| @32||+1&&|F+0&&|i|v|e| @32
+|S|i+0#ffffff16#ff404010|x+0#0000000#ffffff0| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|2|,|2| @11|A|l@1| |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+|/+0&&|i> @72
diff --git a/src/testdir/dumps/Test_winhighlight_hlsearch_2.dump b/src/testdir/dumps/Test_winhighlight_hlsearch_2.dump
new file mode 100644
index 000000000..30d643854
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_hlsearch_2.dump
@@ -0,0 +1,20 @@
+|F+0&#ffffff0|o|u|r| @32||+1&&|F+0#ffffff16#ff404010|o+0#0000000#ffffff0|u|r| @32
+|F|i|v|e| @32||+1&&|F+0#ffffff16#ff404010|i+0#0000000#ffffff0|v|e| @32
+|S|i|x| @33||+1&&|S+0&&|i|x| @33
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|2|,|1| @11|A|l@1
+|/+0&&|F> @72
diff --git a/src/testdir/dumps/Test_winhighlight_occasion_1.dump b/src/testdir/dumps/Test_winhighlight_occasion_1.dump
new file mode 100644
index 000000000..3ecbc1d3c
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_occasion_1.dump
@@ -0,0 +1,20 @@
+>O+0#ffffff16#4040ff13|n|e| @71
+|T+0&#ff404010|w|o| @71
+|T|h|r|e@1| @69
+|~+0(ff4011| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|:+0#0000000#ffffff0|s|e|t|l|o|c|a|l| |w|h|l|=|!|(|:|A|,|!|.|:|B|,|S|t|a|t|u|s|L|i|n|e|:|!|~| @19|1|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_popupwin_1.dump b/src/testdir/dumps/Test_winhighlight_popupwin_1.dump
new file mode 100644
index 000000000..73e5d8ba4
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_popupwin_1.dump
@@ -0,0 +1,20 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @26|╔+0#ffffff16#ff404010|═@16|╗| +0#4040ff13#ffffff0@27
+|~| @26|║+0#ffffff16#ff404010| |i+0࿈ff13|n|t| +0&#ff404010|h|e|l@1|o| |=| |1+0#e000002&|0|;+0#ffffff16&| |║| +0#4040ff13#ffffff0@27
+|~| @26|╚+0#ffffff16#ff404010|═@16|╝| +0#4040ff13#ffffff0@27
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_popupwin_2.dump b/src/testdir/dumps/Test_winhighlight_popupwin_2.dump
new file mode 100644
index 000000000..2aa8f554b
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_popupwin_2.dump
@@ -0,0 +1,20 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @26|╔+0#0000001#ffd7ff255|═@16|╗| +0#4040ff13#ffffff0@27
+|~| @26|║+0#0000001#ffd7ff255| |i+0#00e0003&|n|t| +0#0000001&|h|e|l@1|o| |=| |1+0#e000002&|0|;+0#0000001&| |║| +0#4040ff13#ffffff0@27
+|~| @26|╚+0#0000001#ffd7ff255|═@16|╝| +0#4040ff13#ffffff0@27
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|:+0#0000000&|c|a|l@1| |w|i|n|_|e|x|e|c|u|t|e|(|g|:|i|d|,| |"|s|e|t| |w|h|l|=|"|)| @21|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_syntax_1.dump b/src/testdir/dumps/Test_winhighlight_syntax_1.dump
new file mode 100644
index 000000000..dacf136cf
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_syntax_1.dump
@@ -0,0 +1,8 @@
+>O+0#ffffff16#e000002|n|e| +0#0000000#ffffff0|T+0#ffffff16#e000002|w|o| +0#0000000#ffffff0@67
+|O+0#ffffff16#e000002|n|e| +0#0000000#ffffff0@71
+|T+0#ffffff16#e000002|w|o| +0#0000000#ffffff0@71
+|T+0#ffffff16#e000002|h|r|e@1| +0#0000000#ffffff0@69
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|:+0#0000000&|s|e|t|l|o|c|a|l| |w|h|l|=|A|:|E|r@1|o|r|M|s|g| @32|1|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_syntax_2.dump b/src/testdir/dumps/Test_winhighlight_syntax_2.dump
new file mode 100644
index 000000000..691807c2c
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_syntax_2.dump
@@ -0,0 +1,8 @@
+>O+0#ffffff16#4040ff13|n|e| +0#0000000#ffffff0|T+0#ffffff16#e000002|w|o| +0#0000000#ffffff0@67
+|O+0#ffffff16#4040ff13|n|e| +0#0000000#ffffff0@71
+|T+0#ffffff16#e000002|w|o| +0#0000000#ffffff0@71
+|T+0#ffffff16#e000002|h|r|e@1| +0#0000000#ffffff0@69
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|:+0#0000000&|s|e|t|l|o|c|a|l| |w|h|l|=|B|:|E|r@1|o|r|M|s|g| @32|1|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_syntax_3.dump b/src/testdir/dumps/Test_winhighlight_syntax_3.dump
new file mode 100644
index 000000000..77abcbd0f
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_syntax_3.dump
@@ -0,0 +1,8 @@
+>O+0#ffffff16#4040ff13|n|e| +0#0000000#ffffff0|T+0#ffffff16#4040ff13|w|o| +0#0000000#ffffff0@67
+|O+0#ffffff16#4040ff13|n|e| +0#0000000#ffffff0@71
+|T+0#ffffff16#4040ff13|w|o| +0#0000000#ffffff0@71
+|T+0#ffffff16#e000002|h|r|e@1| +0#0000000#ffffff0@69
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|:+0#0000000&|s|e|t|l|o|c|a|l| |w|h|l|=|C|:|E|r@1|o|r|M|s|g| @32|1|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_winhighlight_term_1.dump b/src/testdir/dumps/Test_winhighlight_term_1.dump
new file mode 100644
index 000000000..18fffa501
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_term_1.dump
@@ -0,0 +1,20 @@
+>>+0#ffffff16#e000002| @73
+|~+0#4040ff13#ffffff0| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|!+2#ffffff16#00e0003|s|h| |[|T|e|r|m|i|n|a|l|]| @42|1|,|1| @11|A|l@1
+| +0#0000000#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|T|e|r|m|i|n|a|l|:|E|r@1|o|r|M|s|g| @43
diff --git a/src/testdir/dumps/Test_winhighlight_term_2.dump b/src/testdir/dumps/Test_winhighlight_term_2.dump
new file mode 100644
index 000000000..33bd034ee
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_term_2.dump
@@ -0,0 +1,20 @@
+|>+0#ffffff16#e000002> @73
+@75
+@75
+@75
+@75
+@75
+@75
+@75
+@75
+|!+2�e0003|s|h| |[|r|u|n@1|i|n|g|]| @43|1|,|1| @11|A|l@1
+| +0#0000000#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
+|:+0&&|s|e|t|l|o|c|a|l| |w|h|l|=|T|e|r|m|i|n|a|l|:|E|r@1|o|r|M|s|g| @43
diff --git a/src/testdir/dumps/Test_winhighlight_term_3.dump b/src/testdir/dumps/Test_winhighlight_term_3.dump
new file mode 100644
index 000000000..e5760d083
--- /dev/null
+++ b/src/testdir/dumps/Test_winhighlight_term_3.dump
@@ -0,0 +1,20 @@
+|>+0#ffffff16#e000002> @35||+1#0000000#ffffff0|>+0#ffffff16#e000002| @35
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+@37||+1#0000000#ffffff0| +0#ffffff16#e000002@36
+|!+2�e0003|s|h| |[|r|u|n@1|i|n|g|]| @5|1|,|1| @11|A|l@1| |!+0&&|s|h| |[|r|u|n@1|i|n|g|]| @5|1|,|1| @11|A|l@1
+| +0#0000000#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
+| +0&&@74
diff --git a/src/testdir/test_highlight.vim b/src/testdir/test_highlight.vim
index c8d6e76ab..0cb6b5b10 100644
--- a/src/testdir/test_highlight.vim
+++ b/src/testdir/test_highlight.vim
@@ -1355,4 +1355,328 @@ func Test_hlset()
call assert_true(hlget('hlg11')[0].cleared)
endfunc
+" Test for the 'winhighlight' option
+func Test_winhighlight()
+ CheckScreendump
+
+ let lines =<< trim END
+ set cursorline
+ call setline(1, ['Four', 'Five', 'Six'])
+ vsplit
+ tabnew
+ tabnew
+ tabfirst
+ END
+ call writefile(lines, 'Xtest_winhighlight', 'D')
+
+ let buf = RunVimInTerminal('-S Xtest_winhighlight', {'rows': 8})
+ call TermWait(buf)
+
+ " Test that window highlight groups are actually local per window
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=CursorLine:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_1', {})
+
+ call term_sendkeys(buf, "\<Esc>:wincmd l\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_2', {})
+
+ call term_sendkeys(buf, "\<Esc>:wincmd h\<CR>\<Esc>:setlocal whl=\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_3', {})
+
+ " Dump files 4 and 5 used to exist, but were removed later, too lazy to
+ " renumber the dump files...
+
+ " Test that VertSplit in winhighlight only affects border if window that
+ " winhighlight is local to is on the left side of the separator/column
+ call term_sendkeys(buf, "\<Esc>:wincmd l\<CR>")
+ call TermWait(buf)
+
+ " Shouldn't affect separator
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=VertSplit:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_6', {})
+
+ call term_sendkeys(buf, "\<Esc>:wincmd h\<CR>")
+ call TermWait(buf)
+
+ " Should affect separator
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=VertSplit:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_7', {})
+
+ " Test that popup menu highlight is affected by current window only
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=Pmenu:ErrorMsg\<CR>iw\<C-x>\<C-v>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_8', {})
+
+ " Switch to other window (shouldn't be affected)
+ call term_sendkeys(buf, "\<Esc>:wincmd l\<CR>iw\<C-x>\<C-v>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_9', {})
+
+ " Test that tabline highlight uses 'winhighlight' of last focused window in
+ " tabpage
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=TabLine:ErrorMsg\<CR>\<Esc>:tabn 3\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_10', {})
+
+ " Make last focused window the other window, which should have no hightlight
+ " in tabline.
+ call term_sendkeys(buf, "\<Esc>:tabn 1\<CR>\<Esc>:wincmd h\<CR>\<Esc>:tabn 3\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_11', {})
+
+ " Test if statusline is highlighted correctly local to window.
+ call term_sendkeys(buf, "\<Esc>:tabn 1\<CR>\<Esc>:set ruler\<CR>\<Esc>:setlocal whl=StatusLine:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_12', {})
+
+ " Make status line change
+ call term_sendkeys(buf, "\<Esc>jj")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_13', {})
+
+ " Go into command line mode (status line should still have same highlight)
+ call term_sendkeys(buf, "\<Esc>:")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_13a', {})
+
+ " Go to next window (statusline highlighting for other window should stop)
+ call term_sendkeys(buf, "\<CR>\<Esc>:wincmd l\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_14', {})
+
+ " Check that overridding Normal group maps to HLF_WIN in 'highlight'.
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=Normal:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_15', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test if 'hlsearch' highlighting works correctly with 'winhighlight'
+func Test_winhighlight_hlsearch()
+ CheckScreendump
+
+ let lines =<< trim END
+ vim9script
+
+ hi A ctermbg=red ctermfg=white
+ hi B ctermbg=red ctermfg=white
+ hi link Search B
+ hi link IncSearch B
+
+ autocmd CmdlineEnter [\/\?] {
+ setlocal whl=Search:A,IncSearch:B
+ hi clear Search
+ hi clear IncSearch
+ }
+ autocmd CmdlineLeave [\/\?] {
+ setlocal whl=
+ hi link Search B
+ hi link IncSearch B
+ }
+
+ setline(1, ['One', 'Two', 'Three'])
+ vsplit
+ setline(1, ['Four', 'Five', 'Six'])
+
+ set incsearch
+ set hlsearch
+ END
+ call writefile(lines, 'Xtest_winhighlight_hlsearch', 'D')
+
+ let buf = RunVimInTerminal('-S Xtest_winhighlight_hlsearch', {'rows': 20})
+ call TermWait(buf)
+
+ call term_sendkeys(buf, "\<Esc>/i")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_hlsearch_1', {})
+
+ call term_sendkeys(buf, "\<Esc>:wincmd l\<CR>")
+ call TermWait(buf)
+
+ call term_sendkeys(buf, "\<Esc>/F")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_hlsearch_2', {})
+
+ call term_sendkeys(buf, "\<Esc>") " Must exit search mode
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test if syntax highlighting works correctly with 'winhighlight'. Also tests
+" handling of highlight links.
+func Test_winhighlight_syntax()
+ CheckScreendump
+
+ let lines =<< trim END
+ vim9script
+
+ hi A ctermbg=blue ctermfg=white
+ hi link B A
+ hi link C B
+ syntax match A display "One"
+ syntax match B display "Two"
+ syntax match C display "Three"
+
+ setline(1, ["One Two", "One", "Two", "Three"])
+ END
+ call writefile(lines, 'Xtest_winhighlight_syntax', 'D')
+
+ let buf = RunVimInTerminal('-S Xtest_winhighlight_syntax', {'rows': 8})
+ call TermWait(buf)
+
+ " Since A is the root of the link chain, it should affect all
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=A:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_syntax_1', {})
+
+ " Since B is in the middle, B and C should be overridden, but not A
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=B:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_syntax_2', {})
+
+ " Since C is is last, it should only be overridden
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=C:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_syntax_3', {})
+
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=A:ErrorMsg,C:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test if terminal is correctly highlighted using 'winhighlight'
+func Test_winhighlight_term()
+ CheckScreendump
+ CheckUnix
+
+ let lines =<< trim END
+ terminal sh
+ END
+ call writefile(lines, 'Xtest_winhighlight_term', 'D')
+
+ let buf = RunVimInTerminal('-S Xtest_winhighlight_term', {'rows': 20, 'env': {'PS1': '>'}})
+ call TermWait(buf)
+
+ call term_sendkeys(buf, "\<C-\>\<C-n>\<Esc>:setlocal whl=Terminal:ErrorMsg\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_term_1', {})
+
+ call term_sendkeys(buf, "i")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_term_2', {})
+
+ " New terminal should have copied over winhighlight settings and updated
+ " accordingly.
+ call term_sendkeys(buf, "\<C-\>\<C-N>\<Esc>:vsplit\<CR>i")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_term_3', {})
+
+ call term_sendkeys(buf, "\<C-\>\<C-N>\<Esc>:bw!\<CR>")
+ call TermWait(buf)
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test if 'winhighlight' works correctly in popup windows
+func Test_winhighlight_popupwin()
+ CheckScreendump
+ CheckUnix
+
+ let lines =<< trim END
+ vim9script
+
+ g:id = popup_dialog("int hello = 10;", {})
+
+ hi A ctermbg=red ctermfg=white
+ hi B ctermbg=blue ctermfg=white
+
+ redraw! # Remove intro message
+ win_execute(g:id, "set filetype=c whl=Pmenu:A,cType:B")
+ END
+ call writefile(lines, 'Xtest_winhighlight_popupwin', 'D')
+
+ let buf = RunVimInTerminal('-S Xtest_winhighlight_popupwin', {'rows': 20})
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_popupwin_1', {})
+
+ call term_sendkeys(buf, "\<Esc>:call win_execute(g:id, \"set whl=\")\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_popupwin_2', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test that 'winhighlight' setting is copied over to new split window
+func Test_winhighlight_copy()
+ CheckScreendump
+
+ let buf = RunVimInTerminal('', {'rows': 20})
+ call TermWait(buf)
+
+ call term_sendkeys(buf, "\<Esc>:setlocal cursorline whl=CursorLine:ErrorMsg\<CR>\<Esc>:vsplit\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_copy_1', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test if using a 'highlight' occasion instead of highlight group name works
+" correctly.
+func Test_winhighlight_occasion()
+ CheckScreendump
+
+ let lines =<< trim END
+ highlight A ctermbg=red ctermfg=white
+ highlight B ctermbg=blue ctermfg=white
+ highlight EndOfBuffer ctermbg=green
+
+ set cursorline
+
+ call setline(1, ["One", "Two", "Three"])
+ END
+ call writefile(lines, 'Xtest_winhighlight_occasion', 'D')
+
+ let buf = RunVimInTerminal('-S Xtest_winhighlight_occasion', {'rows': 20})
+ call TermWait(buf)
+
+ call term_sendkeys(buf, "\<Esc>:setlocal whl=!(:A,!.:B,StatusLine:!~\<CR>")
+ call TermWait(buf)
+
+ call VerifyScreenDump(buf, 'Test_winhighlight_occasion_1', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 58b7620c3..dc1399793 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -623,6 +623,11 @@ func Test_set_completion_string_values()
call assert_equal('top', getcompletion('set printoptions=', 'cmdline')[0])
call assert_equal('SpecialKey', getcompletion('set wincolor=', 'cmdline')[0])
+ call assert_equal('SpecialKey', getcompletion('set winhighlight=', 'cmdline')[0])
+ call assert_equal('SpecialKey', getcompletion('set winhighlight=SpecialKey:', 'cmdline')[0])
+ call assert_equal('SpecialKey', getcompletion('set winhighlight=SpecialKey:SpecialKey,', 'cmdline')[0])
+ call assert_equal('!8', getcompletion('set winhighlight=SpecialKey:SpecialKey,!', 'cmdline')[0])
+
call assert_equal('eol', getcompletion('set listchars+=', 'cmdline')[0])
call assert_equal(['multispace', 'leadmultispace'], getcompletion('set listchars+=', 'cmdline')[-2:])
call assert_equal(['tab', 'leadtab'], getcompletion('set listchars+=', 'cmdline')[5:6])
diff --git a/src/testdir/util/gen_opt_test.vim b/src/testdir/util/gen_opt_test.vim
index 071a158eb..0a010a9f4 100644
--- a/src/testdir/util/gen_opt_test.vim
+++ b/src/testdir/util/gen_opt_test.vim
@@ -358,6 +358,9 @@ let test_values = {
\ ['xxx', 'a4', 'full,full,full,full,full']],
\ 'wildoptions': [['', 'tagfile', 'pum', 'fuzzy'], ['xxx']],
\ 'winaltkeys': [['no', 'yes', 'menu'], ['', 'xxx']],
+ \ 'winhighlight': [['Search:Errormsg,Comment:String', 'Search:Comment', ''],
+ \ ['xxx', ',', 'Search:Comment,', 'Search:Errormsg,Comment:String,',
+ \ ':', 'Search:,', 'Search:']],
\
"\ skipped options
\ 'luadll': [[], []],
diff --git a/src/version.c b/src/version.c
index 2ef4469fe..40ab10bfe 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 93,
/**/
92,
/**/
diff --git a/src/vim.h b/src/vim.h
index 1e75d8a2b..1a38606f7 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1593,6 +1593,7 @@ typedef enum
, HLF_TPLS // tabpanel selected
, HLF_TPLF // tabpanel filler
, HLF_PRI // "preinsert" in 'completeopt'
+ , HLF_WIN // window colour
, HLF_COUNT // MUST be the last one
} hlf_T;
@@ -1605,7 +1606,7 @@ typedef enum
'+', '=', 'k', '<','[', ']', '{', '}', 'x', 'X', 'j', 'H', \
'*', '#', '_', '!', '.', 'o', 'q', \
'z', 'Z', 'g', \
- '%', '^', '&', 'I'}
+ '%', '^', '&', 'I', '('}
/*
* Values for behaviour in spell_move_to
diff --git a/src/window.c b/src/window.c
index e8142ca20..bfca2c345 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1611,8 +1611,13 @@ win_init(win_T *newp, win_T *oldp, int flags UNUSED)
#endif
win_init_some(newp, oldp);
+
#ifdef FEAT_TERMINAL
- term_update_wincolor(newp);
+ // Make sure to also handle highlight overrides copied over from oldp.
+ push_highlight_overrides(newp->w_hl, newp->w_hl_len);
+ if (newp->w_buffer->b_term != NULL)
+ term_init_default_colors(newp->w_buffer->b_term);
+ pop_highlight_overrides();
#endif
}
@@ -2522,7 +2527,7 @@ win_init_empty(win_T *wp)
wp->w_s = &wp->w_buffer->b_s;
#endif
#ifdef FEAT_TERMINAL
- term_reset_wincolor(wp);
+ term_reset_hlfwin(wp);
#endif
}
@@ -5978,6 +5983,8 @@ win_free(
ruby_window_free(wp);
#endif
+ vim_free(wp->w_hl);
+
clear_winopt(&wp->w_onebuf_opt);
clear_winopt(&wp->w_allbuf_opt);