patch 9.1.1796: Wrong cursor position with wrapped "after" virtual text and 
'sbr'

Commit: 
https://github.com/vim/vim/commit/3fc1f2a00e1efb5519a799399f443bcae0891a89
Author: zeertzjq <[email protected]>
Date:   Fri Sep 26 17:00:10 2025 +0000

    patch 9.1.1796: Wrong cursor position with wrapped "after" virtual text and 
'sbr'
    
    Problem:  Wrong cursor position with wrapped "after" virtual text and
              'showbreak' (Ben Jackson)
    Solution: Count size of 'showbreak' in wrapped "after" virtual text in
              line size (zeertzjq).
    
    fixes: #18398
    closes: #18400
    
    Signed-off-by: zeertzjq <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/charset.c b/src/charset.c
index 9c68d4af7..e595cd937 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -918,8 +918,9 @@ win_linetabsize_cts(chartabsize_T *cts, colnr_T len)
     // check for a virtual text at the end of a line or on an empty line
     if (len == MAXCOL && cts->cts_has_prop_with_text && *cts->cts_ptr == NUL)
     {
-       (void)win_lbr_chartabsize(cts, NULL);
-       vcol += cts->cts_cur_text_width;
+       int head = 0;
+       (void)win_lbr_chartabsize(cts, &head);
+       vcol += cts->cts_cur_text_width + head;
        // when properties are above or below the empty line must also be
        // counted
        if (cts->cts_ptr == cts->cts_line && cts->cts_prop_lines > 0)
@@ -1325,7 +1326,8 @@ win_lbr_chartabsize(
                             (vcol + size) % (wp->w_width - col_off) + col_off,
                                              &n_extra, &p, NULL, NULL, FALSE);
 #  ifdef FEAT_LINEBREAK
-                       no_sbr = TRUE;  // don't use 'showbreak' now
+                       if (text_prop_no_showbreak(tp))
+                           no_sbr = TRUE;  // don't use 'showbreak' now
 #  endif
                    }
                    else
diff --git a/src/drawline.c b/src/drawline.c
index 497ba5b85..978ffee0b 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -829,6 +829,23 @@ text_prop_position(
        return cells;
     return (below && col_with_padding > win_col_off(wp) && !wp->w_p_wrap);
 }
+
+# if defined(FEAT_LINEBREAK) || defined(PROTO)
+/*
+ * no 'showbreak' before "below" text property
+ * or after "above" or "right" text property
+ */
+    int
+text_prop_no_showbreak(textprop_T *tp)
+{
+    int            right = (tp->tp_flags & TP_FLAG_ALIGN_RIGHT);
+    int            above = (tp->tp_flags & TP_FLAG_ALIGN_ABOVE);
+    int            below = (tp->tp_flags & TP_FLAG_ALIGN_BELOW);
+    int            wrap = tp->tp_col < MAXCOL || (tp->tp_flags & TP_FLAG_WRAP);
+
+    return (right || above || below || !wrap);
+}
+# endif
 #endif
 
 /*
@@ -2258,10 +2275,8 @@ win_line(
                                // don't combine char attr after EOL
                                text_prop_flags &= ~PT_FLAG_COMBINE;
 # ifdef FEAT_LINEBREAK
-                           if (above || below || right || !wrap)
+                           if (text_prop_no_showbreak(tp))
                            {
-                               // no 'showbreak' before "below" text property
-                               // or after "above" or "right" text property
                                wlv.need_showbreak = FALSE;
                                wlv.dont_use_showbreak = TRUE;
                            }
diff --git a/src/proto/drawline.pro b/src/proto/drawline.pro
index 141ca1b9c..abda9cf74 100644
--- a/src/proto/drawline.pro
+++ b/src/proto/drawline.pro
@@ -1,4 +1,5 @@
 /* drawline.c */
 int text_prop_position(win_T *wp, textprop_T *tp, int vcol, int scr_col, int 
*n_extra, char_u **p_extra, int *n_attr, int *n_attr_skip, int do_skip);
+int text_prop_no_showbreak(textprop_T *tp);
 int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int 
