Mercurial > vim
diff src/move.c @ 34761:b20609f4ab37 v9.1.0258
patch 9.1.0258: half-page scrolling broke backward compatibility
Commit: https://github.com/vim/vim/commit/cb204e688e5c9d56a78b621ef27c35d91860cb09
Author: Luuk van Baal <luukvbaal@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 <luukvbaal@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 02 Apr 2024 21:00:06 +0200 |
parents | ca2da8e8fb53 |
children | be09936c20c7 |
line wrap: on
line diff
--- 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 se { 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 se 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 se 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; + nochange = nochange + && prev_col == curwin->w_cursor.col + && prev_lnum == curwin->w_cursor.lnum; + } + else + { + // 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); + } - // Error if the viewport did not change and the cursor is already - // at the boundary. + // Error if both the viewport and cursor did not change. if (nochange) - { - 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(); - } - else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol) + 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; }