changeset 33077:d03841a271aa v9.0.1825

patch 9.0.1825: wrong cursor position with virt text and 'linebreak' Commit: https://github.com/vim/vim/commit/6e55e85f92aff43c1b3cb564201440f3552d63f0 Author: zeertzjq <zeertzjq@outlook.com> 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 <cb@256bit.org> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
author Christian Brabandt <cb@256bit.org>
date Wed, 30 Aug 2023 17:00:03 +0200
parents d36b31ab54c4
children be72951df2eb
files src/charset.c src/testdir/dumps/Test_prop_inserts_text_before_linebreak_1.dump src/testdir/dumps/Test_prop_inserts_text_before_linebreak_2.dump src/testdir/test_textprop.vim src/version.c
diffstat 5 files changed, 87 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- 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
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| 
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| 
--- 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
 
--- 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,