number_only, spellvars_T *spv);
 /* vim: set ft=c : */
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_01.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_01.dump
new file mode 100644
index 000000000..ae2c456e1
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_01.dump
@@ -0,0 +1,8 @@
+> +8&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|0
+|>+8#4040ff13&| |a+8#0000001#a8a8a8255@3|8|9|0| |1|2|3| |4|5|6| |7|8
+|>+8#4040ff13#ffffff0| |9+8#0000001#a8a8a8255| +8#0000000#ffffff0@16
+|f+0&&|o@1| @16
+|b|a|r| @16
+|~+0#4040ff13&| @18
+|~| @18
+| +0#0000000&@9|1|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_02.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_02.dump
new file mode 100644
index 000000000..72c044ad3
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_02.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|0
+|>+0#4040ff13&| |a+0#0000001#a8a8a8255@3|8|9|0| |1|2|3| |4|5|6| |7|8
+|>+0#4040ff13#ffffff0| |9+0#0000001#a8a8a8255| +0#0000000#ffffff0@16
+>f+8&&|o@1| @16
+|b+0&&|a|r| @16
+|~+0#4040ff13&| @18
+|~| @18
+| +0#0000000&@9|2|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_03.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_03.dump
new file mode 100644
index 000000000..39d655755
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_03.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|0
+|>+0#4040ff13&| |a+0#0000001#a8a8a8255@3|8|9|0| |1|2|3| |4|5|6| |7|8
+|>+0#4040ff13#ffffff0| |9+0#0000001#a8a8a8255| +0#0000000#ffffff0@16
+|f|o@1| @16
+>b+8&&|a|r| @16
+|~+0#4040ff13&| @18
+|~| @18
+| +0#0000000&@9|3|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_04.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_04.dump
new file mode 100644
index 000000000..c19159da9
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_04.dump
@@ -0,0 +1,8 @@
+> +8&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|a+8#0000001#a8a8a8255
+|>+8#4040ff13#ffffff0| |a+8#0000001#a8a8a8255@2|8|9|0| |1|2|3| |4|5|6| |7|8|9
+|f+0#0000000#ffffff0|o@1| @16
+|b|a|r| @16
+|~+0#4040ff13&| @18
+|~| @18
+|~| @18
+| +0#0000000&@9|1|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_05.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_05.dump
new file mode 100644
index 000000000..56ddaf19a
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_05.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|a+0#0000001#a8a8a8255
+|>+0#4040ff13#ffffff0| |a+0#0000001#a8a8a8255@2|8|9|0| |1|2|3| |4|5|6| |7|8|9
+>f+8#0000000#ffffff0|o@1| @16
+|b+0&&|a|r| @16
+|~+0#4040ff13&| @18
+|~| @18
+|~| @18
+| +0#0000000&@9|2|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_06.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_06.dump
new file mode 100644
index 000000000..ff3c9924b
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_06.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|a+0#0000001#a8a8a8255
+|>+0#4040ff13#ffffff0| |a+0#0000001#a8a8a8255@2|8|9|0| |1|2|3| |4|5|6| |7|8|9
+|f+0#0000000#ffffff0|o@1| @16
+>b+8&&|a|r| @16
+|~+0#4040ff13&| @18
+|~| @18
+|~| @18
+| +0#0000000&@9|3|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_07.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_07.dump
new file mode 100644
index 000000000..bf75a92f4
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_07.dump
@@ -0,0 +1,8 @@
+> +8&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|$+8#4040ff13&
+|>| |a+8#0000001#a8a8a8255@3|8|9|0| |1|2|3| |4|5|6| |7|8
+|>+8#4040ff13#ffffff0| |9+8#0000001#a8a8a8255| +8#0000000#ffffff0@16
+|f+0&&|o@1|$+0#4040ff13&| +0#0000000&@15
+|b|a|r|$+0#4040ff13&| +0#0000000&@15
+|~+0#4040ff13&| @18
+|~| @18
+| +0#0000000&@9|1|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_08.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_08.dump
new file mode 100644
index 000000000..1a83d3e5e
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_08.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|$+0#4040ff13&
+|>| |a+0#0000001#a8a8a8255@3|8|9|0| |1|2|3| |4|5|6| |7|8
+|>+0#4040ff13#ffffff0| |9+0#0000001#a8a8a8255| +0#0000000#ffffff0@16
+>f+8&&|o@1|$+8#4040ff13&| +8#0000000&@15
+|b+0&&|a|r|$+0#4040ff13&| +0#0000000&@15
+|~+0#4040ff13&| @18
+|~| @18
+| +0#0000000&@9|2|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_09.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_09.dump
new file mode 100644
index 000000000..9392da83a
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_09.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|9|$+0#4040ff13&
+|>| |a+0#0000001#a8a8a8255@3|8|9|0| |1|2|3| |4|5|6| |7|8
+|>+0#4040ff13#ffffff0| |9+0#0000001#a8a8a8255| +0#0000000#ffffff0@16
+|f|o@1|$+0#4040ff13&| +0#0000000&@15
+>b+8&&|a|r|$+8#4040ff13&| +8#0000000&@15
+|~+0#4040ff13&| @18
+|~| @18
+| +0#0000000&@9|3|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_10.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_10.dump
new file mode 100644
index 000000000..e1ab21354
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_10.dump
@@ -0,0 +1,8 @@
+> +8&#ffffff0@7|"| |1|2|3|4|5|6|7|8|$+8#4040ff13&|a+8#0000001#a8a8a8255
+|>+8#4040ff13#ffffff0| |a+8#0000001#a8a8a8255@2|8|9|0| |1|2|3| |4|5|6| |7|8|9
+|f+0#0000000#ffffff0|o@1|$+0#4040ff13&| +0#0000000&@15
+|b|a|r|$+0#4040ff13&| +0#0000000&@15
+|~+0#4040ff13&| @18
+|~| @18
+|~| @18
+| +0#0000000&@9|1|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_11.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_11.dump
new file mode 100644
index 000000000..5a4790125
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_11.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|$+0#4040ff13&|a+0#0000001#a8a8a8255
+|>+0#4040ff13#ffffff0| |a+0#0000001#a8a8a8255@2|8|9|0| |1|2|3| |4|5|6| |7|8|9
+>f+8#0000000#ffffff0|o@1|$+8#4040ff13&| +8#0000000&@15
+|b+0&&|a|r|$+0#4040ff13&| +0#0000000&@15
+|~+0#4040ff13&| @18
+|~| @18
+|~| @18
+| +0#0000000&@9|2|,|1| @2|A|l@1| 
diff --git a/src/testdir/dumps/Test_text_after_wrap_showbreak_12.dump 
b/src/testdir/dumps/Test_text_after_wrap_showbreak_12.dump
new file mode 100644
index 000000000..dc5b3cca7
--- /dev/null
+++ b/src/testdir/dumps/Test_text_after_wrap_showbreak_12.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@7|"| |1|2|3|4|5|6|7|8|$+0#4040ff13&|a+0#0000001#a8a8a8255
+|>+0#4040ff13#ffffff0| |a+0#0000001#a8a8a8255@2|8|9|0| |1|2|3| |4|5|6| |7|8|9
+|f+0#0000000#ffffff0|o@1|$+0#4040ff13&| +0#0000000&@15
+>b+8&&|a|r|$+8#4040ff13&| +8#0000000&@15
+|~+0#4040ff13&| @18
+|~| @18
+|~| @18
+| +0#0000000&@9|3|,|1| @2|A|l@1| 
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index b5c9f63f6..5340aeef1 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -4264,6 +4264,81 @@ func Test_text_after_nowrap_list()
   call StopVimInTerminal(buf)
 endfunc
 
