]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0093: Not possible to have window-local highlighting groups v9.2.0093
authorFoxe Chen <chen.foxe@gmail.com>
Mon, 2 Mar 2026 19:36:07 +0000 (19:36 +0000)
committerChristian Brabandt <cb@256bit.org>
Mon, 2 Mar 2026 19:36:07 +0000 (19:36 +0000)
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.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
57 files changed:
ci/hlgroups.ignore
runtime/doc/options.txt
runtime/doc/popup.txt
runtime/doc/quickref.txt
runtime/doc/tags
runtime/doc/version9.txt
runtime/optwin.vim
runtime/syntax/vim.vim
src/drawline.c
src/drawscreen.c
src/highlight.c
src/match.c
src/option.c
src/option.h
src/optiondefs.h
src/optionstr.c
src/popupmenu.c
src/popupwin.c
src/proto/highlight.pro
src/proto/optionstr.pro
src/proto/screen.pro
src/proto/terminal.pro
src/screen.c
src/structs.h
src/terminal.c
src/testdir/dumps/Test_winhighlight_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_10.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_11.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_12.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_13.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_13a.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_14.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_15.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_3.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_6.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_7.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_8.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_9.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_copy_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_hlsearch_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_hlsearch_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_occasion_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_popupwin_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_popupwin_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_syntax_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_syntax_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_syntax_3.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_term_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_term_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_winhighlight_term_3.dump [new file with mode: 0644]
src/testdir/test_highlight.vim
src/testdir/test_options.vim
src/testdir/util/gen_opt_test.vim
src/version.c
src/vim.h
src/window.c

index a046eb127daf2a5fd9ade1b3959f34f8b410e5e6..681b120875867ece3fe5f6275ee10cb096dbb13e 100644 (file)
@@ -67,3 +67,4 @@ Visual
 VisualNOS
 WarningMsg
 WildMenu
+WinColor
index 6986fde86bc93b6e9b5ccad6831678dc3abf66f0..327494d68a2587e5c7441627c898c75d08a08dcc 100644 (file)
@@ -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
index 021410eb2cdc5c828318ed817f4a106f1b7fd083..e968a21075a2a3646c2dff7dd5ac8ab83248d039 100644 (file)
@@ -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)
index 2d4cf57e784a51290e735400dc96a7d92323600e..e7b2068b021532e0c84dc9f1b09f25c16aca737d 100644 (file)
@@ -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
index e4478f0d7ad767852a071113d7c729317002addd..a881c0acfe5f921013dbf8d3f8d9c48b805baf65 100644 (file)
@@ -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'*
index 85a6c80322f3a5bff6d2a64f0df5595ecdfdce4b..120c1960d483b294665ee1793c9779188e3b5171 100644 (file)
@@ -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*
index 28d91abc5c798d7bb914e0b6f94115bfd1e4c186..705195d0e015b3dae6f128b1e8127dbb7721d924 100644 (file)
@@ -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 <Bram@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("$", "\t" .. s:local_to_window)
 call <SID>OptionL("wcr")
+call <SID>AddOption("winhighlight", gettext("highlight group mappings for the window"))
+call append("$", "\t" .. 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)
index 4c96b6e7a1138c8061efe19e3d9b928b49e7ef96..a81f82bd58e126a0ac5c00312e38e9894a17808c 100644 (file)
@@ -2,7 +2,7 @@
 " Language:       Vim script
 " Maintainer:     Hirohito Higashi <h.east.727 ATMARK gmail.com>
 "         Doug Kearns <dougkearns@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
index 2758e882ec14a8114aed5289ddfce45ee8c9e5a5..4597d8d3cae7acf1057a6de45a84f4c117434671 100644 (file)
@@ -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 ||
index aff03cb87224ad98447599c24bbe6be95147ddf3..8ce8826c12e3b24863f2fda4ee132ee439260b93 100644 (file)
@@ -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();
 
index f4d6867aa570892e2f6a26840f2cdc485b064cf8..5ce3ea107b6c4c628c703c4911266ae206313424 100644 (file)
@@ -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;
+}
index ff7e8d9f3dfe26d5d4257ebc9d50dbb990562431..912abfd74b8ea12a2d2c8a9a9e8e4fd7399c3c15 100644 (file)
@@ -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;
index e4a94e1c6ee951a604635d9bc2999593cf68f6a6..8de0d9c685d8b066989bc49e183306f8fe70b018 100644 (file)
@@ -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
index 46b8daf09e33d5c0525eb5df24779e974432b1ba..fddc3905cbeb954483a7e2d3a6bfc7171cff3fdf 100644 (file)
@@ -1389,6 +1389,7 @@ enum
     , WV_WFB
     , WV_WFH
     , WV_WFW
+    , WV_WHL
     , WV_WRAP
 #ifdef FEAT_SIGNS
     , WV_SCL
index 65094348091cb2aa8093ad99c9fdd93154a99fd3..2a2b1c0da655c56d76659246e07e2004cd1dd4f9 100644 (file)
 #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},
