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