Patch 9.0.0179
Problem:    Cursor position wrong with wrapping virtual text in empty line.
Solution:   Adjust handling of an empty line. (closes #10875)
Files:      src/charset.c, src/proto/charset.pro, src/misc1.c,
            src/testdir/test_textprop.vim,
            src/testdir/dumps/Test_prop_with_text_empty_line_1.dump,
            src/testdir/dumps/Test_prop_with_text_empty_line_2.dump,
            src/testdir/dumps/Test_prop_with_text_empty_line_3.dump,
            src/testdir/dumps/Test_prop_with_text_empty_line_4.dump,
            src/testdir/dumps/Test_prop_with_text_empty_line_5.dump


*** ../vim-9.0.0178/src/charset.c       2022-08-09 16:55:19.296912275 +0100
--- src/charset.c       2022-08-09 18:18:32.677908662 +0100
***************
*** 759,764 ****
--- 759,772 ----
      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,787 ****
      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);
      clear_chartabsize_arg(&cts);
      return (int)cts.cts_vcol;
  }
  
  /*
   * Return TRUE if 'c' is a normal identifier character:
   * Letters and characters from the 'isident' option.
--- 780,810 ----
      chartabsize_T cts;
  
      init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
!     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,1137 ****
      size = win_chartabsize(wp, s, vcol);
  
  # ifdef FEAT_PROP_POPUP
!     if (cts->cts_has_prop_with_text && *line != NUL)
      {
        int         tab_size = size;
!       int         charlen = mb_ptr2len(s);
        int         i;
        int         col = (int)(s - line);
        garray_T    *gap = &wp->w_buffer->b_textprop_text;
--- 1151,1160 ----
      size = win_chartabsize(wp, s, vcol);
  
  # ifdef FEAT_PROP_POPUP
!     if (cts->cts_has_prop_with_text)
      {
        int         tab_size = size;
!       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,1417 ****
--- 1435,1443 ----
      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,1517 ****
--- 1538,1548 ----
            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,1551 ****
        else
        {
  #ifdef FEAT_PROP_POPUP
!           if ((State & MODE_INSERT) == 0)
!               // cursor is after inserted text
                vcol += cts.cts_cur_text_width;
  #endif
            *cursor = vcol + head;          // cursor at start
--- 1575,1582 ----
        else
        {
  #ifdef FEAT_PROP_POPUP
!           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
*** ../vim-9.0.0178/src/proto/charset.pro       2022-08-04 15:03:16.253142105 
+0100
--- src/proto/charset.pro       2022-08-09 17:49:19.598186450 +0100
***************
*** 18,23 ****
--- 18,24 ----
  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);
*** ../vim-9.0.0178/src/misc1.c 2022-08-06 13:47:16.212982332 +0100
--- src/misc1.c 2022-08-09 17:50:31.858044240 +0100
***************
*** 399,409 ****
      char_u    *s;
      long      col;
      int               width;
  
      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);
  
      /*
       * If list mode is on, then the '$' at the end of the line may take up one
--- 399,417 ----
      char_u    *s;
      long      col;
      int               width;
+     chartabsize_T cts;
  
      s = ml_get_buf(wp->w_buffer, lnum, FALSE);
!     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
*** ../vim-9.0.0178/src/testdir/test_textprop.vim       2022-08-09 
16:55:19.296912275 +0100
--- src/testdir/test_textprop.vim       2022-08-09 18:19:48.653960452 +0100
***************
*** 2557,2562 ****
--- 2557,2588 ----
    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
  
*** ../vim-9.0.0178/src/testdir/dumps/Test_prop_with_text_empty_line_1.dump     
2022-08-09 18:21:40.686014551 +0100
--- src/testdir/dumps/Test_prop_with_text_empty_line_1.dump     2022-08-09 
18:10:25.025112203 +0100
***************
*** 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| 
*** ../vim-9.0.0178/src/testdir/dumps/Test_prop_with_text_empty_line_2.dump     
2022-08-09 18:21:40.690014553 +0100
--- src/testdir/dumps/Test_prop_with_text_empty_line_2.dump     2022-08-09 
18:19:55.353964392 +0100
***************
*** 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| 
*** ../vim-9.0.0178/src/testdir/dumps/Test_prop_with_text_empty_line_3.dump     
2022-08-09 18:21:40.694014554 +0100
--- src/testdir/dumps/Test_prop_with_text_empty_line_3.dump     2022-08-09 
18:19:56.505965061 +0100
***************
*** 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| 
*** ../vim-9.0.0178/src/testdir/dumps/Test_prop_with_text_empty_line_4.dump     
2022-08-09 18:21:40.698014556 +0100
--- src/testdir/dumps/Test_prop_with_text_empty_line_4.dump     2022-08-09 
18:19:57.653965722 +0100
***************
*** 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| 
*** ../vim-9.0.0178/src/testdir/dumps/Test_prop_with_text_empty_line_5.dump     
2022-08-09 18:21:40.702014558 +0100
--- src/testdir/dumps/Test_prop_with_text_empty_line_5.dump     2022-08-09 
18:19:58.805966386 +0100
***************
*** 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| 
*** ../vim-9.0.0178/src/version.c       2022-08-09 16:55:19.296912275 +0100
--- src/version.c       2022-08-09 17:26:48.956583494 +0100
***************
*** 737,738 ****
--- 737,740 ----
  {   /* Add new patch number below this line */
+ /**/
+     179,
  /**/

-- 
    A KNIGHT rides into shot and hacks him to the ground.  He rides off.
    We stay for a moment on the glade.  A MIDDLE-AGED LADY in a C. & A.
    twin-set emerges from the trees and looks in horror at the body of her
    HUSBAND.
MRS HISTORIAN: FRANK!
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// 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/20220809172559.5C1EF1C0EC3%40moolenaar.net.

Raspunde prin e-mail lui