]> granicus.if.org Git - vim/commitdiff
patch 9.0.0179: cursor pos wrong with wrapping virtual text in empty line v9.0.0179
authorBram Moolenaar <Bram@vim.org>
Tue, 9 Aug 2022 17:25:23 +0000 (18:25 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 9 Aug 2022 17:25:23 +0000 (18:25 +0100)
Problem:    Cursor position wrong with wrapping virtual text in empty line.
Solution:   Adjust handling of an empty line. (closes #10875)

src/charset.c
src/misc1.c
src/proto/charset.pro
src/testdir/dumps/Test_prop_with_text_empty_line_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_prop_with_text_empty_line_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_prop_with_text_empty_line_3.dump [new file with mode: 0644]
src/testdir/dumps/Test_prop_with_text_empty_line_4.dump [new file with mode: 0644]
src/testdir/dumps/Test_prop_with_text_empty_line_5.dump [new file with mode: 0644]
src/testdir/test_textprop.vim
src/version.c

index c345f7e2a98b6c9606b32c1b2875e298efbb6c1a..2975cdb194381c6c42790a4857c6f2dad666bd76 100644 (file)
@@ -759,6 +759,14 @@ linetabsize_col(int startcol, char_u *s)
     init_chartabsize_arg(&cts, curwin, 0, startcol, s, s);
     while (*cts.cts_ptr != NUL)
        cts.cts_vcol += lbr_chartabsize_adv(&cts);
+#ifdef FEAT_PROP_POPUP
+    if (cts.cts_has_prop_with_text && cts.cts_ptr == cts.cts_line)
+    {
+       // check for virtual text in an empty line
+       (void)lbr_chartabsize_adv(&cts);
+       cts.cts_vcol += cts.cts_cur_text_width;
+    }
+#endif
     clear_chartabsize_arg(&cts);
     return (int)cts.cts_vcol;
 }
@@ -772,16 +780,31 @@ win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len)
     chartabsize_T cts;
 
     init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
-#ifdef FEAT_PROP_POPUP
-    cts.cts_with_trailing = len == MAXCOL;
-#endif
-    for ( ; *cts.cts_ptr != NUL && (len == MAXCOL || cts.cts_ptr < line + len);
-                                                     MB_PTR_ADV(cts.cts_ptr))
-       cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
+    win_linetabsize_cts(&cts, len);
     clear_chartabsize_arg(&cts);
     return (int)cts.cts_vcol;
 }
 
