patch 9.1.0258: half-page scrolling broke backward compatibility

Commit: 
https://github.com/vim/vim/commit/cb204e688e5c9d56a78b621ef27c35d91860cb09
Author: Luuk van Baal <luukvb...@gmail.com>
Date:   Tue Apr 2 20:49:45 2024 +0200

    patch 9.1.0258: half-page scrolling broke backward compatibility
    
    Problem:  Support for 'smoothscroll' in (half-)page scrolling
              broke backward compatibility and can be made to work better.
              (after v9.1.215)
    Solution: Restore the previous cursor and end-of-buffer behavior for
              half-page scrolling and improve 'smoothscroll' support.
              (Luuk van Baal)
    
    fixes: #14338
    closes: #14377
    
    Signed-off-by: Luuk van Baal <luukvb...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/change.c b/src/change.c
index daf4faed5..dacc06fd4 100644
--- a/src/change.c
+++ b/src/change.c
@@ -574,8 +574,7 @@ changed_common(
                            && wp->w_topline < lnume
                            && win_linetabsize(wp, wp->w_topline,
                                        ml_get(wp->w_topline), (colnr_T)MAXCOL)
-                                   <= wp->w_skipcol + sms_marker_overlap(wp,
-                                       win_col_off(wp) - win_col_off2(wp)))))
+                                   <= wp->w_skipcol + sms_marker_overlap(wp, 
-1))))
                wp->w_skipcol = 0;
 
            // Check if a change in the buffer has invalidated the cached
diff --git a/src/move.c b/src/move.c
index 25f419e5a..6bd9aa846 100644
--- a/src/move.c
+++ b/src/move.c
@@ -197,13 +197,15 @@ redraw_for_cursorcolumn(win_T *wp)
  * Calculates how much the 'listchars' "precedes" or 'smoothscroll' "<<<"
  * marker overlaps with buffer text for window "wp".
  * Parameter "extra2" should be the padding on the 2nd line, not the first
- * line.
+ * line. When "extra2" is -1 calculate the padding.
  * Returns the number of columns of overlap with buffer text, excluding the
  * extra padding on the ledge.
  */
      int
 sms_marker_overlap(win_T *wp, int extra2)
 {
+    if (extra2 == -1)
+       extra2 = win_col_off(wp) - win_col_off2(wp);
 #if defined(FEAT_LINEBREAK)
     // There is no marker overlap when in showbreak mode, thus no need to
     // account for it.  See wlv_screen_line().
@@ -340,12 +342,12 @@ update_topline(void)
                                 && curwin->w_cursor.lnum == curwin->w_topline)
            {
                colnr_T vcol;
+               int overlap;
 
                // Check that the cursor position is visible.  Add columns for
                // the marker displayed in the top-left if needed.
                getvvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
-               int overlap = sms_marker_overlap(curwin, curwin_col_off()
-                                                       - curwin_col_off2());
+               overlap = sms_marker_overlap(curwin, -1);
                if (curwin->w_skipcol + overlap > vcol)
                    check_topline = TRUE;
            }
@@ -1854,6 +1856,9 @@ scrollup(
                    curwin->w_topfill = diff_check_fill(curwin, lnum);
 # endif
                    curwin->w_skipcol = 0;
+                   // Adjusting the cursor later should not adjust skipcol:
+                   // bring it to the first screenline on this new topline.
+                   curwin->w_curswant %= width1;
                    if (todo > 1 && do_sms)
                        size = linetabsize(curwin, curwin->w_topline);
                }
@@ -1971,8 +1976,7 @@ adjust_skipcol(void)
     }
 
     validate_virtcol();
