]> granicus.if.org Git - vim/commitdiff
patch 9.0.0603: with 'nosplitscroll' folds are not handled correctly v9.0.0603
authorLuuk van Baal <luukvbaal@gmail.com>
Tue, 27 Sep 2022 11:31:15 +0000 (12:31 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 27 Sep 2022 11:31:15 +0000 (12:31 +0100)
Problem:    With 'nosplitscroll' folds are not handled correctly.
Solution:   Take care of closed folds when moving the cursor. (Luuk van Baal,
            closes #11234)

src/edit.c
src/proto/edit.pro
src/testdir/dumps/Test_nosplitscroll_fold_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_nosplitscroll_fold_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_nosplitscroll_fold_3.dump [new file with mode: 0644]
src/testdir/test_window_cmd.vim
src/version.c
src/window.c

index ec3e8ff6c41fa5c6660fcbd8d04f35d36530437a..2ac544a6be9a7bbf1e006a8a205d4fab66c589cd 100644 (file)
@@ -2749,52 +2749,62 @@ oneleft(void)
     return OK;
 }
 
-    int
-cursor_up(
-    long       n,
-    int                upd_topline)        // When TRUE: update topline
+/*
+ * 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;
+    linenr_T   lnum = wp->w_cursor.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
+    // 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(curwin))
-       {
-           /*
-            * Count each sequence of folded lines as one logical line.
-            */
-           // go to the start of the current fold
-           (void)hasFolding(lnum, &lnum, NULL);
+       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)hasFolding(lnum, &lnum, NULL);
-           }
-           if (lnum < 1)
-               lnum = 1;
+       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);
        }
-       else
-#endif
-           lnum -= n;
-       curwin->w_cursor.lnum = lnum;
+       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,54 +2816,64 @@ cursor_up(
 }
 
 /*
- * Cursor down a number of logical lines.
+ * Move the cursor down "n" lines in window "wp".
+ * Takes care of closed folds.
+ * Returns the new cursor line or zero for failure.
  */
-    int
-cursor_down(
-    long       n,
-    int                upd_topline)        // When TRUE: update topline
+    linenr_T
+cursor_down_inner(win_T *wp, long n)
 {
-    linenr_T   lnum;
+    linenr_T   lnum = wp->w_cursor.lnum;
+    linenr_T   line_count = wp->w_buffer->b_ml.ml_line_count;
 
-    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
+    // 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(curwin))
-       {
-           linenr_T    last;
+       if (hasAnyFolding(wp))
+    {
+       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;
+       // 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;
        }
-       else
-#endif
-           lnum += n;
-       curwin->w_cursor.lnum = lnum;
+       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);
index f35ec1ed529816d10442d44e1e88a0e333254ae2..4513f4fe0a75c2aeb81bc6f9ee7606af64057493 100644 (file)
@@ -19,7 +19,9 @@ char_u *add_char2buf(int c, char_u *s);
 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);
diff --git a/src/testdir/dumps/Test_nosplitscroll_fold_1.dump b/src/testdir/dumps/Test_nosplitscroll_fold_1.dump
new file mode 100644 (file)
index 0000000..748a3c8
--- /dev/null
@@ -0,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
diff --git a/src/testdir/dumps/Test_nosplitscroll_fold_2.dump b/src/testdir/dumps/Test_nosplitscroll_fold_2.dump
new file mode 100644 (file)
index 0000000..959cb64
--- /dev/null
@@ -0,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| 
diff --git a/src/testdir/dumps/Test_nosplitscroll_fold_3.dump b/src/testdir/dumps/Test_nosplitscroll_fold_3.dump
new file mode 100644 (file)
index 0000000..6880104
--- /dev/null
@@ -0,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
index 2ee4417878cae3b941afab2a786b4b16deebf236..aa69522d720da38d10d5d4b47fbc3462569a586f 100644 (file)
@@ -1848,4 +1848,34 @@ function Test_nosplitscroll_callback()
   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
index 430475110b2e22375336f253ae417a01aaba8146..f6b88274a7a348297f26f2e132f5047ac17e307f 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    603,
 /**/
     602,
 /**/
index db08e41326df4e66d9c094b8b521549eb2a2a06d..d4580e474d6497a3f041a8101f5a1bcbe4186b37 100644 (file)
@@ -6351,7 +6351,7 @@ set_fraction(win_T *wp)
 /*
  * 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.
+ * 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,8 +6359,9 @@ set_fraction(win_T *wp)
     static void
 win_fix_scroll(int resize)
 {
-    win_T    *wp;
-    linenr_T lnum;
+    int                diff;
+    win_T      *wp;
+    linenr_T   lnum;
 
     skip_update_topline = TRUE;  // avoid scrolling in curs_columns()
     FOR_ALL_WINDOWS(wp)
@@ -6368,13 +6369,18 @@ win_fix_scroll(int resize)
        // 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 window has moved update botline to keep the same screenlines.
            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));
+               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,9 +6411,12 @@ win_fix_scroll(int resize)
     static void
 win_fix_cursor(int normal)
 {
-    win_T    *wp = curwin;
-    long     so = get_scrolloff_value();
-    linenr_T nlnum = 0;
+    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,28 +6424,30 @@ win_fix_cursor(int normal)
     if (skip_win_fix_cursor)
        return;
 #endif
-
+    // Determine valid cursor range.
     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
+    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
-       {   // Ensure cursor stays visible if we are not in normal mode.
+       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);