+func Test_text_after_wrap_showbreak()
+  CheckScreendump
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+    set cursorline
+    set shiftwidth=4
+
+    set breakindent
+    set showbreak=>\ 
+    set breakindentopt=shift:2,min:64
+
+    call setline(1, ['        " 1234567890', 'foo', 'bar'])
+
+    call prop_type_add('Test', {
+          \ 'highlight': 'Visual',
+          \ 'priority': 10,
+          \ 'combine': v:true,
+          \ })
+    call prop_add(1, 0, #{
+          \ type: 'Test',
+          \ bufnr: bufnr('%'),
+          \ text: 'aaaa890 123 456 789',
+          \ text_wrap: 'wrap',
+          \ text_align: 'after'
+          \ })
+  END
+  call writefile(lines, 'XTestAfterWrapShowbreak', 'D')
+  let buf = RunVimInTerminal('-S XTestAfterWrapShowbreak', #{rows: 8, cols: 
20})
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_01', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_02', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_03', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_02', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_01', {})
+
+  call term_sendkeys(buf, '$x0')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_04', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_05', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_06', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_05', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_04', {})
+
+  call term_sendkeys(buf, ":set list listchars=eol:$\<CR>")
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_07', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_08', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_09', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_08', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_07', {})
+
+  call term_sendkeys(buf, '$x0')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_10', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_11', {})
+  call term_sendkeys(buf, 'j')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_12', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_11', {})
+  call term_sendkeys(buf, 'k')
+  call VerifyScreenDump(buf, 'Test_text_after_wrap_showbreak_10', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
 func Test_text_below_nowrap()
   CheckScreendump
   CheckRunVimInTerminal
diff --git a/src/version.c b/src/version.c
index e09387370..4d820a9cb 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1796,
 /**/
     1795,
 /**/

-- 
-- 
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 [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1v2C2I-00D8OB-MJ%40256bit.org.

Raspunde prin e-mail lui