patch 9.0.1785: wrong cursor position with 'showbreak' and lcs-eol

Commit: 
https://github.com/vim/vim/commit/1193951bebcff50d88403ce17dec5d3be14f131d
Author: zeertzjq <zeert...@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 <c...@256bit.org>
    Co-authored-by: zeertzjq <zeert...@outlook.com>

diff --git a/src/charset.c b/src/charset.c
index a79b1d9ae..971fefc61 100644
--- 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;
-
-                   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)
+               // 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 (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;
-                   }
-#endif
+               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;
diff --git a/src/move.c b/src/move.c
index 2ba02cf5d..26a66c117 100644
--- 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
        }
diff --git a/src/testdir/dumps/Test_cursor_position_with_showbreak.dump 
b/src/testdir/dumps/Test_cursor_position_with_showbreak_1.dump
similarity index 71%
rename from src/testdir/dumps/Test_cursor_position_with_showbreak.dump
rename to src/testdir/dumps/Test_cursor_position_with_showbreak_1.dump
index 92b79cc47..fd42880e1 100644
--- 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
diff --git a/src/testdir/dumps/Test_cursor_position_with_showbreak_2.dump 
b/src/testdir/dumps/Test_cursor_position_with_showbreak_2.dump
new file mode 100644
index 000000000..e3577d52d
--- /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| 
diff --git a/src/testdir/dumps/Test_prop_inserts_text_showbreak_22.dump 
b/src/testdir/dumps/Test_prop_inserts_text_showbreak_22.dump
new file mode 100644
index 000000000..6481f6d78
--- /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
diff --git a/src/testdir/test_breakindent.vim b/src/testdir/test_breakindent.vim
index 27b1d9847..2bc85a35b 100644
--- 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
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index c272f2e5d..05bba6164 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -2687,6 +2687,8 @@ func Run_test_prop_inserts_text_showbreak(cmd)
   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
diff --git a/src/version.c b/src/version.c
index bcabd0b9c..875846088 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1785,
 /**/
     1784,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qZ2zx-00FvQX-Jw%40256bit.org.

Raspunde prin e-mail lui