summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2023-02-11 13:49:01 +0000
committerBram Moolenaar <Bram@vim.org>2023-02-11 13:49:01 +0000
commit9d9a20ee8799bafe9caac616fef11b7a26db6a8d (patch)
tree9234d5ca9e9e2c94943c650d24aaa39509bd2502
parent3ec78f973fdaec2cea8e036ed38037b2fe40670b (diff)
downloadvim-git-9.0.1301.tar.gz
patch 9.0.1301: virtual text below empty line not displayedv9.0.1301
Problem: Virtual text below empty line not displayed. Solution: Adjust flags and computations. (closes #11959)
-rw-r--r--src/charset.c2
-rw-r--r--src/drawline.c84
-rw-r--r--src/testdir/dumps/Test_prop_above_below_empty_1.dump16
-rw-r--r--src/testdir/test_textprop.vim22
-rw-r--r--src/version.c2
5 files changed, 101 insertions, 25 deletions
diff --git a/src/charset.c b/src/charset.c
index 960929971..ebec2cf40 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -1152,6 +1152,8 @@ win_lbr_chartabsize(
* First get the normal size, without 'linebreak' or text properties
*/
size = win_chartabsize(wp, s, vcol);
+ if (*s == NUL)
+ size = 0; // NUL is not displayed
# ifdef FEAT_PROP_POPUP
if (cts->cts_has_prop_with_text)
diff --git a/src/drawline.c b/src/drawline.c
index b4208a833..4328c06c5 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -1085,6 +1085,7 @@ win_line(
int save_did_emsg;
#endif
#ifdef FEAT_PROP_POPUP
+ int did_line = FALSE; // set to TRUE when line text done
int text_prop_count;
int text_prop_next = 0; // next text property to use
textprop_T *text_props = NULL;
@@ -1914,17 +1915,20 @@ win_line(
// Check if any active property ends.
for (pi = 0; pi < text_props_active; ++pi)
{
- int tpi = text_prop_idxs[pi];
-
- if (text_props[tpi].tp_col != MAXCOL
- && bcol >= text_props[tpi].tp_col - 1
- + text_props[tpi].tp_len)
+ int tpi = text_prop_idxs[pi];
+ textprop_T *tp = &text_props[tpi];
+
+ // An inline property ends when after the start column plus
+ // length. An "above" property ends when used and n_extra
+ // is zero.
+ if ((tp->tp_col != MAXCOL
+ && bcol >= tp->tp_col - 1 + tp->tp_len))
{
if (pi + 1 < text_props_active)
mch_memmove(text_prop_idxs + pi,
text_prop_idxs + pi + 1,
sizeof(int)
- * (text_props_active - (pi + 1)));
+ * (text_props_active - (pi + 1)));
--text_props_active;
--pi;
# ifdef FEAT_LINEBREAK
@@ -1940,6 +1944,9 @@ win_line(
// not on the next char yet, don't start another prop
--bcol;
# endif
+ int display_text_first = FALSE;
+ int active_before = text_props_active;
+
// Add any text property that starts in this column.
// With 'nowrap' and not in the first screen line only "below"
// text prop can show.
@@ -1950,16 +1957,24 @@ win_line(
|| wlv.row == startrow
|| (text_props[text_prop_next].tp_flags
& TP_FLAG_ALIGN_BELOW)))
- || (bcol == 0 &&
- (text_props[text_prop_next].tp_flags
+ || (bcol == 0
+ && (text_props[text_prop_next].tp_flags
& TP_FLAG_ALIGN_ABOVE)))
: bcol >= text_props[text_prop_next].tp_col - 1))
{
if (text_props[text_prop_next].tp_col == MAXCOL
- && *ptr == NUL && wp->w_p_list && lcs_eol_one > 0)
+ && *ptr == NUL
+ && ((wp->w_p_list && lcs_eol_one > 0)
+ || (ptr == line
+ && !did_line
+ && (text_props[text_prop_next].tp_flags
+ & TP_FLAG_ALIGN_BELOW))))
{
- // first display the '$' after the line
+ // first display the '$' after the line or display an
+ // empty line
text_prop_follows = TRUE;
+ if (text_props_active == active_before)
+ display_text_first = TRUE;
break;
}
if (text_props[text_prop_next].tp_col == MAXCOL
@@ -1978,16 +1993,18 @@ win_line(
text_prop_id = 0;
reset_extra_attr = FALSE;
}
- if (text_props_active > 0 && wlv.n_extra == 0)
+ if (text_props_active > 0 && wlv.n_extra == 0
+ && !display_text_first)
{
int used_tpi = -1;
int used_attr = 0;
int other_tpi = -1;
- // Sort the properties on priority and/or starting last.
- // Then combine the attributes, highest priority last.
text_prop_above = FALSE;
text_prop_follows = FALSE;
+
+ // Sort the properties on priority and/or starting last.
+ // Then combine the attributes, highest priority last.
sort_text_props(wp->w_buffer, text_props,
text_prop_idxs, text_props_active);
@@ -2159,8 +2176,8 @@ win_line(
// must wrap anyway.
text_prop_above = above;
text_prop_follows |= other_tpi != -1
- && (wp->w_p_wrap
- || (text_props[other_tpi].tp_flags
+ && (wp->w_p_wrap
+ || (text_props[other_tpi].tp_flags
& (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_RIGHT)));
if (bail_out)
@@ -2495,6 +2512,12 @@ win_line(
#ifdef FEAT_LINEBREAK
c0 = *ptr;
#endif
+#ifdef FEAT_PROP_POPUP
+ if (c == NUL)
+ // text is finished, may display a "below" virtual text
+ did_line = TRUE;
+#endif
+
if (has_mbyte)
{
mb_c = c;
@@ -3576,20 +3599,31 @@ win_line(
// At end of the text line.
if (c == NUL)
{
- draw_screen_line(wp, &wlv);
-
- // Update w_cline_height and w_cline_folded if the cursor line was
- // updated (saves a call to plines() later).
- if (wp == curwin && lnum == curwin->w_cursor.lnum)
+#ifdef FEAT_PROP_POPUP
+ if (text_prop_follows)
+ {
+ // Put the pointer back to the NUL.
+ --ptr;
+ c = ' ';
+ }
+ else
+#endif
{
- curwin->w_cline_row = startrow;
- curwin->w_cline_height = wlv.row - startrow;
+ draw_screen_line(wp, &wlv);
+
+ // Update w_cline_height and w_cline_folded if the cursor line
+ // was updated (saves a call to plines() later).
+ if (wp == curwin && lnum == curwin->w_cursor.lnum)
+ {
+ curwin->w_cline_row = startrow;
+ curwin->w_cline_height = wlv.row - startrow;
#ifdef FEAT_FOLDING
- curwin->w_cline_folded = FALSE;
+ curwin->w_cline_folded = FALSE;
#endif
- curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
+ curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
+ }
+ break;
}
- break;
}
// Show "extends" character from 'listchars' if beyond the line end and
diff --git a/src/testdir/dumps/Test_prop_above_below_empty_1.dump b/src/testdir/dumps/Test_prop_above_below_empty_1.dump
new file mode 100644
index 000000000..f47001693
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_above_below_empty_1.dump
@@ -0,0 +1,16 @@
+| +0#af5f00255#ffffff0@3|-+0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@1|1| |1+0#0000000&@7| @47
+| +0#af5f00255&@3|++0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@3|-+0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@1|2| | +0#0000000&@55
+| +0#af5f00255&@3|++0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@3|-+0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@1|3| |3+0#0000000&@8| @46
+| +0#af5f00255&@3|++0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@3|-+0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@1|4| | +0#0000000&@55
+| +0#af5f00255&@3|++0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@3|-+0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+| +0#af5f00255&@1|5| >5+0#0000000&@10| @44
+| +0#af5f00255&@3|++0#0000001#ffff4012@2| +0#0000000#ffffff0@52
+@42|5|,|1|-|5|7| @7|A|l@1|
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index e00bad6d3..b628c8215 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -2779,6 +2779,28 @@ func Test_prop_with_text_below_after_empty()
call StopVimInTerminal(buf)
endfunc
+func Test_prop_with_text_above_below_empty()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ setlocal number
+ call setline(1, ['11111111', '', '333333333', '', '55555555555'])
+
+ let vt = 'test'
+ call prop_type_add(vt, {'highlight': 'ToDo'})
+ for ln in range(1, line('$'))
+ call prop_add(ln, 0, {'type': vt, 'text': '---', 'text_align': 'above'})
+ call prop_add(ln, 0, {'type': vt, 'text': '+++', 'text_align': 'below'})
+ endfor
+ normal G
+ END
+ call writefile(lines, 'XscriptPropAboveBelowEmpty', 'D')
+ let buf = RunVimInTerminal('-S XscriptPropAboveBelowEmpty', #{rows: 16, cols: 60})
+ call VerifyScreenDump(buf, 'Test_prop_above_below_empty_1', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_prop_with_text_below_after_match()
CheckRunVimInTerminal
diff --git a/src/version.c b/src/version.c
index f28cfd8e2..524abf792 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1301,
+/**/
1300,
/**/
1299,