/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. *//* * move.c: Functions for moving the cursor and scrolling text. * * There are two ways to move the cursor: * 1. Move the cursor directly, the text is scrolled to keep the cursor in the * window. * 2. Scroll the text, the cursor is moved into the text visible in the * window. * The 'scrolloff' option makes this a bit complicated. */ #include "vim.h" static void comp_botline __ARGS((win_T *wp));static int scrolljump_value __ARGS((void));static int check_top_offset __ARGS((void));static void curs_rows __ARGS((win_T *wp, int do_botline));static void validate_botline_win __ARGS((win_T *wp));static void validate_cheight __ARGS((void)); typedef struct{ linenr_T lnum; /* line number */#ifdef FEAT_DIFF int fill; /* filler lines */#endif int height; /* height of added line */} lineoff_T; static void topline_back __ARGS((lineoff_T *lp));static void botline_forw __ARGS((lineoff_T *lp));#ifdef FEAT_DIFFstatic void botline_topline __ARGS((lineoff_T *lp));static void topline_botline __ARGS((lineoff_T *lp));static void max_topfill __ARGS((void));#endif /* * Compute wp->w_botline for the current wp->w_topline. Can be called after * wp->w_topline changed. */ static voidcomp_botline(wp) win_T *wp;{ int n; linenr_T lnum; int done;#ifdef FEAT_FOLDING linenr_T last; int folded;#endif /* * If w_cline_row is valid, start there. * Otherwise have to start at w_topline. */ check_cursor_moved(wp); if (wp->w_valid & VALID_CROW) { lnum = wp->w_cursor.lnum; done = wp->w_cline_row; } else { lnum = wp->w_topline; done = 0; } for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum) {#ifdef FEAT_FOLDING last = lnum; folded = FALSE; if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL)) { n = 1; folded = TRUE; } else#endif#ifdef FEAT_DIFF if (lnum == wp->w_topline) n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill; else#endif n = plines_win(wp, lnum, TRUE); if (#ifdef FEAT_FOLDING lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum#else lnum == wp->w_cursor.lnum#endif ) { wp->w_cline_row = done; wp->w_cline_height = n;#ifdef FEAT_FOLDING wp->w_cline_folded = folded;#endif wp->w_valid |= (VALID_CROW|VALID_CHEIGHT); } if (done + n > wp->w_height) break; done += n;#ifdef FEAT_FOLDING lnum = last;#endif } /* wp->w_botline is the line that is just below the window */ wp->w_botline = lnum; wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; set_empty_rows(wp, done);} /* * Update curwin->w_topline and redraw if necessary. * Used to update the screen before printing a message. */ voidupdate_topline_redraw(){ update_topline(); if (must_redraw) update_screen(0);} /* * Update curwin->w_topline to move the cursor onto the screen. */ voidupdate_topline(){ long line_count; int halfheight; int n; linenr_T old_topline;#ifdef FEAT_DIFF int old_topfill;#endif#ifdef FEAT_FOLDING linenr_T lnum;#endif int check_topline = FALSE; int check_botline = FALSE;#ifdef FEAT_MOUSE int save_so = p_so;#endif if (!screen_valid(TRUE)) return; check_cursor_moved(curwin); if (curwin->w_valid & VALID_TOPLINE) return; #ifdef FEAT_MOUSE /* When dragging with the mouse, don't scroll that quickly */ if (mouse_dragging > 0) p_so = mouse_dragging - 1;#endif old_topline = curwin->w_topline;#ifdef FEAT_DIFF old_topfill = curwin->w_topfill;#endif /* * If the buffer is empty, always set topline to 1. */ if (bufempty()) /* special case - file is empty */ { if (curwin->w_topline != 1) redraw_later(NOT_VALID); curwin->w_topline = 1;#ifdef FEAT_DIFF curwin->w_topfill = 0;#endif curwin->w_botline = 2; curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;#ifdef FEAT_SCROLLBIND curwin->w_scbind_pos = 1;#endif } /* * If the cursor is above or near the top of the window, scroll the window * to show the line the cursor is in, with 'scrolloff' context. */ else { if (curwin->w_topline > 1) { /* If the cursor is above topline, scrolling is always needed. * If the cursor is far below topline and there is no folding, * scrolling down is never needed. */ if (curwin->w_cursor.lnum < curwin->w_topline) check_topline = TRUE; else if (check_top_offset()) check_topline = TRUE; }#ifdef FEAT_DIFF /* Check if there are more filler lines than allowed. */ if (!check_topline && curwin->w_topfill > diff_check_fill(curwin, curwin->w_topline)) check_topline = TRUE;#endif if (check_topline) { halfheight = curwin->w_height / 2 - 1; if (halfheight < 2) halfheight = 2; #ifdef FEAT_FOLDING if (hasAnyFolding(curwin)) { /* Count the number of logical lines between the cursor and * topline + p_so (approximation of how much will be * scrolled). */ n = 0; for (lnum = curwin->w_cursor.lnum; lnum < curwin->w_topline + p_so; ++lnum) { ++n; /* stop at end of file or when we know we are far off */ if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) break; (void)hasFolding(lnum, NULL, &lnum); } } else#endif n = curwin->w_topline + p_so - curwin->w_cursor.lnum; /* If we weren't very close to begin with, we scroll to put the * cursor in the middle of the window. Otherwise put the cursor * near the top of the window. */ if (n >= halfheight) scroll_cursor_halfway(FALSE); else { scroll_cursor_top(scrolljump_value(), FALSE); check_botline = TRUE; } } else {#ifdef FEAT_FOLDING /* Make sure topline is the first line of a fold. */ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);#endif check_botline = TRUE; } } /* * If the cursor is below the bottom of the window, scroll the window * to put the cursor on the window. * When w_botline is invalid, recompute it first, to avoid a redraw later. * If w_botline was approximated, we might need a redraw later in a few * cases, but we don't want to spend (a lot of) time recomputing w_botline * for every small change. */ if (check_botline) { if (!(curwin->w_valid & VALID_BOTLINE_AP)) validate_botline(); if (curwin->w_botline <= curbuf->b_ml.ml_line_count) { if (curwin->w_cursor.lnum < curwin->w_botline && ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so#ifdef FEAT_FOLDING || hasAnyFolding(curwin)#endif )) { lineoff_T loff; /* Cursor is above botline, check if there are 'scrolloff' * window lines below the cursor. If not, need to scroll. */ n = curwin->w_empty_rows; loff.lnum = curwin->w_cursor.lnum;#ifdef FEAT_FOLDING /* In a fold go to its last line. */ (void)hasFolding(loff.lnum, NULL, &loff.lnum);#endif#ifdef FEAT_DIFF loff.fill = 0; n += curwin->w_filler_rows;#endif loff.height = 0; while (loff.lnum < curwin->w_botline#ifdef FEAT_DIFF && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)#endif ) { n += loff.height; if (n >= p_so) break; botline_forw(&loff); } if (n >= p_so) /* sufficient context, no need to scroll */ check_botline = FALSE; } if (check_botline) {#ifdef FEAT_FOLDING if (hasAnyFolding(curwin)) { /* Count the number of logical lines between the cursor and * botline - p_so (approximation of how much will be * scrolled). */ line_count = 0; for (lnum = curwin->w_cursor.lnum; lnum >= curwin->w_botline - p_so; --lnum) { ++line_count; /* stop at end of file or when we know we are far off */ if (lnum <= 0 || line_count > curwin->w_height + 1) break; (void)hasFolding(lnum, &lnum, NULL); } } else#endif line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so; if (line_count <= curwin->w_height + 1) scroll_cursor_bot(scrolljump_value(), FALSE); else scroll_cursor_halfway(FALSE); } } } curwin->w_valid |= VALID_TOPLINE; /* * Need to redraw when topline changed. */ if (curwin->w_topline != old_topline#ifdef FEAT_DIFF || curwin->w_topfill != old_topfill#endif ) { dollar_vcol = 0; if (curwin->w_skipcol != 0) { curwin->w_skipcol = 0; redraw_later(NOT_VALID); } else redraw_later(VALID); /* May need to set w_skipcol when cursor in w_topline. */ if (curwin->w_cursor.lnum == curwin->w_topline) validate_cursor(); } #ifdef FEAT_MOUSE p_so = save_so;#endif} /* * Return the scrolljump value to use for the current window. * When 'scrolljump' is positive use it as-is. * When 'scrolljump' is negative use it as a percentage of the window height. */ static intscrolljump_value(){ if (p_sj >= 0) return (int)p_sj; return (curwin->w_height * -p_sj) / 100;} /* * Return TRUE when there are not 'scrolloff' lines above the cursor for the * current window. */ static intcheck_top_offset(){ lineoff_T loff; int n; if (curwin->w_cursor.lnum < curwin->w_topline + p_so#ifdef FEAT_FOLDING || hasAnyFolding(curwin)#endif ) { loff.lnum = curwin->w_cursor.lnum;#ifdef FEAT_DIFF loff.fill = 0; n = curwin->w_topfill; /* always have this context */#else n = 0;#endif /* Count the visible screen lines above the cursor line. */ while (n < p_so) { topline_back(&loff); /* Stop when included a line above the window. */ if (loff.lnum < curwin->w_topline#ifdef FEAT_DIFF || (loff.lnum == curwin->w_topline && loff.fill > 0)#endif ) break; n += loff.height; } if (n < p_so) return TRUE; } return FALSE;} voidupdate_curswant(){ if (curwin->w_set_curswant) { validate_virtcol(); curwin->w_curswant = curwin->w_virtcol; curwin->w_set_curswant = FALSE; }} /* * Check if the cursor has moved. Set the w_valid flag accordingly. */ voidcheck_cursor_moved(wp) win_T *wp;{ if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum) { wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE); wp->w_valid_cursor = wp->w_cursor; wp->w_valid_leftcol = wp->w_leftcol; } else if (wp->w_cursor.col != wp->w_valid_cursor.col || wp->w_leftcol != wp->w_valid_leftcol#ifdef FEAT_VIRTUALEDIT || wp->w_cursor.coladd != wp->w_valid_cursor.coladd#endif ) { wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); wp->w_valid_cursor.col = wp->w_cursor.col; wp->w_valid_leftcol = wp->w_leftcol;#ifdef FEAT_VIRTUALEDIT wp->w_valid_cursor.coladd = wp->w_cursor.coladd;#endif }} /* * Call this function when some window settings have changed, which require * the cursor position, botline and topline to be recomputed and the window to * be redrawn. E.g, when changing the 'wrap' option or folding. */ voidchanged_window_setting(){ changed_window_setting_win(curwin);} voidchanged_window_setting_win(wp) win_T *wp;{ wp->w_lines_valid = 0; changed_line_abv_curs_win(wp); wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE); redraw_win_later(wp, NOT_VALID);} /* * Set wp->w_topline to a certain number. */ voidLines 1–500 of 2859. Load more
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * move.c: Functions for moving the cursor and scrolling text. * * There are two ways to move the cursor: * 1. Move the cursor directly, the text is scrolled to keep the cursor in the * window. * 2. Scroll the text, the cursor is moved into the text visible in the * window. * The 'scrolloff' option makes this a bit complicated. */ #include "vim.h" static void comp_botline __ARGS((win_T *wp)); static int scrolljump_value __ARGS((void)); static int check_top_offset __ARGS((void)); static void curs_rows __ARGS((win_T *wp, int do_botline)); static void validate_botline_win __ARGS((win_T *wp)); static void validate_cheight __ARGS((void)); typedef struct { linenr_T lnum; /* line number */ #ifdef FEAT_DIFF int fill; /* filler lines */ #endif int height; /* height of added line */ } lineoff_T; static void topline_back __ARGS((lineoff_T *lp)); static void botline_forw __ARGS((lineoff_T *lp)); #ifdef FEAT_DIFF static void botline_topline __ARGS((lineoff_T *lp)); static void topline_botline __ARGS((lineoff_T *lp)); static void max_topfill __ARGS((void)); #endif /* * Compute wp->w_botline for the current wp->w_topline. Can be called after * wp->w_topline changed. */ static void comp_botline(wp) win_T *wp; { int n; linenr_T lnum; int done; #ifdef FEAT_FOLDING linenr_T last; int folded; #endif /* * If w_cline_row is valid, start there. * Otherwise have to start at w_topline. */ check_cursor_moved(wp); if (wp->w_valid & VALID_CROW) { lnum = wp->w_cursor.lnum; done = wp->w_cline_row; } else { lnum = wp->w_topline; done = 0; } for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum) { #ifdef FEAT_FOLDING last = lnum; folded = FALSE; if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL)) { n = 1; folded = TRUE; } else #endif #ifdef FEAT_DIFF if (lnum == wp->w_topline) n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill; else #endif n = plines_win(wp, lnum, TRUE); if ( #ifdef FEAT_FOLDING lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum #else lnum == wp->w_cursor.lnum #endif ) { wp->w_cline_row = done; wp->w_cline_height = n; #ifdef FEAT_FOLDING wp->w_cline_folded = folded; #endif wp->w_valid |= (VALID_CROW|VALID_CHEIGHT); } if (done + n > wp->w_height) break; done += n; #ifdef FEAT_FOLDING lnum = last; #endif } /* wp->w_botline is the line that is just below the window */ wp->w_botline = lnum; wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; set_empty_rows(wp, done); } /* * Update curwin->w_topline and redraw if necessary. * Used to update the screen before printing a message. */ void update_topline_redraw() { update_topline(); if (must_redraw) update_screen(0); } /* * Update curwin->w_topline to move the cursor onto the screen. */ void update_topline() { long line_count; int halfheight; int n; linenr_T old_topline; #ifdef FEAT_DIFF int old_topfill; #endif #ifdef FEAT_FOLDING linenr_T lnum; #endif int check_topline = FALSE; int check_botline = FALSE; #ifdef FEAT_MOUSE int save_so = p_so; #endif if (!screen_valid(TRUE)) return; check_cursor_moved(curwin); if (curwin->w_valid & VALID_TOPLINE) return; #ifdef FEAT_MOUSE /* When dragging with the mouse, don't scroll that quickly */ if (mouse_dragging > 0) p_so = mouse_dragging - 1; #endif old_topline = curwin->w_topline; #ifdef FEAT_DIFF old_topfill = curwin->w_topfill; #endif /* * If the buffer is empty, always set topline to 1. */ if (bufempty()) /* special case - file is empty */ { if (curwin->w_topline != 1) redraw_later(NOT_VALID); curwin->w_topline = 1; #ifdef FEAT_DIFF curwin->w_topfill = 0; #endif curwin->w_botline = 2; curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; #ifdef FEAT_SCROLLBIND curwin->w_scbind_pos = 1; #endif } /* * If the cursor is above or near the top of the window, scroll the window * to show the line the cursor is in, with 'scrolloff' context. */ else { if (curwin->w_topline > 1) { /* If the cursor is above topline, scrolling is always needed. * If the cursor is far below topline and there is no folding, * scrolling down is never needed. */ if (curwin->w_cursor.lnum < curwin->w_topline) check_topline = TRUE; else if (check_top_offset()) check_topline = TRUE; } #ifdef FEAT_DIFF /* Check if there are more filler lines than allowed. */ if (!check_topline && curwin->w_topfill > diff_check_fill(curwin, curwin->w_topline)) check_topline = TRUE; #endif if (check_topline) { halfheight = curwin->w_height / 2 - 1; if (halfheight < 2) halfheight = 2; #ifdef FEAT_FOLDING if (hasAnyFolding(curwin)) { /* Count the number of logical lines between the cursor and * topline + p_so (approximation of how much will be * scrolled). */ n = 0; for (lnum = curwin->w_cursor.lnum; lnum < curwin->w_topline + p_so; ++lnum) { ++n; /* stop at end of file or when we know we are far off */ if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) break; (void)hasFolding(lnum, NULL, &lnum); } } else #endif n = curwin->w_topline + p_so - curwin->w_cursor.lnum; /* If we weren't very close to begin with, we scroll to put the * cursor in the middle of the window. Otherwise put the cursor * near the top of the window. */ if (n >= halfheight) scroll_cursor_halfway(FALSE); else { scroll_cursor_top(scrolljump_value(), FALSE); check_botline = TRUE; } } else { #ifdef FEAT_FOLDING /* Make sure topline is the first line of a fold. */ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); #endif check_botline = TRUE; } } /* * If the cursor is below the bottom of the window, scroll the window * to put the cursor on the window. * When w_botline is invalid, recompute it first, to avoid a redraw later. * If w_botline was approximated, we might need a redraw later in a few * cases, but we don't want to spend (a lot of) time recomputing w_botline * for every small change. */ if (check_botline) { if (!(curwin->w_valid & VALID_BOTLINE_AP)) validate_botline(); if (curwin->w_botline <= curbuf->b_ml.ml_line_count) { if (curwin->w_cursor.lnum < curwin->w_botline && ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so #ifdef FEAT_FOLDING || hasAnyFolding(curwin) #endif )) { lineoff_T loff; /* Cursor is above botline, check if there are 'scrolloff' * window lines below the cursor. If not, need to scroll. */ n = curwin->w_empty_rows; loff.lnum = curwin->w_cursor.lnum; #ifdef FEAT_FOLDING /* In a fold go to its last line. */ (void)hasFolding(loff.lnum, NULL, &loff.lnum); #endif #ifdef FEAT_DIFF loff.fill = 0; n += curwin->w_filler_rows; #endif loff.height = 0; while (loff.lnum < curwin->w_botline #ifdef FEAT_DIFF && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0) #endif ) { n += loff.height; if (n >= p_so) break; botline_forw(&loff); } if (n >= p_so) /* sufficient context, no need to scroll */ check_botline = FALSE; } if (check_botline) { #ifdef FEAT_FOLDING if (hasAnyFolding(curwin)) { /* Count the number of logical lines between the cursor and * botline - p_so (approximation of how much will be * scrolled). */ line_count = 0; for (lnum = curwin->w_cursor.lnum; lnum >= curwin->w_botline - p_so; --lnum) { ++line_count; /* stop at end of file or when we know we are far off */ if (lnum <= 0 || line_count > curwin->w_height + 1) break; (void)hasFolding(lnum, &lnum, NULL); } } else #endif line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so; if (line_count <= curwin->w_height + 1) scroll_cursor_bot(scrolljump_value(), FALSE); else scroll_cursor_halfway(FALSE); } } } curwin->w_valid |= VALID_TOPLINE; /* * Need to redraw when topline changed. */ if (curwin->w_topline != old_topline #ifdef FEAT_DIFF || curwin->w_topfill != old_topfill #endif ) { dollar_vcol = 0; if (curwin->w_skipcol != 0) { curwin->w_skipcol = 0; redraw_later(NOT_VALID); } else redraw_later(VALID); /* May need to set w_skipcol when cursor in w_topline. */ if (curwin->w_cursor.lnum == curwin->w_topline) validate_cursor(); } #ifdef FEAT_MOUSE p_so = save_so; #endif } /* * Return the scrolljump value to use for the current window. * When 'scrolljump' is positive use it as-is. * When 'scrolljump' is negative use it as a percentage of the window height. */ static int scrolljump_value() { if (p_sj >= 0) return (int)p_sj; return (curwin->w_height * -p_sj) / 100; } /* * Return TRUE when there are not 'scrolloff' lines above the cursor for the * current window. */ static int check_top_offset() { lineoff_T loff; int n; if (curwin->w_cursor.lnum < curwin->w_topline + p_so #ifdef FEAT_FOLDING || hasAnyFolding(curwin) #endif ) { loff.lnum = curwin->w_cursor.lnum; #ifdef FEAT_DIFF loff.fill = 0; n = curwin->w_topfill; /* always have this context */ #else n = 0; #endif /* Count the visible screen lines above the cursor line. */ while (n < p_so) { topline_back(&loff); /* Stop when included a line above the window. */ if (loff.lnum < curwin->w_topline #ifdef FEAT_DIFF || (loff.lnum == curwin->w_topline && loff.fill > 0) #endif ) break; n += loff.height; } if (n < p_so) return TRUE; } return FALSE; } void update_curswant() { if (curwin->w_set_curswant) { validate_virtcol(); curwin->w_curswant = curwin->w_virtcol; curwin->w_set_curswant = FALSE; } } /* * Check if the cursor has moved. Set the w_valid flag accordingly. */ void check_cursor_moved(wp) win_T *wp; { if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum) { wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE); wp->w_valid_cursor = wp->w_cursor; wp->w_valid_leftcol = wp->w_leftcol; } else if (wp->w_cursor.col != wp->w_valid_cursor.col || wp->w_leftcol != wp->w_valid_leftcol #ifdef FEAT_VIRTUALEDIT || wp->w_cursor.coladd != wp->w_valid_cursor.coladd #endif ) { wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); wp->w_valid_cursor.col = wp->w_cursor.col; wp->w_valid_leftcol = wp->w_leftcol; #ifdef FEAT_VIRTUALEDIT wp->w_valid_cursor.coladd = wp->w_cursor.coladd; #endif } } /* * Call this function when some window settings have changed, which require * the cursor position, botline and topline to be recomputed and the window to * be redrawn. E.g, when changing the 'wrap' option or folding. */ void changed_window_setting() { changed_window_setting_win(curwin); } void changed_window_setting_win(wp) win_T *wp; { wp->w_lines_valid = 0; changed_line_abv_curs_win(wp); wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE); redraw_win_later(wp, NOT_VALID); } /* * Set wp->w_topline to a certain number. */ void