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