Patch 9.0.0603
Problem:    With 'nosplitscroll' folds are not handled correctly.
Solution:   Take care of closed folds when moving the cursor. (Luuk van Baal,
            closes #11234)
Files:      src/edit.c, src/proto/edit.pro, src/window.c,
            src/testdir/test_window_cmd.vim,
            src/testdir/dumps/Test_nosplitscroll_fold_1.dump,
            src/testdir/dumps/Test_nosplitscroll_fold_2.dump,
            src/testdir/dumps/Test_nosplitscroll_fold_3.dump,
            src/testdir/dumps/Test_nosplitscroll_fold_4.dump


*** ../vim-9.0.0602/src/edit.c  2022-09-25 20:58:08.801019377 +0100
--- src/edit.c  2022-09-27 12:28:59.802429780 +0100
***************
*** 2749,2800 ****
      return OK;
  }
  
!     int
! cursor_up(
!     long      n,
!     int               upd_topline)        // When TRUE: update topline
  {
!     linenr_T  lnum;
  
!     if (n > 0)
!     {
!       lnum = curwin->w_cursor.lnum;
!       // This fails if the cursor is already in the first line or the count
!       // is larger than the line number and '-' is in 'cpoptions'
!       if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
!           return FAIL;
!       if (n >= lnum)
!           lnum = 1;
!       else
  #ifdef FEAT_FOLDING
!           if (hasAnyFolding(curwin))
        {
!           /*
!            * Count each sequence of folded lines as one logical line.
!            */
!           // go to the start of the current fold
!           (void)hasFolding(lnum, &lnum, NULL);
! 
!           while (n--)
!           {
!               // move up one line
!               --lnum;
!               if (lnum <= 1)
!                   break;
!               // If we entered a fold, move to the beginning, unless in
!               // Insert mode or when 'foldopen' contains "all": it will open
!               // in a moment.
!               if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL)))
!                   (void)hasFolding(lnum, &lnum, NULL);
!           }
!           if (lnum < 1)
!               lnum = 1;
        }
!       else
! #endif
!           lnum -= n;
!       curwin->w_cursor.lnum = lnum;
      }
  
      // try to advance to the column we want to be at
      coladvance(curwin->w_curswant);
--- 2749,2810 ----
      return OK;
  }
  
! /*
!  * Move the cursor up "n" lines in window "wp".
!  * Takes care of closed folds.
!  * Returns the new cursor line or zero for failure.
!  */
!     linenr_T
! cursor_up_inner(win_T *wp, long n)
  {
!     linenr_T  lnum = wp->w_cursor.lnum;
  
!     // This fails if the cursor is already in the first line or the count is
!     // larger than the line number and '-' is in 'cpoptions'
!     if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
!       return 0;
!     if (n >= lnum)
!       lnum = 1;
!     else
  #ifdef FEAT_FOLDING
!       if (hasAnyFolding(wp))
!     {
!       /*
!        * Count each sequence of folded lines as one logical line.
!        */
!       // go to the start of the current fold
!       (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
! 
!       while (n--)
        {
!           // move up one line
!           --lnum;
!           if (lnum <= 1)
!               break;
!           // If we entered a fold, move to the beginning, unless in
!           // Insert mode or when 'foldopen' contains "all": it will open
!           // in a moment.
!           if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL)))
!               (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
        }
!       if (lnum < 1)
!           lnum = 1;
      }
+     else
+ #endif
+       lnum -= n;
+ 
+     wp->w_cursor.lnum = lnum;
+     return lnum;
+ }
+ 
+     int
+ cursor_up(
+     long      n,
+     int               upd_topline)        // When TRUE: update topline
+ {
+     if (n > 0 && cursor_up_inner(curwin, n) == 0)
+       return FAIL;
  
      // try to advance to the column we want to be at
      coladvance(curwin->w_curswant);
***************
*** 2806,2859 ****
  }
  
  /*
!  * Cursor down a number of logical lines.
   */
