From: zeertzjq Date: Fri, 3 Apr 2026 09:48:49 +0000 (+0000) Subject: patch 9.2.0289: 'linebreak' may lead to wrong Visual block highlighting X-Git-Tag: v9.2.0289^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=23be1889d1a1212445ca8bb9cd378484d3755f79;p=thirdparty%2Fvim.git patch 9.2.0289: 'linebreak' may lead to wrong Visual block highlighting Problem: 'linebreak' may lead to wrong Visual block highlighting when end char occupies multiple cells (after 7.4.467). Solution: Exclude 'linebreak' from the ending column instead of setting 'virtualedit' temporarily (zeertzjq). fixes: #19898 closes: #19900 Signed-off-by: zeertzjq Signed-off-by: Christian Brabandt --- diff --git a/src/change.c b/src/change.c index 3a4fefb2b8..8dd7e9d9ba 100644 --- a/src/change.c +++ b/src/change.c @@ -1263,7 +1263,7 @@ ins_char_bytes(char_u *buf, int charlen) // characters (zero if it's a TAB). Count the number of bytes to // be deleted to make room for the new character, counting screen // cells. May result in adding spaces to fill a gap. - getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL); + getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL, 0); new_vcol = vcol + chartabsize(buf, vcol); while (oldp[col + oldlen] != NUL && vcol < new_vcol) { diff --git a/src/charset.c b/src/charset.c index 49320fcb64..1fbbf98f76 100644 --- a/src/charset.c +++ b/src/charset.c @@ -905,7 +905,7 @@ win_linetabsize_cts(chartabsize_T *cts, colnr_T len) for ( ; *cts->cts_ptr != NUL && (len == MAXCOL || cts->cts_ptr < cts->cts_line + len); MB_PTR_ADV(cts->cts_ptr)) { - vcol += win_lbr_chartabsize(cts, NULL); + vcol += win_lbr_chartabsize(cts, NULL, NULL); if (vcol > MAXCOL) { cts->cts_vcol = MAXCOL; @@ -919,7 +919,7 @@ win_linetabsize_cts(chartabsize_T *cts, colnr_T len) if (len == MAXCOL && cts->cts_has_prop_with_text && *cts->cts_ptr == NUL) { int head = 0; - (void)win_lbr_chartabsize(cts, &head); + (void)win_lbr_chartabsize(cts, &head, NULL); vcol += cts->cts_cur_text_width + head; // when properties are above or below the empty line must also be // counted @@ -1186,7 +1186,7 @@ lbr_chartabsize(chartabsize_T *cts) RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, cts->cts_ptr, cts->cts_vcol) #if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) } - return win_lbr_chartabsize(cts, NULL); + return win_lbr_chartabsize(cts, NULL, NULL); #endif } @@ -1209,19 +1209,24 @@ lbr_chartabsize_adv(chartabsize_T *cts) * inserts text. * This function is used very often, keep it fast!!!! * - * If "headp" not NULL, set "*headp" to the size of 'showbreak'/'breakindent' + * If "headp" isn't NULL, set "*headp" to the size of 'showbreak'/'breakindent' * included in the return value. * When "cts->cts_max_head_vcol" is positive, only count in "*headp" the size * of 'showbreak'/'breakindent' before "cts->cts_max_head_vcol". * When "cts->cts_max_head_vcol" is negative, only count in "*headp" the size * of 'showbreak'/'breakindent' before where cursor should be placed. * - * Warning: "*headp" may not be set if it's 0, init to 0 before calling. + * If "tailp" isn't NULL, set "*tailp" to the size of 'linebreak' included in + * the return value. + * + * Warning: "*headp" and "*tailp" may not be set if the value is 0, init to 0 + * before calling. */ int win_lbr_chartabsize( chartabsize_T *cts, - int *headp UNUSED) + int *headp UNUSED, + int *tailp UNUSED) { win_T *wp = cts->cts_win; #if defined(FEAT_PROP_POPUP) || defined(FEAT_LINEBREAK) @@ -1470,6 +1475,7 @@ win_lbr_chartabsize( if (headp != NULL) *headp = head; + int size_before_lbr = size; int need_lbr = FALSE; /* * If 'linebreak' set check at a blank before a non-blank if the line @@ -1522,6 +1528,9 @@ win_lbr_chartabsize( } } + if (tailp != NULL) + *tailp = size - size_before_lbr; + # ifdef FEAT_PROP_POPUP size += cts->cts_first_char; # endif @@ -1598,6 +1607,10 @@ in_win_border(win_T *wp, colnr_T vcol) * cursor: where the cursor is on this character (first char, except for TAB) * end: on the last position of this character (TAB, ctrl) * + * When 'linebreak' follows this character, "end" is set to the position before + * 'linebreak' if "flags" contains GETVCOL_END_EXCL_LBR, otherwise it's set to + * the end of 'linebreak'. + * * This is used very often, keep it fast! */ void @@ -1606,13 +1619,15 @@ getvcol( pos_T *pos, colnr_T *start, colnr_T *cursor, - colnr_T *end) + colnr_T *end, + int flags) { colnr_T vcol; char_u *ptr; // points to current char char_u *line; // start of the line int incr; int head; + int tail; #ifdef FEAT_VARTABS int *vts = wp->w_buffer->b_p_vts_array; #endif @@ -1693,6 +1708,8 @@ getvcol( vcol += incr; ptr = next_ptr; } + + tail = 0; } else { @@ -1701,7 +1718,8 @@ getvcol( // A tab gets expanded, depending on the current column. // Other things also take up space. head = 0; - incr = win_lbr_chartabsize(&cts, &head); + tail = 0; + incr = win_lbr_chartabsize(&cts, &head, &tail); // make sure we don't go past the end of the line if (*cts.cts_ptr == NUL) { @@ -1736,7 +1754,7 @@ getvcol( if (start != NULL) *start = vcol + head; if (end != NULL) - *end = vcol + incr - 1; + *end = vcol + incr - (flags & GETVCOL_END_EXCL_LBR ? tail : 0) - 1; if (cursor != NULL) { if (*ptr == TAB @@ -1746,6 +1764,7 @@ getvcol( && !(VIsual_active && (*p_sel == 'e' || LTOREQ_POS(*pos, VIsual))) ) + // TODO: subtracting "tail" may lead to better cursor position *cursor = vcol + incr - 1; // cursor at end else { @@ -1775,9 +1794,9 @@ getvcol_nolist(pos_T *posp) curwin->w_p_list = FALSE; if (posp->coladd) - getvvcol(curwin, posp, NULL, &vcol, NULL); + getvvcol(curwin, posp, NULL, &vcol, NULL, 0); else - getvcol(curwin, posp, NULL, &vcol, NULL); + getvcol(curwin, posp, NULL, &vcol, NULL, 0); curwin->w_p_list = list_save; return vcol; } @@ -1791,7 +1810,8 @@ getvvcol( pos_T *pos, colnr_T *start, colnr_T *cursor, - colnr_T *end) + colnr_T *end, + int flags) { colnr_T col; colnr_T coladd; @@ -1801,7 +1821,7 @@ getvvcol( if (virtual_active()) { // For virtual mode, only want one value - getvcol(wp, pos, &col, NULL, NULL); + getvcol(wp, pos, &col, NULL, NULL, flags); coladd = pos->coladd; endadd = 0; @@ -1829,7 +1849,7 @@ getvvcol( *end = col + endadd; } else - getvcol(wp, pos, start, cursor, end); + getvcol(wp, pos, start, cursor, end, flags); } /* @@ -1842,19 +1862,20 @@ getvcols( pos_T *pos1, pos_T *pos2, colnr_T *left, - colnr_T *right) + colnr_T *right, + int flags) { colnr_T from1, from2, to1, to2; if (LT_POSP(pos1, pos2)) { - getvvcol(wp, pos1, &from1, NULL, &to1); - getvvcol(wp, pos2, &from2, NULL, &to2); + getvvcol(wp, pos1, &from1, NULL, &to1, flags); + getvvcol(wp, pos2, &from2, NULL, &to2, flags); } else { - getvvcol(wp, pos2, &from1, NULL, &to1); - getvvcol(wp, pos1, &from2, NULL, &to2); + getvvcol(wp, pos2, &from1, NULL, &to1, flags); + getvvcol(wp, pos1, &from2, NULL, &to2, flags); } if (from2 < from1) *left = from2; diff --git a/src/cindent.c b/src/cindent.c index 1b4ad0fa4a..ddd268176b 100644 --- a/src/cindent.c +++ b/src/cindent.c @@ -978,7 +978,7 @@ get_indent_nolabel (linenr_T lnum) // XXX fp.col = (colnr_T)(p - l); fp.lnum = lnum; - getvcol(curwin, &fp, &col, NULL, NULL); + getvcol(curwin, &fp, &col, NULL, NULL, 0); return (int)col; } @@ -1062,7 +1062,7 @@ cin_first_id_amount(void) p = skipwhite(p + len); fp.lnum = curwin->w_cursor.lnum; fp.col = (colnr_T)(p - line); - getvcol(curwin, &fp, &col, NULL, NULL); + getvcol(curwin, &fp, &col, NULL, NULL, 0); return (int)col; } @@ -1110,7 +1110,7 @@ cin_get_equal_amount(linenr_T lnum) fp.lnum = lnum; fp.col = (colnr_T)(s - line); - getvcol(curwin, &fp, &col, NULL, NULL); + getvcol(curwin, &fp, &col, NULL, NULL, 0); return (int)col; } @@ -1705,7 +1705,7 @@ get_baseclass_amount(int col) else { curwin->w_cursor.col = col; - getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); + getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL, 0); amount = (int)vcol; } if (amount < curbuf->b_ind_cpp_baseclass) @@ -2265,7 +2265,7 @@ get_c_indent(void) if (trypos != NULL) { // find how indented the line beginning the comment is - getvcol(curwin, trypos, &col, NULL, NULL); + getvcol(curwin, trypos, &col, NULL, NULL, 0); amount = col; goto theend; } @@ -2287,7 +2287,7 @@ get_c_indent(void) int done = FALSE; // find how indented the line beginning the comment is - getvcol(curwin, comment_pos, &col, NULL, NULL); + getvcol(curwin, comment_pos, &col, NULL, NULL, 0); amount = col; *lead_start = NUL; *lead_middle = NUL; @@ -2413,7 +2413,7 @@ get_c_indent(void) if (*look != NUL) // if something after it comment_pos->col = (colnr_T)(skipwhite(look) - start); } - getvcol(curwin, comment_pos, &col, NULL, NULL); + getvcol(curwin, comment_pos, &col, NULL, NULL, 0); amount = col; if (curbuf->b_ind_in_comment2 || *look == NUL) amount += curbuf->b_ind_in_comment; @@ -2615,7 +2615,7 @@ get_c_indent(void) // if we did the above "if". if (our_paren_pos.col > 0) { - getvcol(curwin, &our_paren_pos, &col, NULL, NULL); + getvcol(curwin, &our_paren_pos, &col, NULL, NULL, 0); if (cur_amount > (int)col) cur_amount = col; } @@ -2704,7 +2704,7 @@ get_c_indent(void) look = skipwhite(start); if (*look == '{') { - getvcol(curwin, trypos, &col, NULL, NULL); + getvcol(curwin, trypos, &col, NULL, NULL, 0); amount = col; if (*start == '{') start_brace = BRACE_IN_COL0; diff --git a/src/drawline.c b/src/drawline.c index b7910832ba..b9b92a1e9e 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -1418,7 +1418,8 @@ win_line( wlv.fromcol = 0; else { - getvvcol(wp, top, (colnr_T *)&wlv.fromcol, NULL, NULL); + getvvcol(wp, top, (colnr_T *)&wlv.fromcol, + NULL, NULL, 0); if (gchar_pos(top) == NUL) wlv.tocol = wlv.fromcol + 1; } @@ -1437,11 +1438,11 @@ win_line( pos = *bot; if (*p_sel == 'e') getvvcol(wp, &pos, (colnr_T *)&wlv.tocol, - NULL, NULL); + NULL, NULL, 0); else { getvvcol(wp, &pos, NULL, NULL, - (colnr_T *)&wlv.tocol); + (colnr_T *)&wlv.tocol, 0); ++wlv.tocol; } } @@ -1480,14 +1481,14 @@ win_line( { if (lnum == curwin->w_cursor.lnum) getvcol(curwin, &(curwin->w_cursor), - (colnr_T *)&wlv.fromcol, NULL, NULL); + (colnr_T *)&wlv.fromcol, NULL, NULL, 0); else 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 *)&wlv.tocol, NULL, NULL); + getvcol(curwin, &pos, (colnr_T *)&wlv.tocol, NULL, NULL, 0); } else wlv.tocol = MAXCOL; @@ -1761,7 +1762,7 @@ win_line( { chartabsize_T cts; init_chartabsize_arg(&cts, wp, lnum, 0, line, line); - (void)win_lbr_chartabsize(&cts, NULL); + (void)win_lbr_chartabsize(&cts, NULL, NULL); vcol_first_char = cts.cts_first_char; clear_chartabsize_arg(&cts); } @@ -1785,7 +1786,7 @@ win_line( while (cts.cts_vcol < v) { head = 0; - charsize = win_lbr_chartabsize(&cts, &head); + charsize = win_lbr_chartabsize(&cts, &head, NULL); cts.cts_vcol += charsize; prev_ptr = cts.cts_ptr; if (*prev_ptr == NUL) @@ -3120,7 +3121,8 @@ win_line( // do not want virtual text counted here cts.cts_has_prop_with_text = FALSE; # endif - wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1; + // TODO: consider using "tailp" here + wlv.n_extra = win_lbr_chartabsize(&cts, NULL, NULL) - 1; clear_chartabsize_arg(&cts); if (on_last_col && c != TAB) @@ -3780,7 +3782,7 @@ win_line( colnr_T tcol; if (preedit_end_col == MAXCOL) - getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL); + getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL, 0); else tcol = preedit_end_col; if ((long)preedit_start_col <= wlv.vcol && wlv.vcol < (long)tcol) diff --git a/src/drawscreen.c b/src/drawscreen.c index 68ba60572c..d619859bd0 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -769,7 +769,7 @@ win_redr_ruler(win_T *wp, int always, int ignore_pum) if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL) { wp->w_p_list = FALSE; - getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); + getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL, 0); wp->w_p_list = TRUE; } @@ -2078,17 +2078,10 @@ win_update(win_T *wp) if (VIsual_mode == Ctrl_V) { colnr_T fromc, toc; -#if defined(FEAT_LINEBREAK) - int save_ve_flags = curwin->w_ve_flags; - if (curwin->w_p_lbr) - curwin->w_ve_flags = VE_ALL; -#endif - getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc); + getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc, + GETVCOL_END_EXCL_LBR); ++toc; -#if defined(FEAT_LINEBREAK) - curwin->w_ve_flags = save_ve_flags; -#endif // Highlight to the end of the line, unless 'virtualedit' has // "block". if (curwin->w_curswant == MAXCOL) @@ -2110,7 +2103,7 @@ win_update(win_T *wp) colnr_T t; pos.col = (int)ml_get_buf_len(wp->w_buffer, pos.lnum); - getvvcol(wp, &pos, NULL, NULL, &t); + getvvcol(wp, &pos, NULL, NULL, &t, 0); if (toc < t) toc = t; } diff --git a/src/edit.c b/src/edit.c index 2392361fbf..79a4177bfc 100644 --- a/src/edit.c +++ b/src/edit.c @@ -3354,7 +3354,7 @@ replace_do_bs(int limit_col) { // Get the number of screen cells used by the character we are // going to delete. - getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL); + getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL, 0); orig_vcols = chartabsize(ml_get_cursor(), start_vcol); } if (has_mbyte) @@ -5152,8 +5152,8 @@ ins_tab(void) } // compute virtual column numbers of first white and cursor - getvcol(curwin, &fpos, &vcol, NULL, NULL); - getvcol(curwin, cursor, &want_vcol, NULL, NULL); + getvcol(curwin, &fpos, &vcol, NULL, NULL, 0); + getvcol(curwin, cursor, &want_vcol, NULL, NULL, 0); init_chartabsize_arg(&cts, curwin, 0, vcol, tab, tab); diff --git a/src/evalfunc.c b/src/evalfunc.c index de6975a0d4..f026b384e7 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6186,8 +6186,8 @@ getregionpos( int lbr_saved = reset_lbr(); #endif - getvvcol(curwin, p1, &sc1, NULL, &ec1); - getvvcol(curwin, p2, &sc2, NULL, &ec2); + getvvcol(curwin, p1, &sc1, NULL, &ec1, 0); + getvvcol(curwin, p2, &sc2, NULL, &ec2, 0); #ifdef FEAT_LINEBREAK restore_lbr(lbr_saved); @@ -12782,7 +12782,7 @@ f_virtcol(typval_T *argvars, typval_T *rettv) if (fp->col > len) fp->col = len; } - getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end); + getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end, 0); ++vcol_start; ++vcol_end; } diff --git a/src/ex_cmds.c b/src/ex_cmds.c index d4d57d0a70..4382ea5b70 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -4585,11 +4585,13 @@ ex_substitute(exarg_T *eap) print_line_no_prefix(lnum, subflags.do_number, subflags.do_list); - getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL); + getvcol(curwin, &curwin->w_cursor, + &sc, NULL, NULL, 0); curwin->w_cursor.col = regmatch.endpos[0].col - 1; if (curwin->w_cursor.col < 0) curwin->w_cursor.col = 0; - getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec); + getvcol(curwin, &curwin->w_cursor, + NULL, NULL, &ec, 0); curwin->w_cursor.col = regmatch.startpos[0].col; if (subflags.do_number || curwin->w_p_nu) { diff --git a/src/gui_xim.c b/src/gui_xim.c index 8e9b750a41..26b125d919 100644 --- a/src/gui_xim.c +++ b/src/gui_xim.c @@ -174,7 +174,7 @@ init_preedit_start_col(void) if (State & MODE_CMDLINE) preedit_start_col = cmdline_getvcol_cursor(); else if (curwin != NULL && curwin->w_buffer != NULL) - getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL); + getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL, 0); // Prevent that preediting marks the buffer as changed. xim_changed_while_preediting = curbuf->b_changed; } diff --git a/src/indent.c b/src/indent.c index 26f60701c2..8fe4177c30 100644 --- a/src/indent.c +++ b/src/indent.c @@ -866,7 +866,7 @@ get_number_indent(linenr_T lnum) if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL) return -1; - getvcol(curwin, &pos, &col, NULL, NULL); + getvcol(curwin, &pos, &col, NULL, NULL, 0); return (int)col; } diff --git a/src/misc1.c b/src/misc1.c index 8a951298b9..3fa34c35e7 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -467,7 +467,7 @@ plines_win_col(win_T *wp, linenr_T lnum, long column) init_chartabsize_arg(&cts, wp, lnum, 0, line, line); while (*cts.cts_ptr != NUL && --column >= 0) { - cts.cts_vcol += win_lbr_chartabsize(&cts, NULL); + cts.cts_vcol += win_lbr_chartabsize(&cts, NULL, NULL); MB_PTR_ADV(cts.cts_ptr); } @@ -481,7 +481,7 @@ plines_win_col(win_T *wp, linenr_T lnum, long column) col = cts.cts_vcol; if (*cts.cts_ptr == TAB && (State & MODE_NORMAL) && (!wp->w_p_list || wp->w_lcs_chars.tab1)) - col += win_lbr_chartabsize(&cts, NULL) - 1; + col += win_lbr_chartabsize(&cts, NULL, NULL) - 1; clear_chartabsize_arg(&cts); /* diff --git a/src/misc2.c b/src/misc2.c index a7f52e55eb..1d3a35b062 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -43,7 +43,7 @@ getviscol(void) { colnr_T x; - getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL); + getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL, 0); return (int)x; } @@ -77,7 +77,7 @@ getviscol2(colnr_T col, colnr_T coladd) pos.lnum = curwin->w_cursor.lnum; pos.col = col; pos.coladd = coladd; - getvvcol(curwin, &pos, &x, NULL, NULL); + getvvcol(curwin, &pos, &x, NULL, NULL, 0); return (int)x; } @@ -185,7 +185,7 @@ coladvance2( #endif // Count a tab for what it's worth (if list mode not on) #ifdef FEAT_LINEBREAK - csize = win_lbr_chartabsize(&cts, &head); + csize = win_lbr_chartabsize(&cts, &head, NULL); MB_PTR_ADV(cts.cts_ptr); #else csize = lbr_chartabsize_adv(&cts); @@ -298,7 +298,7 @@ coladvance2( { colnr_T scol, ecol; - getvcol(curwin, pos, &scol, NULL, &ecol); + getvcol(curwin, pos, &scol, NULL, &ecol, 0); pos->coladd = ecol - scol; } } @@ -606,7 +606,7 @@ check_cursor_col_win(win_T *win) { int cs, ce; - getvcol(win, &win->w_cursor, &cs, NULL, &ce); + getvcol(win, &win->w_cursor, &cs, NULL, &ce, 0); if (win->w_cursor.coladd > ce - cs) win->w_cursor.coladd = ce - cs; } @@ -702,7 +702,7 @@ set_leftcol(colnr_T leftcol) // advance the cursor one more char. If this fails (last char of the // line) adjust the scrolling. colnr_T s, e; - getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e); + getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e, 0); if (e > (colnr_T)lastcol) { retval = TRUE; diff --git a/src/mouse.c b/src/mouse.c index e043e1b4fc..3f2f86dc83 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -663,8 +663,8 @@ do_mouse( else if (VIsual_mode == Ctrl_V) { getvcols(curwin, &curwin->w_cursor, &VIsual, - &leftcol, &rightcol); - getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL); + &leftcol, &rightcol, 0); + getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL, 0); if (m_pos.col < leftcol || m_pos.col > rightcol) jump_flags = MOUSE_MAY_STOP_VIS; } @@ -831,7 +831,8 @@ do_mouse( // that is in the quarter that the cursor is in. if (VIsual_mode == Ctrl_V) { - getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol); + getvcols(curwin, &start_visual, &end_visual, + &leftcol, &rightcol, 0); if (curwin->w_curswant > (leftcol + rightcol) / 2) end_visual.col = leftcol; else @@ -3250,7 +3251,7 @@ vcol2col(win_T *wp, linenr_T lnum, int vcol, colnr_T *coladdp) init_chartabsize_arg(&cts, wp, lnum, 0, line, line); while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL) { - int size = win_lbr_chartabsize(&cts, NULL); + int size = win_lbr_chartabsize(&cts, NULL, NULL); if (cts.cts_vcol + size > vcol) break; cts.cts_vcol += size; diff --git a/src/move.c b/src/move.c index ebc8853617..ee9a8eb5aa 100644 --- a/src/move.c +++ b/src/move.c @@ -361,7 +361,7 @@ update_topline(void) // Check that the cursor position is visible. Add columns for // the marker displayed in the top-left if needed. - getvvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); + getvvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL, 0); overlap = sms_marker_overlap(curwin, -1); if (curwin->w_skipcol + overlap > vcol) check_topline = TRUE; @@ -1021,7 +1021,7 @@ validate_virtcol_win(win_T *wp) #ifdef FEAT_PROP_POPUP wp->w_virtcol_first_char = 0; #endif - getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL); + getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL, 0); #ifdef FEAT_SYN_HL redraw_for_cursorcolumn(wp); #endif @@ -1183,7 +1183,7 @@ curs_columns( else #endif getvvcol(curwin, &curwin->w_cursor, - &startcol, &(curwin->w_virtcol), &endcol); + &startcol, &(curwin->w_virtcol), &endcol, 0); // remove '$' from change command when cursor moves onto it if (startcol > dollar_vcol) @@ -1491,7 +1491,7 @@ textpos2screenpos( else # endif { - getvcol(wp, pos, &scol, &ccol, &ecol); + getvcol(wp, pos, &scol, &ccol, &ecol, 0); // similar to what is done in validate_cursor_col() col = scol; diff --git a/src/normal.c b/src/normal.c index 01ea4c0915..e7be757576 100644 --- a/src/normal.c +++ b/src/normal.c @@ -1652,7 +1652,8 @@ clear_showcmd(void) p_sbr = empty_option; curwin->w_p_sbr = empty_option; #endif - getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol); + getvcols(curwin, &curwin->w_cursor, &VIsual, + &leftcol, &rightcol, 0); #ifdef FEAT_LINEBREAK p_sbr = saved_sbr; curwin->w_p_sbr = saved_w_sbr; @@ -2765,7 +2766,7 @@ nv_zet(cmdarg_T *cap) col = 0; // like the cursor is in col 0 else #endif - getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL); + getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL, 0); if ((long)col > siso) col -= siso; else @@ -2786,7 +2787,7 @@ nv_zet(cmdarg_T *cap) col = 0; // like the cursor is in col 0 else #endif - getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); + getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col, 0); n = curwin->w_width - curwin_col_off(); if ((long)col + siso < n) col = 0; @@ -4295,7 +4296,7 @@ nv_csearch(cmdarg_T *cap) { colnr_T scol, ecol; - getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); + getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol, 0); curwin->w_cursor.coladd = ecol - scol; } else @@ -5000,7 +5001,7 @@ v_swap_corners(int cmdchar) if (cmdchar == 'O' && VIsual_mode == Ctrl_V) { old_cursor = curwin->w_cursor; - getvcols(curwin, &old_cursor, &VIsual, &left, &right); + getvcols(curwin, &old_cursor, &VIsual, &left, &right, 0); curwin->w_cursor.lnum = VIsual.lnum; coladvance(left); VIsual = curwin->w_cursor; @@ -5927,7 +5928,7 @@ nv_g_dollar_cmd(cmdarg_T *cap) { colnr_T vcol; - getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol); + getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol, 0); if (vcol >= curwin->w_leftcol + curwin->w_width - col_off) --curwin->w_cursor.col; } @@ -6765,7 +6766,7 @@ unadjust_for_sel_inner(pos_T *pp) mb_adjustpos(curbuf, pp); if (virtual_active()) { - getvcol(curwin, pp, &cs, NULL, &ce); + getvcol(curwin, pp, &cs, NULL, &ce, 0); pp->coladd = ce - cs; } } diff --git a/src/ops.c b/src/ops.c index 3fad2b44fd..140cdc8c58 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2064,7 +2064,7 @@ adjust_cursor_eol(void) colnr_T scol, ecol; // Coladd is set to the width of the last character. - getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); + getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol, 0); curwin->w_cursor.coladd = ecol - scol + 1; } } @@ -2396,6 +2396,9 @@ theend: #ifdef FEAT_LINEBREAK /* + * TODO: consider using "tailp" of win_lbr_chartabsize() instead of temporarily + * resetting 'linebreak'. + * * Reset 'linebreak' and take care of side effects. * Returns the previous value, to be passed to restore_lbr(). */ @@ -2617,7 +2620,7 @@ charwise_block_prep( startcol = start.col; if (virtual_op) { - getvcol(curwin, &start, &cs, NULL, &ce); + getvcol(curwin, &start, &cs, NULL, &ce, false); if (ce != cs && start.coladd > 0) { // Part of a tab selected -- but don't @@ -2636,7 +2639,7 @@ charwise_block_prep( endcol = end.col; if (virtual_op) { - getvcol(curwin, &end, &cs, NULL, &ce); + getvcol(curwin, &end, &cs, NULL, &ce, false); if (p[endcol] == NUL || (cs + end.coladd < ce // Don't add space for double-wide // char; endcol will be on last byte @@ -3409,7 +3412,7 @@ cursor_pos_info(dict_T *dict) oparg.block_mode = TRUE; oparg.op_type = OP_NOP; getvcols(curwin, &min_pos, &max_pos, - &oparg.start_vcol, &oparg.end_vcol); + &oparg.start_vcol, &oparg.end_vcol, 0); #ifdef FEAT_LINEBREAK p_sbr = saved_sbr; curwin->w_p_sbr = saved_w_sbr; @@ -3511,8 +3514,8 @@ cursor_pos_info(dict_T *dict) { if (VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL) { - getvcols(curwin, &min_pos, &max_pos, &min_pos.col, - &max_pos.col); + getvcols(curwin, &min_pos, &max_pos, + &min_pos.col, &max_pos.col, 0); vim_snprintf((char *)buf1, sizeof(buf1), _("%ld Cols; "), (long)(oparg.end_vcol - oparg.start_vcol + 1)); } @@ -3798,11 +3801,11 @@ get_op_vcol( if (has_mbyte) mb_adjustpos(curwin->w_buffer, &oap->end); - getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol); + getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol, 0); if (!redo_VIsual_busy) { - getvvcol(curwin, &(oap->end), &start, NULL, &end); + getvvcol(curwin, &(oap->end), &start, NULL, &end, 0); if (start < oap->start_vcol) oap->start_vcol = start; @@ -3825,7 +3828,7 @@ get_op_vcol( curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum) { - getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end); + getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end, 0); if (end > oap->end_vcol) oap->end_vcol = end; } @@ -4130,12 +4133,12 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank) { if (VIsual_mode != Ctrl_V) getvvcol(curwin, &(oap->end), - NULL, NULL, &oap->end_vcol); + NULL, NULL, &oap->end_vcol, 0); if (VIsual_mode == Ctrl_V || oap->line_count <= 1) { if (VIsual_mode != Ctrl_V) getvvcol(curwin, &(oap->start), - &oap->start_vcol, NULL, NULL); + &oap->start_vcol, NULL, NULL, 0); resel_VIsual_vcol = oap->end_vcol - oap->start_vcol + 1; } else diff --git a/src/popupwin.c b/src/popupwin.c index d54751600f..cbbb7c6e5d 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -212,11 +212,11 @@ set_mousemoved_columns(win_T *wp, int flags) // convert text column to mouse column pos.col = col; pos.coladd = 0; - getvcol(textwp, &pos, &mcol, NULL, NULL); + getvcol(textwp, &pos, &mcol, NULL, NULL, 0); wp->w_popup_mouse_mincol = mcol; pos.col = col + (colnr_T)STRLEN(text) - 1; - getvcol(textwp, &pos, NULL, NULL, &mcol); + getvcol(textwp, &pos, NULL, NULL, &mcol, 0); wp->w_popup_mouse_maxcol = mcol; vim_free(text); } diff --git a/src/proto/charset.pro b/src/proto/charset.pro index c9af1b0d61..bc09b01b8c 100644 --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -40,11 +40,11 @@ void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum, colnr_T void clear_chartabsize_arg(chartabsize_T *cts); int lbr_chartabsize(chartabsize_T *cts); int lbr_chartabsize_adv(chartabsize_T *cts); -int win_lbr_chartabsize(chartabsize_T *cts, int *headp); -void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end); +int win_lbr_chartabsize(chartabsize_T *cts, int *headp, int *tailp); +void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end, int flags); colnr_T getvcol_nolist(pos_T *posp); -void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end); -void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right); +void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end, int flags); +void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right, int flags); char_u *skipwhite(char_u *q); char_u *skipwhite_and_nl(char_u *q); int getwhitecols_curline(void); diff --git a/src/regexp.c b/src/regexp.c index 34325e61d4..6ac74467f9 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -1464,8 +1464,8 @@ reg_match_visual(void) } else if (mode == Ctrl_V) { - getvvcol(wp, &top, &start, NULL, &end); - getvvcol(wp, &bot, &start2, NULL, &end2); + getvvcol(wp, &top, &start, NULL, &end, 0); + getvvcol(wp, &bot, &start2, NULL, &end2, 0); if (start2 < start) start = start2; if (end2 > end) diff --git a/src/regexp_bt.c b/src/regexp_bt.c index 37fba5e6fd..063510c643 100644 --- a/src/regexp_bt.c +++ b/src/regexp_bt.c @@ -1689,7 +1689,7 @@ regatom(int *flagp) colnr_T vcol = 0; getvvcol(curwin, &curwin->w_cursor, - NULL, NULL, &vcol); + NULL, NULL, &vcol, 0); ++vcol; n = vcol; } diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c index 807bc203c7..b17d4d3493 100644 --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -1717,7 +1717,7 @@ nfa_regatom(void) colnr_T vcol = 0; getvvcol(curwin, &curwin->w_cursor, - NULL, NULL, &vcol); + NULL, NULL, &vcol, 0); n = ++vcol; } // \%{n}v \%{n}v diff --git a/src/register.c b/src/register.c index de89b18646..a20e5c1d0f 100644 --- a/src/register.c +++ b/src/register.c @@ -1855,9 +1855,9 @@ do_put( if (dir == FORWARD && c != NUL) { if (cur_ve_flags == VE_ALL) - getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2); + getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2, 0); else - getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); + getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col, 0); if (has_mbyte) // move to start of next multi-byte character @@ -1868,7 +1868,7 @@ do_put( ++col; } else - getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2); + getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2, 0); col += curwin->w_cursor.coladd; if (cur_ve_flags == VE_ALL @@ -2112,7 +2112,7 @@ do_put( pos.lnum = lnum; pos.col = col; pos.coladd = 0; - getvcol(curwin, &pos, NULL, &vcol, NULL); + getvcol(curwin, &pos, NULL, &vcol, NULL, 0); } } diff --git a/src/search.c b/src/search.c index 5d50b1fc5b..9b51ef94a9 100644 --- a/src/search.c +++ b/src/search.c @@ -2858,7 +2858,7 @@ showmatch( return; if (!curwin->w_p_wrap) - getvcol(curwin, lpos, NULL, &vcol, NULL); + getvcol(curwin, lpos, NULL, &vcol, NULL, 0); int col_visible = (curwin->w_p_wrap || (vcol >= curwin->w_leftcol diff --git a/src/testdir/dumps/Test_visual_block_hl_with_linebreak_1.dump b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_1.dump new file mode 100644 index 0000000000..a1825a9ee2 --- /dev/null +++ b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_1.dump @@ -0,0 +1,6 @@ +|f+0#0000001#a8a8a8255|o@1| |x+0#0000000#ffffff0@9| @5||+1&&| +0&&@53 +|f+0#0000001#a8a8a8255|o@1> +0#0000000#ffffff0@16||+1&&|~+0#4040ff13&| @52 +|x+0#0000000&@19||+1&&|~+0#4040ff13&| @52 +|~| @18||+1#0000000&|~+0#4040ff13&| @52 +|<+3#0000000&|a|m|e|]| |[|+|]| |2|,|4| @3|A|l@1| |[+1&&|N|o| |N|a|m|e|]| @26|0|,|0|-|1| @9|A|l@1 +|-+2&&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@45|2|x|2|0| @6 diff --git a/src/testdir/dumps/Test_visual_block_hl_with_linebreak_2.dump b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_2.dump new file mode 100644 index 0000000000..d3dae6661c --- /dev/null +++ b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_2.dump @@ -0,0 +1,6 @@ +|f+0&#ffffff0|o+0#0000001#a8a8a8255@1| @4|b+0#0000000#ffffff0|a|r| @63 +|f|o+0#0000001#a8a8a8255@1|1|2|3|4|5|b+0#0000000#ffffff0|a|r| @63 +|f>o|o+0#0000001#a8a8a8255| @4|b+0#0000000#ffffff0|a|r| @63 +|~+0#4040ff13&| @73 +|~| @73 +|-+2#0000000&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@28|3|x|7| @6|3|,|2| @10|A|l@1| diff --git a/src/testdir/dumps/Test_visual_block_hl_with_linebreak_3.dump b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_3.dump new file mode 100644 index 0000000000..fe26ea2b11 --- /dev/null +++ b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_3.dump @@ -0,0 +1,6 @@ +|f+0&#ffffff0|o+0#0000001#a8a8a8255@1|<|f@3|>|b+0#0000000#ffffff0|a|r| @62 +|f|o+0#0000001#a8a8a8255@1|1|2|3|4|5|6|b+0#0000000#ffffff0|a|r| @62 +|f>o|o+0#0000001#a8a8a8255|<|f@3|>|b+0#0000000#ffffff0|a|r| @62 +|~+0#4040ff13&| @73 +|~| @73 +|-+2#0000000&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@28|3|x|8| @6|3|,|2| @10|A|l@1| diff --git a/src/testdir/dumps/Test_visual_block_hl_with_linebreak_4.dump b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_4.dump new file mode 100644 index 0000000000..cc4c19dfe0 --- /dev/null +++ b/src/testdir/dumps/Test_visual_block_hl_with_linebreak_4.dump @@ -0,0 +1,6 @@ +|x+0&#ffffff0@1|x+0#0000001#a8a8a8255@7|x+0#0000000#ffffff0@4| @59 +|x@1|x+0#0000001#a8a8a8255@1|f+0#0000000#ffffff0|o@1|:| |x+0#0000001#a8a8a8255|x+0#0000000#ffffff0@4| @59 +|x@1|x+0#0000001#a8a8a8255@1|b+0#0000000#ffffff0|a|r|:| >x@5| @59 +|~+0#4040ff13&| @73 +|~| @73 +|-+2#0000000&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@28|3|x|8| @6|3|,|5|-|1|0| @7|A|l@1| diff --git a/src/testdir/test_listlbr_utf8.vim b/src/testdir/test_listlbr_utf8.vim index be77566a79..bde1a49580 100644 --- a/src/testdir/test_listlbr_utf8.vim +++ b/src/testdir/test_listlbr_utf8.vim @@ -385,4 +385,71 @@ func Test_visual_ends_before_showbreak() call StopVimInTerminal(buf) endfunc +func Test_visual_block_hl_with_linebreak() + CheckScreendump + + let lines =<< trim END + func Case1() + 20vnew + setlocal linebreak + call setline(1, ['foo ' .. repeat('x', 10), 'foo ' .. repeat('x', 20)]) + exe "normal! gg0\3lj" + endfunc + + func Case2() + setlocal nolinebreak + call setline(1, ["foo\tbar", 'foo12345bar', "foo\tbar"]) + exe "normal! gg03l\2j2h" + endfunc + + func Case3() + setlocal nolinebreak + call setline(1, ["foo\uffffbar", 'foo123456bar', "foo\uffffbar"]) + exe "normal! gg03l\2j2h" + endfunc + + func Case4() + setlocal nolinebreak + call setline(1, [repeat('x', 15), repeat('x', 10), repeat('x', 10)]) + call prop_type_add('test', {}) + call prop_add(2, 5, #{text: "foo: ",type: "test"}) + call prop_add(3, 5, #{text: "bar: ",type: "test"}) + exe "normal! gg02l\2j2l" + endfunc + + " FIXME: clipboard=autoselect sometimes changes Visual highlight + set clipboard= + END + call writefile(lines, 'XvisualBlockHlWithLinebreak', 'D') + let buf = RunVimInTerminal('-S XvisualBlockHlWithLinebreak', #{rows: 6}) + + " 'linebreak' after end char (initially fixed by patch 7.4.467) + call term_sendkeys(buf, ":call Case1()\r") + call VerifyScreenDump(buf, 'Test_visual_block_hl_with_linebreak_1', {}) + + " TAB as end char: 'linebreak' shouldn't break Visual block hl + call term_sendkeys(buf, "\:bwipe! | call Case2()\r") + call VerifyScreenDump(buf, 'Test_visual_block_hl_with_linebreak_2', {}) + call term_sendkeys(buf, "\:setlocal linebreak\rgv") + call term_wait(buf, 50) + call VerifyScreenDump(buf, 'Test_visual_block_hl_with_linebreak_2', {}) + + " Unprintable end char: 'linebreak' shouldn't break Visual block hl + call term_sendkeys(buf, "\:bwipe! | call Case3()\r") + call VerifyScreenDump(buf, 'Test_visual_block_hl_with_linebreak_3', {}) + call term_sendkeys(buf, "\:setlocal linebreak\rgv") + call term_wait(buf, 50) + call VerifyScreenDump(buf, 'Test_visual_block_hl_with_linebreak_3', {}) + + " Virtual text before end char: 'linebreak' shouldn't break Visual block hl + call term_sendkeys(buf, "\:bwipe! | call Case4()\r") + call VerifyScreenDump(buf, 'Test_visual_block_hl_with_linebreak_4', {}) + call term_sendkeys(buf, "\:setlocal linebreak\rgv") + call term_wait(buf, 50) + call VerifyScreenDump(buf, 'Test_visual_block_hl_with_linebreak_4', {}) + + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index e81115c310..64db5b8842 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 289, /**/ 288, /**/ diff --git a/src/vim.h b/src/vim.h index f2e3a16101..51d0cc1f32 100644 --- a/src/vim.h +++ b/src/vim.h @@ -3093,4 +3093,7 @@ long elapsed(DWORD start_tick); #define CF_INTERFACE 2 // inside an interface #define CF_ABSTRACT_METHOD 4 // inside an abstract class +// Flags used by getvcol() +#define GETVCOL_END_EXCL_LBR 1 + #endif // VIM__H