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