From 3fc1f2a00e1efb5519a799399f443bcae0891a89 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 26 Sep 2025 17:00:10 +0000 Subject: [PATCH] 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 Signed-off-by: Christian Brabandt --- src/charset.c | 8 +- src/drawline.c | 21 +++++- src/proto/drawline.pro | 1 + .../Test_text_after_wrap_showbreak_01.dump | 8 ++ .../Test_text_after_wrap_showbreak_02.dump | 8 ++ .../Test_text_after_wrap_showbreak_03.dump | 8 ++ .../Test_text_after_wrap_showbreak_04.dump | 8 ++ .../Test_text_after_wrap_showbreak_05.dump | 8 ++ .../Test_text_after_wrap_showbreak_06.dump | 8 ++ .../Test_text_after_wrap_showbreak_07.dump | 8 ++ .../Test_text_after_wrap_showbreak_08.dump | 8 ++ .../Test_text_after_wrap_showbreak_09.dump | 8 ++ .../Test_text_after_wrap_showbreak_10.dump | 8 ++ .../Test_text_after_wrap_showbreak_11.dump | 8 ++ .../Test_text_after_wrap_showbreak_12.dump | 8 ++ src/testdir/test_textprop.vim | 75 +++++++++++++++++++ src/version.c | 2 + 17 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_01.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_02.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_03.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_04.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_05.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_06.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_07.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_08.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_09.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_10.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_11.dump create mode 100644 src/testdir/dumps/Test_text_after_wrap_showbreak_12.dump diff --git a/src/charset.c b/src/charset.c index 9c68d4af75..e595cd937e 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 497ba5b85c..978ffee0b0 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 141ca1b9c2..abda9cf74a 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 0000000000..ae2c456e11 --- /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 0000000000..72c044ad32 --- /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 0000000000..39d6557550 --- /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 0000000000..c19159da97 --- /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 0000000000..56ddaf19a8 --- /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 0000000000..ff3c9924be --- /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 0000000000..bf75a92f41 --- /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 0000000000..1a83d3e5ee --- /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 0000000000..9392da83a2 --- /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 0000000000..e1ab21354f --- /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 0000000000..5a47901252 --- /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 0000000000..dc5b3cca78 --- /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 b5c9f63f65..5340aeef1f 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:$\") + 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 e093873703..4d820a9cb4 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, /**/