# HG changeset patch # User Christian Brabandt # Date 1693407603 -7200 # Node ID d03841a271aa3f8f5d2a9f07495a53703cd9ff00 # Parent d36b31ab54c4c7e5384032dd47467fef7573dc82 patch 9.0.1825: wrong cursor position with virt text and 'linebreak' Commit: https://github.com/vim/vim/commit/6e55e85f92aff43c1b3cb564201440f3552d63f0 Author: zeertzjq Date: Wed Aug 30 16:55:09 2023 +0200 patch 9.0.1825: wrong cursor position with virt text and 'linebreak' Problem: Wrong cursor position with virtual text before a whitespace character and 'linebreak'. Solution: Always set "col_adj" to "size - 1" and apply 'linebreak' after adding the size of 'breakindent' and 'showbreak'. closes: #12956 Signed-off-by: Christian Brabandt Co-authored-by: zeertzjq diff --git a/src/charset.c b/src/charset.c --- a/src/charset.c +++ b/src/charset.c @@ -1118,14 +1118,8 @@ win_lbr_chartabsize( char_u *s = cts->cts_ptr; colnr_T vcol = cts->cts_vcol; #ifdef FEAT_LINEBREAK - int c; int size; - colnr_T col2; - colnr_T col_adj = 0; // vcol + screen size of tab - colnr_T colmax; int mb_added = 0; - char_u *ps; - int tab_corr = (*s == TAB); int n; char_u *sbr; int no_sbr = FALSE; @@ -1248,55 +1242,7 @@ win_lbr_chartabsize( # endif # ifdef FEAT_LINEBREAK - c = *s; - if (tab_corr) - col_adj = size - 1; - - /* - * If 'linebreak' set check at a blank before a non-blank if the line - * needs a break here - */ - if (wp->w_p_lbr - && VIM_ISBREAK(c) - && !VIM_ISBREAK((int)s[1]) - && wp->w_p_wrap - && wp->w_width != 0) - { - /* - * Count all characters from first non-blank after a blank up to next - * non-blank after a blank. - */ - int numberextra = win_col_off(wp); - col2 = vcol; - colmax = (colnr_T)(wp->w_width - numberextra - col_adj); - if (vcol >= colmax) - { - colmax += col_adj; - n = colmax + win_col_off2(wp); - if (n > 0) - colmax += (((vcol - colmax) / n) + 1) * n - col_adj; - } - - for (;;) - { - ps = s; - MB_PTR_ADV(s); - c = *s; - if (!(c != NUL - && (VIM_ISBREAK(c) - || (!VIM_ISBREAK(c) - && (col2 == vcol || !VIM_ISBREAK((int)*ps)))))) - break; - - col2 += win_chartabsize(wp, s, col2); - if (col2 >= colmax) // doesn't fit - { - size = colmax - vcol + col_adj; - break; - } - } - } - else if (has_mbyte && size == 2 && MB_BYTE2LEN(*s) > 1 + if (has_mbyte && size == 2 && MB_BYTE2LEN(*s) > 1 && wp->w_p_wrap && in_win_border(wp, vcol)) { ++size; // Count the ">" in the last column. @@ -1314,11 +1260,10 @@ win_lbr_chartabsize( { int col_off_prev = win_col_off(wp); int width2 = wp->w_width - col_off_prev + win_col_off2(wp); - vcol += mb_added; + colnr_T wcol = vcol + col_off_prev; #ifdef FEAT_PROP_POPUP - vcol -= wp->w_virtcol_first_char; + wcol -= wp->w_virtcol_first_char; #endif - colnr_T wcol = vcol + col_off_prev; colnr_T max_head_vcol = cts->cts_max_head_vcol; int added = 0; @@ -1342,6 +1287,8 @@ win_lbr_chartabsize( if (max_head_vcol <= 0 || vcol < max_head_vcol) head += head_prev; } + else + head_prev = 0; wcol += col_off_prev; } @@ -1374,7 +1321,7 @@ win_lbr_chartabsize( else if (max_head_vcol < 0) { int off = 0; - if (c != NUL + if (*s != NUL && ((State & MODE_NORMAL) || cts->cts_start_incl)) off += cts->cts_cur_text_width; if (off >= prev_rem) @@ -1386,8 +1333,56 @@ win_lbr_chartabsize( size += added; } + if (headp != NULL) *headp = head; + + /* + * If 'linebreak' set check at a blank before a non-blank if the line + * needs a break here + */ + if (wp->w_p_lbr + && VIM_ISBREAK((int)s[0]) + && !VIM_ISBREAK((int)s[1]) + && wp->w_p_wrap + && wp->w_width != 0) + { + /* + * Count all characters from first non-blank after a blank up to next + * non-blank after a blank. + */ + int numberextra = win_col_off(wp); + colnr_T col_adj = size - 1; + colnr_T colmax = (colnr_T)(wp->w_width - numberextra - col_adj); + if (vcol >= colmax) + { + colmax += col_adj; + n = colmax + win_col_off2(wp); + if (n > 0) + colmax += (((vcol - colmax) / n) + 1) * n - col_adj; + } + + colnr_T vcol2 = vcol; + for (;;) + { + char_u *ps = s; + MB_PTR_ADV(s); + int c = *s; + if (!(c != NUL + && (VIM_ISBREAK(c) + || (!VIM_ISBREAK(c) + && (vcol2 == vcol || !VIM_ISBREAK((int)*ps)))))) + break; + + vcol2 += win_chartabsize(wp, s, vcol2); + if (vcol2 >= colmax) // doesn't fit + { + size = colmax - vcol + col_adj; + break; + } + } + } + return size; # endif #endif diff --git a/src/testdir/dumps/Test_prop_inserts_text_before_linebreak_1.dump b/src/testdir/dumps/Test_prop_inserts_text_before_linebreak_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_prop_inserts_text_before_linebreak_1.dump @@ -0,0 +1,6 @@ +|a+0&#ffffff0@49 +| @1|++0#4040ff13&|b+0#e000e06&@9| +0#0000000&@36 +@2|++0#4040ff13&|c+0#0000000&@43>c| @1 +|~+0#4040ff13&| @48 +|~| @48 +| +0#0000000&@31|1|,|9|6|-|1|4|8| @5|A|l@1| diff --git a/src/testdir/dumps/Test_prop_inserts_text_before_linebreak_2.dump b/src/testdir/dumps/Test_prop_inserts_text_before_linebreak_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_prop_inserts_text_before_linebreak_2.dump @@ -0,0 +1,6 @@ +|a+0&#ffffff0@44|b+0#e000e06&@4 +| +0#0000000&@1|++0#4040ff13&|b+0#e000e06&@4| +0#0000000&@41 +@2|++0#4040ff13&|c+0#0000000&@43>c| @1 +|~+0#4040ff13&| @48 +|~| @48 +| +0#0000000&@31|1|,|9|1|-|1|4|8| @5|A|l@1| diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim --- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -2791,6 +2791,25 @@ func Test_prop_before_tab_skipcol() call StopVimInTerminal(buf) endfunc +func Test_prop_inserts_text_before_linebreak() + CheckRunVimInTerminal + + let lines =<< trim END + setlocal linebreak showbreak=+ breakindent breakindentopt=shift:2 + call setline(1, repeat('a', 50) .. ' ' .. repeat('c', 45)) + call prop_type_add('theprop', #{highlight: 'Special'}) + call prop_add(1, 51, #{type: 'theprop', text: repeat('b', 10), text_wrap: 'wrap'}) + normal! $ + END + call writefile(lines, 'XscriptPropsBeforeLinebreak', 'D') + let buf = RunVimInTerminal('-S XscriptPropsBeforeLinebreak', #{rows: 6, cols: 50}) + call VerifyScreenDump(buf, 'Test_prop_inserts_text_before_linebreak_1', {}) + call term_sendkeys(buf, '05x$') + call VerifyScreenDump(buf, 'Test_prop_inserts_text_before_linebreak_2', {}) + + call StopVimInTerminal(buf) +endfunc + func Test_prop_inserts_text_lcs_extends() CheckRunVimInTerminal diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1825, +/**/ 1824, /**/ 1823,