diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 02:10:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 02:10:59 +0000 |
commit | cccb21df3b4c6fe0aaa99743c418aa973aeebad0 (patch) | |
tree | 35a2d1f88d47e930fec425da1c1cb89b3ccae6e0 /src/move.c | |
parent | Releasing progress-linux version 2:9.1.0199-1~progress7.99u1. (diff) | |
download | vim-cccb21df3b4c6fe0aaa99743c418aa973aeebad0.tar.xz vim-cccb21df3b4c6fe0aaa99743c418aa973aeebad0.zip |
Merging upstream version 2:9.1.0374.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/move.c')
-rw-r--r-- | src/move.c | 900 |
1 files changed, 299 insertions, 601 deletions
@@ -59,7 +59,7 @@ adjust_plines_for_skipcol(win_T *wp) * the window height. */ static int -plines_correct_topline(win_T *wp, linenr_T lnum) +plines_correct_topline(win_T *wp, linenr_T lnum, int limit_winheight) { int n; #ifdef FEAT_DIFF @@ -70,7 +70,7 @@ plines_correct_topline(win_T *wp, linenr_T lnum) n = plines_win(wp, lnum, FALSE); if (lnum == wp->w_topline) n -= adjust_plines_for_skipcol(wp); - if (n > wp->w_height) + if (limit_winheight && n > wp->w_height) n = wp->w_height; return n; } @@ -119,7 +119,7 @@ comp_botline(win_T *wp) else #endif { - n = plines_correct_topline(wp, lnum); + n = plines_correct_topline(wp, lnum, TRUE); } if ( #ifdef FEAT_FOLDING @@ -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; } @@ -676,6 +678,19 @@ changed_window_setting_buf(buf_T *buf) #endif /* + * Call changed_window_setting_win() for every window. + */ + void +changed_window_setting_all(void) +{ + tabpage_T *tp; + win_T *wp; + + FOR_ALL_TAB_WINDOWS(tp, wp) + changed_window_setting_win(wp); +} + +/* * Set wp->w_topline to a certain number. */ void @@ -919,7 +934,7 @@ curs_rows(win_T *wp) else #endif { - wp->w_cline_row += plines_correct_topline(wp, lnum); + wp->w_cline_row += plines_correct_topline(wp, lnum, TRUE); ++lnum; } } @@ -1600,6 +1615,127 @@ f_virtcol2col(typval_T *argvars UNUSED, typval_T *rettv) #endif /* + * Make sure the cursor is in the visible part of the topline after scrolling + * the screen with 'smoothscroll'. + */ +static void cursor_correct_sms(void) +{ + if (!curwin->w_p_sms ||!curwin->w_p_wrap + || curwin->w_cursor.lnum != curwin->w_topline) + return; + + long so = get_scrolloff_value(); + int width1 = curwin->w_width - curwin_col_off(); + int width2 = width1 + curwin_col_off2(); + int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2; + int space_cols = (curwin->w_height - 1) * width2; + int size = so == 0 ? 0 : win_linetabsize(curwin, curwin->w_topline, + ml_get(curwin->w_topline), (colnr_T)MAXCOL); + + if (curwin->w_topline == 1 && curwin->w_skipcol == 0) + so_cols = 0; // Ignore 'scrolloff' at top of buffer. + else if (so_cols > space_cols / 2) + so_cols = space_cols / 2; // Not enough room: put cursor in the middle. + + // Not enough screen lines in topline: ignore 'scrolloff'. + while (so_cols > size && so_cols - width2 >= width1) + so_cols -= width2; + if (so_cols >= width1 && so_cols > size) + so_cols -= width1; + + // If there is no marker or we have non-zero scrolloff, just ignore it. + int overlap = (curwin->w_skipcol == 0 || so_cols != 0) ? 0 + : sms_marker_overlap(curwin, -1); + int top = curwin->w_skipcol + overlap + so_cols; + int bot = curwin->w_skipcol + width1 + (curwin->w_height - 1) * width2 + - so_cols; + validate_virtcol(); + colnr_T col = curwin->w_virtcol; + + if (col < top) + { + if (col < width1) + col += width1; + while (width2 > 0 && col < top) + col += width2; + } + else + while (width2 > 0 && col >= bot) + col -= width2; + + if (col != curwin->w_virtcol) + { + curwin->w_curswant = col; + coladvance(curwin->w_curswant); + // validate_virtcol() marked various things as valid, but after + // moving the cursor they need to be recomputed + curwin->w_valid &= + ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); + } +} + +/* + * Scroll "count" lines up or down, and redraw. + */ + void +scroll_redraw(int up, long count) +{ + linenr_T prev_topline = curwin->w_topline; + int prev_skipcol = curwin->w_skipcol; +#ifdef FEAT_DIFF + int prev_topfill = curwin->w_topfill; +#endif + linenr_T prev_lnum = curwin->w_cursor.lnum; + + if (up) + scrollup(count, TRUE); + else + scrolldown(count, TRUE); + if (get_scrolloff_value() > 0) + { + // Adjust the cursor position for 'scrolloff'. Mark w_topline as + // valid, otherwise the screen jumps back at the end of the file. + cursor_correct(); + check_cursor_moved(curwin); + curwin->w_valid |= VALID_TOPLINE; + + // If moved back to where we were, at least move the cursor, otherwise + // we get stuck at one position. Don't move the cursor up if the + // first line of the buffer is already on the screen + while (curwin->w_topline == prev_topline + && curwin->w_skipcol == prev_skipcol +#ifdef FEAT_DIFF + && curwin->w_topfill == prev_topfill +#endif + ) + { + if (up) + { + if (curwin->w_cursor.lnum > prev_lnum + || cursor_down(1L, FALSE) == FAIL) + break; + } + else + { + if (curwin->w_cursor.lnum < prev_lnum + || prev_topline == 1L + || cursor_up(1L, FALSE) == FAIL) + break; + } + // Mark w_topline as valid, otherwise the screen jumps back at the + // end of the file. + check_cursor_moved(curwin); + curwin->w_valid |= VALID_TOPLINE; + } + } + + cursor_correct_sms(); + if (curwin->w_cursor.lnum != prev_lnum) + coladvance(curwin->w_curswant); + redraw_later(UPD_VALID); +} + +/* * Scroll the current window down by "line_count" logical lines. "CTRL-Y" */ void @@ -1744,35 +1880,8 @@ scrolldown( #endif coladvance(curwin->w_curswant); } - - if (curwin->w_cursor.lnum == curwin->w_topline && do_sms) - { - long so = get_scrolloff_value(); - int scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; - - // make sure the cursor is in the visible text - validate_virtcol(); - int col = curwin->w_virtcol - curwin->w_skipcol + scrolloff_cols; - int row = 0; - if (col >= width1) - { - col -= width1; - ++row; - } - if (col > width2 && width2 > 0) - { - row += col / width2; - // even so col is not used anymore, - // make sure it is correct, just in case - col = col % width2; - } - if (row >= curwin->w_height) - { - curwin->w_curswant = curwin->w_virtcol - - (row - curwin->w_height + 1) * width2; - coladvance(curwin->w_curswant); - } - } + if (curwin->w_cursor.lnum < curwin->w_topline) + curwin->w_cursor.lnum = curwin->w_topline; } /* @@ -1894,47 +2003,6 @@ scrollup( ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); coladvance(curwin->w_curswant); } - if (curwin->w_cursor.lnum == curwin->w_topline - && do_sms && curwin->w_skipcol > 0) - { - int col_off = curwin_col_off(); - int col_off2 = curwin_col_off2(); - - int width1 = curwin->w_width - col_off; - int width2 = width1 + col_off2; - int extra2 = col_off - col_off2; - long so = get_scrolloff_value(); - int scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; - int space_cols = (curwin->w_height - 1) * width2; - - // If we have non-zero scrolloff, just ignore the marker as we are - // going past it anyway. - int overlap = scrolloff_cols != 0 ? 0 - : sms_marker_overlap(curwin, extra2); - - // Make sure the cursor is in a visible part of the line, taking - // 'scrolloff' into account, but using screen lines. - // If there are not enough screen lines put the cursor in the middle. - if (scrolloff_cols > space_cols / 2) - scrolloff_cols = space_cols / 2; - validate_virtcol(); - if (curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) - { - colnr_T col = curwin->w_virtcol; - - if (col < width1) - col += width1; - while (col < curwin->w_skipcol + overlap + scrolloff_cols) - col += width2; - curwin->w_curswant = col; - coladvance(curwin->w_curswant); - - // validate_virtcol() marked various things as valid, but after - // moving the cursor they need to be recomputed - curwin->w_valid &= - ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); - } - } } /* @@ -1971,8 +2039,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) { @@ -2047,26 +2114,6 @@ check_topfill( } } } - -/* - * Use as many filler lines as possible for w_topline. Make sure w_topline - * is still visible. - */ - static void -max_topfill(void) -{ - int n; - - n = plines_nofill(curwin->w_topline); - if (n >= curwin->w_height) - curwin->w_topfill = 0; - else - { - curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline); - if (curwin->w_topfill + n > curwin->w_height) - curwin->w_topfill = curwin->w_height - n; - } -} #endif /* @@ -2269,38 +2316,6 @@ botline_forw(lineoff_T *lp) } } -#ifdef FEAT_DIFF -/* - * Switch from including filler lines below lp->lnum to including filler - * lines above loff.lnum + 1. This keeps pointing to the same line. - * When there are no filler lines nothing changes. - */ - static void -botline_topline(lineoff_T *lp) -{ - if (lp->fill > 0) - { - ++lp->lnum; - lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1; - } -} - -/* - * Switch from including filler lines above lp->lnum to including filler - * lines below loff.lnum - 1. This keeps pointing to the same line. - * When there are no filler lines nothing changes. - */ - static void -topline_botline(lineoff_T *lp) -{ - if (lp->fill > 0) - { - lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1; - --lp->lnum; - } -} -#endif - /* * Recompute topline to put the cursor at the top of the window. * Scroll at least "min_scroll" lines. @@ -2512,18 +2527,14 @@ scroll_cursor_bot(int min_scroll, int set_topbot) cln = curwin->w_cursor.lnum; if (set_topbot) { - int set_skipcol = FALSE; - used = 0; curwin->w_botline = cln + 1; + loff.lnum = cln + 1; #ifdef FEAT_DIFF loff.fill = 0; #endif - for (curwin->w_topline = curwin->w_botline; - curwin->w_topline > 1; - curwin->w_topline = loff.lnum) + while (TRUE) { - loff.lnum = curwin->w_topline; topline_back_winheight(&loff, FALSE); if (loff.height == MAXCOL) break; @@ -2545,27 +2556,28 @@ scroll_cursor_bot(int min_scroll, int set_topbot) curwin->w_topline = loff.lnum; curwin->w_skipcol = skipcol_from_plines( curwin, plines_offset); - set_skipcol = TRUE; } } break; } - used += loff.height; #ifdef FEAT_DIFF curwin->w_topfill = loff.fill; #endif + curwin->w_topline = loff.lnum; + used += loff.height; } + set_empty_rows(curwin, used); curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; if (curwin->w_topline != old_topline #ifdef FEAT_DIFF || curwin->w_topfill != old_topfill #endif - || set_skipcol + || curwin->w_skipcol != old_skipcol || curwin->w_skipcol != 0) { curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - if (set_skipcol) + if (curwin->w_skipcol != old_skipcol) redraw_later(UPD_NOT_VALID); else reset_skipcol(); @@ -2768,6 +2780,8 @@ scroll_cursor_bot(int min_scroll, int set_topbot) curwin->w_valid = old_valid; } curwin->w_valid |= VALID_TOPLINE; + + cursor_correct_sms(); } /* @@ -3077,508 +3091,192 @@ cursor_correct(void) curwin->w_valid |= VALID_TOPLINE; } -static void get_scroll_overlap(lineoff_T *lp, int dir); - -/* - * Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD) - * and update the screen. - * - * Return FAIL for failure, OK otherwise. - */ - int -onepage(int dir, long count) -{ - long n; - int retval = OK; - lineoff_T loff; - linenr_T old_topline = curwin->w_topline; - long so = get_scrolloff_value(); - - if (curbuf->b_ml.ml_line_count == 1) // nothing to do - { - beep_flush(); - return FAIL; - } - - for ( ; count > 0; --count) - { - validate_botline(); - /* - * It's an error to move a page up when the first line is already on - * the screen. It's an error to move a page down when the last line - * is on the screen and the topline is 'scrolloff' lines from the - * last line. - */ - if (dir == FORWARD - ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so) - && curwin->w_botline > curbuf->b_ml.ml_line_count) - : (curwin->w_topline == 1 -#ifdef FEAT_DIFF - && curwin->w_topfill == - diff_check_fill(curwin, curwin->w_topline) -#endif - )) - { - beep_flush(); - retval = FAIL; - break; - } - -#ifdef FEAT_DIFF - loff.fill = 0; -#endif - if (dir == FORWARD) - { - if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) - { - // Vi compatible scrolling - if (p_window <= 2) - ++curwin->w_topline; - else - curwin->w_topline += p_window - 2; - if (curwin->w_topline > curbuf->b_ml.ml_line_count) - curwin->w_topline = curbuf->b_ml.ml_line_count; - curwin->w_cursor.lnum = curwin->w_topline; - } - else if (curwin->w_botline > curbuf->b_ml.ml_line_count) - { - // at end of file - curwin->w_topline = curbuf->b_ml.ml_line_count; -#ifdef FEAT_DIFF - curwin->w_topfill = 0; -#endif - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - } - else - { - // For the overlap, start with the line just below the window - // and go upwards. - loff.lnum = curwin->w_botline; -#ifdef FEAT_DIFF - loff.fill = diff_check_fill(curwin, loff.lnum) - - curwin->w_filler_rows; -#endif - get_scroll_overlap(&loff, -1); - curwin->w_topline = loff.lnum; -#ifdef FEAT_DIFF - curwin->w_topfill = loff.fill; - check_topfill(curwin, FALSE); -#endif - curwin->w_cursor.lnum = curwin->w_topline; - curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW| - VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); - } - } - else // dir == BACKWARDS - { -#ifdef FEAT_DIFF - if (curwin->w_topline == 1) - { - // Include max number of filler lines - max_topfill(); - continue; - } -#endif - if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) - { - // Vi compatible scrolling (sort of) - if (p_window <= 2) - --curwin->w_topline; - else - curwin->w_topline -= p_window - 2; - if (curwin->w_topline < 1) - curwin->w_topline = 1; - curwin->w_cursor.lnum = curwin->w_topline + p_window - 1; - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - continue; - } - - // Find the line at the top of the window that is going to be the - // line at the bottom of the window. Make sure this results in - // the same line as before doing CTRL-F. - loff.lnum = curwin->w_topline - 1; -#ifdef FEAT_DIFF - loff.fill = diff_check_fill(curwin, loff.lnum + 1) - - curwin->w_topfill; -#endif - get_scroll_overlap(&loff, 1); - - if (loff.lnum >= curbuf->b_ml.ml_line_count) - { - loff.lnum = curbuf->b_ml.ml_line_count; -#ifdef FEAT_DIFF - loff.fill = 0; - } - else - { - botline_topline(&loff); -#endif - } - curwin->w_cursor.lnum = loff.lnum; - - // Find the line just above the new topline to get the right line - // at the bottom of the window. - n = 0; - while (n <= curwin->w_height && loff.lnum >= 1) - { - topline_back(&loff); - if (loff.height == MAXCOL) - n = MAXCOL; - else - n += loff.height; - } - if (loff.lnum < 1) // at begin of file - { - curwin->w_topline = 1; -#ifdef FEAT_DIFF - max_topfill(); -#endif - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } - else - { - // Go two lines forward again. -#ifdef FEAT_DIFF - topline_botline(&loff); -#endif - botline_forw(&loff); - botline_forw(&loff); -#ifdef FEAT_DIFF - botline_topline(&loff); -#endif -#ifdef FEAT_FOLDING - // We're at the wrong end of a fold now. - (void)hasFolding(loff.lnum, &loff.lnum, NULL); -#endif - - // Always scroll at least one line. Avoid getting stuck on - // very long lines. - if (loff.lnum >= curwin->w_topline -#ifdef FEAT_DIFF - && (loff.lnum > curwin->w_topline - || loff.fill >= curwin->w_topfill) -#endif - ) - { -#ifdef FEAT_DIFF - // First try using the maximum number of filler lines. If - // that's not enough, backup one line. - loff.fill = curwin->w_topfill; - if (curwin->w_topfill < diff_check_fill(curwin, - curwin->w_topline)) - max_topfill(); - if (curwin->w_topfill == loff.fill) -#endif - { - --curwin->w_topline; -#ifdef FEAT_DIFF - curwin->w_topfill = 0; -#endif - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - } - comp_botline(curwin); - curwin->w_cursor.lnum = curwin->w_botline - 1; - curwin->w_valid &= - ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW); - } - else - { - curwin->w_topline = loff.lnum; -#ifdef FEAT_DIFF - curwin->w_topfill = loff.fill; - check_topfill(curwin, FALSE); -#endif - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } - } - } - } -#ifdef FEAT_FOLDING - foldAdjustCursor(); -#endif - cursor_correct(); - check_cursor_col(); - if (retval == OK) - beginline(BL_SOL | BL_FIX); - curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL); - - if (retval == OK && dir == FORWARD) - { - // Avoid the screen jumping up and down when 'scrolloff' is non-zero. - // But make sure we scroll at least one line (happens with mix of long - // wrapping lines and non-wrapping line). - if (check_top_offset()) - { - scroll_cursor_top(1, FALSE); - if (curwin->w_topline <= old_topline - && old_topline < curbuf->b_ml.ml_line_count) - { - curwin->w_topline = old_topline + 1; -#ifdef FEAT_FOLDING - (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); -#endif - } - } -#ifdef FEAT_FOLDING - else if (curwin->w_botline > curbuf->b_ml.ml_line_count) - (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); -#endif - } - - redraw_later(UPD_VALID); - return retval; -} - /* * Decide how much overlap to use for page-up or page-down scrolling. * This is symmetric, so that doing both keeps the same lines displayed. * Three lines are examined: * - * before CTRL-F after CTRL-F / before CTRL-B - * etc. l1 - * l1 last but one line ------------ - * l2 last text line l2 top text line - * ------------- l3 second text line - * l3 etc. + * before CTRL-F after CTRL-F / before CTRL-B + * etc. l1 + * l1 last but one line ------------ + * l2 last text line l2 top text line + * ------------- l3 second text line + * l3 etc. */ - static void -get_scroll_overlap(lineoff_T *lp, int dir) +static int get_scroll_overlap(int dir) { - int h1, h2, h3, h4; - int min_height = curwin->w_height - 2; - lineoff_T loff0, loff1, loff2; + lineoff_T loff; + int min_height = curwin->w_height - 2; + validate_botline(); + if ((dir == BACKWARD && curwin->w_topline == 1) + || (dir == FORWARD && curwin->w_botline > curbuf->b_ml.ml_line_count)) + return min_height + 2; // no overlap, still handle 'smoothscroll' + + loff.lnum = dir == FORWARD ? curwin->w_botline : curwin->w_topline - 1; #ifdef FEAT_DIFF - if (lp->fill > 0) - lp->height = 1; - else - lp->height = plines_nofill(lp->lnum); + loff.fill = diff_check_fill(curwin, loff.lnum + (dir == BACKWARD)) + - (dir == FORWARD ? curwin->w_filler_rows : curwin->w_topfill); + loff.height = loff.fill > 0 ? 1 : plines_nofill(loff.lnum); #else - lp->height = plines(lp->lnum); + loff.height = plines(loff.lnum); #endif - h1 = lp->height; - if (h1 > min_height) - return; // no overlap - loff0 = *lp; - if (dir > 0) - botline_forw(lp); + int h1 = loff.height; + if (h1 > min_height) + return min_height + 2; // no overlap + if (dir == FORWARD) + topline_back(&loff); else - topline_back(lp); - h2 = lp->height; - if (h2 == MAXCOL || h2 + h1 > min_height) - { - *lp = loff0; // no overlap - return; - } + botline_forw(&loff); - loff1 = *lp; - if (dir > 0) - botline_forw(lp); + int h2 = loff.height; + if (h2 == MAXCOL || h2 + h1 > min_height) + return min_height + 2; // no overlap + if (dir == FORWARD) + topline_back(&loff); else - topline_back(lp); - h3 = lp->height; - if (h3 == MAXCOL || h3 + h2 > min_height) - { - *lp = loff0; // no overlap - return; - } + botline_forw(&loff); - loff2 = *lp; - if (dir > 0) - botline_forw(lp); + int h3 = loff.height; + if (h3 == MAXCOL || h3 + h2 > min_height) + return min_height + 2; // no overlap + if (dir == FORWARD) + topline_back(&loff); else - topline_back(lp); - h4 = lp->height; + botline_forw(&loff); + + int h4 = loff.height; if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) - *lp = loff1; // 1 line overlap + return min_height + 1; // 1 line overlap else - *lp = loff2; // 2 lines overlap + return min_height; // 2 lines overlap } /* - * Scroll 'scroll' lines up or down. + * Scroll "count" lines with 'smoothscroll' in direction "dir". Return TRUE + * when scrolling happened. */ - void -halfpage(int flag, linenr_T Prenum) +static int scroll_with_sms(int dir, long count) { - long scrolled = 0; - int i; - int n; - int room; - - if (Prenum) - curwin->w_p_scr = (Prenum > curwin->w_height) ? - curwin->w_height : Prenum; - n = (curwin->w_p_scr <= curwin->w_height) ? - curwin->w_p_scr : curwin->w_height; - - update_topline(); - validate_botline(); - room = curwin->w_empty_rows; + int prev_sms = curwin->w_p_sms; + colnr_T prev_skipcol = curwin->w_skipcol; + linenr_T prev_topline = curwin->w_topline; #ifdef FEAT_DIFF - room += curwin->w_filler_rows; -#endif - if (flag) - { - /* - * scroll the text up - */ - while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count) - { -#ifdef FEAT_DIFF - if (curwin->w_topfill > 0) - { - i = 1; - --n; - --curwin->w_topfill; - } - else -#endif - { - i = PLINES_NOFILL(curwin->w_topline); - n -= i; - if (n < 0 && scrolled > 0) - break; -#ifdef FEAT_FOLDING - (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline); -#endif - ++curwin->w_topline; -#ifdef FEAT_DIFF - curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline); + int prev_topfill = curwin->w_topfill; #endif - if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - { - ++curwin->w_cursor.lnum; - curwin->w_valid &= - ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); - } - } - curwin->w_valid &= ~(VALID_CROW|VALID_WROW); - scrolled += i; + curwin->w_p_sms = TRUE; + scroll_redraw(dir == FORWARD, count); + + // Not actually smoothscrolling but ended up with partially visible line. + // Continue scrolling until skipcol is zero. + 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; + while (curwin->w_skipcol > 0 + && curwin->w_topline < curbuf->b_ml.ml_line_count) + scroll_redraw(fixdir == FORWARD, 1); + } + curwin->w_p_sms = prev_sms; - /* - * Correct w_botline for changed w_topline. - * Won't work when there are filler lines. - */ + return curwin->w_topline == prev_topline #ifdef FEAT_DIFF - if (curwin->w_p_diff) - curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); - else + && curwin->w_topfill == prev_topfill #endif - { - room += i; - do - { - i = plines(curwin->w_botline); - if (i > room) - break; -#ifdef FEAT_FOLDING - (void)hasFolding(curwin->w_botline, NULL, - &curwin->w_botline); -#endif - ++curwin->w_botline; - room -= i; - } while (curwin->w_botline <= curbuf->b_ml.ml_line_count); - } + && 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) +{ + 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) + { + // Scroll [count], 'scroll' or current window height lines. + if (count) + curwin->w_p_scr = MIN(curwin->w_height, count); + count = MIN(curwin->w_height, curwin->w_p_scr); + + int curscount = count; + // Adjust count so as to not reveal end of buffer lines. + if (dir == FORWARD) + { + int n = plines_correct_topline(curwin, curwin->w_topline, FALSE); + if (n - count < curwin->w_height && curwin->w_topline < buflen) + n += plines_m_win(curwin, curwin->w_topline + 1, buflen, FALSE); + if (n - count < curwin->w_height) + count = n - curwin->w_height; } - /* - * When hit bottom of the file: move cursor down. - */ - if (n > 0) + // (Try to) scroll the window unless already at the end of the buffer. + if (count > 0) { -# ifdef FEAT_FOLDING - if (hasAnyFolding(curwin)) - { - while (--n >= 0 - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - { - (void)hasFolding(curwin->w_cursor.lnum, NULL, - &curwin->w_cursor.lnum); - ++curwin->w_cursor.lnum; - } - } - else -# endif - curwin->w_cursor.lnum += n; - check_cursor_lnum(); + nochange = scroll_with_sms(dir, count); + curwin->w_cursor.lnum = prev_lnum; + curwin->w_cursor.col = prev_col; + curwin->w_curswant = prev_curswant; } + + // Move the cursor the same amount of screen lines. + if (curwin->w_p_wrap) + nv_screengo(&oa, dir, curscount); + else if (dir == FORWARD) + cursor_down_inner(curwin, curscount); + else + cursor_up_inner(curwin, curscount); } else { - /* - * scroll the text down - */ - while (n > 0 && curwin->w_topline > 1) - { -#ifdef FEAT_DIFF - if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline)) - { - i = 1; - --n; - ++curwin->w_topfill; - } - else -#endif - { - i = PLINES_NOFILL(curwin->w_topline - 1); - n -= i; - if (n < 0 && scrolled > 0) - break; - --curwin->w_topline; -#ifdef FEAT_FOLDING - (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); -#endif -#ifdef FEAT_DIFF - curwin->w_topfill = 0; -#endif - } - curwin->w_valid &= ~(VALID_CROW|VALID_WROW| - VALID_BOTLINE|VALID_BOTLINE_AP); - scrolled += i; - if (curwin->w_cursor.lnum > 1) - { - --curwin->w_cursor.lnum; - curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); - } - } + // 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); - /* - * When hit top of the file: move cursor up. - */ - if (n > 0) - { - if (curwin->w_cursor.lnum <= (linenr_T)n) - curwin->w_cursor.lnum = 1; - else -# ifdef FEAT_FOLDING - if (hasAnyFolding(curwin)) - { - while (--n >= 0 && curwin->w_cursor.lnum > 1) - { - --curwin->w_cursor.lnum; - (void)hasFolding(curwin->w_cursor.lnum, - &curwin->w_cursor.lnum, NULL); - } - } - else -# endif - curwin->w_cursor.lnum -= n; - } + // Place cursor at top or bottom of window. + validate_botline(); + curwin->w_cursor.lnum = (dir == FORWARD ? curwin->w_topline + : curwin->w_botline - 1); } -# ifdef FEAT_FOLDING + + if (get_scrolloff_value() > 0) + cursor_correct(); +#ifdef FEAT_FOLDING // Move cursor to first line of closed fold. foldAdjustCursor(); -# endif -#ifdef FEAT_DIFF - check_topfill(curwin, !flag); #endif - cursor_correct(); - beginline(BL_SOL | BL_FIX); - redraw_later(UPD_VALID); + nochange = nochange + && prev_col == curwin->w_cursor.col + && prev_lnum == curwin->w_cursor.lnum; + + // 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; } void |