diff options
Diffstat (limited to 'src/move.c')
-rw-r--r-- | src/move.c | 275 |
1 files changed, 86 insertions, 189 deletions
diff --git a/src/move.c b/src/move.c index 772b173bc8..25f419e5aa 100644 --- a/src/move.c +++ b/src/move.c @@ -3026,13 +3026,74 @@ cursor_correct(void) } /* + * 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. + */ +static int get_scroll_overlap(int dir) +{ + lineoff_T loff; + int min_height = curwin->w_height - 2; + + validate_botline(); + if (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 + 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 + loff.height = plines(loff.lnum); +#endif + + int h1 = loff.height; + if (h1 > min_height) + return min_height + 2; // no overlap + if (dir == FORWARD) + topline_back(&loff); + else + botline_forw(&loff); + + int h2 = loff.height; + if (h2 == MAXCOL || h2 + h1 > min_height) + return min_height + 2; // no overlap + if (dir == FORWARD) + topline_back(&loff); + else + botline_forw(&loff); + + int h3 = loff.height; + if (h3 == MAXCOL || h3 + h2 > min_height) + return min_height + 2; // no overlap + if (dir == FORWARD) + topline_back(&loff); + else + botline_forw(&loff); + + int h4 = loff.height; + if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) + return min_height + 1; // 1 line overlap + else + return min_height; // 2 lines overlap +} + +/* * 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) +pagescroll(int dir, long count, int half) { #ifdef FEAT_DIFF int prev_topfill = curwin->w_topfill; @@ -3040,9 +3101,17 @@ onepage(int dir, long count) linenr_T prev_topline = curwin->w_topline; colnr_T prev_skipcol = curwin->w_skipcol; - // Scroll 'window' or current window height lines. - count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) ? - p_window : curwin->w_height) - 2; + 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); + } + 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); @@ -3063,6 +3132,10 @@ onepage(int dir, long count) scroll_redraw(dir == FORWARD, count); curwin->w_p_sms = FALSE; } +#ifdef FEAT_FOLDING + // Move cursor to first line of closed fold. + foldAdjustCursor(); +#endif int nochange = curwin->w_topline == prev_topline #ifdef FEAT_DIFF @@ -3070,198 +3143,22 @@ onepage(int dir, long count) #endif && curwin->w_skipcol == prev_skipcol; + // Error if the viewport did not change and the cursor is already + // at the boundary. if (nochange) - beep_flush(); + { + 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) beginline(BL_SOL | BL_FIX); return nochange; } -/* - * Scroll 'scroll' lines up or down. - */ - void -halfpage(int flag, linenr_T Prenum) -{ - 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; -#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); -#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; - - /* - * Correct w_botline for changed w_topline. - * Won't work when there are filler lines. - */ -#ifdef FEAT_DIFF - if (curwin->w_p_diff) - curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); - else -#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); - } - } - - /* - * When hit bottom of the file: move cursor down. - */ - if (n > 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(); - } - } - 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); - } - } - - /* - * 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; - } - } -# 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); -} - void do_check_cursorbind(void) { |