index d4287b46cc9621e1891b96ed15c25607c2b4126a..7fb8bf548a5dcdebb133fe9cf5ad932be46cca25 100644 (file)
@@ -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)
 {
index d316ba99edf740cce2e3c39b95b19b8f3d410fd6..b8c72d44f8cd0793413a38be9be64aa7491f0123 100644 (file)
@@ -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)
index 399ab67ac3c99f19c07d7717ed1bfad65be2019a..7cd39b071c91886d272e52c28008fefc29fc4cf5 100644 (file)
@@ -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
index 908765c2177b6f81972c303be12258e8327edb33..a7691c88fc73a268ff2eed217333af6995ceded6 100644 (file)
@@ -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 : */
index 7e55d3b19990a5359084d578ec88aca54a3a69a5..e4e39e759cd27bda8a658ca379951b45b9865cae 100644 (file)
@@ -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);
index cf7cd95f46210b64b1c580191ac6bd1233764b8f..2dce8869173bac06c91e1427325f17799a7561a3 100644 (file)
@@ -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);
index dfa59cced12c14eadb6a511fc450fc43d969ddb7..5ae6b4ca61e8b5e5634070fbb7de33bf50237041 100644 (file)
@@ -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);
index 716715558cbbb967b6ed3ed76fef29b1bba504d1..316b18b207714bc4fcbab93baf600aa747338036 100644 (file)
@@ -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)
index 1fdc2ee1b90635e31c3cee1c4b980d23c039eac0..b0b559e8a95f36c4f06891965c05f415252a6030 100644 (file)
@@ -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.
 };
 
 /*
index 02ca5d6d95b798335358e91c84d2af6aed7bb300..cea79dac6e726a36df29f021a08365094753419f 100644 (file)
@@ -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 (file)
index 0000000..aa2760b
--- /dev/null
@@ -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 (file)
index 0000000..7b42eba
--- /dev/null
@@ -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 (file)
index 0000000..3534418
--- /dev/null
@@ -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 (file)
index 0000000..12c31ec
--- /dev/null
@@ -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 (file)
index 0000000..ae3e7d3
--- /dev/null
@@ -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 (file)
index 0000000..4a20d46
--- /dev/null
@@ -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 (file)
index 0000000..1ea869d
--- /dev/null
@@ -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 (file)
index 0000000..a90302a
--- /dev/null
@@ -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 (file)
index 0000000..b84ef70
--- /dev/null
@@ -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 (file)
index 0000000..636db41
--- /dev/null
@@ -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 (file)
index 0000000..f5753e1
--- /dev/null
@@ -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 (file)
index 0000000..3967f03
--- /dev/null
@@ -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 (file)
index 0000000..69568fc
--- /dev/null
@@ -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 (file)
index 0000000..174531a
--- /dev/null
@@ -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 (file)
index 0000000..1e61b6f
--- /dev/null
@@ -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 (file)
index 0000000..65f3707
--- /dev/null
@@ -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 (file)
index 0000000..30d6438
--- /dev/null
@@ -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 (file)
index 0000000..3ecbc1d
--- /dev/null
@@ -0,0 +1,20 @@
+>O+0#ffffff16#4040ff13|n|e| @71
+|T+0&#ff404010|w|o| @71
+|T|h|r|e@1| @69
+|~+0&#40ff4011| @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 (file)
index 0000000..73e5d8b
--- /dev/null
@@ -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&#4040ff13|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 (file)
index 0000000..2aa8f55
--- /dev/null
@@ -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 (file)
index 0000000..dacf136
--- /dev/null
@@ -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 (file)
index 0000000..691807c
--- /dev/null
@@ -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 (file)
index 0000000..77abcbd
--- /dev/null
@@ -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 (file)
index 0000000..18fffa5
--- /dev/null
@@ -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 (file)
index 0000000..33bd034
--- /dev/null
@@ -0,0 +1,20 @@
+|>+0#ffffff16#e000002> @73
+@75
+@75
+@75
+@75
+@75
+@75
+@75
+@75
+|!+2&#00e0003|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 (file)
index 0000000..e5760d0
--- /dev/null
@@ -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&#00e0003|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
index c8d6e76abb5444bb6c55f80701b379f2d813257c..0cb6b5b102039fac1a48eabf499202ebeb342ea6 100644 (file)
@@ -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
index 58b7620c3e98cc801a381b4a37664caa6f1737b4..dc1399793ac8282a898fbd69d322de6dfcc79dc0 100644 (file)
@@ -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])
index 071a158ebdf6c875c38636eedfbbec76c803f1ed..0a010a9f4ad9646044c54744b1f152bdf2b167fe 100644 (file)
@@ -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': [[], []],
index 2ef4469fe510a545e85910e2cd581cc6fef7cf05..40ab10bfe4639217408926a799f145a515bef4d6 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    93,
 /**/
     92,
 /**/
index 1e75d8a2be60f1811b7d4d56c4f4dba05dd83365..1a38606f7c286c1e4cf24c5436b99b793b7a7c6d 100644 (file)
--- 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
index e8142ca202b9450a8f2b280d925f56c2b1ce8dd0..bfca2c345ae214783841bfa7878ca02230071ef8 100644 (file)
@@ -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);