!     int
! cursor_down(
!     long      n,
!     int               upd_topline)        // When TRUE: update topline
  {
!     linenr_T  lnum;
  
-     if (n > 0)
-     {
-       lnum = curwin->w_cursor.lnum;
  #ifdef FEAT_FOLDING
!       // Move to last line of fold, will fail if it's the end-of-file.
!       (void)hasFolding(lnum, NULL, &lnum);
  #endif
!       // This fails if the cursor is already in the last line or would move
!       // beyond the last line and '-' is in 'cpoptions'
!       if (lnum >= curbuf->b_ml.ml_line_count
!               || (lnum + n > curbuf->b_ml.ml_line_count
!                   && vim_strchr(p_cpo, CPO_MINUS) != NULL))
!           return FAIL;
!       if (lnum + n >= curbuf->b_ml.ml_line_count)
!           lnum = curbuf->b_ml.ml_line_count;
!       else
  #ifdef FEAT_FOLDING
!       if (hasAnyFolding(curwin))
!       {
!           linenr_T    last;
  
!           // count each sequence of folded lines as one logical line
!           while (n--)
!           {
!               if (hasFolding(lnum, NULL, &last))
!                   lnum = last + 1;
!               else
!                   ++lnum;
!               if (lnum >= curbuf->b_ml.ml_line_count)
!                   break;
!           }
!           if (lnum > curbuf->b_ml.ml_line_count)
!               lnum = curbuf->b_ml.ml_line_count;
        }
!       else
! #endif
!           lnum += n;
!       curwin->w_cursor.lnum = lnum;
      }
  
      // try to advance to the column we want to be at
      coladvance(curwin->w_curswant);
--- 2816,2879 ----
  }
  
  /*
!  * Move the cursor down "n" lines in window "wp".
!  * Takes care of closed folds.
!  * Returns the new cursor line or zero for failure.
   */
