changeset 32977:68a12270d21b

patch 9.0.1785: wrong cursor position with 'showbreak' and lcs-eol Commit: https://github.com/vim/vim/commit/1193951bebcff50d88403ce17dec5d3be14f131d Author: zeertzjq <zeertzjq@outlook.com> Date: Wed Aug 23 20:58:01 2023 +0200 patch 9.0.1785: wrong cursor position with 'showbreak' and lcs-eol Problem: wrong cursor position with 'showbreak' and lcs-eol Solution: Add size of 'showbreak' before when 'listchars' "eol" is used. Also fix wrong cursor position with wrapping virtual text on empty line and 'showbreak'. closes: #12891 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
author Christian Brabandt <cb@256bit.org>
date Thu, 24 Aug 2023 07:35:13 +0200
parents d23645a0aca8
children 25d0060209cc
files src/charset.c src/move.c src/testdir/dumps/Test_cursor_position_with_showbreak.dump src/testdir/dumps/Test_cursor_position_with_showbreak_1.dump src/testdir/dumps/Test_cursor_position_with_showbreak_2.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_22.dump src/testdir/test_breakindent.vim src/testdir/test_textprop.vim src/version.c
diffstat 9 files changed, 71 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/src/charset.c
+++ b/src/charset.c
@@ -1157,11 +1157,13 @@ win_lbr_chartabsize(
     }
 
 #if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP)
+    int has_lcs_eol = wp->w_p_list && wp->w_lcs_chars.eol != NUL;
+
     /*
      * First get the normal size, without 'linebreak' or text properties
      */
     size = win_chartabsize(wp, s, vcol);
-    if (*s == NUL)
+    if (*s == NUL && !has_lcs_eol)
 	size = 0;  // NUL is not displayed
 
 # ifdef FEAT_PROP_POPUP