-    int overlap = sms_marker_overlap(curwin,
-                                        curwin_col_off() - curwin_col_off2());
+    int overlap = sms_marker_overlap(curwin, -1);
     while (curwin->w_skipcol > 0
            && curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols)
     {
@@ -2486,6 +2490,7 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
                    {
                        int plines_offset = used + loff.height
                                                            - curwin->w_height;
+                       int overlap = sms_marker_overlap(curwin, -1);
                        used = curwin->w_height;
 #ifdef FEAT_DIFF
                        curwin->w_topfill = loff.fill;
@@ -2493,6 +2498,7 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
                        curwin->w_topline = loff.lnum;
                        curwin->w_skipcol = skipcol_from_plines(
                                                        curwin, plines_offset);
+                       curwin->w_cursor.col = curwin->w_skipcol + overlap;
                        set_skipcol = TRUE;
                    }
                }
@@ -2503,6 +2509,8 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
            curwin->w_topfill = loff.fill;
 #endif
        }
+       if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+           curwin->w_topline = curbuf->b_ml.ml_line_count;
        set_empty_rows(curwin, used);
        curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
        if (curwin->w_topline != old_topline
@@ -3087,19 +3095,66 @@ static int get_scroll_overlap(int dir)
 }
 
 /*
- * Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD)
- * and update the screen.
+ * Scroll "count" lines with 'smoothscroll' in direction "dir". Adjust "count"
+ * when scrolling more than "count" and return TRUE when scrolling happened.
+ */
+static int scroll_with_sms(int dir, long *count)
+{
+    int                prev_sms = curwin->w_p_sms;
+    colnr_T    prev_skipcol = curwin->w_skipcol;
+    linenr_T   prev_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+    int                prev_topfill = curwin->w_topfill;
+#endif
+
+    curwin->w_p_sms = TRUE;
+    scroll_redraw(dir == FORWARD, *count);
+
+    // Not actually smoothscrolling but ended up with partially visible line.
+    // Continue scrolling and update "count" so that cursor can be moved
+    // accordingly for half-page scrolling.
+    if (!prev_sms && curwin->w_skipcol > 0)
+    {
+       int fixdir = dir;
+       // Reverse the scroll direction when topline already changed. One line
+       // extra for scrolling backward so that consuming skipcol is symmetric.
+       if (labs(curwin->w_topline - prev_topline) > (dir == BACKWARD))
+           fixdir = dir * -1;
+       validate_cursor();
+       while (curwin->w_skipcol > 0
+           && curwin->w_topline < curbuf->b_ml.ml_line_count)
+       {
+           scroll_redraw(fixdir == FORWARD, 1);
+           *count += (fixdir == dir ? 1 : -1);
+       }
+    }
+    curwin->w_p_sms = prev_sms;
+
+    return curwin->w_topline == prev_topline
+#ifdef FEAT_DIFF
+       && curwin->w_topfill == prev_topfill
+#endif
+       && curwin->w_skipcol == prev_skipcol;
+}
+
+/*
+ * Move screen "count" (half) pages up ("dir" is BACKWARD) or down ("dir" is
+ * FORWARD) and update the screen. Handle moving the cursor and not scrolling
+ * to reveal end of buffer lines for half-page scrolling with CTRL-D and 
CTRL-U.
  *
  * Return FAIL for failure, OK otherwise.
  */
     int
 pagescroll(int dir, long count, int half)
 {
-#ifdef FEAT_DIFF
-    int                prev_topfill = curwin->w_topfill;
-#endif
-    linenr_T   prev_topline = curwin->w_topline;
-    colnr_T    prev_skipcol = curwin->w_skipcol;
+    int                nochange = TRUE;
+    int                buflen = curbuf->b_ml.ml_line_count;
+    colnr_T    prev_col = curwin->w_cursor.col;
+    colnr_T    prev_curswant = curwin->w_curswant;
+    linenr_T   prev_lnum = curwin->w_cursor.lnum;
+    oparg_T    oa = { 0 };
+    cmdarg_T   ca = { 0 };
+    ca.oap = &oa;
 
     if (half)
     {
@@ -3107,54 +3162,61 @@ pagescroll(int dir, long count, int half)
        if (count)
            curwin->w_p_scr = MIN(curwin->w_height, count);
        count = MIN(curwin->w_height, curwin->w_p_scr);
-    }
-    else
-       // Scroll 'window' or current window height lines.
-       count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) ?
-                                           p_window - 2 : 
get_scroll_overlap(dir));
 
