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