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 /* 11 * drawscreen.c: Code for updating all the windows on the screen. 12 * This is the top level, drawline.c is the middle and screen.c the lower 13 * level. 14 * 15 * update_screen() is the function that updates all windows and status lines. 16 * It is called form the main loop when must_redraw is non-zero. It may be 17 * called from other places when an immediate screen update is needed. 18 * 19 * The part of the buffer that is displayed in a window is set with: 20 * - w_topline (first buffer line in window) 21 * - w_topfill (filler lines above the first line) 22 * - w_leftcol (leftmost window cell in window), 23 * - w_skipcol (skipped window cells of first line) 24 * 25 * Commands that only move the cursor around in a window, do not need to take 26 * action to update the display. The main loop will check if w_topline is 27 * valid and update it (scroll the window) when needed. 28 * 29 * Commands that scroll a window change w_topline and must call 30 * check_cursor() to move the cursor into the visible part of the window, and 31 * call redraw_later(VALID) to have the window displayed by update_screen() 32 * later. 33 * 34 * Commands that change text in the buffer must call changed_bytes() or 35 * changed_lines() to mark the area that changed and will require updating 36 * later. The main loop will call update_screen(), which will update each 37 * window that shows the changed buffer. This assumes text above the change 38 * can remain displayed as it is. Text after the change may need updating for 39 * scrolling, folding and syntax highlighting. 40 * 41 * Commands that change how a window is displayed (e.g., setting 'list') or 42 * invalidate the contents of a window in another way (e.g., change fold 43 * settings), must call redraw_later(NOT_VALID) to have the whole window 44 * redisplayed by update_screen() later. 45 * 46 * Commands that change how a buffer is displayed (e.g., setting 'tabstop') 47 * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the 48 * buffer redisplayed by update_screen() later. 49 * 50 * Commands that change highlighting and possibly cause a scroll too must call 51 * redraw_later(SOME_VALID) to update the whole window but still use scrolling 52 * to avoid redrawing everything. But the length of displayed lines must not 53 * change, use NOT_VALID then. 54 * 55 * Commands that move the window position must call redraw_later(NOT_VALID). 56 * TODO: should minimize redrawing by scrolling when possible. 57 * 58 * Commands that change everything (e.g., resizing the screen) must call 59 * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR). 60 * 61 * Things that are handled indirectly: 62 * - When messages scroll the screen up, msg_scrolled will be set and 63 * update_screen() called to redraw. 64 */ 65 66 #include "vim.h" 67 68 static void win_update(win_T *wp); 69 #ifdef FEAT_STL_OPT 70 static void redraw_custom_statusline(win_T *wp); 71 #endif 72 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) 73 static int did_update_one_window; 74 #endif 75 76 static void win_redr_status(win_T *wp, int ignore_pum); 77 78 /* 79 * Based on the current value of curwin->w_topline, transfer a screenfull 80 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline. 81 * Return OK when the screen was updated, FAIL if it was not done. 82 */ 83 int 84 update_screen(int type_arg) 85 { 86 int type = type_arg; 87 win_T *wp; 88 static int did_intro = FALSE; 89 #ifdef FEAT_GUI 90 int did_one = FALSE; 91 int did_undraw = FALSE; 92 int gui_cursor_col = 0; 93 int gui_cursor_row = 0; 94 #endif 95 int no_update = FALSE; 96 int save_pum_will_redraw = pum_will_redraw; 97 98 // Don't do anything if the screen structures are (not yet) valid. 99 if (!screen_valid(TRUE)) 100 return FAIL; 101 102 if (type == VALID_NO_UPDATE) 103 { 104 no_update = TRUE; 105 type = 0; 106 } 107 108 #ifdef FEAT_EVAL 109 { 110 buf_T *buf; 111 112 // Before updating the screen, notify any listeners of changed text. 113 FOR_ALL_BUFFERS(buf) 114 invoke_listeners(buf); 115 } 116 #endif 117 118 #ifdef FEAT_DIFF 119 // May have postponed updating diffs. 120 if (need_diff_redraw) 121 diff_redraw(TRUE); 122 #endif 123 124 if (must_redraw) 125 { 126 if (type < must_redraw) // use maximal type 127 type = must_redraw; 128 129 // must_redraw is reset here, so that when we run into some weird 130 // reason to redraw while busy redrawing (e.g., asynchronous 131 // scrolling), or update_topline() in win_update() will cause a 132 // scroll, the screen will be redrawn later or in win_update(). 133 must_redraw = 0; 134 } 135 136 // May need to update w_lines[]. 137 if (curwin->w_lines_valid == 0 && type < NOT_VALID 138 #ifdef FEAT_TERMINAL 139 && !term_do_update_window(curwin) 140 #endif 141 ) 142 type = NOT_VALID; 143 144 // Postpone the redrawing when it's not needed and when being called 145 // recursively. 146 if (!redrawing() || updating_screen) 147 { 148 redraw_later(type); // remember type for next time 149 must_redraw = type; 150 if (type > INVERTED_ALL) 151 curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now 152 return FAIL; 153 } 154 updating_screen = TRUE; 155 156 #ifdef FEAT_PROP_POPUP 157 // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot 158 // in some windows. 159 may_update_popup_mask(type); 160 #endif 161 162 #ifdef FEAT_SYN_HL 163 ++display_tick; // let syntax code know we're in a next round of 164 // display updating 165 #endif 166 if (no_update) 167 ++no_win_do_lines_ins; 168 169 // if the screen was scrolled up when displaying a message, scroll it down 170 if (msg_scrolled) 171 { 172 clear_cmdline = TRUE; 173 if (msg_scrolled > Rows - 5) // clearing is faster 174 type = CLEAR; 175 else if (type != CLEAR) 176 { 177 check_for_delay(FALSE); 178 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL) 179 == FAIL) 180 type = CLEAR; 181 FOR_ALL_WINDOWS(wp) 182 { 183 if (wp->w_winrow < msg_scrolled) 184 { 185 if (W_WINROW(wp) + wp->w_height > msg_scrolled 186 && wp->w_redr_type < REDRAW_TOP 187 && wp->w_lines_valid > 0 188 && wp->w_topline == wp->w_lines[0].wl_lnum) 189 { 190 wp->w_upd_rows = msg_scrolled - W_WINROW(wp); 191 wp->w_redr_type = REDRAW_TOP; 192 } 193 else 194 { 195 wp->w_redr_type = NOT_VALID; 196 if (W_WINROW(wp) + wp->w_height + wp->w_status_height 197 <= msg_scrolled) 198 wp->w_redr_status = TRUE; 199 } 200 } 201 } 202 if (!no_update) 203 redraw_cmdline = TRUE; 204 redraw_tabline = TRUE; 205 } 206 msg_scrolled = 0; 207 need_wait_return = FALSE; 208 } 209 210 // reset cmdline_row now (may have been changed temporarily) 211 compute_cmdrow(); 212 213 // Check for changed highlighting 214 if (need_highlight_changed) 215 highlight_changed(); 216 217 if (type == CLEAR) // first clear screen 218 { 219 screenclear(); // will reset clear_cmdline 220 type = NOT_VALID; 221 // must_redraw may be set indirectly, avoid another redraw later 222 must_redraw = 0; 223 } 224 225 if (clear_cmdline) // going to clear cmdline (done below) 226 check_for_delay(FALSE); 227 228 #ifdef FEAT_LINEBREAK 229 // Force redraw when width of 'number' or 'relativenumber' column 230 // changes. 231 if (curwin->w_redr_type < NOT_VALID 232 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu) 233 ? number_width(curwin) : 0)) 234 curwin->w_redr_type = NOT_VALID; 235 #endif 236 237 // Only start redrawing if there is really something to do. 238 if (type == INVERTED) 239 update_curswant(); 240 if (curwin->w_redr_type < type 241 && !((type == VALID 242 && curwin->w_lines[0].wl_valid 243 #ifdef FEAT_DIFF 244 && curwin->w_topfill == curwin->w_old_topfill 245 && curwin->w_botfill == curwin->w_old_botfill 246 #endif 247 && curwin->w_topline == curwin->w_lines[0].wl_lnum) 248 || (type == INVERTED 249 && VIsual_active 250 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum 251 && curwin->w_old_visual_mode == VIsual_mode 252 && (curwin->w_valid & VALID_VIRTCOL) 253 && curwin->w_old_curswant == curwin->w_curswant) 254 )) 255 curwin->w_redr_type = type; 256 257 // Redraw the tab pages line if needed. 258 if (redraw_tabline || type >= NOT_VALID) 259 draw_tabline(); 260 261 #ifdef FEAT_SYN_HL 262 // Correct stored syntax highlighting info for changes in each displayed 263 // buffer. Each buffer must only be done once. 264 FOR_ALL_WINDOWS(wp) 265 { 266 if (wp->w_buffer->b_mod_set) 267 { 268 win_T *wwp; 269 270 // Check if we already did this buffer. 271 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) 272 if (wwp->w_buffer == wp->w_buffer) 273 break; 274 if (wwp == wp && syntax_present(wp)) 275 syn_stack_apply_changes(wp->w_buffer); 276 } 277 } 278 #endif 279 280 if (pum_redraw_in_same_position()) 281 // Avoid flicker if the popup menu is going to be redrawn in the same 282 // position. 283 pum_will_redraw = TRUE; 284 285 // Go from top to bottom through the windows, redrawing the ones that need 286 // it. 287 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) 288 did_update_one_window = FALSE; 289 #endif 290 #ifdef FEAT_SEARCH_EXTRA 291 screen_search_hl.rm.regprog = NULL; 292 #endif 293 FOR_ALL_WINDOWS(wp) 294 { 295 if (wp->w_redr_type != 0) 296 { 297 cursor_off(); 298 #ifdef FEAT_GUI 299 if (!did_one) 300 { 301 did_one = TRUE; 302 303 // Remove the cursor before starting to do anything, because 304 // scrolling may make it difficult to redraw the text under 305 // it. 306 // Also remove the cursor if it needs to be hidden due to an 307 // ongoing cursor-less sleep. 308 if (gui.in_use && (wp == curwin || cursor_is_sleeping())) 309 { 310 gui_cursor_col = gui.cursor_col; 311 gui_cursor_row = gui.cursor_row; 312 gui_undraw_cursor(); 313 did_undraw = TRUE; 314 } 315 } 316 #endif 317 win_update(wp); 318 } 319 320 // redraw status line after the window to minimize cursor movement 321 if (wp->w_redr_status) 322 { 323 cursor_off(); 324 win_redr_status(wp, TRUE); // any popup menu will be redrawn below 325 } 326 } 327 #if defined(FEAT_SEARCH_EXTRA) 328 end_search_hl(); 329 #endif 330 331 // May need to redraw the popup menu. 332 pum_will_redraw = save_pum_will_redraw; 333 pum_may_redraw(); 334 335 // Reset b_mod_set flags. Going through all windows is probably faster 336 // than going through all buffers (there could be many buffers). 337 FOR_ALL_WINDOWS(wp) 338 wp->w_buffer->b_mod_set = FALSE; 339 340 #ifdef FEAT_PROP_POPUP 341 // Display popup windows on top of the windows and command line. 342 update_popups(win_update); 343 #endif 344 345 after_updating_screen(TRUE); 346 347 // Clear or redraw the command line. Done last, because scrolling may 348 // mess up the command line. 349 if (clear_cmdline || redraw_cmdline || redraw_mode) 350 showmode(); 351 352 if (no_update) 353 --no_win_do_lines_ins; 354 355 // May put up an introductory message when not editing a file 356 if (!did_intro) 357 maybe_intro_message(); 358 did_intro = TRUE; 359 360 #ifdef FEAT_GUI 361 // Redraw the cursor and update the scrollbars when all screen updating is 362 // done. 363 if (gui.in_use) 364 { 365 if (did_undraw && !gui_mch_is_blink_off()) 366 { 367 mch_disable_flush(); 368 out_flush(); // required before updating the cursor 369 mch_enable_flush(); 370 371 // Put the GUI position where the cursor was, gui_update_cursor() 372 // uses that. 373 gui.col = gui_cursor_col; 374 gui.row = gui_cursor_row; 375 gui.col = mb_fix_col(gui.col, gui.row); 376 gui_update_cursor(FALSE, FALSE); 377 gui_may_flush(); 378 screen_cur_col = gui.col; 379 screen_cur_row = gui.row; 380 } 381 else 382 out_flush(); 383 gui_update_scrollbars(FALSE); 384 } 385 #endif 386 return OK; 387 } 388 389 /* 390 * Return the row for drawing the statusline and the ruler of window "wp". 391 */ 392 int 393 statusline_row(win_T *wp) 394 { 395 #if defined(FEAT_PROP_POPUP) 396 // If the window is really zero height the winbar isn't displayed. 397 if (wp->w_frame->fr_height == wp->w_status_height && !popup_is_popup(wp)) 398 return wp->w_winrow; 399 #endif 400 return W_WINROW(wp) + wp->w_height; 401 } 402 403 /* 404 * Redraw the status line of window wp. 405 * 406 * If inversion is possible we use it. Else '=' characters are used. 407 * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is 408 * displayed. 409 */ 410 static void 411 win_redr_status(win_T *wp, int ignore_pum UNUSED) 412 { 413 int row; 414 char_u *p; 415 int len; 416 int fillchar; 417 int attr; 418 int this_ru_col; 419 static int busy = FALSE; 420 421 // It's possible to get here recursively when 'statusline' (indirectly) 422 // invokes ":redrawstatus". Simply ignore the call then. 423 if (busy) 424 return; 425 busy = TRUE; 426 427 row = statusline_row(wp); 428 429 wp->w_redr_status = FALSE; 430 if (wp->w_status_height == 0) 431 { 432 // no status line, can only be last window 433 redraw_cmdline = TRUE; 434 } 435 else if (!redrawing() 436 // don't update status line when popup menu is visible and may be 437 // drawn over it, unless it will be redrawn later 438 || (!ignore_pum && pum_visible())) 439 { 440 // Don't redraw right now, do it later. 441 wp->w_redr_status = TRUE; 442 } 443 #ifdef FEAT_STL_OPT 444 else if (*p_stl != NUL || *wp->w_p_stl != NUL) 445 { 446 // redraw custom status line 447 redraw_custom_statusline(wp); 448 } 449 #endif 450 else 451 { 452 fillchar = fillchar_status(&attr, wp); 453 454 get_trans_bufname(wp->w_buffer); 455 p = NameBuff; 456 len = (int)STRLEN(p); 457 458 if (bt_help(wp->w_buffer) 459 #ifdef FEAT_QUICKFIX 460 || wp->w_p_pvw 461 #endif 462 || bufIsChanged(wp->w_buffer) 463 || wp->w_buffer->b_p_ro) 464 *(p + len++) = ' '; 465 if (bt_help(wp->w_buffer)) 466 { 467 STRCPY(p + len, _("[Help]")); 468 len += (int)STRLEN(p + len); 469 } 470 #ifdef FEAT_QUICKFIX 471 if (wp->w_p_pvw) 472 { 473 STRCPY(p + len, _("[Preview]")); 474 len += (int)STRLEN(p + len); 475 } 476 #endif 477 if (bufIsChanged(wp->w_buffer) 478 #ifdef FEAT_TERMINAL 479 && !bt_terminal(wp->w_buffer) 480 #endif 481 ) 482 { 483 STRCPY(p + len, "[+]"); 484 len += 3; 485 } 486 if (wp->w_buffer->b_p_ro) 487 { 488 STRCPY(p + len, _("[RO]")); 489 len += (int)STRLEN(p + len); 490 } 491 492 this_ru_col = ru_col - (Columns - wp->w_width); 493 if (this_ru_col < (wp->w_width + 1) / 2) 494 this_ru_col = (wp->w_width + 1) / 2; 495 if (this_ru_col <= 1) 496 { 497 p = (char_u *)"<"; // No room for file name! 498 len = 1; 499 } 500 else if (has_mbyte) 501 { 502 int clen = 0, i; 503 504 // Count total number of display cells. 505 clen = mb_string2cells(p, -1); 506 507 // Find first character that will fit. 508 // Going from start to end is much faster for DBCS. 509 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1; 510 i += (*mb_ptr2len)(p + i)) 511 clen -= (*mb_ptr2cells)(p + i); 512 len = clen; 513 if (i > 0) 514 { 515 p = p + i - 1; 516 *p = '<'; 517 ++len; 518 } 519 520 } 521 else if (len > this_ru_col - 1) 522 { 523 p += len - (this_ru_col - 1); 524 *p = '<'; 525 len = this_ru_col - 1; 526 } 527 528 screen_puts(p, row, wp->w_wincol, attr); 529 screen_fill(row, row + 1, len + wp->w_wincol, 530 this_ru_col + wp->w_wincol, fillchar, fillchar, attr); 531 532 if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL) 533 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1)) 534 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff) 535 - 1 + wp->w_wincol), attr); 536 537 #ifdef FEAT_CMDL_INFO 538 win_redr_ruler(wp, TRUE, ignore_pum); 539 #endif 540 } 541 542 /* 543 * May need to draw the character below the vertical separator. 544 */ 545 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing()) 546 { 547 if (stl_connected(wp)) 548 fillchar = fillchar_status(&attr, wp); 549 else 550 fillchar = fillchar_vsep(&attr); 551 screen_putchar(fillchar, row, W_ENDCOL(wp), attr); 552 } 553 busy = FALSE; 554 } 555 556 #ifdef FEAT_STL_OPT 557 /* 558 * Redraw the status line according to 'statusline' and take care of any 559 * errors encountered. 560 */ 561 static void 562 redraw_custom_statusline(win_T *wp) 563 { 564 static int entered = FALSE; 565 int saved_did_emsg = did_emsg; 566 567 // When called recursively return. This can happen when the statusline 568 // contains an expression that triggers a redraw. 569 if (entered) 570 return; 571 entered = TRUE; 572 573 did_emsg = FALSE; 574 win_redr_custom(wp, FALSE); 575 if (did_emsg) 576 { 577 // When there is an error disable the statusline, otherwise the 578 // display is messed up with errors and a redraw triggers the problem 579 // again and again. 580 set_string_option_direct((char_u *)"statusline", -1, 581 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL 582 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR); 583 } 584 did_emsg |= saved_did_emsg; 585 entered = FALSE; 586 } 587 #endif 588 589 /* 590 * Show current status info in ruler and various other places 591 * If always is FALSE, only show ruler if position has changed. 592 */ 593 void 594 showruler(int always) 595 { 596 if (!always && !redrawing()) 597 return; 598 if (pum_visible()) 599 { 600 // Don't redraw right now, do it later. 601 curwin->w_redr_status = TRUE; 602 return; 603 } 604 #if defined(FEAT_STL_OPT) 605 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) 606 redraw_custom_statusline(curwin); 607 else 608 #endif 609 #ifdef FEAT_CMDL_INFO 610 win_redr_ruler(curwin, always, FALSE); 611 #endif 612 613 #ifdef FEAT_TITLE 614 if (need_maketitle 615 # ifdef FEAT_STL_OPT 616 || (p_icon && (stl_syntax & STL_IN_ICON)) 617 || (p_title && (stl_syntax & STL_IN_TITLE)) 618 # endif 619 ) 620 maketitle(); 621 #endif 622 // Redraw the tab pages line if needed. 623 if (redraw_tabline) 624 draw_tabline(); 625 } 626 627 #if defined(FEAT_CMDL_INFO) || defined(PROTO) 628 void 629 win_redr_ruler(win_T *wp, int always, int ignore_pum) 630 { 631 #define RULER_BUF_LEN 70 632 char_u buffer[RULER_BUF_LEN]; 633 int row; 634 int fillchar; 635 int attr; 636 int empty_line = FALSE; 637 colnr_T virtcol; 638 int i; 639 size_t len; 640 int o; 641 int this_ru_col; 642 int off = 0; 643 int width; 644 645 // If 'ruler' off or redrawing disabled, don't do anything 646 if (!p_ru) 647 return; 648 649 /* 650 * Check if cursor.lnum is valid, since win_redr_ruler() may be called 651 * after deleting lines, before cursor.lnum is corrected. 652 */ 653 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) 654 return; 655 656 // Don't draw the ruler while doing insert-completion, it might overwrite 657 // the (long) mode message. 658 if (wp == lastwin && lastwin->w_status_height == 0) 659 if (edit_submode != NULL) 660 return; 661 // Don't draw the ruler when the popup menu is visible, it may overlap. 662 // Except when the popup menu will be redrawn anyway. 663 if (!ignore_pum && pum_visible()) 664 return; 665 666 #ifdef FEAT_STL_OPT 667 if (*p_ruf) 668 { 669 int called_emsg_before = called_emsg; 670 671 win_redr_custom(wp, TRUE); 672 if (called_emsg > called_emsg_before) 673 set_string_option_direct((char_u *)"rulerformat", -1, 674 (char_u *)"", OPT_FREE, SID_ERROR); 675 return; 676 } 677 #endif 678 679 /* 680 * Check if not in Insert mode and the line is empty (will show "0-1"). 681 */ 682 if (!(State & INSERT) 683 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL) 684 empty_line = TRUE; 685 686 /* 687 * Only draw the ruler when something changed. 688 */ 689 validate_virtcol_win(wp); 690 if ( redraw_cmdline 691 || always 692 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum 693 || wp->w_cursor.col != wp->w_ru_cursor.col 694 || wp->w_virtcol != wp->w_ru_virtcol 695 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd 696 || wp->w_topline != wp->w_ru_topline 697 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count 698 #ifdef FEAT_DIFF 699 || wp->w_topfill != wp->w_ru_topfill 700 #endif 701 || empty_line != wp->w_ru_empty) 702 { 703 cursor_off(); 704 if (wp->w_status_height) 705 { 706 row = statusline_row(wp); 707 fillchar = fillchar_status(&attr, wp); 708 off = wp->w_wincol; 709 width = wp->w_width; 710 } 711 else 712 { 713 row = Rows - 1; 714 fillchar = ' '; 715 attr = 0; 716 width = Columns; 717 off = 0; 718 } 719 720 // In list mode virtcol needs to be recomputed 721 virtcol = wp->w_virtcol; 722 if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL) 723 { 724 wp->w_p_list = FALSE; 725 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); 726 wp->w_p_list = TRUE; 727 } 728 729 /* 730 * Some sprintfs return the length, some return a pointer. 731 * To avoid portability problems we use strlen() here. 732 */ 733 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,", 734 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) 735 ? 0L 736 : (long)(wp->w_cursor.lnum)); 737 len = STRLEN(buffer); 738 col_print(buffer + len, RULER_BUF_LEN - len, 739 empty_line ? 0 : (int)wp->w_cursor.col + 1, 740 (int)virtcol + 1); 741 742 /* 743 * Add a "50%" if there is room for it. 744 * On the last line, don't print in the last column (scrolls the 745 * screen up on some terminals). 746 */ 747 i = (int)STRLEN(buffer); 748 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1); 749 o = i + vim_strsize(buffer + i + 1); 750 if (wp->w_status_height == 0) // can't use last char of screen 751 ++o; 752 this_ru_col = ru_col - (Columns - width); 753 if (this_ru_col < 0) 754 this_ru_col = 0; 755 // Never use more than half the window/screen width, leave the other 756 // half for the filename. 757 if (this_ru_col < (width + 1) / 2) 758 this_ru_col = (width + 1) / 2; 759 if (this_ru_col + o < width) 760 { 761 // need at least 3 chars left for get_rel_pos() + NUL 762 while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) 763 { 764 if (has_mbyte) 765 i += (*mb_char2bytes)(fillchar, buffer + i); 766 else 767 buffer[i++] = fillchar; 768 ++o; 769 } 770 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i); 771 } 772 // Truncate at window boundary. 773 if (has_mbyte) 774 { 775 o = 0; 776 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i)) 777 { 778 o += (*mb_ptr2cells)(buffer + i); 779 if (this_ru_col + o > width) 780 { 781 buffer[i] = NUL; 782 break; 783 } 784 } 785 } 786 else if (this_ru_col + (int)STRLEN(buffer) > width) 787 buffer[width - this_ru_col] = NUL; 788 789 screen_puts(buffer, row, this_ru_col + off, attr); 790 i = redraw_cmdline; 791 screen_fill(row, row + 1, 792 this_ru_col + off + (int)STRLEN(buffer), 793 (int)(off + width), 794 fillchar, fillchar, attr); 795 // don't redraw the cmdline because of showing the ruler 796 redraw_cmdline = i; 797 wp->w_ru_cursor = wp->w_cursor; 798 wp->w_ru_virtcol = wp->w_virtcol; 799 wp->w_ru_empty = empty_line; 800 wp->w_ru_topline = wp->w_topline; 801 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count; 802 #ifdef FEAT_DIFF 803 wp->w_ru_topfill = wp->w_topfill; 804 #endif 805 } 806 } 807 #endif 808 809 /* 810 * To be called when "updating_screen" was set before and now the postponed 811 * side effects may take place. 812 */ 813 void 814 after_updating_screen(int may_resize_shell UNUSED) 815 { 816 updating_screen = FALSE; 817 #ifdef FEAT_GUI 818 if (may_resize_shell) 819 gui_may_resize_shell(); 820 #endif 821 #ifdef FEAT_TERMINAL 822 term_check_channel_closed_recently(); 823 #endif 824 825 #ifdef HAVE_DROP_FILE 826 // If handle_drop() was called while updating_screen was TRUE need to 827 // handle the drop now. 828 handle_any_postponed_drop(); 829 #endif 830 } 831 832 /* 833 * Update all windows that are editing the current buffer. 834 */ 835 void 836 update_curbuf(int type) 837 { 838 redraw_curbuf_later(type); 839 update_screen(type); 840 } 841 842 #if defined(FEAT_MENU) || defined(FEAT_FOLDING) 843 /* 844 * Copy "text" to ScreenLines using "attr". 845 * Returns the next screen column. 846 */ 847 static int 848 text_to_screenline(win_T *wp, char_u *text, int col) 849 { 850 int off = (int)(current_ScreenLine - ScreenLines); 851 852 if (has_mbyte) 853 { 854 int cells; 855 int u8c, u8cc[MAX_MCO]; 856 int i; 857 int idx; 858 int c_len; 859 char_u *p; 860 # ifdef FEAT_ARABIC 861 int prev_c = 0; // previous Arabic character 862 int prev_c1 = 0; // first composing char for prev_c 863 # endif 864 865 # ifdef FEAT_RIGHTLEFT 866 if (wp->w_p_rl) 867 idx = off; 868 else 869 # endif 870 idx = off + col; 871 872 // Store multibyte characters in ScreenLines[] et al. correctly. 873 for (p = text; *p != NUL; ) 874 { 875 cells = (*mb_ptr2cells)(p); 876 c_len = (*mb_ptr2len)(p); 877 if (col + cells > wp->w_width 878 # ifdef FEAT_RIGHTLEFT 879 - (wp->w_p_rl ? col : 0) 880 # endif 881 ) 882 break; 883 ScreenLines[idx] = *p; 884 if (enc_utf8) 885 { 886 u8c = utfc_ptr2char(p, u8cc); 887 if (*p < 0x80 && u8cc[0] == 0) 888 { 889 ScreenLinesUC[idx] = 0; 890 #ifdef FEAT_ARABIC 891 prev_c = u8c; 892 #endif 893 } 894 else 895 { 896 #ifdef FEAT_ARABIC 897 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) 898 { 899 // Do Arabic shaping. 900 int pc, pc1, nc; 901 int pcc[MAX_MCO]; 902 int firstbyte = *p; 903 904 // The idea of what is the previous and next 905 // character depends on 'rightleft'. 906 if (wp->w_p_rl) 907 { 908 pc = prev_c; 909 pc1 = prev_c1; 910 nc = utf_ptr2char(p + c_len); 911 prev_c1 = u8cc[0]; 912 } 913 else 914 { 915 pc = utfc_ptr2char(p + c_len, pcc); 916 nc = prev_c; 917 pc1 = pcc[0]; 918 } 919 prev_c = u8c; 920 921 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], 922 pc, pc1, nc); 923 ScreenLines[idx] = firstbyte; 924 } 925 else 926 prev_c = u8c; 927 #endif 928 // Non-BMP character: display as ? or fullwidth ?. 929 ScreenLinesUC[idx] = u8c; 930 for (i = 0; i < Screen_mco; ++i) 931 { 932 ScreenLinesC[i][idx] = u8cc[i]; 933 if (u8cc[i] == 0) 934 break; 935 } 936 } 937 if (cells > 1) 938 ScreenLines[idx + 1] = 0; 939 } 940 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e) 941 // double-byte single width character 942 ScreenLines2[idx] = p[1]; 943 else if (cells > 1) 944 // double-width character 945 ScreenLines[idx + 1] = p[1]; 946 col += cells; 947 idx += cells; 948 p += c_len; 949 } 950 } 951 else 952 { 953 int len = (int)STRLEN(text); 954 955 if (len > wp->w_width - col) 956 len = wp->w_width - col; 957 if (len > 0) 958 { 959 #ifdef FEAT_RIGHTLEFT 960 if (wp->w_p_rl) 961 mch_memmove(current_ScreenLine, text, len); 962 else 963 #endif 964 mch_memmove(current_ScreenLine + col, text, len); 965 col += len; 966 } 967 } 968 return col; 969 } 970 #endif 971 972 #ifdef FEAT_MENU 973 /* 974 * Draw the window toolbar. 975 */ 976 static void 977 redraw_win_toolbar(win_T *wp) 978 { 979 vimmenu_T *menu; 980 int item_idx = 0; 981 int item_count = 0; 982 int col = 0; 983 int next_col; 984 int off = (int)(current_ScreenLine - ScreenLines); 985 int fill_attr = syn_name2attr((char_u *)"ToolbarLine"); 986 int button_attr = syn_name2attr((char_u *)"ToolbarButton"); 987 988 vim_free(wp->w_winbar_items); 989 FOR_ALL_CHILD_MENUS(wp->w_winbar, menu) 990 ++item_count; 991 wp->w_winbar_items = ALLOC_CLEAR_MULT(winbar_item_T, item_count + 1); 992 993 // TODO: use fewer spaces if there is not enough room 994 for (menu = wp->w_winbar->children; 995 menu != NULL && col < wp->w_width; menu = menu->next) 996 { 997 space_to_screenline(off + col, fill_attr); 998 if (++col >= wp->w_width) 999 break; 1000 if (col > 1) 1001 { 1002 space_to_screenline(off + col, fill_attr); 1003 if (++col >= wp->w_width) 1004 break; 1005 } 1006 1007 wp->w_winbar_items[item_idx].wb_startcol = col; 1008 space_to_screenline(off + col, button_attr); 1009 if (++col >= wp->w_width) 1010 break; 1011 1012 next_col = text_to_screenline(wp, menu->name, col); 1013 while (col < next_col) 1014 { 1015 ScreenAttrs[off + col] = button_attr; 1016 ++col; 1017 } 1018 wp->w_winbar_items[item_idx].wb_endcol = col; 1019 wp->w_winbar_items[item_idx].wb_menu = menu; 1020 ++item_idx; 1021 1022 if (col >= wp->w_width) 1023 break; 1024 space_to_screenline(off + col, button_attr); 1025 ++col; 1026 } 1027 while (col < wp->w_width) 1028 { 1029 space_to_screenline(off + col, fill_attr); 1030 ++col; 1031 } 1032 wp->w_winbar_items[item_idx].wb_menu = NULL; // end marker 1033 1034 screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width, 1035 (int)wp->w_width, 0); 1036 } 1037 #endif 1038 1039 #if defined(FEAT_FOLDING) || defined(PROTO) 1040 /* 1041 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr". 1042 */ 1043 static void 1044 copy_text_attr( 1045 int off, 1046 char_u *buf, 1047 int len, 1048 int attr) 1049 { 1050 int i; 1051 1052 mch_memmove(ScreenLines + off, buf, (size_t)len); 1053 if (enc_utf8) 1054 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len); 1055 for (i = 0; i < len; ++i) 1056 ScreenAttrs[off + i] = attr; 1057 } 1058 1059 /* 1060 * Display one folded line. 1061 */ 1062 static void 1063 fold_line( 1064 win_T *wp, 1065 long fold_count, 1066 foldinfo_T *foldinfo, 1067 linenr_T lnum, 1068 int row) 1069 { 1070 // Max value of 'foldcolumn' is 12 and maximum number of bytes in a 1071 // multi-byte character is MAX_MCO. 1072 char_u buf[MAX_MCO * 12 + 1]; 1073 pos_T *top, *bot; 1074 linenr_T lnume = lnum + fold_count - 1; 1075 int len; 1076 char_u *text; 1077 int fdc; 1078 int col; 1079 int txtcol; 1080 int off = (int)(current_ScreenLine - ScreenLines); 1081 int ri; 1082 1083 // Build the fold line: 1084 // 1. Add the cmdwin_type for the command-line window 1085 // 2. Add the 'foldcolumn' 1086 // 3. Add the 'number' or 'relativenumber' column 1087 // 4. Compose the text 1088 // 5. Add the text 1089 // 6. set highlighting for the Visual area an other text 1090 col = 0; 1091 1092 // 1. Add the cmdwin_type for the command-line window 1093 // Ignores 'rightleft', this window is never right-left. 1094 #ifdef FEAT_CMDWIN 1095 if (cmdwin_type != 0 && wp == curwin) 1096 { 1097 ScreenLines[off] = cmdwin_type; 1098 ScreenAttrs[off] = HL_ATTR(HLF_AT); 1099 if (enc_utf8) 1100 ScreenLinesUC[off] = 0; 1101 ++col; 1102 } 1103 #endif 1104 1105 #ifdef FEAT_RIGHTLEFT 1106 # define RL_MEMSET(p, v, l) \ 1107 do { \ 1108 if (wp->w_p_rl) \ 1109 for (ri = 0; ri < l; ++ri) \ 1110 ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \ 1111 else \ 1112 for (ri = 0; ri < l; ++ri) \ 1113 ScreenAttrs[off + (p) + ri] = v; \ 1114 } while (0) 1115 #else 1116 # define RL_MEMSET(p, v, l) \ 1117 do { \ 1118 for (ri = 0; ri < l; ++ri) \ 1119 ScreenAttrs[off + (p) + ri] = v; \ 1120 } while (0) 1121 #endif 1122 1123 // 2. Add the 'foldcolumn' 1124 // Reduce the width when there is not enough space. 1125 fdc = compute_foldcolumn(wp, col); 1126 if (fdc > 0) 1127 { 1128 char_u *p; 1129 int i; 1130 int idx; 1131 1132 fill_foldcolumn(buf, wp, TRUE, lnum); 1133 p = buf; 1134 for (i = 0; i < fdc; i++) 1135 { 1136 int ch; 1137 1138 if (has_mbyte) 1139 ch = mb_ptr2char_adv(&p); 1140 else 1141 ch = *p++; 1142 #ifdef FEAT_RIGHTLEFT 1143 if (wp->w_p_rl) 1144 idx = off + wp->w_width - i - 1 - col; 1145 else 1146 #endif 1147 idx = off + col + i; 1148 if (enc_utf8) 1149 { 1150 if (ch >= 0x80) 1151 { 1152 ScreenLinesUC[idx] = ch; 1153 ScreenLinesC[0][idx] = 0; 1154 ScreenLines[idx] = 0x80; 1155 } 1156 else 1157 { 1158 ScreenLines[idx] = ch; 1159 ScreenLinesUC[idx] = 0; 1160 } 1161 } 1162 else 1163 ScreenLines[idx] = ch; 1164 } 1165 1166 RL_MEMSET(col, HL_ATTR(HLF_FC), fdc); 1167 col += fdc; 1168 } 1169 1170 // Set all attributes of the 'number' or 'relativenumber' column and the 1171 // text 1172 RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col); 1173 1174 #ifdef FEAT_SIGNS 1175 // If signs are being displayed, add two spaces. 1176 if (signcolumn_on(wp)) 1177 { 1178 len = wp->w_width - col; 1179 if (len > 0) 1180 { 1181 if (len > 2) 1182 len = 2; 1183 # ifdef FEAT_RIGHTLEFT 1184 if (wp->w_p_rl) 1185 // the line number isn't reversed 1186 copy_text_attr(off + wp->w_width - len - col, 1187 (char_u *)" ", len, HL_ATTR(HLF_FL)); 1188 else 1189 # endif 1190 copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL)); 1191 col += len; 1192 } 1193 } 1194 #endif 1195 1196 // 3. Add the 'number' or 'relativenumber' column 1197 if (wp->w_p_nu || wp->w_p_rnu) 1198 { 1199 len = wp->w_width - col; 1200 if (len > 0) 1201 { 1202 int w = number_width(wp); 1203 long num; 1204 char *fmt = "%*ld "; 1205 1206 if (len > w + 1) 1207 len = w + 1; 1208 1209 if (wp->w_p_nu && !wp->w_p_rnu) 1210 // 'number' + 'norelativenumber' 1211 num = (long)lnum; 1212 else 1213 { 1214 // 'relativenumber', don't use negative numbers 1215 num = labs((long)get_cursor_rel_lnum(wp, lnum)); 1216 if (num == 0 && wp->w_p_nu && wp->w_p_rnu) 1217 { 1218 // 'number' + 'relativenumber': cursor line shows absolute 1219 // line number 1220 num = lnum; 1221 fmt = "%-*ld "; 1222 } 1223 } 1224 1225 sprintf((char *)buf, fmt, w, num); 1226 #ifdef FEAT_RIGHTLEFT 1227 if (wp->w_p_rl) 1228 // the line number isn't reversed 1229 copy_text_attr(off + wp->w_width - len - col, buf, len, 1230 HL_ATTR(HLF_FL)); 1231 else 1232 #endif 1233 copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL)); 1234 col += len; 1235 } 1236 } 1237 1238 // 4. Compose the folded-line string with 'foldtext', if set. 1239 text = get_foldtext(wp, lnum, lnume, foldinfo, buf); 1240 1241 txtcol = col; // remember where text starts 1242 1243 // 5. move the text to current_ScreenLine. Fill up with "fill_fold". 1244 // Right-left text is put in columns 0 - number-col, normal text is put 1245 // in columns number-col - window-width. 1246 col = text_to_screenline(wp, text, col); 1247 1248 // Fill the rest of the line with the fold filler 1249 #ifdef FEAT_RIGHTLEFT 1250 if (wp->w_p_rl) 1251 col -= txtcol; 1252 #endif 1253 while (col < wp->w_width 1254 #ifdef FEAT_RIGHTLEFT 1255 - (wp->w_p_rl ? txtcol : 0) 1256 #endif 1257 ) 1258 { 1259 if (enc_utf8) 1260 { 1261 if (fill_fold >= 0x80) 1262 { 1263 ScreenLinesUC[off + col] = fill_fold; 1264 ScreenLinesC[0][off + col] = 0; 1265 ScreenLines[off + col] = 0x80; // avoid storing zero 1266 } 1267 else 1268 { 1269 ScreenLinesUC[off + col] = 0; 1270 ScreenLines[off + col] = fill_fold; 1271 } 1272 col++; 1273 } 1274 else 1275 ScreenLines[off + col++] = fill_fold; 1276 } 1277 1278 if (text != buf) 1279 vim_free(text); 1280 1281 // 6. set highlighting for the Visual area an other text. 1282 // If all folded lines are in the Visual area, highlight the line. 1283 if (VIsual_active && wp->w_buffer == curwin->w_buffer) 1284 { 1285 if (LTOREQ_POS(curwin->w_cursor, VIsual)) 1286 { 1287 // Visual is after curwin->w_cursor 1288 top = &curwin->w_cursor; 1289 bot = &VIsual; 1290 } 1291 else 1292 { 1293 // Visual is before curwin->w_cursor 1294 top = &VIsual; 1295 bot = &curwin->w_cursor; 1296 } 1297 if (lnum >= top->lnum 1298 && lnume <= bot->lnum 1299 && (VIsual_mode != 'v' 1300 || ((lnum > top->lnum 1301 || (lnum == top->lnum 1302 && top->col == 0)) 1303 && (lnume < bot->lnum 1304 || (lnume == bot->lnum 1305 && (bot->col - (*p_sel == 'e')) 1306 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE))))))) 1307 { 1308 if (VIsual_mode == Ctrl_V) 1309 { 1310 // Visual block mode: highlight the chars part of the block 1311 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width) 1312 { 1313 if (wp->w_old_cursor_lcol != MAXCOL 1314 && wp->w_old_cursor_lcol + txtcol 1315 < (colnr_T)wp->w_width) 1316 len = wp->w_old_cursor_lcol; 1317 else 1318 len = wp->w_width - txtcol; 1319 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V), 1320 len - (int)wp->w_old_cursor_fcol); 1321 } 1322 } 1323 else 1324 { 1325 // Set all attributes of the text 1326 RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol); 1327 } 1328 } 1329 } 1330 1331 #ifdef FEAT_SYN_HL 1332 // Show colorcolumn in the fold line, but let cursorcolumn override it. 1333 if (wp->w_p_cc_cols) 1334 { 1335 int i = 0; 1336 int j = wp->w_p_cc_cols[i]; 1337 int old_txtcol = txtcol; 1338 1339 while (j > -1) 1340 { 1341 txtcol += j; 1342 if (wp->w_p_wrap) 1343 txtcol -= wp->w_skipcol; 1344 else 1345 txtcol -= wp->w_leftcol; 1346 if (txtcol >= 0 && txtcol < wp->w_width) 1347 ScreenAttrs[off + txtcol] = hl_combine_attr( 1348 ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC)); 1349 txtcol = old_txtcol; 1350 j = wp->w_p_cc_cols[++i]; 1351 } 1352 } 1353 1354 // Show 'cursorcolumn' in the fold line. 1355 if (wp->w_p_cuc) 1356 { 1357 txtcol += wp->w_virtcol; 1358 if (wp->w_p_wrap) 1359 txtcol -= wp->w_skipcol; 1360 else 1361 txtcol -= wp->w_leftcol; 1362 if (txtcol >= 0 && txtcol < wp->w_width) 1363 ScreenAttrs[off + txtcol] = hl_combine_attr( 1364 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC)); 1365 } 1366 #endif 1367 1368 screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width, 1369 (int)wp->w_width, 0); 1370 1371 // Update w_cline_height and w_cline_folded if the cursor line was 1372 // updated (saves a call to plines() later). 1373 if (wp == curwin 1374 && lnum <= curwin->w_cursor.lnum 1375 && lnume >= curwin->w_cursor.lnum) 1376 { 1377 curwin->w_cline_row = row; 1378 curwin->w_cline_height = 1; 1379 curwin->w_cline_folded = TRUE; 1380 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); 1381 } 1382 } 1383 #endif 1384 1385 /* 1386 * Update a single window. 1387 * 1388 * This may cause the windows below it also to be redrawn (when clearing the 1389 * screen or scrolling lines). 1390 * 1391 * How the window is redrawn depends on wp->w_redr_type. Each type also 1392 * implies the one below it. 1393 * NOT_VALID redraw the whole window 1394 * SOME_VALID redraw the whole window but do scroll when possible 1395 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID 1396 * INVERTED redraw the changed part of the Visual area 1397 * INVERTED_ALL redraw the whole Visual area 1398 * VALID 1. scroll up/down to adjust for a changed w_topline 1399 * 2. update lines at the top when scrolled down 1400 * 3. redraw changed text: 1401 * - if wp->w_buffer->b_mod_set set, update lines between 1402 * b_mod_top and b_mod_bot. 1403 * - if wp->w_redraw_top non-zero, redraw lines between 1404 * wp->w_redraw_top and wp->w_redr_bot. 1405 * - continue redrawing when syntax status is invalid. 1406 * 4. if scrolled up, update lines at the bottom. 1407 * This results in three areas that may need updating: 1408 * top: from first row to top_end (when scrolled down) 1409 * mid: from mid_start to mid_end (update inversion or changed text) 1410 * bot: from bot_start to last row (when scrolled up) 1411 */ 1412 static void 1413 win_update(win_T *wp) 1414 { 1415 buf_T *buf = wp->w_buffer; 1416 int type; 1417 int top_end = 0; // Below last row of the top area that needs 1418 // updating. 0 when no top area updating. 1419 int mid_start = 999;// first row of the mid area that needs 1420 // updating. 999 when no mid area updating. 1421 int mid_end = 0; // Below last row of the mid area that needs 1422 // updating. 0 when no mid area updating. 1423 int bot_start = 999;// first row of the bot area that needs 1424 // updating. 999 when no bot area updating 1425 int scrolled_down = FALSE; // TRUE when scrolled down when 1426 // w_topline got smaller a bit 1427 #ifdef FEAT_SEARCH_EXTRA 1428 int top_to_mod = FALSE; // redraw above mod_top 1429 #endif 1430 1431 int row; // current window row to display 1432 linenr_T lnum; // current buffer lnum to display 1433 int idx; // current index in w_lines[] 1434 int srow; // starting row of the current line 1435 1436 int eof = FALSE; // if TRUE, we hit the end of the file 1437 int didline = FALSE; // if TRUE, we finished the last line 1438 int i; 1439 long j; 1440 static int recursive = FALSE; // being called recursively 1441 linenr_T old_botline = wp->w_botline; 1442 #ifdef FEAT_CONCEAL 1443 int old_wrow = wp->w_wrow; 1444 int old_wcol = wp->w_wcol; 1445 #endif 1446 #ifdef FEAT_FOLDING 1447 long fold_count; 1448 #endif 1449 #ifdef FEAT_SYN_HL 1450 // remember what happened to the previous line, to know if 1451 // check_visual_highlight() can be used 1452 #define DID_NONE 1 // didn't update a line 1453 #define DID_LINE 2 // updated a normal line 1454 #define DID_FOLD 3 // updated a folded line 1455 int did_update = DID_NONE; 1456 linenr_T syntax_last_parsed = 0; // last parsed text line 1457 #endif 1458 linenr_T mod_top = 0; 1459 linenr_T mod_bot = 0; 1460 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) 1461 int save_got_int; 1462 #endif 1463 #ifdef SYN_TIME_LIMIT 1464 proftime_T syntax_tm; 1465 #endif 1466 1467 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) 1468 // This needs to be done only for the first window when update_screen() is 1469 // called. 1470 if (!did_update_one_window) 1471 { 1472 did_update_one_window = TRUE; 1473 # ifdef FEAT_SEARCH_EXTRA 1474 start_search_hl(); 1475 # endif 1476 # ifdef FEAT_CLIPBOARD 1477 // When Visual area changed, may have to update selection. 1478 if (clip_star.available && clip_isautosel_star()) 1479 clip_update_selection(&clip_star); 1480 if (clip_plus.available && clip_isautosel_plus()) 1481 clip_update_selection(&clip_plus); 1482 # endif 1483 } 1484 #endif 1485 1486 type = wp->w_redr_type; 1487 1488 if (type == NOT_VALID) 1489 { 1490 wp->w_redr_status = TRUE; 1491 wp->w_lines_valid = 0; 1492 } 1493 1494 // Window frame is zero-height: nothing to draw. 1495 if (wp->w_height + WINBAR_HEIGHT(wp) == 0 1496 || (wp->w_frame->fr_height == wp->w_status_height 1497 #if defined(FEAT_PROP_POPUP) 1498 && !popup_is_popup(wp) 1499 #endif 1500 )) 1501 { 1502 wp->w_redr_type = 0; 1503 return; 1504 } 1505 1506 // Window is zero-width: Only need to draw the separator. 1507 if (wp->w_width == 0) 1508 { 1509 // draw the vertical separator right of this window 1510 draw_vsep_win(wp, 0); 1511 wp->w_redr_type = 0; 1512 return; 1513 } 1514 1515 #ifdef FEAT_TERMINAL 1516 // If this window contains a terminal, redraw works completely differently. 1517 if (term_do_update_window(wp)) 1518 { 1519 term_update_window(wp); 1520 # ifdef FEAT_MENU 1521 // Draw the window toolbar, if there is one. 1522 if (winbar_height(wp) > 0) 1523 redraw_win_toolbar(wp); 1524 # endif 1525 wp->w_redr_type = 0; 1526 return; 1527 } 1528 #endif 1529 1530 #ifdef FEAT_SEARCH_EXTRA 1531 init_search_hl(wp, &screen_search_hl); 1532 #endif 1533 1534 #ifdef FEAT_LINEBREAK 1535 // Force redraw when width of 'number' or 'relativenumber' column 1536 // changes. 1537 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0; 1538 if (wp->w_nrwidth != i) 1539 { 1540 type = NOT_VALID; 1541 wp->w_nrwidth = i; 1542 } 1543 else 1544 #endif 1545 1546 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0) 1547 { 1548 // When there are both inserted/deleted lines and specific lines to be 1549 // redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw 1550 // everything (only happens when redrawing is off for while). 1551 type = NOT_VALID; 1552 } 1553 else 1554 { 1555 // Set mod_top to the first line that needs displaying because of 1556 // changes. Set mod_bot to the first line after the changes. 1557 mod_top = wp->w_redraw_top; 1558 if (wp->w_redraw_bot != 0) 1559 mod_bot = wp->w_redraw_bot + 1; 1560 else 1561 mod_bot = 0; 1562 if (buf->b_mod_set) 1563 { 1564 if (mod_top == 0 || mod_top > buf->b_mod_top) 1565 { 1566 mod_top = buf->b_mod_top; 1567 #ifdef FEAT_SYN_HL 1568 // Need to redraw lines above the change that may be included 1569 // in a pattern match. 1570 if (syntax_present(wp)) 1571 { 1572 mod_top -= buf->b_s.b_syn_sync_linebreaks; 1573 if (mod_top < 1) 1574 mod_top = 1; 1575 } 1576 #endif 1577 } 1578 if (mod_bot == 0 || mod_bot < buf->b_mod_bot) 1579 mod_bot = buf->b_mod_bot; 1580 1581 #ifdef FEAT_SEARCH_EXTRA 1582 // When 'hlsearch' is on and using a multi-line search pattern, a 1583 // change in one line may make the Search highlighting in a 1584 // previous line invalid. Simple solution: redraw all visible 1585 // lines above the change. 1586 // Same for a match pattern. 1587 if (screen_search_hl.rm.regprog != NULL 1588 && re_multiline(screen_search_hl.rm.regprog)) 1589 top_to_mod = TRUE; 1590 else 1591 { 1592 matchitem_T *cur = wp->w_match_head; 1593 1594 while (cur != NULL) 1595 { 1596 if (cur->match.regprog != NULL 1597 && re_multiline(cur->match.regprog)) 1598 { 1599 top_to_mod = TRUE; 1600 break; 1601 } 1602 cur = cur->next; 1603 } 1604 } 1605 #endif 1606 } 1607 #ifdef FEAT_FOLDING 1608 if (mod_top != 0 && hasAnyFolding(wp)) 1609 { 1610 linenr_T lnumt, lnumb; 1611 1612 // A change in a line can cause lines above it to become folded or 1613 // unfolded. Find the top most buffer line that may be affected. 1614 // If the line was previously folded and displayed, get the first 1615 // line of that fold. If the line is folded now, get the first 1616 // folded line. Use the minimum of these two. 1617 1618 // Find last valid w_lines[] entry above mod_top. Set lnumt to 1619 // the line below it. If there is no valid entry, use w_topline. 1620 // Find the first valid w_lines[] entry below mod_bot. Set lnumb 1621 // to this line. If there is no valid entry, use MAXLNUM. 1622 lnumt = wp->w_topline; 1623 lnumb = MAXLNUM; 1624 for (i = 0; i < wp->w_lines_valid; ++i) 1625 if (wp->w_lines[i].wl_valid) 1626 { 1627 if (wp->w_lines[i].wl_lastlnum < mod_top) 1628 lnumt = wp->w_lines[i].wl_lastlnum + 1; 1629 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot) 1630 { 1631 lnumb = wp->w_lines[i].wl_lnum; 1632 // When there is a fold column it might need updating 1633 // in the next line ("J" just above an open fold). 1634 if (compute_foldcolumn(wp, 0) > 0) 1635 ++lnumb; 1636 } 1637 } 1638 1639 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL); 1640 if (mod_top > lnumt) 1641 mod_top = lnumt; 1642 1643 // Now do the same for the bottom line (one above mod_bot). 1644 --mod_bot; 1645 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL); 1646 ++mod_bot; 1647 if (mod_bot < lnumb) 1648 mod_bot = lnumb; 1649 } 1650 #endif 1651 1652 // When a change starts above w_topline and the end is below 1653 // w_topline, start redrawing at w_topline. 1654 // If the end of the change is above w_topline: do like no change was 1655 // made, but redraw the first line to find changes in syntax. 1656 if (mod_top != 0 && mod_top < wp->w_topline) 1657 { 1658 if (mod_bot > wp->w_topline) 1659 mod_top = wp->w_topline; 1660 #ifdef FEAT_SYN_HL 1661 else if (syntax_present(wp)) 1662 top_end = 1; 1663 #endif 1664 } 1665 1666 // When line numbers are displayed need to redraw all lines below 1667 // inserted/deleted lines. 1668 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu) 1669 mod_bot = MAXLNUM; 1670 } 1671 wp->w_redraw_top = 0; // reset for next time 1672 wp->w_redraw_bot = 0; 1673 1674 // When only displaying the lines at the top, set top_end. Used when 1675 // window has scrolled down for msg_scrolled. 1676 if (type == REDRAW_TOP) 1677 { 1678 j = 0; 1679 for (i = 0; i < wp->w_lines_valid; ++i) 1680 { 1681 j += wp->w_lines[i].wl_size; 1682 if (j >= wp->w_upd_rows) 1683 { 1684 top_end = j; 1685 break; 1686 } 1687 } 1688 if (top_end == 0) 1689 // not found (cannot happen?): redraw everything 1690 type = NOT_VALID; 1691 else 1692 // top area defined, the rest is VALID 1693 type = VALID; 1694 } 1695 1696 // Trick: we want to avoid clearing the screen twice. screenclear() will 1697 // set "screen_cleared" to TRUE. The special value MAYBE (which is still 1698 // non-zero and thus not FALSE) will indicate that screenclear() was not 1699 // called. 1700 if (screen_cleared) 1701 screen_cleared = MAYBE; 1702 1703 // If there are no changes on the screen that require a complete redraw, 1704 // handle three cases: 1705 // 1: we are off the top of the screen by a few lines: scroll down 1706 // 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up 1707 // 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in 1708 // w_lines[] that needs updating. 1709 if ((type == VALID || type == SOME_VALID 1710 || type == INVERTED || type == INVERTED_ALL) 1711 #ifdef FEAT_DIFF 1712 && !wp->w_botfill && !wp->w_old_botfill 1713 #endif 1714 ) 1715 { 1716 if (mod_top != 0 1717 && wp->w_topline == mod_top 1718 && (!wp->w_lines[0].wl_valid 1719 || wp->w_topline <= wp->w_lines[0].wl_lnum)) 1720 { 1721 // w_topline is the first changed line and window is not scrolled, 1722 // the scrolling from changed lines will be done further down. 1723 } 1724 else if (wp->w_lines[0].wl_valid 1725 && (wp->w_topline < wp->w_lines[0].wl_lnum 1726 #ifdef FEAT_DIFF 1727 || (wp->w_topline == wp->w_lines[0].wl_lnum 1728 && wp->w_topfill > wp->w_old_topfill) 1729 #endif 1730 )) 1731 { 1732 // New topline is above old topline: May scroll down. 1733 #ifdef FEAT_FOLDING 1734 if (hasAnyFolding(wp)) 1735 { 1736 linenr_T ln; 1737 1738 // count the number of lines we are off, counting a sequence 1739 // of folded lines as one 1740 j = 0; 1741 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln) 1742 { 1743 ++j; 1744 if (j >= wp->w_height - 2) 1745 break; 1746 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL); 1747 } 1748 } 1749 else 1750 #endif 1751 j = wp->w_lines[0].wl_lnum - wp->w_topline; 1752 if (j < wp->w_height - 2) // not too far off 1753 { 1754 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); 1755 #ifdef FEAT_DIFF 1756 // insert extra lines for previously invisible filler lines 1757 if (wp->w_lines[0].wl_lnum != wp->w_topline) 1758 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum) 1759 - wp->w_old_topfill; 1760 #endif 1761 if (i < wp->w_height - 2) // less than a screen off 1762 { 1763 // Try to insert the correct number of lines. 1764 // If not the last window, delete the lines at the bottom. 1765 // win_ins_lines may fail when the terminal can't do it. 1766 if (i > 0) 1767 check_for_delay(FALSE); 1768 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK) 1769 { 1770 if (wp->w_lines_valid != 0) 1771 { 1772 // Need to update rows that are new, stop at the 1773 // first one that scrolled down. 1774 top_end = i; 1775 scrolled_down = TRUE; 1776 1777 // Move the entries that were scrolled, disable 1778 // the entries for the lines to be redrawn. 1779 if ((wp->w_lines_valid += j) > wp->w_height) 1780 wp->w_lines_valid = wp->w_height; 1781 for (idx = wp->w_lines_valid; idx - j >= 0; idx--) 1782 wp->w_lines[idx] = wp->w_lines[idx - j]; 1783 while (idx >= 0) 1784 wp->w_lines[idx--].wl_valid = FALSE; 1785 } 1786 } 1787 else 1788 mid_start = 0; // redraw all lines 1789 } 1790 else 1791 mid_start = 0; // redraw all lines 1792 } 1793 else 1794 mid_start = 0; // redraw all lines 1795 } 1796 else 1797 { 1798 // New topline is at or below old topline: May scroll up. 1799 // When topline didn't change, find first entry in w_lines[] that 1800 // needs updating. 1801 1802 // try to find wp->w_topline in wp->w_lines[].wl_lnum 1803 j = -1; 1804 row = 0; 1805 for (i = 0; i < wp->w_lines_valid; i++) 1806 { 1807 if (wp->w_lines[i].wl_valid 1808 && wp->w_lines[i].wl_lnum == wp->w_topline) 1809 { 1810 j = i; 1811 break; 1812 } 1813 row += wp->w_lines[i].wl_size; 1814 } 1815 if (j == -1) 1816 { 1817 // if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all 1818 // lines 1819 mid_start = 0; 1820 } 1821 else 1822 { 1823 // Try to delete the correct number of lines. 1824 // wp->w_topline is at wp->w_lines[i].wl_lnum. 1825 #ifdef FEAT_DIFF 1826 // If the topline didn't change, delete old filler lines, 1827 // otherwise delete filler lines of the new topline... 1828 if (wp->w_lines[0].wl_lnum == wp->w_topline) 1829 row += wp->w_old_topfill; 1830 else 1831 row += diff_check_fill(wp, wp->w_topline); 1832 // ... but don't delete new filler lines. 1833 row -= wp->w_topfill; 1834 #endif 1835 if (row > 0) 1836 { 1837 check_for_delay(FALSE); 1838 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0) 1839 == OK) 1840 bot_start = wp->w_height - row; 1841 else 1842 mid_start = 0; // redraw all lines 1843 } 1844 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) 1845 { 1846 // Skip the lines (below the deleted lines) that are still 1847 // valid and don't need redrawing. Copy their info 1848 // upwards, to compensate for the deleted lines. Set 1849 // bot_start to the first row that needs redrawing. 1850 bot_start = 0; 1851 idx = 0; 1852 for (;;) 1853 { 1854 wp->w_lines[idx] = wp->w_lines[j]; 1855 // stop at line that didn't fit, unless it is still 1856 // valid (no lines deleted) 1857 if (row > 0 && bot_start + row 1858 + (int)wp->w_lines[j].wl_size > wp->w_height) 1859 { 1860 wp->w_lines_valid = idx + 1; 1861 break; 1862 } 1863 bot_start += wp->w_lines[idx++].wl_size; 1864 1865 // stop at the last valid entry in w_lines[].wl_size 1866 if (++j >= wp->w_lines_valid) 1867 { 1868 wp->w_lines_valid = idx; 1869 break; 1870 } 1871 } 1872 #ifdef FEAT_DIFF 1873 // Correct the first entry for filler lines at the top 1874 // when it won't get updated below. 1875 if (wp->w_p_diff && bot_start > 0) 1876 wp->w_lines[0].wl_size = 1877 plines_win_nofill(wp, wp->w_topline, TRUE) 1878 + wp->w_topfill; 1879 #endif 1880 } 1881 } 1882 } 1883 1884 // When starting redraw in the first line, redraw all lines. When 1885 // there is only one window it's probably faster to clear the screen 1886 // first. 1887 if (mid_start == 0) 1888 { 1889 mid_end = wp->w_height; 1890 if (ONE_WINDOW && !WIN_IS_POPUP(wp)) 1891 { 1892 // Clear the screen when it was not done by win_del_lines() or 1893 // win_ins_lines() above, "screen_cleared" is FALSE or MAYBE 1894 // then. 1895 if (screen_cleared != TRUE) 1896 screenclear(); 1897 // The screen was cleared, redraw the tab pages line. 1898 if (redraw_tabline) 1899 draw_tabline(); 1900 } 1901 } 1902 1903 // When win_del_lines() or win_ins_lines() caused the screen to be 1904 // cleared (only happens for the first window) or when screenclear() 1905 // was called directly above, "must_redraw" will have been set to 1906 // NOT_VALID, need to reset it here to avoid redrawing twice. 1907 if (screen_cleared == TRUE) 1908 must_redraw = 0; 1909 } 1910 else 1911 { 1912 // Not VALID or INVERTED: redraw all lines. 1913 mid_start = 0; 1914 mid_end = wp->w_height; 1915 } 1916 1917 if (type == SOME_VALID) 1918 { 1919 // SOME_VALID: redraw all lines. 1920 mid_start = 0; 1921 mid_end = wp->w_height; 1922 type = NOT_VALID; 1923 } 1924 1925 // check if we are updating or removing the inverted part 1926 if ((VIsual_active && buf == curwin->w_buffer) 1927 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID)) 1928 { 1929 linenr_T from, to; 1930 1931 if (VIsual_active) 1932 { 1933 if (VIsual_active 1934 && (VIsual_mode != wp->w_old_visual_mode 1935 || type == INVERTED_ALL)) 1936 { 1937 // If the type of Visual selection changed, redraw the whole 1938 // selection. Also when the ownership of the X selection is 1939 // gained or lost. 1940 if (curwin->w_cursor.lnum < VIsual.lnum) 1941 { 1942 from = curwin->w_cursor.lnum; 1943 to = VIsual.lnum; 1944 } 1945 else 1946 { 1947 from = VIsual.lnum; 1948 to = curwin->w_cursor.lnum; 1949 } 1950 // redraw more when the cursor moved as well 1951 if (wp->w_old_cursor_lnum < from) 1952 from = wp->w_old_cursor_lnum; 1953 if (wp->w_old_cursor_lnum > to) 1954 to = wp->w_old_cursor_lnum; 1955 if (wp->w_old_visual_lnum < from) 1956 from = wp->w_old_visual_lnum; 1957 if (wp->w_old_visual_lnum > to) 1958 to = wp->w_old_visual_lnum; 1959 } 1960 else 1961 { 1962 // Find the line numbers that need to be updated: The lines 1963 // between the old cursor position and the current cursor 1964 // position. Also check if the Visual position changed. 1965 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum) 1966 { 1967 from = curwin->w_cursor.lnum; 1968 to = wp->w_old_cursor_lnum; 1969 } 1970 else 1971 { 1972 from = wp->w_old_cursor_lnum; 1973 to = curwin->w_cursor.lnum; 1974 if (from == 0) // Visual mode just started 1975 from = to; 1976 } 1977 1978 if (VIsual.lnum != wp->w_old_visual_lnum 1979 || VIsual.col != wp->w_old_visual_col) 1980 { 1981 if (wp->w_old_visual_lnum < from 1982 && wp->w_old_visual_lnum != 0) 1983 from = wp->w_old_visual_lnum; 1984 if (wp->w_old_visual_lnum > to) 1985 to = wp->w_old_visual_lnum; 1986 if (VIsual.lnum < from) 1987 from = VIsual.lnum; 1988 if (VIsual.lnum > to) 1989 to = VIsual.lnum; 1990 } 1991 } 1992 1993 // If in block mode and changed column or curwin->w_curswant: 1994 // update all lines. 1995 // First compute the actual start and end column. 1996 if (VIsual_mode == Ctrl_V) 1997 { 1998 colnr_T fromc, toc; 1999 #if defined(FEAT_LINEBREAK) 2000 int save_ve_flags = ve_flags; 2001 2002 if (curwin->w_p_lbr) 2003 ve_flags = VE_ALL; 2004 #endif 2005 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc); 2006 #if defined(FEAT_LINEBREAK) 2007 ve_flags = save_ve_flags; 2008 #endif 2009 ++toc; 2010 if (curwin->w_curswant == MAXCOL) 2011 toc = MAXCOL; 2012 2013 if (fromc != wp->w_old_cursor_fcol 2014 || toc != wp->w_old_cursor_lcol) 2015 { 2016 if (from > VIsual.lnum) 2017 from = VIsual.lnum; 2018 if (to < VIsual.lnum) 2019 to = VIsual.lnum; 2020 } 2021 wp->w_old_cursor_fcol = fromc; 2022 wp->w_old_cursor_lcol = toc; 2023 } 2024 } 2025 else 2026 { 2027 // Use the line numbers of the old Visual area. 2028 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum) 2029 { 2030 from = wp->w_old_cursor_lnum; 2031 to = wp->w_old_visual_lnum; 2032 } 2033 else 2034 { 2035 from = wp->w_old_visual_lnum; 2036 to = wp->w_old_cursor_lnum; 2037 } 2038 } 2039 2040 // There is no need to update lines above the top of the window. 2041 if (from < wp->w_topline) 2042 from = wp->w_topline; 2043 2044 // If we know the value of w_botline, use it to restrict the update to 2045 // the lines that are visible in the window. 2046 if (wp->w_valid & VALID_BOTLINE) 2047 { 2048 if (from >= wp->w_botline) 2049 from = wp->w_botline - 1; 2050 if (to >= wp->w_botline) 2051 to = wp->w_botline - 1; 2052 } 2053 2054 // Find the minimal part to be updated. 2055 // Watch out for scrolling that made entries in w_lines[] invalid. 2056 // E.g., CTRL-U makes the first half of w_lines[] invalid and sets 2057 // top_end; need to redraw from top_end to the "to" line. 2058 // A middle mouse click with a Visual selection may change the text 2059 // above the Visual area and reset wl_valid, do count these for 2060 // mid_end (in srow). 2061 if (mid_start > 0) 2062 { 2063 lnum = wp->w_topline; 2064 idx = 0; 2065 srow = 0; 2066 if (scrolled_down) 2067 mid_start = top_end; 2068 else 2069 mid_start = 0; 2070 while (lnum < from && idx < wp->w_lines_valid) // find start 2071 { 2072 if (wp->w_lines[idx].wl_valid) 2073 mid_start += wp->w_lines[idx].wl_size; 2074 else if (!scrolled_down) 2075 srow += wp->w_lines[idx].wl_size; 2076 ++idx; 2077 # ifdef FEAT_FOLDING 2078 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid) 2079 lnum = wp->w_lines[idx].wl_lnum; 2080 else 2081 # endif 2082 ++lnum; 2083 } 2084 srow += mid_start; 2085 mid_end = wp->w_height; 2086 for ( ; idx < wp->w_lines_valid; ++idx) // find end 2087 { 2088 if (wp->w_lines[idx].wl_valid 2089 && wp->w_lines[idx].wl_lnum >= to + 1) 2090 { 2091 // Only update until first row of this line 2092 mid_end = srow; 2093 break; 2094 } 2095 srow += wp->w_lines[idx].wl_size; 2096 } 2097 } 2098 } 2099 2100 if (VIsual_active && buf == curwin->w_buffer) 2101 { 2102 wp->w_old_visual_mode = VIsual_mode; 2103 wp->w_old_cursor_lnum = curwin->w_cursor.lnum; 2104 wp->w_old_visual_lnum = VIsual.lnum; 2105 wp->w_old_visual_col = VIsual.col; 2106 wp->w_old_curswant = curwin->w_curswant; 2107 } 2108 else 2109 { 2110 wp->w_old_visual_mode = 0; 2111 wp->w_old_cursor_lnum = 0; 2112 wp->w_old_visual_lnum = 0; 2113 wp->w_old_visual_col = 0; 2114 } 2115 2116 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) 2117 // reset got_int, otherwise regexp won't work 2118 save_got_int = got_int; 2119 got_int = 0; 2120 #endif 2121 #ifdef SYN_TIME_LIMIT 2122 // Set the time limit to 'redrawtime'. 2123 profile_setlimit(p_rdt, &syntax_tm); 2124 syn_set_timeout(&syntax_tm); 2125 #endif 2126 #ifdef FEAT_FOLDING 2127 win_foldinfo.fi_level = 0; 2128 #endif 2129 2130 #ifdef FEAT_MENU 2131 // Draw the window toolbar, if there is one. 2132 // TODO: only when needed. 2133 if (winbar_height(wp) > 0) 2134 redraw_win_toolbar(wp); 2135 #endif 2136 2137 // Update all the window rows. 2138 idx = 0; // first entry in w_lines[].wl_size 2139 row = 0; 2140 srow = 0; 2141 lnum = wp->w_topline; // first line shown in window 2142 for (;;) 2143 { 2144 // stop updating when reached the end of the window (check for _past_ 2145 // the end of the window is at the end of the loop) 2146 if (row == wp->w_height) 2147 { 2148 didline = TRUE; 2149 break; 2150 } 2151 2152 // stop updating when hit the end of the file 2153 if (lnum > buf->b_ml.ml_line_count) 2154 { 2155 eof = TRUE; 2156 break; 2157 } 2158 2159 // Remember the starting row of the line that is going to be dealt 2160 // with. It is used further down when the line doesn't fit. 2161 srow = row; 2162 2163 // Update a line when it is in an area that needs updating, when it 2164 // has changes or w_lines[idx] is invalid. 2165 // "bot_start" may be halfway a wrapped line after using 2166 // win_del_lines(), check if the current line includes it. 2167 // When syntax folding is being used, the saved syntax states will 2168 // already have been updated, we can't see where the syntax state is 2169 // the same again, just update until the end of the window. 2170 if (row < top_end 2171 || (row >= mid_start && row < mid_end) 2172 #ifdef FEAT_SEARCH_EXTRA 2173 || top_to_mod 2174 #endif 2175 || idx >= wp->w_lines_valid 2176 || (row + wp->w_lines[idx].wl_size > bot_start) 2177 || (mod_top != 0 2178 && (lnum == mod_top 2179 || (lnum >= mod_top 2180 && (lnum < mod_bot 2181 #ifdef FEAT_SYN_HL 2182 || did_update == DID_FOLD 2183 || (did_update == DID_LINE 2184 && syntax_present(wp) 2185 && ( 2186 # ifdef FEAT_FOLDING 2187 (foldmethodIsSyntax(wp) 2188 && hasAnyFolding(wp)) || 2189 # endif 2190 syntax_check_changed(lnum))) 2191 #endif 2192 #ifdef FEAT_SEARCH_EXTRA 2193 // match in fixed position might need redraw 2194 // if lines were inserted or deleted 2195 || (wp->w_match_head != NULL 2196 && buf->b_mod_xlines != 0) 2197 #endif 2198 )))) 2199 #ifdef FEAT_SYN_HL 2200 || (wp->w_p_cul && (lnum == wp->w_cursor.lnum 2201 || lnum == wp->w_last_cursorline)) 2202 #endif 2203 ) 2204 { 2205 #ifdef FEAT_SEARCH_EXTRA 2206 if (lnum == mod_top) 2207 top_to_mod = FALSE; 2208 #endif 2209 2210 // When at start of changed lines: May scroll following lines 2211 // up or down to minimize redrawing. 2212 // Don't do this when the change continues until the end. 2213 // Don't scroll when dollar_vcol >= 0, keep the "$". 2214 if (lnum == mod_top 2215 && mod_bot != MAXLNUM 2216 && !(dollar_vcol >= 0 && mod_bot == mod_top + 1)) 2217 { 2218 int old_rows = 0; 2219 int new_rows = 0; 2220 int xtra_rows; 2221 linenr_T l; 2222 2223 // Count the old number of window rows, using w_lines[], which 2224 // should still contain the sizes for the lines as they are 2225 // currently displayed. 2226 for (i = idx; i < wp->w_lines_valid; ++i) 2227 { 2228 // Only valid lines have a meaningful wl_lnum. Invalid 2229 // lines are part of the changed area. 2230 if (wp->w_lines[i].wl_valid 2231 && wp->w_lines[i].wl_lnum == mod_bot) 2232 break; 2233 old_rows += wp->w_lines[i].wl_size; 2234 #ifdef FEAT_FOLDING 2235 if (wp->w_lines[i].wl_valid 2236 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) 2237 { 2238 // Must have found the last valid entry above mod_bot. 2239 // Add following invalid entries. 2240 ++i; 2241 while (i < wp->w_lines_valid 2242 && !wp->w_lines[i].wl_valid) 2243 old_rows += wp->w_lines[i++].wl_size; 2244 break; 2245 } 2246 #endif 2247 } 2248 2249 if (i >= wp->w_lines_valid) 2250 { 2251 // We can't find a valid line below the changed lines, 2252 // need to redraw until the end of the window. 2253 // Inserting/deleting lines has no use. 2254 bot_start = 0; 2255 } 2256 else 2257 { 2258 // Able to count old number of rows: Count new window 2259 // rows, and may insert/delete lines 2260 j = idx; 2261 for (l = lnum; l < mod_bot; ++l) 2262 { 2263 #ifdef FEAT_FOLDING 2264 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL)) 2265 ++new_rows; 2266 else 2267 #endif 2268 #ifdef FEAT_DIFF 2269 if (l == wp->w_topline) 2270 new_rows += plines_win_nofill(wp, l, TRUE) 2271 + wp->w_topfill; 2272 else 2273 #endif 2274 new_rows += plines_win(wp, l, TRUE); 2275 ++j; 2276 if (new_rows > wp->w_height - row - 2) 2277 { 2278 // it's getting too much, must redraw the rest 2279 new_rows = 9999; 2280 break; 2281 } 2282 } 2283 xtra_rows = new_rows - old_rows; 2284 if (xtra_rows < 0) 2285 { 2286 // May scroll text up. If there is not enough 2287 // remaining text or scrolling fails, must redraw the 2288 // rest. If scrolling works, must redraw the text 2289 // below the scrolled text. 2290 if (row - xtra_rows >= wp->w_height - 2) 2291 mod_bot = MAXLNUM; 2292 else 2293 { 2294 check_for_delay(FALSE); 2295 if (win_del_lines(wp, row, 2296 -xtra_rows, FALSE, FALSE, 0) == FAIL) 2297 mod_bot = MAXLNUM; 2298 else 2299 bot_start = wp->w_height + xtra_rows; 2300 } 2301 } 2302 else if (xtra_rows > 0) 2303 { 2304 // May scroll text down. If there is not enough 2305 // remaining text of scrolling fails, must redraw the 2306 // rest. 2307 if (row + xtra_rows >= wp->w_height - 2) 2308 mod_bot = MAXLNUM; 2309 else 2310 { 2311 check_for_delay(FALSE); 2312 if (win_ins_lines(wp, row + old_rows, 2313 xtra_rows, FALSE, FALSE) == FAIL) 2314 mod_bot = MAXLNUM; 2315 else if (top_end > row + old_rows) 2316 // Scrolled the part at the top that requires 2317 // updating down. 2318 top_end += xtra_rows; 2319 } 2320 } 2321 2322 // When not updating the rest, may need to move w_lines[] 2323 // entries. 2324 if (mod_bot != MAXLNUM && i != j) 2325 { 2326 if (j < i) 2327 { 2328 int x = row + new_rows; 2329 2330 // move entries in w_lines[] upwards 2331 for (;;) 2332 { 2333 // stop at last valid entry in w_lines[] 2334 if (i >= wp->w_lines_valid) 2335 { 2336 wp->w_lines_valid = j; 2337 break; 2338 } 2339 wp->w_lines[j] = wp->w_lines[i]; 2340 // stop at a line that won't fit 2341 if (x + (int)wp->w_lines[j].wl_size 2342 > wp->w_height) 2343 { 2344 wp->w_lines_valid = j + 1; 2345 break; 2346 } 2347 x += wp->w_lines[j++].wl_size; 2348 ++i; 2349 } 2350 if (bot_start > x) 2351 bot_start = x; 2352 } 2353 else // j > i 2354 { 2355 // move entries in w_lines[] downwards 2356 j -= i; 2357 wp->w_lines_valid += j; 2358 if (wp->w_lines_valid > wp->w_height) 2359 wp->w_lines_valid = wp->w_height; 2360 for (i = wp->w_lines_valid; i - j >= idx; --i) 2361 wp->w_lines[i] = wp->w_lines[i - j]; 2362 2363 // The w_lines[] entries for inserted lines are 2364 // now invalid, but wl_size may be used above. 2365 // Reset to zero. 2366 while (i >= idx) 2367 { 2368 wp->w_lines[i].wl_size = 0; 2369 wp->w_lines[i--].wl_valid = FALSE; 2370 } 2371 } 2372 } 2373 } 2374 } 2375 2376 #ifdef FEAT_FOLDING 2377 // When lines are folded, display one line for all of them. 2378 // Otherwise, display normally (can be several display lines when 2379 // 'wrap' is on). 2380 fold_count = foldedCount(wp, lnum, &win_foldinfo); 2381 if (fold_count != 0) 2382 { 2383 fold_line(wp, fold_count, &win_foldinfo, lnum, row); 2384 ++row; 2385 --fold_count; 2386 wp->w_lines[idx].wl_folded = TRUE; 2387 wp->w_lines[idx].wl_lastlnum = lnum + fold_count; 2388 # ifdef FEAT_SYN_HL 2389 did_update = DID_FOLD; 2390 # endif 2391 } 2392 else 2393 #endif 2394 if (idx < wp->w_lines_valid 2395 && wp->w_lines[idx].wl_valid 2396 && wp->w_lines[idx].wl_lnum == lnum 2397 && lnum > wp->w_topline 2398 && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) 2399 && !WIN_IS_POPUP(wp) 2400 && srow + wp->w_lines[idx].wl_size > wp->w_height 2401 #ifdef FEAT_DIFF 2402 && diff_check_fill(wp, lnum) == 0 2403 #endif 2404 ) 2405 { 2406 // This line is not going to fit. Don't draw anything here, 2407 // will draw "@ " lines below. 2408 row = wp->w_height + 1; 2409 } 2410 else 2411 { 2412 #ifdef FEAT_SEARCH_EXTRA 2413 prepare_search_hl(wp, &screen_search_hl, lnum); 2414 #endif 2415 #ifdef FEAT_SYN_HL 2416 // Let the syntax stuff know we skipped a few lines. 2417 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum 2418 && syntax_present(wp)) 2419 syntax_end_parsing(syntax_last_parsed + 1); 2420 #endif 2421 2422 // Display one line. 2423 row = win_line(wp, lnum, srow, wp->w_height, 2424 mod_top == 0, FALSE); 2425 2426 #ifdef FEAT_FOLDING 2427 wp->w_lines[idx].wl_folded = FALSE; 2428 wp->w_lines[idx].wl_lastlnum = lnum; 2429 #endif 2430 #ifdef FEAT_SYN_HL 2431 did_update = DID_LINE; 2432 syntax_last_parsed = lnum; 2433 #endif 2434 } 2435 2436 wp->w_lines[idx].wl_lnum = lnum; 2437 wp->w_lines[idx].wl_valid = TRUE; 2438 2439 // Past end of the window or end of the screen. Note that after 2440 // resizing wp->w_height may be end up too big. That's a problem 2441 // elsewhere, but prevent a crash here. 2442 if (row > wp->w_height || row + wp->w_winrow >= Rows) 2443 { 2444 // we may need the size of that too long line later on 2445 if (dollar_vcol == -1) 2446 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE); 2447 ++idx; 2448 break; 2449 } 2450 if (dollar_vcol == -1) 2451 wp->w_lines[idx].wl_size = row - srow; 2452 ++idx; 2453 #ifdef FEAT_FOLDING 2454 lnum += fold_count + 1; 2455 #else 2456 ++lnum; 2457 #endif 2458 } 2459 else 2460 { 2461 if (wp->w_p_rnu) 2462 { 2463 #ifdef FEAT_FOLDING 2464 // 'relativenumber' set: The text doesn't need to be drawn, but 2465 // the number column nearly always does. 2466 fold_count = foldedCount(wp, lnum, &win_foldinfo); 2467 if (fold_count != 0) 2468 fold_line(wp, fold_count, &win_foldinfo, lnum, row); 2469 else 2470 #endif 2471 (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE); 2472 } 2473 2474 // This line does not need to be drawn, advance to the next one. 2475 row += wp->w_lines[idx++].wl_size; 2476 if (row > wp->w_height) // past end of screen 2477 break; 2478 #ifdef FEAT_FOLDING 2479 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1; 2480 #else 2481 ++lnum; 2482 #endif 2483 #ifdef FEAT_SYN_HL 2484 did_update = DID_NONE; 2485 #endif 2486 } 2487 2488 if (lnum > buf->b_ml.ml_line_count) 2489 { 2490 eof = TRUE; 2491 break; 2492 } 2493 } 2494 2495 // End of loop over all window lines. 2496 2497 #ifdef FEAT_VTP 2498 // Rewrite the character at the end of the screen line. 2499 // See the version that was fixed. 2500 if (use_vtp() && get_conpty_fix_type() < 1) 2501 { 2502 int i; 2503 2504 for (i = 0; i < Rows; ++i) 2505 if (enc_utf8) 2506 if ((*mb_off2cells)(LineOffset[i] + Columns - 2, 2507 LineOffset[i] + screen_Columns) > 1) 2508 screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE); 2509 else 2510 screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE); 2511 else 2512 screen_char(LineOffset[i] + Columns - 1, i, Columns - 1); 2513 } 2514 #endif 2515 2516 if (idx > wp->w_lines_valid) 2517 wp->w_lines_valid = idx; 2518 2519 #ifdef FEAT_SYN_HL 2520 // Let the syntax stuff know we stop parsing here. 2521 if (syntax_last_parsed != 0 && syntax_present(wp)) 2522 syntax_end_parsing(syntax_last_parsed + 1); 2523 #endif 2524 2525 // If we didn't hit the end of the file, and we didn't finish the last 2526 // line we were working on, then the line didn't fit. 2527 wp->w_empty_rows = 0; 2528 #ifdef FEAT_DIFF 2529 wp->w_filler_rows = 0; 2530 #endif 2531 if (!eof && !didline) 2532 { 2533 if (lnum == wp->w_topline) 2534 { 2535 // Single line that does not fit! 2536 // Don't overwrite it, it can be edited. 2537 wp->w_botline = lnum + 1; 2538 } 2539 #ifdef FEAT_DIFF 2540 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow) 2541 { 2542 // Window ends in filler lines. 2543 wp->w_botline = lnum; 2544 wp->w_filler_rows = wp->w_height - srow; 2545 } 2546 #endif 2547 #ifdef FEAT_PROP_POPUP 2548 else if (WIN_IS_POPUP(wp)) 2549 { 2550 // popup line that doesn't fit is left as-is 2551 wp->w_botline = lnum; 2552 } 2553 #endif 2554 else if (dy_flags & DY_TRUNCATE) // 'display' has "truncate" 2555 { 2556 int scr_row = W_WINROW(wp) + wp->w_height - 1; 2557 2558 // Last line isn't finished: Display "@@@" in the last screen line. 2559 screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol, 2560 HL_ATTR(HLF_AT)); 2561 screen_fill(scr_row, scr_row + 1, 2562 (int)wp->w_wincol + 2, (int)W_ENDCOL(wp), 2563 '@', ' ', HL_ATTR(HLF_AT)); 2564 set_empty_rows(wp, srow); 2565 wp->w_botline = lnum; 2566 } 2567 else if (dy_flags & DY_LASTLINE) // 'display' has "lastline" 2568 { 2569 // Last line isn't finished: Display "@@@" at the end. 2570 screen_fill(W_WINROW(wp) + wp->w_height - 1, 2571 W_WINROW(wp) + wp->w_height, 2572 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp), 2573 '@', '@', HL_ATTR(HLF_AT)); 2574 set_empty_rows(wp, srow); 2575 wp->w_botline = lnum; 2576 } 2577 else 2578 { 2579 win_draw_end(wp, '@', ' ', TRUE, srow, wp->w_height, HLF_AT); 2580 wp->w_botline = lnum; 2581 } 2582 } 2583 else 2584 { 2585 draw_vsep_win(wp, row); 2586 if (eof) // we hit the end of the file 2587 { 2588 wp->w_botline = buf->b_ml.ml_line_count + 1; 2589 #ifdef FEAT_DIFF 2590 j = diff_check_fill(wp, wp->w_botline); 2591 if (j > 0 && !wp->w_botfill) 2592 { 2593 // Display filler lines at the end of the file. 2594 if (char2cells(fill_diff) > 1) 2595 i = '-'; 2596 else 2597 i = fill_diff; 2598 if (row + j > wp->w_height) 2599 j = wp->w_height - row; 2600 win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED); 2601 row += j; 2602 } 2603 #endif 2604 } 2605 else if (dollar_vcol == -1) 2606 wp->w_botline = lnum; 2607 2608 // Make sure the rest of the screen is blank 2609 // write the 'fill_eob' character to rows that aren't part of the file 2610 if (WIN_IS_POPUP(wp)) 2611 win_draw_end(wp, ' ', ' ', FALSE, row, wp->w_height, HLF_AT); 2612 else 2613 win_draw_end(wp, fill_eob, ' ', FALSE, row, wp->w_height, HLF_EOB); 2614 } 2615 2616 #ifdef SYN_TIME_LIMIT 2617 syn_set_timeout(NULL); 2618 #endif 2619 2620 // Reset the type of redrawing required, the window has been updated. 2621 wp->w_redr_type = 0; 2622 #ifdef FEAT_DIFF 2623 wp->w_old_topfill = wp->w_topfill; 2624 wp->w_old_botfill = wp->w_botfill; 2625 #endif 2626 2627 if (dollar_vcol == -1) 2628 { 2629 // There is a trick with w_botline. If we invalidate it on each 2630 // change that might modify it, this will cause a lot of expensive 2631 // calls to plines() in update_topline() each time. Therefore the 2632 // value of w_botline is often approximated, and this value is used to 2633 // compute the value of w_topline. If the value of w_botline was 2634 // wrong, check that the value of w_topline is correct (cursor is on 2635 // the visible part of the text). If it's not, we need to redraw 2636 // again. Mostly this just means scrolling up a few lines, so it 2637 // doesn't look too bad. Only do this for the current window (where 2638 // changes are relevant). 2639 wp->w_valid |= VALID_BOTLINE; 2640 if (wp == curwin && wp->w_botline != old_botline && !recursive) 2641 { 2642 win_T *wwp; 2643 #if defined(FEAT_CONCEAL) 2644 linenr_T old_topline = wp->w_topline; 2645 int new_wcol = wp->w_wcol; 2646 #endif 2647 recursive = TRUE; 2648 curwin->w_valid &= ~VALID_TOPLINE; 2649 update_topline(); // may invalidate w_botline again 2650 2651 #if defined(FEAT_CONCEAL) 2652 if (old_wcol != new_wcol && (wp->w_valid & (VALID_WCOL|VALID_WROW)) 2653 != (VALID_WCOL|VALID_WROW)) 2654 { 2655 // A win_line() call applied a fix to screen cursor column to 2656 // accommodate concealment of cursor line, but in this call to 2657 // update_topline() the cursor's row or column got invalidated. 2658 // If they are left invalid, setcursor() will recompute them 2659 // but there won't be any further win_line() call to re-fix the 2660 // column and the cursor will end up misplaced. So we call 2661 // cursor validation now and reapply the fix again (or call 2662 // win_line() to do it for us). 2663 validate_cursor(); 2664 if (wp->w_wcol == old_wcol && wp->w_wrow == old_wrow 2665 && old_topline == wp->w_topline) 2666 wp->w_wcol = new_wcol; 2667 else 2668 redrawWinline(wp, wp->w_cursor.lnum); 2669 } 2670 #endif 2671 // New redraw either due to updated topline or due to wcol fix. 2672 if (wp->w_redr_type != 0) 2673 { 2674 // Don't update for changes in buffer again. 2675 i = curbuf->b_mod_set; 2676 curbuf->b_mod_set = FALSE; 2677 j = curbuf->b_mod_xlines; 2678 curbuf->b_mod_xlines = 0; 2679 win_update(curwin); 2680 curbuf->b_mod_set = i; 2681 curbuf->b_mod_xlines = j; 2682 } 2683 // Other windows might have w_redr_type raised in update_topline(). 2684 must_redraw = 0; 2685 FOR_ALL_WINDOWS(wwp) 2686 if (wwp->w_redr_type > must_redraw) 2687 must_redraw = wwp->w_redr_type; 2688 recursive = FALSE; 2689 } 2690 } 2691 2692 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) 2693 // restore got_int, unless CTRL-C was hit while redrawing 2694 if (!got_int) 2695 got_int = save_got_int; 2696 #endif 2697 } 2698 2699 #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI) 2700 /* 2701 * Prepare for updating one or more windows. 2702 * Caller must check for "updating_screen" already set to avoid recursiveness. 2703 */ 2704 static void 2705 update_prepare(void) 2706 { 2707 cursor_off(); 2708 updating_screen = TRUE; 2709 #ifdef FEAT_GUI 2710 // Remove the cursor before starting to do anything, because scrolling may 2711 // make it difficult to redraw the text under it. 2712 if (gui.in_use) 2713 gui_undraw_cursor(); 2714 #endif 2715 #ifdef FEAT_SEARCH_EXTRA 2716 start_search_hl(); 2717 #endif 2718 #ifdef FEAT_PROP_POPUP 2719 // Update popup_mask if needed. 2720 may_update_popup_mask(must_redraw); 2721 #endif 2722 } 2723 2724 /* 2725 * Finish updating one or more windows. 2726 */ 2727 static void 2728 update_finish(void) 2729 { 2730 if (redraw_cmdline || redraw_mode) 2731 showmode(); 2732 2733 # ifdef FEAT_SEARCH_EXTRA 2734 end_search_hl(); 2735 # endif 2736 2737 after_updating_screen(TRUE); 2738 2739 # ifdef FEAT_GUI 2740 // Redraw the cursor and update the scrollbars when all screen updating is 2741 // done. 2742 if (gui.in_use) 2743 { 2744 out_flush_cursor(FALSE, FALSE); 2745 gui_update_scrollbars(FALSE); 2746 } 2747 # endif 2748 } 2749 #endif 2750 2751 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO) 2752 void 2753 update_debug_sign(buf_T *buf, linenr_T lnum) 2754 { 2755 win_T *wp; 2756 int doit = FALSE; 2757 2758 # ifdef FEAT_FOLDING 2759 win_foldinfo.fi_level = 0; 2760 # endif 2761 2762 // update/delete a specific sign 2763 redraw_buf_line_later(buf, lnum); 2764 2765 // check if it resulted in the need to redraw a window 2766 FOR_ALL_WINDOWS(wp) 2767 if (wp->w_redr_type != 0) 2768 doit = TRUE; 2769 2770 // Return when there is nothing to do, screen updating is already 2771 // happening (recursive call), messages on the screen or still starting up. 2772 if (!doit || updating_screen 2773 || State == ASKMORE || State == HITRETURN 2774 || msg_scrolled 2775 #ifdef FEAT_GUI 2776 || gui.starting 2777 #endif 2778 || starting) 2779 return; 2780 2781 // update all windows that need updating 2782 update_prepare(); 2783 2784 FOR_ALL_WINDOWS(wp) 2785 { 2786 if (wp->w_redr_type != 0) 2787 win_update(wp); 2788 if (wp->w_redr_status) 2789 win_redr_status(wp, FALSE); 2790 } 2791 2792 update_finish(); 2793 } 2794 #endif 2795 2796 #if defined(FEAT_GUI) || defined(PROTO) 2797 /* 2798 * Update a single window, its status line and maybe the command line msg. 2799 * Used for the GUI scrollbar. 2800 */ 2801 void 2802 updateWindow(win_T *wp) 2803 { 2804 // return if already busy updating 2805 if (updating_screen) 2806 return; 2807 2808 update_prepare(); 2809 2810 #ifdef FEAT_CLIPBOARD 2811 // When Visual area changed, may have to update selection. 2812 if (clip_star.available && clip_isautosel_star()) 2813 clip_update_selection(&clip_star); 2814 if (clip_plus.available && clip_isautosel_plus()) 2815 clip_update_selection(&clip_plus); 2816 #endif 2817 2818 win_update(wp); 2819 2820 // When the screen was cleared redraw the tab pages line. 2821 if (redraw_tabline) 2822 draw_tabline(); 2823 2824 if (wp->w_redr_status 2825 # ifdef FEAT_CMDL_INFO 2826 || p_ru 2827 # endif 2828 # ifdef FEAT_STL_OPT 2829 || *p_stl != NUL || *wp->w_p_stl != NUL 2830 # endif 2831 ) 2832 win_redr_status(wp, FALSE); 2833 2834 #ifdef FEAT_PROP_POPUP 2835 // Display popup windows on top of everything. 2836 update_popups(win_update); 2837 #endif 2838 2839 update_finish(); 2840 } 2841 #endif 2842 2843 #if defined(FEAT_TERMRESPONSE) || defined(PROTO) 2844 /* 2845 * Redraw as soon as possible. When the command line is not scrolled redraw 2846 * right away and restore what was on the command line. 2847 * Return a code indicating what happened. 2848 */ 2849 int 2850 redraw_asap(int type) 2851 { 2852 int rows; 2853 int cols = screen_Columns; 2854 int r; 2855 int ret = 0; 2856 schar_T *screenline; // copy from ScreenLines[] 2857 sattr_T *screenattr; // copy from ScreenAttrs[] 2858 int i; 2859 u8char_T *screenlineUC = NULL; // copy from ScreenLinesUC[] 2860 u8char_T *screenlineC[MAX_MCO]; // copy from ScreenLinesC[][] 2861 schar_T *screenline2 = NULL; // copy from ScreenLines2[] 2862 2863 redraw_later(type); 2864 if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting) 2865 return ret; 2866 2867 // Allocate space to save the text displayed in the command line area. 2868 rows = screen_Rows - cmdline_row; 2869 screenline = LALLOC_MULT(schar_T, rows * cols); 2870 screenattr = LALLOC_MULT(sattr_T, rows * cols); 2871 if (screenline == NULL || screenattr == NULL) 2872 ret = 2; 2873 if (enc_utf8) 2874 { 2875 screenlineUC = LALLOC_MULT(u8char_T, rows * cols); 2876 if (screenlineUC == NULL) 2877 ret = 2; 2878 for (i = 0; i < p_mco; ++i) 2879 { 2880 screenlineC[i] = LALLOC_MULT(u8char_T, rows * cols); 2881 if (screenlineC[i] == NULL) 2882 ret = 2; 2883 } 2884 } 2885 if (enc_dbcs == DBCS_JPNU) 2886 { 2887 screenline2 = LALLOC_MULT(schar_T, rows * cols); 2888 if (screenline2 == NULL) 2889 ret = 2; 2890 } 2891 2892 if (ret != 2) 2893 { 2894 // Save the text displayed in the command line area. 2895 for (r = 0; r < rows; ++r) 2896 { 2897 mch_memmove(screenline + r * cols, 2898 ScreenLines + LineOffset[cmdline_row + r], 2899 (size_t)cols * sizeof(schar_T)); 2900 mch_memmove(screenattr + r * cols, 2901 ScreenAttrs + LineOffset[cmdline_row + r], 2902 (size_t)cols * sizeof(sattr_T)); 2903 if (enc_utf8) 2904 { 2905 mch_memmove(screenlineUC + r * cols, 2906 ScreenLinesUC + LineOffset[cmdline_row + r], 2907 (size_t)cols * sizeof(u8char_T)); 2908 for (i = 0; i < p_mco; ++i) 2909 mch_memmove(screenlineC[i] + r * cols, 2910 ScreenLinesC[i] + LineOffset[cmdline_row + r], 2911 (size_t)cols * sizeof(u8char_T)); 2912 } 2913 if (enc_dbcs == DBCS_JPNU) 2914 mch_memmove(screenline2 + r * cols, 2915 ScreenLines2 + LineOffset[cmdline_row + r], 2916 (size_t)cols * sizeof(schar_T)); 2917 } 2918 2919 update_screen(0); 2920 ret = 3; 2921 2922 if (must_redraw == 0) 2923 { 2924 int off = (int)(current_ScreenLine - ScreenLines); 2925 2926 // Restore the text displayed in the command line area. 2927 for (r = 0; r < rows; ++r) 2928 { 2929 mch_memmove(current_ScreenLine, 2930 screenline + r * cols, 2931 (size_t)cols * sizeof(schar_T)); 2932 mch_memmove(ScreenAttrs + off, 2933 screenattr + r * cols, 2934 (size_t)cols * sizeof(sattr_T)); 2935 if (enc_utf8) 2936 { 2937 mch_memmove(ScreenLinesUC + off, 2938 screenlineUC + r * cols, 2939 (size_t)cols * sizeof(u8char_T)); 2940 for (i = 0; i < p_mco; ++i) 2941 mch_memmove(ScreenLinesC[i] + off, 2942 screenlineC[i] + r * cols, 2943 (size_t)cols * sizeof(u8char_T)); 2944 } 2945 if (enc_dbcs == DBCS_JPNU) 2946 mch_memmove(ScreenLines2 + off, 2947 screenline2 + r * cols, 2948 (size_t)cols * sizeof(schar_T)); 2949 screen_line(cmdline_row + r, 0, cols, cols, 0); 2950 } 2951 ret = 4; 2952 } 2953 } 2954 2955 vim_free(screenline); 2956 vim_free(screenattr); 2957 if (enc_utf8) 2958 { 2959 vim_free(screenlineUC); 2960 for (i = 0; i < p_mco; ++i) 2961 vim_free(screenlineC[i]); 2962 } 2963 if (enc_dbcs == DBCS_JPNU) 2964 vim_free(screenline2); 2965 2966 // Show the intro message when appropriate. 2967 maybe_intro_message(); 2968 2969 setcursor(); 2970 2971 return ret; 2972 } 2973 #endif 2974 2975 /* 2976 * Invoked after an asynchronous callback is called. 2977 * If an echo command was used the cursor needs to be put back where 2978 * it belongs. If highlighting was changed a redraw is needed. 2979 * If "call_update_screen" is FALSE don't call update_screen() when at the 2980 * command line. 2981 */ 2982 void 2983 redraw_after_callback(int call_update_screen) 2984 { 2985 ++redrawing_for_callback; 2986 2987 if (State == HITRETURN || State == ASKMORE) 2988 ; // do nothing 2989 else if (State & CMDLINE) 2990 { 2991 // Don't redraw when in prompt_for_number(). 2992 if (cmdline_row > 0) 2993 { 2994 // Redrawing only works when the screen didn't scroll. Don't clear 2995 // wildmenu entries. 2996 if (msg_scrolled == 0 2997 #ifdef FEAT_WILDMENU 2998 && wild_menu_showing == 0 2999 #endif 3000 && call_update_screen) 3001 update_screen(0); 3002 3003 // Redraw in the same position, so that the user can continue 3004 // editing the command. 3005 redrawcmdline_ex(FALSE); 3006 } 3007 } 3008 else if (State & (NORMAL | INSERT | TERMINAL)) 3009 { 3010 // keep the command line if possible 3011 update_screen(VALID_NO_UPDATE); 3012 setcursor(); 3013 3014 if (msg_scrolled == 0) 3015 { 3016 // don't want a hit-enter prompt when something else is displayed 3017 msg_didany = FALSE; 3018 need_wait_return = FALSE; 3019 } 3020 } 3021 cursor_on(); 3022 #ifdef FEAT_GUI 3023 if (gui.in_use && !gui_mch_is_blink_off()) 3024 // Don't update the cursor when it is blinking and off to avoid 3025 // flicker. 3026 out_flush_cursor(FALSE, FALSE); 3027 else 3028 #endif 3029 out_flush(); 3030 3031 --redrawing_for_callback; 3032 } 3033 3034 /* 3035 * Redraw the current window later, with update_screen(type). 3036 * Set must_redraw only if not already set to a higher value. 3037 * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. 3038 */ 3039 void 3040 redraw_later(int type) 3041 { 3042 redraw_win_later(curwin, type); 3043 } 3044 3045 void 3046 redraw_win_later( 3047 win_T *wp, 3048 int type) 3049 { 3050 if (!exiting && wp->w_redr_type < type) 3051 { 3052 wp->w_redr_type = type; 3053 if (type >= NOT_VALID) 3054 wp->w_lines_valid = 0; 3055 if (must_redraw < type) // must_redraw is the maximum of all windows 3056 must_redraw = type; 3057 } 3058 } 3059 3060 /* 3061 * Force a complete redraw later. Also resets the highlighting. To be used 3062 * after executing a shell command that messes up the screen. 3063 */ 3064 void 3065 redraw_later_clear(void) 3066 { 3067 redraw_all_later(CLEAR); 3068 reset_screen_attr(); 3069 } 3070 3071 /* 3072 * Mark all windows to be redrawn later. 3073 */ 3074 void 3075 redraw_all_later(int type) 3076 { 3077 win_T *wp; 3078 3079 FOR_ALL_WINDOWS(wp) 3080 redraw_win_later(wp, type); 3081 // This may be needed when switching tabs. 3082 if (must_redraw < type) 3083 must_redraw = type; 3084 } 3085 3086 /* 3087 * Mark all windows that are editing the current buffer to be updated later. 3088 */ 3089 void 3090 redraw_curbuf_later(int type) 3091 { 3092 redraw_buf_later(curbuf, type); 3093 } 3094 3095 void 3096 redraw_buf_later(buf_T *buf, int type) 3097 { 3098 win_T *wp; 3099 3100 FOR_ALL_WINDOWS(wp) 3101 { 3102 if (wp->w_buffer == buf) 3103 redraw_win_later(wp, type); 3104 } 3105 #if defined(FEAT_TERMINAL) && defined(FEAT_PROP_POPUP) 3106 // terminal in popup window is not in list of windows 3107 if (curwin->w_buffer == buf) 3108 redraw_win_later(curwin, type); 3109 #endif 3110 } 3111 3112 #if defined(FEAT_SIGNS) || defined(PROTO) 3113 void 3114 redraw_buf_line_later(buf_T *buf, linenr_T lnum) 3115 { 3116 win_T *wp; 3117 3118 FOR_ALL_WINDOWS(wp) 3119 if (wp->w_buffer == buf && lnum >= wp->w_topline 3120 && lnum < wp->w_botline) 3121 redrawWinline(wp, lnum); 3122 } 3123 #endif 3124 3125 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 3126 void 3127 redraw_buf_and_status_later(buf_T *buf, int type) 3128 { 3129 win_T *wp; 3130 3131 #ifdef FEAT_WILDMENU 3132 if (wild_menu_showing != 0) 3133 // Don't redraw while the command line completion is displayed, it 3134 // would disappear. 3135 return; 3136 #endif 3137 FOR_ALL_WINDOWS(wp) 3138 { 3139 if (wp->w_buffer == buf) 3140 { 3141 redraw_win_later(wp, type); 3142 wp->w_redr_status = TRUE; 3143 } 3144 } 3145 } 3146 #endif 3147 3148 /* 3149 * mark all status lines for redraw; used after first :cd 3150 */ 3151 void 3152 status_redraw_all(void) 3153 { 3154 win_T *wp; 3155 3156 FOR_ALL_WINDOWS(wp) 3157 if (wp->w_status_height) 3158 { 3159 wp->w_redr_status = TRUE; 3160 redraw_later(VALID); 3161 } 3162 } 3163 3164 /* 3165 * mark all status lines of the current buffer for redraw 3166 */ 3167 void 3168 status_redraw_curbuf(void) 3169 { 3170 win_T *wp; 3171 3172 FOR_ALL_WINDOWS(wp) 3173 if (wp->w_status_height != 0 && wp->w_buffer == curbuf) 3174 { 3175 wp->w_redr_status = TRUE; 3176 redraw_later(VALID); 3177 } 3178 } 3179 3180 /* 3181 * Redraw all status lines that need to be redrawn. 3182 */ 3183 void 3184 redraw_statuslines(void) 3185 { 3186 win_T *wp; 3187 3188 FOR_ALL_WINDOWS(wp) 3189 if (wp->w_redr_status) 3190 win_redr_status(wp, FALSE); 3191 if (redraw_tabline) 3192 draw_tabline(); 3193 } 3194 3195 #if defined(FEAT_WILDMENU) || defined(PROTO) 3196 /* 3197 * Redraw all status lines at the bottom of frame "frp". 3198 */ 3199 void 3200 win_redraw_last_status(frame_T *frp) 3201 { 3202 if (frp->fr_layout == FR_LEAF) 3203 frp->fr_win->w_redr_status = TRUE; 3204 else if (frp->fr_layout == FR_ROW) 3205 { 3206 FOR_ALL_FRAMES(frp, frp->fr_child) 3207 win_redraw_last_status(frp); 3208 } 3209 else // frp->fr_layout == FR_COL 3210 { 3211 frp = frp->fr_child; 3212 while (frp->fr_next != NULL) 3213 frp = frp->fr_next; 3214 win_redraw_last_status(frp); 3215 } 3216 } 3217 #endif 3218 3219 /* 3220 * Changed something in the current window, at buffer line "lnum", that 3221 * requires that line and possibly other lines to be redrawn. 3222 * Used when entering/leaving Insert mode with the cursor on a folded line. 3223 * Used to remove the "$" from a change command. 3224 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot 3225 * may become invalid and the whole window will have to be redrawn. 3226 */ 3227 void 3228 redrawWinline( 3229 win_T *wp, 3230 linenr_T lnum) 3231 { 3232 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) 3233 wp->w_redraw_top = lnum; 3234 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) 3235 wp->w_redraw_bot = lnum; 3236 redraw_win_later(wp, VALID); 3237 } 3238