-    if (curwin->w_p_sms)
-       scroll_redraw(dir == FORWARD, count);
-    else
-    {
-       // Scroll at least one full line without 'smoothscroll'.
-#ifdef FEAT_DIFF
-       count -= plines_nofill(curwin->w_topline);
-#else
-       count -= plines(curwin->w_topline);
-#endif
-       scroll_redraw(dir == FORWARD, 1);
+       // Don't scroll if we already know that it will reveal end of buffer 
lines.
+       if (dir == BACKWARD
+           || (curwin->w_botline - 1 < buflen)
+           || (curwin->w_p_sms && curwin->w_botline - 1 == buflen
+               && curwin->w_skipcol < linetabsize(curwin, buflen)))
+       {
+           nochange = scroll_with_sms(dir, &count);
+           validate_botline();
+           // Hide any potentially revealed end of buffer lines.
+           if (!nochange && curwin->w_botline - 1 == buflen)
+           {
+               curwin->w_cursor.lnum = buflen;
+               scroll_cursor_bot(0, TRUE);
+           }
+       }
 
-       // Temporarily set 'smoothscroll' so that scrolling count lines
-       // does not skip over parts of the buffer with wrapped lines.
-       curwin->w_p_sms = TRUE;
-       if (count > 0)
-           scroll_redraw(dir == FORWARD, count);
-       curwin->w_p_sms = FALSE;
-    }
+       // Move the cursor "count" screen lines.
+       curwin->w_curswant = MAXCOL;
+       curwin->w_cursor.col = prev_col;
+       curwin->w_cursor.lnum = prev_lnum;
+       if (curwin->w_p_wrap)
+           nv_screengo(&oa, dir, count);
+       else if (dir == FORWARD)
+           cursor_down_inner(curwin, count);
+       else
+           cursor_up_inner(curwin, count);
+       curwin->w_curswant = prev_curswant;
+
+       if (get_scrolloff_value())
+           cursor_correct();
 #ifdef FEAT_FOLDING
        // Move cursor to first line of closed fold.
        foldAdjustCursor();
 #endif
 
-    int nochange = curwin->w_topline == prev_topline
-#ifdef FEAT_DIFF
-       && curwin->w_topfill == prev_topfill
-#endif
-       && curwin->w_skipcol == prev_skipcol;
-
-    // Error if the viewport did not change and the cursor is already
-    // at the boundary.
-    if (nochange)
+       nochange = nochange
+           && prev_col == curwin->w_cursor.col
+           && prev_lnum == curwin->w_cursor.lnum;
+    }
+    else
     {
-       int prev_cursor = curwin->w_cursor.lnum;
-       curwin->w_cursor.lnum += (count + 1) * (dir == FORWARD ? 1 : -1);
-       check_cursor();
-       if (curwin->w_cursor.lnum == prev_cursor)
-           beep_flush();
+       // Scroll [count] times 'window' or current window height lines.
+       count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) ?
+                               MAX(1, p_window - 2) : get_scroll_overlap(dir));
+       nochange = scroll_with_sms(dir, &count);
     }
-    else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol)
+
+    // Error if both the viewport and cursor did not change.
+    if (nochange)
+       beep_flush();
+    else if (!curwin->w_p_sms)
        beginline(BL_SOL | BL_FIX);
+    else if (p_sol)
+       nv_g_home_m_cmd(&ca);
 
     return nochange;
 }
