comparison src/screen.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 a6c74689fb97
children f249b44039e0
comparison
equal deleted inserted replaced
18123:ceb4be0b23c7 18124:2a806e3c39f6
6 * Do ":help credits" in Vim to see a list of people who contributed. 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. 7 * See README.txt for an overview of the Vim source code.
8 */ 8 */
9 9
10 /* 10 /*
11 * screen.c: code for displaying on the screen 11 * screen.c: Lower level code for displaying on the screen.
12 * 12 *
13 * Output to the screen (console, terminal emulator or GUI window) is minimized 13 * Output to the screen (console, terminal emulator or GUI window) is minimized
14 * by remembering what is already on the screen, and only updating the parts 14 * by remembering what is already on the screen, and only updating the parts
15 * that changed. 15 * that changed.
16 * 16 *
33 * ScreenLines2[] is only used for euc-jp to store the second byte if the 33 * ScreenLines2[] is only used for euc-jp to store the second byte if the
34 * first byte is 0x8e (single-width character). 34 * first byte is 0x8e (single-width character).
35 * 35 *
36 * The screen_*() functions write to the screen and handle updating 36 * The screen_*() functions write to the screen and handle updating
37 * ScreenLines[]. 37 * ScreenLines[].
38 *
39 * update_screen() is the function that updates all windows and status lines.
40 * It is called form the main loop when must_redraw is non-zero. It may be
41 * called from other places when an immediate screen update is needed.
42 *
43 * The part of the buffer that is displayed in a window is set with:
44 * - w_topline (first buffer line in window)
45 * - w_topfill (filler lines above the first line)
46 * - w_leftcol (leftmost window cell in window),
47 * - w_skipcol (skipped window cells of first line)
48 *
49 * Commands that only move the cursor around in a window, do not need to take
50 * action to update the display. The main loop will check if w_topline is
51 * valid and update it (scroll the window) when needed.
52 *
53 * Commands that scroll a window change w_topline and must call
54 * check_cursor() to move the cursor into the visible part of the window, and
55 * call redraw_later(VALID) to have the window displayed by update_screen()
56 * later.
57 *
58 * Commands that change text in the buffer must call changed_bytes() or
59 * changed_lines() to mark the area that changed and will require updating
60 * later. The main loop will call update_screen(), which will update each
61 * window that shows the changed buffer. This assumes text above the change
62 * can remain displayed as it is. Text after the change may need updating for
63 * scrolling, folding and syntax highlighting.
64 *
65 * Commands that change how a window is displayed (e.g., setting 'list') or
66 * invalidate the contents of a window in another way (e.g., change fold
67 * settings), must call redraw_later(NOT_VALID) to have the whole window
68 * redisplayed by update_screen() later.
69 *
70 * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
71 * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
72 * buffer redisplayed by update_screen() later.
73 *
74 * Commands that change highlighting and possibly cause a scroll too must call
75 * redraw_later(SOME_VALID) to update the whole window but still use scrolling
76 * to avoid redrawing everything. But the length of displayed lines must not
77 * change, use NOT_VALID then.
78 *
79 * Commands that move the window position must call redraw_later(NOT_VALID).
80 * TODO: should minimize redrawing by scrolling when possible.
81 *
82 * Commands that change everything (e.g., resizing the screen) must call
83 * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
84 *
85 * Things that are handled indirectly:
86 * - When messages scroll the screen up, msg_scrolled will be set and
87 * update_screen() called to redraw.
88 */ 38 */
89 39
90 #include "vim.h" 40 #include "vim.h"
91 41
92 #define MB_FILLER_CHAR '<' /* character used when a double-width character
93 * doesn't fit. */
94
95 /* 42 /*
96 * The attributes that are actually active for writing to the screen. 43 * The attributes that are actually active for writing to the screen.
97 */ 44 */
98 static int screen_attr = 0; 45 static int screen_attr = 0;
99 46
100 /*
101 * Positioning the cursor is reduced by remembering the last position.
102 * Mostly used by windgoto() and screen_char().
103 */
104 static int screen_cur_row, screen_cur_col; /* last known cursor position */
105
106 #ifdef FEAT_SEARCH_EXTRA
107 static match_T search_hl; // used for 'hlsearch' highlight matching
108 #endif
109
110 #ifdef FEAT_FOLDING
111 static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
112 static int compute_foldcolumn(win_T *wp, int col);
113 #endif
114
115 /* Flag that is set when drawing for a callback, not from the main command
116 * loop. */
117 static int redrawing_for_callback = 0;
118
119 /*
120 * Buffer for one screen line (characters and attributes).
121 */
122 static schar_T *current_ScreenLine;
123
124 static void win_update(win_T *wp);
125 static void win_redr_status(win_T *wp, int ignore_pum);
126 static void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl);
127 #ifdef FEAT_FOLDING
128 static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row);
129 static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
130 static void copy_text_attr(int off, char_u *buf, int len, int attr);
131 #endif
132 static int win_line(win_T *, linenr_T, int, int, int nochange, int number_only);
133 static void draw_vsep_win(win_T *wp, int row);
134 #ifdef FEAT_STL_OPT
135 static void redraw_custom_statusline(win_T *wp);
136 #endif
137 #ifdef FEAT_SEARCH_EXTRA
138 static void start_search_hl(void);
139 static void end_search_hl(void);
140 #endif
141 static void screen_char(unsigned off, int row, int col);
142 static void screen_char_2(unsigned off, int row, int col); 47 static void screen_char_2(unsigned off, int row, int col);
143 static void screenclear2(void); 48 static void screenclear2(void);
144 static void lineclear(unsigned off, int width, int attr); 49 static void lineclear(unsigned off, int width, int attr);
145 static void lineinvalid(unsigned off, int width); 50 static void lineinvalid(unsigned off, int width);
146 static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr); 51 static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
147 static void win_rest_invalid(win_T *wp); 52 static void win_rest_invalid(win_T *wp);
148 static void msg_pos_mode(void); 53 static void msg_pos_mode(void);
149 static void recording_mode(int attr); 54 static void recording_mode(int attr);
150 static int fillchar_status(int *attr, win_T *wp);
151 static int fillchar_vsep(int *attr);
152 #ifdef FEAT_MENU
153 static void redraw_win_toolbar(win_T *wp);
154 #endif
155 #ifdef FEAT_STL_OPT
156 static void win_redr_custom(win_T *wp, int draw_ruler);
157 #endif
158 #ifdef FEAT_CMDL_INFO
159 static void win_redr_ruler(win_T *wp, int always, int ignore_pum);
160 #endif
161 #ifdef FEAT_SYN_HL
162 static void margin_columns_win(win_T *wp, int *left_col, int *right_col);
163 #endif
164 55
165 /* Ugly global: overrule attribute used by screen_char() */ 56 /* Ugly global: overrule attribute used by screen_char() */
166 static int screen_char_attr = 0; 57 static int screen_char_attr = 0;
167
168 #ifdef FEAT_RIGHTLEFT
169 # define HAS_RIGHTLEFT(x) x
170 #else
171 # define HAS_RIGHTLEFT(x) FALSE
172 #endif
173
174 // flags for screen_line()
175 #define SLF_RIGHTLEFT 1
176 #define SLF_POPUP 2
177
178 /*
179 * Redraw the current window later, with update_screen(type).
180 * Set must_redraw only if not already set to a higher value.
181 * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
182 */
183 void
184 redraw_later(int type)
185 {
186 redraw_win_later(curwin, type);
187 }
188
189 void
190 redraw_win_later(
191 win_T *wp,
192 int type)
193 {
194 if (!exiting && wp->w_redr_type < type)
195 {
196 wp->w_redr_type = type;
197 if (type >= NOT_VALID)
198 wp->w_lines_valid = 0;
199 if (must_redraw < type) /* must_redraw is the maximum of all windows */
200 must_redraw = type;
201 }
202 }
203
204 /*
205 * Force a complete redraw later. Also resets the highlighting. To be used
206 * after executing a shell command that messes up the screen.
207 */
208 void
209 redraw_later_clear(void)
210 {
211 redraw_all_later(CLEAR);
212 #ifdef FEAT_GUI
213 if (gui.in_use)
214 /* Use a code that will reset gui.highlight_mask in
215 * gui_stop_highlight(). */
216 screen_attr = HL_ALL + 1;
217 else
218 #endif
219 /* Use attributes that is very unlikely to appear in text. */
220 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
221 }
222
223 /*
224 * Mark all windows to be redrawn later.
225 */
226 void
227 redraw_all_later(int type)
228 {
229 win_T *wp;
230
231 FOR_ALL_WINDOWS(wp)
232 redraw_win_later(wp, type);
233 // This may be needed when switching tabs.
234 if (must_redraw < type)
235 must_redraw = type;
236 }
237
238 /*
239 * Mark all windows that are editing the current buffer to be updated later.
240 */
241 void
242 redraw_curbuf_later(int type)
243 {
244 redraw_buf_later(curbuf, type);
245 }
246
247 void
248 redraw_buf_later(buf_T *buf, int type)
249 {
250 win_T *wp;
251
252 FOR_ALL_WINDOWS(wp)
253 {
254 if (wp->w_buffer == buf)
255 redraw_win_later(wp, type);
256 }
257 }
258
259 #if defined(FEAT_SIGNS) || defined(PROTO)
260 void
261 redraw_buf_line_later(buf_T *buf, linenr_T lnum)
262 {
263 win_T *wp;
264
265 FOR_ALL_WINDOWS(wp)
266 if (wp->w_buffer == buf && lnum >= wp->w_topline
267 && lnum < wp->w_botline)
268 redrawWinline(wp, lnum);
269 }
270 #endif
271
272 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
273 void
274 redraw_buf_and_status_later(buf_T *buf, int type)
275 {
276 win_T *wp;
277
278 #ifdef FEAT_WILDMENU
279 if (wild_menu_showing != 0)
280 /* Don't redraw while the command line completion is displayed, it
281 * would disappear. */
282 return;
283 #endif
284 FOR_ALL_WINDOWS(wp)
285 {
286 if (wp->w_buffer == buf)
287 {
288 redraw_win_later(wp, type);
289 wp->w_redr_status = TRUE;
290 }
291 }
292 }
293 #endif
294
295 #if defined(FEAT_TERMRESPONSE) || defined(PROTO)
296 /*
297 * Redraw as soon as possible. When the command line is not scrolled redraw
298 * right away and restore what was on the command line.
299 * Return a code indicating what happened.
300 */
301 int
302 redraw_asap(int type)
303 {
304 int rows;
305 int cols = screen_Columns;
306 int r;
307 int ret = 0;
308 schar_T *screenline; /* copy from ScreenLines[] */
309 sattr_T *screenattr; /* copy from ScreenAttrs[] */
310 int i;
311 u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */
312 u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */
313 schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */
314
315 redraw_later(type);
316 if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
317 return ret;
318
319 /* Allocate space to save the text displayed in the command line area. */
320 rows = screen_Rows - cmdline_row;
321 screenline = LALLOC_MULT(schar_T, rows * cols);
322 screenattr = LALLOC_MULT(sattr_T, rows * cols);
323 if (screenline == NULL || screenattr == NULL)
324 ret = 2;
325 if (enc_utf8)
326 {
327 screenlineUC = LALLOC_MULT(u8char_T, rows * cols);
328 if (screenlineUC == NULL)
329 ret = 2;
330 for (i = 0; i < p_mco; ++i)
331 {
332 screenlineC[i] = LALLOC_MULT(u8char_T, rows * cols);
333 if (screenlineC[i] == NULL)
334 ret = 2;
335 }
336 }
337 if (enc_dbcs == DBCS_JPNU)
338 {
339 screenline2 = LALLOC_MULT(schar_T, rows * cols);
340 if (screenline2 == NULL)
341 ret = 2;
342 }
343
344 if (ret != 2)
345 {
346 /* Save the text displayed in the command line area. */
347 for (r = 0; r < rows; ++r)
348 {
349 mch_memmove(screenline + r * cols,
350 ScreenLines + LineOffset[cmdline_row + r],
351 (size_t)cols * sizeof(schar_T));
352 mch_memmove(screenattr + r * cols,
353 ScreenAttrs + LineOffset[cmdline_row + r],
354 (size_t)cols * sizeof(sattr_T));
355 if (enc_utf8)
356 {
357 mch_memmove(screenlineUC + r * cols,
358 ScreenLinesUC + LineOffset[cmdline_row + r],
359 (size_t)cols * sizeof(u8char_T));
360 for (i = 0; i < p_mco; ++i)
361 mch_memmove(screenlineC[i] + r * cols,
362 ScreenLinesC[i] + LineOffset[cmdline_row + r],
363 (size_t)cols * sizeof(u8char_T));
364 }
365 if (enc_dbcs == DBCS_JPNU)
366 mch_memmove(screenline2 + r * cols,
367 ScreenLines2 + LineOffset[cmdline_row + r],
368 (size_t)cols * sizeof(schar_T));
369 }
370
371 update_screen(0);
372 ret = 3;
373
374 if (must_redraw == 0)
375 {
376 int off = (int)(current_ScreenLine - ScreenLines);
377
378 /* Restore the text displayed in the command line area. */
379 for (r = 0; r < rows; ++r)
380 {
381 mch_memmove(current_ScreenLine,
382 screenline + r * cols,
383 (size_t)cols * sizeof(schar_T));
384 mch_memmove(ScreenAttrs + off,
385 screenattr + r * cols,
386 (size_t)cols * sizeof(sattr_T));
387 if (enc_utf8)
388 {
389 mch_memmove(ScreenLinesUC + off,
390 screenlineUC + r * cols,
391 (size_t)cols * sizeof(u8char_T));
392 for (i = 0; i < p_mco; ++i)
393 mch_memmove(ScreenLinesC[i] + off,
394 screenlineC[i] + r * cols,
395 (size_t)cols * sizeof(u8char_T));
396 }
397 if (enc_dbcs == DBCS_JPNU)
398 mch_memmove(ScreenLines2 + off,
399 screenline2 + r * cols,
400 (size_t)cols * sizeof(schar_T));
401 screen_line(cmdline_row + r, 0, cols, cols, 0);
402 }
403 ret = 4;
404 }
405 }
406
407 vim_free(screenline);
408 vim_free(screenattr);
409 if (enc_utf8)
410 {
411 vim_free(screenlineUC);
412 for (i = 0; i < p_mco; ++i)
413 vim_free(screenlineC[i]);
414 }
415 if (enc_dbcs == DBCS_JPNU)
416 vim_free(screenline2);
417
418 /* Show the intro message when appropriate. */
419 maybe_intro_message();
420
421 setcursor();
422
423 return ret;
424 }
425 #endif
426
427 /*
428 * Invoked after an asynchronous callback is called.
429 * If an echo command was used the cursor needs to be put back where
430 * it belongs. If highlighting was changed a redraw is needed.
431 * If "call_update_screen" is FALSE don't call update_screen() when at the
432 * command line.
433 */
434 void
435 redraw_after_callback(int call_update_screen)
436 {
437 ++redrawing_for_callback;
438
439 if (State == HITRETURN || State == ASKMORE)
440 ; // do nothing
441 else if (State & CMDLINE)
442 {
443 // Don't redraw when in prompt_for_number().
444 if (cmdline_row > 0)
445 {
446 // Redrawing only works when the screen didn't scroll. Don't clear
447 // wildmenu entries.
448 if (msg_scrolled == 0
449 #ifdef FEAT_WILDMENU
450 && wild_menu_showing == 0
451 #endif
452 && call_update_screen)
453 update_screen(0);
454
455 // Redraw in the same position, so that the user can continue
456 // editing the command.
457 redrawcmdline_ex(FALSE);
458 }
459 }
460 else if (State & (NORMAL | INSERT | TERMINAL))
461 {
462 // keep the command line if possible
463 update_screen(VALID_NO_UPDATE);
464 setcursor();
465 }
466 cursor_on();
467 #ifdef FEAT_GUI
468 if (gui.in_use && !gui_mch_is_blink_off())
469 // Don't update the cursor when it is blinking and off to avoid
470 // flicker.
471 out_flush_cursor(FALSE, FALSE);
472 else
473 #endif
474 out_flush();
475
476 --redrawing_for_callback;
477 }
478
479 /*
480 * Changed something in the current window, at buffer line "lnum", that
481 * requires that line and possibly other lines to be redrawn.
482 * Used when entering/leaving Insert mode with the cursor on a folded line.
483 * Used to remove the "$" from a change command.
484 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
485 * may become invalid and the whole window will have to be redrawn.
486 */
487 void
488 redrawWinline(
489 win_T *wp,
490 linenr_T lnum)
491 {
492 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
493 wp->w_redraw_top = lnum;
494 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
495 wp->w_redraw_bot = lnum;
496 redraw_win_later(wp, VALID);
497 }
498
499 /*
500 * To be called when "updating_screen" was set before and now the postponed
501 * side effects may take place.
502 */
503 void
504 after_updating_screen(int may_resize_shell UNUSED)
505 {
506 updating_screen = FALSE;
507 #ifdef FEAT_GUI
508 if (may_resize_shell)
509 gui_may_resize_shell();
510 #endif
511 #ifdef FEAT_TERMINAL
512 term_check_channel_closed_recently();
513 #endif
514
515 #ifdef HAVE_DROP_FILE
516 // If handle_drop() was called while updating_screen was TRUE need to
517 // handle the drop now.
518 handle_any_postponed_drop();
519 #endif
520 }
521
522 /*
523 * Update all windows that are editing the current buffer.
524 */
525 void
526 update_curbuf(int type)
527 {
528 redraw_curbuf_later(type);
529 update_screen(type);
530 }
531
532 /*
533 * Based on the current value of curwin->w_topline, transfer a screenfull
534 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
535 * Return OK when the screen was updated, FAIL if it was not done.
536 */
537 int
538 update_screen(int type_arg)
539 {
540 int type = type_arg;
541 win_T *wp;
542 static int did_intro = FALSE;
543 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
544 int did_one;
545 #endif
546 #ifdef FEAT_GUI
547 int did_undraw = FALSE;
548 int gui_cursor_col = 0;
549 int gui_cursor_row = 0;
550 #endif
551 int no_update = FALSE;
552
553 /* Don't do anything if the screen structures are (not yet) valid. */
554 if (!screen_valid(TRUE))
555 return FAIL;
556
557 if (type == VALID_NO_UPDATE)
558 {
559 no_update = TRUE;
560 type = 0;
561 }
562
563 #ifdef FEAT_EVAL
564 {
565 buf_T *buf;
566
567 // Before updating the screen, notify any listeners of changed text.
568 FOR_ALL_BUFFERS(buf)
569 invoke_listeners(buf);
570 }
571 #endif
572
573 #ifdef FEAT_DIFF
574 // May have postponed updating diffs.
575 if (need_diff_redraw)
576 diff_redraw(TRUE);
577 #endif
578
579 if (must_redraw)
580 {
581 if (type < must_redraw) /* use maximal type */
582 type = must_redraw;
583
584 /* must_redraw is reset here, so that when we run into some weird
585 * reason to redraw while busy redrawing (e.g., asynchronous
586 * scrolling), or update_topline() in win_update() will cause a
587 * scroll, the screen will be redrawn later or in win_update(). */
588 must_redraw = 0;
589 }
590
591 /* May need to update w_lines[]. */
592 if (curwin->w_lines_valid == 0 && type < NOT_VALID
593 #ifdef FEAT_TERMINAL
594 && !term_do_update_window(curwin)
595 #endif
596 )
597 type = NOT_VALID;
598
599 /* Postpone the redrawing when it's not needed and when being called
600 * recursively. */
601 if (!redrawing() || updating_screen)
602 {
603 redraw_later(type); /* remember type for next time */
604 must_redraw = type;
605 if (type > INVERTED_ALL)
606 curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
607 return FAIL;
608 }
609 updating_screen = TRUE;
610
611 #ifdef FEAT_TEXT_PROP
612 // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot
613 // in some windows.
614 may_update_popup_mask(type);
615 #endif
616
617 #ifdef FEAT_SYN_HL
618 ++display_tick; /* let syntax code know we're in a next round of
619 * display updating */
620 #endif
621 if (no_update)
622 ++no_win_do_lines_ins;
623
624 /*
625 * if the screen was scrolled up when displaying a message, scroll it down
626 */
627 if (msg_scrolled)
628 {
629 clear_cmdline = TRUE;
630 if (msg_scrolled > Rows - 5) /* clearing is faster */
631 type = CLEAR;
632 else if (type != CLEAR)
633 {
634 check_for_delay(FALSE);
635 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
636 == FAIL)
637 type = CLEAR;
638 FOR_ALL_WINDOWS(wp)
639 {
640 if (wp->w_winrow < msg_scrolled)
641 {
642 if (W_WINROW(wp) + wp->w_height > msg_scrolled
643 && wp->w_redr_type < REDRAW_TOP
644 && wp->w_lines_valid > 0
645 && wp->w_topline == wp->w_lines[0].wl_lnum)
646 {
647 wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
648 wp->w_redr_type = REDRAW_TOP;
649 }
650 else
651 {
652 wp->w_redr_type = NOT_VALID;
653 if (W_WINROW(wp) + wp->w_height + wp->w_status_height
654 <= msg_scrolled)
655 wp->w_redr_status = TRUE;
656 }
657 }
658 }
659 if (!no_update)
660 redraw_cmdline = TRUE;
661 redraw_tabline = TRUE;
662 }
663 msg_scrolled = 0;
664 need_wait_return = FALSE;
665 }
666
667 /* reset cmdline_row now (may have been changed temporarily) */
668 compute_cmdrow();
669
670 /* Check for changed highlighting */
671 if (need_highlight_changed)
672 highlight_changed();
673
674 if (type == CLEAR) /* first clear screen */
675 {
676 screenclear(); /* will reset clear_cmdline */
677 type = NOT_VALID;
678 /* must_redraw may be set indirectly, avoid another redraw later */
679 must_redraw = 0;
680 }
681
682 if (clear_cmdline) /* going to clear cmdline (done below) */
683 check_for_delay(FALSE);
684
685 #ifdef FEAT_LINEBREAK
686 /* Force redraw when width of 'number' or 'relativenumber' column
687 * changes. */
688 if (curwin->w_redr_type < NOT_VALID
689 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
690 ? number_width(curwin) : 0))
691 curwin->w_redr_type = NOT_VALID;
692 #endif
693
694 /*
695 * Only start redrawing if there is really something to do.
696 */
697 if (type == INVERTED)
698 update_curswant();
699 if (curwin->w_redr_type < type
700 && !((type == VALID
701 && curwin->w_lines[0].wl_valid
702 #ifdef FEAT_DIFF
703 && curwin->w_topfill == curwin->w_old_topfill
704 && curwin->w_botfill == curwin->w_old_botfill
705 #endif
706 && curwin->w_topline == curwin->w_lines[0].wl_lnum)
707 || (type == INVERTED
708 && VIsual_active
709 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
710 && curwin->w_old_visual_mode == VIsual_mode
711 && (curwin->w_valid & VALID_VIRTCOL)
712 && curwin->w_old_curswant == curwin->w_curswant)
713 ))
714 curwin->w_redr_type = type;
715
716 /* Redraw the tab pages line if needed. */
717 if (redraw_tabline || type >= NOT_VALID)
718 draw_tabline();
719
720 #ifdef FEAT_SYN_HL
721 /*
722 * Correct stored syntax highlighting info for changes in each displayed
723 * buffer. Each buffer must only be done once.
724 */
725 FOR_ALL_WINDOWS(wp)
726 {
727 if (wp->w_buffer->b_mod_set)
728 {
729 win_T *wwp;
730
731 /* Check if we already did this buffer. */
732 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
733 if (wwp->w_buffer == wp->w_buffer)
734 break;
735 if (wwp == wp && syntax_present(wp))
736 syn_stack_apply_changes(wp->w_buffer);
737 }
738 }
739 #endif
740
741 /*
742 * Go from top to bottom through the windows, redrawing the ones that need
743 * it.
744 */
745 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
746 did_one = FALSE;
747 #endif
748 #ifdef FEAT_SEARCH_EXTRA
749 search_hl.rm.regprog = NULL;
750 #endif
751 FOR_ALL_WINDOWS(wp)
752 {
753 if (wp->w_redr_type != 0)
754 {
755 cursor_off();
756 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
757 if (!did_one)
758 {
759 did_one = TRUE;
760 # ifdef FEAT_SEARCH_EXTRA
761 start_search_hl();
762 # endif
763 # ifdef FEAT_CLIPBOARD
764 /* When Visual area changed, may have to update selection. */
765 if (clip_star.available && clip_isautosel_star())
766 clip_update_selection(&clip_star);
767 if (clip_plus.available && clip_isautosel_plus())
768 clip_update_selection(&clip_plus);
769 # endif
770 #ifdef FEAT_GUI
771 /* Remove the cursor before starting to do anything, because
772 * scrolling may make it difficult to redraw the text under
773 * it. */
774 if (gui.in_use && wp == curwin)
775 {
776 gui_cursor_col = gui.cursor_col;
777 gui_cursor_row = gui.cursor_row;
778 gui_undraw_cursor();
779 did_undraw = TRUE;
780 }
781 #endif
782 }
783 #endif
784 win_update(wp);
785 }
786
787 /* redraw status line after the window to minimize cursor movement */
788 if (wp->w_redr_status)
789 {
790 cursor_off();
791 win_redr_status(wp, TRUE); // any popup menu will be redrawn below
792 }
793 }
794 #if defined(FEAT_SEARCH_EXTRA)
795 end_search_hl();
796 #endif
797 /* May need to redraw the popup menu. */
798 pum_may_redraw();
799
800 /* Reset b_mod_set flags. Going through all windows is probably faster
801 * than going through all buffers (there could be many buffers). */
802 FOR_ALL_WINDOWS(wp)
803 wp->w_buffer->b_mod_set = FALSE;
804
805 #ifdef FEAT_TEXT_PROP
806 // Display popup windows on top of the windows and command line.
807 update_popups(win_update);
808 #endif
809
810 after_updating_screen(TRUE);
811
812 /* Clear or redraw the command line. Done last, because scrolling may
813 * mess up the command line. */
814 if (clear_cmdline || redraw_cmdline || redraw_mode)
815 showmode();
816
817 if (no_update)
818 --no_win_do_lines_ins;
819
820 /* May put up an introductory message when not editing a file */
821 if (!did_intro)
822 maybe_intro_message();
823 did_intro = TRUE;
824
825 #ifdef FEAT_GUI
826 /* Redraw the cursor and update the scrollbars when all screen updating is
827 * done. */
828 if (gui.in_use)
829 {
830 if (did_undraw && !gui_mch_is_blink_off())
831 {
832 mch_disable_flush();
833 out_flush(); /* required before updating the cursor */
834 mch_enable_flush();
835
836 /* Put the GUI position where the cursor was, gui_update_cursor()
837 * uses that. */
838 gui.col = gui_cursor_col;
839 gui.row = gui_cursor_row;
840 gui.col = mb_fix_col(gui.col, gui.row);
841 gui_update_cursor(FALSE, FALSE);
842 gui_may_flush();
843 screen_cur_col = gui.col;
844 screen_cur_row = gui.row;
845 }
846 else
847 out_flush();
848 gui_update_scrollbars(FALSE);
849 }
850 #endif
851 return OK;
852 }
853
854 #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI)
855 /*
856 * Prepare for updating one or more windows.
857 * Caller must check for "updating_screen" already set to avoid recursiveness.
858 */
859 static void
860 update_prepare(void)
861 {
862 cursor_off();
863 updating_screen = TRUE;
864 #ifdef FEAT_GUI
865 /* Remove the cursor before starting to do anything, because scrolling may
866 * make it difficult to redraw the text under it. */
867 if (gui.in_use)
868 gui_undraw_cursor();
869 #endif
870 #ifdef FEAT_SEARCH_EXTRA
871 start_search_hl();
872 #endif
873 #ifdef FEAT_TEXT_PROP
874 // Update popup_mask if needed.
875 may_update_popup_mask(must_redraw);
876 #endif
877 }
878
879 /*
880 * Finish updating one or more windows.
881 */
882 static void
883 update_finish(void)
884 {
885 if (redraw_cmdline || redraw_mode)
886 showmode();
887
888 # ifdef FEAT_SEARCH_EXTRA
889 end_search_hl();
890 # endif
891
892 after_updating_screen(TRUE);
893
894 # ifdef FEAT_GUI
895 /* Redraw the cursor and update the scrollbars when all screen updating is
896 * done. */
897 if (gui.in_use)
898 {
899 out_flush_cursor(FALSE, FALSE);
900 gui_update_scrollbars(FALSE);
901 }
902 # endif
903 }
904 #endif
905 58
906 #if defined(FEAT_CONCEAL) || defined(PROTO) 59 #if defined(FEAT_CONCEAL) || defined(PROTO)
907 /* 60 /*
908 * Return TRUE if the cursor line in window "wp" may be concealed, according 61 * Return TRUE if the cursor line in window "wp" may be concealed, according
909 * to the 'concealcursor' option. 62 * to the 'concealcursor' option.
942 curs_columns(TRUE); 95 curs_columns(TRUE);
943 } 96 }
944 } 97 }
945 #endif 98 #endif
946 99
947 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
948 void
949 update_debug_sign(buf_T *buf, linenr_T lnum)
950 {
951 win_T *wp;
952 int doit = FALSE;
953
954 # ifdef FEAT_FOLDING
955 win_foldinfo.fi_level = 0;
956 # endif
957
958 // update/delete a specific sign
959 redraw_buf_line_later(buf, lnum);
960
961 // check if it resulted in the need to redraw a window
962 FOR_ALL_WINDOWS(wp)
963 if (wp->w_redr_type != 0)
964 doit = TRUE;
965
966 /* Return when there is nothing to do, screen updating is already
967 * happening (recursive call), messages on the screen or still starting up.
968 */
969 if (!doit || updating_screen
970 || State == ASKMORE || State == HITRETURN
971 || msg_scrolled
972 #ifdef FEAT_GUI
973 || gui.starting
974 #endif
975 || starting)
976 return;
977
978 /* update all windows that need updating */
979 update_prepare();
980
981 FOR_ALL_WINDOWS(wp)
982 {
983 if (wp->w_redr_type != 0)
984 win_update(wp);
985 if (wp->w_redr_status)
986 win_redr_status(wp, FALSE);
987 }
988
989 update_finish();
990 }
991 #endif
992
993 /* 100 /*
994 * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup 101 * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
995 * window then get the "Pmenu" highlight attribute. 102 * window then get the "Pmenu" highlight attribute.
996 */ 103 */
997 int 104 int
1009 else 116 else
1010 wcr_attr = HL_ATTR(HLF_PNI); // Pmenu 117 wcr_attr = HL_ATTR(HLF_PNI); // Pmenu
1011 } 118 }
1012 #endif 119 #endif
1013 return wcr_attr; 120 return wcr_attr;
1014 }
1015
1016 #if defined(FEAT_GUI) || defined(PROTO)
1017 /*
1018 * Update a single window, its status line and maybe the command line msg.
1019 * Used for the GUI scrollbar.
1020 */
1021 void
1022 updateWindow(win_T *wp)
1023 {
1024 /* return if already busy updating */
1025 if (updating_screen)
1026 return;
1027
1028 update_prepare();
1029
1030 #ifdef FEAT_CLIPBOARD
1031 /* When Visual area changed, may have to update selection. */
1032 if (clip_star.available && clip_isautosel_star())
1033 clip_update_selection(&clip_star);
1034 if (clip_plus.available && clip_isautosel_plus())
1035 clip_update_selection(&clip_plus);
1036 #endif
1037
1038 win_update(wp);
1039
1040 /* When the screen was cleared redraw the tab pages line. */
1041 if (redraw_tabline)
1042 draw_tabline();
1043
1044 if (wp->w_redr_status
1045 # ifdef FEAT_CMDL_INFO
1046 || p_ru
1047 # endif
1048 # ifdef FEAT_STL_OPT
1049 || *p_stl != NUL || *wp->w_p_stl != NUL
1050 # endif
1051 )
1052 win_redr_status(wp, FALSE);
1053
1054 #ifdef FEAT_TEXT_PROP
1055 // Display popup windows on top of everything.
1056 update_popups(win_update);
1057 #endif
1058
1059 update_finish();
1060 }
1061 #endif
1062
1063 /*
1064 * Update a single window.
1065 *
1066 * This may cause the windows below it also to be redrawn (when clearing the
1067 * screen or scrolling lines).
1068 *
1069 * How the window is redrawn depends on wp->w_redr_type. Each type also
1070 * implies the one below it.
1071 * NOT_VALID redraw the whole window
1072 * SOME_VALID redraw the whole window but do scroll when possible
1073 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
1074 * INVERTED redraw the changed part of the Visual area
1075 * INVERTED_ALL redraw the whole Visual area
1076 * VALID 1. scroll up/down to adjust for a changed w_topline
1077 * 2. update lines at the top when scrolled down
1078 * 3. redraw changed text:
1079 * - if wp->w_buffer->b_mod_set set, update lines between
1080 * b_mod_top and b_mod_bot.
1081 * - if wp->w_redraw_top non-zero, redraw lines between
1082 * wp->w_redraw_top and wp->w_redr_bot.
1083 * - continue redrawing when syntax status is invalid.
1084 * 4. if scrolled up, update lines at the bottom.
1085 * This results in three areas that may need updating:
1086 * top: from first row to top_end (when scrolled down)
1087 * mid: from mid_start to mid_end (update inversion or changed text)
1088 * bot: from bot_start to last row (when scrolled up)
1089 */
1090 static void
1091 win_update(win_T *wp)
1092 {
1093 buf_T *buf = wp->w_buffer;
1094 int type;
1095 int top_end = 0; /* Below last row of the top area that needs
1096 updating. 0 when no top area updating. */
1097 int mid_start = 999;/* first row of the mid area that needs
1098 updating. 999 when no mid area updating. */
1099 int mid_end = 0; /* Below last row of the mid area that needs
1100 updating. 0 when no mid area updating. */
1101 int bot_start = 999;/* first row of the bot area that needs
1102 updating. 999 when no bot area updating */
1103 int scrolled_down = FALSE; /* TRUE when scrolled down when
1104 w_topline got smaller a bit */
1105 #ifdef FEAT_SEARCH_EXTRA
1106 int top_to_mod = FALSE; // redraw above mod_top
1107 #endif
1108
1109 int row; /* current window row to display */
1110 linenr_T lnum; /* current buffer lnum to display */
1111 int idx; /* current index in w_lines[] */
1112 int srow; /* starting row of the current line */
1113
1114 int eof = FALSE; /* if TRUE, we hit the end of the file */
1115 int didline = FALSE; /* if TRUE, we finished the last line */
1116 int i;
1117 long j;
1118 static int recursive = FALSE; /* being called recursively */
1119 int old_botline = wp->w_botline;
1120 #ifdef FEAT_FOLDING
1121 long fold_count;
1122 #endif
1123 #ifdef FEAT_SYN_HL
1124 /* remember what happened to the previous line, to know if
1125 * check_visual_highlight() can be used */
1126 #define DID_NONE 1 /* didn't update a line */
1127 #define DID_LINE 2 /* updated a normal line */
1128 #define DID_FOLD 3 /* updated a folded line */
1129 int did_update = DID_NONE;
1130 linenr_T syntax_last_parsed = 0; /* last parsed text line */
1131 #endif
1132 linenr_T mod_top = 0;
1133 linenr_T mod_bot = 0;
1134 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1135 int save_got_int;
1136 #endif
1137 #ifdef SYN_TIME_LIMIT
1138 proftime_T syntax_tm;
1139 #endif
1140
1141 type = wp->w_redr_type;
1142
1143 if (type == NOT_VALID)
1144 {
1145 wp->w_redr_status = TRUE;
1146 wp->w_lines_valid = 0;
1147 }
1148
1149 /* Window is zero-height: nothing to draw. */
1150 if (wp->w_height + WINBAR_HEIGHT(wp) == 0)
1151 {
1152 wp->w_redr_type = 0;
1153 return;
1154 }
1155
1156 /* Window is zero-width: Only need to draw the separator. */
1157 if (wp->w_width == 0)
1158 {
1159 /* draw the vertical separator right of this window */
1160 draw_vsep_win(wp, 0);
1161 wp->w_redr_type = 0;
1162 return;
1163 }
1164
1165 #ifdef FEAT_TERMINAL
1166 // If this window contains a terminal, redraw works completely differently.
1167 if (term_do_update_window(wp))
1168 {
1169 term_update_window(wp);
1170 # ifdef FEAT_MENU
1171 /* Draw the window toolbar, if there is one. */
1172 if (winbar_height(wp) > 0)
1173 redraw_win_toolbar(wp);
1174 # endif
1175 wp->w_redr_type = 0;
1176 return;
1177 }
1178 #endif
1179
1180 #ifdef FEAT_SEARCH_EXTRA
1181 init_search_hl(wp, &search_hl);
1182 #endif
1183
1184 #ifdef FEAT_LINEBREAK
1185 /* Force redraw when width of 'number' or 'relativenumber' column
1186 * changes. */
1187 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
1188 if (wp->w_nrwidth != i)
1189 {
1190 type = NOT_VALID;
1191 wp->w_nrwidth = i;
1192 }
1193 else
1194 #endif
1195
1196 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
1197 {
1198 /*
1199 * When there are both inserted/deleted lines and specific lines to be
1200 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
1201 * everything (only happens when redrawing is off for while).
1202 */
1203 type = NOT_VALID;
1204 }
1205 else
1206 {
1207 /*
1208 * Set mod_top to the first line that needs displaying because of
1209 * changes. Set mod_bot to the first line after the changes.
1210 */
1211 mod_top = wp->w_redraw_top;
1212 if (wp->w_redraw_bot != 0)
1213 mod_bot = wp->w_redraw_bot + 1;
1214 else
1215 mod_bot = 0;
1216 if (buf->b_mod_set)
1217 {
1218 if (mod_top == 0 || mod_top > buf->b_mod_top)
1219 {
1220 mod_top = buf->b_mod_top;
1221 #ifdef FEAT_SYN_HL
1222 /* Need to redraw lines above the change that may be included
1223 * in a pattern match. */
1224 if (syntax_present(wp))
1225 {
1226 mod_top -= buf->b_s.b_syn_sync_linebreaks;
1227 if (mod_top < 1)
1228 mod_top = 1;
1229 }
1230 #endif
1231 }
1232 if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
1233 mod_bot = buf->b_mod_bot;
1234
1235 #ifdef FEAT_SEARCH_EXTRA
1236 // When 'hlsearch' is on and using a multi-line search pattern, a
1237 // change in one line may make the Search highlighting in a
1238 // previous line invalid. Simple solution: redraw all visible
1239 // lines above the change.
1240 // Same for a match pattern.
1241 if (search_hl.rm.regprog != NULL
1242 && re_multiline(search_hl.rm.regprog))
1243 top_to_mod = TRUE;
1244 else
1245 {
1246 matchitem_T *cur = wp->w_match_head;
1247
1248 while (cur != NULL)
1249 {
1250 if (cur->match.regprog != NULL
1251 && re_multiline(cur->match.regprog))
1252 {
1253 top_to_mod = TRUE;
1254 break;
1255 }
1256 cur = cur->next;
1257 }
1258 }
1259 #endif
1260 }
1261 #ifdef FEAT_FOLDING
1262 if (mod_top != 0 && hasAnyFolding(wp))
1263 {
1264 linenr_T lnumt, lnumb;
1265
1266 /*
1267 * A change in a line can cause lines above it to become folded or
1268 * unfolded. Find the top most buffer line that may be affected.
1269 * If the line was previously folded and displayed, get the first
1270 * line of that fold. If the line is folded now, get the first
1271 * folded line. Use the minimum of these two.
1272 */
1273
1274 /* Find last valid w_lines[] entry above mod_top. Set lnumt to
1275 * the line below it. If there is no valid entry, use w_topline.
1276 * Find the first valid w_lines[] entry below mod_bot. Set lnumb
1277 * to this line. If there is no valid entry, use MAXLNUM. */
1278 lnumt = wp->w_topline;
1279 lnumb = MAXLNUM;
1280 for (i = 0; i < wp->w_lines_valid; ++i)
1281 if (wp->w_lines[i].wl_valid)
1282 {
1283 if (wp->w_lines[i].wl_lastlnum < mod_top)
1284 lnumt = wp->w_lines[i].wl_lastlnum + 1;
1285 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1286 {
1287 lnumb = wp->w_lines[i].wl_lnum;
1288 /* When there is a fold column it might need updating
1289 * in the next line ("J" just above an open fold). */
1290 if (compute_foldcolumn(wp, 0) > 0)
1291 ++lnumb;
1292 }
1293 }
1294
1295 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1296 if (mod_top > lnumt)
1297 mod_top = lnumt;
1298
1299 /* Now do the same for the bottom line (one above mod_bot). */
1300 --mod_bot;
1301 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1302 ++mod_bot;
1303 if (mod_bot < lnumb)
1304 mod_bot = lnumb;
1305 }
1306 #endif
1307
1308 /* When a change starts above w_topline and the end is below
1309 * w_topline, start redrawing at w_topline.
1310 * If the end of the change is above w_topline: do like no change was
1311 * made, but redraw the first line to find changes in syntax. */
1312 if (mod_top != 0 && mod_top < wp->w_topline)
1313 {
1314 if (mod_bot > wp->w_topline)
1315 mod_top = wp->w_topline;
1316 #ifdef FEAT_SYN_HL
1317 else if (syntax_present(wp))
1318 top_end = 1;
1319 #endif
1320 }
1321
1322 /* When line numbers are displayed need to redraw all lines below
1323 * inserted/deleted lines. */
1324 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1325 mod_bot = MAXLNUM;
1326 }
1327 wp->w_redraw_top = 0; // reset for next time
1328 wp->w_redraw_bot = 0;
1329
1330 /*
1331 * When only displaying the lines at the top, set top_end. Used when
1332 * window has scrolled down for msg_scrolled.
1333 */
1334 if (type == REDRAW_TOP)
1335 {
1336 j = 0;
1337 for (i = 0; i < wp->w_lines_valid; ++i)
1338 {
1339 j += wp->w_lines[i].wl_size;
1340 if (j >= wp->w_upd_rows)
1341 {
1342 top_end = j;
1343 break;
1344 }
1345 }
1346 if (top_end == 0)
1347 /* not found (cannot happen?): redraw everything */
1348 type = NOT_VALID;
1349 else
1350 /* top area defined, the rest is VALID */
1351 type = VALID;
1352 }
1353
1354 /* Trick: we want to avoid clearing the screen twice. screenclear() will
1355 * set "screen_cleared" to TRUE. The special value MAYBE (which is still
1356 * non-zero and thus not FALSE) will indicate that screenclear() was not
1357 * called. */
1358 if (screen_cleared)
1359 screen_cleared = MAYBE;
1360
1361 /*
1362 * If there are no changes on the screen that require a complete redraw,
1363 * handle three cases:
1364 * 1: we are off the top of the screen by a few lines: scroll down
1365 * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1366 * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1367 * w_lines[] that needs updating.
1368 */
1369 if ((type == VALID || type == SOME_VALID
1370 || type == INVERTED || type == INVERTED_ALL)
1371 #ifdef FEAT_DIFF
1372 && !wp->w_botfill && !wp->w_old_botfill
1373 #endif
1374 )
1375 {
1376 if (mod_top != 0 && wp->w_topline == mod_top)
1377 {
1378 /*
1379 * w_topline is the first changed line, the scrolling will be done
1380 * further down.
1381 */
1382 }
1383 else if (wp->w_lines[0].wl_valid
1384 && (wp->w_topline < wp->w_lines[0].wl_lnum
1385 #ifdef FEAT_DIFF
1386 || (wp->w_topline == wp->w_lines[0].wl_lnum
1387 && wp->w_topfill > wp->w_old_topfill)
1388 #endif
1389 ))
1390 {
1391 /*
1392 * New topline is above old topline: May scroll down.
1393 */
1394 #ifdef FEAT_FOLDING
1395 if (hasAnyFolding(wp))
1396 {
1397 linenr_T ln;
1398
1399 /* count the number of lines we are off, counting a sequence
1400 * of folded lines as one */
1401 j = 0;
1402 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1403 {
1404 ++j;
1405 if (j >= wp->w_height - 2)
1406 break;
1407 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1408 }
1409 }
1410 else
1411 #endif
1412 j = wp->w_lines[0].wl_lnum - wp->w_topline;
1413 if (j < wp->w_height - 2) /* not too far off */
1414 {
1415 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1416 #ifdef FEAT_DIFF
1417 /* insert extra lines for previously invisible filler lines */
1418 if (wp->w_lines[0].wl_lnum != wp->w_topline)
1419 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1420 - wp->w_old_topfill;
1421 #endif
1422 if (i < wp->w_height - 2) /* less than a screen off */
1423 {
1424 /*
1425 * Try to insert the correct number of lines.
1426 * If not the last window, delete the lines at the bottom.
1427 * win_ins_lines may fail when the terminal can't do it.
1428 */
1429 if (i > 0)
1430 check_for_delay(FALSE);
1431 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1432 {
1433 if (wp->w_lines_valid != 0)
1434 {
1435 /* Need to update rows that are new, stop at the
1436 * first one that scrolled down. */
1437 top_end = i;
1438 scrolled_down = TRUE;
1439
1440 /* Move the entries that were scrolled, disable
1441 * the entries for the lines to be redrawn. */
1442 if ((wp->w_lines_valid += j) > wp->w_height)
1443 wp->w_lines_valid = wp->w_height;
1444 for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1445 wp->w_lines[idx] = wp->w_lines[idx - j];
1446 while (idx >= 0)
1447 wp->w_lines[idx--].wl_valid = FALSE;
1448 }
1449 }
1450 else
1451 mid_start = 0; /* redraw all lines */
1452 }
1453 else
1454 mid_start = 0; /* redraw all lines */
1455 }
1456 else
1457 mid_start = 0; /* redraw all lines */
1458 }
1459 else
1460 {
1461 /*
1462 * New topline is at or below old topline: May scroll up.
1463 * When topline didn't change, find first entry in w_lines[] that
1464 * needs updating.
1465 */
1466
1467 /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
1468 j = -1;
1469 row = 0;
1470 for (i = 0; i < wp->w_lines_valid; i++)
1471 {
1472 if (wp->w_lines[i].wl_valid
1473 && wp->w_lines[i].wl_lnum == wp->w_topline)
1474 {
1475 j = i;
1476 break;
1477 }
1478 row += wp->w_lines[i].wl_size;
1479 }
1480 if (j == -1)
1481 {
1482 /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1483 * lines */
1484 mid_start = 0;
1485 }
1486 else
1487 {
1488 /*
1489 * Try to delete the correct number of lines.
1490 * wp->w_topline is at wp->w_lines[i].wl_lnum.
1491 */
1492 #ifdef FEAT_DIFF
1493 /* If the topline didn't change, delete old filler lines,
1494 * otherwise delete filler lines of the new topline... */
1495 if (wp->w_lines[0].wl_lnum == wp->w_topline)
1496 row += wp->w_old_topfill;
1497 else
1498 row += diff_check_fill(wp, wp->w_topline);
1499 /* ... but don't delete new filler lines. */
1500 row -= wp->w_topfill;
1501 #endif
1502 if (row > 0)
1503 {
1504 check_for_delay(FALSE);
1505 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
1506 == OK)
1507 bot_start = wp->w_height - row;
1508 else
1509 mid_start = 0; /* redraw all lines */
1510 }
1511 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1512 {
1513 /*
1514 * Skip the lines (below the deleted lines) that are still
1515 * valid and don't need redrawing. Copy their info
1516 * upwards, to compensate for the deleted lines. Set
1517 * bot_start to the first row that needs redrawing.
1518 */
1519 bot_start = 0;
1520 idx = 0;
1521 for (;;)
1522 {
1523 wp->w_lines[idx] = wp->w_lines[j];
1524 /* stop at line that didn't fit, unless it is still
1525 * valid (no lines deleted) */
1526 if (row > 0 && bot_start + row
1527 + (int)wp->w_lines[j].wl_size > wp->w_height)
1528 {
1529 wp->w_lines_valid = idx + 1;
1530 break;
1531 }
1532 bot_start += wp->w_lines[idx++].wl_size;
1533
1534 /* stop at the last valid entry in w_lines[].wl_size */
1535 if (++j >= wp->w_lines_valid)
1536 {
1537 wp->w_lines_valid = idx;
1538 break;
1539 }
1540 }
1541 #ifdef FEAT_DIFF
1542 /* Correct the first entry for filler lines at the top
1543 * when it won't get updated below. */
1544 if (wp->w_p_diff && bot_start > 0)
1545 wp->w_lines[0].wl_size =
1546 plines_win_nofill(wp, wp->w_topline, TRUE)
1547 + wp->w_topfill;
1548 #endif
1549 }
1550 }
1551 }
1552
1553 /* When starting redraw in the first line, redraw all lines. When
1554 * there is only one window it's probably faster to clear the screen
1555 * first. */
1556 if (mid_start == 0)
1557 {
1558 mid_end = wp->w_height;
1559 if (ONE_WINDOW && !WIN_IS_POPUP(wp))
1560 {
1561 /* Clear the screen when it was not done by win_del_lines() or
1562 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1563 * then. */
1564 if (screen_cleared != TRUE)
1565 screenclear();
1566 /* The screen was cleared, redraw the tab pages line. */
1567 if (redraw_tabline)
1568 draw_tabline();
1569 }
1570 }
1571
1572 /* When win_del_lines() or win_ins_lines() caused the screen to be
1573 * cleared (only happens for the first window) or when screenclear()
1574 * was called directly above, "must_redraw" will have been set to
1575 * NOT_VALID, need to reset it here to avoid redrawing twice. */
1576 if (screen_cleared == TRUE)
1577 must_redraw = 0;
1578 }
1579 else
1580 {
1581 /* Not VALID or INVERTED: redraw all lines. */
1582 mid_start = 0;
1583 mid_end = wp->w_height;
1584 }
1585
1586 if (type == SOME_VALID)
1587 {
1588 /* SOME_VALID: redraw all lines. */
1589 mid_start = 0;
1590 mid_end = wp->w_height;
1591 type = NOT_VALID;
1592 }
1593
1594 /* check if we are updating or removing the inverted part */
1595 if ((VIsual_active && buf == curwin->w_buffer)
1596 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1597 {
1598 linenr_T from, to;
1599
1600 if (VIsual_active)
1601 {
1602 if (VIsual_active
1603 && (VIsual_mode != wp->w_old_visual_mode
1604 || type == INVERTED_ALL))
1605 {
1606 /*
1607 * If the type of Visual selection changed, redraw the whole
1608 * selection. Also when the ownership of the X selection is
1609 * gained or lost.
1610 */
1611 if (curwin->w_cursor.lnum < VIsual.lnum)
1612 {
1613 from = curwin->w_cursor.lnum;
1614 to = VIsual.lnum;
1615 }
1616 else
1617 {
1618 from = VIsual.lnum;
1619 to = curwin->w_cursor.lnum;
1620 }
1621 /* redraw more when the cursor moved as well */
1622 if (wp->w_old_cursor_lnum < from)
1623 from = wp->w_old_cursor_lnum;
1624 if (wp->w_old_cursor_lnum > to)
1625 to = wp->w_old_cursor_lnum;
1626 if (wp->w_old_visual_lnum < from)
1627 from = wp->w_old_visual_lnum;
1628 if (wp->w_old_visual_lnum > to)
1629 to = wp->w_old_visual_lnum;
1630 }
1631 else
1632 {
1633 /*
1634 * Find the line numbers that need to be updated: The lines
1635 * between the old cursor position and the current cursor
1636 * position. Also check if the Visual position changed.
1637 */
1638 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1639 {
1640 from = curwin->w_cursor.lnum;
1641 to = wp->w_old_cursor_lnum;
1642 }
1643 else
1644 {
1645 from = wp->w_old_cursor_lnum;
1646 to = curwin->w_cursor.lnum;
1647 if (from == 0) /* Visual mode just started */
1648 from = to;
1649 }
1650
1651 if (VIsual.lnum != wp->w_old_visual_lnum
1652 || VIsual.col != wp->w_old_visual_col)
1653 {
1654 if (wp->w_old_visual_lnum < from
1655 && wp->w_old_visual_lnum != 0)
1656 from = wp->w_old_visual_lnum;
1657 if (wp->w_old_visual_lnum > to)
1658 to = wp->w_old_visual_lnum;
1659 if (VIsual.lnum < from)
1660 from = VIsual.lnum;
1661 if (VIsual.lnum > to)
1662 to = VIsual.lnum;
1663 }
1664 }
1665
1666 /*
1667 * If in block mode and changed column or curwin->w_curswant:
1668 * update all lines.
1669 * First compute the actual start and end column.
1670 */
1671 if (VIsual_mode == Ctrl_V)
1672 {
1673 colnr_T fromc, toc;
1674 #if defined(FEAT_LINEBREAK)
1675 int save_ve_flags = ve_flags;
1676
1677 if (curwin->w_p_lbr)
1678 ve_flags = VE_ALL;
1679 #endif
1680 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
1681 #if defined(FEAT_LINEBREAK)
1682 ve_flags = save_ve_flags;
1683 #endif
1684 ++toc;
1685 if (curwin->w_curswant == MAXCOL)
1686 toc = MAXCOL;
1687
1688 if (fromc != wp->w_old_cursor_fcol
1689 || toc != wp->w_old_cursor_lcol)
1690 {
1691 if (from > VIsual.lnum)
1692 from = VIsual.lnum;
1693 if (to < VIsual.lnum)
1694 to = VIsual.lnum;
1695 }
1696 wp->w_old_cursor_fcol = fromc;
1697 wp->w_old_cursor_lcol = toc;
1698 }
1699 }
1700 else
1701 {
1702 /* Use the line numbers of the old Visual area. */
1703 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
1704 {
1705 from = wp->w_old_cursor_lnum;
1706 to = wp->w_old_visual_lnum;
1707 }
1708 else
1709 {
1710 from = wp->w_old_visual_lnum;
1711 to = wp->w_old_cursor_lnum;
1712 }
1713 }
1714
1715 /*
1716 * There is no need to update lines above the top of the window.
1717 */
1718 if (from < wp->w_topline)
1719 from = wp->w_topline;
1720
1721 /*
1722 * If we know the value of w_botline, use it to restrict the update to
1723 * the lines that are visible in the window.
1724 */
1725 if (wp->w_valid & VALID_BOTLINE)
1726 {
1727 if (from >= wp->w_botline)
1728 from = wp->w_botline - 1;
1729 if (to >= wp->w_botline)
1730 to = wp->w_botline - 1;
1731 }
1732
1733 /*
1734 * Find the minimal part to be updated.
1735 * Watch out for scrolling that made entries in w_lines[] invalid.
1736 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
1737 * top_end; need to redraw from top_end to the "to" line.
1738 * A middle mouse click with a Visual selection may change the text
1739 * above the Visual area and reset wl_valid, do count these for
1740 * mid_end (in srow).
1741 */
1742 if (mid_start > 0)
1743 {
1744 lnum = wp->w_topline;
1745 idx = 0;
1746 srow = 0;
1747 if (scrolled_down)
1748 mid_start = top_end;
1749 else
1750 mid_start = 0;
1751 while (lnum < from && idx < wp->w_lines_valid) /* find start */
1752 {
1753 if (wp->w_lines[idx].wl_valid)
1754 mid_start += wp->w_lines[idx].wl_size;
1755 else if (!scrolled_down)
1756 srow += wp->w_lines[idx].wl_size;
1757 ++idx;
1758 # ifdef FEAT_FOLDING
1759 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
1760 lnum = wp->w_lines[idx].wl_lnum;
1761 else
1762 # endif
1763 ++lnum;
1764 }
1765 srow += mid_start;
1766 mid_end = wp->w_height;
1767 for ( ; idx < wp->w_lines_valid; ++idx) /* find end */
1768 {
1769 if (wp->w_lines[idx].wl_valid
1770 && wp->w_lines[idx].wl_lnum >= to + 1)
1771 {
1772 /* Only update until first row of this line */
1773 mid_end = srow;
1774 break;
1775 }
1776 srow += wp->w_lines[idx].wl_size;
1777 }
1778 }
1779 }
1780
1781 if (VIsual_active && buf == curwin->w_buffer)
1782 {
1783 wp->w_old_visual_mode = VIsual_mode;
1784 wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
1785 wp->w_old_visual_lnum = VIsual.lnum;
1786 wp->w_old_visual_col = VIsual.col;
1787 wp->w_old_curswant = curwin->w_curswant;
1788 }
1789 else
1790 {
1791 wp->w_old_visual_mode = 0;
1792 wp->w_old_cursor_lnum = 0;
1793 wp->w_old_visual_lnum = 0;
1794 wp->w_old_visual_col = 0;
1795 }
1796
1797 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1798 /* reset got_int, otherwise regexp won't work */
1799 save_got_int = got_int;
1800 got_int = 0;
1801 #endif
1802 #ifdef SYN_TIME_LIMIT
1803 /* Set the time limit to 'redrawtime'. */
1804 profile_setlimit(p_rdt, &syntax_tm);
1805 syn_set_timeout(&syntax_tm);
1806 #endif
1807 #ifdef FEAT_FOLDING
1808 win_foldinfo.fi_level = 0;
1809 #endif
1810
1811 #ifdef FEAT_MENU
1812 /*
1813 * Draw the window toolbar, if there is one.
1814 * TODO: only when needed.
1815 */
1816 if (winbar_height(wp) > 0)
1817 redraw_win_toolbar(wp);
1818 #endif
1819
1820 /*
1821 * Update all the window rows.
1822 */
1823 idx = 0; /* first entry in w_lines[].wl_size */
1824 row = 0;
1825 srow = 0;
1826 lnum = wp->w_topline; /* first line shown in window */
1827 for (;;)
1828 {
1829 /* stop updating when reached the end of the window (check for _past_
1830 * the end of the window is at the end of the loop) */
1831 if (row == wp->w_height)
1832 {
1833 didline = TRUE;
1834 break;
1835 }
1836
1837 /* stop updating when hit the end of the file */
1838 if (lnum > buf->b_ml.ml_line_count)
1839 {
1840 eof = TRUE;
1841 break;
1842 }
1843
1844 /* Remember the starting row of the line that is going to be dealt
1845 * with. It is used further down when the line doesn't fit. */
1846 srow = row;
1847
1848 /*
1849 * Update a line when it is in an area that needs updating, when it
1850 * has changes or w_lines[idx] is invalid.
1851 * "bot_start" may be halfway a wrapped line after using
1852 * win_del_lines(), check if the current line includes it.
1853 * When syntax folding is being used, the saved syntax states will
1854 * already have been updated, we can't see where the syntax state is
1855 * the same again, just update until the end of the window.
1856 */
1857 if (row < top_end
1858 || (row >= mid_start && row < mid_end)
1859 #ifdef FEAT_SEARCH_EXTRA
1860 || top_to_mod
1861 #endif
1862 || idx >= wp->w_lines_valid
1863 || (row + wp->w_lines[idx].wl_size > bot_start)
1864 || (mod_top != 0
1865 && (lnum == mod_top
1866 || (lnum >= mod_top
1867 && (lnum < mod_bot
1868 #ifdef FEAT_SYN_HL
1869 || did_update == DID_FOLD
1870 || (did_update == DID_LINE
1871 && syntax_present(wp)
1872 && (
1873 # ifdef FEAT_FOLDING
1874 (foldmethodIsSyntax(wp)
1875 && hasAnyFolding(wp)) ||
1876 # endif
1877 syntax_check_changed(lnum)))
1878 #endif
1879 #ifdef FEAT_SEARCH_EXTRA
1880 /* match in fixed position might need redraw
1881 * if lines were inserted or deleted */
1882 || (wp->w_match_head != NULL
1883 && buf->b_mod_xlines != 0)
1884 #endif
1885 )))))
1886 {
1887 #ifdef FEAT_SEARCH_EXTRA
1888 if (lnum == mod_top)
1889 top_to_mod = FALSE;
1890 #endif
1891
1892 /*
1893 * When at start of changed lines: May scroll following lines
1894 * up or down to minimize redrawing.
1895 * Don't do this when the change continues until the end.
1896 * Don't scroll when dollar_vcol >= 0, keep the "$".
1897 */
1898 if (lnum == mod_top
1899 && mod_bot != MAXLNUM
1900 && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
1901 {
1902 int old_rows = 0;
1903 int new_rows = 0;
1904 int xtra_rows;
1905 linenr_T l;
1906
1907 /* Count the old number of window rows, using w_lines[], which
1908 * should still contain the sizes for the lines as they are
1909 * currently displayed. */
1910 for (i = idx; i < wp->w_lines_valid; ++i)
1911 {
1912 /* Only valid lines have a meaningful wl_lnum. Invalid
1913 * lines are part of the changed area. */
1914 if (wp->w_lines[i].wl_valid
1915 && wp->w_lines[i].wl_lnum == mod_bot)
1916 break;
1917 old_rows += wp->w_lines[i].wl_size;
1918 #ifdef FEAT_FOLDING
1919 if (wp->w_lines[i].wl_valid
1920 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
1921 {
1922 /* Must have found the last valid entry above mod_bot.
1923 * Add following invalid entries. */
1924 ++i;
1925 while (i < wp->w_lines_valid
1926 && !wp->w_lines[i].wl_valid)
1927 old_rows += wp->w_lines[i++].wl_size;
1928 break;
1929 }
1930 #endif
1931 }
1932
1933 if (i >= wp->w_lines_valid)
1934 {
1935 /* We can't find a valid line below the changed lines,
1936 * need to redraw until the end of the window.
1937 * Inserting/deleting lines has no use. */
1938 bot_start = 0;
1939 }
1940 else
1941 {
1942 /* Able to count old number of rows: Count new window
1943 * rows, and may insert/delete lines */
1944 j = idx;
1945 for (l = lnum; l < mod_bot; ++l)
1946 {
1947 #ifdef FEAT_FOLDING
1948 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
1949 ++new_rows;
1950 else
1951 #endif
1952 #ifdef FEAT_DIFF
1953 if (l == wp->w_topline)
1954 new_rows += plines_win_nofill(wp, l, TRUE)
1955 + wp->w_topfill;
1956 else
1957 #endif
1958 new_rows += plines_win(wp, l, TRUE);
1959 ++j;
1960 if (new_rows > wp->w_height - row - 2)
1961 {
1962 /* it's getting too much, must redraw the rest */
1963 new_rows = 9999;
1964 break;
1965 }
1966 }
1967 xtra_rows = new_rows - old_rows;
1968 if (xtra_rows < 0)
1969 {
1970 /* May scroll text up. If there is not enough
1971 * remaining text or scrolling fails, must redraw the
1972 * rest. If scrolling works, must redraw the text
1973 * below the scrolled text. */
1974 if (row - xtra_rows >= wp->w_height - 2)
1975 mod_bot = MAXLNUM;
1976 else
1977 {
1978 check_for_delay(FALSE);
1979 if (win_del_lines(wp, row,
1980 -xtra_rows, FALSE, FALSE, 0) == FAIL)
1981 mod_bot = MAXLNUM;
1982 else
1983 bot_start = wp->w_height + xtra_rows;
1984 }
1985 }
1986 else if (xtra_rows > 0)
1987 {
1988 /* May scroll text down. If there is not enough
1989 * remaining text of scrolling fails, must redraw the
1990 * rest. */
1991 if (row + xtra_rows >= wp->w_height - 2)
1992 mod_bot = MAXLNUM;
1993 else
1994 {
1995 check_for_delay(FALSE);
1996 if (win_ins_lines(wp, row + old_rows,
1997 xtra_rows, FALSE, FALSE) == FAIL)
1998 mod_bot = MAXLNUM;
1999 else if (top_end > row + old_rows)
2000 /* Scrolled the part at the top that requires
2001 * updating down. */
2002 top_end += xtra_rows;
2003 }
2004 }
2005
2006 /* When not updating the rest, may need to move w_lines[]
2007 * entries. */
2008 if (mod_bot != MAXLNUM && i != j)
2009 {
2010 if (j < i)
2011 {
2012 int x = row + new_rows;
2013
2014 /* move entries in w_lines[] upwards */
2015 for (;;)
2016 {
2017 /* stop at last valid entry in w_lines[] */
2018 if (i >= wp->w_lines_valid)
2019 {
2020 wp->w_lines_valid = j;
2021 break;
2022 }
2023 wp->w_lines[j] = wp->w_lines[i];
2024 /* stop at a line that won't fit */
2025 if (x + (int)wp->w_lines[j].wl_size
2026 > wp->w_height)
2027 {
2028 wp->w_lines_valid = j + 1;
2029 break;
2030 }
2031 x += wp->w_lines[j++].wl_size;
2032 ++i;
2033 }
2034 if (bot_start > x)
2035 bot_start = x;
2036 }
2037 else /* j > i */
2038 {
2039 /* move entries in w_lines[] downwards */
2040 j -= i;
2041 wp->w_lines_valid += j;
2042 if (wp->w_lines_valid > wp->w_height)
2043 wp->w_lines_valid = wp->w_height;
2044 for (i = wp->w_lines_valid; i - j >= idx; --i)
2045 wp->w_lines[i] = wp->w_lines[i - j];
2046
2047 /* The w_lines[] entries for inserted lines are
2048 * now invalid, but wl_size may be used above.
2049 * Reset to zero. */
2050 while (i >= idx)
2051 {
2052 wp->w_lines[i].wl_size = 0;
2053 wp->w_lines[i--].wl_valid = FALSE;
2054 }
2055 }
2056 }
2057 }
2058 }
2059
2060 #ifdef FEAT_FOLDING
2061 /*
2062 * When lines are folded, display one line for all of them.
2063 * Otherwise, display normally (can be several display lines when
2064 * 'wrap' is on).
2065 */
2066 fold_count = foldedCount(wp, lnum, &win_foldinfo);
2067 if (fold_count != 0)
2068 {
2069 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2070 ++row;
2071 --fold_count;
2072 wp->w_lines[idx].wl_folded = TRUE;
2073 wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
2074 # ifdef FEAT_SYN_HL
2075 did_update = DID_FOLD;
2076 # endif
2077 }
2078 else
2079 #endif
2080 if (idx < wp->w_lines_valid
2081 && wp->w_lines[idx].wl_valid
2082 && wp->w_lines[idx].wl_lnum == lnum
2083 && lnum > wp->w_topline
2084 && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
2085 && !WIN_IS_POPUP(wp)
2086 && srow + wp->w_lines[idx].wl_size > wp->w_height
2087 #ifdef FEAT_DIFF
2088 && diff_check_fill(wp, lnum) == 0
2089 #endif
2090 )
2091 {
2092 /* This line is not going to fit. Don't draw anything here,
2093 * will draw "@ " lines below. */
2094 row = wp->w_height + 1;
2095 }
2096 else
2097 {
2098 #ifdef FEAT_SEARCH_EXTRA
2099 prepare_search_hl(wp, &search_hl, lnum);
2100 #endif
2101 #ifdef FEAT_SYN_HL
2102 /* Let the syntax stuff know we skipped a few lines. */
2103 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
2104 && syntax_present(wp))
2105 syntax_end_parsing(syntax_last_parsed + 1);
2106 #endif
2107
2108 /*
2109 * Display one line.
2110 */
2111 row = win_line(wp, lnum, srow, wp->w_height,
2112 mod_top == 0, FALSE);
2113
2114 #ifdef FEAT_FOLDING
2115 wp->w_lines[idx].wl_folded = FALSE;
2116 wp->w_lines[idx].wl_lastlnum = lnum;
2117 #endif
2118 #ifdef FEAT_SYN_HL
2119 did_update = DID_LINE;
2120 syntax_last_parsed = lnum;
2121 #endif
2122 }
2123
2124 wp->w_lines[idx].wl_lnum = lnum;
2125 wp->w_lines[idx].wl_valid = TRUE;
2126
2127 /* Past end of the window or end of the screen. Note that after
2128 * resizing wp->w_height may be end up too big. That's a problem
2129 * elsewhere, but prevent a crash here. */
2130 if (row > wp->w_height || row + wp->w_winrow >= Rows)
2131 {
2132 /* we may need the size of that too long line later on */
2133 if (dollar_vcol == -1)
2134 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
2135 ++idx;
2136 break;
2137 }
2138 if (dollar_vcol == -1)
2139 wp->w_lines[idx].wl_size = row - srow;
2140 ++idx;
2141 #ifdef FEAT_FOLDING
2142 lnum += fold_count + 1;
2143 #else
2144 ++lnum;
2145 #endif
2146 }
2147 else
2148 {
2149 if (wp->w_p_rnu)
2150 {
2151 #ifdef FEAT_FOLDING
2152 // 'relativenumber' set: The text doesn't need to be drawn, but
2153 // the number column nearly always does.
2154 fold_count = foldedCount(wp, lnum, &win_foldinfo);
2155 if (fold_count != 0)
2156 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2157 else
2158 #endif
2159 (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE);
2160 }
2161
2162 // This line does not need to be drawn, advance to the next one.
2163 row += wp->w_lines[idx++].wl_size;
2164 if (row > wp->w_height) /* past end of screen */
2165 break;
2166 #ifdef FEAT_FOLDING
2167 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
2168 #else
2169 ++lnum;
2170 #endif
2171 #ifdef FEAT_SYN_HL
2172 did_update = DID_NONE;
2173 #endif
2174 }
2175
2176 if (lnum > buf->b_ml.ml_line_count)
2177 {
2178 eof = TRUE;
2179 break;
2180 }
2181 }
2182 /*
2183 * End of loop over all window lines.
2184 */
2185
2186 #ifdef FEAT_VTP
2187 /* Rewrite the character at the end of the screen line. */
2188 if (use_vtp())
2189 {
2190 int i;
2191
2192 for (i = 0; i < Rows; ++i)
2193 if (enc_utf8)
2194 if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
2195 LineOffset[i] + screen_Columns) > 1)
2196 screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
2197 else
2198 screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
2199 else
2200 screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
2201 }
2202 #endif
2203
2204 if (idx > wp->w_lines_valid)
2205 wp->w_lines_valid = idx;
2206
2207 #ifdef FEAT_SYN_HL
2208 /*
2209 * Let the syntax stuff know we stop parsing here.
2210 */
2211 if (syntax_last_parsed != 0 && syntax_present(wp))
2212 syntax_end_parsing(syntax_last_parsed + 1);
2213 #endif
2214
2215 /*
2216 * If we didn't hit the end of the file, and we didn't finish the last
2217 * line we were working on, then the line didn't fit.
2218 */
2219 wp->w_empty_rows = 0;
2220 #ifdef FEAT_DIFF
2221 wp->w_filler_rows = 0;
2222 #endif
2223 if (!eof && !didline)
2224 {
2225 if (lnum == wp->w_topline)
2226 {
2227 /*
2228 * Single line that does not fit!
2229 * Don't overwrite it, it can be edited.
2230 */
2231 wp->w_botline = lnum + 1;
2232 }
2233 #ifdef FEAT_DIFF
2234 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
2235 {
2236 /* Window ends in filler lines. */
2237 wp->w_botline = lnum;
2238 wp->w_filler_rows = wp->w_height - srow;
2239 }
2240 #endif
2241 #ifdef FEAT_TEXT_PROP
2242 else if (WIN_IS_POPUP(wp))
2243 {
2244 // popup line that doesn't fit is left as-is
2245 wp->w_botline = lnum;
2246 }
2247 #endif
2248 else if (dy_flags & DY_TRUNCATE) /* 'display' has "truncate" */
2249 {
2250 int scr_row = W_WINROW(wp) + wp->w_height - 1;
2251
2252 /*
2253 * Last line isn't finished: Display "@@@" in the last screen line.
2254 */
2255 screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
2256 HL_ATTR(HLF_AT));
2257 screen_fill(scr_row, scr_row + 1,
2258 (int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
2259 '@', ' ', HL_ATTR(HLF_AT));
2260 set_empty_rows(wp, srow);
2261 wp->w_botline = lnum;
2262 }
2263 else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */
2264 {
2265 /*
2266 * Last line isn't finished: Display "@@@" at the end.
2267 */
2268 screen_fill(W_WINROW(wp) + wp->w_height - 1,
2269 W_WINROW(wp) + wp->w_height,
2270 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
2271 '@', '@', HL_ATTR(HLF_AT));
2272 set_empty_rows(wp, srow);
2273 wp->w_botline = lnum;
2274 }
2275 else
2276 {
2277 win_draw_end(wp, '@', ' ', TRUE, srow, wp->w_height, HLF_AT);
2278 wp->w_botline = lnum;
2279 }
2280 }
2281 else
2282 {
2283 draw_vsep_win(wp, row);
2284 if (eof) /* we hit the end of the file */
2285 {
2286 wp->w_botline = buf->b_ml.ml_line_count + 1;
2287 #ifdef FEAT_DIFF
2288 j = diff_check_fill(wp, wp->w_botline);
2289 if (j > 0 && !wp->w_botfill)
2290 {
2291 // Display filler lines at the end of the file.
2292 if (char2cells(fill_diff) > 1)
2293 i = '-';
2294 else
2295 i = fill_diff;
2296 if (row + j > wp->w_height)
2297 j = wp->w_height - row;
2298 win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED);
2299 row += j;
2300 }
2301 #endif
2302 }
2303 else if (dollar_vcol == -1)
2304 wp->w_botline = lnum;
2305
2306 // Make sure the rest of the screen is blank
2307 // put '~'s on rows that aren't part of the file.
2308 win_draw_end(wp, WIN_IS_POPUP(wp) ? ' ' : '~',
2309 ' ', FALSE, row, wp->w_height, HLF_EOB);
2310 }
2311
2312 #ifdef SYN_TIME_LIMIT
2313 syn_set_timeout(NULL);
2314 #endif
2315
2316 /* Reset the type of redrawing required, the window has been updated. */
2317 wp->w_redr_type = 0;
2318 #ifdef FEAT_DIFF
2319 wp->w_old_topfill = wp->w_topfill;
2320 wp->w_old_botfill = wp->w_botfill;
2321 #endif
2322
2323 if (dollar_vcol == -1)
2324 {
2325 /*
2326 * There is a trick with w_botline. If we invalidate it on each
2327 * change that might modify it, this will cause a lot of expensive
2328 * calls to plines() in update_topline() each time. Therefore the
2329 * value of w_botline is often approximated, and this value is used to
2330 * compute the value of w_topline. If the value of w_botline was
2331 * wrong, check that the value of w_topline is correct (cursor is on
2332 * the visible part of the text). If it's not, we need to redraw
2333 * again. Mostly this just means scrolling up a few lines, so it
2334 * doesn't look too bad. Only do this for the current window (where
2335 * changes are relevant).
2336 */
2337 wp->w_valid |= VALID_BOTLINE;
2338 if (wp == curwin && wp->w_botline != old_botline && !recursive)
2339 {
2340 recursive = TRUE;
2341 curwin->w_valid &= ~VALID_TOPLINE;
2342 update_topline(); /* may invalidate w_botline again */
2343 if (must_redraw != 0)
2344 {
2345 /* Don't update for changes in buffer again. */
2346 i = curbuf->b_mod_set;
2347 curbuf->b_mod_set = FALSE;
2348 win_update(curwin);
2349 must_redraw = 0;
2350 curbuf->b_mod_set = i;
2351 }
2352 recursive = FALSE;
2353 }
2354 }
2355
2356 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2357 /* restore got_int, unless CTRL-C was hit while redrawing */
2358 if (!got_int)
2359 got_int = save_got_int;
2360 #endif
2361 } 121 }
2362 122
2363 /* 123 /*
2364 * Call screen_fill() with the columns adjusted for 'rightleft' if needed. 124 * Call screen_fill() with the columns adjusted for 'rightleft' if needed.
2365 * Return the new offset. 125 * Return the new offset.
2397 /* 157 /*
2398 * Clear lines near the end the window and mark the unused lines with "c1". 158 * Clear lines near the end the window and mark the unused lines with "c1".
2399 * use "c2" as the filler character. 159 * use "c2" as the filler character.
2400 * When "draw_margin" is TRUE then draw the sign, fold and number columns. 160 * When "draw_margin" is TRUE then draw the sign, fold and number columns.
2401 */ 161 */
2402 static void 162 void
2403 win_draw_end( 163 win_draw_end(
2404 win_T *wp, 164 win_T *wp,
2405 int c1, 165 int c1,
2406 int c2, 166 int c2,
2407 int draw_margin, 167 int draw_margin,
2457 } 217 }
2458 218
2459 set_empty_rows(wp, row); 219 set_empty_rows(wp, row);
2460 } 220 }
2461 221
2462 #ifdef FEAT_SYN_HL 222 #if defined(FEAT_FOLDING) || defined(PROTO)
2463 /*
2464 * Advance **color_cols and return TRUE when there are columns to draw.
2465 */
2466 static int
2467 advance_color_col(int vcol, int **color_cols)
2468 {
2469 while (**color_cols >= 0 && vcol > **color_cols)
2470 ++*color_cols;
2471 return (**color_cols >= 0);
2472 }
2473 #endif
2474
2475 #if defined(FEAT_MENU) || defined(FEAT_FOLDING)
2476 /*
2477 * Copy "text" to ScreenLines using "attr".
2478 * Returns the next screen column.
2479 */
2480 static int
2481 text_to_screenline(win_T *wp, char_u *text, int col)
2482 {
2483 int off = (int)(current_ScreenLine - ScreenLines);
2484
2485 if (has_mbyte)
2486 {
2487 int cells;
2488 int u8c, u8cc[MAX_MCO];
2489 int i;
2490 int idx;
2491 int c_len;
2492 char_u *p;
2493 # ifdef FEAT_ARABIC
2494 int prev_c = 0; /* previous Arabic character */
2495 int prev_c1 = 0; /* first composing char for prev_c */
2496 # endif
2497
2498 # ifdef FEAT_RIGHTLEFT
2499 if (wp->w_p_rl)
2500 idx = off;
2501 else
2502 # endif
2503 idx = off + col;
2504
2505 /* Store multibyte characters in ScreenLines[] et al. correctly. */
2506 for (p = text; *p != NUL; )
2507 {
2508 cells = (*mb_ptr2cells)(p);
2509 c_len = (*mb_ptr2len)(p);
2510 if (col + cells > wp->w_width
2511 # ifdef FEAT_RIGHTLEFT
2512 - (wp->w_p_rl ? col : 0)
2513 # endif
2514 )
2515 break;
2516 ScreenLines[idx] = *p;
2517 if (enc_utf8)
2518 {
2519 u8c = utfc_ptr2char(p, u8cc);
2520 if (*p < 0x80 && u8cc[0] == 0)
2521 {
2522 ScreenLinesUC[idx] = 0;
2523 #ifdef FEAT_ARABIC
2524 prev_c = u8c;
2525 #endif
2526 }
2527 else
2528 {
2529 #ifdef FEAT_ARABIC
2530 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
2531 {
2532 /* Do Arabic shaping. */
2533 int pc, pc1, nc;
2534 int pcc[MAX_MCO];
2535 int firstbyte = *p;
2536
2537 /* The idea of what is the previous and next
2538 * character depends on 'rightleft'. */
2539 if (wp->w_p_rl)
2540 {
2541 pc = prev_c;
2542 pc1 = prev_c1;
2543 nc = utf_ptr2char(p + c_len);
2544 prev_c1 = u8cc[0];
2545 }
2546 else
2547 {
2548 pc = utfc_ptr2char(p + c_len, pcc);
2549 nc = prev_c;
2550 pc1 = pcc[0];
2551 }
2552 prev_c = u8c;
2553
2554 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
2555 pc, pc1, nc);
2556 ScreenLines[idx] = firstbyte;
2557 }
2558 else
2559 prev_c = u8c;
2560 #endif
2561 /* Non-BMP character: display as ? or fullwidth ?. */
2562 ScreenLinesUC[idx] = u8c;
2563 for (i = 0; i < Screen_mco; ++i)
2564 {
2565 ScreenLinesC[i][idx] = u8cc[i];
2566 if (u8cc[i] == 0)
2567 break;
2568 }
2569 }
2570 if (cells > 1)
2571 ScreenLines[idx + 1] = 0;
2572 }
2573 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
2574 /* double-byte single width character */
2575 ScreenLines2[idx] = p[1];
2576 else if (cells > 1)
2577 /* double-width character */
2578 ScreenLines[idx + 1] = p[1];
2579 col += cells;
2580 idx += cells;
2581 p += c_len;
2582 }
2583 }
2584 else
2585 {
2586 int len = (int)STRLEN(text);
2587
2588 if (len > wp->w_width - col)
2589 len = wp->w_width - col;
2590 if (len > 0)
2591 {
2592 #ifdef FEAT_RIGHTLEFT
2593 if (wp->w_p_rl)
2594 mch_memmove(current_ScreenLine, text, len);
2595 else
2596 #endif
2597 mch_memmove(current_ScreenLine + col, text, len);
2598 col += len;
2599 }
2600 }
2601 return col;
2602 }
2603 #endif
2604
2605 #ifdef FEAT_FOLDING
2606 /* 223 /*
2607 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much 224 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
2608 * space is available for window "wp", minus "col". 225 * space is available for window "wp", minus "col".
2609 */ 226 */
2610 static int 227 int
2611 compute_foldcolumn(win_T *wp, int col) 228 compute_foldcolumn(win_T *wp, int col)
2612 { 229 {
2613 int fdc = wp->w_p_fdc; 230 int fdc = wp->w_p_fdc;
2614 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw; 231 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
2615 int wwidth = wp->w_width; 232 int wwidth = wp->w_width;
2618 fdc = wwidth - (col + wmw); 235 fdc = wwidth - (col + wmw);
2619 return fdc; 236 return fdc;
2620 } 237 }
2621 238
2622 /* 239 /*
2623 * Display one folded line.
2624 */
2625 static void
2626 fold_line(
2627 win_T *wp,
2628 long fold_count,
2629 foldinfo_T *foldinfo,
2630 linenr_T lnum,
2631 int row)
2632 {
2633 char_u buf[FOLD_TEXT_LEN];
2634 pos_T *top, *bot;
2635 linenr_T lnume = lnum + fold_count - 1;
2636 int len;
2637 char_u *text;
2638 int fdc;
2639 int col;
2640 int txtcol;
2641 int off = (int)(current_ScreenLine - ScreenLines);
2642 int ri;
2643
2644 /* Build the fold line:
2645 * 1. Add the cmdwin_type for the command-line window
2646 * 2. Add the 'foldcolumn'
2647 * 3. Add the 'number' or 'relativenumber' column
2648 * 4. Compose the text
2649 * 5. Add the text
2650 * 6. set highlighting for the Visual area an other text
2651 */
2652 col = 0;
2653
2654 /*
2655 * 1. Add the cmdwin_type for the command-line window
2656 * Ignores 'rightleft', this window is never right-left.
2657 */
2658 #ifdef FEAT_CMDWIN
2659 if (cmdwin_type != 0 && wp == curwin)
2660 {
2661 ScreenLines[off] = cmdwin_type;
2662 ScreenAttrs[off] = HL_ATTR(HLF_AT);
2663 if (enc_utf8)
2664 ScreenLinesUC[off] = 0;
2665 ++col;
2666 }
2667 #endif
2668
2669 /*
2670 * 2. Add the 'foldcolumn'
2671 * Reduce the width when there is not enough space.
2672 */
2673 fdc = compute_foldcolumn(wp, col);
2674 if (fdc > 0)
2675 {
2676 fill_foldcolumn(buf, wp, TRUE, lnum);
2677 #ifdef FEAT_RIGHTLEFT
2678 if (wp->w_p_rl)
2679 {
2680 int i;
2681
2682 copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
2683 HL_ATTR(HLF_FC));
2684 /* reverse the fold column */
2685 for (i = 0; i < fdc; ++i)
2686 ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
2687 }
2688 else
2689 #endif
2690 copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
2691 col += fdc;
2692 }
2693
2694 #ifdef FEAT_RIGHTLEFT
2695 # define RL_MEMSET(p, v, l) \
2696 do { \
2697 if (wp->w_p_rl) \
2698 for (ri = 0; ri < l; ++ri) \
2699 ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \
2700 else \
2701 for (ri = 0; ri < l; ++ri) \
2702 ScreenAttrs[off + (p) + ri] = v; \
2703 } while (0)
2704 #else
2705 # define RL_MEMSET(p, v, l) \
2706 do { \
2707 for (ri = 0; ri < l; ++ri) \
2708 ScreenAttrs[off + (p) + ri] = v; \
2709 } while (0)
2710 #endif
2711
2712 /* Set all attributes of the 'number' or 'relativenumber' column and the
2713 * text */
2714 RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
2715
2716 #ifdef FEAT_SIGNS
2717 /* If signs are being displayed, add two spaces. */
2718 if (signcolumn_on(wp))
2719 {
2720 len = wp->w_width - col;
2721 if (len > 0)
2722 {
2723 if (len > 2)
2724 len = 2;
2725 # ifdef FEAT_RIGHTLEFT
2726 if (wp->w_p_rl)
2727 /* the line number isn't reversed */
2728 copy_text_attr(off + wp->w_width - len - col,
2729 (char_u *)" ", len, HL_ATTR(HLF_FL));
2730 else
2731 # endif
2732 copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL));
2733 col += len;
2734 }
2735 }
2736 #endif
2737
2738 /*
2739 * 3. Add the 'number' or 'relativenumber' column
2740 */
2741 if (wp->w_p_nu || wp->w_p_rnu)
2742 {
2743 len = wp->w_width - col;
2744 if (len > 0)
2745 {
2746 int w = number_width(wp);
2747 long num;
2748 char *fmt = "%*ld ";
2749
2750 if (len > w + 1)
2751 len = w + 1;
2752
2753 if (wp->w_p_nu && !wp->w_p_rnu)
2754 /* 'number' + 'norelativenumber' */
2755 num = (long)lnum;
2756 else
2757 {
2758 /* 'relativenumber', don't use negative numbers */
2759 num = labs((long)get_cursor_rel_lnum(wp, lnum));
2760 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
2761 {
2762 /* 'number' + 'relativenumber': cursor line shows absolute
2763 * line number */
2764 num = lnum;
2765 fmt = "%-*ld ";
2766 }
2767 }
2768
2769 sprintf((char *)buf, fmt, w, num);
2770 #ifdef FEAT_RIGHTLEFT
2771 if (wp->w_p_rl)
2772 /* the line number isn't reversed */
2773 copy_text_attr(off + wp->w_width - len - col, buf, len,
2774 HL_ATTR(HLF_FL));
2775 else
2776 #endif
2777 copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL));
2778 col += len;
2779 }
2780 }
2781
2782 /*
2783 * 4. Compose the folded-line string with 'foldtext', if set.
2784 */
2785 text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
2786
2787 txtcol = col; /* remember where text starts */
2788
2789 /*
2790 * 5. move the text to current_ScreenLine. Fill up with "fill_fold".
2791 * Right-left text is put in columns 0 - number-col, normal text is put
2792 * in columns number-col - window-width.
2793 */
2794 col = text_to_screenline(wp, text, col);
2795
2796 /* Fill the rest of the line with the fold filler */
2797 #ifdef FEAT_RIGHTLEFT
2798 if (wp->w_p_rl)
2799 col -= txtcol;
2800 #endif
2801 while (col < wp->w_width
2802 #ifdef FEAT_RIGHTLEFT
2803 - (wp->w_p_rl ? txtcol : 0)
2804 #endif
2805 )
2806 {
2807 if (enc_utf8)
2808 {
2809 if (fill_fold >= 0x80)
2810 {
2811 ScreenLinesUC[off + col] = fill_fold;
2812 ScreenLinesC[0][off + col] = 0;
2813 ScreenLines[off + col] = 0x80; /* avoid storing zero */
2814 }
2815 else
2816 {
2817 ScreenLinesUC[off + col] = 0;
2818 ScreenLines[off + col] = fill_fold;
2819 }
2820 col++;
2821 }
2822 else
2823 ScreenLines[off + col++] = fill_fold;
2824 }
2825
2826 if (text != buf)
2827 vim_free(text);
2828
2829 /*
2830 * 6. set highlighting for the Visual area an other text.
2831 * If all folded lines are in the Visual area, highlight the line.
2832 */
2833 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
2834 {
2835 if (LTOREQ_POS(curwin->w_cursor, VIsual))
2836 {
2837 /* Visual is after curwin->w_cursor */
2838 top = &curwin->w_cursor;
2839 bot = &VIsual;
2840 }
2841 else
2842 {
2843 /* Visual is before curwin->w_cursor */
2844 top = &VIsual;
2845 bot = &curwin->w_cursor;
2846 }
2847 if (lnum >= top->lnum
2848 && lnume <= bot->lnum
2849 && (VIsual_mode != 'v'
2850 || ((lnum > top->lnum
2851 || (lnum == top->lnum
2852 && top->col == 0))
2853 && (lnume < bot->lnum
2854 || (lnume == bot->lnum
2855 && (bot->col - (*p_sel == 'e'))
2856 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
2857 {
2858 if (VIsual_mode == Ctrl_V)
2859 {
2860 /* Visual block mode: highlight the chars part of the block */
2861 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width)
2862 {
2863 if (wp->w_old_cursor_lcol != MAXCOL
2864 && wp->w_old_cursor_lcol + txtcol
2865 < (colnr_T)wp->w_width)
2866 len = wp->w_old_cursor_lcol;
2867 else
2868 len = wp->w_width - txtcol;
2869 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V),
2870 len - (int)wp->w_old_cursor_fcol);
2871 }
2872 }
2873 else
2874 {
2875 /* Set all attributes of the text */
2876 RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol);
2877 }
2878 }
2879 }
2880
2881 #ifdef FEAT_SYN_HL
2882 /* Show colorcolumn in the fold line, but let cursorcolumn override it. */
2883 if (wp->w_p_cc_cols)
2884 {
2885 int i = 0;
2886 int j = wp->w_p_cc_cols[i];
2887 int old_txtcol = txtcol;
2888
2889 while (j > -1)
2890 {
2891 txtcol += j;
2892 if (wp->w_p_wrap)
2893 txtcol -= wp->w_skipcol;
2894 else
2895 txtcol -= wp->w_leftcol;
2896 if (txtcol >= 0 && txtcol < wp->w_width)
2897 ScreenAttrs[off + txtcol] = hl_combine_attr(
2898 ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC));
2899 txtcol = old_txtcol;
2900 j = wp->w_p_cc_cols[++i];
2901 }
2902 }
2903
2904 /* Show 'cursorcolumn' in the fold line. */
2905 if (wp->w_p_cuc)
2906 {
2907 txtcol += wp->w_virtcol;
2908 if (wp->w_p_wrap)
2909 txtcol -= wp->w_skipcol;
2910 else
2911 txtcol -= wp->w_leftcol;
2912 if (txtcol >= 0 && txtcol < wp->w_width)
2913 ScreenAttrs[off + txtcol] = hl_combine_attr(
2914 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC));
2915 }
2916 #endif
2917
2918 screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
2919 (int)wp->w_width, 0);
2920
2921 /*
2922 * Update w_cline_height and w_cline_folded if the cursor line was
2923 * updated (saves a call to plines() later).
2924 */
2925 if (wp == curwin
2926 && lnum <= curwin->w_cursor.lnum
2927 && lnume >= curwin->w_cursor.lnum)
2928 {
2929 curwin->w_cline_row = row;
2930 curwin->w_cline_height = 1;
2931 curwin->w_cline_folded = TRUE;
2932 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
2933 }
2934 }
2935
2936 /*
2937 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
2938 */
2939 static void
2940 copy_text_attr(
2941 int off,
2942 char_u *buf,
2943 int len,
2944 int attr)
2945 {
2946 int i;
2947
2948 mch_memmove(ScreenLines + off, buf, (size_t)len);
2949 if (enc_utf8)
2950 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
2951 for (i = 0; i < len; ++i)
2952 ScreenAttrs[off + i] = attr;
2953 }
2954
2955 /*
2956 * Fill the foldcolumn at "p" for window "wp". 240 * Fill the foldcolumn at "p" for window "wp".
2957 * Only to be called when 'foldcolumn' > 0. 241 * Only to be called when 'foldcolumn' > 0.
2958 */ 242 */
2959 static void 243 void
2960 fill_foldcolumn( 244 fill_foldcolumn(
2961 char_u *p, 245 char_u *p,
2962 win_T *wp, 246 win_T *wp,
2963 int closed, /* TRUE of FALSE */ 247 int closed, /* TRUE of FALSE */
2964 linenr_T lnum) /* current line number */ 248 linenr_T lnum) /* current line number */
3001 } 285 }
3002 if (closed) 286 if (closed)
3003 p[i >= fdc ? i - 1 : i] = '+'; 287 p[i >= fdc ? i - 1 : i] = '+';
3004 } 288 }
3005 #endif /* FEAT_FOLDING */ 289 #endif /* FEAT_FOLDING */
3006
3007 #ifdef FEAT_TEXT_PROP
3008 static textprop_T *current_text_props = NULL;
3009 static buf_T *current_buf = NULL;
3010
3011 static int
3012 text_prop_compare(const void *s1, const void *s2)
3013 {
3014 int idx1, idx2;
3015 proptype_T *pt1, *pt2;
3016 colnr_T col1, col2;
3017
3018 idx1 = *(int *)s1;
3019 idx2 = *(int *)s2;
3020 pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type);
3021 pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type);
3022 if (pt1 == pt2)
3023 return 0;
3024 if (pt1 == NULL)
3025 return -1;
3026 if (pt2 == NULL)
3027 return 1;
3028 if (pt1->pt_priority != pt2->pt_priority)
3029 return pt1->pt_priority > pt2->pt_priority ? 1 : -1;
3030 col1 = current_text_props[idx1].tp_col;
3031 col2 = current_text_props[idx2].tp_col;
3032 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1;
3033 }
3034 #endif
3035
3036 #ifdef FEAT_SIGNS
3037 /*
3038 * Get information needed to display the sign in line 'lnum' in window 'wp'.
3039 * If 'nrcol' is TRUE, the sign is going to be displayed in the number column.
3040 * Otherwise the sign is going to be displayed in the sign column.
3041 */
3042 static void
3043 get_sign_display_info(
3044 int nrcol,
3045 win_T *wp,
3046 linenr_T lnum UNUSED,
3047 sign_attrs_T *sattr,
3048 int wcr_attr,
3049 int row,
3050 int startrow,
3051 int filler_lines UNUSED,
3052 int filler_todo UNUSED,
3053 int *c_extrap,
3054 int *c_finalp,
3055 char_u *extra,
3056 char_u **pp_extra,
3057 int *n_extrap,
3058 int *char_attrp)
3059 {
3060 int text_sign;
3061 # ifdef FEAT_SIGN_ICONS
3062 int icon_sign;
3063 # endif
3064
3065 // Draw two cells with the sign value or blank.
3066 *c_extrap = ' ';
3067 *c_finalp = NUL;
3068 if (nrcol)
3069 *n_extrap = number_width(wp) + 1;
3070 else
3071 {
3072 *char_attrp = hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC));
3073 *n_extrap = 2;
3074 }
3075
3076 if (row == startrow
3077 #ifdef FEAT_DIFF
3078 + filler_lines && filler_todo <= 0
3079 #endif
3080 )
3081 {
3082 text_sign = (sattr->text != NULL) ? sattr->typenr : 0;
3083 # ifdef FEAT_SIGN_ICONS
3084 icon_sign = (sattr->icon != NULL) ? sattr->typenr : 0;
3085 if (gui.in_use && icon_sign != 0)
3086 {
3087 // Use the image in this position.
3088 if (nrcol)
3089 {
3090 *c_extrap = NUL;
3091 sprintf((char *)extra, "%-*c ", number_width(wp), SIGN_BYTE);
3092 *pp_extra = extra;
3093 *n_extrap = (int)STRLEN(*pp_extra);
3094 }
3095 else
3096 *c_extrap = SIGN_BYTE;
3097 # ifdef FEAT_NETBEANS_INTG
3098 if (netbeans_active() && (buf_signcount(wp->w_buffer, lnum) > 1))
3099 {
3100 if (nrcol)
3101 {
3102 *c_extrap = NUL;
3103 sprintf((char *)extra, "%-*c ", number_width(wp),
3104 MULTISIGN_BYTE);
3105 *pp_extra = extra;
3106 *n_extrap = (int)STRLEN(*pp_extra);
3107 }
3108 else
3109 *c_extrap = MULTISIGN_BYTE;
3110 }
3111 # endif
3112 *c_finalp = NUL;
3113 *char_attrp = icon_sign;
3114 }
3115 else
3116 # endif
3117 if (text_sign != 0)
3118 {
3119 *pp_extra = sattr->text;
3120 if (*pp_extra != NULL)
3121 {
3122 if (nrcol)
3123 {
3124 int n, width = number_width(wp) - 2;
3125
3126 for (n = 0; n < width; n++)
3127 extra[n] = ' ';
3128 extra[n] = 0;
3129 STRCAT(extra, *pp_extra);
3130 STRCAT(extra, " ");
3131 *pp_extra = extra;
3132 }
3133 *c_extrap = NUL;
3134 *c_finalp = NUL;
3135 *n_extrap = (int)STRLEN(*pp_extra);
3136 }
3137 *char_attrp = sattr->texthl;
3138 }
3139 }
3140 }
3141 #endif
3142
3143 /*
3144 * Display line "lnum" of window 'wp' on the screen.
3145 * Start at row "startrow", stop when "endrow" is reached.
3146 * wp->w_virtcol needs to be valid.
3147 *
3148 * Return the number of last row the line occupies.
3149 */
3150 static int
3151 win_line(
3152 win_T *wp,
3153 linenr_T lnum,
3154 int startrow,
3155 int endrow,
3156 int nochange UNUSED, // not updating for changed text
3157 int number_only) // only update the number column
3158 {
3159 int col = 0; // visual column on screen
3160 unsigned off; // offset in ScreenLines/ScreenAttrs
3161 int c = 0; // init for GCC
3162 long vcol = 0; // virtual column (for tabs)
3163 #ifdef FEAT_LINEBREAK
3164 long vcol_sbr = -1; // virtual column after showbreak
3165 #endif
3166 long vcol_prev = -1; // "vcol" of previous character
3167 char_u *line; // current line
3168 char_u *ptr; // current position in "line"
3169 int row; // row in the window, excl w_winrow
3170 int screen_row; // row on the screen, incl w_winrow
3171
3172 char_u extra[21]; // "%ld " and 'fdc' must fit in here
3173 int n_extra = 0; // number of extra chars
3174 char_u *p_extra = NULL; // string of extra chars, plus NUL
3175 char_u *p_extra_free = NULL; // p_extra needs to be freed
3176 int c_extra = NUL; // extra chars, all the same
3177 int c_final = NUL; // final char, mandatory if set
3178 int extra_attr = 0; // attributes when n_extra != 0
3179 static char_u *at_end_str = (char_u *)""; // used for p_extra when
3180 // displaying lcs_eol at end-of-line
3181 int lcs_eol_one = lcs_eol; // lcs_eol until it's been used
3182 int lcs_prec_todo = lcs_prec; // lcs_prec until it's been used
3183
3184 // saved "extra" items for when draw_state becomes WL_LINE (again)
3185 int saved_n_extra = 0;
3186 char_u *saved_p_extra = NULL;
3187 int saved_c_extra = 0;
3188 int saved_c_final = 0;
3189 int saved_char_attr = 0;
3190
3191 int n_attr = 0; /* chars with special attr */
3192 int saved_attr2 = 0; /* char_attr saved for n_attr */
3193 int n_attr3 = 0; /* chars with overruling special attr */
3194 int saved_attr3 = 0; /* char_attr saved for n_attr3 */
3195
3196 int n_skip = 0; /* nr of chars to skip for 'nowrap' */
3197
3198 int fromcol = -10; // start of inverting
3199 int tocol = MAXCOL; // end of inverting
3200 int fromcol_prev = -2; // start of inverting after cursor
3201 int noinvcur = FALSE; // don't invert the cursor
3202 pos_T *top, *bot;
3203 int lnum_in_visual_area = FALSE;
3204 pos_T pos;
3205 long v;
3206
3207 int char_attr = 0; // attributes for next character
3208 int attr_pri = FALSE; // char_attr has priority
3209 int area_highlighting = FALSE; // Visual or incsearch highlighting
3210 // in this line
3211 int vi_attr = 0; // attributes for Visual and incsearch
3212 // highlighting
3213 int wcr_attr = 0; // attributes from 'wincolor'
3214 int win_attr = 0; // background for whole window, except
3215 // margins and "~" lines.
3216 int area_attr = 0; // attributes desired by highlighting
3217 int search_attr = 0; // attributes desired by 'hlsearch'
3218 #ifdef FEAT_SYN_HL
3219 int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */
3220 int syntax_attr = 0; /* attributes desired by syntax */
3221 int has_syntax = FALSE; /* this buffer has syntax highl. */
3222 int save_did_emsg;
3223 int draw_color_col = FALSE; /* highlight colorcolumn */
3224 int *color_cols = NULL; /* pointer to according columns array */
3225 #endif
3226 int eol_hl_off = 0; /* 1 if highlighted char after EOL */
3227 #ifdef FEAT_TEXT_PROP
3228 int text_prop_count;
3229 int text_prop_next = 0; // next text property to use
3230 textprop_T *text_props = NULL;
3231 int *text_prop_idxs = NULL;
3232 int text_props_active = 0;
3233 proptype_T *text_prop_type = NULL;
3234 int text_prop_attr = 0;
3235 int text_prop_combine = FALSE;
3236 #endif
3237 #ifdef FEAT_SPELL
3238 int has_spell = FALSE; /* this buffer has spell checking */
3239 # define SPWORDLEN 150
3240 char_u nextline[SPWORDLEN * 2];/* text with start of the next line */
3241 int nextlinecol = 0; /* column where nextline[] starts */
3242 int nextline_idx = 0; /* index in nextline[] where next line
3243 starts */
3244 int spell_attr = 0; /* attributes desired by spelling */
3245 int word_end = 0; /* last byte with same spell_attr */
3246 static linenr_T checked_lnum = 0; /* line number for "checked_col" */
3247 static int checked_col = 0; /* column in "checked_lnum" up to which
3248 * there are no spell errors */
3249 static int cap_col = -1; /* column to check for Cap word */
3250 static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */
3251 int cur_checked_col = 0; /* checked column for current line */
3252 #endif
3253 int extra_check = 0; // has extra highlighting
3254 int multi_attr = 0; /* attributes desired by multibyte */
3255 int mb_l = 1; /* multi-byte byte length */
3256 int mb_c = 0; /* decoded multi-byte character */
3257 int mb_utf8 = FALSE; /* screen char is UTF-8 char */
3258 int u8cc[MAX_MCO]; /* composing UTF-8 chars */
3259 #if defined(FEAT_DIFF) || defined(FEAT_SIGNS)
3260 int filler_lines = 0; /* nr of filler lines to be drawn */
3261 int filler_todo = 0; /* nr of filler lines still to do + 1 */
3262 #endif
3263 #ifdef FEAT_DIFF
3264 hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */
3265 int change_start = MAXCOL; /* first col of changed area */
3266 int change_end = -1; /* last col of changed area */
3267 #endif
3268 colnr_T trailcol = MAXCOL; /* start of trailing spaces */
3269 #ifdef FEAT_LINEBREAK
3270 int need_showbreak = FALSE; /* overlong line, skipping first x
3271 chars */
3272 #endif
3273 #if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \
3274 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
3275 # define LINE_ATTR
3276 int line_attr = 0; // attribute for the whole line
3277 int line_attr_save;
3278 #endif
3279 #ifdef FEAT_SIGNS
3280 int sign_present = FALSE;
3281 sign_attrs_T sattr;
3282 #endif
3283 #ifdef FEAT_ARABIC
3284 int prev_c = 0; /* previous Arabic character */
3285 int prev_c1 = 0; /* first composing char for prev_c */
3286 #endif
3287 #if defined(LINE_ATTR)
3288 int did_line_attr = 0;
3289 #endif
3290 #ifdef FEAT_TERMINAL
3291 int get_term_attr = FALSE;
3292 #endif
3293 #ifdef FEAT_SYN_HL
3294 int cul_attr = 0; // set when 'cursorline' active
3295
3296 // 'cursorlineopt' has "screenline" and cursor is in this line
3297 int cul_screenline = FALSE;
3298
3299 // margin columns for the screen line, needed for when 'cursorlineopt'
3300 // contains "screenline"
3301 int left_curline_col = 0;
3302 int right_curline_col = 0;
3303 #endif
3304
3305 /* draw_state: items that are drawn in sequence: */
3306 #define WL_START 0 /* nothing done yet */
3307 #ifdef FEAT_CMDWIN
3308 # define WL_CMDLINE WL_START + 1 /* cmdline window column */
3309 #else
3310 # define WL_CMDLINE WL_START
3311 #endif
3312 #ifdef FEAT_FOLDING
3313 # define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
3314 #else
3315 # define WL_FOLD WL_CMDLINE
3316 #endif
3317 #ifdef FEAT_SIGNS
3318 # define WL_SIGN WL_FOLD + 1 /* column for signs */
3319 #else
3320 # define WL_SIGN WL_FOLD /* column for signs */
3321 #endif
3322 #define WL_NR WL_SIGN + 1 /* line number */
3323 #ifdef FEAT_LINEBREAK
3324 # define WL_BRI WL_NR + 1 /* 'breakindent' */
3325 #else
3326 # define WL_BRI WL_NR
3327 #endif
3328 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3329 # define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */
3330 #else
3331 # define WL_SBR WL_BRI
3332 #endif
3333 #define WL_LINE WL_SBR + 1 /* text in the line */
3334 int draw_state = WL_START; /* what to draw next */
3335 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
3336 int feedback_col = 0;
3337 int feedback_old_attr = -1;
3338 #endif
3339 int screen_line_flags = 0;
3340
3341 #if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA)
3342 int match_conc = 0; // cchar for match functions
3343 #endif
3344 #ifdef FEAT_CONCEAL
3345 int syntax_flags = 0;
3346 int syntax_seqnr = 0;
3347 int prev_syntax_id = 0;
3348 int conceal_attr = HL_ATTR(HLF_CONCEAL);
3349 int is_concealing = FALSE;
3350 int boguscols = 0; // nonexistent columns added to force
3351 // wrapping
3352 int vcol_off = 0; // offset for concealed characters
3353 int did_wcol = FALSE;
3354 int old_boguscols = 0;
3355 # define VCOL_HLC (vcol - vcol_off)
3356 # define FIX_FOR_BOGUSCOLS \
3357 { \
3358 n_extra += vcol_off; \
3359 vcol -= vcol_off; \
3360 vcol_off = 0; \
3361 col -= boguscols; \
3362 old_boguscols = boguscols; \
3363 boguscols = 0; \
3364 }
3365 #else
3366 # define VCOL_HLC (vcol)
3367 #endif
3368
3369 if (startrow > endrow) /* past the end already! */
3370 return startrow;
3371
3372 row = startrow;
3373 screen_row = row + W_WINROW(wp);
3374
3375 if (!number_only)
3376 {
3377 /*
3378 * To speed up the loop below, set extra_check when there is linebreak,
3379 * trailing white space and/or syntax processing to be done.
3380 */
3381 #ifdef FEAT_LINEBREAK
3382 extra_check = wp->w_p_lbr;
3383 #endif
3384 #ifdef FEAT_SYN_HL
3385 if (syntax_present(wp) && !wp->w_s->b_syn_error
3386 # ifdef SYN_TIME_LIMIT
3387 && !wp->w_s->b_syn_slow
3388 # endif
3389 )
3390 {
3391 /* Prepare for syntax highlighting in this line. When there is an
3392 * error, stop syntax highlighting. */
3393 save_did_emsg = did_emsg;
3394 did_emsg = FALSE;
3395 syntax_start(wp, lnum);
3396 if (did_emsg)
3397 wp->w_s->b_syn_error = TRUE;
3398 else
3399 {
3400 did_emsg = save_did_emsg;
3401 #ifdef SYN_TIME_LIMIT
3402 if (!wp->w_s->b_syn_slow)
3403 #endif
3404 {
3405 has_syntax = TRUE;
3406 extra_check = TRUE;
3407 }
3408 }
3409 }
3410
3411 /* Check for columns to display for 'colorcolumn'. */
3412 color_cols = wp->w_p_cc_cols;
3413 if (color_cols != NULL)
3414 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
3415 #endif
3416
3417 #ifdef FEAT_TERMINAL
3418 if (term_show_buffer(wp->w_buffer))
3419 {
3420 extra_check = TRUE;
3421 get_term_attr = TRUE;
3422 win_attr = term_get_attr(wp->w_buffer, lnum, -1);
3423 }
3424 #endif
3425
3426 #ifdef FEAT_SPELL
3427 if (wp->w_p_spell
3428 && *wp->w_s->b_p_spl != NUL
3429 && wp->w_s->b_langp.ga_len > 0
3430 && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
3431 {
3432 /* Prepare for spell checking. */
3433 has_spell = TRUE;
3434 extra_check = TRUE;
3435
3436 /* Get the start of the next line, so that words that wrap to the
3437 * next line are found too: "et<line-break>al.".
3438 * Trick: skip a few chars for C/shell/Vim comments */
3439 nextline[SPWORDLEN] = NUL;
3440 if (lnum < wp->w_buffer->b_ml.ml_line_count)
3441 {
3442 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
3443 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
3444 }
3445
3446 /* When a word wrapped from the previous line the start of the
3447 * current line is valid. */
3448 if (lnum == checked_lnum)
3449 cur_checked_col = checked_col;
3450 checked_lnum = 0;
3451
3452 /* When there was a sentence end in the previous line may require a
3453 * word starting with capital in this line. In line 1 always check
3454 * the first word. */
3455 if (lnum != capcol_lnum)
3456 cap_col = -1;
3457 if (lnum == 1)
3458 cap_col = 0;
3459 capcol_lnum = 0;
3460 }
3461 #endif
3462
3463 /*
3464 * handle Visual active in this window
3465 */
3466 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
3467 {
3468 if (LTOREQ_POS(curwin->w_cursor, VIsual))
3469 {
3470 // Visual is after curwin->w_cursor
3471 top = &curwin->w_cursor;
3472 bot = &VIsual;
3473 }
3474 else
3475 {
3476 // Visual is before curwin->w_cursor
3477 top = &VIsual;
3478 bot = &curwin->w_cursor;
3479 }
3480 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
3481 if (VIsual_mode == Ctrl_V)
3482 {
3483 // block mode
3484 if (lnum_in_visual_area)
3485 {
3486 fromcol = wp->w_old_cursor_fcol;
3487 tocol = wp->w_old_cursor_lcol;
3488 }
3489 }
3490 else
3491 {
3492 // non-block mode
3493 if (lnum > top->lnum && lnum <= bot->lnum)
3494 fromcol = 0;
3495 else if (lnum == top->lnum)
3496 {
3497 if (VIsual_mode == 'V') // linewise
3498 fromcol = 0;
3499 else
3500 {
3501 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
3502 if (gchar_pos(top) == NUL)
3503 tocol = fromcol + 1;
3504 }
3505 }
3506 if (VIsual_mode != 'V' && lnum == bot->lnum)
3507 {
3508 if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0)
3509 {
3510 fromcol = -10;
3511 tocol = MAXCOL;
3512 }
3513 else if (bot->col == MAXCOL)
3514 tocol = MAXCOL;
3515 else
3516 {
3517 pos = *bot;
3518 if (*p_sel == 'e')
3519 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
3520 else
3521 {
3522 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
3523 ++tocol;
3524 }
3525 }
3526 }
3527 }
3528
3529 /* Check if the character under the cursor should not be inverted */
3530 if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
3531 #ifdef FEAT_GUI
3532 && !gui.in_use
3533 #endif
3534 )
3535 noinvcur = TRUE;
3536
3537 /* if inverting in this line set area_highlighting */
3538 if (fromcol >= 0)
3539 {
3540 area_highlighting = TRUE;
3541 vi_attr = HL_ATTR(HLF_V);
3542 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3543 if ((clip_star.available && !clip_star.owned
3544 && clip_isautosel_star())
3545 || (clip_plus.available && !clip_plus.owned
3546 && clip_isautosel_plus()))
3547 vi_attr = HL_ATTR(HLF_VNC);
3548 #endif
3549 }
3550 }
3551
3552 /*
3553 * handle 'incsearch' and ":s///c" highlighting
3554 */
3555 else if (highlight_match
3556 && wp == curwin
3557 && lnum >= curwin->w_cursor.lnum
3558 && lnum <= curwin->w_cursor.lnum + search_match_lines)
3559 {
3560 if (lnum == curwin->w_cursor.lnum)
3561 getvcol(curwin, &(curwin->w_cursor),
3562 (colnr_T *)&fromcol, NULL, NULL);
3563 else
3564 fromcol = 0;
3565 if (lnum == curwin->w_cursor.lnum + search_match_lines)
3566 {
3567 pos.lnum = lnum;
3568 pos.col = search_match_endcol;
3569 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
3570 }
3571 else
3572 tocol = MAXCOL;
3573 /* do at least one character; happens when past end of line */
3574 if (fromcol == tocol)
3575 tocol = fromcol + 1;
3576 area_highlighting = TRUE;
3577 vi_attr = HL_ATTR(HLF_I);
3578 }
3579 }
3580
3581 #ifdef FEAT_DIFF
3582 filler_lines = diff_check(wp, lnum);
3583 if (filler_lines < 0)
3584 {
3585 if (filler_lines == -1)
3586 {
3587 if (diff_find_change(wp, lnum, &change_start, &change_end))
3588 diff_hlf = HLF_ADD; /* added line */
3589 else if (change_start == 0)
3590 diff_hlf = HLF_TXD; /* changed text */
3591 else
3592 diff_hlf = HLF_CHD; /* changed line */
3593 }
3594 else
3595 diff_hlf = HLF_ADD; /* added line */
3596 filler_lines = 0;
3597 area_highlighting = TRUE;
3598 }
3599 if (lnum == wp->w_topline)
3600 filler_lines = wp->w_topfill;
3601 filler_todo = filler_lines;
3602 #endif
3603
3604 #ifdef FEAT_SIGNS
3605 sign_present = buf_get_signattrs(wp->w_buffer, lnum, &sattr);
3606 #endif
3607
3608 #ifdef LINE_ATTR
3609 # ifdef FEAT_SIGNS
3610 /* If this line has a sign with line highlighting set line_attr. */
3611 if (sign_present)
3612 line_attr = sattr.linehl;
3613 # endif
3614 # if defined(FEAT_QUICKFIX)
3615 /* Highlight the current line in the quickfix window. */
3616 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
3617 line_attr = HL_ATTR(HLF_QFL);
3618 # endif
3619 if (line_attr != 0)
3620 area_highlighting = TRUE;
3621 #endif
3622
3623 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3624 ptr = line;
3625
3626 #ifdef FEAT_SPELL
3627 if (has_spell && !number_only)
3628 {
3629 /* For checking first word with a capital skip white space. */
3630 if (cap_col == 0)
3631 cap_col = getwhitecols(line);
3632
3633 /* To be able to spell-check over line boundaries copy the end of the
3634 * current line into nextline[]. Above the start of the next line was
3635 * copied to nextline[SPWORDLEN]. */
3636 if (nextline[SPWORDLEN] == NUL)
3637 {
3638 /* No next line or it is empty. */
3639 nextlinecol = MAXCOL;
3640 nextline_idx = 0;
3641 }
3642 else
3643 {
3644 v = (long)STRLEN(line);
3645 if (v < SPWORDLEN)
3646 {
3647 /* Short line, use it completely and append the start of the
3648 * next line. */
3649 nextlinecol = 0;
3650 mch_memmove(nextline, line, (size_t)v);
3651 STRMOVE(nextline + v, nextline + SPWORDLEN);
3652 nextline_idx = v + 1;
3653 }
3654 else
3655 {
3656 /* Long line, use only the last SPWORDLEN bytes. */
3657 nextlinecol = v - SPWORDLEN;
3658 mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
3659 nextline_idx = SPWORDLEN + 1;
3660 }
3661 }
3662 }
3663 #endif
3664
3665 if (wp->w_p_list)
3666 {
3667 if (lcs_space || lcs_trail || lcs_nbsp)
3668 extra_check = TRUE;
3669 /* find start of trailing whitespace */
3670 if (lcs_trail)
3671 {
3672 trailcol = (colnr_T)STRLEN(ptr);
3673 while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
3674 --trailcol;
3675 trailcol += (colnr_T) (ptr - line);
3676 }
3677 }
3678
3679 wcr_attr = get_wcr_attr(wp);
3680 if (wcr_attr != 0)
3681 {
3682 win_attr = wcr_attr;
3683 area_highlighting = TRUE;
3684 }
3685 #ifdef FEAT_TEXT_PROP
3686 if (WIN_IS_POPUP(wp))
3687 screen_line_flags |= SLF_POPUP;
3688 #endif
3689
3690 /*
3691 * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
3692 * first character to be displayed.
3693 */
3694 if (wp->w_p_wrap)
3695 v = wp->w_skipcol;
3696 else
3697 v = wp->w_leftcol;
3698 if (v > 0 && !number_only)
3699 {
3700 char_u *prev_ptr = ptr;
3701
3702 while (vcol < v && *ptr != NUL)
3703 {
3704 c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
3705 vcol += c;
3706 prev_ptr = ptr;
3707 MB_PTR_ADV(ptr);
3708 }
3709
3710 /* When:
3711 * - 'cuc' is set, or
3712 * - 'colorcolumn' is set, or
3713 * - 'virtualedit' is set, or
3714 * - the visual mode is active,
3715 * the end of the line may be before the start of the displayed part.
3716 */
3717 if (vcol < v && (
3718 #ifdef FEAT_SYN_HL
3719 wp->w_p_cuc || draw_color_col ||
3720 #endif
3721 virtual_active() ||
3722 (VIsual_active && wp->w_buffer == curwin->w_buffer)))
3723 vcol = v;
3724
3725 /* Handle a character that's not completely on the screen: Put ptr at
3726 * that character but skip the first few screen characters. */
3727 if (vcol > v)
3728 {
3729 vcol -= c;
3730 ptr = prev_ptr;
3731 /* If the character fits on the screen, don't need to skip it.
3732 * Except for a TAB. */
3733 if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0)
3734 n_skip = v - vcol;
3735 }
3736
3737 /*
3738 * Adjust for when the inverted text is before the screen,
3739 * and when the start of the inverted text is before the screen.
3740 */
3741 if (tocol <= vcol)
3742 fromcol = 0;
3743 else if (fromcol >= 0 && fromcol < vcol)
3744 fromcol = vcol;
3745
3746 #ifdef FEAT_LINEBREAK
3747 /* When w_skipcol is non-zero, first line needs 'showbreak' */
3748 if (wp->w_p_wrap)
3749 need_showbreak = TRUE;
3750 #endif
3751 #ifdef FEAT_SPELL
3752 /* When spell checking a word we need to figure out the start of the
3753 * word and if it's badly spelled or not. */
3754 if (has_spell)
3755 {
3756 int len;
3757 colnr_T linecol = (colnr_T)(ptr - line);
3758 hlf_T spell_hlf = HLF_COUNT;
3759
3760 pos = wp->w_cursor;
3761 wp->w_cursor.lnum = lnum;
3762 wp->w_cursor.col = linecol;
3763 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
3764
3765 /* spell_move_to() may call ml_get() and make "line" invalid */
3766 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3767 ptr = line + linecol;
3768
3769 if (len == 0 || (int)wp->w_cursor.col > ptr - line)
3770 {
3771 /* no bad word found at line start, don't check until end of a
3772 * word */
3773 spell_hlf = HLF_COUNT;
3774 word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
3775 }
3776 else
3777 {
3778 /* bad word found, use attributes until end of word */
3779 word_end = wp->w_cursor.col + len + 1;
3780
3781 /* Turn index into actual attributes. */
3782 if (spell_hlf != HLF_COUNT)
3783 spell_attr = highlight_attr[spell_hlf];
3784 }
3785 wp->w_cursor = pos;
3786
3787 # ifdef FEAT_SYN_HL
3788 /* Need to restart syntax highlighting for this line. */
3789 if (has_syntax)
3790 syntax_start(wp, lnum);
3791 # endif
3792 }
3793 #endif
3794 }
3795
3796 /*
3797 * Correct highlighting for cursor that can't be disabled.
3798 * Avoids having to check this for each character.
3799 */
3800 if (fromcol >= 0)
3801 {
3802 if (noinvcur)
3803 {
3804 if ((colnr_T)fromcol == wp->w_virtcol)
3805 {
3806 /* highlighting starts at cursor, let it start just after the
3807 * cursor */
3808 fromcol_prev = fromcol;
3809 fromcol = -1;
3810 }
3811 else if ((colnr_T)fromcol < wp->w_virtcol)
3812 /* restart highlighting after the cursor */
3813 fromcol_prev = wp->w_virtcol;
3814 }
3815 if (fromcol >= tocol)
3816 fromcol = -1;
3817 }
3818
3819 #ifdef FEAT_SEARCH_EXTRA
3820 if (!number_only)
3821 {
3822 v = (long)(ptr - line);
3823 area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
3824 &line, &search_hl, &search_attr);
3825 ptr = line + v; // "line" may have been updated
3826 }
3827 #endif
3828
3829 #ifdef FEAT_SYN_HL
3830 // Cursor line highlighting for 'cursorline' in the current window.
3831 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
3832 {
3833 // Do not show the cursor line in the text when Visual mode is active,
3834 // because it's not clear what is selected then. Do update
3835 // w_last_cursorline.
3836 if (!(wp == curwin && VIsual_active)
3837 && wp->w_p_culopt_flags != CULOPT_NBR)
3838 {
3839 cul_screenline = (wp->w_p_wrap
3840 && (wp->w_p_culopt_flags & CULOPT_SCRLINE));
3841
3842 // Only set line_attr here when "screenline" is not present in
3843 // 'cursorlineopt'. Otherwise it's done later.
3844 if (!cul_screenline)
3845 {
3846 cul_attr = HL_ATTR(HLF_CUL);
3847 line_attr = cul_attr;
3848 wp->w_last_cursorline = wp->w_cursor.lnum;
3849 }
3850 else
3851 {
3852 line_attr_save = line_attr;
3853 wp->w_last_cursorline = 0;
3854 margin_columns_win(wp, &left_curline_col, &right_curline_col);
3855 }
3856 area_highlighting = TRUE;
3857 }
3858 else
3859 wp->w_last_cursorline = wp->w_cursor.lnum;
3860 }
3861 #endif
3862
3863 #ifdef FEAT_TEXT_PROP
3864 {
3865 char_u *prop_start;
3866
3867 text_prop_count = get_text_props(wp->w_buffer, lnum,
3868 &prop_start, FALSE);
3869 if (text_prop_count > 0)
3870 {
3871 // Make a copy of the properties, so that they are properly
3872 // aligned.
3873 text_props = ALLOC_MULT(textprop_T, text_prop_count);
3874 if (text_props != NULL)
3875 mch_memmove(text_props, prop_start,
3876 text_prop_count * sizeof(textprop_T));
3877
3878 // Allocate an array for the indexes.
3879 text_prop_idxs = ALLOC_MULT(int, text_prop_count);
3880 area_highlighting = TRUE;
3881 extra_check = TRUE;
3882 }
3883 }
3884 #endif
3885
3886 off = (unsigned)(current_ScreenLine - ScreenLines);
3887 col = 0;
3888
3889 #ifdef FEAT_RIGHTLEFT
3890 if (wp->w_p_rl)
3891 {
3892 /* Rightleft window: process the text in the normal direction, but put
3893 * it in current_ScreenLine[] from right to left. Start at the
3894 * rightmost column of the window. */
3895 col = wp->w_width - 1;
3896 off += col;
3897 screen_line_flags |= SLF_RIGHTLEFT;
3898 }
3899 #endif
3900
3901 /*
3902 * Repeat for the whole displayed line.
3903 */
3904 for (;;)
3905 {
3906 #if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA)
3907 int has_match_conc = 0; // match wants to conceal
3908 #endif
3909 #ifdef FEAT_CONCEAL
3910 int did_decrement_ptr = FALSE;
3911 #endif
3912 /* Skip this quickly when working on the text. */
3913 if (draw_state != WL_LINE)
3914 {
3915 #ifdef FEAT_CMDWIN
3916 if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
3917 {
3918 draw_state = WL_CMDLINE;
3919 if (cmdwin_type != 0 && wp == curwin)
3920 {
3921 /* Draw the cmdline character. */
3922 n_extra = 1;
3923 c_extra = cmdwin_type;
3924 c_final = NUL;
3925 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_AT));
3926 }
3927 }
3928 #endif
3929
3930 #ifdef FEAT_FOLDING
3931 if (draw_state == WL_FOLD - 1 && n_extra == 0)
3932 {
3933 int fdc = compute_foldcolumn(wp, 0);
3934
3935 draw_state = WL_FOLD;
3936 if (fdc > 0)
3937 {
3938 /* Draw the 'foldcolumn'. Allocate a buffer, "extra" may
3939 * already be in use. */
3940 vim_free(p_extra_free);
3941 p_extra_free = alloc(12 + 1);
3942
3943 if (p_extra_free != NULL)
3944 {
3945 fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
3946 n_extra = fdc;
3947 p_extra_free[n_extra] = NUL;
3948 p_extra = p_extra_free;
3949 c_extra = NUL;
3950 c_final = NUL;
3951 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC));
3952 }
3953 }
3954 }
3955 #endif
3956
3957 #ifdef FEAT_SIGNS
3958 if (draw_state == WL_SIGN - 1 && n_extra == 0)
3959 {
3960 draw_state = WL_SIGN;
3961 /* Show the sign column when there are any signs in this
3962 * buffer or when using Netbeans. */
3963 if (signcolumn_on(wp))
3964 get_sign_display_info(FALSE, wp, lnum, &sattr, wcr_attr,
3965 row, startrow, filler_lines, filler_todo, &c_extra,
3966 &c_final, extra, &p_extra, &n_extra, &char_attr);
3967 }
3968 #endif
3969
3970 if (draw_state == WL_NR - 1 && n_extra == 0)
3971 {
3972 draw_state = WL_NR;
3973 /* Display the absolute or relative line number. After the
3974 * first fill with blanks when the 'n' flag isn't in 'cpo' */
3975 if ((wp->w_p_nu || wp->w_p_rnu)
3976 && (row == startrow
3977 #ifdef FEAT_DIFF
3978 + filler_lines
3979 #endif
3980 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
3981 {
3982 #ifdef FEAT_SIGNS
3983 // If 'signcolumn' is set to 'number' and a sign is present
3984 // in 'lnum', then display the sign instead of the line
3985 // number.
3986 if ((*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')
3987 && sign_present)
3988 get_sign_display_info(TRUE, wp, lnum, &sattr, wcr_attr,
3989 row, startrow, filler_lines, filler_todo,
3990 &c_extra, &c_final, extra, &p_extra, &n_extra,
3991 &char_attr);
3992 else
3993 #endif
3994 {
3995 /* Draw the line number (empty space after wrapping). */
3996 if (row == startrow
3997 #ifdef FEAT_DIFF
3998 + filler_lines
3999 #endif
4000 )
4001 {
4002 long num;
4003 char *fmt = "%*ld ";
4004
4005 if (wp->w_p_nu && !wp->w_p_rnu)
4006 /* 'number' + 'norelativenumber' */
4007 num = (long)lnum;
4008 else
4009 {
4010 /* 'relativenumber', don't use negative numbers */
4011 num = labs((long)get_cursor_rel_lnum(wp, lnum));
4012 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
4013 {
4014 /* 'number' + 'relativenumber' */
4015 num = lnum;
4016 fmt = "%-*ld ";
4017 }
4018 }
4019
4020 sprintf((char *)extra, fmt,
4021 number_width(wp), num);
4022 if (wp->w_skipcol > 0)
4023 for (p_extra = extra; *p_extra == ' '; ++p_extra)
4024 *p_extra = '-';
4025 #ifdef FEAT_RIGHTLEFT
4026 if (wp->w_p_rl) /* reverse line numbers */
4027 {
4028 char_u *p1, *p2;
4029 int t;
4030
4031 // like rl_mirror(), but keep the space at the end
4032 p2 = skiptowhite(extra) - 1;
4033 for (p1 = extra; p1 < p2; ++p1, --p2)
4034 {
4035 t = *p1;
4036 *p1 = *p2;
4037 *p2 = t;
4038 }
4039 }
4040 #endif
4041 p_extra = extra;
4042 c_extra = NUL;
4043 c_final = NUL;
4044 }
4045 else
4046 {
4047 c_extra = ' ';
4048 c_final = NUL;
4049 }
4050 n_extra = number_width(wp) + 1;
4051 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_N));
4052 #ifdef FEAT_SYN_HL
4053 // When 'cursorline' is set highlight the line number of
4054 // the current line differently.
4055 // When 'cursorlineopt' has "screenline" only highlight
4056 // the line number itself.
4057 // TODO: Can we use CursorLine instead of CursorLineNr
4058 // when CursorLineNr isn't set?
4059 if ((wp->w_p_cul || wp->w_p_rnu)
4060 && (wp->w_p_culopt_flags & CULOPT_NBR)
4061 && (row == startrow
4062 || wp->w_p_culopt_flags & CULOPT_LINE)
4063 && lnum == wp->w_cursor.lnum)
4064 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_CLN));
4065 #endif
4066 }
4067 }
4068 }
4069
4070 #ifdef FEAT_LINEBREAK
4071 if (wp->w_p_brisbr && draw_state == WL_BRI - 1
4072 && n_extra == 0 && *p_sbr != NUL)
4073 /* draw indent after showbreak value */
4074 draw_state = WL_BRI;
4075 else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0)
4076 /* After the showbreak, draw the breakindent */
4077 draw_state = WL_BRI - 1;
4078
4079 /* draw 'breakindent': indent wrapped text accordingly */
4080 if (draw_state == WL_BRI - 1 && n_extra == 0)
4081 {
4082 draw_state = WL_BRI;
4083 /* if need_showbreak is set, breakindent also applies */
4084 if (wp->w_p_bri && n_extra == 0
4085 && (row != startrow || need_showbreak)
4086 # ifdef FEAT_DIFF
4087 && filler_lines == 0
4088 # endif
4089 )
4090 {
4091 char_attr = 0;
4092 # ifdef FEAT_DIFF
4093 if (diff_hlf != (hlf_T)0)
4094 {
4095 char_attr = HL_ATTR(diff_hlf);
4096 # ifdef FEAT_SYN_HL
4097 if (cul_attr != 0)
4098 char_attr = hl_combine_attr(char_attr, cul_attr);
4099 # endif
4100 }
4101 # endif
4102 p_extra = NULL;
4103 c_extra = ' ';
4104 n_extra = get_breakindent_win(wp,
4105 ml_get_buf(wp->w_buffer, lnum, FALSE));
4106 /* Correct end of highlighted area for 'breakindent',
4107 * required when 'linebreak' is also set. */
4108 if (tocol == vcol)
4109 tocol += n_extra;
4110 }
4111 }
4112 #endif
4113
4114 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
4115 if (draw_state == WL_SBR - 1 && n_extra == 0)
4116 {
4117 draw_state = WL_SBR;
4118 # ifdef FEAT_DIFF
4119 if (filler_todo > 0)
4120 {
4121 /* Draw "deleted" diff line(s). */
4122 if (char2cells(fill_diff) > 1)
4123 {
4124 c_extra = '-';
4125 c_final = NUL;
4126 }
4127 else
4128 {
4129 c_extra = fill_diff;
4130 c_final = NUL;
4131 }
4132 # ifdef FEAT_RIGHTLEFT
4133 if (wp->w_p_rl)
4134 n_extra = col + 1;
4135 else
4136 # endif
4137 n_extra = wp->w_width - col;
4138 char_attr = HL_ATTR(HLF_DED);
4139 }
4140 # endif
4141 # ifdef FEAT_LINEBREAK
4142 if (*p_sbr != NUL && need_showbreak)
4143 {
4144 /* Draw 'showbreak' at the start of each broken line. */
4145 p_extra = p_sbr;
4146 c_extra = NUL;
4147 c_final = NUL;
4148 n_extra = (int)STRLEN(p_sbr);
4149 char_attr = HL_ATTR(HLF_AT);
4150 need_showbreak = FALSE;
4151 vcol_sbr = vcol + MB_CHARLEN(p_sbr);
4152 /* Correct end of highlighted area for 'showbreak',
4153 * required when 'linebreak' is also set. */
4154 if (tocol == vcol)
4155 tocol += n_extra;
4156 // combine 'showbreak' with 'wincolor'
4157 if (win_attr != 0)
4158 char_attr = hl_combine_attr(win_attr, char_attr);
4159 # ifdef FEAT_SYN_HL
4160 // combine 'showbreak' with 'cursorline'
4161 if (cul_attr != 0)
4162 char_attr = hl_combine_attr(char_attr, cul_attr);
4163 # endif
4164 }
4165 # endif
4166 }
4167 #endif
4168
4169 if (draw_state == WL_LINE - 1 && n_extra == 0)
4170 {
4171 draw_state = WL_LINE;
4172 if (saved_n_extra)
4173 {
4174 /* Continue item from end of wrapped line. */
4175 n_extra = saved_n_extra;
4176 c_extra = saved_c_extra;
4177 c_final = saved_c_final;
4178 p_extra = saved_p_extra;
4179 char_attr = saved_char_attr;
4180 }
4181 else
4182 char_attr = win_attr;
4183 }
4184 }
4185 #ifdef FEAT_SYN_HL
4186 if (cul_screenline)
4187 {
4188 if (draw_state == WL_LINE
4189 && vcol >= left_curline_col
4190 && vcol < right_curline_col)
4191 {
4192 cul_attr = HL_ATTR(HLF_CUL);
4193 line_attr = cul_attr;
4194 }
4195 else
4196 {
4197 cul_attr = 0;
4198 line_attr = line_attr_save;
4199 }
4200 }
4201 #endif
4202
4203 // When still displaying '$' of change command, stop at cursor.
4204 // When only displaying the (relative) line number and that's done,
4205 // stop here.
4206 if ((dollar_vcol >= 0 && wp == curwin
4207 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
4208 #ifdef FEAT_DIFF
4209 && filler_todo <= 0
4210 #endif
4211 )
4212 || (number_only && draw_state > WL_NR))
4213 {
4214 screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
4215 screen_line_flags);
4216 /* Pretend we have finished updating the window. Except when
4217 * 'cursorcolumn' is set. */
4218 #ifdef FEAT_SYN_HL
4219 if (wp->w_p_cuc)
4220 row = wp->w_cline_row + wp->w_cline_height;
4221 else
4222 #endif
4223 row = wp->w_height;
4224 break;
4225 }
4226
4227 if (draw_state == WL_LINE && (area_highlighting
4228 #ifdef FEAT_SPELL
4229 || has_spell
4230 #endif
4231 ))
4232 {
4233 /* handle Visual or match highlighting in this line */
4234 if (vcol == fromcol
4235 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
4236 && (*mb_ptr2cells)(ptr) > 1)
4237 || ((int)vcol_prev == fromcol_prev
4238 && vcol_prev < vcol /* not at margin */
4239 && vcol < tocol))
4240 area_attr = vi_attr; /* start highlighting */
4241 else if (area_attr != 0
4242 && (vcol == tocol
4243 || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
4244 area_attr = 0; /* stop highlighting */
4245
4246 #ifdef FEAT_SEARCH_EXTRA
4247 if (!n_extra)
4248 {
4249 /*
4250 * Check for start/end of 'hlsearch' and other matches.
4251 * After end, check for start/end of next match.
4252 * When another match, have to check for start again.
4253 */
4254 v = (long)(ptr - line);
4255 search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line,
4256 &search_hl, &has_match_conc, &match_conc,
4257 did_line_attr, lcs_eol_one);
4258 ptr = line + v; // "line" may have been changed
4259 }
4260 #endif
4261
4262 #ifdef FEAT_DIFF
4263 if (diff_hlf != (hlf_T)0)
4264 {
4265 if (diff_hlf == HLF_CHD && ptr - line >= change_start
4266 && n_extra == 0)
4267 diff_hlf = HLF_TXD; /* changed text */
4268 if (diff_hlf == HLF_TXD && ptr - line > change_end
4269 && n_extra == 0)
4270 diff_hlf = HLF_CHD; /* changed line */
4271 line_attr = HL_ATTR(diff_hlf);
4272 if (wp->w_p_cul && lnum == wp->w_cursor.lnum
4273 && wp->w_p_culopt_flags != CULOPT_NBR
4274 && (!cul_screenline || (vcol >= left_curline_col
4275 && vcol <= right_curline_col)))
4276 line_attr = hl_combine_attr(
4277 line_attr, HL_ATTR(HLF_CUL));
4278 }
4279 #endif
4280
4281 #ifdef FEAT_TEXT_PROP
4282 if (text_props != NULL)
4283 {
4284 int pi;
4285 int bcol = (int)(ptr - line);
4286
4287 if (n_extra > 0)
4288 --bcol; // still working on the previous char, e.g. Tab
4289
4290 // Check if any active property ends.
4291 for (pi = 0; pi < text_props_active; ++pi)
4292 {
4293 int tpi = text_prop_idxs[pi];
4294
4295 if (bcol >= text_props[tpi].tp_col - 1
4296 + text_props[tpi].tp_len)
4297 {
4298 if (pi + 1 < text_props_active)
4299 mch_memmove(text_prop_idxs + pi,
4300 text_prop_idxs + pi + 1,
4301 sizeof(int)
4302 * (text_props_active - (pi + 1)));
4303 --text_props_active;
4304 --pi;
4305 }
4306 }
4307
4308 // Add any text property that starts in this column.
4309 while (text_prop_next < text_prop_count
4310 && bcol >= text_props[text_prop_next].tp_col - 1)
4311 text_prop_idxs[text_props_active++] = text_prop_next++;
4312
4313 text_prop_attr = 0;
4314 text_prop_combine = FALSE;
4315 if (text_props_active > 0)
4316 {
4317 // Sort the properties on priority and/or starting last.
4318 // Then combine the attributes, highest priority last.
4319 current_text_props = text_props;
4320 current_buf = wp->w_buffer;
4321 qsort((void *)text_prop_idxs, (size_t)text_props_active,
4322 sizeof(int), text_prop_compare);
4323
4324 for (pi = 0; pi < text_props_active; ++pi)
4325 {
4326 int tpi = text_prop_idxs[pi];
4327 proptype_T *pt = text_prop_type_by_id(
4328 wp->w_buffer, text_props[tpi].tp_type);
4329
4330 if (pt != NULL && pt->pt_hl_id > 0)
4331 {
4332 int pt_attr = syn_id2attr(pt->pt_hl_id);
4333
4334 text_prop_type = pt;
4335 text_prop_attr =
4336 hl_combine_attr(text_prop_attr, pt_attr);
4337 text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE;
4338 }
4339 }
4340 }
4341 }
4342 #endif
4343
4344 /* Decide which of the highlight attributes to use. */
4345 attr_pri = TRUE;
4346 #ifdef LINE_ATTR
4347 if (area_attr != 0)
4348 char_attr = hl_combine_attr(line_attr, area_attr);
4349 else if (search_attr != 0)
4350 char_attr = hl_combine_attr(line_attr, search_attr);
4351 # ifdef FEAT_TEXT_PROP
4352 else if (text_prop_type != NULL)
4353 {
4354 char_attr = hl_combine_attr(
4355 line_attr != 0 ? line_attr : win_attr, text_prop_attr);
4356 }
4357 # endif
4358 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
4359 || vcol < fromcol || vcol_prev < fromcol_prev
4360 || vcol >= tocol))
4361 {
4362 // Use line_attr when not in the Visual or 'incsearch' area
4363 // (area_attr may be 0 when "noinvcur" is set).
4364 char_attr = line_attr;
4365 attr_pri = FALSE;
4366 }
4367 #else
4368 if (area_attr != 0)
4369 char_attr = area_attr;
4370 else if (search_attr != 0)
4371 char_attr = search_attr;
4372 #endif
4373 else
4374 {
4375 attr_pri = FALSE;
4376 #ifdef FEAT_TEXT_PROP
4377 if (text_prop_type != NULL)
4378 {
4379 if (text_prop_combine)
4380 char_attr = hl_combine_attr(
4381 syntax_attr, text_prop_attr);
4382 else
4383 char_attr = hl_combine_attr(
4384 win_attr, text_prop_attr);
4385 }
4386 else
4387 #endif
4388 #ifdef FEAT_SYN_HL
4389 if (has_syntax)
4390 char_attr = syntax_attr;
4391 else
4392 #endif
4393 char_attr = 0;
4394 }
4395 }
4396 if (char_attr == 0)
4397 char_attr = win_attr;
4398
4399 /*
4400 * Get the next character to put on the screen.
4401 */
4402 /*
4403 * The "p_extra" points to the extra stuff that is inserted to
4404 * represent special characters (non-printable stuff) and other
4405 * things. When all characters are the same, c_extra is used.
4406 * If c_final is set, it will compulsorily be used at the end.
4407 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
4408 * "p_extra[n_extra]".
4409 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
4410 */
4411 if (n_extra > 0)
4412 {
4413 if (c_extra != NUL || (n_extra == 1 && c_final != NUL))
4414 {
4415 c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra;
4416 mb_c = c; /* doesn't handle non-utf-8 multi-byte! */
4417 if (enc_utf8 && utf_char2len(c) > 1)
4418 {
4419 mb_utf8 = TRUE;
4420 u8cc[0] = 0;
4421 c = 0xc0;
4422 }
4423 else
4424 mb_utf8 = FALSE;
4425 }
4426 else
4427 {
4428 c = *p_extra;
4429 if (has_mbyte)
4430 {
4431 mb_c = c;
4432 if (enc_utf8)
4433 {
4434 /* If the UTF-8 character is more than one byte:
4435 * Decode it into "mb_c". */
4436 mb_l = utfc_ptr2len(p_extra);
4437 mb_utf8 = FALSE;
4438 if (mb_l > n_extra)
4439 mb_l = 1;
4440 else if (mb_l > 1)
4441 {
4442 mb_c = utfc_ptr2char(p_extra, u8cc);
4443 mb_utf8 = TRUE;
4444 c = 0xc0;
4445 }
4446 }
4447 else
4448 {
4449 /* if this is a DBCS character, put it in "mb_c" */
4450 mb_l = MB_BYTE2LEN(c);
4451 if (mb_l >= n_extra)
4452 mb_l = 1;
4453 else if (mb_l > 1)
4454 mb_c = (c << 8) + p_extra[1];
4455 }
4456 if (mb_l == 0) /* at the NUL at end-of-line */
4457 mb_l = 1;
4458
4459 /* If a double-width char doesn't fit display a '>' in the
4460 * last column. */
4461 if ((
4462 # ifdef FEAT_RIGHTLEFT
4463 wp->w_p_rl ? (col <= 0) :
4464 # endif
4465 (col >= wp->w_width - 1))
4466 && (*mb_char2cells)(mb_c) == 2)
4467 {
4468 c = '>';
4469 mb_c = c;
4470 mb_l = 1;
4471 mb_utf8 = FALSE;
4472 multi_attr = HL_ATTR(HLF_AT);
4473 #ifdef FEAT_SYN_HL
4474 if (cul_attr)
4475 multi_attr = hl_combine_attr(multi_attr, cul_attr);
4476 #endif
4477 /* put the pointer back to output the double-width
4478 * character at the start of the next line. */
4479 ++n_extra;
4480 --p_extra;
4481 }
4482 else
4483 {
4484 n_extra -= mb_l - 1;
4485 p_extra += mb_l - 1;
4486 }
4487 }
4488 ++p_extra;
4489 }
4490 --n_extra;
4491 }
4492 else
4493 {
4494 #ifdef FEAT_LINEBREAK
4495 int c0;
4496 #endif
4497
4498 if (p_extra_free != NULL)
4499 VIM_CLEAR(p_extra_free);
4500 /*
4501 * Get a character from the line itself.
4502 */
4503 c = *ptr;
4504 #ifdef FEAT_LINEBREAK
4505 c0 = *ptr;
4506 #endif
4507 if (has_mbyte)
4508 {
4509 mb_c = c;
4510 if (enc_utf8)
4511 {
4512 /* If the UTF-8 character is more than one byte: Decode it
4513 * into "mb_c". */
4514 mb_l = utfc_ptr2len(ptr);
4515 mb_utf8 = FALSE;
4516 if (mb_l > 1)
4517 {
4518 mb_c = utfc_ptr2char(ptr, u8cc);
4519 /* Overlong encoded ASCII or ASCII with composing char
4520 * is displayed normally, except a NUL. */
4521 if (mb_c < 0x80)
4522 {
4523 c = mb_c;
4524 #ifdef FEAT_LINEBREAK
4525 c0 = mb_c;
4526 #endif
4527 }
4528 mb_utf8 = TRUE;
4529
4530 /* At start of the line we can have a composing char.
4531 * Draw it as a space with a composing char. */
4532 if (utf_iscomposing(mb_c))
4533 {
4534 int i;
4535
4536 for (i = Screen_mco - 1; i > 0; --i)
4537 u8cc[i] = u8cc[i - 1];
4538 u8cc[0] = mb_c;
4539 mb_c = ' ';
4540 }
4541 }
4542
4543 if ((mb_l == 1 && c >= 0x80)
4544 || (mb_l >= 1 && mb_c == 0)
4545 || (mb_l > 1 && (!vim_isprintc(mb_c))))
4546 {
4547 /*
4548 * Illegal UTF-8 byte: display as <xx>.
4549 * Non-BMP character : display as ? or fullwidth ?.
4550 */
4551 transchar_hex(extra, mb_c);
4552 # ifdef FEAT_RIGHTLEFT
4553 if (wp->w_p_rl) /* reverse */
4554 rl_mirror(extra);
4555 # endif
4556 p_extra = extra;
4557 c = *p_extra;
4558 mb_c = mb_ptr2char_adv(&p_extra);
4559 mb_utf8 = (c >= 0x80);
4560 n_extra = (int)STRLEN(p_extra);
4561 c_extra = NUL;
4562 c_final = NUL;
4563 if (area_attr == 0 && search_attr == 0)
4564 {
4565 n_attr = n_extra + 1;
4566 extra_attr = HL_ATTR(HLF_8);
4567 saved_attr2 = char_attr; /* save current attr */
4568 }
4569 }
4570 else if (mb_l == 0) /* at the NUL at end-of-line */
4571 mb_l = 1;
4572 #ifdef FEAT_ARABIC
4573 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
4574 {
4575 /* Do Arabic shaping. */
4576 int pc, pc1, nc;
4577 int pcc[MAX_MCO];
4578
4579 /* The idea of what is the previous and next
4580 * character depends on 'rightleft'. */
4581 if (wp->w_p_rl)
4582 {
4583 pc = prev_c;
4584 pc1 = prev_c1;
4585 nc = utf_ptr2char(ptr + mb_l);
4586 prev_c1 = u8cc[0];
4587 }
4588 else
4589 {
4590 pc = utfc_ptr2char(ptr + mb_l, pcc);
4591 nc = prev_c;
4592 pc1 = pcc[0];
4593 }
4594 prev_c = mb_c;
4595
4596 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
4597 }
4598 else
4599 prev_c = mb_c;
4600 #endif
4601 }
4602 else /* enc_dbcs */
4603 {
4604 mb_l = MB_BYTE2LEN(c);
4605 if (mb_l == 0) /* at the NUL at end-of-line */
4606 mb_l = 1;
4607 else if (mb_l > 1)
4608 {
4609 /* We assume a second byte below 32 is illegal.
4610 * Hopefully this is OK for all double-byte encodings!
4611 */
4612 if (ptr[1] >= 32)
4613 mb_c = (c << 8) + ptr[1];
4614 else
4615 {
4616 if (ptr[1] == NUL)
4617 {
4618 /* head byte at end of line */
4619 mb_l = 1;
4620 transchar_nonprint(extra, c);
4621 }
4622 else
4623 {
4624 /* illegal tail byte */
4625 mb_l = 2;
4626 STRCPY(extra, "XX");
4627 }
4628 p_extra = extra;
4629 n_extra = (int)STRLEN(extra) - 1;
4630 c_extra = NUL;
4631 c_final = NUL;
4632 c = *p_extra++;
4633 if (area_attr == 0 && search_attr == 0)
4634 {
4635 n_attr = n_extra + 1;
4636 extra_attr = HL_ATTR(HLF_8);
4637 saved_attr2 = char_attr; /* save current attr */
4638 }
4639 mb_c = c;
4640 }
4641 }
4642 }
4643 /* If a double-width char doesn't fit display a '>' in the
4644 * last column; the character is displayed at the start of the
4645 * next line. */
4646 if ((
4647 # ifdef FEAT_RIGHTLEFT
4648 wp->w_p_rl ? (col <= 0) :
4649 # endif
4650 (col >= wp->w_width - 1))
4651 && (*mb_char2cells)(mb_c) == 2)
4652 {
4653 c = '>';
4654 mb_c = c;
4655 mb_utf8 = FALSE;
4656 mb_l = 1;
4657 multi_attr = HL_ATTR(HLF_AT);
4658 // Put pointer back so that the character will be
4659 // displayed at the start of the next line.
4660 --ptr;
4661 #ifdef FEAT_CONCEAL
4662 did_decrement_ptr = TRUE;
4663 #endif
4664 }
4665 else if (*ptr != NUL)
4666 ptr += mb_l - 1;
4667
4668 /* If a double-width char doesn't fit at the left side display
4669 * a '<' in the first column. Don't do this for unprintable
4670 * characters. */
4671 if (n_skip > 0 && mb_l > 1 && n_extra == 0)
4672 {
4673 n_extra = 1;
4674 c_extra = MB_FILLER_CHAR;
4675 c_final = NUL;
4676 c = ' ';
4677 if (area_attr == 0 && search_attr == 0)
4678 {
4679 n_attr = n_extra + 1;
4680 extra_attr = HL_ATTR(HLF_AT);
4681 saved_attr2 = char_attr; /* save current attr */
4682 }
4683 mb_c = c;
4684 mb_utf8 = FALSE;
4685 mb_l = 1;
4686 }
4687
4688 }
4689 ++ptr;
4690
4691 if (extra_check)
4692 {
4693 #ifdef FEAT_SPELL
4694 int can_spell = TRUE;
4695 #endif
4696
4697 #ifdef FEAT_TERMINAL
4698 if (get_term_attr)
4699 {
4700 syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol);
4701
4702 if (!attr_pri)
4703 char_attr = syntax_attr;
4704 else
4705 char_attr = hl_combine_attr(syntax_attr, char_attr);
4706 }
4707 #endif
4708
4709 #ifdef FEAT_SYN_HL
4710 // Get syntax attribute, unless still at the start of the line
4711 // (double-wide char that doesn't fit).
4712 v = (long)(ptr - line);
4713 if (has_syntax && v > 0)
4714 {
4715 /* Get the syntax attribute for the character. If there
4716 * is an error, disable syntax highlighting. */
4717 save_did_emsg = did_emsg;
4718 did_emsg = FALSE;
4719
4720 syntax_attr = get_syntax_attr((colnr_T)v - 1,
4721 # ifdef FEAT_SPELL
4722 has_spell ? &can_spell :
4723 # endif
4724 NULL, FALSE);
4725
4726 if (did_emsg)
4727 {
4728 wp->w_s->b_syn_error = TRUE;
4729 has_syntax = FALSE;
4730 syntax_attr = 0;
4731 }
4732 else
4733 did_emsg = save_did_emsg;
4734
4735 // combine syntax attribute with 'wincolor'
4736 if (win_attr != 0)
4737 syntax_attr = hl_combine_attr(win_attr, syntax_attr);
4738
4739 # ifdef SYN_TIME_LIMIT
4740 if (wp->w_s->b_syn_slow)
4741 has_syntax = FALSE;
4742 # endif
4743
4744 /* Need to get the line again, a multi-line regexp may
4745 * have made it invalid. */
4746 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4747 ptr = line + v;
4748
4749 # ifdef FEAT_TEXT_PROP
4750 // Text properties overrule syntax highlighting or combine.
4751 if (text_prop_attr == 0 || text_prop_combine)
4752 # endif
4753 {
4754 int comb_attr = syntax_attr;
4755 # ifdef FEAT_TEXT_PROP
4756 comb_attr = hl_combine_attr(text_prop_attr, comb_attr);
4757 # endif
4758 if (!attr_pri)
4759 {
4760 #ifdef FEAT_SYN_HL
4761 if (cul_attr)
4762 char_attr = hl_combine_attr(
4763 comb_attr, cul_attr);
4764 else
4765 #endif
4766 if (line_attr)
4767 char_attr = hl_combine_attr(
4768 comb_attr, line_attr);
4769 else
4770 char_attr = comb_attr;
4771 }
4772 else
4773 char_attr = hl_combine_attr(comb_attr, char_attr);
4774 }
4775 # ifdef FEAT_CONCEAL
4776 // no concealing past the end of the line, it interferes
4777 // with line highlighting
4778 if (c == NUL)
4779 syntax_flags = 0;
4780 else
4781 syntax_flags = get_syntax_info(&syntax_seqnr);
4782 # endif
4783 }
4784 #endif
4785
4786 #ifdef FEAT_SPELL
4787 /* Check spelling (unless at the end of the line).
4788 * Only do this when there is no syntax highlighting, the
4789 * @Spell cluster is not used or the current syntax item
4790 * contains the @Spell cluster. */
4791 if (has_spell && v >= word_end && v > cur_checked_col)
4792 {
4793 spell_attr = 0;
4794 if (c != 0 && (
4795 # ifdef FEAT_SYN_HL
4796 !has_syntax ||
4797 # endif
4798 can_spell))
4799 {
4800 char_u *prev_ptr, *p;
4801 int len;
4802 hlf_T spell_hlf = HLF_COUNT;
4803 if (has_mbyte)
4804 {
4805 prev_ptr = ptr - mb_l;
4806 v -= mb_l - 1;
4807 }
4808 else
4809 prev_ptr = ptr - 1;
4810
4811 /* Use nextline[] if possible, it has the start of the
4812 * next line concatenated. */
4813 if ((prev_ptr - line) - nextlinecol >= 0)
4814 p = nextline + (prev_ptr - line) - nextlinecol;
4815 else
4816 p = prev_ptr;
4817 cap_col -= (int)(prev_ptr - line);
4818 len = spell_check(wp, p, &spell_hlf, &cap_col,
4819 nochange);
4820 word_end = v + len;
4821
4822 /* In Insert mode only highlight a word that
4823 * doesn't touch the cursor. */
4824 if (spell_hlf != HLF_COUNT
4825 && (State & INSERT) != 0
4826 && wp->w_cursor.lnum == lnum
4827 && wp->w_cursor.col >=
4828 (colnr_T)(prev_ptr - line)
4829 && wp->w_cursor.col < (colnr_T)word_end)
4830 {
4831 spell_hlf = HLF_COUNT;
4832 spell_redraw_lnum = lnum;
4833 }
4834
4835 if (spell_hlf == HLF_COUNT && p != prev_ptr
4836 && (p - nextline) + len > nextline_idx)
4837 {
4838 /* Remember that the good word continues at the
4839 * start of the next line. */
4840 checked_lnum = lnum + 1;
4841 checked_col = (int)((p - nextline) + len - nextline_idx);
4842 }
4843
4844 /* Turn index into actual attributes. */
4845 if (spell_hlf != HLF_COUNT)
4846 spell_attr = highlight_attr[spell_hlf];
4847
4848 if (cap_col > 0)
4849 {
4850 if (p != prev_ptr
4851 && (p - nextline) + cap_col >= nextline_idx)
4852 {
4853 /* Remember that the word in the next line
4854 * must start with a capital. */
4855 capcol_lnum = lnum + 1;
4856 cap_col = (int)((p - nextline) + cap_col
4857 - nextline_idx);
4858 }
4859 else
4860 /* Compute the actual column. */
4861 cap_col += (int)(prev_ptr - line);
4862 }
4863 }
4864 }
4865 if (spell_attr != 0)
4866 {
4867 if (!attr_pri)
4868 char_attr = hl_combine_attr(char_attr, spell_attr);
4869 else
4870 char_attr = hl_combine_attr(spell_attr, char_attr);
4871 }
4872 #endif
4873 #ifdef FEAT_LINEBREAK
4874 /*
4875 * Found last space before word: check for line break.
4876 */
4877 if (wp->w_p_lbr && c0 == c
4878 && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr))
4879 {
4880 int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0;
4881 char_u *p = ptr - (mb_off + 1);
4882
4883 /* TODO: is passing p for start of the line OK? */
4884 n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
4885 NULL) - 1;
4886 if (c == TAB && n_extra + col > wp->w_width)
4887 # ifdef FEAT_VARTABS
4888 n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
4889 wp->w_buffer->b_p_vts_array) - 1;
4890 # else
4891 n_extra = (int)wp->w_buffer->b_p_ts
4892 - vcol % (int)wp->w_buffer->b_p_ts - 1;
4893 # endif
4894
4895 c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
4896 c_final = NUL;
4897 if (VIM_ISWHITE(c))
4898 {
4899 #ifdef FEAT_CONCEAL
4900 if (c == TAB)
4901 /* See "Tab alignment" below. */
4902 FIX_FOR_BOGUSCOLS;
4903 #endif
4904 if (!wp->w_p_list)
4905 c = ' ';
4906 }
4907 }
4908 #endif
4909
4910 // 'list': Change char 160 to lcs_nbsp and space to lcs_space.
4911 // But not when the character is followed by a composing
4912 // character (use mb_l to check that).
4913 if (wp->w_p_list
4914 && ((((c == 160 && mb_l == 1)
4915 || (mb_utf8
4916 && ((mb_c == 160 && mb_l == 2)
4917 || (mb_c == 0x202f && mb_l == 3))))
4918 && lcs_nbsp)
4919 || (c == ' '
4920 && mb_l == 1
4921 && lcs_space
4922 && ptr - line <= trailcol)))
4923 {
4924 c = (c == ' ') ? lcs_space : lcs_nbsp;
4925 if (area_attr == 0 && search_attr == 0)
4926 {
4927 n_attr = 1;
4928 extra_attr = HL_ATTR(HLF_8);
4929 saved_attr2 = char_attr; /* save current attr */
4930 }
4931 mb_c = c;
4932 if (enc_utf8 && utf_char2len(c) > 1)
4933 {
4934 mb_utf8 = TRUE;
4935 u8cc[0] = 0;
4936 c = 0xc0;
4937 }
4938 else
4939 mb_utf8 = FALSE;
4940 }
4941
4942 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
4943 {
4944 c = lcs_trail;
4945 if (!attr_pri)
4946 {
4947 n_attr = 1;
4948 extra_attr = HL_ATTR(HLF_8);
4949 saved_attr2 = char_attr; /* save current attr */
4950 }
4951 mb_c = c;
4952 if (enc_utf8 && utf_char2len(c) > 1)
4953 {
4954 mb_utf8 = TRUE;
4955 u8cc[0] = 0;
4956 c = 0xc0;
4957 }
4958 else
4959 mb_utf8 = FALSE;
4960 }
4961 }
4962
4963 /*
4964 * Handling of non-printable characters.
4965 */
4966 if (!vim_isprintc(c))
4967 {
4968 /*
4969 * when getting a character from the file, we may have to
4970 * turn it into something else on the way to putting it
4971 * into "ScreenLines".
4972 */
4973 if (c == TAB && (!wp->w_p_list || lcs_tab1))
4974 {
4975 int tab_len = 0;
4976 long vcol_adjusted = vcol; /* removed showbreak length */
4977 #ifdef FEAT_LINEBREAK
4978 /* only adjust the tab_len, when at the first column
4979 * after the showbreak value was drawn */
4980 if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap)
4981 vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
4982 #endif
4983 // tab amount depends on current column
4984 #ifdef FEAT_VARTABS
4985 tab_len = tabstop_padding(vcol_adjusted,
4986 wp->w_buffer->b_p_ts,
4987 wp->w_buffer->b_p_vts_array) - 1;
4988 #else
4989 tab_len = (int)wp->w_buffer->b_p_ts
4990 - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
4991 #endif
4992
4993 #ifdef FEAT_LINEBREAK
4994 if (!wp->w_p_lbr || !wp->w_p_list)
4995 #endif
4996 // tab amount depends on current column
4997 n_extra = tab_len;
4998 #ifdef FEAT_LINEBREAK
4999 else
5000 {
5001 char_u *p;
5002 int len;
5003 int i;
5004 int saved_nextra = n_extra;
5005
5006 #ifdef FEAT_CONCEAL
5007 if (vcol_off > 0)
5008 // there are characters to conceal
5009 tab_len += vcol_off;
5010 // boguscols before FIX_FOR_BOGUSCOLS macro from above
5011 if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
5012 && n_extra > tab_len)
5013 tab_len += n_extra - tab_len;
5014 #endif
5015
5016 // if n_extra > 0, it gives the number of chars, to
5017 // use for a tab, else we need to calculate the width
5018 // for a tab
5019 len = (tab_len * mb_char2len(lcs_tab2));
5020 if (n_extra > 0)
5021 len += n_extra - tab_len;
5022 c = lcs_tab1;
5023 p = alloc(len + 1);
5024 vim_memset(p, ' ', len);
5025 p[len] = NUL;
5026 vim_free(p_extra_free);
5027 p_extra_free = p;
5028 for (i = 0; i < tab_len; i++)
5029 {
5030 int lcs = lcs_tab2;
5031
5032 if (*p == NUL)
5033 {
5034 tab_len = i;
5035 break;
5036 }
5037
5038 // if lcs_tab3 is given, need to change the char
5039 // for tab
5040 if (lcs_tab3 && i == tab_len - 1)
5041 lcs = lcs_tab3;
5042 mb_char2bytes(lcs, p);
5043 p += mb_char2len(lcs);
5044 n_extra += mb_char2len(lcs)
5045 - (saved_nextra > 0 ? 1 : 0);
5046 }
5047 p_extra = p_extra_free;
5048 #ifdef FEAT_CONCEAL
5049 // n_extra will be increased by FIX_FOX_BOGUSCOLS
5050 // macro below, so need to adjust for that here
5051 if (vcol_off > 0)
5052 n_extra -= vcol_off;
5053 #endif
5054 }
5055 #endif
5056 #ifdef FEAT_CONCEAL
5057 {
5058 int vc_saved = vcol_off;
5059
5060 /* Tab alignment should be identical regardless of
5061 * 'conceallevel' value. So tab compensates of all
5062 * previous concealed characters, and thus resets
5063 * vcol_off and boguscols accumulated so far in the
5064 * line. Note that the tab can be longer than
5065 * 'tabstop' when there are concealed characters. */
5066 FIX_FOR_BOGUSCOLS;
5067
5068 /* Make sure, the highlighting for the tab char will be
5069 * correctly set further below (effectively reverts the
5070 * FIX_FOR_BOGSUCOLS macro */
5071 if (n_extra == tab_len + vc_saved && wp->w_p_list
5072 && lcs_tab1)
5073 tab_len += vc_saved;
5074 }
5075 #endif
5076 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5077 if (wp->w_p_list)
5078 {
5079 c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
5080 #ifdef FEAT_LINEBREAK
5081 if (wp->w_p_lbr)
5082 c_extra = NUL; /* using p_extra from above */
5083 else
5084 #endif
5085 c_extra = lcs_tab2;
5086 c_final = lcs_tab3;
5087 n_attr = tab_len + 1;
5088 extra_attr = HL_ATTR(HLF_8);
5089 saved_attr2 = char_attr; /* save current attr */
5090 mb_c = c;
5091 if (enc_utf8 && utf_char2len(c) > 1)
5092 {
5093 mb_utf8 = TRUE;
5094 u8cc[0] = 0;
5095 c = 0xc0;
5096 }
5097 }
5098 else
5099 {
5100 c_final = NUL;
5101 c_extra = ' ';
5102 c = ' ';
5103 }
5104 }
5105 else if (c == NUL
5106 && (wp->w_p_list
5107 || ((fromcol >= 0 || fromcol_prev >= 0)
5108 && tocol > vcol
5109 && VIsual_mode != Ctrl_V
5110 && (
5111 # ifdef FEAT_RIGHTLEFT
5112 wp->w_p_rl ? (col >= 0) :
5113 # endif
5114 (col < wp->w_width))
5115 && !(noinvcur
5116 && lnum == wp->w_cursor.lnum
5117 && (colnr_T)vcol == wp->w_virtcol)))
5118 && lcs_eol_one > 0)
5119 {
5120 /* Display a '$' after the line or highlight an extra
5121 * character if the line break is included. */
5122 #if defined(FEAT_DIFF) || defined(LINE_ATTR)
5123 /* For a diff line the highlighting continues after the
5124 * "$". */
5125 if (
5126 # ifdef FEAT_DIFF
5127 diff_hlf == (hlf_T)0
5128 # ifdef LINE_ATTR
5129 &&
5130 # endif
5131 # endif
5132 # ifdef LINE_ATTR
5133 line_attr == 0
5134 # endif
5135 )
5136 #endif
5137 {
5138 /* In virtualedit, visual selections may extend
5139 * beyond end of line. */
5140 if (area_highlighting && virtual_active()
5141 && tocol != MAXCOL && vcol < tocol)
5142 n_extra = 0;
5143 else
5144 {
5145 p_extra = at_end_str;
5146 n_extra = 1;
5147 c_extra = NUL;
5148 c_final = NUL;
5149 }
5150 }
5151 if (wp->w_p_list && lcs_eol > 0)
5152 c = lcs_eol;
5153 else
5154 c = ' ';
5155 lcs_eol_one = -1;
5156 --ptr; /* put it back at the NUL */
5157 if (!attr_pri)
5158 {
5159 extra_attr = HL_ATTR(HLF_AT);
5160 n_attr = 1;
5161 }
5162 mb_c = c;
5163 if (enc_utf8 && utf_char2len(c) > 1)
5164 {
5165 mb_utf8 = TRUE;
5166 u8cc[0] = 0;
5167 c = 0xc0;
5168 }
5169 else
5170 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5171 }
5172 else if (c != NUL)
5173 {
5174 p_extra = transchar(c);
5175 if (n_extra == 0)
5176 n_extra = byte2cells(c) - 1;
5177 #ifdef FEAT_RIGHTLEFT
5178 if ((dy_flags & DY_UHEX) && wp->w_p_rl)
5179 rl_mirror(p_extra); /* reverse "<12>" */
5180 #endif
5181 c_extra = NUL;
5182 c_final = NUL;
5183 #ifdef FEAT_LINEBREAK
5184 if (wp->w_p_lbr)
5185 {
5186 char_u *p;
5187
5188 c = *p_extra;
5189 p = alloc(n_extra + 1);
5190 vim_memset(p, ' ', n_extra);
5191 STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
5192 p[n_extra] = NUL;
5193 vim_free(p_extra_free);
5194 p_extra_free = p_extra = p;
5195 }
5196 else
5197 #endif
5198 {
5199 n_extra = byte2cells(c) - 1;
5200 c = *p_extra++;
5201 }
5202 if (!attr_pri)
5203 {
5204 n_attr = n_extra + 1;
5205 extra_attr = HL_ATTR(HLF_8);
5206 saved_attr2 = char_attr; /* save current attr */
5207 }
5208 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5209 }
5210 else if (VIsual_active
5211 && (VIsual_mode == Ctrl_V
5212 || VIsual_mode == 'v')
5213 && virtual_active()
5214 && tocol != MAXCOL
5215 && vcol < tocol
5216 && (
5217 #ifdef FEAT_RIGHTLEFT
5218 wp->w_p_rl ? (col >= 0) :
5219 #endif
5220 (col < wp->w_width)))
5221 {
5222 c = ' ';
5223 --ptr; /* put it back at the NUL */
5224 }
5225 #if defined(LINE_ATTR)
5226 else if ((
5227 # ifdef FEAT_DIFF
5228 diff_hlf != (hlf_T)0 ||
5229 # endif
5230 # ifdef FEAT_TERMINAL
5231 win_attr != 0 ||
5232 # endif
5233 line_attr != 0
5234 ) && (
5235 # ifdef FEAT_RIGHTLEFT
5236 wp->w_p_rl ? (col >= 0) :
5237 # endif
5238 (col
5239 # ifdef FEAT_CONCEAL
5240 - boguscols
5241 # endif
5242 < wp->w_width)))
5243 {
5244 /* Highlight until the right side of the window */
5245 c = ' ';
5246 --ptr; /* put it back at the NUL */
5247
5248 /* Remember we do the char for line highlighting. */
5249 ++did_line_attr;
5250
5251 /* don't do search HL for the rest of the line */
5252 if (line_attr != 0 && char_attr == search_attr
5253 && (did_line_attr > 1
5254 || (wp->w_p_list && lcs_eol > 0)))
5255 char_attr = line_attr;
5256 # ifdef FEAT_DIFF
5257 if (diff_hlf == HLF_TXD)
5258 {
5259 diff_hlf = HLF_CHD;
5260 if (vi_attr == 0 || char_attr != vi_attr)
5261 {
5262 char_attr = HL_ATTR(diff_hlf);
5263 if (wp->w_p_cul && lnum == wp->w_cursor.lnum
5264 && wp->w_p_culopt_flags != CULOPT_NBR
5265 && (!cul_screenline
5266 || (vcol >= left_curline_col
5267 && vcol <= right_curline_col)))
5268 char_attr = hl_combine_attr(
5269 char_attr, HL_ATTR(HLF_CUL));
5270 }
5271 }
5272 # endif
5273 # ifdef FEAT_TERMINAL
5274 if (win_attr != 0)
5275 {
5276 char_attr = win_attr;
5277 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
5278 {
5279 if (!cul_screenline || (vcol >= left_curline_col
5280 && vcol <= right_curline_col))
5281 char_attr = hl_combine_attr(
5282 char_attr, HL_ATTR(HLF_CUL));
5283 }
5284 else if (line_attr)
5285 char_attr = hl_combine_attr(char_attr, line_attr);
5286 }
5287 # endif
5288 }
5289 #endif
5290 }
5291
5292 #ifdef FEAT_CONCEAL
5293 if ( wp->w_p_cole > 0
5294 && (wp != curwin || lnum != wp->w_cursor.lnum ||
5295 conceal_cursor_line(wp))
5296 && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
5297 && !(lnum_in_visual_area
5298 && vim_strchr(wp->w_p_cocu, 'v') == NULL))
5299 {
5300 char_attr = conceal_attr;
5301 if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
5302 && (syn_get_sub_char() != NUL || match_conc
5303 || wp->w_p_cole == 1)
5304 && wp->w_p_cole != 3)
5305 {
5306 /* First time at this concealed item: display one
5307 * character. */
5308 if (match_conc)
5309 c = match_conc;
5310 else if (syn_get_sub_char() != NUL)
5311 c = syn_get_sub_char();
5312 else if (lcs_conceal != NUL)
5313 c = lcs_conceal;
5314 else
5315 c = ' ';
5316
5317 prev_syntax_id = syntax_seqnr;
5318
5319 if (n_extra > 0)
5320 vcol_off += n_extra;
5321 vcol += n_extra;
5322 if (wp->w_p_wrap && n_extra > 0)
5323 {
5324 # ifdef FEAT_RIGHTLEFT
5325 if (wp->w_p_rl)
5326 {
5327 col -= n_extra;
5328 boguscols -= n_extra;
5329 }
5330 else
5331 # endif
5332 {
5333 boguscols += n_extra;
5334 col += n_extra;
5335 }
5336 }
5337 n_extra = 0;
5338 n_attr = 0;
5339 }
5340 else if (n_skip == 0)
5341 {
5342 is_concealing = TRUE;
5343 n_skip = 1;
5344 }
5345 mb_c = c;
5346 if (enc_utf8 && utf_char2len(c) > 1)
5347 {
5348 mb_utf8 = TRUE;
5349 u8cc[0] = 0;
5350 c = 0xc0;
5351 }
5352 else
5353 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5354 }
5355 else
5356 {
5357 prev_syntax_id = 0;
5358 is_concealing = FALSE;
5359 }
5360
5361 if (n_skip > 0 && did_decrement_ptr)
5362 // not showing the '>', put pointer back to avoid getting stuck
5363 ++ptr;
5364
5365 #endif // FEAT_CONCEAL
5366 }
5367
5368 #ifdef FEAT_CONCEAL
5369 /* In the cursor line and we may be concealing characters: correct
5370 * the cursor column when we reach its position. */
5371 if (!did_wcol && draw_state == WL_LINE
5372 && wp == curwin && lnum == wp->w_cursor.lnum
5373 && conceal_cursor_line(wp)
5374 && (int)wp->w_virtcol <= vcol + n_skip)
5375 {
5376 # ifdef FEAT_RIGHTLEFT
5377 if (wp->w_p_rl)
5378 wp->w_wcol = wp->w_width - col + boguscols - 1;
5379 else
5380 # endif
5381 wp->w_wcol = col - boguscols;
5382 wp->w_wrow = row;
5383 did_wcol = TRUE;
5384 curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
5385 }
5386 #endif
5387
5388 /* Don't override visual selection highlighting. */
5389 if (n_attr > 0
5390 && draw_state == WL_LINE
5391 && !attr_pri)
5392 {
5393 #ifdef LINE_ATTR
5394 if (line_attr)
5395 char_attr = hl_combine_attr(extra_attr, line_attr);
5396 else
5397 #endif
5398 char_attr = extra_attr;
5399 }
5400
5401 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
5402 /* XIM don't send preedit_start and preedit_end, but they send
5403 * preedit_changed and commit. Thus Vim can't set "im_is_active", use
5404 * im_is_preediting() here. */
5405 if (p_imst == IM_ON_THE_SPOT
5406 && xic != NULL
5407 && lnum == wp->w_cursor.lnum
5408 && (State & INSERT)
5409 && !p_imdisable
5410 && im_is_preediting()
5411 && draw_state == WL_LINE)
5412 {
5413 colnr_T tcol;
5414
5415 if (preedit_end_col == MAXCOL)
5416 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
5417 else
5418 tcol = preedit_end_col;
5419 if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
5420 {
5421 if (feedback_old_attr < 0)
5422 {
5423 feedback_col = 0;
5424 feedback_old_attr = char_attr;
5425 }
5426 char_attr = im_get_feedback_attr(feedback_col);
5427 if (char_attr < 0)
5428 char_attr = feedback_old_attr;
5429 feedback_col++;
5430 }
5431 else if (feedback_old_attr >= 0)
5432 {
5433 char_attr = feedback_old_attr;
5434 feedback_old_attr = -1;
5435 feedback_col = 0;
5436 }
5437 }
5438 #endif
5439 /*
5440 * Handle the case where we are in column 0 but not on the first
5441 * character of the line and the user wants us to show us a
5442 * special character (via 'listchars' option "precedes:<char>".
5443 */
5444 if (lcs_prec_todo != NUL
5445 && wp->w_p_list
5446 && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
5447 #ifdef FEAT_DIFF
5448 && filler_todo <= 0
5449 #endif
5450 && draw_state > WL_NR
5451 && c != NUL)
5452 {
5453 c = lcs_prec;
5454 lcs_prec_todo = NUL;
5455 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5456 {
5457 /* Double-width character being overwritten by the "precedes"
5458 * character, need to fill up half the character. */
5459 c_extra = MB_FILLER_CHAR;
5460 c_final = NUL;
5461 n_extra = 1;
5462 n_attr = 2;
5463 extra_attr = HL_ATTR(HLF_AT);
5464 }
5465 mb_c = c;
5466 if (enc_utf8 && utf_char2len(c) > 1)
5467 {
5468 mb_utf8 = TRUE;
5469 u8cc[0] = 0;
5470 c = 0xc0;
5471 }
5472 else
5473 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5474 if (!attr_pri)
5475 {
5476 saved_attr3 = char_attr; /* save current attr */
5477 char_attr = HL_ATTR(HLF_AT); /* later copied to char_attr */
5478 n_attr3 = 1;
5479 }
5480 }
5481
5482 /*
5483 * At end of the text line or just after the last character.
5484 */
5485 if ((c == NUL
5486 #if defined(LINE_ATTR)
5487 || did_line_attr == 1
5488 #endif
5489 ) && eol_hl_off == 0)
5490 {
5491 #ifdef FEAT_SEARCH_EXTRA
5492 // flag to indicate whether prevcol equals startcol of search_hl or
5493 // one of the matches
5494 int prevcol_hl_flag = get_prevcol_hl_flag(wp, &search_hl,
5495 (long)(ptr - line) - (c == NUL));
5496 #endif
5497 // Invert at least one char, used for Visual and empty line or
5498 // highlight match at end of line. If it's beyond the last
5499 // char on the screen, just overwrite that one (tricky!) Not
5500 // needed when a '$' was displayed for 'list'.
5501 if (lcs_eol == lcs_eol_one
5502 && ((area_attr != 0 && vcol == fromcol
5503 && (VIsual_mode != Ctrl_V
5504 || lnum == VIsual.lnum
5505 || lnum == curwin->w_cursor.lnum)
5506 && c == NUL)
5507 #ifdef FEAT_SEARCH_EXTRA
5508 // highlight 'hlsearch' match at end of line
5509 || (prevcol_hl_flag
5510 # ifdef FEAT_SYN_HL
5511 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
5512 && !(wp == curwin && VIsual_active))
5513 # endif
5514 # ifdef FEAT_DIFF
5515 && diff_hlf == (hlf_T)0
5516 # endif
5517 # if defined(LINE_ATTR)
5518 && did_line_attr <= 1
5519 # endif
5520 )
5521 #endif
5522 ))
5523 {
5524 int n = 0;
5525
5526 #ifdef FEAT_RIGHTLEFT
5527 if (wp->w_p_rl)
5528 {
5529 if (col < 0)
5530 n = 1;
5531 }
5532 else
5533 #endif
5534 {
5535 if (col >= wp->w_width)
5536 n = -1;
5537 }
5538 if (n != 0)
5539 {
5540 /* At the window boundary, highlight the last character
5541 * instead (better than nothing). */
5542 off += n;
5543 col += n;
5544 }
5545 else
5546 {
5547 /* Add a blank character to highlight. */
5548 ScreenLines[off] = ' ';
5549 if (enc_utf8)
5550 ScreenLinesUC[off] = 0;
5551 }
5552 #ifdef FEAT_SEARCH_EXTRA
5553 if (area_attr == 0)
5554 {
5555 // Use attributes from match with highest priority among
5556 // 'search_hl' and the match list.
5557 get_search_match_hl(wp, &search_hl,
5558 (long)(ptr - line), &char_attr);
5559 }
5560 #endif
5561 ScreenAttrs[off] = char_attr;
5562 #ifdef FEAT_RIGHTLEFT
5563 if (wp->w_p_rl)
5564 {
5565 --col;
5566 --off;
5567 }
5568 else
5569 #endif
5570 {
5571 ++col;
5572 ++off;
5573 }
5574 ++vcol;
5575 eol_hl_off = 1;
5576 }
5577 }
5578
5579 /*
5580 * At end of the text line.
5581 */
5582 if (c == NUL)
5583 {
5584 #ifdef FEAT_SYN_HL
5585 /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */
5586 if (wp->w_p_wrap)
5587 v = wp->w_skipcol;
5588 else
5589 v = wp->w_leftcol;
5590
5591 /* check if line ends before left margin */
5592 if (vcol < v + col - win_col_off(wp))
5593 vcol = v + col - win_col_off(wp);
5594 #ifdef FEAT_CONCEAL
5595 // Get rid of the boguscols now, we want to draw until the right
5596 // edge for 'cursorcolumn'.
5597 col -= boguscols;
5598 boguscols = 0;
5599 #endif
5600
5601 if (draw_color_col)
5602 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
5603
5604 if (((wp->w_p_cuc
5605 && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
5606 && (int)wp->w_virtcol <
5607 wp->w_width * (row - startrow + 1) + v
5608 && lnum != wp->w_cursor.lnum)
5609 || draw_color_col
5610 || win_attr != 0)
5611 # ifdef FEAT_RIGHTLEFT
5612 && !wp->w_p_rl
5613 # endif
5614 )
5615 {
5616 int rightmost_vcol = 0;
5617 int i;
5618
5619 if (wp->w_p_cuc)
5620 rightmost_vcol = wp->w_virtcol;
5621 if (draw_color_col)
5622 /* determine rightmost colorcolumn to possibly draw */
5623 for (i = 0; color_cols[i] >= 0; ++i)
5624 if (rightmost_vcol < color_cols[i])
5625 rightmost_vcol = color_cols[i];
5626
5627 while (col < wp->w_width)
5628 {
5629 ScreenLines[off] = ' ';
5630 if (enc_utf8)
5631 ScreenLinesUC[off] = 0;
5632 ++col;
5633 if (draw_color_col)
5634 draw_color_col = advance_color_col(VCOL_HLC,
5635 &color_cols);
5636
5637 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol)
5638 ScreenAttrs[off++] = HL_ATTR(HLF_CUC);
5639 else if (draw_color_col && VCOL_HLC == *color_cols)
5640 ScreenAttrs[off++] = HL_ATTR(HLF_MC);
5641 else
5642 ScreenAttrs[off++] = win_attr;
5643
5644 if (VCOL_HLC >= rightmost_vcol && win_attr == 0)
5645 break;
5646
5647 ++vcol;
5648 }
5649 }
5650 #endif
5651
5652 screen_line(screen_row, wp->w_wincol, col,
5653 (int)wp->w_width, screen_line_flags);
5654 row++;
5655
5656 /*
5657 * Update w_cline_height and w_cline_folded if the cursor line was
5658 * updated (saves a call to plines() later).
5659 */
5660 if (wp == curwin && lnum == curwin->w_cursor.lnum)
5661 {
5662 curwin->w_cline_row = startrow;
5663 curwin->w_cline_height = row - startrow;
5664 #ifdef FEAT_FOLDING
5665 curwin->w_cline_folded = FALSE;
5666 #endif
5667 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
5668 }
5669
5670 break;
5671 }
5672
5673 // Show "extends" character from 'listchars' if beyond the line end and
5674 // 'list' is set.
5675 if (lcs_ext != NUL
5676 && wp->w_p_list
5677 && !wp->w_p_wrap
5678 #ifdef FEAT_DIFF
5679 && filler_todo <= 0
5680 #endif
5681 && (
5682 #ifdef FEAT_RIGHTLEFT
5683 wp->w_p_rl ? col == 0 :
5684 #endif
5685 col == wp->w_width - 1)
5686 && (*ptr != NUL
5687 || (wp->w_p_list && lcs_eol_one > 0)
5688 || (n_extra && (c_extra != NUL || *p_extra != NUL))))
5689 {
5690 c = lcs_ext;
5691 char_attr = HL_ATTR(HLF_AT);
5692 mb_c = c;
5693 if (enc_utf8 && utf_char2len(c) > 1)
5694 {
5695 mb_utf8 = TRUE;
5696 u8cc[0] = 0;
5697 c = 0xc0;
5698 }
5699 else
5700 mb_utf8 = FALSE;
5701 }
5702
5703 #ifdef FEAT_SYN_HL
5704 /* advance to the next 'colorcolumn' */
5705 if (draw_color_col)
5706 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
5707
5708 /* Highlight the cursor column if 'cursorcolumn' is set. But don't
5709 * highlight the cursor position itself.
5710 * Also highlight the 'colorcolumn' if it is different than
5711 * 'cursorcolumn' */
5712 vcol_save_attr = -1;
5713 if (draw_state == WL_LINE && !lnum_in_visual_area
5714 && search_attr == 0 && area_attr == 0)
5715 {
5716 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
5717 && lnum != wp->w_cursor.lnum)
5718 {
5719 vcol_save_attr = char_attr;
5720 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC));
5721 }
5722 else if (draw_color_col && VCOL_HLC == *color_cols)
5723 {
5724 vcol_save_attr = char_attr;
5725 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC));
5726 }
5727 }
5728 #endif
5729
5730 /*
5731 * Store character to be displayed.
5732 * Skip characters that are left of the screen for 'nowrap'.
5733 */
5734 vcol_prev = vcol;
5735 if (draw_state < WL_LINE || n_skip <= 0)
5736 {
5737 /*
5738 * Store the character.
5739 */
5740 #if defined(FEAT_RIGHTLEFT)
5741 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
5742 {
5743 /* A double-wide character is: put first halve in left cell. */
5744 --off;
5745 --col;
5746 }
5747 #endif
5748 ScreenLines[off] = c;
5749 if (enc_dbcs == DBCS_JPNU)
5750 {
5751 if ((mb_c & 0xff00) == 0x8e00)
5752 ScreenLines[off] = 0x8e;
5753 ScreenLines2[off] = mb_c & 0xff;
5754 }
5755 else if (enc_utf8)
5756 {
5757 if (mb_utf8)
5758 {
5759 int i;
5760
5761 ScreenLinesUC[off] = mb_c;
5762 if ((c & 0xff) == 0)
5763 ScreenLines[off] = 0x80; /* avoid storing zero */
5764 for (i = 0; i < Screen_mco; ++i)
5765 {
5766 ScreenLinesC[i][off] = u8cc[i];
5767 if (u8cc[i] == 0)
5768 break;
5769 }
5770 }
5771 else
5772 ScreenLinesUC[off] = 0;
5773 }
5774 if (multi_attr)
5775 {
5776 ScreenAttrs[off] = multi_attr;
5777 multi_attr = 0;
5778 }
5779 else
5780 ScreenAttrs[off] = char_attr;
5781
5782 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5783 {
5784 /* Need to fill two screen columns. */
5785 ++off;
5786 ++col;
5787 if (enc_utf8)
5788 /* UTF-8: Put a 0 in the second screen char. */
5789 ScreenLines[off] = 0;
5790 else
5791 /* DBCS: Put second byte in the second screen char. */
5792 ScreenLines[off] = mb_c & 0xff;
5793 if (draw_state > WL_NR
5794 #ifdef FEAT_DIFF
5795 && filler_todo <= 0
5796 #endif
5797 )
5798 ++vcol;
5799 /* When "tocol" is halfway a character, set it to the end of
5800 * the character, otherwise highlighting won't stop. */
5801 if (tocol == vcol)
5802 ++tocol;
5803 #ifdef FEAT_RIGHTLEFT
5804 if (wp->w_p_rl)
5805 {
5806 /* now it's time to backup one cell */
5807 --off;
5808 --col;
5809 }
5810 #endif
5811 }
5812 #ifdef FEAT_RIGHTLEFT
5813 if (wp->w_p_rl)
5814 {
5815 --off;
5816 --col;
5817 }
5818 else
5819 #endif
5820 {
5821 ++off;
5822 ++col;
5823 }
5824 }
5825 #ifdef FEAT_CONCEAL
5826 else if (wp->w_p_cole > 0 && is_concealing)
5827 {
5828 --n_skip;
5829 ++vcol_off;
5830 if (n_extra > 0)
5831 vcol_off += n_extra;
5832 if (wp->w_p_wrap)
5833 {
5834 /*
5835 * Special voodoo required if 'wrap' is on.
5836 *
5837 * Advance the column indicator to force the line
5838 * drawing to wrap early. This will make the line
5839 * take up the same screen space when parts are concealed,
5840 * so that cursor line computations aren't messed up.
5841 *
5842 * To avoid the fictitious advance of 'col' causing
5843 * trailing junk to be written out of the screen line
5844 * we are building, 'boguscols' keeps track of the number
5845 * of bad columns we have advanced.
5846 */
5847 if (n_extra > 0)
5848 {
5849 vcol += n_extra;
5850 # ifdef FEAT_RIGHTLEFT
5851 if (wp->w_p_rl)
5852 {
5853 col -= n_extra;
5854 boguscols -= n_extra;
5855 }
5856 else
5857 # endif
5858 {
5859 col += n_extra;
5860 boguscols += n_extra;
5861 }
5862 n_extra = 0;
5863 n_attr = 0;
5864 }
5865
5866
5867 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5868 {
5869 /* Need to fill two screen columns. */
5870 # ifdef FEAT_RIGHTLEFT
5871 if (wp->w_p_rl)
5872 {
5873 --boguscols;
5874 --col;
5875 }
5876 else
5877 # endif
5878 {
5879 ++boguscols;
5880 ++col;
5881 }
5882 }
5883
5884 # ifdef FEAT_RIGHTLEFT
5885 if (wp->w_p_rl)
5886 {
5887 --boguscols;
5888 --col;
5889 }
5890 else
5891 # endif
5892 {
5893 ++boguscols;
5894 ++col;
5895 }
5896 }
5897 else
5898 {
5899 if (n_extra > 0)
5900 {
5901 vcol += n_extra;
5902 n_extra = 0;
5903 n_attr = 0;
5904 }
5905 }
5906
5907 }
5908 #endif /* FEAT_CONCEAL */
5909 else
5910 --n_skip;
5911
5912 /* Only advance the "vcol" when after the 'number' or 'relativenumber'
5913 * column. */
5914 if (draw_state > WL_NR
5915 #ifdef FEAT_DIFF
5916 && filler_todo <= 0
5917 #endif
5918 )
5919 ++vcol;
5920
5921 #ifdef FEAT_SYN_HL
5922 if (vcol_save_attr >= 0)
5923 char_attr = vcol_save_attr;
5924 #endif
5925
5926 /* restore attributes after "predeces" in 'listchars' */
5927 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
5928 char_attr = saved_attr3;
5929
5930 /* restore attributes after last 'listchars' or 'number' char */
5931 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
5932 char_attr = saved_attr2;
5933
5934 /*
5935 * At end of screen line and there is more to come: Display the line
5936 * so far. If there is no more to display it is caught above.
5937 */
5938 if ((
5939 #ifdef FEAT_RIGHTLEFT
5940 wp->w_p_rl ? (col < 0) :
5941 #endif
5942 (col >= wp->w_width))
5943 && (*ptr != NUL
5944 #ifdef FEAT_DIFF
5945 || filler_todo > 0
5946 #endif
5947 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
5948 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
5949 )
5950 {
5951 #ifdef FEAT_CONCEAL
5952 screen_line(screen_row, wp->w_wincol, col - boguscols,
5953 (int)wp->w_width, screen_line_flags);
5954 boguscols = 0;
5955 #else
5956 screen_line(screen_row, wp->w_wincol, col,
5957 (int)wp->w_width, screen_line_flags);
5958 #endif
5959 ++row;
5960 ++screen_row;
5961
5962 /* When not wrapping and finished diff lines, or when displayed
5963 * '$' and highlighting until last column, break here. */
5964 if ((!wp->w_p_wrap
5965 #ifdef FEAT_DIFF
5966 && filler_todo <= 0
5967 #endif
5968 ) || lcs_eol_one == -1)
5969 break;
5970
5971 /* When the window is too narrow draw all "@" lines. */
5972 if (draw_state != WL_LINE
5973 #ifdef FEAT_DIFF
5974 && filler_todo <= 0
5975 #endif
5976 )
5977 {
5978 win_draw_end(wp, '@', ' ', TRUE, row, wp->w_height, HLF_AT);
5979 draw_vsep_win(wp, row);
5980 row = endrow;
5981 }
5982
5983 /* When line got too long for screen break here. */
5984 if (row == endrow)
5985 {
5986 ++row;
5987 break;
5988 }
5989
5990 if (screen_cur_row == screen_row - 1
5991 #ifdef FEAT_DIFF
5992 && filler_todo <= 0
5993 #endif
5994 && wp->w_width == Columns)
5995 {
5996 /* Remember that the line wraps, used for modeless copy. */
5997 LineWraps[screen_row - 1] = TRUE;
5998
5999 /*
6000 * Special trick to make copy/paste of wrapped lines work with
6001 * xterm/screen: write an extra character beyond the end of
6002 * the line. This will work with all terminal types
6003 * (regardless of the xn,am settings).
6004 * Only do this on a fast tty.
6005 * Only do this if the cursor is on the current line
6006 * (something has been written in it).
6007 * Don't do this for the GUI.
6008 * Don't do this for double-width characters.
6009 * Don't do this for a window not at the right screen border.
6010 */
6011 if (p_tf
6012 #ifdef FEAT_GUI
6013 && !gui.in_use
6014 #endif
6015 && !(has_mbyte
6016 && ((*mb_off2cells)(LineOffset[screen_row],
6017 LineOffset[screen_row] + screen_Columns)
6018 == 2
6019 || (*mb_off2cells)(LineOffset[screen_row - 1]
6020 + (int)Columns - 2,
6021 LineOffset[screen_row] + screen_Columns)
6022 == 2)))
6023 {
6024 /* First make sure we are at the end of the screen line,
6025 * then output the same character again to let the
6026 * terminal know about the wrap. If the terminal doesn't
6027 * auto-wrap, we overwrite the character. */
6028 if (screen_cur_col != wp->w_width)
6029 screen_char(LineOffset[screen_row - 1]
6030 + (unsigned)Columns - 1,
6031 screen_row - 1, (int)(Columns - 1));
6032
6033 /* When there is a multi-byte character, just output a
6034 * space to keep it simple. */
6035 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
6036 screen_row - 1] + (Columns - 1)]) > 1)
6037 out_char(' ');
6038 else
6039 out_char(ScreenLines[LineOffset[screen_row - 1]
6040 + (Columns - 1)]);
6041 /* force a redraw of the first char on the next line */
6042 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
6043 screen_start(); /* don't know where cursor is now */
6044 }
6045 }
6046
6047 col = 0;
6048 off = (unsigned)(current_ScreenLine - ScreenLines);
6049 #ifdef FEAT_RIGHTLEFT
6050 if (wp->w_p_rl)
6051 {
6052 col = wp->w_width - 1; /* col is not used if breaking! */
6053 off += col;
6054 }
6055 #endif
6056
6057 /* reset the drawing state for the start of a wrapped line */
6058 draw_state = WL_START;
6059 saved_n_extra = n_extra;
6060 saved_p_extra = p_extra;
6061 saved_c_extra = c_extra;
6062 saved_c_final = c_final;
6063 #ifdef FEAT_SYN_HL
6064 if (!(cul_screenline
6065 # ifdef FEAT_DIFF
6066 && diff_hlf == (hlf_T)0)
6067 # endif
6068 )
6069 saved_char_attr = char_attr;
6070 else
6071 #endif
6072 saved_char_attr = 0;
6073 n_extra = 0;
6074 lcs_prec_todo = lcs_prec;
6075 #ifdef FEAT_LINEBREAK
6076 # ifdef FEAT_DIFF
6077 if (filler_todo <= 0)
6078 # endif
6079 need_showbreak = TRUE;
6080 #endif
6081 #ifdef FEAT_DIFF
6082 --filler_todo;
6083 /* When the filler lines are actually below the last line of the
6084 * file, don't draw the line itself, break here. */
6085 if (filler_todo == 0 && wp->w_botfill)
6086 break;
6087 #endif
6088 }
6089
6090 } /* for every character in the line */
6091
6092 #ifdef FEAT_SPELL
6093 /* After an empty line check first word for capital. */
6094 if (*skipwhite(line) == NUL)
6095 {
6096 capcol_lnum = lnum + 1;
6097 cap_col = 0;
6098 }
6099 #endif
6100 #ifdef FEAT_TEXT_PROP
6101 vim_free(text_props);
6102 vim_free(text_prop_idxs);
6103 #endif
6104
6105 vim_free(p_extra_free);
6106 return row;
6107 }
6108 290
6109 /* 291 /*
6110 * Return if the composing characters at "off_from" and "off_to" differ. 292 * Return if the composing characters at "off_from" and "off_to" differ.
6111 * Only to be used when ScreenLinesUC[off_from] != 0. 293 * Only to be used when ScreenLinesUC[off_from] != 0.
6112 */ 294 */
6180 return FALSE; 362 return FALSE;
6181 off = row * screen_Columns + col; 363 off = row * screen_Columns + col;
6182 return popup_mask[off] > screen_zindex || popup_transparent[off]; 364 return popup_mask[off] > screen_zindex || popup_transparent[off];
6183 } 365 }
6184 #endif 366 #endif
367
368 /*
369 * Reset the highlighting. Used before clearing the screen.
370 */
371 void
372 reset_screen_attr(void)
373 {
374 #ifdef FEAT_GUI
375 if (gui.in_use)
376 // Use a code that will reset gui.highlight_mask in
377 // gui_stop_highlight().
378 screen_attr = HL_ALL + 1;
379 else
380 #endif
381 // Use attributes that is very unlikely to appear in text.
382 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
383 }
6185 384
6186 /* 385 /*
6187 * Move one "cooked" screen line to the screen, but only the characters that 386 * Move one "cooked" screen line to the screen, but only the characters that
6188 * have actually changed. Handle insert/delete character. 387 * have actually changed. Handle insert/delete character.
6189 * "coloff" gives the first column on the screen for this line. 388 * "coloff" gives the first column on the screen for this line.
6594 } 793 }
6595 } 794 }
6596 #endif 795 #endif
6597 796
6598 /* 797 /*
6599 * mark all status lines for redraw; used after first :cd 798 * Draw the verticap separator right of window "wp" starting with line "row".
6600 */ 799 */
6601 void 800 void
6602 status_redraw_all(void)
6603 {
6604 win_T *wp;
6605
6606 FOR_ALL_WINDOWS(wp)
6607 if (wp->w_status_height)
6608 {
6609 wp->w_redr_status = TRUE;
6610 redraw_later(VALID);
6611 }
6612 }
6613
6614 /*
6615 * mark all status lines of the current buffer for redraw
6616 */
6617 void
6618 status_redraw_curbuf(void)
6619 {
6620 win_T *wp;
6621
6622 FOR_ALL_WINDOWS(wp)
6623 if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
6624 {
6625 wp->w_redr_status = TRUE;
6626 redraw_later(VALID);
6627 }
6628 }
6629
6630 /*
6631 * Redraw all status lines that need to be redrawn.
6632 */
6633 void
6634 redraw_statuslines(void)
6635 {
6636 win_T *wp;
6637
6638 FOR_ALL_WINDOWS(wp)
6639 if (wp->w_redr_status)
6640 win_redr_status(wp, FALSE);
6641 if (redraw_tabline)
6642 draw_tabline();
6643 }
6644
6645 #if defined(FEAT_WILDMENU) || defined(PROTO)
6646 /*
6647 * Redraw all status lines at the bottom of frame "frp".
6648 */
6649 void
6650 win_redraw_last_status(frame_T *frp)
6651 {
6652 if (frp->fr_layout == FR_LEAF)
6653 frp->fr_win->w_redr_status = TRUE;
6654 else if (frp->fr_layout == FR_ROW)
6655 {
6656 FOR_ALL_FRAMES(frp, frp->fr_child)
6657 win_redraw_last_status(frp);
6658 }
6659 else /* frp->fr_layout == FR_COL */
6660 {
6661 frp = frp->fr_child;
6662 while (frp->fr_next != NULL)
6663 frp = frp->fr_next;
6664 win_redraw_last_status(frp);
6665 }
6666 }
6667 #endif
6668
6669 /*
6670 * Draw the verticap separator right of window "wp" starting with line "row".
6671 */
6672 static void
6673 draw_vsep_win(win_T *wp, int row) 801 draw_vsep_win(win_T *wp, int row)
6674 { 802 {
6675 int hl; 803 int hl;
6676 int c; 804 int c;
6677 805
6954 vim_free(buf); 1082 vim_free(buf);
6955 } 1083 }
6956 #endif 1084 #endif
6957 1085
6958 /* 1086 /*
6959 * Redraw the status line of window wp.
6960 *
6961 * If inversion is possible we use it. Else '=' characters are used.
6962 * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is
6963 * displayed.
6964 */
6965 static void
6966 win_redr_status(win_T *wp, int ignore_pum UNUSED)
6967 {
6968 int row;
6969 char_u *p;
6970 int len;
6971 int fillchar;
6972 int attr;
6973 int this_ru_col;
6974 static int busy = FALSE;
6975
6976 /* It's possible to get here recursively when 'statusline' (indirectly)
6977 * invokes ":redrawstatus". Simply ignore the call then. */
6978 if (busy)
6979 return;
6980 busy = TRUE;
6981
6982 wp->w_redr_status = FALSE;
6983 if (wp->w_status_height == 0)
6984 {
6985 /* no status line, can only be last window */
6986 redraw_cmdline = TRUE;
6987 }
6988 else if (!redrawing()
6989 // don't update status line when popup menu is visible and may be
6990 // drawn over it, unless it will be redrawn later
6991 || (!ignore_pum && pum_visible()))
6992 {
6993 /* Don't redraw right now, do it later. */
6994 wp->w_redr_status = TRUE;
6995 }
6996 #ifdef FEAT_STL_OPT
6997 else if (*p_stl != NUL || *wp->w_p_stl != NUL)
6998 {
6999 /* redraw custom status line */
7000 redraw_custom_statusline(wp);
7001 }
7002 #endif
7003 else
7004 {
7005 fillchar = fillchar_status(&attr, wp);
7006
7007 get_trans_bufname(wp->w_buffer);
7008 p = NameBuff;
7009 len = (int)STRLEN(p);
7010
7011 if (bt_help(wp->w_buffer)
7012 #ifdef FEAT_QUICKFIX
7013 || wp->w_p_pvw
7014 #endif
7015 || bufIsChanged(wp->w_buffer)
7016 || wp->w_buffer->b_p_ro)
7017 *(p + len++) = ' ';
7018 if (bt_help(wp->w_buffer))
7019 {
7020 STRCPY(p + len, _("[Help]"));
7021 len += (int)STRLEN(p + len);
7022 }
7023 #ifdef FEAT_QUICKFIX
7024 if (wp->w_p_pvw)
7025 {
7026 STRCPY(p + len, _("[Preview]"));
7027 len += (int)STRLEN(p + len);
7028 }
7029 #endif
7030 if (bufIsChanged(wp->w_buffer)
7031 #ifdef FEAT_TERMINAL
7032 && !bt_terminal(wp->w_buffer)
7033 #endif
7034 )
7035 {
7036 STRCPY(p + len, "[+]");
7037 len += 3;
7038 }
7039 if (wp->w_buffer->b_p_ro)
7040 {
7041 STRCPY(p + len, _("[RO]"));
7042 len += (int)STRLEN(p + len);
7043 }
7044
7045 this_ru_col = ru_col - (Columns - wp->w_width);
7046 if (this_ru_col < (wp->w_width + 1) / 2)
7047 this_ru_col = (wp->w_width + 1) / 2;
7048 if (this_ru_col <= 1)
7049 {
7050 p = (char_u *)"<"; /* No room for file name! */
7051 len = 1;
7052 }
7053 else if (has_mbyte)
7054 {
7055 int clen = 0, i;
7056
7057 /* Count total number of display cells. */
7058 clen = mb_string2cells(p, -1);
7059
7060 /* Find first character that will fit.
7061 * Going from start to end is much faster for DBCS. */
7062 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
7063 i += (*mb_ptr2len)(p + i))
7064 clen -= (*mb_ptr2cells)(p + i);
7065 len = clen;
7066 if (i > 0)
7067 {
7068 p = p + i - 1;
7069 *p = '<';
7070 ++len;
7071 }
7072
7073 }
7074 else if (len > this_ru_col - 1)
7075 {
7076 p += len - (this_ru_col - 1);
7077 *p = '<';
7078 len = this_ru_col - 1;
7079 }
7080
7081 row = W_WINROW(wp) + wp->w_height;
7082 screen_puts(p, row, wp->w_wincol, attr);
7083 screen_fill(row, row + 1, len + wp->w_wincol,
7084 this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
7085
7086 if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
7087 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
7088 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
7089 - 1 + wp->w_wincol), attr);
7090
7091 #ifdef FEAT_CMDL_INFO
7092 win_redr_ruler(wp, TRUE, ignore_pum);
7093 #endif
7094 }
7095
7096 /*
7097 * May need to draw the character below the vertical separator.
7098 */
7099 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
7100 {
7101 if (stl_connected(wp))
7102 fillchar = fillchar_status(&attr, wp);
7103 else
7104 fillchar = fillchar_vsep(&attr);
7105 screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
7106 attr);
7107 }
7108 busy = FALSE;
7109 }
7110
7111 #ifdef FEAT_STL_OPT
7112 /*
7113 * Redraw the status line according to 'statusline' and take care of any
7114 * errors encountered.
7115 */
7116 static void
7117 redraw_custom_statusline(win_T *wp)
7118 {
7119 static int entered = FALSE;
7120 int saved_did_emsg = did_emsg;
7121
7122 /* When called recursively return. This can happen when the statusline
7123 * contains an expression that triggers a redraw. */
7124 if (entered)
7125 return;
7126 entered = TRUE;
7127
7128 did_emsg = FALSE;
7129 win_redr_custom(wp, FALSE);
7130 if (did_emsg)
7131 {
7132 /* When there is an error disable the statusline, otherwise the
7133 * display is messed up with errors and a redraw triggers the problem
7134 * again and again. */
7135 set_string_option_direct((char_u *)"statusline", -1,
7136 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
7137 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
7138 }
7139 did_emsg |= saved_did_emsg;
7140 entered = FALSE;
7141 }
7142 #endif
7143
7144 /*
7145 * Return TRUE if the status line of window "wp" is connected to the status 1087 * Return TRUE if the status line of window "wp" is connected to the status
7146 * line of the window right of it. If not, then it's a vertical separator. 1088 * line of the window right of it. If not, then it's a vertical separator.
7147 * Only call if (wp->w_vsep_width != 0). 1089 * Only call if (wp->w_vsep_width != 0).
7148 */ 1090 */
7149 int 1091 int
7221 #if defined(FEAT_STL_OPT) || defined(PROTO) 1163 #if defined(FEAT_STL_OPT) || defined(PROTO)
7222 /* 1164 /*
7223 * Redraw the status line or ruler of window "wp". 1165 * Redraw the status line or ruler of window "wp".
7224 * When "wp" is NULL redraw the tab pages line from 'tabline'. 1166 * When "wp" is NULL redraw the tab pages line from 'tabline'.
7225 */ 1167 */
7226 static void 1168 void
7227 win_redr_custom( 1169 win_redr_custom(
7228 win_T *wp, 1170 win_T *wp,
7229 int draw_ruler) /* TRUE or FALSE */ 1171 int draw_ruler) // TRUE or FALSE
7230 { 1172 {
7231 static int entered = FALSE; 1173 static int entered = FALSE;
7232 int attr; 1174 int attr;
7233 int curattr; 1175 int curattr;
7234 int row; 1176 int row;
7245 struct stl_hlrec tabtab[STL_MAX_ITEM]; 1187 struct stl_hlrec tabtab[STL_MAX_ITEM];
7246 int use_sandbox = FALSE; 1188 int use_sandbox = FALSE;
7247 win_T *ewp; 1189 win_T *ewp;
7248 int p_crb_save; 1190 int p_crb_save;
7249 1191
7250 /* There is a tiny chance that this gets called recursively: When 1192 // There is a tiny chance that this gets called recursively: When
7251 * redrawing a status line triggers redrawing the ruler or tabline. 1193 // redrawing a status line triggers redrawing the ruler or tabline.
7252 * Avoid trouble by not allowing recursion. */ 1194 // Avoid trouble by not allowing recursion.
7253 if (entered) 1195 if (entered)
7254 return; 1196 return;
7255 entered = TRUE; 1197 entered = TRUE;
7256 1198
7257 /* setup environment for the task at hand */ 1199 // setup environment for the task at hand
7258 if (wp == NULL) 1200 if (wp == NULL)
7259 { 1201 {
7260 /* Use 'tabline'. Always at the first line of the screen. */ 1202 // Use 'tabline'. Always at the first line of the screen.
7261 stl = p_tal; 1203 stl = p_tal;
7262 row = 0; 1204 row = 0;
7263 fillchar = ' '; 1205 fillchar = ' ';
7264 attr = HL_ATTR(HLF_TPF); 1206 attr = HL_ATTR(HLF_TPF);
7265 maxwidth = Columns; 1207 maxwidth = Columns;
7274 maxwidth = wp->w_width; 1216 maxwidth = wp->w_width;
7275 1217
7276 if (draw_ruler) 1218 if (draw_ruler)
7277 { 1219 {
7278 stl = p_ruf; 1220 stl = p_ruf;
7279 /* advance past any leading group spec - implicit in ru_col */ 1221 // advance past any leading group spec - implicit in ru_col
7280 if (*stl == '%') 1222 if (*stl == '%')
7281 { 1223 {
7282 if (*++stl == '-') 1224 if (*++stl == '-')
7283 stl++; 1225 stl++;
7284 if (atoi((char *)stl)) 1226 if (atoi((char *)stl))
7292 col = (wp->w_width + 1) / 2; 1234 col = (wp->w_width + 1) / 2;
7293 maxwidth = wp->w_width - col; 1235 maxwidth = wp->w_width - col;
7294 if (!wp->w_status_height) 1236 if (!wp->w_status_height)
7295 { 1237 {
7296 row = Rows - 1; 1238 row = Rows - 1;
7297 --maxwidth; /* writing in last column may cause scrolling */ 1239 --maxwidth; // writing in last column may cause scrolling
7298 fillchar = ' '; 1240 fillchar = ' ';
7299 attr = 0; 1241 attr = 0;
7300 } 1242 }
7301 1243
7302 # ifdef FEAT_EVAL 1244 # ifdef FEAT_EVAL
7319 } 1261 }
7320 1262
7321 if (maxwidth <= 0) 1263 if (maxwidth <= 0)
7322 goto theend; 1264 goto theend;
7323 1265
7324 /* Temporarily reset 'cursorbind', we don't want a side effect from moving 1266 // Temporarily reset 'cursorbind', we don't want a side effect from moving
7325 * the cursor away and back. */ 1267 // the cursor away and back.
7326 ewp = wp == NULL ? curwin : wp; 1268 ewp = wp == NULL ? curwin : wp;
7327 p_crb_save = ewp->w_p_crb; 1269 p_crb_save = ewp->w_p_crb;
7328 ewp->w_p_crb = FALSE; 1270 ewp->w_p_crb = FALSE;
7329 1271
7330 /* Make a copy, because the statusline may include a function call that 1272 // Make a copy, because the statusline may include a function call that
7331 * might change the option value and free the memory. */ 1273 // might change the option value and free the memory.
7332 stl = vim_strsave(stl); 1274 stl = vim_strsave(stl);
7333 width = build_stl_str_hl(ewp, buf, sizeof(buf), 1275 width = build_stl_str_hl(ewp, buf, sizeof(buf),
7334 stl, use_sandbox, 1276 stl, use_sandbox,
7335 fillchar, maxwidth, hltab, tabtab); 1277 fillchar, maxwidth, hltab, tabtab);
7336 vim_free(stl); 1278 vim_free(stl);
7337 ewp->w_p_crb = p_crb_save; 1279 ewp->w_p_crb = p_crb_save;
7338 1280
7339 /* Make all characters printable. */ 1281 // Make all characters printable.
7340 p = transstr(buf); 1282 p = transstr(buf);
7341 if (p != NULL) 1283 if (p != NULL)
7342 { 1284 {
7343 vim_strncpy(buf, p, sizeof(buf) - 1); 1285 vim_strncpy(buf, p, sizeof(buf) - 1);
7344 vim_free(p); 1286 vim_free(p);
7345 } 1287 }
7346 1288
7347 /* fill up with "fillchar" */ 1289 // fill up with "fillchar"
7348 len = (int)STRLEN(buf); 1290 len = (int)STRLEN(buf);
7349 while (width < maxwidth && len < (int)sizeof(buf) - 1) 1291 while (width < maxwidth && len < (int)sizeof(buf) - 1)
7350 { 1292 {
7351 len += (*mb_char2bytes)(fillchar, buf + len); 1293 len += (*mb_char2bytes)(fillchar, buf + len);
7352 ++width; 1294 ++width;
7384 } 1326 }
7385 screen_puts(p, row, col, curattr); 1327 screen_puts(p, row, col, curattr);
7386 1328
7387 if (wp == NULL) 1329 if (wp == NULL)
7388 { 1330 {
7389 /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */ 1331 // Fill the TabPageIdxs[] array for clicking in the tab pagesline.
7390 col = 0; 1332 col = 0;
7391 len = 0; 1333 len = 0;
7392 p = buf; 1334 p = buf;
7393 fillchar = 0; 1335 fillchar = 0;
7394 for (n = 0; tabtab[n].start != NULL; n++) 1336 for (n = 0; tabtab[n].start != NULL; n++)
7405 1347
7406 theend: 1348 theend:
7407 entered = FALSE; 1349 entered = FALSE;
7408 } 1350 }
7409 1351
7410 #endif /* FEAT_STL_OPT */ 1352 #endif // FEAT_STL_OPT
7411 1353
7412 /* 1354 /*
7413 * Output a single character directly to the screen and update ScreenLines. 1355 * Output a single character directly to the screen and update ScreenLines.
7414 */ 1356 */
7415 void 1357 void
7434 void 1376 void
7435 screen_getbytes(int row, int col, char_u *bytes, int *attrp) 1377 screen_getbytes(int row, int col, char_u *bytes, int *attrp)
7436 { 1378 {
7437 unsigned off; 1379 unsigned off;
7438 1380
7439 /* safety check */ 1381 // safety check
7440 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns) 1382 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
7441 { 1383 {
7442 off = LineOffset[row] + col; 1384 off = LineOffset[row] + col;
7443 *attrp = ScreenAttrs[off]; 1385 *attrp = ScreenAttrs[off];
7444 bytes[0] = ScreenLines[off]; 1386 bytes[0] = ScreenLines[off];
7517 int mbyte_cells = 1; 1459 int mbyte_cells = 1;
7518 int u8c = 0; 1460 int u8c = 0;
7519 int u8cc[MAX_MCO]; 1461 int u8cc[MAX_MCO];
7520 int clear_next_cell = FALSE; 1462 int clear_next_cell = FALSE;
7521 #ifdef FEAT_ARABIC 1463 #ifdef FEAT_ARABIC
7522 int prev_c = 0; /* previous Arabic character */ 1464 int prev_c = 0; // previous Arabic character
7523 int pc, nc, nc1; 1465 int pc, nc, nc1;
7524 int pcc[MAX_MCO]; 1466 int pcc[MAX_MCO];
7525 #endif 1467 #endif
7526 int force_redraw_this; 1468 int force_redraw_this;
7527 int force_redraw_next = FALSE; 1469 int force_redraw_next = FALSE;
7533 || row >= screen_Rows || row < 0 1475 || row >= screen_Rows || row < 0
7534 || col >= screen_Columns || col < 0) 1476 || col >= screen_Columns || col < 0)
7535 return; 1477 return;
7536 off = LineOffset[row] + col; 1478 off = LineOffset[row] + col;
7537 1479
7538 /* When drawing over the right halve of a double-wide char clear out the 1480 // When drawing over the right halve of a double-wide char clear out the
7539 * left halve. Only needed in a terminal. */ 1481 // left halve. Only needed in a terminal.
7540 if (has_mbyte && col > 0 && col < screen_Columns 1482 if (has_mbyte && col > 0 && col < screen_Columns
7541 #ifdef FEAT_GUI 1483 #ifdef FEAT_GUI
7542 && !gui.in_use 1484 && !gui.in_use
7543 #endif 1485 #endif
7544 && mb_fix_col(col, row) != col) 1486 && mb_fix_col(col, row) != col)
7548 if (enc_utf8) 1490 if (enc_utf8)
7549 { 1491 {
7550 ScreenLinesUC[off - 1] = 0; 1492 ScreenLinesUC[off - 1] = 0;
7551 ScreenLinesC[0][off - 1] = 0; 1493 ScreenLinesC[0][off - 1] = 0;
7552 } 1494 }
7553 /* redraw the previous cell, make it empty */ 1495 // redraw the previous cell, make it empty
7554 screen_char(off - 1, row, col - 1); 1496 screen_char(off - 1, row, col - 1);
7555 /* force the cell at "col" to be redrawn */ 1497 // force the cell at "col" to be redrawn
7556 force_redraw_next = TRUE; 1498 force_redraw_next = TRUE;
7557 } 1499 }
7558 1500
7559 max_off = LineOffset[row] + screen_Columns; 1501 max_off = LineOffset[row] + screen_Columns;
7560 while (col < screen_Columns 1502 while (col < screen_Columns
7754 else 1696 else
7755 screen_char(off, row, col); 1697 screen_char(off, row, col);
7756 } 1698 }
7757 } 1699 }
7758 1700
7759 #ifdef FEAT_SEARCH_EXTRA 1701 #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
7760 /* 1702 /*
7761 * Prepare for 'hlsearch' highlighting. 1703 * Prepare for 'hlsearch' highlighting.
7762 */ 1704 */
7763 static void 1705 void
7764 start_search_hl(void) 1706 start_search_hl(void)
7765 { 1707 {
7766 if (p_hls && !no_hlsearch) 1708 if (p_hls && !no_hlsearch)
7767 { 1709 {
7768 last_pat_prog(&search_hl.rm); 1710 last_pat_prog(&screen_search_hl.rm);
7769 search_hl.attr = HL_ATTR(HLF_L); 1711 screen_search_hl.attr = HL_ATTR(HLF_L);
7770 # ifdef FEAT_RELTIME 1712 # ifdef FEAT_RELTIME
7771 /* Set the time limit to 'redrawtime'. */ 1713 /* Set the time limit to 'redrawtime'. */
7772 profile_setlimit(p_rdt, &search_hl.tm); 1714 profile_setlimit(p_rdt, &screen_search_hl.tm);
7773 # endif 1715 # endif
7774 } 1716 }
7775 } 1717 }
7776 1718
7777 /* 1719 /*
7778 * Clean up for 'hlsearch' highlighting. 1720 * Clean up for 'hlsearch' highlighting.
7779 */ 1721 */
7780 static void 1722 void
7781 end_search_hl(void) 1723 end_search_hl(void)
7782 { 1724 {
7783 if (search_hl.rm.regprog != NULL) 1725 if (screen_search_hl.rm.regprog != NULL)
7784 { 1726 {
7785 vim_regfree(search_hl.rm.regprog); 1727 vim_regfree(screen_search_hl.rm.regprog);
7786 search_hl.rm.regprog = NULL; 1728 screen_search_hl.rm.regprog = NULL;
7787 } 1729 }
7788 } 1730 }
7789 #endif 1731 #endif
7790 1732
7791 static void 1733 static void
8062 2004
8063 /* 2005 /*
8064 * Put character ScreenLines["off"] on the screen at position "row" and "col", 2006 * Put character ScreenLines["off"] on the screen at position "row" and "col",
8065 * using the attributes from ScreenAttrs["off"]. 2007 * using the attributes from ScreenAttrs["off"].
8066 */ 2008 */
8067 static void 2009 void
8068 screen_char(unsigned off, int row, int col) 2010 screen_char(unsigned off, int row, int col)
8069 { 2011 {
8070 int attr; 2012 int attr;
8071 2013
8072 /* Check for illegal values, just in case (could happen just after 2014 /* Check for illegal values, just in case (could happen just after
8253 width = wp->w_width; 2195 width = wp->w_width;
8254 } 2196 }
8255 screen_draw_rectangle(row, col, end - row, width, FALSE); 2197 screen_draw_rectangle(row, col, end - row, width, FALSE);
8256 } 2198 }
8257 2199
8258 static void 2200 void
8259 space_to_screenline(int off, int attr) 2201 space_to_screenline(int off, int attr)
8260 { 2202 {
8261 ScreenLines[off] = ' '; 2203 ScreenLines[off] = ' ';
8262 ScreenAttrs[off] = attr; 2204 ScreenAttrs[off] = attr;
8263 if (enc_utf8) 2205 if (enc_utf8)
10501 } 4443 }
10502 4444
10503 /* 4445 /*
10504 * Get the character to use in a status line. Get its attributes in "*attr". 4446 * Get the character to use in a status line. Get its attributes in "*attr".
10505 */ 4447 */
10506 static int 4448 int
10507 fillchar_status(int *attr, win_T *wp) 4449 fillchar_status(int *attr, win_T *wp)
10508 { 4450 {
10509 int fill; 4451 int fill;
10510 4452
10511 #ifdef FEAT_TERMINAL 4453 #ifdef FEAT_TERMINAL
10548 4490
10549 /* 4491 /*
10550 * Get the character to use in a separator between vertically split windows. 4492 * Get the character to use in a separator between vertically split windows.
10551 * Get its attributes in "*attr". 4493 * Get its attributes in "*attr".
10552 */ 4494 */
10553 static int 4495 int
10554 fillchar_vsep(int *attr) 4496 fillchar_vsep(int *attr)
10555 { 4497 {
10556 *attr = HL_ATTR(HLF_C); 4498 *attr = HL_ATTR(HLF_C);
10557 if (*attr == 0 && fill_vert == ' ') 4499 if (*attr == 0 && fill_vert == ' ')
10558 return '|'; 4500 return '|';
10584 int 4526 int
10585 messaging(void) 4527 messaging(void)
10586 { 4528 {
10587 return (!(p_lz && char_avail() && !KeyTyped)); 4529 return (!(p_lz && char_avail() && !KeyTyped));
10588 } 4530 }
10589
10590 #ifdef FEAT_MENU
10591 /*
10592 * Draw the window toolbar.
10593 */
10594 static void
10595 redraw_win_toolbar(win_T *wp)
10596 {
10597 vimmenu_T *menu;
10598 int item_idx = 0;
10599 int item_count = 0;
10600 int col = 0;
10601 int next_col;
10602 int off = (int)(current_ScreenLine - ScreenLines);
10603 int fill_attr = syn_name2attr((char_u *)"ToolbarLine");
10604 int button_attr = syn_name2attr((char_u *)"ToolbarButton");
10605
10606 vim_free(wp->w_winbar_items);
10607 for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next)
10608 ++item_count;
10609 wp->w_winbar_items = ALLOC_CLEAR_MULT(winbar_item_T, item_count + 1);
10610
10611 /* TODO: use fewer spaces if there is not enough room */
10612 for (menu = wp->w_winbar->children;
10613 menu != NULL && col < wp->w_width; menu = menu->next)
10614 {
10615 space_to_screenline(off + col, fill_attr);
10616 if (++col >= wp->w_width)
10617 break;
10618 if (col > 1)
10619 {
10620 space_to_screenline(off + col, fill_attr);
10621 if (++col >= wp->w_width)
10622 break;
10623 }
10624
10625 wp->w_winbar_items[item_idx].wb_startcol = col;
10626 space_to_screenline(off + col, button_attr);
10627 if (++col >= wp->w_width)
10628 break;
10629
10630 next_col = text_to_screenline(wp, menu->name, col);
10631 while (col < next_col)
10632 {
10633 ScreenAttrs[off + col] = button_attr;
10634 ++col;
10635 }
10636 wp->w_winbar_items[item_idx].wb_endcol = col;
10637 wp->w_winbar_items[item_idx].wb_menu = menu;
10638 ++item_idx;
10639
10640 if (col >= wp->w_width)
10641 break;
10642 space_to_screenline(off + col, button_attr);
10643 ++col;
10644 }
10645 while (col < wp->w_width)
10646 {
10647 space_to_screenline(off + col, fill_attr);
10648 ++col;
10649 }
10650 wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */
10651
10652 screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
10653 (int)wp->w_width, 0);
10654 }
10655 #endif
10656
10657 /*
10658 * Show current status info in ruler and various other places
10659 * If always is FALSE, only show ruler if position has changed.
10660 */
10661 void
10662 showruler(int always)
10663 {
10664 if (!always && !redrawing())
10665 return;
10666 if (pum_visible())
10667 {
10668 /* Don't redraw right now, do it later. */
10669 curwin->w_redr_status = TRUE;
10670 return;
10671 }
10672 #if defined(FEAT_STL_OPT)
10673 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
10674 redraw_custom_statusline(curwin);
10675 else
10676 #endif
10677 #ifdef FEAT_CMDL_INFO
10678 win_redr_ruler(curwin, always, FALSE);
10679 #endif
10680
10681 #ifdef FEAT_TITLE
10682 if (need_maketitle
10683 # ifdef FEAT_STL_OPT
10684 || (p_icon && (stl_syntax & STL_IN_ICON))
10685 || (p_title && (stl_syntax & STL_IN_TITLE))
10686 # endif
10687 )
10688 maketitle();
10689 #endif
10690 /* Redraw the tab pages line if needed. */
10691 if (redraw_tabline)
10692 draw_tabline();
10693 }
10694
10695 #ifdef FEAT_CMDL_INFO
10696 static void
10697 win_redr_ruler(win_T *wp, int always, int ignore_pum)
10698 {
10699 #define RULER_BUF_LEN 70
10700 char_u buffer[RULER_BUF_LEN];
10701 int row;
10702 int fillchar;
10703 int attr;
10704 int empty_line = FALSE;
10705 colnr_T virtcol;
10706 int i;
10707 size_t len;
10708 int o;
10709 int this_ru_col;
10710 int off = 0;
10711 int width;
10712
10713 /* If 'ruler' off or redrawing disabled, don't do anything */
10714 if (!p_ru)
10715 return;
10716
10717 /*
10718 * Check if cursor.lnum is valid, since win_redr_ruler() may be called
10719 * after deleting lines, before cursor.lnum is corrected.
10720 */
10721 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
10722 return;
10723
10724 // Don't draw the ruler while doing insert-completion, it might overwrite
10725 // the (long) mode message.
10726 if (wp == lastwin && lastwin->w_status_height == 0)
10727 if (edit_submode != NULL)
10728 return;
10729 // Don't draw the ruler when the popup menu is visible, it may overlap.
10730 // Except when the popup menu will be redrawn anyway.
10731 if (!ignore_pum && pum_visible())
10732 return;
10733
10734 #ifdef FEAT_STL_OPT
10735 if (*p_ruf)
10736 {
10737 int save_called_emsg = called_emsg;
10738
10739 called_emsg = FALSE;
10740 win_redr_custom(wp, TRUE);
10741 if (called_emsg)
10742 set_string_option_direct((char_u *)"rulerformat", -1,
10743 (char_u *)"", OPT_FREE, SID_ERROR);
10744 called_emsg |= save_called_emsg;
10745 return;
10746 }
10747 #endif
10748
10749 /*
10750 * Check if not in Insert mode and the line is empty (will show "0-1").
10751 */
10752 if (!(State & INSERT)
10753 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
10754 empty_line = TRUE;
10755
10756 /*
10757 * Only draw the ruler when something changed.
10758 */
10759 validate_virtcol_win(wp);
10760 if ( redraw_cmdline
10761 || always
10762 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
10763 || wp->w_cursor.col != wp->w_ru_cursor.col
10764 || wp->w_virtcol != wp->w_ru_virtcol
10765 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
10766 || wp->w_topline != wp->w_ru_topline
10767 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
10768 #ifdef FEAT_DIFF
10769 || wp->w_topfill != wp->w_ru_topfill
10770 #endif
10771 || empty_line != wp->w_ru_empty)
10772 {
10773 cursor_off();
10774 if (wp->w_status_height)
10775 {
10776 row = W_WINROW(wp) + wp->w_height;
10777 fillchar = fillchar_status(&attr, wp);
10778 off = wp->w_wincol;
10779 width = wp->w_width;
10780 }
10781 else
10782 {
10783 row = Rows - 1;
10784 fillchar = ' ';
10785 attr = 0;
10786 width = Columns;
10787 off = 0;
10788 }
10789
10790 /* In list mode virtcol needs to be recomputed */
10791 virtcol = wp->w_virtcol;
10792 if (wp->w_p_list && lcs_tab1 == NUL)
10793 {
10794 wp->w_p_list = FALSE;
10795 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
10796 wp->w_p_list = TRUE;
10797 }
10798
10799 /*
10800 * Some sprintfs return the length, some return a pointer.
10801 * To avoid portability problems we use strlen() here.
10802 */
10803 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
10804 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
10805 ? 0L
10806 : (long)(wp->w_cursor.lnum));
10807 len = STRLEN(buffer);
10808 col_print(buffer + len, RULER_BUF_LEN - len,
10809 empty_line ? 0 : (int)wp->w_cursor.col + 1,
10810 (int)virtcol + 1);
10811
10812 /*
10813 * Add a "50%" if there is room for it.
10814 * On the last line, don't print in the last column (scrolls the
10815 * screen up on some terminals).
10816 */
10817 i = (int)STRLEN(buffer);
10818 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
10819 o = i + vim_strsize(buffer + i + 1);
10820 if (wp->w_status_height == 0) /* can't use last char of screen */
10821 ++o;
10822 this_ru_col = ru_col - (Columns - width);
10823 if (this_ru_col < 0)
10824 this_ru_col = 0;
10825 /* Never use more than half the window/screen width, leave the other
10826 * half for the filename. */
10827 if (this_ru_col < (width + 1) / 2)
10828 this_ru_col = (width + 1) / 2;
10829 if (this_ru_col + o < width)
10830 {
10831 /* need at least 3 chars left for get_rel_pos() + NUL */
10832 while (this_ru_col + o < width && RULER_BUF_LEN > i + 4)
10833 {
10834 if (has_mbyte)
10835 i += (*mb_char2bytes)(fillchar, buffer + i);
10836 else
10837 buffer[i++] = fillchar;
10838 ++o;
10839 }
10840 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
10841 }
10842 /* Truncate at window boundary. */
10843 if (has_mbyte)
10844 {
10845 o = 0;
10846 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
10847 {
10848 o += (*mb_ptr2cells)(buffer + i);
10849 if (this_ru_col + o > width)
10850 {
10851 buffer[i] = NUL;
10852 break;
10853 }
10854 }
10855 }
10856 else if (this_ru_col + (int)STRLEN(buffer) > width)
10857 buffer[width - this_ru_col] = NUL;
10858
10859 screen_puts(buffer, row, this_ru_col + off, attr);
10860 i = redraw_cmdline;
10861 screen_fill(row, row + 1,
10862 this_ru_col + off + (int)STRLEN(buffer),
10863 (int)(off + width),
10864 fillchar, fillchar, attr);
10865 /* don't redraw the cmdline because of showing the ruler */
10866 redraw_cmdline = i;
10867 wp->w_ru_cursor = wp->w_cursor;
10868 wp->w_ru_virtcol = wp->w_virtcol;
10869 wp->w_ru_empty = empty_line;
10870 wp->w_ru_topline = wp->w_topline;
10871 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
10872 #ifdef FEAT_DIFF
10873 wp->w_ru_topfill = wp->w_topfill;
10874 #endif
10875 }
10876 }
10877 #endif
10878 4531
10879 /* 4532 /*
10880 * Compute columns for ruler and shown command. 'sc_col' is also used to 4533 * Compute columns for ruler and shown command. 'sc_col' is also used to
10881 * decide what the maximum length of a message on the status line can be. 4534 * decide what the maximum length of a message on the status line can be.
10882 * If there is a status line for the last window, 'sc_col' is independent 4535 * If there is a status line for the last window, 'sc_col' is independent
11123 } 4776 }
11124 4777
11125 return NULL; // no error 4778 return NULL; // no error
11126 } 4779 }
11127 4780
11128 #ifdef FEAT_SYN_HL
11129 /*
11130 * Used when 'cursorlineopt' contains "screenline": compute the margins between
11131 * which the highlighting is used.
11132 */
11133 static void
11134 margin_columns_win(win_T *wp, int *left_col, int *right_col)
11135 {
11136 // cache previous calculations depending on w_virtcol
11137 static int saved_w_virtcol;
11138 static win_T *prev_wp;
11139 static int prev_left_col;
11140 static int prev_right_col;
11141 static int prev_col_off;
11142
11143 int cur_col_off = win_col_off(wp);
11144 int width1;
11145 int width2;
11146
11147 if (saved_w_virtcol == wp->w_virtcol
11148 && prev_wp == wp && prev_col_off == cur_col_off)
11149 {
11150 *right_col = prev_right_col;
11151 *left_col = prev_left_col;
11152 return;
11153 }
11154
11155 width1 = wp->w_width - cur_col_off;
11156 width2 = width1 + win_col_off2(wp);
11157
11158 *left_col = 0;
11159 *right_col = width1;
11160
11161 if (wp->w_virtcol >= (colnr_T)width1)
11162 *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2;
11163 if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0)
11164 *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1;
11165
11166 // cache values
11167 prev_left_col = *left_col;
11168 prev_right_col = *right_col;
11169 prev_wp = wp;
11170 saved_w_virtcol = wp->w_virtcol;
11171 prev_col_off = cur_col_off;
11172 }
11173 #endif