diff options
Diffstat (limited to 'src/nvim/screen.c')
-rw-r--r-- | src/nvim/screen.c | 159 |
1 files changed, 129 insertions, 30 deletions
diff --git a/src/nvim/screen.c b/src/nvim/screen.c index b048facfb7..2fc5777937 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1371,7 +1371,9 @@ static void win_update(win_T *wp, Providers *providers) // match in fixed position might need redraw // if lines were inserted or deleted || (wp->w_match_head != NULL - && buf->b_mod_xlines != 0)))))) { + && buf->b_mod_xlines != 0))))) + || (wp->w_p_cul && (lnum == wp->w_cursor.lnum + || lnum == wp->w_last_cursorline))) { if (lnum == mod_top) { top_to_mod = false; } @@ -1381,10 +1383,12 @@ static void win_update(win_T *wp, Providers *providers) * up or down to minimize redrawing. * Don't do this when the change continues until the end. * Don't scroll when dollar_vcol >= 0, keep the "$". + * Don't scroll when redrawing the top, scrolled already above. */ if (lnum == mod_top && mod_bot != MAXLNUM - && !(dollar_vcol >= 0 && mod_bot == mod_top + 1)) { + && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) + && row >= top_end) { int old_rows = 0; int new_rows = 0; int xtra_rows; @@ -2090,7 +2094,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, sign_attrs_T sattrs[SIGN_SHOW_MAX]; // attributes for signs int num_signs; // number of signs for line int line_attr = 0; // attribute for the whole line + int line_attr_save; int line_attr_lowprio = 0; // low-priority attribute for the line + int line_attr_lowprio_save; matchitem_T *cur; // points to the match list match_T *shl; // points to search_hl or a match bool shl_flag; // flag to indicate whether search_hl @@ -2109,6 +2115,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool area_active = false; + int cul_attr = 0; // set when 'cursorline' active + // 'cursorlineopt' has "screenline" and cursor is in this line + bool cul_screenline = false; + // margin columns for the screen line, needed for when 'cursorlineopt' + // contains "screenline" + int left_curline_col = 0; + int right_curline_col = 0; + /* draw_state: items that are drawn in sequence: */ #define WL_START 0 /* nothing done yet */ # define WL_CMDLINE WL_START + 1 /* cmdline window column */ @@ -2360,26 +2374,34 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, // Cursor line highlighting for 'cursorline' in the current window. if (lnum == wp->w_cursor.lnum) { - // Do not show the cursor line when Visual mode is active, because it's - // not clear what is selected then. + // Do not show the cursor line in the text when Visual mode is active, + // because it's not clear what is selected then. if (wp->w_p_cul && !(wp == curwin && VIsual_active) - && *wp->w_p_culopt != 'n') { - int cul_attr = win_hl_attr(wp, HLF_CUL); + && wp->w_p_culopt_flags != CULOPT_NBR) { + cul_screenline = (wp->w_p_wrap + && (wp->w_p_culopt_flags & CULOPT_SCRLINE)); + cul_attr = win_hl_attr(wp, HLF_CUL); HlAttrs ae = syn_attr2entry(cul_attr); // We make a compromise here (#7383): // * low-priority CursorLine if fg is not set // * high-priority ("same as Vim" priority) CursorLine if fg is set - if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) { - line_attr_lowprio = cul_attr; - } else { - if (!(State & INSERT) && bt_quickfix(wp->w_buffer) - && qf_current_entry(wp) == lnum) { - line_attr = hl_combine_attr(cul_attr, line_attr); + if (!cul_screenline) { + if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) { + line_attr_lowprio = cul_attr; } else { - line_attr = cul_attr; + if (!(State & INSERT) && bt_quickfix(wp->w_buffer) + && qf_current_entry(wp) == lnum) { + line_attr = hl_combine_attr(cul_attr, line_attr); + } else { + line_attr = cul_attr; + } } + } else { + cul_attr = 0; + margin_columns_win(wp, &left_curline_col, &right_curline_col); } + area_highlighting = true; } // Update w_last_cursorline even if Visual mode is active. wp->w_last_cursorline = wp->w_cursor.lnum; @@ -2404,6 +2426,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, area_highlighting = true; } + if (cul_screenline) { + line_attr_save = line_attr; + line_attr_lowprio_save = line_attr_lowprio; + } + line = ml_get_buf(wp->w_buffer, lnum, FALSE); ptr = line; @@ -2786,12 +2813,16 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (num_sattr != NULL) { // :sign defined with "numhl" highlight. char_attr = num_sattr->sat_numhl; - } else if ((wp->w_p_cul || wp->w_p_rnu) - && *wp->w_p_culopt != 'l' + } else if (wp->w_p_cul && lnum == wp->w_cursor.lnum + && (wp->w_p_culopt_flags & CULOPT_NBR) + && (row == startrow + || wp->w_p_culopt_flags & CULOPT_LINE) && filler_todo == 0) { // When 'cursorline' is set highlight the line number of // the current line differently. + // When 'cursorlineopt' has "screenline" only highlight + // the line number itself. // TODO(vim): Can we use CursorLine instead of CursorLineNr // when CursorLineNr isn't set? char_attr = win_hl_attr(wp, HLF_CLN); @@ -2823,9 +2854,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (diff_hlf != (hlf_T)0) { char_attr = win_hl_attr(wp, diff_hlf); - if (wp->w_p_cul && lnum == wp->w_cursor.lnum - && *wp->w_p_culopt != 'n') { - char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUL)); + if (cul_attr) { + char_attr = hl_combine_attr(char_attr, cul_attr); } } p_extra = NULL; @@ -2884,9 +2914,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (tocol == vcol) tocol += n_extra; // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. - if (wp->w_p_cul && lnum == wp->w_cursor.lnum - && *wp->w_p_culopt != 'n') { - char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), char_attr); + if (cul_attr) { + char_attr = hl_combine_attr(cul_attr, char_attr); } } } @@ -2913,6 +2942,24 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } } + if (cul_screenline) { + if (draw_state == WL_LINE + && vcol >= left_curline_col + && vcol < right_curline_col) { + cul_attr = win_hl_attr(wp, HLF_CUL); + HlAttrs ae = syn_attr2entry(cul_attr); + if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) { + line_attr_lowprio = cul_attr; + } else { + line_attr = cul_attr; + } + } else { + cul_attr = 0; + line_attr = line_attr_save; + line_attr_lowprio = line_attr_lowprio_save; + } + } + // When still displaying '$' of change command, stop at cursor if (((dollar_vcol >= 0 && wp == curwin @@ -3120,13 +3167,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } line_attr = win_hl_attr(wp, diff_hlf); // Overlay CursorLine onto diff-mode highlight. - if (wp->w_p_cul && lnum == wp->w_cursor.lnum - && *wp->w_p_culopt != 'n') { + if (cul_attr) { line_attr = 0 != line_attr_lowprio // Low-priority CursorLine - ? hl_combine_attr(hl_combine_attr(win_hl_attr(wp, HLF_CUL), - line_attr), + ? hl_combine_attr(hl_combine_attr(cul_attr, line_attr), hl_get_underline()) - : hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL)); + : hl_combine_attr(line_attr, cul_attr); } } @@ -3202,6 +3247,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, (void)mb_l; multi_attr = win_hl_attr(wp, HLF_AT); + if (cul_attr) { + multi_attr = 0 != line_attr_lowprio + ? hl_combine_attr(cul_attr, multi_attr) + : hl_combine_attr(multi_attr, cul_attr); + } + // put the pointer back to output the double-width // character at the start of the next line. n_extra++; @@ -3362,7 +3413,13 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, ptr = line + v; if (!attr_pri) { - char_attr = syntax_attr; + if (cul_attr) { + char_attr = 0 != line_attr_lowprio + ? hl_combine_attr(cul_attr, syntax_attr) + : hl_combine_attr(syntax_attr, cul_attr); + } else { + char_attr = syntax_attr; + } } else { char_attr = hl_combine_attr(syntax_attr, char_attr); } @@ -3929,9 +3986,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } int eol_attr = char_attr; - if (wp->w_p_cul && lnum == wp->w_cursor.lnum - && *wp->w_p_culopt != 'n') { - eol_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), eol_attr); + if (cul_attr) { + eol_attr = hl_combine_attr(cul_attr, eol_attr); } linebuf_attr[off] = eol_attr; if (wp->w_p_rl) { @@ -7516,6 +7572,49 @@ int number_width(win_T *wp) return n; } +/// Used when 'cursorlineopt' contains "screenline": compute the margins between +/// which the highlighting is used. +static void margin_columns_win(win_T *wp, int *left_col, int *right_col) +{ + // cache previous calculations depending on w_virtcol + static int saved_w_virtcol; + static win_T *prev_wp; + static int prev_left_col; + static int prev_right_col; + static int prev_col_off; + + int cur_col_off = win_col_off(wp); + int width1; + int width2; + + if (saved_w_virtcol == wp->w_virtcol && prev_wp == wp + && prev_col_off == cur_col_off) { + *right_col = prev_right_col; + *left_col = prev_left_col; + return; + } + + width1 = wp->w_width - cur_col_off; + width2 = width1 + win_col_off2(wp); + + *left_col = 0; + *right_col = width1; + + if (wp->w_virtcol >= (colnr_T)width1) { + *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2; + } + if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) { + *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1; + } + + // cache values + prev_left_col = *left_col; + prev_right_col = *right_col; + prev_wp = wp; + saved_w_virtcol = wp->w_virtcol; + prev_col_off = cur_col_off; +} + /// Set dimensions of the Nvim application "shell". void screen_resize(int width, int height) { |