diff options
-rw-r--r-- | runtime/doc/options.txt | 3 | ||||
-rw-r--r-- | runtime/doc/syntax.txt | 2 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 6 | ||||
-rw-r--r-- | src/nvim/globals.h | 3 | ||||
-rw-r--r-- | src/nvim/option.c | 43 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/options.lua | 8 | ||||
-rw-r--r-- | src/nvim/screen.c | 91 | ||||
-rw-r--r-- | src/nvim/window.c | 6 | ||||
-rw-r--r-- | test/functional/ui/cursor_spec.lua | 4 |
10 files changed, 143 insertions, 24 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index e72241518c..cddd043929 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -3128,7 +3128,8 @@ A jump table for the options with a short description can be found at |Q_op|. use for that occasion. The occasions are: |hl-SpecialKey| 8 Meta and special keys listed with ":map" |hl-Whitespace| 0 - |hl-EndOfBuffer| ~ lines after the last line in the buffer + |hl-EndOfBuffer| ~ lines after the last line in the buffer + |hl-NormalNC| I inactive (not the current) window |hl-TermCursor| z Cursor in a focused terminal |hl-TermCursorNC| Z Cursor in an unfocused terminal |hl-NonText| @ '@' at the end of the window and diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index a45fa3096a..18920d81e3 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -4922,6 +4922,8 @@ NonText '@' at the end of the window, characters from 'showbreak' fit at the end of the line). See also |hl-EndOfBuffer|. *hl-Normal* Normal normal text + *hl-NormalNC* +NormalNC normal text in non-current window *hl-Pmenu* Pmenu Popup menu: normal item. *hl-PmenuSel* diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 20a2b931bd..88fa9726a4 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -233,6 +233,8 @@ typedef struct { # define w_p_crb_save w_onebuf_opt.wo_crb_save char_u *wo_scl; # define w_p_scl w_onebuf_opt.wo_scl // 'signcolumn' + char_u *wo_winhl; +# define w_p_winhl w_onebuf_opt.wo_winhl // 'winhighlight' int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */ # define w_p_scriptID w_onebuf_opt.wo_scriptID @@ -930,6 +932,10 @@ 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 + win_T *w_prev; /* link to previous window */ win_T *w_next; /* link to next window */ bool w_closing; /* window is being closed, don't let diff --git a/src/nvim/globals.h b/src/nvim/globals.h index df9f418951..c7985d6a65 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -465,6 +465,7 @@ typedef enum { , HLF_MC // 'colorcolumn' , HLF_QFL // selected quickfix line , HLF_0 // Whitespace + , HLF_INACTIVE // Inactive window , HLF_COUNT // MUST be the last one } hlf_T; @@ -473,7 +474,7 @@ typedef enum { #define HL_FLAGS { '8', '~', 'z', 'Z', '@', 'd', 'e', 'i', 'l', 'm', 'M', 'n', \ 'N', 'r', 's', 'S', 'c', 't', 'v', 'V', 'w', 'W', 'f', 'F', \ 'A', 'C', 'D', 'T', '-', '>', 'B', 'P', 'R', 'L', '+', '=', \ - 'x', 'X', '*', '#', '_', '!', '.', 'o', 'q', '0' } + 'x', 'X', '*', '#', '_', '!', '.', 'o', 'q', '0', 'I' } EXTERN int highlight_attr[HLF_COUNT]; /* Highl. attr for each context. */ EXTERN int highlight_user[9]; /* User[1-9] attributes */ diff --git a/src/nvim/option.c b/src/nvim/option.c index 95e9844187..ad09b936e0 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -252,7 +252,7 @@ typedef struct vimoption { "B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \ "x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill," \ "!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine," \ - "0:Whitespace" + "0:Whitespace,I:NormalNC" /* * options[] is initialized here. @@ -3174,6 +3174,10 @@ did_set_string_option ( if (!valid_filetype(*varp)) { errmsg = e_invarg; } + } else if (varp == &curwin->w_p_winhl) { + if (!parse_winhl_opt(curwin)) { + errmsg = e_invarg; + } } else { // Options that are a list of flags. p = NULL; @@ -3582,6 +3586,38 @@ static char_u *compile_cap_prog(synblock_T *synblock) return NULL; } +/// Handle setting `winhighlight' in window "wp" +static bool parse_winhl_opt(win_T *wp) +{ + int w_hl_id = 0, w_hl_id_inactive = 0; + + const char *p = (const char *)wp->w_p_winhl; + while (*p) { + char *colon = strchr(p, ':'); + if (!colon) { + return false; + } + size_t nlen = (size_t)(colon-p); + char *hi = colon+1; + char *commap = xstrchrnul(hi, ','); + 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; + } else { + return false; + } + + p = *commap ? commap+1 : ""; + } + + wp->w_hl_id = w_hl_id; + wp->w_hl_id_inactive = w_hl_id_inactive; + return true; +} + /* * Set the scriptID for an option, taking care of setting the buffer- or * window-local value. @@ -5491,6 +5527,7 @@ static char_u *get_varp(vimoption_T *p) case PV_WM: return (char_u *)&(curbuf->b_p_wm); case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap); case PV_SCL: return (char_u *)&(curwin->w_p_scl); + case PV_WINHL: return (char_u *)&(curwin->w_p_winhl); default: EMSG(_("E356: get_varp ERROR")); } /* always return a valid pointer to avoid a crash! */ @@ -5568,6 +5605,7 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_fdt = vim_strsave(from->wo_fdt); to->wo_fmr = vim_strsave(from->wo_fmr); to->wo_scl = vim_strsave(from->wo_scl); + to->wo_winhl = vim_strsave(from->wo_winhl); check_winopt(to); // don't want NULL pointers } @@ -5597,6 +5635,7 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_cc); check_string_option(&wop->wo_cocu); check_string_option(&wop->wo_briopt); + check_string_option(&wop->wo_winhl); } /* @@ -5616,12 +5655,14 @@ void clear_winopt(winopt_T *wop) clear_string_option(&wop->wo_cc); clear_string_option(&wop->wo_cocu); clear_string_option(&wop->wo_briopt); + clear_string_option(&wop->wo_winhl); } void didset_window_options(win_T *wp) { check_colorcolumn(wp); briopt_check(wp); + parse_winhl_opt(wp); } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 4ee0f4f225..e68dba734e 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -807,6 +807,7 @@ enum { , WV_WFW , WV_WRAP , WV_SCL + , WV_WINHL , WV_COUNT // must be the last one }; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index ba7bf5bafb..6ad0501f0a 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2702,6 +2702,14 @@ return { defaults={if_true={vi="menu"}} }, { + full_name='winhighlight', abbreviation='winhl', + type='string', scope={'window'}, + vi_def=true, + alloced=true, + redraw={'current_window'}, + defaults={if_true={vi=""}} + }, + { full_name='window', abbreviation='wi', type='number', scope={'global'}, vi_def=true, diff --git a/src/nvim/screen.c b/src/nvim/screen.c index f2709c48fd..238b3f07c8 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1584,6 +1584,11 @@ 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); + } + if (wp->w_p_rl) { // No check for cmdline window: should never be right-left. n = fdc; @@ -1612,10 +1617,10 @@ 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, W_ENDCOL(wp) - 1 - FDC_OFF, - c2, c2, hl_attr(hl)); + c2, c2, attr); screen_fill(wp->w_winrow + row, wp->w_winrow + endrow, W_ENDCOL(wp) - 1 - FDC_OFF, W_ENDCOL(wp) - FDC_OFF, - c1, c2, hl_attr(hl)); + c1, c2, attr); } else { if (cmdwin_type != 0 && wp == curwin) { /* draw the cmdline character in the leftmost column */ @@ -1653,7 +1658,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 + FDC_OFF, W_ENDCOL(wp), - c1, c2, hl_attr(hl)); + c1, c2, attr); } set_empty_rows(wp, row); } @@ -2418,6 +2423,10 @@ win_line ( line_attr = hl_attr(HLF_QFL); } + if (wp->w_hl_attr != 0) { + line_attr = hl_combine_attr(wp->w_hl_attr, line_attr); + } + if (line_attr != 0) { area_highlighting = true; } @@ -2849,6 +2858,10 @@ win_line ( } else char_attr = 0; } + + if (wp->w_hl_attr != 0) { + char_attr = hl_combine_attr(wp->w_hl_attr, char_attr); + } } /* When still displaying '$' of change command, stop at cursor */ @@ -3083,10 +3096,14 @@ win_line ( mb_l = 1; mb_utf8 = FALSE; multi_attr = hl_attr(HLF_AT); - /* put the pointer back to output the double-width - * character at the start of the next line. */ - ++n_extra; - --p_extra; + if (wp->w_hl_attr != 0) { + multi_attr = hl_combine_attr(wp->w_hl_attr, multi_attr); + } + + // put the pointer back to output the double-width + // character at the start of the next line. + n_extra++; + p_extra--; } else { n_extra -= mb_l - 1; p_extra += mb_l - 1; @@ -3221,11 +3238,15 @@ win_line ( mb_utf8 = FALSE; mb_l = 1; multi_attr = hl_attr(HLF_AT); - /* Put pointer back so that the character will be - * displayed at the start of the next line. */ - --ptr; - } else if (*ptr != NUL) + if (wp->w_hl_attr != 0) { + multi_attr = hl_combine_attr(wp->w_hl_attr, multi_attr); + } + // Put pointer back so that the character will be + // displayed at the start of the next line. + ptr--; + } else if (*ptr != NUL) { ptr += mb_l - 1; + } /* If a double-width char doesn't fit at the left side display * a '<' in the first column. Don't do this for unprintable @@ -3752,7 +3773,10 @@ win_line ( mb_utf8 = false; // don't draw as UTF-8 } saved_attr3 = char_attr; // save current attr - char_attr = hl_attr(HLF_AT); // later copied to char_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); + } n_attr3 = 1; } @@ -3836,6 +3860,10 @@ win_line ( } } } + + if (wp->w_hl_attr != 0) { + char_attr = hl_combine_attr(wp->w_hl_attr, char_attr); + } ScreenAttrs[off] = char_attr; if (wp->w_p_rl) { --col; @@ -3897,6 +3925,14 @@ 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); + } + + while (col < wp->w_width) { ScreenLines[off] = ' '; if (enc_utf8) @@ -3906,12 +3942,13 @@ win_line ( draw_color_col = advance_color_col(VCOL_HLC, &color_cols); - if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) - ScreenAttrs[off++] = hl_attr(HLF_CUC); - else if (draw_color_col && VCOL_HLC == *color_cols) - ScreenAttrs[off++] = hl_attr(HLF_MC); - else - ScreenAttrs[off++] = 0; + if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) { + ScreenAttrs[off++] = cuc_attr; + } else if (draw_color_col && VCOL_HLC == *color_cols) { + ScreenAttrs[off++] = mc_attr; + } else { + ScreenAttrs[off++] = wp->w_hl_attr; + } if (VCOL_HLC >= rightmost_vcol) break; @@ -3920,6 +3957,7 @@ win_line ( } } + // TODO(bfredl): integrate with the common beyond-the-end-loop if (wp->w_buffer->terminal) { // terminal buffers may need to highlight beyond the end of the // logical line @@ -3961,6 +3999,9 @@ win_line ( || (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); + } mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { mb_utf8 = TRUE; @@ -5510,7 +5551,19 @@ 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 */ + // time limit is set at the toplevel, for all windows + + // 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); + } } /* diff --git a/src/nvim/window.c b/src/nvim/window.c index 85f3667b6b..b71b48a6b7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3722,6 +3722,12 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, if (restart_edit) redraw_later(VALID); /* causes status line redraw */ + if (hl_attr(HLF_INACTIVE) + || (prevwin && prevwin->w_hl_id_inactive) + || curwin->w_hl_id_inactive) { + redraw_all_later(NOT_VALID); + } + /* set window height to desired minimal value */ if (curwin->w_height < p_wh && !curwin->w_p_wfh) win_setheight((int)p_wh); diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index e6036a6b79..f4eec4bdc7 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -194,8 +194,8 @@ describe('ui/cursor', function() if m.blinkoff then m.blinkoff = 400 end if m.blinkwait then m.blinkwait = 700 end end - if m.hl_id then m.hl_id = 46 end - if m.id_lm then m.id_lm = 47 end + if m.hl_id then m.hl_id = 47 end + if m.id_lm then m.id_lm = 48 end end -- Assert the new expectation. |