diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 7ed0c1b3c0..dbbeabbba2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -73,6 +73,7 @@ typedef struct { LineDrawState draw_state; ///< what to draw next linenr_T lnum; ///< line number to be drawn + foldinfo_T foldinfo; ///< fold info for this line int startrow; ///< first row in the window to be drawn int row; ///< row in the window, excl w_winrow @@ -88,6 +89,12 @@ typedef struct { int line_attr; ///< attribute for the whole line int line_attr_lowprio; ///< low-priority attribute for the line + int fromcol; ///< start of inverting + int tocol; ///< end of inverting + + long vcol_sbr; ///< virtual column after showbreak + bool need_showbreak; ///< overlong line, skipping first x chars + int char_attr; ///< attributes for next character int n_extra; ///< number of extra bytes @@ -98,8 +105,18 @@ typedef struct { int c_extra; ///< extra chars, all the same int c_final; ///< final char, mandatory if set + // saved "extra" items for when draw_state becomes WL_LINE (again) + int saved_n_extra; + char *saved_p_extra; + int saved_c_extra; + int saved_c_final; + int saved_char_attr; + char extra[57]; ///< sign, line number and 'fdc' must fit in here + hlf_T diff_hlf; ///< type of diff highlighting + + int n_virt_lines; ///< nr of virtual lines int filler_lines; ///< nr of filler lines to be drawn int filler_todo; ///< nr of filler lines still to do + 1 SignTextAttrs sattrs[SIGN_SHOW_MAX]; ///< sign attributes for the sign column @@ -337,13 +354,36 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, } /// Return true if CursorLineSign highlight is to be used. -static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) +static bool use_cursor_line_highlight(win_T *wp, linenr_T lnum) { return wp->w_p_cul && lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR); } +/// Setup for drawing the 'foldcolumn', if there is one. +static void handle_foldcolumn(win_T *wp, winlinevars_T *wlv) +{ + int fdc = compute_foldcolumn(wp, 0); + if (fdc <= 0) { + return; + } + + // Allocate a buffer, "wlv->extra[]" may already be in use. + xfree(wlv->p_extra_free); + wlv->p_extra_free = xmalloc(MAX_MCO * (size_t)fdc + 1); + wlv->n_extra = (int)fill_foldcolumn(wlv->p_extra_free, wp, wlv->foldinfo, wlv->lnum); + wlv->p_extra_free[wlv->n_extra] = NUL; + wlv->p_extra = wlv->p_extra_free; + wlv->c_extra = NUL; + wlv->c_final = NUL; + if (use_cursor_line_highlight(wp, wlv->lnum)) { + wlv->char_attr = win_hl_attr(wp, HLF_CLF); + } else { + wlv->char_attr = win_hl_attr(wp, HLF_FC); + } +} + /// Get information needed to display the sign in line "wlv->lnum" in window "wp". /// If "nrcol" is true, the sign is going to be displayed in the number column. /// Otherwise the sign is going to be displayed in the sign column. @@ -356,7 +396,7 @@ static void get_sign_display_info(bool nrcol, win_T *wp, winlinevars_T *wlv, int if (nrcol) { wlv->n_extra = number_width(wp) + 1; } else { - if (use_cursor_line_sign(wp, wlv->lnum)) { + if (use_cursor_line_highlight(wp, wlv->lnum)) { wlv->char_attr = win_hl_attr(wp, HLF_CLS); } else { wlv->char_attr = win_hl_attr(wp, HLF_SC); @@ -401,7 +441,7 @@ static void get_sign_display_info(bool nrcol, win_T *wp, winlinevars_T *wlv, int } } - if (use_cursor_line_sign(wp, wlv->lnum) && sign_cul_attr > 0) { + if (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr > 0) { wlv->char_attr = sign_cul_attr; } else { wlv->char_attr = sattr->hl_attr_id; @@ -429,6 +469,67 @@ static int get_sign_attrs(buf_T *buf, winlinevars_T *wlv, int *sign_num_attrp, i return num_signs; } +static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len) +{ + long num; + char *fmt = "%*ld "; + + if (wp->w_p_nu && !wp->w_p_rnu) { + // 'number' + 'norelativenumber' + num = (long)lnum; + } else { + // 'relativenumber', don't use negative numbers + num = labs((long)get_cursor_rel_lnum(wp, lnum)); + if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { + // 'number' + 'relativenumber' + num = lnum; + fmt = "%-*ld "; + } + } + + snprintf(buf, buf_len, fmt, number_width(wp), num); +} + +/// Return true if CursorLineNr highlight is to be used for the number column. +/// - 'cursorline' must be set +/// - "wlv->lnum" must be the cursor line +/// - 'cursorlineopt' has "number" +/// - don't highlight filler lines (when in diff mode) +/// - When line is wrapped and 'cursorlineopt' does not have "line", only highlight the line number +/// itself on the first screenline of the wrapped line, otherwise highlight the number column of +/// all screenlines of the wrapped line. +static bool use_cursor_line_nr(win_T *wp, winlinevars_T *wlv) +{ + return wp->w_p_cul + && wlv->lnum == wp->w_cursorline + && (wp->w_p_culopt_flags & CULOPT_NBR) + && (wlv->row == wlv->startrow + wlv->filler_lines + || (wlv->row > wlv->startrow + wlv->filler_lines + && (wp->w_p_culopt_flags & CULOPT_LINE))); +} + +static int get_line_number_attr(win_T *wp, winlinevars_T *wlv) +{ + if (use_cursor_line_nr(wp, wlv)) { + // TODO(vim): Can we use CursorLine instead of CursorLineNr + // when CursorLineNr isn't set? + return win_hl_attr(wp, HLF_CLN); + } + + if (wp->w_p_rnu) { + if (wlv->lnum < wp->w_cursor.lnum) { + // Use LineNrAbove + return win_hl_attr(wp, HLF_LNA); + } + if (wlv->lnum > wp->w_cursor.lnum) { + // Use LineNrBelow + return win_hl_attr(wp, HLF_LNB); + } + } + + return win_hl_attr(wp, HLF_N); +} + /// Display the absolute or relative line number. After the first row fill with /// blanks when the 'n' flag isn't in 'cpo'. static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int num_signs, int sign_idx, @@ -554,66 +655,101 @@ static void get_statuscol_display_info(statuscol_T *stcp, winlinevars_T *wlv) } while (wlv->n_extra == 0 && stcp->textp < stcp->text_end); } -/// Return true if CursorLineNr highlight is to be used for the number column. -/// -/// - 'cursorline' must be set -/// - lnum must be the cursor line -/// - 'cursorlineopt' has "number" -/// - don't highlight filler lines (when in diff mode) -/// - When line is wrapped and 'cursorlineopt' does not have "line", only highlight the line number -/// itself on the first screenline of the wrapped line, otherwise highlight the number column of -/// all screenlines of the wrapped line. -static bool use_cursor_line_nr(win_T *wp, winlinevars_T *wlv) +static void handle_breakindent(win_T *wp, winlinevars_T *wlv) { - return wp->w_p_cul - && wlv->lnum == wp->w_cursorline - && (wp->w_p_culopt_flags & CULOPT_NBR) - && (wlv->row == wlv->startrow + wlv->filler_lines - || (wlv->row > wlv->startrow + wlv->filler_lines - && (wp->w_p_culopt_flags & CULOPT_LINE))); + if (wp->w_briopt_sbr && wlv->draw_state == WL_BRI - 1 + && *get_showbreak_value(wp) != NUL) { + // draw indent after showbreak value + wlv->draw_state = WL_BRI; + } else if (wp->w_briopt_sbr && wlv->draw_state == WL_SBR) { + // after the showbreak, draw the breakindent + wlv->draw_state = WL_BRI - 1; + } + + // draw 'breakindent': indent wrapped text accordingly + if (wlv->draw_state == WL_BRI - 1 && wlv->n_extra == 0) { + wlv->draw_state = WL_BRI; + // if wlv->need_showbreak is set, breakindent also applies + if (wp->w_p_bri && (wlv->row != wlv->startrow || wlv->need_showbreak) + && wlv->filler_lines == 0) { + wlv->char_attr = 0; + if (wlv->diff_hlf != (hlf_T)0) { + wlv->char_attr = win_hl_attr(wp, (int)wlv->diff_hlf); + } + wlv->p_extra = NULL; + wlv->c_extra = ' '; + wlv->c_final = NUL; + wlv->n_extra = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, wlv->lnum, false)); + if (wlv->row == wlv->startrow) { + wlv->n_extra -= win_col_off2(wp); + if (wlv->n_extra < 0) { + wlv->n_extra = 0; + } + } + if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) { + wlv->need_showbreak = false; + } + // Correct end of highlighted area for 'breakindent', + // required wen 'linebreak' is also set. + if (wlv->tocol == wlv->vcol) { + wlv->tocol += wlv->n_extra; + } + } + } } -static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len) +static void handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv) { - long num; - char *fmt = "%*ld "; - - if (wp->w_p_nu && !wp->w_p_rnu) { - // 'number' + 'norelativenumber' - num = (long)lnum; - } else { - // 'relativenumber', don't use negative numbers - num = labs((long)get_cursor_rel_lnum(wp, lnum)); - if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { - // 'number' + 'relativenumber' - num = lnum; - fmt = "%-*ld "; + if (wlv->filler_todo > wlv->filler_lines - wlv->n_virt_lines) { + // TODO(bfredl): check this doesn't inhibit TUI-style + // clear-to-end-of-line. + wlv->c_extra = ' '; + wlv->c_final = NUL; + if (wp->w_p_rl) { + wlv->n_extra = wlv->col + 1; + } else { + wlv->n_extra = wp->w_grid.cols - wlv->col; } + wlv->char_attr = 0; + } else if (wlv->filler_todo > 0) { + // Draw "deleted" diff line(s) + if (char2cells(wp->w_p_fcs_chars.diff) > 1) { + wlv->c_extra = '-'; + wlv->c_final = NUL; + } else { + wlv->c_extra = wp->w_p_fcs_chars.diff; + wlv->c_final = NUL; + } + if (wp->w_p_rl) { + wlv->n_extra = wlv->col + 1; + } else { + wlv->n_extra = wp->w_grid.cols - wlv->col; + } + wlv->char_attr = win_hl_attr(wp, HLF_DED); } - snprintf(buf, buf_len, fmt, number_width(wp), num); -} - -static int get_line_number_attr(win_T *wp, winlinevars_T *wlv) -{ - if (use_cursor_line_nr(wp, wlv)) { - // TODO(vim): Can we use CursorLine instead of CursorLineNr - // when CursorLineNr isn't set? - return win_hl_attr(wp, HLF_CLN); - } - - if (wp->w_p_rnu) { - if (wlv->lnum < wp->w_cursor.lnum) { - // Use LineNrAbove - return win_hl_attr(wp, HLF_LNA); + char *const sbr = get_showbreak_value(wp); + if (*sbr != NUL && wlv->need_showbreak) { + // Draw 'showbreak' at the start of each broken line. + wlv->p_extra = sbr; + wlv->c_extra = NUL; + wlv->c_final = NUL; + wlv->n_extra = (int)strlen(sbr); + wlv->char_attr = win_hl_attr(wp, HLF_AT); + if (wp->w_skipcol == 0 || !wp->w_p_wrap) { + wlv->need_showbreak = false; } - if (wlv->lnum > wp->w_cursor.lnum) { - // Use LineNrBelow - return win_hl_attr(wp, HLF_LNB); + wlv->vcol_sbr = wlv->vcol + mb_charlen(sbr); + // Correct end of highlighted area for 'showbreak', + // required when 'linebreak' is also set. + if (wlv->tocol == wlv->vcol) { + wlv->tocol += wlv->n_extra; + } + // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. + if (wlv->cul_attr) { + wlv->char_attr = hl_combine_attr(wlv->cul_attr, wlv->char_attr); } } - - return win_hl_attr(wp, HLF_N); } static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv) @@ -683,10 +819,11 @@ static colnr_T get_leadcol(win_T *wp, const char *ptr, const char *line) } /// Start a screen line at column zero. -static void win_line_start(win_T *wp, winlinevars_T *wlv) +static void win_line_start(win_T *wp, winlinevars_T *wlv, bool save_extra) { wlv->col = 0; wlv->off = 0; + if (wp->w_p_rl) { // Rightleft window: process the text in the normal direction, but put // it in linebuf_char[wlv.off] from right to left. Start at the @@ -694,6 +831,33 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv) wlv->col = wp->w_grid.cols - 1; wlv->off += wlv->col; } + + if (save_extra) { + // reset the drawing state for the start of a wrapped line + wlv->draw_state = WL_START; + wlv->saved_n_extra = wlv->n_extra; + wlv->saved_p_extra = wlv->p_extra; + wlv->saved_c_extra = wlv->c_extra; + wlv->saved_c_final = wlv->c_final; + wlv->saved_char_attr = wlv->char_attr; + + wlv->n_extra = 0; + } +} + +/// Called when wlv->draw_state is set to WL_LINE. +static void win_line_continue(winlinevars_T *wlv) +{ + if (wlv->saved_n_extra > 0) { + // Continue item from end of wrapped line. + wlv->n_extra = wlv->saved_n_extra; + wlv->c_extra = wlv->saved_c_extra; + wlv->c_final = wlv->saved_c_final; + wlv->p_extra = wlv->saved_p_extra; + wlv->char_attr = wlv->saved_char_attr; + } else { + wlv->char_attr = 0; + } } /// Display line "lnum" of window 'wp' on the screen. @@ -716,7 +880,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, winlinevars_T wlv; // variables passed between functions int c = 0; // init for GCC - long vcol_sbr = -1; // virtual column after showbreak long vcol_prev = -1; // "wlv.vcol" of previous character char *line; // current line char *ptr; // current position in "line" @@ -726,13 +889,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // at end-of-line bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0; - // saved "extra" items for when draw_state becomes WL_LINE (again) - int saved_n_extra = 0; - char *saved_p_extra = NULL; - int saved_c_extra = 0; - int saved_c_final = 0; - int saved_char_attr = 0; - int n_attr = 0; // chars with special attr int saved_attr2 = 0; // char_attr saved for n_attr int n_attr3 = 0; // chars with overruling special attr @@ -740,8 +896,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int n_skip = 0; // nr of chars to skip for 'nowrap' - int fromcol = -10; // start of inverting - int tocol = MAXCOL; // end of inverting int fromcol_prev = -2; // start of inverting after cursor bool noinvcur = false; // don't invert the cursor bool lnum_in_visual_area = false; @@ -780,12 +934,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int mb_c = 0; // decoded multi-byte character bool mb_utf8 = false; // screen char is UTF-8 char int u8cc[MAX_MCO]; // composing UTF-8 chars - hlf_T diff_hlf = (hlf_T)0; // type of diff highlighting int change_start = MAXCOL; // first col of changed area int change_end = -1; // last col of changed area bool in_multispace = false; // in multiple consecutive spaces int multispace_pos = 0; // position in lcs-multispace string - bool need_showbreak = false; // overlong line, skip first x chars int line_attr_save; int line_attr_lowprio_save; int prev_c = 0; // previous Arabic character @@ -833,8 +985,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, CLEAR_FIELD(wlv); wlv.lnum = lnum; + wlv.foldinfo = foldinfo; wlv.startrow = startrow; wlv.row = startrow; + wlv.fromcol = -10; + wlv.tocol = MAXCOL; + wlv.vcol_sbr = -1; buf_T *buf = wp->w_buffer; bool end_fill = (lnum == buf->b_ml.ml_line_count + 1); @@ -936,37 +1092,37 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (VIsual_mode == Ctrl_V) { // block mode if (lnum_in_visual_area) { - fromcol = wp->w_old_cursor_fcol; - tocol = wp->w_old_cursor_lcol; + wlv.fromcol = wp->w_old_cursor_fcol; + wlv.tocol = wp->w_old_cursor_lcol; } } else { // non-block mode if (lnum > top->lnum && lnum <= bot->lnum) { - fromcol = 0; + wlv.fromcol = 0; } else if (lnum == top->lnum) { if (VIsual_mode == 'V') { // linewise - fromcol = 0; + wlv.fromcol = 0; } else { - getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL); + getvvcol(wp, top, (colnr_T *)&wlv.fromcol, NULL, NULL); if (gchar_pos(top) == NUL) { - tocol = fromcol + 1; + wlv.tocol = wlv.fromcol + 1; } } } if (VIsual_mode != 'V' && lnum == bot->lnum) { if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0) { - fromcol = -10; - tocol = MAXCOL; + wlv.fromcol = -10; + wlv.tocol = MAXCOL; } else if (bot->col == MAXCOL) { - tocol = MAXCOL; + wlv.tocol = MAXCOL; } else { pos = *bot; if (*p_sel == 'e') { - getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL); + getvvcol(wp, &pos, (colnr_T *)&wlv.tocol, NULL, NULL); } else { - getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol); - tocol++; + getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&wlv.tocol); + wlv.tocol++; } } } @@ -979,7 +1135,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // if inverting in this line set area_highlighting - if (fromcol >= 0) { + if (wlv.fromcol >= 0) { area_highlighting = true; vi_attr = win_hl_attr(wp, HLF_V); } @@ -991,18 +1147,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && lnum <= curwin->w_cursor.lnum + search_match_lines) { if (lnum == curwin->w_cursor.lnum) { getvcol(curwin, &(curwin->w_cursor), - (colnr_T *)&fromcol, NULL, NULL); + (colnr_T *)&wlv.fromcol, NULL, NULL); } else { - fromcol = 0; + wlv.fromcol = 0; } if (lnum == curwin->w_cursor.lnum + search_match_lines) { pos.lnum = lnum; pos.col = search_match_endcol; - getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL); + getvcol(curwin, &pos, (colnr_T *)&wlv.tocol, NULL, NULL); } // do at least one character; happens when past end of line - if (fromcol == tocol && search_match_endcol) { - tocol = fromcol + 1; + if (wlv.fromcol == wlv.tocol && search_match_endcol) { + wlv.tocol = wlv.fromcol + 1; } area_highlighting = true; vi_attr = win_hl_attr(wp, HLF_I); @@ -1016,14 +1172,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wlv.filler_lines < 0 || linestatus < 0) { if (wlv.filler_lines == -1 || linestatus == -1) { if (diff_find_change(wp, lnum, &change_start, &change_end)) { - diff_hlf = HLF_ADD; // added line + wlv.diff_hlf = HLF_ADD; // added line } else if (change_start == 0) { - diff_hlf = HLF_TXD; // changed text + wlv.diff_hlf = HLF_TXD; // changed text } else { - diff_hlf = HLF_CHD; // changed line + wlv.diff_hlf = HLF_CHD; // changed line } } else { - diff_hlf = HLF_ADD; // added line + wlv.diff_hlf = HLF_ADD; // added line } if (linestatus == 0) { wlv.filler_lines = 0; @@ -1031,11 +1187,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, area_highlighting = true; } VirtLines virt_lines = KV_INITIAL_VALUE; - int n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines, has_fold); - wlv.filler_lines += n_virt_lines; + wlv.n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines, has_fold); + wlv.filler_lines += wlv.n_virt_lines; if (lnum == wp->w_topline) { wlv.filler_lines = wp->w_topfill; - n_virt_lines = MIN(n_virt_lines, wlv.filler_lines); + wlv.n_virt_lines = MIN(wlv.n_virt_lines, wlv.filler_lines); } wlv.filler_todo = wlv.filler_lines; @@ -1174,15 +1330,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Adjust for when the inverted text is before the screen, // and when the start of the inverted text is before the screen. - if (tocol <= wlv.vcol) { - fromcol = 0; - } else if (fromcol >= 0 && fromcol < wlv.vcol) { - fromcol = wlv.vcol; + if (wlv.tocol <= wlv.vcol) { + wlv.fromcol = 0; + } else if (wlv.fromcol >= 0 && wlv.fromcol < wlv.vcol) { + wlv.fromcol = wlv.vcol; } // When w_skipcol is non-zero, first line needs 'showbreak' if (wp->w_p_wrap) { - need_showbreak = true; + wlv.need_showbreak = true; } // When spell checking a word we need to figure out the start of the // word and if it's badly spelled or not. @@ -1226,20 +1382,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Correct highlighting for cursor that can't be disabled. // Avoids having to check this for each character. - if (fromcol >= 0) { + if (wlv.fromcol >= 0) { if (noinvcur) { - if ((colnr_T)fromcol == wp->w_virtcol) { + if ((colnr_T)wlv.fromcol == wp->w_virtcol) { // highlighting starts at cursor, let it start just after the // cursor - fromcol_prev = fromcol; - fromcol = -1; - } else if ((colnr_T)fromcol < wp->w_virtcol) { + fromcol_prev = wlv.fromcol; + wlv.fromcol = -1; + } else if ((colnr_T)wlv.fromcol < wp->w_virtcol) { // restart highlighting after the cursor fromcol_prev = wp->w_virtcol; } } - if (fromcol >= tocol) { - fromcol = -1; + if (wlv.fromcol >= wlv.tocol) { + wlv.fromcol = -1; } } @@ -1251,7 +1407,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, ptr = line + v; // "line" may have been updated } - win_line_start(wp, &wlv); + win_line_start(wp, &wlv, false); // won't highlight after TERM_ATTRS_MAX columns int term_attrs[TERM_ATTRS_MAX] = { 0 }; @@ -1267,7 +1423,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, statuscol.sattrs = wlv.sattrs; statuscol.foldinfo = foldinfo; statuscol.width = win_col_off(wp) - (cmdwin_type != 0 && wp == curwin); - statuscol.use_cul = use_cursor_line_sign(wp, lnum); + statuscol.use_cul = use_cursor_line_highlight(wp, lnum); statuscol.sign_cul_attr = statuscol.use_cul ? sign_cul_attr : 0; statuscol.num_attr = sign_num_attr ? sign_num_attr : get_line_number_attr(wp, &wlv); } @@ -1303,7 +1459,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) { if (wlv.filler_todo > 0) { - int index = wlv.filler_todo - (wlv.filler_lines - n_virt_lines); + int index = wlv.filler_todo - (wlv.filler_lines - wlv.n_virt_lines); if (index > 0) { virt_line_index = (int)kv_size(virt_lines) - index; assert(virt_line_index >= 0); @@ -1320,24 +1476,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) { - int fdc = compute_foldcolumn(wp, 0); wlv.draw_state = WL_FOLD; - if (fdc > 0) { - // Draw the 'foldcolumn'. - // Allocate a buffer, "wlv->extra[]" may already be in use. - xfree(wlv.p_extra_free); - wlv.p_extra_free = xmalloc(MAX_MCO * (size_t)fdc + 1); - wlv.n_extra = (int)fill_foldcolumn(wlv.p_extra_free, wp, foldinfo, lnum); - wlv.p_extra_free[wlv.n_extra] = NUL; - wlv.p_extra = wlv.p_extra_free; - wlv.c_extra = NUL; - wlv.c_final = NUL; - if (use_cursor_line_sign(wp, lnum)) { - wlv.char_attr = win_hl_attr(wp, HLF_CLF); - } else { - wlv.char_attr = win_hl_attr(wp, HLF_FC); - } - } + handle_foldcolumn(wp, &wlv); } // sign column, this is hit until sign_idx reaches count @@ -1379,120 +1519,25 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, win_col_offset = wlv.off; } - if (wp->w_briopt_sbr && wlv.draw_state == WL_BRI - 1 - && wlv.n_extra == 0 && *get_showbreak_value(wp) != NUL) { - // draw indent after showbreak value - wlv.draw_state = WL_BRI; - } else if (wp->w_briopt_sbr && wlv.draw_state == WL_SBR && wlv.n_extra == 0) { - // after the showbreak, draw the breakindent - wlv.draw_state = WL_BRI - 1; - } - - // draw 'breakindent': indent wrapped text accordingly - if (wlv.draw_state == WL_BRI - 1 && wlv.n_extra == 0) { - wlv.draw_state = WL_BRI; - // if need_showbreak is set, breakindent also applies - if (wp->w_p_bri && (wlv.row != startrow || need_showbreak) - && wlv.filler_lines == 0) { - wlv.char_attr = 0; - - if (diff_hlf != (hlf_T)0) { - wlv.char_attr = win_hl_attr(wp, (int)diff_hlf); - } - wlv.p_extra = NULL; - wlv.c_extra = ' '; - wlv.c_final = NUL; - wlv.n_extra = - get_breakindent_win(wp, ml_get_buf(wp->w_buffer, lnum, false)); - if (wlv.row == startrow) { - wlv.n_extra -= win_col_off2(wp); - if (wlv.n_extra < 0) { - wlv.n_extra = 0; - } - } - if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) { - need_showbreak = false; - } - // Correct end of highlighted area for 'breakindent', - // required wen 'linebreak' is also set. - if (tocol == wlv.vcol) { - tocol += wlv.n_extra; - } - } + // Check if 'breakindent' applies and show it. + // May change wlv.draw_state to WL_BRI or WL_BRI - 1. + if (wlv.n_extra == 0) { + handle_breakindent(wp, &wlv); } if (wlv.draw_state == WL_SBR - 1 && wlv.n_extra == 0) { wlv.draw_state = WL_SBR; - if (wlv.filler_todo > wlv.filler_lines - n_virt_lines) { - // TODO(bfredl): check this doesn't inhibit TUI-style - // clear-to-end-of-line. - wlv.c_extra = ' '; - wlv.c_final = NUL; - if (wp->w_p_rl) { - wlv.n_extra = wlv.col + 1; - } else { - wlv.n_extra = grid->cols - wlv.col; - } - wlv.char_attr = 0; - } else if (wlv.filler_todo > 0) { - // Draw "deleted" diff line(s) - if (char2cells(wp->w_p_fcs_chars.diff) > 1) { - wlv.c_extra = '-'; - wlv.c_final = NUL; - } else { - wlv.c_extra = wp->w_p_fcs_chars.diff; - wlv.c_final = NUL; - } - if (wp->w_p_rl) { - wlv.n_extra = wlv.col + 1; - } else { - wlv.n_extra = grid->cols - wlv.col; - } - wlv.char_attr = win_hl_attr(wp, HLF_DED); - } - char *const sbr = get_showbreak_value(wp); - if (*sbr != NUL && need_showbreak) { - // Draw 'showbreak' at the start of each broken line. - wlv.p_extra = sbr; - wlv.c_extra = NUL; - wlv.c_final = NUL; - wlv.n_extra = (int)strlen(sbr); - wlv.char_attr = win_hl_attr(wp, HLF_AT); - if (wp->w_skipcol == 0 || !wp->w_p_wrap) { - need_showbreak = false; - } - vcol_sbr = wlv.vcol + mb_charlen(sbr); - // Correct end of highlighted area for 'showbreak', - // required when 'linebreak' is also set. - if (tocol == wlv.vcol) { - tocol += wlv.n_extra; - } - // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. - if (wlv.cul_attr) { - wlv.char_attr = hl_combine_attr(wlv.cul_attr, wlv.char_attr); - } - } + handle_showbreak_and_filler(wp, &wlv); } if (wlv.draw_state == WL_LINE - 1 && wlv.n_extra == 0) { sign_idx = 0; wlv.draw_state = WL_LINE; - if (has_decor && wlv.row == startrow + wlv.filler_lines) { // hide virt_text on text hidden by 'nowrap' decor_redraw_col(wp->w_buffer, wlv.vcol, wlv.off, true, &decor_state); } - - if (saved_n_extra) { - // Continue item from end of wrapped line. - wlv.n_extra = saved_n_extra; - wlv.c_extra = saved_c_extra; - wlv.c_final = saved_c_final; - wlv.p_extra = saved_p_extra; - wlv.char_attr = saved_char_attr; - } else { - wlv.char_attr = 0; - } + win_line_continue(&wlv); // use wlv.saved_ values } } @@ -1565,19 +1610,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wlv.draw_state == WL_LINE && (area_highlighting || has_spell)) { // handle Visual or match highlighting in this line - if (wlv.vcol == fromcol - || (wlv.vcol + 1 == fromcol && wlv.n_extra == 0 + if (wlv.vcol == wlv.fromcol + || (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0 && utf_ptr2cells(ptr) > 1) || ((int)vcol_prev == fromcol_prev && vcol_prev < wlv.vcol // not at margin - && wlv.vcol < tocol)) { + && wlv.vcol < wlv.tocol)) { area_attr = vi_attr; // start highlighting if (area_highlighting) { area_active = true; } - } else if (area_attr != 0 && (wlv.vcol == tocol - || (noinvcur - && wlv.vcol == wp->w_virtcol))) { + } else if (area_attr != 0 && (wlv.vcol == wlv.tocol + || (noinvcur && wlv.vcol == wp->w_virtcol))) { area_attr = 0; // stop highlighting area_active = false; } @@ -1599,16 +1643,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } - if (diff_hlf != (hlf_T)0) { - if (diff_hlf == HLF_CHD && ptr - line >= change_start + if (wlv.diff_hlf != (hlf_T)0) { + if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start && wlv.n_extra == 0) { - diff_hlf = HLF_TXD; // changed text + wlv.diff_hlf = HLF_TXD; // changed text } - if (diff_hlf == HLF_TXD && ptr - line > change_end + if (wlv.diff_hlf == HLF_TXD && ptr - line > change_end && wlv.n_extra == 0) { - diff_hlf = HLF_CHD; // changed line + wlv.diff_hlf = HLF_CHD; // changed line } - wlv.line_attr = win_hl_attr(wp, (int)diff_hlf); + wlv.line_attr = win_hl_attr(wp, (int)wlv.diff_hlf); // Overlay CursorLine onto diff-mode highlight. if (wlv.cul_attr) { wlv.line_attr = 0 != wlv.line_attr_lowprio // Low-priority CursorLine @@ -1629,9 +1673,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } else if (search_attr != 0) { wlv.char_attr = hl_combine_attr(wlv.line_attr, search_attr); - } else if (wlv.line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL) - || wlv.vcol < fromcol || vcol_prev < fromcol_prev - || wlv.vcol >= tocol)) { + } else if (wlv.line_attr != 0 + && ((wlv.fromcol == -10 && wlv.tocol == MAXCOL) + || wlv.vcol < wlv.fromcol + || vcol_prev < fromcol_prev + || wlv.vcol >= wlv.tocol)) { // Use wlv.line_attr when not in the Visual or 'incsearch' area // (area_attr may be 0 when "noinvcur" is set). wlv.char_attr = wlv.line_attr; @@ -1990,7 +2036,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // We have just drawn the showbreak value, no need to add // space for it again. - if (wlv.vcol == vcol_sbr) { + if (wlv.vcol == wlv.vcol_sbr) { wlv.n_extra -= mb_charlen(get_showbreak_value(wp)); if (wlv.n_extra < 0) { wlv.n_extra = 0; @@ -2091,7 +2137,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Only adjust the tab_len, when at the first column after the // showbreak value was drawn. - if (*sbr != NUL && wlv.vcol == vcol_sbr && wp->w_p_wrap) { + if (*sbr != NUL && wlv.vcol == wlv.vcol_sbr && wp->w_p_wrap) { vcol_adjusted = wlv.vcol - mb_charlen(sbr); } // tab amount depends on current column @@ -2200,8 +2246,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } else if (c == NUL && (wp->w_p_list - || ((fromcol >= 0 || fromcol_prev >= 0) - && tocol > wlv.vcol + || ((wlv.fromcol >= 0 || fromcol_prev >= 0) + && wlv.tocol > wlv.vcol && VIsual_mode != Ctrl_V && (wp->w_p_rl ? (wlv.col >= 0) : (wlv.col < grid->cols)) && !(noinvcur @@ -2211,12 +2257,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Display a '$' after the line or highlight an extra // character if the line break is included. // For a diff line the highlighting continues after the "$". - if (diff_hlf == (hlf_T)0 + if (wlv.diff_hlf == (hlf_T)0 && wlv.line_attr == 0 && wlv.line_attr_lowprio == 0) { // In virtualedit, visual selections may extend beyond end of line if (area_highlighting && virtual_active() - && tocol != MAXCOL && wlv.vcol < tocol) { + && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol) { wlv.n_extra = 0; } else { wlv.p_extra = at_end_str; @@ -2269,8 +2315,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } else if (VIsual_active && (VIsual_mode == Ctrl_V || VIsual_mode == 'v') && virtual_active() - && tocol != MAXCOL - && wlv.vcol < tocol + && wlv.tocol != MAXCOL + && wlv.vcol < wlv.tocol && (wp->w_p_rl ? (wlv.col >= 0) : (wlv.col < grid->cols))) { c = ' '; ptr--; // put it back at the NUL @@ -2400,7 +2446,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // char on the screen, just overwrite that one (tricky!) Not // needed when a '$' was displayed for 'list'. if (wp->w_p_lcs_chars.eol == lcs_eol_one - && ((area_attr != 0 && wlv.vcol == fromcol + && ((area_attr != 0 && wlv.vcol == wlv.fromcol && (VIsual_mode != Ctrl_V || lnum == VIsual.lnum || lnum == curwin->w_cursor.lnum)) @@ -2491,7 +2537,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, (long)grid->cols * (wlv.row - startrow + 1) + v && lnum != wp->w_cursor.lnum) || draw_color_col || wlv.line_attr_lowprio || wlv.line_attr - || diff_hlf != (hlf_T)0 || has_virttext)) { + || wlv.diff_hlf != (hlf_T)0 || has_virttext)) { int rightmost_vcol = 0; if (wp->w_p_cuc) { @@ -2511,11 +2557,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int mc_attr = win_hl_attr(wp, HLF_MC); int diff_attr = 0; - if (diff_hlf == HLF_TXD) { - diff_hlf = HLF_CHD; + if (wlv.diff_hlf == HLF_TXD) { + wlv.diff_hlf = HLF_CHD; } - if (diff_hlf != 0) { - diff_attr = win_hl_attr(wp, (int)diff_hlf); + if (wlv.diff_hlf != 0) { + diff_attr = win_hl_attr(wp, (int)wlv.diff_hlf); } int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr); @@ -2668,10 +2714,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) { wlv.vcol++; } - // When "tocol" is halfway through a character, set it to the end of - // the character, otherwise highlighting won't stop. - if (tocol == wlv.vcol) { - tocol++; + // When "wlv.tocol" is halfway through a character, set it to the end + // of the character, otherwise highlighting won't stop. + if (wlv.tocol == wlv.vcol) { + wlv.tocol++; } if (wp->w_p_rl) { // now it's time to backup one cell @@ -2829,19 +2875,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, break; } - win_line_start(wp, &wlv); + win_line_start(wp, &wlv, true); - // reset the drawing state for the start of a wrapped line - wlv.draw_state = WL_START; - saved_n_extra = wlv.n_extra; - saved_p_extra = wlv.p_extra; - saved_c_extra = wlv.c_extra; - saved_c_final = wlv.c_final; - saved_char_attr = wlv.char_attr; - wlv.n_extra = 0; lcs_prec_todo = wp->w_p_lcs_chars.prec; if (wlv.filler_todo <= 0) { - need_showbreak = true; + wlv.need_showbreak = true; } if (statuscol.draw) { if (wlv.row == startrow + wlv.filler_lines + 1