Patch 9.0.1301
Problem:    Virtual text below empty line not displayed.
Solution:   Adjust flags and computations. (closes #11959)
Files:      src/drawline.c, src/charset.c, src/testdir/test_textprop.vim,
            src/testdir/dumps/Test_prop_above_below_empty_1.dump


*** ../vim-9.0.1300/src/drawline.c      2023-01-21 15:54:40.426545808 +0000
--- src/drawline.c      2023-02-11 13:45:47.382682457 +0000
***************
*** 1085,1090 ****
--- 1085,1091 ----
      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,1930 ****
                // 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)
                    {
                        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;
  # ifdef FEAT_LINEBREAK
--- 1915,1934 ----
                // Check if any active property ends.
                for (pi = 0; pi < text_props_active; ++pi)
                {
!                   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;
  # ifdef FEAT_LINEBREAK
***************
*** 1940,1945 ****
--- 1944,1952 ----
                    // 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,1965 ****
                                      || wlv.row == startrow
                                      || (text_props[text_prop_next].tp_flags
                                                       & TP_FLAG_ALIGN_BELOW)))
!                              || (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)
                    {
!                       // first display the '$' after the line
                        text_prop_follows = TRUE;
                        break;
                    }
                    if (text_props[text_prop_next].tp_col == MAXCOL
--- 1957,1980 ----
                                      || wlv.row == startrow
                                      || (text_props[text_prop_next].tp_flags
                                                       & TP_FLAG_ALIGN_BELOW)))
!                              || (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 == line
!                                       && !did_line
!                                       && (text_props[text_prop_next].tp_flags
!                                                      & TP_FLAG_ALIGN_BELOW))))
                    {
!                       // 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,1993 ****
                    text_prop_id = 0;
                    reset_extra_attr = FALSE;
                }
!               if (text_props_active > 0 && wlv.n_extra == 0)
                {
                    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_text_props(wp->w_buffer, text_props,
                                            text_prop_idxs, text_props_active);
  
--- 1993,2010 ----
                    text_prop_id = 0;
                    reset_extra_attr = FALSE;
                }
!               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.
                    sort_text_props(wp->w_buffer, text_props,
                                            text_prop_idxs, text_props_active);
  
***************
*** 2159,2166 ****
                        // must wrap anyway.
                        text_prop_above = above;
                        text_prop_follows |= other_tpi != -1
!                           && (wp->w_p_wrap
!                                  || (text_props[other_tpi].tp_flags
                               & (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_RIGHT)));
  
                        if (bail_out)
--- 2176,2183 ----
                        // must wrap anyway.
                        text_prop_above = above;
                        text_prop_follows |= other_tpi != -1
!                                       && (wp->w_p_wrap
!                                            || (text_props[other_tpi].tp_flags
                               & (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_RIGHT)));
  
                        if (bail_out)
***************
*** 2495,2500 ****
--- 2512,2523 ----
  #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,3595 ****
        // 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)
            {
!               curwin->w_cline_row = startrow;
!               curwin->w_cline_height = wlv.row - startrow;
  #ifdef FEAT_FOLDING
!               curwin->w_cline_folded = FALSE;
  #endif
!               curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
            }
-           break;
        }
  
        // Show "extends" character from 'listchars' if beyond the line end and
--- 3599,3629 ----
        // At end of the text line.
        if (c == NUL)
        {
! #ifdef FEAT_PROP_POPUP
!           if (text_prop_follows)
!           {
!               // Put the pointer back to the NUL.
!               --ptr;
!               c = ' ';
!           }
!           else
! #endif
            {
!               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;
  #endif
!                   curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
!               }
!               break;
            }
        }
  
        // Show "extends" character from 'listchars' if beyond the line end and
*** ../vim-9.0.1300/src/charset.c       2023-02-05 18:00:38.353400148 +0000
--- src/charset.c       2023-02-11 13:32:56.238573887 +0000
***************
*** 1152,1157 ****
--- 1152,1159 ----
       * 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)
*** ../vim-9.0.1300/src/testdir/test_textprop.vim       2023-01-28 
19:18:56.733720607 +0000
--- src/testdir/test_textprop.vim       2023-02-11 13:42:49.574667255 +0000
***************
*** 2779,2784 ****
--- 2779,2806 ----
    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
  
*** ../vim-9.0.1300/src/testdir/dumps/Test_prop_above_below_empty_1.dump        
2023-02-11 13:47:27.350689573 +0000
--- src/testdir/dumps/Test_prop_above_below_empty_1.dump        2023-02-11 
13:42:24.622664830 +0000
***************
*** 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| 
*** ../vim-9.0.1300/src/version.c       2023-02-11 11:15:19.999085252 +0000
--- src/version.c       2023-02-11 13:34:40.430597456 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1301,
  /**/

-- 
FIXME and XXX are two common keywords used to mark broken or incomplete code
not only since XXX as a sex reference would grab everybody's attention but
simply due to the fact that Vim would highlight these words.
                                        -- Hendrik Scholz

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230211134935.877911C0830%40moolenaar.net.

Raspunde prin e-mail lui