+    void
+win_linetabsize_cts(chartabsize_T *cts, colnr_T len)
+{
+#ifdef FEAT_PROP_POPUP
+    cts->cts_with_trailing = len == MAXCOL;
+#endif
+    for ( ; *cts->cts_ptr != NUL && (len == MAXCOL || cts->cts_ptr < cts->cts_line + len);
+                                                     MB_PTR_ADV(cts->cts_ptr))
+       cts->cts_vcol += win_lbr_chartabsize(cts, NULL);
+#ifdef FEAT_PROP_POPUP
+    // check for a virtual text on an empty line
+    if (cts->cts_has_prop_with_text && *cts->cts_ptr == NUL
+                                             && cts->cts_ptr == cts->cts_line)
+    {
+       (void)win_lbr_chartabsize(cts, NULL);
+       cts->cts_vcol += cts->cts_cur_text_width;
+    }
+#endif
+}
+
 /*
  * Return TRUE if 'c' is a normal identifier character:
  * Letters and characters from the 'isident' option.
@@ -1128,10 +1151,10 @@ win_lbr_chartabsize(
     size = win_chartabsize(wp, s, vcol);
 
 # ifdef FEAT_PROP_POPUP
-    if (cts->cts_has_prop_with_text && *line != NUL)
+    if (cts->cts_has_prop_with_text)
     {
        int         tab_size = size;
-       int         charlen = mb_ptr2len(s);
+       int         charlen = *s == NUL ? 1 : mb_ptr2len(s);
        int         i;
        int         col = (int)(s - line);
        garray_T    *gap = &wp->w_buffer->b_textprop_text;
@@ -1412,6 +1435,9 @@ getvcol(
     int                ts = wp->w_buffer->b_p_ts;
     int                c;
     chartabsize_T cts;
+#ifdef FEAT_PROP_POPUP
+    int                on_NUL = FALSE;
+#endif
 
     vcol = 0;
     line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
@@ -1512,6 +1538,11 @@ getvcol(
            if (*cts.cts_ptr == NUL)
            {
                incr = 1;       // NUL at end of line only takes one column
+#ifdef FEAT_PROP_POPUP
+               if (cts.cts_cur_text_width > 0)
+                   incr = cts.cts_cur_text_width;
+               on_NUL = TRUE;
+#endif
                break;
            }
 
@@ -1544,8 +1575,8 @@ getvcol(
        else
        {
 #ifdef FEAT_PROP_POPUP
-           if ((State & MODE_INSERT) == 0)
-               // cursor is after inserted text
+           if ((State & MODE_INSERT) == 0 && !on_NUL)
+               // cursor is after inserted text, unless on the NUL
                vcol += cts.cts_cur_text_width;
 #endif
            *cursor = vcol + head;          // cursor at start
index f3d90f876d6a3dbcde57a459a3b075c5511d7403..f4a313d4164ea48e39a741398a32d737b02706c1 100644 (file)
@@ -399,11 +399,19 @@ plines_win_nofold(win_T *wp, linenr_T lnum)
     char_u     *s;
     long       col;
     int                width;
+    chartabsize_T cts;
 
     s = ml_get_buf(wp->w_buffer, lnum, FALSE);
-    if (*s == NUL)             // empty line
-       return 1;
-    col = win_linetabsize(wp, lnum, s, (colnr_T)MAXCOL);
+    init_chartabsize_arg(&cts, wp, lnum, 0, s, s);
+    if (*s == NUL
+#ifdef FEAT_PROP_POPUP
+           && !cts.cts_has_prop_with_text
+#endif
+           )
+       return 1; // be quick for an empty line
+    win_linetabsize_cts(&cts, (colnr_T)MAXCOL);
+    clear_chartabsize_arg(&cts);
+    col = (int)cts.cts_vcol;
 
     /*
      * If list mode is on, then the '$' at the end of the line may take up one
index 307b3ceec93005727b8e753aeb81568e996d48bc..6bc8eab990f5f1668224ec0d1c81365dc550a01c 100644 (file)
@@ -18,6 +18,7 @@ int chartabsize(char_u *p, colnr_T col);
 int linetabsize(char_u *s);
 int linetabsize_col(int startcol, char_u *s);
 int win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len);
+void win_linetabsize_cts(chartabsize_T *cts, colnr_T len);
 int vim_isIDc(int c);
 int vim_isNormalIDc(int c);
 int vim_iswordc(int c);
diff --git a/src/testdir/dumps/Test_prop_with_text_empty_line_1.dump b/src/testdir/dumps/Test_prop_with_text_empty_line_1.dump
new file mode 100644 (file)
index 0000000..426d64e
--- /dev/null
@@ -0,0 +1,8 @@
+>X+0&#ffff4012@59
+|a+0&#ffffff0@2| @56
+|X+0&#ffff4012@59
+@1| +0&#ffffff0@58
+|b@5| @53
+|~+0#4040ff13&| @58
+|~| @58
+| +0#0000000&@41|1|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_prop_with_text_empty_line_2.dump b/src/testdir/dumps/Test_prop_with_text_empty_line_2.dump
new file mode 100644 (file)
index 0000000..426d64e
--- /dev/null
@@ -0,0 +1,8 @@
+>X+0&#ffff4012@59
+|a+0&#ffffff0@2| @56
+|X+0&#ffff4012@59
+@1| +0&#ffffff0@58
+|b@5| @53
+|~+0#4040ff13&| @58
+|~| @58
+| +0#0000000&@41|1|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_prop_with_text_empty_line_3.dump b/src/testdir/dumps/Test_prop_with_text_empty_line_3.dump
new file mode 100644 (file)
index 0000000..3e3e9ea
--- /dev/null
@@ -0,0 +1,8 @@
+|X+0&#ffff4012@59
+|a+0&#ffffff0@1>a| @56
+|X+0&#ffff4012@59
+@1| +0&#ffffff0@58
+|b@5| @53
+|~+0#4040ff13&| @58
+|~| @58
+| +0#0000000&@41|2|,|3| @10|A|l@1| 
diff --git a/src/testdir/dumps/Test_prop_with_text_empty_line_4.dump b/src/testdir/dumps/Test_prop_with_text_empty_line_4.dump
new file mode 100644 (file)
index 0000000..8689ac4
--- /dev/null
@@ -0,0 +1,8 @@
+|X+0&#ffff4012@59
+|a+0&#ffffff0@2| @56
+>X+0&#ffff4012@59
+@1| +0&#ffffff0@58
+|b@5| @53
+|~+0#4040ff13&| @58
+|~| @58
+| +0#0000000&@41|3|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_prop_with_text_empty_line_5.dump b/src/testdir/dumps/Test_prop_with_text_empty_line_5.dump
new file mode 100644 (file)
index 0000000..9ea16dc
--- /dev/null
@@ -0,0 +1,8 @@
+|X+0&#ffff4012@59
+|a+0&#ffffff0@2| @56
+|X+0&#ffff4012@59
+@1| +0&#ffffff0@58
+|b@4>b| @53
+|~+0#4040ff13&| @58
+|~| @58
+| +0#0000000&@41|4|,|6| @10|A|l@1| 
index caf933d25f8f9ddefdf8dff9349085a9f9c804da..f60eb830036ae9ea9d36049a3235685e5a202979 100644 (file)
@@ -2557,6 +2557,32 @@ func Test_props_with_text_after_truncated()
   call delete('XscriptPropsWithTextAfterTrunc')
 endfunc
 
+func Test_props_with_text_empty_line()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+      call setline(1, ['', 'aaa', '', 'bbbbbb'])
+      call prop_type_add('prop1', #{highlight: 'Search'})
+      call prop_add(1, 1, #{type: 'prop1', text_wrap: 'wrap', text: repeat('X', &columns)})
+      call prop_add(3, 1, #{type: 'prop1', text_wrap: 'wrap', text: repeat('X', &columns + 1)})
+      normal gg0
+  END
+  call writefile(lines, 'XscriptPropsWithTextEmptyLine')
+  let buf = RunVimInTerminal('-S XscriptPropsWithTextEmptyLine', #{rows: 8, cols: 60})
+  call VerifyScreenDump(buf, 'Test_prop_with_text_empty_line_1', {})
+  call term_sendkeys(buf, "$")
+  call VerifyScreenDump(buf, 'Test_prop_with_text_empty_line_2', {})
+  call term_sendkeys(buf, "j")
+  call VerifyScreenDump(buf, 'Test_prop_with_text_empty_line_3', {})
+  call term_sendkeys(buf, "j")
+  call VerifyScreenDump(buf, 'Test_prop_with_text_empty_line_4', {})
+  call term_sendkeys(buf, "j")
+  call VerifyScreenDump(buf, 'Test_prop_with_text_empty_line_5', {})
+
+  call StopVimInTerminal(buf)
+  call delete('XscriptPropsWithTextEmptyLine')
+endfunc
+
 func Test_props_with_text_after_wraps()
   CheckRunVimInTerminal
 
index f105ab797fb0820e1839991d19a66cf0056df8cb..895c4e0f05f820958e695fa3537da435b88404e6 100644 (file)
@@ -735,6 +735,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    179,
 /**/
     178,
 /**/