@@ -1175,8 +1177,11 @@ win_lbr_chartabsize(
 
 	// The "$" for 'list' mode will go between the EOL and
 	// the text prop, account for that.
-	if (wp->w_p_list && wp->w_lcs_chars.eol != NUL)
+	if (has_lcs_eol)
+	{
 	    ++vcol;
+	    --size;
+	}
 
 	for (i = 0; i < cts->cts_text_prop_count; ++i)
 	{
@@ -1235,8 +1240,11 @@ win_lbr_chartabsize(
 	    if (tp->tp_col != MAXCOL && tp->tp_col - 1 > col)
 		break;
 	}
-	if (wp->w_p_list && wp->w_lcs_chars.eol != NUL)
+	if (has_lcs_eol)
+	{
 	    --vcol;
+	    ++size;
+	}
     }
 # endif
 
@@ -1298,12 +1306,12 @@ win_lbr_chartabsize(
 
     /*
      * May have to add something for 'breakindent' and/or 'showbreak'
-     * string at start of line.
-     * Do not use 'showbreak' at the NUL after the text.
+     * string at the start of a screen line.
      */
     int head = mb_added;
-    sbr = (c == NUL || no_sbr) ? empty_option : get_showbreak_value(wp);
-    if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap)
+    sbr = no_sbr ? empty_option : get_showbreak_value(wp);
+    // When "size" is 0, no new screen line is started.
+    if (size > 0 && wp->w_p_wrap && (*sbr != NUL || wp->w_p_bri))
     {
 	int	col_off_prev = win_col_off(wp);
 	int	width2 = wp->w_width - col_off_prev + win_col_off2(wp);
@@ -1348,37 +1356,34 @@ win_lbr_chartabsize(
 		head_mid += vim_strsize(sbr);
 	    if (wp->w_p_bri)
 		head_mid += get_breakindent_win(wp, line);
-	    if (head_mid > 0)
+	    if (head_mid > 0 && wcol + size > wp->w_width)
 	    {
-		if (wcol + size > wp->w_width)
-		{
-		    // calculate effective window width
-		    int prev_rem = wp->w_width - wcol;
-		    int width = width2 - head_mid;
+		// calculate effective window width
+		int prev_rem = wp->w_width - wcol;
+		int width = width2 - head_mid;
 
-		    if (width <= 0)
-			width = 1;
-		    // divide "size - prev_width" by "width", rounding up
-		    int cnt = (size - prev_rem + width - 1) / width;
-		    added += cnt * head_mid;
+		if (width <= 0)
+		    width = 1;
+		// divide "size - prev_width" by "width", rounding up
+		int cnt = (size - prev_rem + width - 1) / width;
+		added += cnt * head_mid;
 
-		    if (max_head_vcol == 0
-					|| vcol + size + added < max_head_vcol)
-			head += cnt * head_mid;
-		    else if (max_head_vcol > vcol + head_prev + prev_rem)
-			head += (max_head_vcol - (vcol + head_prev + prev_rem)
+		if (max_head_vcol == 0 || vcol + size + added < max_head_vcol)
+		    head += cnt * head_mid;
+		else if (max_head_vcol > vcol + head_prev + prev_rem)
+		    head += (max_head_vcol - (vcol + head_prev + prev_rem)
 					     + width2 - 1) / width2 * head_mid;
 #ifdef FEAT_PROP_POPUP
-		    else if (max_head_vcol < 0)
-		    {
-			int off = 0;
-			if ((State & MODE_NORMAL) || cts->cts_start_incl)
-			    off += cts->cts_cur_text_width;
-			if (off >= prev_rem)
-			    head += (1 + (off - prev_rem) / width) * head_mid;
-		    }
+		else if (max_head_vcol < 0)
+		{
+		    int off = 0;
+		    if (c != NUL
+			     && ((State & MODE_NORMAL) || cts->cts_start_incl))
+			off += cts->cts_cur_text_width;
+		    if (off >= prev_rem)
+			head += (1 + (off - prev_rem) / width) * head_mid;
+		}
 #endif
-		}
 	    }
 
 	    size += added;
--- a/src/move.c
+++ b/src/move.c
@@ -1212,7 +1212,8 @@ curs_columns(
 	    // column
 	    char_u *sbr = get_showbreak_value(curwin);
 	    if (*sbr && *ml_get_cursor() == NUL
-				    && curwin->w_wcol == vim_strsize(sbr))
+		    && curwin->w_wcol
+			      == (curwin->w_width - width2) + vim_strsize(sbr))
 		curwin->w_wcol = 0;
 #endif
 	}
rename from src/testdir/dumps/Test_cursor_position_with_showbreak.dump
rename to src/testdir/dumps/Test_cursor_position_with_showbreak_1.dump
--- a/src/testdir/dumps/Test_cursor_position_with_showbreak.dump
+++ b/src/testdir/dumps/Test_cursor_position_with_showbreak_1.dump
@@ -1,5 +1,5 @@
 | +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0@71|X
-> +0#0000e05#a8a8a8255@1|s+0#0000000#ffffff0|e|c|o|n|d| |l|i|n|e| @61
+| +0#0000e05#a8a8a8255@1>s+0#0000000#ffffff0|e|c|o|n|d| |l|i|n|e| @61
 |~+0#4040ff13&| @73
 |~| @73
 |~| @73
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_cursor_position_with_showbreak_2.dump
@@ -0,0 +1,6 @@
+| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0@71|X
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1|++0#4040ff13&>$| +0#0000000&@68
+| +0#0000e05#a8a8a8255@1|s+0#0000000#ffffff0|e|c|o|n|d| |l|i|n|e|$+0#4040ff13&| +0#0000000&@60
+|~+0#4040ff13&| @73
+|~| @73
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|1|,|7|4| @9|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_22.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| >1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3| +0#0000000&@2
+|~+0#4040ff13&| @28
+|~| @28
+| +0#0000000&@29
--- a/src/testdir/test_breakindent.vim
+++ b/src/testdir/test_breakindent.vim
@@ -897,7 +897,9 @@ func Test_cursor_position_with_showbreak
   let lines =<< trim END
       vim9script
       &signcolumn = 'yes'
-      &showbreak = '+ '
+      &showbreak = '++'
+      &breakindent = true
+      &breakindentopt = 'shift:2'
       var leftcol: number = win_getid()->getwininfo()->get(0, {})->get('textoff')
       repeat('x', &columns - leftcol - 1)->setline(1)
       'second line'->setline(2)
@@ -906,7 +908,13 @@ func Test_cursor_position_with_showbreak
   let buf = RunVimInTerminal('-S XscriptShowbreak', #{rows: 6})
 
   call term_sendkeys(buf, "AX")
-  call VerifyScreenDump(buf, 'Test_cursor_position_with_showbreak', {})
+  call VerifyScreenDump(buf, 'Test_cursor_position_with_showbreak_1', {})
+  " No line wraps, so changing 'showbreak' should lead to the same screen.
+  call term_sendkeys(buf, "\<C-\>\<C-O>:setlocal showbreak=+\<CR>")
+  call VerifyScreenDump(buf, 'Test_cursor_position_with_showbreak_1', {})
+  " The first line now wraps because of "eol" in 'listchars'.
+  call term_sendkeys(buf, "\<C-\>\<C-O>:setlocal list\<CR>")
+  call VerifyScreenDump(buf, 'Test_cursor_position_with_showbreak_2', {})
 
   call StopVimInTerminal(buf)
 endfunc
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -2687,6 +2687,8 @@ func Run_test_prop_inserts_text_showbrea
   call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_20', {})
   call term_sendkeys(buf, "\<C-E>")
   call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_21', {})
+  call term_sendkeys(buf, "zbx")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_22', {})
 
   call StopVimInTerminal(buf)
 endfunc
--- 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 */
 /**/
+    1785,
+/**/
     1786,
 /**/
     1783,