changeset 31938:96d6d31dd66b v9.0.1301

patch 9.0.1301: virtual text below empty line not displayed Commit: https://github.com/vim/vim/commit/9d9a20ee8799bafe9caac616fef11b7a26db6a8d Author: Bram Moolenaar <Bram@vim.org> Date: Sat Feb 11 13:49:01 2023 +0000 patch 9.0.1301: virtual text below empty line not displayed Problem: Virtual text below empty line not displayed. Solution: Adjust flags and computations. (closes https://github.com/vim/vim/issues/11959)
author Bram Moolenaar <Bram@vim.org>
date Sat, 11 Feb 2023 15:00:04 +0100
parents 65c19095296f
children 5c671537304d
files src/charset.c src/drawline.c src/testdir/dumps/Test_prop_above_below_empty_1.dump src/testdir/test_textprop.vim src/version.c
diffstat 5 files changed, 101 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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;
 
+		    text_prop_above = FALSE;
+		    text_prop_follows = FALSE;
+
 		    // 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_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
new file mode 100644
--- /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| 
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -2779,6 +2779,28 @@ func Test_prop_with_text_below_after_emp
   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
 
--- 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,