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