diff --git a/src/normal.c b/src/normal.c
index 83b74ccc6..955cd365a 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -2303,7 +2303,7 @@ find_decl(
  *
  * Return OK if able to move cursor, FAIL otherwise.
  */
-    static int
+    int
 nv_screengo(oparg_T *oap, int dir, long dist)
 {
 
@@ -5745,7 +5745,7 @@ nv_gv_cmd(cmdarg_T *cap)
  * "g0", "g^" : Like "0" and "^" but for screen lines.
  * "gm": middle of "g0" and "g$".
  */
-    static void
+    void
 nv_g_home_m_cmd(cmdarg_T *cap)
 {
     int                i;
@@ -5771,6 +5771,15 @@ nv_g_home_m_cmd(cmdarg_T *cap)
        i = 0;
        if (virtcol >= (colnr_T)width1 && width2 > 0)
            i = (virtcol - width1) / width2 * width2 + width1;
+
+       // When ending up below 'smoothscroll' marker, move just beyond it so
+       // that skipcol is not adjusted later.
+       if (curwin->w_skipcol > 0 && curwin->w_cursor.lnum == curwin->w_topline)
+       {
+           int overlap = sms_marker_overlap(curwin, -1);
+           if (overlap > 0 && i == curwin->w_skipcol)
+               i += overlap;
+       }
     }
     else
        i = curwin->w_leftcol;
@@ -7263,8 +7272,9 @@ nv_at(cmdarg_T *cap)
     static void
 nv_halfpage(cmdarg_T *cap)
 {
+    int        dir = cap->cmdchar == Ctrl_D ? FORWARD : BACKWARD;
     if (!checkclearop(cap->oap))
-       pagescroll(cap->cmdchar == Ctrl_D, cap->count0, TRUE);
+       pagescroll(dir, cap->count0, TRUE);
 }
 
 /*
diff --git a/src/proto/normal.pro b/src/proto/normal.pro
index eff08dfa8..afa079930 100644
--- a/src/proto/normal.pro
+++ b/src/proto/normal.pro
@@ -22,6 +22,8 @@ void pop_showcmd(void);
 void do_check_scrollbind(int check);
 void check_scrollbind(linenr_T topline_diff, long leftcol_diff);
 int find_decl(char_u *ptr, int len, int locally, int thisblock, int flags_arg);
+void nv_g_home_m_cmd(cmdarg_T *cap);
+int nv_screengo(oparg_T *oap, int dir, long dist);
 void nv_scroll_line(cmdarg_T *cap);
 void scroll_redraw(int up, long count);
 void handle_tabmenu(void);
diff --git a/src/testdir/dumps/Test_cursorline_redraw_2.dump 
b/src/testdir/dumps/Test_cursorline_redraw_2.dump
index d1b4e4e17..323bef8e2 100644
--- a/src/testdir/dumps/Test_cursorline_redraw_2.dump
+++ b/src/testdir/dumps/Test_cursorline_redraw_2.dump
@@ -1,20 +1,20 @@
-|T+0&#ffffff0|h|e| |{|o|p|t|i|o|n|}| |a|r|g|u|m|e|n|t|s| |t|o| |"|:|s|e|t|"| 
|m|a|y| |b|e| 
+| +0&#ffffff0@39
+|T|h|e| |{|o|p|t|i|o|n|}| |a|r|g|u|m|e|n|t|s| |t|o| |"|:|s|e|t|"| |m|a|y| 
|b|e| 
 |r|e|p|e|a|t|e|d|.| @1|F|o|r| |e|x|a|m|p|l|e|:| |>| @14
-@8|:|s|e|t| |a|i| |n|o|s|i| |s|w|=|3| |t|s|=|3| @9
-|I|f| |y|o|u| |m|a|k|e| |a|n| |e|r@1|o|r| |i|n| |o|n|e| |o|f| |t|h|e| 
|a|r|g|u|m
+| +8&&@7>:|s|e|t| |a|i| |n|o|s|i| |s|w|=|3| |t|s|=|3| @9
+|I+0&&|f| |y|o|u| |m|a|k|e| |a|n| |e|r@1|o|r| |i|n| |o|n|e| |o|f| |t|h|e| 
|a|r|g|u|m
 |e|n|t|s|,| |a|n| |e|r@1|o|r| |m|e|s@1|a|g|e| |w|i|l@1| |b|e| |g|i|v|e|n| @3
 |a|n|d| |t|h|e| |f|o|l@1|o|w|i|n|g| |a|r|g|u|m|e|n|t|s| |w|i|l@1| |b|e| 
|i|g|n|o
 |r|e|d|.| @35
 @40
 @40
 @16|*|:|s|e|t|-|v|e|r|b|o|s|e|*| @9
->W+8&&|h|e|n| |'|v|e|r|b|o|s|e|'| |i|s| |n|o|n|-|z|e|r|o|,| 
|d|i|s|p|l|a|y|i|n|g| |a
+|W|h|e|n| |'|v|e|r|b|o|s|e|'| |i|s| |n|o|n|-|z|e|r|o|,| |d|i|s|p|l|a|y|i|n|g| 
|a
 |n| |o|p|t|i|o|n| |v|a|l|u|e| |w|i|l@1| |a|l|s|o| |t|e|l@1| |w|h|e|r|e| |i|t| 
@1
-|w+0&&|a|s| |l|a|s|t| |s|e|t|.| @1|E|x|a|m|p|l|e|:| |>| @14
+|w|a|s| |l|a|s|t| |s|e|t|.| @1|E|x|a|m|p|l|e|:| |>| @14
 @8|:|v|e|r|b|o|s|e| |s|e|t| |s|h|i|f|t|w|i|d|t|h| |c|i|n|d|e|n|t|?
 |<| @1|s|h|i|f|t|w|i|d|t|h|=|4| |~| @22
 @10|L|a|s|t| |s|e|t| |f|r|o|m| |m|o|d|e|l|i|n|e| |l|i|n|e| |1| 
 |~| @38
 @2|c|i|n|d|e|n|t| |~| @28
-|@+0#4040ff13&@2| @36
-| +0#0000000&@21|1|2|,|1| @9|5|0|%| 
+@22|7|,|2|-|9| @8|4@1|%| 
diff --git a/src/testdir/dumps/Test_display_visual_block_scroll.dump 
b/src/testdir/dumps/Test_display_visual_block_scroll.dump
index 13aae592d..36eae0c02 100644
--- a/src/testdir/dumps/Test_display_visual_block_scroll.dump
+++ b/src/testdir/dumps/Test_display_visual_block_scroll.dump
@@ -1,7 +1,7 @@
 |{+0#0000001#a8a8a8255| | +0#0000000#ffffff0@72
->}+0&#40ffff15| +0#0000001#a8a8a8255| +0#0000000#ffffff0@72
-|{| @73
-|f| @73
-|g| @73
+|}+0#0000001#a8a8a8255| | +0#0000000#ffffff0@72
+|{+0#0000001#a8a8a8255| | +0#0000000#ffffff0@72
+|f+0#0000001#a8a8a8255| | +0#0000000#ffffff0@72
+>g| +0#0000001#a8a8a8255| +0#0000000#ffffff0@72
 |}| @73
-|-+2&&@1| |V|I|S|U|A|L| |L|I|N|E| |-@1| +0&&@29|4| @8|8|,|1| @10|B|o|t| 
+|-+2&&@1| |V|I|S|U|A|L| |L|I|N|E| |-@1| +0&&@29|7| @8|1@1|,|1| @9|B|o|t| 
diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim
index 344571fc1..b8d0057a1 100644
--- a/src/testdir/test_diffmode.vim
+++ b/src/testdir/test_diffmode.vim
@@ -1679,8 +1679,7 @@ func Test_diff_scroll_many_filler()
   endfor
 
   set smoothscroll&
-  bwipe!
-  bwipe!
+  %bwipe!
 endfunc
 
 " This was trying to update diffs for a buffer being closed
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
index 5e3e9cbe1..cdf20976e 100644
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -1302,7 +1302,7 @@ func Test_edit_PAGEUP_PAGEDOWN()
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
   call assert_equal([0, 10, 1, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 2, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   " <S-Up> is the same as <PageUp>
   " <S-Down> is the same as <PageDown>
   call cursor(1, 1)
@@ -1325,7 +1325,7 @@ func Test_edit_PAGEUP_PAGEDOWN()
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
   call assert_equal([0, 10, 1, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 2, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   set nostartofline
   call cursor(30, 11)
   norm! zt
@@ -1338,7 +1338,7 @@ func Test_edit_PAGEUP_PAGEDOWN()
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
   call assert_equal([0, 10, 11, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 2, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   call cursor(1, 1)
   call feedkeys("A\<PageDown>\<esc>", 'tnix')
   call assert_equal([0, 9, 11, 0], getpos('.'))
@@ -1363,7 +1363,7 @@ func Test_edit_PAGEUP_PAGEDOWN()
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
   call assert_equal([0, 10, 11, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 2, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   call cursor(1, 1)
   call feedkeys("A\<S-Down>\<esc>", 'tnix')
   call assert_equal([0, 9, 11, 0], getpos('.'))
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index 14440fb69..1acdfcecb 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -1280,13 +1280,9 @@ func Test_vert_scroll_cmds()
   exe "normal \<C-D>"
   call assert_equal(46, line('.'))
   exe "normal \<C-U>"
-  call assert_equal(36, line('w0'))
-  call assert_equal(46, line('.'))
-  exe "normal \<C-U>"
-  call assert_equal(1,  line('w0'))
-  call assert_equal(40, line('.'))
+  call assert_equal(36, line('.'))
   exe "normal \<C-U>"
-  call assert_equal(30, line('.'))
+  call assert_equal(1, line('.'))
   exe "normal \<C-U>"
   call assert_equal(1, line('.'))
   set scroll&
@@ -1307,8 +1303,9 @@ func Test_vert_scroll_cmds()
   call assert_equal(50, line('.'))
   call assert_equal(100, line('w$'))
   normal z.
+  let lnum = winline()
   exe "normal \<C-D>"
-  call assert_equal(1, winline())
+  call assert_equal(lnum, winline())
   call assert_equal(50, line('.'))
   normal zt
   exe "normal \<C-D>"
@@ -3069,8 +3066,7 @@ func Test_normal42_halfpage()
   call assert_equal(2, &scroll)
   set scroll=5
   exe "norm! \<c-u>"
-  call assert_equal('3', getline('w0'))
-  call assert_equal('8', getline('.'))
+  call assert_equal('3', getline('.'))
   1
   set scrolloff=5
   exe "norm! \<c-d>"
@@ -3818,7 +3814,7 @@ func Test_normal_vert_scroll_longline()
   call assert_equal(1, winline())
   exe "normal \<C-B>"
   call assert_equal(10, line('.'))
-  call assert_equal(10, winline())
+  call assert_equal(4, winline())
   exe "normal \<C-B>\<C-B>"
   call assert_equal(5, line('.'))
   call assert_equal(5, winline())
diff --git a/src/testdir/test_scroll_opt.vim b/src/testdir/test_scroll_opt.vim
index d7a79076d..dd2af0125 100644
--- a/src/testdir/test_scroll_opt.vim
+++ b/src/testdir/test_scroll_opt.vim
@@ -552,11 +552,11 @@ func Test_smoothscroll_cursor_position()
   " Test "g0/g<Home>"
   exe "normal gg\<C-E>"
   norm $gkg0
-  call s:check_col_calc(1, 2, 21)
+  call s:check_col_calc(4, 1, 24)
 
   " Test moving the cursor behind the <<< display with 'virtualedit'
   set virtualedit=all
-  exe "normal \<C-E>3lgkh"
+  exe "normal \<C-E>gkh"
   call s:check_col_calc(3, 2, 23)
   set virtualedit&
 
@@ -1017,26 +1017,72 @@ func Test_smoothscroll_page()
   exe "norm! \<C-B>"
   call assert_equal(0, winsaveview().skipcol)
 
-  exe "norm! \<C-D>"
+  " Half-page scrolling does not go beyond end of buffer and moves the cursor.
+  exe "norm! 0\<C-D>"
   call assert_equal(200, winsaveview().skipcol)
+  call assert_equal(204, col('.'))
   exe "norm! \<C-D>"
   call assert_equal(400, winsaveview().skipcol)
+  call assert_equal(404, col('.'))
   exe "norm! \<C-D>"
-  call assert_equal(600, winsaveview().skipcol)
+  call assert_equal(520, winsaveview().skipcol)
+  call assert_equal(601, col('.'))
   exe "norm! \<C-D>"
-  call assert_equal(800, winsaveview().skipcol)
-  exe "norm! \<C-D>"
-  call assert_equal(880, winsaveview().skipcol)
+  call assert_equal(520, winsaveview().skipcol)
+  call assert_equal(801, col('.'))
   exe "norm! \<C-U>"
-  call assert_equal(680, winsaveview().skipcol)
+  call assert_equal(520, winsaveview().skipcol)
+  call assert_equal(601, col('.'))
   exe "norm! \<C-U>"
-  call assert_equal(480, winsaveview().skipcol)
-  exe "norm! \<C-U>"
-  call assert_equal(280, winsaveview().skipcol)
+  call assert_equal(400, winsaveview().skipcol)
+  call assert_equal(404, col('.'))
   exe "norm! \<C-U>"
-  call assert_equal(80, winsaveview().skipcol)
+  call assert_equal(200, winsaveview().skipcol)
+  call assert_equal(204, col('.'))
   exe "norm! \<C-U>"
   call assert_equal(0, winsaveview().skipcol)
+  call assert_equal(1, col('.'))
+
+  bwipe!
+endfunc
+
+func Test_smoothscroll_next_topline()
+  call NewWindow(10, 40)
+  setlocal smoothscroll
+  call setline(1, ['abcde '->repeat(150)]->repeat(2))
+
+  " Scrolling a screenline that causes the cursor to move to the next buffer
+  " line should not skip part of that line to bring the cursor into view.
+  exe "norm! 22\<C-E>"
+  call assert_equal(880, winsaveview().skipcol)
+  exe "norm! \<C-E>"
+  redraw
+  call assert_equal(0, winsaveview().skipcol)
+
+  " Cursor in correct place when not in the first screenline of a buffer line.
+  exe "norm! gg4gj20\<C-D>\<C-D>"
+  redraw
+  call assert_equal(2, line('w0'))
+
+  bwipe!
+endfunc
+
+func Test_smoothscroll_long_line_zb()
+  call NewWindow(10, 40)
+  call setline(1, 'abcde '->repeat(150))
+
+  " Also works without 'smoothscroll' when last line of buffer doesn't fit.
+  " Used to set topline to buffer line count plus one, causing an empty screen.
+  norm zb
+  redraw
+  call assert_equal(1, winsaveview().topline)
+
+  " Moving cursor to bottom works on line that doesn't fit with 'smoothscroll'.
+  " Skipcol was adjusted later for cursor being on not visible part of line.
+  setlocal smoothscroll
+  norm zb
+  redraw
+  call assert_equal(520, winsaveview().skipcol)
 
   bwipe!
 endfunc
diff --git a/src/version.c b/src/version.c
index 0e5492626..9373a2958 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    258,
 /**/
     257,
 /**/

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1rrjMc-004OYu-ER%40256bit.org.

Raspunde prin e-mail lui