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 * screen.c: code for displaying on the screen 12 * 13 * Output to the screen (console, terminal emulator or GUI window) is minimized 14 * by remembering what is already on the screen, and only updating the parts 15 * that changed. 16 * 17 * ScreenLines[off] Contains a copy of the whole screen, as it is currently 18 * displayed (excluding text written by external commands). 19 * ScreenAttrs[off] Contains the associated attributes. 20 * LineOffset[row] Contains the offset into ScreenLines*[] and ScreenAttrs[] 21 * for each line. 22 * LineWraps[row] Flag for each line whether it wraps to the next line. 23 * 24 * For double-byte characters, two consecutive bytes in ScreenLines[] can form 25 * one character which occupies two display cells. 26 * For UTF-8 a multi-byte character is converted to Unicode and stored in 27 * ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII 28 * character without composing chars ScreenLinesUC[] will be 0 and 29 * ScreenLinesC[][] is not used. When the character occupies two display 30 * cells the next byte in ScreenLines[] is 0. 31 * ScreenLinesC[][] contain up to 'maxcombine' composing characters 32 * (drawn on top of the first character). There is 0 after the last one used. 33 * ScreenLines2[] is only used for euc-jp to store the second byte if the 34 * first byte is 0x8e (single-width character). 35 * 36 * The screen_*() functions write to the screen and handle updating 37 * ScreenLines[]. 38 * 39 * update_screen() is the function that updates all windows and status lines. 40 * It is called form the main loop when must_redraw is non-zero. It may be 41 * called from other places when an immediate screen update is needed. 42 * 43 * The part of the buffer that is displayed in a window is set with: 44 * - w_topline (first buffer line in window) 45 * - w_topfill (filler lines above the first line) 46 * - w_leftcol (leftmost window cell in window), 47 * - w_skipcol (skipped window cells of first line) 48 * 49 * Commands that only move the cursor around in a window, do not need to take 50 * action to update the display. The main loop will check if w_topline is 51 * valid and update it (scroll the window) when needed. 52 * 53 * Commands that scroll a window change w_topline and must call 54 * check_cursor() to move the cursor into the visible part of the window, and 55 * call redraw_later(VALID) to have the window displayed by update_screen() 56 * later. 57 * 58 * Commands that change text in the buffer must call changed_bytes() or 59 * changed_lines() to mark the area that changed and will require updating 60 * later. The main loop will call update_screen(), which will update each 61 * window that shows the changed buffer. This assumes text above the change 62 * can remain displayed as it is. Text after the change may need updating for 63 * scrolling, folding and syntax highlighting. 64 * 65 * Commands that change how a window is displayed (e.g., setting 'list') or 66 * invalidate the contents of a window in another way (e.g., change fold 67 * settings), must call redraw_later(NOT_VALID) to have the whole window 68 * redisplayed by update_screen() later. 69 * 70 * Commands that change how a buffer is displayed (e.g., setting 'tabstop') 71 * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the 72 * buffer redisplayed by update_screen() later. 73 * 74 * Commands that change highlighting and possibly cause a scroll too must call 75 * redraw_later(SOME_VALID) to update the whole window but still use scrolling 76 * to avoid redrawing everything. But the length of displayed lines must not 77 * change, use NOT_VALID then. 78 * 79 * Commands that move the window position must call redraw_later(NOT_VALID). 80 * TODO: should minimize redrawing by scrolling when possible. 81 * 82 * Commands that change everything (e.g., resizing the screen) must call 83 * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR). 84 * 85 * Things that are handled indirectly: 86 * - When messages scroll the screen up, msg_scrolled will be set and 87 * update_screen() called to redraw. 88 */ 89 90 #include "vim.h" 91 92 #define MB_FILLER_CHAR '<' /* character used when a double-width character 93 * doesn't fit. */ 94 95 /* 96 * The attributes that are actually active for writing to the screen. 97 */ 98 static int screen_attr = 0; 99 100 /* 101 * Positioning the cursor is reduced by remembering the last position. 102 * Mostly used by windgoto() and screen_char(). 103 */ 104 static int screen_cur_row, screen_cur_col; /* last known cursor position */ 105 106 #ifdef FEAT_SEARCH_EXTRA 107 static match_T search_hl; /* used for 'hlsearch' highlight matching */ 108 #endif 109 110 #ifdef FEAT_FOLDING 111 static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */ 112 static int compute_foldcolumn(win_T *wp, int col); 113 #endif 114 115 /* Flag that is set when drawing for a callback, not from the main command 116 * loop. */ 117 static int redrawing_for_callback = 0; 118 119 /* 120 * Buffer for one screen line (characters and attributes). 121 */ 122 static schar_T *current_ScreenLine; 123 124 static void win_update(win_T *wp); 125 static void win_redr_status(win_T *wp, int ignore_pum); 126 static void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl); 127 #ifdef FEAT_FOLDING 128 static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row); 129 static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum); 130 static void copy_text_attr(int off, char_u *buf, int len, int attr); 131 #endif 132 static int win_line(win_T *, linenr_T, int, int, int nochange, int number_only); 133 static void draw_vsep_win(win_T *wp, int row); 134 #ifdef FEAT_STL_OPT 135 static void redraw_custom_statusline(win_T *wp); 136 #endif 137 #ifdef FEAT_SEARCH_EXTRA 138 # define SEARCH_HL_PRIORITY 0 139 static void start_search_hl(void); 140 static void end_search_hl(void); 141 static void init_search_hl(win_T *wp); 142 static void prepare_search_hl(win_T *wp, linenr_T lnum); 143 static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur); 144 static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol); 145 #endif 146 static void screen_char(unsigned off, int row, int col); 147 static void screen_char_2(unsigned off, int row, int col); 148 static void screenclear2(void); 149 static void lineclear(unsigned off, int width, int attr); 150 static void lineinvalid(unsigned off, int width); 151 static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr); 152 static void win_rest_invalid(win_T *wp); 153 static void msg_pos_mode(void); 154 static void recording_mode(int attr); 155 static int fillchar_status(int *attr, win_T *wp); 156 static int fillchar_vsep(int *attr); 157 #ifdef FEAT_MENU 158 static void redraw_win_toolbar(win_T *wp); 159 #endif 160 #ifdef FEAT_STL_OPT 161 static void win_redr_custom(win_T *wp, int draw_ruler); 162 #endif 163 #ifdef FEAT_CMDL_INFO 164 static void win_redr_ruler(win_T *wp, int always, int ignore_pum); 165 #endif 166 167 /* Ugly global: overrule attribute used by screen_char() */ 168 static int screen_char_attr = 0; 169 170 #if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) 171 /* Can limit syntax highlight time to 'redrawtime'. */ 172 # define SYN_TIME_LIMIT 1 173 #endif 174 175 #ifdef FEAT_RIGHTLEFT 176 # define HAS_RIGHTLEFT(x) x 177 #else 178 # define HAS_RIGHTLEFT(x) FALSE 179 #endif 180 181 /* 182 * Redraw the current window later, with update_screen(type). 183 * Set must_redraw only if not already set to a higher value. 184 * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. 185 */ 186 void 187 redraw_later(int type) 188 { 189 redraw_win_later(curwin, type); 190 } 191 192 void 193 redraw_win_later( 194 win_T *wp, 195 int type) 196 { 197 if (!exiting && wp->w_redr_type < type) 198 { 199 wp->w_redr_type = type; 200 if (type >= NOT_VALID) 201 wp->w_lines_valid = 0; 202 if (must_redraw < type) /* must_redraw is the maximum of all windows */ 203 must_redraw = type; 204 } 205 } 206 207 /* 208 * Force a complete redraw later. Also resets the highlighting. To be used 209 * after executing a shell command that messes up the screen. 210 */ 211 void 212 redraw_later_clear(void) 213 { 214 redraw_all_later(CLEAR); 215 #ifdef FEAT_GUI 216 if (gui.in_use) 217 /* Use a code that will reset gui.highlight_mask in 218 * gui_stop_highlight(). */ 219 screen_attr = HL_ALL + 1; 220 else 221 #endif 222 /* Use attributes that is very unlikely to appear in text. */ 223 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH; 224 } 225 226 /* 227 * Mark all windows to be redrawn later. 228 */ 229 void 230 redraw_all_later(int type) 231 { 232 win_T *wp; 233 234 FOR_ALL_WINDOWS(wp) 235 redraw_win_later(wp, type); 236 // This may be needed when switching tabs. 237 if (must_redraw < type) 238 must_redraw = type; 239 } 240 241 /* 242 * Mark all windows that are editing the current buffer to be updated later. 243 */ 244 void 245 redraw_curbuf_later(int type) 246 { 247 redraw_buf_later(curbuf, type); 248 } 249 250 void 251 redraw_buf_later(buf_T *buf, int type) 252 { 253 win_T *wp; 254 255 FOR_ALL_WINDOWS(wp) 256 { 257 if (wp->w_buffer == buf) 258 redraw_win_later(wp, type); 259 } 260 } 261 262 #if defined(FEAT_SIGNS) || defined(PROTO) 263 void 264 redraw_buf_line_later(buf_T *buf, linenr_T lnum) 265 { 266 win_T *wp; 267 268 FOR_ALL_WINDOWS(wp) 269 if (wp->w_buffer == buf && lnum >= wp->w_topline 270 && lnum < wp->w_botline) 271 redrawWinline(wp, lnum); 272 } 273 #endif 274 275 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 276 void 277 redraw_buf_and_status_later(buf_T *buf, int type) 278 { 279 win_T *wp; 280 281 #ifdef FEAT_WILDMENU 282 if (wild_menu_showing != 0) 283 /* Don't redraw while the command line completion is displayed, it 284 * would disappear. */ 285 return; 286 #endif 287 FOR_ALL_WINDOWS(wp) 288 { 289 if (wp->w_buffer == buf) 290 { 291 redraw_win_later(wp, type); 292 wp->w_redr_status = TRUE; 293 } 294 } 295 } 296 #endif 297 298 #if defined(FEAT_TERMRESPONSE) || defined(PROTO) 299 /* 300 * Redraw as soon as possible. When the command line is not scrolled redraw 301 * right away and restore what was on the command line. 302 * Return a code indicating what happened. 303 */ 304 int 305 redraw_asap(int type) 306 { 307 int rows; 308 int cols = screen_Columns; 309 int r; 310 int ret = 0; 311 schar_T *screenline; /* copy from ScreenLines[] */ 312 sattr_T *screenattr; /* copy from ScreenAttrs[] */ 313 int i; 314 u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */ 315 u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */ 316 schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */ 317 318 redraw_later(type); 319 if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting) 320 return ret; 321 322 /* Allocate space to save the text displayed in the command line area. */ 323 rows = screen_Rows - cmdline_row; 324 screenline = (schar_T *)lalloc( 325 (long_u)(rows * cols * sizeof(schar_T)), FALSE); 326 screenattr = (sattr_T *)lalloc( 327 (long_u)(rows * cols * sizeof(sattr_T)), FALSE); 328 if (screenline == NULL || screenattr == NULL) 329 ret = 2; 330 if (enc_utf8) 331 { 332 screenlineUC = (u8char_T *)lalloc( 333 (long_u)(rows * cols * sizeof(u8char_T)), FALSE); 334 if (screenlineUC == NULL) 335 ret = 2; 336 for (i = 0; i < p_mco; ++i) 337 { 338 screenlineC[i] = (u8char_T *)lalloc( 339 (long_u)(rows * cols * sizeof(u8char_T)), FALSE); 340 if (screenlineC[i] == NULL) 341 ret = 2; 342 } 343 } 344 if (enc_dbcs == DBCS_JPNU) 345 { 346 screenline2 = (schar_T *)lalloc( 347 (long_u)(rows * cols * sizeof(schar_T)), FALSE); 348 if (screenline2 == NULL) 349 ret = 2; 350 } 351 352 if (ret != 2) 353 { 354 /* Save the text displayed in the command line area. */ 355 for (r = 0; r < rows; ++r) 356 { 357 mch_memmove(screenline + r * cols, 358 ScreenLines + LineOffset[cmdline_row + r], 359 (size_t)cols * sizeof(schar_T)); 360 mch_memmove(screenattr + r * cols, 361 ScreenAttrs + LineOffset[cmdline_row + r], 362 (size_t)cols * sizeof(sattr_T)); 363 if (enc_utf8) 364 { 365 mch_memmove(screenlineUC + r * cols, 366 ScreenLinesUC + LineOffset[cmdline_row + r], 367 (size_t)cols * sizeof(u8char_T)); 368 for (i = 0; i < p_mco; ++i) 369 mch_memmove(screenlineC[i] + r * cols, 370 ScreenLinesC[i] + LineOffset[cmdline_row + r], 371 (size_t)cols * sizeof(u8char_T)); 372 } 373 if (enc_dbcs == DBCS_JPNU) 374 mch_memmove(screenline2 + r * cols, 375 ScreenLines2 + LineOffset[cmdline_row + r], 376 (size_t)cols * sizeof(schar_T)); 377 } 378 379 update_screen(0); 380 ret = 3; 381 382 if (must_redraw == 0) 383 { 384 int off = (int)(current_ScreenLine - ScreenLines); 385 386 /* Restore the text displayed in the command line area. */ 387 for (r = 0; r < rows; ++r) 388 { 389 mch_memmove(current_ScreenLine, 390 screenline + r * cols, 391 (size_t)cols * sizeof(schar_T)); 392 mch_memmove(ScreenAttrs + off, 393 screenattr + r * cols, 394 (size_t)cols * sizeof(sattr_T)); 395 if (enc_utf8) 396 { 397 mch_memmove(ScreenLinesUC + off, 398 screenlineUC + r * cols, 399 (size_t)cols * sizeof(u8char_T)); 400 for (i = 0; i < p_mco; ++i) 401 mch_memmove(ScreenLinesC[i] + off, 402 screenlineC[i] + r * cols, 403 (size_t)cols * sizeof(u8char_T)); 404 } 405 if (enc_dbcs == DBCS_JPNU) 406 mch_memmove(ScreenLines2 + off, 407 screenline2 + r * cols, 408 (size_t)cols * sizeof(schar_T)); 409 screen_line(cmdline_row + r, 0, cols, cols, FALSE); 410 } 411 ret = 4; 412 } 413 } 414 415 vim_free(screenline); 416 vim_free(screenattr); 417 if (enc_utf8) 418 { 419 vim_free(screenlineUC); 420 for (i = 0; i < p_mco; ++i) 421 vim_free(screenlineC[i]); 422 } 423 if (enc_dbcs == DBCS_JPNU) 424 vim_free(screenline2); 425 426 /* Show the intro message when appropriate. */ 427 maybe_intro_message(); 428 429 setcursor(); 430 431 return ret; 432 } 433 #endif 434 435 /* 436 * Invoked after an asynchronous callback is called. 437 * If an echo command was used the cursor needs to be put back where 438 * it belongs. If highlighting was changed a redraw is needed. 439 * If "call_update_screen" is FALSE don't call update_screen() when at the 440 * command line. 441 */ 442 void 443 redraw_after_callback(int call_update_screen) 444 { 445 ++redrawing_for_callback; 446 447 if (State == HITRETURN || State == ASKMORE) 448 ; // do nothing 449 else if (State & CMDLINE) 450 { 451 // Don't redraw when in prompt_for_number(). 452 if (cmdline_row > 0) 453 { 454 // Redrawing only works when the screen didn't scroll. Don't clear 455 // wildmenu entries. 456 if (msg_scrolled == 0 457 #ifdef FEAT_WILDMENU 458 && wild_menu_showing == 0 459 #endif 460 && call_update_screen) 461 update_screen(0); 462 463 // Redraw in the same position, so that the user can continue 464 // editing the command. 465 redrawcmdline_ex(FALSE); 466 } 467 } 468 else if (State & (NORMAL | INSERT | TERMINAL)) 469 { 470 // keep the command line if possible 471 update_screen(VALID_NO_UPDATE); 472 setcursor(); 473 } 474 cursor_on(); 475 #ifdef FEAT_GUI 476 if (gui.in_use && !gui_mch_is_blink_off()) 477 // Don't update the cursor when it is blinking and off to avoid 478 // flicker. 479 out_flush_cursor(FALSE, FALSE); 480 else 481 #endif 482 out_flush(); 483 484 --redrawing_for_callback; 485 } 486 487 /* 488 * Changed something in the current window, at buffer line "lnum", that 489 * requires that line and possibly other lines to be redrawn. 490 * Used when entering/leaving Insert mode with the cursor on a folded line. 491 * Used to remove the "$" from a change command. 492 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot 493 * may become invalid and the whole window will have to be redrawn. 494 */ 495 void 496 redrawWinline( 497 win_T *wp, 498 linenr_T lnum) 499 { 500 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) 501 wp->w_redraw_top = lnum; 502 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) 503 wp->w_redraw_bot = lnum; 504 redraw_win_later(wp, VALID); 505 } 506 507 void 508 reset_updating_screen(int may_resize_shell UNUSED) 509 { 510 updating_screen = FALSE; 511 #ifdef FEAT_GUI 512 if (may_resize_shell) 513 gui_may_resize_shell(); 514 #endif 515 #ifdef FEAT_TERMINAL 516 term_check_channel_closed_recently(); 517 #endif 518 519 #ifdef HAVE_DROP_FILE 520 // If handle_drop() was called while updating_screen was TRUE need to 521 // handle the drop now. 522 handle_any_postponed_drop(); 523 #endif 524 } 525 526 /* 527 * Update all windows that are editing the current buffer. 528 */ 529 void 530 update_curbuf(int type) 531 { 532 redraw_curbuf_later(type); 533 update_screen(type); 534 } 535 536 /* 537 * Based on the current value of curwin->w_topline, transfer a screenfull 538 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline. 539 * Return OK when the screen was updated, FAIL if it was not done. 540 */ 541 int 542 update_screen(int type_arg) 543 { 544 int type = type_arg; 545 win_T *wp; 546 static int did_intro = FALSE; 547 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) 548 int did_one; 549 #endif 550 #ifdef FEAT_GUI 551 int did_undraw = FALSE; 552 int gui_cursor_col; 553 int gui_cursor_row; 554 #endif 555 int no_update = FALSE; 556 557 /* Don't do anything if the screen structures are (not yet) valid. */ 558 if (!screen_valid(TRUE)) 559 return FAIL; 560 561 if (type == VALID_NO_UPDATE) 562 { 563 no_update = TRUE; 564 type = 0; 565 } 566 567 if (must_redraw) 568 { 569 if (type < must_redraw) /* use maximal type */ 570 type = must_redraw; 571 572 /* must_redraw is reset here, so that when we run into some weird 573 * reason to redraw while busy redrawing (e.g., asynchronous 574 * scrolling), or update_topline() in win_update() will cause a 575 * scroll, the screen will be redrawn later or in win_update(). */ 576 must_redraw = 0; 577 } 578 579 /* May need to update w_lines[]. */ 580 if (curwin->w_lines_valid == 0 && type < NOT_VALID 581 #ifdef FEAT_TERMINAL 582 && !term_do_update_window(curwin) 583 #endif 584 ) 585 type = NOT_VALID; 586 587 /* Postpone the redrawing when it's not needed and when being called 588 * recursively. */ 589 if (!redrawing() || updating_screen) 590 { 591 redraw_later(type); /* remember type for next time */ 592 must_redraw = type; 593 if (type > INVERTED_ALL) 594 curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */ 595 return FAIL; 596 } 597 598 updating_screen = TRUE; 599 #ifdef FEAT_SYN_HL 600 ++display_tick; /* let syntax code know we're in a next round of 601 * display updating */ 602 #endif 603 if (no_update) 604 ++no_win_do_lines_ins; 605 606 /* 607 * if the screen was scrolled up when displaying a message, scroll it down 608 */ 609 if (msg_scrolled) 610 { 611 clear_cmdline = TRUE; 612 if (msg_scrolled > Rows - 5) /* clearing is faster */ 613 type = CLEAR; 614 else if (type != CLEAR) 615 { 616 check_for_delay(FALSE); 617 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL) 618 == FAIL) 619 type = CLEAR; 620 FOR_ALL_WINDOWS(wp) 621 { 622 if (W_WINROW(wp) < msg_scrolled) 623 { 624 if (W_WINROW(wp) + wp->w_height > msg_scrolled 625 && wp->w_redr_type < REDRAW_TOP 626 && wp->w_lines_valid > 0 627 && wp->w_topline == wp->w_lines[0].wl_lnum) 628 { 629 wp->w_upd_rows = msg_scrolled - W_WINROW(wp); 630 wp->w_redr_type = REDRAW_TOP; 631 } 632 else 633 { 634 wp->w_redr_type = NOT_VALID; 635 if (W_WINROW(wp) + wp->w_height + wp->w_status_height 636 <= msg_scrolled) 637 wp->w_redr_status = TRUE; 638 } 639 } 640 } 641 if (!no_update) 642 redraw_cmdline = TRUE; 643 redraw_tabline = TRUE; 644 } 645 msg_scrolled = 0; 646 need_wait_return = FALSE; 647 } 648 649 /* reset cmdline_row now (may have been changed temporarily) */ 650 compute_cmdrow(); 651 652 /* Check for changed highlighting */ 653 if (need_highlight_changed) 654 highlight_changed(); 655 656 if (type == CLEAR) /* first clear screen */ 657 { 658 screenclear(); /* will reset clear_cmdline */ 659 type = NOT_VALID; 660 /* must_redraw may be set indirectly, avoid another redraw later */ 661 must_redraw = 0; 662 } 663 664 if (clear_cmdline) /* going to clear cmdline (done below) */ 665 check_for_delay(FALSE); 666 667 #ifdef FEAT_LINEBREAK 668 /* Force redraw when width of 'number' or 'relativenumber' column 669 * changes. */ 670 if (curwin->w_redr_type < NOT_VALID 671 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu) 672 ? number_width(curwin) : 0)) 673 curwin->w_redr_type = NOT_VALID; 674 #endif 675 676 /* 677 * Only start redrawing if there is really something to do. 678 */ 679 if (type == INVERTED) 680 update_curswant(); 681 if (curwin->w_redr_type < type 682 && !((type == VALID 683 && curwin->w_lines[0].wl_valid 684 #ifdef FEAT_DIFF 685 && curwin->w_topfill == curwin->w_old_topfill 686 && curwin->w_botfill == curwin->w_old_botfill 687 #endif 688 && curwin->w_topline == curwin->w_lines[0].wl_lnum) 689 || (type == INVERTED 690 && VIsual_active 691 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum 692 && curwin->w_old_visual_mode == VIsual_mode 693 && (curwin->w_valid & VALID_VIRTCOL) 694 && curwin->w_old_curswant == curwin->w_curswant) 695 )) 696 curwin->w_redr_type = type; 697 698 /* Redraw the tab pages line if needed. */ 699 if (redraw_tabline || type >= NOT_VALID) 700 draw_tabline(); 701 702 #ifdef FEAT_SYN_HL 703 /* 704 * Correct stored syntax highlighting info for changes in each displayed 705 * buffer. Each buffer must only be done once. 706 */ 707 FOR_ALL_WINDOWS(wp) 708 { 709 if (wp->w_buffer->b_mod_set) 710 { 711 win_T *wwp; 712 713 /* Check if we already did this buffer. */ 714 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) 715 if (wwp->w_buffer == wp->w_buffer) 716 break; 717 if (wwp == wp && syntax_present(wp)) 718 syn_stack_apply_changes(wp->w_buffer); 719 } 720 } 721 #endif 722 723 /* 724 * Go from top to bottom through the windows, redrawing the ones that need 725 * it. 726 */ 727 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) 728 did_one = FALSE; 729 #endif 730 #ifdef FEAT_SEARCH_EXTRA 731 search_hl.rm.regprog = NULL; 732 #endif 733 FOR_ALL_WINDOWS(wp) 734 { 735 if (wp->w_redr_type != 0) 736 { 737 cursor_off(); 738 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) 739 if (!did_one) 740 { 741 did_one = TRUE; 742 # ifdef FEAT_SEARCH_EXTRA 743 start_search_hl(); 744 # endif 745 # ifdef FEAT_CLIPBOARD 746 /* When Visual area changed, may have to update selection. */ 747 if (clip_star.available && clip_isautosel_star()) 748 clip_update_selection(&clip_star); 749 if (clip_plus.available && clip_isautosel_plus()) 750 clip_update_selection(&clip_plus); 751 # endif 752 #ifdef FEAT_GUI 753 /* Remove the cursor before starting to do anything, because 754 * scrolling may make it difficult to redraw the text under 755 * it. */ 756 if (gui.in_use && wp == curwin) 757 { 758 gui_cursor_col = gui.cursor_col; 759 gui_cursor_row = gui.cursor_row; 760 gui_undraw_cursor(); 761 did_undraw = TRUE; 762 } 763 #endif 764 } 765 #endif 766 win_update(wp); 767 } 768 769 /* redraw status line after the window to minimize cursor movement */ 770 if (wp->w_redr_status) 771 { 772 cursor_off(); 773 win_redr_status(wp, TRUE); // any popup menu will be redrawn below 774 } 775 } 776 #if defined(FEAT_SEARCH_EXTRA) 777 end_search_hl(); 778 #endif 779 #ifdef FEAT_INS_EXPAND 780 /* May need to redraw the popup menu. */ 781 pum_may_redraw(); 782 #endif 783 784 /* Reset b_mod_set flags. Going through all windows is probably faster 785 * than going through all buffers (there could be many buffers). */ 786 FOR_ALL_WINDOWS(wp) 787 wp->w_buffer->b_mod_set = FALSE; 788 789 reset_updating_screen(TRUE); 790 791 /* Clear or redraw the command line. Done last, because scrolling may 792 * mess up the command line. */ 793 if (clear_cmdline || redraw_cmdline) 794 showmode(); 795 796 if (no_update) 797 --no_win_do_lines_ins; 798 799 /* May put up an introductory message when not editing a file */ 800 if (!did_intro) 801 maybe_intro_message(); 802 did_intro = TRUE; 803 804 #ifdef FEAT_GUI 805 /* Redraw the cursor and update the scrollbars when all screen updating is 806 * done. */ 807 if (gui.in_use) 808 { 809 if (did_undraw && !gui_mch_is_blink_off()) 810 { 811 mch_disable_flush(); 812 out_flush(); /* required before updating the cursor */ 813 mch_enable_flush(); 814 815 /* Put the GUI position where the cursor was, gui_update_cursor() 816 * uses that. */ 817 gui.col = gui_cursor_col; 818 gui.row = gui_cursor_row; 819 gui.col = mb_fix_col(gui.col, gui.row); 820 gui_update_cursor(FALSE, FALSE); 821 gui_may_flush(); 822 screen_cur_col = gui.col; 823 screen_cur_row = gui.row; 824 } 825 else 826 out_flush(); 827 gui_update_scrollbars(FALSE); 828 } 829 #endif 830 return OK; 831 } 832 833 #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI) 834 /* 835 * Prepare for updating one or more windows. 836 * Caller must check for "updating_screen" already set to avoid recursiveness. 837 */ 838 static void 839 update_prepare(void) 840 { 841 cursor_off(); 842 updating_screen = TRUE; 843 #ifdef FEAT_GUI 844 /* Remove the cursor before starting to do anything, because scrolling may 845 * make it difficult to redraw the text under it. */ 846 if (gui.in_use) 847 gui_undraw_cursor(); 848 #endif 849 #ifdef FEAT_SEARCH_EXTRA 850 start_search_hl(); 851 #endif 852 } 853 854 /* 855 * Finish updating one or more windows. 856 */ 857 static void 858 update_finish(void) 859 { 860 if (redraw_cmdline) 861 showmode(); 862 863 # ifdef FEAT_SEARCH_EXTRA 864 end_search_hl(); 865 # endif 866 867 reset_updating_screen(TRUE); 868 869 # ifdef FEAT_GUI 870 /* Redraw the cursor and update the scrollbars when all screen updating is 871 * done. */ 872 if (gui.in_use) 873 { 874 out_flush_cursor(FALSE, FALSE); 875 gui_update_scrollbars(FALSE); 876 } 877 # endif 878 } 879 #endif 880 881 #if defined(FEAT_CONCEAL) || defined(PROTO) 882 /* 883 * Return TRUE if the cursor line in window "wp" may be concealed, according 884 * to the 'concealcursor' option. 885 */ 886 int 887 conceal_cursor_line(win_T *wp) 888 { 889 int c; 890 891 if (*wp->w_p_cocu == NUL) 892 return FALSE; 893 if (get_real_state() & VISUAL) 894 c = 'v'; 895 else if (State & INSERT) 896 c = 'i'; 897 else if (State & NORMAL) 898 c = 'n'; 899 else if (State & CMDLINE) 900 c = 'c'; 901 else 902 return FALSE; 903 return vim_strchr(wp->w_p_cocu, c) != NULL; 904 } 905 906 /* 907 * Check if the cursor line needs to be redrawn because of 'concealcursor'. 908 */ 909 void 910 conceal_check_cursor_line(void) 911 { 912 if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin)) 913 { 914 need_cursor_line_redraw = TRUE; 915 /* Need to recompute cursor column, e.g., when starting Visual mode 916 * without concealing. */ 917 curs_columns(TRUE); 918 } 919 } 920 #endif 921 922 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO) 923 void 924 update_debug_sign(buf_T *buf, linenr_T lnum) 925 { 926 win_T *wp; 927 int doit = FALSE; 928 929 # ifdef FEAT_FOLDING 930 win_foldinfo.fi_level = 0; 931 # endif 932 933 // update/delete a specific sign 934 redraw_buf_line_later(buf, lnum); 935 936 // check if it resulted in the need to redraw a window 937 FOR_ALL_WINDOWS(wp) 938 if (wp->w_redr_type != 0) 939 doit = TRUE; 940 941 /* Return when there is nothing to do, screen updating is already 942 * happening (recursive call), messages on the screen or still starting up. 943 */ 944 if (!doit || updating_screen 945 || State == ASKMORE || State == HITRETURN 946 || msg_scrolled 947 #ifdef FEAT_GUI 948 || gui.starting 949 #endif 950 || starting) 951 return; 952 953 /* update all windows that need updating */ 954 update_prepare(); 955 956 FOR_ALL_WINDOWS(wp) 957 { 958 if (wp->w_redr_type != 0) 959 win_update(wp); 960 if (wp->w_redr_status) 961 win_redr_status(wp, FALSE); 962 } 963 964 update_finish(); 965 } 966 #endif 967 968 969 #if defined(FEAT_GUI) || defined(PROTO) 970 /* 971 * Update a single window, its status line and maybe the command line msg. 972 * Used for the GUI scrollbar. 973 */ 974 void 975 updateWindow(win_T *wp) 976 { 977 /* return if already busy updating */ 978 if (updating_screen) 979 return; 980 981 update_prepare(); 982 983 #ifdef FEAT_CLIPBOARD 984 /* When Visual area changed, may have to update selection. */ 985 if (clip_star.available && clip_isautosel_star()) 986 clip_update_selection(&clip_star); 987 if (clip_plus.available && clip_isautosel_plus()) 988 clip_update_selection(&clip_plus); 989 #endif 990 991 win_update(wp); 992 993 /* When the screen was cleared redraw the tab pages line. */ 994 if (redraw_tabline) 995 draw_tabline(); 996 997 if (wp->w_redr_status 998 # ifdef FEAT_CMDL_INFO 999 || p_ru 1000 # endif 1001 # ifdef FEAT_STL_OPT 1002 || *p_stl != NUL || *wp->w_p_stl != NUL 1003 # endif 1004 ) 1005 win_redr_status(wp, FALSE); 1006 1007 update_finish(); 1008 } 1009 #endif 1010 1011 /* 1012 * Update a single window. 1013 * 1014 * This may cause the windows below it also to be redrawn (when clearing the 1015 * screen or scrolling lines). 1016 * 1017 * How the window is redrawn depends on wp->w_redr_type. Each type also 1018 * implies the one below it. 1019 * NOT_VALID redraw the whole window 1020 * SOME_VALID redraw the whole window but do scroll when possible 1021 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID 1022 * INVERTED redraw the changed part of the Visual area 1023 * INVERTED_ALL redraw the whole Visual area 1024 * VALID 1. scroll up/down to adjust for a changed w_topline 1025 * 2. update lines at the top when scrolled down 1026 * 3. redraw changed text: 1027 * - if wp->w_buffer->b_mod_set set, update lines between 1028 * b_mod_top and b_mod_bot. 1029 * - if wp->w_redraw_top non-zero, redraw lines between 1030 * wp->w_redraw_top and wp->w_redr_bot. 1031 * - continue redrawing when syntax status is invalid. 1032 * 4. if scrolled up, update lines at the bottom. 1033 * This results in three areas that may need updating: 1034 * top: from first row to top_end (when scrolled down) 1035 * mid: from mid_start to mid_end (update inversion or changed text) 1036 * bot: from bot_start to last row (when scrolled up) 1037 */ 1038 static void 1039 win_update(win_T *wp) 1040 { 1041 buf_T *buf = wp->w_buffer; 1042 int type; 1043 int top_end = 0; /* Below last row of the top area that needs 1044 updating. 0 when no top area updating. */ 1045 int mid_start = 999;/* first row of the mid area that needs 1046 updating. 999 when no mid area updating. */ 1047 int mid_end = 0; /* Below last row of the mid area that needs 1048 updating. 0 when no mid area updating. */ 1049 int bot_start = 999;/* first row of the bot area that needs 1050 updating. 999 when no bot area updating */ 1051 int scrolled_down = FALSE; /* TRUE when scrolled down when 1052 w_topline got smaller a bit */ 1053 #ifdef FEAT_SEARCH_EXTRA 1054 matchitem_T *cur; /* points to the match list */ 1055 int top_to_mod = FALSE; /* redraw above mod_top */ 1056 #endif 1057 1058 int row; /* current window row to display */ 1059 linenr_T lnum; /* current buffer lnum to display */ 1060 int idx; /* current index in w_lines[] */ 1061 int srow; /* starting row of the current line */ 1062 1063 int eof = FALSE; /* if TRUE, we hit the end of the file */ 1064 int didline = FALSE; /* if TRUE, we finished the last line */ 1065 int i; 1066 long j; 1067 static int recursive = FALSE; /* being called recursively */ 1068 int old_botline = wp->w_botline; 1069 #ifdef FEAT_FOLDING 1070 long fold_count; 1071 #endif 1072 #ifdef FEAT_SYN_HL 1073 /* remember what happened to the previous line, to know if 1074 * check_visual_highlight() can be used */ 1075 #define DID_NONE 1 /* didn't update a line */ 1076 #define DID_LINE 2 /* updated a normal line */ 1077 #define DID_FOLD 3 /* updated a folded line */ 1078 int did_update = DID_NONE; 1079 linenr_T syntax_last_parsed = 0; /* last parsed text line */ 1080 #endif 1081 linenr_T mod_top = 0; 1082 linenr_T mod_bot = 0; 1083 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) 1084 int save_got_int; 1085 #endif 1086 #ifdef SYN_TIME_LIMIT 1087 proftime_T syntax_tm; 1088 #endif 1089 1090 type = wp->w_redr_type; 1091 1092 if (type == NOT_VALID) 1093 { 1094 wp->w_redr_status = TRUE; 1095 wp->w_lines_valid = 0; 1096 } 1097 1098 /* Window is zero-height: nothing to draw. */ 1099 if (wp->w_height + WINBAR_HEIGHT(wp) == 0) 1100 { 1101 wp->w_redr_type = 0; 1102 return; 1103 } 1104 1105 /* Window is zero-width: Only need to draw the separator. */ 1106 if (wp->w_width == 0) 1107 { 1108 /* draw the vertical separator right of this window */ 1109 draw_vsep_win(wp, 0); 1110 wp->w_redr_type = 0; 1111 return; 1112 } 1113 1114 #ifdef FEAT_TERMINAL 1115 // If this window contains a terminal, redraw works completely differently. 1116 if (term_do_update_window(wp)) 1117 { 1118 term_update_window(wp); 1119 # ifdef FEAT_MENU 1120 /* Draw the window toolbar, if there is one. */ 1121 if (winbar_height(wp) > 0) 1122 redraw_win_toolbar(wp); 1123 # endif 1124 wp->w_redr_type = 0; 1125 return; 1126 } 1127 #endif 1128 1129 #ifdef FEAT_SEARCH_EXTRA 1130 init_search_hl(wp); 1131 #endif 1132 1133 #ifdef FEAT_LINEBREAK 1134 /* Force redraw when width of 'number' or 'relativenumber' column 1135 * changes. */ 1136 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0; 1137 if (wp->w_nrwidth != i) 1138 { 1139 type = NOT_VALID; 1140 wp->w_nrwidth = i; 1141 } 1142 else 1143 #endif 1144 1145 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0) 1146 { 1147 /* 1148 * When there are both inserted/deleted lines and specific lines to be 1149 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw 1150 * everything (only happens when redrawing is off for while). 1151 */ 1152 type = NOT_VALID; 1153 } 1154 else 1155 { 1156 /* 1157 * Set mod_top to the first line that needs displaying because of 1158 * changes. Set mod_bot to the first line after the changes. 1159 */ 1160 mod_top = wp->w_redraw_top; 1161 if (wp->w_redraw_bot != 0) 1162 mod_bot = wp->w_redraw_bot + 1; 1163 else 1164 mod_bot = 0; 1165 if (buf->b_mod_set) 1166 { 1167 if (mod_top == 0 || mod_top > buf->b_mod_top) 1168 { 1169 mod_top = buf->b_mod_top; 1170 #ifdef FEAT_SYN_HL 1171 /* Need to redraw lines above the change that may be included 1172 * in a pattern match. */ 1173 if (syntax_present(wp)) 1174 { 1175 mod_top -= buf->b_s.b_syn_sync_linebreaks; 1176 if (mod_top < 1) 1177 mod_top = 1; 1178 } 1179 #endif 1180 } 1181 if (mod_bot == 0 || mod_bot < buf->b_mod_bot) 1182 mod_bot = buf->b_mod_bot; 1183 1184 #ifdef FEAT_SEARCH_EXTRA 1185 /* When 'hlsearch' is on and using a multi-line search pattern, a 1186 * change in one line may make the Search highlighting in a 1187 * previous line invalid. Simple solution: redraw all visible 1188 * lines above the change. 1189 * Same for a match pattern. 1190 */ 1191 if (search_hl.rm.regprog != NULL 1192 && re_multiline(search_hl.rm.regprog)) 1193 top_to_mod = TRUE; 1194 else 1195 { 1196 cur = wp->w_match_head; 1197 while (cur != NULL) 1198 { 1199 if (cur->match.regprog != NULL 1200 && re_multiline(cur->match.regprog)) 1201 { 1202 top_to_mod = TRUE; 1203 break; 1204 } 1205 cur = cur->next; 1206 } 1207 } 1208 #endif 1209 } 1210 #ifdef FEAT_FOLDING 1211 if (mod_top != 0 && hasAnyFolding(wp)) 1212 { 1213 linenr_T lnumt, lnumb; 1214 1215 /* 1216 * A change in a line can cause lines above it to become folded or 1217 * unfolded. Find the top most buffer line that may be affected. 1218 * If the line was previously folded and displayed, get the first 1219 * line of that fold. If the line is folded now, get the first 1220 * folded line. Use the minimum of these two. 1221 */ 1222 1223 /* Find last valid w_lines[] entry above mod_top. Set lnumt to 1224 * the line below it. If there is no valid entry, use w_topline. 1225 * Find the first valid w_lines[] entry below mod_bot. Set lnumb 1226 * to this line. If there is no valid entry, use MAXLNUM. */ 1227 lnumt = wp->w_topline; 1228 lnumb = MAXLNUM; 1229 for (i = 0; i < wp->w_lines_valid; ++i) 1230 if (wp->w_lines[i].wl_valid) 1231 { 1232 if (wp->w_lines[i].wl_lastlnum < mod_top) 1233 lnumt = wp->w_lines[i].wl_lastlnum + 1; 1234 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot) 1235 { 1236 lnumb = wp->w_lines[i].wl_lnum; 1237 /* When there is a fold column it might need updating 1238 * in the next line ("J" just above an open fold). */ 1239 if (compute_foldcolumn(wp, 0) > 0) 1240 ++lnumb; 1241 } 1242 } 1243 1244 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL); 1245 if (mod_top > lnumt) 1246 mod_top = lnumt; 1247 1248 /* Now do the same for the bottom line (one above mod_bot). */ 1249 --mod_bot; 1250 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL); 1251 ++mod_bot; 1252 if (mod_bot < lnumb) 1253 mod_bot = lnumb; 1254 } 1255 #endif 1256 1257 /* When a change starts above w_topline and the end is below 1258 * w_topline, start redrawing at w_topline. 1259 * If the end of the change is above w_topline: do like no change was 1260 * made, but redraw the first line to find changes in syntax. */ 1261 if (mod_top != 0 && mod_top < wp->w_topline) 1262 { 1263 if (mod_bot > wp->w_topline) 1264 mod_top = wp->w_topline; 1265 #ifdef FEAT_SYN_HL 1266 else if (syntax_present(wp)) 1267 top_end = 1; 1268 #endif 1269 } 1270 1271 /* When line numbers are displayed need to redraw all lines below 1272 * inserted/deleted lines. */ 1273 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu) 1274 mod_bot = MAXLNUM; 1275 } 1276 wp->w_redraw_top = 0; // reset for next time 1277 wp->w_redraw_bot = 0; 1278 1279 /* 1280 * When only displaying the lines at the top, set top_end. Used when 1281 * window has scrolled down for msg_scrolled. 1282 */ 1283 if (type == REDRAW_TOP) 1284 { 1285 j = 0; 1286 for (i = 0; i < wp->w_lines_valid; ++i) 1287 { 1288 j += wp->w_lines[i].wl_size; 1289 if (j >= wp->w_upd_rows) 1290 { 1291 top_end = j; 1292 break; 1293 } 1294 } 1295 if (top_end == 0) 1296 /* not found (cannot happen?): redraw everything */ 1297 type = NOT_VALID; 1298 else 1299 /* top area defined, the rest is VALID */ 1300 type = VALID; 1301 } 1302 1303 /* Trick: we want to avoid clearing the screen twice. screenclear() will 1304 * set "screen_cleared" to TRUE. The special value MAYBE (which is still 1305 * non-zero and thus not FALSE) will indicate that screenclear() was not 1306 * called. */ 1307 if (screen_cleared) 1308 screen_cleared = MAYBE; 1309 1310 /* 1311 * If there are no changes on the screen that require a complete redraw, 1312 * handle three cases: 1313 * 1: we are off the top of the screen by a few lines: scroll down 1314 * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up 1315 * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in 1316 * w_lines[] that needs updating. 1317 */ 1318 if ((type == VALID || type == SOME_VALID 1319 || type == INVERTED || type == INVERTED_ALL) 1320 #ifdef FEAT_DIFF 1321 && !wp->w_botfill && !wp->w_old_botfill 1322 #endif 1323 ) 1324 { 1325 if (mod_top != 0 && wp->w_topline == mod_top) 1326 { 1327 /* 1328 * w_topline is the first changed line, the scrolling will be done 1329 * further down. 1330 */ 1331 } 1332 else if (wp->w_lines[0].wl_valid 1333 && (wp->w_topline < wp->w_lines[0].wl_lnum 1334 #ifdef FEAT_DIFF 1335 || (wp->w_topline == wp->w_lines[0].wl_lnum 1336 && wp->w_topfill > wp->w_old_topfill) 1337 #endif 1338 )) 1339 { 1340 /* 1341 * New topline is above old topline: May scroll down. 1342 */ 1343 #ifdef FEAT_FOLDING 1344 if (hasAnyFolding(wp)) 1345 { 1346 linenr_T ln; 1347 1348 /* count the number of lines we are off, counting a sequence 1349 * of folded lines as one */ 1350 j = 0; 1351 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln) 1352 { 1353 ++j; 1354 if (j >= wp->w_height - 2) 1355 break; 1356 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL); 1357 } 1358 } 1359 else 1360 #endif 1361 j = wp->w_lines[0].wl_lnum - wp->w_topline; 1362 if (j < wp->w_height - 2) /* not too far off */ 1363 { 1364 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); 1365 #ifdef FEAT_DIFF 1366 /* insert extra lines for previously invisible filler lines */ 1367 if (wp->w_lines[0].wl_lnum != wp->w_topline) 1368 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum) 1369 - wp->w_old_topfill; 1370 #endif 1371 if (i < wp->w_height - 2) /* less than a screen off */ 1372 { 1373 /* 1374 * Try to insert the correct number of lines. 1375 * If not the last window, delete the lines at the bottom. 1376 * win_ins_lines may fail when the terminal can't do it. 1377 */ 1378 if (i > 0) 1379 check_for_delay(FALSE); 1380 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK) 1381 { 1382 if (wp->w_lines_valid != 0) 1383 { 1384 /* Need to update rows that are new, stop at the 1385 * first one that scrolled down. */ 1386 top_end = i; 1387 scrolled_down = TRUE; 1388 1389 /* Move the entries that were scrolled, disable 1390 * the entries for the lines to be redrawn. */ 1391 if ((wp->w_lines_valid += j) > wp->w_height) 1392 wp->w_lines_valid = wp->w_height; 1393 for (idx = wp->w_lines_valid; idx - j >= 0; idx--) 1394 wp->w_lines[idx] = wp->w_lines[idx - j]; 1395 while (idx >= 0) 1396 wp->w_lines[idx--].wl_valid = FALSE; 1397 } 1398 } 1399 else 1400 mid_start = 0; /* redraw all lines */ 1401 } 1402 else 1403 mid_start = 0; /* redraw all lines */ 1404 } 1405 else 1406 mid_start = 0; /* redraw all lines */ 1407 } 1408 else 1409 { 1410 /* 1411 * New topline is at or below old topline: May scroll up. 1412 * When topline didn't change, find first entry in w_lines[] that 1413 * needs updating. 1414 */ 1415 1416 /* try to find wp->w_topline in wp->w_lines[].wl_lnum */ 1417 j = -1; 1418 row = 0; 1419 for (i = 0; i < wp->w_lines_valid; i++) 1420 { 1421 if (wp->w_lines[i].wl_valid 1422 && wp->w_lines[i].wl_lnum == wp->w_topline) 1423 { 1424 j = i; 1425 break; 1426 } 1427 row += wp->w_lines[i].wl_size; 1428 } 1429 if (j == -1) 1430 { 1431 /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all 1432 * lines */ 1433 mid_start = 0; 1434 } 1435 else 1436 { 1437 /* 1438 * Try to delete the correct number of lines. 1439 * wp->w_topline is at wp->w_lines[i].wl_lnum. 1440 */ 1441 #ifdef FEAT_DIFF 1442 /* If the topline didn't change, delete old filler lines, 1443 * otherwise delete filler lines of the new topline... */ 1444 if (wp->w_lines[0].wl_lnum == wp->w_topline) 1445 row += wp->w_old_topfill; 1446 else 1447 row += diff_check_fill(wp, wp->w_topline); 1448 /* ... but don't delete new filler lines. */ 1449 row -= wp->w_topfill; 1450 #endif 1451 if (row > 0) 1452 { 1453 check_for_delay(FALSE); 1454 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0) 1455 == OK) 1456 bot_start = wp->w_height - row; 1457 else 1458 mid_start = 0; /* redraw all lines */ 1459 } 1460 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) 1461 { 1462 /* 1463 * Skip the lines (below the deleted lines) that are still 1464 * valid and don't need redrawing. Copy their info 1465 * upwards, to compensate for the deleted lines. Set 1466 * bot_start to the first row that needs redrawing. 1467 */ 1468 bot_start = 0; 1469 idx = 0; 1470 for (;;) 1471 { 1472 wp->w_lines[idx] = wp->w_lines[j]; 1473 /* stop at line that didn't fit, unless it is still 1474 * valid (no lines deleted) */ 1475 if (row > 0 && bot_start + row 1476 + (int)wp->w_lines[j].wl_size > wp->w_height) 1477 { 1478 wp->w_lines_valid = idx + 1; 1479 break; 1480 } 1481 bot_start += wp->w_lines[idx++].wl_size; 1482 1483 /* stop at the last valid entry in w_lines[].wl_size */ 1484 if (++j >= wp->w_lines_valid) 1485 { 1486 wp->w_lines_valid = idx; 1487 break; 1488 } 1489 } 1490 #ifdef FEAT_DIFF 1491 /* Correct the first entry for filler lines at the top 1492 * when it won't get updated below. */ 1493 if (wp->w_p_diff && bot_start > 0) 1494 wp->w_lines[0].wl_size = 1495 plines_win_nofill(wp, wp->w_topline, TRUE) 1496 + wp->w_topfill; 1497 #endif 1498 } 1499 } 1500 } 1501 1502 /* When starting redraw in the first line, redraw all lines. When 1503 * there is only one window it's probably faster to clear the screen 1504 * first. */ 1505 if (mid_start == 0) 1506 { 1507 mid_end = wp->w_height; 1508 if (ONE_WINDOW) 1509 { 1510 /* Clear the screen when it was not done by win_del_lines() or 1511 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE 1512 * then. */ 1513 if (screen_cleared != TRUE) 1514 screenclear(); 1515 /* The screen was cleared, redraw the tab pages line. */ 1516 if (redraw_tabline) 1517 draw_tabline(); 1518 } 1519 } 1520 1521 /* When win_del_lines() or win_ins_lines() caused the screen to be 1522 * cleared (only happens for the first window) or when screenclear() 1523 * was called directly above, "must_redraw" will have been set to 1524 * NOT_VALID, need to reset it here to avoid redrawing twice. */ 1525 if (screen_cleared == TRUE) 1526 must_redraw = 0; 1527 } 1528 else 1529 { 1530 /* Not VALID or INVERTED: redraw all lines. */ 1531 mid_start = 0; 1532 mid_end = wp->w_height; 1533 } 1534 1535 if (type == SOME_VALID) 1536 { 1537 /* SOME_VALID: redraw all lines. */ 1538 mid_start = 0; 1539 mid_end = wp->w_height; 1540 type = NOT_VALID; 1541 } 1542 1543 /* check if we are updating or removing the inverted part */ 1544 if ((VIsual_active && buf == curwin->w_buffer) 1545 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID)) 1546 { 1547 linenr_T from, to; 1548 1549 if (VIsual_active) 1550 { 1551 if (VIsual_active 1552 && (VIsual_mode != wp->w_old_visual_mode 1553 || type == INVERTED_ALL)) 1554 { 1555 /* 1556 * If the type of Visual selection changed, redraw the whole 1557 * selection. Also when the ownership of the X selection is 1558 * gained or lost. 1559 */ 1560 if (curwin->w_cursor.lnum < VIsual.lnum) 1561 { 1562 from = curwin->w_cursor.lnum; 1563 to = VIsual.lnum; 1564 } 1565 else 1566 { 1567 from = VIsual.lnum; 1568 to = curwin->w_cursor.lnum; 1569 } 1570 /* redraw more when the cursor moved as well */ 1571 if (wp->w_old_cursor_lnum < from) 1572 from = wp->w_old_cursor_lnum; 1573 if (wp->w_old_cursor_lnum > to) 1574 to = wp->w_old_cursor_lnum; 1575 if (wp->w_old_visual_lnum < from) 1576 from = wp->w_old_visual_lnum; 1577 if (wp->w_old_visual_lnum > to) 1578 to = wp->w_old_visual_lnum; 1579 } 1580 else 1581 { 1582 /* 1583 * Find the line numbers that need to be updated: The lines 1584 * between the old cursor position and the current cursor 1585 * position. Also check if the Visual position changed. 1586 */ 1587 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum) 1588 { 1589 from = curwin->w_cursor.lnum; 1590 to = wp->w_old_cursor_lnum; 1591 } 1592 else 1593 { 1594 from = wp->w_old_cursor_lnum; 1595 to = curwin->w_cursor.lnum; 1596 if (from == 0) /* Visual mode just started */ 1597 from = to; 1598 } 1599 1600 if (VIsual.lnum != wp->w_old_visual_lnum 1601 || VIsual.col != wp->w_old_visual_col) 1602 { 1603 if (wp->w_old_visual_lnum < from 1604 && wp->w_old_visual_lnum != 0) 1605 from = wp->w_old_visual_lnum; 1606 if (wp->w_old_visual_lnum > to) 1607 to = wp->w_old_visual_lnum; 1608 if (VIsual.lnum < from) 1609 from = VIsual.lnum; 1610 if (VIsual.lnum > to) 1611 to = VIsual.lnum; 1612 } 1613 } 1614 1615 /* 1616 * If in block mode and changed column or curwin->w_curswant: 1617 * update all lines. 1618 * First compute the actual start and end column. 1619 */ 1620 if (VIsual_mode == Ctrl_V) 1621 { 1622 colnr_T fromc, toc; 1623 #if defined(FEAT_LINEBREAK) 1624 int save_ve_flags = ve_flags; 1625 1626 if (curwin->w_p_lbr) 1627 ve_flags = VE_ALL; 1628 #endif 1629 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc); 1630 #if defined(FEAT_LINEBREAK) 1631 ve_flags = save_ve_flags; 1632 #endif 1633 ++toc; 1634 if (curwin->w_curswant == MAXCOL) 1635 toc = MAXCOL; 1636 1637 if (fromc != wp->w_old_cursor_fcol 1638 || toc != wp->w_old_cursor_lcol) 1639 { 1640 if (from > VIsual.lnum) 1641 from = VIsual.lnum; 1642 if (to < VIsual.lnum) 1643 to = VIsual.lnum; 1644 } 1645 wp->w_old_cursor_fcol = fromc; 1646 wp->w_old_cursor_lcol = toc; 1647 } 1648 } 1649 else 1650 { 1651 /* Use the line numbers of the old Visual area. */ 1652 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum) 1653 { 1654 from = wp->w_old_cursor_lnum; 1655 to = wp->w_old_visual_lnum; 1656 } 1657 else 1658 { 1659 from = wp->w_old_visual_lnum; 1660 to = wp->w_old_cursor_lnum; 1661 } 1662 } 1663 1664 /* 1665 * There is no need to update lines above the top of the window. 1666 */ 1667 if (from < wp->w_topline) 1668 from = wp->w_topline; 1669 1670 /* 1671 * If we know the value of w_botline, use it to restrict the update to 1672 * the lines that are visible in the window. 1673 */ 1674 if (wp->w_valid & VALID_BOTLINE) 1675 { 1676 if (from >= wp->w_botline) 1677 from = wp->w_botline - 1; 1678 if (to >= wp->w_botline) 1679 to = wp->w_botline - 1; 1680 } 1681 1682 /* 1683 * Find the minimal part to be updated. 1684 * Watch out for scrolling that made entries in w_lines[] invalid. 1685 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets 1686 * top_end; need to redraw from top_end to the "to" line. 1687 * A middle mouse click with a Visual selection may change the text 1688 * above the Visual area and reset wl_valid, do count these for 1689 * mid_end (in srow). 1690 */ 1691 if (mid_start > 0) 1692 { 1693 lnum = wp->w_topline; 1694 idx = 0; 1695 srow = 0; 1696 if (scrolled_down) 1697 mid_start = top_end; 1698 else 1699 mid_start = 0; 1700 while (lnum < from && idx < wp->w_lines_valid) /* find start */ 1701 { 1702 if (wp->w_lines[idx].wl_valid) 1703 mid_start += wp->w_lines[idx].wl_size; 1704 else if (!scrolled_down) 1705 srow += wp->w_lines[idx].wl_size; 1706 ++idx; 1707 # ifdef FEAT_FOLDING 1708 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid) 1709 lnum = wp->w_lines[idx].wl_lnum; 1710 else 1711 # endif 1712 ++lnum; 1713 } 1714 srow += mid_start; 1715 mid_end = wp->w_height; 1716 for ( ; idx < wp->w_lines_valid; ++idx) /* find end */ 1717 { 1718 if (wp->w_lines[idx].wl_valid 1719 && wp->w_lines[idx].wl_lnum >= to + 1) 1720 { 1721 /* Only update until first row of this line */ 1722 mid_end = srow; 1723 break; 1724 } 1725 srow += wp->w_lines[idx].wl_size; 1726 } 1727 } 1728 } 1729 1730 if (VIsual_active && buf == curwin->w_buffer) 1731 { 1732 wp->w_old_visual_mode = VIsual_mode; 1733 wp->w_old_cursor_lnum = curwin->w_cursor.lnum; 1734 wp->w_old_visual_lnum = VIsual.lnum; 1735 wp->w_old_visual_col = VIsual.col; 1736 wp->w_old_curswant = curwin->w_curswant; 1737 } 1738 else 1739 { 1740 wp->w_old_visual_mode = 0; 1741 wp->w_old_cursor_lnum = 0; 1742 wp->w_old_visual_lnum = 0; 1743 wp->w_old_visual_col = 0; 1744 } 1745 1746 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) 1747 /* reset got_int, otherwise regexp won't work */ 1748 save_got_int = got_int; 1749 got_int = 0; 1750 #endif 1751 #ifdef SYN_TIME_LIMIT 1752 /* Set the time limit to 'redrawtime'. */ 1753 profile_setlimit(p_rdt, &syntax_tm); 1754 syn_set_timeout(&syntax_tm); 1755 #endif 1756 #ifdef FEAT_FOLDING 1757 win_foldinfo.fi_level = 0; 1758 #endif 1759 1760 #ifdef FEAT_MENU 1761 /* 1762 * Draw the window toolbar, if there is one. 1763 * TODO: only when needed. 1764 */ 1765 if (winbar_height(wp) > 0) 1766 redraw_win_toolbar(wp); 1767 #endif 1768 1769 /* 1770 * Update all the window rows. 1771 */ 1772 idx = 0; /* first entry in w_lines[].wl_size */ 1773 row = 0; 1774 srow = 0; 1775 lnum = wp->w_topline; /* first line shown in window */ 1776 for (;;) 1777 { 1778 /* stop updating when reached the end of the window (check for _past_ 1779 * the end of the window is at the end of the loop) */ 1780 if (row == wp->w_height) 1781 { 1782 didline = TRUE; 1783 break; 1784 } 1785 1786 /* stop updating when hit the end of the file */ 1787 if (lnum > buf->b_ml.ml_line_count) 1788 { 1789 eof = TRUE; 1790 break; 1791 } 1792 1793 /* Remember the starting row of the line that is going to be dealt 1794 * with. It is used further down when the line doesn't fit. */ 1795 srow = row; 1796 1797 /* 1798 * Update a line when it is in an area that needs updating, when it 1799 * has changes or w_lines[idx] is invalid. 1800 * "bot_start" may be halfway a wrapped line after using 1801 * win_del_lines(), check if the current line includes it. 1802 * When syntax folding is being used, the saved syntax states will 1803 * already have been updated, we can't see where the syntax state is 1804 * the same again, just update until the end of the window. 1805 */ 1806 if (row < top_end 1807 || (row >= mid_start && row < mid_end) 1808 #ifdef FEAT_SEARCH_EXTRA 1809 || top_to_mod 1810 #endif 1811 || idx >= wp->w_lines_valid 1812 || (row + wp->w_lines[idx].wl_size > bot_start) 1813 || (mod_top != 0 1814 && (lnum == mod_top 1815 || (lnum >= mod_top 1816 && (lnum < mod_bot 1817 #ifdef FEAT_SYN_HL 1818 || did_update == DID_FOLD 1819 || (did_update == DID_LINE 1820 && syntax_present(wp) 1821 && ( 1822 # ifdef FEAT_FOLDING 1823 (foldmethodIsSyntax(wp) 1824 && hasAnyFolding(wp)) || 1825 # endif 1826 syntax_check_changed(lnum))) 1827 #endif 1828 #ifdef FEAT_SEARCH_EXTRA 1829 /* match in fixed position might need redraw 1830 * if lines were inserted or deleted */ 1831 || (wp->w_match_head != NULL 1832 && buf->b_mod_xlines != 0) 1833 #endif 1834 ))))) 1835 { 1836 #ifdef FEAT_SEARCH_EXTRA 1837 if (lnum == mod_top) 1838 top_to_mod = FALSE; 1839 #endif 1840 1841 /* 1842 * When at start of changed lines: May scroll following lines 1843 * up or down to minimize redrawing. 1844 * Don't do this when the change continues until the end. 1845 * Don't scroll when dollar_vcol >= 0, keep the "$". 1846 */ 1847 if (lnum == mod_top 1848 && mod_bot != MAXLNUM 1849 && !(dollar_vcol >= 0 && mod_bot == mod_top + 1)) 1850 { 1851 int old_rows = 0; 1852 int new_rows = 0; 1853 int xtra_rows; 1854 linenr_T l; 1855 1856 /* Count the old number of window rows, using w_lines[], which 1857 * should still contain the sizes for the lines as they are 1858 * currently displayed. */ 1859 for (i = idx; i < wp->w_lines_valid; ++i) 1860 { 1861 /* Only valid lines have a meaningful wl_lnum. Invalid 1862 * lines are part of the changed area. */ 1863 if (wp->w_lines[i].wl_valid 1864 && wp->w_lines[i].wl_lnum == mod_bot) 1865 break; 1866 old_rows += wp->w_lines[i].wl_size; 1867 #ifdef FEAT_FOLDING 1868 if (wp->w_lines[i].wl_valid 1869 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) 1870 { 1871 /* Must have found the last valid entry above mod_bot. 1872 * Add following invalid entries. */ 1873 ++i; 1874 while (i < wp->w_lines_valid 1875 && !wp->w_lines[i].wl_valid) 1876 old_rows += wp->w_lines[i++].wl_size; 1877 break; 1878 } 1879 #endif 1880 } 1881 1882 if (i >= wp->w_lines_valid) 1883 { 1884 /* We can't find a valid line below the changed lines, 1885 * need to redraw until the end of the window. 1886 * Inserting/deleting lines has no use. */ 1887 bot_start = 0; 1888 } 1889 else 1890 { 1891 /* Able to count old number of rows: Count new window 1892 * rows, and may insert/delete lines */ 1893 j = idx; 1894 for (l = lnum; l < mod_bot; ++l) 1895 { 1896 #ifdef FEAT_FOLDING 1897 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL)) 1898 ++new_rows; 1899 else 1900 #endif 1901 #ifdef FEAT_DIFF 1902 if (l == wp->w_topline) 1903 new_rows += plines_win_nofill(wp, l, TRUE) 1904 + wp->w_topfill; 1905 else 1906 #endif 1907 new_rows += plines_win(wp, l, TRUE); 1908 ++j; 1909 if (new_rows > wp->w_height - row - 2) 1910 { 1911 /* it's getting too much, must redraw the rest */ 1912 new_rows = 9999; 1913 break; 1914 } 1915 } 1916 xtra_rows = new_rows - old_rows; 1917 if (xtra_rows < 0) 1918 { 1919 /* May scroll text up. If there is not enough 1920 * remaining text or scrolling fails, must redraw the 1921 * rest. If scrolling works, must redraw the text 1922 * below the scrolled text. */ 1923 if (row - xtra_rows >= wp->w_height - 2) 1924 mod_bot = MAXLNUM; 1925 else 1926 { 1927 check_for_delay(FALSE); 1928 if (win_del_lines(wp, row, 1929 -xtra_rows, FALSE, FALSE, 0) == FAIL) 1930 mod_bot = MAXLNUM; 1931 else 1932 bot_start = wp->w_height + xtra_rows; 1933 } 1934 } 1935 else if (xtra_rows > 0) 1936 { 1937 /* May scroll text down. If there is not enough 1938 * remaining text of scrolling fails, must redraw the 1939 * rest. */ 1940 if (row + xtra_rows >= wp->w_height - 2) 1941 mod_bot = MAXLNUM; 1942 else 1943 { 1944 check_for_delay(FALSE); 1945 if (win_ins_lines(wp, row + old_rows, 1946 xtra_rows, FALSE, FALSE) == FAIL) 1947 mod_bot = MAXLNUM; 1948 else if (top_end > row + old_rows) 1949 /* Scrolled the part at the top that requires 1950 * updating down. */ 1951 top_end += xtra_rows; 1952 } 1953 } 1954 1955 /* When not updating the rest, may need to move w_lines[] 1956 * entries. */ 1957 if (mod_bot != MAXLNUM && i != j) 1958 { 1959 if (j < i) 1960 { 1961 int x = row + new_rows; 1962 1963 /* move entries in w_lines[] upwards */ 1964 for (;;) 1965 { 1966 /* stop at last valid entry in w_lines[] */ 1967 if (i >= wp->w_lines_valid) 1968 { 1969 wp->w_lines_valid = j; 1970 break; 1971 } 1972 wp->w_lines[j] = wp->w_lines[i]; 1973 /* stop at a line that won't fit */ 1974 if (x + (int)wp->w_lines[j].wl_size 1975 > wp->w_height) 1976 { 1977 wp->w_lines_valid = j + 1; 1978 break; 1979 } 1980 x += wp->w_lines[j++].wl_size; 1981 ++i; 1982 } 1983 if (bot_start > x) 1984 bot_start = x; 1985 } 1986 else /* j > i */ 1987 { 1988 /* move entries in w_lines[] downwards */ 1989 j -= i; 1990 wp->w_lines_valid += j; 1991 if (wp->w_lines_valid > wp->w_height) 1992 wp->w_lines_valid = wp->w_height; 1993 for (i = wp->w_lines_valid; i - j >= idx; --i) 1994 wp->w_lines[i] = wp->w_lines[i - j]; 1995 1996 /* The w_lines[] entries for inserted lines are 1997 * now invalid, but wl_size may be used above. 1998 * Reset to zero. */ 1999 while (i >= idx) 2000 { 2001 wp->w_lines[i].wl_size = 0; 2002 wp->w_lines[i--].wl_valid = FALSE; 2003 } 2004 } 2005 } 2006 } 2007 } 2008 2009 #ifdef FEAT_FOLDING 2010 /* 2011 * When lines are folded, display one line for all of them. 2012 * Otherwise, display normally (can be several display lines when 2013 * 'wrap' is on). 2014 */ 2015 fold_count = foldedCount(wp, lnum, &win_foldinfo); 2016 if (fold_count != 0) 2017 { 2018 fold_line(wp, fold_count, &win_foldinfo, lnum, row); 2019 ++row; 2020 --fold_count; 2021 wp->w_lines[idx].wl_folded = TRUE; 2022 wp->w_lines[idx].wl_lastlnum = lnum + fold_count; 2023 # ifdef FEAT_SYN_HL 2024 did_update = DID_FOLD; 2025 # endif 2026 } 2027 else 2028 #endif 2029 if (idx < wp->w_lines_valid 2030 && wp->w_lines[idx].wl_valid 2031 && wp->w_lines[idx].wl_lnum == lnum 2032 && lnum > wp->w_topline 2033 && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) 2034 && srow + wp->w_lines[idx].wl_size > wp->w_height 2035 #ifdef FEAT_DIFF 2036 && diff_check_fill(wp, lnum) == 0 2037 #endif 2038 ) 2039 { 2040 /* This line is not going to fit. Don't draw anything here, 2041 * will draw "@ " lines below. */ 2042 row = wp->w_height + 1; 2043 } 2044 else 2045 { 2046 #ifdef FEAT_SEARCH_EXTRA 2047 prepare_search_hl(wp, lnum); 2048 #endif 2049 #ifdef FEAT_SYN_HL 2050 /* Let the syntax stuff know we skipped a few lines. */ 2051 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum 2052 && syntax_present(wp)) 2053 syntax_end_parsing(syntax_last_parsed + 1); 2054 #endif 2055 2056 /* 2057 * Display one line. 2058 */ 2059 row = win_line(wp, lnum, srow, wp->w_height, 2060 mod_top == 0, FALSE); 2061 2062 #ifdef FEAT_FOLDING 2063 wp->w_lines[idx].wl_folded = FALSE; 2064 wp->w_lines[idx].wl_lastlnum = lnum; 2065 #endif 2066 #ifdef FEAT_SYN_HL 2067 did_update = DID_LINE; 2068 syntax_last_parsed = lnum; 2069 #endif 2070 } 2071 2072 wp->w_lines[idx].wl_lnum = lnum; 2073 wp->w_lines[idx].wl_valid = TRUE; 2074 2075 /* Past end of the window or end of the screen. Note that after 2076 * resizing wp->w_height may be end up too big. That's a problem 2077 * elsewhere, but prevent a crash here. */ 2078 if (row > wp->w_height || row + wp->w_winrow >= Rows) 2079 { 2080 /* we may need the size of that too long line later on */ 2081 if (dollar_vcol == -1) 2082 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE); 2083 ++idx; 2084 break; 2085 } 2086 if (dollar_vcol == -1) 2087 wp->w_lines[idx].wl_size = row - srow; 2088 ++idx; 2089 #ifdef FEAT_FOLDING 2090 lnum += fold_count + 1; 2091 #else 2092 ++lnum; 2093 #endif 2094 } 2095 else 2096 { 2097 if (wp->w_p_rnu) 2098 { 2099 #ifdef FEAT_FOLDING 2100 // 'relativenumber' set: The text doesn't need to be drawn, but 2101 // the number column nearly always does. 2102 fold_count = foldedCount(wp, lnum, &win_foldinfo); 2103 if (fold_count != 0) 2104 fold_line(wp, fold_count, &win_foldinfo, lnum, row); 2105 else 2106 #endif 2107 (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE); 2108 } 2109 2110 // This line does not need to be drawn, advance to the next one. 2111 row += wp->w_lines[idx++].wl_size; 2112 if (row > wp->w_height) /* past end of screen */ 2113 break; 2114 #ifdef FEAT_FOLDING 2115 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1; 2116 #else 2117 ++lnum; 2118 #endif 2119 #ifdef FEAT_SYN_HL 2120 did_update = DID_NONE; 2121 #endif 2122 } 2123 2124 if (lnum > buf->b_ml.ml_line_count) 2125 { 2126 eof = TRUE; 2127 break; 2128 } 2129 } 2130 /* 2131 * End of loop over all window lines. 2132 */ 2133 2134 #ifdef FEAT_VTP 2135 /* Rewrite the character at the end of the screen line. */ 2136 if (use_vtp()) 2137 { 2138 int i; 2139 2140 for (i = 0; i < Rows; ++i) 2141 if (enc_utf8) 2142 if ((*mb_off2cells)(LineOffset[i] + Columns - 2, 2143 LineOffset[i] + screen_Columns) > 1) 2144 screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE); 2145 else 2146 screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE); 2147 else 2148 screen_char(LineOffset[i] + Columns - 1, i, Columns - 1); 2149 } 2150 #endif 2151 2152 if (idx > wp->w_lines_valid) 2153 wp->w_lines_valid = idx; 2154 2155 #ifdef FEAT_SYN_HL 2156 /* 2157 * Let the syntax stuff know we stop parsing here. 2158 */ 2159 if (syntax_last_parsed != 0 && syntax_present(wp)) 2160 syntax_end_parsing(syntax_last_parsed + 1); 2161 #endif 2162 2163 /* 2164 * If we didn't hit the end of the file, and we didn't finish the last 2165 * line we were working on, then the line didn't fit. 2166 */ 2167 wp->w_empty_rows = 0; 2168 #ifdef FEAT_DIFF 2169 wp->w_filler_rows = 0; 2170 #endif 2171 if (!eof && !didline) 2172 { 2173 if (lnum == wp->w_topline) 2174 { 2175 /* 2176 * Single line that does not fit! 2177 * Don't overwrite it, it can be edited. 2178 */ 2179 wp->w_botline = lnum + 1; 2180 } 2181 #ifdef FEAT_DIFF 2182 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow) 2183 { 2184 /* Window ends in filler lines. */ 2185 wp->w_botline = lnum; 2186 wp->w_filler_rows = wp->w_height - srow; 2187 } 2188 #endif 2189 else if (dy_flags & DY_TRUNCATE) /* 'display' has "truncate" */ 2190 { 2191 int scr_row = W_WINROW(wp) + wp->w_height - 1; 2192 2193 /* 2194 * Last line isn't finished: Display "@@@" in the last screen line. 2195 */ 2196 screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol, 2197 HL_ATTR(HLF_AT)); 2198 screen_fill(scr_row, scr_row + 1, 2199 (int)wp->w_wincol + 2, (int)W_ENDCOL(wp), 2200 '@', ' ', HL_ATTR(HLF_AT)); 2201 set_empty_rows(wp, srow); 2202 wp->w_botline = lnum; 2203 } 2204 else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */ 2205 { 2206 /* 2207 * Last line isn't finished: Display "@@@" at the end. 2208 */ 2209 screen_fill(W_WINROW(wp) + wp->w_height - 1, 2210 W_WINROW(wp) + wp->w_height, 2211 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp), 2212 '@', '@', HL_ATTR(HLF_AT)); 2213 set_empty_rows(wp, srow); 2214 wp->w_botline = lnum; 2215 } 2216 else 2217 { 2218 win_draw_end(wp, '@', ' ', TRUE, srow, wp->w_height, HLF_AT); 2219 wp->w_botline = lnum; 2220 } 2221 } 2222 else 2223 { 2224 draw_vsep_win(wp, row); 2225 if (eof) /* we hit the end of the file */ 2226 { 2227 wp->w_botline = buf->b_ml.ml_line_count + 1; 2228 #ifdef FEAT_DIFF 2229 j = diff_check_fill(wp, wp->w_botline); 2230 if (j > 0 && !wp->w_botfill) 2231 { 2232 // Display filler lines at the end of the file. 2233 if (char2cells(fill_diff) > 1) 2234 i = '-'; 2235 else 2236 i = fill_diff; 2237 if (row + j > wp->w_height) 2238 j = wp->w_height - row; 2239 win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED); 2240 row += j; 2241 } 2242 #endif 2243 } 2244 else if (dollar_vcol == -1) 2245 wp->w_botline = lnum; 2246 2247 // Make sure the rest of the screen is blank 2248 // put '~'s on rows that aren't part of the file. 2249 win_draw_end(wp, '~', ' ', FALSE, row, wp->w_height, HLF_EOB); 2250 } 2251 2252 #ifdef SYN_TIME_LIMIT 2253 syn_set_timeout(NULL); 2254 #endif 2255 2256 /* Reset the type of redrawing required, the window has been updated. */ 2257 wp->w_redr_type = 0; 2258 #ifdef FEAT_DIFF 2259 wp->w_old_topfill = wp->w_topfill; 2260 wp->w_old_botfill = wp->w_botfill; 2261 #endif 2262 2263 if (dollar_vcol == -1) 2264 { 2265 /* 2266 * There is a trick with w_botline. If we invalidate it on each 2267 * change that might modify it, this will cause a lot of expensive 2268 * calls to plines() in update_topline() each time. Therefore the 2269 * value of w_botline is often approximated, and this value is used to 2270 * compute the value of w_topline. If the value of w_botline was 2271 * wrong, check that the value of w_topline is correct (cursor is on 2272 * the visible part of the text). If it's not, we need to redraw 2273 * again. Mostly this just means scrolling up a few lines, so it 2274 * doesn't look too bad. Only do this for the current window (where 2275 * changes are relevant). 2276 */ 2277 wp->w_valid |= VALID_BOTLINE; 2278 if (wp == curwin && wp->w_botline != old_botline && !recursive) 2279 { 2280 recursive = TRUE; 2281 curwin->w_valid &= ~VALID_TOPLINE; 2282 update_topline(); /* may invalidate w_botline again */ 2283 if (must_redraw != 0) 2284 { 2285 /* Don't update for changes in buffer again. */ 2286 i = curbuf->b_mod_set; 2287 curbuf->b_mod_set = FALSE; 2288 win_update(curwin); 2289 must_redraw = 0; 2290 curbuf->b_mod_set = i; 2291 } 2292 recursive = FALSE; 2293 } 2294 } 2295 2296 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) 2297 /* restore got_int, unless CTRL-C was hit while redrawing */ 2298 if (!got_int) 2299 got_int = save_got_int; 2300 #endif 2301 } 2302 2303 /* 2304 * Call screen_fill() with the columns adjusted for 'rightleft' if needed. 2305 * Return the new offset. 2306 */ 2307 static int 2308 screen_fill_end( 2309 win_T *wp, 2310 int c1, 2311 int c2, 2312 int off, 2313 int width, 2314 int row, 2315 int endrow, 2316 int attr) 2317 { 2318 int nn = off + width; 2319 2320 if (nn > wp->w_width) 2321 nn = wp->w_width; 2322 #ifdef FEAT_RIGHTLEFT 2323 if (wp->w_p_rl) 2324 { 2325 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow, 2326 W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off, 2327 c1, c2, attr); 2328 } 2329 else 2330 #endif 2331 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow, 2332 wp->w_wincol + off, (int)wp->w_wincol + nn, 2333 c1, c2, attr); 2334 return nn; 2335 } 2336 2337 /* 2338 * Clear lines near the end the window and mark the unused lines with "c1". 2339 * use "c2" as the filler character. 2340 * When "draw_margin" is TRUE then draw the sign, fold and number columns. 2341 */ 2342 static void 2343 win_draw_end( 2344 win_T *wp, 2345 int c1, 2346 int c2, 2347 int draw_margin, 2348 int row, 2349 int endrow, 2350 hlf_T hl) 2351 { 2352 int n = 0; 2353 2354 if (draw_margin) 2355 { 2356 #ifdef FEAT_FOLDING 2357 int fdc = compute_foldcolumn(wp, 0); 2358 2359 if (fdc > 0) 2360 // draw the fold column 2361 n = screen_fill_end(wp, ' ', ' ', n, fdc, 2362 row, endrow, HL_ATTR(HLF_FC)); 2363 #endif 2364 #ifdef FEAT_SIGNS 2365 if (signcolumn_on(wp)) 2366 // draw the sign column 2367 n = screen_fill_end(wp, ' ', ' ', n, 2, 2368 row, endrow, HL_ATTR(HLF_SC)); 2369 #endif 2370 if ((wp->w_p_nu || wp->w_p_rnu) 2371 && vim_strchr(p_cpo, CPO_NUMCOL) == NULL) 2372 // draw the number column 2373 n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1, 2374 row, endrow, HL_ATTR(HLF_N)); 2375 } 2376 2377 #ifdef FEAT_RIGHTLEFT 2378 if (wp->w_p_rl) 2379 { 2380 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow, 2381 wp->w_wincol, W_ENDCOL(wp) - 1 - n, 2382 c2, c2, HL_ATTR(hl)); 2383 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow, 2384 W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n, 2385 c1, c2, HL_ATTR(hl)); 2386 } 2387 else 2388 #endif 2389 { 2390 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow, 2391 wp->w_wincol + n, (int)W_ENDCOL(wp), 2392 c1, c2, HL_ATTR(hl)); 2393 } 2394 2395 set_empty_rows(wp, row); 2396 } 2397 2398 #ifdef FEAT_SYN_HL 2399 /* 2400 * Advance **color_cols and return TRUE when there are columns to draw. 2401 */ 2402 static int 2403 advance_color_col(int vcol, int **color_cols) 2404 { 2405 while (**color_cols >= 0 && vcol > **color_cols) 2406 ++*color_cols; 2407 return (**color_cols >= 0); 2408 } 2409 #endif 2410 2411 #if defined(FEAT_MENU) || defined(FEAT_FOLDING) 2412 /* 2413 * Copy "text" to ScreenLines using "attr". 2414 * Returns the next screen column. 2415 */ 2416 static int 2417 text_to_screenline(win_T *wp, char_u *text, int col) 2418 { 2419 int off = (int)(current_ScreenLine - ScreenLines); 2420 2421 if (has_mbyte) 2422 { 2423 int cells; 2424 int u8c, u8cc[MAX_MCO]; 2425 int i; 2426 int idx; 2427 int c_len; 2428 char_u *p; 2429 # ifdef FEAT_ARABIC 2430 int prev_c = 0; /* previous Arabic character */ 2431 int prev_c1 = 0; /* first composing char for prev_c */ 2432 # endif 2433 2434 # ifdef FEAT_RIGHTLEFT 2435 if (wp->w_p_rl) 2436 idx = off; 2437 else 2438 # endif 2439 idx = off + col; 2440 2441 /* Store multibyte characters in ScreenLines[] et al. correctly. */ 2442 for (p = text; *p != NUL; ) 2443 { 2444 cells = (*mb_ptr2cells)(p); 2445 c_len = (*mb_ptr2len)(p); 2446 if (col + cells > wp->w_width 2447 # ifdef FEAT_RIGHTLEFT 2448 - (wp->w_p_rl ? col : 0) 2449 # endif 2450 ) 2451 break; 2452 ScreenLines[idx] = *p; 2453 if (enc_utf8) 2454 { 2455 u8c = utfc_ptr2char(p, u8cc); 2456 if (*p < 0x80 && u8cc[0] == 0) 2457 { 2458 ScreenLinesUC[idx] = 0; 2459 #ifdef FEAT_ARABIC 2460 prev_c = u8c; 2461 #endif 2462 } 2463 else 2464 { 2465 #ifdef FEAT_ARABIC 2466 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) 2467 { 2468 /* Do Arabic shaping. */ 2469 int pc, pc1, nc; 2470 int pcc[MAX_MCO]; 2471 int firstbyte = *p; 2472 2473 /* The idea of what is the previous and next 2474 * character depends on 'rightleft'. */ 2475 if (wp->w_p_rl) 2476 { 2477 pc = prev_c; 2478 pc1 = prev_c1; 2479 nc = utf_ptr2char(p + c_len); 2480 prev_c1 = u8cc[0]; 2481 } 2482 else 2483 { 2484 pc = utfc_ptr2char(p + c_len, pcc); 2485 nc = prev_c; 2486 pc1 = pcc[0]; 2487 } 2488 prev_c = u8c; 2489 2490 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], 2491 pc, pc1, nc); 2492 ScreenLines[idx] = firstbyte; 2493 } 2494 else 2495 prev_c = u8c; 2496 #endif 2497 /* Non-BMP character: display as ? or fullwidth ?. */ 2498 ScreenLinesUC[idx] = u8c; 2499 for (i = 0; i < Screen_mco; ++i) 2500 { 2501 ScreenLinesC[i][idx] = u8cc[i]; 2502 if (u8cc[i] == 0) 2503 break; 2504 } 2505 } 2506 if (cells > 1) 2507 ScreenLines[idx + 1] = 0; 2508 } 2509 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e) 2510 /* double-byte single width character */ 2511 ScreenLines2[idx] = p[1]; 2512 else if (cells > 1) 2513 /* double-width character */ 2514 ScreenLines[idx + 1] = p[1]; 2515 col += cells; 2516 idx += cells; 2517 p += c_len; 2518 } 2519 } 2520 else 2521 { 2522 int len = (int)STRLEN(text); 2523 2524 if (len > wp->w_width - col) 2525 len = wp->w_width - col; 2526 if (len > 0) 2527 { 2528 #ifdef FEAT_RIGHTLEFT 2529 if (wp->w_p_rl) 2530 mch_memmove(current_ScreenLine, text, len); 2531 else 2532 #endif 2533 mch_memmove(current_ScreenLine + col, text, len); 2534 col += len; 2535 } 2536 } 2537 return col; 2538 } 2539 #endif 2540 2541 #ifdef FEAT_FOLDING 2542 /* 2543 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much 2544 * space is available for window "wp", minus "col". 2545 */ 2546 static int 2547 compute_foldcolumn(win_T *wp, int col) 2548 { 2549 int fdc = wp->w_p_fdc; 2550 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw; 2551 int wwidth = wp->w_width; 2552 2553 if (fdc > wwidth - (col + wmw)) 2554 fdc = wwidth - (col + wmw); 2555 return fdc; 2556 } 2557 2558 /* 2559 * Display one folded line. 2560 */ 2561 static void 2562 fold_line( 2563 win_T *wp, 2564 long fold_count, 2565 foldinfo_T *foldinfo, 2566 linenr_T lnum, 2567 int row) 2568 { 2569 char_u buf[FOLD_TEXT_LEN]; 2570 pos_T *top, *bot; 2571 linenr_T lnume = lnum + fold_count - 1; 2572 int len; 2573 char_u *text; 2574 int fdc; 2575 int col; 2576 int txtcol; 2577 int off = (int)(current_ScreenLine - ScreenLines); 2578 int ri; 2579 2580 /* Build the fold line: 2581 * 1. Add the cmdwin_type for the command-line window 2582 * 2. Add the 'foldcolumn' 2583 * 3. Add the 'number' or 'relativenumber' column 2584 * 4. Compose the text 2585 * 5. Add the text 2586 * 6. set highlighting for the Visual area an other text 2587 */ 2588 col = 0; 2589 2590 /* 2591 * 1. Add the cmdwin_type for the command-line window 2592 * Ignores 'rightleft', this window is never right-left. 2593 */ 2594 #ifdef FEAT_CMDWIN 2595 if (cmdwin_type != 0 && wp == curwin) 2596 { 2597 ScreenLines[off] = cmdwin_type; 2598 ScreenAttrs[off] = HL_ATTR(HLF_AT); 2599 if (enc_utf8) 2600 ScreenLinesUC[off] = 0; 2601 ++col; 2602 } 2603 #endif 2604 2605 /* 2606 * 2. Add the 'foldcolumn' 2607 * Reduce the width when there is not enough space. 2608 */ 2609 fdc = compute_foldcolumn(wp, col); 2610 if (fdc > 0) 2611 { 2612 fill_foldcolumn(buf, wp, TRUE, lnum); 2613 #ifdef FEAT_RIGHTLEFT 2614 if (wp->w_p_rl) 2615 { 2616 int i; 2617 2618 copy_text_attr(off + wp->w_width - fdc - col, buf, fdc, 2619 HL_ATTR(HLF_FC)); 2620 /* reverse the fold column */ 2621 for (i = 0; i < fdc; ++i) 2622 ScreenLines[off + wp->w_width - i - 1 - col] = buf[i]; 2623 } 2624 else 2625 #endif 2626 copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC)); 2627 col += fdc; 2628 } 2629 2630 #ifdef FEAT_RIGHTLEFT 2631 # define RL_MEMSET(p, v, l) \ 2632 do { \ 2633 if (wp->w_p_rl) \ 2634 for (ri = 0; ri < l; ++ri) \ 2635 ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \ 2636 else \ 2637 for (ri = 0; ri < l; ++ri) \ 2638 ScreenAttrs[off + (p) + ri] = v; \ 2639 } while (0) 2640 #else 2641 # define RL_MEMSET(p, v, l) \ 2642 do { \ 2643 for (ri = 0; ri < l; ++ri) \ 2644 ScreenAttrs[off + (p) + ri] = v; \ 2645 } while (0) 2646 #endif 2647 2648 /* Set all attributes of the 'number' or 'relativenumber' column and the 2649 * text */ 2650 RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col); 2651 2652 #ifdef FEAT_SIGNS 2653 /* If signs are being displayed, add two spaces. */ 2654 if (signcolumn_on(wp)) 2655 { 2656 len = wp->w_width - col; 2657 if (len > 0) 2658 { 2659 if (len > 2) 2660 len = 2; 2661 # ifdef FEAT_RIGHTLEFT 2662 if (wp->w_p_rl) 2663 /* the line number isn't reversed */ 2664 copy_text_attr(off + wp->w_width - len - col, 2665 (char_u *)" ", len, HL_ATTR(HLF_FL)); 2666 else 2667 # endif 2668 copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL)); 2669 col += len; 2670 } 2671 } 2672 #endif 2673 2674 /* 2675 * 3. Add the 'number' or 'relativenumber' column 2676 */ 2677 if (wp->w_p_nu || wp->w_p_rnu) 2678 { 2679 len = wp->w_width - col; 2680 if (len > 0) 2681 { 2682 int w = number_width(wp); 2683 long num; 2684 char *fmt = "%*ld "; 2685 2686 if (len > w + 1) 2687 len = w + 1; 2688 2689 if (wp->w_p_nu && !wp->w_p_rnu) 2690 /* 'number' + 'norelativenumber' */ 2691 num = (long)lnum; 2692 else 2693 { 2694 /* 'relativenumber', don't use negative numbers */ 2695 num = labs((long)get_cursor_rel_lnum(wp, lnum)); 2696 if (num == 0 && wp->w_p_nu && wp->w_p_rnu) 2697 { 2698 /* 'number' + 'relativenumber': cursor line shows absolute 2699 * line number */ 2700 num = lnum; 2701 fmt = "%-*ld "; 2702 } 2703 } 2704 2705 sprintf((char *)buf, fmt, w, num); 2706 #ifdef FEAT_RIGHTLEFT 2707 if (wp->w_p_rl) 2708 /* the line number isn't reversed */ 2709 copy_text_attr(off + wp->w_width - len - col, buf, len, 2710 HL_ATTR(HLF_FL)); 2711 else 2712 #endif 2713 copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL)); 2714 col += len; 2715 } 2716 } 2717 2718 /* 2719 * 4. Compose the folded-line string with 'foldtext', if set. 2720 */ 2721 text = get_foldtext(wp, lnum, lnume, foldinfo, buf); 2722 2723 txtcol = col; /* remember where text starts */ 2724 2725 /* 2726 * 5. move the text to current_ScreenLine. Fill up with "fill_fold". 2727 * Right-left text is put in columns 0 - number-col, normal text is put 2728 * in columns number-col - window-width. 2729 */ 2730 col = text_to_screenline(wp, text, col); 2731 2732 /* Fill the rest of the line with the fold filler */ 2733 #ifdef FEAT_RIGHTLEFT 2734 if (wp->w_p_rl) 2735 col -= txtcol; 2736 #endif 2737 while (col < wp->w_width 2738 #ifdef FEAT_RIGHTLEFT 2739 - (wp->w_p_rl ? txtcol : 0) 2740 #endif 2741 ) 2742 { 2743 if (enc_utf8) 2744 { 2745 if (fill_fold >= 0x80) 2746 { 2747 ScreenLinesUC[off + col] = fill_fold; 2748 ScreenLinesC[0][off + col] = 0; 2749 ScreenLines[off + col] = 0x80; /* avoid storing zero */ 2750 } 2751 else 2752 { 2753 ScreenLinesUC[off + col] = 0; 2754 ScreenLines[off + col] = fill_fold; 2755 } 2756 col++; 2757 } 2758 else 2759 ScreenLines[off + col++] = fill_fold; 2760 } 2761 2762 if (text != buf) 2763 vim_free(text); 2764 2765 /* 2766 * 6. set highlighting for the Visual area an other text. 2767 * If all folded lines are in the Visual area, highlight the line. 2768 */ 2769 if (VIsual_active && wp->w_buffer == curwin->w_buffer) 2770 { 2771 if (LTOREQ_POS(curwin->w_cursor, VIsual)) 2772 { 2773 /* Visual is after curwin->w_cursor */ 2774 top = &curwin->w_cursor; 2775 bot = &VIsual; 2776 } 2777 else 2778 { 2779 /* Visual is before curwin->w_cursor */ 2780 top = &VIsual; 2781 bot = &curwin->w_cursor; 2782 } 2783 if (lnum >= top->lnum 2784 && lnume <= bot->lnum 2785 && (VIsual_mode != 'v' 2786 || ((lnum > top->lnum 2787 || (lnum == top->lnum 2788 && top->col == 0)) 2789 && (lnume < bot->lnum 2790 || (lnume == bot->lnum 2791 && (bot->col - (*p_sel == 'e')) 2792 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE))))))) 2793 { 2794 if (VIsual_mode == Ctrl_V) 2795 { 2796 /* Visual block mode: highlight the chars part of the block */ 2797 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width) 2798 { 2799 if (wp->w_old_cursor_lcol != MAXCOL 2800 && wp->w_old_cursor_lcol + txtcol 2801 < (colnr_T)wp->w_width) 2802 len = wp->w_old_cursor_lcol; 2803 else 2804 len = wp->w_width - txtcol; 2805 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V), 2806 len - (int)wp->w_old_cursor_fcol); 2807 } 2808 } 2809 else 2810 { 2811 /* Set all attributes of the text */ 2812 RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol); 2813 } 2814 } 2815 } 2816 2817 #ifdef FEAT_SYN_HL 2818 /* Show colorcolumn in the fold line, but let cursorcolumn override it. */ 2819 if (wp->w_p_cc_cols) 2820 { 2821 int i = 0; 2822 int j = wp->w_p_cc_cols[i]; 2823 int old_txtcol = txtcol; 2824 2825 while (j > -1) 2826 { 2827 txtcol += j; 2828 if (wp->w_p_wrap) 2829 txtcol -= wp->w_skipcol; 2830 else 2831 txtcol -= wp->w_leftcol; 2832 if (txtcol >= 0 && txtcol < wp->w_width) 2833 ScreenAttrs[off + txtcol] = hl_combine_attr( 2834 ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC)); 2835 txtcol = old_txtcol; 2836 j = wp->w_p_cc_cols[++i]; 2837 } 2838 } 2839 2840 /* Show 'cursorcolumn' in the fold line. */ 2841 if (wp->w_p_cuc) 2842 { 2843 txtcol += wp->w_virtcol; 2844 if (wp->w_p_wrap) 2845 txtcol -= wp->w_skipcol; 2846 else 2847 txtcol -= wp->w_leftcol; 2848 if (txtcol >= 0 && txtcol < wp->w_width) 2849 ScreenAttrs[off + txtcol] = hl_combine_attr( 2850 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC)); 2851 } 2852 #endif 2853 2854 screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width, 2855 (int)wp->w_width, FALSE); 2856 2857 /* 2858 * Update w_cline_height and w_cline_folded if the cursor line was 2859 * updated (saves a call to plines() later). 2860 */ 2861 if (wp == curwin 2862 && lnum <= curwin->w_cursor.lnum 2863 && lnume >= curwin->w_cursor.lnum) 2864 { 2865 curwin->w_cline_row = row; 2866 curwin->w_cline_height = 1; 2867 curwin->w_cline_folded = TRUE; 2868 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); 2869 } 2870 } 2871 2872 /* 2873 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr". 2874 */ 2875 static void 2876 copy_text_attr( 2877 int off, 2878 char_u *buf, 2879 int len, 2880 int attr) 2881 { 2882 int i; 2883 2884 mch_memmove(ScreenLines + off, buf, (size_t)len); 2885 if (enc_utf8) 2886 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len); 2887 for (i = 0; i < len; ++i) 2888 ScreenAttrs[off + i] = attr; 2889 } 2890 2891 /* 2892 * Fill the foldcolumn at "p" for window "wp". 2893 * Only to be called when 'foldcolumn' > 0. 2894 */ 2895 static void 2896 fill_foldcolumn( 2897 char_u *p, 2898 win_T *wp, 2899 int closed, /* TRUE of FALSE */ 2900 linenr_T lnum) /* current line number */ 2901 { 2902 int i = 0; 2903 int level; 2904 int first_level; 2905 int empty; 2906 int fdc = compute_foldcolumn(wp, 0); 2907 2908 /* Init to all spaces. */ 2909 vim_memset(p, ' ', (size_t)fdc); 2910 2911 level = win_foldinfo.fi_level; 2912 if (level > 0) 2913 { 2914 /* If there is only one column put more info in it. */ 2915 empty = (fdc == 1) ? 0 : 1; 2916 2917 /* If the column is too narrow, we start at the lowest level that 2918 * fits and use numbers to indicated the depth. */ 2919 first_level = level - fdc - closed + 1 + empty; 2920 if (first_level < 1) 2921 first_level = 1; 2922 2923 for (i = 0; i + empty < fdc; ++i) 2924 { 2925 if (win_foldinfo.fi_lnum == lnum 2926 && first_level + i >= win_foldinfo.fi_low_level) 2927 p[i] = '-'; 2928 else if (first_level == 1) 2929 p[i] = '|'; 2930 else if (first_level + i <= 9) 2931 p[i] = '0' + first_level + i; 2932 else 2933 p[i] = '>'; 2934 if (first_level + i == level) 2935 break; 2936 } 2937 } 2938 if (closed) 2939 p[i >= fdc ? i - 1 : i] = '+'; 2940 } 2941 #endif /* FEAT_FOLDING */ 2942 2943 #ifdef FEAT_TEXT_PROP 2944 static textprop_T *current_text_props = NULL; 2945 static buf_T *current_buf = NULL; 2946 2947 static int 2948 #ifdef __BORLANDC__ 2949 _RTLENTRYF 2950 #endif 2951 text_prop_compare(const void *s1, const void *s2) 2952 { 2953 int idx1, idx2; 2954 proptype_T *pt1, *pt2; 2955 colnr_T col1, col2; 2956 2957 idx1 = *(int *)s1; 2958 idx2 = *(int *)s2; 2959 pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type); 2960 pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type); 2961 if (pt1 == pt2) 2962 return 0; 2963 if (pt1 == NULL) 2964 return -1; 2965 if (pt2 == NULL) 2966 return 1; 2967 if (pt1->pt_priority != pt2->pt_priority) 2968 return pt1->pt_priority > pt2->pt_priority ? 1 : -1; 2969 col1 = current_text_props[idx1].tp_col; 2970 col2 = current_text_props[idx2].tp_col; 2971 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1; 2972 } 2973 #endif 2974 2975 /* 2976 * Display line "lnum" of window 'wp' on the screen. 2977 * Start at row "startrow", stop when "endrow" is reached. 2978 * wp->w_virtcol needs to be valid. 2979 * 2980 * Return the number of last row the line occupies. 2981 */ 2982 static int 2983 win_line( 2984 win_T *wp, 2985 linenr_T lnum, 2986 int startrow, 2987 int endrow, 2988 int nochange UNUSED, // not updating for changed text 2989 int number_only) // only update the number column 2990 { 2991 int col = 0; /* visual column on screen */ 2992 unsigned off; /* offset in ScreenLines/ScreenAttrs */ 2993 int c = 0; /* init for GCC */ 2994 long vcol = 0; /* virtual column (for tabs) */ 2995 #ifdef FEAT_LINEBREAK 2996 long vcol_sbr = -1; /* virtual column after showbreak */ 2997 #endif 2998 long vcol_prev = -1; /* "vcol" of previous character */ 2999 char_u *line; /* current line */ 3000 char_u *ptr; /* current position in "line" */ 3001 int row; /* row in the window, excl w_winrow */ 3002 int screen_row; /* row on the screen, incl w_winrow */ 3003 3004 char_u extra[18]; /* "%ld" and 'fdc' must fit in here */ 3005 int n_extra = 0; /* number of extra chars */ 3006 char_u *p_extra = NULL; /* string of extra chars, plus NUL */ 3007 char_u *p_extra_free = NULL; /* p_extra needs to be freed */ 3008 int c_extra = NUL; /* extra chars, all the same */ 3009 int c_final = NUL; /* final char, mandatory if set */ 3010 int extra_attr = 0; /* attributes when n_extra != 0 */ 3011 static char_u *at_end_str = (char_u *)""; /* used for p_extra when 3012 displaying lcs_eol at end-of-line */ 3013 int lcs_eol_one = lcs_eol; /* lcs_eol until it's been used */ 3014 int lcs_prec_todo = lcs_prec; /* lcs_prec until it's been used */ 3015 3016 /* saved "extra" items for when draw_state becomes WL_LINE (again) */ 3017 int saved_n_extra = 0; 3018 char_u *saved_p_extra = NULL; 3019 int saved_c_extra = 0; 3020 int saved_c_final = 0; 3021 int saved_char_attr = 0; 3022 3023 int n_attr = 0; /* chars with special attr */ 3024 int saved_attr2 = 0; /* char_attr saved for n_attr */ 3025 int n_attr3 = 0; /* chars with overruling special attr */ 3026 int saved_attr3 = 0; /* char_attr saved for n_attr3 */ 3027 3028 int n_skip = 0; /* nr of chars to skip for 'nowrap' */ 3029 3030 int fromcol, tocol; /* start/end of inverting */ 3031 int fromcol_prev = -2; /* start of inverting after cursor */ 3032 int noinvcur = FALSE; /* don't invert the cursor */ 3033 pos_T *top, *bot; 3034 int lnum_in_visual_area = FALSE; 3035 pos_T pos; 3036 long v; 3037 3038 int char_attr = 0; /* attributes for next character */ 3039 int attr_pri = FALSE; /* char_attr has priority */ 3040 int area_highlighting = FALSE; /* Visual or incsearch highlighting 3041 in this line */ 3042 int attr = 0; /* attributes for area highlighting */ 3043 int area_attr = 0; /* attributes desired by highlighting */ 3044 int search_attr = 0; /* attributes desired by 'hlsearch' */ 3045 #ifdef FEAT_SYN_HL 3046 int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */ 3047 int syntax_attr = 0; /* attributes desired by syntax */ 3048 int has_syntax = FALSE; /* this buffer has syntax highl. */ 3049 int save_did_emsg; 3050 int eol_hl_off = 0; /* 1 if highlighted char after EOL */ 3051 int draw_color_col = FALSE; /* highlight colorcolumn */ 3052 int *color_cols = NULL; /* pointer to according columns array */ 3053 #endif 3054 #ifdef FEAT_TEXT_PROP 3055 int text_prop_count; 3056 int text_prop_next = 0; // next text property to use 3057 textprop_T *text_props = NULL; 3058 int *text_prop_idxs = NULL; 3059 int text_props_active = 0; 3060 proptype_T *text_prop_type = NULL; 3061 int text_prop_attr = 0; 3062 #endif 3063 #ifdef FEAT_SPELL 3064 int has_spell = FALSE; /* this buffer has spell checking */ 3065 # define SPWORDLEN 150 3066 char_u nextline[SPWORDLEN * 2];/* text with start of the next line */ 3067 int nextlinecol = 0; /* column where nextline[] starts */ 3068 int nextline_idx = 0; /* index in nextline[] where next line 3069 starts */ 3070 int spell_attr = 0; /* attributes desired by spelling */ 3071 int word_end = 0; /* last byte with same spell_attr */ 3072 static linenr_T checked_lnum = 0; /* line number for "checked_col" */ 3073 static int checked_col = 0; /* column in "checked_lnum" up to which 3074 * there are no spell errors */ 3075 static int cap_col = -1; /* column to check for Cap word */ 3076 static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */ 3077 int cur_checked_col = 0; /* checked column for current line */ 3078 #endif 3079 int extra_check = 0; // has extra highlighting 3080 int multi_attr = 0; /* attributes desired by multibyte */ 3081 int mb_l = 1; /* multi-byte byte length */ 3082 int mb_c = 0; /* decoded multi-byte character */ 3083 int mb_utf8 = FALSE; /* screen char is UTF-8 char */ 3084 int u8cc[MAX_MCO]; /* composing UTF-8 chars */ 3085 #ifdef FEAT_DIFF 3086 int filler_lines; /* nr of filler lines to be drawn */ 3087 int filler_todo; /* nr of filler lines still to do + 1 */ 3088 hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */ 3089 int change_start = MAXCOL; /* first col of changed area */ 3090 int change_end = -1; /* last col of changed area */ 3091 #endif 3092 colnr_T trailcol = MAXCOL; /* start of trailing spaces */ 3093 #ifdef FEAT_LINEBREAK 3094 int need_showbreak = FALSE; /* overlong line, skipping first x 3095 chars */ 3096 #endif 3097 #if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \ 3098 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF) 3099 # define LINE_ATTR 3100 int line_attr = 0; /* attribute for the whole line */ 3101 #endif 3102 #ifdef FEAT_SEARCH_EXTRA 3103 matchitem_T *cur; /* points to the match list */ 3104 match_T *shl; /* points to search_hl or a match */ 3105 int shl_flag; /* flag to indicate whether search_hl 3106 has been processed or not */ 3107 int pos_inprogress; /* marks that position match search is 3108 in progress */ 3109 int prevcol_hl_flag; /* flag to indicate whether prevcol 3110 equals startcol of search_hl or one 3111 of the matches */ 3112 #endif 3113 #ifdef FEAT_ARABIC 3114 int prev_c = 0; /* previous Arabic character */ 3115 int prev_c1 = 0; /* first composing char for prev_c */ 3116 #endif 3117 #if defined(LINE_ATTR) 3118 int did_line_attr = 0; 3119 #endif 3120 #ifdef FEAT_TERMINAL 3121 int get_term_attr = FALSE; 3122 int term_attr = 0; /* background for terminal window */ 3123 #endif 3124 3125 /* draw_state: items that are drawn in sequence: */ 3126 #define WL_START 0 /* nothing done yet */ 3127 #ifdef FEAT_CMDWIN 3128 # define WL_CMDLINE WL_START + 1 /* cmdline window column */ 3129 #else 3130 # define WL_CMDLINE WL_START 3131 #endif 3132 #ifdef FEAT_FOLDING 3133 # define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */ 3134 #else 3135 # define WL_FOLD WL_CMDLINE 3136 #endif 3137 #ifdef FEAT_SIGNS 3138 # define WL_SIGN WL_FOLD + 1 /* column for signs */ 3139 #else 3140 # define WL_SIGN WL_FOLD /* column for signs */ 3141 #endif 3142 #define WL_NR WL_SIGN + 1 /* line number */ 3143 #ifdef FEAT_LINEBREAK 3144 # define WL_BRI WL_NR + 1 /* 'breakindent' */ 3145 #else 3146 # define WL_BRI WL_NR 3147 #endif 3148 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) 3149 # define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */ 3150 #else 3151 # define WL_SBR WL_BRI 3152 #endif 3153 #define WL_LINE WL_SBR + 1 /* text in the line */ 3154 int draw_state = WL_START; /* what to draw next */ 3155 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 3156 int feedback_col = 0; 3157 int feedback_old_attr = -1; 3158 #endif 3159 3160 #ifdef FEAT_CONCEAL 3161 int syntax_flags = 0; 3162 int syntax_seqnr = 0; 3163 int prev_syntax_id = 0; 3164 int conceal_attr = HL_ATTR(HLF_CONCEAL); 3165 int is_concealing = FALSE; 3166 int boguscols = 0; /* nonexistent columns added to force 3167 wrapping */ 3168 int vcol_off = 0; /* offset for concealed characters */ 3169 int did_wcol = FALSE; 3170 int match_conc = 0; /* cchar for match functions */ 3171 int has_match_conc = 0; /* match wants to conceal */ 3172 int old_boguscols = 0; 3173 # define VCOL_HLC (vcol - vcol_off) 3174 # define FIX_FOR_BOGUSCOLS \ 3175 { \ 3176 n_extra += vcol_off; \ 3177 vcol -= vcol_off; \ 3178 vcol_off = 0; \ 3179 col -= boguscols; \ 3180 old_boguscols = boguscols; \ 3181 boguscols = 0; \ 3182 } 3183 #else 3184 # define VCOL_HLC (vcol) 3185 #endif 3186 3187 if (startrow > endrow) /* past the end already! */ 3188 return startrow; 3189 3190 row = startrow; 3191 screen_row = row + W_WINROW(wp); 3192 3193 if (!number_only) 3194 { 3195 /* 3196 * To speed up the loop below, set extra_check when there is linebreak, 3197 * trailing white space and/or syntax processing to be done. 3198 */ 3199 #ifdef FEAT_LINEBREAK 3200 extra_check = wp->w_p_lbr; 3201 #endif 3202 #ifdef FEAT_SYN_HL 3203 if (syntax_present(wp) && !wp->w_s->b_syn_error 3204 # ifdef SYN_TIME_LIMIT 3205 && !wp->w_s->b_syn_slow 3206 # endif 3207 ) 3208 { 3209 /* Prepare for syntax highlighting in this line. When there is an 3210 * error, stop syntax highlighting. */ 3211 save_did_emsg = did_emsg; 3212 did_emsg = FALSE; 3213 syntax_start(wp, lnum); 3214 if (did_emsg) 3215 wp->w_s->b_syn_error = TRUE; 3216 else 3217 { 3218 did_emsg = save_did_emsg; 3219 #ifdef SYN_TIME_LIMIT 3220 if (!wp->w_s->b_syn_slow) 3221 #endif 3222 { 3223 has_syntax = TRUE; 3224 extra_check = TRUE; 3225 } 3226 } 3227 } 3228 3229 /* Check for columns to display for 'colorcolumn'. */ 3230 color_cols = wp->w_p_cc_cols; 3231 if (color_cols != NULL) 3232 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); 3233 #endif 3234 3235 #ifdef FEAT_TERMINAL 3236 if (term_show_buffer(wp->w_buffer)) 3237 { 3238 extra_check = TRUE; 3239 get_term_attr = TRUE; 3240 term_attr = term_get_attr(wp->w_buffer, lnum, -1); 3241 } 3242 #endif 3243 3244 #ifdef FEAT_SPELL 3245 if (wp->w_p_spell 3246 && *wp->w_s->b_p_spl != NUL 3247 && wp->w_s->b_langp.ga_len > 0 3248 && *(char **)(wp->w_s->b_langp.ga_data) != NULL) 3249 { 3250 /* Prepare for spell checking. */ 3251 has_spell = TRUE; 3252 extra_check = TRUE; 3253 3254 /* Get the start of the next line, so that words that wrap to the 3255 * next line are found too: "et<line-break>al.". 3256 * Trick: skip a few chars for C/shell/Vim comments */ 3257 nextline[SPWORDLEN] = NUL; 3258 if (lnum < wp->w_buffer->b_ml.ml_line_count) 3259 { 3260 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE); 3261 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); 3262 } 3263 3264 /* When a word wrapped from the previous line the start of the 3265 * current line is valid. */ 3266 if (lnum == checked_lnum) 3267 cur_checked_col = checked_col; 3268 checked_lnum = 0; 3269 3270 /* When there was a sentence end in the previous line may require a 3271 * word starting with capital in this line. In line 1 always check 3272 * the first word. */ 3273 if (lnum != capcol_lnum) 3274 cap_col = -1; 3275 if (lnum == 1) 3276 cap_col = 0; 3277 capcol_lnum = 0; 3278 } 3279 #endif 3280 3281 /* 3282 * handle visual active in this window 3283 */ 3284 fromcol = -10; 3285 tocol = MAXCOL; 3286 if (VIsual_active && wp->w_buffer == curwin->w_buffer) 3287 { 3288 /* Visual is after curwin->w_cursor */ 3289 if (LTOREQ_POS(curwin->w_cursor, VIsual)) 3290 { 3291 top = &curwin->w_cursor; 3292 bot = &VIsual; 3293 } 3294 else /* Visual is before curwin->w_cursor */ 3295 { 3296 top = &VIsual; 3297 bot = &curwin->w_cursor; 3298 } 3299 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum); 3300 if (VIsual_mode == Ctrl_V) /* block mode */ 3301 { 3302 if (lnum_in_visual_area) 3303 { 3304 fromcol = wp->w_old_cursor_fcol; 3305 tocol = wp->w_old_cursor_lcol; 3306 } 3307 } 3308 else /* non-block mode */ 3309 { 3310 if (lnum > top->lnum && lnum <= bot->lnum) 3311 fromcol = 0; 3312 else if (lnum == top->lnum) 3313 { 3314 if (VIsual_mode == 'V') /* linewise */ 3315 fromcol = 0; 3316 else 3317 { 3318 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL); 3319 if (gchar_pos(top) == NUL) 3320 tocol = fromcol + 1; 3321 } 3322 } 3323 if (VIsual_mode != 'V' && lnum == bot->lnum) 3324 { 3325 if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0) 3326 { 3327 fromcol = -10; 3328 tocol = MAXCOL; 3329 } 3330 else if (bot->col == MAXCOL) 3331 tocol = MAXCOL; 3332 else 3333 { 3334 pos = *bot; 3335 if (*p_sel == 'e') 3336 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL); 3337 else 3338 { 3339 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol); 3340 ++tocol; 3341 } 3342 } 3343 } 3344 } 3345 3346 /* Check if the character under the cursor should not be inverted */ 3347 if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin 3348 #ifdef FEAT_GUI 3349 && !gui.in_use 3350 #endif 3351 ) 3352 noinvcur = TRUE; 3353 3354 /* if inverting in this line set area_highlighting */ 3355 if (fromcol >= 0) 3356 { 3357 area_highlighting = TRUE; 3358 attr = HL_ATTR(HLF_V); 3359 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) 3360 if ((clip_star.available && !clip_star.owned 3361 && clip_isautosel_star()) 3362 || (clip_plus.available && !clip_plus.owned 3363 && clip_isautosel_plus())) 3364 attr = HL_ATTR(HLF_VNC); 3365 #endif 3366 } 3367 } 3368 3369 /* 3370 * handle 'incsearch' and ":s///c" highlighting 3371 */ 3372 else if (highlight_match 3373 && wp == curwin 3374 && lnum >= curwin->w_cursor.lnum 3375 && lnum <= curwin->w_cursor.lnum + search_match_lines) 3376 { 3377 if (lnum == curwin->w_cursor.lnum) 3378 getvcol(curwin, &(curwin->w_cursor), 3379 (colnr_T *)&fromcol, NULL, NULL); 3380 else 3381 fromcol = 0; 3382 if (lnum == curwin->w_cursor.lnum + search_match_lines) 3383 { 3384 pos.lnum = lnum; 3385 pos.col = search_match_endcol; 3386 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL); 3387 } 3388 else 3389 tocol = MAXCOL; 3390 /* do at least one character; happens when past end of line */ 3391 if (fromcol == tocol) 3392 tocol = fromcol + 1; 3393 area_highlighting = TRUE; 3394 attr = HL_ATTR(HLF_I); 3395 } 3396 } 3397 3398 #ifdef FEAT_DIFF 3399 filler_lines = diff_check(wp, lnum); 3400 if (filler_lines < 0) 3401 { 3402 if (filler_lines == -1) 3403 { 3404 if (diff_find_change(wp, lnum, &change_start, &change_end)) 3405 diff_hlf = HLF_ADD; /* added line */ 3406 else if (change_start == 0) 3407 diff_hlf = HLF_TXD; /* changed text */ 3408 else 3409 diff_hlf = HLF_CHD; /* changed line */ 3410 } 3411 else 3412 diff_hlf = HLF_ADD; /* added line */ 3413 filler_lines = 0; 3414 area_highlighting = TRUE; 3415 } 3416 if (lnum == wp->w_topline) 3417 filler_lines = wp->w_topfill; 3418 filler_todo = filler_lines; 3419 #endif 3420 3421 #ifdef LINE_ATTR 3422 # ifdef FEAT_SIGNS 3423 /* If this line has a sign with line highlighting set line_attr. */ 3424 v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL); 3425 if (v != 0) 3426 line_attr = sign_get_attr((int)v, TRUE); 3427 # endif 3428 # if defined(FEAT_QUICKFIX) 3429 /* Highlight the current line in the quickfix window. */ 3430 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) 3431 line_attr = HL_ATTR(HLF_QFL); 3432 # endif 3433 if (line_attr != 0) 3434 area_highlighting = TRUE; 3435 #endif 3436 3437 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 3438 ptr = line; 3439 3440 #ifdef FEAT_SPELL 3441 if (has_spell && !number_only) 3442 { 3443 /* For checking first word with a capital skip white space. */ 3444 if (cap_col == 0) 3445 cap_col = getwhitecols(line); 3446 3447 /* To be able to spell-check over line boundaries copy the end of the 3448 * current line into nextline[]. Above the start of the next line was 3449 * copied to nextline[SPWORDLEN]. */ 3450 if (nextline[SPWORDLEN] == NUL) 3451 { 3452 /* No next line or it is empty. */ 3453 nextlinecol = MAXCOL; 3454 nextline_idx = 0; 3455 } 3456 else 3457 { 3458 v = (long)STRLEN(line); 3459 if (v < SPWORDLEN) 3460 { 3461 /* Short line, use it completely and append the start of the 3462 * next line. */ 3463 nextlinecol = 0; 3464 mch_memmove(nextline, line, (size_t)v); 3465 STRMOVE(nextline + v, nextline + SPWORDLEN); 3466 nextline_idx = v + 1; 3467 } 3468 else 3469 { 3470 /* Long line, use only the last SPWORDLEN bytes. */ 3471 nextlinecol = v - SPWORDLEN; 3472 mch_memmove(nextline, line + nextlinecol, SPWORDLEN); 3473 nextline_idx = SPWORDLEN + 1; 3474 } 3475 } 3476 } 3477 #endif 3478 3479 if (wp->w_p_list) 3480 { 3481 if (lcs_space || lcs_trail || lcs_nbsp) 3482 extra_check = TRUE; 3483 /* find start of trailing whitespace */ 3484 if (lcs_trail) 3485 { 3486 trailcol = (colnr_T)STRLEN(ptr); 3487 while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1])) 3488 --trailcol; 3489 trailcol += (colnr_T) (ptr - line); 3490 } 3491 } 3492 3493 /* 3494 * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the 3495 * first character to be displayed. 3496 */ 3497 if (wp->w_p_wrap) 3498 v = wp->w_skipcol; 3499 else 3500 v = wp->w_leftcol; 3501 if (v > 0 && !number_only) 3502 { 3503 char_u *prev_ptr = ptr; 3504 3505 while (vcol < v && *ptr != NUL) 3506 { 3507 c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL); 3508 vcol += c; 3509 prev_ptr = ptr; 3510 MB_PTR_ADV(ptr); 3511 } 3512 3513 /* When: 3514 * - 'cuc' is set, or 3515 * - 'colorcolumn' is set, or 3516 * - 'virtualedit' is set, or 3517 * - the visual mode is active, 3518 * the end of the line may be before the start of the displayed part. 3519 */ 3520 if (vcol < v && ( 3521 #ifdef FEAT_SYN_HL 3522 wp->w_p_cuc || draw_color_col || 3523 #endif 3524 virtual_active() || 3525 (VIsual_active && wp->w_buffer == curwin->w_buffer))) 3526 vcol = v; 3527 3528 /* Handle a character that's not completely on the screen: Put ptr at 3529 * that character but skip the first few screen characters. */ 3530 if (vcol > v) 3531 { 3532 vcol -= c; 3533 ptr = prev_ptr; 3534 /* If the character fits on the screen, don't need to skip it. 3535 * Except for a TAB. */ 3536 if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0) 3537 n_skip = v - vcol; 3538 } 3539 3540 /* 3541 * Adjust for when the inverted text is before the screen, 3542 * and when the start of the inverted text is before the screen. 3543 */ 3544 if (tocol <= vcol) 3545 fromcol = 0; 3546 else if (fromcol >= 0 && fromcol < vcol) 3547 fromcol = vcol; 3548 3549 #ifdef FEAT_LINEBREAK 3550 /* When w_skipcol is non-zero, first line needs 'showbreak' */ 3551 if (wp->w_p_wrap) 3552 need_showbreak = TRUE; 3553 #endif 3554 #ifdef FEAT_SPELL 3555 /* When spell checking a word we need to figure out the start of the 3556 * word and if it's badly spelled or not. */ 3557 if (has_spell) 3558 { 3559 int len; 3560 colnr_T linecol = (colnr_T)(ptr - line); 3561 hlf_T spell_hlf = HLF_COUNT; 3562 3563 pos = wp->w_cursor; 3564 wp->w_cursor.lnum = lnum; 3565 wp->w_cursor.col = linecol; 3566 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf); 3567 3568 /* spell_move_to() may call ml_get() and make "line" invalid */ 3569 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 3570 ptr = line + linecol; 3571 3572 if (len == 0 || (int)wp->w_cursor.col > ptr - line) 3573 { 3574 /* no bad word found at line start, don't check until end of a 3575 * word */ 3576 spell_hlf = HLF_COUNT; 3577 word_end = (int)(spell_to_word_end(ptr, wp) - line + 1); 3578 } 3579 else 3580 { 3581 /* bad word found, use attributes until end of word */ 3582 word_end = wp->w_cursor.col + len + 1; 3583 3584 /* Turn index into actual attributes. */ 3585 if (spell_hlf != HLF_COUNT) 3586 spell_attr = highlight_attr[spell_hlf]; 3587 } 3588 wp->w_cursor = pos; 3589 3590 # ifdef FEAT_SYN_HL 3591 /* Need to restart syntax highlighting for this line. */ 3592 if (has_syntax) 3593 syntax_start(wp, lnum); 3594 # endif 3595 } 3596 #endif 3597 } 3598 3599 /* 3600 * Correct highlighting for cursor that can't be disabled. 3601 * Avoids having to check this for each character. 3602 */ 3603 if (fromcol >= 0) 3604 { 3605 if (noinvcur) 3606 { 3607 if ((colnr_T)fromcol == wp->w_virtcol) 3608 { 3609 /* highlighting starts at cursor, let it start just after the 3610 * cursor */ 3611 fromcol_prev = fromcol; 3612 fromcol = -1; 3613 } 3614 else if ((colnr_T)fromcol < wp->w_virtcol) 3615 /* restart highlighting after the cursor */ 3616 fromcol_prev = wp->w_virtcol; 3617 } 3618 if (fromcol >= tocol) 3619 fromcol = -1; 3620 } 3621 3622 #ifdef FEAT_SEARCH_EXTRA 3623 /* 3624 * Handle highlighting the last used search pattern and matches. 3625 * Do this for both search_hl and the match list. 3626 */ 3627 cur = wp->w_match_head; 3628 shl_flag = FALSE; 3629 while ((cur != NULL || shl_flag == FALSE) && !number_only) 3630 { 3631 if (shl_flag == FALSE) 3632 { 3633 shl = &search_hl; 3634 shl_flag = TRUE; 3635 } 3636 else 3637 shl = &cur->hl; 3638 shl->startcol = MAXCOL; 3639 shl->endcol = MAXCOL; 3640 shl->attr_cur = 0; 3641 shl->is_addpos = FALSE; 3642 v = (long)(ptr - line); 3643 if (cur != NULL) 3644 cur->pos.cur = 0; 3645 next_search_hl(wp, shl, lnum, (colnr_T)v, 3646 shl == &search_hl ? NULL : cur); 3647 3648 /* Need to get the line again, a multi-line regexp may have made it 3649 * invalid. */ 3650 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 3651 ptr = line + v; 3652 3653 if (shl->lnum != 0 && shl->lnum <= lnum) 3654 { 3655 if (shl->lnum == lnum) 3656 shl->startcol = shl->rm.startpos[0].col; 3657 else 3658 shl->startcol = 0; 3659 if (lnum == shl->lnum + shl->rm.endpos[0].lnum 3660 - shl->rm.startpos[0].lnum) 3661 shl->endcol = shl->rm.endpos[0].col; 3662 else 3663 shl->endcol = MAXCOL; 3664 /* Highlight one character for an empty match. */ 3665 if (shl->startcol == shl->endcol) 3666 { 3667 if (has_mbyte && line[shl->endcol] != NUL) 3668 shl->endcol += (*mb_ptr2len)(line + shl->endcol); 3669 else 3670 ++shl->endcol; 3671 } 3672 if ((long)shl->startcol < v) /* match at leftcol */ 3673 { 3674 shl->attr_cur = shl->attr; 3675 search_attr = shl->attr; 3676 } 3677 area_highlighting = TRUE; 3678 } 3679 if (shl != &search_hl && cur != NULL) 3680 cur = cur->next; 3681 } 3682 #endif 3683 3684 #ifdef FEAT_SYN_HL 3685 // Cursor line highlighting for 'cursorline' in the current window. 3686 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) 3687 { 3688 // Do not show the cursor line when Visual mode is active, because it's 3689 // not clear what is selected then. Do update w_last_cursorline. 3690 if (!(wp == curwin && VIsual_active)) 3691 { 3692 line_attr = HL_ATTR(HLF_CUL); 3693 area_highlighting = TRUE; 3694 } 3695 wp->w_last_cursorline = wp->w_cursor.lnum; 3696 } 3697 #endif 3698 3699 #ifdef FEAT_TEXT_PROP 3700 { 3701 char_u *prop_start; 3702 3703 text_prop_count = get_text_props(wp->w_buffer, lnum, 3704 &prop_start, FALSE); 3705 if (text_prop_count > 0) 3706 { 3707 // Make a copy of the properties, so that they are properly 3708 // aligned. 3709 text_props = (textprop_T *)alloc( 3710 text_prop_count * sizeof(textprop_T)); 3711 if (text_props != NULL) 3712 mch_memmove(text_props, prop_start, 3713 text_prop_count * sizeof(textprop_T)); 3714 3715 // Allocate an array for the indexes. 3716 text_prop_idxs = (int *)alloc(text_prop_count * sizeof(int)); 3717 area_highlighting = TRUE; 3718 extra_check = TRUE; 3719 } 3720 } 3721 #endif 3722 3723 off = (unsigned)(current_ScreenLine - ScreenLines); 3724 col = 0; 3725 #ifdef FEAT_RIGHTLEFT 3726 if (wp->w_p_rl) 3727 { 3728 /* Rightleft window: process the text in the normal direction, but put 3729 * it in current_ScreenLine[] from right to left. Start at the 3730 * rightmost column of the window. */ 3731 col = wp->w_width - 1; 3732 off += col; 3733 } 3734 #endif 3735 3736 /* 3737 * Repeat for the whole displayed line. 3738 */ 3739 for (;;) 3740 { 3741 #ifdef FEAT_CONCEAL 3742 has_match_conc = 0; 3743 #endif 3744 /* Skip this quickly when working on the text. */ 3745 if (draw_state != WL_LINE) 3746 { 3747 #ifdef FEAT_CMDWIN 3748 if (draw_state == WL_CMDLINE - 1 && n_extra == 0) 3749 { 3750 draw_state = WL_CMDLINE; 3751 if (cmdwin_type != 0 && wp == curwin) 3752 { 3753 /* Draw the cmdline character. */ 3754 n_extra = 1; 3755 c_extra = cmdwin_type; 3756 c_final = NUL; 3757 char_attr = HL_ATTR(HLF_AT); 3758 } 3759 } 3760 #endif 3761 3762 #ifdef FEAT_FOLDING 3763 if (draw_state == WL_FOLD - 1 && n_extra == 0) 3764 { 3765 int fdc = compute_foldcolumn(wp, 0); 3766 3767 draw_state = WL_FOLD; 3768 if (fdc > 0) 3769 { 3770 /* Draw the 'foldcolumn'. Allocate a buffer, "extra" may 3771 * already be in use. */ 3772 vim_free(p_extra_free); 3773 p_extra_free = alloc(12 + 1); 3774 3775 if (p_extra_free != NULL) 3776 { 3777 fill_foldcolumn(p_extra_free, wp, FALSE, lnum); 3778 n_extra = fdc; 3779 p_extra_free[n_extra] = NUL; 3780 p_extra = p_extra_free; 3781 c_extra = NUL; 3782 c_final = NUL; 3783 char_attr = HL_ATTR(HLF_FC); 3784 } 3785 } 3786 } 3787 #endif 3788 3789 #ifdef FEAT_SIGNS 3790 if (draw_state == WL_SIGN - 1 && n_extra == 0) 3791 { 3792 draw_state = WL_SIGN; 3793 /* Show the sign column when there are any signs in this 3794 * buffer or when using Netbeans. */ 3795 if (signcolumn_on(wp)) 3796 { 3797 int text_sign; 3798 # ifdef FEAT_SIGN_ICONS 3799 int icon_sign; 3800 # endif 3801 3802 /* Draw two cells with the sign value or blank. */ 3803 c_extra = ' '; 3804 c_final = NUL; 3805 char_attr = HL_ATTR(HLF_SC); 3806 n_extra = 2; 3807 3808 if (row == startrow 3809 #ifdef FEAT_DIFF 3810 + filler_lines && filler_todo <= 0 3811 #endif 3812 ) 3813 { 3814 text_sign = buf_getsigntype(wp->w_buffer, lnum, 3815 SIGN_TEXT); 3816 # ifdef FEAT_SIGN_ICONS 3817 icon_sign = buf_getsigntype(wp->w_buffer, lnum, 3818 SIGN_ICON); 3819 if (gui.in_use && icon_sign != 0) 3820 { 3821 /* Use the image in this position. */ 3822 c_extra = SIGN_BYTE; 3823 c_final = NUL; 3824 # ifdef FEAT_NETBEANS_INTG 3825 if (buf_signcount(wp->w_buffer, lnum) > 1) 3826 { 3827 c_extra = MULTISIGN_BYTE; 3828 c_final = NUL; 3829 } 3830 # endif 3831 char_attr = icon_sign; 3832 } 3833 else 3834 # endif 3835 if (text_sign != 0) 3836 { 3837 p_extra = sign_get_text(text_sign); 3838 if (p_extra != NULL) 3839 { 3840 c_extra = NUL; 3841 c_final = NUL; 3842 n_extra = (int)STRLEN(p_extra); 3843 } 3844 char_attr = sign_get_attr(text_sign, FALSE); 3845 } 3846 } 3847 } 3848 } 3849 #endif 3850 3851 if (draw_state == WL_NR - 1 && n_extra == 0) 3852 { 3853 draw_state = WL_NR; 3854 /* Display the absolute or relative line number. After the 3855 * first fill with blanks when the 'n' flag isn't in 'cpo' */ 3856 if ((wp->w_p_nu || wp->w_p_rnu) 3857 && (row == startrow 3858 #ifdef FEAT_DIFF 3859 + filler_lines 3860 #endif 3861 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL)) 3862 { 3863 /* Draw the line number (empty space after wrapping). */ 3864 if (row == startrow 3865 #ifdef FEAT_DIFF 3866 + filler_lines 3867 #endif 3868 ) 3869 { 3870 long num; 3871 char *fmt = "%*ld "; 3872 3873 if (wp->w_p_nu && !wp->w_p_rnu) 3874 /* 'number' + 'norelativenumber' */ 3875 num = (long)lnum; 3876 else 3877 { 3878 /* 'relativenumber', don't use negative numbers */ 3879 num = labs((long)get_cursor_rel_lnum(wp, lnum)); 3880 if (num == 0 && wp->w_p_nu && wp->w_p_rnu) 3881 { 3882 /* 'number' + 'relativenumber' */ 3883 num = lnum; 3884 fmt = "%-*ld "; 3885 } 3886 } 3887 3888 sprintf((char *)extra, fmt, 3889 number_width(wp), num); 3890 if (wp->w_skipcol > 0) 3891 for (p_extra = extra; *p_extra == ' '; ++p_extra) 3892 *p_extra = '-'; 3893 #ifdef FEAT_RIGHTLEFT 3894 if (wp->w_p_rl) /* reverse line numbers */ 3895 { 3896 char_u *p1, *p2; 3897 int t; 3898 3899 // like rl_mirror(), but keep the space at the end 3900 p2 = skiptowhite(extra) - 1; 3901 for (p1 = extra; p1 < p2; ++p1, --p2) 3902 { 3903 t = *p1; 3904 *p1 = *p2; 3905 *p2 = t; 3906 } 3907 } 3908 #endif 3909 p_extra = extra; 3910 c_extra = NUL; 3911 c_final = NUL; 3912 } 3913 else 3914 { 3915 c_extra = ' '; 3916 c_final = NUL; 3917 } 3918 n_extra = number_width(wp) + 1; 3919 char_attr = HL_ATTR(HLF_N); 3920 #ifdef FEAT_SYN_HL 3921 /* When 'cursorline' is set highlight the line number of 3922 * the current line differently. 3923 * TODO: Can we use CursorLine instead of CursorLineNr 3924 * when CursorLineNr isn't set? */ 3925 if ((wp->w_p_cul || wp->w_p_rnu) 3926 && lnum == wp->w_cursor.lnum) 3927 char_attr = HL_ATTR(HLF_CLN); 3928 #endif 3929 } 3930 } 3931 3932 #ifdef FEAT_LINEBREAK 3933 if (wp->w_p_brisbr && draw_state == WL_BRI - 1 3934 && n_extra == 0 && *p_sbr != NUL) 3935 /* draw indent after showbreak value */ 3936 draw_state = WL_BRI; 3937 else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0) 3938 /* After the showbreak, draw the breakindent */ 3939 draw_state = WL_BRI - 1; 3940 3941 /* draw 'breakindent': indent wrapped text accordingly */ 3942 if (draw_state == WL_BRI - 1 && n_extra == 0) 3943 { 3944 draw_state = WL_BRI; 3945 /* if need_showbreak is set, breakindent also applies */ 3946 if (wp->w_p_bri && n_extra == 0 3947 && (row != startrow || need_showbreak) 3948 # ifdef FEAT_DIFF 3949 && filler_lines == 0 3950 # endif 3951 ) 3952 { 3953 char_attr = 0; 3954 # ifdef FEAT_DIFF 3955 if (diff_hlf != (hlf_T)0) 3956 { 3957 char_attr = HL_ATTR(diff_hlf); 3958 # ifdef FEAT_SYN_HL 3959 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) 3960 char_attr = hl_combine_attr(char_attr, 3961 HL_ATTR(HLF_CUL)); 3962 # endif 3963 } 3964 # endif 3965 p_extra = NULL; 3966 c_extra = ' '; 3967 n_extra = get_breakindent_win(wp, 3968 ml_get_buf(wp->w_buffer, lnum, FALSE)); 3969 /* Correct end of highlighted area for 'breakindent', 3970 * required when 'linebreak' is also set. */ 3971 if (tocol == vcol) 3972 tocol += n_extra; 3973 } 3974 } 3975 #endif 3976 3977 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) 3978 if (draw_state == WL_SBR - 1 && n_extra == 0) 3979 { 3980 draw_state = WL_SBR; 3981 # ifdef FEAT_DIFF 3982 if (filler_todo > 0) 3983 { 3984 /* Draw "deleted" diff line(s). */ 3985 if (char2cells(fill_diff) > 1) 3986 { 3987 c_extra = '-'; 3988 c_final = NUL; 3989 } 3990 else 3991 { 3992 c_extra = fill_diff; 3993 c_final = NUL; 3994 } 3995 # ifdef FEAT_RIGHTLEFT 3996 if (wp->w_p_rl) 3997 n_extra = col + 1; 3998 else 3999 # endif 4000 n_extra = wp->w_width - col; 4001 char_attr = HL_ATTR(HLF_DED); 4002 } 4003 # endif 4004 # ifdef FEAT_LINEBREAK 4005 if (*p_sbr != NUL && need_showbreak) 4006 { 4007 /* Draw 'showbreak' at the start of each broken line. */ 4008 p_extra = p_sbr; 4009 c_extra = NUL; 4010 c_final = NUL; 4011 n_extra = (int)STRLEN(p_sbr); 4012 char_attr = HL_ATTR(HLF_AT); 4013 need_showbreak = FALSE; 4014 vcol_sbr = vcol + MB_CHARLEN(p_sbr); 4015 /* Correct end of highlighted area for 'showbreak', 4016 * required when 'linebreak' is also set. */ 4017 if (tocol == vcol) 4018 tocol += n_extra; 4019 #ifdef FEAT_SYN_HL 4020 /* combine 'showbreak' with 'cursorline' */ 4021 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) 4022 char_attr = hl_combine_attr(char_attr, 4023 HL_ATTR(HLF_CUL)); 4024 #endif 4025 } 4026 # endif 4027 } 4028 #endif 4029 4030 if (draw_state == WL_LINE - 1 && n_extra == 0) 4031 { 4032 draw_state = WL_LINE; 4033 if (saved_n_extra) 4034 { 4035 /* Continue item from end of wrapped line. */ 4036 n_extra = saved_n_extra; 4037 c_extra = saved_c_extra; 4038 c_final = saved_c_final; 4039 p_extra = saved_p_extra; 4040 char_attr = saved_char_attr; 4041 } 4042 else 4043 char_attr = 0; 4044 } 4045 } 4046 4047 // When still displaying '$' of change command, stop at cursor. 4048 // When only displaying the (relative) line number and that's done, 4049 // stop here. 4050 if ((dollar_vcol >= 0 && wp == curwin 4051 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol 4052 #ifdef FEAT_DIFF 4053 && filler_todo <= 0 4054 #endif 4055 ) 4056 || (number_only && draw_state > WL_NR)) 4057 { 4058 screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width, 4059 HAS_RIGHTLEFT(wp->w_p_rl)); 4060 /* Pretend we have finished updating the window. Except when 4061 * 'cursorcolumn' is set. */ 4062 #ifdef FEAT_SYN_HL 4063 if (wp->w_p_cuc) 4064 row = wp->w_cline_row + wp->w_cline_height; 4065 else 4066 #endif 4067 row = wp->w_height; 4068 break; 4069 } 4070 4071 if (draw_state == WL_LINE && (area_highlighting 4072 #ifdef FEAT_SPELL 4073 || has_spell 4074 #endif 4075 )) 4076 { 4077 /* handle Visual or match highlighting in this line */ 4078 if (vcol == fromcol 4079 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0 4080 && (*mb_ptr2cells)(ptr) > 1) 4081 || ((int)vcol_prev == fromcol_prev 4082 && vcol_prev < vcol /* not at margin */ 4083 && vcol < tocol)) 4084 area_attr = attr; /* start highlighting */ 4085 else if (area_attr != 0 4086 && (vcol == tocol 4087 || (noinvcur && (colnr_T)vcol == wp->w_virtcol))) 4088 area_attr = 0; /* stop highlighting */ 4089 4090 #ifdef FEAT_SEARCH_EXTRA 4091 if (!n_extra) 4092 { 4093 /* 4094 * Check for start/end of search pattern match. 4095 * After end, check for start/end of next match. 4096 * When another match, have to check for start again. 4097 * Watch out for matching an empty string! 4098 * Do this for 'search_hl' and the match list (ordered by 4099 * priority). 4100 */ 4101 v = (long)(ptr - line); 4102 cur = wp->w_match_head; 4103 shl_flag = FALSE; 4104 while (cur != NULL || shl_flag == FALSE) 4105 { 4106 if (shl_flag == FALSE 4107 && ((cur != NULL 4108 && cur->priority > SEARCH_HL_PRIORITY) 4109 || cur == NULL)) 4110 { 4111 shl = &search_hl; 4112 shl_flag = TRUE; 4113 } 4114 else 4115 shl = &cur->hl; 4116 if (cur != NULL) 4117 cur->pos.cur = 0; 4118 pos_inprogress = TRUE; 4119 while (shl->rm.regprog != NULL 4120 || (cur != NULL && pos_inprogress)) 4121 { 4122 if (shl->startcol != MAXCOL 4123 && v >= (long)shl->startcol 4124 && v < (long)shl->endcol) 4125 { 4126 int tmp_col = v + MB_PTR2LEN(ptr); 4127 4128 if (shl->endcol < tmp_col) 4129 shl->endcol = tmp_col; 4130 shl->attr_cur = shl->attr; 4131 #ifdef FEAT_CONCEAL 4132 // Match with the "Conceal" group results in hiding 4133 // the match. 4134 if (cur != NULL 4135 && shl != &search_hl 4136 && syn_name2id((char_u *)"Conceal") 4137 == cur->hlg_id) 4138 { 4139 has_match_conc = 4140 v == (long)shl->startcol ? 2 : 1; 4141 match_conc = cur->conceal_char; 4142 } 4143 else 4144 has_match_conc = match_conc = 0; 4145 #endif 4146 } 4147 else if (v == (long)shl->endcol) 4148 { 4149 shl->attr_cur = 0; 4150 next_search_hl(wp, shl, lnum, (colnr_T)v, 4151 shl == &search_hl ? NULL : cur); 4152 pos_inprogress = cur == NULL || cur->pos.cur == 0 4153 ? FALSE : TRUE; 4154 4155 /* Need to get the line again, a multi-line regexp 4156 * may have made it invalid. */ 4157 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 4158 ptr = line + v; 4159 4160 if (shl->lnum == lnum) 4161 { 4162 shl->startcol = shl->rm.startpos[0].col; 4163 if (shl->rm.endpos[0].lnum == 0) 4164 shl->endcol = shl->rm.endpos[0].col; 4165 else 4166 shl->endcol = MAXCOL; 4167 4168 if (shl->startcol == shl->endcol) 4169 { 4170 /* highlight empty match, try again after 4171 * it */ 4172 if (has_mbyte) 4173 shl->endcol += (*mb_ptr2len)(line 4174 + shl->endcol); 4175 else 4176 ++shl->endcol; 4177 } 4178 4179 /* Loop to check if the match starts at the 4180 * current position */ 4181 continue; 4182 } 4183 } 4184 break; 4185 } 4186 if (shl != &search_hl && cur != NULL) 4187 cur = cur->next; 4188 } 4189 4190 /* Use attributes from match with highest priority among 4191 * 'search_hl' and the match list. */ 4192 search_attr = search_hl.attr_cur; 4193 cur = wp->w_match_head; 4194 shl_flag = FALSE; 4195 while (cur != NULL || shl_flag == FALSE) 4196 { 4197 if (shl_flag == FALSE 4198 && ((cur != NULL 4199 && cur->priority > SEARCH_HL_PRIORITY) 4200 || cur == NULL)) 4201 { 4202 shl = &search_hl; 4203 shl_flag = TRUE; 4204 } 4205 else 4206 shl = &cur->hl; 4207 if (shl->attr_cur != 0) 4208 search_attr = shl->attr_cur; 4209 if (shl != &search_hl && cur != NULL) 4210 cur = cur->next; 4211 } 4212 /* Only highlight one character after the last column. */ 4213 if (*ptr == NUL && (did_line_attr >= 1 4214 || (wp->w_p_list && lcs_eol_one == -1))) 4215 search_attr = 0; 4216 } 4217 #endif 4218 4219 #ifdef FEAT_DIFF 4220 if (diff_hlf != (hlf_T)0) 4221 { 4222 if (diff_hlf == HLF_CHD && ptr - line >= change_start 4223 && n_extra == 0) 4224 diff_hlf = HLF_TXD; /* changed text */ 4225 if (diff_hlf == HLF_TXD && ptr - line > change_end 4226 && n_extra == 0) 4227 diff_hlf = HLF_CHD; /* changed line */ 4228 line_attr = HL_ATTR(diff_hlf); 4229 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) 4230 line_attr = hl_combine_attr(line_attr, HL_ATTR(HLF_CUL)); 4231 } 4232 #endif 4233 4234 #ifdef FEAT_TEXT_PROP 4235 if (text_props != NULL) 4236 { 4237 int pi; 4238 int bcol = (int)(ptr - line); 4239 4240 // Check if any active property ends. 4241 for (pi = 0; pi < text_props_active; ++pi) 4242 { 4243 int tpi = text_prop_idxs[pi]; 4244 4245 if (bcol >= text_props[tpi].tp_col - 1 4246 + text_props[tpi].tp_len) 4247 { 4248 if (pi + 1 < text_props_active) 4249 mch_memmove(text_prop_idxs + pi, 4250 text_prop_idxs + pi + 1, 4251 sizeof(int) 4252 * (text_props_active - (pi + 1))); 4253 --text_props_active; 4254 --pi; 4255 } 4256 } 4257 4258 // Add any text property that starts in this column. 4259 while (text_prop_next < text_prop_count 4260 && bcol >= text_props[text_prop_next].tp_col - 1) 4261 text_prop_idxs[text_props_active++] = text_prop_next++; 4262 4263 text_prop_attr = 0; 4264 if (text_props_active > 0) 4265 { 4266 // Sort the properties on priority and/or starting last. 4267 // Then combine the attributes, highest priority last. 4268 current_text_props = text_props; 4269 current_buf = wp->w_buffer; 4270 qsort((void *)text_prop_idxs, (size_t)text_props_active, 4271 sizeof(int), text_prop_compare); 4272 4273 for (pi = 0; pi < text_props_active; ++pi) 4274 { 4275 int tpi = text_prop_idxs[pi]; 4276 proptype_T *pt = text_prop_type_by_id(wp->w_buffer, text_props[tpi].tp_type); 4277 4278 if (pt != NULL) 4279 { 4280 int pt_attr = syn_id2attr(pt->pt_hl_id); 4281 4282 text_prop_type = pt; 4283 if (text_prop_attr == 0) 4284 text_prop_attr = pt_attr; 4285 else 4286 text_prop_attr = hl_combine_attr(text_prop_attr, pt_attr); 4287 } 4288 } 4289 } 4290 } 4291 #endif 4292 4293 /* Decide which of the highlight attributes to use. */ 4294 attr_pri = TRUE; 4295 #ifdef LINE_ATTR 4296 if (area_attr != 0) 4297 char_attr = hl_combine_attr(line_attr, area_attr); 4298 else if (search_attr != 0) 4299 char_attr = hl_combine_attr(line_attr, search_attr); 4300 /* Use line_attr when not in the Visual or 'incsearch' area 4301 * (area_attr may be 0 when "noinvcur" is set). */ 4302 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL) 4303 || vcol < fromcol || vcol_prev < fromcol_prev 4304 || vcol >= tocol)) 4305 char_attr = line_attr; 4306 #else 4307 if (area_attr != 0) 4308 char_attr = area_attr; 4309 else if (search_attr != 0) 4310 char_attr = search_attr; 4311 #endif 4312 else 4313 { 4314 attr_pri = FALSE; 4315 #ifdef FEAT_TEXT_PROP 4316 if (text_prop_type != NULL) 4317 char_attr = text_prop_attr; 4318 else 4319 #endif 4320 #ifdef FEAT_SYN_HL 4321 if (has_syntax) 4322 char_attr = syntax_attr; 4323 else 4324 #endif 4325 char_attr = 0; 4326 } 4327 } 4328 4329 /* 4330 * Get the next character to put on the screen. 4331 */ 4332 /* 4333 * The "p_extra" points to the extra stuff that is inserted to 4334 * represent special characters (non-printable stuff) and other 4335 * things. When all characters are the same, c_extra is used. 4336 * If c_final is set, it will compulsorily be used at the end. 4337 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past 4338 * "p_extra[n_extra]". 4339 * For the '$' of the 'list' option, n_extra == 1, p_extra == "". 4340 */ 4341 if (n_extra > 0) 4342 { 4343 if (c_extra != NUL || (n_extra == 1 && c_final != NUL)) 4344 { 4345 c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra; 4346 mb_c = c; /* doesn't handle non-utf-8 multi-byte! */ 4347 if (enc_utf8 && utf_char2len(c) > 1) 4348 { 4349 mb_utf8 = TRUE; 4350 u8cc[0] = 0; 4351 c = 0xc0; 4352 } 4353 else 4354 mb_utf8 = FALSE; 4355 } 4356 else 4357 { 4358 c = *p_extra; 4359 if (has_mbyte) 4360 { 4361 mb_c = c; 4362 if (enc_utf8) 4363 { 4364 /* If the UTF-8 character is more than one byte: 4365 * Decode it into "mb_c". */ 4366 mb_l = utfc_ptr2len(p_extra); 4367 mb_utf8 = FALSE; 4368 if (mb_l > n_extra) 4369 mb_l = 1; 4370 else if (mb_l > 1) 4371 { 4372 mb_c = utfc_ptr2char(p_extra, u8cc); 4373 mb_utf8 = TRUE; 4374 c = 0xc0; 4375 } 4376 } 4377 else 4378 { 4379 /* if this is a DBCS character, put it in "mb_c" */ 4380 mb_l = MB_BYTE2LEN(c); 4381 if (mb_l >= n_extra) 4382 mb_l = 1; 4383 else if (mb_l > 1) 4384 mb_c = (c << 8) + p_extra[1]; 4385 } 4386 if (mb_l == 0) /* at the NUL at end-of-line */ 4387 mb_l = 1; 4388 4389 /* If a double-width char doesn't fit display a '>' in the 4390 * last column. */ 4391 if (( 4392 # ifdef FEAT_RIGHTLEFT 4393 wp->w_p_rl ? (col <= 0) : 4394 # endif 4395 (col >= wp->w_width - 1)) 4396 && (*mb_char2cells)(mb_c) == 2) 4397 { 4398 c = '>'; 4399 mb_c = c; 4400 mb_l = 1; 4401 mb_utf8 = FALSE; 4402 multi_attr = HL_ATTR(HLF_AT); 4403 /* put the pointer back to output the double-width 4404 * character at the start of the next line. */ 4405 ++n_extra; 4406 --p_extra; 4407 } 4408 else 4409 { 4410 n_extra -= mb_l - 1; 4411 p_extra += mb_l - 1; 4412 } 4413 } 4414 ++p_extra; 4415 } 4416 --n_extra; 4417 } 4418 else 4419 { 4420 #ifdef FEAT_LINEBREAK 4421 int c0; 4422 #endif 4423 4424 if (p_extra_free != NULL) 4425 VIM_CLEAR(p_extra_free); 4426 /* 4427 * Get a character from the line itself. 4428 */ 4429 c = *ptr; 4430 #ifdef FEAT_LINEBREAK 4431 c0 = *ptr; 4432 #endif 4433 if (has_mbyte) 4434 { 4435 mb_c = c; 4436 if (enc_utf8) 4437 { 4438 /* If the UTF-8 character is more than one byte: Decode it 4439 * into "mb_c". */ 4440 mb_l = utfc_ptr2len(ptr); 4441 mb_utf8 = FALSE; 4442 if (mb_l > 1) 4443 { 4444 mb_c = utfc_ptr2char(ptr, u8cc); 4445 /* Overlong encoded ASCII or ASCII with composing char 4446 * is displayed normally, except a NUL. */ 4447 if (mb_c < 0x80) 4448 { 4449 c = mb_c; 4450 #ifdef FEAT_LINEBREAK 4451 c0 = mb_c; 4452 #endif 4453 } 4454 mb_utf8 = TRUE; 4455 4456 /* At start of the line we can have a composing char. 4457 * Draw it as a space with a composing char. */ 4458 if (utf_iscomposing(mb_c)) 4459 { 4460 int i; 4461 4462 for (i = Screen_mco - 1; i > 0; --i) 4463 u8cc[i] = u8cc[i - 1]; 4464 u8cc[0] = mb_c; 4465 mb_c = ' '; 4466 } 4467 } 4468 4469 if ((mb_l == 1 && c >= 0x80) 4470 || (mb_l >= 1 && mb_c == 0) 4471 || (mb_l > 1 && (!vim_isprintc(mb_c)))) 4472 { 4473 /* 4474 * Illegal UTF-8 byte: display as <xx>. 4475 * Non-BMP character : display as ? or fullwidth ?. 4476 */ 4477 transchar_hex(extra, mb_c); 4478 # ifdef FEAT_RIGHTLEFT 4479 if (wp->w_p_rl) /* reverse */ 4480 rl_mirror(extra); 4481 # endif 4482 p_extra = extra; 4483 c = *p_extra; 4484 mb_c = mb_ptr2char_adv(&p_extra); 4485 mb_utf8 = (c >= 0x80); 4486 n_extra = (int)STRLEN(p_extra); 4487 c_extra = NUL; 4488 c_final = NUL; 4489 if (area_attr == 0 && search_attr == 0) 4490 { 4491 n_attr = n_extra + 1; 4492 extra_attr = HL_ATTR(HLF_8); 4493 saved_attr2 = char_attr; /* save current attr */ 4494 } 4495 } 4496 else if (mb_l == 0) /* at the NUL at end-of-line */ 4497 mb_l = 1; 4498 #ifdef FEAT_ARABIC 4499 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c)) 4500 { 4501 /* Do Arabic shaping. */ 4502 int pc, pc1, nc; 4503 int pcc[MAX_MCO]; 4504 4505 /* The idea of what is the previous and next 4506 * character depends on 'rightleft'. */ 4507 if (wp->w_p_rl) 4508 { 4509 pc = prev_c; 4510 pc1 = prev_c1; 4511 nc = utf_ptr2char(ptr + mb_l); 4512 prev_c1 = u8cc[0]; 4513 } 4514 else 4515 { 4516 pc = utfc_ptr2char(ptr + mb_l, pcc); 4517 nc = prev_c; 4518 pc1 = pcc[0]; 4519 } 4520 prev_c = mb_c; 4521 4522 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc); 4523 } 4524 else 4525 prev_c = mb_c; 4526 #endif 4527 } 4528 else /* enc_dbcs */ 4529 { 4530 mb_l = MB_BYTE2LEN(c); 4531 if (mb_l == 0) /* at the NUL at end-of-line */ 4532 mb_l = 1; 4533 else if (mb_l > 1) 4534 { 4535 /* We assume a second byte below 32 is illegal. 4536 * Hopefully this is OK for all double-byte encodings! 4537 */ 4538 if (ptr[1] >= 32) 4539 mb_c = (c << 8) + ptr[1]; 4540 else 4541 { 4542 if (ptr[1] == NUL) 4543 { 4544 /* head byte at end of line */ 4545 mb_l = 1; 4546 transchar_nonprint(extra, c); 4547 } 4548 else 4549 { 4550 /* illegal tail byte */ 4551 mb_l = 2; 4552 STRCPY(extra, "XX"); 4553 } 4554 p_extra = extra; 4555 n_extra = (int)STRLEN(extra) - 1; 4556 c_extra = NUL; 4557 c_final = NUL; 4558 c = *p_extra++; 4559 if (area_attr == 0 && search_attr == 0) 4560 { 4561 n_attr = n_extra + 1; 4562 extra_attr = HL_ATTR(HLF_8); 4563 saved_attr2 = char_attr; /* save current attr */ 4564 } 4565 mb_c = c; 4566 } 4567 } 4568 } 4569 /* If a double-width char doesn't fit display a '>' in the 4570 * last column; the character is displayed at the start of the 4571 * next line. */ 4572 if (( 4573 # ifdef FEAT_RIGHTLEFT 4574 wp->w_p_rl ? (col <= 0) : 4575 # endif 4576 (col >= wp->w_width - 1)) 4577 && (*mb_char2cells)(mb_c) == 2) 4578 { 4579 c = '>'; 4580 mb_c = c; 4581 mb_utf8 = FALSE; 4582 mb_l = 1; 4583 multi_attr = HL_ATTR(HLF_AT); 4584 /* Put pointer back so that the character will be 4585 * displayed at the start of the next line. */ 4586 --ptr; 4587 } 4588 else if (*ptr != NUL) 4589 ptr += mb_l - 1; 4590 4591 /* If a double-width char doesn't fit at the left side display 4592 * a '<' in the first column. Don't do this for unprintable 4593 * characters. */ 4594 if (n_skip > 0 && mb_l > 1 && n_extra == 0) 4595 { 4596 n_extra = 1; 4597 c_extra = MB_FILLER_CHAR; 4598 c_final = NUL; 4599 c = ' '; 4600 if (area_attr == 0 && search_attr == 0) 4601 { 4602 n_attr = n_extra + 1; 4603 extra_attr = HL_ATTR(HLF_AT); 4604 saved_attr2 = char_attr; /* save current attr */ 4605 } 4606 mb_c = c; 4607 mb_utf8 = FALSE; 4608 mb_l = 1; 4609 } 4610 4611 } 4612 ++ptr; 4613 4614 if (extra_check) 4615 { 4616 #ifdef FEAT_SPELL 4617 int can_spell = TRUE; 4618 #endif 4619 4620 #ifdef FEAT_TERMINAL 4621 if (get_term_attr) 4622 { 4623 syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol); 4624 4625 if (!attr_pri) 4626 char_attr = syntax_attr; 4627 else 4628 char_attr = hl_combine_attr(syntax_attr, char_attr); 4629 } 4630 #endif 4631 4632 #ifdef FEAT_SYN_HL 4633 // Get syntax attribute, unless still at the start of the line 4634 // (double-wide char that doesn't fit). 4635 v = (long)(ptr - line); 4636 if (has_syntax && v > 0) 4637 { 4638 /* Get the syntax attribute for the character. If there 4639 * is an error, disable syntax highlighting. */ 4640 save_did_emsg = did_emsg; 4641 did_emsg = FALSE; 4642 4643 syntax_attr = get_syntax_attr((colnr_T)v - 1, 4644 # ifdef FEAT_SPELL 4645 has_spell ? &can_spell : 4646 # endif 4647 NULL, FALSE); 4648 4649 if (did_emsg) 4650 { 4651 wp->w_s->b_syn_error = TRUE; 4652 has_syntax = FALSE; 4653 } 4654 else 4655 did_emsg = save_did_emsg; 4656 #ifdef SYN_TIME_LIMIT 4657 if (wp->w_s->b_syn_slow) 4658 has_syntax = FALSE; 4659 #endif 4660 4661 /* Need to get the line again, a multi-line regexp may 4662 * have made it invalid. */ 4663 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 4664 ptr = line + v; 4665 4666 # ifdef FEAT_TEXT_PROP 4667 // Text properties overrule syntax highlighting. 4668 if (text_prop_attr == 0) 4669 #endif 4670 { 4671 if (!attr_pri) 4672 char_attr = syntax_attr; 4673 else 4674 char_attr = hl_combine_attr(syntax_attr, char_attr); 4675 } 4676 # ifdef FEAT_CONCEAL 4677 /* no concealing past the end of the line, it interferes 4678 * with line highlighting */ 4679 if (c == NUL) 4680 syntax_flags = 0; 4681 else 4682 syntax_flags = get_syntax_info(&syntax_seqnr); 4683 # endif 4684 } 4685 #endif 4686 4687 #ifdef FEAT_SPELL 4688 /* Check spelling (unless at the end of the line). 4689 * Only do this when there is no syntax highlighting, the 4690 * @Spell cluster is not used or the current syntax item 4691 * contains the @Spell cluster. */ 4692 if (has_spell && v >= word_end && v > cur_checked_col) 4693 { 4694 spell_attr = 0; 4695 if (c != 0 && ( 4696 # ifdef FEAT_SYN_HL 4697 !has_syntax || 4698 # endif 4699 can_spell)) 4700 { 4701 char_u *prev_ptr, *p; 4702 int len; 4703 hlf_T spell_hlf = HLF_COUNT; 4704 if (has_mbyte) 4705 { 4706 prev_ptr = ptr - mb_l; 4707 v -= mb_l - 1; 4708 } 4709 else 4710 prev_ptr = ptr - 1; 4711 4712 /* Use nextline[] if possible, it has the start of the 4713 * next line concatenated. */ 4714 if ((prev_ptr - line) - nextlinecol >= 0) 4715 p = nextline + (prev_ptr - line) - nextlinecol; 4716 else 4717 p = prev_ptr; 4718 cap_col -= (int)(prev_ptr - line); 4719 len = spell_check(wp, p, &spell_hlf, &cap_col, 4720 nochange); 4721 word_end = v + len; 4722 4723 /* In Insert mode only highlight a word that 4724 * doesn't touch the cursor. */ 4725 if (spell_hlf != HLF_COUNT 4726 && (State & INSERT) != 0 4727 && wp->w_cursor.lnum == lnum 4728 && wp->w_cursor.col >= 4729 (colnr_T)(prev_ptr - line) 4730 && wp->w_cursor.col < (colnr_T)word_end) 4731 { 4732 spell_hlf = HLF_COUNT; 4733 spell_redraw_lnum = lnum; 4734 } 4735 4736 if (spell_hlf == HLF_COUNT && p != prev_ptr 4737 && (p - nextline) + len > nextline_idx) 4738 { 4739 /* Remember that the good word continues at the 4740 * start of the next line. */ 4741 checked_lnum = lnum + 1; 4742 checked_col = (int)((p - nextline) + len - nextline_idx); 4743 } 4744 4745 /* Turn index into actual attributes. */ 4746 if (spell_hlf != HLF_COUNT) 4747 spell_attr = highlight_attr[spell_hlf]; 4748 4749 if (cap_col > 0) 4750 { 4751 if (p != prev_ptr 4752 && (p - nextline) + cap_col >= nextline_idx) 4753 { 4754 /* Remember that the word in the next line 4755 * must start with a capital. */ 4756 capcol_lnum = lnum + 1; 4757 cap_col = (int)((p - nextline) + cap_col 4758 - nextline_idx); 4759 } 4760 else 4761 /* Compute the actual column. */ 4762 cap_col += (int)(prev_ptr - line); 4763 } 4764 } 4765 } 4766 if (spell_attr != 0) 4767 { 4768 if (!attr_pri) 4769 char_attr = hl_combine_attr(char_attr, spell_attr); 4770 else 4771 char_attr = hl_combine_attr(spell_attr, char_attr); 4772 } 4773 #endif 4774 #ifdef FEAT_LINEBREAK 4775 /* 4776 * Found last space before word: check for line break. 4777 */ 4778 if (wp->w_p_lbr && c0 == c 4779 && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr)) 4780 { 4781 int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0; 4782 char_u *p = ptr - (mb_off + 1); 4783 4784 /* TODO: is passing p for start of the line OK? */ 4785 n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, 4786 NULL) - 1; 4787 if (c == TAB && n_extra + col > wp->w_width) 4788 # ifdef FEAT_VARTABS 4789 n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts, 4790 wp->w_buffer->b_p_vts_array) - 1; 4791 # else 4792 n_extra = (int)wp->w_buffer->b_p_ts 4793 - vcol % (int)wp->w_buffer->b_p_ts - 1; 4794 # endif 4795 4796 c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; 4797 c_final = NUL; 4798 if (VIM_ISWHITE(c)) 4799 { 4800 #ifdef FEAT_CONCEAL 4801 if (c == TAB) 4802 /* See "Tab alignment" below. */ 4803 FIX_FOR_BOGUSCOLS; 4804 #endif 4805 if (!wp->w_p_list) 4806 c = ' '; 4807 } 4808 } 4809 #endif 4810 4811 // 'list': Change char 160 to lcs_nbsp and space to lcs_space. 4812 // But not when the character is followed by a composing 4813 // character (use mb_l to check that). 4814 if (wp->w_p_list 4815 && ((((c == 160 && mb_l == 1) 4816 || (mb_utf8 4817 && ((mb_c == 160 && mb_l == 2) 4818 || (mb_c == 0x202f && mb_l == 3)))) 4819 && lcs_nbsp) 4820 || (c == ' ' 4821 && mb_l == 1 4822 && lcs_space 4823 && ptr - line <= trailcol))) 4824 { 4825 c = (c == ' ') ? lcs_space : lcs_nbsp; 4826 if (area_attr == 0 && search_attr == 0) 4827 { 4828 n_attr = 1; 4829 extra_attr = HL_ATTR(HLF_8); 4830 saved_attr2 = char_attr; /* save current attr */ 4831 } 4832 mb_c = c; 4833 if (enc_utf8 && utf_char2len(c) > 1) 4834 { 4835 mb_utf8 = TRUE; 4836 u8cc[0] = 0; 4837 c = 0xc0; 4838 } 4839 else 4840 mb_utf8 = FALSE; 4841 } 4842 4843 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') 4844 { 4845 c = lcs_trail; 4846 if (!attr_pri) 4847 { 4848 n_attr = 1; 4849 extra_attr = HL_ATTR(HLF_8); 4850 saved_attr2 = char_attr; /* save current attr */ 4851 } 4852 mb_c = c; 4853 if (enc_utf8 && utf_char2len(c) > 1) 4854 { 4855 mb_utf8 = TRUE; 4856 u8cc[0] = 0; 4857 c = 0xc0; 4858 } 4859 else 4860 mb_utf8 = FALSE; 4861 } 4862 } 4863 4864 /* 4865 * Handling of non-printable characters. 4866 */ 4867 if (!vim_isprintc(c)) 4868 { 4869 /* 4870 * when getting a character from the file, we may have to 4871 * turn it into something else on the way to putting it 4872 * into "ScreenLines". 4873 */ 4874 if (c == TAB && (!wp->w_p_list || lcs_tab1)) 4875 { 4876 int tab_len = 0; 4877 long vcol_adjusted = vcol; /* removed showbreak length */ 4878 #ifdef FEAT_LINEBREAK 4879 /* only adjust the tab_len, when at the first column 4880 * after the showbreak value was drawn */ 4881 if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) 4882 vcol_adjusted = vcol - MB_CHARLEN(p_sbr); 4883 #endif 4884 /* tab amount depends on current column */ 4885 #ifdef FEAT_VARTABS 4886 tab_len = tabstop_padding(vcol_adjusted, 4887 wp->w_buffer->b_p_ts, 4888 wp->w_buffer->b_p_vts_array) - 1; 4889 #else 4890 tab_len = (int)wp->w_buffer->b_p_ts 4891 - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1; 4892 #endif 4893 4894 #ifdef FEAT_LINEBREAK 4895 if (!wp->w_p_lbr || !wp->w_p_list) 4896 #endif 4897 /* tab amount depends on current column */ 4898 n_extra = tab_len; 4899 #ifdef FEAT_LINEBREAK 4900 else 4901 { 4902 char_u *p; 4903 int len; 4904 int i; 4905 int saved_nextra = n_extra; 4906 4907 #ifdef FEAT_CONCEAL 4908 if (vcol_off > 0) 4909 /* there are characters to conceal */ 4910 tab_len += vcol_off; 4911 /* boguscols before FIX_FOR_BOGUSCOLS macro from above 4912 */ 4913 if (wp->w_p_list && lcs_tab1 && old_boguscols > 0 4914 && n_extra > tab_len) 4915 tab_len += n_extra - tab_len; 4916 #endif 4917 4918 /* if n_extra > 0, it gives the number of chars, to 4919 * use for a tab, else we need to calculate the width 4920 * for a tab */ 4921 len = (tab_len * mb_char2len(lcs_tab2)); 4922 if (n_extra > 0) 4923 len += n_extra - tab_len; 4924 c = lcs_tab1; 4925 p = alloc((unsigned)(len + 1)); 4926 vim_memset(p, ' ', len); 4927 p[len] = NUL; 4928 vim_free(p_extra_free); 4929 p_extra_free = p; 4930 for (i = 0; i < tab_len; i++) 4931 { 4932 if (*p == NUL) 4933 { 4934 tab_len = i; 4935 break; 4936 } 4937 mb_char2bytes(lcs_tab2, p); 4938 p += mb_char2len(lcs_tab2); 4939 n_extra += mb_char2len(lcs_tab2) 4940 - (saved_nextra > 0 ? 1 : 0); 4941 } 4942 p_extra = p_extra_free; 4943 #ifdef FEAT_CONCEAL 4944 /* n_extra will be increased by FIX_FOX_BOGUSCOLS 4945 * macro below, so need to adjust for that here */ 4946 if (vcol_off > 0) 4947 n_extra -= vcol_off; 4948 #endif 4949 } 4950 #endif 4951 #ifdef FEAT_CONCEAL 4952 { 4953 int vc_saved = vcol_off; 4954 4955 /* Tab alignment should be identical regardless of 4956 * 'conceallevel' value. So tab compensates of all 4957 * previous concealed characters, and thus resets 4958 * vcol_off and boguscols accumulated so far in the 4959 * line. Note that the tab can be longer than 4960 * 'tabstop' when there are concealed characters. */ 4961 FIX_FOR_BOGUSCOLS; 4962 4963 /* Make sure, the highlighting for the tab char will be 4964 * correctly set further below (effectively reverts the 4965 * FIX_FOR_BOGSUCOLS macro */ 4966 if (n_extra == tab_len + vc_saved && wp->w_p_list 4967 && lcs_tab1) 4968 tab_len += vc_saved; 4969 } 4970 #endif 4971 mb_utf8 = FALSE; /* don't draw as UTF-8 */ 4972 if (wp->w_p_list) 4973 { 4974 c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1; 4975 #ifdef FEAT_LINEBREAK 4976 if (wp->w_p_lbr) 4977 c_extra = NUL; /* using p_extra from above */ 4978 else 4979 #endif 4980 c_extra = lcs_tab2; 4981 c_final = lcs_tab3; 4982 n_attr = tab_len + 1; 4983 extra_attr = HL_ATTR(HLF_8); 4984 saved_attr2 = char_attr; /* save current attr */ 4985 mb_c = c; 4986 if (enc_utf8 && utf_char2len(c) > 1) 4987 { 4988 mb_utf8 = TRUE; 4989 u8cc[0] = 0; 4990 c = 0xc0; 4991 } 4992 } 4993 else 4994 { 4995 c_final = NUL; 4996 c_extra = ' '; 4997 c = ' '; 4998 } 4999 } 5000 else if (c == NUL 5001 && (wp->w_p_list 5002 || ((fromcol >= 0 || fromcol_prev >= 0) 5003 && tocol > vcol 5004 && VIsual_mode != Ctrl_V 5005 && ( 5006 # ifdef FEAT_RIGHTLEFT 5007 wp->w_p_rl ? (col >= 0) : 5008 # endif 5009 (col < wp->w_width)) 5010 && !(noinvcur 5011 && lnum == wp->w_cursor.lnum 5012 && (colnr_T)vcol == wp->w_virtcol))) 5013 && lcs_eol_one > 0) 5014 { 5015 /* Display a '$' after the line or highlight an extra 5016 * character if the line break is included. */ 5017 #if defined(FEAT_DIFF) || defined(LINE_ATTR) 5018 /* For a diff line the highlighting continues after the 5019 * "$". */ 5020 if ( 5021 # ifdef FEAT_DIFF 5022 diff_hlf == (hlf_T)0 5023 # ifdef LINE_ATTR 5024 && 5025 # endif 5026 # endif 5027 # ifdef LINE_ATTR 5028 line_attr == 0 5029 # endif 5030 ) 5031 #endif 5032 { 5033 /* In virtualedit, visual selections may extend 5034 * beyond end of line. */ 5035 if (area_highlighting && virtual_active() 5036 && tocol != MAXCOL && vcol < tocol) 5037 n_extra = 0; 5038 else 5039 { 5040 p_extra = at_end_str; 5041 n_extra = 1; 5042 c_extra = NUL; 5043 c_final = NUL; 5044 } 5045 } 5046 if (wp->w_p_list && lcs_eol > 0) 5047 c = lcs_eol; 5048 else 5049 c = ' '; 5050 lcs_eol_one = -1; 5051 --ptr; /* put it back at the NUL */ 5052 if (!attr_pri) 5053 { 5054 extra_attr = HL_ATTR(HLF_AT); 5055 n_attr = 1; 5056 } 5057 mb_c = c; 5058 if (enc_utf8 && utf_char2len(c) > 1) 5059 { 5060 mb_utf8 = TRUE; 5061 u8cc[0] = 0; 5062 c = 0xc0; 5063 } 5064 else 5065 mb_utf8 = FALSE; /* don't draw as UTF-8 */ 5066 } 5067 else if (c != NUL) 5068 { 5069 p_extra = transchar(c); 5070 if (n_extra == 0) 5071 n_extra = byte2cells(c) - 1; 5072 #ifdef FEAT_RIGHTLEFT 5073 if ((dy_flags & DY_UHEX) && wp->w_p_rl) 5074 rl_mirror(p_extra); /* reverse "<12>" */ 5075 #endif 5076 c_extra = NUL; 5077 c_final = NUL; 5078 #ifdef FEAT_LINEBREAK 5079 if (wp->w_p_lbr) 5080 { 5081 char_u *p; 5082 5083 c = *p_extra; 5084 p = alloc((unsigned)n_extra + 1); 5085 vim_memset(p, ' ', n_extra); 5086 STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1); 5087 p[n_extra] = NUL; 5088 vim_free(p_extra_free); 5089 p_extra_free = p_extra = p; 5090 } 5091 else 5092 #endif 5093 { 5094 n_extra = byte2cells(c) - 1; 5095 c = *p_extra++; 5096 } 5097 if (!attr_pri) 5098 { 5099 n_attr = n_extra + 1; 5100 extra_attr = HL_ATTR(HLF_8); 5101 saved_attr2 = char_attr; /* save current attr */ 5102 } 5103 mb_utf8 = FALSE; /* don't draw as UTF-8 */ 5104 } 5105 else if (VIsual_active 5106 && (VIsual_mode == Ctrl_V 5107 || VIsual_mode == 'v') 5108 && virtual_active() 5109 && tocol != MAXCOL 5110 && vcol < tocol 5111 && ( 5112 #ifdef FEAT_RIGHTLEFT 5113 wp->w_p_rl ? (col >= 0) : 5114 #endif 5115 (col < wp->w_width))) 5116 { 5117 c = ' '; 5118 --ptr; /* put it back at the NUL */ 5119 } 5120 #if defined(LINE_ATTR) 5121 else if (( 5122 # ifdef FEAT_DIFF 5123 diff_hlf != (hlf_T)0 || 5124 # endif 5125 # ifdef FEAT_TERMINAL 5126 term_attr != 0 || 5127 # endif 5128 line_attr != 0 5129 ) && ( 5130 # ifdef FEAT_RIGHTLEFT 5131 wp->w_p_rl ? (col >= 0) : 5132 # endif 5133 (col 5134 # ifdef FEAT_CONCEAL 5135 - boguscols 5136 # endif 5137 < wp->w_width))) 5138 { 5139 /* Highlight until the right side of the window */ 5140 c = ' '; 5141 --ptr; /* put it back at the NUL */ 5142 5143 /* Remember we do the char for line highlighting. */ 5144 ++did_line_attr; 5145 5146 /* don't do search HL for the rest of the line */ 5147 if (line_attr != 0 && char_attr == search_attr 5148 && (did_line_attr > 1 5149 || (wp->w_p_list && lcs_eol > 0))) 5150 char_attr = line_attr; 5151 # ifdef FEAT_DIFF 5152 if (diff_hlf == HLF_TXD) 5153 { 5154 diff_hlf = HLF_CHD; 5155 if (attr == 0 || char_attr != attr) 5156 { 5157 char_attr = HL_ATTR(diff_hlf); 5158 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) 5159 char_attr = hl_combine_attr(char_attr, 5160 HL_ATTR(HLF_CUL)); 5161 } 5162 } 5163 # endif 5164 # ifdef FEAT_TERMINAL 5165 if (term_attr != 0) 5166 { 5167 char_attr = term_attr; 5168 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) 5169 char_attr = hl_combine_attr(char_attr, 5170 HL_ATTR(HLF_CUL)); 5171 } 5172 # endif 5173 } 5174 #endif 5175 } 5176 5177 #ifdef FEAT_CONCEAL 5178 if ( wp->w_p_cole > 0 5179 && (wp != curwin || lnum != wp->w_cursor.lnum || 5180 conceal_cursor_line(wp)) 5181 && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0) 5182 && !(lnum_in_visual_area 5183 && vim_strchr(wp->w_p_cocu, 'v') == NULL)) 5184 { 5185 char_attr = conceal_attr; 5186 if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1) 5187 && (syn_get_sub_char() != NUL || match_conc 5188 || wp->w_p_cole == 1) 5189 && wp->w_p_cole != 3) 5190 { 5191 /* First time at this concealed item: display one 5192 * character. */ 5193 if (match_conc) 5194 c = match_conc; 5195 else if (syn_get_sub_char() != NUL) 5196 c = syn_get_sub_char(); 5197 else if (lcs_conceal != NUL) 5198 c = lcs_conceal; 5199 else 5200 c = ' '; 5201 5202 prev_syntax_id = syntax_seqnr; 5203 5204 if (n_extra > 0) 5205 vcol_off += n_extra; 5206 vcol += n_extra; 5207 if (wp->w_p_wrap && n_extra > 0) 5208 { 5209 # ifdef FEAT_RIGHTLEFT 5210 if (wp->w_p_rl) 5211 { 5212 col -= n_extra; 5213 boguscols -= n_extra; 5214 } 5215 else 5216 # endif 5217 { 5218 boguscols += n_extra; 5219 col += n_extra; 5220 } 5221 } 5222 n_extra = 0; 5223 n_attr = 0; 5224 } 5225 else if (n_skip == 0) 5226 { 5227 is_concealing = TRUE; 5228 n_skip = 1; 5229 } 5230 mb_c = c; 5231 if (enc_utf8 && utf_char2len(c) > 1) 5232 { 5233 mb_utf8 = TRUE; 5234 u8cc[0] = 0; 5235 c = 0xc0; 5236 } 5237 else 5238 mb_utf8 = FALSE; /* don't draw as UTF-8 */ 5239 } 5240 else 5241 { 5242 prev_syntax_id = 0; 5243 is_concealing = FALSE; 5244 } 5245 #endif /* FEAT_CONCEAL */ 5246 } 5247 5248 #ifdef FEAT_CONCEAL 5249 /* In the cursor line and we may be concealing characters: correct 5250 * the cursor column when we reach its position. */ 5251 if (!did_wcol && draw_state == WL_LINE 5252 && wp == curwin && lnum == wp->w_cursor.lnum 5253 && conceal_cursor_line(wp) 5254 && (int)wp->w_virtcol <= vcol + n_skip) 5255 { 5256 # ifdef FEAT_RIGHTLEFT 5257 if (wp->w_p_rl) 5258 wp->w_wcol = wp->w_width - col + boguscols - 1; 5259 else 5260 # endif 5261 wp->w_wcol = col - boguscols; 5262 wp->w_wrow = row; 5263 did_wcol = TRUE; 5264 } 5265 #endif 5266 5267 /* Don't override visual selection highlighting. */ 5268 if (n_attr > 0 5269 && draw_state == WL_LINE 5270 && !attr_pri) 5271 char_attr = extra_attr; 5272 5273 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 5274 /* XIM don't send preedit_start and preedit_end, but they send 5275 * preedit_changed and commit. Thus Vim can't set "im_is_active", use 5276 * im_is_preediting() here. */ 5277 if (p_imst == IM_ON_THE_SPOT 5278 && xic != NULL 5279 && lnum == wp->w_cursor.lnum 5280 && (State & INSERT) 5281 && !p_imdisable 5282 && im_is_preediting() 5283 && draw_state == WL_LINE) 5284 { 5285 colnr_T tcol; 5286 5287 if (preedit_end_col == MAXCOL) 5288 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL); 5289 else 5290 tcol = preedit_end_col; 5291 if ((long)preedit_start_col <= vcol && vcol < (long)tcol) 5292 { 5293 if (feedback_old_attr < 0) 5294 { 5295 feedback_col = 0; 5296 feedback_old_attr = char_attr; 5297 } 5298 char_attr = im_get_feedback_attr(feedback_col); 5299 if (char_attr < 0) 5300 char_attr = feedback_old_attr; 5301 feedback_col++; 5302 } 5303 else if (feedback_old_attr >= 0) 5304 { 5305 char_attr = feedback_old_attr; 5306 feedback_old_attr = -1; 5307 feedback_col = 0; 5308 } 5309 } 5310 #endif 5311 /* 5312 * Handle the case where we are in column 0 but not on the first 5313 * character of the line and the user wants us to show us a 5314 * special character (via 'listchars' option "precedes:<char>". 5315 */ 5316 if (lcs_prec_todo != NUL 5317 && wp->w_p_list 5318 && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0) 5319 #ifdef FEAT_DIFF 5320 && filler_todo <= 0 5321 #endif 5322 && draw_state > WL_NR 5323 && c != NUL) 5324 { 5325 c = lcs_prec; 5326 lcs_prec_todo = NUL; 5327 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) 5328 { 5329 /* Double-width character being overwritten by the "precedes" 5330 * character, need to fill up half the character. */ 5331 c_extra = MB_FILLER_CHAR; 5332 c_final = NUL; 5333 n_extra = 1; 5334 n_attr = 2; 5335 extra_attr = HL_ATTR(HLF_AT); 5336 } 5337 mb_c = c; 5338 if (enc_utf8 && utf_char2len(c) > 1) 5339 { 5340 mb_utf8 = TRUE; 5341 u8cc[0] = 0; 5342 c = 0xc0; 5343 } 5344 else 5345 mb_utf8 = FALSE; /* don't draw as UTF-8 */ 5346 if (!attr_pri) 5347 { 5348 saved_attr3 = char_attr; /* save current attr */ 5349 char_attr = HL_ATTR(HLF_AT); /* later copied to char_attr */ 5350 n_attr3 = 1; 5351 } 5352 } 5353 5354 /* 5355 * At end of the text line or just after the last character. 5356 */ 5357 if (c == NUL 5358 #if defined(LINE_ATTR) 5359 || did_line_attr == 1 5360 #endif 5361 ) 5362 { 5363 #ifdef FEAT_SEARCH_EXTRA 5364 long prevcol = (long)(ptr - line) - (c == NUL); 5365 5366 /* we're not really at that column when skipping some text */ 5367 if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) 5368 ++prevcol; 5369 #endif 5370 5371 /* Invert at least one char, used for Visual and empty line or 5372 * highlight match at end of line. If it's beyond the last 5373 * char on the screen, just overwrite that one (tricky!) Not 5374 * needed when a '$' was displayed for 'list'. */ 5375 #ifdef FEAT_SEARCH_EXTRA 5376 prevcol_hl_flag = FALSE; 5377 if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol) 5378 prevcol_hl_flag = TRUE; 5379 else 5380 { 5381 cur = wp->w_match_head; 5382 while (cur != NULL) 5383 { 5384 if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol) 5385 { 5386 prevcol_hl_flag = TRUE; 5387 break; 5388 } 5389 cur = cur->next; 5390 } 5391 } 5392 #endif 5393 if (lcs_eol == lcs_eol_one 5394 && ((area_attr != 0 && vcol == fromcol 5395 && (VIsual_mode != Ctrl_V 5396 || lnum == VIsual.lnum 5397 || lnum == curwin->w_cursor.lnum) 5398 && c == NUL) 5399 #ifdef FEAT_SEARCH_EXTRA 5400 /* highlight 'hlsearch' match at end of line */ 5401 || (prevcol_hl_flag == TRUE 5402 # ifdef FEAT_SYN_HL 5403 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum 5404 && !(wp == curwin && VIsual_active)) 5405 # endif 5406 # ifdef FEAT_DIFF 5407 && diff_hlf == (hlf_T)0 5408 # endif 5409 # if defined(LINE_ATTR) 5410 && did_line_attr <= 1 5411 # endif 5412 ) 5413 #endif 5414 )) 5415 { 5416 int n = 0; 5417 5418 #ifdef FEAT_RIGHTLEFT 5419 if (wp->w_p_rl) 5420 { 5421 if (col < 0) 5422 n = 1; 5423 } 5424 else 5425 #endif 5426 { 5427 if (col >= wp->w_width) 5428 n = -1; 5429 } 5430 if (n != 0) 5431 { 5432 /* At the window boundary, highlight the last character 5433 * instead (better than nothing). */ 5434 off += n; 5435 col += n; 5436 } 5437 else 5438 { 5439 /* Add a blank character to highlight. */ 5440 ScreenLines[off] = ' '; 5441 if (enc_utf8) 5442 ScreenLinesUC[off] = 0; 5443 } 5444 #ifdef FEAT_SEARCH_EXTRA 5445 if (area_attr == 0) 5446 { 5447 /* Use attributes from match with highest priority among 5448 * 'search_hl' and the match list. */ 5449 char_attr = search_hl.attr; 5450 cur = wp->w_match_head; 5451 shl_flag = FALSE; 5452 while (cur != NULL || shl_flag == FALSE) 5453 { 5454 if (shl_flag == FALSE 5455 && ((cur != NULL 5456 && cur->priority > SEARCH_HL_PRIORITY) 5457 || cur == NULL)) 5458 { 5459 shl = &search_hl; 5460 shl_flag = TRUE; 5461 } 5462 else 5463 shl = &cur->hl; 5464 if ((ptr - line) - 1 == (long)shl->startcol 5465 && (shl == &search_hl || !shl->is_addpos)) 5466 char_attr = shl->attr; 5467 if (shl != &search_hl && cur != NULL) 5468 cur = cur->next; 5469 } 5470 } 5471 #endif 5472 ScreenAttrs[off] = char_attr; 5473 #ifdef FEAT_RIGHTLEFT 5474 if (wp->w_p_rl) 5475 { 5476 --col; 5477 --off; 5478 } 5479 else 5480 #endif 5481 { 5482 ++col; 5483 ++off; 5484 } 5485 ++vcol; 5486 #ifdef FEAT_SYN_HL 5487 eol_hl_off = 1; 5488 #endif 5489 } 5490 } 5491 5492 /* 5493 * At end of the text line. 5494 */ 5495 if (c == NUL) 5496 { 5497 #ifdef FEAT_SYN_HL 5498 /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */ 5499 if (wp->w_p_wrap) 5500 v = wp->w_skipcol; 5501 else 5502 v = wp->w_leftcol; 5503 5504 /* check if line ends before left margin */ 5505 if (vcol < v + col - win_col_off(wp)) 5506 vcol = v + col - win_col_off(wp); 5507 #ifdef FEAT_CONCEAL 5508 // Get rid of the boguscols now, we want to draw until the right 5509 // edge for 'cursorcolumn'. 5510 col -= boguscols; 5511 boguscols = 0; 5512 #endif 5513 5514 if (draw_color_col) 5515 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); 5516 5517 if (((wp->w_p_cuc 5518 && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off 5519 && (int)wp->w_virtcol < 5520 wp->w_width * (row - startrow + 1) + v 5521 && lnum != wp->w_cursor.lnum) 5522 || draw_color_col) 5523 # ifdef FEAT_RIGHTLEFT 5524 && !wp->w_p_rl 5525 # endif 5526 ) 5527 { 5528 int rightmost_vcol = 0; 5529 int i; 5530 5531 if (wp->w_p_cuc) 5532 rightmost_vcol = wp->w_virtcol; 5533 if (draw_color_col) 5534 /* determine rightmost colorcolumn to possibly draw */ 5535 for (i = 0; color_cols[i] >= 0; ++i) 5536 if (rightmost_vcol < color_cols[i]) 5537 rightmost_vcol = color_cols[i]; 5538 5539 while (col < wp->w_width) 5540 { 5541 ScreenLines[off] = ' '; 5542 if (enc_utf8) 5543 ScreenLinesUC[off] = 0; 5544 ++col; 5545 if (draw_color_col) 5546 draw_color_col = advance_color_col(VCOL_HLC, 5547 &color_cols); 5548 5549 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) 5550 ScreenAttrs[off++] = HL_ATTR(HLF_CUC); 5551 else if (draw_color_col && VCOL_HLC == *color_cols) 5552 ScreenAttrs[off++] = HL_ATTR(HLF_MC); 5553 else 5554 ScreenAttrs[off++] = 0; 5555 5556 if (VCOL_HLC >= rightmost_vcol) 5557 break; 5558 5559 ++vcol; 5560 } 5561 } 5562 #endif 5563 5564 screen_line(screen_row, wp->w_wincol, col, 5565 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl)); 5566 row++; 5567 5568 /* 5569 * Update w_cline_height and w_cline_folded if the cursor line was 5570 * updated (saves a call to plines() later). 5571 */ 5572 if (wp == curwin && lnum == curwin->w_cursor.lnum) 5573 { 5574 curwin->w_cline_row = startrow; 5575 curwin->w_cline_height = row - startrow; 5576 #ifdef FEAT_FOLDING 5577 curwin->w_cline_folded = FALSE; 5578 #endif 5579 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); 5580 } 5581 5582 break; 5583 } 5584 5585 /* line continues beyond line end */ 5586 if (lcs_ext 5587 && !wp->w_p_wrap 5588 #ifdef FEAT_DIFF 5589 && filler_todo <= 0 5590 #endif 5591 && ( 5592 #ifdef FEAT_RIGHTLEFT 5593 wp->w_p_rl ? col == 0 : 5594 #endif 5595 col == wp->w_width - 1) 5596 && (*ptr != NUL 5597 || (wp->w_p_list && lcs_eol_one > 0) 5598 || (n_extra && (c_extra != NUL || *p_extra != NUL)))) 5599 { 5600 c = lcs_ext; 5601 char_attr = HL_ATTR(HLF_AT); 5602 mb_c = c; 5603 if (enc_utf8 && utf_char2len(c) > 1) 5604 { 5605 mb_utf8 = TRUE; 5606 u8cc[0] = 0; 5607 c = 0xc0; 5608 } 5609 else 5610 mb_utf8 = FALSE; 5611 } 5612 5613 #ifdef FEAT_SYN_HL 5614 /* advance to the next 'colorcolumn' */ 5615 if (draw_color_col) 5616 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); 5617 5618 /* Highlight the cursor column if 'cursorcolumn' is set. But don't 5619 * highlight the cursor position itself. 5620 * Also highlight the 'colorcolumn' if it is different than 5621 * 'cursorcolumn' */ 5622 vcol_save_attr = -1; 5623 if (draw_state == WL_LINE && !lnum_in_visual_area 5624 && search_attr == 0 && area_attr == 0) 5625 { 5626 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol 5627 && lnum != wp->w_cursor.lnum) 5628 { 5629 vcol_save_attr = char_attr; 5630 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC)); 5631 } 5632 else if (draw_color_col && VCOL_HLC == *color_cols) 5633 { 5634 vcol_save_attr = char_attr; 5635 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC)); 5636 } 5637 } 5638 #endif 5639 5640 /* 5641 * Store character to be displayed. 5642 * Skip characters that are left of the screen for 'nowrap'. 5643 */ 5644 vcol_prev = vcol; 5645 if (draw_state < WL_LINE || n_skip <= 0) 5646 { 5647 /* 5648 * Store the character. 5649 */ 5650 #if defined(FEAT_RIGHTLEFT) 5651 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1) 5652 { 5653 /* A double-wide character is: put first halve in left cell. */ 5654 --off; 5655 --col; 5656 } 5657 #endif 5658 ScreenLines[off] = c; 5659 if (enc_dbcs == DBCS_JPNU) 5660 { 5661 if ((mb_c & 0xff00) == 0x8e00) 5662 ScreenLines[off] = 0x8e; 5663 ScreenLines2[off] = mb_c & 0xff; 5664 } 5665 else if (enc_utf8) 5666 { 5667 if (mb_utf8) 5668 { 5669 int i; 5670 5671 ScreenLinesUC[off] = mb_c; 5672 if ((c & 0xff) == 0) 5673 ScreenLines[off] = 0x80; /* avoid storing zero */ 5674 for (i = 0; i < Screen_mco; ++i) 5675 { 5676 ScreenLinesC[i][off] = u8cc[i]; 5677 if (u8cc[i] == 0) 5678 break; 5679 } 5680 } 5681 else 5682 ScreenLinesUC[off] = 0; 5683 } 5684 if (multi_attr) 5685 { 5686 ScreenAttrs[off] = multi_attr; 5687 multi_attr = 0; 5688 } 5689 else 5690 ScreenAttrs[off] = char_attr; 5691 5692 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) 5693 { 5694 /* Need to fill two screen columns. */ 5695 ++off; 5696 ++col; 5697 if (enc_utf8) 5698 /* UTF-8: Put a 0 in the second screen char. */ 5699 ScreenLines[off] = 0; 5700 else 5701 /* DBCS: Put second byte in the second screen char. */ 5702 ScreenLines[off] = mb_c & 0xff; 5703 if (draw_state > WL_NR 5704 #ifdef FEAT_DIFF 5705 && filler_todo <= 0 5706 #endif 5707 ) 5708 ++vcol; 5709 /* When "tocol" is halfway a character, set it to the end of 5710 * the character, otherwise highlighting won't stop. */ 5711 if (tocol == vcol) 5712 ++tocol; 5713 #ifdef FEAT_RIGHTLEFT 5714 if (wp->w_p_rl) 5715 { 5716 /* now it's time to backup one cell */ 5717 --off; 5718 --col; 5719 } 5720 #endif 5721 } 5722 #ifdef FEAT_RIGHTLEFT 5723 if (wp->w_p_rl) 5724 { 5725 --off; 5726 --col; 5727 } 5728 else 5729 #endif 5730 { 5731 ++off; 5732 ++col; 5733 } 5734 } 5735 #ifdef FEAT_CONCEAL 5736 else if (wp->w_p_cole > 0 && is_concealing) 5737 { 5738 --n_skip; 5739 ++vcol_off; 5740 if (n_extra > 0) 5741 vcol_off += n_extra; 5742 if (wp->w_p_wrap) 5743 { 5744 /* 5745 * Special voodoo required if 'wrap' is on. 5746 * 5747 * Advance the column indicator to force the line 5748 * drawing to wrap early. This will make the line 5749 * take up the same screen space when parts are concealed, 5750 * so that cursor line computations aren't messed up. 5751 * 5752 * To avoid the fictitious advance of 'col' causing 5753 * trailing junk to be written out of the screen line 5754 * we are building, 'boguscols' keeps track of the number 5755 * of bad columns we have advanced. 5756 */ 5757 if (n_extra > 0) 5758 { 5759 vcol += n_extra; 5760 # ifdef FEAT_RIGHTLEFT 5761 if (wp->w_p_rl) 5762 { 5763 col -= n_extra; 5764 boguscols -= n_extra; 5765 } 5766 else 5767 # endif 5768 { 5769 col += n_extra; 5770 boguscols += n_extra; 5771 } 5772 n_extra = 0; 5773 n_attr = 0; 5774 } 5775 5776 5777 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) 5778 { 5779 /* Need to fill two screen columns. */ 5780 # ifdef FEAT_RIGHTLEFT 5781 if (wp->w_p_rl) 5782 { 5783 --boguscols; 5784 --col; 5785 } 5786 else 5787 # endif 5788 { 5789 ++boguscols; 5790 ++col; 5791 } 5792 } 5793 5794 # ifdef FEAT_RIGHTLEFT 5795 if (wp->w_p_rl) 5796 { 5797 --boguscols; 5798 --col; 5799 } 5800 else 5801 # endif 5802 { 5803 ++boguscols; 5804 ++col; 5805 } 5806 } 5807 else 5808 { 5809 if (n_extra > 0) 5810 { 5811 vcol += n_extra; 5812 n_extra = 0; 5813 n_attr = 0; 5814 } 5815 } 5816 5817 } 5818 #endif /* FEAT_CONCEAL */ 5819 else 5820 --n_skip; 5821 5822 /* Only advance the "vcol" when after the 'number' or 'relativenumber' 5823 * column. */ 5824 if (draw_state > WL_NR 5825 #ifdef FEAT_DIFF 5826 && filler_todo <= 0 5827 #endif 5828 ) 5829 ++vcol; 5830 5831 #ifdef FEAT_SYN_HL 5832 if (vcol_save_attr >= 0) 5833 char_attr = vcol_save_attr; 5834 #endif 5835 5836 /* restore attributes after "predeces" in 'listchars' */ 5837 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) 5838 char_attr = saved_attr3; 5839 5840 /* restore attributes after last 'listchars' or 'number' char */ 5841 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0) 5842 char_attr = saved_attr2; 5843 5844 /* 5845 * At end of screen line and there is more to come: Display the line 5846 * so far. If there is no more to display it is caught above. 5847 */ 5848 if (( 5849 #ifdef FEAT_RIGHTLEFT 5850 wp->w_p_rl ? (col < 0) : 5851 #endif 5852 (col >= wp->w_width)) 5853 && (*ptr != NUL 5854 #ifdef FEAT_DIFF 5855 || filler_todo > 0 5856 #endif 5857 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str) 5858 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL))) 5859 ) 5860 { 5861 #ifdef FEAT_CONCEAL 5862 screen_line(screen_row, wp->w_wincol, col - boguscols, 5863 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl)); 5864 boguscols = 0; 5865 #else 5866 screen_line(screen_row, wp->w_wincol, col, 5867 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl)); 5868 #endif 5869 ++row; 5870 ++screen_row; 5871 5872 /* When not wrapping and finished diff lines, or when displayed 5873 * '$' and highlighting until last column, break here. */ 5874 if ((!wp->w_p_wrap 5875 #ifdef FEAT_DIFF 5876 && filler_todo <= 0 5877 #endif 5878 ) || lcs_eol_one == -1) 5879 break; 5880 5881 /* When the window is too narrow draw all "@" lines. */ 5882 if (draw_state != WL_LINE 5883 #ifdef FEAT_DIFF 5884 && filler_todo <= 0 5885 #endif 5886 ) 5887 { 5888 win_draw_end(wp, '@', ' ', TRUE, row, wp->w_height, HLF_AT); 5889 draw_vsep_win(wp, row); 5890 row = endrow; 5891 } 5892 5893 /* When line got too long for screen break here. */ 5894 if (row == endrow) 5895 { 5896 ++row; 5897 break; 5898 } 5899 5900 if (screen_cur_row == screen_row - 1 5901 #ifdef FEAT_DIFF 5902 && filler_todo <= 0 5903 #endif 5904 && wp->w_width == Columns) 5905 { 5906 /* Remember that the line wraps, used for modeless copy. */ 5907 LineWraps[screen_row - 1] = TRUE; 5908 5909 /* 5910 * Special trick to make copy/paste of wrapped lines work with 5911 * xterm/screen: write an extra character beyond the end of 5912 * the line. This will work with all terminal types 5913 * (regardless of the xn,am settings). 5914 * Only do this on a fast tty. 5915 * Only do this if the cursor is on the current line 5916 * (something has been written in it). 5917 * Don't do this for the GUI. 5918 * Don't do this for double-width characters. 5919 * Don't do this for a window not at the right screen border. 5920 */ 5921 if (p_tf 5922 #ifdef FEAT_GUI 5923 && !gui.in_use 5924 #endif 5925 && !(has_mbyte 5926 && ((*mb_off2cells)(LineOffset[screen_row], 5927 LineOffset[screen_row] + screen_Columns) 5928 == 2 5929 || (*mb_off2cells)(LineOffset[screen_row - 1] 5930 + (int)Columns - 2, 5931 LineOffset[screen_row] + screen_Columns) 5932 == 2))) 5933 { 5934 /* First make sure we are at the end of the screen line, 5935 * then output the same character again to let the 5936 * terminal know about the wrap. If the terminal doesn't 5937 * auto-wrap, we overwrite the character. */ 5938 if (screen_cur_col != wp->w_width) 5939 screen_char(LineOffset[screen_row - 1] 5940 + (unsigned)Columns - 1, 5941 screen_row - 1, (int)(Columns - 1)); 5942 5943 /* When there is a multi-byte character, just output a 5944 * space to keep it simple. */ 5945 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[ 5946 screen_row - 1] + (Columns - 1)]) > 1) 5947 out_char(' '); 5948 else 5949 out_char(ScreenLines[LineOffset[screen_row - 1] 5950 + (Columns - 1)]); 5951 /* force a redraw of the first char on the next line */ 5952 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1; 5953 screen_start(); /* don't know where cursor is now */ 5954 } 5955 } 5956 5957 col = 0; 5958 off = (unsigned)(current_ScreenLine - ScreenLines); 5959 #ifdef FEAT_RIGHTLEFT 5960 if (wp->w_p_rl) 5961 { 5962 col = wp->w_width - 1; /* col is not used if breaking! */ 5963 off += col; 5964 } 5965 #endif 5966 5967 /* reset the drawing state for the start of a wrapped line */ 5968 draw_state = WL_START; 5969 saved_n_extra = n_extra; 5970 saved_p_extra = p_extra; 5971 saved_c_extra = c_extra; 5972 saved_c_final = c_final; 5973 saved_char_attr = char_attr; 5974 n_extra = 0; 5975 lcs_prec_todo = lcs_prec; 5976 #ifdef FEAT_LINEBREAK 5977 # ifdef FEAT_DIFF 5978 if (filler_todo <= 0) 5979 # endif 5980 need_showbreak = TRUE; 5981 #endif 5982 #ifdef FEAT_DIFF 5983 --filler_todo; 5984 /* When the filler lines are actually below the last line of the 5985 * file, don't draw the line itself, break here. */ 5986 if (filler_todo == 0 && wp->w_botfill) 5987 break; 5988 #endif 5989 } 5990 5991 } /* for every character in the line */ 5992 5993 #ifdef FEAT_SPELL 5994 /* After an empty line check first word for capital. */ 5995 if (*skipwhite(line) == NUL) 5996 { 5997 capcol_lnum = lnum + 1; 5998 cap_col = 0; 5999 } 6000 #endif 6001 #ifdef FEAT_TEXT_PROP 6002 vim_free(text_props); 6003 vim_free(text_prop_idxs); 6004 #endif 6005 6006 vim_free(p_extra_free); 6007 return row; 6008 } 6009 6010 /* 6011 * Return if the composing characters at "off_from" and "off_to" differ. 6012 * Only to be used when ScreenLinesUC[off_from] != 0. 6013 */ 6014 static int 6015 comp_char_differs(int off_from, int off_to) 6016 { 6017 int i; 6018 6019 for (i = 0; i < Screen_mco; ++i) 6020 { 6021 if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to]) 6022 return TRUE; 6023 if (ScreenLinesC[i][off_from] == 0) 6024 break; 6025 } 6026 return FALSE; 6027 } 6028 6029 /* 6030 * Check whether the given character needs redrawing: 6031 * - the (first byte of the) character is different 6032 * - the attributes are different 6033 * - the character is multi-byte and the next byte is different 6034 * - the character is two cells wide and the second cell differs. 6035 */ 6036 static int 6037 char_needs_redraw(int off_from, int off_to, int cols) 6038 { 6039 if (cols > 0 6040 && ((ScreenLines[off_from] != ScreenLines[off_to] 6041 || ScreenAttrs[off_from] != ScreenAttrs[off_to]) 6042 || (enc_dbcs != 0 6043 && MB_BYTE2LEN(ScreenLines[off_from]) > 1 6044 && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e 6045 ? ScreenLines2[off_from] != ScreenLines2[off_to] 6046 : (cols > 1 && ScreenLines[off_from + 1] 6047 != ScreenLines[off_to + 1]))) 6048 || (enc_utf8 6049 && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to] 6050 || (ScreenLinesUC[off_from] != 0 6051 && comp_char_differs(off_from, off_to)) 6052 || ((*mb_off2cells)(off_from, off_from + cols) > 1 6053 && ScreenLines[off_from + 1] 6054 != ScreenLines[off_to + 1]))))) 6055 return TRUE; 6056 return FALSE; 6057 } 6058 6059 #if defined(FEAT_TERMINAL) || defined(PROTO) 6060 /* 6061 * Return the index in ScreenLines[] for the current screen line. 6062 */ 6063 int 6064 screen_get_current_line_off() 6065 { 6066 return (int)(current_ScreenLine - ScreenLines); 6067 } 6068 #endif 6069 6070 /* 6071 * Move one "cooked" screen line to the screen, but only the characters that 6072 * have actually changed. Handle insert/delete character. 6073 * "coloff" gives the first column on the screen for this line. 6074 * "endcol" gives the columns where valid characters are. 6075 * "clear_width" is the width of the window. It's > 0 if the rest of the line 6076 * needs to be cleared, negative otherwise. 6077 * "rlflag" is TRUE in a rightleft window: 6078 * When TRUE and "clear_width" > 0, clear columns 0 to "endcol" 6079 * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width" 6080 */ 6081 void 6082 screen_line( 6083 int row, 6084 int coloff, 6085 int endcol, 6086 int clear_width, 6087 int rlflag UNUSED) 6088 { 6089 unsigned off_from; 6090 unsigned off_to; 6091 unsigned max_off_from; 6092 unsigned max_off_to; 6093 int col = 0; 6094 int hl; 6095 int force = FALSE; /* force update rest of the line */ 6096 int redraw_this /* bool: does character need redraw? */ 6097 #ifdef FEAT_GUI 6098 = TRUE /* For GUI when while-loop empty */ 6099 #endif 6100 ; 6101 int redraw_next; /* redraw_this for next character */ 6102 int clear_next = FALSE; 6103 int char_cells; /* 1: normal char */ 6104 /* 2: occupies two display cells */ 6105 # define CHAR_CELLS char_cells 6106 6107 /* Check for illegal row and col, just in case. */ 6108 if (row >= Rows) 6109 row = Rows - 1; 6110 if (endcol > Columns) 6111 endcol = Columns; 6112 6113 # ifdef FEAT_CLIPBOARD 6114 clip_may_clear_selection(row, row); 6115 # endif 6116 6117 off_from = (unsigned)(current_ScreenLine - ScreenLines); 6118 off_to = LineOffset[row] + coloff; 6119 max_off_from = off_from + screen_Columns; 6120 max_off_to = LineOffset[row] + screen_Columns; 6121 6122 #ifdef FEAT_RIGHTLEFT 6123 if (rlflag) 6124 { 6125 /* Clear rest first, because it's left of the text. */ 6126 if (clear_width > 0) 6127 { 6128 while (col <= endcol && ScreenLines[off_to] == ' ' 6129 && ScreenAttrs[off_to] == 0 6130 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)) 6131 { 6132 ++off_to; 6133 ++col; 6134 } 6135 if (col <= endcol) 6136 screen_fill(row, row + 1, col + coloff, 6137 endcol + coloff + 1, ' ', ' ', 0); 6138 } 6139 col = endcol + 1; 6140 off_to = LineOffset[row] + col + coloff; 6141 off_from += col; 6142 endcol = (clear_width > 0 ? clear_width : -clear_width); 6143 } 6144 #endif /* FEAT_RIGHTLEFT */ 6145 6146 redraw_next = char_needs_redraw(off_from, off_to, endcol - col); 6147 6148 while (col < endcol) 6149 { 6150 if (has_mbyte && (col + 1 < endcol)) 6151 char_cells = (*mb_off2cells)(off_from, max_off_from); 6152 else 6153 char_cells = 1; 6154 6155 redraw_this = redraw_next; 6156 redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS, 6157 off_to + CHAR_CELLS, endcol - col - CHAR_CELLS); 6158 6159 #ifdef FEAT_GUI 6160 /* If the next character was bold, then redraw the current character to 6161 * remove any pixels that might have spilt over into us. This only 6162 * happens in the GUI. 6163 */ 6164 if (redraw_next && gui.in_use) 6165 { 6166 hl = ScreenAttrs[off_to + CHAR_CELLS]; 6167 if (hl > HL_ALL) 6168 hl = syn_attr2attr(hl); 6169 if (hl & HL_BOLD) 6170 redraw_this = TRUE; 6171 } 6172 #endif 6173 6174 if (redraw_this) 6175 { 6176 /* 6177 * Special handling when 'xs' termcap flag set (hpterm): 6178 * Attributes for characters are stored at the position where the 6179 * cursor is when writing the highlighting code. The 6180 * start-highlighting code must be written with the cursor on the 6181 * first highlighted character. The stop-highlighting code must 6182 * be written with the cursor just after the last highlighted 6183 * character. 6184 * Overwriting a character doesn't remove its highlighting. Need 6185 * to clear the rest of the line, and force redrawing it 6186 * completely. 6187 */ 6188 if ( p_wiv 6189 && !force 6190 #ifdef FEAT_GUI 6191 && !gui.in_use 6192 #endif 6193 && ScreenAttrs[off_to] != 0 6194 && ScreenAttrs[off_from] != ScreenAttrs[off_to]) 6195 { 6196 /* 6197 * Need to remove highlighting attributes here. 6198 */ 6199 windgoto(row, col + coloff); 6200 out_str(T_CE); /* clear rest of this screen line */ 6201 screen_start(); /* don't know where cursor is now */ 6202 force = TRUE; /* force redraw of rest of the line */ 6203 redraw_next = TRUE; /* or else next char would miss out */ 6204 6205 /* 6206 * If the previous character was highlighted, need to stop 6207 * highlighting at this character. 6208 */ 6209 if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0) 6210 { 6211 screen_attr = ScreenAttrs[off_to - 1]; 6212 term_windgoto(row, col + coloff); 6213 screen_stop_highlight(); 6214 } 6215 else 6216 screen_attr = 0; /* highlighting has stopped */ 6217 } 6218 if (enc_dbcs != 0) 6219 { 6220 /* Check if overwriting a double-byte with a single-byte or 6221 * the other way around requires another character to be 6222 * redrawn. For UTF-8 this isn't needed, because comparing 6223 * ScreenLinesUC[] is sufficient. */ 6224 if (char_cells == 1 6225 && col + 1 < endcol 6226 && (*mb_off2cells)(off_to, max_off_to) > 1) 6227 { 6228 /* Writing a single-cell character over a double-cell 6229 * character: need to redraw the next cell. */ 6230 ScreenLines[off_to + 1] = 0; 6231 redraw_next = TRUE; 6232 } 6233 else if (char_cells == 2 6234 && col + 2 < endcol 6235 && (*mb_off2cells)(off_to, max_off_to) == 1 6236 && (*mb_off2cells)(off_to + 1, max_off_to) > 1) 6237 { 6238 /* Writing the second half of a double-cell character over 6239 * a double-cell character: need to redraw the second 6240 * cell. */ 6241 ScreenLines[off_to + 2] = 0; 6242 redraw_next = TRUE; 6243 } 6244 6245 if (enc_dbcs == DBCS_JPNU) 6246 ScreenLines2[off_to] = ScreenLines2[off_from]; 6247 } 6248 /* When writing a single-width character over a double-width 6249 * character and at the end of the redrawn text, need to clear out 6250 * the right halve of the old character. 6251 * Also required when writing the right halve of a double-width 6252 * char over the left halve of an existing one. */ 6253 if (has_mbyte && col + char_cells == endcol 6254 && ((char_cells == 1 6255 && (*mb_off2cells)(off_to, max_off_to) > 1) 6256 || (char_cells == 2 6257 && (*mb_off2cells)(off_to, max_off_to) == 1 6258 && (*mb_off2cells)(off_to + 1, max_off_to) > 1))) 6259 clear_next = TRUE; 6260 6261 ScreenLines[off_to] = ScreenLines[off_from]; 6262 if (enc_utf8) 6263 { 6264 ScreenLinesUC[off_to] = ScreenLinesUC[off_from]; 6265 if (ScreenLinesUC[off_from] != 0) 6266 { 6267 int i; 6268 6269 for (i = 0; i < Screen_mco; ++i) 6270 ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from]; 6271 } 6272 } 6273 if (char_cells == 2) 6274 ScreenLines[off_to + 1] = ScreenLines[off_from + 1]; 6275 6276 #if defined(FEAT_GUI) || defined(UNIX) 6277 /* The bold trick makes a single column of pixels appear in the 6278 * next character. When a bold character is removed, the next 6279 * character should be redrawn too. This happens for our own GUI 6280 * and for some xterms. */ 6281 if ( 6282 # ifdef FEAT_GUI 6283 gui.in_use 6284 # endif 6285 # if defined(FEAT_GUI) && defined(UNIX) 6286 || 6287 # endif 6288 # ifdef UNIX 6289 term_is_xterm 6290 # endif 6291 ) 6292 { 6293 hl = ScreenAttrs[off_to]; 6294 if (hl > HL_ALL) 6295 hl = syn_attr2attr(hl); 6296 if (hl & HL_BOLD) 6297 redraw_next = TRUE; 6298 } 6299 #endif 6300 ScreenAttrs[off_to] = ScreenAttrs[off_from]; 6301 6302 /* For simplicity set the attributes of second half of a 6303 * double-wide character equal to the first half. */ 6304 if (char_cells == 2) 6305 ScreenAttrs[off_to + 1] = ScreenAttrs[off_from]; 6306 6307 if (enc_dbcs != 0 && char_cells == 2) 6308 screen_char_2(off_to, row, col + coloff); 6309 else 6310 screen_char(off_to, row, col + coloff); 6311 } 6312 else if ( p_wiv 6313 #ifdef FEAT_GUI 6314 && !gui.in_use 6315 #endif 6316 && col + coloff > 0) 6317 { 6318 if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1]) 6319 { 6320 /* 6321 * Don't output stop-highlight when moving the cursor, it will 6322 * stop the highlighting when it should continue. 6323 */ 6324 screen_attr = 0; 6325 } 6326 else if (screen_attr != 0) 6327 screen_stop_highlight(); 6328 } 6329 6330 off_to += CHAR_CELLS; 6331 off_from += CHAR_CELLS; 6332 col += CHAR_CELLS; 6333 } 6334 6335 if (clear_next) 6336 { 6337 /* Clear the second half of a double-wide character of which the left 6338 * half was overwritten with a single-wide character. */ 6339 ScreenLines[off_to] = ' '; 6340 if (enc_utf8) 6341 ScreenLinesUC[off_to] = 0; 6342 screen_char(off_to, row, col + coloff); 6343 } 6344 6345 if (clear_width > 0 6346 #ifdef FEAT_RIGHTLEFT 6347 && !rlflag 6348 #endif 6349 ) 6350 { 6351 #ifdef FEAT_GUI 6352 int startCol = col; 6353 #endif 6354 6355 /* blank out the rest of the line */ 6356 while (col < clear_width && ScreenLines[off_to] == ' ' 6357 && ScreenAttrs[off_to] == 0 6358 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)) 6359 { 6360 ++off_to; 6361 ++col; 6362 } 6363 if (col < clear_width) 6364 { 6365 #ifdef FEAT_GUI 6366 /* 6367 * In the GUI, clearing the rest of the line may leave pixels 6368 * behind if the first character cleared was bold. Some bold 6369 * fonts spill over the left. In this case we redraw the previous 6370 * character too. If we didn't skip any blanks above, then we 6371 * only redraw if the character wasn't already redrawn anyway. 6372 */ 6373 if (gui.in_use && (col > startCol || !redraw_this)) 6374 { 6375 hl = ScreenAttrs[off_to]; 6376 if (hl > HL_ALL || (hl & HL_BOLD)) 6377 { 6378 int prev_cells = 1; 6379 6380 if (enc_utf8) 6381 /* for utf-8, ScreenLines[char_offset + 1] == 0 means 6382 * that its width is 2. */ 6383 prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1; 6384 else if (enc_dbcs != 0) 6385 { 6386 /* find previous character by counting from first 6387 * column and get its width. */ 6388 unsigned off = LineOffset[row]; 6389 unsigned max_off = LineOffset[row] + screen_Columns; 6390 6391 while (off < off_to) 6392 { 6393 prev_cells = (*mb_off2cells)(off, max_off); 6394 off += prev_cells; 6395 } 6396 } 6397 6398 if (enc_dbcs != 0 && prev_cells > 1) 6399 screen_char_2(off_to - prev_cells, row, 6400 col + coloff - prev_cells); 6401 else 6402 screen_char(off_to - prev_cells, row, 6403 col + coloff - prev_cells); 6404 } 6405 } 6406 #endif 6407 screen_fill(row, row + 1, col + coloff, clear_width + coloff, 6408 ' ', ' ', 0); 6409 off_to += clear_width - col; 6410 col = clear_width; 6411 } 6412 } 6413 6414 if (clear_width > 0) 6415 { 6416 /* For a window that's left of another, draw the separator char. */ 6417 if (col + coloff < Columns) 6418 { 6419 int c; 6420 6421 c = fillchar_vsep(&hl); 6422 if (ScreenLines[off_to] != (schar_T)c 6423 || (enc_utf8 && (int)ScreenLinesUC[off_to] 6424 != (c >= 0x80 ? c : 0)) 6425 || ScreenAttrs[off_to] != hl) 6426 { 6427 ScreenLines[off_to] = c; 6428 ScreenAttrs[off_to] = hl; 6429 if (enc_utf8) 6430 { 6431 if (c >= 0x80) 6432 { 6433 ScreenLinesUC[off_to] = c; 6434 ScreenLinesC[0][off_to] = 0; 6435 } 6436 else 6437 ScreenLinesUC[off_to] = 0; 6438 } 6439 screen_char(off_to, row, col + coloff); 6440 } 6441 } 6442 else 6443 LineWraps[row] = FALSE; 6444 } 6445 } 6446 6447 #if defined(FEAT_RIGHTLEFT) || defined(PROTO) 6448 /* 6449 * Mirror text "str" for right-left displaying. 6450 * Only works for single-byte characters (e.g., numbers). 6451 */ 6452 void 6453 rl_mirror(char_u *str) 6454 { 6455 char_u *p1, *p2; 6456 int t; 6457 6458 for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2) 6459 { 6460 t = *p1; 6461 *p1 = *p2; 6462 *p2 = t; 6463 } 6464 } 6465 #endif 6466 6467 /* 6468 * mark all status lines for redraw; used after first :cd 6469 */ 6470 void 6471 status_redraw_all(void) 6472 { 6473 win_T *wp; 6474 6475 FOR_ALL_WINDOWS(wp) 6476 if (wp->w_status_height) 6477 { 6478 wp->w_redr_status = TRUE; 6479 redraw_later(VALID); 6480 } 6481 } 6482 6483 /* 6484 * mark all status lines of the current buffer for redraw 6485 */ 6486 void 6487 status_redraw_curbuf(void) 6488 { 6489 win_T *wp; 6490 6491 FOR_ALL_WINDOWS(wp) 6492 if (wp->w_status_height != 0 && wp->w_buffer == curbuf) 6493 { 6494 wp->w_redr_status = TRUE; 6495 redraw_later(VALID); 6496 } 6497 } 6498 6499 /* 6500 * Redraw all status lines that need to be redrawn. 6501 */ 6502 void 6503 redraw_statuslines(void) 6504 { 6505 win_T *wp; 6506 6507 FOR_ALL_WINDOWS(wp) 6508 if (wp->w_redr_status) 6509 win_redr_status(wp, FALSE); 6510 if (redraw_tabline) 6511 draw_tabline(); 6512 } 6513 6514 #if defined(FEAT_WILDMENU) || defined(PROTO) 6515 /* 6516 * Redraw all status lines at the bottom of frame "frp". 6517 */ 6518 void 6519 win_redraw_last_status(frame_T *frp) 6520 { 6521 if (frp->fr_layout == FR_LEAF) 6522 frp->fr_win->w_redr_status = TRUE; 6523 else if (frp->fr_layout == FR_ROW) 6524 { 6525 FOR_ALL_FRAMES(frp, frp->fr_child) 6526 win_redraw_last_status(frp); 6527 } 6528 else /* frp->fr_layout == FR_COL */ 6529 { 6530 frp = frp->fr_child; 6531 while (frp->fr_next != NULL) 6532 frp = frp->fr_next; 6533 win_redraw_last_status(frp); 6534 } 6535 } 6536 #endif 6537 6538 /* 6539 * Draw the verticap separator right of window "wp" starting with line "row". 6540 */ 6541 static void 6542 draw_vsep_win(win_T *wp, int row) 6543 { 6544 int hl; 6545 int c; 6546 6547 if (wp->w_vsep_width) 6548 { 6549 /* draw the vertical separator right of this window */ 6550 c = fillchar_vsep(&hl); 6551 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height, 6552 W_ENDCOL(wp), W_ENDCOL(wp) + 1, 6553 c, ' ', hl); 6554 } 6555 } 6556 6557 #ifdef FEAT_WILDMENU 6558 static int skip_status_match_char(expand_T *xp, char_u *s); 6559 6560 /* 6561 * Get the length of an item as it will be shown in the status line. 6562 */ 6563 static int 6564 status_match_len(expand_T *xp, char_u *s) 6565 { 6566 int len = 0; 6567 6568 #ifdef FEAT_MENU 6569 int emenu = (xp->xp_context == EXPAND_MENUS 6570 || xp->xp_context == EXPAND_MENUNAMES); 6571 6572 /* Check for menu separators - replace with '|'. */ 6573 if (emenu && menu_is_separator(s)) 6574 return 1; 6575 #endif 6576 6577 while (*s != NUL) 6578 { 6579 s += skip_status_match_char(xp, s); 6580 len += ptr2cells(s); 6581 MB_PTR_ADV(s); 6582 } 6583 6584 return len; 6585 } 6586 6587 /* 6588 * Return the number of characters that should be skipped in a status match. 6589 * These are backslashes used for escaping. Do show backslashes in help tags. 6590 */ 6591 static int 6592 skip_status_match_char(expand_T *xp, char_u *s) 6593 { 6594 if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP) 6595 #ifdef FEAT_MENU 6596 || ((xp->xp_context == EXPAND_MENUS 6597 || xp->xp_context == EXPAND_MENUNAMES) 6598 && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL))) 6599 #endif 6600 ) 6601 { 6602 #ifndef BACKSLASH_IN_FILENAME 6603 if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!') 6604 return 2; 6605 #endif 6606 return 1; 6607 } 6608 return 0; 6609 } 6610 6611 /* 6612 * Show wildchar matches in the status line. 6613 * Show at least the "match" item. 6614 * We start at item 'first_match' in the list and show all matches that fit. 6615 * 6616 * If inversion is possible we use it. Else '=' characters are used. 6617 */ 6618 void 6619 win_redr_status_matches( 6620 expand_T *xp, 6621 int num_matches, 6622 char_u **matches, /* list of matches */ 6623 int match, 6624 int showtail) 6625 { 6626 #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m]) 6627 int row; 6628 char_u *buf; 6629 int len; 6630 int clen; /* length in screen cells */ 6631 int fillchar; 6632 int attr; 6633 int i; 6634 int highlight = TRUE; 6635 char_u *selstart = NULL; 6636 int selstart_col = 0; 6637 char_u *selend = NULL; 6638 static int first_match = 0; 6639 int add_left = FALSE; 6640 char_u *s; 6641 #ifdef FEAT_MENU 6642 int emenu; 6643 #endif 6644 int l; 6645 6646 if (matches == NULL) /* interrupted completion? */ 6647 return; 6648 6649 if (has_mbyte) 6650 buf = alloc((unsigned)Columns * MB_MAXBYTES + 1); 6651 else 6652 buf = alloc((unsigned)Columns + 1); 6653 if (buf == NULL) 6654 return; 6655 6656 if (match == -1) /* don't show match but original text */ 6657 { 6658 match = 0; 6659 highlight = FALSE; 6660 } 6661 /* count 1 for the ending ">" */ 6662 clen = status_match_len(xp, L_MATCH(match)) + 3; 6663 if (match == 0) 6664 first_match = 0; 6665 else if (match < first_match) 6666 { 6667 /* jumping left, as far as we can go */ 6668 first_match = match; 6669 add_left = TRUE; 6670 } 6671 else 6672 { 6673 /* check if match fits on the screen */ 6674 for (i = first_match; i < match; ++i) 6675 clen += status_match_len(xp, L_MATCH(i)) + 2; 6676 if (first_match > 0) 6677 clen += 2; 6678 /* jumping right, put match at the left */ 6679 if ((long)clen > Columns) 6680 { 6681 first_match = match; 6682 /* if showing the last match, we can add some on the left */ 6683 clen = 2; 6684 for (i = match; i < num_matches; ++i) 6685 { 6686 clen += status_match_len(xp, L_MATCH(i)) + 2; 6687 if ((long)clen >= Columns) 6688 break; 6689 } 6690 if (i == num_matches) 6691 add_left = TRUE; 6692 } 6693 } 6694 if (add_left) 6695 while (first_match > 0) 6696 { 6697 clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2; 6698 if ((long)clen >= Columns) 6699 break; 6700 --first_match; 6701 } 6702 6703 fillchar = fillchar_status(&attr, curwin); 6704 6705 if (first_match == 0) 6706 { 6707 *buf = NUL; 6708 len = 0; 6709 } 6710 else 6711 { 6712 STRCPY(buf, "< "); 6713 len = 2; 6714 } 6715 clen = len; 6716 6717 i = first_match; 6718 while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns) 6719 { 6720 if (i == match) 6721 { 6722 selstart = buf + len; 6723 selstart_col = clen; 6724 } 6725 6726 s = L_MATCH(i); 6727 /* Check for menu separators - replace with '|' */ 6728 #ifdef FEAT_MENU 6729 emenu = (xp->xp_context == EXPAND_MENUS 6730 || xp->xp_context == EXPAND_MENUNAMES); 6731 if (emenu && menu_is_separator(s)) 6732 { 6733 STRCPY(buf + len, transchar('|')); 6734 l = (int)STRLEN(buf + len); 6735 len += l; 6736 clen += l; 6737 } 6738 else 6739 #endif 6740 for ( ; *s != NUL; ++s) 6741 { 6742 s += skip_status_match_char(xp, s); 6743 clen += ptr2cells(s); 6744 if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) 6745 { 6746 STRNCPY(buf + len, s, l); 6747 s += l - 1; 6748 len += l; 6749 } 6750 else 6751 { 6752 STRCPY(buf + len, transchar_byte(*s)); 6753 len += (int)STRLEN(buf + len); 6754 } 6755 } 6756 if (i == match) 6757 selend = buf + len; 6758 6759 *(buf + len++) = ' '; 6760 *(buf + len++) = ' '; 6761 clen += 2; 6762 if (++i == num_matches) 6763 break; 6764 } 6765 6766 if (i != num_matches) 6767 { 6768 *(buf + len++) = '>'; 6769 ++clen; 6770 } 6771 6772 buf[len] = NUL; 6773 6774 row = cmdline_row - 1; 6775 if (row >= 0) 6776 { 6777 if (wild_menu_showing == 0) 6778 { 6779 if (msg_scrolled > 0) 6780 { 6781 /* Put the wildmenu just above the command line. If there is 6782 * no room, scroll the screen one line up. */ 6783 if (cmdline_row == Rows - 1) 6784 { 6785 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL); 6786 ++msg_scrolled; 6787 } 6788 else 6789 { 6790 ++cmdline_row; 6791 ++row; 6792 } 6793 wild_menu_showing = WM_SCROLLED; 6794 } 6795 else 6796 { 6797 /* Create status line if needed by setting 'laststatus' to 2. 6798 * Set 'winminheight' to zero to avoid that the window is 6799 * resized. */ 6800 if (lastwin->w_status_height == 0) 6801 { 6802 save_p_ls = p_ls; 6803 save_p_wmh = p_wmh; 6804 p_ls = 2; 6805 p_wmh = 0; 6806 last_status(FALSE); 6807 } 6808 wild_menu_showing = WM_SHOWN; 6809 } 6810 } 6811 6812 screen_puts(buf, row, 0, attr); 6813 if (selstart != NULL && highlight) 6814 { 6815 *selend = NUL; 6816 screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM)); 6817 } 6818 6819 screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr); 6820 } 6821 6822 win_redraw_last_status(topframe); 6823 vim_free(buf); 6824 } 6825 #endif 6826 6827 /* 6828 * Redraw the status line of window wp. 6829 * 6830 * If inversion is possible we use it. Else '=' characters are used. 6831 * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is 6832 * displayed. 6833 */ 6834 static void 6835 win_redr_status(win_T *wp, int ignore_pum UNUSED) 6836 { 6837 int row; 6838 char_u *p; 6839 int len; 6840 int fillchar; 6841 int attr; 6842 int this_ru_col; 6843 static int busy = FALSE; 6844 6845 /* It's possible to get here recursively when 'statusline' (indirectly) 6846 * invokes ":redrawstatus". Simply ignore the call then. */ 6847 if (busy) 6848 return; 6849 busy = TRUE; 6850 6851 wp->w_redr_status = FALSE; 6852 if (wp->w_status_height == 0) 6853 { 6854 /* no status line, can only be last window */ 6855 redraw_cmdline = TRUE; 6856 } 6857 else if (!redrawing() 6858 #ifdef FEAT_INS_EXPAND 6859 // don't update status line when popup menu is visible and may be 6860 // drawn over it, unless it will be redrawn later 6861 || (!ignore_pum && pum_visible()) 6862 #endif 6863 ) 6864 { 6865 /* Don't redraw right now, do it later. */ 6866 wp->w_redr_status = TRUE; 6867 } 6868 #ifdef FEAT_STL_OPT 6869 else if (*p_stl != NUL || *wp->w_p_stl != NUL) 6870 { 6871 /* redraw custom status line */ 6872 redraw_custom_statusline(wp); 6873 } 6874 #endif 6875 else 6876 { 6877 fillchar = fillchar_status(&attr, wp); 6878 6879 get_trans_bufname(wp->w_buffer); 6880 p = NameBuff; 6881 len = (int)STRLEN(p); 6882 6883 if (bt_help(wp->w_buffer) 6884 #ifdef FEAT_QUICKFIX 6885 || wp->w_p_pvw 6886 #endif 6887 || bufIsChanged(wp->w_buffer) 6888 || wp->w_buffer->b_p_ro) 6889 *(p + len++) = ' '; 6890 if (bt_help(wp->w_buffer)) 6891 { 6892 STRCPY(p + len, _("[Help]")); 6893 len += (int)STRLEN(p + len); 6894 } 6895 #ifdef FEAT_QUICKFIX 6896 if (wp->w_p_pvw) 6897 { 6898 STRCPY(p + len, _("[Preview]")); 6899 len += (int)STRLEN(p + len); 6900 } 6901 #endif 6902 if (bufIsChanged(wp->w_buffer) 6903 #ifdef FEAT_TERMINAL 6904 && !bt_terminal(wp->w_buffer) 6905 #endif 6906 ) 6907 { 6908 STRCPY(p + len, "[+]"); 6909 len += 3; 6910 } 6911 if (wp->w_buffer->b_p_ro) 6912 { 6913 STRCPY(p + len, _("[RO]")); 6914 len += (int)STRLEN(p + len); 6915 } 6916 6917 this_ru_col = ru_col - (Columns - wp->w_width); 6918 if (this_ru_col < (wp->w_width + 1) / 2) 6919 this_ru_col = (wp->w_width + 1) / 2; 6920 if (this_ru_col <= 1) 6921 { 6922 p = (char_u *)"<"; /* No room for file name! */ 6923 len = 1; 6924 } 6925 else if (has_mbyte) 6926 { 6927 int clen = 0, i; 6928 6929 /* Count total number of display cells. */ 6930 clen = mb_string2cells(p, -1); 6931 6932 /* Find first character that will fit. 6933 * Going from start to end is much faster for DBCS. */ 6934 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1; 6935 i += (*mb_ptr2len)(p + i)) 6936 clen -= (*mb_ptr2cells)(p + i); 6937 len = clen; 6938 if (i > 0) 6939 { 6940 p = p + i - 1; 6941 *p = '<'; 6942 ++len; 6943 } 6944 6945 } 6946 else if (len > this_ru_col - 1) 6947 { 6948 p += len - (this_ru_col - 1); 6949 *p = '<'; 6950 len = this_ru_col - 1; 6951 } 6952 6953 row = W_WINROW(wp) + wp->w_height; 6954 screen_puts(p, row, wp->w_wincol, attr); 6955 screen_fill(row, row + 1, len + wp->w_wincol, 6956 this_ru_col + wp->w_wincol, fillchar, fillchar, attr); 6957 6958 if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL) 6959 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1)) 6960 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff) 6961 - 1 + wp->w_wincol), attr); 6962 6963 #ifdef FEAT_CMDL_INFO 6964 win_redr_ruler(wp, TRUE, ignore_pum); 6965 #endif 6966 } 6967 6968 /* 6969 * May need to draw the character below the vertical separator. 6970 */ 6971 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing()) 6972 { 6973 if (stl_connected(wp)) 6974 fillchar = fillchar_status(&attr, wp); 6975 else 6976 fillchar = fillchar_vsep(&attr); 6977 screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp), 6978 attr); 6979 } 6980 busy = FALSE; 6981 } 6982 6983 #ifdef FEAT_STL_OPT 6984 /* 6985 * Redraw the status line according to 'statusline' and take care of any 6986 * errors encountered. 6987 */ 6988 static void 6989 redraw_custom_statusline(win_T *wp) 6990 { 6991 static int entered = FALSE; 6992 int saved_did_emsg = did_emsg; 6993 6994 /* When called recursively return. This can happen when the statusline 6995 * contains an expression that triggers a redraw. */ 6996 if (entered) 6997 return; 6998 entered = TRUE; 6999 7000 did_emsg = FALSE; 7001 win_redr_custom(wp, FALSE); 7002 if (did_emsg) 7003 { 7004 /* When there is an error disable the statusline, otherwise the 7005 * display is messed up with errors and a redraw triggers the problem 7006 * again and again. */ 7007 set_string_option_direct((char_u *)"statusline", -1, 7008 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL 7009 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR); 7010 } 7011 did_emsg |= saved_did_emsg; 7012 entered = FALSE; 7013 } 7014 #endif 7015 7016 /* 7017 * Return TRUE if the status line of window "wp" is connected to the status 7018 * line of the window right of it. If not, then it's a vertical separator. 7019 * Only call if (wp->w_vsep_width != 0). 7020 */ 7021 int 7022 stl_connected(win_T *wp) 7023 { 7024 frame_T *fr; 7025 7026 fr = wp->w_frame; 7027 while (fr->fr_parent != NULL) 7028 { 7029 if (fr->fr_parent->fr_layout == FR_COL) 7030 { 7031 if (fr->fr_next != NULL) 7032 break; 7033 } 7034 else 7035 { 7036 if (fr->fr_next != NULL) 7037 return TRUE; 7038 } 7039 fr = fr->fr_parent; 7040 } 7041 return FALSE; 7042 } 7043 7044 7045 /* 7046 * Get the value to show for the language mappings, active 'keymap'. 7047 */ 7048 int 7049 get_keymap_str( 7050 win_T *wp, 7051 char_u *fmt, /* format string containing one %s item */ 7052 char_u *buf, /* buffer for the result */ 7053 int len) /* length of buffer */ 7054 { 7055 char_u *p; 7056 7057 if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) 7058 return FALSE; 7059 7060 { 7061 #ifdef FEAT_EVAL 7062 buf_T *old_curbuf = curbuf; 7063 win_T *old_curwin = curwin; 7064 char_u *s; 7065 7066 curbuf = wp->w_buffer; 7067 curwin = wp; 7068 STRCPY(buf, "b:keymap_name"); /* must be writable */ 7069 ++emsg_skip; 7070 s = p = eval_to_string(buf, NULL, FALSE); 7071 --emsg_skip; 7072 curbuf = old_curbuf; 7073 curwin = old_curwin; 7074 if (p == NULL || *p == NUL) 7075 #endif 7076 { 7077 #ifdef FEAT_KEYMAP 7078 if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED) 7079 p = wp->w_buffer->b_p_keymap; 7080 else 7081 #endif 7082 p = (char_u *)"lang"; 7083 } 7084 if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1) 7085 buf[0] = NUL; 7086 #ifdef FEAT_EVAL 7087 vim_free(s); 7088 #endif 7089 } 7090 return buf[0] != NUL; 7091 } 7092 7093 #if defined(FEAT_STL_OPT) || defined(PROTO) 7094 /* 7095 * Redraw the status line or ruler of window "wp". 7096 * When "wp" is NULL redraw the tab pages line from 'tabline'. 7097 */ 7098 static void 7099 win_redr_custom( 7100 win_T *wp, 7101 int draw_ruler) /* TRUE or FALSE */ 7102 { 7103 static int entered = FALSE; 7104 int attr; 7105 int curattr; 7106 int row; 7107 int col = 0; 7108 int maxwidth; 7109 int width; 7110 int n; 7111 int len; 7112 int fillchar; 7113 char_u buf[MAXPATHL]; 7114 char_u *stl; 7115 char_u *p; 7116 struct stl_hlrec hltab[STL_MAX_ITEM]; 7117 struct stl_hlrec tabtab[STL_MAX_ITEM]; 7118 int use_sandbox = FALSE; 7119 win_T *ewp; 7120 int p_crb_save; 7121 7122 /* There is a tiny chance that this gets called recursively: When 7123 * redrawing a status line triggers redrawing the ruler or tabline. 7124 * Avoid trouble by not allowing recursion. */ 7125 if (entered) 7126 return; 7127 entered = TRUE; 7128 7129 /* setup environment for the task at hand */ 7130 if (wp == NULL) 7131 { 7132 /* Use 'tabline'. Always at the first line of the screen. */ 7133 stl = p_tal; 7134 row = 0; 7135 fillchar = ' '; 7136 attr = HL_ATTR(HLF_TPF); 7137 maxwidth = Columns; 7138 # ifdef FEAT_EVAL 7139 use_sandbox = was_set_insecurely((char_u *)"tabline", 0); 7140 # endif 7141 } 7142 else 7143 { 7144 row = W_WINROW(wp) + wp->w_height; 7145 fillchar = fillchar_status(&attr, wp); 7146 maxwidth = wp->w_width; 7147 7148 if (draw_ruler) 7149 { 7150 stl = p_ruf; 7151 /* advance past any leading group spec - implicit in ru_col */ 7152 if (*stl == '%') 7153 { 7154 if (*++stl == '-') 7155 stl++; 7156 if (atoi((char *)stl)) 7157 while (VIM_ISDIGIT(*stl)) 7158 stl++; 7159 if (*stl++ != '(') 7160 stl = p_ruf; 7161 } 7162 col = ru_col - (Columns - wp->w_width); 7163 if (col < (wp->w_width + 1) / 2) 7164 col = (wp->w_width + 1) / 2; 7165 maxwidth = wp->w_width - col; 7166 if (!wp->w_status_height) 7167 { 7168 row = Rows - 1; 7169 --maxwidth; /* writing in last column may cause scrolling */ 7170 fillchar = ' '; 7171 attr = 0; 7172 } 7173 7174 # ifdef FEAT_EVAL 7175 use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0); 7176 # endif 7177 } 7178 else 7179 { 7180 if (*wp->w_p_stl != NUL) 7181 stl = wp->w_p_stl; 7182 else 7183 stl = p_stl; 7184 # ifdef FEAT_EVAL 7185 use_sandbox = was_set_insecurely((char_u *)"statusline", 7186 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL); 7187 # endif 7188 } 7189 7190 col += wp->w_wincol; 7191 } 7192 7193 if (maxwidth <= 0) 7194 goto theend; 7195 7196 /* Temporarily reset 'cursorbind', we don't want a side effect from moving 7197 * the cursor away and back. */ 7198 ewp = wp == NULL ? curwin : wp; 7199 p_crb_save = ewp->w_p_crb; 7200 ewp->w_p_crb = FALSE; 7201 7202 /* Make a copy, because the statusline may include a function call that 7203 * might change the option value and free the memory. */ 7204 stl = vim_strsave(stl); 7205 width = build_stl_str_hl(ewp, buf, sizeof(buf), 7206 stl, use_sandbox, 7207 fillchar, maxwidth, hltab, tabtab); 7208 vim_free(stl); 7209 ewp->w_p_crb = p_crb_save; 7210 7211 /* Make all characters printable. */ 7212 p = transstr(buf); 7213 if (p != NULL) 7214 { 7215 vim_strncpy(buf, p, sizeof(buf) - 1); 7216 vim_free(p); 7217 } 7218 7219 /* fill up with "fillchar" */ 7220 len = (int)STRLEN(buf); 7221 while (width < maxwidth && len < (int)sizeof(buf) - 1) 7222 { 7223 len += (*mb_char2bytes)(fillchar, buf + len); 7224 ++width; 7225 } 7226 buf[len] = NUL; 7227 7228 /* 7229 * Draw each snippet with the specified highlighting. 7230 */ 7231 curattr = attr; 7232 p = buf; 7233 for (n = 0; hltab[n].start != NULL; n++) 7234 { 7235 len = (int)(hltab[n].start - p); 7236 screen_puts_len(p, len, row, col, curattr); 7237 col += vim_strnsize(p, len); 7238 p = hltab[n].start; 7239 7240 if (hltab[n].userhl == 0) 7241 curattr = attr; 7242 else if (hltab[n].userhl < 0) 7243 curattr = syn_id2attr(-hltab[n].userhl); 7244 #ifdef FEAT_TERMINAL 7245 else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer) 7246 && wp->w_status_height != 0) 7247 curattr = highlight_stltermnc[hltab[n].userhl - 1]; 7248 else if (wp != NULL && bt_terminal(wp->w_buffer) 7249 && wp->w_status_height != 0) 7250 curattr = highlight_stlterm[hltab[n].userhl - 1]; 7251 #endif 7252 else if (wp != NULL && wp != curwin && wp->w_status_height != 0) 7253 curattr = highlight_stlnc[hltab[n].userhl - 1]; 7254 else 7255 curattr = highlight_user[hltab[n].userhl - 1]; 7256 } 7257 screen_puts(p, row, col, curattr); 7258 7259 if (wp == NULL) 7260 { 7261 /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */ 7262 col = 0; 7263 len = 0; 7264 p = buf; 7265 fillchar = 0; 7266 for (n = 0; tabtab[n].start != NULL; n++) 7267 { 7268 len += vim_strnsize(p, (int)(tabtab[n].start - p)); 7269 while (col < len) 7270 TabPageIdxs[col++] = fillchar; 7271 p = tabtab[n].start; 7272 fillchar = tabtab[n].userhl; 7273 } 7274 while (col < Columns) 7275 TabPageIdxs[col++] = fillchar; 7276 } 7277 7278 theend: 7279 entered = FALSE; 7280 } 7281 7282 #endif /* FEAT_STL_OPT */ 7283 7284 /* 7285 * Output a single character directly to the screen and update ScreenLines. 7286 */ 7287 void 7288 screen_putchar(int c, int row, int col, int attr) 7289 { 7290 char_u buf[MB_MAXBYTES + 1]; 7291 7292 if (has_mbyte) 7293 buf[(*mb_char2bytes)(c, buf)] = NUL; 7294 else 7295 { 7296 buf[0] = c; 7297 buf[1] = NUL; 7298 } 7299 screen_puts(buf, row, col, attr); 7300 } 7301 7302 /* 7303 * Get a single character directly from ScreenLines into "bytes[]". 7304 * Also return its attribute in *attrp; 7305 */ 7306 void 7307 screen_getbytes(int row, int col, char_u *bytes, int *attrp) 7308 { 7309 unsigned off; 7310 7311 /* safety check */ 7312 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns) 7313 { 7314 off = LineOffset[row] + col; 7315 *attrp = ScreenAttrs[off]; 7316 bytes[0] = ScreenLines[off]; 7317 bytes[1] = NUL; 7318 7319 if (enc_utf8 && ScreenLinesUC[off] != 0) 7320 bytes[utfc_char2bytes(off, bytes)] = NUL; 7321 else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e) 7322 { 7323 bytes[0] = ScreenLines[off]; 7324 bytes[1] = ScreenLines2[off]; 7325 bytes[2] = NUL; 7326 } 7327 else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1) 7328 { 7329 bytes[1] = ScreenLines[off + 1]; 7330 bytes[2] = NUL; 7331 } 7332 } 7333 } 7334 7335 /* 7336 * Return TRUE if composing characters for screen posn "off" differs from 7337 * composing characters in "u8cc". 7338 * Only to be used when ScreenLinesUC[off] != 0. 7339 */ 7340 static int 7341 screen_comp_differs(int off, int *u8cc) 7342 { 7343 int i; 7344 7345 for (i = 0; i < Screen_mco; ++i) 7346 { 7347 if (ScreenLinesC[i][off] != (u8char_T)u8cc[i]) 7348 return TRUE; 7349 if (u8cc[i] == 0) 7350 break; 7351 } 7352 return FALSE; 7353 } 7354 7355 /* 7356 * Put string '*text' on the screen at position 'row' and 'col', with 7357 * attributes 'attr', and update ScreenLines[] and ScreenAttrs[]. 7358 * Note: only outputs within one row, message is truncated at screen boundary! 7359 * Note: if ScreenLines[], row and/or col is invalid, nothing is done. 7360 */ 7361 void 7362 screen_puts( 7363 char_u *text, 7364 int row, 7365 int col, 7366 int attr) 7367 { 7368 screen_puts_len(text, -1, row, col, attr); 7369 } 7370 7371 /* 7372 * Like screen_puts(), but output "text[len]". When "len" is -1 output up to 7373 * a NUL. 7374 */ 7375 void 7376 screen_puts_len( 7377 char_u *text, 7378 int textlen, 7379 int row, 7380 int col, 7381 int attr) 7382 { 7383 unsigned off; 7384 char_u *ptr = text; 7385 int len = textlen; 7386 int c; 7387 unsigned max_off; 7388 int mbyte_blen = 1; 7389 int mbyte_cells = 1; 7390 int u8c = 0; 7391 int u8cc[MAX_MCO]; 7392 int clear_next_cell = FALSE; 7393 #ifdef FEAT_ARABIC 7394 int prev_c = 0; /* previous Arabic character */ 7395 int pc, nc, nc1; 7396 int pcc[MAX_MCO]; 7397 #endif 7398 int force_redraw_this; 7399 int force_redraw_next = FALSE; 7400 int need_redraw; 7401 7402 if (ScreenLines == NULL || row >= screen_Rows) /* safety check */ 7403 return; 7404 off = LineOffset[row] + col; 7405 7406 /* When drawing over the right halve of a double-wide char clear out the 7407 * left halve. Only needed in a terminal. */ 7408 if (has_mbyte && col > 0 && col < screen_Columns 7409 #ifdef FEAT_GUI 7410 && !gui.in_use 7411 #endif 7412 && mb_fix_col(col, row) != col) 7413 { 7414 ScreenLines[off - 1] = ' '; 7415 ScreenAttrs[off - 1] = 0; 7416 if (enc_utf8) 7417 { 7418 ScreenLinesUC[off - 1] = 0; 7419 ScreenLinesC[0][off - 1] = 0; 7420 } 7421 /* redraw the previous cell, make it empty */ 7422 screen_char(off - 1, row, col - 1); 7423 /* force the cell at "col" to be redrawn */ 7424 force_redraw_next = TRUE; 7425 } 7426 7427 max_off = LineOffset[row] + screen_Columns; 7428 while (col < screen_Columns 7429 && (len < 0 || (int)(ptr - text) < len) 7430 && *ptr != NUL) 7431 { 7432 c = *ptr; 7433 /* check if this is the first byte of a multibyte */ 7434 if (has_mbyte) 7435 { 7436 if (enc_utf8 && len > 0) 7437 mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr)); 7438 else 7439 mbyte_blen = (*mb_ptr2len)(ptr); 7440 if (enc_dbcs == DBCS_JPNU && c == 0x8e) 7441 mbyte_cells = 1; 7442 else if (enc_dbcs != 0) 7443 mbyte_cells = mbyte_blen; 7444 else /* enc_utf8 */ 7445 { 7446 if (len >= 0) 7447 u8c = utfc_ptr2char_len(ptr, u8cc, 7448 (int)((text + len) - ptr)); 7449 else 7450 u8c = utfc_ptr2char(ptr, u8cc); 7451 mbyte_cells = utf_char2cells(u8c); 7452 #ifdef FEAT_ARABIC 7453 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) 7454 { 7455 /* Do Arabic shaping. */ 7456 if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len) 7457 { 7458 /* Past end of string to be displayed. */ 7459 nc = NUL; 7460 nc1 = NUL; 7461 } 7462 else 7463 { 7464 nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc, 7465 (int)((text + len) - ptr - mbyte_blen)); 7466 nc1 = pcc[0]; 7467 } 7468 pc = prev_c; 7469 prev_c = u8c; 7470 u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc); 7471 } 7472 else 7473 prev_c = u8c; 7474 #endif 7475 if (col + mbyte_cells > screen_Columns) 7476 { 7477 /* Only 1 cell left, but character requires 2 cells: 7478 * display a '>' in the last column to avoid wrapping. */ 7479 c = '>'; 7480 mbyte_cells = 1; 7481 } 7482 } 7483 } 7484 7485 force_redraw_this = force_redraw_next; 7486 force_redraw_next = FALSE; 7487 7488 need_redraw = ScreenLines[off] != c 7489 || (mbyte_cells == 2 7490 && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0)) 7491 || (enc_dbcs == DBCS_JPNU 7492 && c == 0x8e 7493 && ScreenLines2[off] != ptr[1]) 7494 || (enc_utf8 7495 && (ScreenLinesUC[off] != 7496 (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c) 7497 || (ScreenLinesUC[off] != 0 7498 && screen_comp_differs(off, u8cc)))) 7499 || ScreenAttrs[off] != attr 7500 || exmode_active; 7501 7502 if (need_redraw || force_redraw_this) 7503 { 7504 #if defined(FEAT_GUI) || defined(UNIX) 7505 /* The bold trick makes a single row of pixels appear in the next 7506 * character. When a bold character is removed, the next 7507 * character should be redrawn too. This happens for our own GUI 7508 * and for some xterms. */ 7509 if (need_redraw && ScreenLines[off] != ' ' && ( 7510 # ifdef FEAT_GUI 7511 gui.in_use 7512 # endif 7513 # if defined(FEAT_GUI) && defined(UNIX) 7514 || 7515 # endif 7516 # ifdef UNIX 7517 term_is_xterm 7518 # endif 7519 )) 7520 { 7521 int n = ScreenAttrs[off]; 7522 7523 if (n > HL_ALL) 7524 n = syn_attr2attr(n); 7525 if (n & HL_BOLD) 7526 force_redraw_next = TRUE; 7527 } 7528 #endif 7529 /* When at the end of the text and overwriting a two-cell 7530 * character with a one-cell character, need to clear the next 7531 * cell. Also when overwriting the left halve of a two-cell char 7532 * with the right halve of a two-cell char. Do this only once 7533 * (mb_off2cells() may return 2 on the right halve). */ 7534 if (clear_next_cell) 7535 clear_next_cell = FALSE; 7536 else if (has_mbyte 7537 && (len < 0 ? ptr[mbyte_blen] == NUL 7538 : ptr + mbyte_blen >= text + len) 7539 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1) 7540 || (mbyte_cells == 2 7541 && (*mb_off2cells)(off, max_off) == 1 7542 && (*mb_off2cells)(off + 1, max_off) > 1))) 7543 clear_next_cell = TRUE; 7544 7545 /* Make sure we never leave a second byte of a double-byte behind, 7546 * it confuses mb_off2cells(). */ 7547 if (enc_dbcs 7548 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1) 7549 || (mbyte_cells == 2 7550 && (*mb_off2cells)(off, max_off) == 1 7551 && (*mb_off2cells)(off + 1, max_off) > 1))) 7552 ScreenLines[off + mbyte_blen] = 0; 7553 ScreenLines[off] = c; 7554 ScreenAttrs[off] = attr; 7555 if (enc_utf8) 7556 { 7557 if (c < 0x80 && u8cc[0] == 0) 7558 ScreenLinesUC[off] = 0; 7559 else 7560 { 7561 int i; 7562 7563 ScreenLinesUC[off] = u8c; 7564 for (i = 0; i < Screen_mco; ++i) 7565 { 7566 ScreenLinesC[i][off] = u8cc[i]; 7567 if (u8cc[i] == 0) 7568 break; 7569 } 7570 } 7571 if (mbyte_cells == 2) 7572 { 7573 ScreenLines[off + 1] = 0; 7574 ScreenAttrs[off + 1] = attr; 7575 } 7576 screen_char(off, row, col); 7577 } 7578 else if (mbyte_cells == 2) 7579 { 7580 ScreenLines[off + 1] = ptr[1]; 7581 ScreenAttrs[off + 1] = attr; 7582 screen_char_2(off, row, col); 7583 } 7584 else if (enc_dbcs == DBCS_JPNU && c == 0x8e) 7585 { 7586 ScreenLines2[off] = ptr[1]; 7587 screen_char(off, row, col); 7588 } 7589 else 7590 screen_char(off, row, col); 7591 } 7592 if (has_mbyte) 7593 { 7594 off += mbyte_cells; 7595 col += mbyte_cells; 7596 ptr += mbyte_blen; 7597 if (clear_next_cell) 7598 { 7599 /* This only happens at the end, display one space next. */ 7600 ptr = (char_u *)" "; 7601 len = -1; 7602 } 7603 } 7604 else 7605 { 7606 ++off; 7607 ++col; 7608 ++ptr; 7609 } 7610 } 7611 7612 /* If we detected the next character needs to be redrawn, but the text 7613 * doesn't extend up to there, update the character here. */ 7614 if (force_redraw_next && col < screen_Columns) 7615 { 7616 if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1) 7617 screen_char_2(off, row, col); 7618 else 7619 screen_char(off, row, col); 7620 } 7621 } 7622 7623 #ifdef FEAT_SEARCH_EXTRA 7624 /* 7625 * Prepare for 'hlsearch' highlighting. 7626 */ 7627 static void 7628 start_search_hl(void) 7629 { 7630 if (p_hls && !no_hlsearch) 7631 { 7632 last_pat_prog(&search_hl.rm); 7633 search_hl.attr = HL_ATTR(HLF_L); 7634 # ifdef FEAT_RELTIME 7635 /* Set the time limit to 'redrawtime'. */ 7636 profile_setlimit(p_rdt, &search_hl.tm); 7637 # endif 7638 } 7639 } 7640 7641 /* 7642 * Clean up for 'hlsearch' highlighting. 7643 */ 7644 static void 7645 end_search_hl(void) 7646 { 7647 if (search_hl.rm.regprog != NULL) 7648 { 7649 vim_regfree(search_hl.rm.regprog); 7650 search_hl.rm.regprog = NULL; 7651 } 7652 } 7653 7654 /* 7655 * Init for calling prepare_search_hl(). 7656 */ 7657 static void 7658 init_search_hl(win_T *wp) 7659 { 7660 matchitem_T *cur; 7661 7662 /* Setup for match and 'hlsearch' highlighting. Disable any previous 7663 * match */ 7664 cur = wp->w_match_head; 7665 while (cur != NULL) 7666 { 7667 cur->hl.rm = cur->match; 7668 if (cur->hlg_id == 0) 7669 cur->hl.attr = 0; 7670 else 7671 cur->hl.attr = syn_id2attr(cur->hlg_id); 7672 cur->hl.buf = wp->w_buffer; 7673 cur->hl.lnum = 0; 7674 cur->hl.first_lnum = 0; 7675 # ifdef FEAT_RELTIME 7676 /* Set the time limit to 'redrawtime'. */ 7677 profile_setlimit(p_rdt, &(cur->hl.tm)); 7678 # endif 7679 cur = cur->next; 7680 } 7681 search_hl.buf = wp->w_buffer; 7682 search_hl.lnum = 0; 7683 search_hl.first_lnum = 0; 7684 /* time limit is set at the toplevel, for all windows */ 7685 } 7686 7687 /* 7688 * Advance to the match in window "wp" line "lnum" or past it. 7689 */ 7690 static void 7691 prepare_search_hl(win_T *wp, linenr_T lnum) 7692 { 7693 matchitem_T *cur; /* points to the match list */ 7694 match_T *shl; /* points to search_hl or a match */ 7695 int shl_flag; /* flag to indicate whether search_hl 7696 has been processed or not */ 7697 int pos_inprogress; /* marks that position match search is 7698 in progress */ 7699 int n; 7700 7701 /* 7702 * When using a multi-line pattern, start searching at the top 7703 * of the window or just after a closed fold. 7704 * Do this both for search_hl and the match list. 7705 */ 7706 cur = wp->w_match_head; 7707 shl_flag = FALSE; 7708 while (cur != NULL || shl_flag == FALSE) 7709 { 7710 if (shl_flag == FALSE) 7711 { 7712 shl = &search_hl; 7713 shl_flag = TRUE; 7714 } 7715 else 7716 shl = &cur->hl; 7717 if (shl->rm.regprog != NULL 7718 && shl->lnum == 0 7719 && re_multiline(shl->rm.regprog)) 7720 { 7721 if (shl->first_lnum == 0) 7722 { 7723 # ifdef FEAT_FOLDING 7724 for (shl->first_lnum = lnum; 7725 shl->first_lnum > wp->w_topline; --shl->first_lnum) 7726 if (hasFoldingWin(wp, shl->first_lnum - 1, 7727 NULL, NULL, TRUE, NULL)) 7728 break; 7729 # else 7730 shl->first_lnum = wp->w_topline; 7731 # endif 7732 } 7733 if (cur != NULL) 7734 cur->pos.cur = 0; 7735 pos_inprogress = TRUE; 7736 n = 0; 7737 while (shl->first_lnum < lnum && (shl->rm.regprog != NULL 7738 || (cur != NULL && pos_inprogress))) 7739 { 7740 next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, 7741 shl == &search_hl ? NULL : cur); 7742 pos_inprogress = cur == NULL || cur->pos.cur == 0 7743 ? FALSE : TRUE; 7744 if (shl->lnum != 0) 7745 { 7746 shl->first_lnum = shl->lnum 7747 + shl->rm.endpos[0].lnum 7748 - shl->rm.startpos[0].lnum; 7749 n = shl->rm.endpos[0].col; 7750 } 7751 else 7752 { 7753 ++shl->first_lnum; 7754 n = 0; 7755 } 7756 } 7757 } 7758 if (shl != &search_hl && cur != NULL) 7759 cur = cur->next; 7760 } 7761 } 7762 7763 /* 7764 * Search for a next 'hlsearch' or match. 7765 * Uses shl->buf. 7766 * Sets shl->lnum and shl->rm contents. 7767 * Note: Assumes a previous match is always before "lnum", unless 7768 * shl->lnum is zero. 7769 * Careful: Any pointers for buffer lines will become invalid. 7770 */ 7771 static void 7772 next_search_hl( 7773 win_T *win, 7774 match_T *shl, /* points to search_hl or a match */ 7775 linenr_T lnum, 7776 colnr_T mincol, /* minimal column for a match */ 7777 matchitem_T *cur) /* to retrieve match positions if any */ 7778 { 7779 linenr_T l; 7780 colnr_T matchcol; 7781 long nmatched; 7782 int save_called_emsg = called_emsg; 7783 7784 // for :{range}s/pat only highlight inside the range 7785 if (lnum < search_first_line || lnum > search_last_line) 7786 { 7787 shl->lnum = 0; 7788 return; 7789 } 7790 7791 if (shl->lnum != 0) 7792 { 7793 /* Check for three situations: 7794 * 1. If the "lnum" is below a previous match, start a new search. 7795 * 2. If the previous match includes "mincol", use it. 7796 * 3. Continue after the previous match. 7797 */ 7798 l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum; 7799 if (lnum > l) 7800 shl->lnum = 0; 7801 else if (lnum < l || shl->rm.endpos[0].col > mincol) 7802 return; 7803 } 7804 7805 /* 7806 * Repeat searching for a match until one is found that includes "mincol" 7807 * or none is found in this line. 7808 */ 7809 called_emsg = FALSE; 7810 for (;;) 7811 { 7812 #ifdef FEAT_RELTIME 7813 /* Stop searching after passing the time limit. */ 7814 if (profile_passed_limit(&(shl->tm))) 7815 { 7816 shl->lnum = 0; /* no match found in time */ 7817 break; 7818 } 7819 #endif 7820 /* Three situations: 7821 * 1. No useful previous match: search from start of line. 7822 * 2. Not Vi compatible or empty match: continue at next character. 7823 * Break the loop if this is beyond the end of the line. 7824 * 3. Vi compatible searching: continue at end of previous match. 7825 */ 7826 if (shl->lnum == 0) 7827 matchcol = 0; 7828 else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL 7829 || (shl->rm.endpos[0].lnum == 0 7830 && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) 7831 { 7832 char_u *ml; 7833 7834 matchcol = shl->rm.startpos[0].col; 7835 ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol; 7836 if (*ml == NUL) 7837 { 7838 ++matchcol; 7839 shl->lnum = 0; 7840 break; 7841 } 7842 if (has_mbyte) 7843 matchcol += mb_ptr2len(ml); 7844 else 7845 ++matchcol; 7846 } 7847 else 7848 matchcol = shl->rm.endpos[0].col; 7849 7850 shl->lnum = lnum; 7851 if (shl->rm.regprog != NULL) 7852 { 7853 /* Remember whether shl->rm is using a copy of the regprog in 7854 * cur->match. */ 7855 int regprog_is_copy = (shl != &search_hl && cur != NULL 7856 && shl == &cur->hl 7857 && cur->match.regprog == cur->hl.rm.regprog); 7858 int timed_out = FALSE; 7859 7860 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, 7861 matchcol, 7862 #ifdef FEAT_RELTIME 7863 &(shl->tm), &timed_out 7864 #else 7865 NULL, NULL 7866 #endif 7867 ); 7868 /* Copy the regprog, in case it got freed and recompiled. */ 7869 if (regprog_is_copy) 7870 cur->match.regprog = cur->hl.rm.regprog; 7871 7872 if (called_emsg || got_int || timed_out) 7873 { 7874 /* Error while handling regexp: stop using this regexp. */ 7875 if (shl == &search_hl) 7876 { 7877 /* don't free regprog in the match list, it's a copy */ 7878 vim_regfree(shl->rm.regprog); 7879 set_no_hlsearch(TRUE); 7880 } 7881 shl->rm.regprog = NULL; 7882 shl->lnum = 0; 7883 got_int = FALSE; /* avoid the "Type :quit to exit Vim" 7884 message */ 7885 break; 7886 } 7887 } 7888 else if (cur != NULL) 7889 nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); 7890 else 7891 nmatched = 0; 7892 if (nmatched == 0) 7893 { 7894 shl->lnum = 0; /* no match found */ 7895 break; 7896 } 7897 if (shl->rm.startpos[0].lnum > 0 7898 || shl->rm.startpos[0].col >= mincol 7899 || nmatched > 1 7900 || shl->rm.endpos[0].col > mincol) 7901 { 7902 shl->lnum += shl->rm.startpos[0].lnum; 7903 break; /* useful match found */ 7904 } 7905 } 7906 7907 // Restore called_emsg for assert_fails(). 7908 called_emsg = save_called_emsg; 7909 } 7910 7911 /* 7912 * If there is a match fill "shl" and return one. 7913 * Return zero otherwise. 7914 */ 7915 static int 7916 next_search_hl_pos( 7917 match_T *shl, /* points to a match */ 7918 linenr_T lnum, 7919 posmatch_T *posmatch, /* match positions */ 7920 colnr_T mincol) /* minimal column for a match */ 7921 { 7922 int i; 7923 int found = -1; 7924 7925 for (i = posmatch->cur; i < MAXPOSMATCH; i++) 7926 { 7927 llpos_T *pos = &posmatch->pos[i]; 7928 7929 if (pos->lnum == 0) 7930 break; 7931 if (pos->len == 0 && pos->col < mincol) 7932 continue; 7933 if (pos->lnum == lnum) 7934 { 7935 if (found >= 0) 7936 { 7937 /* if this match comes before the one at "found" then swap 7938 * them */ 7939 if (pos->col < posmatch->pos[found].col) 7940 { 7941 llpos_T tmp = *pos; 7942 7943 *pos = posmatch->pos[found]; 7944 posmatch->pos[found] = tmp; 7945 } 7946 } 7947 else 7948 found = i; 7949 } 7950 } 7951 posmatch->cur = 0; 7952 if (found >= 0) 7953 { 7954 colnr_T start = posmatch->pos[found].col == 0 7955 ? 0 : posmatch->pos[found].col - 1; 7956 colnr_T end = posmatch->pos[found].col == 0 7957 ? MAXCOL : start + posmatch->pos[found].len; 7958 7959 shl->lnum = lnum; 7960 shl->rm.startpos[0].lnum = 0; 7961 shl->rm.startpos[0].col = start; 7962 shl->rm.endpos[0].lnum = 0; 7963 shl->rm.endpos[0].col = end; 7964 shl->is_addpos = TRUE; 7965 posmatch->cur = found + 1; 7966 return 1; 7967 } 7968 return 0; 7969 } 7970 #endif 7971 7972 static void 7973 screen_start_highlight(int attr) 7974 { 7975 attrentry_T *aep = NULL; 7976 7977 screen_attr = attr; 7978 if (full_screen 7979 #ifdef MSWIN 7980 && termcap_active 7981 #endif 7982 ) 7983 { 7984 #ifdef FEAT_GUI 7985 if (gui.in_use) 7986 { 7987 char buf[20]; 7988 7989 /* The GUI handles this internally. */ 7990 sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr); 7991 OUT_STR(buf); 7992 } 7993 else 7994 #endif 7995 { 7996 if (attr > HL_ALL) /* special HL attr. */ 7997 { 7998 if (IS_CTERM) 7999 aep = syn_cterm_attr2entry(attr); 8000 else 8001 aep = syn_term_attr2entry(attr); 8002 if (aep == NULL) /* did ":syntax clear" */ 8003 attr = 0; 8004 else 8005 attr = aep->ae_attr; 8006 } 8007 if ((attr & HL_BOLD) && *T_MD != NUL) /* bold */ 8008 out_str(T_MD); 8009 else if (aep != NULL && cterm_normal_fg_bold && ( 8010 #ifdef FEAT_TERMGUICOLORS 8011 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR 8012 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR 8013 : 8014 #endif 8015 t_colors > 1 && aep->ae_u.cterm.fg_color)) 8016 /* If the Normal FG color has BOLD attribute and the new HL 8017 * has a FG color defined, clear BOLD. */ 8018 out_str(T_ME); 8019 if ((attr & HL_STANDOUT) && *T_SO != NUL) /* standout */ 8020 out_str(T_SO); 8021 if ((attr & HL_UNDERCURL) && *T_UCS != NUL) /* undercurl */ 8022 out_str(T_UCS); 8023 if (((attr & HL_UNDERLINE) /* underline or undercurl */ 8024 || ((attr & HL_UNDERCURL) && *T_UCS == NUL)) 8025 && *T_US != NUL) 8026 out_str(T_US); 8027 if ((attr & HL_ITALIC) && *T_CZH != NUL) /* italic */ 8028 out_str(T_CZH); 8029 if ((attr & HL_INVERSE) && *T_MR != NUL) /* inverse (reverse) */ 8030 out_str(T_MR); 8031 if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) /* strike */ 8032 out_str(T_STS); 8033 8034 /* 8035 * Output the color or start string after bold etc., in case the 8036 * bold etc. override the color setting. 8037 */ 8038 if (aep != NULL) 8039 { 8040 #ifdef FEAT_TERMGUICOLORS 8041 /* When 'termguicolors' is set but fg or bg is unset, 8042 * fall back to the cterm colors. This helps for SpellBad, 8043 * where the GUI uses a red undercurl. */ 8044 if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR) 8045 { 8046 if (aep->ae_u.cterm.fg_rgb != INVALCOLOR) 8047 term_fg_rgb_color(aep->ae_u.cterm.fg_rgb); 8048 } 8049 else 8050 #endif 8051 if (t_colors > 1) 8052 { 8053 if (aep->ae_u.cterm.fg_color) 8054 term_fg_color(aep->ae_u.cterm.fg_color - 1); 8055 } 8056 #ifdef FEAT_TERMGUICOLORS 8057 if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR) 8058 { 8059 if (aep->ae_u.cterm.bg_rgb != INVALCOLOR) 8060 term_bg_rgb_color(aep->ae_u.cterm.bg_rgb); 8061 } 8062 else 8063 #endif 8064 if (t_colors > 1) 8065 { 8066 if (aep->ae_u.cterm.bg_color) 8067 term_bg_color(aep->ae_u.cterm.bg_color - 1); 8068 } 8069 8070 if (!IS_CTERM) 8071 { 8072 if (aep->ae_u.term.start != NULL) 8073 out_str(aep->ae_u.term.start); 8074 } 8075 } 8076 } 8077 } 8078 } 8079 8080 void 8081 screen_stop_highlight(void) 8082 { 8083 int do_ME = FALSE; /* output T_ME code */ 8084 8085 if (screen_attr != 0 8086 #ifdef MSWIN 8087 && termcap_active 8088 #endif 8089 ) 8090 { 8091 #ifdef FEAT_GUI 8092 if (gui.in_use) 8093 { 8094 char buf[20]; 8095 8096 /* use internal GUI code */ 8097 sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr); 8098 OUT_STR(buf); 8099 } 8100 else 8101 #endif 8102 { 8103 if (screen_attr > HL_ALL) /* special HL attr. */ 8104 { 8105 attrentry_T *aep; 8106 8107 if (IS_CTERM) 8108 { 8109 /* 8110 * Assume that t_me restores the original colors! 8111 */ 8112 aep = syn_cterm_attr2entry(screen_attr); 8113 if (aep != NULL && (( 8114 #ifdef FEAT_TERMGUICOLORS 8115 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR 8116 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR 8117 : 8118 #endif 8119 aep->ae_u.cterm.fg_color) || ( 8120 #ifdef FEAT_TERMGUICOLORS 8121 p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR 8122 ? aep->ae_u.cterm.bg_rgb != INVALCOLOR 8123 : 8124 #endif 8125 aep->ae_u.cterm.bg_color))) 8126 do_ME = TRUE; 8127 } 8128 else 8129 { 8130 aep = syn_term_attr2entry(screen_attr); 8131 if (aep != NULL && aep->ae_u.term.stop != NULL) 8132 { 8133 if (STRCMP(aep->ae_u.term.stop, T_ME) == 0) 8134 do_ME = TRUE; 8135 else 8136 out_str(aep->ae_u.term.stop); 8137 } 8138 } 8139 if (aep == NULL) /* did ":syntax clear" */ 8140 screen_attr = 0; 8141 else 8142 screen_attr = aep->ae_attr; 8143 } 8144 8145 /* 8146 * Often all ending-codes are equal to T_ME. Avoid outputting the 8147 * same sequence several times. 8148 */ 8149 if (screen_attr & HL_STANDOUT) 8150 { 8151 if (STRCMP(T_SE, T_ME) == 0) 8152 do_ME = TRUE; 8153 else 8154 out_str(T_SE); 8155 } 8156 if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL) 8157 { 8158 if (STRCMP(T_UCE, T_ME) == 0) 8159 do_ME = TRUE; 8160 else 8161 out_str(T_UCE); 8162 } 8163 if ((screen_attr & HL_UNDERLINE) 8164 || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL)) 8165 { 8166 if (STRCMP(T_UE, T_ME) == 0) 8167 do_ME = TRUE; 8168 else 8169 out_str(T_UE); 8170 } 8171 if (screen_attr & HL_ITALIC) 8172 { 8173 if (STRCMP(T_CZR, T_ME) == 0) 8174 do_ME = TRUE; 8175 else 8176 out_str(T_CZR); 8177 } 8178 if (screen_attr & HL_STRIKETHROUGH) 8179 { 8180 if (STRCMP(T_STE, T_ME) == 0) 8181 do_ME = TRUE; 8182 else 8183 out_str(T_STE); 8184 } 8185 if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE))) 8186 out_str(T_ME); 8187 8188 #ifdef FEAT_TERMGUICOLORS 8189 if (p_tgc) 8190 { 8191 if (cterm_normal_fg_gui_color != INVALCOLOR) 8192 term_fg_rgb_color(cterm_normal_fg_gui_color); 8193 if (cterm_normal_bg_gui_color != INVALCOLOR) 8194 term_bg_rgb_color(cterm_normal_bg_gui_color); 8195 } 8196 else 8197 #endif 8198 { 8199 if (t_colors > 1) 8200 { 8201 /* set Normal cterm colors */ 8202 if (cterm_normal_fg_color != 0) 8203 term_fg_color(cterm_normal_fg_color - 1); 8204 if (cterm_normal_bg_color != 0) 8205 term_bg_color(cterm_normal_bg_color - 1); 8206 if (cterm_normal_fg_bold) 8207 out_str(T_MD); 8208 } 8209 } 8210 } 8211 } 8212 screen_attr = 0; 8213 } 8214 8215 /* 8216 * Reset the colors for a cterm. Used when leaving Vim. 8217 * The machine specific code may override this again. 8218 */ 8219 void 8220 reset_cterm_colors(void) 8221 { 8222 if (IS_CTERM) 8223 { 8224 /* set Normal cterm colors */ 8225 #ifdef FEAT_TERMGUICOLORS 8226 if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR 8227 || cterm_normal_bg_gui_color != INVALCOLOR) 8228 : (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)) 8229 #else 8230 if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0) 8231 #endif 8232 { 8233 out_str(T_OP); 8234 screen_attr = -1; 8235 } 8236 if (cterm_normal_fg_bold) 8237 { 8238 out_str(T_ME); 8239 screen_attr = -1; 8240 } 8241 } 8242 } 8243 8244 /* 8245 * Put character ScreenLines["off"] on the screen at position "row" and "col", 8246 * using the attributes from ScreenAttrs["off"]. 8247 */ 8248 static void 8249 screen_char(unsigned off, int row, int col) 8250 { 8251 int attr; 8252 8253 /* Check for illegal values, just in case (could happen just after 8254 * resizing). */ 8255 if (row >= screen_Rows || col >= screen_Columns) 8256 return; 8257 8258 #ifdef FEAT_INS_EXPAND 8259 if (pum_under_menu(row, col)) 8260 return; 8261 #endif 8262 /* Outputting a character in the last cell on the screen may scroll the 8263 * screen up. Only do it when the "xn" termcap property is set, otherwise 8264 * mark the character invalid (update it when scrolled up). */ 8265 if (*T_XN == NUL 8266 && row == screen_Rows - 1 && col == screen_Columns - 1 8267 #ifdef FEAT_RIGHTLEFT 8268 /* account for first command-line character in rightleft mode */ 8269 && !cmdmsg_rl 8270 #endif 8271 ) 8272 { 8273 ScreenAttrs[off] = (sattr_T)-1; 8274 return; 8275 } 8276 8277 /* 8278 * Stop highlighting first, so it's easier to move the cursor. 8279 */ 8280 if (screen_char_attr != 0) 8281 attr = screen_char_attr; 8282 else 8283 attr = ScreenAttrs[off]; 8284 if (screen_attr != attr) 8285 screen_stop_highlight(); 8286 8287 windgoto(row, col); 8288 8289 if (screen_attr != attr) 8290 screen_start_highlight(attr); 8291 8292 if (enc_utf8 && ScreenLinesUC[off] != 0) 8293 { 8294 char_u buf[MB_MAXBYTES + 1]; 8295 8296 if (utf_ambiguous_width(ScreenLinesUC[off])) 8297 { 8298 if (*p_ambw == 'd' 8299 #ifdef FEAT_GUI 8300 && !gui.in_use 8301 #endif 8302 ) 8303 { 8304 /* Clear the two screen cells. If the character is actually 8305 * single width it won't change the second cell. */ 8306 out_str((char_u *)" "); 8307 term_windgoto(row, col); 8308 } 8309 /* not sure where the cursor is after drawing the ambiguous width 8310 * character */ 8311 screen_cur_col = 9999; 8312 } 8313 else if (utf_char2cells(ScreenLinesUC[off]) > 1) 8314 ++screen_cur_col; 8315 8316 /* Convert the UTF-8 character to bytes and write it. */ 8317 buf[utfc_char2bytes(off, buf)] = NUL; 8318 out_str(buf); 8319 } 8320 else 8321 { 8322 out_flush_check(); 8323 out_char(ScreenLines[off]); 8324 /* double-byte character in single-width cell */ 8325 if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e) 8326 out_char(ScreenLines2[off]); 8327 } 8328 8329 screen_cur_col++; 8330 } 8331 8332 /* 8333 * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"] 8334 * on the screen at position 'row' and 'col'. 8335 * The attributes of the first byte is used for all. This is required to 8336 * output the two bytes of a double-byte character with nothing in between. 8337 */ 8338 static void 8339 screen_char_2(unsigned off, int row, int col) 8340 { 8341 /* Check for illegal values (could be wrong when screen was resized). */ 8342 if (off + 1 >= (unsigned)(screen_Rows * screen_Columns)) 8343 return; 8344 8345 /* Outputting the last character on the screen may scrollup the screen. 8346 * Don't to it! Mark the character invalid (update it when scrolled up) */ 8347 if (row == screen_Rows - 1 && col >= screen_Columns - 2) 8348 { 8349 ScreenAttrs[off] = (sattr_T)-1; 8350 return; 8351 } 8352 8353 /* Output the first byte normally (positions the cursor), then write the 8354 * second byte directly. */ 8355 screen_char(off, row, col); 8356 out_char(ScreenLines[off + 1]); 8357 ++screen_cur_col; 8358 } 8359 8360 /* 8361 * Draw a rectangle of the screen, inverted when "invert" is TRUE. 8362 * This uses the contents of ScreenLines[] and doesn't change it. 8363 */ 8364 void 8365 screen_draw_rectangle( 8366 int row, 8367 int col, 8368 int height, 8369 int width, 8370 int invert) 8371 { 8372 int r, c; 8373 int off; 8374 int max_off; 8375 8376 /* Can't use ScreenLines unless initialized */ 8377 if (ScreenLines == NULL) 8378 return; 8379 8380 if (invert) 8381 screen_char_attr = HL_INVERSE; 8382 for (r = row; r < row + height; ++r) 8383 { 8384 off = LineOffset[r]; 8385 max_off = off + screen_Columns; 8386 for (c = col; c < col + width; ++c) 8387 { 8388 if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1) 8389 { 8390 screen_char_2(off + c, r, c); 8391 ++c; 8392 } 8393 else 8394 { 8395 screen_char(off + c, r, c); 8396 if (utf_off2cells(off + c, max_off) > 1) 8397 ++c; 8398 } 8399 } 8400 } 8401 screen_char_attr = 0; 8402 } 8403 8404 /* 8405 * Redraw the characters for a vertically split window. 8406 */ 8407 static void 8408 redraw_block(int row, int end, win_T *wp) 8409 { 8410 int col; 8411 int width; 8412 8413 # ifdef FEAT_CLIPBOARD 8414 clip_may_clear_selection(row, end - 1); 8415 # endif 8416 8417 if (wp == NULL) 8418 { 8419 col = 0; 8420 width = Columns; 8421 } 8422 else 8423 { 8424 col = wp->w_wincol; 8425 width = wp->w_width; 8426 } 8427 screen_draw_rectangle(row, col, end - row, width, FALSE); 8428 } 8429 8430 static void 8431 space_to_screenline(int off, int attr) 8432 { 8433 ScreenLines[off] = ' '; 8434 ScreenAttrs[off] = attr; 8435 if (enc_utf8) 8436 ScreenLinesUC[off] = 0; 8437 } 8438 8439 /* 8440 * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col' 8441 * with character 'c1' in first column followed by 'c2' in the other columns. 8442 * Use attributes 'attr'. 8443 */ 8444 void 8445 screen_fill( 8446 int start_row, 8447 int end_row, 8448 int start_col, 8449 int end_col, 8450 int c1, 8451 int c2, 8452 int attr) 8453 { 8454 int row; 8455 int col; 8456 int off; 8457 int end_off; 8458 int did_delete; 8459 int c; 8460 int norm_term; 8461 #if defined(FEAT_GUI) || defined(UNIX) 8462 int force_next = FALSE; 8463 #endif 8464 8465 if (end_row > screen_Rows) /* safety check */ 8466 end_row = screen_Rows; 8467 if (end_col > screen_Columns) /* safety check */ 8468 end_col = screen_Columns; 8469 if (ScreenLines == NULL 8470 || start_row >= end_row 8471 || start_col >= end_col) /* nothing to do */ 8472 return; 8473 8474 /* it's a "normal" terminal when not in a GUI or cterm */ 8475 norm_term = ( 8476 #ifdef FEAT_GUI 8477 !gui.in_use && 8478 #endif 8479 !IS_CTERM); 8480 for (row = start_row; row < end_row; ++row) 8481 { 8482 if (has_mbyte 8483 #ifdef FEAT_GUI 8484 && !gui.in_use 8485 #endif 8486 ) 8487 { 8488 /* When drawing over the right halve of a double-wide char clear 8489 * out the left halve. When drawing over the left halve of a 8490 * double wide-char clear out the right halve. Only needed in a 8491 * terminal. */ 8492 if (start_col > 0 && mb_fix_col(start_col, row) != start_col) 8493 screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0); 8494 if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col) 8495 screen_puts_len((char_u *)" ", 1, row, end_col, 0); 8496 } 8497 /* 8498 * Try to use delete-line termcap code, when no attributes or in a 8499 * "normal" terminal, where a bold/italic space is just a 8500 * space. 8501 */ 8502 did_delete = FALSE; 8503 if (c2 == ' ' 8504 && end_col == Columns 8505 && can_clear(T_CE) 8506 && (attr == 0 8507 || (norm_term 8508 && attr <= HL_ALL 8509 && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0)))) 8510 { 8511 /* 8512 * check if we really need to clear something 8513 */ 8514 col = start_col; 8515 if (c1 != ' ') /* don't clear first char */ 8516 ++col; 8517 8518 off = LineOffset[row] + col; 8519 end_off = LineOffset[row] + end_col; 8520 8521 /* skip blanks (used often, keep it fast!) */ 8522 if (enc_utf8) 8523 while (off < end_off && ScreenLines[off] == ' ' 8524 && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0) 8525 ++off; 8526 else 8527 while (off < end_off && ScreenLines[off] == ' ' 8528 && ScreenAttrs[off] == 0) 8529 ++off; 8530 if (off < end_off) /* something to be cleared */ 8531 { 8532 col = off - LineOffset[row]; 8533 screen_stop_highlight(); 8534 term_windgoto(row, col);/* clear rest of this screen line */ 8535 out_str(T_CE); 8536 screen_start(); /* don't know where cursor is now */ 8537 col = end_col - col; 8538 while (col--) /* clear chars in ScreenLines */ 8539 { 8540 space_to_screenline(off, 0); 8541 ++off; 8542 } 8543 } 8544 did_delete = TRUE; /* the chars are cleared now */ 8545 } 8546 8547 off = LineOffset[row] + start_col; 8548 c = c1; 8549 for (col = start_col; col < end_col; ++col) 8550 { 8551 if (ScreenLines[off] != c 8552 || (enc_utf8 && (int)ScreenLinesUC[off] 8553 != (c >= 0x80 ? c : 0)) 8554 || ScreenAttrs[off] != attr 8555 #if defined(FEAT_GUI) || defined(UNIX) 8556 || force_next 8557 #endif 8558 ) 8559 { 8560 #if defined(FEAT_GUI) || defined(UNIX) 8561 /* The bold trick may make a single row of pixels appear in 8562 * the next character. When a bold character is removed, the 8563 * next character should be redrawn too. This happens for our 8564 * own GUI and for some xterms. */ 8565 if ( 8566 # ifdef FEAT_GUI 8567 gui.in_use 8568 # endif 8569 # if defined(FEAT_GUI) && defined(UNIX) 8570 || 8571 # endif 8572 # ifdef UNIX 8573 term_is_xterm 8574 # endif 8575 ) 8576 { 8577 if (ScreenLines[off] != ' ' 8578 && (ScreenAttrs[off] > HL_ALL 8579 || ScreenAttrs[off] & HL_BOLD)) 8580 force_next = TRUE; 8581 else 8582 force_next = FALSE; 8583 } 8584 #endif 8585 ScreenLines[off] = c; 8586 if (enc_utf8) 8587 { 8588 if (c >= 0x80) 8589 { 8590 ScreenLinesUC[off] = c; 8591 ScreenLinesC[0][off] = 0; 8592 } 8593 else 8594 ScreenLinesUC[off] = 0; 8595 } 8596 ScreenAttrs[off] = attr; 8597 if (!did_delete || c != ' ') 8598 screen_char(off, row, col); 8599 } 8600 ++off; 8601 if (col == start_col) 8602 { 8603 if (did_delete) 8604 break; 8605 c = c2; 8606 } 8607 } 8608 if (end_col == Columns) 8609 LineWraps[row] = FALSE; 8610 if (row == Rows - 1) /* overwritten the command line */ 8611 { 8612 redraw_cmdline = TRUE; 8613 if (start_col == 0 && end_col == Columns 8614 && c1 == ' ' && c2 == ' ' && attr == 0) 8615 clear_cmdline = FALSE; /* command line has been cleared */ 8616 if (start_col == 0) 8617 mode_displayed = FALSE; /* mode cleared or overwritten */ 8618 } 8619 } 8620 } 8621 8622 /* 8623 * Check if there should be a delay. Used before clearing or redrawing the 8624 * screen or the command line. 8625 */ 8626 void 8627 check_for_delay(int check_msg_scroll) 8628 { 8629 if ((emsg_on_display || (check_msg_scroll && msg_scroll)) 8630 && !did_wait_return 8631 && emsg_silent == 0) 8632 { 8633 out_flush(); 8634 ui_delay(1000L, TRUE); 8635 emsg_on_display = FALSE; 8636 if (check_msg_scroll) 8637 msg_scroll = FALSE; 8638 } 8639 } 8640 8641 /* 8642 * screen_valid - allocate screen buffers if size changed 8643 * If "doclear" is TRUE: clear screen if it has been resized. 8644 * Returns TRUE if there is a valid screen to write to. 8645 * Returns FALSE when starting up and screen not initialized yet. 8646 */ 8647 int 8648 screen_valid(int doclear) 8649 { 8650 screenalloc(doclear); /* allocate screen buffers if size changed */ 8651 return (ScreenLines != NULL); 8652 } 8653 8654 /* 8655 * Resize the shell to Rows and Columns. 8656 * Allocate ScreenLines[] and associated items. 8657 * 8658 * There may be some time between setting Rows and Columns and (re)allocating 8659 * ScreenLines[]. This happens when starting up and when (manually) changing 8660 * the shell size. Always use screen_Rows and screen_Columns to access items 8661 * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the 8662 * final size of the shell is needed. 8663 */ 8664 void 8665 screenalloc(int doclear) 8666 { 8667 int new_row, old_row; 8668 #ifdef FEAT_GUI 8669 int old_Rows; 8670 #endif 8671 win_T *wp; 8672 int outofmem = FALSE; 8673 int len; 8674 schar_T *new_ScreenLines; 8675 u8char_T *new_ScreenLinesUC = NULL; 8676 u8char_T *new_ScreenLinesC[MAX_MCO]; 8677 schar_T *new_ScreenLines2 = NULL; 8678 int i; 8679 sattr_T *new_ScreenAttrs; 8680 unsigned *new_LineOffset; 8681 char_u *new_LineWraps; 8682 short *new_TabPageIdxs; 8683 tabpage_T *tp; 8684 static int entered = FALSE; /* avoid recursiveness */ 8685 static int done_outofmem_msg = FALSE; /* did outofmem message */ 8686 int retry_count = 0; 8687 8688 retry: 8689 /* 8690 * Allocation of the screen buffers is done only when the size changes and 8691 * when Rows and Columns have been set and we have started doing full 8692 * screen stuff. 8693 */ 8694 if ((ScreenLines != NULL 8695 && Rows == screen_Rows 8696 && Columns == screen_Columns 8697 && enc_utf8 == (ScreenLinesUC != NULL) 8698 && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL) 8699 && p_mco == Screen_mco) 8700 || Rows == 0 8701 || Columns == 0 8702 || (!full_screen && ScreenLines == NULL)) 8703 return; 8704 8705 /* 8706 * It's possible that we produce an out-of-memory message below, which 8707 * will cause this function to be called again. To break the loop, just 8708 * return here. 8709 */ 8710 if (entered) 8711 return; 8712 entered = TRUE; 8713 8714 /* 8715 * Note that the window sizes are updated before reallocating the arrays, 8716 * thus we must not redraw here! 8717 */ 8718 ++RedrawingDisabled; 8719 8720 win_new_shellsize(); /* fit the windows in the new sized shell */ 8721 8722 comp_col(); /* recompute columns for shown command and ruler */ 8723 8724 /* 8725 * We're changing the size of the screen. 8726 * - Allocate new arrays for ScreenLines and ScreenAttrs. 8727 * - Move lines from the old arrays into the new arrays, clear extra 8728 * lines (unless the screen is going to be cleared). 8729 * - Free the old arrays. 8730 * 8731 * If anything fails, make ScreenLines NULL, so we don't do anything! 8732 * Continuing with the old ScreenLines may result in a crash, because the 8733 * size is wrong. 8734 */ 8735 FOR_ALL_TAB_WINDOWS(tp, wp) 8736 win_free_lsize(wp); 8737 if (aucmd_win != NULL) 8738 win_free_lsize(aucmd_win); 8739 8740 new_ScreenLines = (schar_T *)lalloc((long_u)( 8741 (Rows + 1) * Columns * sizeof(schar_T)), FALSE); 8742 vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO); 8743 if (enc_utf8) 8744 { 8745 new_ScreenLinesUC = (u8char_T *)lalloc((long_u)( 8746 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE); 8747 for (i = 0; i < p_mco; ++i) 8748 new_ScreenLinesC[i] = (u8char_T *)lalloc_clear((long_u)( 8749 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE); 8750 } 8751 if (enc_dbcs == DBCS_JPNU) 8752 new_ScreenLines2 = (schar_T *)lalloc((long_u)( 8753 (Rows + 1) * Columns * sizeof(schar_T)), FALSE); 8754 new_ScreenAttrs = (sattr_T *)lalloc((long_u)( 8755 (Rows + 1) * Columns * sizeof(sattr_T)), FALSE); 8756 new_LineOffset = (unsigned *)lalloc((long_u)( 8757 Rows * sizeof(unsigned)), FALSE); 8758 new_LineWraps = (char_u *)lalloc((long_u)(Rows * sizeof(char_u)), FALSE); 8759 new_TabPageIdxs = (short *)lalloc((long_u)(Columns * sizeof(short)), FALSE); 8760 8761 FOR_ALL_TAB_WINDOWS(tp, wp) 8762 { 8763 if (win_alloc_lines(wp) == FAIL) 8764 { 8765 outofmem = TRUE; 8766 goto give_up; 8767 } 8768 } 8769 if (aucmd_win != NULL && aucmd_win->w_lines == NULL 8770 && win_alloc_lines(aucmd_win) == FAIL) 8771 outofmem = TRUE; 8772 give_up: 8773 8774 for (i = 0; i < p_mco; ++i) 8775 if (new_ScreenLinesC[i] == NULL) 8776 break; 8777 if (new_ScreenLines == NULL 8778 || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco)) 8779 || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL) 8780 || new_ScreenAttrs == NULL 8781 || new_LineOffset == NULL 8782 || new_LineWraps == NULL 8783 || new_TabPageIdxs == NULL 8784 || outofmem) 8785 { 8786 if (ScreenLines != NULL || !done_outofmem_msg) 8787 { 8788 /* guess the size */ 8789 do_outofmem_msg((long_u)((Rows + 1) * Columns)); 8790 8791 /* Remember we did this to avoid getting outofmem messages over 8792 * and over again. */ 8793 done_outofmem_msg = TRUE; 8794 } 8795 VIM_CLEAR(new_ScreenLines); 8796 VIM_CLEAR(new_ScreenLinesUC); 8797 for (i = 0; i < p_mco; ++i) 8798 VIM_CLEAR(new_ScreenLinesC[i]); 8799 VIM_CLEAR(new_ScreenLines2); 8800 VIM_CLEAR(new_ScreenAttrs); 8801 VIM_CLEAR(new_LineOffset); 8802 VIM_CLEAR(new_LineWraps); 8803 VIM_CLEAR(new_TabPageIdxs); 8804 } 8805 else 8806 { 8807 done_outofmem_msg = FALSE; 8808 8809 for (new_row = 0; new_row < Rows; ++new_row) 8810 { 8811 new_LineOffset[new_row] = new_row * Columns; 8812 new_LineWraps[new_row] = FALSE; 8813 8814 /* 8815 * If the screen is not going to be cleared, copy as much as 8816 * possible from the old screen to the new one and clear the rest 8817 * (used when resizing the window at the "--more--" prompt or when 8818 * executing an external command, for the GUI). 8819 */ 8820 if (!doclear) 8821 { 8822 (void)vim_memset(new_ScreenLines + new_row * Columns, 8823 ' ', (size_t)Columns * sizeof(schar_T)); 8824 if (enc_utf8) 8825 { 8826 (void)vim_memset(new_ScreenLinesUC + new_row * Columns, 8827 0, (size_t)Columns * sizeof(u8char_T)); 8828 for (i = 0; i < p_mco; ++i) 8829 (void)vim_memset(new_ScreenLinesC[i] 8830 + new_row * Columns, 8831 0, (size_t)Columns * sizeof(u8char_T)); 8832 } 8833 if (enc_dbcs == DBCS_JPNU) 8834 (void)vim_memset(new_ScreenLines2 + new_row * Columns, 8835 0, (size_t)Columns * sizeof(schar_T)); 8836 (void)vim_memset(new_ScreenAttrs + new_row * Columns, 8837 0, (size_t)Columns * sizeof(sattr_T)); 8838 old_row = new_row + (screen_Rows - Rows); 8839 if (old_row >= 0 && ScreenLines != NULL) 8840 { 8841 if (screen_Columns < Columns) 8842 len = screen_Columns; 8843 else 8844 len = Columns; 8845 /* When switching to utf-8 don't copy characters, they 8846 * may be invalid now. Also when p_mco changes. */ 8847 if (!(enc_utf8 && ScreenLinesUC == NULL) 8848 && p_mco == Screen_mco) 8849 mch_memmove(new_ScreenLines + new_LineOffset[new_row], 8850 ScreenLines + LineOffset[old_row], 8851 (size_t)len * sizeof(schar_T)); 8852 if (enc_utf8 && ScreenLinesUC != NULL 8853 && p_mco == Screen_mco) 8854 { 8855 mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row], 8856 ScreenLinesUC + LineOffset[old_row], 8857 (size_t)len * sizeof(u8char_T)); 8858 for (i = 0; i < p_mco; ++i) 8859 mch_memmove(new_ScreenLinesC[i] 8860 + new_LineOffset[new_row], 8861 ScreenLinesC[i] + LineOffset[old_row], 8862 (size_t)len * sizeof(u8char_T)); 8863 } 8864 if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL) 8865 mch_memmove(new_ScreenLines2 + new_LineOffset[new_row], 8866 ScreenLines2 + LineOffset[old_row], 8867 (size_t)len * sizeof(schar_T)); 8868 mch_memmove(new_ScreenAttrs + new_LineOffset[new_row], 8869 ScreenAttrs + LineOffset[old_row], 8870 (size_t)len * sizeof(sattr_T)); 8871 } 8872 } 8873 } 8874 /* Use the last line of the screen for the current line. */ 8875 current_ScreenLine = new_ScreenLines + Rows * Columns; 8876 } 8877 8878 free_screenlines(); 8879 8880 ScreenLines = new_ScreenLines; 8881 ScreenLinesUC = new_ScreenLinesUC; 8882 for (i = 0; i < p_mco; ++i) 8883 ScreenLinesC[i] = new_ScreenLinesC[i]; 8884 Screen_mco = p_mco; 8885 ScreenLines2 = new_ScreenLines2; 8886 ScreenAttrs = new_ScreenAttrs; 8887 LineOffset = new_LineOffset; 8888 LineWraps = new_LineWraps; 8889 TabPageIdxs = new_TabPageIdxs; 8890 8891 /* It's important that screen_Rows and screen_Columns reflect the actual 8892 * size of ScreenLines[]. Set them before calling anything. */ 8893 #ifdef FEAT_GUI 8894 old_Rows = screen_Rows; 8895 #endif 8896 screen_Rows = Rows; 8897 screen_Columns = Columns; 8898 8899 must_redraw = CLEAR; /* need to clear the screen later */ 8900 if (doclear) 8901 screenclear2(); 8902 8903 #ifdef FEAT_GUI 8904 else if (gui.in_use 8905 && !gui.starting 8906 && ScreenLines != NULL 8907 && old_Rows != Rows) 8908 { 8909 (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0); 8910 /* 8911 * Adjust the position of the cursor, for when executing an external 8912 * command. 8913 */ 8914 if (msg_row >= Rows) /* Rows got smaller */ 8915 msg_row = Rows - 1; /* put cursor at last row */ 8916 else if (Rows > old_Rows) /* Rows got bigger */ 8917 msg_row += Rows - old_Rows; /* put cursor in same place */ 8918 if (msg_col >= Columns) /* Columns got smaller */ 8919 msg_col = Columns - 1; /* put cursor at last column */ 8920 } 8921 #endif 8922 8923 entered = FALSE; 8924 --RedrawingDisabled; 8925 8926 /* 8927 * Do not apply autocommands more than 3 times to avoid an endless loop 8928 * in case applying autocommands always changes Rows or Columns. 8929 */ 8930 if (starting == 0 && ++retry_count <= 3) 8931 { 8932 apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf); 8933 /* In rare cases, autocommands may have altered Rows or Columns, 8934 * jump back to check if we need to allocate the screen again. */ 8935 goto retry; 8936 } 8937 } 8938 8939 void 8940 free_screenlines(void) 8941 { 8942 int i; 8943 8944 vim_free(ScreenLinesUC); 8945 for (i = 0; i < Screen_mco; ++i) 8946 vim_free(ScreenLinesC[i]); 8947 vim_free(ScreenLines2); 8948 vim_free(ScreenLines); 8949 vim_free(ScreenAttrs); 8950 vim_free(LineOffset); 8951 vim_free(LineWraps); 8952 vim_free(TabPageIdxs); 8953 } 8954 8955 void 8956 screenclear(void) 8957 { 8958 check_for_delay(FALSE); 8959 screenalloc(FALSE); /* allocate screen buffers if size changed */ 8960 screenclear2(); /* clear the screen */ 8961 } 8962 8963 static void 8964 screenclear2(void) 8965 { 8966 int i; 8967 8968 if (starting == NO_SCREEN || ScreenLines == NULL 8969 #ifdef FEAT_GUI 8970 || (gui.in_use && gui.starting) 8971 #endif 8972 ) 8973 return; 8974 8975 #ifdef FEAT_GUI 8976 if (!gui.in_use) 8977 #endif 8978 screen_attr = -1; /* force setting the Normal colors */ 8979 screen_stop_highlight(); /* don't want highlighting here */ 8980 8981 #ifdef FEAT_CLIPBOARD 8982 /* disable selection without redrawing it */ 8983 clip_scroll_selection(9999); 8984 #endif 8985 8986 /* blank out ScreenLines */ 8987 for (i = 0; i < Rows; ++i) 8988 { 8989 lineclear(LineOffset[i], (int)Columns, 0); 8990 LineWraps[i] = FALSE; 8991 } 8992 8993 if (can_clear(T_CL)) 8994 { 8995 out_str(T_CL); /* clear the display */ 8996 clear_cmdline = FALSE; 8997 mode_displayed = FALSE; 8998 } 8999 else 9000 { 9001 /* can't clear the screen, mark all chars with invalid attributes */ 9002 for (i = 0; i < Rows; ++i) 9003 lineinvalid(LineOffset[i], (int)Columns); 9004 clear_cmdline = TRUE; 9005 } 9006 9007 screen_cleared = TRUE; /* can use contents of ScreenLines now */ 9008 9009 win_rest_invalid(firstwin); 9010 redraw_cmdline = TRUE; 9011 redraw_tabline = TRUE; 9012 if (must_redraw == CLEAR) /* no need to clear again */ 9013 must_redraw = NOT_VALID; 9014 compute_cmdrow(); 9015 msg_row = cmdline_row; /* put cursor on last line for messages */ 9016 msg_col = 0; 9017 screen_start(); /* don't know where cursor is now */ 9018 msg_scrolled = 0; /* can't scroll back */ 9019 msg_didany = FALSE; 9020 msg_didout = FALSE; 9021 } 9022 9023 /* 9024 * Clear one line in ScreenLines. 9025 */ 9026 static void 9027 lineclear(unsigned off, int width, int attr) 9028 { 9029 (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T)); 9030 if (enc_utf8) 9031 (void)vim_memset(ScreenLinesUC + off, 0, 9032 (size_t)width * sizeof(u8char_T)); 9033 (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T)); 9034 } 9035 9036 /* 9037 * Mark one line in ScreenLines invalid by setting the attributes to an 9038 * invalid value. 9039 */ 9040 static void 9041 lineinvalid(unsigned off, int width) 9042 { 9043 (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T)); 9044 } 9045 9046 /* 9047 * Copy part of a Screenline for vertically split window "wp". 9048 */ 9049 static void 9050 linecopy(int to, int from, win_T *wp) 9051 { 9052 unsigned off_to = LineOffset[to] + wp->w_wincol; 9053 unsigned off_from = LineOffset[from] + wp->w_wincol; 9054 9055 mch_memmove(ScreenLines + off_to, ScreenLines + off_from, 9056 wp->w_width * sizeof(schar_T)); 9057 if (enc_utf8) 9058 { 9059 int i; 9060 9061 mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from, 9062 wp->w_width * sizeof(u8char_T)); 9063 for (i = 0; i < p_mco; ++i) 9064 mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from, 9065 wp->w_width * sizeof(u8char_T)); 9066 } 9067 if (enc_dbcs == DBCS_JPNU) 9068 mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from, 9069 wp->w_width * sizeof(schar_T)); 9070 mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from, 9071 wp->w_width * sizeof(sattr_T)); 9072 } 9073 9074 /* 9075 * Return TRUE if clearing with term string "p" would work. 9076 * It can't work when the string is empty or it won't set the right background. 9077 */ 9078 int 9079 can_clear(char_u *p) 9080 { 9081 return (*p != NUL && (t_colors <= 1 9082 #ifdef FEAT_GUI 9083 || gui.in_use 9084 #endif 9085 #ifdef FEAT_TERMGUICOLORS 9086 || (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR) 9087 || (!p_tgc && cterm_normal_bg_color == 0) 9088 #else 9089 || cterm_normal_bg_color == 0 9090 #endif 9091 || *T_UT != NUL)); 9092 } 9093 9094 /* 9095 * Reset cursor position. Use whenever cursor was moved because of outputting 9096 * something directly to the screen (shell commands) or a terminal control 9097 * code. 9098 */ 9099 void 9100 screen_start(void) 9101 { 9102 screen_cur_row = screen_cur_col = 9999; 9103 } 9104 9105 /* 9106 * Move the cursor to position "row","col" in the screen. 9107 * This tries to find the most efficient way to move, minimizing the number of 9108 * characters sent to the terminal. 9109 */ 9110 void 9111 windgoto(int row, int col) 9112 { 9113 sattr_T *p; 9114 int i; 9115 int plan; 9116 int cost; 9117 int wouldbe_col; 9118 int noinvcurs; 9119 char_u *bs; 9120 int goto_cost; 9121 int attr; 9122 9123 #define GOTO_COST 7 /* assume a term_windgoto() takes about 7 chars */ 9124 #define HIGHL_COST 5 /* assume unhighlight takes 5 chars */ 9125 9126 #define PLAN_LE 1 9127 #define PLAN_CR 2 9128 #define PLAN_NL 3 9129 #define PLAN_WRITE 4 9130 /* Can't use ScreenLines unless initialized */ 9131 if (ScreenLines == NULL) 9132 return; 9133 9134 if (col != screen_cur_col || row != screen_cur_row) 9135 { 9136 /* Check for valid position. */ 9137 if (row < 0) /* window without text lines? */ 9138 row = 0; 9139 if (row >= screen_Rows) 9140 row = screen_Rows - 1; 9141 if (col >= screen_Columns) 9142 col = screen_Columns - 1; 9143 9144 /* check if no cursor movement is allowed in highlight mode */ 9145 if (screen_attr && *T_MS == NUL) 9146 noinvcurs = HIGHL_COST; 9147 else 9148 noinvcurs = 0; 9149 goto_cost = GOTO_COST + noinvcurs; 9150 9151 /* 9152 * Plan how to do the positioning: 9153 * 1. Use CR to move it to column 0, same row. 9154 * 2. Use T_LE to move it a few columns to the left. 9155 * 3. Use NL to move a few lines down, column 0. 9156 * 4. Move a few columns to the right with T_ND or by writing chars. 9157 * 9158 * Don't do this if the cursor went beyond the last column, the cursor 9159 * position is unknown then (some terminals wrap, some don't ) 9160 * 9161 * First check if the highlighting attributes allow us to write 9162 * characters to move the cursor to the right. 9163 */ 9164 if (row >= screen_cur_row && screen_cur_col < Columns) 9165 { 9166 /* 9167 * If the cursor is in the same row, bigger col, we can use CR 9168 * or T_LE. 9169 */ 9170 bs = NULL; /* init for GCC */ 9171 attr = screen_attr; 9172 if (row == screen_cur_row && col < screen_cur_col) 9173 { 9174 /* "le" is preferred over "bc", because "bc" is obsolete */ 9175 if (*T_LE) 9176 bs = T_LE; /* "cursor left" */ 9177 else 9178 bs = T_BC; /* "backspace character (old) */ 9179 if (*bs) 9180 cost = (screen_cur_col - col) * (int)STRLEN(bs); 9181 else 9182 cost = 999; 9183 if (col + 1 < cost) /* using CR is less characters */ 9184 { 9185 plan = PLAN_CR; 9186 wouldbe_col = 0; 9187 cost = 1; /* CR is just one character */ 9188 } 9189 else 9190 { 9191 plan = PLAN_LE; 9192 wouldbe_col = col; 9193 } 9194 if (noinvcurs) /* will stop highlighting */ 9195 { 9196 cost += noinvcurs; 9197 attr = 0; 9198 } 9199 } 9200 9201 /* 9202 * If the cursor is above where we want to be, we can use CR LF. 9203 */ 9204 else if (row > screen_cur_row) 9205 { 9206 plan = PLAN_NL; 9207 wouldbe_col = 0; 9208 cost = (row - screen_cur_row) * 2; /* CR LF */ 9209 if (noinvcurs) /* will stop highlighting */ 9210 { 9211 cost += noinvcurs; 9212 attr = 0; 9213 } 9214 } 9215 9216 /* 9217 * If the cursor is in the same row, smaller col, just use write. 9218 */ 9219 else 9220 { 9221 plan = PLAN_WRITE; 9222 wouldbe_col = screen_cur_col; 9223 cost = 0; 9224 } 9225 9226 /* 9227 * Check if any characters that need to be written have the 9228 * correct attributes. Also avoid UTF-8 characters. 9229 */ 9230 i = col - wouldbe_col; 9231 if (i > 0) 9232 cost += i; 9233 if (cost < goto_cost && i > 0) 9234 { 9235 /* 9236 * Check if the attributes are correct without additionally 9237 * stopping highlighting. 9238 */ 9239 p = ScreenAttrs + LineOffset[row] + wouldbe_col; 9240 while (i && *p++ == attr) 9241 --i; 9242 if (i != 0) 9243 { 9244 /* 9245 * Try if it works when highlighting is stopped here. 9246 */ 9247 if (*--p == 0) 9248 { 9249 cost += noinvcurs; 9250 while (i && *p++ == 0) 9251 --i; 9252 } 9253 if (i != 0) 9254 cost = 999; /* different attributes, don't do it */ 9255 } 9256 if (enc_utf8) 9257 { 9258 /* Don't use an UTF-8 char for positioning, it's slow. */ 9259 for (i = wouldbe_col; i < col; ++i) 9260 if (ScreenLinesUC[LineOffset[row] + i] != 0) 9261 { 9262 cost = 999; 9263 break; 9264 } 9265 } 9266 } 9267 9268 /* 9269 * We can do it without term_windgoto()! 9270 */ 9271 if (cost < goto_cost) 9272 { 9273 if (plan == PLAN_LE) 9274 { 9275 if (noinvcurs) 9276 screen_stop_highlight(); 9277 while (screen_cur_col > col) 9278 { 9279 out_str(bs); 9280 --screen_cur_col; 9281 } 9282 } 9283 else if (plan == PLAN_CR) 9284 { 9285 if (noinvcurs) 9286 screen_stop_highlight(); 9287 out_char('\r'); 9288 screen_cur_col = 0; 9289 } 9290 else if (plan == PLAN_NL) 9291 { 9292 if (noinvcurs) 9293 screen_stop_highlight(); 9294 while (screen_cur_row < row) 9295 { 9296 out_char('\n'); 9297 ++screen_cur_row; 9298 } 9299 screen_cur_col = 0; 9300 } 9301 9302 i = col - screen_cur_col; 9303 if (i > 0) 9304 { 9305 /* 9306 * Use cursor-right if it's one character only. Avoids 9307 * removing a line of pixels from the last bold char, when 9308 * using the bold trick in the GUI. 9309 */ 9310 if (T_ND[0] != NUL && T_ND[1] == NUL) 9311 { 9312 while (i-- > 0) 9313 out_char(*T_ND); 9314 } 9315 else 9316 { 9317 int off; 9318 9319 off = LineOffset[row] + screen_cur_col; 9320 while (i-- > 0) 9321 { 9322 if (ScreenAttrs[off] != screen_attr) 9323 screen_stop_highlight(); 9324 out_flush_check(); 9325 out_char(ScreenLines[off]); 9326 if (enc_dbcs == DBCS_JPNU 9327 && ScreenLines[off] == 0x8e) 9328 out_char(ScreenLines2[off]); 9329 ++off; 9330 } 9331 } 9332 } 9333 } 9334 } 9335 else 9336 cost = 999; 9337 9338 if (cost >= goto_cost) 9339 { 9340 if (noinvcurs) 9341 screen_stop_highlight(); 9342 if (row == screen_cur_row && (col > screen_cur_col) 9343 && *T_CRI != NUL) 9344 term_cursor_right(col - screen_cur_col); 9345 else 9346 term_windgoto(row, col); 9347 } 9348 screen_cur_row = row; 9349 screen_cur_col = col; 9350 } 9351 } 9352 9353 /* 9354 * Set cursor to its position in the current window. 9355 */ 9356 void 9357 setcursor(void) 9358 { 9359 setcursor_mayforce(FALSE); 9360 } 9361 9362 /* 9363 * Set cursor to its position in the current window. 9364 * When "force" is TRUE also when not redrawing. 9365 */ 9366 void 9367 setcursor_mayforce(int force) 9368 { 9369 if (force || redrawing()) 9370 { 9371 validate_cursor(); 9372 windgoto(W_WINROW(curwin) + curwin->w_wrow, 9373 curwin->w_wincol + ( 9374 #ifdef FEAT_RIGHTLEFT 9375 /* With 'rightleft' set and the cursor on a double-wide 9376 * character, position it on the leftmost column. */ 9377 curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol 9378 - ((has_mbyte 9379 && (*mb_ptr2cells)(ml_get_cursor()) == 2 9380 && vim_isprintc(gchar_cursor())) ? 2 : 1)) : 9381 #endif 9382 curwin->w_wcol)); 9383 } 9384 } 9385 9386 9387 /* 9388 * Insert 'line_count' lines at 'row' in window 'wp'. 9389 * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated. 9390 * If 'mayclear' is TRUE the screen will be cleared if it is faster than 9391 * scrolling. 9392 * Returns FAIL if the lines are not inserted, OK for success. 9393 */ 9394 int 9395 win_ins_lines( 9396 win_T *wp, 9397 int row, 9398 int line_count, 9399 int invalid, 9400 int mayclear) 9401 { 9402 int did_delete; 9403 int nextrow; 9404 int lastrow; 9405 int retval; 9406 9407 if (invalid) 9408 wp->w_lines_valid = 0; 9409 9410 if (wp->w_height < 5) 9411 return FAIL; 9412 9413 if (line_count > wp->w_height - row) 9414 line_count = wp->w_height - row; 9415 9416 retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0); 9417 if (retval != MAYBE) 9418 return retval; 9419 9420 /* 9421 * If there is a next window or a status line, we first try to delete the 9422 * lines at the bottom to avoid messing what is after the window. 9423 * If this fails and there are following windows, don't do anything to avoid 9424 * messing up those windows, better just redraw. 9425 */ 9426 did_delete = FALSE; 9427 if (wp->w_next != NULL || wp->w_status_height) 9428 { 9429 if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count, 9430 line_count, (int)Rows, FALSE, 0, NULL) == OK) 9431 did_delete = TRUE; 9432 else if (wp->w_next) 9433 return FAIL; 9434 } 9435 /* 9436 * if no lines deleted, blank the lines that will end up below the window 9437 */ 9438 if (!did_delete) 9439 { 9440 wp->w_redr_status = TRUE; 9441 redraw_cmdline = TRUE; 9442 nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height; 9443 lastrow = nextrow + line_count; 9444 if (lastrow > Rows) 9445 lastrow = Rows; 9446 screen_fill(nextrow - line_count, lastrow - line_count, 9447 wp->w_wincol, (int)W_ENDCOL(wp), 9448 ' ', ' ', 0); 9449 } 9450 9451 if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL) 9452 == FAIL) 9453 { 9454 /* deletion will have messed up other windows */ 9455 if (did_delete) 9456 { 9457 wp->w_redr_status = TRUE; 9458 win_rest_invalid(W_NEXT(wp)); 9459 } 9460 return FAIL; 9461 } 9462 9463 return OK; 9464 } 9465 9466 /* 9467 * Delete "line_count" window lines at "row" in window "wp". 9468 * If "invalid" is TRUE curwin->w_lines[] is invalidated. 9469 * If "mayclear" is TRUE the screen will be cleared if it is faster than 9470 * scrolling 9471 * Return OK for success, FAIL if the lines are not deleted. 9472 */ 9473 int 9474 win_del_lines( 9475 win_T *wp, 9476 int row, 9477 int line_count, 9478 int invalid, 9479 int mayclear, 9480 int clear_attr) /* for clearing lines */ 9481 { 9482 int retval; 9483 9484 if (invalid) 9485 wp->w_lines_valid = 0; 9486 9487 if (line_count > wp->w_height - row) 9488 line_count = wp->w_height - row; 9489 9490 retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr); 9491 if (retval != MAYBE) 9492 return retval; 9493 9494 if (screen_del_lines(0, W_WINROW(wp) + row, line_count, 9495 (int)Rows, FALSE, clear_attr, NULL) == FAIL) 9496 return FAIL; 9497 9498 /* 9499 * If there are windows or status lines below, try to put them at the 9500 * correct place. If we can't do that, they have to be redrawn. 9501 */ 9502 if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1) 9503 { 9504 if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count, 9505 line_count, (int)Rows, clear_attr, NULL) == FAIL) 9506 { 9507 wp->w_redr_status = TRUE; 9508 win_rest_invalid(wp->w_next); 9509 } 9510 } 9511 /* 9512 * If this is the last window and there is no status line, redraw the 9513 * command line later. 9514 */ 9515 else 9516 redraw_cmdline = TRUE; 9517 return OK; 9518 } 9519 9520 /* 9521 * Common code for win_ins_lines() and win_del_lines(). 9522 * Returns OK or FAIL when the work has been done. 9523 * Returns MAYBE when not finished yet. 9524 */ 9525 static int 9526 win_do_lines( 9527 win_T *wp, 9528 int row, 9529 int line_count, 9530 int mayclear, 9531 int del, 9532 int clear_attr) 9533 { 9534 int retval; 9535 9536 if (!redrawing() || line_count <= 0) 9537 return FAIL; 9538 9539 /* When inserting lines would result in loss of command output, just redraw 9540 * the lines. */ 9541 if (no_win_do_lines_ins && !del) 9542 return FAIL; 9543 9544 /* only a few lines left: redraw is faster */ 9545 if (mayclear && Rows - line_count < 5 && wp->w_width == Columns) 9546 { 9547 if (!no_win_do_lines_ins) 9548 screenclear(); /* will set wp->w_lines_valid to 0 */ 9549 return FAIL; 9550 } 9551 9552 /* 9553 * Delete all remaining lines 9554 */ 9555 if (row + line_count >= wp->w_height) 9556 { 9557 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height, 9558 wp->w_wincol, (int)W_ENDCOL(wp), 9559 ' ', ' ', 0); 9560 return OK; 9561 } 9562 9563 /* 9564 * When scrolling, the message on the command line should be cleared, 9565 * otherwise it will stay there forever. 9566 * Don't do this when avoiding to insert lines. 9567 */ 9568 if (!no_win_do_lines_ins) 9569 clear_cmdline = TRUE; 9570 9571 /* 9572 * If the terminal can set a scroll region, use that. 9573 * Always do this in a vertically split window. This will redraw from 9574 * ScreenLines[] when t_CV isn't defined. That's faster than using 9575 * win_line(). 9576 * Don't use a scroll region when we are going to redraw the text, writing 9577 * a character in the lower right corner of the scroll region may cause a 9578 * scroll-up . 9579 */ 9580 if (scroll_region || wp->w_width != Columns) 9581 { 9582 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL)) 9583 scroll_region_set(wp, row); 9584 if (del) 9585 retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count, 9586 wp->w_height - row, FALSE, clear_attr, wp); 9587 else 9588 retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count, 9589 wp->w_height - row, clear_attr, wp); 9590 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL)) 9591 scroll_region_reset(); 9592 return retval; 9593 } 9594 9595 if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */ 9596 return FAIL; 9597 9598 return MAYBE; 9599 } 9600 9601 /* 9602 * window 'wp' and everything after it is messed up, mark it for redraw 9603 */ 9604 static void 9605 win_rest_invalid(win_T *wp) 9606 { 9607 while (wp != NULL) 9608 { 9609 redraw_win_later(wp, NOT_VALID); 9610 wp->w_redr_status = TRUE; 9611 wp = wp->w_next; 9612 } 9613 redraw_cmdline = TRUE; 9614 } 9615 9616 /* 9617 * The rest of the routines in this file perform screen manipulations. The 9618 * given operation is performed physically on the screen. The corresponding 9619 * change is also made to the internal screen image. In this way, the editor 9620 * anticipates the effect of editing changes on the appearance of the screen. 9621 * That way, when we call screenupdate a complete redraw isn't usually 9622 * necessary. Another advantage is that we can keep adding code to anticipate 9623 * screen changes, and in the meantime, everything still works. 9624 */ 9625 9626 /* 9627 * types for inserting or deleting lines 9628 */ 9629 #define USE_T_CAL 1 9630 #define USE_T_CDL 2 9631 #define USE_T_AL 3 9632 #define USE_T_CE 4 9633 #define USE_T_DL 5 9634 #define USE_T_SR 6 9635 #define USE_NL 7 9636 #define USE_T_CD 8 9637 #define USE_REDRAW 9 9638 9639 /* 9640 * insert lines on the screen and update ScreenLines[] 9641 * 'end' is the line after the scrolled part. Normally it is Rows. 9642 * When scrolling region used 'off' is the offset from the top for the region. 9643 * 'row' and 'end' are relative to the start of the region. 9644 * 9645 * return FAIL for failure, OK for success. 9646 */ 9647 int 9648 screen_ins_lines( 9649 int off, 9650 int row, 9651 int line_count, 9652 int end, 9653 int clear_attr, 9654 win_T *wp) /* NULL or window to use width from */ 9655 { 9656 int i; 9657 int j; 9658 unsigned temp; 9659 int cursor_row; 9660 int cursor_col = 0; 9661 int type; 9662 int result_empty; 9663 int can_ce = can_clear(T_CE); 9664 9665 /* 9666 * FAIL if 9667 * - there is no valid screen 9668 * - the screen has to be redrawn completely 9669 * - the line count is less than one 9670 * - the line count is more than 'ttyscroll' 9671 * - redrawing for a callback and there is a modeless selection 9672 */ 9673 if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll 9674 #ifdef FEAT_CLIPBOARD 9675 || (clip_star.state != SELECT_CLEARED 9676 && redrawing_for_callback > 0) 9677 #endif 9678 ) 9679 return FAIL; 9680 9681 /* 9682 * There are seven ways to insert lines: 9683 * 0. When in a vertically split window and t_CV isn't set, redraw the 9684 * characters from ScreenLines[]. 9685 * 1. Use T_CD (clear to end of display) if it exists and the result of 9686 * the insert is just empty lines 9687 * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not 9688 * present or line_count > 1. It looks better if we do all the inserts 9689 * at once. 9690 * 3. Use T_CDL (delete multiple lines) if it exists and the result of the 9691 * insert is just empty lines and T_CE is not present or line_count > 9692 * 1. 9693 * 4. Use T_AL (insert line) if it exists. 9694 * 5. Use T_CE (erase line) if it exists and the result of the insert is 9695 * just empty lines. 9696 * 6. Use T_DL (delete line) if it exists and the result of the insert is 9697 * just empty lines. 9698 * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and 9699 * the 'da' flag is not set or we have clear line capability. 9700 * 8. redraw the characters from ScreenLines[]. 9701 * 9702 * Careful: In a hpterm scroll reverse doesn't work as expected, it moves 9703 * the scrollbar for the window. It does have insert line, use that if it 9704 * exists. 9705 */ 9706 result_empty = (row + line_count >= end); 9707 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL) 9708 type = USE_REDRAW; 9709 else if (can_clear(T_CD) && result_empty) 9710 type = USE_T_CD; 9711 else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL)) 9712 type = USE_T_CAL; 9713 else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce)) 9714 type = USE_T_CDL; 9715 else if (*T_AL != NUL) 9716 type = USE_T_AL; 9717 else if (can_ce && result_empty) 9718 type = USE_T_CE; 9719 else if (*T_DL != NUL && result_empty) 9720 type = USE_T_DL; 9721 else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce)) 9722 type = USE_T_SR; 9723 else 9724 return FAIL; 9725 9726 /* 9727 * For clearing the lines screen_del_lines() is used. This will also take 9728 * care of t_db if necessary. 9729 */ 9730 if (type == USE_T_CD || type == USE_T_CDL || 9731 type == USE_T_CE || type == USE_T_DL) 9732 return screen_del_lines(off, row, line_count, end, FALSE, 0, wp); 9733 9734 /* 9735 * If text is retained below the screen, first clear or delete as many 9736 * lines at the bottom of the window as are about to be inserted so that 9737 * the deleted lines won't later surface during a screen_del_lines. 9738 */ 9739 if (*T_DB) 9740 screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp); 9741 9742 #ifdef FEAT_CLIPBOARD 9743 /* Remove a modeless selection when inserting lines halfway the screen 9744 * or not the full width of the screen. */ 9745 if (off + row > 0 || (wp != NULL && wp->w_width != Columns)) 9746 clip_clear_selection(&clip_star); 9747 else 9748 clip_scroll_selection(-line_count); 9749 #endif 9750 9751 #ifdef FEAT_GUI 9752 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the 9753 * scrolling is actually carried out. */ 9754 gui_dont_update_cursor(row + off <= gui.cursor_row); 9755 #endif 9756 9757 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL) 9758 cursor_col = wp->w_wincol; 9759 9760 if (*T_CCS != NUL) /* cursor relative to region */ 9761 cursor_row = row; 9762 else 9763 cursor_row = row + off; 9764 9765 /* 9766 * Shift LineOffset[] line_count down to reflect the inserted lines. 9767 * Clear the inserted lines in ScreenLines[]. 9768 */ 9769 row += off; 9770 end += off; 9771 for (i = 0; i < line_count; ++i) 9772 { 9773 if (wp != NULL && wp->w_width != Columns) 9774 { 9775 /* need to copy part of a line */ 9776 j = end - 1 - i; 9777 while ((j -= line_count) >= row) 9778 linecopy(j + line_count, j, wp); 9779 j += line_count; 9780 if (can_clear((char_u *)" ")) 9781 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width, 9782 clear_attr); 9783 else 9784 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width); 9785 LineWraps[j] = FALSE; 9786 } 9787 else 9788 { 9789 j = end - 1 - i; 9790 temp = LineOffset[j]; 9791 while ((j -= line_count) >= row) 9792 { 9793 LineOffset[j + line_count] = LineOffset[j]; 9794 LineWraps[j + line_count] = LineWraps[j]; 9795 } 9796 LineOffset[j + line_count] = temp; 9797 LineWraps[j + line_count] = FALSE; 9798 if (can_clear((char_u *)" ")) 9799 lineclear(temp, (int)Columns, clear_attr); 9800 else 9801 lineinvalid(temp, (int)Columns); 9802 } 9803 } 9804 9805 screen_stop_highlight(); 9806 windgoto(cursor_row, cursor_col); 9807 if (clear_attr != 0) 9808 screen_start_highlight(clear_attr); 9809 9810 /* redraw the characters */ 9811 if (type == USE_REDRAW) 9812 redraw_block(row, end, wp); 9813 else if (type == USE_T_CAL) 9814 { 9815 term_append_lines(line_count); 9816 screen_start(); /* don't know where cursor is now */ 9817 } 9818 else 9819 { 9820 for (i = 0; i < line_count; i++) 9821 { 9822 if (type == USE_T_AL) 9823 { 9824 if (i && cursor_row != 0) 9825 windgoto(cursor_row, cursor_col); 9826 out_str(T_AL); 9827 } 9828 else /* type == USE_T_SR */ 9829 out_str(T_SR); 9830 screen_start(); /* don't know where cursor is now */ 9831 } 9832 } 9833 9834 /* 9835 * With scroll-reverse and 'da' flag set we need to clear the lines that 9836 * have been scrolled down into the region. 9837 */ 9838 if (type == USE_T_SR && *T_DA) 9839 { 9840 for (i = 0; i < line_count; ++i) 9841 { 9842 windgoto(off + i, cursor_col); 9843 out_str(T_CE); 9844 screen_start(); /* don't know where cursor is now */ 9845 } 9846 } 9847 9848 #ifdef FEAT_GUI 9849 gui_can_update_cursor(); 9850 if (gui.in_use) 9851 out_flush(); /* always flush after a scroll */ 9852 #endif 9853 return OK; 9854 } 9855 9856 /* 9857 * Delete lines on the screen and update ScreenLines[]. 9858 * "end" is the line after the scrolled part. Normally it is Rows. 9859 * When scrolling region used "off" is the offset from the top for the region. 9860 * "row" and "end" are relative to the start of the region. 9861 * 9862 * Return OK for success, FAIL if the lines are not deleted. 9863 */ 9864 int 9865 screen_del_lines( 9866 int off, 9867 int row, 9868 int line_count, 9869 int end, 9870 int force, /* even when line_count > p_ttyscroll */ 9871 int clear_attr, /* used for clearing lines */ 9872 win_T *wp UNUSED) /* NULL or window to use width from */ 9873 { 9874 int j; 9875 int i; 9876 unsigned temp; 9877 int cursor_row; 9878 int cursor_col = 0; 9879 int cursor_end; 9880 int result_empty; /* result is empty until end of region */ 9881 int can_delete; /* deleting line codes can be used */ 9882 int type; 9883 9884 /* 9885 * FAIL if 9886 * - there is no valid screen 9887 * - the screen has to be redrawn completely 9888 * - the line count is less than one 9889 * - the line count is more than 'ttyscroll' 9890 * - redrawing for a callback and there is a modeless selection 9891 */ 9892 if (!screen_valid(TRUE) || line_count <= 0 9893 || (!force && line_count > p_ttyscroll) 9894 #ifdef FEAT_CLIPBOARD 9895 || (clip_star.state != SELECT_CLEARED 9896 && redrawing_for_callback > 0) 9897 #endif 9898 ) 9899 return FAIL; 9900 9901 /* 9902 * Check if the rest of the current region will become empty. 9903 */ 9904 result_empty = row + line_count >= end; 9905 9906 /* 9907 * We can delete lines only when 'db' flag not set or when 'ce' option 9908 * available. 9909 */ 9910 can_delete = (*T_DB == NUL || can_clear(T_CE)); 9911 9912 /* 9913 * There are six ways to delete lines: 9914 * 0. When in a vertically split window and t_CV isn't set, redraw the 9915 * characters from ScreenLines[]. 9916 * 1. Use T_CD if it exists and the result is empty. 9917 * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist. 9918 * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or 9919 * none of the other ways work. 9920 * 4. Use T_CE (erase line) if the result is empty. 9921 * 5. Use T_DL (delete line) if it exists. 9922 * 6. redraw the characters from ScreenLines[]. 9923 */ 9924 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL) 9925 type = USE_REDRAW; 9926 else if (can_clear(T_CD) && result_empty) 9927 type = USE_T_CD; 9928 #if defined(__BEOS__) && defined(BEOS_DR8) 9929 /* 9930 * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in 9931 * its internal termcap... this works okay for tests which test *T_DB != 9932 * NUL. It has the disadvantage that the user cannot use any :set t_* 9933 * command to get T_DB (back) to empty_option, only :set term=... will do 9934 * the trick... 9935 * Anyway, this hack will hopefully go away with the next OS release. 9936 * (Olaf Seibert) 9937 */ 9938 else if (row == 0 && T_DB == empty_option 9939 && (line_count == 1 || *T_CDL == NUL)) 9940 #else 9941 else if (row == 0 && ( 9942 #ifndef AMIGA 9943 /* On the Amiga, somehow '\n' on the last line doesn't always scroll 9944 * up, so use delete-line command */ 9945 line_count == 1 || 9946 #endif 9947 *T_CDL == NUL)) 9948 #endif 9949 type = USE_NL; 9950 else if (*T_CDL != NUL && line_count > 1 && can_delete) 9951 type = USE_T_CDL; 9952 else if (can_clear(T_CE) && result_empty 9953 && (wp == NULL || wp->w_width == Columns)) 9954 type = USE_T_CE; 9955 else if (*T_DL != NUL && can_delete) 9956 type = USE_T_DL; 9957 else if (*T_CDL != NUL && can_delete) 9958 type = USE_T_CDL; 9959 else 9960 return FAIL; 9961 9962 #ifdef FEAT_CLIPBOARD 9963 /* Remove a modeless selection when deleting lines halfway the screen or 9964 * not the full width of the screen. */ 9965 if (off + row > 0 || (wp != NULL && wp->w_width != Columns)) 9966 clip_clear_selection(&clip_star); 9967 else 9968 clip_scroll_selection(line_count); 9969 #endif 9970 9971 #ifdef FEAT_GUI 9972 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the 9973 * scrolling is actually carried out. */ 9974 gui_dont_update_cursor(gui.cursor_row >= row + off 9975 && gui.cursor_row < end + off); 9976 #endif 9977 9978 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL) 9979 cursor_col = wp->w_wincol; 9980 9981 if (*T_CCS != NUL) /* cursor relative to region */ 9982 { 9983 cursor_row = row; 9984 cursor_end = end; 9985 } 9986 else 9987 { 9988 cursor_row = row + off; 9989 cursor_end = end + off; 9990 } 9991 9992 /* 9993 * Now shift LineOffset[] line_count up to reflect the deleted lines. 9994 * Clear the inserted lines in ScreenLines[]. 9995 */ 9996 row += off; 9997 end += off; 9998 for (i = 0; i < line_count; ++i) 9999 { 10000 if (wp != NULL && wp->w_width != Columns) 10001 { 10002 /* need to copy part of a line */ 10003 j = row + i; 10004 while ((j += line_count) <= end - 1) 10005 linecopy(j - line_count, j, wp); 10006 j -= line_count; 10007 if (can_clear((char_u *)" ")) 10008 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width, 10009 clear_attr); 10010 else 10011 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width); 10012 LineWraps[j] = FALSE; 10013 } 10014 else 10015 { 10016 /* whole width, moving the line pointers is faster */ 10017 j = row + i; 10018 temp = LineOffset[j]; 10019 while ((j += line_count) <= end - 1) 10020 { 10021 LineOffset[j - line_count] = LineOffset[j]; 10022 LineWraps[j - line_count] = LineWraps[j]; 10023 } 10024 LineOffset[j - line_count] = temp; 10025 LineWraps[j - line_count] = FALSE; 10026 if (can_clear((char_u *)" ")) 10027 lineclear(temp, (int)Columns, clear_attr); 10028 else 10029 lineinvalid(temp, (int)Columns); 10030 } 10031 } 10032 10033 if (screen_attr != clear_attr) 10034 screen_stop_highlight(); 10035 if (clear_attr != 0) 10036 screen_start_highlight(clear_attr); 10037 10038 /* redraw the characters */ 10039 if (type == USE_REDRAW) 10040 redraw_block(row, end, wp); 10041 else if (type == USE_T_CD) /* delete the lines */ 10042 { 10043 windgoto(cursor_row, cursor_col); 10044 out_str(T_CD); 10045 screen_start(); /* don't know where cursor is now */ 10046 } 10047 else if (type == USE_T_CDL) 10048 { 10049 windgoto(cursor_row, cursor_col); 10050 term_delete_lines(line_count); 10051 screen_start(); /* don't know where cursor is now */ 10052 } 10053 /* 10054 * Deleting lines at top of the screen or scroll region: Just scroll 10055 * the whole screen (scroll region) up by outputting newlines on the 10056 * last line. 10057 */ 10058 else if (type == USE_NL) 10059 { 10060 windgoto(cursor_end - 1, cursor_col); 10061 for (i = line_count; --i >= 0; ) 10062 out_char('\n'); /* cursor will remain on same line */ 10063 } 10064 else 10065 { 10066 for (i = line_count; --i >= 0; ) 10067 { 10068 if (type == USE_T_DL) 10069 { 10070 windgoto(cursor_row, cursor_col); 10071 out_str(T_DL); /* delete a line */ 10072 } 10073 else /* type == USE_T_CE */ 10074 { 10075 windgoto(cursor_row + i, cursor_col); 10076 out_str(T_CE); /* erase a line */ 10077 } 10078 screen_start(); /* don't know where cursor is now */ 10079 } 10080 } 10081 10082 /* 10083 * If the 'db' flag is set, we need to clear the lines that have been 10084 * scrolled up at the bottom of the region. 10085 */ 10086 if (*T_DB && (type == USE_T_DL || type == USE_T_CDL)) 10087 { 10088 for (i = line_count; i > 0; --i) 10089 { 10090 windgoto(cursor_end - i, cursor_col); 10091 out_str(T_CE); /* erase a line */ 10092 screen_start(); /* don't know where cursor is now */ 10093 } 10094 } 10095 10096 #ifdef FEAT_GUI 10097 gui_can_update_cursor(); 10098 if (gui.in_use) 10099 out_flush(); /* always flush after a scroll */ 10100 #endif 10101 10102 return OK; 10103 } 10104 10105 /* 10106 * Return TRUE when postponing displaying the mode message: when not redrawing 10107 * or inside a mapping. 10108 */ 10109 int 10110 skip_showmode() 10111 { 10112 // Call char_avail() only when we are going to show something, because it 10113 // takes a bit of time. redrawing() may also call char_avail_avail(). 10114 if (global_busy 10115 || msg_silent != 0 10116 || !redrawing() 10117 || (char_avail() && !KeyTyped)) 10118 { 10119 redraw_cmdline = TRUE; // show mode later 10120 return TRUE; 10121 } 10122 return FALSE; 10123 } 10124 10125 /* 10126 * Show the current mode and ruler. 10127 * 10128 * If clear_cmdline is TRUE, clear the rest of the cmdline. 10129 * If clear_cmdline is FALSE there may be a message there that needs to be 10130 * cleared only if a mode is shown. 10131 * Return the length of the message (0 if no message). 10132 */ 10133 int 10134 showmode(void) 10135 { 10136 int need_clear; 10137 int length = 0; 10138 int do_mode; 10139 int attr; 10140 int nwr_save; 10141 #ifdef FEAT_INS_EXPAND 10142 int sub_attr; 10143 #endif 10144 10145 do_mode = ((p_smd && msg_silent == 0) 10146 && ((State & INSERT) 10147 || restart_edit != NUL 10148 || VIsual_active)); 10149 if (do_mode || reg_recording != 0) 10150 { 10151 if (skip_showmode()) 10152 return 0; // show mode later 10153 10154 nwr_save = need_wait_return; 10155 10156 /* wait a bit before overwriting an important message */ 10157 check_for_delay(FALSE); 10158 10159 /* if the cmdline is more than one line high, erase top lines */ 10160 need_clear = clear_cmdline; 10161 if (clear_cmdline && cmdline_row < Rows - 1) 10162 msg_clr_cmdline(); /* will reset clear_cmdline */ 10163 10164 /* Position on the last line in the window, column 0 */ 10165 msg_pos_mode(); 10166 cursor_off(); 10167 attr = HL_ATTR(HLF_CM); /* Highlight mode */ 10168 if (do_mode) 10169 { 10170 msg_puts_attr("--", attr); 10171 #if defined(FEAT_XIM) 10172 if ( 10173 # ifdef FEAT_GUI_GTK 10174 preedit_get_status() 10175 # else 10176 im_get_status() 10177 # endif 10178 ) 10179 # ifdef FEAT_GUI_GTK /* most of the time, it's not XIM being used */ 10180 msg_puts_attr(" IM", attr); 10181 # else 10182 msg_puts_attr(" XIM", attr); 10183 # endif 10184 #endif 10185 #if defined(FEAT_HANGULIN) && defined(FEAT_GUI) 10186 if (gui.in_use) 10187 { 10188 if (hangul_input_state_get()) 10189 { 10190 /* HANGUL */ 10191 if (enc_utf8) 10192 msg_puts_attr(" \355\225\234\352\270\200", attr); 10193 else 10194 msg_puts_attr(" \307\321\261\333", attr); 10195 } 10196 } 10197 #endif 10198 #ifdef FEAT_INS_EXPAND 10199 /* CTRL-X in Insert mode */ 10200 if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU)) 10201 { 10202 /* These messages can get long, avoid a wrap in a narrow 10203 * window. Prefer showing edit_submode_extra. */ 10204 length = (Rows - msg_row) * Columns - 3; 10205 if (edit_submode_extra != NULL) 10206 length -= vim_strsize(edit_submode_extra); 10207 if (length > 0) 10208 { 10209 if (edit_submode_pre != NULL) 10210 length -= vim_strsize(edit_submode_pre); 10211 if (length - vim_strsize(edit_submode) > 0) 10212 { 10213 if (edit_submode_pre != NULL) 10214 msg_puts_attr((char *)edit_submode_pre, attr); 10215 msg_puts_attr((char *)edit_submode, attr); 10216 } 10217 if (edit_submode_extra != NULL) 10218 { 10219 msg_puts_attr(" ", attr); /* add a space in between */ 10220 if ((int)edit_submode_highl < (int)HLF_COUNT) 10221 sub_attr = HL_ATTR(edit_submode_highl); 10222 else 10223 sub_attr = attr; 10224 msg_puts_attr((char *)edit_submode_extra, sub_attr); 10225 } 10226 } 10227 } 10228 else 10229 #endif 10230 { 10231 if (State & VREPLACE_FLAG) 10232 msg_puts_attr(_(" VREPLACE"), attr); 10233 else if (State & REPLACE_FLAG) 10234 msg_puts_attr(_(" REPLACE"), attr); 10235 else if (State & INSERT) 10236 { 10237 #ifdef FEAT_RIGHTLEFT 10238 if (p_ri) 10239 msg_puts_attr(_(" REVERSE"), attr); 10240 #endif 10241 msg_puts_attr(_(" INSERT"), attr); 10242 } 10243 else if (restart_edit == 'I' || restart_edit == 'A') 10244 msg_puts_attr(_(" (insert)"), attr); 10245 else if (restart_edit == 'R') 10246 msg_puts_attr(_(" (replace)"), attr); 10247 else if (restart_edit == 'V') 10248 msg_puts_attr(_(" (vreplace)"), attr); 10249 #ifdef FEAT_RIGHTLEFT 10250 if (p_hkmap) 10251 msg_puts_attr(_(" Hebrew"), attr); 10252 #endif 10253 #ifdef FEAT_KEYMAP 10254 if (State & LANGMAP) 10255 { 10256 # ifdef FEAT_ARABIC 10257 if (curwin->w_p_arab) 10258 msg_puts_attr(_(" Arabic"), attr); 10259 else 10260 # endif 10261 if (get_keymap_str(curwin, (char_u *)" (%s)", 10262 NameBuff, MAXPATHL)) 10263 msg_puts_attr((char *)NameBuff, attr); 10264 } 10265 #endif 10266 if ((State & INSERT) && p_paste) 10267 msg_puts_attr(_(" (paste)"), attr); 10268 10269 if (VIsual_active) 10270 { 10271 char *p; 10272 10273 /* Don't concatenate separate words to avoid translation 10274 * problems. */ 10275 switch ((VIsual_select ? 4 : 0) 10276 + (VIsual_mode == Ctrl_V) * 2 10277 + (VIsual_mode == 'V')) 10278 { 10279 case 0: p = N_(" VISUAL"); break; 10280 case 1: p = N_(" VISUAL LINE"); break; 10281 case 2: p = N_(" VISUAL BLOCK"); break; 10282 case 4: p = N_(" SELECT"); break; 10283 case 5: p = N_(" SELECT LINE"); break; 10284 default: p = N_(" SELECT BLOCK"); break; 10285 } 10286 msg_puts_attr(_(p), attr); 10287 } 10288 msg_puts_attr(" --", attr); 10289 } 10290 10291 need_clear = TRUE; 10292 } 10293 if (reg_recording != 0 10294 #ifdef FEAT_INS_EXPAND 10295 && edit_submode == NULL /* otherwise it gets too long */ 10296 #endif 10297 ) 10298 { 10299 recording_mode(attr); 10300 need_clear = TRUE; 10301 } 10302 10303 mode_displayed = TRUE; 10304 if (need_clear || clear_cmdline) 10305 msg_clr_eos(); 10306 msg_didout = FALSE; /* overwrite this message */ 10307 length = msg_col; 10308 msg_col = 0; 10309 need_wait_return = nwr_save; /* never ask for hit-return for this */ 10310 } 10311 else if (clear_cmdline && msg_silent == 0) 10312 /* Clear the whole command line. Will reset "clear_cmdline". */ 10313 msg_clr_cmdline(); 10314 10315 #ifdef FEAT_CMDL_INFO 10316 /* In Visual mode the size of the selected area must be redrawn. */ 10317 if (VIsual_active) 10318 clear_showcmd(); 10319 10320 /* If the last window has no status line, the ruler is after the mode 10321 * message and must be redrawn */ 10322 if (redrawing() && lastwin->w_status_height == 0) 10323 win_redr_ruler(lastwin, TRUE, FALSE); 10324 #endif 10325 redraw_cmdline = FALSE; 10326 clear_cmdline = FALSE; 10327 10328 return length; 10329 } 10330 10331 /* 10332 * Position for a mode message. 10333 */ 10334 static void 10335 msg_pos_mode(void) 10336 { 10337 msg_col = 0; 10338 msg_row = Rows - 1; 10339 } 10340 10341 /* 10342 * Delete mode message. Used when ESC is typed which is expected to end 10343 * Insert mode (but Insert mode didn't end yet!). 10344 * Caller should check "mode_displayed". 10345 */ 10346 void 10347 unshowmode(int force) 10348 { 10349 /* 10350 * Don't delete it right now, when not redrawing or inside a mapping. 10351 */ 10352 if (!redrawing() || (!force && char_avail() && !KeyTyped)) 10353 redraw_cmdline = TRUE; /* delete mode later */ 10354 else 10355 clearmode(); 10356 } 10357 10358 /* 10359 * Clear the mode message. 10360 */ 10361 void 10362 clearmode(void) 10363 { 10364 int save_msg_row = msg_row; 10365 int save_msg_col = msg_col; 10366 10367 msg_pos_mode(); 10368 if (reg_recording != 0) 10369 recording_mode(HL_ATTR(HLF_CM)); 10370 msg_clr_eos(); 10371 10372 msg_col = save_msg_col; 10373 msg_row = save_msg_row; 10374 } 10375 10376 static void 10377 recording_mode(int attr) 10378 { 10379 msg_puts_attr(_("recording"), attr); 10380 if (!shortmess(SHM_RECORDING)) 10381 { 10382 char s[4]; 10383 10384 sprintf(s, " @%c", reg_recording); 10385 msg_puts_attr(s, attr); 10386 } 10387 } 10388 10389 /* 10390 * Draw the tab pages line at the top of the Vim window. 10391 */ 10392 void 10393 draw_tabline(void) 10394 { 10395 int tabcount = 0; 10396 tabpage_T *tp; 10397 int tabwidth; 10398 int col = 0; 10399 int scol = 0; 10400 int attr; 10401 win_T *wp; 10402 win_T *cwp; 10403 int wincount; 10404 int modified; 10405 int c; 10406 int len; 10407 int attr_sel = HL_ATTR(HLF_TPS); 10408 int attr_nosel = HL_ATTR(HLF_TP); 10409 int attr_fill = HL_ATTR(HLF_TPF); 10410 char_u *p; 10411 int room; 10412 int use_sep_chars = (t_colors < 8 10413 #ifdef FEAT_GUI 10414 && !gui.in_use 10415 #endif 10416 #ifdef FEAT_TERMGUICOLORS 10417 && !p_tgc 10418 #endif 10419 ); 10420 10421 if (ScreenLines == NULL) 10422 return; 10423 redraw_tabline = FALSE; 10424 10425 #ifdef FEAT_GUI_TABLINE 10426 /* Take care of a GUI tabline. */ 10427 if (gui_use_tabline()) 10428 { 10429 gui_update_tabline(); 10430 return; 10431 } 10432 #endif 10433 10434 if (tabline_height() < 1) 10435 return; 10436 10437 #if defined(FEAT_STL_OPT) 10438 10439 /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */ 10440 for (scol = 0; scol < Columns; ++scol) 10441 TabPageIdxs[scol] = 0; 10442 10443 /* Use the 'tabline' option if it's set. */ 10444 if (*p_tal != NUL) 10445 { 10446 int saved_did_emsg = did_emsg; 10447 10448 /* Check for an error. If there is one we would loop in redrawing the 10449 * screen. Avoid that by making 'tabline' empty. */ 10450 did_emsg = FALSE; 10451 win_redr_custom(NULL, FALSE); 10452 if (did_emsg) 10453 set_string_option_direct((char_u *)"tabline", -1, 10454 (char_u *)"", OPT_FREE, SID_ERROR); 10455 did_emsg |= saved_did_emsg; 10456 } 10457 else 10458 #endif 10459 { 10460 FOR_ALL_TABPAGES(tp) 10461 ++tabcount; 10462 10463 tabwidth = (Columns - 1 + tabcount / 2) / tabcount; 10464 if (tabwidth < 6) 10465 tabwidth = 6; 10466 10467 attr = attr_nosel; 10468 tabcount = 0; 10469 for (tp = first_tabpage; tp != NULL && col < Columns - 4; 10470 tp = tp->tp_next) 10471 { 10472 scol = col; 10473 10474 if (tp->tp_topframe == topframe) 10475 attr = attr_sel; 10476 if (use_sep_chars && col > 0) 10477 screen_putchar('|', 0, col++, attr); 10478 10479 if (tp->tp_topframe != topframe) 10480 attr = attr_nosel; 10481 10482 screen_putchar(' ', 0, col++, attr); 10483 10484 if (tp == curtab) 10485 { 10486 cwp = curwin; 10487 wp = firstwin; 10488 } 10489 else 10490 { 10491 cwp = tp->tp_curwin; 10492 wp = tp->tp_firstwin; 10493 } 10494 10495 modified = FALSE; 10496 for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount) 10497 if (bufIsChanged(wp->w_buffer)) 10498 modified = TRUE; 10499 if (modified || wincount > 1) 10500 { 10501 if (wincount > 1) 10502 { 10503 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount); 10504 len = (int)STRLEN(NameBuff); 10505 if (col + len >= Columns - 3) 10506 break; 10507 screen_puts_len(NameBuff, len, 0, col, 10508 #if defined(FEAT_SYN_HL) 10509 hl_combine_attr(attr, HL_ATTR(HLF_T)) 10510 #else 10511 attr 10512 #endif 10513 ); 10514 col += len; 10515 } 10516 if (modified) 10517 screen_puts_len((char_u *)"+", 1, 0, col++, attr); 10518 screen_putchar(' ', 0, col++, attr); 10519 } 10520 10521 room = scol - col + tabwidth - 1; 10522 if (room > 0) 10523 { 10524 /* Get buffer name in NameBuff[] */ 10525 get_trans_bufname(cwp->w_buffer); 10526 shorten_dir(NameBuff); 10527 len = vim_strsize(NameBuff); 10528 p = NameBuff; 10529 if (has_mbyte) 10530 while (len > room) 10531 { 10532 len -= ptr2cells(p); 10533 MB_PTR_ADV(p); 10534 } 10535 else if (len > room) 10536 { 10537 p += len - room; 10538 len = room; 10539 } 10540 if (len > Columns - col - 1) 10541 len = Columns - col - 1; 10542 10543 screen_puts_len(p, (int)STRLEN(p), 0, col, attr); 10544 col += len; 10545 } 10546 screen_putchar(' ', 0, col++, attr); 10547 10548 /* Store the tab page number in TabPageIdxs[], so that 10549 * jump_to_mouse() knows where each one is. */ 10550 ++tabcount; 10551 while (scol < col) 10552 TabPageIdxs[scol++] = tabcount; 10553 } 10554 10555 if (use_sep_chars) 10556 c = '_'; 10557 else 10558 c = ' '; 10559 screen_fill(0, 1, col, (int)Columns, c, c, attr_fill); 10560 10561 /* Put an "X" for closing the current tab if there are several. */ 10562 if (first_tabpage->tp_next != NULL) 10563 { 10564 screen_putchar('X', 0, (int)Columns - 1, attr_nosel); 10565 TabPageIdxs[Columns - 1] = -999; 10566 } 10567 } 10568 10569 /* Reset the flag here again, in case evaluating 'tabline' causes it to be 10570 * set. */ 10571 redraw_tabline = FALSE; 10572 } 10573 10574 /* 10575 * Get buffer name for "buf" into NameBuff[]. 10576 * Takes care of special buffer names and translates special characters. 10577 */ 10578 void 10579 get_trans_bufname(buf_T *buf) 10580 { 10581 if (buf_spname(buf) != NULL) 10582 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1); 10583 else 10584 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE); 10585 trans_characters(NameBuff, MAXPATHL); 10586 } 10587 10588 /* 10589 * Get the character to use in a status line. Get its attributes in "*attr". 10590 */ 10591 static int 10592 fillchar_status(int *attr, win_T *wp) 10593 { 10594 int fill; 10595 10596 #ifdef FEAT_TERMINAL 10597 if (bt_terminal(wp->w_buffer)) 10598 { 10599 if (wp == curwin) 10600 { 10601 *attr = HL_ATTR(HLF_ST); 10602 fill = fill_stl; 10603 } 10604 else 10605 { 10606 *attr = HL_ATTR(HLF_STNC); 10607 fill = fill_stlnc; 10608 } 10609 } 10610 else 10611 #endif 10612 if (wp == curwin) 10613 { 10614 *attr = HL_ATTR(HLF_S); 10615 fill = fill_stl; 10616 } 10617 else 10618 { 10619 *attr = HL_ATTR(HLF_SNC); 10620 fill = fill_stlnc; 10621 } 10622 /* Use fill when there is highlighting, and highlighting of current 10623 * window differs, or the fillchars differ, or this is not the 10624 * current window */ 10625 if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC) 10626 || wp != curwin || ONE_WINDOW) 10627 || (fill_stl != fill_stlnc))) 10628 return fill; 10629 if (wp == curwin) 10630 return '^'; 10631 return '='; 10632 } 10633 10634 /* 10635 * Get the character to use in a separator between vertically split windows. 10636 * Get its attributes in "*attr". 10637 */ 10638 static int 10639 fillchar_vsep(int *attr) 10640 { 10641 *attr = HL_ATTR(HLF_C); 10642 if (*attr == 0 && fill_vert == ' ') 10643 return '|'; 10644 else 10645 return fill_vert; 10646 } 10647 10648 /* 10649 * Return TRUE if redrawing should currently be done. 10650 */ 10651 int 10652 redrawing(void) 10653 { 10654 #ifdef FEAT_EVAL 10655 if (disable_redraw_for_testing) 10656 return 0; 10657 else 10658 #endif 10659 return ((!RedrawingDisabled 10660 #ifdef FEAT_EVAL 10661 || ignore_redraw_flag_for_testing 10662 #endif 10663 ) && !(p_lz && char_avail() && !KeyTyped && !do_redraw)); 10664 } 10665 10666 /* 10667 * Return TRUE if printing messages should currently be done. 10668 */ 10669 int 10670 messaging(void) 10671 { 10672 return (!(p_lz && char_avail() && !KeyTyped)); 10673 } 10674 10675 #ifdef FEAT_MENU 10676 /* 10677 * Draw the window toolbar. 10678 */ 10679 static void 10680 redraw_win_toolbar(win_T *wp) 10681 { 10682 vimmenu_T *menu; 10683 int item_idx = 0; 10684 int item_count = 0; 10685 int col = 0; 10686 int next_col; 10687 int off = (int)(current_ScreenLine - ScreenLines); 10688 int fill_attr = syn_name2attr((char_u *)"ToolbarLine"); 10689 int button_attr = syn_name2attr((char_u *)"ToolbarButton"); 10690 10691 vim_free(wp->w_winbar_items); 10692 for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next) 10693 ++item_count; 10694 wp->w_winbar_items = (winbar_item_T *)alloc_clear( 10695 (unsigned)sizeof(winbar_item_T) * (item_count + 1)); 10696 10697 /* TODO: use fewer spaces if there is not enough room */ 10698 for (menu = wp->w_winbar->children; 10699 menu != NULL && col < wp->w_width; menu = menu->next) 10700 { 10701 space_to_screenline(off + col, fill_attr); 10702 if (++col >= wp->w_width) 10703 break; 10704 if (col > 1) 10705 { 10706 space_to_screenline(off + col, fill_attr); 10707 if (++col >= wp->w_width) 10708 break; 10709 } 10710 10711 wp->w_winbar_items[item_idx].wb_startcol = col; 10712 space_to_screenline(off + col, button_attr); 10713 if (++col >= wp->w_width) 10714 break; 10715 10716 next_col = text_to_screenline(wp, menu->name, col); 10717 while (col < next_col) 10718 { 10719 ScreenAttrs[off + col] = button_attr; 10720 ++col; 10721 } 10722 wp->w_winbar_items[item_idx].wb_endcol = col; 10723 wp->w_winbar_items[item_idx].wb_menu = menu; 10724 ++item_idx; 10725 10726 if (col >= wp->w_width) 10727 break; 10728 space_to_screenline(off + col, button_attr); 10729 ++col; 10730 } 10731 while (col < wp->w_width) 10732 { 10733 space_to_screenline(off + col, fill_attr); 10734 ++col; 10735 } 10736 wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */ 10737 10738 screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width, 10739 (int)wp->w_width, FALSE); 10740 } 10741 #endif 10742 10743 /* 10744 * Show current status info in ruler and various other places 10745 * If always is FALSE, only show ruler if position has changed. 10746 */ 10747 void 10748 showruler(int always) 10749 { 10750 if (!always && !redrawing()) 10751 return; 10752 #ifdef FEAT_INS_EXPAND 10753 if (pum_visible()) 10754 { 10755 /* Don't redraw right now, do it later. */ 10756 curwin->w_redr_status = TRUE; 10757 return; 10758 } 10759 #endif 10760 #if defined(FEAT_STL_OPT) 10761 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) 10762 redraw_custom_statusline(curwin); 10763 else 10764 #endif 10765 #ifdef FEAT_CMDL_INFO 10766 win_redr_ruler(curwin, always, FALSE); 10767 #endif 10768 10769 #ifdef FEAT_TITLE 10770 if (need_maketitle 10771 # ifdef FEAT_STL_OPT 10772 || (p_icon && (stl_syntax & STL_IN_ICON)) 10773 || (p_title && (stl_syntax & STL_IN_TITLE)) 10774 # endif 10775 ) 10776 maketitle(); 10777 #endif 10778 /* Redraw the tab pages line if needed. */ 10779 if (redraw_tabline) 10780 draw_tabline(); 10781 } 10782 10783 #ifdef FEAT_CMDL_INFO 10784 static void 10785 win_redr_ruler(win_T *wp, int always, int ignore_pum) 10786 { 10787 #define RULER_BUF_LEN 70 10788 char_u buffer[RULER_BUF_LEN]; 10789 int row; 10790 int fillchar; 10791 int attr; 10792 int empty_line = FALSE; 10793 colnr_T virtcol; 10794 int i; 10795 size_t len; 10796 int o; 10797 int this_ru_col; 10798 int off = 0; 10799 int width; 10800 10801 /* If 'ruler' off or redrawing disabled, don't do anything */ 10802 if (!p_ru) 10803 return; 10804 10805 /* 10806 * Check if cursor.lnum is valid, since win_redr_ruler() may be called 10807 * after deleting lines, before cursor.lnum is corrected. 10808 */ 10809 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) 10810 return; 10811 10812 #ifdef FEAT_INS_EXPAND 10813 /* Don't draw the ruler while doing insert-completion, it might overwrite 10814 * the (long) mode message. */ 10815 if (wp == lastwin && lastwin->w_status_height == 0) 10816 if (edit_submode != NULL) 10817 return; 10818 // Don't draw the ruler when the popup menu is visible, it may overlap. 10819 // Except when the popup menu will be redrawn anyway. 10820 if (!ignore_pum && pum_visible()) 10821 return; 10822 #endif 10823 10824 #ifdef FEAT_STL_OPT 10825 if (*p_ruf) 10826 { 10827 int save_called_emsg = called_emsg; 10828 10829 called_emsg = FALSE; 10830 win_redr_custom(wp, TRUE); 10831 if (called_emsg) 10832 set_string_option_direct((char_u *)"rulerformat", -1, 10833 (char_u *)"", OPT_FREE, SID_ERROR); 10834 called_emsg |= save_called_emsg; 10835 return; 10836 } 10837 #endif 10838 10839 /* 10840 * Check if not in Insert mode and the line is empty (will show "0-1"). 10841 */ 10842 if (!(State & INSERT) 10843 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL) 10844 empty_line = TRUE; 10845 10846 /* 10847 * Only draw the ruler when something changed. 10848 */ 10849 validate_virtcol_win(wp); 10850 if ( redraw_cmdline 10851 || always 10852 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum 10853 || wp->w_cursor.col != wp->w_ru_cursor.col 10854 || wp->w_virtcol != wp->w_ru_virtcol 10855 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd 10856 || wp->w_topline != wp->w_ru_topline 10857 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count 10858 #ifdef FEAT_DIFF 10859 || wp->w_topfill != wp->w_ru_topfill 10860 #endif 10861 || empty_line != wp->w_ru_empty) 10862 { 10863 cursor_off(); 10864 if (wp->w_status_height) 10865 { 10866 row = W_WINROW(wp) + wp->w_height; 10867 fillchar = fillchar_status(&attr, wp); 10868 off = wp->w_wincol; 10869 width = wp->w_width; 10870 } 10871 else 10872 { 10873 row = Rows - 1; 10874 fillchar = ' '; 10875 attr = 0; 10876 width = Columns; 10877 off = 0; 10878 } 10879 10880 /* In list mode virtcol needs to be recomputed */ 10881 virtcol = wp->w_virtcol; 10882 if (wp->w_p_list && lcs_tab1 == NUL) 10883 { 10884 wp->w_p_list = FALSE; 10885 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); 10886 wp->w_p_list = TRUE; 10887 } 10888 10889 /* 10890 * Some sprintfs return the length, some return a pointer. 10891 * To avoid portability problems we use strlen() here. 10892 */ 10893 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,", 10894 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) 10895 ? 0L 10896 : (long)(wp->w_cursor.lnum)); 10897 len = STRLEN(buffer); 10898 col_print(buffer + len, RULER_BUF_LEN - len, 10899 empty_line ? 0 : (int)wp->w_cursor.col + 1, 10900 (int)virtcol + 1); 10901 10902 /* 10903 * Add a "50%" if there is room for it. 10904 * On the last line, don't print in the last column (scrolls the 10905 * screen up on some terminals). 10906 */ 10907 i = (int)STRLEN(buffer); 10908 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1); 10909 o = i + vim_strsize(buffer + i + 1); 10910 if (wp->w_status_height == 0) /* can't use last char of screen */ 10911 ++o; 10912 this_ru_col = ru_col - (Columns - width); 10913 if (this_ru_col < 0) 10914 this_ru_col = 0; 10915 /* Never use more than half the window/screen width, leave the other 10916 * half for the filename. */ 10917 if (this_ru_col < (width + 1) / 2) 10918 this_ru_col = (width + 1) / 2; 10919 if (this_ru_col + o < width) 10920 { 10921 /* need at least 3 chars left for get_rel_pos() + NUL */ 10922 while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) 10923 { 10924 if (has_mbyte) 10925 i += (*mb_char2bytes)(fillchar, buffer + i); 10926 else 10927 buffer[i++] = fillchar; 10928 ++o; 10929 } 10930 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i); 10931 } 10932 /* Truncate at window boundary. */ 10933 if (has_mbyte) 10934 { 10935 o = 0; 10936 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i)) 10937 { 10938 o += (*mb_ptr2cells)(buffer + i); 10939 if (this_ru_col + o > width) 10940 { 10941 buffer[i] = NUL; 10942 break; 10943 } 10944 } 10945 } 10946 else if (this_ru_col + (int)STRLEN(buffer) > width) 10947 buffer[width - this_ru_col] = NUL; 10948 10949 screen_puts(buffer, row, this_ru_col + off, attr); 10950 i = redraw_cmdline; 10951 screen_fill(row, row + 1, 10952 this_ru_col + off + (int)STRLEN(buffer), 10953 (int)(off + width), 10954 fillchar, fillchar, attr); 10955 /* don't redraw the cmdline because of showing the ruler */ 10956 redraw_cmdline = i; 10957 wp->w_ru_cursor = wp->w_cursor; 10958 wp->w_ru_virtcol = wp->w_virtcol; 10959 wp->w_ru_empty = empty_line; 10960 wp->w_ru_topline = wp->w_topline; 10961 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count; 10962 #ifdef FEAT_DIFF 10963 wp->w_ru_topfill = wp->w_topfill; 10964 #endif 10965 } 10966 } 10967 #endif 10968 10969 #if defined(FEAT_LINEBREAK) || defined(PROTO) 10970 /* 10971 * Return the width of the 'number' and 'relativenumber' column. 10972 * Caller may need to check if 'number' or 'relativenumber' is set. 10973 * Otherwise it depends on 'numberwidth' and the line count. 10974 */ 10975 int 10976 number_width(win_T *wp) 10977 { 10978 int n; 10979 linenr_T lnum; 10980 10981 if (wp->w_p_rnu && !wp->w_p_nu) 10982 /* cursor line shows "0" */ 10983 lnum = wp->w_height; 10984 else 10985 /* cursor line shows absolute line number */ 10986 lnum = wp->w_buffer->b_ml.ml_line_count; 10987 10988 if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw) 10989 return wp->w_nrwidth_width; 10990 wp->w_nrwidth_line_count = lnum; 10991 10992 n = 0; 10993 do 10994 { 10995 lnum /= 10; 10996 ++n; 10997 } while (lnum > 0); 10998 10999 /* 'numberwidth' gives the minimal width plus one */ 11000 if (n < wp->w_p_nuw - 1) 11001 n = wp->w_p_nuw - 1; 11002 11003 wp->w_nrwidth_width = n; 11004 wp->w_nuw_cached = wp->w_p_nuw; 11005 return n; 11006 } 11007 #endif 11008 11009 #if defined(FEAT_EVAL) || defined(PROTO) 11010 /* 11011 * Return the current cursor column. This is the actual position on the 11012 * screen. First column is 0. 11013 */ 11014 int 11015 screen_screencol(void) 11016 { 11017 return screen_cur_col; 11018 } 11019 11020 /* 11021 * Return the current cursor row. This is the actual position on the screen. 11022 * First row is 0. 11023 */ 11024 int 11025 screen_screenrow(void) 11026 { 11027 return screen_cur_row; 11028 } 11029 #endif 11030