diff options
-rw-r--r-- | runtime/doc/options.txt | 13 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 17 | ||||
-rw-r--r-- | src/nvim/globals.h | 118 | ||||
-rw-r--r-- | src/nvim/highlight_defs.h | 126 | ||||
-rw-r--r-- | src/nvim/option.c | 23 | ||||
-rw-r--r-- | src/nvim/popupmnu.c | 8 | ||||
-rw-r--r-- | src/nvim/screen.c | 417 | ||||
-rw-r--r-- | src/nvim/syntax_defs.h | 3 | ||||
-rw-r--r-- | src/nvim/terminal.c | 6 | ||||
-rw-r--r-- | src/nvim/window.c | 4 | ||||
-rw-r--r-- | test/functional/ui/highlight_spec.lua | 170 |
11 files changed, 547 insertions, 358 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 2097cbf32b..bb5cfb4a80 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6778,9 +6778,16 @@ A jump table for the options with a short description can be found at |Q_op|. Window-local highlights. Comma-delimited list of |group-name| pairs "{hl-builtin}:{hl-group},..." where each {hl-builtin} is a group (from |highlight-groups|) to be overridden by {hl-group} in the window where - this option was set. - Currently |hl-Normal| and |hl-NormalNC| can be overridden. - Useful for changing the background color. Example: > + this option was set. Only builting ui highlights are supported, not + syntax highlighting. For that purpose, use |:ownsyntax|. + + Most highlights occuring within the frame of a window are supported. + Highlights of vertical separators are determined by the window to the + left of the separator. The highlight of a tabpage in |tabline| is + determined by the last focused window in the tabpage. Highlights of + the popupmenu are determined by the current window. Highlights in the + message area are not overridable. Example for overriding the + backgrond color: > set winhighlight=Normal:MyNormal,NormalNC:MyNormalNC < *'winfixheight'* *'wfh'* *'nowinfixheight'* *'nowfh'* diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index c065ce60f1..af2b50e22d 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -18,6 +18,8 @@ typedef struct { // for garray_T #include "nvim/garray.h" +// for HLF_COUNT +#include "nvim/highlight_defs.h" // for pos_T, lpos_T and linenr_T #include "nvim/pos.h" // for the number window-local and buffer-local options @@ -936,9 +938,13 @@ struct window_S { synblock_T *w_s; /* for :ownsyntax */ - int w_hl_id; ///< 'winhighlight' id - int w_hl_id_inactive; ///< 'winhighlight' id for inactive window - int w_hl_attr; ///< 'winhighlight' final attrs + int w_hl_id_normal; ///< 'winhighlight' normal id + int w_hl_attr_normal; ///< 'winhighlight' normal final attrs + + int w_hl_ids[HLF_COUNT]; ///< 'winhighlight' id + int w_hl_attrs[HLF_COUNT]; ///< 'winhighlight' final attrs + + int w_hl_needs_update; ///< attrs need to be recalculated win_T *w_prev; /* link to previous window */ win_T *w_next; /* link to next window */ @@ -1169,4 +1175,9 @@ struct window_S { qf_info_T *w_llist_ref; }; +static inline int win_hl_attr(win_T *wp, int hlf) +{ + return wp->w_hl_attrs[hlf]; +} + #endif // NVIM_BUFFER_DEFS_H diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 0e84900d48..840be928c8 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -439,124 +439,6 @@ EXTERN int did_check_timestamps INIT(= FALSE); /* did check timestamps recently */ EXTERN int no_check_timestamps INIT(= 0); /* Don't check timestamps */ -/* - * Values for index in highlight_attr[]. - * When making changes, also update hlf_names below! - */ -typedef enum { - HLF_8 = 0 /* Meta & special keys listed with ":map", text that is - displayed different from what it is */ - , HLF_EOB // after the last line in the buffer - , HLF_TERM // terminal cursor focused - , HLF_TERMNC // terminal cursor unfocused - , HLF_AT // @ characters at end of screen, characters that - // don't really exist in the text - , HLF_D // directories in CTRL-D listing - , HLF_E // error messages - , HLF_I // incremental search - , HLF_L // last search string - , HLF_M // "--More--" message - , HLF_CM // Mode (e.g., "-- INSERT --") - , HLF_N // line number for ":number" and ":#" commands - , HLF_CLN // current line number - , HLF_R // return to continue message and yes/no questions - , HLF_S // status lines - , HLF_SNC // status lines of not-current windows - , HLF_C // column to separate vertically split windows - , HLF_T // Titles for output from ":set all", ":autocmd" etc. - , HLF_V // Visual mode - , HLF_VNC // Visual mode, autoselecting and not clipboard owner - , HLF_W // warning messages - , HLF_WM // Wildmenu highlight - , HLF_FL // Folded line - , HLF_FC // Fold column - , HLF_ADD // Added diff line - , HLF_CHD // Changed diff line - , HLF_DED // Deleted diff line - , HLF_TXD // Text Changed in diff line - , HLF_SC // Sign column - , HLF_CONCEAL // Concealed text - , HLF_SPB // SpellBad - , HLF_SPC // SpellCap - , HLF_SPR // SpellRare - , HLF_SPL // SpellLocal - , HLF_PNI // popup menu normal item - , HLF_PSI // popup menu selected item - , HLF_PSB // popup menu scrollbar - , HLF_PST // popup menu scrollbar thumb - , HLF_TP // tabpage line - , HLF_TPS // tabpage line selected - , HLF_TPF // tabpage line filler - , HLF_CUC // 'cursurcolumn' - , HLF_CUL // 'cursurline' - , HLF_MC // 'colorcolumn' - , HLF_QFL // selected quickfix line - , HLF_0 // Whitespace - , HLF_INACTIVE // NormalNC: Normal text in non-current windows - , HLF_COUNT // MUST be the last one -} hlf_T; - -EXTERN const char *hlf_names[] INIT(= { - [HLF_8] = "SpecialKey", - [HLF_EOB] = "EndOfBuffer", - [HLF_TERM] = "TermCursor", - [HLF_TERMNC] = "TermCursorNC", - [HLF_AT] = "NonText", - [HLF_D] = "Directory", - [HLF_E] = "ErrorMsg", - [HLF_I] = "IncSearch", - [HLF_L] = "Search", - [HLF_M] = "MoreMsg", - [HLF_CM] = "ModeMsg", - [HLF_N] = "LineNr", - [HLF_CLN] = "CursorLineNr", - [HLF_R] = "Question", - [HLF_S] = "StatusLine", - [HLF_SNC] = "StatusLineNC", - [HLF_C] = "VertSplit", - [HLF_T] = "Title", - [HLF_V] = "Visual", - [HLF_VNC] = "VisualNOS", - [HLF_W] = "WarningMsg", - [HLF_WM] = "WildMenu", - [HLF_FL] = "Folded", - [HLF_FC] = "FoldColumn", - [HLF_ADD] = "DiffAdd", - [HLF_CHD] = "DiffChange", - [HLF_DED] = "DiffDelete", - [HLF_TXD] = "DiffText", - [HLF_SC] = "SignColumn", - [HLF_CONCEAL] = "Conceal", - [HLF_SPB] = "SpellBad", - [HLF_SPC] = "SpellCap", - [HLF_SPR] = "SpellRare", - [HLF_SPL] = "SpellLocal", - [HLF_PNI] = "Pmenu", - [HLF_PSI] = "PmenuSel", - [HLF_PSB] = "PmenuSbar", - [HLF_PST] = "PmenuThumb", - [HLF_TP] = "TabLine", - [HLF_TPS] = "TabLineSel", - [HLF_TPF] = "TabLineFill", - [HLF_CUC] = "CursorColumn", - [HLF_CUL] = "CursorLine", - [HLF_MC] = "ColorColumn", - [HLF_QFL] = "QuickFixLine", - [HLF_0] = "Whitespace", - [HLF_INACTIVE] = "NormalNC", -}); - - -EXTERN int highlight_attr[HLF_COUNT]; /* Highl. attr for each context. */ -EXTERN int highlight_user[9]; /* User[1-9] attributes */ -EXTERN int highlight_stlnc[9]; /* On top of user */ -EXTERN int cterm_normal_fg_color INIT(= 0); -EXTERN int cterm_normal_fg_bold INIT(= 0); -EXTERN int cterm_normal_bg_color INIT(= 0); -EXTERN RgbValue normal_fg INIT(= -1); -EXTERN RgbValue normal_bg INIT(= -1); -EXTERN RgbValue normal_sp INIT(= -1); - EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */ EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */ EXTERN int autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */ diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h new file mode 100644 index 0000000000..927fc94bbe --- /dev/null +++ b/src/nvim/highlight_defs.h @@ -0,0 +1,126 @@ +#ifndef NVIM_HIGHLIGHT_DEFS_H +#define NVIM_HIGHLIGHT_DEFS_H + +#include <inttypes.h> + +#include "nvim/macros.h" + +typedef int32_t RgbValue; + +/// Values for index in highlight_attr[]. +/// When making changes, also update hlf_names below! +typedef enum { + HLF_8 = 0 // Meta & special keys listed with ":map", text that is + // displayed different from what it is + , HLF_EOB // after the last line in the buffer + , HLF_TERM // terminal cursor focused + , HLF_TERMNC // terminal cursor unfocused + , HLF_AT // @ characters at end of screen, characters that + // don't really exist in the text + , HLF_D // directories in CTRL-D listing + , HLF_E // error messages + , HLF_I // incremental search + , HLF_L // last search string + , HLF_M // "--More--" message + , HLF_CM // Mode (e.g., "-- INSERT --") + , HLF_N // line number for ":number" and ":#" commands + , HLF_CLN // current line number + , HLF_R // return to continue message and yes/no questions + , HLF_S // status lines + , HLF_SNC // status lines of not-current windows + , HLF_C // column to separate vertically split windows + , HLF_T // Titles for output from ":set all", ":autocmd" etc. + , HLF_V // Visual mode + , HLF_VNC // Visual mode, autoselecting and not clipboard owner + , HLF_W // warning messages + , HLF_WM // Wildmenu highlight + , HLF_FL // Folded line + , HLF_FC // Fold column + , HLF_ADD // Added diff line + , HLF_CHD // Changed diff line + , HLF_DED // Deleted diff line + , HLF_TXD // Text Changed in diff line + , HLF_SC // Sign column + , HLF_CONCEAL // Concealed text + , HLF_SPB // SpellBad + , HLF_SPC // SpellCap + , HLF_SPR // SpellRare + , HLF_SPL // SpellLocal + , HLF_PNI // popup menu normal item + , HLF_PSI // popup menu selected item + , HLF_PSB // popup menu scrollbar + , HLF_PST // popup menu scrollbar thumb + , HLF_TP // tabpage line + , HLF_TPS // tabpage line selected + , HLF_TPF // tabpage line filler + , HLF_CUC // 'cursurcolumn' + , HLF_CUL // 'cursurline' + , HLF_MC // 'colorcolumn' + , HLF_QFL // selected quickfix line + , HLF_0 // Whitespace + , HLF_INACTIVE // NormalNC: Normal text in non-current windows + , HLF_COUNT // MUST be the last one +} hlf_T; + +EXTERN const char *hlf_names[] INIT(= { + [HLF_8] = "SpecialKey", + [HLF_EOB] = "EndOfBuffer", + [HLF_TERM] = "TermCursor", + [HLF_TERMNC] = "TermCursorNC", + [HLF_AT] = "NonText", + [HLF_D] = "Directory", + [HLF_E] = "ErrorMsg", + [HLF_I] = "IncSearch", + [HLF_L] = "Search", + [HLF_M] = "MoreMsg", + [HLF_CM] = "ModeMsg", + [HLF_N] = "LineNr", + [HLF_CLN] = "CursorLineNr", + [HLF_R] = "Question", + [HLF_S] = "StatusLine", + [HLF_SNC] = "StatusLineNC", + [HLF_C] = "VertSplit", + [HLF_T] = "Title", + [HLF_V] = "Visual", + [HLF_VNC] = "VisualNC", + [HLF_W] = "WarningMsg", + [HLF_WM] = "WildMenu", + [HLF_FL] = "Folded", + [HLF_FC] = "FoldColumn", + [HLF_ADD] = "DiffAdd", + [HLF_CHD] = "DiffChange", + [HLF_DED] = "DiffDelete", + [HLF_TXD] = "DiffText", + [HLF_SC] = "SignColumn", + [HLF_CONCEAL] = "Conceal", + [HLF_SPB] = "SpellBad", + [HLF_SPC] = "SpellCap", + [HLF_SPR] = "SpellRare", + [HLF_SPL] = "SpellLocal", + [HLF_PNI] = "Pmenu", + [HLF_PSI] = "PmenuSel", + [HLF_PSB] = "PmenuSbar", + [HLF_PST] = "PmenuThumb", + [HLF_TP] = "TabLine", + [HLF_TPS] = "TabLineSel", + [HLF_TPF] = "TabLineFill", + [HLF_CUC] = "CursorColumn", + [HLF_CUL] = "CursorLine", + [HLF_MC] = "ColorColumn", + [HLF_QFL] = "QuickFixLine", + [HLF_0] = "Whitespace", + [HLF_INACTIVE] = "NormalNC" +}); + + +EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context. +EXTERN int highlight_user[9]; // User[1-9] attributes +EXTERN int highlight_stlnc[9]; // On top of user +EXTERN int cterm_normal_fg_color INIT(= 0); +EXTERN int cterm_normal_fg_bold INIT(= 0); +EXTERN int cterm_normal_bg_color INIT(= 0); +EXTERN RgbValue normal_fg INIT(= -1); +EXTERN RgbValue normal_bg INIT(= -1); +EXTERN RgbValue normal_sp INIT(= -1); + +#endif // NVIM_HIGHLIGHT_DEFS_H diff --git a/src/nvim/option.c b/src/nvim/option.c index 337d16a55b..b48ffae85b 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3579,7 +3579,9 @@ static char_u *compile_cap_prog(synblock_T *synblock) /// Handle setting `winhighlight' in window "wp" static bool parse_winhl_opt(win_T *wp) { - int w_hl_id = 0, w_hl_id_inactive = 0; + int w_hl_id_normal = 0; + int w_hl_ids[HLF_COUNT] = { 0 }; + int hlf; const char *p = (const char *)wp->w_p_winhl; while (*p) { @@ -3593,18 +3595,25 @@ static bool parse_winhl_opt(win_T *wp) int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi)); if (strncmp("Normal", p, nlen) == 0) { - w_hl_id = hl_id; - } else if (strncmp("NormalNC", p, nlen) == 0) { - w_hl_id_inactive = hl_id; + w_hl_id_normal = hl_id; } else { - return false; + for (hlf = 0; hlf < (int)HLF_COUNT; hlf++) { + if (strncmp(hlf_names[hlf], p, nlen) == 0) { + w_hl_ids[hlf] = hl_id; + break; + } + } + if (hlf == HLF_COUNT) { + return false; + } } p = *commap ? commap+1 : ""; } - wp->w_hl_id = w_hl_id; - wp->w_hl_id_inactive = w_hl_id_inactive; + wp->w_hl_id_normal = w_hl_id_normal; + memcpy(wp->w_hl_ids, w_hl_ids, sizeof(w_hl_ids)); + wp->w_hl_needs_update = true; return true; } diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index 9f3abfcb89..2462975c9b 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -307,10 +307,10 @@ void pum_redraw(void) { int row = pum_row; int col; - int attr_norm = highlight_attr[HLF_PNI]; - int attr_select = highlight_attr[HLF_PSI]; - int attr_scroll = highlight_attr[HLF_PSB]; - int attr_thumb = highlight_attr[HLF_PST]; + int attr_norm = win_hl_attr(curwin, HLF_PNI); + int attr_select = win_hl_attr(curwin, HLF_PSI); + int attr_scroll = win_hl_attr(curwin, HLF_PSB); + int attr_thumb = win_hl_attr(curwin, HLF_PST); int attr; int i; int idx; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 4f4363d121..3ff2a94a20 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -155,7 +155,6 @@ static schar_T *current_ScreenLine; StlClickDefinition *tab_page_click_defs = NULL; long tab_page_click_defs_size = 0; -# define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c), (rl)) #ifdef INCLUDE_GENERATED_DECLARATIONS # include "screen.c.generated.h" #endif @@ -380,15 +379,24 @@ void update_screen(int type) )) curwin->w_redr_type = type; - /* Redraw the tab pages line if needed. */ - if (redraw_tabline || type >= NOT_VALID) + // Redraw the tab pages line if needed. + if (redraw_tabline || type >= NOT_VALID) { + update_window_hl(curwin, type >= NOT_VALID); + FOR_ALL_TABS(tp) { + if (tp != curtab) { + update_window_hl(tp->tp_curwin, type >= NOT_VALID); + } + } draw_tabline(); + } /* * Correct stored syntax highlighting info for changes in each displayed * buffer. Each buffer must only be done once. */ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + update_window_hl(wp, type >= NOT_VALID); + if (wp->w_buffer->b_mod_set) { win_T *wwp; @@ -1488,11 +1496,11 @@ static void win_update(win_T *wp) // Last line isn't finished: Display "@@@" in the last screen line. screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol, - hl_attr(HLF_AT)); + win_hl_attr(wp, HLF_AT)); screen_fill(scr_row, scr_row + 1, (int)wp->w_wincol + 2, (int)W_ENDCOL(wp), - '@', ' ', hl_attr(HLF_AT)); + '@', ' ', win_hl_attr(wp, HLF_AT)); set_empty_rows(wp, srow); wp->w_botline = lnum; } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" @@ -1500,7 +1508,7 @@ static void win_update(win_T *wp) screen_fill(wp->w_winrow + wp->w_height - 1, wp->w_winrow + wp->w_height, W_ENDCOL(wp) - 3, W_ENDCOL(wp), - '@', '@', hl_attr(HLF_AT)); + '@', '@', win_hl_attr(wp, HLF_AT)); set_empty_rows(wp, srow); wp->w_botline = lnum; } else { @@ -1584,10 +1592,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h # define FDC_OFF n int fdc = compute_foldcolumn(wp, 0); - int attr = hl_attr(hl); - if (wp->w_hl_attr != 0) { - attr = hl_combine_attr(wp->w_hl_attr, attr); - } + int attr = win_hl_attr(wp, hl); if (wp->w_p_rl) { // No check for cmdline window: should never be right-left. @@ -1599,7 +1604,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h n = wp->w_width; screen_fill(wp->w_winrow + row, wp->w_winrow + endrow, W_ENDCOL(wp) - n, W_ENDCOL(wp), - ' ', ' ', hl_attr(HLF_FC)); + ' ', ' ', win_hl_attr(wp, HLF_FC)); } if (signcolumn_on(wp)) { @@ -1611,7 +1616,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h } screen_fill(wp->w_winrow + row, wp->w_winrow + endrow, W_ENDCOL(wp) - nn, W_ENDCOL(wp) - n, - ' ', ' ', hl_attr(HLF_SC)); + ' ', ' ', win_hl_attr(wp, HLF_SC)); n = nn; } @@ -1629,7 +1634,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h n = wp->w_width; screen_fill(wp->w_winrow + row, wp->w_winrow + endrow, wp->w_wincol, wp->w_wincol + n, - cmdwin_type, ' ', hl_attr(HLF_AT)); + cmdwin_type, ' ', win_hl_attr(wp, HLF_AT)); } if (fdc > 0) { int nn = n + fdc; @@ -1639,7 +1644,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h nn = wp->w_width; screen_fill(wp->w_winrow + row, wp->w_winrow + endrow, wp->w_wincol + n, wp->w_wincol + nn, - ' ', ' ', hl_attr(HLF_FC)); + ' ', ' ', win_hl_attr(wp, HLF_FC)); n = nn; } @@ -1652,7 +1657,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h } screen_fill(wp->w_winrow + row, wp->w_winrow + endrow, wp->w_wincol + n, wp->w_wincol + nn, - ' ', ' ', hl_attr(HLF_SC)); + ' ', ' ', win_hl_attr(wp, HLF_SC)); n = nn; } @@ -1720,10 +1725,9 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T */ if (cmdwin_type != 0 && wp == curwin) { ScreenLines[off] = cmdwin_type; - ScreenAttrs[off] = hl_attr(HLF_AT); - if (enc_utf8) - ScreenLinesUC[off] = 0; - ++col; + ScreenAttrs[off] = win_hl_attr(wp, HLF_AT); + ScreenLinesUC[off] = 0; + col++; } // 2. Add the 'foldcolumn' @@ -1735,12 +1739,14 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T int i; copy_text_attr(off + wp->w_width - fdc - col, buf, fdc, - hl_attr(HLF_FC)); - /* reverse the fold column */ - for (i = 0; i < fdc; ++i) + win_hl_attr(wp, HLF_FC)); + // reverse the fold column + for (i = 0; i < fdc; i++) { ScreenLines[off + wp->w_width - i - 1 - col] = buf[i]; - } else - copy_text_attr(off + col, buf, fdc, hl_attr(HLF_FC)); + } + } else { + copy_text_attr(off + col, buf, fdc, win_hl_attr(wp, HLF_FC)); + } col += fdc; } @@ -1753,7 +1759,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T /* Set all attributes of the 'number' or 'relativenumber' column and the * text */ - RL_MEMSET(col, hl_attr(HLF_FL), wp->w_width - col); + RL_MEMSET(col, win_hl_attr(wp, HLF_FL), wp->w_width - col); // If signs are being displayed, add two spaces. if (signcolumn_on(wp)) { @@ -1762,7 +1768,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T if (len > 2) { len = 2; } - copy_text_attr(off + col, (char_u *)" ", len, hl_attr(HLF_FL)); + copy_text_attr(off + col, (char_u *)" ", len, + win_hl_attr(wp, HLF_FL)); col += len; } } @@ -1794,13 +1801,14 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T } } - sprintf((char *)buf, fmt, w, num); - if (wp->w_p_rl) - /* the line number isn't reversed */ + snprintf((char *)buf, FOLD_TEXT_LEN, fmt, w, num); + if (wp->w_p_rl) { + // the line number isn't reversed copy_text_attr(off + wp->w_width - len - col, buf, len, - hl_attr(HLF_FL)); - else - copy_text_attr(off + col, buf, len, hl_attr(HLF_FL)); + win_hl_attr(wp, HLF_FL)); + } else { + copy_text_attr(off + col, buf, len, win_hl_attr(wp, HLF_FL)); + } col += len; } } @@ -1958,12 +1966,12 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T len = wp->w_old_cursor_lcol; else len = wp->w_width - txtcol; - RL_MEMSET(wp->w_old_cursor_fcol + txtcol, hl_attr(HLF_V), - len - (int)wp->w_old_cursor_fcol); + RL_MEMSET(wp->w_old_cursor_fcol + txtcol, win_hl_attr(wp, HLF_V), + len - (int)wp->w_old_cursor_fcol); } } else { - /* Set all attributes of the text */ - RL_MEMSET(txtcol, hl_attr(HLF_V), wp->w_width - txtcol); + // Set all attributes of the text + RL_MEMSET(txtcol, win_hl_attr(wp, HLF_V), wp->w_width - txtcol); } } } @@ -1983,7 +1991,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T } if (txtcol >= 0 && txtcol < wp->w_width) { ScreenAttrs[off + txtcol] = - hl_combine_attr(ScreenAttrs[off + txtcol], hl_attr(HLF_MC)); + hl_combine_attr(ScreenAttrs[off + txtcol], win_hl_attr(wp, HLF_MC)); } txtcol = old_txtcol; j = wp->w_p_cc_cols[++i]; @@ -1999,11 +2007,11 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T txtcol -= wp->w_leftcol; if (txtcol >= 0 && txtcol < wp->w_width) ScreenAttrs[off + txtcol] = hl_combine_attr( - ScreenAttrs[off + txtcol], hl_attr(HLF_CUC)); + ScreenAttrs[off + txtcol], win_hl_attr(wp, HLF_CUC)); } - SCREEN_LINE(row + wp->w_winrow, wp->w_wincol, wp->w_width, - wp->w_width, FALSE); + screen_line(row + wp->w_winrow, wp->w_wincol, wp->w_width, + wp->w_width, false, wp); /* * Update w_cline_height and w_cline_folded if the cursor line was @@ -2218,7 +2226,7 @@ win_line ( int syntax_flags = 0; int syntax_seqnr = 0; int prev_syntax_id = 0; - int conceal_attr = hl_attr(HLF_CONCEAL); + int conceal_attr = win_hl_attr(wp, HLF_CONCEAL); int is_concealing = false; int boguscols = 0; ///< nonexistent columns added to ///< force wrapping @@ -2366,8 +2374,8 @@ win_line ( /* if inverting in this line set area_highlighting */ if (fromcol >= 0) { - area_highlighting = TRUE; - attr = hl_attr(HLF_V); + area_highlighting = true; + attr = win_hl_attr(wp, HLF_V); } } /* @@ -2391,8 +2399,8 @@ win_line ( /* do at least one character; happens when past end of line */ if (fromcol == tocol) tocol = fromcol + 1; - area_highlighting = TRUE; - attr = hl_attr(HLF_I); + area_highlighting = true; + attr = win_hl_attr(wp, HLF_I); } filler_lines = diff_check(wp, lnum); @@ -2420,11 +2428,11 @@ win_line ( // Highlight the current line in the quickfix window. if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) { - line_attr = hl_attr(HLF_QFL); + line_attr = win_hl_attr(wp, HLF_QFL); } - if (wp->w_hl_attr != 0) { - line_attr = hl_combine_attr(wp->w_hl_attr, line_attr); + if (wp->w_hl_attr_normal != 0) { + line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr); } if (line_attr != 0) { @@ -2652,9 +2660,9 @@ win_line ( && !(wp == curwin && VIsual_active)) { if (line_attr != 0 && !(State & INSERT) && bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) { - line_attr = hl_combine_attr(hl_attr(HLF_CUL), line_attr); + line_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), line_attr); } else { - line_attr = hl_attr(HLF_CUL); + line_attr = win_hl_attr(wp, HLF_CUL); } area_highlighting = true; } @@ -2687,7 +2695,7 @@ win_line ( /* Draw the cmdline character. */ n_extra = 1; c_extra = cmdwin_type; - char_attr = hl_attr(HLF_AT); + char_attr = win_hl_attr(wp, HLF_AT); } } @@ -2702,7 +2710,7 @@ win_line ( p_extra = extra; p_extra[n_extra] = NUL; c_extra = NUL; - char_attr = hl_attr(HLF_FC); + char_attr = win_hl_attr(wp, HLF_FC); } } @@ -2715,7 +2723,7 @@ win_line ( int text_sign; /* Draw two cells with the sign value or blank. */ c_extra = ' '; - char_attr = hl_attr(HLF_SC); + char_attr = win_hl_attr(wp, HLF_SC); n_extra = 2; if (row == startrow + filler_lines && filler_todo <= 0) { @@ -2772,14 +2780,15 @@ win_line ( } else c_extra = ' '; n_extra = number_width(wp) + 1; - char_attr = hl_attr(HLF_N); - /* When 'cursorline' is set highlight the line number of - * the current line differently. - * TODO: Can we use CursorLine instead of CursorLineNr - * when CursorLineNr isn't set? */ + char_attr = win_hl_attr(wp, HLF_N); + // When 'cursorline' is set highlight the line number of + // the current line differently. + // TODO(vim): Can we use CursorLine instead of CursorLineNr + // when CursorLineNr isn't set? if ((wp->w_p_cul || wp->w_p_rnu) - && lnum == wp->w_cursor.lnum) - char_attr = hl_attr(HLF_CLN); + && lnum == wp->w_cursor.lnum) { + char_attr = win_hl_attr(wp, HLF_CLN); + } } } @@ -2796,12 +2805,12 @@ win_line ( if (draw_state == WL_BRI - 1 && n_extra == 0) { draw_state = WL_BRI; if (wp->w_p_bri && row != startrow && filler_lines == 0) { - char_attr = 0; // was: hl_attr(HLF_AT); + char_attr = wp->w_hl_attr_normal; // was: hl_attr(HLF_AT); if (diff_hlf != (hlf_T)0) { - char_attr = hl_attr(diff_hlf); + char_attr = win_hl_attr(wp, diff_hlf); if (wp->w_p_cul && lnum == wp->w_cursor.lnum) { - char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUL)); + char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUL)); } } p_extra = NULL; @@ -2826,15 +2835,15 @@ win_line ( n_extra = col + 1; else n_extra = wp->w_width - col; - char_attr = hl_attr(HLF_DED); + char_attr = win_hl_attr(wp, HLF_DED); } if (*p_sbr != NUL && need_showbreak) { /* Draw 'showbreak' at the start of each broken line. */ p_extra = p_sbr; c_extra = NUL; n_extra = (int)STRLEN(p_sbr); - char_attr = hl_attr(HLF_AT); - need_showbreak = FALSE; + char_attr = win_hl_attr(wp, HLF_AT); + need_showbreak = false; vcol_sbr = vcol + MB_CHARLEN(p_sbr); /* Correct end of highlighted area for 'showbreak', * required when 'linebreak' is also set. */ @@ -2842,7 +2851,7 @@ win_line ( tocol += n_extra; /* combine 'showbreak' with 'cursorline' */ if (wp->w_p_cul && lnum == wp->w_cursor.lnum) { - char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUL)); + char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUL)); } } } @@ -2855,12 +2864,9 @@ win_line ( c_extra = saved_c_extra; p_extra = saved_p_extra; char_attr = saved_char_attr; - } else - char_attr = 0; - } - - if (wp->w_hl_attr != 0) { - char_attr = hl_combine_attr(wp->w_hl_attr, char_attr); + } else { + char_attr = wp->w_hl_attr_normal; + } } } @@ -2869,13 +2875,14 @@ win_line ( && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol && filler_todo <= 0 ) { - SCREEN_LINE(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl); - /* Pretend we have finished updating the window. Except when - * 'cursorcolumn' is set. */ - if (wp->w_p_cuc) + screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp); + // Pretend we have finished updating the window. Except when + // 'cursorcolumn' is set. + if (wp->w_p_cuc) { row = wp->w_cline_row + wp->w_cline_height; - else + } else { row = wp->w_height; + } break; } @@ -3003,14 +3010,16 @@ win_line ( if (diff_hlf != (hlf_T)0) { if (diff_hlf == HLF_CHD && ptr - line >= change_start - && n_extra == 0) - diff_hlf = HLF_TXD; /* changed text */ + && n_extra == 0) { + diff_hlf = HLF_TXD; // changed text + } if (diff_hlf == HLF_TXD && ptr - line > change_end - && n_extra == 0) - diff_hlf = HLF_CHD; /* changed line */ - line_attr = hl_attr(diff_hlf); + && n_extra == 0) { + diff_hlf = HLF_CHD; // changed line + } + line_attr = win_hl_attr(wp, diff_hlf); if (wp->w_p_cul && lnum == wp->w_cursor.lnum) { - line_attr = hl_combine_attr(line_attr, hl_attr(HLF_CUL)); + line_attr = hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL)); } } @@ -3026,14 +3035,15 @@ win_line ( // (area_attr may be 0 when "noinvcur" is set). else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL) || vcol < fromcol || vcol_prev < fromcol_prev - || vcol >= tocol)) + || vcol >= tocol)) { char_attr = line_attr; - else { - attr_pri = FALSE; - if (has_syntax) + } else { + attr_pri = false; + if (has_syntax) { char_attr = syntax_attr; - else - char_attr = 0; + } else { + char_attr = wp->w_hl_attr_normal; + } } } @@ -3094,11 +3104,8 @@ win_line ( c = '>'; mb_c = c; mb_l = 1; - mb_utf8 = FALSE; - multi_attr = hl_attr(HLF_AT); - if (wp->w_hl_attr != 0) { - multi_attr = hl_combine_attr(wp->w_hl_attr, multi_attr); - } + mb_utf8 = false; + multi_attr = win_hl_attr(wp, HLF_AT); // put the pointer back to output the double-width // character at the start of the next line. @@ -3166,8 +3173,8 @@ win_line ( c_extra = NUL; if (area_attr == 0 && search_attr == 0) { n_attr = n_extra + 1; - extra_attr = hl_attr(HLF_8); - saved_attr2 = char_attr; /* save current attr */ + extra_attr = win_hl_attr(wp, HLF_8); + saved_attr2 = char_attr; // save current attr } } else if (mb_l == 0) /* at the NUL at end-of-line */ mb_l = 1; @@ -3219,8 +3226,8 @@ win_line ( c = *p_extra++; if (area_attr == 0 && search_attr == 0) { n_attr = n_extra + 1; - extra_attr = hl_attr(HLF_8); - saved_attr2 = char_attr; /* save current attr */ + extra_attr = win_hl_attr(wp, HLF_8); + saved_attr2 = char_attr; // save current attr } mb_c = c; } @@ -3237,10 +3244,7 @@ win_line ( mb_c = c; mb_utf8 = FALSE; mb_l = 1; - multi_attr = hl_attr(HLF_AT); - if (wp->w_hl_attr != 0) { - multi_attr = hl_combine_attr(wp->w_hl_attr, multi_attr); - } + multi_attr = win_hl_attr(wp, HLF_AT); // Put pointer back so that the character will be // displayed at the start of the next line. ptr--; @@ -3257,8 +3261,8 @@ win_line ( c = ' '; if (area_attr == 0 && search_attr == 0) { n_attr = n_extra + 1; - extra_attr = hl_attr(HLF_AT); - saved_attr2 = char_attr; /* save current attr */ + extra_attr = win_hl_attr(wp, HLF_AT); + saved_attr2 = char_attr; // save current attr } mb_c = c; mb_utf8 = FALSE; @@ -3306,7 +3310,7 @@ win_line ( else syntax_flags = get_syntax_info(&syntax_seqnr); } else if (!attr_pri) { - char_attr = 0; + char_attr = wp->w_hl_attr_normal; } /* Check spelling (unless at the end of the line). @@ -3432,7 +3436,7 @@ win_line ( || (c == ' ' && lcs_space && ptr - line <= trailcol))) { c = (c == ' ') ? lcs_space : lcs_nbsp; n_attr = 1; - extra_attr = hl_attr(HLF_0); + extra_attr = win_hl_attr(wp, HLF_0); saved_attr2 = char_attr; // save current attr mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { @@ -3447,7 +3451,7 @@ win_line ( if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') { c = lcs_trail; n_attr = 1; - extra_attr = hl_attr(HLF_0); + extra_attr = win_hl_attr(wp, HLF_0); saved_attr2 = char_attr; // save current attr mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { @@ -3548,7 +3552,7 @@ win_line ( c_extra = lcs_tab2; } n_attr = tab_len + 1; - extra_attr = hl_attr(HLF_0); + extra_attr = win_hl_attr(wp, HLF_0); saved_attr2 = char_attr; // save current attr mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { @@ -3595,7 +3599,7 @@ win_line ( } lcs_eol_one = -1; ptr--; // put it back at the NUL - extra_attr = hl_attr(HLF_AT); + extra_attr = win_hl_attr(wp, HLF_AT); n_attr = 1; mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { @@ -3626,7 +3630,7 @@ win_line ( c = *p_extra++; } n_attr = n_extra + 1; - extra_attr = hl_attr(HLF_8); + extra_attr = win_hl_attr(wp, HLF_8); saved_attr2 = char_attr; // save current attr mb_utf8 = false; // don't draw as UTF-8 } else if (VIsual_active @@ -3658,9 +3662,10 @@ win_line ( if (diff_hlf == HLF_TXD) { diff_hlf = HLF_CHD; if (attr == 0 || char_attr != attr) { - char_attr = hl_attr(diff_hlf); + char_attr = win_hl_attr(wp, diff_hlf); if (wp->w_p_cul && lnum == wp->w_cursor.lnum) { - char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUL)); + char_attr = hl_combine_attr(char_attr, + win_hl_attr(wp, HLF_CUL)); } } } @@ -3762,7 +3767,7 @@ win_line ( c_extra = MB_FILLER_CHAR; n_extra = 1; n_attr = 2; - extra_attr = hl_attr(HLF_AT); + extra_attr = win_hl_attr(wp, HLF_AT); } mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { @@ -3773,10 +3778,7 @@ win_line ( mb_utf8 = false; // don't draw as UTF-8 } saved_attr3 = char_attr; // save current attr - char_attr = hl_attr(HLF_AT); // overwriting char_attr - if (wp->w_hl_attr != 0) { - char_attr = hl_combine_attr(wp->w_hl_attr, char_attr); - } + char_attr = win_hl_attr(wp, HLF_AT); // overwriting char_attr n_attr3 = 1; } @@ -3861,8 +3863,8 @@ win_line ( } } - if (wp->w_hl_attr != 0) { - char_attr = hl_combine_attr(wp->w_hl_attr, char_attr); + if (wp->w_hl_attr_normal != 0) { + char_attr = hl_combine_attr(wp->w_hl_attr_normal, char_attr); } ScreenAttrs[off] = char_attr; if (wp->w_p_rl) { @@ -3925,13 +3927,8 @@ win_line ( if (rightmost_vcol < color_cols[i]) rightmost_vcol = color_cols[i]; - int cuc_attr = hl_attr(HLF_CUC); - int mc_attr = hl_attr(HLF_MC); - if (wp->w_hl_attr != 0) { - cuc_attr = hl_combine_attr(wp->w_hl_attr, cuc_attr); - mc_attr = hl_combine_attr(wp->w_hl_attr, mc_attr); - } - + int cuc_attr = win_hl_attr(wp, HLF_CUC); + int mc_attr = win_hl_attr(wp, HLF_MC); while (col < wp->w_width) { ScreenLines[off] = ' '; @@ -3947,7 +3944,7 @@ win_line ( } else if (draw_color_col && VCOL_HLC == *color_cols) { ScreenAttrs[off++] = mc_attr; } else { - ScreenAttrs[off++] = wp->w_hl_attr; + ScreenAttrs[off++] = wp->w_hl_attr_normal; } if (VCOL_HLC >= rightmost_vcol) @@ -3970,7 +3967,7 @@ win_line ( col++; } } - SCREEN_LINE(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl); + screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp); row++; /* @@ -3998,10 +3995,7 @@ win_line ( || (wp->w_p_list && lcs_eol_one > 0) || (n_extra && (c_extra != NUL || *p_extra != NUL)))) { c = lcs_ext; - char_attr = hl_attr(HLF_AT); - if (wp->w_hl_attr != 0) { - char_attr = hl_combine_attr(wp->w_hl_attr, char_attr); - } + char_attr = win_hl_attr(wp, HLF_AT); mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { mb_utf8 = TRUE; @@ -4024,10 +4018,10 @@ win_line ( if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol && lnum != wp->w_cursor.lnum) { vcol_save_attr = char_attr; - char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUC)); + char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUC)); } else if (draw_color_col && VCOL_HLC == *color_cols) { vcol_save_attr = char_attr; - char_attr = hl_combine_attr(char_attr, hl_attr(HLF_MC)); + char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_MC)); } } @@ -4195,8 +4189,8 @@ win_line ( || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str) || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL))) ) { - SCREEN_LINE(screen_row, wp->w_wincol, col - boguscols, - wp->w_width, wp->w_p_rl); + screen_line(screen_row, wp->w_wincol, col - boguscols, + wp->w_width, wp->w_p_rl, wp); boguscols = 0; ++row; ++screen_row; @@ -4364,7 +4358,8 @@ static int char_needs_redraw(int off_from, int off_to, int cols) * When TRUE and "clear_width" > 0, clear columns 0 to "endcol" * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width" */ -static void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag) +static void screen_line(int row, int coloff, int endcol, + int clear_width, int rlflag, win_T *wp) { unsigned off_from; unsigned off_to; @@ -4526,11 +4521,11 @@ static void screen_line(int row, int coloff, int endcol, int clear_width, int rl } if (clear_width > 0) { - /* For a window that's left of another, draw the separator char. */ - if (col + coloff < Columns) { + // For a window that's left of another, draw the separator char. + if (col + coloff < Columns && wp->w_vsep_width > 0) { int c; - c = fillchar_vsep(&hl); + c = fillchar_vsep(wp, &hl); if (ScreenLines[off_to] != (schar_T)c || (enc_utf8 && (int)ScreenLinesUC[off_to] != (c >= 0x80 ? c : 0)) @@ -4635,8 +4630,8 @@ static void draw_vsep_win(win_T *wp, int row) int c; if (wp->w_vsep_width) { - /* draw the vertical separator right of this window */ - c = fillchar_vsep(&hl); + // draw the vertical separator right of this window + c = fillchar_vsep(wp, &hl); screen_fill(wp->w_winrow + row, wp->w_winrow + wp->w_height, W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); @@ -4766,7 +4761,7 @@ win_redr_status_matches ( --first_match; } - fillchar = fillchar_status(&attr, TRUE); + fillchar = fillchar_status(&attr, curwin); if (first_match == 0) { *buf = NUL; @@ -4898,7 +4893,7 @@ void win_redr_status(win_T *wp) /* redraw custom status line */ redraw_custom_statusline(wp); } else { - fillchar = fillchar_status(&attr, wp == curwin); + fillchar = fillchar_status(&attr, wp); get_trans_bufname(wp->w_buffer); p = NameBuff; @@ -4970,10 +4965,11 @@ void win_redr_status(win_T *wp) * May need to draw the character below the vertical separator. */ if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing()) { - if (stl_connected(wp)) - fillchar = fillchar_status(&attr, wp == curwin); - else - fillchar = fillchar_vsep(&attr); + if (stl_connected(wp)) { + fillchar = fillchar_status(&attr, wp); + } else { + fillchar = fillchar_vsep(wp, &attr); + } screen_putchar(fillchar, wp->w_winrow + wp->w_height, W_ENDCOL(wp), attr); } @@ -5123,7 +5119,7 @@ win_redr_custom ( use_sandbox = was_set_insecurely((char_u *)"tabline", 0); } else { row = wp->w_winrow + wp->w_height; - fillchar = fillchar_status(&attr, wp == curwin); + fillchar = fillchar_status(&attr, wp); maxwidth = wp->w_width; if (draw_ruler) { @@ -5508,8 +5504,7 @@ static void start_search_hl(void) { if (p_hls && !no_hlsearch) { last_pat_prog(&search_hl.rm); - search_hl.attr = hl_attr(HLF_L); - /* Set the time limit to 'redrawtime'. */ + // Set the time limit to 'redrawtime'. search_hl.tm = profile_setlimit(p_rdt); } } @@ -5525,6 +5520,42 @@ static void end_search_hl(void) } } +static void update_window_hl(win_T *wp, bool invalid) +{ + if (!wp->w_hl_needs_update && !invalid) { + return; + } + wp->w_hl_needs_update = false; + + // determine window specific background set in 'winhighlight' + if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) { + wp->w_hl_attr_normal = syn_id2attr(wp->w_hl_ids[HLF_INACTIVE]); + } else if (wp->w_hl_id_normal > 0) { + wp->w_hl_attr_normal = syn_id2attr(wp->w_hl_id_normal); + } else { + wp->w_hl_attr_normal = 0; + } + if (wp != curwin) { + wp->w_hl_attr_normal = hl_combine_attr(hl_attr(HLF_INACTIVE), + wp->w_hl_attr_normal); + } + + for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) { + int attr; + if (wp->w_hl_ids[hlf] > 0) { + attr = syn_id2attr(wp->w_hl_ids[hlf]); + } else { + attr = hl_attr(hlf); + } + if (wp->w_hl_attr_normal != 0) { + attr = hl_combine_attr(wp->w_hl_attr_normal, attr); + } + wp->w_hl_attrs[hlf] = attr; + } +} + + + /* * Init for calling prepare_search_hl(). */ @@ -5551,19 +5582,9 @@ static void init_search_hl(win_T *wp) search_hl.buf = wp->w_buffer; search_hl.lnum = 0; search_hl.first_lnum = 0; - // time limit is set at the toplevel, for all windows + search_hl.attr = win_hl_attr(wp, HLF_L); - // determine window specific background set in 'winhighlight' - if (wp != curwin && wp->w_hl_id_inactive > 0) { - wp->w_hl_attr = syn_id2attr(wp->w_hl_id_inactive); - } else if (wp->w_hl_id > 0) { - wp->w_hl_attr = syn_id2attr(wp->w_hl_id); - } else { - wp->w_hl_attr = 0; - } - if (wp != curwin) { - wp->w_hl_attr = hl_combine_attr(hl_attr(HLF_INACTIVE), wp->w_hl_attr); - } + // time limit is set at the toplevel, for all windows } /* @@ -6775,7 +6796,7 @@ int showmode(void) if (edit_submode_extra != NULL) { MSG_PUTS_ATTR(" ", attr); // Add a space in between. if ((int)edit_submode_highl < (int)HLF_COUNT) { - sub_attr = hl_attr(edit_submode_highl); + sub_attr = win_hl_attr(curwin, edit_submode_highl); } else { sub_attr = attr; } @@ -6928,7 +6949,6 @@ static void 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); char_u *p; @@ -6990,16 +7010,6 @@ static void draw_tabline(void) scol = col; - if (tp->tp_topframe == topframe) - attr = attr_sel; - if (use_sep_chars && col > 0) - screen_putchar('|', 0, col++, attr); - - if (tp->tp_topframe != topframe) - attr = attr_nosel; - - screen_putchar(' ', 0, col++, attr); - if (tp == curtab) { cwp = curwin; wp = firstwin; @@ -7008,10 +7018,29 @@ static void draw_tabline(void) wp = tp->tp_firstwin; } - modified = FALSE; - for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount) - if (bufIsChanged(wp->w_buffer)) - modified = TRUE; + + if (tp->tp_topframe == topframe) { + attr = win_hl_attr(cwp, HLF_TPS); + } + if (use_sep_chars && col > 0) { + screen_putchar('|', 0, col++, attr); + } + + if (tp->tp_topframe != topframe) { + attr = win_hl_attr(cwp, HLF_TP); + } + + screen_putchar(' ', 0, col++, attr); + + modified = false; + + for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount) { + if (bufIsChanged(wp->w_buffer)) { + modified = true; + } + } + + if (modified || wincount > 1) { if (wincount > 1) { vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount); @@ -7019,7 +7048,7 @@ static void draw_tabline(void) if (col + len >= Columns - 3) break; screen_puts_len(NameBuff, len, 0, col, - hl_combine_attr(attr, hl_attr(HLF_T))); + hl_combine_attr(attr, win_hl_attr(cwp, HLF_T))); col += len; } if (modified) @@ -7117,25 +7146,28 @@ void get_trans_bufname(buf_T *buf) /* * Get the character to use in a status line. Get its attributes in "*attr". */ -static int fillchar_status(int *attr, int is_curwin) +static int fillchar_status(int *attr, win_T *wp) { int fill; + bool is_curwin = (wp == curwin); if (is_curwin) { - *attr = hl_attr(HLF_S); + *attr = win_hl_attr(wp, HLF_S); fill = fill_stl; } else { - *attr = hl_attr(HLF_SNC); + *attr = win_hl_attr(wp, HLF_SNC); fill = fill_stlnc; } /* Use fill when there is highlighting, and highlighting of current * window differs, or the fillchars differ, or this is not the * current window */ - if (*attr != 0 && ((hl_attr(HLF_S) != hl_attr(HLF_SNC) + if (*attr != 0 && ((win_hl_attr(wp, HLF_S) != win_hl_attr(wp, HLF_SNC) || !is_curwin || firstwin == lastwin) - || (fill_stl != fill_stlnc))) + || (fill_stl != fill_stlnc))) { return fill; - if (is_curwin) + } + if (is_curwin) { return '^'; + } return '='; } @@ -7143,13 +7175,14 @@ static int fillchar_status(int *attr, int is_curwin) * Get the character to use in a separator between vertically split windows. * Get its attributes in "*attr". */ -static int fillchar_vsep(int *attr) +static int fillchar_vsep(win_T *wp, int *attr) { - *attr = hl_attr(HLF_C); - if (*attr == 0 && fill_vert == ' ') + *attr = win_hl_attr(wp, HLF_C); + if (*attr == 0 && fill_vert == ' ') { return '|'; - else + } else { return fill_vert; + } } /* @@ -7264,7 +7297,7 @@ static void win_redr_ruler(win_T *wp, int always) if (wp->w_status_height) { row = wp->w_winrow + wp->w_height; - fillchar = fillchar_status(&attr, wp == curwin); + fillchar = fillchar_status(&attr, wp); off = wp->w_wincol; width = wp->w_width; } else { diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h index 8d207e6286..9f309451b0 100644 --- a/src/nvim/syntax_defs.h +++ b/src/nvim/syntax_defs.h @@ -1,10 +1,9 @@ #ifndef NVIM_SYNTAX_DEFS_H #define NVIM_SYNTAX_DEFS_H +#include "nvim/highlight_defs.h" #include "nvim/regexp_defs.h" -typedef int32_t RgbValue; - # define SST_MIN_ENTRIES 150 /* minimal size for state stack array */ # define SST_MAX_ENTRIES 1000 /* maximal size for state stack array */ # define SST_FIX_STATES 7 /* size of sst_stack[]. */ diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index bde07b0cd9..1882f263db 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -601,8 +601,10 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, if (term->cursor.visible && term->cursor.row == row && term->cursor.col == col) { - attr_id = hl_combine_attr(attr_id, is_focused(term) && wp == curwin ? - hl_attr(HLF_TERM) : hl_attr(HLF_TERMNC)); + attr_id = hl_combine_attr(attr_id, + is_focused(term) && wp == curwin + ? win_hl_attr(wp, HLF_TERM) + : win_hl_attr(wp, HLF_TERMNC)); } term_attrs[col] = attr_id; diff --git a/src/nvim/window.c b/src/nvim/window.c index b71b48a6b7..43af2e5e4f 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3723,8 +3723,8 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, redraw_later(VALID); /* causes status line redraw */ if (hl_attr(HLF_INACTIVE) - || (prevwin && prevwin->w_hl_id_inactive) - || curwin->w_hl_id_inactive) { + || (prevwin && prevwin->w_hl_ids[HLF_INACTIVE]) + || curwin->w_hl_ids[HLF_INACTIVE]) { redraw_all_later(NOT_VALID); } diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 4fd00cc320..d1357ea525 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -5,6 +5,7 @@ local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local command = helpers.command local eval, exc_exec = helpers.eval, helpers.exc_exec local feed_command, request, eq = helpers.feed_command, helpers.request, helpers.eq +local curbufmeths = helpers.curbufmeths describe('colorscheme compatibility', function() before_each(function() @@ -670,12 +671,26 @@ describe("'winhighlight' highlight", function() [8] = {background = Screen.colors.DarkMagenta, bold = true, foreground = Screen.colors.Blue1}, [9] = {foreground = Screen.colors.Brown}, [10] = {foreground = Screen.colors.Brown, background = Screen.colors.DarkBlue}, + [11] = {background = Screen.colors.DarkBlue, bold = true, reverse = true}, + [12] = {background = Screen.colors.DarkGreen, reverse = true}, + [13] = {background = Screen.colors.Magenta4, reverse = true}, + [14] = {background = Screen.colors.DarkBlue, reverse = true}, + [15] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [16] = {foreground = Screen.colors.Blue1}, + [17] = {background = Screen.colors.LightRed}, + [18] = {background = Screen.colors.Gray90}, + [19] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray}, + [20] = {background = Screen.colors.LightGrey, underline = true}, + [21] = {bold = true}, + [22] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [23] = {background = Screen.colors.LightMagenta}, + [24] = {background = Screen.colors.WebGray}, }) command("hi Background1 guibg=DarkBlue") command("hi Background2 guibg=DarkGreen") end) - it('works', function() + it('works for background color', function() insert("aa") command("split") command("set winhl=Normal:Background1") @@ -683,7 +698,7 @@ describe("'winhighlight' highlight", function() {1:a^a }| {2:~ }| {2:~ }| - {3:[No Name] [+] }| + {11:[No Name] [+] }| aa | {0:~ }| {4:[No Name] [+] }| @@ -695,7 +710,7 @@ describe("'winhighlight' highlight", function() {1:^ }| {2:~ }| {2:~ }| - {3:[No Name] }| + {11:[No Name] }| aa | {0:~ }| {4:[No Name] [+] }| @@ -740,7 +755,7 @@ describe("'winhighlight' highlight", function() {1:a^a }| {2:~ }| {2:~ }| - {3:[No Name] [+] }| + {11:[No Name] [+] }| aa | {0:~ }| {4:[No Name] [+] }| @@ -764,16 +779,15 @@ describe("'winhighlight' highlight", function() {1:^aa }| {2:~ }| {2:~ }| - {3:[No Name] [+] }| + {11:[No Name] [+] }| aa | {0:~ }| {4:[No Name] [+] }| <f 1 --100%-- col 1 | ]]) - end) - it('for inactive window works', function() + it('for inactive window background works', function() command("set winhl=Normal:Background1,NormalNC:Background2") -- tests global value is copied across split command("split") @@ -781,10 +795,10 @@ describe("'winhighlight' highlight", function() {1:^ }| {2:~ }| {2:~ }| - {3:[No Name] }| + {11:[No Name] }| {5: }| {6:~ }| - {4:[No Name] }| + {12:[No Name] }| | ]]) @@ -793,10 +807,10 @@ describe("'winhighlight' highlight", function() {5: }| {6:~ }| {6:~ }| - {4:[No Name] }| + {12:[No Name] }| {1:^ }| {2:~ }| - {3:[No Name] }| + {11:[No Name] }| | ]]) @@ -805,13 +819,12 @@ describe("'winhighlight' highlight", function() {1:^ }| {2:~ }| {2:~ }| - {3:[No Name] }| + {11:[No Name] }| {5: }| {6:~ }| - {4:[No Name] }| + {12:[No Name] }| | ]]) - end) it('works with NormalNC', function() @@ -825,7 +838,7 @@ describe("'winhighlight' highlight", function() {3:[No Name] }| {7: }| {8:~ }| - {4:[No Name] }| + {13:[No Name] }| | ]]) @@ -834,7 +847,7 @@ describe("'winhighlight' highlight", function() {7: }| {8:~ }| {8:~ }| - {4:[No Name] }| + {13:[No Name] }| ^ | {0:~ }| {3:[No Name] }| @@ -848,10 +861,10 @@ describe("'winhighlight' highlight", function() {7: }| {8:~ }| {8:~ }| - {4:[No Name] }| + {13:[No Name] }| {1:^ }| {2:~ }| - {3:[No Name] }| + {11:[No Name] }| | ]]) @@ -863,7 +876,7 @@ describe("'winhighlight' highlight", function() {3:[No Name] }| {1: }| {2:~ }| - {4:[No Name] }| + {14:[No Name] }| | ]]) @@ -873,10 +886,10 @@ describe("'winhighlight' highlight", function() {7: }| {8:~ }| {8:~ }| - {4:[No Name] }| + {13:[No Name] }| {1:^ }| {2:~ }| - {3:[No Name] }| + {11:[No Name] }| | ]]) @@ -888,13 +901,12 @@ describe("'winhighlight' highlight", function() {3:[No Name] }| {5: }| {6:~ }| - {4:[No Name] }| + {12:[No Name] }| | ]]) - end) - it('applies also to non-text', function() + it('background applies also to non-text', function() insert('Lorem ipsum dolor sit amet ') command('set shiftwidth=2') feed('>>') @@ -940,6 +952,114 @@ describe("'winhighlight' highlight", function() | ]]) end) -end) + it('can override NonText, Conceal and EndOfBuffer', function() + curbufmeths.set_lines(0,-1,true, {"raa\000"}) + command('call matchaddpos("Conceal", [[1,2]], 0, -1, {"conceal": "#"})') + command('set cole=2 cocu=nvic') + command('split') + command('call matchaddpos("Conceal", [[1,2]], 0, -1, {"conceal": "#"})') + command('set winhl=SpecialKey:ErrorMsg,EndOfBuffer:Background1,' + ..'Conceal:Background2') + + screen:expect([[ + ^r{5:#}a{15:^@} | + {1:~ }| + {1:~ }| + {3:[No Name] [+] }| + r{19:#}a{16:^@} | + {0:~ }| + {4:[No Name] [+] }| + | + ]]) + end) + + it('can override LineNr, CursorColumn and ColorColumn', function() + insert('very text\nmore text') + command('set number') + command('set colorcolumn=2') + command('set cursorcolumn') + + command('split') + command('set winhl=LineNr:Background1,CursorColumn:Background2,' + ..'ColorColumn:ErrorMsg') + screen:expect([[ + {1: 1 }v{15:e}ry tex{5:t} | + {1: 2 }m{15:o}re tex^t | + {0:~ }| + {3:[No Name] [+] }| + {9: 1 }v{17:e}ry tex{18:t} | + {9: 2 }m{17:o}re text | + {4:[No Name] [+] }| + | + ]]) + end) + + it('can override Tabline', function() + command('tabnew') + command('set winhl=TabLine:Background1,TabLineSel:ErrorMsg') + + screen:expect([[ + {20: No Name] }{15: No Name]}{20:X}| + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + command("tabnext") + screen:expect([[ + {21: No Name] }{1: No Name]}{20:X}| + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) + + it('can override popupmenu', function() + insert('word wording wordy') + command('split') + command('set winhl=Pmenu:Background1,PmenuSel:Background2,' + ..'PmenuSbar:ErrorMsg,PmenuThumb:Normal') + screen:expect([[ + word wording word^y | + {0:~ }| + {0:~ }| + {3:[No Name] [+] }| + word wording wordy | + {0:~ }| + {4:[No Name] [+] }| + | + ]]) + feed('oword<c-x><c-p>') + screen:expect([[ + word wording wordy | + wordy^ | + {1:word }{0: }| + {1:wording }{3: }| + {5:wordy }rdy | + wordy | + {4:[No Name] [+] }| + {21:-- }{22:match 1 of 3} | + ]]) + + feed('<esc>u<c-w><c-w>oword<c-x><c-p>') + screen:expect([[ + word wording wordy | + wordy | + {23:word }{0: }| + {23:wording }{4: }| + {24:wordy }rdy | + wordy^ | + {3:[No Name] [+] }| + {21:-- }{22:match 1 of 3} | + ]]) + end) +end) |