!     linenr_T
! cursor_down_inner(win_T *wp, long n)
  {
!     linenr_T  lnum = wp->w_cursor.lnum;
!     linenr_T  line_count = wp->w_buffer->b_ml.ml_line_count;
  
  #ifdef FEAT_FOLDING
!     // Move to last line of fold, will fail if it's the end-of-file.
!     (void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
  #endif
!     // This fails if the cursor is already in the last line or would move
!     // beyond the last line and '-' is in 'cpoptions'
!     if (lnum >= line_count
!           || (lnum + n > line_count && vim_strchr(p_cpo, CPO_MINUS) != NULL))
!       return FAIL;
!     if (lnum + n >= line_count)
!       lnum = line_count;
!     else
  #ifdef FEAT_FOLDING
!       if (hasAnyFolding(wp))
!     {
!       linenr_T        last;
  
!       // count each sequence of folded lines as one logical line
!       while (n--)
!       {
!           if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
!               lnum = last + 1;
!           else
!               ++lnum;
!           if (lnum >= line_count)
!               break;
        }
!       if (lnum > line_count)
!           lnum = line_count;
      }
+     else
+ #endif
+       lnum += n;
+ 
+     wp->w_cursor.lnum = lnum;
+     return lnum;
+ }
+ 
+ /*
+  * Cursor down a number of logical lines.
+  */
+     int
+ cursor_down(
+     long      n,
+     int               upd_topline)        // When TRUE: update topline
+ {
+     if (n > 0 &&  cursor_down_inner(curwin, n) == 0)
+       return FAIL;
  
      // try to advance to the column we want to be at
      coladvance(curwin->w_curswant);
*** ../vim-9.0.0602/src/proto/edit.pro  2022-08-16 14:51:49.442515641 +0100
--- src/proto/edit.pro  2022-09-27 12:22:20.579274093 +0100
***************
*** 19,25 ****
--- 19,27 ----
  void beginline(int flags);
  int oneright(void);
  int oneleft(void);
+ linenr_T cursor_up_inner(win_T *wp, long n);
  int cursor_up(long n, int upd_topline);
+ linenr_T cursor_down_inner(win_T *wp, long n);
  int cursor_down(long n, int upd_topline);
  int stuff_inserted(int c, long count, int no_esc);
  char_u *get_last_insert(void);
*** ../vim-9.0.0602/src/window.c        2022-09-26 23:08:17.444945122 +0100
--- src/window.c        2022-09-27 12:28:07.622543490 +0100
***************
*** 6351,6357 ****
  /*
   * Handle scroll position for 'nosplitscroll'.  Replaces scroll_to_fraction()
   * call from win_new_height().  Instead we iterate over all windows in a
!  * tabpage and calculate the new scroll/cursor position.
   * TODO: Ensure this also works with wrapped lines.
   * Requires topline to be able to be set to a bufferline with some
   * offset(row-wise scrolling/smoothscroll).
--- 6351,6357 ----
  /*
   * Handle scroll position for 'nosplitscroll'.  Replaces scroll_to_fraction()
   * call from win_new_height().  Instead we iterate over all windows in a
!  * tabpage and calculate the new scroll position.
   * TODO: Ensure this also works with wrapped lines.
   * Requires topline to be able to be set to a bufferline with some
   * offset(row-wise scrolling/smoothscroll).
***************
*** 6359,6366 ****
      static void
  win_fix_scroll(int resize)
  {
!     win_T    *wp;
!     linenr_T lnum;
  
      skip_update_topline = TRUE;  // avoid scrolling in curs_columns()
      FOR_ALL_WINDOWS(wp)
--- 6359,6367 ----
      static void
  win_fix_scroll(int resize)
  {
!     int               diff;
!     win_T     *wp;
!     linenr_T  lnum;
  
      skip_update_topline = TRUE;  // avoid scrolling in curs_columns()
      FOR_ALL_WINDOWS(wp)
***************
*** 6368,6380 ****
        // Skip when window height has not changed.
        if (wp->w_height != wp->w_prev_height)
        {
!           // Determine botline needed to avoid scrolling and set cursor.
            if (wp->w_winrow != wp->w_prev_winrow)
            {
                lnum = wp->w_cursor.lnum;
!               wp->w_cursor.lnum = MIN(wp->w_buffer->b_ml.ml_line_count,
!                       wp->w_botline - 1 + (wp->w_winrow - wp->w_prev_winrow)
!                                         + (wp->w_height - wp->w_prev_height));
                // Bring the new cursor position to the bottom of the screen.
                wp->w_fraction = FRACTION_MULT;
                scroll_to_fraction(wp, wp->w_prev_height);
--- 6369,6386 ----
        // Skip when window height has not changed.
        if (wp->w_height != wp->w_prev_height)
        {
!           // If window has moved update botline to keep the same screenlines.
            if (wp->w_winrow != wp->w_prev_winrow)
            {
                lnum = wp->w_cursor.lnum;
!               diff = (wp->w_winrow - wp->w_prev_winrow)
!                    + (wp->w_height - wp->w_prev_height);
!               wp->w_cursor.lnum = wp->w_botline - 1;
!               //  Add difference in height and row to botline.
!               if (diff > 0)
!                   cursor_down_inner(wp, diff);
!               else
!                   cursor_up_inner(wp, -diff);
                // Bring the new cursor position to the bottom of the screen.
                wp->w_fraction = FRACTION_MULT;
                scroll_to_fraction(wp, wp->w_prev_height);
***************
*** 6405,6413 ****
      static void
  win_fix_cursor(int normal)
  {
!     win_T    *wp = curwin;
!     long     so = get_scrolloff_value();
!     linenr_T nlnum = 0;
  
      if (wp->w_buffer->b_ml.ml_line_count < wp->w_height)
        return;
--- 6411,6422 ----
      static void
  win_fix_cursor(int normal)
  {
!     long      so = get_scrolloff_value();
!     win_T     *wp = curwin;
!     linenr_T  nlnum = 0;
!     linenr_T    lnum = wp->w_cursor.lnum;
!     linenr_T    bot;
!     linenr_T    top;
  
      if (wp->w_buffer->b_ml.ml_line_count < wp->w_height)
        return;
***************
*** 6415,6442 ****
      if (skip_win_fix_cursor)
        return;
  #endif
! 
      so = MIN(wp->w_height / 2, so);
!     // Check if cursor position is above topline or below botline.
!     if (wp->w_cursor.lnum < (wp->w_topline + so) && wp->w_topline != 1)
!       nlnum = MIN(wp->w_topline + so, wp->w_buffer->b_ml.ml_line_count);
!     else if (wp->w_cursor.lnum > (wp->w_botline - so - 1)
!           && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1)
!       nlnum = MAX(wp->w_botline - so - 1, 1);
!     // If cursor was invalid scroll or change cursor.
!     if (nlnum)
      {
!       if (normal)
!       {   // Make sure cursor is closer to topline than botline.
!           if (so == wp->w_height / 2
!                         && nlnum - wp->w_topline > wp->w_botline - 1 - nlnum)
!               nlnum--;
!           setmark('\'');              // save cursor position
!           wp->w_cursor.lnum = nlnum;  // change to avoid scrolling
            curs_columns(TRUE);         // validate w_wrow
        }
!       else
!       {   // Ensure cursor stays visible if we are not in normal mode.
            wp->w_fraction = 0.5 * FRACTION_MULT;
            scroll_to_fraction(wp, wp->w_prev_height);
            validate_botline_win(curwin);
--- 6424,6453 ----
      if (skip_win_fix_cursor)
        return;
  #endif
!     // Determine valid cursor range.
      so = MIN(wp->w_height / 2, so);
!     wp->w_cursor.lnum = wp->w_topline;
!     top = cursor_down_inner(wp, so);
!     wp->w_cursor.lnum = wp->w_botline - 1;
!     bot = cursor_up_inner(wp, so);
!     // Check if cursor position is above or below valid cursor range.
!     if (lnum > bot && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1)
!       nlnum = bot;
!     else if (lnum < top && wp->w_topline != 1)
!       nlnum = (so == wp->w_height / 2) ? bot : top;
! 
!     wp->w_cursor.lnum = lnum;
! 
!     if (nlnum)  // Cursor is invalid for current scroll position.
      {
!       if (normal)  // Save to jumplist and set cursor to avoid scrolling.
!       {
!           setmark('\'');
!           wp->w_cursor.lnum = nlnum;
            curs_columns(TRUE);         // validate w_wrow
        }
!       else  // Scroll instead when not in normal mode.
!       {
            wp->w_fraction = 0.5 * FRACTION_MULT;
            scroll_to_fraction(wp, wp->w_prev_height);
            validate_botline_win(curwin);
*** ../vim-9.0.0602/src/testdir/test_window_cmd.vim     2022-09-23 
12:56:49.305714732 +0100
--- src/testdir/test_window_cmd.vim     2022-09-27 12:25:33.110875003 +0100
***************
*** 1848,1851 ****
--- 1848,1881 ----
    call VerifyScreenDump(buf, 'Test_nosplitscroll_callback_4', {})
  endfunc
  
+ function Test_nosplitscroll_fold()
+ CheckScreendump
+ 
+ let lines =<< trim END
+   set nosplitscroll
+   set foldmethod=marker
+   set number
+   let line = 1
+   for n in range(1, &lines)
+     call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
+           \ 'after fold'])
+     let line += 8
+   endfor
+ END
+   call writefile(lines, 'XTestNosplitscrollFold', 'D')
+   let buf = RunVimInTerminal('-S XTestNosplitscrollFold', #{rows: 10})
+ 
+   call term_sendkeys(buf, "L:wincmd s\<CR>")
+   call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_1', {})
+ 
+   call term_sendkeys(buf, ":quit\<CR>")
+   call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_2', {})
+ 
+   call term_sendkeys(buf, "H:below split\<CR>")
+   call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_3', {})
+ 
+   call term_sendkeys(buf, ":wincmd k\<CR>:quit\<CR>")
+   call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_4', {})
+ endfunction
+ 
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-9.0.0602/src/testdir/dumps/Test_nosplitscroll_fold_1.dump    
2022-09-27 12:30:28.514234792 +0100
--- src/testdir/dumps/Test_nosplitscroll_fold_1.dump    2022-09-27 
12:25:33.110875003 +0100
***************
*** 0 ****
--- 1,10 ----
+ | +0#0000e05#a8a8a8255@1|1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0@1|8| >a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255@1|9| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0|1|6| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @43|8|,|1| @11|T|o|p
+ | +0#af5f00255&|2|4| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255|2|5| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0|3|2| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @43|2|3|,|1| @10|3|2|%
+ |:+0&&|w|i|n|c|m|d| |s| @65
*** ../vim-9.0.0602/src/testdir/dumps/Test_nosplitscroll_fold_2.dump    
2022-09-27 12:30:28.518234783 +0100
--- src/testdir/dumps/Test_nosplitscroll_fold_2.dump    2022-09-27 
12:25:33.110875003 +0100
***************
*** 0 ****
--- 1,10 ----
+ | +0#0000e05#a8a8a8255@1|1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0@1|8| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255@1|9| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0|1|6| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255|1|7| >+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0|2|4| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255|2|5| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0|3|2| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255|3@1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ |:+0#0000000#ffffff0|q|u|i|t| @51|1|7|,|1| @9|T|o|p| 
*** ../vim-9.0.0602/src/testdir/dumps/Test_nosplitscroll_fold_3.dump    
2022-09-27 12:30:28.522234775 +0100
--- src/testdir/dumps/Test_nosplitscroll_fold_3.dump    2022-09-27 
12:25:33.110875003 +0100
***************
*** 0 ****
--- 1,10 ----
+ | +0#0000e05#a8a8a8255@1|1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0@1|8| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255@1|9| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ |[+1#0000000#ffffff0|N|o| |N|a|m|e|]| |[|+|]| @43|1|,|1| @11|T|o|p
+ | +0#0000e05#a8a8a8255|1|7| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0|2|4| >a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ | +0#0000e05#a8a8a8255|2|5| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| 
|F|u|n|c|N|a|m|e|(|)| |{|-@40
+ | +0#af5f00255#ffffff0|3|2| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+ |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @43|2|4|,|1| @10|2|5|%
+ |:+0&&|b|e|l|o|w| |s|p|l|i|t| @62
*** ../vim-9.0.0602/src/version.c       2022-09-27 11:57:09.785256754 +0100
--- src/version.c       2022-09-27 12:30:04.742287235 +0100
***************
*** 701,702 ****
--- 701,704 ----
  {   /* Add new patch number below this line */
+ /**/
+     603,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
192. Your boss asks you to "go fer" coffee and you come up with 235 FTP sites.

 /// 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/20220927113608.A32661C0413%40moolenaar.net.

Raspunde prin e-mail lui