1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * drawline.c: Functions for drawing window lines on the screen. 12 * This is the middle level, drawscreen. is the higher level and screen.c the 13 * lower level. 14 */ 15 16 #include "vim.h" 17 18 #ifdef FEAT_SYN_HL 19 /* 20 * Advance **color_cols and return TRUE when there are columns to draw. 21 */ 22 static int 23 advance_color_col(int vcol, int **color_cols) 24 { 25 while (**color_cols >= 0 && vcol > **color_cols) 26 ++*color_cols; 27 return (**color_cols >= 0); 28 } 29 #endif 30 31 #ifdef FEAT_SYN_HL 32 /* 33 * Used when 'cursorlineopt' contains "screenline": compute the margins between 34 * which the highlighting is used. 35 */ 36 static void 37 margin_columns_win(win_T *wp, int *left_col, int *right_col) 38 { 39 // cache previous calculations depending on w_virtcol 40 static int saved_w_virtcol; 41 static win_T *prev_wp; 42 static int prev_left_col; 43 static int prev_right_col; 44 static int prev_col_off; 45 46 int cur_col_off = win_col_off(wp); 47 int width1; 48 int width2; 49 50 if (saved_w_virtcol == wp->w_virtcol 51 && prev_wp == wp && prev_col_off == cur_col_off) 52 { 53 *right_col = prev_right_col; 54 *left_col = prev_left_col; 55 return; 56 } 57 58 width1 = wp->w_width - cur_col_off; 59 width2 = width1 + win_col_off2(wp); 60 61 *left_col = 0; 62 *right_col = width1; 63 64 if (wp->w_virtcol >= (colnr_T)width1) 65 *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2; 66 if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) 67 *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1; 68 69 // cache values 70 prev_left_col = *left_col; 71 prev_right_col = *right_col; 72 prev_wp = wp; 73 saved_w_virtcol = wp->w_virtcol; 74 prev_col_off = cur_col_off; 75 } 76 #endif 77 78 #ifdef FEAT_SIGNS 79 /* 80 * Get information needed to display the sign in line 'lnum' in window 'wp'. 81 * If 'nrcol' is TRUE, the sign is going to be displayed in the number column. 82 * Otherwise the sign is going to be displayed in the sign column. 83 */ 84 static void 85 get_sign_display_info( 86 int nrcol, 87 win_T *wp, 88 linenr_T lnum UNUSED, 89 sign_attrs_T *sattr, 90 int wcr_attr, 91 int row, 92 int startrow, 93 int filler_lines UNUSED, 94 int filler_todo UNUSED, 95 int *c_extrap, 96 int *c_finalp, 97 char_u *extra, 98 char_u **pp_extra, 99 int *n_extrap, 100 int *char_attrp) 101 { 102 int text_sign; 103 # ifdef FEAT_SIGN_ICONS 104 int icon_sign; 105 # endif 106 107 // Draw two cells with the sign value or blank. 108 *c_extrap = ' '; 109 *c_finalp = NUL; 110 if (nrcol) 111 *n_extrap = number_width(wp) + 1; 112 else 113 { 114 *char_attrp = hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)); 115 *n_extrap = 2; 116 } 117 118 if (row == startrow 119 #ifdef FEAT_DIFF 120 + filler_lines && filler_todo <= 0 121 #endif 122 ) 123 { 124 text_sign = (sattr->sat_text != NULL) ? sattr->sat_typenr : 0; 125 # ifdef FEAT_SIGN_ICONS 126 icon_sign = (sattr->sat_icon != NULL) ? sattr->sat_typenr : 0; 127 if (gui.in_use && icon_sign != 0) 128 { 129 // Use the image in this position. 130 if (nrcol) 131 { 132 *c_extrap = NUL; 133 sprintf((char *)extra, "%-*c ", number_width(wp), SIGN_BYTE); 134 *pp_extra = extra; 135 *n_extrap = (int)STRLEN(*pp_extra); 136 } 137 else 138 *c_extrap = SIGN_BYTE; 139 # ifdef FEAT_NETBEANS_INTG 140 if (netbeans_active() && (buf_signcount(wp->w_buffer, lnum) > 1)) 141 { 142 if (nrcol) 143 { 144 *c_extrap = NUL; 145 sprintf((char *)extra, "%-*c ", number_width(wp), 146 MULTISIGN_BYTE); 147 *pp_extra = extra; 148 *n_extrap = (int)STRLEN(*pp_extra); 149 } 150 else 151 *c_extrap = MULTISIGN_BYTE; 152 } 153 # endif 154 *c_finalp = NUL; 155 *char_attrp = icon_sign; 156 } 157 else 158 # endif 159 if (text_sign != 0) 160 { 161 *pp_extra = sattr->sat_text; 162 if (*pp_extra != NULL) 163 { 164 if (nrcol) 165 { 166 int n, width = number_width(wp) - 2; 167 168 for (n = 0; n < width; n++) 169 extra[n] = ' '; 170 extra[n] = 0; 171 STRCAT(extra, *pp_extra); 172 STRCAT(extra, " "); 173 *pp_extra = extra; 174 } 175 *c_extrap = NUL; 176 *c_finalp = NUL; 177 *n_extrap = (int)STRLEN(*pp_extra); 178 } 179 *char_attrp = sattr->sat_texthl; 180 } 181 } 182 } 183 #endif 184 185 #ifdef FEAT_PROP_POPUP 186 static textprop_T *current_text_props = NULL; 187 static buf_T *current_buf = NULL; 188 189 static int 190 text_prop_compare(const void *s1, const void *s2) 191 { 192 int idx1, idx2; 193 proptype_T *pt1, *pt2; 194 colnr_T col1, col2; 195 196 idx1 = *(int *)s1; 197 idx2 = *(int *)s2; 198 pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type); 199 pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type); 200 if (pt1 == pt2) 201 return 0; 202 if (pt1 == NULL) 203 return -1; 204 if (pt2 == NULL) 205 return 1; 206 if (pt1->pt_priority != pt2->pt_priority) 207 return pt1->pt_priority > pt2->pt_priority ? 1 : -1; 208 col1 = current_text_props[idx1].tp_col; 209 col2 = current_text_props[idx2].tp_col; 210 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1; 211 } 212 #endif 213 214 /* 215 * Display line "lnum" of window 'wp' on the screen. 216 * Start at row "startrow", stop when "endrow" is reached. 217 * wp->w_virtcol needs to be valid. 218 * 219 * Return the number of last row the line occupies. 220 */ 221 int 222 win_line( 223 win_T *wp, 224 linenr_T lnum, 225 int startrow, 226 int endrow, 227 int nochange UNUSED, // not updating for changed text 228 int number_only) // only update the number column 229 { 230 int col = 0; // visual column on screen 231 unsigned off; // offset in ScreenLines/ScreenAttrs 232 int c = 0; // init for GCC 233 long vcol = 0; // virtual column (for tabs) 234 #ifdef FEAT_LINEBREAK 235 long vcol_sbr = -1; // virtual column after showbreak 236 #endif 237 long vcol_prev = -1; // "vcol" of previous character 238 char_u *line; // current line 239 char_u *ptr; // current position in "line" 240 int row; // row in the window, excl w_winrow 241 int screen_row; // row on the screen, incl w_winrow 242 243 char_u extra[21]; // "%ld " and 'fdc' must fit in here 244 int n_extra = 0; // number of extra chars 245 char_u *p_extra = NULL; // string of extra chars, plus NUL 246 char_u *p_extra_free = NULL; // p_extra needs to be freed 247 int c_extra = NUL; // extra chars, all the same 248 int c_final = NUL; // final char, mandatory if set 249 int extra_attr = 0; // attributes when n_extra != 0 250 static char_u *at_end_str = (char_u *)""; // used for p_extra when 251 // displaying lcs_eol at end-of-line 252 int lcs_eol_one = lcs_eol; // lcs_eol until it's been used 253 int lcs_prec_todo = lcs_prec; // lcs_prec until it's been used 254 255 // saved "extra" items for when draw_state becomes WL_LINE (again) 256 int saved_n_extra = 0; 257 char_u *saved_p_extra = NULL; 258 int saved_c_extra = 0; 259 int saved_c_final = 0; 260 int saved_char_attr = 0; 261 262 int n_attr = 0; // chars with special attr 263 int saved_attr2 = 0; // char_attr saved for n_attr 264 int n_attr3 = 0; // chars with overruling special attr 265 int saved_attr3 = 0; // char_attr saved for n_attr3 266 267 int n_skip = 0; // nr of chars to skip for 'nowrap' 268 269 int fromcol = -10; // start of inverting 270 int tocol = MAXCOL; // end of inverting 271 int fromcol_prev = -2; // start of inverting after cursor 272 int noinvcur = FALSE; // don't invert the cursor 273 int lnum_in_visual_area = FALSE; 274 pos_T pos; 275 long v; 276 277 int char_attr = 0; // attributes for next character 278 int attr_pri = FALSE; // char_attr has priority 279 int area_highlighting = FALSE; // Visual or incsearch highlighting 280 // in this line 281 int vi_attr = 0; // attributes for Visual and incsearch 282 // highlighting 283 int wcr_attr = 0; // attributes from 'wincolor' 284 int win_attr = 0; // background for whole window, except 285 // margins and "~" lines. 286 int area_attr = 0; // attributes desired by highlighting 287 int search_attr = 0; // attributes desired by 'hlsearch' 288 #ifdef FEAT_SYN_HL 289 int vcol_save_attr = 0; // saved attr for 'cursorcolumn' 290 int syntax_attr = 0; // attributes desired by syntax 291 int prev_syntax_col = -1; // column of prev_syntax_attr 292 int prev_syntax_attr = 0; // syntax_attr at prev_syntax_col 293 int has_syntax = FALSE; // this buffer has syntax highl. 294 int save_did_emsg; 295 int draw_color_col = FALSE; // highlight colorcolumn 296 int *color_cols = NULL; // pointer to according columns array 297 #endif 298 int eol_hl_off = 0; // 1 if highlighted char after EOL 299 #ifdef FEAT_PROP_POPUP 300 int text_prop_count; 301 int text_prop_next = 0; // next text property to use 302 textprop_T *text_props = NULL; 303 int *text_prop_idxs = NULL; 304 int text_props_active = 0; 305 proptype_T *text_prop_type = NULL; 306 int text_prop_attr = 0; 307 int text_prop_combine = FALSE; 308 #endif 309 #ifdef FEAT_SPELL 310 int has_spell = FALSE; // this buffer has spell checking 311 int can_spell; 312 # define SPWORDLEN 150 313 char_u nextline[SPWORDLEN * 2];// text with start of the next line 314 int nextlinecol = 0; // column where nextline[] starts 315 int nextline_idx = 0; // index in nextline[] where next line 316 // starts 317 int spell_attr = 0; // attributes desired by spelling 318 int word_end = 0; // last byte with same spell_attr 319 static linenr_T checked_lnum = 0; // line number for "checked_col" 320 static int checked_col = 0; // column in "checked_lnum" up to which 321 // there are no spell errors 322 static int cap_col = -1; // column to check for Cap word 323 static linenr_T capcol_lnum = 0; // line number where "cap_col" used 324 int cur_checked_col = 0; // checked column for current line 325 #endif 326 int extra_check = 0; // has extra highlighting 327 int multi_attr = 0; // attributes desired by multibyte 328 int mb_l = 1; // multi-byte byte length 329 int mb_c = 0; // decoded multi-byte character 330 int mb_utf8 = FALSE; // screen char is UTF-8 char 331 int u8cc[MAX_MCO]; // composing UTF-8 chars 332 #if defined(FEAT_DIFF) || defined(FEAT_SIGNS) 333 int filler_lines = 0; // nr of filler lines to be drawn 334 int filler_todo = 0; // nr of filler lines still to do + 1 335 #endif 336 #ifdef FEAT_DIFF 337 hlf_T diff_hlf = (hlf_T)0; // type of diff highlighting 338 int change_start = MAXCOL; // first col of changed area 339 int change_end = -1; // last col of changed area 340 #endif 341 colnr_T trailcol = MAXCOL; // start of trailing spaces 342 #ifdef FEAT_LINEBREAK 343 int need_showbreak = FALSE; // overlong line, skipping first x 344 // chars 345 #endif 346 #if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \ 347 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF) 348 # define LINE_ATTR 349 int line_attr = 0; // attribute for the whole line 350 int line_attr_save; 351 #endif 352 #ifdef FEAT_SIGNS 353 int sign_present = FALSE; 354 sign_attrs_T sattr; 355 #endif 356 #ifdef FEAT_ARABIC 357 int prev_c = 0; // previous Arabic character 358 int prev_c1 = 0; // first composing char for prev_c 359 #endif 360 #if defined(LINE_ATTR) 361 int did_line_attr = 0; 362 #endif 363 #ifdef FEAT_TERMINAL 364 int get_term_attr = FALSE; 365 #endif 366 #ifdef FEAT_SYN_HL 367 int cul_attr = 0; // set when 'cursorline' active 368 369 // 'cursorlineopt' has "screenline" and cursor is in this line 370 int cul_screenline = FALSE; 371 372 // margin columns for the screen line, needed for when 'cursorlineopt' 373 // contains "screenline" 374 int left_curline_col = 0; 375 int right_curline_col = 0; 376 #endif 377 378 // draw_state: items that are drawn in sequence: 379 #define WL_START 0 // nothing done yet 380 #ifdef FEAT_CMDWIN 381 # define WL_CMDLINE WL_START + 1 // cmdline window column 382 #else 383 # define WL_CMDLINE WL_START 384 #endif 385 #ifdef FEAT_FOLDING 386 # define WL_FOLD WL_CMDLINE + 1 // 'foldcolumn' 387 #else 388 # define WL_FOLD WL_CMDLINE 389 #endif 390 #ifdef FEAT_SIGNS 391 # define WL_SIGN WL_FOLD + 1 // column for signs 392 #else 393 # define WL_SIGN WL_FOLD // column for signs 394 #endif 395 #define WL_NR WL_SIGN + 1 // line number 396 #ifdef FEAT_LINEBREAK 397 # define WL_BRI WL_NR + 1 // 'breakindent' 398 #else 399 # define WL_BRI WL_NR 400 #endif 401 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) 402 # define WL_SBR WL_BRI + 1 // 'showbreak' or 'diff' 403 #else 404 # define WL_SBR WL_BRI 405 #endif 406 #define WL_LINE WL_SBR + 1 // text in the line 407 int draw_state = WL_START; // what to draw next 408 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 409 int feedback_col = 0; 410 int feedback_old_attr = -1; 411 #endif 412 int screen_line_flags = 0; 413 414 #if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) 415 int match_conc = 0; // cchar for match functions 416 #endif 417 #ifdef FEAT_CONCEAL 418 int syntax_flags = 0; 419 int syntax_seqnr = 0; 420 int prev_syntax_id = 0; 421 int conceal_attr = HL_ATTR(HLF_CONCEAL); 422 int is_concealing = FALSE; 423 int boguscols = 0; // nonexistent columns added to force 424 // wrapping 425 int vcol_off = 0; // offset for concealed characters 426 int did_wcol = FALSE; 427 int old_boguscols = 0; 428 # define VCOL_HLC (vcol - vcol_off) 429 # define FIX_FOR_BOGUSCOLS \ 430 { \ 431 n_extra += vcol_off; \ 432 vcol -= vcol_off; \ 433 vcol_off = 0; \ 434 col -= boguscols; \ 435 old_boguscols = boguscols; \ 436 boguscols = 0; \ 437 } 438 #else 439 # define VCOL_HLC (vcol) 440 #endif 441 442 if (startrow > endrow) // past the end already! 443 return startrow; 444 445 row = startrow; 446 screen_row = row + W_WINROW(wp); 447 448 if (!number_only) 449 { 450 // To speed up the loop below, set extra_check when there is linebreak, 451 // trailing white space and/or syntax processing to be done. 452 #ifdef FEAT_LINEBREAK 453 extra_check = wp->w_p_lbr; 454 #endif 455 #ifdef FEAT_SYN_HL 456 if (syntax_present(wp) && !wp->w_s->b_syn_error 457 # ifdef SYN_TIME_LIMIT 458 && !wp->w_s->b_syn_slow 459 # endif 460 ) 461 { 462 // Prepare for syntax highlighting in this line. When there is an 463 // error, stop syntax highlighting. 464 save_did_emsg = did_emsg; 465 did_emsg = FALSE; 466 syntax_start(wp, lnum); 467 if (did_emsg) 468 wp->w_s->b_syn_error = TRUE; 469 else 470 { 471 did_emsg = save_did_emsg; 472 #ifdef SYN_TIME_LIMIT 473 if (!wp->w_s->b_syn_slow) 474 #endif 475 { 476 has_syntax = TRUE; 477 extra_check = TRUE; 478 } 479 } 480 } 481 482 // Check for columns to display for 'colorcolumn'. 483 color_cols = wp->w_p_cc_cols; 484 if (color_cols != NULL) 485 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); 486 #endif 487 488 #ifdef FEAT_TERMINAL 489 if (term_show_buffer(wp->w_buffer)) 490 { 491 extra_check = TRUE; 492 get_term_attr = TRUE; 493 win_attr = term_get_attr(wp, lnum, -1); 494 } 495 #endif 496 497 #ifdef FEAT_SPELL 498 if (wp->w_p_spell 499 && *wp->w_s->b_p_spl != NUL 500 && wp->w_s->b_langp.ga_len > 0 501 && *(char **)(wp->w_s->b_langp.ga_data) != NULL) 502 { 503 // Prepare for spell checking. 504 has_spell = TRUE; 505 extra_check = TRUE; 506 507 // Get the start of the next line, so that words that wrap to the 508 // next line are found too: "et<line-break>al.". 509 // Trick: skip a few chars for C/shell/Vim comments 510 nextline[SPWORDLEN] = NUL; 511 if (lnum < wp->w_buffer->b_ml.ml_line_count) 512 { 513 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE); 514 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); 515 } 516 517 // When a word wrapped from the previous line the start of the 518 // current line is valid. 519 if (lnum == checked_lnum) 520 cur_checked_col = checked_col; 521 checked_lnum = 0; 522 523 // When there was a sentence end in the previous line may require a 524 // word starting with capital in this line. In line 1 always check 525 // the first word. 526 if (lnum != capcol_lnum) 527 cap_col = -1; 528 if (lnum == 1) 529 cap_col = 0; 530 capcol_lnum = 0; 531 } 532 #endif 533 534 // handle Visual active in this window 535 if (VIsual_active && wp->w_buffer == curwin->w_buffer) 536 { 537 pos_T *top, *bot; 538 539 if (LTOREQ_POS(curwin->w_cursor, VIsual)) 540 { 541 // Visual is after curwin->w_cursor 542 top = &curwin->w_cursor; 543 bot = &VIsual; 544 } 545 else 546 { 547 // Visual is before curwin->w_cursor 548 top = &VIsual; 549 bot = &curwin->w_cursor; 550 } 551 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum); 552 if (VIsual_mode == Ctrl_V) 553 { 554 // block mode 555 if (lnum_in_visual_area) 556 { 557 fromcol = wp->w_old_cursor_fcol; 558 tocol = wp->w_old_cursor_lcol; 559 } 560 } 561 else 562 { 563 // non-block mode 564 if (lnum > top->lnum && lnum <= bot->lnum) 565 fromcol = 0; 566 else if (lnum == top->lnum) 567 { 568 if (VIsual_mode == 'V') // linewise 569 fromcol = 0; 570 else 571 { 572 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL); 573 if (gchar_pos(top) == NUL) 574 tocol = fromcol + 1; 575 } 576 } 577 if (VIsual_mode != 'V' && lnum == bot->lnum) 578 { 579 if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0) 580 { 581 fromcol = -10; 582 tocol = MAXCOL; 583 } 584 else if (bot->col == MAXCOL) 585 tocol = MAXCOL; 586 else 587 { 588 pos = *bot; 589 if (*p_sel == 'e') 590 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL); 591 else 592 { 593 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol); 594 ++tocol; 595 } 596 } 597 } 598 } 599 600 // Check if the character under the cursor should not be inverted 601 if (!highlight_match && lnum == curwin->w_cursor.lnum 602 && wp == curwin 603 #ifdef FEAT_GUI 604 && !gui.in_use 605 #endif 606 ) 607 noinvcur = TRUE; 608 609 // if inverting in this line set area_highlighting 610 if (fromcol >= 0) 611 { 612 area_highlighting = TRUE; 613 vi_attr = HL_ATTR(HLF_V); 614 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) 615 if ((clip_star.available && !clip_star.owned 616 && clip_isautosel_star()) 617 || (clip_plus.available && !clip_plus.owned 618 && clip_isautosel_plus())) 619 vi_attr = HL_ATTR(HLF_VNC); 620 #endif 621 } 622 } 623 624 // handle 'incsearch' and ":s///c" highlighting 625 else if (highlight_match 626 && wp == curwin 627 && lnum >= curwin->w_cursor.lnum 628 && lnum <= curwin->w_cursor.lnum + search_match_lines) 629 { 630 if (lnum == curwin->w_cursor.lnum) 631 getvcol(curwin, &(curwin->w_cursor), 632 (colnr_T *)&fromcol, NULL, NULL); 633 else 634 fromcol = 0; 635 if (lnum == curwin->w_cursor.lnum + search_match_lines) 636 { 637 pos.lnum = lnum; 638 pos.col = search_match_endcol; 639 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL); 640 } 641 else 642 tocol = MAXCOL; 643 // do at least one character; happens when past end of line 644 if (fromcol == tocol) 645 tocol = fromcol + 1; 646 area_highlighting = TRUE; 647 vi_attr = HL_ATTR(HLF_I); 648 } 649 } 650 651 #ifdef FEAT_DIFF 652 filler_lines = diff_check(wp, lnum); 653 if (filler_lines < 0) 654 { 655 if (filler_lines == -1) 656 { 657 if (diff_find_change(wp, lnum, &change_start, &change_end)) 658 diff_hlf = HLF_ADD; // added line 659 else if (change_start == 0) 660 diff_hlf = HLF_TXD; // changed text 661 else 662 diff_hlf = HLF_CHD; // changed line 663 } 664 else 665 diff_hlf = HLF_ADD; // added line 666 filler_lines = 0; 667 area_highlighting = TRUE; 668 } 669 if (lnum == wp->w_topline) 670 filler_lines = wp->w_topfill; 671 filler_todo = filler_lines; 672 #endif 673 674 #ifdef FEAT_SIGNS 675 sign_present = buf_get_signattrs(wp, lnum, &sattr); 676 #endif 677 678 #ifdef LINE_ATTR 679 # ifdef FEAT_SIGNS 680 // If this line has a sign with line highlighting set line_attr. 681 if (sign_present) 682 line_attr = sattr.sat_linehl; 683 # endif 684 # if defined(FEAT_QUICKFIX) 685 // Highlight the current line in the quickfix window. 686 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) 687 line_attr = HL_ATTR(HLF_QFL); 688 # endif 689 if (line_attr != 0) 690 area_highlighting = TRUE; 691 #endif 692 693 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 694 ptr = line; 695 696 #ifdef FEAT_SPELL 697 if (has_spell && !number_only) 698 { 699 // For checking first word with a capital skip white space. 700 if (cap_col == 0) 701 cap_col = getwhitecols(line); 702 703 // To be able to spell-check over line boundaries copy the end of the 704 // current line into nextline[]. Above the start of the next line was 705 // copied to nextline[SPWORDLEN]. 706 if (nextline[SPWORDLEN] == NUL) 707 { 708 // No next line or it is empty. 709 nextlinecol = MAXCOL; 710 nextline_idx = 0; 711 } 712 else 713 { 714 v = (long)STRLEN(line); 715 if (v < SPWORDLEN) 716 { 717 // Short line, use it completely and append the start of the 718 // next line. 719 nextlinecol = 0; 720 mch_memmove(nextline, line, (size_t)v); 721 STRMOVE(nextline + v, nextline + SPWORDLEN); 722 nextline_idx = v + 1; 723 } 724 else 725 { 726 // Long line, use only the last SPWORDLEN bytes. 727 nextlinecol = v - SPWORDLEN; 728 mch_memmove(nextline, line + nextlinecol, SPWORDLEN); 729 nextline_idx = SPWORDLEN + 1; 730 } 731 } 732 } 733 #endif 734 735 if (wp->w_p_list) 736 { 737 if (lcs_space || lcs_trail || lcs_nbsp) 738 extra_check = TRUE; 739 // find start of trailing whitespace 740 if (lcs_trail) 741 { 742 trailcol = (colnr_T)STRLEN(ptr); 743 while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1])) 744 --trailcol; 745 trailcol += (colnr_T) (ptr - line); 746 } 747 } 748 749 wcr_attr = get_wcr_attr(wp); 750 if (wcr_attr != 0) 751 { 752 win_attr = wcr_attr; 753 area_highlighting = TRUE; 754 } 755 756 #ifdef FEAT_PROP_POPUP 757 if (WIN_IS_POPUP(wp)) 758 screen_line_flags |= SLF_POPUP; 759 #endif 760 761 // 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the 762 // first character to be displayed. 763 if (wp->w_p_wrap) 764 v = wp->w_skipcol; 765 else 766 v = wp->w_leftcol; 767 if (v > 0 && !number_only) 768 { 769 char_u *prev_ptr = ptr; 770 771 while (vcol < v && *ptr != NUL) 772 { 773 c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL); 774 vcol += c; 775 prev_ptr = ptr; 776 MB_PTR_ADV(ptr); 777 } 778 779 // When: 780 // - 'cuc' is set, or 781 // - 'colorcolumn' is set, or 782 // - 'virtualedit' is set, or 783 // - the visual mode is active, 784 // the end of the line may be before the start of the displayed part. 785 if (vcol < v && ( 786 #ifdef FEAT_SYN_HL 787 wp->w_p_cuc || draw_color_col || 788 #endif 789 virtual_active() || 790 (VIsual_active && wp->w_buffer == curwin->w_buffer))) 791 vcol = v; 792 793 // Handle a character that's not completely on the screen: Put ptr at 794 // that character but skip the first few screen characters. 795 if (vcol > v) 796 { 797 vcol -= c; 798 ptr = prev_ptr; 799 // If the character fits on the screen, don't need to skip it. 800 // Except for a TAB. 801 if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0) 802 n_skip = v - vcol; 803 } 804 805 // Adjust for when the inverted text is before the screen, 806 // and when the start of the inverted text is before the screen. 807 if (tocol <= vcol) 808 fromcol = 0; 809 else if (fromcol >= 0 && fromcol < vcol) 810 fromcol = vcol; 811 812 #ifdef FEAT_LINEBREAK 813 // When w_skipcol is non-zero, first line needs 'showbreak' 814 if (wp->w_p_wrap) 815 need_showbreak = TRUE; 816 #endif 817 #ifdef FEAT_SPELL 818 // When spell checking a word we need to figure out the start of the 819 // word and if it's badly spelled or not. 820 if (has_spell) 821 { 822 int len; 823 colnr_T linecol = (colnr_T)(ptr - line); 824 hlf_T spell_hlf = HLF_COUNT; 825 826 pos = wp->w_cursor; 827 wp->w_cursor.lnum = lnum; 828 wp->w_cursor.col = linecol; 829 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf); 830 831 // spell_move_to() may call ml_get() and make "line" invalid 832 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 833 ptr = line + linecol; 834 835 if (len == 0 || (int)wp->w_cursor.col > ptr - line) 836 { 837 // no bad word found at line start, don't check until end of a 838 // word 839 spell_hlf = HLF_COUNT; 840 word_end = (int)(spell_to_word_end(ptr, wp) - line + 1); 841 } 842 else 843 { 844 // bad word found, use attributes until end of word 845 word_end = wp->w_cursor.col + len + 1; 846 847 // Turn index into actual attributes. 848 if (spell_hlf != HLF_COUNT) 849 spell_attr = highlight_attr[spell_hlf]; 850 } 851 wp->w_cursor = pos; 852 853 # ifdef FEAT_SYN_HL 854 // Need to restart syntax highlighting for this line. 855 if (has_syntax) 856 syntax_start(wp, lnum); 857 # endif 858 } 859 #endif 860 } 861 862 // Correct highlighting for cursor that can't be disabled. 863 // Avoids having to check this for each character. 864 if (fromcol >= 0) 865 { 866 if (noinvcur) 867 { 868 if ((colnr_T)fromcol == wp->w_virtcol) 869 { 870 // highlighting starts at cursor, let it start just after the 871 // cursor 872 fromcol_prev = fromcol; 873 fromcol = -1; 874 } 875 else if ((colnr_T)fromcol < wp->w_virtcol) 876 // restart highlighting after the cursor 877 fromcol_prev = wp->w_virtcol; 878 } 879 if (fromcol >= tocol) 880 fromcol = -1; 881 } 882 883 #ifdef FEAT_SEARCH_EXTRA 884 if (!number_only) 885 { 886 v = (long)(ptr - line); 887 area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v, 888 &line, &screen_search_hl, 889 &search_attr); 890 ptr = line + v; // "line" may have been updated 891 } 892 #endif 893 894 #ifdef FEAT_SYN_HL 895 // Cursor line highlighting for 'cursorline' in the current window. 896 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) 897 { 898 // Do not show the cursor line in the text when Visual mode is active, 899 // because it's not clear what is selected then. Do update 900 // w_last_cursorline. 901 if (!(wp == curwin && VIsual_active) 902 && wp->w_p_culopt_flags != CULOPT_NBR) 903 { 904 cul_screenline = (wp->w_p_wrap 905 && (wp->w_p_culopt_flags & CULOPT_SCRLINE)); 906 907 // Only set line_attr here when "screenline" is not present in 908 // 'cursorlineopt'. Otherwise it's done later. 909 if (!cul_screenline) 910 { 911 cul_attr = HL_ATTR(HLF_CUL); 912 line_attr = cul_attr; 913 wp->w_last_cursorline = wp->w_cursor.lnum; 914 } 915 else 916 { 917 line_attr_save = line_attr; 918 wp->w_last_cursorline = 0; 919 margin_columns_win(wp, &left_curline_col, &right_curline_col); 920 } 921 area_highlighting = TRUE; 922 } 923 else 924 wp->w_last_cursorline = wp->w_cursor.lnum; 925 } 926 #endif 927 928 #ifdef FEAT_PROP_POPUP 929 { 930 char_u *prop_start; 931 932 text_prop_count = get_text_props(wp->w_buffer, lnum, 933 &prop_start, FALSE); 934 if (text_prop_count > 0) 935 { 936 // Make a copy of the properties, so that they are properly 937 // aligned. 938 text_props = ALLOC_MULT(textprop_T, text_prop_count); 939 if (text_props != NULL) 940 mch_memmove(text_props, prop_start, 941 text_prop_count * sizeof(textprop_T)); 942 943 // Allocate an array for the indexes. 944 text_prop_idxs = ALLOC_MULT(int, text_prop_count); 945 area_highlighting = TRUE; 946 extra_check = TRUE; 947 } 948 } 949 #endif 950 951 off = (unsigned)(current_ScreenLine - ScreenLines); 952 col = 0; 953 954 #ifdef FEAT_RIGHTLEFT 955 if (wp->w_p_rl) 956 { 957 // Rightleft window: process the text in the normal direction, but put 958 // it in current_ScreenLine[] from right to left. Start at the 959 // rightmost column of the window. 960 col = wp->w_width - 1; 961 off += col; 962 screen_line_flags |= SLF_RIGHTLEFT; 963 } 964 #endif 965 966 // Repeat for the whole displayed line. 967 for (;;) 968 { 969 #if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) 970 int has_match_conc = 0; // match wants to conceal 971 #endif 972 #ifdef FEAT_CONCEAL 973 int did_decrement_ptr = FALSE; 974 #endif 975 // Skip this quickly when working on the text. 976 if (draw_state != WL_LINE) 977 { 978 #ifdef FEAT_CMDWIN 979 if (draw_state == WL_CMDLINE - 1 && n_extra == 0) 980 { 981 draw_state = WL_CMDLINE; 982 if (cmdwin_type != 0 && wp == curwin) 983 { 984 // Draw the cmdline character. 985 n_extra = 1; 986 c_extra = cmdwin_type; 987 c_final = NUL; 988 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_AT)); 989 } 990 } 991 #endif 992 993 #ifdef FEAT_FOLDING 994 if (draw_state == WL_FOLD - 1 && n_extra == 0) 995 { 996 int fdc = compute_foldcolumn(wp, 0); 997 998 draw_state = WL_FOLD; 999 if (fdc > 0) 1000 { 1001 // Draw the 'foldcolumn'. Allocate a buffer, "extra" may 1002 // already be in use. 1003 vim_free(p_extra_free); 1004 p_extra_free = alloc(12 + 1); 1005 1006 if (p_extra_free != NULL) 1007 { 1008 fill_foldcolumn(p_extra_free, wp, FALSE, lnum); 1009 n_extra = fdc; 1010 p_extra_free[n_extra] = NUL; 1011 p_extra = p_extra_free; 1012 c_extra = NUL; 1013 c_final = NUL; 1014 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)); 1015 } 1016 } 1017 } 1018 #endif 1019 1020 #ifdef FEAT_SIGNS 1021 if (draw_state == WL_SIGN - 1 && n_extra == 0) 1022 { 1023 draw_state = WL_SIGN; 1024 // Show the sign column when there are any signs in this 1025 // buffer or when using Netbeans. 1026 if (signcolumn_on(wp)) 1027 get_sign_display_info(FALSE, wp, lnum, &sattr, wcr_attr, 1028 row, startrow, filler_lines, filler_todo, &c_extra, 1029 &c_final, extra, &p_extra, &n_extra, &char_attr); 1030 } 1031 #endif 1032 1033 if (draw_state == WL_NR - 1 && n_extra == 0) 1034 { 1035 draw_state = WL_NR; 1036 // Display the absolute or relative line number. After the 1037 // first fill with blanks when the 'n' flag isn't in 'cpo' 1038 if ((wp->w_p_nu || wp->w_p_rnu) 1039 && (row == startrow 1040 #ifdef FEAT_DIFF 1041 + filler_lines 1042 #endif 1043 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL)) 1044 { 1045 #ifdef FEAT_SIGNS 1046 // If 'signcolumn' is set to 'number' and a sign is present 1047 // in 'lnum', then display the sign instead of the line 1048 // number. 1049 if ((*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u') 1050 && sign_present) 1051 get_sign_display_info(TRUE, wp, lnum, &sattr, wcr_attr, 1052 row, startrow, filler_lines, filler_todo, 1053 &c_extra, &c_final, extra, &p_extra, &n_extra, 1054 &char_attr); 1055 else 1056 #endif 1057 { 1058 // Draw the line number (empty space after wrapping). 1059 if (row == startrow 1060 #ifdef FEAT_DIFF 1061 + filler_lines 1062 #endif 1063 ) 1064 { 1065 long num; 1066 char *fmt = "%*ld "; 1067 1068 if (wp->w_p_nu && !wp->w_p_rnu) 1069 // 'number' + 'norelativenumber' 1070 num = (long)lnum; 1071 else 1072 { 1073 // 'relativenumber', don't use negative numbers 1074 num = labs((long)get_cursor_rel_lnum(wp, lnum)); 1075 if (num == 0 && wp->w_p_nu && wp->w_p_rnu) 1076 { 1077 // 'number' + 'relativenumber' 1078 num = lnum; 1079 fmt = "%-*ld "; 1080 } 1081 } 1082 1083 sprintf((char *)extra, fmt, 1084 number_width(wp), num); 1085 if (wp->w_skipcol > 0) 1086 for (p_extra = extra; *p_extra == ' '; ++p_extra) 1087 *p_extra = '-'; 1088 #ifdef FEAT_RIGHTLEFT 1089 if (wp->w_p_rl) // reverse line numbers 1090 { 1091 char_u *p1, *p2; 1092 int t; 1093 1094 // like rl_mirror(), but keep the space at the end 1095 p2 = skiptowhite(extra) - 1; 1096 for (p1 = extra; p1 < p2; ++p1, --p2) 1097 { 1098 t = *p1; 1099 *p1 = *p2; 1100 *p2 = t; 1101 } 1102 } 1103 #endif 1104 p_extra = extra; 1105 c_extra = NUL; 1106 c_final = NUL; 1107 } 1108 else 1109 { 1110 c_extra = ' '; 1111 c_final = NUL; 1112 } 1113 n_extra = number_width(wp) + 1; 1114 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)); 1115 #ifdef FEAT_SYN_HL 1116 // When 'cursorline' is set highlight the line number of 1117 // the current line differently. 1118 // When 'cursorlineopt' has "screenline" only highlight 1119 // the line number itself. 1120 // TODO: Can we use CursorLine instead of CursorLineNr 1121 // when CursorLineNr isn't set? 1122 if (wp->w_p_cul 1123 && lnum == wp->w_cursor.lnum 1124 && (wp->w_p_culopt_flags & CULOPT_NBR) 1125 && (row == startrow 1126 || wp->w_p_culopt_flags & CULOPT_LINE)) 1127 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_CLN)); 1128 #endif 1129 if (wp->w_p_rnu && lnum < wp->w_cursor.lnum 1130 && HL_ATTR(HLF_LNA) != 0) 1131 // Use LineNrAbove 1132 char_attr = hl_combine_attr(wcr_attr, 1133 HL_ATTR(HLF_LNA)); 1134 if (wp->w_p_rnu && lnum > wp->w_cursor.lnum 1135 && HL_ATTR(HLF_LNB) != 0) 1136 // Use LineNrBelow 1137 char_attr = hl_combine_attr(wcr_attr, 1138 HL_ATTR(HLF_LNB)); 1139 } 1140 } 1141 } 1142 1143 #ifdef FEAT_LINEBREAK 1144 if (wp->w_briopt_sbr && draw_state == WL_BRI - 1 1145 && n_extra == 0 && *get_showbreak_value(wp) != NUL) 1146 // draw indent after showbreak value 1147 draw_state = WL_BRI; 1148 else if (wp->w_briopt_sbr && draw_state == WL_SBR && n_extra == 0) 1149 // After the showbreak, draw the breakindent 1150 draw_state = WL_BRI - 1; 1151 1152 // draw 'breakindent': indent wrapped text accordingly 1153 if (draw_state == WL_BRI - 1 && n_extra == 0) 1154 { 1155 draw_state = WL_BRI; 1156 // if need_showbreak is set, breakindent also applies 1157 if (wp->w_p_bri && n_extra == 0 1158 && (row != startrow || need_showbreak) 1159 # ifdef FEAT_DIFF 1160 && filler_lines == 0 1161 # endif 1162 ) 1163 { 1164 char_attr = 0; 1165 # ifdef FEAT_DIFF 1166 if (diff_hlf != (hlf_T)0) 1167 { 1168 char_attr = HL_ATTR(diff_hlf); 1169 # ifdef FEAT_SYN_HL 1170 if (cul_attr != 0) 1171 char_attr = hl_combine_attr(char_attr, cul_attr); 1172 # endif 1173 } 1174 # endif 1175 p_extra = NULL; 1176 c_extra = ' '; 1177 c_final = NUL; 1178 n_extra = get_breakindent_win(wp, 1179 ml_get_buf(wp->w_buffer, lnum, FALSE)); 1180 if (row == startrow) 1181 { 1182 n_extra -= win_col_off2(wp); 1183 if (n_extra < 0) 1184 n_extra = 0; 1185 } 1186 if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) 1187 need_showbreak = FALSE; 1188 // Correct end of highlighted area for 'breakindent', 1189 // required when 'linebreak' is also set. 1190 if (tocol == vcol) 1191 tocol += n_extra; 1192 } 1193 } 1194 #endif 1195 1196 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) 1197 if (draw_state == WL_SBR - 1 && n_extra == 0) 1198 { 1199 char_u *sbr; 1200 1201 draw_state = WL_SBR; 1202 # ifdef FEAT_DIFF 1203 if (filler_todo > 0) 1204 { 1205 // Draw "deleted" diff line(s). 1206 if (char2cells(fill_diff) > 1) 1207 { 1208 c_extra = '-'; 1209 c_final = NUL; 1210 } 1211 else 1212 { 1213 c_extra = fill_diff; 1214 c_final = NUL; 1215 } 1216 # ifdef FEAT_RIGHTLEFT 1217 if (wp->w_p_rl) 1218 n_extra = col + 1; 1219 else 1220 # endif 1221 n_extra = wp->w_width - col; 1222 char_attr = HL_ATTR(HLF_DED); 1223 } 1224 # endif 1225 # ifdef FEAT_LINEBREAK 1226 sbr = get_showbreak_value(wp); 1227 if (*sbr != NUL && need_showbreak) 1228 { 1229 // Draw 'showbreak' at the start of each broken line. 1230 p_extra = sbr; 1231 c_extra = NUL; 1232 c_final = NUL; 1233 n_extra = (int)STRLEN(sbr); 1234 if (wp->w_skipcol == 0 || !wp->w_p_wrap) 1235 need_showbreak = FALSE; 1236 vcol_sbr = vcol + MB_CHARLEN(sbr); 1237 // Correct end of highlighted area for 'showbreak', 1238 // required when 'linebreak' is also set. 1239 if (tocol == vcol) 1240 tocol += n_extra; 1241 // combine 'showbreak' with 'wincolor' 1242 char_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); 1243 # ifdef FEAT_SYN_HL 1244 // combine 'showbreak' with 'cursorline' 1245 if (cul_attr != 0) 1246 char_attr = hl_combine_attr(char_attr, cul_attr); 1247 # endif 1248 } 1249 # endif 1250 } 1251 #endif 1252 1253 if (draw_state == WL_LINE - 1 && n_extra == 0) 1254 { 1255 draw_state = WL_LINE; 1256 if (saved_n_extra) 1257 { 1258 // Continue item from end of wrapped line. 1259 n_extra = saved_n_extra; 1260 c_extra = saved_c_extra; 1261 c_final = saved_c_final; 1262 p_extra = saved_p_extra; 1263 char_attr = saved_char_attr; 1264 } 1265 else 1266 char_attr = win_attr; 1267 } 1268 } 1269 #ifdef FEAT_SYN_HL 1270 if (cul_screenline) 1271 { 1272 if (draw_state == WL_LINE 1273 && vcol >= left_curline_col 1274 && vcol < right_curline_col) 1275 { 1276 cul_attr = HL_ATTR(HLF_CUL); 1277 line_attr = cul_attr; 1278 } 1279 else 1280 { 1281 cul_attr = 0; 1282 line_attr = line_attr_save; 1283 } 1284 } 1285 #endif 1286 1287 // When still displaying '$' of change command, stop at cursor. 1288 // When only displaying the (relative) line number and that's done, 1289 // stop here. 1290 if ((dollar_vcol >= 0 && wp == curwin 1291 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol 1292 #ifdef FEAT_DIFF 1293 && filler_todo <= 0 1294 #endif 1295 ) 1296 || (number_only && draw_state > WL_NR)) 1297 { 1298 screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width, 1299 screen_line_flags); 1300 // Pretend we have finished updating the window. Except when 1301 // 'cursorcolumn' is set. 1302 #ifdef FEAT_SYN_HL 1303 if (wp->w_p_cuc) 1304 row = wp->w_cline_row + wp->w_cline_height; 1305 else 1306 #endif 1307 row = wp->w_height; 1308 break; 1309 } 1310 1311 if (draw_state == WL_LINE && (area_highlighting || extra_check)) 1312 { 1313 // handle Visual or match highlighting in this line 1314 if (vcol == fromcol 1315 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0 1316 && (*mb_ptr2cells)(ptr) > 1) 1317 || ((int)vcol_prev == fromcol_prev 1318 && vcol_prev < vcol // not at margin 1319 && vcol < tocol)) 1320 area_attr = vi_attr; // start highlighting 1321 else if (area_attr != 0 1322 && (vcol == tocol 1323 || (noinvcur && (colnr_T)vcol == wp->w_virtcol))) 1324 area_attr = 0; // stop highlighting 1325 1326 #ifdef FEAT_SEARCH_EXTRA 1327 if (!n_extra) 1328 { 1329 // Check for start/end of 'hlsearch' and other matches. 1330 // After end, check for start/end of next match. 1331 // When another match, have to check for start again. 1332 v = (long)(ptr - line); 1333 search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, 1334 &screen_search_hl, &has_match_conc, 1335 &match_conc, did_line_attr, lcs_eol_one); 1336 ptr = line + v; // "line" may have been changed 1337 } 1338 #endif 1339 1340 #ifdef FEAT_DIFF 1341 if (diff_hlf != (hlf_T)0) 1342 { 1343 if (diff_hlf == HLF_CHD && ptr - line >= change_start 1344 && n_extra == 0) 1345 diff_hlf = HLF_TXD; // changed text 1346 if (diff_hlf == HLF_TXD && ptr - line > change_end 1347 && n_extra == 0) 1348 diff_hlf = HLF_CHD; // changed line 1349 line_attr = HL_ATTR(diff_hlf); 1350 if (wp->w_p_cul && lnum == wp->w_cursor.lnum 1351 && wp->w_p_culopt_flags != CULOPT_NBR 1352 && (!cul_screenline || (vcol >= left_curline_col 1353 && vcol <= right_curline_col))) 1354 line_attr = hl_combine_attr( 1355 line_attr, HL_ATTR(HLF_CUL)); 1356 } 1357 #endif 1358 1359 #ifdef FEAT_PROP_POPUP 1360 if (text_props != NULL) 1361 { 1362 int pi; 1363 int bcol = (int)(ptr - line); 1364 1365 if (n_extra > 0) 1366 --bcol; // still working on the previous char, e.g. Tab 1367 1368 // Check if any active property ends. 1369 for (pi = 0; pi < text_props_active; ++pi) 1370 { 1371 int tpi = text_prop_idxs[pi]; 1372 1373 if (bcol >= text_props[tpi].tp_col - 1 1374 + text_props[tpi].tp_len) 1375 { 1376 if (pi + 1 < text_props_active) 1377 mch_memmove(text_prop_idxs + pi, 1378 text_prop_idxs + pi + 1, 1379 sizeof(int) 1380 * (text_props_active - (pi + 1))); 1381 --text_props_active; 1382 --pi; 1383 } 1384 } 1385 1386 // Add any text property that starts in this column. 1387 while (text_prop_next < text_prop_count 1388 && bcol >= text_props[text_prop_next].tp_col - 1) 1389 text_prop_idxs[text_props_active++] = text_prop_next++; 1390 1391 text_prop_attr = 0; 1392 text_prop_combine = FALSE; 1393 text_prop_type = NULL; 1394 if (text_props_active > 0) 1395 { 1396 // Sort the properties on priority and/or starting last. 1397 // Then combine the attributes, highest priority last. 1398 current_text_props = text_props; 1399 current_buf = wp->w_buffer; 1400 qsort((void *)text_prop_idxs, (size_t)text_props_active, 1401 sizeof(int), text_prop_compare); 1402 1403 for (pi = 0; pi < text_props_active; ++pi) 1404 { 1405 int tpi = text_prop_idxs[pi]; 1406 proptype_T *pt = text_prop_type_by_id( 1407 wp->w_buffer, text_props[tpi].tp_type); 1408 1409 if (pt != NULL && pt->pt_hl_id > 0) 1410 { 1411 int pt_attr = syn_id2attr(pt->pt_hl_id); 1412 1413 text_prop_type = pt; 1414 text_prop_attr = 1415 hl_combine_attr(text_prop_attr, pt_attr); 1416 text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE; 1417 } 1418 } 1419 } 1420 } 1421 #endif 1422 1423 #ifdef FEAT_SYN_HL 1424 if (extra_check && n_extra == 0) 1425 { 1426 syntax_attr = 0; 1427 # ifdef FEAT_TERMINAL 1428 if (get_term_attr) 1429 syntax_attr = term_get_attr(wp, lnum, vcol); 1430 # endif 1431 // Get syntax attribute. 1432 if (has_syntax) 1433 { 1434 // Get the syntax attribute for the character. If there 1435 // is an error, disable syntax highlighting. 1436 save_did_emsg = did_emsg; 1437 did_emsg = FALSE; 1438 1439 v = (long)(ptr - line); 1440 if (v == prev_syntax_col) 1441 // at same column again 1442 syntax_attr = prev_syntax_attr; 1443 else 1444 { 1445 # ifdef FEAT_SPELL 1446 can_spell = TRUE; 1447 # endif 1448 syntax_attr = get_syntax_attr((colnr_T)v, 1449 # ifdef FEAT_SPELL 1450 has_spell ? &can_spell : 1451 # endif 1452 NULL, FALSE); 1453 prev_syntax_col = v; 1454 prev_syntax_attr = syntax_attr; 1455 } 1456 1457 if (did_emsg) 1458 { 1459 wp->w_s->b_syn_error = TRUE; 1460 has_syntax = FALSE; 1461 syntax_attr = 0; 1462 } 1463 else 1464 did_emsg = save_did_emsg; 1465 # ifdef SYN_TIME_LIMIT 1466 if (wp->w_s->b_syn_slow) 1467 has_syntax = FALSE; 1468 # endif 1469 1470 // Need to get the line again, a multi-line regexp may 1471 // have made it invalid. 1472 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 1473 ptr = line + v; 1474 # ifdef FEAT_CONCEAL 1475 // no concealing past the end of the line, it interferes 1476 // with line highlighting 1477 if (*ptr == NUL) 1478 syntax_flags = 0; 1479 else 1480 syntax_flags = get_syntax_info(&syntax_seqnr); 1481 # endif 1482 } 1483 } 1484 # ifdef FEAT_PROP_POPUP 1485 // Combine text property highlight into syntax highlight. 1486 if (text_prop_type != NULL) 1487 { 1488 if (text_prop_combine) 1489 syntax_attr = hl_combine_attr(syntax_attr, text_prop_attr); 1490 else 1491 syntax_attr = text_prop_attr; 1492 } 1493 # endif 1494 #endif 1495 1496 // Decide which of the highlight attributes to use. 1497 attr_pri = TRUE; 1498 #ifdef LINE_ATTR 1499 if (area_attr != 0) 1500 { 1501 char_attr = hl_combine_attr(line_attr, area_attr); 1502 # ifdef FEAT_SYN_HL 1503 char_attr = hl_combine_attr(syntax_attr, char_attr); 1504 # endif 1505 } 1506 else if (search_attr != 0) 1507 { 1508 char_attr = hl_combine_attr(line_attr, search_attr); 1509 # ifdef FEAT_SYN_HL 1510 char_attr = hl_combine_attr(syntax_attr, char_attr); 1511 # endif 1512 } 1513 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL) 1514 || vcol < fromcol || vcol_prev < fromcol_prev 1515 || vcol >= tocol)) 1516 { 1517 // Use line_attr when not in the Visual or 'incsearch' area 1518 // (area_attr may be 0 when "noinvcur" is set). 1519 # ifdef FEAT_SYN_HL 1520 char_attr = hl_combine_attr(syntax_attr, line_attr); 1521 # else 1522 char_attr = line_attr; 1523 # endif 1524 attr_pri = FALSE; 1525 } 1526 #else 1527 if (area_attr != 0) 1528 char_attr = area_attr; 1529 else if (search_attr != 0) 1530 char_attr = search_attr; 1531 #endif 1532 else 1533 { 1534 attr_pri = FALSE; 1535 #ifdef FEAT_SYN_HL 1536 char_attr = syntax_attr; 1537 #else 1538 char_attr = 0; 1539 #endif 1540 } 1541 } 1542 1543 // combine attribute with 'wincolor' 1544 if (win_attr != 0) 1545 { 1546 if (char_attr == 0) 1547 char_attr = win_attr; 1548 else 1549 char_attr = hl_combine_attr(win_attr, char_attr); 1550 } 1551 1552 // Get the next character to put on the screen. 1553 1554 // The "p_extra" points to the extra stuff that is inserted to 1555 // represent special characters (non-printable stuff) and other 1556 // things. When all characters are the same, c_extra is used. 1557 // If c_final is set, it will compulsorily be used at the end. 1558 // "p_extra" must end in a NUL to avoid mb_ptr2len() reads past 1559 // "p_extra[n_extra]". 1560 // For the '$' of the 'list' option, n_extra == 1, p_extra == "". 1561 if (n_extra > 0) 1562 { 1563 if (c_extra != NUL || (n_extra == 1 && c_final != NUL)) 1564 { 1565 c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra; 1566 mb_c = c; // doesn't handle non-utf-8 multi-byte! 1567 if (enc_utf8 && utf_char2len(c) > 1) 1568 { 1569 mb_utf8 = TRUE; 1570 u8cc[0] = 0; 1571 c = 0xc0; 1572 } 1573 else 1574 mb_utf8 = FALSE; 1575 } 1576 else 1577 { 1578 c = *p_extra; 1579 if (has_mbyte) 1580 { 1581 mb_c = c; 1582 if (enc_utf8) 1583 { 1584 // If the UTF-8 character is more than one byte: 1585 // Decode it into "mb_c". 1586 mb_l = utfc_ptr2len(p_extra); 1587 mb_utf8 = FALSE; 1588 if (mb_l > n_extra) 1589 mb_l = 1; 1590 else if (mb_l > 1) 1591 { 1592 mb_c = utfc_ptr2char(p_extra, u8cc); 1593 mb_utf8 = TRUE; 1594 c = 0xc0; 1595 } 1596 } 1597 else 1598 { 1599 // if this is a DBCS character, put it in "mb_c" 1600 mb_l = MB_BYTE2LEN(c); 1601 if (mb_l >= n_extra) 1602 mb_l = 1; 1603 else if (mb_l > 1) 1604 mb_c = (c << 8) + p_extra[1]; 1605 } 1606 if (mb_l == 0) // at the NUL at end-of-line 1607 mb_l = 1; 1608 1609 // If a double-width char doesn't fit display a '>' in the 1610 // last column. 1611 if (( 1612 # ifdef FEAT_RIGHTLEFT 1613 wp->w_p_rl ? (col <= 0) : 1614 # endif 1615 (col >= wp->w_width - 1)) 1616 && (*mb_char2cells)(mb_c) == 2) 1617 { 1618 c = '>'; 1619 mb_c = c; 1620 mb_l = 1; 1621 mb_utf8 = FALSE; 1622 multi_attr = HL_ATTR(HLF_AT); 1623 #ifdef FEAT_SYN_HL 1624 if (cul_attr) 1625 multi_attr = hl_combine_attr(multi_attr, cul_attr); 1626 #endif 1627 multi_attr = hl_combine_attr(win_attr, multi_attr); 1628 1629 // put the pointer back to output the double-width 1630 // character at the start of the next line. 1631 ++n_extra; 1632 --p_extra; 1633 } 1634 else 1635 { 1636 n_extra -= mb_l - 1; 1637 p_extra += mb_l - 1; 1638 } 1639 } 1640 ++p_extra; 1641 } 1642 --n_extra; 1643 } 1644 else 1645 { 1646 #ifdef FEAT_LINEBREAK 1647 int c0; 1648 #endif 1649 VIM_CLEAR(p_extra_free); 1650 1651 // Get a character from the line itself. 1652 c = *ptr; 1653 #ifdef FEAT_LINEBREAK 1654 c0 = *ptr; 1655 #endif 1656 if (has_mbyte) 1657 { 1658 mb_c = c; 1659 if (enc_utf8) 1660 { 1661 // If the UTF-8 character is more than one byte: Decode it 1662 // into "mb_c". 1663 mb_l = utfc_ptr2len(ptr); 1664 mb_utf8 = FALSE; 1665 if (mb_l > 1) 1666 { 1667 mb_c = utfc_ptr2char(ptr, u8cc); 1668 // Overlong encoded ASCII or ASCII with composing char 1669 // is displayed normally, except a NUL. 1670 if (mb_c < 0x80) 1671 { 1672 c = mb_c; 1673 #ifdef FEAT_LINEBREAK 1674 c0 = mb_c; 1675 #endif 1676 } 1677 mb_utf8 = TRUE; 1678 1679 // At start of the line we can have a composing char. 1680 // Draw it as a space with a composing char. 1681 if (utf_iscomposing(mb_c)) 1682 { 1683 int i; 1684 1685 for (i = Screen_mco - 1; i > 0; --i) 1686 u8cc[i] = u8cc[i - 1]; 1687 u8cc[0] = mb_c; 1688 mb_c = ' '; 1689 } 1690 } 1691 1692 if ((mb_l == 1 && c >= 0x80) 1693 || (mb_l >= 1 && mb_c == 0) 1694 || (mb_l > 1 && (!vim_isprintc(mb_c)))) 1695 { 1696 // Illegal UTF-8 byte: display as <xx>. 1697 // Non-BMP character : display as ? or fullwidth ?. 1698 transchar_hex(extra, mb_c); 1699 # ifdef FEAT_RIGHTLEFT 1700 if (wp->w_p_rl) // reverse 1701 rl_mirror(extra); 1702 # endif 1703 p_extra = extra; 1704 c = *p_extra; 1705 mb_c = mb_ptr2char_adv(&p_extra); 1706 mb_utf8 = (c >= 0x80); 1707 n_extra = (int)STRLEN(p_extra); 1708 c_extra = NUL; 1709 c_final = NUL; 1710 if (area_attr == 0 && search_attr == 0) 1711 { 1712 n_attr = n_extra + 1; 1713 extra_attr = hl_combine_attr( 1714 win_attr, HL_ATTR(HLF_8)); 1715 saved_attr2 = char_attr; // save current attr 1716 } 1717 } 1718 else if (mb_l == 0) // at the NUL at end-of-line 1719 mb_l = 1; 1720 #ifdef FEAT_ARABIC 1721 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c)) 1722 { 1723 // Do Arabic shaping. 1724 int pc, pc1, nc; 1725 int pcc[MAX_MCO]; 1726 1727 // The idea of what is the previous and next 1728 // character depends on 'rightleft'. 1729 if (wp->w_p_rl) 1730 { 1731 pc = prev_c; 1732 pc1 = prev_c1; 1733 nc = utf_ptr2char(ptr + mb_l); 1734 prev_c1 = u8cc[0]; 1735 } 1736 else 1737 { 1738 pc = utfc_ptr2char(ptr + mb_l, pcc); 1739 nc = prev_c; 1740 pc1 = pcc[0]; 1741 } 1742 prev_c = mb_c; 1743 1744 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc); 1745 } 1746 else 1747 prev_c = mb_c; 1748 #endif 1749 } 1750 else // enc_dbcs 1751 { 1752 mb_l = MB_BYTE2LEN(c); 1753 if (mb_l == 0) // at the NUL at end-of-line 1754 mb_l = 1; 1755 else if (mb_l > 1) 1756 { 1757 // We assume a second byte below 32 is illegal. 1758 // Hopefully this is OK for all double-byte encodings! 1759 if (ptr[1] >= 32) 1760 mb_c = (c << 8) + ptr[1]; 1761 else 1762 { 1763 if (ptr[1] == NUL) 1764 { 1765 // head byte at end of line 1766 mb_l = 1; 1767 transchar_nonprint(extra, c); 1768 } 1769 else 1770 { 1771 // illegal tail byte 1772 mb_l = 2; 1773 STRCPY(extra, "XX"); 1774 } 1775 p_extra = extra; 1776 n_extra = (int)STRLEN(extra) - 1; 1777 c_extra = NUL; 1778 c_final = NUL; 1779 c = *p_extra++; 1780 if (area_attr == 0 && search_attr == 0) 1781 { 1782 n_attr = n_extra + 1; 1783 extra_attr = hl_combine_attr( 1784 win_attr, HL_ATTR(HLF_8)); 1785 saved_attr2 = char_attr; // save current attr 1786 } 1787 mb_c = c; 1788 } 1789 } 1790 } 1791 // If a double-width char doesn't fit display a '>' in the 1792 // last column; the character is displayed at the start of the 1793 // next line. 1794 if (( 1795 # ifdef FEAT_RIGHTLEFT 1796 wp->w_p_rl ? (col <= 0) : 1797 # endif 1798 (col >= wp->w_width - 1)) 1799 && (*mb_char2cells)(mb_c) == 2) 1800 { 1801 c = '>'; 1802 mb_c = c; 1803 mb_utf8 = FALSE; 1804 mb_l = 1; 1805 multi_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); 1806 // Put pointer back so that the character will be 1807 // displayed at the start of the next line. 1808 --ptr; 1809 #ifdef FEAT_CONCEAL 1810 did_decrement_ptr = TRUE; 1811 #endif 1812 } 1813 else if (*ptr != NUL) 1814 ptr += mb_l - 1; 1815 1816 // If a double-width char doesn't fit at the left side display 1817 // a '<' in the first column. Don't do this for unprintable 1818 // characters. 1819 if (n_skip > 0 && mb_l > 1 && n_extra == 0) 1820 { 1821 n_extra = 1; 1822 c_extra = MB_FILLER_CHAR; 1823 c_final = NUL; 1824 c = ' '; 1825 if (area_attr == 0 && search_attr == 0) 1826 { 1827 n_attr = n_extra + 1; 1828 extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); 1829 saved_attr2 = char_attr; // save current attr 1830 } 1831 mb_c = c; 1832 mb_utf8 = FALSE; 1833 mb_l = 1; 1834 } 1835 1836 } 1837 ++ptr; 1838 1839 if (extra_check) 1840 { 1841 #ifdef FEAT_SPELL 1842 // Check spelling (unless at the end of the line). 1843 // Only do this when there is no syntax highlighting, the 1844 // @Spell cluster is not used or the current syntax item 1845 // contains the @Spell cluster. 1846 v = (long)(ptr - line); 1847 if (has_spell && v >= word_end && v > cur_checked_col) 1848 { 1849 spell_attr = 0; 1850 if (c != 0 && ( 1851 # ifdef FEAT_SYN_HL 1852 !has_syntax || 1853 # endif 1854 can_spell)) 1855 { 1856 char_u *prev_ptr, *p; 1857 int len; 1858 hlf_T spell_hlf = HLF_COUNT; 1859 if (has_mbyte) 1860 { 1861 prev_ptr = ptr - mb_l; 1862 v -= mb_l - 1; 1863 } 1864 else 1865 prev_ptr = ptr - 1; 1866 1867 // Use nextline[] if possible, it has the start of the 1868 // next line concatenated. 1869 if ((prev_ptr - line) - nextlinecol >= 0) 1870 p = nextline + (prev_ptr - line) - nextlinecol; 1871 else 1872 p = prev_ptr; 1873 cap_col -= (int)(prev_ptr - line); 1874 len = spell_check(wp, p, &spell_hlf, &cap_col, 1875 nochange); 1876 word_end = v + len; 1877 1878 // In Insert mode only highlight a word that 1879 // doesn't touch the cursor. 1880 if (spell_hlf != HLF_COUNT 1881 && (State & INSERT) != 0 1882 && wp->w_cursor.lnum == lnum 1883 && wp->w_cursor.col >= 1884 (colnr_T)(prev_ptr - line) 1885 && wp->w_cursor.col < (colnr_T)word_end) 1886 { 1887 spell_hlf = HLF_COUNT; 1888 spell_redraw_lnum = lnum; 1889 } 1890 1891 if (spell_hlf == HLF_COUNT && p != prev_ptr 1892 && (p - nextline) + len > nextline_idx) 1893 { 1894 // Remember that the good word continues at the 1895 // start of the next line. 1896 checked_lnum = lnum + 1; 1897 checked_col = (int)((p - nextline) 1898 + len - nextline_idx); 1899 } 1900 1901 // Turn index into actual attributes. 1902 if (spell_hlf != HLF_COUNT) 1903 spell_attr = highlight_attr[spell_hlf]; 1904 1905 if (cap_col > 0) 1906 { 1907 if (p != prev_ptr 1908 && (p - nextline) + cap_col >= nextline_idx) 1909 { 1910 // Remember that the word in the next line 1911 // must start with a capital. 1912 capcol_lnum = lnum + 1; 1913 cap_col = (int)((p - nextline) + cap_col 1914 - nextline_idx); 1915 } 1916 else 1917 // Compute the actual column. 1918 cap_col += (int)(prev_ptr - line); 1919 } 1920 } 1921 } 1922 if (spell_attr != 0) 1923 { 1924 if (!attr_pri) 1925 char_attr = hl_combine_attr(char_attr, spell_attr); 1926 else 1927 char_attr = hl_combine_attr(spell_attr, char_attr); 1928 } 1929 #endif 1930 #ifdef FEAT_LINEBREAK 1931 // Found last space before word: check for line break. 1932 if (wp->w_p_lbr && c0 == c 1933 && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr)) 1934 { 1935 int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0; 1936 char_u *p = ptr - (mb_off + 1); 1937 1938 // TODO: is passing p for start of the line OK? 1939 n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, 1940 NULL) - 1; 1941 if (c == TAB && n_extra + col > wp->w_width) 1942 # ifdef FEAT_VARTABS 1943 n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts, 1944 wp->w_buffer->b_p_vts_array) - 1; 1945 # else 1946 n_extra = (int)wp->w_buffer->b_p_ts 1947 - vcol % (int)wp->w_buffer->b_p_ts - 1; 1948 # endif 1949 1950 c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; 1951 c_final = NUL; 1952 if (VIM_ISWHITE(c)) 1953 { 1954 # ifdef FEAT_CONCEAL 1955 if (c == TAB) 1956 // See "Tab alignment" below. 1957 FIX_FOR_BOGUSCOLS; 1958 # endif 1959 if (!wp->w_p_list) 1960 c = ' '; 1961 } 1962 } 1963 #endif 1964 1965 // 'list': Change char 160 to lcs_nbsp and space to lcs_space. 1966 // But not when the character is followed by a composing 1967 // character (use mb_l to check that). 1968 if (wp->w_p_list 1969 && ((((c == 160 && mb_l == 1) 1970 || (mb_utf8 1971 && ((mb_c == 160 && mb_l == 2) 1972 || (mb_c == 0x202f && mb_l == 3)))) 1973 && lcs_nbsp) 1974 || (c == ' ' 1975 && mb_l == 1 1976 && lcs_space 1977 && ptr - line <= trailcol))) 1978 { 1979 c = (c == ' ') ? lcs_space : lcs_nbsp; 1980 if (area_attr == 0 && search_attr == 0) 1981 { 1982 n_attr = 1; 1983 extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_8)); 1984 saved_attr2 = char_attr; // save current attr 1985 } 1986 mb_c = c; 1987 if (enc_utf8 && utf_char2len(c) > 1) 1988 { 1989 mb_utf8 = TRUE; 1990 u8cc[0] = 0; 1991 c = 0xc0; 1992 } 1993 else 1994 mb_utf8 = FALSE; 1995 } 1996 1997 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') 1998 { 1999 c = lcs_trail; 2000 if (!attr_pri) 2001 { 2002 n_attr = 1; 2003 extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_8)); 2004 saved_attr2 = char_attr; // save current attr 2005 } 2006 mb_c = c; 2007 if (enc_utf8 && utf_char2len(c) > 1) 2008 { 2009 mb_utf8 = TRUE; 2010 u8cc[0] = 0; 2011 c = 0xc0; 2012 } 2013 else 2014 mb_utf8 = FALSE; 2015 } 2016 } 2017 2018 // Handling of non-printable characters. 2019 if (!vim_isprintc(c)) 2020 { 2021 // when getting a character from the file, we may have to 2022 // turn it into something else on the way to putting it 2023 // into "ScreenLines". 2024 if (c == TAB && (!wp->w_p_list || lcs_tab1)) 2025 { 2026 int tab_len = 0; 2027 long vcol_adjusted = vcol; // removed showbreak length 2028 #ifdef FEAT_LINEBREAK 2029 char_u *sbr = get_showbreak_value(wp); 2030 2031 // only adjust the tab_len, when at the first column 2032 // after the showbreak value was drawn 2033 if (*sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) 2034 vcol_adjusted = vcol - MB_CHARLEN(sbr); 2035 #endif 2036 // tab amount depends on current column 2037 #ifdef FEAT_VARTABS 2038 tab_len = tabstop_padding(vcol_adjusted, 2039 wp->w_buffer->b_p_ts, 2040 wp->w_buffer->b_p_vts_array) - 1; 2041 #else 2042 tab_len = (int)wp->w_buffer->b_p_ts 2043 - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1; 2044 #endif 2045 2046 #ifdef FEAT_LINEBREAK 2047 if (!wp->w_p_lbr || !wp->w_p_list) 2048 #endif 2049 // tab amount depends on current column 2050 n_extra = tab_len; 2051 #ifdef FEAT_LINEBREAK 2052 else 2053 { 2054 char_u *p; 2055 int len; 2056 int i; 2057 int saved_nextra = n_extra; 2058 2059 #ifdef FEAT_CONCEAL 2060 if (vcol_off > 0) 2061 // there are characters to conceal 2062 tab_len += vcol_off; 2063 // boguscols before FIX_FOR_BOGUSCOLS macro from above 2064 if (wp->w_p_list && lcs_tab1 && old_boguscols > 0 2065 && n_extra > tab_len) 2066 tab_len += n_extra - tab_len; 2067 #endif 2068 2069 // if n_extra > 0, it gives the number of chars, to 2070 // use for a tab, else we need to calculate the width 2071 // for a tab 2072 len = (tab_len * mb_char2len(lcs_tab2)); 2073 if (n_extra > 0) 2074 len += n_extra - tab_len; 2075 c = lcs_tab1; 2076 p = alloc(len + 1); 2077 vim_memset(p, ' ', len); 2078 p[len] = NUL; 2079 vim_free(p_extra_free); 2080 p_extra_free = p; 2081 for (i = 0; i < tab_len; i++) 2082 { 2083 int lcs = lcs_tab2; 2084 2085 if (*p == NUL) 2086 { 2087 tab_len = i; 2088 break; 2089 } 2090 2091 // if lcs_tab3 is given, need to change the char 2092 // for tab 2093 if (lcs_tab3 && i == tab_len - 1) 2094 lcs = lcs_tab3; 2095 mb_char2bytes(lcs, p); 2096 p += mb_char2len(lcs); 2097 n_extra += mb_char2len(lcs) 2098 - (saved_nextra > 0 ? 1 : 0); 2099 } 2100 p_extra = p_extra_free; 2101 #ifdef FEAT_CONCEAL 2102 // n_extra will be increased by FIX_FOX_BOGUSCOLS 2103 // macro below, so need to adjust for that here 2104 if (vcol_off > 0) 2105 n_extra -= vcol_off; 2106 #endif 2107 } 2108 #endif 2109 #ifdef FEAT_CONCEAL 2110 { 2111 int vc_saved = vcol_off; 2112 2113 // Tab alignment should be identical regardless of 2114 // 'conceallevel' value. So tab compensates of all 2115 // previous concealed characters, and thus resets 2116 // vcol_off and boguscols accumulated so far in the 2117 // line. Note that the tab can be longer than 2118 // 'tabstop' when there are concealed characters. 2119 FIX_FOR_BOGUSCOLS; 2120 2121 // Make sure, the highlighting for the tab char will be 2122 // correctly set further below (effectively reverts the 2123 // FIX_FOR_BOGSUCOLS macro 2124 if (n_extra == tab_len + vc_saved && wp->w_p_list 2125 && lcs_tab1) 2126 tab_len += vc_saved; 2127 } 2128 #endif 2129 mb_utf8 = FALSE; // don't draw as UTF-8 2130 if (wp->w_p_list) 2131 { 2132 c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1; 2133 #ifdef FEAT_LINEBREAK 2134 if (wp->w_p_lbr) 2135 c_extra = NUL; // using p_extra from above 2136 else 2137 #endif 2138 c_extra = lcs_tab2; 2139 c_final = lcs_tab3; 2140 n_attr = tab_len + 1; 2141 extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_8)); 2142 saved_attr2 = char_attr; // save current attr 2143 mb_c = c; 2144 if (enc_utf8 && utf_char2len(c) > 1) 2145 { 2146 mb_utf8 = TRUE; 2147 u8cc[0] = 0; 2148 c = 0xc0; 2149 } 2150 } 2151 else 2152 { 2153 c_final = NUL; 2154 c_extra = ' '; 2155 c = ' '; 2156 } 2157 } 2158 else if (c == NUL 2159 && (wp->w_p_list 2160 || ((fromcol >= 0 || fromcol_prev >= 0) 2161 && tocol > vcol 2162 && VIsual_mode != Ctrl_V 2163 && ( 2164 # ifdef FEAT_RIGHTLEFT 2165 wp->w_p_rl ? (col >= 0) : 2166 # endif 2167 (col < wp->w_width)) 2168 && !(noinvcur 2169 && lnum == wp->w_cursor.lnum 2170 && (colnr_T)vcol == wp->w_virtcol))) 2171 && lcs_eol_one > 0) 2172 { 2173 // Display a '$' after the line or highlight an extra 2174 // character if the line break is included. 2175 #if defined(FEAT_DIFF) || defined(LINE_ATTR) 2176 // For a diff line the highlighting continues after the 2177 // "$". 2178 if ( 2179 # ifdef FEAT_DIFF 2180 diff_hlf == (hlf_T)0 2181 # ifdef LINE_ATTR 2182 && 2183 # endif 2184 # endif 2185 # ifdef LINE_ATTR 2186 line_attr == 0 2187 # endif 2188 ) 2189 #endif 2190 { 2191 // In virtualedit, visual selections may extend 2192 // beyond end of line. 2193 if (area_highlighting && virtual_active() 2194 && tocol != MAXCOL && vcol < tocol) 2195 n_extra = 0; 2196 else 2197 { 2198 p_extra = at_end_str; 2199 n_extra = 1; 2200 c_extra = NUL; 2201 c_final = NUL; 2202 } 2203 } 2204 if (wp->w_p_list && lcs_eol > 0) 2205 c = lcs_eol; 2206 else 2207 c = ' '; 2208 lcs_eol_one = -1; 2209 --ptr; // put it back at the NUL 2210 if (!attr_pri) 2211 { 2212 extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); 2213 n_attr = 1; 2214 } 2215 mb_c = c; 2216 if (enc_utf8 && utf_char2len(c) > 1) 2217 { 2218 mb_utf8 = TRUE; 2219 u8cc[0] = 0; 2220 c = 0xc0; 2221 } 2222 else 2223 mb_utf8 = FALSE; // don't draw as UTF-8 2224 } 2225 else if (c != NUL) 2226 { 2227 p_extra = transchar(c); 2228 if (n_extra == 0) 2229 n_extra = byte2cells(c) - 1; 2230 #ifdef FEAT_RIGHTLEFT 2231 if ((dy_flags & DY_UHEX) && wp->w_p_rl) 2232 rl_mirror(p_extra); // reverse "<12>" 2233 #endif 2234 c_extra = NUL; 2235 c_final = NUL; 2236 #ifdef FEAT_LINEBREAK 2237 if (wp->w_p_lbr) 2238 { 2239 char_u *p; 2240 2241 c = *p_extra; 2242 p = alloc(n_extra + 1); 2243 vim_memset(p, ' ', n_extra); 2244 STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1); 2245 p[n_extra] = NUL; 2246 vim_free(p_extra_free); 2247 p_extra_free = p_extra = p; 2248 } 2249 else 2250 #endif 2251 { 2252 n_extra = byte2cells(c) - 1; 2253 c = *p_extra++; 2254 } 2255 if (!attr_pri) 2256 { 2257 n_attr = n_extra + 1; 2258 extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_8)); 2259 saved_attr2 = char_attr; // save current attr 2260 } 2261 mb_utf8 = FALSE; // don't draw as UTF-8 2262 } 2263 else if (VIsual_active 2264 && (VIsual_mode == Ctrl_V 2265 || VIsual_mode == 'v') 2266 && virtual_active() 2267 && tocol != MAXCOL 2268 && vcol < tocol 2269 && ( 2270 #ifdef FEAT_RIGHTLEFT 2271 wp->w_p_rl ? (col >= 0) : 2272 #endif 2273 (col < wp->w_width))) 2274 { 2275 c = ' '; 2276 --ptr; // put it back at the NUL 2277 } 2278 #if defined(LINE_ATTR) 2279 else if (( 2280 # ifdef FEAT_DIFF 2281 diff_hlf != (hlf_T)0 || 2282 # endif 2283 # ifdef FEAT_TERMINAL 2284 win_attr != 0 || 2285 # endif 2286 line_attr != 0 2287 ) && ( 2288 # ifdef FEAT_RIGHTLEFT 2289 wp->w_p_rl ? (col >= 0) : 2290 # endif 2291 (col 2292 # ifdef FEAT_CONCEAL 2293 - boguscols 2294 # endif 2295 < wp->w_width))) 2296 { 2297 // Highlight until the right side of the window 2298 c = ' '; 2299 --ptr; // put it back at the NUL 2300 2301 // Remember we do the char for line highlighting. 2302 ++did_line_attr; 2303 2304 // don't do search HL for the rest of the line 2305 if (line_attr != 0 && char_attr == search_attr 2306 && (did_line_attr > 1 2307 || (wp->w_p_list && lcs_eol > 0))) 2308 char_attr = line_attr; 2309 # ifdef FEAT_DIFF 2310 if (diff_hlf == HLF_TXD) 2311 { 2312 diff_hlf = HLF_CHD; 2313 if (vi_attr == 0 || char_attr != vi_attr) 2314 { 2315 char_attr = HL_ATTR(diff_hlf); 2316 if (wp->w_p_cul && lnum == wp->w_cursor.lnum 2317 && wp->w_p_culopt_flags != CULOPT_NBR 2318 && (!cul_screenline 2319 || (vcol >= left_curline_col 2320 && vcol <= right_curline_col))) 2321 char_attr = hl_combine_attr( 2322 char_attr, HL_ATTR(HLF_CUL)); 2323 } 2324 } 2325 # endif 2326 # ifdef FEAT_TERMINAL 2327 if (win_attr != 0) 2328 { 2329 char_attr = win_attr; 2330 if (wp->w_p_cul && lnum == wp->w_cursor.lnum 2331 && wp->w_p_culopt_flags != CULOPT_NBR) 2332 { 2333 if (!cul_screenline || (vcol >= left_curline_col 2334 && vcol <= right_curline_col)) 2335 char_attr = hl_combine_attr( 2336 char_attr, HL_ATTR(HLF_CUL)); 2337 } 2338 else if (line_attr) 2339 char_attr = hl_combine_attr(char_attr, line_attr); 2340 } 2341 # endif 2342 } 2343 #endif 2344 } 2345 2346 #ifdef FEAT_CONCEAL 2347 if ( wp->w_p_cole > 0 2348 && (wp != curwin || lnum != wp->w_cursor.lnum || 2349 conceal_cursor_line(wp)) 2350 && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0) 2351 && !(lnum_in_visual_area 2352 && vim_strchr(wp->w_p_cocu, 'v') == NULL)) 2353 { 2354 char_attr = conceal_attr; 2355 if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1) 2356 && (syn_get_sub_char() != NUL || match_conc 2357 || wp->w_p_cole == 1) 2358 && wp->w_p_cole != 3) 2359 { 2360 // First time at this concealed item: display one 2361 // character. 2362 if (match_conc) 2363 c = match_conc; 2364 else if (syn_get_sub_char() != NUL) 2365 c = syn_get_sub_char(); 2366 else if (lcs_conceal != NUL) 2367 c = lcs_conceal; 2368 else 2369 c = ' '; 2370 2371 prev_syntax_id = syntax_seqnr; 2372 2373 if (n_extra > 0) 2374 vcol_off += n_extra; 2375 vcol += n_extra; 2376 if (wp->w_p_wrap && n_extra > 0) 2377 { 2378 # ifdef FEAT_RIGHTLEFT 2379 if (wp->w_p_rl) 2380 { 2381 col -= n_extra; 2382 boguscols -= n_extra; 2383 } 2384 else 2385 # endif 2386 { 2387 boguscols += n_extra; 2388 col += n_extra; 2389 } 2390 } 2391 n_extra = 0; 2392 n_attr = 0; 2393 } 2394 else if (n_skip == 0) 2395 { 2396 is_concealing = TRUE; 2397 n_skip = 1; 2398 } 2399 mb_c = c; 2400 if (enc_utf8 && utf_char2len(c) > 1) 2401 { 2402 mb_utf8 = TRUE; 2403 u8cc[0] = 0; 2404 c = 0xc0; 2405 } 2406 else 2407 mb_utf8 = FALSE; // don't draw as UTF-8 2408 } 2409 else 2410 { 2411 prev_syntax_id = 0; 2412 is_concealing = FALSE; 2413 } 2414 2415 if (n_skip > 0 && did_decrement_ptr) 2416 // not showing the '>', put pointer back to avoid getting stuck 2417 ++ptr; 2418 2419 #endif // FEAT_CONCEAL 2420 } 2421 2422 #ifdef FEAT_CONCEAL 2423 // In the cursor line and we may be concealing characters: correct 2424 // the cursor column when we reach its position. 2425 if (!did_wcol && draw_state == WL_LINE 2426 && wp == curwin && lnum == wp->w_cursor.lnum 2427 && conceal_cursor_line(wp) 2428 && (int)wp->w_virtcol <= vcol + n_skip) 2429 { 2430 # ifdef FEAT_RIGHTLEFT 2431 if (wp->w_p_rl) 2432 wp->w_wcol = wp->w_width - col + boguscols - 1; 2433 else 2434 # endif 2435 wp->w_wcol = col - boguscols; 2436 wp->w_wrow = row; 2437 did_wcol = TRUE; 2438 curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; 2439 } 2440 #endif 2441 2442 // Don't override visual selection highlighting. 2443 if (n_attr > 0 2444 && draw_state == WL_LINE 2445 && !attr_pri) 2446 { 2447 #ifdef LINE_ATTR 2448 if (line_attr) 2449 char_attr = hl_combine_attr(extra_attr, line_attr); 2450 else 2451 #endif 2452 char_attr = extra_attr; 2453 } 2454 2455 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 2456 // XIM don't send preedit_start and preedit_end, but they send 2457 // preedit_changed and commit. Thus Vim can't set "im_is_active", use 2458 // im_is_preediting() here. 2459 if (p_imst == IM_ON_THE_SPOT 2460 && xic != NULL 2461 && lnum == wp->w_cursor.lnum 2462 && (State & INSERT) 2463 && !p_imdisable 2464 && im_is_preediting() 2465 && draw_state == WL_LINE) 2466 { 2467 colnr_T tcol; 2468 2469 if (preedit_end_col == MAXCOL) 2470 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL); 2471 else 2472 tcol = preedit_end_col; 2473 if ((long)preedit_start_col <= vcol && vcol < (long)tcol) 2474 { 2475 if (feedback_old_attr < 0) 2476 { 2477 feedback_col = 0; 2478 feedback_old_attr = char_attr; 2479 } 2480 char_attr = im_get_feedback_attr(feedback_col); 2481 if (char_attr < 0) 2482 char_attr = feedback_old_attr; 2483 feedback_col++; 2484 } 2485 else if (feedback_old_attr >= 0) 2486 { 2487 char_attr = feedback_old_attr; 2488 feedback_old_attr = -1; 2489 feedback_col = 0; 2490 } 2491 } 2492 #endif 2493 // Handle the case where we are in column 0 but not on the first 2494 // character of the line and the user wants us to show us a 2495 // special character (via 'listchars' option "precedes:<char>". 2496 if (lcs_prec_todo != NUL 2497 && wp->w_p_list 2498 && (wp->w_p_wrap ? 2499 (wp->w_skipcol > 0 && row == 0) : 2500 wp->w_leftcol > 0) 2501 #ifdef FEAT_DIFF 2502 && filler_todo <= 0 2503 #endif 2504 && draw_state > WL_NR 2505 && c != NUL) 2506 { 2507 c = lcs_prec; 2508 lcs_prec_todo = NUL; 2509 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) 2510 { 2511 // Double-width character being overwritten by the "precedes" 2512 // character, need to fill up half the character. 2513 c_extra = MB_FILLER_CHAR; 2514 c_final = NUL; 2515 n_extra = 1; 2516 n_attr = 2; 2517 extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); 2518 } 2519 mb_c = c; 2520 if (enc_utf8 && utf_char2len(c) > 1) 2521 { 2522 mb_utf8 = TRUE; 2523 u8cc[0] = 0; 2524 c = 0xc0; 2525 } 2526 else 2527 mb_utf8 = FALSE; // don't draw as UTF-8 2528 if (!attr_pri) 2529 { 2530 saved_attr3 = char_attr; // save current attr 2531 char_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); 2532 n_attr3 = 1; 2533 } 2534 } 2535 2536 // At end of the text line or just after the last character. 2537 if ((c == NUL 2538 #if defined(LINE_ATTR) 2539 || did_line_attr == 1 2540 #endif 2541 ) && eol_hl_off == 0) 2542 { 2543 #ifdef FEAT_SEARCH_EXTRA 2544 // flag to indicate whether prevcol equals startcol of search_hl or 2545 // one of the matches 2546 int prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl, 2547 (long)(ptr - line) - (c == NUL)); 2548 #endif 2549 // Invert at least one char, used for Visual and empty line or 2550 // highlight match at end of line. If it's beyond the last 2551 // char on the screen, just overwrite that one (tricky!) Not 2552 // needed when a '$' was displayed for 'list'. 2553 if (lcs_eol == lcs_eol_one 2554 && ((area_attr != 0 && vcol == fromcol 2555 && (VIsual_mode != Ctrl_V 2556 || lnum == VIsual.lnum 2557 || lnum == curwin->w_cursor.lnum) 2558 && c == NUL) 2559 #ifdef FEAT_SEARCH_EXTRA 2560 // highlight 'hlsearch' match at end of line 2561 || (prevcol_hl_flag 2562 # ifdef FEAT_SYN_HL 2563 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum 2564 && !(wp == curwin && VIsual_active)) 2565 # endif 2566 # ifdef FEAT_DIFF 2567 && diff_hlf == (hlf_T)0 2568 # endif 2569 # if defined(LINE_ATTR) 2570 && did_line_attr <= 1 2571 # endif 2572 ) 2573 #endif 2574 )) 2575 { 2576 int n = 0; 2577 2578 #ifdef FEAT_RIGHTLEFT 2579 if (wp->w_p_rl) 2580 { 2581 if (col < 0) 2582 n = 1; 2583 } 2584 else 2585 #endif 2586 { 2587 if (col >= wp->w_width) 2588 n = -1; 2589 } 2590 if (n != 0) 2591 { 2592 // At the window boundary, highlight the last character 2593 // instead (better than nothing). 2594 off += n; 2595 col += n; 2596 } 2597 else 2598 { 2599 // Add a blank character to highlight. 2600 ScreenLines[off] = ' '; 2601 if (enc_utf8) 2602 ScreenLinesUC[off] = 0; 2603 } 2604 #ifdef FEAT_SEARCH_EXTRA 2605 if (area_attr == 0) 2606 { 2607 // Use attributes from match with highest priority among 2608 // 'search_hl' and the match list. 2609 get_search_match_hl(wp, &screen_search_hl, 2610 (long)(ptr - line), &char_attr); 2611 } 2612 #endif 2613 ScreenAttrs[off] = char_attr; 2614 #ifdef FEAT_RIGHTLEFT 2615 if (wp->w_p_rl) 2616 { 2617 --col; 2618 --off; 2619 } 2620 else 2621 #endif 2622 { 2623 ++col; 2624 ++off; 2625 } 2626 ++vcol; 2627 eol_hl_off = 1; 2628 } 2629 } 2630 2631 // At end of the text line. 2632 if (c == NUL) 2633 { 2634 #ifdef FEAT_SYN_HL 2635 // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. 2636 if (wp->w_p_wrap) 2637 v = wp->w_skipcol; 2638 else 2639 v = wp->w_leftcol; 2640 2641 // check if line ends before left margin 2642 if (vcol < v + col - win_col_off(wp)) 2643 vcol = v + col - win_col_off(wp); 2644 #ifdef FEAT_CONCEAL 2645 // Get rid of the boguscols now, we want to draw until the right 2646 // edge for 'cursorcolumn'. 2647 col -= boguscols; 2648 boguscols = 0; 2649 #endif 2650 2651 if (draw_color_col) 2652 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); 2653 2654 if (((wp->w_p_cuc 2655 && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off 2656 && (int)wp->w_virtcol < 2657 wp->w_width * (row - startrow + 1) + v 2658 && lnum != wp->w_cursor.lnum) 2659 || draw_color_col 2660 || win_attr != 0) 2661 # ifdef FEAT_RIGHTLEFT 2662 && !wp->w_p_rl 2663 # endif 2664 ) 2665 { 2666 int rightmost_vcol = 0; 2667 int i; 2668 2669 if (wp->w_p_cuc) 2670 rightmost_vcol = wp->w_virtcol; 2671 if (draw_color_col) 2672 // determine rightmost colorcolumn to possibly draw 2673 for (i = 0; color_cols[i] >= 0; ++i) 2674 if (rightmost_vcol < color_cols[i]) 2675 rightmost_vcol = color_cols[i]; 2676 2677 while (col < wp->w_width) 2678 { 2679 ScreenLines[off] = ' '; 2680 if (enc_utf8) 2681 ScreenLinesUC[off] = 0; 2682 ++col; 2683 if (draw_color_col) 2684 draw_color_col = advance_color_col(VCOL_HLC, 2685 &color_cols); 2686 2687 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) 2688 ScreenAttrs[off++] = HL_ATTR(HLF_CUC); 2689 else if (draw_color_col && VCOL_HLC == *color_cols) 2690 ScreenAttrs[off++] = HL_ATTR(HLF_MC); 2691 else 2692 ScreenAttrs[off++] = win_attr; 2693 2694 if (VCOL_HLC >= rightmost_vcol && win_attr == 0) 2695 break; 2696 2697 ++vcol; 2698 } 2699 } 2700 #endif 2701 2702 screen_line(screen_row, wp->w_wincol, col, 2703 (int)wp->w_width, screen_line_flags); 2704 row++; 2705 2706 // Update w_cline_height and w_cline_folded if the cursor line was 2707 // updated (saves a call to plines() later). 2708 if (wp == curwin && lnum == curwin->w_cursor.lnum) 2709 { 2710 curwin->w_cline_row = startrow; 2711 curwin->w_cline_height = row - startrow; 2712 #ifdef FEAT_FOLDING 2713 curwin->w_cline_folded = FALSE; 2714 #endif 2715 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); 2716 } 2717 2718 break; 2719 } 2720 2721 // Show "extends" character from 'listchars' if beyond the line end and 2722 // 'list' is set. 2723 if (lcs_ext != NUL 2724 && wp->w_p_list 2725 && !wp->w_p_wrap 2726 #ifdef FEAT_DIFF 2727 && filler_todo <= 0 2728 #endif 2729 && ( 2730 #ifdef FEAT_RIGHTLEFT 2731 wp->w_p_rl ? col == 0 : 2732 #endif 2733 col == wp->w_width - 1) 2734 && (*ptr != NUL 2735 || (wp->w_p_list && lcs_eol_one > 0) 2736 || (n_extra && (c_extra != NUL || *p_extra != NUL)))) 2737 { 2738 c = lcs_ext; 2739 char_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); 2740 mb_c = c; 2741 if (enc_utf8 && utf_char2len(c) > 1) 2742 { 2743 mb_utf8 = TRUE; 2744 u8cc[0] = 0; 2745 c = 0xc0; 2746 } 2747 else 2748 mb_utf8 = FALSE; 2749 } 2750 2751 #ifdef FEAT_SYN_HL 2752 // advance to the next 'colorcolumn' 2753 if (draw_color_col) 2754 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); 2755 2756 // Highlight the cursor column if 'cursorcolumn' is set. But don't 2757 // highlight the cursor position itself. 2758 // Also highlight the 'colorcolumn' if it is different than 2759 // 'cursorcolumn' 2760 vcol_save_attr = -1; 2761 if (draw_state == WL_LINE && !lnum_in_visual_area 2762 && search_attr == 0 && area_attr == 0) 2763 { 2764 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol 2765 && lnum != wp->w_cursor.lnum) 2766 { 2767 vcol_save_attr = char_attr; 2768 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC)); 2769 } 2770 else if (draw_color_col && VCOL_HLC == *color_cols) 2771 { 2772 vcol_save_attr = char_attr; 2773 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC)); 2774 } 2775 } 2776 #endif 2777 2778 // Store character to be displayed. 2779 // Skip characters that are left of the screen for 'nowrap'. 2780 vcol_prev = vcol; 2781 if (draw_state < WL_LINE || n_skip <= 0) 2782 { 2783 // Store the character. 2784 #if defined(FEAT_RIGHTLEFT) 2785 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1) 2786 { 2787 // A double-wide character is: put first halve in left cell. 2788 --off; 2789 --col; 2790 } 2791 #endif 2792 ScreenLines[off] = c; 2793 if (enc_dbcs == DBCS_JPNU) 2794 { 2795 if ((mb_c & 0xff00) == 0x8e00) 2796 ScreenLines[off] = 0x8e; 2797 ScreenLines2[off] = mb_c & 0xff; 2798 } 2799 else if (enc_utf8) 2800 { 2801 if (mb_utf8) 2802 { 2803 int i; 2804 2805 ScreenLinesUC[off] = mb_c; 2806 if ((c & 0xff) == 0) 2807 ScreenLines[off] = 0x80; // avoid storing zero 2808 for (i = 0; i < Screen_mco; ++i) 2809 { 2810 ScreenLinesC[i][off] = u8cc[i]; 2811 if (u8cc[i] == 0) 2812 break; 2813 } 2814 } 2815 else 2816 ScreenLinesUC[off] = 0; 2817 } 2818 if (multi_attr) 2819 { 2820 ScreenAttrs[off] = multi_attr; 2821 multi_attr = 0; 2822 } 2823 else 2824 ScreenAttrs[off] = char_attr; 2825 2826 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) 2827 { 2828 // Need to fill two screen columns. 2829 ++off; 2830 ++col; 2831 if (enc_utf8) 2832 // UTF-8: Put a 0 in the second screen char. 2833 ScreenLines[off] = 0; 2834 else 2835 // DBCS: Put second byte in the second screen char. 2836 ScreenLines[off] = mb_c & 0xff; 2837 if (draw_state > WL_NR 2838 #ifdef FEAT_DIFF 2839 && filler_todo <= 0 2840 #endif 2841 ) 2842 ++vcol; 2843 // When "tocol" is halfway a character, set it to the end of 2844 // the character, otherwise highlighting won't stop. 2845 if (tocol == vcol) 2846 ++tocol; 2847 #ifdef FEAT_RIGHTLEFT 2848 if (wp->w_p_rl) 2849 { 2850 // now it's time to backup one cell 2851 --off; 2852 --col; 2853 } 2854 #endif 2855 } 2856 #ifdef FEAT_RIGHTLEFT 2857 if (wp->w_p_rl) 2858 { 2859 --off; 2860 --col; 2861 } 2862 else 2863 #endif 2864 { 2865 ++off; 2866 ++col; 2867 } 2868 } 2869 #ifdef FEAT_CONCEAL 2870 else if (wp->w_p_cole > 0 && is_concealing) 2871 { 2872 --n_skip; 2873 ++vcol_off; 2874 if (n_extra > 0) 2875 vcol_off += n_extra; 2876 if (wp->w_p_wrap) 2877 { 2878 // Special voodoo required if 'wrap' is on. 2879 // 2880 // Advance the column indicator to force the line 2881 // drawing to wrap early. This will make the line 2882 // take up the same screen space when parts are concealed, 2883 // so that cursor line computations aren't messed up. 2884 // 2885 // To avoid the fictitious advance of 'col' causing 2886 // trailing junk to be written out of the screen line 2887 // we are building, 'boguscols' keeps track of the number 2888 // of bad columns we have advanced. 2889 if (n_extra > 0) 2890 { 2891 vcol += n_extra; 2892 # ifdef FEAT_RIGHTLEFT 2893 if (wp->w_p_rl) 2894 { 2895 col -= n_extra; 2896 boguscols -= n_extra; 2897 } 2898 else 2899 # endif 2900 { 2901 col += n_extra; 2902 boguscols += n_extra; 2903 } 2904 n_extra = 0; 2905 n_attr = 0; 2906 } 2907 2908 2909 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) 2910 { 2911 // Need to fill two screen columns. 2912 # ifdef FEAT_RIGHTLEFT 2913 if (wp->w_p_rl) 2914 { 2915 --boguscols; 2916 --col; 2917 } 2918 else 2919 # endif 2920 { 2921 ++boguscols; 2922 ++col; 2923 } 2924 } 2925 2926 # ifdef FEAT_RIGHTLEFT 2927 if (wp->w_p_rl) 2928 { 2929 --boguscols; 2930 --col; 2931 } 2932 else 2933 # endif 2934 { 2935 ++boguscols; 2936 ++col; 2937 } 2938 } 2939 else 2940 { 2941 if (n_extra > 0) 2942 { 2943 vcol += n_extra; 2944 n_extra = 0; 2945 n_attr = 0; 2946 } 2947 } 2948 2949 } 2950 #endif // FEAT_CONCEAL 2951 else 2952 --n_skip; 2953 2954 // Only advance the "vcol" when after the 'number' or 'relativenumber' 2955 // column. 2956 if (draw_state > WL_NR 2957 #ifdef FEAT_DIFF 2958 && filler_todo <= 0 2959 #endif 2960 ) 2961 ++vcol; 2962 2963 #ifdef FEAT_SYN_HL 2964 if (vcol_save_attr >= 0) 2965 char_attr = vcol_save_attr; 2966 #endif 2967 2968 // restore attributes after "predeces" in 'listchars' 2969 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) 2970 char_attr = saved_attr3; 2971 2972 // restore attributes after last 'listchars' or 'number' char 2973 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0) 2974 char_attr = saved_attr2; 2975 2976 // At end of screen line and there is more to come: Display the line 2977 // so far. If there is no more to display it is caught above. 2978 if (( 2979 #ifdef FEAT_RIGHTLEFT 2980 wp->w_p_rl ? (col < 0) : 2981 #endif 2982 (col >= wp->w_width)) 2983 && (*ptr != NUL 2984 #ifdef FEAT_DIFF 2985 || filler_todo > 0 2986 #endif 2987 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str) 2988 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL))) 2989 ) 2990 { 2991 #ifdef FEAT_CONCEAL 2992 screen_line(screen_row, wp->w_wincol, col - boguscols, 2993 (int)wp->w_width, screen_line_flags); 2994 boguscols = 0; 2995 #else 2996 screen_line(screen_row, wp->w_wincol, col, 2997 (int)wp->w_width, screen_line_flags); 2998 #endif 2999 ++row; 3000 ++screen_row; 3001 3002 // When not wrapping and finished diff lines, or when displayed 3003 // '$' and highlighting until last column, break here. 3004 if ((!wp->w_p_wrap 3005 #ifdef FEAT_DIFF 3006 && filler_todo <= 0 3007 #endif 3008 ) || lcs_eol_one == -1) 3009 break; 3010 3011 // When the window is too narrow draw all "@" lines. 3012 if (draw_state != WL_LINE 3013 #ifdef FEAT_DIFF 3014 && filler_todo <= 0 3015 #endif 3016 ) 3017 { 3018 win_draw_end(wp, '@', ' ', TRUE, row, wp->w_height, HLF_AT); 3019 draw_vsep_win(wp, row); 3020 row = endrow; 3021 } 3022 3023 // When line got too long for screen break here. 3024 if (row == endrow) 3025 { 3026 ++row; 3027 break; 3028 } 3029 3030 if (screen_cur_row == screen_row - 1 3031 #ifdef FEAT_DIFF 3032 && filler_todo <= 0 3033 #endif 3034 && wp->w_width == Columns) 3035 { 3036 // Remember that the line wraps, used for modeless copy. 3037 LineWraps[screen_row - 1] = TRUE; 3038 3039 // Special trick to make copy/paste of wrapped lines work with 3040 // xterm/screen: write an extra character beyond the end of 3041 // the line. This will work with all terminal types 3042 // (regardless of the xn,am settings). 3043 // Only do this on a fast tty. 3044 // Only do this if the cursor is on the current line 3045 // (something has been written in it). 3046 // Don't do this for the GUI. 3047 // Don't do this for double-width characters. 3048 // Don't do this for a window not at the right screen border. 3049 if (p_tf 3050 #ifdef FEAT_GUI 3051 && !gui.in_use 3052 #endif 3053 && !(has_mbyte 3054 && ((*mb_off2cells)(LineOffset[screen_row], 3055 LineOffset[screen_row] + screen_Columns) 3056 == 2 3057 || (*mb_off2cells)(LineOffset[screen_row - 1] 3058 + (int)Columns - 2, 3059 LineOffset[screen_row] + screen_Columns) 3060 == 2))) 3061 { 3062 // First make sure we are at the end of the screen line, 3063 // then output the same character again to let the 3064 // terminal know about the wrap. If the terminal doesn't 3065 // auto-wrap, we overwrite the character. 3066 if (screen_cur_col != wp->w_width) 3067 screen_char(LineOffset[screen_row - 1] 3068 + (unsigned)Columns - 1, 3069 screen_row - 1, (int)(Columns - 1)); 3070 3071 // When there is a multi-byte character, just output a 3072 // space to keep it simple. 3073 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[ 3074 screen_row - 1] + (Columns - 1)]) > 1) 3075 out_char(' '); 3076 else 3077 out_char(ScreenLines[LineOffset[screen_row - 1] 3078 + (Columns - 1)]); 3079 // force a redraw of the first char on the next line 3080 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1; 3081 screen_start(); // don't know where cursor is now 3082 } 3083 } 3084 3085 col = 0; 3086 off = (unsigned)(current_ScreenLine - ScreenLines); 3087 #ifdef FEAT_RIGHTLEFT 3088 if (wp->w_p_rl) 3089 { 3090 col = wp->w_width - 1; // col is not used if breaking! 3091 off += col; 3092 } 3093 #endif 3094 3095 // reset the drawing state for the start of a wrapped line 3096 draw_state = WL_START; 3097 saved_n_extra = n_extra; 3098 saved_p_extra = p_extra; 3099 saved_c_extra = c_extra; 3100 saved_c_final = c_final; 3101 #ifdef FEAT_SYN_HL 3102 if (!(cul_screenline 3103 # ifdef FEAT_DIFF 3104 && diff_hlf == (hlf_T)0 3105 # endif 3106 )) 3107 saved_char_attr = char_attr; 3108 else 3109 #endif 3110 saved_char_attr = 0; 3111 n_extra = 0; 3112 lcs_prec_todo = lcs_prec; 3113 #ifdef FEAT_LINEBREAK 3114 # ifdef FEAT_DIFF 3115 if (filler_todo <= 0) 3116 # endif 3117 need_showbreak = TRUE; 3118 #endif 3119 #ifdef FEAT_DIFF 3120 --filler_todo; 3121 // When the filler lines are actually below the last line of the 3122 // file, don't draw the line itself, break here. 3123 if (filler_todo == 0 && wp->w_botfill) 3124 break; 3125 #endif 3126 } 3127 3128 } // for every character in the line 3129 3130 #ifdef FEAT_SPELL 3131 // After an empty line check first word for capital. 3132 if (*skipwhite(line) == NUL) 3133 { 3134 capcol_lnum = lnum + 1; 3135 cap_col = 0; 3136 } 3137 #endif 3138 #ifdef FEAT_PROP_POPUP 3139 vim_free(text_props); 3140 vim_free(text_prop_idxs); 3141 #endif 3142 3143 vim_free(p_extra_free); 3144 return row; 3145 } 3146