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