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