comparison src/drawline.c @ 18124:2a806e3c39f6 v8.1.2057

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