summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-08-09 18:25:23 +0100
committerBram Moolenaar <Bram@vim.org>2022-08-09 18:25:23 +0100
commit49a90792d950c51608d0459ef8699fe921070718 (patch)
treea4f212b416b59ac517fd1b7a0aec9775d0369c31
parente428fa04a758cc87ea580c856a796e58e407504b (diff)
patch 9.0.0179: cursor pos wrong with wrapping virtual text in empty linev9.0.0179
Problem: Cursor position wrong with wrapping virtual text in empty line. Solution: Adjust handling of an empty line. (closes #10875)
-rw-r--r--src/charset.c51
-rw-r--r--src/misc1.c14
-rw-r--r--src/proto/charset.pro1
-rw-r--r--src/testdir/dumps/Test_prop_with_text_empty_line_1.dump8
-rw-r--r--src/testdir/dumps/Test_prop_with_text_empty_line_2.dump8
-rw-r--r--src/testdir/dumps/Test_prop_with_text_empty_line_3.dump8
-rw-r--r--src/testdir/dumps/Test_prop_with_text_empty_line_4.dump8
-rw-r--r--src/testdir/dumps/Test_prop_with_text_empty_line_5.dump8
-rw-r--r--src/testdir/test_textprop.vim26
-rw-r--r--src/version.c2
10 files changed, 121 insertions, 13 deletions
diff --git a/src/charset.c b/src/charset.c
index c345f7e2a9..2975cdb194 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -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
diff --git a/src/misc1.c b/src/misc1.c
index f3d90f876d..f4a313d416 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -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
diff --git a/src/proto/charset.pro b/src/proto/charset.pro
index 307b3ceec9..6bc8eab990 100644
--- a/src/proto/charset.pro
+++ b/src/proto/charset.pro
@@ -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
index 0000000000..426d64eb05
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_with_text_empty_line_1.dump
@@ -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
index 0000000000..426d64eb05
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_with_text_empty_line_2.dump
@@ -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
index 0000000000..3e3e9ea88e
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_with_text_empty_line_3.dump
@@ -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
index 0000000000..8689ac4d99
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_with_text_empty_line_4.dump
@@ -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
index 0000000000..9ea16dcbf8
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_with_text_empty_line_5.dump
@@ -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|
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index caf933d25f..f60eb83003 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index f105ab797f..895c4e0f05 100644
--- a/src/version.c
+++ b/src/version.c
@@ -736,6 +736,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 179,
+/**/
178,
/**/
177,