1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 /* 10 * move.c: Functions for moving the cursor and scrolling text. 11 * 12 * There are two ways to move the cursor: 13 * 1. Move the cursor directly, the text is scrolled to keep the cursor in the 14 * window. 15 * 2. Scroll the text, the cursor is moved into the text visible in the 16 * window. 17 * The 'scrolloff' option makes this a bit complicated. 18 */ 19 20 #include "vim.h" 21 22 static int scrolljump_value(void); 23 static int check_top_offset(void); 24 static void curs_rows(win_T *wp); 25 26 typedef struct 27 { 28 linenr_T lnum; // line number 29 #ifdef FEAT_DIFF 30 int fill; // filler lines 31 #endif 32 int height; // height of added line 33 } lineoff_T; 34 35 static void topline_back(lineoff_T *lp); 36 static void botline_forw(lineoff_T *lp); 37 38 /* 39 * Compute wp->w_botline for the current wp->w_topline. Can be called after 40 * wp->w_topline changed. 41 */ 42 static void 43 comp_botline(win_T *wp) 44 { 45 int n; 46 linenr_T lnum; 47 int done; 48 #ifdef FEAT_FOLDING 49 linenr_T last; 50 int folded; 51 #endif 52 53 /* 54 * If w_cline_row is valid, start there. 55 * Otherwise have to start at w_topline. 56 */ 57 check_cursor_moved(wp); 58 if (wp->w_valid & VALID_CROW) 59 { 60 lnum = wp->w_cursor.lnum; 61 done = wp->w_cline_row; 62 } 63 else 64 { 65 lnum = wp->w_topline; 66 done = 0; 67 } 68 69 for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum) 70 { 71 #ifdef FEAT_FOLDING 72 last = lnum; 73 folded = FALSE; 74 if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL)) 75 { 76 n = 1; 77 folded = TRUE; 78 } 79 else 80 #endif 81 #ifdef FEAT_DIFF 82 if (lnum == wp->w_topline) 83 n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill; 84 else 85 #endif 86 n = plines_win(wp, lnum, TRUE); 87 if ( 88 #ifdef FEAT_FOLDING 89 lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum 90 #else 91 lnum == wp->w_cursor.lnum 92 #endif 93 ) 94 { 95 wp->w_cline_row = done; 96 wp->w_cline_height = n; 97 #ifdef FEAT_FOLDING 98 wp->w_cline_folded = folded; 99 #endif 100 redraw_for_cursorline(wp); 101 wp->w_valid |= (VALID_CROW|VALID_CHEIGHT); 102 } 103 if (done + n > wp->w_height) 104 break; 105 done += n; 106 #ifdef FEAT_FOLDING 107 lnum = last; 108 #endif 109 } 110 111 // wp->w_botline is the line that is just below the window 112 wp->w_botline = lnum; 113 wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; 114 115 set_empty_rows(wp, done); 116 } 117 118 #ifdef FEAT_SYN_HL 119 void 120 reset_cursorline(void) 121 { 122 curwin->w_last_cursorline = 0; 123 } 124 #endif 125 126 /* 127 * Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is 128 * set. 129 */ 130 void 131 redraw_for_cursorline(win_T *wp) 132 { 133 if ((wp->w_p_rnu 134 #ifdef FEAT_SYN_HL 135 || wp->w_p_cul 136 #endif 137 ) 138 && (wp->w_valid & VALID_CROW) == 0 139 && !pum_visible()) 140 { 141 if (wp->w_p_rnu) 142 // win_line() will redraw the number column only. 143 redraw_win_later(wp, VALID); 144 #ifdef FEAT_SYN_HL 145 if (wp->w_p_cul) 146 { 147 if (wp->w_redr_type <= VALID && wp->w_last_cursorline != 0) 148 { 149 // "w_last_cursorline" may be outdated, worst case we redraw 150 // too much. This is optimized for moving the cursor around in 151 // the current window. 152 redrawWinline(wp, wp->w_last_cursorline); 153 redrawWinline(wp, wp->w_cursor.lnum); 154 } 155 else 156 redraw_win_later(wp, SOME_VALID); 157 } 158 #endif 159 } 160 } 161 162 /* 163 * Update curwin->w_topline and redraw if necessary. 164 * Used to update the screen before printing a message. 165 */ 166 void 167 update_topline_redraw(void) 168 { 169 update_topline(); 170 if (must_redraw) 171 update_screen(0); 172 } 173 174 /* 175 * Update curwin->w_topline to move the cursor onto the screen. 176 */ 177 void 178 update_topline(void) 179 { 180 long line_count; 181 int halfheight; 182 int n; 183 linenr_T old_topline; 184 #ifdef FEAT_DIFF 185 int old_topfill; 186 #endif 187 #ifdef FEAT_FOLDING 188 linenr_T lnum; 189 #endif 190 int check_topline = FALSE; 191 int check_botline = FALSE; 192 long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; 193 int save_so = *so_ptr; 194 195 // If there is no valid screen and when the window height is zero just use 196 // the cursor line. 197 if (!screen_valid(TRUE) || curwin->w_height == 0) 198 { 199 check_cursor_lnum(); 200 curwin->w_topline = curwin->w_cursor.lnum; 201 curwin->w_botline = curwin->w_topline; 202 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; 203 curwin->w_scbind_pos = 1; 204 return; 205 } 206 207 check_cursor_moved(curwin); 208 if (curwin->w_valid & VALID_TOPLINE) 209 return; 210 211 // When dragging with the mouse, don't scroll that quickly 212 if (mouse_dragging > 0) 213 *so_ptr = mouse_dragging - 1; 214 215 old_topline = curwin->w_topline; 216 #ifdef FEAT_DIFF 217 old_topfill = curwin->w_topfill; 218 #endif 219 220 /* 221 * If the buffer is empty, always set topline to 1. 222 */ 223 if (BUFEMPTY()) // special case - file is empty 224 { 225 if (curwin->w_topline != 1) 226 redraw_later(NOT_VALID); 227 curwin->w_topline = 1; 228 curwin->w_botline = 2; 229 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; 230 curwin->w_scbind_pos = 1; 231 } 232 233 /* 234 * If the cursor is above or near the top of the window, scroll the window 235 * to show the line the cursor is in, with 'scrolloff' context. 236 */ 237 else 238 { 239 if (curwin->w_topline > 1) 240 { 241 // If the cursor is above topline, scrolling is always needed. 242 // If the cursor is far below topline and there is no folding, 243 // scrolling down is never needed. 244 if (curwin->w_cursor.lnum < curwin->w_topline) 245 check_topline = TRUE; 246 else if (check_top_offset()) 247 check_topline = TRUE; 248 } 249 #ifdef FEAT_DIFF 250 // Check if there are more filler lines than allowed. 251 if (!check_topline && curwin->w_topfill > diff_check_fill(curwin, 252 curwin->w_topline)) 253 check_topline = TRUE; 254 #endif 255 256 if (check_topline) 257 { 258 halfheight = curwin->w_height / 2 - 1; 259 if (halfheight < 2) 260 halfheight = 2; 261 262 #ifdef FEAT_FOLDING 263 if (hasAnyFolding(curwin)) 264 { 265 // Count the number of logical lines between the cursor and 266 // topline + scrolloff (approximation of how much will be 267 // scrolled). 268 n = 0; 269 for (lnum = curwin->w_cursor.lnum; 270 lnum < curwin->w_topline + *so_ptr; ++lnum) 271 { 272 ++n; 273 // stop at end of file or when we know we are far off 274 if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) 275 break; 276 (void)hasFolding(lnum, NULL, &lnum); 277 } 278 } 279 else 280 #endif 281 n = curwin->w_topline + *so_ptr - curwin->w_cursor.lnum; 282 283 // If we weren't very close to begin with, we scroll to put the 284 // cursor in the middle of the window. Otherwise put the cursor 285 // near the top of the window. 286 if (n >= halfheight) 287 scroll_cursor_halfway(FALSE); 288 else 289 { 290 scroll_cursor_top(scrolljump_value(), FALSE); 291 check_botline = TRUE; 292 } 293 } 294 295 else 296 { 297 #ifdef FEAT_FOLDING 298 // Make sure topline is the first line of a fold. 299 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 300 #endif 301 check_botline = TRUE; 302 } 303 } 304 305 /* 306 * If the cursor is below the bottom of the window, scroll the window 307 * to put the cursor on the window. 308 * When w_botline is invalid, recompute it first, to avoid a redraw later. 309 * If w_botline was approximated, we might need a redraw later in a few 310 * cases, but we don't want to spend (a lot of) time recomputing w_botline 311 * for every small change. 312 */ 313 if (check_botline) 314 { 315 if (!(curwin->w_valid & VALID_BOTLINE_AP)) 316 validate_botline(); 317 318 if (curwin->w_botline <= curbuf->b_ml.ml_line_count) 319 { 320 if (curwin->w_cursor.lnum < curwin->w_botline) 321 { 322 if (((long)curwin->w_cursor.lnum 323 >= (long)curwin->w_botline - *so_ptr 324 #ifdef FEAT_FOLDING 325 || hasAnyFolding(curwin) 326 #endif 327 )) 328 { 329 lineoff_T loff; 330 331 // Cursor is (a few lines) above botline, check if there are 332 // 'scrolloff' window lines below the cursor. If not, need to 333 // scroll. 334 n = curwin->w_empty_rows; 335 loff.lnum = curwin->w_cursor.lnum; 336 #ifdef FEAT_FOLDING 337 // In a fold go to its last line. 338 (void)hasFolding(loff.lnum, NULL, &loff.lnum); 339 #endif 340 #ifdef FEAT_DIFF 341 loff.fill = 0; 342 n += curwin->w_filler_rows; 343 #endif 344 loff.height = 0; 345 while (loff.lnum < curwin->w_botline 346 #ifdef FEAT_DIFF 347 && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0) 348 #endif 349 ) 350 { 351 n += loff.height; 352 if (n >= *so_ptr) 353 break; 354 botline_forw(&loff); 355 } 356 if (n >= *so_ptr) 357 // sufficient context, no need to scroll 358 check_botline = FALSE; 359 } 360 else 361 // sufficient context, no need to scroll 362 check_botline = FALSE; 363 } 364 if (check_botline) 365 { 366 #ifdef FEAT_FOLDING 367 if (hasAnyFolding(curwin)) 368 { 369 // Count the number of logical lines between the cursor and 370 // botline - scrolloff (approximation of how much will be 371 // scrolled). 372 line_count = 0; 373 for (lnum = curwin->w_cursor.lnum; 374 lnum >= curwin->w_botline - *so_ptr; --lnum) 375 { 376 ++line_count; 377 // stop at end of file or when we know we are far off 378 if (lnum <= 0 || line_count > curwin->w_height + 1) 379 break; 380 (void)hasFolding(lnum, &lnum, NULL); 381 } 382 } 383 else 384 #endif 385 line_count = curwin->w_cursor.lnum - curwin->w_botline 386 + 1 + *so_ptr; 387 if (line_count <= curwin->w_height + 1) 388 scroll_cursor_bot(scrolljump_value(), FALSE); 389 else 390 scroll_cursor_halfway(FALSE); 391 } 392 } 393 } 394 curwin->w_valid |= VALID_TOPLINE; 395 396 /* 397 * Need to redraw when topline changed. 398 */ 399 if (curwin->w_topline != old_topline 400 #ifdef FEAT_DIFF 401 || curwin->w_topfill != old_topfill 402 #endif 403 ) 404 { 405 dollar_vcol = -1; 406 if (curwin->w_skipcol != 0) 407 { 408 curwin->w_skipcol = 0; 409 redraw_later(NOT_VALID); 410 } 411 else 412 redraw_later(VALID); 413 // May need to set w_skipcol when cursor in w_topline. 414 if (curwin->w_cursor.lnum == curwin->w_topline) 415 validate_cursor(); 416 } 417 418 *so_ptr = save_so; 419 } 420 421 /* 422 * Return the scrolljump value to use for the current window. 423 * When 'scrolljump' is positive use it as-is. 424 * When 'scrolljump' is negative use it as a percentage of the window height. 425 */ 426 static int 427 scrolljump_value(void) 428 { 429 if (p_sj >= 0) 430 return (int)p_sj; 431 return (curwin->w_height * -p_sj) / 100; 432 } 433 434 /* 435 * Return TRUE when there are not 'scrolloff' lines above the cursor for the 436 * current window. 437 */ 438 static int 439 check_top_offset(void) 440 { 441 lineoff_T loff; 442 int n; 443 long so = get_scrolloff_value(); 444 445 if (curwin->w_cursor.lnum < curwin->w_topline + so 446 #ifdef FEAT_FOLDING 447 || hasAnyFolding(curwin) 448 #endif 449 ) 450 { 451 loff.lnum = curwin->w_cursor.lnum; 452 #ifdef FEAT_DIFF 453 loff.fill = 0; 454 n = curwin->w_topfill; // always have this context 455 #else 456 n = 0; 457 #endif 458 // Count the visible screen lines above the cursor line. 459 while (n < so) 460 { 461 topline_back(&loff); 462 // Stop when included a line above the window. 463 if (loff.lnum < curwin->w_topline 464 #ifdef FEAT_DIFF 465 || (loff.lnum == curwin->w_topline && loff.fill > 0) 466 #endif 467 ) 468 break; 469 n += loff.height; 470 } 471 if (n < so) 472 return TRUE; 473 } 474 return FALSE; 475 } 476 477 void 478 update_curswant(void) 479 { 480 if (curwin->w_set_curswant) 481 { 482 validate_virtcol(); 483 curwin->w_curswant = curwin->w_virtcol; 484 curwin->w_set_curswant = FALSE; 485 } 486 } 487 488 /* 489 * Check if the cursor has moved. Set the w_valid flag accordingly. 490 */ 491 void 492 check_cursor_moved(win_T *wp) 493 { 494 if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum) 495 { 496 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL 497 |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE); 498 wp->w_valid_cursor = wp->w_cursor; 499 wp->w_valid_leftcol = wp->w_leftcol; 500 } 501 else if (wp->w_cursor.col != wp->w_valid_cursor.col 502 || wp->w_leftcol != wp->w_valid_leftcol 503 || wp->w_cursor.coladd != wp->w_valid_cursor.coladd) 504 { 505 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); 506 wp->w_valid_cursor.col = wp->w_cursor.col; 507 wp->w_valid_leftcol = wp->w_leftcol; 508 wp->w_valid_cursor.coladd = wp->w_cursor.coladd; 509 } 510 } 511 512 /* 513 * Call this function when some window settings have changed, which require 514 * the cursor position, botline and topline to be recomputed and the window to 515 * be redrawn. E.g, when changing the 'wrap' option or folding. 516 */ 517 void 518 changed_window_setting(void) 519 { 520 changed_window_setting_win(curwin); 521 } 522 523 void 524 changed_window_setting_win(win_T *wp) 525 { 526 wp->w_lines_valid = 0; 527 changed_line_abv_curs_win(wp); 528 wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE); 529 redraw_win_later(wp, NOT_VALID); 530 } 531 532 /* 533 * Set wp->w_topline to a certain number. 534 */ 535 void 536 set_topline(win_T *wp, linenr_T lnum) 537 { 538 #ifdef FEAT_DIFF 539 linenr_T prev_topline = wp->w_topline; 540 #endif 541 542 #ifdef FEAT_FOLDING 543 // go to first of folded lines 544 (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL); 545 #endif 546 // Approximate the value of w_botline 547 wp->w_botline += lnum - wp->w_topline; 548 if (wp->w_botline > wp->w_buffer->b_ml.ml_line_count + 1) 549 wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1; 550 wp->w_topline = lnum; 551 wp->w_topline_was_set = TRUE; 552 #ifdef FEAT_DIFF 553 if (lnum != prev_topline) 554 // Keep the filler lines when the topline didn't change. 555 wp->w_topfill = 0; 556 #endif 557 wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE); 558 // Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. 559 redraw_later(VALID); 560 } 561 562 /* 563 * Call this function when the length of the cursor line (in screen 564 * characters) has changed, and the change is before the cursor. 565 * Need to take care of w_botline separately! 566 */ 567 void 568 changed_cline_bef_curs(void) 569 { 570 curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL 571 |VALID_CHEIGHT|VALID_TOPLINE); 572 } 573 574 void 575 changed_cline_bef_curs_win(win_T *wp) 576 { 577 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL 578 |VALID_CHEIGHT|VALID_TOPLINE); 579 } 580 581 /* 582 * Call this function when the length of a line (in screen characters) above 583 * the cursor have changed. 584 * Need to take care of w_botline separately! 585 */ 586 void 587 changed_line_abv_curs(void) 588 { 589 curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW 590 |VALID_CHEIGHT|VALID_TOPLINE); 591 } 592 593 void 594 changed_line_abv_curs_win(win_T *wp) 595 { 596 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW 597 |VALID_CHEIGHT|VALID_TOPLINE); 598 } 599 600 /* 601 * Make sure the value of curwin->w_botline is valid. 602 */ 603 void 604 validate_botline(void) 605 { 606 validate_botline_win(curwin); 607 } 608 609 /* 610 * Make sure the value of wp->w_botline is valid. 611 */ 612 void 613 validate_botline_win(win_T *wp) 614 { 615 if (!(wp->w_valid & VALID_BOTLINE)) 616 comp_botline(wp); 617 } 618 619 /* 620 * Mark curwin->w_botline as invalid (because of some change in the buffer). 621 */ 622 void 623 invalidate_botline(void) 624 { 625 curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); 626 } 627 628 void 629 invalidate_botline_win(win_T *wp) 630 { 631 wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); 632 } 633 634 void 635 approximate_botline_win( 636 win_T *wp) 637 { 638 wp->w_valid &= ~VALID_BOTLINE; 639 } 640 641 /* 642 * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid. 643 */ 644 int 645 cursor_valid(void) 646 { 647 check_cursor_moved(curwin); 648 return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) == 649 (VALID_WROW|VALID_WCOL)); 650 } 651 652 /* 653 * Validate cursor position. Makes sure w_wrow and w_wcol are valid. 654 * w_topline must be valid, you may need to call update_topline() first! 655 */ 656 void 657 validate_cursor(void) 658 { 659 check_cursor_moved(curwin); 660 if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) 661 curs_columns(TRUE); 662 } 663 664 #if defined(FEAT_GUI) || defined(PROTO) 665 /* 666 * validate w_cline_row. 667 */ 668 void 669 validate_cline_row(void) 670 { 671 /* 672 * First make sure that w_topline is valid (after moving the cursor). 673 */ 674 update_topline(); 675 check_cursor_moved(curwin); 676 if (!(curwin->w_valid & VALID_CROW)) 677 curs_rows(curwin); 678 } 679 #endif 680 681 /* 682 * Compute wp->w_cline_row and wp->w_cline_height, based on the current value 683 * of wp->w_topline. 684 */ 685 static void 686 curs_rows(win_T *wp) 687 { 688 linenr_T lnum; 689 int i; 690 int all_invalid; 691 int valid; 692 #ifdef FEAT_FOLDING 693 long fold_count; 694 #endif 695 696 // Check if wp->w_lines[].wl_size is invalid 697 all_invalid = (!redrawing() 698 || wp->w_lines_valid == 0 699 || wp->w_lines[0].wl_lnum > wp->w_topline); 700 i = 0; 701 wp->w_cline_row = 0; 702 for (lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i) 703 { 704 valid = FALSE; 705 if (!all_invalid && i < wp->w_lines_valid) 706 { 707 if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid) 708 continue; // skip changed or deleted lines 709 if (wp->w_lines[i].wl_lnum == lnum) 710 { 711 #ifdef FEAT_FOLDING 712 // Check for newly inserted lines below this row, in which 713 // case we need to check for folded lines. 714 if (!wp->w_buffer->b_mod_set 715 || wp->w_lines[i].wl_lastlnum < wp->w_cursor.lnum 716 || wp->w_buffer->b_mod_top 717 > wp->w_lines[i].wl_lastlnum + 1) 718 #endif 719 valid = TRUE; 720 } 721 else if (wp->w_lines[i].wl_lnum > lnum) 722 --i; // hold at inserted lines 723 } 724 if (valid 725 #ifdef FEAT_DIFF 726 && (lnum != wp->w_topline || !wp->w_p_diff) 727 #endif 728 ) 729 { 730 #ifdef FEAT_FOLDING 731 lnum = wp->w_lines[i].wl_lastlnum + 1; 732 // Cursor inside folded lines, don't count this row 733 if (lnum > wp->w_cursor.lnum) 734 break; 735 #else 736 ++lnum; 737 #endif 738 wp->w_cline_row += wp->w_lines[i].wl_size; 739 } 740 else 741 { 742 #ifdef FEAT_FOLDING 743 fold_count = foldedCount(wp, lnum, NULL); 744 if (fold_count) 745 { 746 lnum += fold_count; 747 if (lnum > wp->w_cursor.lnum) 748 break; 749 ++wp->w_cline_row; 750 } 751 else 752 #endif 753 #ifdef FEAT_DIFF 754 if (lnum == wp->w_topline) 755 wp->w_cline_row += plines_win_nofill(wp, lnum++, TRUE) 756 + wp->w_topfill; 757 else 758 #endif 759 wp->w_cline_row += plines_win(wp, lnum++, TRUE); 760 } 761 } 762 763 check_cursor_moved(wp); 764 if (!(wp->w_valid & VALID_CHEIGHT)) 765 { 766 if (all_invalid 767 || i == wp->w_lines_valid 768 || (i < wp->w_lines_valid 769 && (!wp->w_lines[i].wl_valid 770 || wp->w_lines[i].wl_lnum != wp->w_cursor.lnum))) 771 { 772 #ifdef FEAT_DIFF 773 if (wp->w_cursor.lnum == wp->w_topline) 774 wp->w_cline_height = plines_win_nofill(wp, wp->w_cursor.lnum, 775 TRUE) + wp->w_topfill; 776 else 777 #endif 778 wp->w_cline_height = plines_win(wp, wp->w_cursor.lnum, TRUE); 779 #ifdef FEAT_FOLDING 780 wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum, 781 NULL, NULL, TRUE, NULL); 782 #endif 783 } 784 else if (i > wp->w_lines_valid) 785 { 786 // a line that is too long to fit on the last screen line 787 wp->w_cline_height = 0; 788 #ifdef FEAT_FOLDING 789 wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum, 790 NULL, NULL, TRUE, NULL); 791 #endif 792 } 793 else 794 { 795 wp->w_cline_height = wp->w_lines[i].wl_size; 796 #ifdef FEAT_FOLDING 797 wp->w_cline_folded = wp->w_lines[i].wl_folded; 798 #endif 799 } 800 } 801 802 redraw_for_cursorline(curwin); 803 wp->w_valid |= VALID_CROW|VALID_CHEIGHT; 804 805 } 806 807 /* 808 * Validate curwin->w_virtcol only. 809 */ 810 void 811 validate_virtcol(void) 812 { 813 validate_virtcol_win(curwin); 814 } 815 816 /* 817 * Validate wp->w_virtcol only. 818 */ 819 void 820 validate_virtcol_win(win_T *wp) 821 { 822 check_cursor_moved(wp); 823 if (!(wp->w_valid & VALID_VIRTCOL)) 824 { 825 getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL); 826 wp->w_valid |= VALID_VIRTCOL; 827 #ifdef FEAT_SYN_HL 828 if (wp->w_p_cuc && !pum_visible()) 829 redraw_win_later(wp, SOME_VALID); 830 #endif 831 } 832 } 833 834 /* 835 * Validate curwin->w_cline_height only. 836 */ 837 void 838 validate_cheight(void) 839 { 840 check_cursor_moved(curwin); 841 if (!(curwin->w_valid & VALID_CHEIGHT)) 842 { 843 #ifdef FEAT_DIFF 844 if (curwin->w_cursor.lnum == curwin->w_topline) 845 curwin->w_cline_height = plines_nofill(curwin->w_cursor.lnum) 846 + curwin->w_topfill; 847 else 848 #endif 849 curwin->w_cline_height = plines(curwin->w_cursor.lnum); 850 #ifdef FEAT_FOLDING 851 curwin->w_cline_folded = hasFolding(curwin->w_cursor.lnum, NULL, NULL); 852 #endif 853 curwin->w_valid |= VALID_CHEIGHT; 854 } 855 } 856 857 /* 858 * Validate w_wcol and w_virtcol only. 859 */ 860 void 861 validate_cursor_col(void) 862 { 863 colnr_T off; 864 colnr_T col; 865 int width; 866 867 validate_virtcol(); 868 if (!(curwin->w_valid & VALID_WCOL)) 869 { 870 col = curwin->w_virtcol; 871 off = curwin_col_off(); 872 col += off; 873 width = curwin->w_width - off + curwin_col_off2(); 874 875 // long line wrapping, adjust curwin->w_wrow 876 if (curwin->w_p_wrap 877 && col >= (colnr_T)curwin->w_width 878 && width > 0) 879 // use same formula as what is used in curs_columns() 880 col -= ((col - curwin->w_width) / width + 1) * width; 881 if (col > (int)curwin->w_leftcol) 882 col -= curwin->w_leftcol; 883 else 884 col = 0; 885 curwin->w_wcol = col; 886 887 curwin->w_valid |= VALID_WCOL; 888 #ifdef FEAT_PROP_POPUP 889 curwin->w_flags &= ~WFLAG_WCOL_OFF_ADDED; 890 #endif 891 } 892 } 893 894 /* 895 * Compute offset of a window, occupied by absolute or relative line number, 896 * fold column and sign column (these don't move when scrolling horizontally). 897 */ 898 int 899 win_col_off(win_T *wp) 900 { 901 return (((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0) 902 #ifdef FEAT_CMDWIN 903 + (cmdwin_type == 0 || wp != curwin ? 0 : 1) 904 #endif 905 #ifdef FEAT_FOLDING 906 + wp->w_p_fdc 907 #endif 908 #ifdef FEAT_SIGNS 909 + (signcolumn_on(wp) ? 2 : 0) 910 #endif 911 ); 912 } 913 914 int 915 curwin_col_off(void) 916 { 917 return win_col_off(curwin); 918 } 919 920 /* 921 * Return the difference in column offset for the second screen line of a 922 * wrapped line. It's 8 if 'number' or 'relativenumber' is on and 'n' is in 923 * 'cpoptions'. 924 */ 925 int 926 win_col_off2(win_T *wp) 927 { 928 if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL) 929 return number_width(wp) + 1; 930 return 0; 931 } 932 933 int 934 curwin_col_off2(void) 935 { 936 return win_col_off2(curwin); 937 } 938 939 /* 940 * Compute curwin->w_wcol and curwin->w_virtcol. 941 * Also updates curwin->w_wrow and curwin->w_cline_row. 942 * Also updates curwin->w_leftcol. 943 */ 944 void 945 curs_columns( 946 int may_scroll) // when TRUE, may scroll horizontally 947 { 948 int diff; 949 int extra; // offset for first screen line 950 int off_left, off_right; 951 int n; 952 int p_lines; 953 int width = 0; 954 int textwidth; 955 int new_leftcol; 956 colnr_T startcol; 957 colnr_T endcol; 958 colnr_T prev_skipcol; 959 long so = get_scrolloff_value(); 960 long siso = get_sidescrolloff_value(); 961 962 /* 963 * First make sure that w_topline is valid (after moving the cursor). 964 */ 965 update_topline(); 966 967 /* 968 * Next make sure that w_cline_row is valid. 969 */ 970 if (!(curwin->w_valid & VALID_CROW)) 971 curs_rows(curwin); 972 973 /* 974 * Compute the number of virtual columns. 975 */ 976 #ifdef FEAT_FOLDING 977 if (curwin->w_cline_folded) 978 // In a folded line the cursor is always in the first column 979 startcol = curwin->w_virtcol = endcol = curwin->w_leftcol; 980 else 981 #endif 982 getvvcol(curwin, &curwin->w_cursor, 983 &startcol, &(curwin->w_virtcol), &endcol); 984 985 // remove '$' from change command when cursor moves onto it 986 if (startcol > dollar_vcol) 987 dollar_vcol = -1; 988 989 extra = curwin_col_off(); 990 curwin->w_wcol = curwin->w_virtcol + extra; 991 endcol += extra; 992 993 /* 994 * Now compute w_wrow, counting screen lines from w_cline_row. 995 */ 996 curwin->w_wrow = curwin->w_cline_row; 997 998 textwidth = curwin->w_width - extra; 999 if (textwidth <= 0) 1000 { 1001 // No room for text, put cursor in last char of window. 1002 // If not wrapping, the last non-empty line. 1003 curwin->w_wcol = curwin->w_width - 1; 1004 if (curwin->w_p_wrap) 1005 curwin->w_wrow = curwin->w_height - 1; 1006 else 1007 curwin->w_wrow = curwin->w_height - 1 - curwin->w_empty_rows; 1008 } 1009 else if (curwin->w_p_wrap && curwin->w_width != 0) 1010 { 1011 width = textwidth + curwin_col_off2(); 1012 1013 // long line wrapping, adjust curwin->w_wrow 1014 if (curwin->w_wcol >= curwin->w_width) 1015 { 1016 #ifdef FEAT_LINEBREAK 1017 char_u *sbr; 1018 #endif 1019 1020 // this same formula is used in validate_cursor_col() 1021 n = (curwin->w_wcol - curwin->w_width) / width + 1; 1022 curwin->w_wcol -= n * width; 1023 curwin->w_wrow += n; 1024 1025 #ifdef FEAT_LINEBREAK 1026 // When cursor wraps to first char of next line in Insert 1027 // mode, the 'showbreak' string isn't shown, backup to first 1028 // column 1029 sbr = get_showbreak_value(curwin); 1030 if (*sbr && *ml_get_cursor() == NUL 1031 && curwin->w_wcol == vim_strsize(sbr)) 1032 curwin->w_wcol = 0; 1033 #endif 1034 } 1035 } 1036 1037 // No line wrapping: compute curwin->w_leftcol if scrolling is on and line 1038 // is not folded. 1039 // If scrolling is off, curwin->w_leftcol is assumed to be 0 1040 else if (may_scroll 1041 #ifdef FEAT_FOLDING 1042 && !curwin->w_cline_folded 1043 #endif 1044 ) 1045 { 1046 /* 1047 * If Cursor is left of the screen, scroll rightwards. 1048 * If Cursor is right of the screen, scroll leftwards 1049 * If we get closer to the edge than 'sidescrolloff', scroll a little 1050 * extra 1051 */ 1052 off_left = (int)startcol - (int)curwin->w_leftcol - siso; 1053 off_right = (int)endcol - (int)(curwin->w_leftcol + curwin->w_width 1054 - siso) + 1; 1055 if (off_left < 0 || off_right > 0) 1056 { 1057 if (off_left < 0) 1058 diff = -off_left; 1059 else 1060 diff = off_right; 1061 1062 // When far off or not enough room on either side, put cursor in 1063 // middle of window. 1064 if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left) 1065 new_leftcol = curwin->w_wcol - extra - textwidth / 2; 1066 else 1067 { 1068 if (diff < p_ss) 1069 diff = p_ss; 1070 if (off_left < 0) 1071 new_leftcol = curwin->w_leftcol - diff; 1072 else 1073 new_leftcol = curwin->w_leftcol + diff; 1074 } 1075 if (new_leftcol < 0) 1076 new_leftcol = 0; 1077 if (new_leftcol != (int)curwin->w_leftcol) 1078 { 1079 curwin->w_leftcol = new_leftcol; 1080 // screen has to be redrawn with new curwin->w_leftcol 1081 redraw_later(NOT_VALID); 1082 } 1083 } 1084 curwin->w_wcol -= curwin->w_leftcol; 1085 } 1086 else if (curwin->w_wcol > (int)curwin->w_leftcol) 1087 curwin->w_wcol -= curwin->w_leftcol; 1088 else 1089 curwin->w_wcol = 0; 1090 1091 #ifdef FEAT_DIFF 1092 // Skip over filler lines. At the top use w_topfill, there 1093 // may be some filler lines above the window. 1094 if (curwin->w_cursor.lnum == curwin->w_topline) 1095 curwin->w_wrow += curwin->w_topfill; 1096 else 1097 curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum); 1098 #endif 1099 1100 prev_skipcol = curwin->w_skipcol; 1101 1102 p_lines = 0; 1103 1104 if ((curwin->w_wrow >= curwin->w_height 1105 || ((prev_skipcol > 0 1106 || curwin->w_wrow + so >= curwin->w_height) 1107 && (p_lines = 1108 #ifdef FEAT_DIFF 1109 plines_win_nofill 1110 #else 1111 plines_win 1112 #endif 1113 (curwin, curwin->w_cursor.lnum, FALSE)) 1114 - 1 >= curwin->w_height)) 1115 && curwin->w_height != 0 1116 && curwin->w_cursor.lnum == curwin->w_topline 1117 && width > 0 1118 && curwin->w_width != 0) 1119 { 1120 // Cursor past end of screen. Happens with a single line that does 1121 // not fit on screen. Find a skipcol to show the text around the 1122 // cursor. Avoid scrolling all the time. compute value of "extra": 1123 // 1: Less than 'scrolloff' lines above 1124 // 2: Less than 'scrolloff' lines below 1125 // 3: both of them 1126 extra = 0; 1127 if (curwin->w_skipcol + so * width > curwin->w_virtcol) 1128 extra = 1; 1129 // Compute last display line of the buffer line that we want at the 1130 // bottom of the window. 1131 if (p_lines == 0) 1132 p_lines = plines_win(curwin, curwin->w_cursor.lnum, FALSE); 1133 --p_lines; 1134 if (p_lines > curwin->w_wrow + so) 1135 n = curwin->w_wrow + so; 1136 else 1137 n = p_lines; 1138 if ((colnr_T)n >= curwin->w_height + curwin->w_skipcol / width - so) 1139 extra += 2; 1140 1141 if (extra == 3 || p_lines <= so * 2) 1142 { 1143 // not enough room for 'scrolloff', put cursor in the middle 1144 n = curwin->w_virtcol / width; 1145 if (n > curwin->w_height / 2) 1146 n -= curwin->w_height / 2; 1147 else 1148 n = 0; 1149 // don't skip more than necessary 1150 if (n > p_lines - curwin->w_height + 1) 1151 n = p_lines - curwin->w_height + 1; 1152 curwin->w_skipcol = n * width; 1153 } 1154 else if (extra == 1) 1155 { 1156 // less then 'scrolloff' lines above, decrease skipcol 1157 extra = (curwin->w_skipcol + so * width - curwin->w_virtcol 1158 + width - 1) / width; 1159 if (extra > 0) 1160 { 1161 if ((colnr_T)(extra * width) > curwin->w_skipcol) 1162 extra = curwin->w_skipcol / width; 1163 curwin->w_skipcol -= extra * width; 1164 } 1165 } 1166 else if (extra == 2) 1167 { 1168 // less then 'scrolloff' lines below, increase skipcol 1169 endcol = (n - curwin->w_height + 1) * width; 1170 while (endcol > curwin->w_virtcol) 1171 endcol -= width; 1172 if (endcol > curwin->w_skipcol) 1173 curwin->w_skipcol = endcol; 1174 } 1175 1176 curwin->w_wrow -= curwin->w_skipcol / width; 1177 if (curwin->w_wrow >= curwin->w_height) 1178 { 1179 // small window, make sure cursor is in it 1180 extra = curwin->w_wrow - curwin->w_height + 1; 1181 curwin->w_skipcol += extra * width; 1182 curwin->w_wrow -= extra; 1183 } 1184 1185 extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width; 1186 if (extra > 0) 1187 win_ins_lines(curwin, 0, extra, FALSE, FALSE); 1188 else if (extra < 0) 1189 win_del_lines(curwin, 0, -extra, FALSE, FALSE, 0); 1190 } 1191 else 1192 curwin->w_skipcol = 0; 1193 if (prev_skipcol != curwin->w_skipcol) 1194 redraw_later(NOT_VALID); 1195 1196 #ifdef FEAT_SYN_HL 1197 // Redraw when w_virtcol changes and 'cursorcolumn' is set 1198 if (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0 1199 && !pum_visible()) 1200 redraw_later(SOME_VALID); 1201 #endif 1202 #if defined(FEAT_PROP_POPUP) && defined(FEAT_TERMINAL) 1203 if (popup_is_popup(curwin) && curbuf->b_term != NULL) 1204 { 1205 curwin->w_wrow += popup_top_extra(curwin); 1206 curwin->w_wcol += popup_left_extra(curwin); 1207 curwin->w_flags |= WFLAG_WCOL_OFF_ADDED + WFLAG_WROW_OFF_ADDED; 1208 } 1209 else 1210 curwin->w_flags &= ~(WFLAG_WCOL_OFF_ADDED + WFLAG_WROW_OFF_ADDED); 1211 #endif 1212 1213 // now w_leftcol is valid, avoid check_cursor_moved() thinking otherwise 1214 curwin->w_valid_leftcol = curwin->w_leftcol; 1215 1216 curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; 1217 } 1218 1219 #if (defined(FEAT_EVAL) || defined(FEAT_PROP_POPUP)) || defined(PROTO) 1220 /* 1221 * Compute the screen position of text character at "pos" in window "wp" 1222 * The resulting values are one-based, zero when character is not visible. 1223 */ 1224 void 1225 textpos2screenpos( 1226 win_T *wp, 1227 pos_T *pos, 1228 int *rowp, // screen row 1229 int *scolp, // start screen column 1230 int *ccolp, // cursor screen column 1231 int *ecolp) // end screen column 1232 { 1233 colnr_T scol = 0, ccol = 0, ecol = 0; 1234 int row = 0; 1235 int rowoff = 0; 1236 colnr_T coloff = 0; 1237 1238 if (pos->lnum >= wp->w_topline && pos->lnum <= wp->w_botline) 1239 { 1240 colnr_T off; 1241 colnr_T col; 1242 int width; 1243 1244 row = plines_m_win(wp, wp->w_topline, pos->lnum - 1) + 1; 1245 getvcol(wp, pos, &scol, &ccol, &ecol); 1246 1247 // similar to what is done in validate_cursor_col() 1248 col = scol; 1249 off = win_col_off(wp); 1250 col += off; 1251 width = wp->w_width - off + win_col_off2(wp); 1252 1253 // long line wrapping, adjust row 1254 if (wp->w_p_wrap 1255 && col >= (colnr_T)wp->w_width 1256 && width > 0) 1257 { 1258 // use same formula as what is used in curs_columns() 1259 rowoff = ((col - wp->w_width) / width + 1); 1260 col -= rowoff * width; 1261 } 1262 col -= wp->w_leftcol; 1263 if (col >= wp->w_width) 1264 col = -1; 1265 if (col >= 0 && row + rowoff <= wp->w_height) 1266 coloff = col - scol + wp->w_wincol + 1; 1267 else 1268 // character is left, right or below of the window 1269 row = rowoff = scol = ccol = ecol = 0; 1270 } 1271 *rowp = W_WINROW(wp) + row + rowoff; 1272 *scolp = scol + coloff; 1273 *ccolp = ccol + coloff; 1274 *ecolp = ecol + coloff; 1275 } 1276 #endif 1277 1278 #if defined(FEAT_EVAL) || defined(PROTO) 1279 /* 1280 * "screenpos({winid}, {lnum}, {col})" function 1281 */ 1282 void 1283 f_screenpos(typval_T *argvars UNUSED, typval_T *rettv) 1284 { 1285 dict_T *dict; 1286 win_T *wp; 1287 pos_T pos; 1288 int row = 0; 1289 int scol = 0, ccol = 0, ecol = 0; 1290 1291 if (rettv_dict_alloc(rettv) != OK) 1292 return; 1293 dict = rettv->vval.v_dict; 1294 1295 if (in_vim9script() 1296 && (check_for_number_arg(argvars, 0) == FAIL 1297 || check_for_number_arg(argvars, 1) == FAIL 1298 || check_for_number_arg(argvars, 2) == FAIL)) 1299 return; 1300 1301 wp = find_win_by_nr_or_id(&argvars[0]); 1302 if (wp == NULL) 1303 return; 1304 1305 pos.lnum = tv_get_number(&argvars[1]); 1306 pos.col = tv_get_number(&argvars[2]) - 1; 1307 pos.coladd = 0; 1308 textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol); 1309 1310 dict_add_number(dict, "row", row); 1311 dict_add_number(dict, "col", scol); 1312 dict_add_number(dict, "curscol", ccol); 1313 dict_add_number(dict, "endcol", ecol); 1314 } 1315 #endif 1316 1317 /* 1318 * Scroll the current window down by "line_count" logical lines. "CTRL-Y" 1319 */ 1320 void 1321 scrolldown( 1322 long line_count, 1323 int byfold UNUSED) // TRUE: count a closed fold as one line 1324 { 1325 long done = 0; // total # of physical lines done 1326 int wrow; 1327 int moved = FALSE; 1328 1329 #ifdef FEAT_FOLDING 1330 linenr_T first; 1331 1332 // Make sure w_topline is at the first of a sequence of folded lines. 1333 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 1334 #endif 1335 validate_cursor(); // w_wrow needs to be valid 1336 while (line_count-- > 0) 1337 { 1338 #ifdef FEAT_DIFF 1339 if (curwin->w_topfill < diff_check(curwin, curwin->w_topline) 1340 && curwin->w_topfill < curwin->w_height - 1) 1341 { 1342 ++curwin->w_topfill; 1343 ++done; 1344 } 1345 else 1346 #endif 1347 { 1348 if (curwin->w_topline == 1) 1349 break; 1350 --curwin->w_topline; 1351 #ifdef FEAT_DIFF 1352 curwin->w_topfill = 0; 1353 #endif 1354 #ifdef FEAT_FOLDING 1355 // A sequence of folded lines only counts for one logical line 1356 if (hasFolding(curwin->w_topline, &first, NULL)) 1357 { 1358 ++done; 1359 if (!byfold) 1360 line_count -= curwin->w_topline - first - 1; 1361 curwin->w_botline -= curwin->w_topline - first; 1362 curwin->w_topline = first; 1363 } 1364 else 1365 #endif 1366 done += PLINES_NOFILL(curwin->w_topline); 1367 } 1368 --curwin->w_botline; // approximate w_botline 1369 invalidate_botline(); 1370 } 1371 curwin->w_wrow += done; // keep w_wrow updated 1372 curwin->w_cline_row += done; // keep w_cline_row updated 1373 1374 #ifdef FEAT_DIFF 1375 if (curwin->w_cursor.lnum == curwin->w_topline) 1376 curwin->w_cline_row = 0; 1377 check_topfill(curwin, TRUE); 1378 #endif 1379 1380 /* 1381 * Compute the row number of the last row of the cursor line 1382 * and move the cursor onto the displayed part of the window. 1383 */ 1384 wrow = curwin->w_wrow; 1385 if (curwin->w_p_wrap && curwin->w_width != 0) 1386 { 1387 validate_virtcol(); 1388 validate_cheight(); 1389 wrow += curwin->w_cline_height - 1 - 1390 curwin->w_virtcol / curwin->w_width; 1391 } 1392 while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1) 1393 { 1394 #ifdef FEAT_FOLDING 1395 if (hasFolding(curwin->w_cursor.lnum, &first, NULL)) 1396 { 1397 --wrow; 1398 if (first == 1) 1399 curwin->w_cursor.lnum = 1; 1400 else 1401 curwin->w_cursor.lnum = first - 1; 1402 } 1403 else 1404 #endif 1405 wrow -= plines(curwin->w_cursor.lnum--); 1406 curwin->w_valid &= 1407 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); 1408 moved = TRUE; 1409 } 1410 if (moved) 1411 { 1412 #ifdef FEAT_FOLDING 1413 // Move cursor to first line of closed fold. 1414 foldAdjustCursor(); 1415 #endif 1416 coladvance(curwin->w_curswant); 1417 } 1418 } 1419 1420 /* 1421 * Scroll the current window up by "line_count" logical lines. "CTRL-E" 1422 */ 1423 void 1424 scrollup( 1425 long line_count, 1426 int byfold UNUSED) // TRUE: count a closed fold as one line 1427 { 1428 #if defined(FEAT_FOLDING) || defined(FEAT_DIFF) 1429 linenr_T lnum; 1430 1431 if ( 1432 # ifdef FEAT_FOLDING 1433 (byfold && hasAnyFolding(curwin)) 1434 # ifdef FEAT_DIFF 1435 || 1436 # endif 1437 # endif 1438 # ifdef FEAT_DIFF 1439 curwin->w_p_diff 1440 # endif 1441 ) 1442 { 1443 // count each sequence of folded lines as one logical line 1444 lnum = curwin->w_topline; 1445 while (line_count--) 1446 { 1447 # ifdef FEAT_DIFF 1448 if (curwin->w_topfill > 0) 1449 --curwin->w_topfill; 1450 else 1451 # endif 1452 { 1453 # ifdef FEAT_FOLDING 1454 if (byfold) 1455 (void)hasFolding(lnum, NULL, &lnum); 1456 # endif 1457 if (lnum >= curbuf->b_ml.ml_line_count) 1458 break; 1459 ++lnum; 1460 # ifdef FEAT_DIFF 1461 curwin->w_topfill = diff_check_fill(curwin, lnum); 1462 # endif 1463 } 1464 } 1465 // approximate w_botline 1466 curwin->w_botline += lnum - curwin->w_topline; 1467 curwin->w_topline = lnum; 1468 } 1469 else 1470 #endif 1471 { 1472 curwin->w_topline += line_count; 1473 curwin->w_botline += line_count; // approximate w_botline 1474 } 1475 1476 if (curwin->w_topline > curbuf->b_ml.ml_line_count) 1477 curwin->w_topline = curbuf->b_ml.ml_line_count; 1478 if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1) 1479 curwin->w_botline = curbuf->b_ml.ml_line_count + 1; 1480 1481 #ifdef FEAT_DIFF 1482 check_topfill(curwin, FALSE); 1483 #endif 1484 1485 #ifdef FEAT_FOLDING 1486 if (hasAnyFolding(curwin)) 1487 // Make sure w_topline is at the first of a sequence of folded lines. 1488 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 1489 #endif 1490 1491 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); 1492 if (curwin->w_cursor.lnum < curwin->w_topline) 1493 { 1494 curwin->w_cursor.lnum = curwin->w_topline; 1495 curwin->w_valid &= 1496 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); 1497 coladvance(curwin->w_curswant); 1498 } 1499 } 1500 1501 #ifdef FEAT_DIFF 1502 /* 1503 * Don't end up with too many filler lines in the window. 1504 */ 1505 void 1506 check_topfill( 1507 win_T *wp, 1508 int down) // when TRUE scroll down when not enough space 1509 { 1510 int n; 1511 1512 if (wp->w_topfill > 0) 1513 { 1514 n = plines_win_nofill(wp, wp->w_topline, TRUE); 1515 if (wp->w_topfill + n > wp->w_height) 1516 { 1517 if (down && wp->w_topline > 1) 1518 { 1519 --wp->w_topline; 1520 wp->w_topfill = 0; 1521 } 1522 else 1523 { 1524 wp->w_topfill = wp->w_height - n; 1525 if (wp->w_topfill < 0) 1526 wp->w_topfill = 0; 1527 } 1528 } 1529 } 1530 } 1531 1532 /* 1533 * Use as many filler lines as possible for w_topline. Make sure w_topline 1534 * is still visible. 1535 */ 1536 static void 1537 max_topfill(void) 1538 { 1539 int n; 1540 1541 n = plines_nofill(curwin->w_topline); 1542 if (n >= curwin->w_height) 1543 curwin->w_topfill = 0; 1544 else 1545 { 1546 curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline); 1547 if (curwin->w_topfill + n > curwin->w_height) 1548 curwin->w_topfill = curwin->w_height - n; 1549 } 1550 } 1551 #endif 1552 1553 /* 1554 * Scroll the screen one line down, but don't do it if it would move the 1555 * cursor off the screen. 1556 */ 1557 void 1558 scrolldown_clamp(void) 1559 { 1560 int end_row; 1561 #ifdef FEAT_DIFF 1562 int can_fill = (curwin->w_topfill 1563 < diff_check_fill(curwin, curwin->w_topline)); 1564 #endif 1565 1566 if (curwin->w_topline <= 1 1567 #ifdef FEAT_DIFF 1568 && !can_fill 1569 #endif 1570 ) 1571 return; 1572 1573 validate_cursor(); // w_wrow needs to be valid 1574 1575 /* 1576 * Compute the row number of the last row of the cursor line 1577 * and make sure it doesn't go off the screen. Make sure the cursor 1578 * doesn't go past 'scrolloff' lines from the screen end. 1579 */ 1580 end_row = curwin->w_wrow; 1581 #ifdef FEAT_DIFF 1582 if (can_fill) 1583 ++end_row; 1584 else 1585 end_row += plines_nofill(curwin->w_topline - 1); 1586 #else 1587 end_row += plines(curwin->w_topline - 1); 1588 #endif 1589 if (curwin->w_p_wrap && curwin->w_width != 0) 1590 { 1591 validate_cheight(); 1592 validate_virtcol(); 1593 end_row += curwin->w_cline_height - 1 - 1594 curwin->w_virtcol / curwin->w_width; 1595 } 1596 if (end_row < curwin->w_height - get_scrolloff_value()) 1597 { 1598 #ifdef FEAT_DIFF 1599 if (can_fill) 1600 { 1601 ++curwin->w_topfill; 1602 check_topfill(curwin, TRUE); 1603 } 1604 else 1605 { 1606 --curwin->w_topline; 1607 curwin->w_topfill = 0; 1608 } 1609 #else 1610 --curwin->w_topline; 1611 #endif 1612 #ifdef FEAT_FOLDING 1613 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 1614 #endif 1615 --curwin->w_botline; // approximate w_botline 1616 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); 1617 } 1618 } 1619 1620 /* 1621 * Scroll the screen one line up, but don't do it if it would move the cursor 1622 * off the screen. 1623 */ 1624 void 1625 scrollup_clamp(void) 1626 { 1627 int start_row; 1628 1629 if (curwin->w_topline == curbuf->b_ml.ml_line_count 1630 #ifdef FEAT_DIFF 1631 && curwin->w_topfill == 0 1632 #endif 1633 ) 1634 return; 1635 1636 validate_cursor(); // w_wrow needs to be valid 1637 1638 /* 1639 * Compute the row number of the first row of the cursor line 1640 * and make sure it doesn't go off the screen. Make sure the cursor 1641 * doesn't go before 'scrolloff' lines from the screen start. 1642 */ 1643 #ifdef FEAT_DIFF 1644 start_row = curwin->w_wrow - plines_nofill(curwin->w_topline) 1645 - curwin->w_topfill; 1646 #else 1647 start_row = curwin->w_wrow - plines(curwin->w_topline); 1648 #endif 1649 if (curwin->w_p_wrap && curwin->w_width != 0) 1650 { 1651 validate_virtcol(); 1652 start_row -= curwin->w_virtcol / curwin->w_width; 1653 } 1654 if (start_row >= get_scrolloff_value()) 1655 { 1656 #ifdef FEAT_DIFF 1657 if (curwin->w_topfill > 0) 1658 --curwin->w_topfill; 1659 else 1660 #endif 1661 { 1662 #ifdef FEAT_FOLDING 1663 (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline); 1664 #endif 1665 ++curwin->w_topline; 1666 } 1667 ++curwin->w_botline; // approximate w_botline 1668 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); 1669 } 1670 } 1671 1672 /* 1673 * Add one line above "lp->lnum". This can be a filler line, a closed fold or 1674 * a (wrapped) text line. Uses and sets "lp->fill". 1675 * Returns the height of the added line in "lp->height". 1676 * Lines above the first one are incredibly high: MAXCOL. 1677 */ 1678 static void 1679 topline_back(lineoff_T *lp) 1680 { 1681 #ifdef FEAT_DIFF 1682 if (lp->fill < diff_check_fill(curwin, lp->lnum)) 1683 { 1684 // Add a filler line. 1685 ++lp->fill; 1686 lp->height = 1; 1687 } 1688 else 1689 #endif 1690 { 1691 --lp->lnum; 1692 #ifdef FEAT_DIFF 1693 lp->fill = 0; 1694 #endif 1695 if (lp->lnum < 1) 1696 lp->height = MAXCOL; 1697 else 1698 #ifdef FEAT_FOLDING 1699 if (hasFolding(lp->lnum, &lp->lnum, NULL)) 1700 // Add a closed fold 1701 lp->height = 1; 1702 else 1703 #endif 1704 lp->height = PLINES_NOFILL(lp->lnum); 1705 } 1706 } 1707 1708 /* 1709 * Add one line below "lp->lnum". This can be a filler line, a closed fold or 1710 * a (wrapped) text line. Uses and sets "lp->fill". 1711 * Returns the height of the added line in "lp->height". 1712 * Lines below the last one are incredibly high. 1713 */ 1714 static void 1715 botline_forw(lineoff_T *lp) 1716 { 1717 #ifdef FEAT_DIFF 1718 if (lp->fill < diff_check_fill(curwin, lp->lnum + 1)) 1719 { 1720 // Add a filler line. 1721 ++lp->fill; 1722 lp->height = 1; 1723 } 1724 else 1725 #endif 1726 { 1727 ++lp->lnum; 1728 #ifdef FEAT_DIFF 1729 lp->fill = 0; 1730 #endif 1731 if (lp->lnum > curbuf->b_ml.ml_line_count) 1732 lp->height = MAXCOL; 1733 else 1734 #ifdef FEAT_FOLDING 1735 if (hasFolding(lp->lnum, NULL, &lp->lnum)) 1736 // Add a closed fold 1737 lp->height = 1; 1738 else 1739 #endif 1740 lp->height = PLINES_NOFILL(lp->lnum); 1741 } 1742 } 1743 1744 #ifdef FEAT_DIFF 1745 /* 1746 * Switch from including filler lines below lp->lnum to including filler 1747 * lines above loff.lnum + 1. This keeps pointing to the same line. 1748 * When there are no filler lines nothing changes. 1749 */ 1750 static void 1751 botline_topline(lineoff_T *lp) 1752 { 1753 if (lp->fill > 0) 1754 { 1755 ++lp->lnum; 1756 lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1; 1757 } 1758 } 1759 1760 /* 1761 * Switch from including filler lines above lp->lnum to including filler 1762 * lines below loff.lnum - 1. This keeps pointing to the same line. 1763 * When there are no filler lines nothing changes. 1764 */ 1765 static void 1766 topline_botline(lineoff_T *lp) 1767 { 1768 if (lp->fill > 0) 1769 { 1770 lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1; 1771 --lp->lnum; 1772 } 1773 } 1774 #endif 1775 1776 /* 1777 * Recompute topline to put the cursor at the top of the window. 1778 * Scroll at least "min_scroll" lines. 1779 * If "always" is TRUE, always set topline (for "zt"). 1780 */ 1781 void 1782 scroll_cursor_top(int min_scroll, int always) 1783 { 1784 int scrolled = 0; 1785 int extra = 0; 1786 int used; 1787 int i; 1788 linenr_T top; // just above displayed lines 1789 linenr_T bot; // just below displayed lines 1790 linenr_T old_topline = curwin->w_topline; 1791 #ifdef FEAT_DIFF 1792 linenr_T old_topfill = curwin->w_topfill; 1793 #endif 1794 linenr_T new_topline; 1795 int off = get_scrolloff_value(); 1796 1797 if (mouse_dragging > 0) 1798 off = mouse_dragging - 1; 1799 1800 /* 1801 * Decrease topline until: 1802 * - it has become 1 1803 * - (part of) the cursor line is moved off the screen or 1804 * - moved at least 'scrolljump' lines and 1805 * - at least 'scrolloff' lines above and below the cursor 1806 */ 1807 validate_cheight(); 1808 used = curwin->w_cline_height; // includes filler lines above 1809 if (curwin->w_cursor.lnum < curwin->w_topline) 1810 scrolled = used; 1811 1812 #ifdef FEAT_FOLDING 1813 if (hasFolding(curwin->w_cursor.lnum, &top, &bot)) 1814 { 1815 --top; 1816 ++bot; 1817 } 1818 else 1819 #endif 1820 { 1821 top = curwin->w_cursor.lnum - 1; 1822 bot = curwin->w_cursor.lnum + 1; 1823 } 1824 new_topline = top + 1; 1825 1826 #ifdef FEAT_DIFF 1827 // "used" already contains the number of filler lines above, don't add it 1828 // again. 1829 // Hide filler lines above cursor line by adding them to "extra". 1830 extra += diff_check_fill(curwin, curwin->w_cursor.lnum); 1831 #endif 1832 1833 /* 1834 * Check if the lines from "top" to "bot" fit in the window. If they do, 1835 * set new_topline and advance "top" and "bot" to include more lines. 1836 */ 1837 while (top > 0) 1838 { 1839 #ifdef FEAT_FOLDING 1840 if (hasFolding(top, &top, NULL)) 1841 // count one logical line for a sequence of folded lines 1842 i = 1; 1843 else 1844 #endif 1845 i = PLINES_NOFILL(top); 1846 used += i; 1847 if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) 1848 { 1849 #ifdef FEAT_FOLDING 1850 if (hasFolding(bot, NULL, &bot)) 1851 // count one logical line for a sequence of folded lines 1852 ++used; 1853 else 1854 #endif 1855 used += plines(bot); 1856 } 1857 if (used > curwin->w_height) 1858 break; 1859 if (top < curwin->w_topline) 1860 scrolled += i; 1861 1862 /* 1863 * If scrolling is needed, scroll at least 'sj' lines. 1864 */ 1865 if ((new_topline >= curwin->w_topline || scrolled > min_scroll) 1866 && extra >= off) 1867 break; 1868 1869 extra += i; 1870 new_topline = top; 1871 --top; 1872 ++bot; 1873 } 1874 1875 /* 1876 * If we don't have enough space, put cursor in the middle. 1877 * This makes sure we get the same position when using "k" and "j" 1878 * in a small window. 1879 */ 1880 if (used > curwin->w_height) 1881 scroll_cursor_halfway(FALSE); 1882 else 1883 { 1884 /* 1885 * If "always" is FALSE, only adjust topline to a lower value, higher 1886 * value may happen with wrapping lines 1887 */ 1888 if (new_topline < curwin->w_topline || always) 1889 curwin->w_topline = new_topline; 1890 if (curwin->w_topline > curwin->w_cursor.lnum) 1891 curwin->w_topline = curwin->w_cursor.lnum; 1892 #ifdef FEAT_DIFF 1893 curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline); 1894 if (curwin->w_topfill > 0 && extra > off) 1895 { 1896 curwin->w_topfill -= extra - off; 1897 if (curwin->w_topfill < 0) 1898 curwin->w_topfill = 0; 1899 } 1900 check_topfill(curwin, FALSE); 1901 #endif 1902 if (curwin->w_topline != old_topline 1903 #ifdef FEAT_DIFF 1904 || curwin->w_topfill != old_topfill 1905 #endif 1906 ) 1907 curwin->w_valid &= 1908 ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); 1909 curwin->w_valid |= VALID_TOPLINE; 1910 } 1911 } 1912 1913 /* 1914 * Set w_empty_rows and w_filler_rows for window "wp", having used up "used" 1915 * screen lines for text lines. 1916 */ 1917 void 1918 set_empty_rows(win_T *wp, int used) 1919 { 1920 #ifdef FEAT_DIFF 1921 wp->w_filler_rows = 0; 1922 #endif 1923 if (used == 0) 1924 wp->w_empty_rows = 0; // single line that doesn't fit 1925 else 1926 { 1927 wp->w_empty_rows = wp->w_height - used; 1928 #ifdef FEAT_DIFF 1929 if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) 1930 { 1931 wp->w_filler_rows = diff_check_fill(wp, wp->w_botline); 1932 if (wp->w_empty_rows > wp->w_filler_rows) 1933 wp->w_empty_rows -= wp->w_filler_rows; 1934 else 1935 { 1936 wp->w_filler_rows = wp->w_empty_rows; 1937 wp->w_empty_rows = 0; 1938 } 1939 } 1940 #endif 1941 } 1942 } 1943 1944 /* 1945 * Recompute topline to put the cursor at the bottom of the window. 1946 * Scroll at least "min_scroll" lines. 1947 * If "set_topbot" is TRUE, set topline and botline first (for "zb"). 1948 * This is messy stuff!!! 1949 */ 1950 void 1951 scroll_cursor_bot(int min_scroll, int set_topbot) 1952 { 1953 int used; 1954 int scrolled = 0; 1955 int extra = 0; 1956 int i; 1957 linenr_T line_count; 1958 linenr_T old_topline = curwin->w_topline; 1959 lineoff_T loff; 1960 lineoff_T boff; 1961 #ifdef FEAT_DIFF 1962 int old_topfill = curwin->w_topfill; 1963 int fill_below_window; 1964 #endif 1965 linenr_T old_botline = curwin->w_botline; 1966 linenr_T old_valid = curwin->w_valid; 1967 int old_empty_rows = curwin->w_empty_rows; 1968 linenr_T cln; // Cursor Line Number 1969 long so = get_scrolloff_value(); 1970 1971 cln = curwin->w_cursor.lnum; 1972 if (set_topbot) 1973 { 1974 used = 0; 1975 curwin->w_botline = cln + 1; 1976 #ifdef FEAT_DIFF 1977 loff.fill = 0; 1978 #endif 1979 for (curwin->w_topline = curwin->w_botline; 1980 curwin->w_topline > 1; 1981 curwin->w_topline = loff.lnum) 1982 { 1983 loff.lnum = curwin->w_topline; 1984 topline_back(&loff); 1985 if (loff.height == MAXCOL || used + loff.height > curwin->w_height) 1986 break; 1987 used += loff.height; 1988 #ifdef FEAT_DIFF 1989 curwin->w_topfill = loff.fill; 1990 #endif 1991 } 1992 set_empty_rows(curwin, used); 1993 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; 1994 if (curwin->w_topline != old_topline 1995 #ifdef FEAT_DIFF 1996 || curwin->w_topfill != old_topfill 1997 #endif 1998 ) 1999 curwin->w_valid &= ~(VALID_WROW|VALID_CROW); 2000 } 2001 else 2002 validate_botline(); 2003 2004 // The lines of the cursor line itself are always used. 2005 #ifdef FEAT_DIFF 2006 used = plines_nofill(cln); 2007 #else 2008 validate_cheight(); 2009 used = curwin->w_cline_height; 2010 #endif 2011 2012 // If the cursor is below botline, we will at least scroll by the height 2013 // of the cursor line. Correct for empty lines, which are really part of 2014 // botline. 2015 if (cln >= curwin->w_botline) 2016 { 2017 scrolled = used; 2018 if (cln == curwin->w_botline) 2019 scrolled -= curwin->w_empty_rows; 2020 } 2021 2022 /* 2023 * Stop counting lines to scroll when 2024 * - hitting start of the file 2025 * - scrolled nothing or at least 'sj' lines 2026 * - at least 'scrolloff' lines below the cursor 2027 * - lines between botline and cursor have been counted 2028 */ 2029 #ifdef FEAT_FOLDING 2030 if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum)) 2031 #endif 2032 { 2033 loff.lnum = cln; 2034 boff.lnum = cln; 2035 } 2036 #ifdef FEAT_DIFF 2037 loff.fill = 0; 2038 boff.fill = 0; 2039 fill_below_window = diff_check_fill(curwin, curwin->w_botline) 2040 - curwin->w_filler_rows; 2041 #endif 2042 2043 while (loff.lnum > 1) 2044 { 2045 // Stop when scrolled nothing or at least "min_scroll", found "extra" 2046 // context for 'scrolloff' and counted all lines below the window. 2047 if ((((scrolled <= 0 || scrolled >= min_scroll) 2048 && extra >= (mouse_dragging > 0 ? mouse_dragging - 1 : so)) 2049 || boff.lnum + 1 > curbuf->b_ml.ml_line_count) 2050 && loff.lnum <= curwin->w_botline 2051 #ifdef FEAT_DIFF 2052 && (loff.lnum < curwin->w_botline 2053 || loff.fill >= fill_below_window) 2054 #endif 2055 ) 2056 break; 2057 2058 // Add one line above 2059 topline_back(&loff); 2060 if (loff.height == MAXCOL) 2061 used = MAXCOL; 2062 else 2063 used += loff.height; 2064 if (used > curwin->w_height) 2065 break; 2066 if (loff.lnum >= curwin->w_botline 2067 #ifdef FEAT_DIFF 2068 && (loff.lnum > curwin->w_botline 2069 || loff.fill <= fill_below_window) 2070 #endif 2071 ) 2072 { 2073 // Count screen lines that are below the window. 2074 scrolled += loff.height; 2075 if (loff.lnum == curwin->w_botline 2076 #ifdef FEAT_DIFF 2077 && loff.fill == 0 2078 #endif 2079 ) 2080 scrolled -= curwin->w_empty_rows; 2081 } 2082 2083 if (boff.lnum < curbuf->b_ml.ml_line_count) 2084 { 2085 // Add one line below 2086 botline_forw(&boff); 2087 used += boff.height; 2088 if (used > curwin->w_height) 2089 break; 2090 if (extra < ( mouse_dragging > 0 ? mouse_dragging - 1 : so) 2091 || scrolled < min_scroll) 2092 { 2093 extra += boff.height; 2094 if (boff.lnum >= curwin->w_botline 2095 #ifdef FEAT_DIFF 2096 || (boff.lnum + 1 == curwin->w_botline 2097 && boff.fill > curwin->w_filler_rows) 2098 #endif 2099 ) 2100 { 2101 // Count screen lines that are below the window. 2102 scrolled += boff.height; 2103 if (boff.lnum == curwin->w_botline 2104 #ifdef FEAT_DIFF 2105 && boff.fill == 0 2106 #endif 2107 ) 2108 scrolled -= curwin->w_empty_rows; 2109 } 2110 } 2111 } 2112 } 2113 2114 // curwin->w_empty_rows is larger, no need to scroll 2115 if (scrolled <= 0) 2116 line_count = 0; 2117 // more than a screenfull, don't scroll but redraw 2118 else if (used > curwin->w_height) 2119 line_count = used; 2120 // scroll minimal number of lines 2121 else 2122 { 2123 line_count = 0; 2124 #ifdef FEAT_DIFF 2125 boff.fill = curwin->w_topfill; 2126 #endif 2127 boff.lnum = curwin->w_topline - 1; 2128 for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; ) 2129 { 2130 botline_forw(&boff); 2131 i += boff.height; 2132 ++line_count; 2133 } 2134 if (i < scrolled) // below curwin->w_botline, don't scroll 2135 line_count = 9999; 2136 } 2137 2138 /* 2139 * Scroll up if the cursor is off the bottom of the screen a bit. 2140 * Otherwise put it at 1/2 of the screen. 2141 */ 2142 if (line_count >= curwin->w_height && line_count > min_scroll) 2143 scroll_cursor_halfway(FALSE); 2144 else 2145 scrollup(line_count, TRUE); 2146 2147 /* 2148 * If topline didn't change we need to restore w_botline and w_empty_rows 2149 * (we changed them). 2150 * If topline did change, update_screen() will set botline. 2151 */ 2152 if (curwin->w_topline == old_topline && set_topbot) 2153 { 2154 curwin->w_botline = old_botline; 2155 curwin->w_empty_rows = old_empty_rows; 2156 curwin->w_valid = old_valid; 2157 } 2158 curwin->w_valid |= VALID_TOPLINE; 2159 } 2160 2161 /* 2162 * Recompute topline to put the cursor halfway the window 2163 * If "atend" is TRUE, also put it halfway at the end of the file. 2164 */ 2165 void 2166 scroll_cursor_halfway(int atend) 2167 { 2168 int above = 0; 2169 linenr_T topline; 2170 #ifdef FEAT_DIFF 2171 int topfill = 0; 2172 #endif 2173 int below = 0; 2174 int used; 2175 lineoff_T loff; 2176 lineoff_T boff; 2177 #ifdef FEAT_DIFF 2178 linenr_T old_topline = curwin->w_topline; 2179 #endif 2180 2181 #ifdef FEAT_PROP_POPUP 2182 // if the width changed this needs to be updated first 2183 may_update_popup_position(); 2184 #endif 2185 loff.lnum = boff.lnum = curwin->w_cursor.lnum; 2186 #ifdef FEAT_FOLDING 2187 (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum); 2188 #endif 2189 #ifdef FEAT_DIFF 2190 used = plines_nofill(loff.lnum); 2191 loff.fill = 0; 2192 boff.fill = 0; 2193 #else 2194 used = plines(loff.lnum); 2195 #endif 2196 topline = loff.lnum; 2197 while (topline > 1) 2198 { 2199 if (below <= above) // add a line below the cursor first 2200 { 2201 if (boff.lnum < curbuf->b_ml.ml_line_count) 2202 { 2203 botline_forw(&boff); 2204 used += boff.height; 2205 if (used > curwin->w_height) 2206 break; 2207 below += boff.height; 2208 } 2209 else 2210 { 2211 ++below; // count a "~" line 2212 if (atend) 2213 ++used; 2214 } 2215 } 2216 2217 if (below > above) // add a line above the cursor 2218 { 2219 topline_back(&loff); 2220 if (loff.height == MAXCOL) 2221 used = MAXCOL; 2222 else 2223 used += loff.height; 2224 if (used > curwin->w_height) 2225 break; 2226 above += loff.height; 2227 topline = loff.lnum; 2228 #ifdef FEAT_DIFF 2229 topfill = loff.fill; 2230 #endif 2231 } 2232 } 2233 #ifdef FEAT_FOLDING 2234 if (!hasFolding(topline, &curwin->w_topline, NULL)) 2235 #endif 2236 curwin->w_topline = topline; 2237 #ifdef FEAT_DIFF 2238 curwin->w_topfill = topfill; 2239 if (old_topline > curwin->w_topline + curwin->w_height) 2240 curwin->w_botfill = FALSE; 2241 check_topfill(curwin, FALSE); 2242 #endif 2243 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); 2244 curwin->w_valid |= VALID_TOPLINE; 2245 } 2246 2247 /* 2248 * Correct the cursor position so that it is in a part of the screen at least 2249 * 'scrolloff' lines from the top and bottom, if possible. 2250 * If not possible, put it at the same position as scroll_cursor_halfway(). 2251 * When called topline must be valid! 2252 */ 2253 void 2254 cursor_correct(void) 2255 { 2256 int above = 0; // screen lines above topline 2257 linenr_T topline; 2258 int below = 0; // screen lines below botline 2259 linenr_T botline; 2260 int above_wanted, below_wanted; 2261 linenr_T cln; // Cursor Line Number 2262 int max_off; 2263 long so = get_scrolloff_value(); 2264 2265 /* 2266 * How many lines we would like to have above/below the cursor depends on 2267 * whether the first/last line of the file is on screen. 2268 */ 2269 above_wanted = so; 2270 below_wanted = so; 2271 if (mouse_dragging > 0) 2272 { 2273 above_wanted = mouse_dragging - 1; 2274 below_wanted = mouse_dragging - 1; 2275 } 2276 if (curwin->w_topline == 1) 2277 { 2278 above_wanted = 0; 2279 max_off = curwin->w_height / 2; 2280 if (below_wanted > max_off) 2281 below_wanted = max_off; 2282 } 2283 validate_botline(); 2284 if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1 2285 && mouse_dragging == 0) 2286 { 2287 below_wanted = 0; 2288 max_off = (curwin->w_height - 1) / 2; 2289 if (above_wanted > max_off) 2290 above_wanted = max_off; 2291 } 2292 2293 /* 2294 * If there are sufficient file-lines above and below the cursor, we can 2295 * return now. 2296 */ 2297 cln = curwin->w_cursor.lnum; 2298 if (cln >= curwin->w_topline + above_wanted 2299 && cln < curwin->w_botline - below_wanted 2300 #ifdef FEAT_FOLDING 2301 && !hasAnyFolding(curwin) 2302 #endif 2303 ) 2304 return; 2305 2306 /* 2307 * Narrow down the area where the cursor can be put by taking lines from 2308 * the top and the bottom until: 2309 * - the desired context lines are found 2310 * - the lines from the top is past the lines from the bottom 2311 */ 2312 topline = curwin->w_topline; 2313 botline = curwin->w_botline - 1; 2314 #ifdef FEAT_DIFF 2315 // count filler lines as context 2316 above = curwin->w_topfill; 2317 below = curwin->w_filler_rows; 2318 #endif 2319 while ((above < above_wanted || below < below_wanted) && topline < botline) 2320 { 2321 if (below < below_wanted && (below <= above || above >= above_wanted)) 2322 { 2323 #ifdef FEAT_FOLDING 2324 if (hasFolding(botline, &botline, NULL)) 2325 ++below; 2326 else 2327 #endif 2328 below += plines(botline); 2329 --botline; 2330 } 2331 if (above < above_wanted && (above < below || below >= below_wanted)) 2332 { 2333 #ifdef FEAT_FOLDING 2334 if (hasFolding(topline, NULL, &topline)) 2335 ++above; 2336 else 2337 #endif 2338 above += PLINES_NOFILL(topline); 2339 #ifdef FEAT_DIFF 2340 // Count filler lines below this line as context. 2341 if (topline < botline) 2342 above += diff_check_fill(curwin, topline + 1); 2343 #endif 2344 ++topline; 2345 } 2346 } 2347 if (topline == botline || botline == 0) 2348 curwin->w_cursor.lnum = topline; 2349 else if (topline > botline) 2350 curwin->w_cursor.lnum = botline; 2351 else 2352 { 2353 if (cln < topline && curwin->w_topline > 1) 2354 { 2355 curwin->w_cursor.lnum = topline; 2356 curwin->w_valid &= 2357 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW); 2358 } 2359 if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count) 2360 { 2361 curwin->w_cursor.lnum = botline; 2362 curwin->w_valid &= 2363 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW); 2364 } 2365 } 2366 curwin->w_valid |= VALID_TOPLINE; 2367 } 2368 2369 static void get_scroll_overlap(lineoff_T *lp, int dir); 2370 2371 /* 2372 * move screen 'count' pages up or down and update screen 2373 * 2374 * return FAIL for failure, OK otherwise 2375 */ 2376 int 2377 onepage(int dir, long count) 2378 { 2379 long n; 2380 int retval = OK; 2381 lineoff_T loff; 2382 linenr_T old_topline = curwin->w_topline; 2383 long so = get_scrolloff_value(); 2384 2385 if (curbuf->b_ml.ml_line_count == 1) // nothing to do 2386 { 2387 beep_flush(); 2388 return FAIL; 2389 } 2390 2391 for ( ; count > 0; --count) 2392 { 2393 validate_botline(); 2394 /* 2395 * It's an error to move a page up when the first line is already on 2396 * the screen. It's an error to move a page down when the last line 2397 * is on the screen and the topline is 'scrolloff' lines from the 2398 * last line. 2399 */ 2400 if (dir == FORWARD 2401 ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so) 2402 && curwin->w_botline > curbuf->b_ml.ml_line_count) 2403 : (curwin->w_topline == 1 2404 #ifdef FEAT_DIFF 2405 && curwin->w_topfill == 2406 diff_check_fill(curwin, curwin->w_topline) 2407 #endif 2408 )) 2409 { 2410 beep_flush(); 2411 retval = FAIL; 2412 break; 2413 } 2414 2415 #ifdef FEAT_DIFF 2416 loff.fill = 0; 2417 #endif 2418 if (dir == FORWARD) 2419 { 2420 if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) 2421 { 2422 // Vi compatible scrolling 2423 if (p_window <= 2) 2424 ++curwin->w_topline; 2425 else 2426 curwin->w_topline += p_window - 2; 2427 if (curwin->w_topline > curbuf->b_ml.ml_line_count) 2428 curwin->w_topline = curbuf->b_ml.ml_line_count; 2429 curwin->w_cursor.lnum = curwin->w_topline; 2430 } 2431 else if (curwin->w_botline > curbuf->b_ml.ml_line_count) 2432 { 2433 // at end of file 2434 curwin->w_topline = curbuf->b_ml.ml_line_count; 2435 #ifdef FEAT_DIFF 2436 curwin->w_topfill = 0; 2437 #endif 2438 curwin->w_valid &= ~(VALID_WROW|VALID_CROW); 2439 } 2440 else 2441 { 2442 // For the overlap, start with the line just below the window 2443 // and go upwards. 2444 loff.lnum = curwin->w_botline; 2445 #ifdef FEAT_DIFF 2446 loff.fill = diff_check_fill(curwin, loff.lnum) 2447 - curwin->w_filler_rows; 2448 #endif 2449 get_scroll_overlap(&loff, -1); 2450 curwin->w_topline = loff.lnum; 2451 #ifdef FEAT_DIFF 2452 curwin->w_topfill = loff.fill; 2453 check_topfill(curwin, FALSE); 2454 #endif 2455 curwin->w_cursor.lnum = curwin->w_topline; 2456 curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW| 2457 VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); 2458 } 2459 } 2460 else // dir == BACKWARDS 2461 { 2462 #ifdef FEAT_DIFF 2463 if (curwin->w_topline == 1) 2464 { 2465 // Include max number of filler lines 2466 max_topfill(); 2467 continue; 2468 } 2469 #endif 2470 if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) 2471 { 2472 // Vi compatible scrolling (sort of) 2473 if (p_window <= 2) 2474 --curwin->w_topline; 2475 else 2476 curwin->w_topline -= p_window - 2; 2477 if (curwin->w_topline < 1) 2478 curwin->w_topline = 1; 2479 curwin->w_cursor.lnum = curwin->w_topline + p_window - 1; 2480 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 2481 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 2482 continue; 2483 } 2484 2485 // Find the line at the top of the window that is going to be the 2486 // line at the bottom of the window. Make sure this results in 2487 // the same line as before doing CTRL-F. 2488 loff.lnum = curwin->w_topline - 1; 2489 #ifdef FEAT_DIFF 2490 loff.fill = diff_check_fill(curwin, loff.lnum + 1) 2491 - curwin->w_topfill; 2492 #endif 2493 get_scroll_overlap(&loff, 1); 2494 2495 if (loff.lnum >= curbuf->b_ml.ml_line_count) 2496 { 2497 loff.lnum = curbuf->b_ml.ml_line_count; 2498 #ifdef FEAT_DIFF 2499 loff.fill = 0; 2500 } 2501 else 2502 { 2503 botline_topline(&loff); 2504 #endif 2505 } 2506 curwin->w_cursor.lnum = loff.lnum; 2507 2508 // Find the line just above the new topline to get the right line 2509 // at the bottom of the window. 2510 n = 0; 2511 while (n <= curwin->w_height && loff.lnum >= 1) 2512 { 2513 topline_back(&loff); 2514 if (loff.height == MAXCOL) 2515 n = MAXCOL; 2516 else 2517 n += loff.height; 2518 } 2519 if (loff.lnum < 1) // at begin of file 2520 { 2521 curwin->w_topline = 1; 2522 #ifdef FEAT_DIFF 2523 max_topfill(); 2524 #endif 2525 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); 2526 } 2527 else 2528 { 2529 // Go two lines forward again. 2530 #ifdef FEAT_DIFF 2531 topline_botline(&loff); 2532 #endif 2533 botline_forw(&loff); 2534 botline_forw(&loff); 2535 #ifdef FEAT_DIFF 2536 botline_topline(&loff); 2537 #endif 2538 #ifdef FEAT_FOLDING 2539 // We're at the wrong end of a fold now. 2540 (void)hasFolding(loff.lnum, &loff.lnum, NULL); 2541 #endif 2542 2543 // Always scroll at least one line. Avoid getting stuck on 2544 // very long lines. 2545 if (loff.lnum >= curwin->w_topline 2546 #ifdef FEAT_DIFF 2547 && (loff.lnum > curwin->w_topline 2548 || loff.fill >= curwin->w_topfill) 2549 #endif 2550 ) 2551 { 2552 #ifdef FEAT_DIFF 2553 // First try using the maximum number of filler lines. If 2554 // that's not enough, backup one line. 2555 loff.fill = curwin->w_topfill; 2556 if (curwin->w_topfill < diff_check_fill(curwin, 2557 curwin->w_topline)) 2558 max_topfill(); 2559 if (curwin->w_topfill == loff.fill) 2560 #endif 2561 { 2562 --curwin->w_topline; 2563 #ifdef FEAT_DIFF 2564 curwin->w_topfill = 0; 2565 #endif 2566 } 2567 comp_botline(curwin); 2568 curwin->w_cursor.lnum = curwin->w_botline - 1; 2569 curwin->w_valid &= 2570 ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW); 2571 } 2572 else 2573 { 2574 curwin->w_topline = loff.lnum; 2575 #ifdef FEAT_DIFF 2576 curwin->w_topfill = loff.fill; 2577 check_topfill(curwin, FALSE); 2578 #endif 2579 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); 2580 } 2581 } 2582 } 2583 } 2584 #ifdef FEAT_FOLDING 2585 foldAdjustCursor(); 2586 #endif 2587 cursor_correct(); 2588 check_cursor_col(); 2589 if (retval == OK) 2590 beginline(BL_SOL | BL_FIX); 2591 curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL); 2592 2593 if (retval == OK && dir == FORWARD) 2594 { 2595 // Avoid the screen jumping up and down when 'scrolloff' is non-zero. 2596 // But make sure we scroll at least one line (happens with mix of long 2597 // wrapping lines and non-wrapping line). 2598 if (check_top_offset()) 2599 { 2600 scroll_cursor_top(1, FALSE); 2601 if (curwin->w_topline <= old_topline 2602 && old_topline < curbuf->b_ml.ml_line_count) 2603 { 2604 curwin->w_topline = old_topline + 1; 2605 #ifdef FEAT_FOLDING 2606 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 2607 #endif 2608 } 2609 } 2610 #ifdef FEAT_FOLDING 2611 else if (curwin->w_botline > curbuf->b_ml.ml_line_count) 2612 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 2613 #endif 2614 } 2615 2616 redraw_later(VALID); 2617 return retval; 2618 } 2619 2620 /* 2621 * Decide how much overlap to use for page-up or page-down scrolling. 2622 * This is symmetric, so that doing both keeps the same lines displayed. 2623 * Three lines are examined: 2624 * 2625 * before CTRL-F after CTRL-F / before CTRL-B 2626 * etc. l1 2627 * l1 last but one line ------------ 2628 * l2 last text line l2 top text line 2629 * ------------- l3 second text line 2630 * l3 etc. 2631 */ 2632 static void 2633 get_scroll_overlap(lineoff_T *lp, int dir) 2634 { 2635 int h1, h2, h3, h4; 2636 int min_height = curwin->w_height - 2; 2637 lineoff_T loff0, loff1, loff2; 2638 2639 #ifdef FEAT_DIFF 2640 if (lp->fill > 0) 2641 lp->height = 1; 2642 else 2643 lp->height = plines_nofill(lp->lnum); 2644 #else 2645 lp->height = plines(lp->lnum); 2646 #endif 2647 h1 = lp->height; 2648 if (h1 > min_height) 2649 return; // no overlap 2650 2651 loff0 = *lp; 2652 if (dir > 0) 2653 botline_forw(lp); 2654 else 2655 topline_back(lp); 2656 h2 = lp->height; 2657 if (h2 == MAXCOL || h2 + h1 > min_height) 2658 { 2659 *lp = loff0; // no overlap 2660 return; 2661 } 2662 2663 loff1 = *lp; 2664 if (dir > 0) 2665 botline_forw(lp); 2666 else 2667 topline_back(lp); 2668 h3 = lp->height; 2669 if (h3 == MAXCOL || h3 + h2 > min_height) 2670 { 2671 *lp = loff0; // no overlap 2672 return; 2673 } 2674 2675 loff2 = *lp; 2676 if (dir > 0) 2677 botline_forw(lp); 2678 else 2679 topline_back(lp); 2680 h4 = lp->height; 2681 if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) 2682 *lp = loff1; // 1 line overlap 2683 else 2684 *lp = loff2; // 2 lines overlap 2685 return; 2686 } 2687 2688 /* 2689 * Scroll 'scroll' lines up or down. 2690 */ 2691 void 2692 halfpage(int flag, linenr_T Prenum) 2693 { 2694 long scrolled = 0; 2695 int i; 2696 int n; 2697 int room; 2698 2699 if (Prenum) 2700 curwin->w_p_scr = (Prenum > curwin->w_height) ? 2701 curwin->w_height : Prenum; 2702 n = (curwin->w_p_scr <= curwin->w_height) ? 2703 curwin->w_p_scr : curwin->w_height; 2704 2705 update_topline(); 2706 validate_botline(); 2707 room = curwin->w_empty_rows; 2708 #ifdef FEAT_DIFF 2709 room += curwin->w_filler_rows; 2710 #endif 2711 if (flag) 2712 { 2713 /* 2714 * scroll the text up 2715 */ 2716 while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count) 2717 { 2718 #ifdef FEAT_DIFF 2719 if (curwin->w_topfill > 0) 2720 { 2721 i = 1; 2722 --n; 2723 --curwin->w_topfill; 2724 } 2725 else 2726 #endif 2727 { 2728 i = PLINES_NOFILL(curwin->w_topline); 2729 n -= i; 2730 if (n < 0 && scrolled > 0) 2731 break; 2732 #ifdef FEAT_FOLDING 2733 (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline); 2734 #endif 2735 ++curwin->w_topline; 2736 #ifdef FEAT_DIFF 2737 curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline); 2738 #endif 2739 2740 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 2741 { 2742 ++curwin->w_cursor.lnum; 2743 curwin->w_valid &= 2744 ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); 2745 } 2746 } 2747 curwin->w_valid &= ~(VALID_CROW|VALID_WROW); 2748 scrolled += i; 2749 2750 /* 2751 * Correct w_botline for changed w_topline. 2752 * Won't work when there are filler lines. 2753 */ 2754 #ifdef FEAT_DIFF 2755 if (curwin->w_p_diff) 2756 curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); 2757 else 2758 #endif 2759 { 2760 room += i; 2761 do 2762 { 2763 i = plines(curwin->w_botline); 2764 if (i > room) 2765 break; 2766 #ifdef FEAT_FOLDING 2767 (void)hasFolding(curwin->w_botline, NULL, 2768 &curwin->w_botline); 2769 #endif 2770 ++curwin->w_botline; 2771 room -= i; 2772 } while (curwin->w_botline <= curbuf->b_ml.ml_line_count); 2773 } 2774 } 2775 2776 /* 2777 * When hit bottom of the file: move cursor down. 2778 */ 2779 if (n > 0) 2780 { 2781 # ifdef FEAT_FOLDING 2782 if (hasAnyFolding(curwin)) 2783 { 2784 while (--n >= 0 2785 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 2786 { 2787 (void)hasFolding(curwin->w_cursor.lnum, NULL, 2788 &curwin->w_cursor.lnum); 2789 ++curwin->w_cursor.lnum; 2790 } 2791 } 2792 else 2793 # endif 2794 curwin->w_cursor.lnum += n; 2795 check_cursor_lnum(); 2796 } 2797 } 2798 else 2799 { 2800 /* 2801 * scroll the text down 2802 */ 2803 while (n > 0 && curwin->w_topline > 1) 2804 { 2805 #ifdef FEAT_DIFF 2806 if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline)) 2807 { 2808 i = 1; 2809 --n; 2810 ++curwin->w_topfill; 2811 } 2812 else 2813 #endif 2814 { 2815 i = PLINES_NOFILL(curwin->w_topline - 1); 2816 n -= i; 2817 if (n < 0 && scrolled > 0) 2818 break; 2819 --curwin->w_topline; 2820 #ifdef FEAT_FOLDING 2821 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 2822 #endif 2823 #ifdef FEAT_DIFF 2824 curwin->w_topfill = 0; 2825 #endif 2826 } 2827 curwin->w_valid &= ~(VALID_CROW|VALID_WROW| 2828 VALID_BOTLINE|VALID_BOTLINE_AP); 2829 scrolled += i; 2830 if (curwin->w_cursor.lnum > 1) 2831 { 2832 --curwin->w_cursor.lnum; 2833 curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); 2834 } 2835 } 2836 2837 /* 2838 * When hit top of the file: move cursor up. 2839 */ 2840 if (n > 0) 2841 { 2842 if (curwin->w_cursor.lnum <= (linenr_T)n) 2843 curwin->w_cursor.lnum = 1; 2844 else 2845 # ifdef FEAT_FOLDING 2846 if (hasAnyFolding(curwin)) 2847 { 2848 while (--n >= 0 && curwin->w_cursor.lnum > 1) 2849 { 2850 --curwin->w_cursor.lnum; 2851 (void)hasFolding(curwin->w_cursor.lnum, 2852 &curwin->w_cursor.lnum, NULL); 2853 } 2854 } 2855 else 2856 # endif 2857 curwin->w_cursor.lnum -= n; 2858 } 2859 } 2860 # ifdef FEAT_FOLDING 2861 // Move cursor to first line of closed fold. 2862 foldAdjustCursor(); 2863 # endif 2864 #ifdef FEAT_DIFF 2865 check_topfill(curwin, !flag); 2866 #endif 2867 cursor_correct(); 2868 beginline(BL_SOL | BL_FIX); 2869 redraw_later(VALID); 2870 } 2871 2872 void 2873 do_check_cursorbind(void) 2874 { 2875 linenr_T line = curwin->w_cursor.lnum; 2876 colnr_T col = curwin->w_cursor.col; 2877 colnr_T coladd = curwin->w_cursor.coladd; 2878 colnr_T curswant = curwin->w_curswant; 2879 int set_curswant = curwin->w_set_curswant; 2880 win_T *old_curwin = curwin; 2881 buf_T *old_curbuf = curbuf; 2882 int restart_edit_save; 2883 int old_VIsual_select = VIsual_select; 2884 int old_VIsual_active = VIsual_active; 2885 2886 /* 2887 * loop through the cursorbound windows 2888 */ 2889 VIsual_select = VIsual_active = 0; 2890 FOR_ALL_WINDOWS(curwin) 2891 { 2892 curbuf = curwin->w_buffer; 2893 // skip original window and windows with 'noscrollbind' 2894 if (curwin != old_curwin && curwin->w_p_crb) 2895 { 2896 # ifdef FEAT_DIFF 2897 if (curwin->w_p_diff) 2898 curwin->w_cursor.lnum = 2899 diff_get_corresponding_line(old_curbuf, line); 2900 else 2901 # endif 2902 curwin->w_cursor.lnum = line; 2903 curwin->w_cursor.col = col; 2904 curwin->w_cursor.coladd = coladd; 2905 curwin->w_curswant = curswant; 2906 curwin->w_set_curswant = set_curswant; 2907 2908 // Make sure the cursor is in a valid position. Temporarily set 2909 // "restart_edit" to allow the cursor to be beyond the EOL. 2910 restart_edit_save = restart_edit; 2911 restart_edit = TRUE; 2912 check_cursor(); 2913 # ifdef FEAT_SYN_HL 2914 if (curwin->w_p_cul || curwin->w_p_cuc) 2915 validate_cursor(); 2916 # endif 2917 restart_edit = restart_edit_save; 2918 // Correct cursor for multi-byte character. 2919 if (has_mbyte) 2920 mb_adjust_cursor(); 2921 redraw_later(VALID); 2922 2923 // Only scroll when 'scrollbind' hasn't done this. 2924 if (!curwin->w_p_scb) 2925 update_topline(); 2926 curwin->w_redr_status = TRUE; 2927 } 2928 } 2929 2930 /* 2931 * reset current-window 2932 */ 2933 VIsual_select = old_VIsual_select; 2934 VIsual_active = old_VIsual_active; 2935 curwin = old_curwin; 2936 curbuf = old_curbuf; 2937 } 2938