blob: 926a09083c1427a2f82ff54dc882c35b78114a07 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * screen.c: code for displaying on the screen
12 *
13 * Output to the screen (console, terminal emulator or GUI window) is minimized
14 * by remembering what is already on the screen, and only updating the parts
15 * that changed.
16 *
17 * ScreenLines[off] Contains a copy of the whole screen, as it is currently
18 * displayed (excluding text written by external commands).
19 * ScreenAttrs[off] Contains the associated attributes.
20 * LineOffset[row] Contains the offset into ScreenLines*[] and ScreenAttrs[]
21 * for each line.
22 * LineWraps[row] Flag for each line whether it wraps to the next line.
23 *
24 * For double-byte characters, two consecutive bytes in ScreenLines[] can form
25 * one character which occupies two display cells.
26 * For UTF-8 a multi-byte character is converted to Unicode and stored in
27 * ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII
Bram Moolenaar70c49c12010-03-23 15:36:35 +010028 * character without composing chars ScreenLinesUC[] will be 0 and
29 * ScreenLinesC[][] is not used. When the character occupies two display
30 * cells the next byte in ScreenLines[] is 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +000031 * ScreenLinesC[][] contain up to 'maxcombine' composing characters
Bram Moolenaar70c49c12010-03-23 15:36:35 +010032 * (drawn on top of the first character). There is 0 after the last one used.
Bram Moolenaar071d4272004-06-13 20:20:40 +000033 * ScreenLines2[] is only used for euc-jp to store the second byte if the
34 * first byte is 0x8e (single-width character).
35 *
36 * The screen_*() functions write to the screen and handle updating
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
Bram Moolenaar2c7a7632007-05-10 18:19:11 +000041 * called from other places when an immediate screen update is needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +000042 *
43 * The part of the buffer that is displayed in a window is set with:
44 * - w_topline (first buffer line in window)
Bram Moolenaarea389e92014-05-28 21:40:52 +020045 * - w_topfill (filler lines above the first line)
Bram Moolenaar071d4272004-06-13 20:20:40 +000046 * - 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 *
Bram Moolenaar600dddc2006-03-12 22:05:10 +000074 * 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 *
Bram Moolenaar071d4272004-06-13 20:20:40 +000079 * 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 */
89
90#include "vim.h"
91
Bram Moolenaar5641f382012-06-13 18:06:36 +020092#define MB_FILLER_CHAR '<' /* character used when a double-width character
93 * doesn't fit. */
94
Bram Moolenaar071d4272004-06-13 20:20:40 +000095/*
96 * The attributes that are actually active for writing to the screen.
97 */
98static int screen_attr = 0;
99
100/*
101 * Positioning the cursor is reduced by remembering the last position.
102 * Mostly used by windgoto() and screen_char().
103 */
104static int screen_cur_row, screen_cur_col; /* last known cursor position */
105
106#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar071d4272004-06-13 20:20:40 +0000107static match_T search_hl; /* used for 'hlsearch' highlight matching */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108#endif
109
110#ifdef FEAT_FOLDING
111static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100112static int compute_foldcolumn(win_T *wp, int col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113#endif
114
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200115/* Flag that is set when drawing for a callback, not from the main command
116 * loop. */
117static int redrawing_for_callback = 0;
118
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119/*
120 * Buffer for one screen line (characters and attributes).
121 */
122static schar_T *current_ScreenLine;
123
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100124static void win_update(win_T *wp);
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +0200125static void win_redr_status(win_T *wp, int ignore_pum);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100126static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127#ifdef FEAT_FOLDING
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100128static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row);
129static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
130static void copy_text_attr(int off, char_u *buf, int len, int attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131#endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +0200132static int win_line(win_T *, linenr_T, int, int, int nochange, int number_only);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100133static void draw_vsep_win(win_T *wp, int row);
Bram Moolenaar238a5642006-02-21 22:12:05 +0000134#ifdef FEAT_STL_OPT
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100135static void redraw_custom_statusline(win_T *wp);
Bram Moolenaar238a5642006-02-21 22:12:05 +0000136#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000137#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarde993ea2014-06-17 23:18:01 +0200138# define SEARCH_HL_PRIORITY 0
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100139static void start_search_hl(void);
140static void end_search_hl(void);
141static void init_search_hl(win_T *wp);
142static void prepare_search_hl(win_T *wp, linenr_T lnum);
143static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur);
144static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100146static void screen_char(unsigned off, int row, int col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147#ifdef FEAT_MBYTE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100148static void screen_char_2(unsigned off, int row, int col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100150static void screenclear2(void);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200151static void lineclear(unsigned off, int width, int attr);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100152static void lineinvalid(unsigned off, int width);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200153static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100154static void win_rest_invalid(win_T *wp);
155static void msg_pos_mode(void);
156static void recording_mode(int attr);
Bram Moolenaar3633cf52017-07-31 22:29:35 +0200157static int fillchar_status(int *attr, win_T *wp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100158static int fillchar_vsep(int *attr);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +0200159#ifdef FEAT_MENU
160static void redraw_win_toolbar(win_T *wp);
161#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162#ifdef FEAT_STL_OPT
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100163static void win_redr_custom(win_T *wp, int draw_ruler);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164#endif
165#ifdef FEAT_CMDL_INFO
Bram Moolenaar491ac282018-06-17 14:47:55 +0200166static void win_redr_ruler(win_T *wp, int always, int ignore_pum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167#endif
168
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169/* Ugly global: overrule attribute used by screen_char() */
170static int screen_char_attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200172#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME)
173/* Can limit syntax highlight time to 'redrawtime'. */
174# define SYN_TIME_LIMIT 1
175#endif
176
Bram Moolenaarc0aa4822017-07-16 14:04:29 +0200177#ifdef FEAT_RIGHTLEFT
178# define HAS_RIGHTLEFT(x) x
179#else
180# define HAS_RIGHTLEFT(x) FALSE
181#endif
182
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183/*
184 * Redraw the current window later, with update_screen(type).
185 * Set must_redraw only if not already set to a higher value.
186 * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
187 */
188 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100189redraw_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190{
191 redraw_win_later(curwin, type);
192}
193
194 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100195redraw_win_later(
196 win_T *wp,
197 int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198{
Bram Moolenaar4f198282017-10-23 21:53:30 +0200199 if (!exiting && wp->w_redr_type < type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200 {
201 wp->w_redr_type = type;
202 if (type >= NOT_VALID)
203 wp->w_lines_valid = 0;
204 if (must_redraw < type) /* must_redraw is the maximum of all windows */
205 must_redraw = type;
206 }
207}
208
209/*
210 * Force a complete redraw later. Also resets the highlighting. To be used
211 * after executing a shell command that messes up the screen.
212 */
213 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100214redraw_later_clear(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215{
216 redraw_all_later(CLEAR);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000217#ifdef FEAT_GUI
218 if (gui.in_use)
219 /* Use a code that will reset gui.highlight_mask in
220 * gui_stop_highlight(). */
221 screen_attr = HL_ALL + 1;
222 else
223#endif
224 /* Use attributes that is very unlikely to appear in text. */
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +0200225 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226}
227
228/*
229 * Mark all windows to be redrawn later.
230 */
231 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100232redraw_all_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233{
234 win_T *wp;
235
236 FOR_ALL_WINDOWS(wp)
237 {
238 redraw_win_later(wp, type);
239 }
Bram Moolenaar04b4e1a2019-01-06 22:22:07 +0100240 // This may be needed when switching tabs.
241 if (must_redraw < type)
242 must_redraw = type;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243}
244
245/*
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000246 * Mark all windows that are editing the current buffer to be updated later.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000247 */
248 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100249redraw_curbuf_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000250{
251 redraw_buf_later(curbuf, type);
252}
253
254 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100255redraw_buf_later(buf_T *buf, int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000256{
257 win_T *wp;
258
259 FOR_ALL_WINDOWS(wp)
260 {
261 if (wp->w_buffer == buf)
262 redraw_win_later(wp, type);
263 }
264}
265
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200266 void
Bram Moolenaar27a472c2019-01-09 21:47:30 +0100267redraw_buf_line_later(buf_T *buf, linenr_T lnum)
268{
269 win_T *wp;
270
271 FOR_ALL_WINDOWS(wp)
272 if (wp->w_buffer == buf && lnum >= wp->w_topline
273 && lnum < wp->w_botline)
274 redrawWinline(wp, lnum);
275}
276
277 void
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200278redraw_buf_and_status_later(buf_T *buf, int type)
279{
280 win_T *wp;
281
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200282#ifdef FEAT_WILDMENU
Bram Moolenaar86033562017-07-12 20:24:41 +0200283 if (wild_menu_showing != 0)
284 /* Don't redraw while the command line completion is displayed, it
285 * would disappear. */
286 return;
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200287#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200288 FOR_ALL_WINDOWS(wp)
289 {
290 if (wp->w_buffer == buf)
291 {
292 redraw_win_later(wp, type);
293 wp->w_redr_status = TRUE;
294 }
295 }
296}
297
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298/*
Bram Moolenaar2951b772013-07-03 12:45:31 +0200299 * Redraw as soon as possible. When the command line is not scrolled redraw
300 * right away and restore what was on the command line.
301 * Return a code indicating what happened.
302 */
303 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100304redraw_asap(int type)
Bram Moolenaar2951b772013-07-03 12:45:31 +0200305{
306 int rows;
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200307 int cols = screen_Columns;
Bram Moolenaar2951b772013-07-03 12:45:31 +0200308 int r;
309 int ret = 0;
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200310 schar_T *screenline; /* copy from ScreenLines[] */
311 sattr_T *screenattr; /* copy from ScreenAttrs[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200312#ifdef FEAT_MBYTE
313 int i;
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200314 u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200315 u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200316 schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200317#endif
318
319 redraw_later(type);
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200320 if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
Bram Moolenaar2951b772013-07-03 12:45:31 +0200321 return ret;
322
323 /* Allocate space to save the text displayed in the command line area. */
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200324 rows = screen_Rows - cmdline_row;
Bram Moolenaar2951b772013-07-03 12:45:31 +0200325 screenline = (schar_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200326 (long_u)(rows * cols * sizeof(schar_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200327 screenattr = (sattr_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200328 (long_u)(rows * cols * sizeof(sattr_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200329 if (screenline == NULL || screenattr == NULL)
330 ret = 2;
331#ifdef FEAT_MBYTE
332 if (enc_utf8)
333 {
334 screenlineUC = (u8char_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200335 (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200336 if (screenlineUC == NULL)
337 ret = 2;
338 for (i = 0; i < p_mco; ++i)
339 {
340 screenlineC[i] = (u8char_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200341 (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200342 if (screenlineC[i] == NULL)
343 ret = 2;
344 }
345 }
346 if (enc_dbcs == DBCS_JPNU)
347 {
348 screenline2 = (schar_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200349 (long_u)(rows * cols * sizeof(schar_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200350 if (screenline2 == NULL)
351 ret = 2;
352 }
353#endif
354
355 if (ret != 2)
356 {
357 /* Save the text displayed in the command line area. */
358 for (r = 0; r < rows; ++r)
359 {
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200360 mch_memmove(screenline + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200361 ScreenLines + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200362 (size_t)cols * sizeof(schar_T));
363 mch_memmove(screenattr + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200364 ScreenAttrs + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200365 (size_t)cols * sizeof(sattr_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200366#ifdef FEAT_MBYTE
367 if (enc_utf8)
368 {
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200369 mch_memmove(screenlineUC + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200370 ScreenLinesUC + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200371 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200372 for (i = 0; i < p_mco; ++i)
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200373 mch_memmove(screenlineC[i] + r * cols,
374 ScreenLinesC[i] + LineOffset[cmdline_row + r],
375 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200376 }
377 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200378 mch_memmove(screenline2 + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200379 ScreenLines2 + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200380 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200381#endif
382 }
383
384 update_screen(0);
385 ret = 3;
386
387 if (must_redraw == 0)
388 {
389 int off = (int)(current_ScreenLine - ScreenLines);
390
391 /* Restore the text displayed in the command line area. */
392 for (r = 0; r < rows; ++r)
393 {
394 mch_memmove(current_ScreenLine,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200395 screenline + r * cols,
396 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200397 mch_memmove(ScreenAttrs + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200398 screenattr + r * cols,
399 (size_t)cols * sizeof(sattr_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200400#ifdef FEAT_MBYTE
401 if (enc_utf8)
402 {
403 mch_memmove(ScreenLinesUC + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200404 screenlineUC + r * cols,
405 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200406 for (i = 0; i < p_mco; ++i)
407 mch_memmove(ScreenLinesC[i] + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200408 screenlineC[i] + r * cols,
409 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200410 }
411 if (enc_dbcs == DBCS_JPNU)
412 mch_memmove(ScreenLines2 + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200413 screenline2 + r * cols,
414 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200415#endif
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200416 screen_line(cmdline_row + r, 0, cols, cols, FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200417 }
418 ret = 4;
419 }
Bram Moolenaar2951b772013-07-03 12:45:31 +0200420 }
421
422 vim_free(screenline);
423 vim_free(screenattr);
424#ifdef FEAT_MBYTE
425 if (enc_utf8)
426 {
427 vim_free(screenlineUC);
428 for (i = 0; i < p_mco; ++i)
429 vim_free(screenlineC[i]);
430 }
431 if (enc_dbcs == DBCS_JPNU)
432 vim_free(screenline2);
433#endif
434
Bram Moolenaar249f0dd2013-07-04 22:31:03 +0200435 /* Show the intro message when appropriate. */
436 maybe_intro_message();
437
438 setcursor();
439
Bram Moolenaar2951b772013-07-03 12:45:31 +0200440 return ret;
441}
442
443/*
Bram Moolenaar975b5272016-03-15 23:10:59 +0100444 * Invoked after an asynchronous callback is called.
445 * If an echo command was used the cursor needs to be put back where
446 * it belongs. If highlighting was changed a redraw is needed.
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200447 * If "call_update_screen" is FALSE don't call update_screen() when at the
448 * command line.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100449 */
450 void
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200451redraw_after_callback(int call_update_screen)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100452{
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200453 ++redrawing_for_callback;
454
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100455 if (State == HITRETURN || State == ASKMORE)
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200456 ; // do nothing
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100457 else if (State & CMDLINE)
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200458 {
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200459 // Don't redraw when in prompt_for_number().
460 if (cmdline_row > 0)
461 {
462 // Redrawing only works when the screen didn't scroll. Don't clear
463 // wildmenu entries.
464 if (msg_scrolled == 0
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200465#ifdef FEAT_WILDMENU
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200466 && wild_menu_showing == 0
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200467#endif
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200468 && call_update_screen)
469 update_screen(0);
470
471 // Redraw in the same position, so that the user can continue
472 // editing the command.
473 redrawcmdline_ex(FALSE);
474 }
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200475 }
Bram Moolenaar1b9645d2017-09-17 23:03:31 +0200476 else if (State & (NORMAL | INSERT | TERMINAL))
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100477 {
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200478 // keep the command line if possible
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200479 update_screen(VALID_NO_UPDATE);
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100480 setcursor();
481 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100482 cursor_on();
Bram Moolenaar975b5272016-03-15 23:10:59 +0100483#ifdef FEAT_GUI
Bram Moolenaara338adc2018-01-31 20:51:47 +0100484 if (gui.in_use && !gui_mch_is_blink_off())
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200485 // Don't update the cursor when it is blinking and off to avoid
486 // flicker.
Bram Moolenaara338adc2018-01-31 20:51:47 +0100487 out_flush_cursor(FALSE, FALSE);
488 else
Bram Moolenaar975b5272016-03-15 23:10:59 +0100489#endif
Bram Moolenaaracda04f2018-02-08 09:57:28 +0100490 out_flush();
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200491
492 --redrawing_for_callback;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100493}
494
495/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 * Changed something in the current window, at buffer line "lnum", that
497 * requires that line and possibly other lines to be redrawn.
498 * Used when entering/leaving Insert mode with the cursor on a folded line.
499 * Used to remove the "$" from a change command.
500 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
501 * may become invalid and the whole window will have to be redrawn.
502 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100504redrawWinline(
Bram Moolenaar90a99792018-09-12 21:52:18 +0200505 win_T *wp,
Bram Moolenaarae12f4b2019-01-09 20:51:04 +0100506 linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507{
Bram Moolenaar90a99792018-09-12 21:52:18 +0200508 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
509 wp->w_redraw_top = lnum;
510 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
511 wp->w_redraw_bot = lnum;
512 redraw_win_later(wp, VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513}
514
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200515 void
516reset_updating_screen(int may_resize_shell UNUSED)
517{
518 updating_screen = FALSE;
519#ifdef FEAT_GUI
520 if (may_resize_shell)
521 gui_may_resize_shell();
522#endif
523#ifdef FEAT_TERMINAL
524 term_check_channel_closed_recently();
525#endif
Bram Moolenaar92d147b2018-07-29 17:35:23 +0200526
527#ifdef HAVE_DROP_FILE
528 // If handle_drop() was called while updating_screen was TRUE need to
529 // handle the drop now.
530 handle_any_postponed_drop();
531#endif
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200532}
533
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534/*
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200535 * Update all windows that are editing the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536 */
537 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100538update_curbuf(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539{
540 redraw_curbuf_later(type);
541 update_screen(type);
542}
543
544/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 * Based on the current value of curwin->w_topline, transfer a screenfull
546 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
Bram Moolenaar072412e2017-09-13 22:11:35 +0200547 * Return OK when the screen was updated, FAIL if it was not done.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 */
Bram Moolenaar072412e2017-09-13 22:11:35 +0200549 int
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200550update_screen(int type_arg)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551{
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200552 int type = type_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 win_T *wp;
554 static int did_intro = FALSE;
555#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
556 int did_one;
557#endif
Bram Moolenaar144445d2016-07-08 21:41:54 +0200558#ifdef FEAT_GUI
Bram Moolenaar107abd22016-08-12 14:08:25 +0200559 int did_undraw = FALSE;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200560 int gui_cursor_col;
561 int gui_cursor_row;
562#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200563 int no_update = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000564
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000565 /* Don't do anything if the screen structures are (not yet) valid. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 if (!screen_valid(TRUE))
Bram Moolenaar072412e2017-09-13 22:11:35 +0200567 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200569 if (type == VALID_NO_UPDATE)
570 {
571 no_update = TRUE;
572 type = 0;
573 }
574
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 if (must_redraw)
576 {
577 if (type < must_redraw) /* use maximal type */
578 type = must_redraw;
Bram Moolenaar943fae42007-07-30 20:00:38 +0000579
580 /* must_redraw is reset here, so that when we run into some weird
581 * reason to redraw while busy redrawing (e.g., asynchronous
582 * scrolling), or update_topline() in win_update() will cause a
583 * scroll, the screen will be redrawn later or in win_update(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584 must_redraw = 0;
585 }
586
Bram Moolenaar6eddadf2018-05-06 16:40:16 +0200587 /* May need to update w_lines[]. */
588 if (curwin->w_lines_valid == 0 && type < NOT_VALID
589#ifdef FEAT_TERMINAL
590 && !term_do_update_window(curwin)
591#endif
592 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593 type = NOT_VALID;
594
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000595 /* Postpone the redrawing when it's not needed and when being called
596 * recursively. */
597 if (!redrawing() || updating_screen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000598 {
599 redraw_later(type); /* remember type for next time */
600 must_redraw = type;
601 if (type > INVERTED_ALL)
602 curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
Bram Moolenaar072412e2017-09-13 22:11:35 +0200603 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000604 }
605
606 updating_screen = TRUE;
607#ifdef FEAT_SYN_HL
608 ++display_tick; /* let syntax code know we're in a next round of
609 * display updating */
610#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200611 if (no_update)
612 ++no_win_do_lines_ins;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613
614 /*
615 * if the screen was scrolled up when displaying a message, scroll it down
616 */
617 if (msg_scrolled)
618 {
619 clear_cmdline = TRUE;
620 if (msg_scrolled > Rows - 5) /* clearing is faster */
621 type = CLEAR;
622 else if (type != CLEAR)
623 {
624 check_for_delay(FALSE);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200625 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
626 == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 type = CLEAR;
628 FOR_ALL_WINDOWS(wp)
629 {
630 if (W_WINROW(wp) < msg_scrolled)
631 {
632 if (W_WINROW(wp) + wp->w_height > msg_scrolled
633 && wp->w_redr_type < REDRAW_TOP
634 && wp->w_lines_valid > 0
635 && wp->w_topline == wp->w_lines[0].wl_lnum)
636 {
637 wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
638 wp->w_redr_type = REDRAW_TOP;
639 }
640 else
641 {
642 wp->w_redr_type = NOT_VALID;
Bram Moolenaare0de17d2017-09-24 16:24:34 +0200643 if (W_WINROW(wp) + wp->w_height + wp->w_status_height
644 <= msg_scrolled)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 }
647 }
648 }
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200649 if (!no_update)
650 redraw_cmdline = TRUE;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +0000651 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652 }
653 msg_scrolled = 0;
654 need_wait_return = FALSE;
655 }
656
657 /* reset cmdline_row now (may have been changed temporarily) */
658 compute_cmdrow();
659
660 /* Check for changed highlighting */
661 if (need_highlight_changed)
662 highlight_changed();
663
664 if (type == CLEAR) /* first clear screen */
665 {
666 screenclear(); /* will reset clear_cmdline */
667 type = NOT_VALID;
Bram Moolenaar9f5f7bf2017-06-28 20:45:26 +0200668 /* must_redraw may be set indirectly, avoid another redraw later */
669 must_redraw = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670 }
671
672 if (clear_cmdline) /* going to clear cmdline (done below) */
673 check_for_delay(FALSE);
674
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000675#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +0200676 /* Force redraw when width of 'number' or 'relativenumber' column
677 * changes. */
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000678 if (curwin->w_redr_type < NOT_VALID
Bram Moolenaar64486672010-05-16 15:46:46 +0200679 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
680 ? number_width(curwin) : 0))
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000681 curwin->w_redr_type = NOT_VALID;
682#endif
683
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 /*
685 * Only start redrawing if there is really something to do.
686 */
687 if (type == INVERTED)
688 update_curswant();
689 if (curwin->w_redr_type < type
690 && !((type == VALID
691 && curwin->w_lines[0].wl_valid
692#ifdef FEAT_DIFF
693 && curwin->w_topfill == curwin->w_old_topfill
694 && curwin->w_botfill == curwin->w_old_botfill
695#endif
696 && curwin->w_topline == curwin->w_lines[0].wl_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697 || (type == INVERTED
Bram Moolenaarb0c9a852006-11-28 15:14:56 +0000698 && VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
700 && curwin->w_old_visual_mode == VIsual_mode
701 && (curwin->w_valid & VALID_VIRTCOL)
702 && curwin->w_old_curswant == curwin->w_curswant)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703 ))
704 curwin->w_redr_type = type;
705
Bram Moolenaar5a305422006-04-28 22:38:25 +0000706 /* Redraw the tab pages line if needed. */
707 if (redraw_tabline || type >= NOT_VALID)
708 draw_tabline();
Bram Moolenaar5a305422006-04-28 22:38:25 +0000709
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710#ifdef FEAT_SYN_HL
711 /*
712 * Correct stored syntax highlighting info for changes in each displayed
713 * buffer. Each buffer must only be done once.
714 */
715 FOR_ALL_WINDOWS(wp)
716 {
717 if (wp->w_buffer->b_mod_set)
718 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 win_T *wwp;
720
721 /* Check if we already did this buffer. */
722 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
723 if (wwp->w_buffer == wp->w_buffer)
724 break;
Bram Moolenaar4033c552017-09-16 20:54:51 +0200725 if (wwp == wp && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 syn_stack_apply_changes(wp->w_buffer);
727 }
728 }
729#endif
730
731 /*
732 * Go from top to bottom through the windows, redrawing the ones that need
733 * it.
734 */
735#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
736 did_one = FALSE;
737#endif
738#ifdef FEAT_SEARCH_EXTRA
739 search_hl.rm.regprog = NULL;
740#endif
741 FOR_ALL_WINDOWS(wp)
742 {
743 if (wp->w_redr_type != 0)
744 {
745 cursor_off();
746#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
747 if (!did_one)
748 {
749 did_one = TRUE;
750# ifdef FEAT_SEARCH_EXTRA
751 start_search_hl();
752# endif
753# ifdef FEAT_CLIPBOARD
754 /* When Visual area changed, may have to update selection. */
Bram Moolenaarc0885aa2012-07-10 16:49:23 +0200755 if (clip_star.available && clip_isautosel_star())
756 clip_update_selection(&clip_star);
757 if (clip_plus.available && clip_isautosel_plus())
758 clip_update_selection(&clip_plus);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759# endif
760#ifdef FEAT_GUI
761 /* Remove the cursor before starting to do anything, because
762 * scrolling may make it difficult to redraw the text under
763 * it. */
Bram Moolenaar107abd22016-08-12 14:08:25 +0200764 if (gui.in_use && wp == curwin)
Bram Moolenaar144445d2016-07-08 21:41:54 +0200765 {
766 gui_cursor_col = gui.cursor_col;
767 gui_cursor_row = gui.cursor_row;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 gui_undraw_cursor();
Bram Moolenaar107abd22016-08-12 14:08:25 +0200769 did_undraw = TRUE;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200770 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771#endif
772 }
773#endif
774 win_update(wp);
775 }
776
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 /* redraw status line after the window to minimize cursor movement */
778 if (wp->w_redr_status)
779 {
780 cursor_off();
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +0200781 win_redr_status(wp, TRUE); // any popup menu will be redrawn below
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783 }
784#if defined(FEAT_SEARCH_EXTRA)
785 end_search_hl();
786#endif
Bram Moolenaar51971b32013-02-13 12:16:05 +0100787#ifdef FEAT_INS_EXPAND
788 /* May need to redraw the popup menu. */
Bram Moolenaar491ac282018-06-17 14:47:55 +0200789 pum_may_redraw();
Bram Moolenaar51971b32013-02-13 12:16:05 +0100790#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 /* Reset b_mod_set flags. Going through all windows is probably faster
793 * than going through all buffers (there could be many buffers). */
Bram Moolenaar29323592016-07-24 22:04:11 +0200794 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795 wp->w_buffer->b_mod_set = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200797 reset_updating_screen(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798
799 /* Clear or redraw the command line. Done last, because scrolling may
800 * mess up the command line. */
801 if (clear_cmdline || redraw_cmdline)
802 showmode();
803
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200804 if (no_update)
805 --no_win_do_lines_ins;
806
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807 /* May put up an introductory message when not editing a file */
Bram Moolenaar249f0dd2013-07-04 22:31:03 +0200808 if (!did_intro)
809 maybe_intro_message();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 did_intro = TRUE;
811
812#ifdef FEAT_GUI
813 /* Redraw the cursor and update the scrollbars when all screen updating is
814 * done. */
815 if (gui.in_use)
816 {
Bram Moolenaar107abd22016-08-12 14:08:25 +0200817 if (did_undraw && !gui_mch_is_blink_off())
Bram Moolenaar144445d2016-07-08 21:41:54 +0200818 {
Bram Moolenaara338adc2018-01-31 20:51:47 +0100819 mch_disable_flush();
820 out_flush(); /* required before updating the cursor */
821 mch_enable_flush();
822
Bram Moolenaar144445d2016-07-08 21:41:54 +0200823 /* Put the GUI position where the cursor was, gui_update_cursor()
824 * uses that. */
825 gui.col = gui_cursor_col;
826 gui.row = gui_cursor_row;
Bram Moolenaar84dbd492016-10-02 23:09:31 +0200827# ifdef FEAT_MBYTE
828 gui.col = mb_fix_col(gui.col, gui.row);
829# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 gui_update_cursor(FALSE, FALSE);
Bram Moolenaara338adc2018-01-31 20:51:47 +0100831 gui_may_flush();
Bram Moolenaar65549bd2016-07-08 22:52:37 +0200832 screen_cur_col = gui.col;
833 screen_cur_row = gui.row;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200834 }
Bram Moolenaara338adc2018-01-31 20:51:47 +0100835 else
836 out_flush();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 gui_update_scrollbars(FALSE);
838 }
839#endif
Bram Moolenaar072412e2017-09-13 22:11:35 +0200840 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841}
842
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100843#if defined(FEAT_SIGNS) || defined(FEAT_GUI) || defined(FEAT_CONCEAL)
844/*
845 * Prepare for updating one or more windows.
846 * Caller must check for "updating_screen" already set to avoid recursiveness.
847 */
848 static void
849update_prepare(void)
850{
851 cursor_off();
852 updating_screen = TRUE;
853#ifdef FEAT_GUI
854 /* Remove the cursor before starting to do anything, because scrolling may
855 * make it difficult to redraw the text under it. */
856 if (gui.in_use)
857 gui_undraw_cursor();
858#endif
859#ifdef FEAT_SEARCH_EXTRA
860 start_search_hl();
861#endif
862}
863
864/*
865 * Finish updating one or more windows.
866 */
867 static void
868update_finish(void)
869{
870 if (redraw_cmdline)
871 showmode();
872
873# ifdef FEAT_SEARCH_EXTRA
874 end_search_hl();
875# endif
876
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200877 reset_updating_screen(TRUE);
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100878
879# ifdef FEAT_GUI
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100880 /* Redraw the cursor and update the scrollbars when all screen updating is
881 * done. */
882 if (gui.in_use)
883 {
Bram Moolenaara338adc2018-01-31 20:51:47 +0100884 out_flush_cursor(FALSE, FALSE);
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100885 gui_update_scrollbars(FALSE);
886 }
887# endif
888}
889#endif
890
Bram Moolenaar860cae12010-06-05 23:22:07 +0200891#if defined(FEAT_CONCEAL) || defined(PROTO)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200892/*
893 * Return TRUE if the cursor line in window "wp" may be concealed, according
894 * to the 'concealcursor' option.
895 */
896 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100897conceal_cursor_line(win_T *wp)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200898{
899 int c;
900
901 if (*wp->w_p_cocu == NUL)
902 return FALSE;
903 if (get_real_state() & VISUAL)
904 c = 'v';
905 else if (State & INSERT)
906 c = 'i';
907 else if (State & NORMAL)
908 c = 'n';
Bram Moolenaarca8c9862010-07-24 15:00:38 +0200909 else if (State & CMDLINE)
910 c = 'c';
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200911 else
912 return FALSE;
913 return vim_strchr(wp->w_p_cocu, c) != NULL;
914}
915
916/*
917 * Check if the cursor line needs to be redrawn because of 'concealcursor'.
918 */
919 void
Bram Moolenaarb9464822018-05-10 15:09:49 +0200920conceal_check_cursor_line(void)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200921{
922 if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin))
923 {
924 need_cursor_line_redraw = TRUE;
925 /* Need to recompute cursor column, e.g., when starting Visual mode
926 * without concealing. */
927 curs_columns(TRUE);
928 }
929}
930
Bram Moolenaar860cae12010-06-05 23:22:07 +0200931 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100932update_single_line(win_T *wp, linenr_T lnum)
Bram Moolenaar860cae12010-06-05 23:22:07 +0200933{
934 int row;
935 int j;
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200936#ifdef SYN_TIME_LIMIT
937 proftime_T syntax_tm;
938#endif
Bram Moolenaar860cae12010-06-05 23:22:07 +0200939
Bram Moolenaar908be432016-05-24 10:51:30 +0200940 /* Don't do anything if the screen structures are (not yet) valid. */
Bram Moolenaar070b33d2017-01-31 21:53:39 +0100941 if (!screen_valid(TRUE) || updating_screen)
Bram Moolenaar908be432016-05-24 10:51:30 +0200942 return;
943
Bram Moolenaar860cae12010-06-05 23:22:07 +0200944 if (lnum >= wp->w_topline && lnum < wp->w_botline
Bram Moolenaar370df582010-06-22 05:16:38 +0200945 && foldedCount(wp, lnum, &win_foldinfo) == 0)
Bram Moolenaar860cae12010-06-05 23:22:07 +0200946 {
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200947#ifdef SYN_TIME_LIMIT
948 /* Set the time limit to 'redrawtime'. */
949 profile_setlimit(p_rdt, &syntax_tm);
Bram Moolenaarf3d769a2017-09-22 13:44:56 +0200950 syn_set_timeout(&syntax_tm);
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200951#endif
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100952 update_prepare();
953
Bram Moolenaar860cae12010-06-05 23:22:07 +0200954 row = 0;
955 for (j = 0; j < wp->w_lines_valid; ++j)
956 {
957 if (lnum == wp->w_lines[j].wl_lnum)
958 {
959 screen_start(); /* not sure of screen cursor */
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +0200960# ifdef FEAT_SEARCH_EXTRA
961 init_search_hl(wp);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200962 prepare_search_hl(wp, lnum);
963# endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +0200964 win_line(wp, lnum, row, row + wp->w_lines[j].wl_size,
965 FALSE, FALSE);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200966 break;
967 }
968 row += wp->w_lines[j].wl_size;
969 }
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100970
971 update_finish();
Bram Moolenaarf3d769a2017-09-22 13:44:56 +0200972
973#ifdef SYN_TIME_LIMIT
974 syn_set_timeout(NULL);
975#endif
Bram Moolenaar860cae12010-06-05 23:22:07 +0200976 }
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200977 need_cursor_line_redraw = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978}
979#endif
980
981#if defined(FEAT_SIGNS) || defined(PROTO)
982 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100983update_debug_sign(buf_T *buf, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984{
985 win_T *wp;
986 int doit = FALSE;
987
988# ifdef FEAT_FOLDING
989 win_foldinfo.fi_level = 0;
990# endif
991
Bram Moolenaar27a472c2019-01-09 21:47:30 +0100992 // update/delete a specific sign
993 redraw_buf_line_later(buf, lnum);
994
995 // check if it resulted in the need to redraw a window
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000997 if (wp->w_redr_type != 0)
998 doit = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999
Bram Moolenaar738f8fc2012-01-10 12:42:09 +01001000 /* Return when there is nothing to do, screen updating is already
Bram Moolenaar07920482017-08-01 20:53:30 +02001001 * happening (recursive call), messages on the screen or still starting up.
1002 */
Bram Moolenaar738f8fc2012-01-10 12:42:09 +01001003 if (!doit || updating_screen
Bram Moolenaar07920482017-08-01 20:53:30 +02001004 || State == ASKMORE || State == HITRETURN
1005 || msg_scrolled
Bram Moolenaar738f8fc2012-01-10 12:42:09 +01001006#ifdef FEAT_GUI
1007 || gui.starting
1008#endif
1009 || starting)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010 return;
1011
1012 /* update all windows that need updating */
1013 update_prepare();
1014
Bram Moolenaar29323592016-07-24 22:04:11 +02001015 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016 {
1017 if (wp->w_redr_type != 0)
1018 win_update(wp);
1019 if (wp->w_redr_status)
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001020 win_redr_status(wp, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001021 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022
1023 update_finish();
1024}
1025#endif
1026
1027
1028#if defined(FEAT_GUI) || defined(PROTO)
1029/*
1030 * Update a single window, its status line and maybe the command line msg.
1031 * Used for the GUI scrollbar.
1032 */
1033 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001034updateWindow(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035{
Bram Moolenaar19f990e2009-11-25 12:08:03 +00001036 /* return if already busy updating */
1037 if (updating_screen)
1038 return;
1039
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 update_prepare();
1041
1042#ifdef FEAT_CLIPBOARD
1043 /* When Visual area changed, may have to update selection. */
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02001044 if (clip_star.available && clip_isautosel_star())
1045 clip_update_selection(&clip_star);
1046 if (clip_plus.available && clip_isautosel_plus())
1047 clip_update_selection(&clip_plus);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001048#endif
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001049
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050 win_update(wp);
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001051
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001052 /* When the screen was cleared redraw the tab pages line. */
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00001053 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001054 draw_tabline();
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001055
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056 if (wp->w_redr_status
1057# ifdef FEAT_CMDL_INFO
1058 || p_ru
1059# endif
1060# ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00001061 || *p_stl != NUL || *wp->w_p_stl != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062# endif
1063 )
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001064 win_redr_status(wp, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065
1066 update_finish();
1067}
1068#endif
1069
1070/*
1071 * Update a single window.
1072 *
1073 * This may cause the windows below it also to be redrawn (when clearing the
1074 * screen or scrolling lines).
1075 *
1076 * How the window is redrawn depends on wp->w_redr_type. Each type also
1077 * implies the one below it.
1078 * NOT_VALID redraw the whole window
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001079 * SOME_VALID redraw the whole window but do scroll when possible
Bram Moolenaar071d4272004-06-13 20:20:40 +00001080 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
1081 * INVERTED redraw the changed part of the Visual area
1082 * INVERTED_ALL redraw the whole Visual area
1083 * VALID 1. scroll up/down to adjust for a changed w_topline
1084 * 2. update lines at the top when scrolled down
1085 * 3. redraw changed text:
Bram Moolenaar75c50c42005-06-04 22:06:24 +00001086 * - if wp->w_buffer->b_mod_set set, update lines between
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 * b_mod_top and b_mod_bot.
1088 * - if wp->w_redraw_top non-zero, redraw lines between
1089 * wp->w_redraw_top and wp->w_redr_bot.
1090 * - continue redrawing when syntax status is invalid.
1091 * 4. if scrolled up, update lines at the bottom.
1092 * This results in three areas that may need updating:
1093 * top: from first row to top_end (when scrolled down)
1094 * mid: from mid_start to mid_end (update inversion or changed text)
1095 * bot: from bot_start to last row (when scrolled up)
1096 */
1097 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001098win_update(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099{
1100 buf_T *buf = wp->w_buffer;
1101 int type;
1102 int top_end = 0; /* Below last row of the top area that needs
1103 updating. 0 when no top area updating. */
1104 int mid_start = 999;/* first row of the mid area that needs
1105 updating. 999 when no mid area updating. */
1106 int mid_end = 0; /* Below last row of the mid area that needs
1107 updating. 0 when no mid area updating. */
1108 int bot_start = 999;/* first row of the bot area that needs
1109 updating. 999 when no bot area updating */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 int scrolled_down = FALSE; /* TRUE when scrolled down when
1111 w_topline got smaller a bit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001113 matchitem_T *cur; /* points to the match list */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114 int top_to_mod = FALSE; /* redraw above mod_top */
1115#endif
1116
1117 int row; /* current window row to display */
1118 linenr_T lnum; /* current buffer lnum to display */
1119 int idx; /* current index in w_lines[] */
1120 int srow; /* starting row of the current line */
1121
1122 int eof = FALSE; /* if TRUE, we hit the end of the file */
1123 int didline = FALSE; /* if TRUE, we finished the last line */
1124 int i;
1125 long j;
1126 static int recursive = FALSE; /* being called recursively */
1127 int old_botline = wp->w_botline;
1128#ifdef FEAT_FOLDING
1129 long fold_count;
1130#endif
1131#ifdef FEAT_SYN_HL
1132 /* remember what happened to the previous line, to know if
1133 * check_visual_highlight() can be used */
1134#define DID_NONE 1 /* didn't update a line */
1135#define DID_LINE 2 /* updated a normal line */
1136#define DID_FOLD 3 /* updated a folded line */
1137 int did_update = DID_NONE;
1138 linenr_T syntax_last_parsed = 0; /* last parsed text line */
1139#endif
1140 linenr_T mod_top = 0;
1141 linenr_T mod_bot = 0;
1142#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1143 int save_got_int;
1144#endif
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001145#ifdef SYN_TIME_LIMIT
1146 proftime_T syntax_tm;
1147#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001148
1149 type = wp->w_redr_type;
1150
1151 if (type == NOT_VALID)
1152 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001154 wp->w_lines_valid = 0;
1155 }
1156
1157 /* Window is zero-height: nothing to draw. */
Bram Moolenaar415a6932017-12-05 20:31:07 +01001158 if (wp->w_height + WINBAR_HEIGHT(wp) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159 {
1160 wp->w_redr_type = 0;
1161 return;
1162 }
1163
Bram Moolenaar071d4272004-06-13 20:20:40 +00001164 /* Window is zero-width: Only need to draw the separator. */
1165 if (wp->w_width == 0)
1166 {
1167 /* draw the vertical separator right of this window */
1168 draw_vsep_win(wp, 0);
1169 wp->w_redr_type = 0;
1170 return;
1171 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001173#ifdef FEAT_TERMINAL
Bram Moolenaar6eddadf2018-05-06 16:40:16 +02001174 // If this window contains a terminal, redraw works completely differently.
1175 if (term_do_update_window(wp))
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001176 {
Bram Moolenaar6eddadf2018-05-06 16:40:16 +02001177 term_update_window(wp);
Bram Moolenaar181ca992018-02-13 21:19:21 +01001178# ifdef FEAT_MENU
1179 /* Draw the window toolbar, if there is one. */
1180 if (winbar_height(wp) > 0)
1181 redraw_win_toolbar(wp);
1182# endif
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001183 wp->w_redr_type = 0;
1184 return;
1185 }
1186#endif
1187
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +02001189 init_search_hl(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190#endif
1191
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001192#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +02001193 /* Force redraw when width of 'number' or 'relativenumber' column
1194 * changes. */
1195 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001196 if (wp->w_nrwidth != i)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001197 {
1198 type = NOT_VALID;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001199 wp->w_nrwidth = i;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001200 }
1201 else
1202#endif
1203
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
1205 {
1206 /*
1207 * When there are both inserted/deleted lines and specific lines to be
1208 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
1209 * everything (only happens when redrawing is off for while).
1210 */
1211 type = NOT_VALID;
1212 }
1213 else
1214 {
1215 /*
1216 * Set mod_top to the first line that needs displaying because of
1217 * changes. Set mod_bot to the first line after the changes.
1218 */
1219 mod_top = wp->w_redraw_top;
1220 if (wp->w_redraw_bot != 0)
1221 mod_bot = wp->w_redraw_bot + 1;
1222 else
1223 mod_bot = 0;
1224 wp->w_redraw_top = 0; /* reset for next time */
1225 wp->w_redraw_bot = 0;
1226 if (buf->b_mod_set)
1227 {
1228 if (mod_top == 0 || mod_top > buf->b_mod_top)
1229 {
1230 mod_top = buf->b_mod_top;
1231#ifdef FEAT_SYN_HL
1232 /* Need to redraw lines above the change that may be included
1233 * in a pattern match. */
Bram Moolenaar860cae12010-06-05 23:22:07 +02001234 if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02001236 mod_top -= buf->b_s.b_syn_sync_linebreaks;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 if (mod_top < 1)
1238 mod_top = 1;
1239 }
1240#endif
1241 }
1242 if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
1243 mod_bot = buf->b_mod_bot;
1244
1245#ifdef FEAT_SEARCH_EXTRA
1246 /* When 'hlsearch' is on and using a multi-line search pattern, a
1247 * change in one line may make the Search highlighting in a
1248 * previous line invalid. Simple solution: redraw all visible
1249 * lines above the change.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001250 * Same for a match pattern.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251 */
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001252 if (search_hl.rm.regprog != NULL
1253 && re_multiline(search_hl.rm.regprog))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 top_to_mod = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001255 else
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001256 {
1257 cur = wp->w_match_head;
1258 while (cur != NULL)
1259 {
1260 if (cur->match.regprog != NULL
1261 && re_multiline(cur->match.regprog))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001262 {
1263 top_to_mod = TRUE;
1264 break;
1265 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001266 cur = cur->next;
1267 }
1268 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269#endif
1270 }
1271#ifdef FEAT_FOLDING
1272 if (mod_top != 0 && hasAnyFolding(wp))
1273 {
1274 linenr_T lnumt, lnumb;
1275
1276 /*
1277 * A change in a line can cause lines above it to become folded or
1278 * unfolded. Find the top most buffer line that may be affected.
1279 * If the line was previously folded and displayed, get the first
1280 * line of that fold. If the line is folded now, get the first
1281 * folded line. Use the minimum of these two.
1282 */
1283
1284 /* Find last valid w_lines[] entry above mod_top. Set lnumt to
1285 * the line below it. If there is no valid entry, use w_topline.
1286 * Find the first valid w_lines[] entry below mod_bot. Set lnumb
1287 * to this line. If there is no valid entry, use MAXLNUM. */
1288 lnumt = wp->w_topline;
1289 lnumb = MAXLNUM;
1290 for (i = 0; i < wp->w_lines_valid; ++i)
1291 if (wp->w_lines[i].wl_valid)
1292 {
1293 if (wp->w_lines[i].wl_lastlnum < mod_top)
1294 lnumt = wp->w_lines[i].wl_lastlnum + 1;
1295 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1296 {
1297 lnumb = wp->w_lines[i].wl_lnum;
1298 /* When there is a fold column it might need updating
1299 * in the next line ("J" just above an open fold). */
Bram Moolenaar1c934292015-01-27 16:39:29 +01001300 if (compute_foldcolumn(wp, 0) > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301 ++lnumb;
1302 }
1303 }
1304
1305 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1306 if (mod_top > lnumt)
1307 mod_top = lnumt;
1308
1309 /* Now do the same for the bottom line (one above mod_bot). */
1310 --mod_bot;
1311 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1312 ++mod_bot;
1313 if (mod_bot < lnumb)
1314 mod_bot = lnumb;
1315 }
1316#endif
1317
1318 /* When a change starts above w_topline and the end is below
1319 * w_topline, start redrawing at w_topline.
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001320 * If the end of the change is above w_topline: do like no change was
1321 * made, but redraw the first line to find changes in syntax. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322 if (mod_top != 0 && mod_top < wp->w_topline)
1323 {
1324 if (mod_bot > wp->w_topline)
1325 mod_top = wp->w_topline;
1326#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02001327 else if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328 top_end = 1;
1329#endif
1330 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001331
1332 /* When line numbers are displayed need to redraw all lines below
1333 * inserted/deleted lines. */
1334 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1335 mod_bot = MAXLNUM;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336 }
1337
1338 /*
1339 * When only displaying the lines at the top, set top_end. Used when
1340 * window has scrolled down for msg_scrolled.
1341 */
1342 if (type == REDRAW_TOP)
1343 {
1344 j = 0;
1345 for (i = 0; i < wp->w_lines_valid; ++i)
1346 {
1347 j += wp->w_lines[i].wl_size;
1348 if (j >= wp->w_upd_rows)
1349 {
1350 top_end = j;
1351 break;
1352 }
1353 }
1354 if (top_end == 0)
1355 /* not found (cannot happen?): redraw everything */
1356 type = NOT_VALID;
1357 else
1358 /* top area defined, the rest is VALID */
1359 type = VALID;
1360 }
1361
Bram Moolenaar367329b2007-08-30 11:53:22 +00001362 /* Trick: we want to avoid clearing the screen twice. screenclear() will
Bram Moolenaar943fae42007-07-30 20:00:38 +00001363 * set "screen_cleared" to TRUE. The special value MAYBE (which is still
1364 * non-zero and thus not FALSE) will indicate that screenclear() was not
1365 * called. */
1366 if (screen_cleared)
1367 screen_cleared = MAYBE;
1368
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369 /*
1370 * If there are no changes on the screen that require a complete redraw,
1371 * handle three cases:
1372 * 1: we are off the top of the screen by a few lines: scroll down
1373 * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1374 * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1375 * w_lines[] that needs updating.
1376 */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001377 if ((type == VALID || type == SOME_VALID
1378 || type == INVERTED || type == INVERTED_ALL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001379#ifdef FEAT_DIFF
1380 && !wp->w_botfill && !wp->w_old_botfill
1381#endif
1382 )
1383 {
1384 if (mod_top != 0 && wp->w_topline == mod_top)
1385 {
1386 /*
1387 * w_topline is the first changed line, the scrolling will be done
1388 * further down.
1389 */
1390 }
1391 else if (wp->w_lines[0].wl_valid
1392 && (wp->w_topline < wp->w_lines[0].wl_lnum
1393#ifdef FEAT_DIFF
1394 || (wp->w_topline == wp->w_lines[0].wl_lnum
1395 && wp->w_topfill > wp->w_old_topfill)
1396#endif
1397 ))
1398 {
1399 /*
1400 * New topline is above old topline: May scroll down.
1401 */
1402#ifdef FEAT_FOLDING
1403 if (hasAnyFolding(wp))
1404 {
1405 linenr_T ln;
1406
1407 /* count the number of lines we are off, counting a sequence
1408 * of folded lines as one */
1409 j = 0;
1410 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1411 {
1412 ++j;
1413 if (j >= wp->w_height - 2)
1414 break;
1415 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1416 }
1417 }
1418 else
1419#endif
1420 j = wp->w_lines[0].wl_lnum - wp->w_topline;
1421 if (j < wp->w_height - 2) /* not too far off */
1422 {
1423 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1424#ifdef FEAT_DIFF
1425 /* insert extra lines for previously invisible filler lines */
1426 if (wp->w_lines[0].wl_lnum != wp->w_topline)
1427 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1428 - wp->w_old_topfill;
1429#endif
1430 if (i < wp->w_height - 2) /* less than a screen off */
1431 {
1432 /*
1433 * Try to insert the correct number of lines.
1434 * If not the last window, delete the lines at the bottom.
1435 * win_ins_lines may fail when the terminal can't do it.
1436 */
1437 if (i > 0)
1438 check_for_delay(FALSE);
1439 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1440 {
1441 if (wp->w_lines_valid != 0)
1442 {
1443 /* Need to update rows that are new, stop at the
1444 * first one that scrolled down. */
1445 top_end = i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446 scrolled_down = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001447
1448 /* Move the entries that were scrolled, disable
1449 * the entries for the lines to be redrawn. */
1450 if ((wp->w_lines_valid += j) > wp->w_height)
1451 wp->w_lines_valid = wp->w_height;
1452 for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1453 wp->w_lines[idx] = wp->w_lines[idx - j];
1454 while (idx >= 0)
1455 wp->w_lines[idx--].wl_valid = FALSE;
1456 }
1457 }
1458 else
1459 mid_start = 0; /* redraw all lines */
1460 }
1461 else
1462 mid_start = 0; /* redraw all lines */
1463 }
1464 else
1465 mid_start = 0; /* redraw all lines */
1466 }
1467 else
1468 {
1469 /*
1470 * New topline is at or below old topline: May scroll up.
1471 * When topline didn't change, find first entry in w_lines[] that
1472 * needs updating.
1473 */
1474
1475 /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
1476 j = -1;
1477 row = 0;
1478 for (i = 0; i < wp->w_lines_valid; i++)
1479 {
1480 if (wp->w_lines[i].wl_valid
1481 && wp->w_lines[i].wl_lnum == wp->w_topline)
1482 {
1483 j = i;
1484 break;
1485 }
1486 row += wp->w_lines[i].wl_size;
1487 }
1488 if (j == -1)
1489 {
1490 /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1491 * lines */
1492 mid_start = 0;
1493 }
1494 else
1495 {
1496 /*
1497 * Try to delete the correct number of lines.
1498 * wp->w_topline is at wp->w_lines[i].wl_lnum.
1499 */
1500#ifdef FEAT_DIFF
1501 /* If the topline didn't change, delete old filler lines,
1502 * otherwise delete filler lines of the new topline... */
1503 if (wp->w_lines[0].wl_lnum == wp->w_topline)
1504 row += wp->w_old_topfill;
1505 else
1506 row += diff_check_fill(wp, wp->w_topline);
1507 /* ... but don't delete new filler lines. */
1508 row -= wp->w_topfill;
1509#endif
1510 if (row > 0)
1511 {
1512 check_for_delay(FALSE);
Bram Moolenaarcfce7172017-08-17 20:31:48 +02001513 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
1514 == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001515 bot_start = wp->w_height - row;
1516 else
1517 mid_start = 0; /* redraw all lines */
1518 }
1519 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1520 {
1521 /*
1522 * Skip the lines (below the deleted lines) that are still
1523 * valid and don't need redrawing. Copy their info
1524 * upwards, to compensate for the deleted lines. Set
1525 * bot_start to the first row that needs redrawing.
1526 */
1527 bot_start = 0;
1528 idx = 0;
1529 for (;;)
1530 {
1531 wp->w_lines[idx] = wp->w_lines[j];
1532 /* stop at line that didn't fit, unless it is still
1533 * valid (no lines deleted) */
1534 if (row > 0 && bot_start + row
1535 + (int)wp->w_lines[j].wl_size > wp->w_height)
1536 {
1537 wp->w_lines_valid = idx + 1;
1538 break;
1539 }
1540 bot_start += wp->w_lines[idx++].wl_size;
1541
1542 /* stop at the last valid entry in w_lines[].wl_size */
1543 if (++j >= wp->w_lines_valid)
1544 {
1545 wp->w_lines_valid = idx;
1546 break;
1547 }
1548 }
1549#ifdef FEAT_DIFF
1550 /* Correct the first entry for filler lines at the top
1551 * when it won't get updated below. */
1552 if (wp->w_p_diff && bot_start > 0)
1553 wp->w_lines[0].wl_size =
1554 plines_win_nofill(wp, wp->w_topline, TRUE)
1555 + wp->w_topfill;
1556#endif
1557 }
1558 }
1559 }
1560
1561 /* When starting redraw in the first line, redraw all lines. When
1562 * there is only one window it's probably faster to clear the screen
1563 * first. */
1564 if (mid_start == 0)
1565 {
1566 mid_end = wp->w_height;
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01001567 if (ONE_WINDOW)
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001568 {
Bram Moolenaar943fae42007-07-30 20:00:38 +00001569 /* Clear the screen when it was not done by win_del_lines() or
1570 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1571 * then. */
1572 if (screen_cleared != TRUE)
1573 screenclear();
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001574 /* The screen was cleared, redraw the tab pages line. */
1575 if (redraw_tabline)
1576 draw_tabline();
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001577 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001578 }
Bram Moolenaar943fae42007-07-30 20:00:38 +00001579
1580 /* When win_del_lines() or win_ins_lines() caused the screen to be
1581 * cleared (only happens for the first window) or when screenclear()
1582 * was called directly above, "must_redraw" will have been set to
1583 * NOT_VALID, need to reset it here to avoid redrawing twice. */
1584 if (screen_cleared == TRUE)
1585 must_redraw = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001586 }
1587 else
1588 {
1589 /* Not VALID or INVERTED: redraw all lines. */
1590 mid_start = 0;
1591 mid_end = wp->w_height;
1592 }
1593
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001594 if (type == SOME_VALID)
1595 {
1596 /* SOME_VALID: redraw all lines. */
1597 mid_start = 0;
1598 mid_end = wp->w_height;
1599 type = NOT_VALID;
1600 }
1601
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 /* check if we are updating or removing the inverted part */
1603 if ((VIsual_active && buf == curwin->w_buffer)
1604 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1605 {
1606 linenr_T from, to;
1607
1608 if (VIsual_active)
1609 {
1610 if (VIsual_active
1611 && (VIsual_mode != wp->w_old_visual_mode
1612 || type == INVERTED_ALL))
1613 {
1614 /*
1615 * If the type of Visual selection changed, redraw the whole
1616 * selection. Also when the ownership of the X selection is
1617 * gained or lost.
1618 */
1619 if (curwin->w_cursor.lnum < VIsual.lnum)
1620 {
1621 from = curwin->w_cursor.lnum;
1622 to = VIsual.lnum;
1623 }
1624 else
1625 {
1626 from = VIsual.lnum;
1627 to = curwin->w_cursor.lnum;
1628 }
1629 /* redraw more when the cursor moved as well */
1630 if (wp->w_old_cursor_lnum < from)
1631 from = wp->w_old_cursor_lnum;
1632 if (wp->w_old_cursor_lnum > to)
1633 to = wp->w_old_cursor_lnum;
1634 if (wp->w_old_visual_lnum < from)
1635 from = wp->w_old_visual_lnum;
1636 if (wp->w_old_visual_lnum > to)
1637 to = wp->w_old_visual_lnum;
1638 }
1639 else
1640 {
1641 /*
1642 * Find the line numbers that need to be updated: The lines
1643 * between the old cursor position and the current cursor
1644 * position. Also check if the Visual position changed.
1645 */
1646 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1647 {
1648 from = curwin->w_cursor.lnum;
1649 to = wp->w_old_cursor_lnum;
1650 }
1651 else
1652 {
1653 from = wp->w_old_cursor_lnum;
1654 to = curwin->w_cursor.lnum;
1655 if (from == 0) /* Visual mode just started */
1656 from = to;
1657 }
1658
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001659 if (VIsual.lnum != wp->w_old_visual_lnum
1660 || VIsual.col != wp->w_old_visual_col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661 {
1662 if (wp->w_old_visual_lnum < from
1663 && wp->w_old_visual_lnum != 0)
1664 from = wp->w_old_visual_lnum;
1665 if (wp->w_old_visual_lnum > to)
1666 to = wp->w_old_visual_lnum;
1667 if (VIsual.lnum < from)
1668 from = VIsual.lnum;
1669 if (VIsual.lnum > to)
1670 to = VIsual.lnum;
1671 }
1672 }
1673
1674 /*
1675 * If in block mode and changed column or curwin->w_curswant:
1676 * update all lines.
1677 * First compute the actual start and end column.
1678 */
1679 if (VIsual_mode == Ctrl_V)
1680 {
Bram Moolenaar404406a2014-10-09 13:24:43 +02001681 colnr_T fromc, toc;
1682#if defined(FEAT_VIRTUALEDIT) && defined(FEAT_LINEBREAK)
1683 int save_ve_flags = ve_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684
Bram Moolenaar404406a2014-10-09 13:24:43 +02001685 if (curwin->w_p_lbr)
1686 ve_flags = VE_ALL;
1687#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
Bram Moolenaar404406a2014-10-09 13:24:43 +02001689#if defined(FEAT_VIRTUALEDIT) && defined(FEAT_LINEBREAK)
1690 ve_flags = save_ve_flags;
1691#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692 ++toc;
1693 if (curwin->w_curswant == MAXCOL)
1694 toc = MAXCOL;
1695
1696 if (fromc != wp->w_old_cursor_fcol
1697 || toc != wp->w_old_cursor_lcol)
1698 {
1699 if (from > VIsual.lnum)
1700 from = VIsual.lnum;
1701 if (to < VIsual.lnum)
1702 to = VIsual.lnum;
1703 }
1704 wp->w_old_cursor_fcol = fromc;
1705 wp->w_old_cursor_lcol = toc;
1706 }
1707 }
1708 else
1709 {
1710 /* Use the line numbers of the old Visual area. */
1711 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
1712 {
1713 from = wp->w_old_cursor_lnum;
1714 to = wp->w_old_visual_lnum;
1715 }
1716 else
1717 {
1718 from = wp->w_old_visual_lnum;
1719 to = wp->w_old_cursor_lnum;
1720 }
1721 }
1722
1723 /*
1724 * There is no need to update lines above the top of the window.
1725 */
1726 if (from < wp->w_topline)
1727 from = wp->w_topline;
1728
1729 /*
1730 * If we know the value of w_botline, use it to restrict the update to
1731 * the lines that are visible in the window.
1732 */
1733 if (wp->w_valid & VALID_BOTLINE)
1734 {
1735 if (from >= wp->w_botline)
1736 from = wp->w_botline - 1;
1737 if (to >= wp->w_botline)
1738 to = wp->w_botline - 1;
1739 }
1740
1741 /*
1742 * Find the minimal part to be updated.
1743 * Watch out for scrolling that made entries in w_lines[] invalid.
1744 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
1745 * top_end; need to redraw from top_end to the "to" line.
1746 * A middle mouse click with a Visual selection may change the text
1747 * above the Visual area and reset wl_valid, do count these for
1748 * mid_end (in srow).
1749 */
1750 if (mid_start > 0)
1751 {
1752 lnum = wp->w_topline;
1753 idx = 0;
1754 srow = 0;
1755 if (scrolled_down)
1756 mid_start = top_end;
1757 else
1758 mid_start = 0;
1759 while (lnum < from && idx < wp->w_lines_valid) /* find start */
1760 {
1761 if (wp->w_lines[idx].wl_valid)
1762 mid_start += wp->w_lines[idx].wl_size;
1763 else if (!scrolled_down)
1764 srow += wp->w_lines[idx].wl_size;
1765 ++idx;
1766# ifdef FEAT_FOLDING
1767 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
1768 lnum = wp->w_lines[idx].wl_lnum;
1769 else
1770# endif
1771 ++lnum;
1772 }
1773 srow += mid_start;
1774 mid_end = wp->w_height;
1775 for ( ; idx < wp->w_lines_valid; ++idx) /* find end */
1776 {
1777 if (wp->w_lines[idx].wl_valid
1778 && wp->w_lines[idx].wl_lnum >= to + 1)
1779 {
1780 /* Only update until first row of this line */
1781 mid_end = srow;
1782 break;
1783 }
1784 srow += wp->w_lines[idx].wl_size;
1785 }
1786 }
1787 }
1788
1789 if (VIsual_active && buf == curwin->w_buffer)
1790 {
1791 wp->w_old_visual_mode = VIsual_mode;
1792 wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
1793 wp->w_old_visual_lnum = VIsual.lnum;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001794 wp->w_old_visual_col = VIsual.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 wp->w_old_curswant = curwin->w_curswant;
1796 }
1797 else
1798 {
1799 wp->w_old_visual_mode = 0;
1800 wp->w_old_cursor_lnum = 0;
1801 wp->w_old_visual_lnum = 0;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001802 wp->w_old_visual_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804
1805#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1806 /* reset got_int, otherwise regexp won't work */
1807 save_got_int = got_int;
1808 got_int = 0;
1809#endif
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001810#ifdef SYN_TIME_LIMIT
1811 /* Set the time limit to 'redrawtime'. */
1812 profile_setlimit(p_rdt, &syntax_tm);
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02001813 syn_set_timeout(&syntax_tm);
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001814#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815#ifdef FEAT_FOLDING
1816 win_foldinfo.fi_level = 0;
1817#endif
1818
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02001819#ifdef FEAT_MENU
1820 /*
1821 * Draw the window toolbar, if there is one.
1822 * TODO: only when needed.
1823 */
1824 if (winbar_height(wp) > 0)
1825 redraw_win_toolbar(wp);
1826#endif
1827
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 /*
1829 * Update all the window rows.
1830 */
1831 idx = 0; /* first entry in w_lines[].wl_size */
1832 row = 0;
1833 srow = 0;
1834 lnum = wp->w_topline; /* first line shown in window */
1835 for (;;)
1836 {
1837 /* stop updating when reached the end of the window (check for _past_
1838 * the end of the window is at the end of the loop) */
1839 if (row == wp->w_height)
1840 {
1841 didline = TRUE;
1842 break;
1843 }
1844
1845 /* stop updating when hit the end of the file */
1846 if (lnum > buf->b_ml.ml_line_count)
1847 {
1848 eof = TRUE;
1849 break;
1850 }
1851
1852 /* Remember the starting row of the line that is going to be dealt
1853 * with. It is used further down when the line doesn't fit. */
1854 srow = row;
1855
1856 /*
1857 * Update a line when it is in an area that needs updating, when it
1858 * has changes or w_lines[idx] is invalid.
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02001859 * "bot_start" may be halfway a wrapped line after using
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 * win_del_lines(), check if the current line includes it.
1861 * When syntax folding is being used, the saved syntax states will
1862 * already have been updated, we can't see where the syntax state is
1863 * the same again, just update until the end of the window.
1864 */
1865 if (row < top_end
1866 || (row >= mid_start && row < mid_end)
1867#ifdef FEAT_SEARCH_EXTRA
1868 || top_to_mod
1869#endif
1870 || idx >= wp->w_lines_valid
1871 || (row + wp->w_lines[idx].wl_size > bot_start)
1872 || (mod_top != 0
1873 && (lnum == mod_top
1874 || (lnum >= mod_top
1875 && (lnum < mod_bot
1876#ifdef FEAT_SYN_HL
1877 || did_update == DID_FOLD
1878 || (did_update == DID_LINE
Bram Moolenaar860cae12010-06-05 23:22:07 +02001879 && syntax_present(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880 && (
1881# ifdef FEAT_FOLDING
1882 (foldmethodIsSyntax(wp)
1883 && hasAnyFolding(wp)) ||
1884# endif
1885 syntax_check_changed(lnum)))
1886#endif
Bram Moolenaar4ce239b2013-06-15 23:00:30 +02001887#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaardab70c62014-07-02 17:16:58 +02001888 /* match in fixed position might need redraw
1889 * if lines were inserted or deleted */
1890 || (wp->w_match_head != NULL
1891 && buf->b_mod_xlines != 0)
Bram Moolenaar4ce239b2013-06-15 23:00:30 +02001892#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 )))))
1894 {
1895#ifdef FEAT_SEARCH_EXTRA
1896 if (lnum == mod_top)
1897 top_to_mod = FALSE;
1898#endif
1899
1900 /*
1901 * When at start of changed lines: May scroll following lines
1902 * up or down to minimize redrawing.
1903 * Don't do this when the change continues until the end.
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001904 * Don't scroll when dollar_vcol >= 0, keep the "$".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 */
1906 if (lnum == mod_top
1907 && mod_bot != MAXLNUM
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001908 && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909 {
1910 int old_rows = 0;
1911 int new_rows = 0;
1912 int xtra_rows;
1913 linenr_T l;
1914
1915 /* Count the old number of window rows, using w_lines[], which
1916 * should still contain the sizes for the lines as they are
1917 * currently displayed. */
1918 for (i = idx; i < wp->w_lines_valid; ++i)
1919 {
1920 /* Only valid lines have a meaningful wl_lnum. Invalid
1921 * lines are part of the changed area. */
1922 if (wp->w_lines[i].wl_valid
1923 && wp->w_lines[i].wl_lnum == mod_bot)
1924 break;
1925 old_rows += wp->w_lines[i].wl_size;
1926#ifdef FEAT_FOLDING
1927 if (wp->w_lines[i].wl_valid
1928 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
1929 {
1930 /* Must have found the last valid entry above mod_bot.
1931 * Add following invalid entries. */
1932 ++i;
1933 while (i < wp->w_lines_valid
1934 && !wp->w_lines[i].wl_valid)
1935 old_rows += wp->w_lines[i++].wl_size;
1936 break;
1937 }
1938#endif
1939 }
1940
1941 if (i >= wp->w_lines_valid)
1942 {
1943 /* We can't find a valid line below the changed lines,
1944 * need to redraw until the end of the window.
1945 * Inserting/deleting lines has no use. */
1946 bot_start = 0;
1947 }
1948 else
1949 {
1950 /* Able to count old number of rows: Count new window
1951 * rows, and may insert/delete lines */
1952 j = idx;
1953 for (l = lnum; l < mod_bot; ++l)
1954 {
1955#ifdef FEAT_FOLDING
1956 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
1957 ++new_rows;
1958 else
1959#endif
1960#ifdef FEAT_DIFF
1961 if (l == wp->w_topline)
1962 new_rows += plines_win_nofill(wp, l, TRUE)
1963 + wp->w_topfill;
1964 else
1965#endif
1966 new_rows += plines_win(wp, l, TRUE);
1967 ++j;
1968 if (new_rows > wp->w_height - row - 2)
1969 {
1970 /* it's getting too much, must redraw the rest */
1971 new_rows = 9999;
1972 break;
1973 }
1974 }
1975 xtra_rows = new_rows - old_rows;
1976 if (xtra_rows < 0)
1977 {
1978 /* May scroll text up. If there is not enough
1979 * remaining text or scrolling fails, must redraw the
1980 * rest. If scrolling works, must redraw the text
1981 * below the scrolled text. */
1982 if (row - xtra_rows >= wp->w_height - 2)
1983 mod_bot = MAXLNUM;
1984 else
1985 {
1986 check_for_delay(FALSE);
1987 if (win_del_lines(wp, row,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02001988 -xtra_rows, FALSE, FALSE, 0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 mod_bot = MAXLNUM;
1990 else
1991 bot_start = wp->w_height + xtra_rows;
1992 }
1993 }
1994 else if (xtra_rows > 0)
1995 {
1996 /* May scroll text down. If there is not enough
1997 * remaining text of scrolling fails, must redraw the
1998 * rest. */
1999 if (row + xtra_rows >= wp->w_height - 2)
2000 mod_bot = MAXLNUM;
2001 else
2002 {
2003 check_for_delay(FALSE);
2004 if (win_ins_lines(wp, row + old_rows,
2005 xtra_rows, FALSE, FALSE) == FAIL)
2006 mod_bot = MAXLNUM;
2007 else if (top_end > row + old_rows)
2008 /* Scrolled the part at the top that requires
2009 * updating down. */
2010 top_end += xtra_rows;
2011 }
2012 }
2013
2014 /* When not updating the rest, may need to move w_lines[]
2015 * entries. */
2016 if (mod_bot != MAXLNUM && i != j)
2017 {
2018 if (j < i)
2019 {
2020 int x = row + new_rows;
2021
2022 /* move entries in w_lines[] upwards */
2023 for (;;)
2024 {
2025 /* stop at last valid entry in w_lines[] */
2026 if (i >= wp->w_lines_valid)
2027 {
2028 wp->w_lines_valid = j;
2029 break;
2030 }
2031 wp->w_lines[j] = wp->w_lines[i];
2032 /* stop at a line that won't fit */
2033 if (x + (int)wp->w_lines[j].wl_size
2034 > wp->w_height)
2035 {
2036 wp->w_lines_valid = j + 1;
2037 break;
2038 }
2039 x += wp->w_lines[j++].wl_size;
2040 ++i;
2041 }
2042 if (bot_start > x)
2043 bot_start = x;
2044 }
2045 else /* j > i */
2046 {
2047 /* move entries in w_lines[] downwards */
2048 j -= i;
2049 wp->w_lines_valid += j;
2050 if (wp->w_lines_valid > wp->w_height)
2051 wp->w_lines_valid = wp->w_height;
2052 for (i = wp->w_lines_valid; i - j >= idx; --i)
2053 wp->w_lines[i] = wp->w_lines[i - j];
2054
2055 /* The w_lines[] entries for inserted lines are
2056 * now invalid, but wl_size may be used above.
2057 * Reset to zero. */
2058 while (i >= idx)
2059 {
2060 wp->w_lines[i].wl_size = 0;
2061 wp->w_lines[i--].wl_valid = FALSE;
2062 }
2063 }
2064 }
2065 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 }
2067
2068#ifdef FEAT_FOLDING
2069 /*
2070 * When lines are folded, display one line for all of them.
2071 * Otherwise, display normally (can be several display lines when
2072 * 'wrap' is on).
2073 */
2074 fold_count = foldedCount(wp, lnum, &win_foldinfo);
2075 if (fold_count != 0)
2076 {
2077 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2078 ++row;
2079 --fold_count;
2080 wp->w_lines[idx].wl_folded = TRUE;
2081 wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
2082# ifdef FEAT_SYN_HL
2083 did_update = DID_FOLD;
2084# endif
2085 }
2086 else
2087#endif
2088 if (idx < wp->w_lines_valid
2089 && wp->w_lines[idx].wl_valid
2090 && wp->w_lines[idx].wl_lnum == lnum
2091 && lnum > wp->w_topline
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002092 && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093 && srow + wp->w_lines[idx].wl_size > wp->w_height
2094#ifdef FEAT_DIFF
2095 && diff_check_fill(wp, lnum) == 0
2096#endif
2097 )
2098 {
2099 /* This line is not going to fit. Don't draw anything here,
2100 * will draw "@ " lines below. */
2101 row = wp->w_height + 1;
2102 }
2103 else
2104 {
2105#ifdef FEAT_SEARCH_EXTRA
2106 prepare_search_hl(wp, lnum);
2107#endif
2108#ifdef FEAT_SYN_HL
2109 /* Let the syntax stuff know we skipped a few lines. */
2110 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
Bram Moolenaar860cae12010-06-05 23:22:07 +02002111 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112 syntax_end_parsing(syntax_last_parsed + 1);
2113#endif
2114
2115 /*
2116 * Display one line.
2117 */
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002118 row = win_line(wp, lnum, srow, wp->w_height,
2119 mod_top == 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120
2121#ifdef FEAT_FOLDING
2122 wp->w_lines[idx].wl_folded = FALSE;
2123 wp->w_lines[idx].wl_lastlnum = lnum;
2124#endif
2125#ifdef FEAT_SYN_HL
2126 did_update = DID_LINE;
2127 syntax_last_parsed = lnum;
2128#endif
2129 }
2130
2131 wp->w_lines[idx].wl_lnum = lnum;
2132 wp->w_lines[idx].wl_valid = TRUE;
Bram Moolenaar0e19fc02017-10-28 14:45:16 +02002133
2134 /* Past end of the window or end of the screen. Note that after
2135 * resizing wp->w_height may be end up too big. That's a problem
2136 * elsewhere, but prevent a crash here. */
2137 if (row > wp->w_height || row + wp->w_winrow >= Rows)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 {
2139 /* we may need the size of that too long line later on */
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002140 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
2142 ++idx;
2143 break;
2144 }
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002145 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146 wp->w_lines[idx].wl_size = row - srow;
2147 ++idx;
2148#ifdef FEAT_FOLDING
2149 lnum += fold_count + 1;
2150#else
2151 ++lnum;
2152#endif
2153 }
2154 else
2155 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002156 if (wp->w_p_rnu)
2157 {
Bram Moolenaar0e9deef2018-10-02 21:48:34 +02002158#ifdef FEAT_FOLDING
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002159 // 'relativenumber' set: The text doesn't need to be drawn, but
2160 // the number column nearly always does.
Bram Moolenaar7701f302018-10-02 21:20:32 +02002161 fold_count = foldedCount(wp, lnum, &win_foldinfo);
2162 if (fold_count != 0)
Bram Moolenaar7701f302018-10-02 21:20:32 +02002163 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
Bram Moolenaar7701f302018-10-02 21:20:32 +02002164 else
Bram Moolenaar0e9deef2018-10-02 21:48:34 +02002165#endif
Bram Moolenaar7701f302018-10-02 21:20:32 +02002166 (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE);
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002167 }
2168
2169 // This line does not need to be drawn, advance to the next one.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170 row += wp->w_lines[idx++].wl_size;
2171 if (row > wp->w_height) /* past end of screen */
2172 break;
2173#ifdef FEAT_FOLDING
2174 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
2175#else
2176 ++lnum;
2177#endif
2178#ifdef FEAT_SYN_HL
2179 did_update = DID_NONE;
2180#endif
2181 }
2182
2183 if (lnum > buf->b_ml.ml_line_count)
2184 {
2185 eof = TRUE;
2186 break;
2187 }
2188 }
2189 /*
2190 * End of loop over all window lines.
2191 */
2192
Bram Moolenaarcafafb32018-02-22 21:07:09 +01002193#ifdef FEAT_VTP
2194 /* Rewrite the character at the end of the screen line. */
2195 if (use_vtp())
2196 {
2197 int i;
2198
2199 for (i = 0; i < Rows; ++i)
2200# ifdef FEAT_MBYTE
2201 if (enc_utf8)
2202 if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
2203 LineOffset[i] + screen_Columns) > 1)
2204 screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
2205 else
2206 screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
2207 else
2208# endif
2209 screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
2210 }
2211#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212
2213 if (idx > wp->w_lines_valid)
2214 wp->w_lines_valid = idx;
2215
2216#ifdef FEAT_SYN_HL
2217 /*
2218 * Let the syntax stuff know we stop parsing here.
2219 */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002220 if (syntax_last_parsed != 0 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 syntax_end_parsing(syntax_last_parsed + 1);
2222#endif
2223
2224 /*
2225 * If we didn't hit the end of the file, and we didn't finish the last
2226 * line we were working on, then the line didn't fit.
2227 */
2228 wp->w_empty_rows = 0;
2229#ifdef FEAT_DIFF
2230 wp->w_filler_rows = 0;
2231#endif
2232 if (!eof && !didline)
2233 {
2234 if (lnum == wp->w_topline)
2235 {
2236 /*
2237 * Single line that does not fit!
2238 * Don't overwrite it, it can be edited.
2239 */
2240 wp->w_botline = lnum + 1;
2241 }
2242#ifdef FEAT_DIFF
2243 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
2244 {
2245 /* Window ends in filler lines. */
2246 wp->w_botline = lnum;
2247 wp->w_filler_rows = wp->w_height - srow;
2248 }
2249#endif
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002250 else if (dy_flags & DY_TRUNCATE) /* 'display' has "truncate" */
2251 {
2252 int scr_row = W_WINROW(wp) + wp->w_height - 1;
2253
2254 /*
2255 * Last line isn't finished: Display "@@@" in the last screen line.
2256 */
Bram Moolenaar53f81742017-09-22 14:35:51 +02002257 screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002258 HL_ATTR(HLF_AT));
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002259 screen_fill(scr_row, scr_row + 1,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002260 (int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002261 '@', ' ', HL_ATTR(HLF_AT));
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002262 set_empty_rows(wp, srow);
2263 wp->w_botline = lnum;
2264 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */
2266 {
2267 /*
2268 * Last line isn't finished: Display "@@@" at the end.
2269 */
2270 screen_fill(W_WINROW(wp) + wp->w_height - 1,
2271 W_WINROW(wp) + wp->w_height,
2272 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002273 '@', '@', HL_ATTR(HLF_AT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 set_empty_rows(wp, srow);
2275 wp->w_botline = lnum;
2276 }
2277 else
2278 {
2279 win_draw_end(wp, '@', ' ', srow, wp->w_height, HLF_AT);
2280 wp->w_botline = lnum;
2281 }
2282 }
2283 else
2284 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 draw_vsep_win(wp, row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 if (eof) /* we hit the end of the file */
2287 {
2288 wp->w_botline = buf->b_ml.ml_line_count + 1;
2289#ifdef FEAT_DIFF
2290 j = diff_check_fill(wp, wp->w_botline);
2291 if (j > 0 && !wp->w_botfill)
2292 {
2293 /*
2294 * Display filler lines at the end of the file
2295 */
2296 if (char2cells(fill_diff) > 1)
2297 i = '-';
2298 else
2299 i = fill_diff;
2300 if (row + j > wp->w_height)
2301 j = wp->w_height - row;
2302 win_draw_end(wp, i, i, row, row + (int)j, HLF_DED);
2303 row += j;
2304 }
2305#endif
2306 }
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002307 else if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 wp->w_botline = lnum;
2309
2310 /* make sure the rest of the screen is blank */
2311 /* put '~'s on rows that aren't part of the file. */
Bram Moolenaar58b85342016-08-14 19:54:54 +02002312 win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_EOB);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 }
2314
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02002315#ifdef SYN_TIME_LIMIT
2316 syn_set_timeout(NULL);
2317#endif
2318
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 /* Reset the type of redrawing required, the window has been updated. */
2320 wp->w_redr_type = 0;
2321#ifdef FEAT_DIFF
2322 wp->w_old_topfill = wp->w_topfill;
2323 wp->w_old_botfill = wp->w_botfill;
2324#endif
2325
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002326 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327 {
2328 /*
2329 * There is a trick with w_botline. If we invalidate it on each
2330 * change that might modify it, this will cause a lot of expensive
2331 * calls to plines() in update_topline() each time. Therefore the
2332 * value of w_botline is often approximated, and this value is used to
2333 * compute the value of w_topline. If the value of w_botline was
2334 * wrong, check that the value of w_topline is correct (cursor is on
2335 * the visible part of the text). If it's not, we need to redraw
2336 * again. Mostly this just means scrolling up a few lines, so it
2337 * doesn't look too bad. Only do this for the current window (where
2338 * changes are relevant).
2339 */
2340 wp->w_valid |= VALID_BOTLINE;
2341 if (wp == curwin && wp->w_botline != old_botline && !recursive)
2342 {
2343 recursive = TRUE;
2344 curwin->w_valid &= ~VALID_TOPLINE;
2345 update_topline(); /* may invalidate w_botline again */
2346 if (must_redraw != 0)
2347 {
2348 /* Don't update for changes in buffer again. */
2349 i = curbuf->b_mod_set;
2350 curbuf->b_mod_set = FALSE;
2351 win_update(curwin);
2352 must_redraw = 0;
2353 curbuf->b_mod_set = i;
2354 }
2355 recursive = FALSE;
2356 }
2357 }
2358
2359#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2360 /* restore got_int, unless CTRL-C was hit while redrawing */
2361 if (!got_int)
2362 got_int = save_got_int;
2363#endif
2364}
2365
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366/*
2367 * Clear the rest of the window and mark the unused lines with "c1". use "c2"
2368 * as the filler character.
2369 */
2370 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002371win_draw_end(
2372 win_T *wp,
2373 int c1,
2374 int c2,
2375 int row,
2376 int endrow,
2377 hlf_T hl)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378{
2379#if defined(FEAT_FOLDING) || defined(FEAT_SIGNS) || defined(FEAT_CMDWIN)
2380 int n = 0;
2381# define FDC_OFF n
2382#else
2383# define FDC_OFF 0
2384#endif
Bram Moolenaar1c934292015-01-27 16:39:29 +01002385#ifdef FEAT_FOLDING
2386 int fdc = compute_foldcolumn(wp, 0);
2387#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388
2389#ifdef FEAT_RIGHTLEFT
2390 if (wp->w_p_rl)
2391 {
2392 /* No check for cmdline window: should never be right-left. */
2393# ifdef FEAT_FOLDING
Bram Moolenaar1c934292015-01-27 16:39:29 +01002394 n = fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395
2396 if (n > 0)
2397 {
2398 /* draw the fold column at the right */
Bram Moolenaar02631462017-09-22 15:20:32 +02002399 if (n > wp->w_width)
2400 n = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2402 W_ENDCOL(wp) - n, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002403 ' ', ' ', HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 }
2405# endif
2406# ifdef FEAT_SIGNS
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02002407 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 {
2409 int nn = n + 2;
2410
2411 /* draw the sign column left of the fold column */
Bram Moolenaar02631462017-09-22 15:20:32 +02002412 if (nn > wp->w_width)
2413 nn = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2415 W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - n,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002416 ' ', ' ', HL_ATTR(HLF_SC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417 n = nn;
2418 }
2419# endif
2420 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002421 wp->w_wincol, W_ENDCOL(wp) - 1 - FDC_OFF,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002422 c2, c2, HL_ATTR(hl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002423 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2424 W_ENDCOL(wp) - 1 - FDC_OFF, W_ENDCOL(wp) - FDC_OFF,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002425 c1, c2, HL_ATTR(hl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 }
2427 else
2428#endif
2429 {
2430#ifdef FEAT_CMDWIN
2431 if (cmdwin_type != 0 && wp == curwin)
2432 {
2433 /* draw the cmdline character in the leftmost column */
2434 n = 1;
2435 if (n > wp->w_width)
2436 n = wp->w_width;
2437 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002438 wp->w_wincol, (int)wp->w_wincol + n,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002439 cmdwin_type, ' ', HL_ATTR(HLF_AT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 }
2441#endif
2442#ifdef FEAT_FOLDING
Bram Moolenaar1c934292015-01-27 16:39:29 +01002443 if (fdc > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 {
Bram Moolenaar1c934292015-01-27 16:39:29 +01002445 int nn = n + fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446
2447 /* draw the fold column at the left */
Bram Moolenaar02631462017-09-22 15:20:32 +02002448 if (nn > wp->w_width)
2449 nn = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002451 wp->w_wincol + n, (int)wp->w_wincol + nn,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002452 ' ', ' ', HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453 n = nn;
2454 }
2455#endif
2456#ifdef FEAT_SIGNS
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02002457 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002458 {
2459 int nn = n + 2;
2460
2461 /* draw the sign column after the fold column */
Bram Moolenaar02631462017-09-22 15:20:32 +02002462 if (nn > wp->w_width)
2463 nn = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002465 wp->w_wincol + n, (int)wp->w_wincol + nn,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002466 ' ', ' ', HL_ATTR(HLF_SC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 n = nn;
2468 }
2469#endif
2470 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002471 wp->w_wincol + FDC_OFF, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002472 c1, c2, HL_ATTR(hl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 }
2474 set_empty_rows(wp, row);
2475}
2476
Bram Moolenaar1a384422010-07-14 19:53:30 +02002477#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02002478/*
2479 * Advance **color_cols and return TRUE when there are columns to draw.
2480 */
2481 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002482advance_color_col(int vcol, int **color_cols)
Bram Moolenaar1a384422010-07-14 19:53:30 +02002483{
2484 while (**color_cols >= 0 && vcol > **color_cols)
2485 ++*color_cols;
2486 return (**color_cols >= 0);
2487}
2488#endif
2489
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002490#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
2491/*
2492 * Copy "text" to ScreenLines using "attr".
2493 * Returns the next screen column.
2494 */
2495 static int
2496text_to_screenline(win_T *wp, char_u *text, int col)
2497{
2498 int off = (int)(current_ScreenLine - ScreenLines);
2499
2500#ifdef FEAT_MBYTE
2501 if (has_mbyte)
2502 {
2503 int cells;
2504 int u8c, u8cc[MAX_MCO];
2505 int i;
2506 int idx;
2507 int c_len;
2508 char_u *p;
2509# ifdef FEAT_ARABIC
2510 int prev_c = 0; /* previous Arabic character */
2511 int prev_c1 = 0; /* first composing char for prev_c */
2512# endif
2513
2514# ifdef FEAT_RIGHTLEFT
2515 if (wp->w_p_rl)
2516 idx = off;
2517 else
2518# endif
2519 idx = off + col;
2520
2521 /* Store multibyte characters in ScreenLines[] et al. correctly. */
2522 for (p = text; *p != NUL; )
2523 {
2524 cells = (*mb_ptr2cells)(p);
2525 c_len = (*mb_ptr2len)(p);
Bram Moolenaar02631462017-09-22 15:20:32 +02002526 if (col + cells > wp->w_width
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002527# ifdef FEAT_RIGHTLEFT
2528 - (wp->w_p_rl ? col : 0)
2529# endif
2530 )
2531 break;
2532 ScreenLines[idx] = *p;
2533 if (enc_utf8)
2534 {
2535 u8c = utfc_ptr2char(p, u8cc);
2536 if (*p < 0x80 && u8cc[0] == 0)
2537 {
2538 ScreenLinesUC[idx] = 0;
2539#ifdef FEAT_ARABIC
2540 prev_c = u8c;
2541#endif
2542 }
2543 else
2544 {
2545#ifdef FEAT_ARABIC
2546 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
2547 {
2548 /* Do Arabic shaping. */
2549 int pc, pc1, nc;
2550 int pcc[MAX_MCO];
2551 int firstbyte = *p;
2552
2553 /* The idea of what is the previous and next
2554 * character depends on 'rightleft'. */
2555 if (wp->w_p_rl)
2556 {
2557 pc = prev_c;
2558 pc1 = prev_c1;
2559 nc = utf_ptr2char(p + c_len);
2560 prev_c1 = u8cc[0];
2561 }
2562 else
2563 {
2564 pc = utfc_ptr2char(p + c_len, pcc);
2565 nc = prev_c;
2566 pc1 = pcc[0];
2567 }
2568 prev_c = u8c;
2569
2570 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
2571 pc, pc1, nc);
2572 ScreenLines[idx] = firstbyte;
2573 }
2574 else
2575 prev_c = u8c;
2576#endif
2577 /* Non-BMP character: display as ? or fullwidth ?. */
2578#ifdef UNICODE16
2579 if (u8c >= 0x10000)
2580 ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?';
2581 else
2582#endif
2583 ScreenLinesUC[idx] = u8c;
2584 for (i = 0; i < Screen_mco; ++i)
2585 {
2586 ScreenLinesC[i][idx] = u8cc[i];
2587 if (u8cc[i] == 0)
2588 break;
2589 }
2590 }
2591 if (cells > 1)
2592 ScreenLines[idx + 1] = 0;
2593 }
2594 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
2595 /* double-byte single width character */
2596 ScreenLines2[idx] = p[1];
2597 else if (cells > 1)
2598 /* double-width character */
2599 ScreenLines[idx + 1] = p[1];
2600 col += cells;
2601 idx += cells;
2602 p += c_len;
2603 }
2604 }
2605 else
2606#endif
2607 {
2608 int len = (int)STRLEN(text);
2609
Bram Moolenaar02631462017-09-22 15:20:32 +02002610 if (len > wp->w_width - col)
2611 len = wp->w_width - col;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002612 if (len > 0)
2613 {
2614#ifdef FEAT_RIGHTLEFT
2615 if (wp->w_p_rl)
2616 STRNCPY(current_ScreenLine, text, len);
2617 else
2618#endif
2619 STRNCPY(current_ScreenLine + col, text, len);
2620 col += len;
2621 }
2622 }
2623 return col;
2624}
2625#endif
2626
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627#ifdef FEAT_FOLDING
2628/*
Bram Moolenaar1c934292015-01-27 16:39:29 +01002629 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
2630 * space is available for window "wp", minus "col".
2631 */
2632 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002633compute_foldcolumn(win_T *wp, int col)
Bram Moolenaar1c934292015-01-27 16:39:29 +01002634{
2635 int fdc = wp->w_p_fdc;
2636 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
Bram Moolenaar02631462017-09-22 15:20:32 +02002637 int wwidth = wp->w_width;
Bram Moolenaar1c934292015-01-27 16:39:29 +01002638
2639 if (fdc > wwidth - (col + wmw))
2640 fdc = wwidth - (col + wmw);
2641 return fdc;
2642}
2643
2644/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 * Display one folded line.
2646 */
2647 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002648fold_line(
2649 win_T *wp,
2650 long fold_count,
2651 foldinfo_T *foldinfo,
2652 linenr_T lnum,
2653 int row)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654{
Bram Moolenaaree695f72016-08-03 22:08:45 +02002655 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656 pos_T *top, *bot;
2657 linenr_T lnume = lnum + fold_count - 1;
2658 int len;
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002659 char_u *text;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660 int fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661 int col;
2662 int txtcol;
2663 int off = (int)(current_ScreenLine - ScreenLines);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002664 int ri;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665
2666 /* Build the fold line:
2667 * 1. Add the cmdwin_type for the command-line window
2668 * 2. Add the 'foldcolumn'
Bram Moolenaar64486672010-05-16 15:46:46 +02002669 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002670 * 4. Compose the text
2671 * 5. Add the text
2672 * 6. set highlighting for the Visual area an other text
2673 */
2674 col = 0;
2675
2676 /*
2677 * 1. Add the cmdwin_type for the command-line window
2678 * Ignores 'rightleft', this window is never right-left.
2679 */
2680#ifdef FEAT_CMDWIN
2681 if (cmdwin_type != 0 && wp == curwin)
2682 {
2683 ScreenLines[off] = cmdwin_type;
Bram Moolenaar8820b482017-03-16 17:23:31 +01002684 ScreenAttrs[off] = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685#ifdef FEAT_MBYTE
2686 if (enc_utf8)
2687 ScreenLinesUC[off] = 0;
2688#endif
2689 ++col;
2690 }
2691#endif
2692
2693 /*
2694 * 2. Add the 'foldcolumn'
Bram Moolenaar1c934292015-01-27 16:39:29 +01002695 * Reduce the width when there is not enough space.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 */
Bram Moolenaar1c934292015-01-27 16:39:29 +01002697 fdc = compute_foldcolumn(wp, col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 if (fdc > 0)
2699 {
2700 fill_foldcolumn(buf, wp, TRUE, lnum);
2701#ifdef FEAT_RIGHTLEFT
2702 if (wp->w_p_rl)
2703 {
2704 int i;
2705
Bram Moolenaar02631462017-09-22 15:20:32 +02002706 copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002707 HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 /* reverse the fold column */
2709 for (i = 0; i < fdc; ++i)
Bram Moolenaar02631462017-09-22 15:20:32 +02002710 ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 }
2712 else
2713#endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002714 copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 col += fdc;
2716 }
2717
2718#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6f470022018-04-10 18:47:20 +02002719# define RL_MEMSET(p, v, l) \
2720 do { \
2721 if (wp->w_p_rl) \
2722 for (ri = 0; ri < l; ++ri) \
2723 ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \
2724 else \
2725 for (ri = 0; ri < l; ++ri) \
2726 ScreenAttrs[off + (p) + ri] = v; \
2727 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002728#else
Bram Moolenaar6f470022018-04-10 18:47:20 +02002729# define RL_MEMSET(p, v, l) \
2730 do { \
2731 for (ri = 0; ri < l; ++ri) \
2732 ScreenAttrs[off + (p) + ri] = v; \
2733 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734#endif
2735
Bram Moolenaar64486672010-05-16 15:46:46 +02002736 /* Set all attributes of the 'number' or 'relativenumber' column and the
2737 * text */
Bram Moolenaar02631462017-09-22 15:20:32 +02002738 RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739
2740#ifdef FEAT_SIGNS
2741 /* If signs are being displayed, add two spaces. */
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02002742 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 {
Bram Moolenaar02631462017-09-22 15:20:32 +02002744 len = wp->w_width - col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 if (len > 0)
2746 {
2747 if (len > 2)
2748 len = 2;
2749# ifdef FEAT_RIGHTLEFT
2750 if (wp->w_p_rl)
2751 /* the line number isn't reversed */
Bram Moolenaar02631462017-09-22 15:20:32 +02002752 copy_text_attr(off + wp->w_width - len - col,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002753 (char_u *)" ", len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 else
2755# endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002756 copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757 col += len;
2758 }
2759 }
2760#endif
2761
2762 /*
Bram Moolenaar64486672010-05-16 15:46:46 +02002763 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 */
Bram Moolenaar64486672010-05-16 15:46:46 +02002765 if (wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 {
Bram Moolenaar02631462017-09-22 15:20:32 +02002767 len = wp->w_width - col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768 if (len > 0)
2769 {
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002770 int w = number_width(wp);
Bram Moolenaar24dc2302014-05-13 20:19:58 +02002771 long num;
2772 char *fmt = "%*ld ";
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002773
2774 if (len > w + 1)
2775 len = w + 1;
Bram Moolenaar64486672010-05-16 15:46:46 +02002776
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002777 if (wp->w_p_nu && !wp->w_p_rnu)
2778 /* 'number' + 'norelativenumber' */
Bram Moolenaar64486672010-05-16 15:46:46 +02002779 num = (long)lnum;
2780 else
Bram Moolenaar700e7342013-01-30 12:31:36 +01002781 {
Bram Moolenaar64486672010-05-16 15:46:46 +02002782 /* 'relativenumber', don't use negative numbers */
Bram Moolenaar7eb46522010-12-30 14:57:08 +01002783 num = labs((long)get_cursor_rel_lnum(wp, lnum));
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002784 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01002785 {
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002786 /* 'number' + 'relativenumber': cursor line shows absolute
2787 * line number */
Bram Moolenaar700e7342013-01-30 12:31:36 +01002788 num = lnum;
2789 fmt = "%-*ld ";
2790 }
2791 }
Bram Moolenaar64486672010-05-16 15:46:46 +02002792
Bram Moolenaar700e7342013-01-30 12:31:36 +01002793 sprintf((char *)buf, fmt, w, num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794#ifdef FEAT_RIGHTLEFT
2795 if (wp->w_p_rl)
2796 /* the line number isn't reversed */
Bram Moolenaar02631462017-09-22 15:20:32 +02002797 copy_text_attr(off + wp->w_width - len - col, buf, len,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002798 HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 else
2800#endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002801 copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002802 col += len;
2803 }
2804 }
2805
2806 /*
2807 * 4. Compose the folded-line string with 'foldtext', if set.
2808 */
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002809 text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002810
2811 txtcol = col; /* remember where text starts */
2812
2813 /*
2814 * 5. move the text to current_ScreenLine. Fill up with "fill_fold".
2815 * Right-left text is put in columns 0 - number-col, normal text is put
2816 * in columns number-col - window-width.
2817 */
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002818 col = text_to_screenline(wp, text, col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819
2820 /* Fill the rest of the line with the fold filler */
2821#ifdef FEAT_RIGHTLEFT
2822 if (wp->w_p_rl)
2823 col -= txtcol;
2824#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02002825 while (col < wp->w_width
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826#ifdef FEAT_RIGHTLEFT
2827 - (wp->w_p_rl ? txtcol : 0)
2828#endif
2829 )
2830 {
2831#ifdef FEAT_MBYTE
2832 if (enc_utf8)
2833 {
2834 if (fill_fold >= 0x80)
2835 {
2836 ScreenLinesUC[off + col] = fill_fold;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002837 ScreenLinesC[0][off + col] = 0;
Bram Moolenaaracda04f2018-02-08 09:57:28 +01002838 ScreenLines[off + col] = 0x80; /* avoid storing zero */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002839 }
2840 else
Bram Moolenaar8da1e6c2017-03-29 20:38:59 +02002841 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002842 ScreenLinesUC[off + col] = 0;
Bram Moolenaar8da1e6c2017-03-29 20:38:59 +02002843 ScreenLines[off + col] = fill_fold;
2844 }
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002845 col++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846 }
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002847 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848#endif
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002849 ScreenLines[off + col++] = fill_fold;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850 }
2851
2852 if (text != buf)
2853 vim_free(text);
2854
2855 /*
2856 * 6. set highlighting for the Visual area an other text.
2857 * If all folded lines are in the Visual area, highlight the line.
2858 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
2860 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01002861 if (LTOREQ_POS(curwin->w_cursor, VIsual))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862 {
2863 /* Visual is after curwin->w_cursor */
2864 top = &curwin->w_cursor;
2865 bot = &VIsual;
2866 }
2867 else
2868 {
2869 /* Visual is before curwin->w_cursor */
2870 top = &VIsual;
2871 bot = &curwin->w_cursor;
2872 }
2873 if (lnum >= top->lnum
2874 && lnume <= bot->lnum
2875 && (VIsual_mode != 'v'
2876 || ((lnum > top->lnum
2877 || (lnum == top->lnum
2878 && top->col == 0))
2879 && (lnume < bot->lnum
2880 || (lnume == bot->lnum
2881 && (bot->col - (*p_sel == 'e'))
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002882 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883 {
2884 if (VIsual_mode == Ctrl_V)
2885 {
2886 /* Visual block mode: highlight the chars part of the block */
Bram Moolenaar02631462017-09-22 15:20:32 +02002887 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 {
Bram Moolenaar6c167c62011-09-02 14:07:36 +02002889 if (wp->w_old_cursor_lcol != MAXCOL
2890 && wp->w_old_cursor_lcol + txtcol
Bram Moolenaar02631462017-09-22 15:20:32 +02002891 < (colnr_T)wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 len = wp->w_old_cursor_lcol;
2893 else
Bram Moolenaar02631462017-09-22 15:20:32 +02002894 len = wp->w_width - txtcol;
Bram Moolenaar8820b482017-03-16 17:23:31 +01002895 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V),
Bram Moolenaar68b76a62005-03-25 21:53:48 +00002896 len - (int)wp->w_old_cursor_fcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 }
2898 }
2899 else
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002900 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901 /* Set all attributes of the text */
Bram Moolenaar02631462017-09-22 15:20:32 +02002902 RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002903 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904 }
2905 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002907#ifdef FEAT_SYN_HL
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002908 /* Show colorcolumn in the fold line, but let cursorcolumn override it. */
2909 if (wp->w_p_cc_cols)
2910 {
2911 int i = 0;
2912 int j = wp->w_p_cc_cols[i];
2913 int old_txtcol = txtcol;
2914
2915 while (j > -1)
2916 {
2917 txtcol += j;
2918 if (wp->w_p_wrap)
2919 txtcol -= wp->w_skipcol;
2920 else
2921 txtcol -= wp->w_leftcol;
Bram Moolenaar02631462017-09-22 15:20:32 +02002922 if (txtcol >= 0 && txtcol < wp->w_width)
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002923 ScreenAttrs[off + txtcol] = hl_combine_attr(
Bram Moolenaar8820b482017-03-16 17:23:31 +01002924 ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC));
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002925 txtcol = old_txtcol;
2926 j = wp->w_p_cc_cols[++i];
2927 }
2928 }
2929
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002930 /* Show 'cursorcolumn' in the fold line. */
Bram Moolenaar85595c52008-10-02 16:04:05 +00002931 if (wp->w_p_cuc)
2932 {
2933 txtcol += wp->w_virtcol;
2934 if (wp->w_p_wrap)
2935 txtcol -= wp->w_skipcol;
2936 else
2937 txtcol -= wp->w_leftcol;
Bram Moolenaar02631462017-09-22 15:20:32 +02002938 if (txtcol >= 0 && txtcol < wp->w_width)
Bram Moolenaar85595c52008-10-02 16:04:05 +00002939 ScreenAttrs[off + txtcol] = hl_combine_attr(
Bram Moolenaar8820b482017-03-16 17:23:31 +01002940 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC));
Bram Moolenaar85595c52008-10-02 16:04:05 +00002941 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002942#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943
Bram Moolenaar02631462017-09-22 15:20:32 +02002944 screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
2945 (int)wp->w_width, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946
2947 /*
2948 * Update w_cline_height and w_cline_folded if the cursor line was
2949 * updated (saves a call to plines() later).
2950 */
2951 if (wp == curwin
2952 && lnum <= curwin->w_cursor.lnum
2953 && lnume >= curwin->w_cursor.lnum)
2954 {
2955 curwin->w_cline_row = row;
2956 curwin->w_cline_height = 1;
2957 curwin->w_cline_folded = TRUE;
2958 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
2959 }
2960}
2961
2962/*
2963 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
2964 */
2965 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002966copy_text_attr(
2967 int off,
2968 char_u *buf,
2969 int len,
2970 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971{
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002972 int i;
2973
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974 mch_memmove(ScreenLines + off, buf, (size_t)len);
2975# ifdef FEAT_MBYTE
2976 if (enc_utf8)
2977 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
2978# endif
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002979 for (i = 0; i < len; ++i)
2980 ScreenAttrs[off + i] = attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981}
2982
2983/*
2984 * Fill the foldcolumn at "p" for window "wp".
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +00002985 * Only to be called when 'foldcolumn' > 0.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 */
2987 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002988fill_foldcolumn(
2989 char_u *p,
2990 win_T *wp,
2991 int closed, /* TRUE of FALSE */
2992 linenr_T lnum) /* current line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993{
2994 int i = 0;
2995 int level;
2996 int first_level;
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002997 int empty;
Bram Moolenaar1c934292015-01-27 16:39:29 +01002998 int fdc = compute_foldcolumn(wp, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002999
3000 /* Init to all spaces. */
Bram Moolenaar2536d4f2015-07-17 13:22:51 +02003001 vim_memset(p, ' ', (size_t)fdc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002
3003 level = win_foldinfo.fi_level;
3004 if (level > 0)
3005 {
Bram Moolenaar578b49e2005-09-10 19:22:57 +00003006 /* If there is only one column put more info in it. */
Bram Moolenaar1c934292015-01-27 16:39:29 +01003007 empty = (fdc == 1) ? 0 : 1;
Bram Moolenaar578b49e2005-09-10 19:22:57 +00003008
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 /* If the column is too narrow, we start at the lowest level that
3010 * fits and use numbers to indicated the depth. */
Bram Moolenaar1c934292015-01-27 16:39:29 +01003011 first_level = level - fdc - closed + 1 + empty;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012 if (first_level < 1)
3013 first_level = 1;
3014
Bram Moolenaar1c934292015-01-27 16:39:29 +01003015 for (i = 0; i + empty < fdc; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 {
3017 if (win_foldinfo.fi_lnum == lnum
3018 && first_level + i >= win_foldinfo.fi_low_level)
3019 p[i] = '-';
3020 else if (first_level == 1)
3021 p[i] = '|';
3022 else if (first_level + i <= 9)
3023 p[i] = '0' + first_level + i;
3024 else
3025 p[i] = '>';
3026 if (first_level + i == level)
3027 break;
3028 }
3029 }
3030 if (closed)
Bram Moolenaar1c934292015-01-27 16:39:29 +01003031 p[i >= fdc ? i - 1 : i] = '+';
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032}
3033#endif /* FEAT_FOLDING */
3034
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01003035#ifdef FEAT_TEXT_PROP
3036static textprop_T *current_text_props = NULL;
3037static buf_T *current_buf = NULL;
3038
3039 static int
3040#ifdef __BORLANDC__
3041_RTLENTRYF
3042#endif
3043text_prop_compare(const void *s1, const void *s2)
3044{
3045 int idx1, idx2;
3046 proptype_T *pt1, *pt2;
3047 colnr_T col1, col2;
3048
3049 idx1 = *(int *)s1;
3050 idx2 = *(int *)s2;
3051 pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type);
3052 pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type);
3053 if (pt1 == pt2)
3054 return 0;
3055 if (pt1 == NULL)
3056 return -1;
3057 if (pt2 == NULL)
3058 return 1;
3059 if (pt1->pt_priority != pt2->pt_priority)
3060 return pt1->pt_priority > pt2->pt_priority ? 1 : -1;
3061 col1 = current_text_props[idx1].tp_col;
3062 col2 = current_text_props[idx2].tp_col;
3063 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1;
3064}
3065#endif
3066
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067/*
3068 * Display line "lnum" of window 'wp' on the screen.
3069 * Start at row "startrow", stop when "endrow" is reached.
3070 * wp->w_virtcol needs to be valid.
3071 *
3072 * Return the number of last row the line occupies.
3073 */
3074 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003075win_line(
3076 win_T *wp,
3077 linenr_T lnum,
3078 int startrow,
3079 int endrow,
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003080 int nochange UNUSED, // not updating for changed text
3081 int number_only) // only update the number column
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082{
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003083 int col = 0; /* visual column on screen */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 unsigned off; /* offset in ScreenLines/ScreenAttrs */
3085 int c = 0; /* init for GCC */
3086 long vcol = 0; /* virtual column (for tabs) */
Bram Moolenaard574ea22015-01-14 19:35:14 +01003087#ifdef FEAT_LINEBREAK
3088 long vcol_sbr = -1; /* virtual column after showbreak */
3089#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090 long vcol_prev = -1; /* "vcol" of previous character */
3091 char_u *line; /* current line */
3092 char_u *ptr; /* current position in "line" */
3093 int row; /* row in the window, excl w_winrow */
3094 int screen_row; /* row on the screen, incl w_winrow */
3095
3096 char_u extra[18]; /* "%ld" and 'fdc' must fit in here */
3097 int n_extra = 0; /* number of extra chars */
Bram Moolenaara064ac82007-08-05 18:10:54 +00003098 char_u *p_extra = NULL; /* string of extra chars, plus NUL */
Bram Moolenaar86b17e92014-07-02 20:00:47 +02003099 char_u *p_extra_free = NULL; /* p_extra needs to be freed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 int c_extra = NUL; /* extra chars, all the same */
3101 int extra_attr = 0; /* attributes when n_extra != 0 */
3102 static char_u *at_end_str = (char_u *)""; /* used for p_extra when
3103 displaying lcs_eol at end-of-line */
3104 int lcs_eol_one = lcs_eol; /* lcs_eol until it's been used */
3105 int lcs_prec_todo = lcs_prec; /* lcs_prec until it's been used */
3106
3107 /* saved "extra" items for when draw_state becomes WL_LINE (again) */
3108 int saved_n_extra = 0;
3109 char_u *saved_p_extra = NULL;
3110 int saved_c_extra = 0;
3111 int saved_char_attr = 0;
3112
3113 int n_attr = 0; /* chars with special attr */
3114 int saved_attr2 = 0; /* char_attr saved for n_attr */
3115 int n_attr3 = 0; /* chars with overruling special attr */
3116 int saved_attr3 = 0; /* char_attr saved for n_attr3 */
3117
3118 int n_skip = 0; /* nr of chars to skip for 'nowrap' */
3119
3120 int fromcol, tocol; /* start/end of inverting */
3121 int fromcol_prev = -2; /* start of inverting after cursor */
3122 int noinvcur = FALSE; /* don't invert the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003123 pos_T *top, *bot;
Bram Moolenaar54ef7112009-02-21 20:11:41 +00003124 int lnum_in_visual_area = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003125 pos_T pos;
3126 long v;
3127
3128 int char_attr = 0; /* attributes for next character */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003129 int attr_pri = FALSE; /* char_attr has priority */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 int area_highlighting = FALSE; /* Visual or incsearch highlighting
3131 in this line */
3132 int attr = 0; /* attributes for area highlighting */
3133 int area_attr = 0; /* attributes desired by highlighting */
3134 int search_attr = 0; /* attributes desired by 'hlsearch' */
3135#ifdef FEAT_SYN_HL
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003136 int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137 int syntax_attr = 0; /* attributes desired by syntax */
3138 int has_syntax = FALSE; /* this buffer has syntax highl. */
3139 int save_did_emsg;
Bram Moolenaara443af82007-11-08 13:51:42 +00003140 int eol_hl_off = 0; /* 1 if highlighted char after EOL */
Bram Moolenaar1a384422010-07-14 19:53:30 +02003141 int draw_color_col = FALSE; /* highlight colorcolumn */
3142 int *color_cols = NULL; /* pointer to according columns array */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003143#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003144#ifdef FEAT_TEXT_PROP
3145 int text_prop_count;
3146 int text_prop_next = 0; // next text property to use
3147 textprop_T *text_props = NULL;
3148 int *text_prop_idxs = NULL;
3149 int text_props_active = 0;
3150 proptype_T *text_prop_type = NULL;
3151 int text_prop_attr = 0;
3152#endif
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003153#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00003154 int has_spell = FALSE; /* this buffer has spell checking */
Bram Moolenaar30abd282005-06-22 22:35:10 +00003155# define SPWORDLEN 150
3156 char_u nextline[SPWORDLEN * 2];/* text with start of the next line */
Bram Moolenaar3b506942005-06-23 22:36:45 +00003157 int nextlinecol = 0; /* column where nextline[] starts */
3158 int nextline_idx = 0; /* index in nextline[] where next line
Bram Moolenaar30abd282005-06-22 22:35:10 +00003159 starts */
Bram Moolenaar217ad922005-03-20 22:37:15 +00003160 int spell_attr = 0; /* attributes desired by spelling */
3161 int word_end = 0; /* last byte with same spell_attr */
Bram Moolenaard042c562005-06-30 22:04:15 +00003162 static linenr_T checked_lnum = 0; /* line number for "checked_col" */
3163 static int checked_col = 0; /* column in "checked_lnum" up to which
Bram Moolenaar30abd282005-06-22 22:35:10 +00003164 * there are no spell errors */
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003165 static int cap_col = -1; /* column to check for Cap word */
3166 static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */
Bram Moolenaar30abd282005-06-22 22:35:10 +00003167 int cur_checked_col = 0; /* checked column for current line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003169 int extra_check = 0; // has extra highlighting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170#ifdef FEAT_MBYTE
3171 int multi_attr = 0; /* attributes desired by multibyte */
3172 int mb_l = 1; /* multi-byte byte length */
3173 int mb_c = 0; /* decoded multi-byte character */
3174 int mb_utf8 = FALSE; /* screen char is UTF-8 char */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003175 int u8cc[MAX_MCO]; /* composing UTF-8 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176#endif
3177#ifdef FEAT_DIFF
3178 int filler_lines; /* nr of filler lines to be drawn */
3179 int filler_todo; /* nr of filler lines still to do + 1 */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003180 hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181 int change_start = MAXCOL; /* first col of changed area */
3182 int change_end = -1; /* last col of changed area */
3183#endif
3184 colnr_T trailcol = MAXCOL; /* start of trailing spaces */
3185#ifdef FEAT_LINEBREAK
Bram Moolenaar6c896862016-11-17 19:46:51 +01003186 int need_showbreak = FALSE; /* overlong line, skipping first x
3187 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02003189#if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00003190 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191# define LINE_ATTR
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003192 int line_attr = 0; /* attribute for the whole line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193#endif
3194#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003195 matchitem_T *cur; /* points to the match list */
3196 match_T *shl; /* points to search_hl or a match */
3197 int shl_flag; /* flag to indicate whether search_hl
3198 has been processed or not */
Bram Moolenaarb3414592014-06-17 17:48:32 +02003199 int pos_inprogress; /* marks that position match search is
3200 in progress */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003201 int prevcol_hl_flag; /* flag to indicate whether prevcol
3202 equals startcol of search_hl or one
3203 of the matches */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204#endif
3205#ifdef FEAT_ARABIC
3206 int prev_c = 0; /* previous Arabic character */
3207 int prev_c1 = 0; /* first composing char for prev_c */
3208#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00003209#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00003210 int did_line_attr = 0;
3211#endif
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003212#ifdef FEAT_TERMINAL
3213 int get_term_attr = FALSE;
Bram Moolenaar238d43b2017-09-11 22:00:51 +02003214 int term_attr = 0; /* background for terminal window */
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003215#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216
3217 /* draw_state: items that are drawn in sequence: */
3218#define WL_START 0 /* nothing done yet */
3219#ifdef FEAT_CMDWIN
3220# define WL_CMDLINE WL_START + 1 /* cmdline window column */
3221#else
3222# define WL_CMDLINE WL_START
3223#endif
3224#ifdef FEAT_FOLDING
3225# define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
3226#else
3227# define WL_FOLD WL_CMDLINE
3228#endif
3229#ifdef FEAT_SIGNS
3230# define WL_SIGN WL_FOLD + 1 /* column for signs */
3231#else
3232# define WL_SIGN WL_FOLD /* column for signs */
3233#endif
3234#define WL_NR WL_SIGN + 1 /* line number */
Bram Moolenaar597a4222014-06-25 14:39:50 +02003235#ifdef FEAT_LINEBREAK
3236# define WL_BRI WL_NR + 1 /* 'breakindent' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237#else
Bram Moolenaar597a4222014-06-25 14:39:50 +02003238# define WL_BRI WL_NR
3239#endif
3240#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3241# define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */
3242#else
3243# define WL_SBR WL_BRI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244#endif
3245#define WL_LINE WL_SBR + 1 /* text in the line */
3246 int draw_state = WL_START; /* what to draw next */
Bram Moolenaar9372a112005-12-06 19:59:18 +00003247#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248 int feedback_col = 0;
3249 int feedback_old_attr = -1;
3250#endif
3251
Bram Moolenaar860cae12010-06-05 23:22:07 +02003252#ifdef FEAT_CONCEAL
3253 int syntax_flags = 0;
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02003254 int syntax_seqnr = 0;
Bram Moolenaar27c735b2010-07-22 22:16:29 +02003255 int prev_syntax_id = 0;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003256 int conceal_attr = HL_ATTR(HLF_CONCEAL);
Bram Moolenaar860cae12010-06-05 23:22:07 +02003257 int is_concealing = FALSE;
3258 int boguscols = 0; /* nonexistent columns added to force
3259 wrapping */
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02003260 int vcol_off = 0; /* offset for concealed characters */
Bram Moolenaarf5963f72010-07-23 22:10:27 +02003261 int did_wcol = FALSE;
Bram Moolenaar4d585022016-04-14 19:50:22 +02003262 int match_conc = 0; /* cchar for match functions */
3263 int has_match_conc = 0; /* match wants to conceal */
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01003264 int old_boguscols = 0;
Bram Moolenaarac550fd2010-07-18 13:55:02 +02003265# define VCOL_HLC (vcol - vcol_off)
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02003266# define FIX_FOR_BOGUSCOLS \
3267 { \
3268 n_extra += vcol_off; \
3269 vcol -= vcol_off; \
3270 vcol_off = 0; \
3271 col -= boguscols; \
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01003272 old_boguscols = boguscols; \
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02003273 boguscols = 0; \
3274 }
Bram Moolenaarac550fd2010-07-18 13:55:02 +02003275#else
3276# define VCOL_HLC (vcol)
Bram Moolenaar860cae12010-06-05 23:22:07 +02003277#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278
3279 if (startrow > endrow) /* past the end already! */
3280 return startrow;
3281
3282 row = startrow;
3283 screen_row = row + W_WINROW(wp);
3284
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003285 if (!number_only)
3286 {
3287 /*
3288 * To speed up the loop below, set extra_check when there is linebreak,
3289 * trailing white space and/or syntax processing to be done.
3290 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291#ifdef FEAT_LINEBREAK
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003292 extra_check = wp->w_p_lbr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293#endif
3294#ifdef FEAT_SYN_HL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003295 if (syntax_present(wp) && !wp->w_s->b_syn_error
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003296# ifdef SYN_TIME_LIMIT
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003297 && !wp->w_s->b_syn_slow
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003298# endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003299 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003301 /* Prepare for syntax highlighting in this line. When there is an
3302 * error, stop syntax highlighting. */
3303 save_did_emsg = did_emsg;
3304 did_emsg = FALSE;
3305 syntax_start(wp, lnum);
3306 if (did_emsg)
3307 wp->w_s->b_syn_error = TRUE;
3308 else
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003309 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003310 did_emsg = save_did_emsg;
3311#ifdef SYN_TIME_LIMIT
3312 if (!wp->w_s->b_syn_slow)
3313#endif
3314 {
3315 has_syntax = TRUE;
3316 extra_check = TRUE;
3317 }
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003318 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 }
Bram Moolenaar1a384422010-07-14 19:53:30 +02003320
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003321 /* Check for columns to display for 'colorcolumn'. */
3322 color_cols = wp->w_p_cc_cols;
3323 if (color_cols != NULL)
3324 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003325#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00003326
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003327#ifdef FEAT_TERMINAL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003328 if (term_show_buffer(wp->w_buffer))
3329 {
3330 extra_check = TRUE;
3331 get_term_attr = TRUE;
3332 term_attr = term_get_attr(wp->w_buffer, lnum, -1);
3333 }
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003334#endif
3335
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003336#ifdef FEAT_SPELL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003337 if (wp->w_p_spell
3338 && *wp->w_s->b_p_spl != NUL
3339 && wp->w_s->b_langp.ga_len > 0
3340 && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
Bram Moolenaar30abd282005-06-22 22:35:10 +00003341 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003342 /* Prepare for spell checking. */
3343 has_spell = TRUE;
3344 extra_check = TRUE;
3345
Bram Moolenaar7701f302018-10-02 21:20:32 +02003346 /* Get the start of the next line, so that words that wrap to the
3347 * next line are found too: "et<line-break>al.".
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003348 * Trick: skip a few chars for C/shell/Vim comments */
3349 nextline[SPWORDLEN] = NUL;
3350 if (lnum < wp->w_buffer->b_ml.ml_line_count)
3351 {
3352 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
3353 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
3354 }
3355
Bram Moolenaar7701f302018-10-02 21:20:32 +02003356 /* When a word wrapped from the previous line the start of the
3357 * current line is valid. */
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003358 if (lnum == checked_lnum)
3359 cur_checked_col = checked_col;
3360 checked_lnum = 0;
3361
3362 /* When there was a sentence end in the previous line may require a
3363 * word starting with capital in this line. In line 1 always check
3364 * the first word. */
3365 if (lnum != capcol_lnum)
3366 cap_col = -1;
3367 if (lnum == 1)
3368 cap_col = 0;
3369 capcol_lnum = 0;
Bram Moolenaar30abd282005-06-22 22:35:10 +00003370 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371#endif
3372
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003373 /*
3374 * handle visual active in this window
3375 */
3376 fromcol = -10;
3377 tocol = MAXCOL;
3378 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003380 /* Visual is after curwin->w_cursor */
3381 if (LTOREQ_POS(curwin->w_cursor, VIsual))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003382 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003383 top = &curwin->w_cursor;
3384 bot = &VIsual;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385 }
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003386 else /* Visual is before curwin->w_cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003388 top = &VIsual;
3389 bot = &curwin->w_cursor;
3390 }
3391 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
3392 if (VIsual_mode == Ctrl_V) /* block mode */
3393 {
3394 if (lnum_in_visual_area)
3395 {
3396 fromcol = wp->w_old_cursor_fcol;
3397 tocol = wp->w_old_cursor_lcol;
3398 }
3399 }
3400 else /* non-block mode */
3401 {
3402 if (lnum > top->lnum && lnum <= bot->lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003403 fromcol = 0;
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003404 else if (lnum == top->lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003406 if (VIsual_mode == 'V') /* linewise */
3407 fromcol = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003408 else
3409 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003410 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
3411 if (gchar_pos(top) == NUL)
3412 tocol = fromcol + 1;
3413 }
3414 }
3415 if (VIsual_mode != 'V' && lnum == bot->lnum)
3416 {
3417 if (*p_sel == 'e' && bot->col == 0
3418#ifdef FEAT_VIRTUALEDIT
3419 && bot->coladd == 0
3420#endif
3421 )
3422 {
3423 fromcol = -10;
3424 tocol = MAXCOL;
3425 }
3426 else if (bot->col == MAXCOL)
3427 tocol = MAXCOL;
3428 else
3429 {
3430 pos = *bot;
3431 if (*p_sel == 'e')
3432 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
3433 else
3434 {
3435 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
3436 ++tocol;
3437 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 }
3439 }
3440 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003442 /* Check if the character under the cursor should not be inverted */
3443 if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003444#ifdef FEAT_GUI
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003445 && !gui.in_use
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003446#endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003447 )
3448 noinvcur = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003450 /* if inverting in this line set area_highlighting */
3451 if (fromcol >= 0)
3452 {
3453 area_highlighting = TRUE;
3454 attr = HL_ATTR(HLF_V);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003456 if ((clip_star.available && !clip_star.owned
3457 && clip_isautosel_star())
3458 || (clip_plus.available && !clip_plus.owned
3459 && clip_isautosel_plus()))
3460 attr = HL_ATTR(HLF_VNC);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461#endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003465 /*
3466 * handle 'incsearch' and ":s///c" highlighting
3467 */
3468 else if (highlight_match
3469 && wp == curwin
3470 && lnum >= curwin->w_cursor.lnum
3471 && lnum <= curwin->w_cursor.lnum + search_match_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003473 if (lnum == curwin->w_cursor.lnum)
3474 getvcol(curwin, &(curwin->w_cursor),
3475 (colnr_T *)&fromcol, NULL, NULL);
3476 else
3477 fromcol = 0;
3478 if (lnum == curwin->w_cursor.lnum + search_match_lines)
3479 {
3480 pos.lnum = lnum;
3481 pos.col = search_match_endcol;
3482 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
3483 }
3484 else
3485 tocol = MAXCOL;
3486 /* do at least one character; happens when past end of line */
3487 if (fromcol == tocol)
3488 tocol = fromcol + 1;
3489 area_highlighting = TRUE;
3490 attr = HL_ATTR(HLF_I);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492 }
3493
3494#ifdef FEAT_DIFF
3495 filler_lines = diff_check(wp, lnum);
3496 if (filler_lines < 0)
3497 {
3498 if (filler_lines == -1)
3499 {
3500 if (diff_find_change(wp, lnum, &change_start, &change_end))
3501 diff_hlf = HLF_ADD; /* added line */
3502 else if (change_start == 0)
3503 diff_hlf = HLF_TXD; /* changed text */
3504 else
3505 diff_hlf = HLF_CHD; /* changed line */
3506 }
3507 else
3508 diff_hlf = HLF_ADD; /* added line */
3509 filler_lines = 0;
3510 area_highlighting = TRUE;
3511 }
3512 if (lnum == wp->w_topline)
3513 filler_lines = wp->w_topfill;
3514 filler_todo = filler_lines;
3515#endif
3516
3517#ifdef LINE_ATTR
3518# ifdef FEAT_SIGNS
3519 /* If this line has a sign with line highlighting set line_attr. */
3520 v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
3521 if (v != 0)
3522 line_attr = sign_get_attr((int)v, TRUE);
3523# endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02003524# if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 /* Highlight the current line in the quickfix window. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00003526 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
Bram Moolenaar21020352017-06-13 17:21:04 +02003527 line_attr = HL_ATTR(HLF_QFL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528# endif
3529 if (line_attr != 0)
3530 area_highlighting = TRUE;
3531#endif
3532
3533 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3534 ptr = line;
3535
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003536#ifdef FEAT_SPELL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003537 if (has_spell && !number_only)
Bram Moolenaar30abd282005-06-22 22:35:10 +00003538 {
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003539 /* For checking first word with a capital skip white space. */
3540 if (cap_col == 0)
Bram Moolenaare2e69e42017-09-02 20:30:35 +02003541 cap_col = getwhitecols(line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003542
Bram Moolenaar30abd282005-06-22 22:35:10 +00003543 /* To be able to spell-check over line boundaries copy the end of the
3544 * current line into nextline[]. Above the start of the next line was
3545 * copied to nextline[SPWORDLEN]. */
3546 if (nextline[SPWORDLEN] == NUL)
3547 {
3548 /* No next line or it is empty. */
3549 nextlinecol = MAXCOL;
3550 nextline_idx = 0;
3551 }
3552 else
3553 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003554 v = (long)STRLEN(line);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003555 if (v < SPWORDLEN)
3556 {
3557 /* Short line, use it completely and append the start of the
3558 * next line. */
3559 nextlinecol = 0;
3560 mch_memmove(nextline, line, (size_t)v);
Bram Moolenaar446cb832008-06-24 21:56:24 +00003561 STRMOVE(nextline + v, nextline + SPWORDLEN);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003562 nextline_idx = v + 1;
3563 }
3564 else
3565 {
3566 /* Long line, use only the last SPWORDLEN bytes. */
3567 nextlinecol = v - SPWORDLEN;
3568 mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
3569 nextline_idx = SPWORDLEN + 1;
3570 }
3571 }
3572 }
3573#endif
3574
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003575 if (wp->w_p_list)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576 {
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003577 if (lcs_space || lcs_trail)
3578 extra_check = TRUE;
3579 /* find start of trailing whitespace */
3580 if (lcs_trail)
3581 {
3582 trailcol = (colnr_T)STRLEN(ptr);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003583 while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003584 --trailcol;
3585 trailcol += (colnr_T) (ptr - line);
3586 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587 }
3588
3589 /*
3590 * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
3591 * first character to be displayed.
3592 */
3593 if (wp->w_p_wrap)
3594 v = wp->w_skipcol;
3595 else
3596 v = wp->w_leftcol;
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003597 if (v > 0 && !number_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598 {
3599#ifdef FEAT_MBYTE
3600 char_u *prev_ptr = ptr;
3601#endif
3602 while (vcol < v && *ptr != NUL)
3603 {
Bram Moolenaar597a4222014-06-25 14:39:50 +02003604 c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605 vcol += c;
3606#ifdef FEAT_MBYTE
3607 prev_ptr = ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608#endif
Bram Moolenaar91acfff2017-03-12 19:22:36 +01003609 MB_PTR_ADV(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610 }
3611
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003612 /* When:
3613 * - 'cuc' is set, or
Bram Moolenaar1a384422010-07-14 19:53:30 +02003614 * - 'colorcolumn' is set, or
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003615 * - 'virtualedit' is set, or
3616 * - the visual mode is active,
3617 * the end of the line may be before the start of the displayed part.
3618 */
3619 if (vcol < v && (
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01003620#ifdef FEAT_SYN_HL
3621 wp->w_p_cuc || draw_color_col ||
3622#endif
3623#ifdef FEAT_VIRTUALEDIT
3624 virtual_active() ||
3625#endif
3626 (VIsual_active && wp->w_buffer == curwin->w_buffer)))
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003627 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628 vcol = v;
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003629 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630
3631 /* Handle a character that's not completely on the screen: Put ptr at
3632 * that character but skip the first few screen characters. */
3633 if (vcol > v)
3634 {
3635 vcol -= c;
3636#ifdef FEAT_MBYTE
3637 ptr = prev_ptr;
3638#else
3639 --ptr;
3640#endif
Bram Moolenaarabc39ab2017-03-01 18:04:05 +01003641 /* If the character fits on the screen, don't need to skip it.
3642 * Except for a TAB. */
3643 if ((
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003644#ifdef FEAT_MBYTE
Bram Moolenaarabc39ab2017-03-01 18:04:05 +01003645 (*mb_ptr2cells)(ptr) >= c ||
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003646#endif
Bram Moolenaarabc39ab2017-03-01 18:04:05 +01003647 *ptr == TAB) && col == 0)
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003648 n_skip = v - vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649 }
3650
3651 /*
3652 * Adjust for when the inverted text is before the screen,
3653 * and when the start of the inverted text is before the screen.
3654 */
3655 if (tocol <= vcol)
3656 fromcol = 0;
3657 else if (fromcol >= 0 && fromcol < vcol)
3658 fromcol = vcol;
3659
3660#ifdef FEAT_LINEBREAK
3661 /* When w_skipcol is non-zero, first line needs 'showbreak' */
3662 if (wp->w_p_wrap)
3663 need_showbreak = TRUE;
3664#endif
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003665#ifdef FEAT_SPELL
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003666 /* When spell checking a word we need to figure out the start of the
3667 * word and if it's badly spelled or not. */
3668 if (has_spell)
3669 {
3670 int len;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003671 colnr_T linecol = (colnr_T)(ptr - line);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003672 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003673
3674 pos = wp->w_cursor;
3675 wp->w_cursor.lnum = lnum;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003676 wp->w_cursor.col = linecol;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003677 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003678
3679 /* spell_move_to() may call ml_get() and make "line" invalid */
3680 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3681 ptr = line + linecol;
3682
Bram Moolenaar60a795a2005-09-16 21:55:43 +00003683 if (len == 0 || (int)wp->w_cursor.col > ptr - line)
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003684 {
3685 /* no bad word found at line start, don't check until end of a
3686 * word */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003687 spell_hlf = HLF_COUNT;
Bram Moolenaar3b393a02012-06-06 19:05:50 +02003688 word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003689 }
3690 else
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003691 {
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003692 /* bad word found, use attributes until end of word */
3693 word_end = wp->w_cursor.col + len + 1;
3694
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003695 /* Turn index into actual attributes. */
3696 if (spell_hlf != HLF_COUNT)
3697 spell_attr = highlight_attr[spell_hlf];
3698 }
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003699 wp->w_cursor = pos;
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003700
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003701# ifdef FEAT_SYN_HL
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003702 /* Need to restart syntax highlighting for this line. */
3703 if (has_syntax)
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02003704 syntax_start(wp, lnum);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003705# endif
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003706 }
3707#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708 }
3709
3710 /*
3711 * Correct highlighting for cursor that can't be disabled.
3712 * Avoids having to check this for each character.
3713 */
3714 if (fromcol >= 0)
3715 {
3716 if (noinvcur)
3717 {
3718 if ((colnr_T)fromcol == wp->w_virtcol)
3719 {
3720 /* highlighting starts at cursor, let it start just after the
3721 * cursor */
3722 fromcol_prev = fromcol;
3723 fromcol = -1;
3724 }
3725 else if ((colnr_T)fromcol < wp->w_virtcol)
3726 /* restart highlighting after the cursor */
3727 fromcol_prev = wp->w_virtcol;
3728 }
3729 if (fromcol >= tocol)
3730 fromcol = -1;
3731 }
3732
3733#ifdef FEAT_SEARCH_EXTRA
3734 /*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003735 * Handle highlighting the last used search pattern and matches.
3736 * Do this for both search_hl and the match list.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003738 cur = wp->w_match_head;
3739 shl_flag = FALSE;
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003740 while ((cur != NULL || shl_flag == FALSE) && !number_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003742 if (shl_flag == FALSE)
3743 {
3744 shl = &search_hl;
3745 shl_flag = TRUE;
3746 }
3747 else
3748 shl = &cur->hl;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003749 shl->startcol = MAXCOL;
3750 shl->endcol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 shl->attr_cur = 0;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02003752 shl->is_addpos = FALSE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02003753 v = (long)(ptr - line);
3754 if (cur != NULL)
3755 cur->pos.cur = 0;
Bram Moolenaare17bdff2016-08-27 18:34:29 +02003756 next_search_hl(wp, shl, lnum, (colnr_T)v,
3757 shl == &search_hl ? NULL : cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02003758
3759 /* Need to get the line again, a multi-line regexp may have made it
3760 * invalid. */
3761 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3762 ptr = line + v;
3763
3764 if (shl->lnum != 0 && shl->lnum <= lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 {
Bram Moolenaarb3414592014-06-17 17:48:32 +02003766 if (shl->lnum == lnum)
3767 shl->startcol = shl->rm.startpos[0].col;
3768 else
3769 shl->startcol = 0;
3770 if (lnum == shl->lnum + shl->rm.endpos[0].lnum
3771 - shl->rm.startpos[0].lnum)
3772 shl->endcol = shl->rm.endpos[0].col;
3773 else
3774 shl->endcol = MAXCOL;
3775 /* Highlight one character for an empty match. */
3776 if (shl->startcol == shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003778#ifdef FEAT_MBYTE
Bram Moolenaarb3414592014-06-17 17:48:32 +02003779 if (has_mbyte && line[shl->endcol] != NUL)
3780 shl->endcol += (*mb_ptr2len)(line + shl->endcol);
3781 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003782#endif
Bram Moolenaarb3414592014-06-17 17:48:32 +02003783 ++shl->endcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003784 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02003785 if ((long)shl->startcol < v) /* match at leftcol */
3786 {
3787 shl->attr_cur = shl->attr;
3788 search_attr = shl->attr;
3789 }
3790 area_highlighting = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003792 if (shl != &search_hl && cur != NULL)
3793 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 }
3795#endif
3796
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003797#ifdef FEAT_SYN_HL
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02003798 /* Cursor line highlighting for 'cursorline' in the current window. Not
3799 * when Visual mode is active, because it's not clear what is selected
3800 * then. */
Bram Moolenaarbd65c462013-07-01 20:18:33 +02003801 if (wp->w_p_cul && lnum == wp->w_cursor.lnum
Bram Moolenaarb3414592014-06-17 17:48:32 +02003802 && !(wp == curwin && VIsual_active))
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003803 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003804 line_attr = HL_ATTR(HLF_CUL);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003805 area_highlighting = TRUE;
3806 }
3807#endif
3808
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003809#ifdef FEAT_TEXT_PROP
3810 {
3811 char_u *prop_start;
3812
3813 text_prop_count = get_text_props(wp->w_buffer, lnum,
3814 &prop_start, FALSE);
3815 if (text_prop_count > 0)
3816 {
3817 // Make a copy of the properties, so that they are properly
3818 // aligned.
3819 text_props = (textprop_T *)alloc(
3820 text_prop_count * sizeof(textprop_T));
3821 if (text_props != NULL)
3822 mch_memmove(text_props, prop_start,
3823 text_prop_count * sizeof(textprop_T));
3824
3825 // Allocate an array for the indexes.
3826 text_prop_idxs = (int *)alloc(text_prop_count * sizeof(int));
3827 area_highlighting = TRUE;
3828 extra_check = TRUE;
3829 }
3830 }
3831#endif
3832
Bram Moolenaar92d640f2005-09-05 22:11:52 +00003833 off = (unsigned)(current_ScreenLine - ScreenLines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 col = 0;
3835#ifdef FEAT_RIGHTLEFT
3836 if (wp->w_p_rl)
3837 {
3838 /* Rightleft window: process the text in the normal direction, but put
3839 * it in current_ScreenLine[] from right to left. Start at the
3840 * rightmost column of the window. */
Bram Moolenaar02631462017-09-22 15:20:32 +02003841 col = wp->w_width - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003842 off += col;
3843 }
3844#endif
3845
3846 /*
3847 * Repeat for the whole displayed line.
3848 */
3849 for (;;)
3850 {
Bram Moolenaar6561d522015-07-21 15:48:27 +02003851#ifdef FEAT_CONCEAL
Bram Moolenaar4d585022016-04-14 19:50:22 +02003852 has_match_conc = 0;
Bram Moolenaar6561d522015-07-21 15:48:27 +02003853#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854 /* Skip this quickly when working on the text. */
3855 if (draw_state != WL_LINE)
3856 {
3857#ifdef FEAT_CMDWIN
3858 if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
3859 {
3860 draw_state = WL_CMDLINE;
3861 if (cmdwin_type != 0 && wp == curwin)
3862 {
3863 /* Draw the cmdline character. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003864 n_extra = 1;
Bram Moolenaara064ac82007-08-05 18:10:54 +00003865 c_extra = cmdwin_type;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003866 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867 }
3868 }
3869#endif
3870
3871#ifdef FEAT_FOLDING
3872 if (draw_state == WL_FOLD - 1 && n_extra == 0)
3873 {
Bram Moolenaar1c934292015-01-27 16:39:29 +01003874 int fdc = compute_foldcolumn(wp, 0);
3875
Bram Moolenaar071d4272004-06-13 20:20:40 +00003876 draw_state = WL_FOLD;
Bram Moolenaar1c934292015-01-27 16:39:29 +01003877 if (fdc > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003878 {
Bram Moolenaar62706602016-12-09 19:28:48 +01003879 /* Draw the 'foldcolumn'. Allocate a buffer, "extra" may
Bram Moolenaarc695cec2017-01-08 20:00:04 +01003880 * already be in use. */
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01003881 vim_free(p_extra_free);
Bram Moolenaar62706602016-12-09 19:28:48 +01003882 p_extra_free = alloc(12 + 1);
3883
3884 if (p_extra_free != NULL)
3885 {
3886 fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
3887 n_extra = fdc;
3888 p_extra_free[n_extra] = NUL;
3889 p_extra = p_extra_free;
3890 c_extra = NUL;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003891 char_attr = HL_ATTR(HLF_FC);
Bram Moolenaar62706602016-12-09 19:28:48 +01003892 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 }
3894 }
3895#endif
3896
3897#ifdef FEAT_SIGNS
3898 if (draw_state == WL_SIGN - 1 && n_extra == 0)
3899 {
3900 draw_state = WL_SIGN;
3901 /* Show the sign column when there are any signs in this
3902 * buffer or when using Netbeans. */
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02003903 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 {
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01003905 int text_sign;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906# ifdef FEAT_SIGN_ICONS
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01003907 int icon_sign;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908# endif
3909
3910 /* Draw two cells with the sign value or blank. */
3911 c_extra = ' ';
Bram Moolenaar8820b482017-03-16 17:23:31 +01003912 char_attr = HL_ATTR(HLF_SC);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913 n_extra = 2;
3914
Bram Moolenaarbc6cf6c2014-05-22 15:51:04 +02003915 if (row == startrow
3916#ifdef FEAT_DIFF
3917 + filler_lines && filler_todo <= 0
3918#endif
3919 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 {
3921 text_sign = buf_getsigntype(wp->w_buffer, lnum,
3922 SIGN_TEXT);
3923# ifdef FEAT_SIGN_ICONS
3924 icon_sign = buf_getsigntype(wp->w_buffer, lnum,
3925 SIGN_ICON);
3926 if (gui.in_use && icon_sign != 0)
3927 {
3928 /* Use the image in this position. */
3929 c_extra = SIGN_BYTE;
3930# ifdef FEAT_NETBEANS_INTG
3931 if (buf_signcount(wp->w_buffer, lnum) > 1)
3932 c_extra = MULTISIGN_BYTE;
3933# endif
3934 char_attr = icon_sign;
3935 }
3936 else
3937# endif
3938 if (text_sign != 0)
3939 {
3940 p_extra = sign_get_text(text_sign);
3941 if (p_extra != NULL)
3942 {
3943 c_extra = NUL;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003944 n_extra = (int)STRLEN(p_extra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945 }
3946 char_attr = sign_get_attr(text_sign, FALSE);
3947 }
3948 }
3949 }
3950 }
3951#endif
3952
3953 if (draw_state == WL_NR - 1 && n_extra == 0)
3954 {
3955 draw_state = WL_NR;
Bram Moolenaar64486672010-05-16 15:46:46 +02003956 /* Display the absolute or relative line number. After the
3957 * first fill with blanks when the 'n' flag isn't in 'cpo' */
3958 if ((wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959 && (row == startrow
3960#ifdef FEAT_DIFF
3961 + filler_lines
3962#endif
3963 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
3964 {
3965 /* Draw the line number (empty space after wrapping). */
3966 if (row == startrow
3967#ifdef FEAT_DIFF
3968 + filler_lines
3969#endif
3970 )
3971 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003972 long num;
Bram Moolenaar700e7342013-01-30 12:31:36 +01003973 char *fmt = "%*ld ";
Bram Moolenaar64486672010-05-16 15:46:46 +02003974
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003975 if (wp->w_p_nu && !wp->w_p_rnu)
3976 /* 'number' + 'norelativenumber' */
Bram Moolenaar64486672010-05-16 15:46:46 +02003977 num = (long)lnum;
3978 else
Bram Moolenaar700e7342013-01-30 12:31:36 +01003979 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003980 /* 'relativenumber', don't use negative numbers */
Bram Moolenaar7eb46522010-12-30 14:57:08 +01003981 num = labs((long)get_cursor_rel_lnum(wp, lnum));
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003982 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01003983 {
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003984 /* 'number' + 'relativenumber' */
Bram Moolenaar700e7342013-01-30 12:31:36 +01003985 num = lnum;
3986 fmt = "%-*ld ";
3987 }
3988 }
Bram Moolenaar64486672010-05-16 15:46:46 +02003989
Bram Moolenaar700e7342013-01-30 12:31:36 +01003990 sprintf((char *)extra, fmt,
Bram Moolenaar64486672010-05-16 15:46:46 +02003991 number_width(wp), num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992 if (wp->w_skipcol > 0)
3993 for (p_extra = extra; *p_extra == ' '; ++p_extra)
3994 *p_extra = '-';
3995#ifdef FEAT_RIGHTLEFT
3996 if (wp->w_p_rl) /* reverse line numbers */
3997 rl_mirror(extra);
3998#endif
3999 p_extra = extra;
4000 c_extra = NUL;
4001 }
4002 else
4003 c_extra = ' ';
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004004 n_extra = number_width(wp) + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004005 char_attr = HL_ATTR(HLF_N);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004006#ifdef FEAT_SYN_HL
4007 /* When 'cursorline' is set highlight the line number of
Bram Moolenaar06ca5132012-03-23 16:25:17 +01004008 * the current line differently.
4009 * TODO: Can we use CursorLine instead of CursorLineNr
4010 * when CursorLineNr isn't set? */
Bram Moolenaarbd65c462013-07-01 20:18:33 +02004011 if ((wp->w_p_cul || wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01004012 && lnum == wp->w_cursor.lnum)
Bram Moolenaar8820b482017-03-16 17:23:31 +01004013 char_attr = HL_ATTR(HLF_CLN);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004014#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015 }
4016 }
4017
Bram Moolenaar597a4222014-06-25 14:39:50 +02004018#ifdef FEAT_LINEBREAK
4019 if (wp->w_p_brisbr && draw_state == WL_BRI - 1
4020 && n_extra == 0 && *p_sbr != NUL)
4021 /* draw indent after showbreak value */
4022 draw_state = WL_BRI;
4023 else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0)
4024 /* After the showbreak, draw the breakindent */
4025 draw_state = WL_BRI - 1;
4026
4027 /* draw 'breakindent': indent wrapped text accordingly */
4028 if (draw_state == WL_BRI - 1 && n_extra == 0)
4029 {
4030 draw_state = WL_BRI;
Bram Moolenaar6c896862016-11-17 19:46:51 +01004031 /* if need_showbreak is set, breakindent also applies */
4032 if (wp->w_p_bri && n_extra == 0
4033 && (row != startrow || need_showbreak)
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004034# ifdef FEAT_DIFF
Bram Moolenaar597a4222014-06-25 14:39:50 +02004035 && filler_lines == 0
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004036# endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02004037 )
4038 {
Bram Moolenaar6c896862016-11-17 19:46:51 +01004039 char_attr = 0;
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004040# ifdef FEAT_DIFF
Bram Moolenaar597a4222014-06-25 14:39:50 +02004041 if (diff_hlf != (hlf_T)0)
Bram Moolenaare0f14822014-08-06 13:20:56 +02004042 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004043 char_attr = HL_ATTR(diff_hlf);
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004044# ifdef FEAT_SYN_HL
Bram Moolenaare0f14822014-08-06 13:20:56 +02004045 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
4046 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01004047 HL_ATTR(HLF_CUL));
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004048# endif
Bram Moolenaare0f14822014-08-06 13:20:56 +02004049 }
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004050# endif
Bram Moolenaarb8b57462014-07-03 22:54:08 +02004051 p_extra = NULL;
Bram Moolenaar597a4222014-06-25 14:39:50 +02004052 c_extra = ' ';
4053 n_extra = get_breakindent_win(wp,
4054 ml_get_buf(wp->w_buffer, lnum, FALSE));
4055 /* Correct end of highlighted area for 'breakindent',
4056 * required when 'linebreak' is also set. */
4057 if (tocol == vcol)
4058 tocol += n_extra;
4059 }
4060 }
4061#endif
4062
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
4064 if (draw_state == WL_SBR - 1 && n_extra == 0)
4065 {
4066 draw_state = WL_SBR;
4067# ifdef FEAT_DIFF
4068 if (filler_todo > 0)
4069 {
4070 /* Draw "deleted" diff line(s). */
4071 if (char2cells(fill_diff) > 1)
4072 c_extra = '-';
4073 else
4074 c_extra = fill_diff;
4075# ifdef FEAT_RIGHTLEFT
4076 if (wp->w_p_rl)
4077 n_extra = col + 1;
4078 else
4079# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004080 n_extra = wp->w_width - col;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004081 char_attr = HL_ATTR(HLF_DED);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004082 }
4083# endif
4084# ifdef FEAT_LINEBREAK
4085 if (*p_sbr != NUL && need_showbreak)
4086 {
4087 /* Draw 'showbreak' at the start of each broken line. */
4088 p_extra = p_sbr;
4089 c_extra = NUL;
4090 n_extra = (int)STRLEN(p_sbr);
Bram Moolenaar8820b482017-03-16 17:23:31 +01004091 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 need_showbreak = FALSE;
Bram Moolenaard574ea22015-01-14 19:35:14 +01004093 vcol_sbr = vcol + MB_CHARLEN(p_sbr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 /* Correct end of highlighted area for 'showbreak',
4095 * required when 'linebreak' is also set. */
4096 if (tocol == vcol)
4097 tocol += n_extra;
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02004098#ifdef FEAT_SYN_HL
4099 /* combine 'showbreak' with 'cursorline' */
Bram Moolenaarbd65c462013-07-01 20:18:33 +02004100 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
Bram Moolenaare0f14822014-08-06 13:20:56 +02004101 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01004102 HL_ATTR(HLF_CUL));
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02004103#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 }
4105# endif
4106 }
4107#endif
4108
4109 if (draw_state == WL_LINE - 1 && n_extra == 0)
4110 {
4111 draw_state = WL_LINE;
4112 if (saved_n_extra)
4113 {
4114 /* Continue item from end of wrapped line. */
4115 n_extra = saved_n_extra;
4116 c_extra = saved_c_extra;
4117 p_extra = saved_p_extra;
4118 char_attr = saved_char_attr;
4119 }
4120 else
4121 char_attr = 0;
4122 }
4123 }
4124
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02004125 // When still displaying '$' of change command, stop at cursor.
4126 // When only displaying the (relative) line number and that's done,
4127 // stop here.
4128 if ((dollar_vcol >= 0 && wp == curwin
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004129 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
Bram Moolenaar071d4272004-06-13 20:20:40 +00004130#ifdef FEAT_DIFF
4131 && filler_todo <= 0
4132#endif
4133 )
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02004134 || (number_only && draw_state > WL_NR))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 {
Bram Moolenaar02631462017-09-22 15:20:32 +02004136 screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
Bram Moolenaarc0aa4822017-07-16 14:04:29 +02004137 HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004138 /* Pretend we have finished updating the window. Except when
4139 * 'cursorcolumn' is set. */
4140#ifdef FEAT_SYN_HL
4141 if (wp->w_p_cuc)
4142 row = wp->w_cline_row + wp->w_cline_height;
4143 else
4144#endif
4145 row = wp->w_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 break;
4147 }
4148
Bram Moolenaar637532b2019-01-03 21:44:40 +01004149 if (draw_state == WL_LINE && (area_highlighting
4150#ifdef FEAT_SPELL
4151 || has_spell
4152#endif
4153 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 {
4155 /* handle Visual or match highlighting in this line */
4156 if (vcol == fromcol
4157#ifdef FEAT_MBYTE
4158 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
4159 && (*mb_ptr2cells)(ptr) > 1)
4160#endif
4161 || ((int)vcol_prev == fromcol_prev
Bram Moolenaarfa363cd2009-02-21 20:23:59 +00004162 && vcol_prev < vcol /* not at margin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 && vcol < tocol))
4164 area_attr = attr; /* start highlighting */
4165 else if (area_attr != 0
4166 && (vcol == tocol
4167 || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 area_attr = 0; /* stop highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169
4170#ifdef FEAT_SEARCH_EXTRA
4171 if (!n_extra)
4172 {
4173 /*
4174 * Check for start/end of search pattern match.
4175 * After end, check for start/end of next match.
4176 * When another match, have to check for start again.
4177 * Watch out for matching an empty string!
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004178 * Do this for 'search_hl' and the match list (ordered by
4179 * priority).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180 */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004181 v = (long)(ptr - line);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004182 cur = wp->w_match_head;
4183 shl_flag = FALSE;
4184 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004186 if (shl_flag == FALSE
4187 && ((cur != NULL
4188 && cur->priority > SEARCH_HL_PRIORITY)
4189 || cur == NULL))
4190 {
4191 shl = &search_hl;
4192 shl_flag = TRUE;
4193 }
4194 else
4195 shl = &cur->hl;
Bram Moolenaarb3414592014-06-17 17:48:32 +02004196 if (cur != NULL)
4197 cur->pos.cur = 0;
4198 pos_inprogress = TRUE;
4199 while (shl->rm.regprog != NULL
4200 || (cur != NULL && pos_inprogress))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004202 if (shl->startcol != MAXCOL
4203 && v >= (long)shl->startcol
4204 && v < (long)shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205 {
Bram Moolenaaraff5c3a2014-12-13 03:36:39 +01004206#ifdef FEAT_MBYTE
4207 int tmp_col = v + MB_PTR2LEN(ptr);
4208
4209 if (shl->endcol < tmp_col)
4210 shl->endcol = tmp_col;
4211#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004212 shl->attr_cur = shl->attr;
Bram Moolenaar6561d522015-07-21 15:48:27 +02004213#ifdef FEAT_CONCEAL
4214 if (cur != NULL && syn_name2id((char_u *)"Conceal")
4215 == cur->hlg_id)
4216 {
Bram Moolenaar4d585022016-04-14 19:50:22 +02004217 has_match_conc =
4218 v == (long)shl->startcol ? 2 : 1;
Bram Moolenaar6561d522015-07-21 15:48:27 +02004219 match_conc = cur->conceal_char;
4220 }
4221 else
Bram Moolenaar4d585022016-04-14 19:50:22 +02004222 has_match_conc = match_conc = 0;
Bram Moolenaar6561d522015-07-21 15:48:27 +02004223#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224 }
Bram Moolenaaraff5c3a2014-12-13 03:36:39 +01004225 else if (v == (long)shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226 {
4227 shl->attr_cur = 0;
Bram Moolenaare17bdff2016-08-27 18:34:29 +02004228 next_search_hl(wp, shl, lnum, (colnr_T)v,
4229 shl == &search_hl ? NULL : cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02004230 pos_inprogress = cur == NULL || cur->pos.cur == 0
Bram Moolenaar6561d522015-07-21 15:48:27 +02004231 ? FALSE : TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232
4233 /* Need to get the line again, a multi-line regexp
4234 * may have made it invalid. */
4235 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4236 ptr = line + v;
4237
4238 if (shl->lnum == lnum)
4239 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004240 shl->startcol = shl->rm.startpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 if (shl->rm.endpos[0].lnum == 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004242 shl->endcol = shl->rm.endpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243 else
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004244 shl->endcol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004246 if (shl->startcol == shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247 {
4248 /* highlight empty match, try again after
4249 * it */
4250#ifdef FEAT_MBYTE
4251 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004252 shl->endcol += (*mb_ptr2len)(line
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004253 + shl->endcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 else
4255#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004256 ++shl->endcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 }
4258
4259 /* Loop to check if the match starts at the
4260 * current position */
4261 continue;
4262 }
4263 }
4264 break;
4265 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004266 if (shl != &search_hl && cur != NULL)
4267 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004269
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004270 /* Use attributes from match with highest priority among
4271 * 'search_hl' and the match list. */
4272 search_attr = search_hl.attr_cur;
4273 cur = wp->w_match_head;
4274 shl_flag = FALSE;
4275 while (cur != NULL || shl_flag == FALSE)
4276 {
4277 if (shl_flag == FALSE
4278 && ((cur != NULL
4279 && cur->priority > SEARCH_HL_PRIORITY)
4280 || cur == NULL))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004281 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004282 shl = &search_hl;
4283 shl_flag = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004284 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004285 else
4286 shl = &cur->hl;
4287 if (shl->attr_cur != 0)
4288 search_attr = shl->attr_cur;
4289 if (shl != &search_hl && cur != NULL)
4290 cur = cur->next;
4291 }
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02004292 /* Only highlight one character after the last column. */
Bram Moolenaar5ece3e32017-10-01 14:35:02 +02004293 if (*ptr == NUL && (did_line_attr >= 1
4294 || (wp->w_p_list && lcs_eol_one == -1)))
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02004295 search_attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 }
4297#endif
4298
Bram Moolenaar071d4272004-06-13 20:20:40 +00004299#ifdef FEAT_DIFF
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004300 if (diff_hlf != (hlf_T)0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 {
Bram Moolenaar4b80a512007-06-19 15:44:58 +00004302 if (diff_hlf == HLF_CHD && ptr - line >= change_start
4303 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304 diff_hlf = HLF_TXD; /* changed text */
Bram Moolenaar4b80a512007-06-19 15:44:58 +00004305 if (diff_hlf == HLF_TXD && ptr - line > change_end
4306 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004307 diff_hlf = HLF_CHD; /* changed line */
Bram Moolenaar8820b482017-03-16 17:23:31 +01004308 line_attr = HL_ATTR(diff_hlf);
Bram Moolenaare0f14822014-08-06 13:20:56 +02004309 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
Bram Moolenaar8820b482017-03-16 17:23:31 +01004310 line_attr = hl_combine_attr(line_attr, HL_ATTR(HLF_CUL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311 }
4312#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004313
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004314#ifdef FEAT_TEXT_PROP
4315 if (text_props != NULL)
4316 {
4317 int pi;
Bram Moolenaar5e53ac02019-01-01 20:31:31 +01004318 int bcol = (int)(ptr - line);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004319
4320 // Check if any active property ends.
4321 for (pi = 0; pi < text_props_active; ++pi)
4322 {
4323 int tpi = text_prop_idxs[pi];
4324
Bram Moolenaar5e53ac02019-01-01 20:31:31 +01004325 if (bcol >= text_props[tpi].tp_col - 1
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004326 + text_props[tpi].tp_len)
4327 {
4328 if (pi + 1 < text_props_active)
4329 mch_memmove(text_prop_idxs + pi,
4330 text_prop_idxs + pi + 1,
4331 sizeof(int)
4332 * (text_props_active - (pi + 1)));
4333 --text_props_active;
4334 --pi;
4335 }
4336 }
4337
4338 // Add any text property that starts in this column.
4339 while (text_prop_next < text_prop_count
Bram Moolenaar5e53ac02019-01-01 20:31:31 +01004340 && bcol >= text_props[text_prop_next].tp_col - 1)
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004341 text_prop_idxs[text_props_active++] = text_prop_next++;
4342
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004343 text_prop_attr = 0;
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004344 if (text_props_active > 0)
4345 {
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004346 // Sort the properties on priority and/or starting last.
4347 // Then combine the attributes, highest priority last.
4348 current_text_props = text_props;
4349 current_buf = wp->w_buffer;
4350 qsort((void *)text_prop_idxs, (size_t)text_props_active,
4351 sizeof(int), text_prop_compare);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004352
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004353 for (pi = 0; pi < text_props_active; ++pi)
4354 {
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004355 int tpi = text_prop_idxs[pi];
4356 proptype_T *pt = text_prop_type_by_id(wp->w_buffer, text_props[tpi].tp_type);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004357
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004358 if (pt != NULL)
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004359 {
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004360 int pt_attr = syn_id2attr(pt->pt_hl_id);
4361
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004362 text_prop_type = pt;
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004363 if (text_prop_attr == 0)
4364 text_prop_attr = pt_attr;
4365 else
4366 text_prop_attr = hl_combine_attr(text_prop_attr, pt_attr);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004367 }
4368 }
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004369 }
4370 }
4371#endif
4372
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004373 /* Decide which of the highlight attributes to use. */
4374 attr_pri = TRUE;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004375#ifdef LINE_ATTR
Bram Moolenaar09deeb72015-03-24 18:22:41 +01004376 if (area_attr != 0)
4377 char_attr = hl_combine_attr(line_attr, area_attr);
4378 else if (search_attr != 0)
4379 char_attr = hl_combine_attr(line_attr, search_attr);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004380 /* Use line_attr when not in the Visual or 'incsearch' area
4381 * (area_attr may be 0 when "noinvcur" is set). */
4382 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
Bram Moolenaarf837ef92009-03-11 16:47:21 +00004383 || vcol < fromcol || vcol_prev < fromcol_prev
4384 || vcol >= tocol))
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004385 char_attr = line_attr;
Bram Moolenaar09deeb72015-03-24 18:22:41 +01004386#else
4387 if (area_attr != 0)
4388 char_attr = area_attr;
4389 else if (search_attr != 0)
4390 char_attr = search_attr;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004391#endif
4392 else
4393 {
4394 attr_pri = FALSE;
Bram Moolenaar98aefe72018-12-13 22:20:09 +01004395#ifdef FEAT_TEXT_PROP
4396 if (text_prop_type != NULL)
4397 char_attr = text_prop_attr;
4398 else
4399#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004400#ifdef FEAT_SYN_HL
4401 if (has_syntax)
4402 char_attr = syntax_attr;
4403 else
4404#endif
4405 char_attr = 0;
4406 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407 }
4408
4409 /*
4410 * Get the next character to put on the screen.
4411 */
4412 /*
Bram Moolenaara064ac82007-08-05 18:10:54 +00004413 * The "p_extra" points to the extra stuff that is inserted to
4414 * represent special characters (non-printable stuff) and other
4415 * things. When all characters are the same, c_extra is used.
4416 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
4417 * "p_extra[n_extra]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
4419 */
4420 if (n_extra > 0)
4421 {
4422 if (c_extra != NUL)
4423 {
4424 c = c_extra;
4425#ifdef FEAT_MBYTE
4426 mb_c = c; /* doesn't handle non-utf-8 multi-byte! */
Bram Moolenaarace95982017-03-29 17:30:27 +02004427 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004428 {
4429 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004430 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004431 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432 }
4433 else
4434 mb_utf8 = FALSE;
4435#endif
4436 }
4437 else
4438 {
4439 c = *p_extra;
4440#ifdef FEAT_MBYTE
4441 if (has_mbyte)
4442 {
4443 mb_c = c;
4444 if (enc_utf8)
4445 {
4446 /* If the UTF-8 character is more than one byte:
4447 * Decode it into "mb_c". */
Bram Moolenaarace95982017-03-29 17:30:27 +02004448 mb_l = utfc_ptr2len(p_extra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449 mb_utf8 = FALSE;
4450 if (mb_l > n_extra)
4451 mb_l = 1;
4452 else if (mb_l > 1)
4453 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004454 mb_c = utfc_ptr2char(p_extra, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 mb_utf8 = TRUE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004456 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457 }
4458 }
4459 else
4460 {
4461 /* if this is a DBCS character, put it in "mb_c" */
4462 mb_l = MB_BYTE2LEN(c);
4463 if (mb_l >= n_extra)
4464 mb_l = 1;
4465 else if (mb_l > 1)
4466 mb_c = (c << 8) + p_extra[1];
4467 }
Bram Moolenaar92d640f2005-09-05 22:11:52 +00004468 if (mb_l == 0) /* at the NUL at end-of-line */
4469 mb_l = 1;
4470
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471 /* If a double-width char doesn't fit display a '>' in the
4472 * last column. */
Bram Moolenaar92d640f2005-09-05 22:11:52 +00004473 if ((
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474# ifdef FEAT_RIGHTLEFT
4475 wp->w_p_rl ? (col <= 0) :
4476# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004477 (col >= wp->w_width - 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 && (*mb_char2cells)(mb_c) == 2)
4479 {
4480 c = '>';
4481 mb_c = c;
4482 mb_l = 1;
4483 mb_utf8 = FALSE;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004484 multi_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004485 /* put the pointer back to output the double-width
4486 * character at the start of the next line. */
4487 ++n_extra;
4488 --p_extra;
4489 }
4490 else
4491 {
4492 n_extra -= mb_l - 1;
4493 p_extra += mb_l - 1;
4494 }
4495 }
4496#endif
4497 ++p_extra;
4498 }
4499 --n_extra;
4500 }
4501 else
4502 {
Bram Moolenaar88e76882017-02-27 20:33:46 +01004503#ifdef FEAT_LINEBREAK
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004504 int c0;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004505#endif
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004506
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004507 if (p_extra_free != NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +01004508 VIM_CLEAR(p_extra_free);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509 /*
4510 * Get a character from the line itself.
4511 */
Bram Moolenaar10a8da02017-02-27 21:11:35 +01004512 c = *ptr;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004513#ifdef FEAT_LINEBREAK
Bram Moolenaar10a8da02017-02-27 21:11:35 +01004514 c0 = *ptr;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004515#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516#ifdef FEAT_MBYTE
4517 if (has_mbyte)
4518 {
4519 mb_c = c;
4520 if (enc_utf8)
4521 {
4522 /* If the UTF-8 character is more than one byte: Decode it
4523 * into "mb_c". */
Bram Moolenaarace95982017-03-29 17:30:27 +02004524 mb_l = utfc_ptr2len(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525 mb_utf8 = FALSE;
4526 if (mb_l > 1)
4527 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004528 mb_c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529 /* Overlong encoded ASCII or ASCII with composing char
4530 * is displayed normally, except a NUL. */
4531 if (mb_c < 0x80)
Bram Moolenaar88e76882017-02-27 20:33:46 +01004532 {
4533 c = mb_c;
4534# ifdef FEAT_LINEBREAK
4535 c0 = mb_c;
4536# endif
4537 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 mb_utf8 = TRUE;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00004539
4540 /* At start of the line we can have a composing char.
4541 * Draw it as a space with a composing char. */
4542 if (utf_iscomposing(mb_c))
4543 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004544 int i;
4545
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004546 for (i = Screen_mco - 1; i > 0; --i)
4547 u8cc[i] = u8cc[i - 1];
4548 u8cc[0] = mb_c;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00004549 mb_c = ' ';
4550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 }
4552
4553 if ((mb_l == 1 && c >= 0x80)
4554 || (mb_l >= 1 && mb_c == 0)
4555 || (mb_l > 1 && (!vim_isprintc(mb_c)
Bram Moolenaar11936362007-09-17 20:39:42 +00004556# ifdef UNICODE16
4557 || mb_c >= 0x10000
4558# endif
4559 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560 {
4561 /*
4562 * Illegal UTF-8 byte: display as <xx>.
4563 * Non-BMP character : display as ? or fullwidth ?.
4564 */
Bram Moolenaar11936362007-09-17 20:39:42 +00004565# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566 if (mb_c < 0x10000)
Bram Moolenaar11936362007-09-17 20:39:42 +00004567# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568 {
4569 transchar_hex(extra, mb_c);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004570# ifdef FEAT_RIGHTLEFT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571 if (wp->w_p_rl) /* reverse */
4572 rl_mirror(extra);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004573# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574 }
Bram Moolenaar11936362007-09-17 20:39:42 +00004575# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00004576 else if (utf_char2cells(mb_c) != 2)
4577 STRCPY(extra, "?");
4578 else
4579 /* 0xff1f in UTF-8: full-width '?' */
4580 STRCPY(extra, "\357\274\237");
Bram Moolenaar11936362007-09-17 20:39:42 +00004581# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582
4583 p_extra = extra;
4584 c = *p_extra;
4585 mb_c = mb_ptr2char_adv(&p_extra);
4586 mb_utf8 = (c >= 0x80);
4587 n_extra = (int)STRLEN(p_extra);
4588 c_extra = NUL;
4589 if (area_attr == 0 && search_attr == 0)
4590 {
4591 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004592 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593 saved_attr2 = char_attr; /* save current attr */
4594 }
4595 }
4596 else if (mb_l == 0) /* at the NUL at end-of-line */
4597 mb_l = 1;
4598#ifdef FEAT_ARABIC
4599 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
4600 {
4601 /* Do Arabic shaping. */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004602 int pc, pc1, nc;
4603 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604
4605 /* The idea of what is the previous and next
4606 * character depends on 'rightleft'. */
4607 if (wp->w_p_rl)
4608 {
4609 pc = prev_c;
4610 pc1 = prev_c1;
4611 nc = utf_ptr2char(ptr + mb_l);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004612 prev_c1 = u8cc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613 }
4614 else
4615 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004616 pc = utfc_ptr2char(ptr + mb_l, pcc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 nc = prev_c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004618 pc1 = pcc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619 }
4620 prev_c = mb_c;
4621
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004622 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 }
4624 else
4625 prev_c = mb_c;
4626#endif
4627 }
4628 else /* enc_dbcs */
4629 {
4630 mb_l = MB_BYTE2LEN(c);
4631 if (mb_l == 0) /* at the NUL at end-of-line */
4632 mb_l = 1;
4633 else if (mb_l > 1)
4634 {
4635 /* We assume a second byte below 32 is illegal.
4636 * Hopefully this is OK for all double-byte encodings!
4637 */
4638 if (ptr[1] >= 32)
4639 mb_c = (c << 8) + ptr[1];
4640 else
4641 {
4642 if (ptr[1] == NUL)
4643 {
4644 /* head byte at end of line */
4645 mb_l = 1;
4646 transchar_nonprint(extra, c);
4647 }
4648 else
4649 {
4650 /* illegal tail byte */
4651 mb_l = 2;
4652 STRCPY(extra, "XX");
4653 }
4654 p_extra = extra;
4655 n_extra = (int)STRLEN(extra) - 1;
4656 c_extra = NUL;
4657 c = *p_extra++;
4658 if (area_attr == 0 && search_attr == 0)
4659 {
4660 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004661 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004662 saved_attr2 = char_attr; /* save current attr */
4663 }
4664 mb_c = c;
4665 }
4666 }
4667 }
4668 /* If a double-width char doesn't fit display a '>' in the
4669 * last column; the character is displayed at the start of the
4670 * next line. */
4671 if ((
4672# ifdef FEAT_RIGHTLEFT
4673 wp->w_p_rl ? (col <= 0) :
4674# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004675 (col >= wp->w_width - 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 && (*mb_char2cells)(mb_c) == 2)
4677 {
4678 c = '>';
4679 mb_c = c;
4680 mb_utf8 = FALSE;
4681 mb_l = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004682 multi_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683 /* Put pointer back so that the character will be
4684 * displayed at the start of the next line. */
4685 --ptr;
4686 }
4687 else if (*ptr != NUL)
4688 ptr += mb_l - 1;
4689
4690 /* If a double-width char doesn't fit at the left side display
Bram Moolenaar7ba6ed32010-08-07 16:38:13 +02004691 * a '<' in the first column. Don't do this for unprintable
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02004692 * characters. */
Bram Moolenaar7ba6ed32010-08-07 16:38:13 +02004693 if (n_skip > 0 && mb_l > 1 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695 n_extra = 1;
Bram Moolenaar5641f382012-06-13 18:06:36 +02004696 c_extra = MB_FILLER_CHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697 c = ' ';
4698 if (area_attr == 0 && search_attr == 0)
4699 {
4700 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004701 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702 saved_attr2 = char_attr; /* save current attr */
4703 }
4704 mb_c = c;
4705 mb_utf8 = FALSE;
4706 mb_l = 1;
4707 }
4708
4709 }
4710#endif
4711 ++ptr;
4712
4713 if (extra_check)
4714 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004715#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00004716 int can_spell = TRUE;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004717#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00004718
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02004719#ifdef FEAT_TERMINAL
4720 if (get_term_attr)
4721 {
Bram Moolenaar68c4bdd2017-07-30 13:57:41 +02004722 syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol);
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02004723
4724 if (!attr_pri)
4725 char_attr = syntax_attr;
4726 else
4727 char_attr = hl_combine_attr(syntax_attr, char_attr);
4728 }
4729#endif
4730
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004731#ifdef FEAT_SYN_HL
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004732 // Get syntax attribute, unless still at the start of the line
4733 // (double-wide char that doesn't fit).
Bram Moolenaar217ad922005-03-20 22:37:15 +00004734 v = (long)(ptr - line);
4735 if (has_syntax && v > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736 {
4737 /* Get the syntax attribute for the character. If there
4738 * is an error, disable syntax highlighting. */
4739 save_did_emsg = did_emsg;
4740 did_emsg = FALSE;
4741
Bram Moolenaar217ad922005-03-20 22:37:15 +00004742 syntax_attr = get_syntax_attr((colnr_T)v - 1,
Bram Moolenaar860cae12010-06-05 23:22:07 +02004743# ifdef FEAT_SPELL
4744 has_spell ? &can_spell :
4745# endif
4746 NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004747
4748 if (did_emsg)
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004749 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02004750 wp->w_s->b_syn_error = TRUE;
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004751 has_syntax = FALSE;
4752 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753 else
4754 did_emsg = save_did_emsg;
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02004755#ifdef SYN_TIME_LIMIT
4756 if (wp->w_s->b_syn_slow)
4757 has_syntax = FALSE;
4758#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759
4760 /* Need to get the line again, a multi-line regexp may
4761 * have made it invalid. */
4762 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4763 ptr = line + v;
4764
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004765# ifdef FEAT_TEXT_PROP
4766 // Text properties overrule syntax highlighting.
4767 if (text_prop_attr == 0)
4768#endif
4769 {
4770 if (!attr_pri)
4771 char_attr = syntax_attr;
4772 else
4773 char_attr = hl_combine_attr(syntax_attr, char_attr);
4774 }
Bram Moolenaarc095b282010-07-20 22:33:34 +02004775# 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;
Bram Moolenaar27c735b2010-07-22 22:16:29 +02004780 else
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02004781 syntax_flags = get_syntax_info(&syntax_seqnr);
Bram Moolenaarc095b282010-07-20 22:33:34 +02004782# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004783 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004784#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00004785
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004786#ifdef FEAT_SPELL
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004787 /* Check spelling (unless at the end of the line).
Bram Moolenaarf3681cc2005-06-08 22:03:13 +00004788 * 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. */
Bram Moolenaar30abd282005-06-22 22:35:10 +00004791 if (has_spell && v >= word_end && v > cur_checked_col)
Bram Moolenaar217ad922005-03-20 22:37:15 +00004792 {
Bram Moolenaar68b76a62005-03-25 21:53:48 +00004793 spell_attr = 0;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004794 if (c != 0 && (
4795# ifdef FEAT_SYN_HL
4796 !has_syntax ||
4797# endif
4798 can_spell))
Bram Moolenaar217ad922005-03-20 22:37:15 +00004799 {
Bram Moolenaar30abd282005-06-22 22:35:10 +00004800 char_u *prev_ptr, *p;
4801 int len;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004802 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004803# ifdef FEAT_MBYTE
Bram Moolenaare7566042005-06-17 22:00:15 +00004804 if (has_mbyte)
4805 {
4806 prev_ptr = ptr - mb_l;
4807 v -= mb_l - 1;
4808 }
4809 else
Bram Moolenaar217ad922005-03-20 22:37:15 +00004810# endif
Bram Moolenaare7566042005-06-17 22:00:15 +00004811 prev_ptr = ptr - 1;
Bram Moolenaar30abd282005-06-22 22:35:10 +00004812
4813 /* Use nextline[] if possible, it has the start of the
4814 * next line concatenated. */
4815 if ((prev_ptr - line) - nextlinecol >= 0)
4816 p = nextline + (prev_ptr - line) - nextlinecol;
4817 else
4818 p = prev_ptr;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004819 cap_col -= (int)(prev_ptr - line);
Bram Moolenaar4770d092006-01-12 23:22:24 +00004820 len = spell_check(wp, p, &spell_hlf, &cap_col,
4821 nochange);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004822 word_end = v + len;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004823
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004824 /* In Insert mode only highlight a word that
4825 * doesn't touch the cursor. */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004826 if (spell_hlf != HLF_COUNT
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004827 && (State & INSERT) != 0
4828 && wp->w_cursor.lnum == lnum
4829 && wp->w_cursor.col >=
Bram Moolenaar217ad922005-03-20 22:37:15 +00004830 (colnr_T)(prev_ptr - line)
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004831 && wp->w_cursor.col < (colnr_T)word_end)
4832 {
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004833 spell_hlf = HLF_COUNT;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004834 spell_redraw_lnum = lnum;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004835 }
Bram Moolenaar30abd282005-06-22 22:35:10 +00004836
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004837 if (spell_hlf == HLF_COUNT && p != prev_ptr
Bram Moolenaar30abd282005-06-22 22:35:10 +00004838 && (p - nextline) + len > nextline_idx)
4839 {
4840 /* Remember that the good word continues at the
4841 * start of the next line. */
4842 checked_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004843 checked_col = (int)((p - nextline) + len - nextline_idx);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004844 }
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004845
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004846 /* Turn index into actual attributes. */
4847 if (spell_hlf != HLF_COUNT)
4848 spell_attr = highlight_attr[spell_hlf];
4849
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004850 if (cap_col > 0)
4851 {
4852 if (p != prev_ptr
4853 && (p - nextline) + cap_col >= nextline_idx)
4854 {
4855 /* Remember that the word in the next line
4856 * must start with a capital. */
4857 capcol_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004858 cap_col = (int)((p - nextline) + cap_col
4859 - nextline_idx);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004860 }
4861 else
4862 /* Compute the actual column. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004863 cap_col += (int)(prev_ptr - line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004864 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004865 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004866 }
4867 if (spell_attr != 0)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004868 {
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004869 if (!attr_pri)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004870 char_attr = hl_combine_attr(char_attr, spell_attr);
4871 else
4872 char_attr = hl_combine_attr(spell_attr, char_attr);
4873 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874#endif
4875#ifdef FEAT_LINEBREAK
4876 /*
Bram Moolenaar217ad922005-03-20 22:37:15 +00004877 * Found last space before word: check for line break.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878 */
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004879 if (wp->w_p_lbr && c0 == c
Bram Moolenaar977d0372017-03-12 21:31:58 +01004880 && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004881 {
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004882# ifdef FEAT_MBYTE
Bram Moolenaar4df70292015-03-21 14:20:16 +01004883 int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0;
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004884# endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02004885 char_u *p = ptr - (
Bram Moolenaar071d4272004-06-13 20:20:40 +00004886# ifdef FEAT_MBYTE
Bram Moolenaar4df70292015-03-21 14:20:16 +01004887 mb_off +
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888# endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02004889 1);
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004890
Bram Moolenaar597a4222014-06-25 14:39:50 +02004891 /* TODO: is passing p for start of the line OK? */
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004892 n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
Bram Moolenaar597a4222014-06-25 14:39:50 +02004893 NULL) - 1;
Bram Moolenaar02631462017-09-22 15:20:32 +02004894 if (c == TAB && n_extra + col > wp->w_width)
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02004895# ifdef FEAT_VARTABS
Bram Moolenaara87b72c2018-06-25 21:24:51 +02004896 n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02004897 wp->w_buffer->b_p_vts_array) - 1;
4898# else
Bram Moolenaara3650912014-11-19 13:21:57 +01004899 n_extra = (int)wp->w_buffer->b_p_ts
4900 - vcol % (int)wp->w_buffer->b_p_ts - 1;
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02004901# endif
Bram Moolenaara3650912014-11-19 13:21:57 +01004902
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004903# ifdef FEAT_MBYTE
Bram Moolenaar4df70292015-03-21 14:20:16 +01004904 c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004905# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906 c_extra = ' ';
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004907# endif
Bram Moolenaar1c465442017-03-12 20:10:05 +01004908 if (VIM_ISWHITE(c))
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02004909 {
4910#ifdef FEAT_CONCEAL
4911 if (c == TAB)
4912 /* See "Tab alignment" below. */
4913 FIX_FOR_BOGUSCOLS;
4914#endif
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004915 if (!wp->w_p_list)
4916 c = ' ';
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02004917 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 }
4919#endif
4920
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004921 /* 'list': change char 160 to lcs_nbsp and space to lcs_space.
4922 */
4923 if (wp->w_p_list
4924 && (((c == 160
4925#ifdef FEAT_MBYTE
4926 || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f))
4927#endif
4928 ) && lcs_nbsp)
4929 || (c == ' ' && lcs_space && ptr - line <= trailcol)))
4930 {
4931 c = (c == ' ') ? lcs_space : lcs_nbsp;
4932 if (area_attr == 0 && search_attr == 0)
4933 {
4934 n_attr = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004935 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004936 saved_attr2 = char_attr; /* save current attr */
4937 }
4938#ifdef FEAT_MBYTE
4939 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02004940 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004941 {
4942 mb_utf8 = TRUE;
4943 u8cc[0] = 0;
4944 c = 0xc0;
4945 }
4946 else
4947 mb_utf8 = FALSE;
4948#endif
4949 }
4950
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
4952 {
4953 c = lcs_trail;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004954 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004955 {
4956 n_attr = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004957 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004958 saved_attr2 = char_attr; /* save current attr */
4959 }
4960#ifdef FEAT_MBYTE
4961 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02004962 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004963 {
4964 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004965 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004966 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967 }
4968 else
4969 mb_utf8 = FALSE;
4970#endif
4971 }
4972 }
4973
4974 /*
4975 * Handling of non-printable characters.
4976 */
Bram Moolenaar88e8f9f2016-01-20 22:48:02 +01004977 if (!vim_isprintc(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004978 {
4979 /*
4980 * when getting a character from the file, we may have to
4981 * turn it into something else on the way to putting it
4982 * into "ScreenLines".
4983 */
4984 if (c == TAB && (!wp->w_p_list || lcs_tab1))
4985 {
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004986 int tab_len = 0;
Bram Moolenaard574ea22015-01-14 19:35:14 +01004987 long vcol_adjusted = vcol; /* removed showbreak length */
4988#ifdef FEAT_LINEBREAK
4989 /* only adjust the tab_len, when at the first column
4990 * after the showbreak value was drawn */
4991 if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap)
4992 vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
4993#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004994 /* tab amount depends on current column */
Bram Moolenaar04958cb2018-06-23 19:23:02 +02004995#ifdef FEAT_VARTABS
4996 tab_len = tabstop_padding(vcol_adjusted,
4997 wp->w_buffer->b_p_ts,
4998 wp->w_buffer->b_p_vts_array) - 1;
4999#else
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005000 tab_len = (int)wp->w_buffer->b_p_ts
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005001 - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
5002#endif
Bram Moolenaard574ea22015-01-14 19:35:14 +01005003
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005004#ifdef FEAT_LINEBREAK
Bram Moolenaarb81c85d2014-07-30 16:44:22 +02005005 if (!wp->w_p_lbr || !wp->w_p_list)
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005006#endif
5007 /* tab amount depends on current column */
5008 n_extra = tab_len;
5009#ifdef FEAT_LINEBREAK
5010 else
5011 {
5012 char_u *p;
5013 int len = n_extra;
5014 int i;
5015 int saved_nextra = n_extra;
5016
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02005017#ifdef FEAT_CONCEAL
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01005018 if (vcol_off > 0)
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02005019 /* there are characters to conceal */
5020 tab_len += vcol_off;
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01005021 /* boguscols before FIX_FOR_BOGUSCOLS macro from above
5022 */
5023 if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
5024 && n_extra > tab_len)
5025 tab_len += n_extra - tab_len;
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02005026#endif
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01005027
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005028 /* if n_extra > 0, it gives the number of chars, to
5029 * use for a tab, else we need to calculate the width
5030 * for a tab */
5031#ifdef FEAT_MBYTE
5032 len = (tab_len * mb_char2len(lcs_tab2));
5033 if (n_extra > 0)
5034 len += n_extra - tab_len;
5035#endif
5036 c = lcs_tab1;
5037 p = alloc((unsigned)(len + 1));
5038 vim_memset(p, ' ', len);
5039 p[len] = NUL;
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01005040 vim_free(p_extra_free);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005041 p_extra_free = p;
5042 for (i = 0; i < tab_len; i++)
5043 {
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02005044 if (*p == NUL)
5045 {
5046 tab_len = i;
5047 break;
5048 }
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005049#ifdef FEAT_MBYTE
5050 mb_char2bytes(lcs_tab2, p);
5051 p += mb_char2len(lcs_tab2);
5052 n_extra += mb_char2len(lcs_tab2)
5053 - (saved_nextra > 0 ? 1 : 0);
5054#else
5055 p[i] = lcs_tab2;
5056#endif
5057 }
5058 p_extra = p_extra_free;
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02005059#ifdef FEAT_CONCEAL
5060 /* n_extra will be increased by FIX_FOX_BOGUSCOLS
5061 * macro below, so need to adjust for that here */
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01005062 if (vcol_off > 0)
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02005063 n_extra -= vcol_off;
5064#endif
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005065 }
5066#endif
Bram Moolenaar0f9d0862012-12-05 15:32:30 +01005067#ifdef FEAT_CONCEAL
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01005068 {
5069 int vc_saved = vcol_off;
5070
5071 /* Tab alignment should be identical regardless of
5072 * 'conceallevel' value. So tab compensates of all
5073 * previous concealed characters, and thus resets
5074 * vcol_off and boguscols accumulated so far in the
5075 * line. Note that the tab can be longer than
5076 * 'tabstop' when there are concealed characters. */
5077 FIX_FOR_BOGUSCOLS;
5078
5079 /* Make sure, the highlighting for the tab char will be
5080 * correctly set further below (effectively reverts the
5081 * FIX_FOR_BOGSUCOLS macro */
5082 if (n_extra == tab_len + vc_saved && wp->w_p_list
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01005083 && lcs_tab1)
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01005084 tab_len += vc_saved;
5085 }
Bram Moolenaar0f9d0862012-12-05 15:32:30 +01005086#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087#ifdef FEAT_MBYTE
5088 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5089#endif
5090 if (wp->w_p_list)
5091 {
5092 c = lcs_tab1;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005093#ifdef FEAT_LINEBREAK
5094 if (wp->w_p_lbr)
5095 c_extra = NUL; /* using p_extra from above */
5096 else
5097#endif
5098 c_extra = lcs_tab2;
5099 n_attr = tab_len + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005100 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 saved_attr2 = char_attr; /* save current attr */
5102#ifdef FEAT_MBYTE
5103 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005104 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005105 {
5106 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005107 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005108 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109 }
5110#endif
5111 }
5112 else
5113 {
5114 c_extra = ' ';
5115 c = ' ';
5116 }
5117 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005118 else if (c == NUL
Bram Moolenaard59c0992015-05-04 16:52:01 +02005119 && (wp->w_p_list
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005120 || ((fromcol >= 0 || fromcol_prev >= 0)
5121 && tocol > vcol
5122 && VIsual_mode != Ctrl_V
5123 && (
5124# ifdef FEAT_RIGHTLEFT
5125 wp->w_p_rl ? (col >= 0) :
5126# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005127 (col < wp->w_width))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005128 && !(noinvcur
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005129 && lnum == wp->w_cursor.lnum
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005130 && (colnr_T)vcol == wp->w_virtcol)))
Bram Moolenaar0481fee2015-05-14 05:56:09 +02005131 && lcs_eol_one > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005133 /* Display a '$' after the line or highlight an extra
5134 * character if the line break is included. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005135#if defined(FEAT_DIFF) || defined(LINE_ATTR)
5136 /* For a diff line the highlighting continues after the
5137 * "$". */
5138 if (
5139# ifdef FEAT_DIFF
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005140 diff_hlf == (hlf_T)0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005141# ifdef LINE_ATTR
5142 &&
5143# endif
5144# endif
5145# ifdef LINE_ATTR
5146 line_attr == 0
5147# endif
5148 )
5149#endif
5150 {
5151#ifdef FEAT_VIRTUALEDIT
5152 /* In virtualedit, visual selections may extend
5153 * beyond end of line. */
5154 if (area_highlighting && virtual_active()
5155 && tocol != MAXCOL && vcol < tocol)
5156 n_extra = 0;
5157 else
5158#endif
5159 {
5160 p_extra = at_end_str;
5161 n_extra = 1;
5162 c_extra = NUL;
5163 }
5164 }
Bram Moolenaard59c0992015-05-04 16:52:01 +02005165 if (wp->w_p_list && lcs_eol > 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005166 c = lcs_eol;
5167 else
5168 c = ' ';
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169 lcs_eol_one = -1;
5170 --ptr; /* put it back at the NUL */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005171 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01005173 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174 n_attr = 1;
5175 }
5176#ifdef FEAT_MBYTE
5177 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005178 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 {
5180 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005181 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005182 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005183 }
5184 else
5185 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5186#endif
5187 }
5188 else if (c != NUL)
5189 {
5190 p_extra = transchar(c);
Bram Moolenaar5524aeb2014-07-16 17:29:51 +02005191 if (n_extra == 0)
5192 n_extra = byte2cells(c) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005193#ifdef FEAT_RIGHTLEFT
5194 if ((dy_flags & DY_UHEX) && wp->w_p_rl)
5195 rl_mirror(p_extra); /* reverse "<12>" */
5196#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005197 c_extra = NUL;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005198#ifdef FEAT_LINEBREAK
5199 if (wp->w_p_lbr)
5200 {
5201 char_u *p;
5202
5203 c = *p_extra;
5204 p = alloc((unsigned)n_extra + 1);
5205 vim_memset(p, ' ', n_extra);
5206 STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
5207 p[n_extra] = NUL;
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01005208 vim_free(p_extra_free);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005209 p_extra_free = p_extra = p;
5210 }
5211 else
5212#endif
5213 {
5214 n_extra = byte2cells(c) - 1;
5215 c = *p_extra++;
5216 }
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005217 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005218 {
5219 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005220 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 saved_attr2 = char_attr; /* save current attr */
5222 }
5223#ifdef FEAT_MBYTE
5224 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5225#endif
5226 }
5227#ifdef FEAT_VIRTUALEDIT
5228 else if (VIsual_active
5229 && (VIsual_mode == Ctrl_V
5230 || VIsual_mode == 'v')
5231 && virtual_active()
5232 && tocol != MAXCOL
5233 && vcol < tocol
5234 && (
5235# ifdef FEAT_RIGHTLEFT
5236 wp->w_p_rl ? (col >= 0) :
5237# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005238 (col < wp->w_width)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239 {
5240 c = ' ';
5241 --ptr; /* put it back at the NUL */
5242 }
5243#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005244#if defined(LINE_ATTR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005245 else if ((
5246# ifdef FEAT_DIFF
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005247 diff_hlf != (hlf_T)0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00005248# endif
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005249# ifdef FEAT_TERMINAL
5250 term_attr != 0 ||
5251# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252 line_attr != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253 ) && (
5254# ifdef FEAT_RIGHTLEFT
5255 wp->w_p_rl ? (col >= 0) :
5256# endif
Bram Moolenaar2a988a12010-08-13 15:24:39 +02005257 (col
5258# ifdef FEAT_CONCEAL
5259 - boguscols
5260# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005261 < wp->w_width)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005262 {
5263 /* Highlight until the right side of the window */
5264 c = ' ';
5265 --ptr; /* put it back at the NUL */
Bram Moolenaar91170f82006-05-05 21:15:17 +00005266
5267 /* Remember we do the char for line highlighting. */
5268 ++did_line_attr;
5269
5270 /* don't do search HL for the rest of the line */
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02005271 if (line_attr != 0 && char_attr == search_attr
5272 && (did_line_attr > 1
5273 || (wp->w_p_list && lcs_eol > 0)))
Bram Moolenaar91170f82006-05-05 21:15:17 +00005274 char_attr = line_attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005275# ifdef FEAT_DIFF
5276 if (diff_hlf == HLF_TXD)
5277 {
5278 diff_hlf = HLF_CHD;
5279 if (attr == 0 || char_attr != attr)
Bram Moolenaare0f14822014-08-06 13:20:56 +02005280 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01005281 char_attr = HL_ATTR(diff_hlf);
Bram Moolenaare0f14822014-08-06 13:20:56 +02005282 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
5283 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01005284 HL_ATTR(HLF_CUL));
Bram Moolenaare0f14822014-08-06 13:20:56 +02005285 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005286 }
5287# endif
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005288# ifdef FEAT_TERMINAL
5289 if (term_attr != 0)
5290 {
5291 char_attr = term_attr;
5292 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
5293 char_attr = hl_combine_attr(char_attr,
5294 HL_ATTR(HLF_CUL));
5295 }
5296# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005297 }
5298#endif
5299 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005300
5301#ifdef FEAT_CONCEAL
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005302 if ( wp->w_p_cole > 0
5303 && (wp != curwin || lnum != wp->w_cursor.lnum ||
Bram Moolenaar6561d522015-07-21 15:48:27 +02005304 conceal_cursor_line(wp) )
Bram Moolenaar4d585022016-04-14 19:50:22 +02005305 && ( (syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
Bram Moolenaare6dc5732010-07-24 23:52:26 +02005306 && !(lnum_in_visual_area
5307 && vim_strchr(wp->w_p_cocu, 'v') == NULL))
Bram Moolenaar860cae12010-06-05 23:22:07 +02005308 {
5309 char_attr = conceal_attr;
Bram Moolenaar4d585022016-04-14 19:50:22 +02005310 if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
Bram Moolenaar6561d522015-07-21 15:48:27 +02005311 && (syn_get_sub_char() != NUL || match_conc
5312 || wp->w_p_cole == 1)
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005313 && wp->w_p_cole != 3)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005314 {
Bram Moolenaar27c735b2010-07-22 22:16:29 +02005315 /* First time at this concealed item: display one
5316 * character. */
Bram Moolenaar6561d522015-07-21 15:48:27 +02005317 if (match_conc)
5318 c = match_conc;
5319 else if (syn_get_sub_char() != NUL)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005320 c = syn_get_sub_char();
5321 else if (lcs_conceal != NUL)
5322 c = lcs_conceal;
5323 else
5324 c = ' ';
5325
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02005326 prev_syntax_id = syntax_seqnr;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005327
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005328 if (n_extra > 0)
5329 vcol_off += n_extra;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005330 vcol += n_extra;
5331 if (wp->w_p_wrap && n_extra > 0)
5332 {
5333# ifdef FEAT_RIGHTLEFT
5334 if (wp->w_p_rl)
5335 {
5336 col -= n_extra;
5337 boguscols -= n_extra;
5338 }
5339 else
5340# endif
5341 {
5342 boguscols += n_extra;
5343 col += n_extra;
5344 }
5345 }
5346 n_extra = 0;
5347 n_attr = 0;
5348 }
5349 else if (n_skip == 0)
5350 {
5351 is_concealing = TRUE;
5352 n_skip = 1;
5353 }
5354# ifdef FEAT_MBYTE
5355 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005356 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005357 {
5358 mb_utf8 = TRUE;
5359 u8cc[0] = 0;
5360 c = 0xc0;
5361 }
5362 else
5363 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5364# endif
5365 }
5366 else
5367 {
Bram Moolenaar27c735b2010-07-22 22:16:29 +02005368 prev_syntax_id = 0;
Bram Moolenaarc400cb92010-07-19 19:52:13 +02005369 is_concealing = FALSE;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005370 }
5371#endif /* FEAT_CONCEAL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372 }
5373
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005374#ifdef FEAT_CONCEAL
5375 /* In the cursor line and we may be concealing characters: correct
5376 * the cursor column when we reach its position. */
Bram Moolenaarf691b842010-07-24 13:31:09 +02005377 if (!did_wcol && draw_state == WL_LINE
5378 && wp == curwin && lnum == wp->w_cursor.lnum
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005379 && conceal_cursor_line(wp)
5380 && (int)wp->w_virtcol <= vcol + n_skip)
5381 {
Bram Moolenaare39b3d92016-01-15 22:52:22 +01005382# ifdef FEAT_RIGHTLEFT
5383 if (wp->w_p_rl)
Bram Moolenaar02631462017-09-22 15:20:32 +02005384 wp->w_wcol = wp->w_width - col + boguscols - 1;
Bram Moolenaare39b3d92016-01-15 22:52:22 +01005385 else
5386# endif
5387 wp->w_wcol = col - boguscols;
Bram Moolenaar72ada0f2010-07-24 17:39:52 +02005388 wp->w_wrow = row;
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005389 did_wcol = TRUE;
5390 }
5391#endif
5392
Bram Moolenaar071d4272004-06-13 20:20:40 +00005393 /* Don't override visual selection highlighting. */
5394 if (n_attr > 0
5395 && draw_state == WL_LINE
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005396 && !attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397 char_attr = extra_attr;
5398
Bram Moolenaar81695252004-12-29 20:58:21 +00005399#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005400 /* XIM don't send preedit_start and preedit_end, but they send
5401 * preedit_changed and commit. Thus Vim can't set "im_is_active", use
5402 * im_is_preediting() here. */
Bram Moolenaar5c6dbcb2017-08-30 22:00:20 +02005403 if (p_imst == IM_ON_THE_SPOT
5404 && xic != NULL
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005405 && lnum == wp->w_cursor.lnum
Bram Moolenaar071d4272004-06-13 20:20:40 +00005406 && (State & INSERT)
5407 && !p_imdisable
5408 && im_is_preediting()
5409 && draw_state == WL_LINE)
5410 {
5411 colnr_T tcol;
5412
5413 if (preedit_end_col == MAXCOL)
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005414 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005415 else
5416 tcol = preedit_end_col;
5417 if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
5418 {
5419 if (feedback_old_attr < 0)
5420 {
5421 feedback_col = 0;
5422 feedback_old_attr = char_attr;
5423 }
5424 char_attr = im_get_feedback_attr(feedback_col);
5425 if (char_attr < 0)
5426 char_attr = feedback_old_attr;
5427 feedback_col++;
5428 }
5429 else if (feedback_old_attr >= 0)
5430 {
5431 char_attr = feedback_old_attr;
5432 feedback_old_attr = -1;
5433 feedback_col = 0;
5434 }
5435 }
5436#endif
5437 /*
5438 * Handle the case where we are in column 0 but not on the first
5439 * character of the line and the user wants us to show us a
5440 * special character (via 'listchars' option "precedes:<char>".
5441 */
5442 if (lcs_prec_todo != NUL
Bram Moolenaar7425b932014-10-10 15:28:46 +02005443 && wp->w_p_list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005444 && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
5445#ifdef FEAT_DIFF
5446 && filler_todo <= 0
5447#endif
5448 && draw_state > WL_NR
5449 && c != NUL)
5450 {
5451 c = lcs_prec;
5452 lcs_prec_todo = NUL;
5453#ifdef FEAT_MBYTE
Bram Moolenaar5641f382012-06-13 18:06:36 +02005454 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5455 {
5456 /* Double-width character being overwritten by the "precedes"
5457 * character, need to fill up half the character. */
5458 c_extra = MB_FILLER_CHAR;
5459 n_extra = 1;
5460 n_attr = 2;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005461 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar5641f382012-06-13 18:06:36 +02005462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005463 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005464 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 {
5466 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005467 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005468 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005469 }
5470 else
5471 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5472#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005473 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005474 {
5475 saved_attr3 = char_attr; /* save current attr */
Bram Moolenaar8820b482017-03-16 17:23:31 +01005476 char_attr = HL_ATTR(HLF_AT); /* later copied to char_attr */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005477 n_attr3 = 1;
5478 }
5479 }
5480
5481 /*
Bram Moolenaar91170f82006-05-05 21:15:17 +00005482 * At end of the text line or just after the last character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483 */
Bram Moolenaar91170f82006-05-05 21:15:17 +00005484 if (c == NUL
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005485#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00005486 || did_line_attr == 1
5487#endif
5488 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489 {
Bram Moolenaar91170f82006-05-05 21:15:17 +00005490#ifdef FEAT_SEARCH_EXTRA
5491 long prevcol = (long)(ptr - line) - (c == NUL);
Bram Moolenaara443af82007-11-08 13:51:42 +00005492
5493 /* we're not really at that column when skipping some text */
Bram Moolenaar33741a02007-11-08 20:24:19 +00005494 if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
Bram Moolenaara443af82007-11-08 13:51:42 +00005495 ++prevcol;
Bram Moolenaar91170f82006-05-05 21:15:17 +00005496#endif
5497
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005498 /* Invert at least one char, used for Visual and empty line or
Bram Moolenaar071d4272004-06-13 20:20:40 +00005499 * highlight match at end of line. If it's beyond the last
5500 * char on the screen, just overwrite that one (tricky!) Not
5501 * needed when a '$' was displayed for 'list'. */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005502#ifdef FEAT_SEARCH_EXTRA
5503 prevcol_hl_flag = FALSE;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02005504 if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005505 prevcol_hl_flag = TRUE;
5506 else
5507 {
5508 cur = wp->w_match_head;
5509 while (cur != NULL)
5510 {
Bram Moolenaar4f416e42016-08-16 16:08:18 +02005511 if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005512 {
5513 prevcol_hl_flag = TRUE;
5514 break;
5515 }
5516 cur = cur->next;
5517 }
5518 }
5519#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520 if (lcs_eol == lcs_eol_one
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005521 && ((area_attr != 0 && vcol == fromcol
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005522 && (VIsual_mode != Ctrl_V
5523 || lnum == VIsual.lnum
5524 || lnum == curwin->w_cursor.lnum)
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005525 && c == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005526#ifdef FEAT_SEARCH_EXTRA
5527 /* highlight 'hlsearch' match at end of line */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005528 || (prevcol_hl_flag == TRUE
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02005529# ifdef FEAT_SYN_HL
5530 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
5531 && !(wp == curwin && VIsual_active))
5532# endif
5533# ifdef FEAT_DIFF
5534 && diff_hlf == (hlf_T)0
5535# endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005536# if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00005537 && did_line_attr <= 1
5538# endif
5539 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00005540#endif
5541 ))
5542 {
5543 int n = 0;
5544
5545#ifdef FEAT_RIGHTLEFT
5546 if (wp->w_p_rl)
5547 {
5548 if (col < 0)
5549 n = 1;
5550 }
5551 else
5552#endif
5553 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005554 if (col >= wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005555 n = -1;
5556 }
5557 if (n != 0)
5558 {
5559 /* At the window boundary, highlight the last character
5560 * instead (better than nothing). */
5561 off += n;
5562 col += n;
5563 }
5564 else
5565 {
5566 /* Add a blank character to highlight. */
5567 ScreenLines[off] = ' ';
5568#ifdef FEAT_MBYTE
5569 if (enc_utf8)
5570 ScreenLinesUC[off] = 0;
5571#endif
5572 }
5573#ifdef FEAT_SEARCH_EXTRA
5574 if (area_attr == 0)
5575 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005576 /* Use attributes from match with highest priority among
5577 * 'search_hl' and the match list. */
5578 char_attr = search_hl.attr;
5579 cur = wp->w_match_head;
5580 shl_flag = FALSE;
5581 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005582 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005583 if (shl_flag == FALSE
5584 && ((cur != NULL
5585 && cur->priority > SEARCH_HL_PRIORITY)
5586 || cur == NULL))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005587 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005588 shl = &search_hl;
5589 shl_flag = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005590 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005591 else
5592 shl = &cur->hl;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02005593 if ((ptr - line) - 1 == (long)shl->startcol
5594 && (shl == &search_hl || !shl->is_addpos))
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005595 char_attr = shl->attr;
5596 if (shl != &search_hl && cur != NULL)
5597 cur = cur->next;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005598 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599 }
5600#endif
5601 ScreenAttrs[off] = char_attr;
5602#ifdef FEAT_RIGHTLEFT
5603 if (wp->w_p_rl)
Bram Moolenaara443af82007-11-08 13:51:42 +00005604 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005605 --col;
Bram Moolenaara443af82007-11-08 13:51:42 +00005606 --off;
5607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608 else
5609#endif
Bram Moolenaara443af82007-11-08 13:51:42 +00005610 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005611 ++col;
Bram Moolenaara443af82007-11-08 13:51:42 +00005612 ++off;
5613 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005614 ++vcol;
Bram Moolenaara443af82007-11-08 13:51:42 +00005615#ifdef FEAT_SYN_HL
5616 eol_hl_off = 1;
5617#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005618 }
Bram Moolenaar91170f82006-05-05 21:15:17 +00005619 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005620
Bram Moolenaar91170f82006-05-05 21:15:17 +00005621 /*
5622 * At end of the text line.
5623 */
5624 if (c == NUL)
5625 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005626#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02005627 /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00005628 if (wp->w_p_wrap)
5629 v = wp->w_skipcol;
5630 else
5631 v = wp->w_leftcol;
Bram Moolenaar1a384422010-07-14 19:53:30 +02005632
Bram Moolenaar8dff8182006-04-06 20:18:50 +00005633 /* check if line ends before left margin */
5634 if (vcol < v + col - win_col_off(wp))
Bram Moolenaar8dff8182006-04-06 20:18:50 +00005635 vcol = v + col - win_col_off(wp);
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005636#ifdef FEAT_CONCEAL
5637 /* Get rid of the boguscols now, we want to draw until the right
5638 * edge for 'cursorcolumn'. */
5639 col -= boguscols;
5640 boguscols = 0;
5641#endif
Bram Moolenaar1a384422010-07-14 19:53:30 +02005642
5643 if (draw_color_col)
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005644 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005645
5646 if (((wp->w_p_cuc
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005647 && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
5648 && (int)wp->w_virtcol <
Bram Moolenaar02631462017-09-22 15:20:32 +02005649 wp->w_width * (row - startrow + 1) + v
Bram Moolenaar1a384422010-07-14 19:53:30 +02005650 && lnum != wp->w_cursor.lnum)
5651 || draw_color_col)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005652# ifdef FEAT_RIGHTLEFT
5653 && !wp->w_p_rl
5654# endif
5655 )
5656 {
Bram Moolenaar1a384422010-07-14 19:53:30 +02005657 int rightmost_vcol = 0;
5658 int i;
5659
5660 if (wp->w_p_cuc)
5661 rightmost_vcol = wp->w_virtcol;
5662 if (draw_color_col)
5663 /* determine rightmost colorcolumn to possibly draw */
5664 for (i = 0; color_cols[i] >= 0; ++i)
5665 if (rightmost_vcol < color_cols[i])
5666 rightmost_vcol = color_cols[i];
5667
Bram Moolenaar02631462017-09-22 15:20:32 +02005668 while (col < wp->w_width)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005669 {
5670 ScreenLines[off] = ' ';
5671#ifdef FEAT_MBYTE
5672 if (enc_utf8)
5673 ScreenLinesUC[off] = 0;
5674#endif
5675 ++col;
Bram Moolenaar973bd472010-07-20 11:29:07 +02005676 if (draw_color_col)
5677 draw_color_col = advance_color_col(VCOL_HLC,
5678 &color_cols);
5679
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005680 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol)
Bram Moolenaar8820b482017-03-16 17:23:31 +01005681 ScreenAttrs[off++] = HL_ATTR(HLF_CUC);
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005682 else if (draw_color_col && VCOL_HLC == *color_cols)
Bram Moolenaar8820b482017-03-16 17:23:31 +01005683 ScreenAttrs[off++] = HL_ATTR(HLF_MC);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005684 else
5685 ScreenAttrs[off++] = 0;
5686
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005687 if (VCOL_HLC >= rightmost_vcol)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005688 break;
Bram Moolenaar1a384422010-07-14 19:53:30 +02005689
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005690 ++vcol;
5691 }
5692 }
5693#endif
5694
Bram Moolenaar53f81742017-09-22 14:35:51 +02005695 screen_line(screen_row, wp->w_wincol, col,
Bram Moolenaar02631462017-09-22 15:20:32 +02005696 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005697 row++;
5698
5699 /*
5700 * Update w_cline_height and w_cline_folded if the cursor line was
5701 * updated (saves a call to plines() later).
5702 */
5703 if (wp == curwin && lnum == curwin->w_cursor.lnum)
5704 {
5705 curwin->w_cline_row = startrow;
5706 curwin->w_cline_height = row - startrow;
5707#ifdef FEAT_FOLDING
5708 curwin->w_cline_folded = FALSE;
5709#endif
5710 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
5711 }
5712
5713 break;
5714 }
5715
5716 /* line continues beyond line end */
5717 if (lcs_ext
5718 && !wp->w_p_wrap
5719#ifdef FEAT_DIFF
5720 && filler_todo <= 0
5721#endif
5722 && (
5723#ifdef FEAT_RIGHTLEFT
5724 wp->w_p_rl ? col == 0 :
5725#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005726 col == wp->w_width - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005727 && (*ptr != NUL
Bram Moolenaar5bbc21d2008-03-09 13:30:56 +00005728 || (wp->w_p_list && lcs_eol_one > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005729 || (n_extra && (c_extra != NUL || *p_extra != NUL))))
5730 {
5731 c = lcs_ext;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005732 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005733#ifdef FEAT_MBYTE
5734 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005735 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005736 {
5737 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005738 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005739 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005740 }
5741 else
5742 mb_utf8 = FALSE;
5743#endif
5744 }
5745
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005746#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02005747 /* advance to the next 'colorcolumn' */
5748 if (draw_color_col)
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005749 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005750
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005751 /* Highlight the cursor column if 'cursorcolumn' is set. But don't
Bram Moolenaar1a384422010-07-14 19:53:30 +02005752 * highlight the cursor position itself.
5753 * Also highlight the 'colorcolumn' if it is different than
5754 * 'cursorcolumn' */
5755 vcol_save_attr = -1;
Bram Moolenaar774e5a92017-06-25 18:03:37 +02005756 if (draw_state == WL_LINE && !lnum_in_visual_area
5757 && search_attr == 0 && area_attr == 0)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005758 {
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005759 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
Bram Moolenaar1a384422010-07-14 19:53:30 +02005760 && lnum != wp->w_cursor.lnum)
5761 {
5762 vcol_save_attr = char_attr;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005763 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC));
Bram Moolenaar1a384422010-07-14 19:53:30 +02005764 }
Bram Moolenaard160c342010-07-18 23:30:34 +02005765 else if (draw_color_col && VCOL_HLC == *color_cols)
Bram Moolenaar1a384422010-07-14 19:53:30 +02005766 {
5767 vcol_save_attr = char_attr;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005768 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC));
Bram Moolenaar1a384422010-07-14 19:53:30 +02005769 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005770 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005771#endif
5772
Bram Moolenaar071d4272004-06-13 20:20:40 +00005773 /*
5774 * Store character to be displayed.
5775 * Skip characters that are left of the screen for 'nowrap'.
5776 */
5777 vcol_prev = vcol;
5778 if (draw_state < WL_LINE || n_skip <= 0)
5779 {
5780 /*
5781 * Store the character.
5782 */
5783#if defined(FEAT_RIGHTLEFT) && defined(FEAT_MBYTE)
5784 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
5785 {
5786 /* A double-wide character is: put first halve in left cell. */
5787 --off;
5788 --col;
5789 }
5790#endif
5791 ScreenLines[off] = c;
5792#ifdef FEAT_MBYTE
5793 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaar990bb662010-02-03 15:48:04 +01005794 {
5795 if ((mb_c & 0xff00) == 0x8e00)
5796 ScreenLines[off] = 0x8e;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005797 ScreenLines2[off] = mb_c & 0xff;
Bram Moolenaar990bb662010-02-03 15:48:04 +01005798 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799 else if (enc_utf8)
5800 {
5801 if (mb_utf8)
5802 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005803 int i;
5804
Bram Moolenaar071d4272004-06-13 20:20:40 +00005805 ScreenLinesUC[off] = mb_c;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005806 if ((c & 0xff) == 0)
5807 ScreenLines[off] = 0x80; /* avoid storing zero */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005808 for (i = 0; i < Screen_mco; ++i)
5809 {
5810 ScreenLinesC[i][off] = u8cc[i];
5811 if (u8cc[i] == 0)
5812 break;
5813 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005814 }
5815 else
5816 ScreenLinesUC[off] = 0;
5817 }
5818 if (multi_attr)
5819 {
5820 ScreenAttrs[off] = multi_attr;
5821 multi_attr = 0;
5822 }
5823 else
5824#endif
5825 ScreenAttrs[off] = char_attr;
5826
5827#ifdef FEAT_MBYTE
5828 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5829 {
5830 /* Need to fill two screen columns. */
5831 ++off;
5832 ++col;
5833 if (enc_utf8)
5834 /* UTF-8: Put a 0 in the second screen char. */
5835 ScreenLines[off] = 0;
5836 else
5837 /* DBCS: Put second byte in the second screen char. */
5838 ScreenLines[off] = mb_c & 0xff;
Bram Moolenaar32a214e2015-12-03 14:29:02 +01005839 if (draw_state > WL_NR
5840#ifdef FEAT_DIFF
5841 && filler_todo <= 0
5842#endif
5843 )
5844 ++vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845 /* When "tocol" is halfway a character, set it to the end of
5846 * the character, otherwise highlighting won't stop. */
5847 if (tocol == vcol)
5848 ++tocol;
5849#ifdef FEAT_RIGHTLEFT
5850 if (wp->w_p_rl)
5851 {
5852 /* now it's time to backup one cell */
5853 --off;
5854 --col;
5855 }
5856#endif
5857 }
5858#endif
5859#ifdef FEAT_RIGHTLEFT
5860 if (wp->w_p_rl)
5861 {
5862 --off;
5863 --col;
5864 }
5865 else
5866#endif
5867 {
5868 ++off;
5869 ++col;
5870 }
5871 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005872#ifdef FEAT_CONCEAL
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005873 else if (wp->w_p_cole > 0 && is_concealing)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005874 {
5875 --n_skip;
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005876 ++vcol_off;
5877 if (n_extra > 0)
5878 vcol_off += n_extra;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005879 if (wp->w_p_wrap)
5880 {
5881 /*
5882 * Special voodoo required if 'wrap' is on.
5883 *
5884 * Advance the column indicator to force the line
5885 * drawing to wrap early. This will make the line
5886 * take up the same screen space when parts are concealed,
5887 * so that cursor line computations aren't messed up.
5888 *
5889 * To avoid the fictitious advance of 'col' causing
5890 * trailing junk to be written out of the screen line
5891 * we are building, 'boguscols' keeps track of the number
5892 * of bad columns we have advanced.
5893 */
5894 if (n_extra > 0)
5895 {
5896 vcol += n_extra;
5897# ifdef FEAT_RIGHTLEFT
5898 if (wp->w_p_rl)
5899 {
5900 col -= n_extra;
5901 boguscols -= n_extra;
5902 }
5903 else
5904# endif
5905 {
5906 col += n_extra;
5907 boguscols += n_extra;
5908 }
5909 n_extra = 0;
5910 n_attr = 0;
5911 }
5912
5913
5914# ifdef FEAT_MBYTE
5915 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5916 {
5917 /* Need to fill two screen columns. */
5918# ifdef FEAT_RIGHTLEFT
5919 if (wp->w_p_rl)
5920 {
5921 --boguscols;
5922 --col;
5923 }
5924 else
5925# endif
5926 {
5927 ++boguscols;
5928 ++col;
5929 }
5930 }
5931# endif
5932
5933# ifdef FEAT_RIGHTLEFT
5934 if (wp->w_p_rl)
5935 {
5936 --boguscols;
5937 --col;
5938 }
5939 else
5940# endif
5941 {
5942 ++boguscols;
5943 ++col;
5944 }
5945 }
5946 else
5947 {
5948 if (n_extra > 0)
5949 {
5950 vcol += n_extra;
5951 n_extra = 0;
5952 n_attr = 0;
5953 }
5954 }
5955
5956 }
5957#endif /* FEAT_CONCEAL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005958 else
5959 --n_skip;
5960
Bram Moolenaar64486672010-05-16 15:46:46 +02005961 /* Only advance the "vcol" when after the 'number' or 'relativenumber'
5962 * column. */
Bram Moolenaar1b636fa2009-03-18 15:28:08 +00005963 if (draw_state > WL_NR
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964#ifdef FEAT_DIFF
5965 && filler_todo <= 0
5966#endif
5967 )
5968 ++vcol;
5969
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005970#ifdef FEAT_SYN_HL
5971 if (vcol_save_attr >= 0)
5972 char_attr = vcol_save_attr;
5973#endif
5974
Bram Moolenaar071d4272004-06-13 20:20:40 +00005975 /* restore attributes after "predeces" in 'listchars' */
5976 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
5977 char_attr = saved_attr3;
5978
5979 /* restore attributes after last 'listchars' or 'number' char */
5980 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
5981 char_attr = saved_attr2;
5982
5983 /*
5984 * At end of screen line and there is more to come: Display the line
Bram Moolenaar367329b2007-08-30 11:53:22 +00005985 * so far. If there is no more to display it is caught above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005986 */
5987 if ((
5988#ifdef FEAT_RIGHTLEFT
5989 wp->w_p_rl ? (col < 0) :
5990#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005991 (col >= wp->w_width))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992 && (*ptr != NUL
5993#ifdef FEAT_DIFF
5994 || filler_todo > 0
5995#endif
Bram Moolenaare9d4b582011-03-22 13:29:24 +01005996 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005997 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
5998 )
5999 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02006000#ifdef FEAT_CONCEAL
Bram Moolenaar53f81742017-09-22 14:35:51 +02006001 screen_line(screen_row, wp->w_wincol, col - boguscols,
Bram Moolenaar02631462017-09-22 15:20:32 +02006002 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar860cae12010-06-05 23:22:07 +02006003 boguscols = 0;
6004#else
Bram Moolenaar53f81742017-09-22 14:35:51 +02006005 screen_line(screen_row, wp->w_wincol, col,
Bram Moolenaar02631462017-09-22 15:20:32 +02006006 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar860cae12010-06-05 23:22:07 +02006007#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006008 ++row;
6009 ++screen_row;
6010
6011 /* When not wrapping and finished diff lines, or when displayed
6012 * '$' and highlighting until last column, break here. */
6013 if ((!wp->w_p_wrap
6014#ifdef FEAT_DIFF
6015 && filler_todo <= 0
6016#endif
6017 ) || lcs_eol_one == -1)
6018 break;
6019
6020 /* When the window is too narrow draw all "@" lines. */
6021 if (draw_state != WL_LINE
6022#ifdef FEAT_DIFF
6023 && filler_todo <= 0
6024#endif
6025 )
6026 {
6027 win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006028 draw_vsep_win(wp, row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006029 row = endrow;
6030 }
6031
6032 /* When line got too long for screen break here. */
6033 if (row == endrow)
6034 {
6035 ++row;
6036 break;
6037 }
6038
6039 if (screen_cur_row == screen_row - 1
6040#ifdef FEAT_DIFF
6041 && filler_todo <= 0
6042#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02006043 && wp->w_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044 {
6045 /* Remember that the line wraps, used for modeless copy. */
6046 LineWraps[screen_row - 1] = TRUE;
6047
6048 /*
6049 * Special trick to make copy/paste of wrapped lines work with
6050 * xterm/screen: write an extra character beyond the end of
6051 * the line. This will work with all terminal types
6052 * (regardless of the xn,am settings).
6053 * Only do this on a fast tty.
6054 * Only do this if the cursor is on the current line
6055 * (something has been written in it).
6056 * Don't do this for the GUI.
6057 * Don't do this for double-width characters.
6058 * Don't do this for a window not at the right screen border.
6059 */
6060 if (p_tf
6061#ifdef FEAT_GUI
6062 && !gui.in_use
6063#endif
6064#ifdef FEAT_MBYTE
6065 && !(has_mbyte
Bram Moolenaar367329b2007-08-30 11:53:22 +00006066 && ((*mb_off2cells)(LineOffset[screen_row],
6067 LineOffset[screen_row] + screen_Columns)
6068 == 2
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069 || (*mb_off2cells)(LineOffset[screen_row - 1]
Bram Moolenaar367329b2007-08-30 11:53:22 +00006070 + (int)Columns - 2,
6071 LineOffset[screen_row] + screen_Columns)
6072 == 2))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006073#endif
6074 )
6075 {
6076 /* First make sure we are at the end of the screen line,
6077 * then output the same character again to let the
6078 * terminal know about the wrap. If the terminal doesn't
6079 * auto-wrap, we overwrite the character. */
Bram Moolenaar02631462017-09-22 15:20:32 +02006080 if (screen_cur_col != wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006081 screen_char(LineOffset[screen_row - 1]
6082 + (unsigned)Columns - 1,
6083 screen_row - 1, (int)(Columns - 1));
6084
6085#ifdef FEAT_MBYTE
6086 /* When there is a multi-byte character, just output a
6087 * space to keep it simple. */
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00006088 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
6089 screen_row - 1] + (Columns - 1)]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006090 out_char(' ');
6091 else
6092#endif
6093 out_char(ScreenLines[LineOffset[screen_row - 1]
6094 + (Columns - 1)]);
6095 /* force a redraw of the first char on the next line */
6096 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
6097 screen_start(); /* don't know where cursor is now */
6098 }
6099 }
6100
6101 col = 0;
6102 off = (unsigned)(current_ScreenLine - ScreenLines);
6103#ifdef FEAT_RIGHTLEFT
6104 if (wp->w_p_rl)
6105 {
Bram Moolenaar02631462017-09-22 15:20:32 +02006106 col = wp->w_width - 1; /* col is not used if breaking! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006107 off += col;
6108 }
6109#endif
6110
6111 /* reset the drawing state for the start of a wrapped line */
6112 draw_state = WL_START;
6113 saved_n_extra = n_extra;
6114 saved_p_extra = p_extra;
6115 saved_c_extra = c_extra;
6116 saved_char_attr = char_attr;
6117 n_extra = 0;
6118 lcs_prec_todo = lcs_prec;
6119#ifdef FEAT_LINEBREAK
6120# ifdef FEAT_DIFF
6121 if (filler_todo <= 0)
6122# endif
6123 need_showbreak = TRUE;
6124#endif
6125#ifdef FEAT_DIFF
6126 --filler_todo;
6127 /* When the filler lines are actually below the last line of the
6128 * file, don't draw the line itself, break here. */
6129 if (filler_todo == 0 && wp->w_botfill)
6130 break;
6131#endif
6132 }
6133
6134 } /* for every character in the line */
6135
Bram Moolenaar600dddc2006-03-12 22:05:10 +00006136#ifdef FEAT_SPELL
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00006137 /* After an empty line check first word for capital. */
6138 if (*skipwhite(line) == NUL)
6139 {
6140 capcol_lnum = lnum + 1;
6141 cap_col = 0;
6142 }
6143#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006144#ifdef FEAT_TEXT_PROP
6145 vim_free(text_props);
6146 vim_free(text_prop_idxs);
6147#endif
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00006148
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01006149 vim_free(p_extra_free);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006150 return row;
6151}
6152
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006153#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006154/*
6155 * Return if the composing characters at "off_from" and "off_to" differ.
Bram Moolenaar70c49c12010-03-23 15:36:35 +01006156 * Only to be used when ScreenLinesUC[off_from] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006157 */
6158 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006159comp_char_differs(int off_from, int off_to)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006160{
6161 int i;
6162
6163 for (i = 0; i < Screen_mco; ++i)
6164 {
6165 if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
6166 return TRUE;
6167 if (ScreenLinesC[i][off_from] == 0)
6168 break;
6169 }
6170 return FALSE;
6171}
6172#endif
6173
Bram Moolenaar071d4272004-06-13 20:20:40 +00006174/*
6175 * Check whether the given character needs redrawing:
6176 * - the (first byte of the) character is different
6177 * - the attributes are different
6178 * - the character is multi-byte and the next byte is different
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00006179 * - the character is two cells wide and the second cell differs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006180 */
6181 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006182char_needs_redraw(int off_from, int off_to, int cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006183{
6184 if (cols > 0
6185 && ((ScreenLines[off_from] != ScreenLines[off_to]
6186 || ScreenAttrs[off_from] != ScreenAttrs[off_to])
6187
6188#ifdef FEAT_MBYTE
6189 || (enc_dbcs != 0
6190 && MB_BYTE2LEN(ScreenLines[off_from]) > 1
6191 && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
6192 ? ScreenLines2[off_from] != ScreenLines2[off_to]
6193 : (cols > 1 && ScreenLines[off_from + 1]
6194 != ScreenLines[off_to + 1])))
6195 || (enc_utf8
6196 && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
6197 || (ScreenLinesUC[off_from] != 0
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00006198 && comp_char_differs(off_from, off_to))
Bram Moolenaar451cf632012-08-23 18:58:14 +02006199 || ((*mb_off2cells)(off_from, off_from + cols) > 1
6200 && ScreenLines[off_from + 1]
6201 != ScreenLines[off_to + 1])))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006202#endif
6203 ))
6204 return TRUE;
6205 return FALSE;
6206}
6207
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006208#if defined(FEAT_TERMINAL) || defined(PROTO)
6209/*
6210 * Return the index in ScreenLines[] for the current screen line.
6211 */
6212 int
6213screen_get_current_line_off()
6214{
6215 return (int)(current_ScreenLine - ScreenLines);
6216}
6217#endif
6218
Bram Moolenaar071d4272004-06-13 20:20:40 +00006219/*
6220 * Move one "cooked" screen line to the screen, but only the characters that
6221 * have actually changed. Handle insert/delete character.
6222 * "coloff" gives the first column on the screen for this line.
6223 * "endcol" gives the columns where valid characters are.
6224 * "clear_width" is the width of the window. It's > 0 if the rest of the line
6225 * needs to be cleared, negative otherwise.
6226 * "rlflag" is TRUE in a rightleft window:
6227 * When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
6228 * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
6229 */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006230 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006231screen_line(
6232 int row,
6233 int coloff,
6234 int endcol,
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006235 int clear_width,
6236 int rlflag UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237{
6238 unsigned off_from;
6239 unsigned off_to;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006240#ifdef FEAT_MBYTE
6241 unsigned max_off_from;
6242 unsigned max_off_to;
6243#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244 int col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006245 int hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246 int force = FALSE; /* force update rest of the line */
6247 int redraw_this /* bool: does character need redraw? */
6248#ifdef FEAT_GUI
6249 = TRUE /* For GUI when while-loop empty */
6250#endif
6251 ;
6252 int redraw_next; /* redraw_this for next character */
6253#ifdef FEAT_MBYTE
6254 int clear_next = FALSE;
6255 int char_cells; /* 1: normal char */
6256 /* 2: occupies two display cells */
6257# define CHAR_CELLS char_cells
6258#else
6259# define CHAR_CELLS 1
6260#endif
6261
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01006262 /* Check for illegal row and col, just in case. */
6263 if (row >= Rows)
6264 row = Rows - 1;
6265 if (endcol > Columns)
6266 endcol = Columns;
6267
Bram Moolenaar071d4272004-06-13 20:20:40 +00006268# ifdef FEAT_CLIPBOARD
6269 clip_may_clear_selection(row, row);
6270# endif
6271
6272 off_from = (unsigned)(current_ScreenLine - ScreenLines);
6273 off_to = LineOffset[row] + coloff;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006274#ifdef FEAT_MBYTE
6275 max_off_from = off_from + screen_Columns;
6276 max_off_to = LineOffset[row] + screen_Columns;
6277#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006278
6279#ifdef FEAT_RIGHTLEFT
6280 if (rlflag)
6281 {
6282 /* Clear rest first, because it's left of the text. */
6283 if (clear_width > 0)
6284 {
6285 while (col <= endcol && ScreenLines[off_to] == ' '
6286 && ScreenAttrs[off_to] == 0
6287# ifdef FEAT_MBYTE
6288 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
6289# endif
6290 )
6291 {
6292 ++off_to;
6293 ++col;
6294 }
6295 if (col <= endcol)
6296 screen_fill(row, row + 1, col + coloff,
6297 endcol + coloff + 1, ' ', ' ', 0);
6298 }
6299 col = endcol + 1;
6300 off_to = LineOffset[row] + col + coloff;
6301 off_from += col;
6302 endcol = (clear_width > 0 ? clear_width : -clear_width);
6303 }
6304#endif /* FEAT_RIGHTLEFT */
6305
6306 redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
6307
6308 while (col < endcol)
6309 {
6310#ifdef FEAT_MBYTE
6311 if (has_mbyte && (col + 1 < endcol))
Bram Moolenaar367329b2007-08-30 11:53:22 +00006312 char_cells = (*mb_off2cells)(off_from, max_off_from);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006313 else
6314 char_cells = 1;
6315#endif
6316
6317 redraw_this = redraw_next;
6318 redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
6319 off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
6320
6321#ifdef FEAT_GUI
6322 /* If the next character was bold, then redraw the current character to
6323 * remove any pixels that might have spilt over into us. This only
6324 * happens in the GUI.
6325 */
6326 if (redraw_next && gui.in_use)
6327 {
6328 hl = ScreenAttrs[off_to + CHAR_CELLS];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00006329 if (hl > HL_ALL)
6330 hl = syn_attr2attr(hl);
6331 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006332 redraw_this = TRUE;
6333 }
6334#endif
6335
6336 if (redraw_this)
6337 {
6338 /*
6339 * Special handling when 'xs' termcap flag set (hpterm):
6340 * Attributes for characters are stored at the position where the
6341 * cursor is when writing the highlighting code. The
6342 * start-highlighting code must be written with the cursor on the
6343 * first highlighted character. The stop-highlighting code must
6344 * be written with the cursor just after the last highlighted
6345 * character.
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01006346 * Overwriting a character doesn't remove its highlighting. Need
Bram Moolenaar071d4272004-06-13 20:20:40 +00006347 * to clear the rest of the line, and force redrawing it
6348 * completely.
6349 */
6350 if ( p_wiv
6351 && !force
6352#ifdef FEAT_GUI
6353 && !gui.in_use
6354#endif
6355 && ScreenAttrs[off_to] != 0
6356 && ScreenAttrs[off_from] != ScreenAttrs[off_to])
6357 {
6358 /*
6359 * Need to remove highlighting attributes here.
6360 */
6361 windgoto(row, col + coloff);
6362 out_str(T_CE); /* clear rest of this screen line */
6363 screen_start(); /* don't know where cursor is now */
6364 force = TRUE; /* force redraw of rest of the line */
6365 redraw_next = TRUE; /* or else next char would miss out */
6366
6367 /*
6368 * If the previous character was highlighted, need to stop
6369 * highlighting at this character.
6370 */
6371 if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
6372 {
6373 screen_attr = ScreenAttrs[off_to - 1];
6374 term_windgoto(row, col + coloff);
6375 screen_stop_highlight();
6376 }
6377 else
6378 screen_attr = 0; /* highlighting has stopped */
6379 }
6380#ifdef FEAT_MBYTE
6381 if (enc_dbcs != 0)
6382 {
6383 /* Check if overwriting a double-byte with a single-byte or
6384 * the other way around requires another character to be
6385 * redrawn. For UTF-8 this isn't needed, because comparing
6386 * ScreenLinesUC[] is sufficient. */
6387 if (char_cells == 1
6388 && col + 1 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00006389 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390 {
6391 /* Writing a single-cell character over a double-cell
6392 * character: need to redraw the next cell. */
6393 ScreenLines[off_to + 1] = 0;
6394 redraw_next = TRUE;
6395 }
6396 else if (char_cells == 2
6397 && col + 2 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00006398 && (*mb_off2cells)(off_to, max_off_to) == 1
6399 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006400 {
6401 /* Writing the second half of a double-cell character over
6402 * a double-cell character: need to redraw the second
6403 * cell. */
6404 ScreenLines[off_to + 2] = 0;
6405 redraw_next = TRUE;
6406 }
6407
6408 if (enc_dbcs == DBCS_JPNU)
6409 ScreenLines2[off_to] = ScreenLines2[off_from];
6410 }
6411 /* When writing a single-width character over a double-width
6412 * character and at the end of the redrawn text, need to clear out
6413 * the right halve of the old character.
6414 * Also required when writing the right halve of a double-width
6415 * char over the left halve of an existing one. */
6416 if (has_mbyte && col + char_cells == endcol
6417 && ((char_cells == 1
Bram Moolenaar367329b2007-08-30 11:53:22 +00006418 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006419 || (char_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00006420 && (*mb_off2cells)(off_to, max_off_to) == 1
6421 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006422 clear_next = TRUE;
6423#endif
6424
6425 ScreenLines[off_to] = ScreenLines[off_from];
6426#ifdef FEAT_MBYTE
6427 if (enc_utf8)
6428 {
6429 ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
6430 if (ScreenLinesUC[off_from] != 0)
6431 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006432 int i;
6433
6434 for (i = 0; i < Screen_mco; ++i)
6435 ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006436 }
6437 }
6438 if (char_cells == 2)
6439 ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
6440#endif
6441
6442#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006443 /* The bold trick makes a single column of pixels appear in the
6444 * next character. When a bold character is removed, the next
Bram Moolenaar071d4272004-06-13 20:20:40 +00006445 * character should be redrawn too. This happens for our own GUI
6446 * and for some xterms. */
6447 if (
6448# ifdef FEAT_GUI
6449 gui.in_use
6450# endif
6451# if defined(FEAT_GUI) && defined(UNIX)
6452 ||
6453# endif
6454# ifdef UNIX
6455 term_is_xterm
6456# endif
6457 )
6458 {
6459 hl = ScreenAttrs[off_to];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00006460 if (hl > HL_ALL)
6461 hl = syn_attr2attr(hl);
6462 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006463 redraw_next = TRUE;
6464 }
6465#endif
6466 ScreenAttrs[off_to] = ScreenAttrs[off_from];
6467#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00006468 /* For simplicity set the attributes of second half of a
6469 * double-wide character equal to the first half. */
6470 if (char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006471 ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
Bram Moolenaar910f66f2006-04-05 20:41:53 +00006472
6473 if (enc_dbcs != 0 && char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006474 screen_char_2(off_to, row, col + coloff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006475 else
6476#endif
6477 screen_char(off_to, row, col + coloff);
6478 }
6479 else if ( p_wiv
6480#ifdef FEAT_GUI
6481 && !gui.in_use
6482#endif
6483 && col + coloff > 0)
6484 {
6485 if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
6486 {
6487 /*
6488 * Don't output stop-highlight when moving the cursor, it will
6489 * stop the highlighting when it should continue.
6490 */
6491 screen_attr = 0;
6492 }
6493 else if (screen_attr != 0)
6494 screen_stop_highlight();
6495 }
6496
6497 off_to += CHAR_CELLS;
6498 off_from += CHAR_CELLS;
6499 col += CHAR_CELLS;
6500 }
6501
6502#ifdef FEAT_MBYTE
6503 if (clear_next)
6504 {
6505 /* Clear the second half of a double-wide character of which the left
6506 * half was overwritten with a single-wide character. */
6507 ScreenLines[off_to] = ' ';
6508 if (enc_utf8)
6509 ScreenLinesUC[off_to] = 0;
6510 screen_char(off_to, row, col + coloff);
6511 }
6512#endif
6513
6514 if (clear_width > 0
6515#ifdef FEAT_RIGHTLEFT
6516 && !rlflag
6517#endif
6518 )
6519 {
6520#ifdef FEAT_GUI
6521 int startCol = col;
6522#endif
6523
6524 /* blank out the rest of the line */
6525 while (col < clear_width && ScreenLines[off_to] == ' '
6526 && ScreenAttrs[off_to] == 0
6527#ifdef FEAT_MBYTE
6528 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
6529#endif
6530 )
6531 {
6532 ++off_to;
6533 ++col;
6534 }
6535 if (col < clear_width)
6536 {
6537#ifdef FEAT_GUI
6538 /*
6539 * In the GUI, clearing the rest of the line may leave pixels
6540 * behind if the first character cleared was bold. Some bold
6541 * fonts spill over the left. In this case we redraw the previous
6542 * character too. If we didn't skip any blanks above, then we
6543 * only redraw if the character wasn't already redrawn anyway.
6544 */
Bram Moolenaar9c697322006-10-09 20:11:17 +00006545 if (gui.in_use && (col > startCol || !redraw_this))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006546 {
6547 hl = ScreenAttrs[off_to];
6548 if (hl > HL_ALL || (hl & HL_BOLD))
Bram Moolenaar9c697322006-10-09 20:11:17 +00006549 {
6550 int prev_cells = 1;
6551# ifdef FEAT_MBYTE
6552 if (enc_utf8)
6553 /* for utf-8, ScreenLines[char_offset + 1] == 0 means
6554 * that its width is 2. */
6555 prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
6556 else if (enc_dbcs != 0)
6557 {
6558 /* find previous character by counting from first
6559 * column and get its width. */
6560 unsigned off = LineOffset[row];
Bram Moolenaar367329b2007-08-30 11:53:22 +00006561 unsigned max_off = LineOffset[row] + screen_Columns;
Bram Moolenaar9c697322006-10-09 20:11:17 +00006562
6563 while (off < off_to)
6564 {
Bram Moolenaar367329b2007-08-30 11:53:22 +00006565 prev_cells = (*mb_off2cells)(off, max_off);
Bram Moolenaar9c697322006-10-09 20:11:17 +00006566 off += prev_cells;
6567 }
6568 }
6569
6570 if (enc_dbcs != 0 && prev_cells > 1)
6571 screen_char_2(off_to - prev_cells, row,
6572 col + coloff - prev_cells);
6573 else
6574# endif
6575 screen_char(off_to - prev_cells, row,
6576 col + coloff - prev_cells);
6577 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006578 }
6579#endif
6580 screen_fill(row, row + 1, col + coloff, clear_width + coloff,
6581 ' ', ' ', 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582 off_to += clear_width - col;
6583 col = clear_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006584 }
6585 }
6586
6587 if (clear_width > 0)
6588 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006589 /* For a window that's left of another, draw the separator char. */
6590 if (col + coloff < Columns)
6591 {
6592 int c;
6593
6594 c = fillchar_vsep(&hl);
Bram Moolenaarc60c4f62015-01-07 19:04:28 +01006595 if (ScreenLines[off_to] != (schar_T)c
Bram Moolenaar4033c552017-09-16 20:54:51 +02006596#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006597 || (enc_utf8 && (int)ScreenLinesUC[off_to]
6598 != (c >= 0x80 ? c : 0))
Bram Moolenaar4033c552017-09-16 20:54:51 +02006599#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006600 || ScreenAttrs[off_to] != hl)
6601 {
6602 ScreenLines[off_to] = c;
6603 ScreenAttrs[off_to] = hl;
Bram Moolenaar4033c552017-09-16 20:54:51 +02006604#ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00006605 if (enc_utf8)
6606 {
6607 if (c >= 0x80)
6608 {
6609 ScreenLinesUC[off_to] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006610 ScreenLinesC[0][off_to] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006611 }
6612 else
6613 ScreenLinesUC[off_to] = 0;
6614 }
Bram Moolenaar4033c552017-09-16 20:54:51 +02006615#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006616 screen_char(off_to, row, col + coloff);
6617 }
6618 }
6619 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006620 LineWraps[row] = FALSE;
6621 }
6622}
6623
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006624#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006625/*
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006626 * Mirror text "str" for right-left displaying.
6627 * Only works for single-byte characters (e.g., numbers).
Bram Moolenaar071d4272004-06-13 20:20:40 +00006628 */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006629 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006630rl_mirror(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006631{
6632 char_u *p1, *p2;
6633 int t;
6634
6635 for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
6636 {
6637 t = *p1;
6638 *p1 = *p2;
6639 *p2 = t;
6640 }
6641}
6642#endif
6643
Bram Moolenaar071d4272004-06-13 20:20:40 +00006644/*
6645 * mark all status lines for redraw; used after first :cd
6646 */
6647 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006648status_redraw_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649{
6650 win_T *wp;
6651
Bram Moolenaar29323592016-07-24 22:04:11 +02006652 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006653 if (wp->w_status_height)
6654 {
6655 wp->w_redr_status = TRUE;
6656 redraw_later(VALID);
6657 }
6658}
6659
6660/*
6661 * mark all status lines of the current buffer for redraw
6662 */
6663 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006664status_redraw_curbuf(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006665{
6666 win_T *wp;
6667
Bram Moolenaar29323592016-07-24 22:04:11 +02006668 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006669 if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
6670 {
6671 wp->w_redr_status = TRUE;
6672 redraw_later(VALID);
6673 }
6674}
6675
6676/*
6677 * Redraw all status lines that need to be redrawn.
6678 */
6679 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006680redraw_statuslines(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006681{
6682 win_T *wp;
6683
Bram Moolenaar29323592016-07-24 22:04:11 +02006684 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006685 if (wp->w_redr_status)
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006686 win_redr_status(wp, FALSE);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00006687 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006688 draw_tabline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006689}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006690
Bram Moolenaar4033c552017-09-16 20:54:51 +02006691#if defined(FEAT_WILDMENU) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006692/*
6693 * Redraw all status lines at the bottom of frame "frp".
6694 */
6695 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006696win_redraw_last_status(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006697{
6698 if (frp->fr_layout == FR_LEAF)
6699 frp->fr_win->w_redr_status = TRUE;
6700 else if (frp->fr_layout == FR_ROW)
6701 {
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01006702 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006703 win_redraw_last_status(frp);
6704 }
6705 else /* frp->fr_layout == FR_COL */
6706 {
6707 frp = frp->fr_child;
6708 while (frp->fr_next != NULL)
6709 frp = frp->fr_next;
6710 win_redraw_last_status(frp);
6711 }
6712}
6713#endif
6714
Bram Moolenaar071d4272004-06-13 20:20:40 +00006715/*
6716 * Draw the verticap separator right of window "wp" starting with line "row".
6717 */
6718 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01006719draw_vsep_win(win_T *wp, int row)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006720{
6721 int hl;
6722 int c;
6723
6724 if (wp->w_vsep_width)
6725 {
6726 /* draw the vertical separator right of this window */
6727 c = fillchar_vsep(&hl);
6728 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
6729 W_ENDCOL(wp), W_ENDCOL(wp) + 1,
6730 c, ' ', hl);
6731 }
6732}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006733
6734#ifdef FEAT_WILDMENU
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01006735static int skip_status_match_char(expand_T *xp, char_u *s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006736
6737/*
Bram Moolenaar367329b2007-08-30 11:53:22 +00006738 * Get the length of an item as it will be shown in the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006739 */
6740 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006741status_match_len(expand_T *xp, char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006742{
6743 int len = 0;
6744
6745#ifdef FEAT_MENU
6746 int emenu = (xp->xp_context == EXPAND_MENUS
6747 || xp->xp_context == EXPAND_MENUNAMES);
6748
6749 /* Check for menu separators - replace with '|'. */
6750 if (emenu && menu_is_separator(s))
6751 return 1;
6752#endif
6753
6754 while (*s != NUL)
6755 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006756 s += skip_status_match_char(xp, s);
Bram Moolenaar81695252004-12-29 20:58:21 +00006757 len += ptr2cells(s);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006758 MB_PTR_ADV(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006759 }
6760
6761 return len;
6762}
6763
6764/*
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006765 * Return the number of characters that should be skipped in a status match.
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006766 * These are backslashes used for escaping. Do show backslashes in help tags.
6767 */
6768 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006769skip_status_match_char(expand_T *xp, char_u *s)
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006770{
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006771 if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006772#ifdef FEAT_MENU
6773 || ((xp->xp_context == EXPAND_MENUS
6774 || xp->xp_context == EXPAND_MENUNAMES)
6775 && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
6776#endif
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006777 )
6778 {
6779#ifndef BACKSLASH_IN_FILENAME
6780 if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
6781 return 2;
6782#endif
6783 return 1;
6784 }
6785 return 0;
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006786}
6787
6788/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006789 * Show wildchar matches in the status line.
6790 * Show at least the "match" item.
6791 * We start at item 'first_match' in the list and show all matches that fit.
6792 *
6793 * If inversion is possible we use it. Else '=' characters are used.
6794 */
6795 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006796win_redr_status_matches(
6797 expand_T *xp,
6798 int num_matches,
6799 char_u **matches, /* list of matches */
6800 int match,
6801 int showtail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006802{
6803#define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
6804 int row;
6805 char_u *buf;
6806 int len;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006807 int clen; /* length in screen cells */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006808 int fillchar;
6809 int attr;
6810 int i;
6811 int highlight = TRUE;
6812 char_u *selstart = NULL;
6813 int selstart_col = 0;
6814 char_u *selend = NULL;
6815 static int first_match = 0;
6816 int add_left = FALSE;
6817 char_u *s;
6818#ifdef FEAT_MENU
6819 int emenu;
6820#endif
6821#if defined(FEAT_MBYTE) || defined(FEAT_MENU)
6822 int l;
6823#endif
6824
6825 if (matches == NULL) /* interrupted completion? */
6826 return;
6827
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006828#ifdef FEAT_MBYTE
6829 if (has_mbyte)
6830 buf = alloc((unsigned)Columns * MB_MAXBYTES + 1);
6831 else
6832#endif
6833 buf = alloc((unsigned)Columns + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006834 if (buf == NULL)
6835 return;
6836
6837 if (match == -1) /* don't show match but original text */
6838 {
6839 match = 0;
6840 highlight = FALSE;
6841 }
6842 /* count 1 for the ending ">" */
6843 clen = status_match_len(xp, L_MATCH(match)) + 3;
6844 if (match == 0)
6845 first_match = 0;
6846 else if (match < first_match)
6847 {
6848 /* jumping left, as far as we can go */
6849 first_match = match;
6850 add_left = TRUE;
6851 }
6852 else
6853 {
6854 /* check if match fits on the screen */
6855 for (i = first_match; i < match; ++i)
6856 clen += status_match_len(xp, L_MATCH(i)) + 2;
6857 if (first_match > 0)
6858 clen += 2;
6859 /* jumping right, put match at the left */
6860 if ((long)clen > Columns)
6861 {
6862 first_match = match;
6863 /* if showing the last match, we can add some on the left */
6864 clen = 2;
6865 for (i = match; i < num_matches; ++i)
6866 {
6867 clen += status_match_len(xp, L_MATCH(i)) + 2;
6868 if ((long)clen >= Columns)
6869 break;
6870 }
6871 if (i == num_matches)
6872 add_left = TRUE;
6873 }
6874 }
6875 if (add_left)
6876 while (first_match > 0)
6877 {
6878 clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
6879 if ((long)clen >= Columns)
6880 break;
6881 --first_match;
6882 }
6883
Bram Moolenaar3633cf52017-07-31 22:29:35 +02006884 fillchar = fillchar_status(&attr, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006885
6886 if (first_match == 0)
6887 {
6888 *buf = NUL;
6889 len = 0;
6890 }
6891 else
6892 {
6893 STRCPY(buf, "< ");
6894 len = 2;
6895 }
6896 clen = len;
6897
6898 i = first_match;
6899 while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
6900 {
6901 if (i == match)
6902 {
6903 selstart = buf + len;
6904 selstart_col = clen;
6905 }
6906
6907 s = L_MATCH(i);
6908 /* Check for menu separators - replace with '|' */
6909#ifdef FEAT_MENU
6910 emenu = (xp->xp_context == EXPAND_MENUS
6911 || xp->xp_context == EXPAND_MENUNAMES);
6912 if (emenu && menu_is_separator(s))
6913 {
6914 STRCPY(buf + len, transchar('|'));
6915 l = (int)STRLEN(buf + len);
6916 len += l;
6917 clen += l;
6918 }
6919 else
6920#endif
6921 for ( ; *s != NUL; ++s)
6922 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006923 s += skip_status_match_char(xp, s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006924 clen += ptr2cells(s);
6925#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006926 if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006927 {
6928 STRNCPY(buf + len, s, l);
6929 s += l - 1;
6930 len += l;
6931 }
6932 else
6933#endif
6934 {
6935 STRCPY(buf + len, transchar_byte(*s));
6936 len += (int)STRLEN(buf + len);
6937 }
6938 }
6939 if (i == match)
6940 selend = buf + len;
6941
6942 *(buf + len++) = ' ';
6943 *(buf + len++) = ' ';
6944 clen += 2;
6945 if (++i == num_matches)
6946 break;
6947 }
6948
6949 if (i != num_matches)
6950 {
6951 *(buf + len++) = '>';
6952 ++clen;
6953 }
6954
6955 buf[len] = NUL;
6956
6957 row = cmdline_row - 1;
6958 if (row >= 0)
6959 {
6960 if (wild_menu_showing == 0)
6961 {
6962 if (msg_scrolled > 0)
6963 {
6964 /* Put the wildmenu just above the command line. If there is
6965 * no room, scroll the screen one line up. */
6966 if (cmdline_row == Rows - 1)
6967 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02006968 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006969 ++msg_scrolled;
6970 }
6971 else
6972 {
6973 ++cmdline_row;
6974 ++row;
6975 }
6976 wild_menu_showing = WM_SCROLLED;
6977 }
6978 else
6979 {
6980 /* Create status line if needed by setting 'laststatus' to 2.
6981 * Set 'winminheight' to zero to avoid that the window is
6982 * resized. */
6983 if (lastwin->w_status_height == 0)
6984 {
6985 save_p_ls = p_ls;
6986 save_p_wmh = p_wmh;
6987 p_ls = 2;
6988 p_wmh = 0;
6989 last_status(FALSE);
6990 }
6991 wild_menu_showing = WM_SHOWN;
6992 }
6993 }
6994
6995 screen_puts(buf, row, 0, attr);
6996 if (selstart != NULL && highlight)
6997 {
6998 *selend = NUL;
Bram Moolenaar8820b482017-03-16 17:23:31 +01006999 screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007000 }
7001
7002 screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
7003 }
7004
Bram Moolenaar071d4272004-06-13 20:20:40 +00007005 win_redraw_last_status(topframe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007006 vim_free(buf);
7007}
7008#endif
7009
Bram Moolenaar071d4272004-06-13 20:20:40 +00007010/*
7011 * Redraw the status line of window wp.
7012 *
7013 * If inversion is possible we use it. Else '=' characters are used.
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02007014 * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is
7015 * displayed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007016 */
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02007017 static void
Bram Moolenaar829adb72018-06-24 19:24:03 +02007018win_redr_status(win_T *wp, int ignore_pum UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007019{
7020 int row;
7021 char_u *p;
7022 int len;
7023 int fillchar;
7024 int attr;
7025 int this_ru_col;
Bram Moolenaaradb09c22009-06-16 15:22:12 +00007026 static int busy = FALSE;
7027
7028 /* It's possible to get here recursively when 'statusline' (indirectly)
7029 * invokes ":redrawstatus". Simply ignore the call then. */
7030 if (busy)
7031 return;
7032 busy = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007033
7034 wp->w_redr_status = FALSE;
7035 if (wp->w_status_height == 0)
7036 {
7037 /* no status line, can only be last window */
7038 redraw_cmdline = TRUE;
7039 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00007040 else if (!redrawing()
7041#ifdef FEAT_INS_EXPAND
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02007042 // don't update status line when popup menu is visible and may be
7043 // drawn over it, unless it will be redrawn later
7044 || (!ignore_pum && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00007045#endif
7046 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00007047 {
7048 /* Don't redraw right now, do it later. */
7049 wp->w_redr_status = TRUE;
7050 }
7051#ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007052 else if (*p_stl != NUL || *wp->w_p_stl != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007053 {
7054 /* redraw custom status line */
Bram Moolenaar362f3562009-11-03 16:20:34 +00007055 redraw_custom_statusline(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007056 }
7057#endif
7058 else
7059 {
Bram Moolenaar3633cf52017-07-31 22:29:35 +02007060 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007061
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007062 get_trans_bufname(wp->w_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007063 p = NameBuff;
7064 len = (int)STRLEN(p);
7065
Bram Moolenaard85f2712017-07-28 21:51:57 +02007066 if (bt_help(wp->w_buffer)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007067#ifdef FEAT_QUICKFIX
7068 || wp->w_p_pvw
7069#endif
7070 || bufIsChanged(wp->w_buffer)
7071 || wp->w_buffer->b_p_ro)
7072 *(p + len++) = ' ';
Bram Moolenaard85f2712017-07-28 21:51:57 +02007073 if (bt_help(wp->w_buffer))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +00007075 STRCPY(p + len, _("[Help]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007076 len += (int)STRLEN(p + len);
7077 }
7078#ifdef FEAT_QUICKFIX
7079 if (wp->w_p_pvw)
7080 {
7081 STRCPY(p + len, _("[Preview]"));
7082 len += (int)STRLEN(p + len);
7083 }
7084#endif
Bram Moolenaar086d5352017-08-05 18:19:55 +02007085 if (bufIsChanged(wp->w_buffer)
7086#ifdef FEAT_TERMINAL
7087 && !bt_terminal(wp->w_buffer)
7088#endif
7089 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00007090 {
7091 STRCPY(p + len, "[+]");
7092 len += 3;
7093 }
7094 if (wp->w_buffer->b_p_ro)
7095 {
Bram Moolenaar23584032013-06-07 20:17:11 +02007096 STRCPY(p + len, _("[RO]"));
Bram Moolenaar3457d292017-02-23 14:55:59 +01007097 len += (int)STRLEN(p + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007098 }
7099
Bram Moolenaar02631462017-09-22 15:20:32 +02007100 this_ru_col = ru_col - (Columns - wp->w_width);
7101 if (this_ru_col < (wp->w_width + 1) / 2)
7102 this_ru_col = (wp->w_width + 1) / 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007103 if (this_ru_col <= 1)
7104 {
7105 p = (char_u *)"<"; /* No room for file name! */
7106 len = 1;
7107 }
7108 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007109#ifdef FEAT_MBYTE
7110 if (has_mbyte)
7111 {
7112 int clen = 0, i;
7113
7114 /* Count total number of display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02007115 clen = mb_string2cells(p, -1);
7116
Bram Moolenaar071d4272004-06-13 20:20:40 +00007117 /* Find first character that will fit.
7118 * Going from start to end is much faster for DBCS. */
7119 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007120 i += (*mb_ptr2len)(p + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007121 clen -= (*mb_ptr2cells)(p + i);
7122 len = clen;
7123 if (i > 0)
7124 {
7125 p = p + i - 1;
7126 *p = '<';
7127 ++len;
7128 }
7129
7130 }
7131 else
7132#endif
7133 if (len > this_ru_col - 1)
7134 {
7135 p += len - (this_ru_col - 1);
7136 *p = '<';
7137 len = this_ru_col - 1;
7138 }
7139
7140 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar53f81742017-09-22 14:35:51 +02007141 screen_puts(p, row, wp->w_wincol, attr);
7142 screen_fill(row, row + 1, len + wp->w_wincol,
7143 this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007144
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02007145 if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007146 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
7147 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
Bram Moolenaar53f81742017-09-22 14:35:51 +02007148 - 1 + wp->w_wincol), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007149
7150#ifdef FEAT_CMDL_INFO
Bram Moolenaar491ac282018-06-17 14:47:55 +02007151 win_redr_ruler(wp, TRUE, ignore_pum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007152#endif
7153 }
7154
Bram Moolenaar071d4272004-06-13 20:20:40 +00007155 /*
7156 * May need to draw the character below the vertical separator.
7157 */
7158 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
7159 {
7160 if (stl_connected(wp))
Bram Moolenaar3633cf52017-07-31 22:29:35 +02007161 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007162 else
7163 fillchar = fillchar_vsep(&attr);
7164 screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
7165 attr);
7166 }
Bram Moolenaaradb09c22009-06-16 15:22:12 +00007167 busy = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007168}
7169
Bram Moolenaar238a5642006-02-21 22:12:05 +00007170#ifdef FEAT_STL_OPT
7171/*
7172 * Redraw the status line according to 'statusline' and take care of any
7173 * errors encountered.
7174 */
7175 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007176redraw_custom_statusline(win_T *wp)
Bram Moolenaar238a5642006-02-21 22:12:05 +00007177{
Bram Moolenaar362f3562009-11-03 16:20:34 +00007178 static int entered = FALSE;
Bram Moolenaara742e082016-04-05 21:10:38 +02007179 int saved_did_emsg = did_emsg;
Bram Moolenaar362f3562009-11-03 16:20:34 +00007180
7181 /* When called recursively return. This can happen when the statusline
7182 * contains an expression that triggers a redraw. */
7183 if (entered)
7184 return;
7185 entered = TRUE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007186
Bram Moolenaara742e082016-04-05 21:10:38 +02007187 did_emsg = FALSE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007188 win_redr_custom(wp, FALSE);
Bram Moolenaara742e082016-04-05 21:10:38 +02007189 if (did_emsg)
Bram Moolenaar362f3562009-11-03 16:20:34 +00007190 {
7191 /* When there is an error disable the statusline, otherwise the
7192 * display is messed up with errors and a redraw triggers the problem
7193 * again and again. */
Bram Moolenaar238a5642006-02-21 22:12:05 +00007194 set_string_option_direct((char_u *)"statusline", -1,
7195 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007196 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
Bram Moolenaar362f3562009-11-03 16:20:34 +00007197 }
Bram Moolenaara742e082016-04-05 21:10:38 +02007198 did_emsg |= saved_did_emsg;
Bram Moolenaar362f3562009-11-03 16:20:34 +00007199 entered = FALSE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007200}
7201#endif
7202
Bram Moolenaar071d4272004-06-13 20:20:40 +00007203/*
7204 * Return TRUE if the status line of window "wp" is connected to the status
7205 * line of the window right of it. If not, then it's a vertical separator.
7206 * Only call if (wp->w_vsep_width != 0).
7207 */
7208 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007209stl_connected(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007210{
7211 frame_T *fr;
7212
7213 fr = wp->w_frame;
7214 while (fr->fr_parent != NULL)
7215 {
7216 if (fr->fr_parent->fr_layout == FR_COL)
7217 {
7218 if (fr->fr_next != NULL)
7219 break;
7220 }
7221 else
7222 {
7223 if (fr->fr_next != NULL)
7224 return TRUE;
7225 }
7226 fr = fr->fr_parent;
7227 }
7228 return FALSE;
7229}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007230
Bram Moolenaar071d4272004-06-13 20:20:40 +00007231
Bram Moolenaar071d4272004-06-13 20:20:40 +00007232/*
7233 * Get the value to show for the language mappings, active 'keymap'.
7234 */
7235 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007236get_keymap_str(
7237 win_T *wp,
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02007238 char_u *fmt, /* format string containing one %s item */
Bram Moolenaar05540972016-01-30 20:31:25 +01007239 char_u *buf, /* buffer for the result */
7240 int len) /* length of buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007241{
7242 char_u *p;
7243
7244 if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
7245 return FALSE;
7246
7247 {
7248#ifdef FEAT_EVAL
7249 buf_T *old_curbuf = curbuf;
7250 win_T *old_curwin = curwin;
7251 char_u *s;
7252
7253 curbuf = wp->w_buffer;
7254 curwin = wp;
7255 STRCPY(buf, "b:keymap_name"); /* must be writable */
7256 ++emsg_skip;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007257 s = p = eval_to_string(buf, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007258 --emsg_skip;
7259 curbuf = old_curbuf;
7260 curwin = old_curwin;
7261 if (p == NULL || *p == NUL)
7262#endif
7263 {
7264#ifdef FEAT_KEYMAP
7265 if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
7266 p = wp->w_buffer->b_p_keymap;
7267 else
7268#endif
7269 p = (char_u *)"lang";
7270 }
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02007271 if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007272 buf[0] = NUL;
7273#ifdef FEAT_EVAL
7274 vim_free(s);
7275#endif
7276 }
7277 return buf[0] != NUL;
7278}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007279
7280#if defined(FEAT_STL_OPT) || defined(PROTO)
7281/*
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007282 * Redraw the status line or ruler of window "wp".
7283 * When "wp" is NULL redraw the tab pages line from 'tabline'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007284 */
7285 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007286win_redr_custom(
7287 win_T *wp,
7288 int draw_ruler) /* TRUE or FALSE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007289{
Bram Moolenaar1d633412013-12-11 15:52:01 +01007290 static int entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007291 int attr;
7292 int curattr;
7293 int row;
7294 int col = 0;
7295 int maxwidth;
7296 int width;
7297 int n;
7298 int len;
7299 int fillchar;
7300 char_u buf[MAXPATHL];
Bram Moolenaar362f3562009-11-03 16:20:34 +00007301 char_u *stl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007302 char_u *p;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007303 struct stl_hlrec hltab[STL_MAX_ITEM];
7304 struct stl_hlrec tabtab[STL_MAX_ITEM];
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007305 int use_sandbox = FALSE;
Bram Moolenaar61452852011-02-01 18:01:11 +01007306 win_T *ewp;
7307 int p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007308
Bram Moolenaar1d633412013-12-11 15:52:01 +01007309 /* There is a tiny chance that this gets called recursively: When
7310 * redrawing a status line triggers redrawing the ruler or tabline.
7311 * Avoid trouble by not allowing recursion. */
7312 if (entered)
7313 return;
7314 entered = TRUE;
7315
Bram Moolenaar071d4272004-06-13 20:20:40 +00007316 /* setup environment for the task at hand */
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007317 if (wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007318 {
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007319 /* Use 'tabline'. Always at the first line of the screen. */
Bram Moolenaar362f3562009-11-03 16:20:34 +00007320 stl = p_tal;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007321 row = 0;
Bram Moolenaar65c923a2006-03-03 22:56:30 +00007322 fillchar = ' ';
Bram Moolenaar8820b482017-03-16 17:23:31 +01007323 attr = HL_ATTR(HLF_TPF);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007324 maxwidth = Columns;
7325# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007326 use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007327# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007328 }
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007329 else
7330 {
7331 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar3633cf52017-07-31 22:29:35 +02007332 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar02631462017-09-22 15:20:32 +02007333 maxwidth = wp->w_width;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007334
7335 if (draw_ruler)
7336 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00007337 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007338 /* advance past any leading group spec - implicit in ru_col */
Bram Moolenaar362f3562009-11-03 16:20:34 +00007339 if (*stl == '%')
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007340 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00007341 if (*++stl == '-')
7342 stl++;
7343 if (atoi((char *)stl))
7344 while (VIM_ISDIGIT(*stl))
7345 stl++;
7346 if (*stl++ != '(')
7347 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007348 }
Bram Moolenaar02631462017-09-22 15:20:32 +02007349 col = ru_col - (Columns - wp->w_width);
7350 if (col < (wp->w_width + 1) / 2)
7351 col = (wp->w_width + 1) / 2;
7352 maxwidth = wp->w_width - col;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007353 if (!wp->w_status_height)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007354 {
7355 row = Rows - 1;
7356 --maxwidth; /* writing in last column may cause scrolling */
7357 fillchar = ' ';
7358 attr = 0;
7359 }
7360
7361# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007362 use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007363# endif
7364 }
7365 else
7366 {
7367 if (*wp->w_p_stl != NUL)
Bram Moolenaar362f3562009-11-03 16:20:34 +00007368 stl = wp->w_p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007369 else
Bram Moolenaar362f3562009-11-03 16:20:34 +00007370 stl = p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007371# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007372 use_sandbox = was_set_insecurely((char_u *)"statusline",
7373 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007374# endif
7375 }
7376
Bram Moolenaar53f81742017-09-22 14:35:51 +02007377 col += wp->w_wincol;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007378 }
7379
Bram Moolenaar071d4272004-06-13 20:20:40 +00007380 if (maxwidth <= 0)
Bram Moolenaar1d633412013-12-11 15:52:01 +01007381 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007382
Bram Moolenaar61452852011-02-01 18:01:11 +01007383 /* Temporarily reset 'cursorbind', we don't want a side effect from moving
7384 * the cursor away and back. */
7385 ewp = wp == NULL ? curwin : wp;
7386 p_crb_save = ewp->w_p_crb;
7387 ewp->w_p_crb = FALSE;
7388
Bram Moolenaar362f3562009-11-03 16:20:34 +00007389 /* Make a copy, because the statusline may include a function call that
7390 * might change the option value and free the memory. */
7391 stl = vim_strsave(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01007392 width = build_stl_str_hl(ewp, buf, sizeof(buf),
Bram Moolenaar362f3562009-11-03 16:20:34 +00007393 stl, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007394 fillchar, maxwidth, hltab, tabtab);
Bram Moolenaar362f3562009-11-03 16:20:34 +00007395 vim_free(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01007396 ewp->w_p_crb = p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007397
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01007398 /* Make all characters printable. */
7399 p = transstr(buf);
7400 if (p != NULL)
7401 {
7402 vim_strncpy(buf, p, sizeof(buf) - 1);
7403 vim_free(p);
7404 }
7405
7406 /* fill up with "fillchar" */
7407 len = (int)STRLEN(buf);
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007408 while (width < maxwidth && len < (int)sizeof(buf) - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007409 {
7410#ifdef FEAT_MBYTE
7411 len += (*mb_char2bytes)(fillchar, buf + len);
7412#else
7413 buf[len++] = fillchar;
7414#endif
7415 ++width;
7416 }
7417 buf[len] = NUL;
7418
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007419 /*
7420 * Draw each snippet with the specified highlighting.
7421 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007422 curattr = attr;
7423 p = buf;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007424 for (n = 0; hltab[n].start != NULL; n++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007425 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007426 len = (int)(hltab[n].start - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007427 screen_puts_len(p, len, row, col, curattr);
7428 col += vim_strnsize(p, len);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007429 p = hltab[n].start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007430
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007431 if (hltab[n].userhl == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007432 curattr = attr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007433 else if (hltab[n].userhl < 0)
7434 curattr = syn_id2attr(-hltab[n].userhl);
Bram Moolenaar4033c552017-09-16 20:54:51 +02007435#ifdef FEAT_TERMINAL
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02007436 else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
7437 && wp->w_status_height != 0)
7438 curattr = highlight_stltermnc[hltab[n].userhl - 1];
Bram Moolenaarbce4f622017-08-13 21:37:43 +02007439 else if (wp != NULL && bt_terminal(wp->w_buffer)
7440 && wp->w_status_height != 0)
7441 curattr = highlight_stlterm[hltab[n].userhl - 1];
Bram Moolenaar4033c552017-09-16 20:54:51 +02007442#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +00007443 else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007444 curattr = highlight_stlnc[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007445 else
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007446 curattr = highlight_user[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007447 }
7448 screen_puts(p, row, col, curattr);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007449
7450 if (wp == NULL)
7451 {
7452 /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */
7453 col = 0;
7454 len = 0;
7455 p = buf;
7456 fillchar = 0;
7457 for (n = 0; tabtab[n].start != NULL; n++)
7458 {
7459 len += vim_strnsize(p, (int)(tabtab[n].start - p));
7460 while (col < len)
7461 TabPageIdxs[col++] = fillchar;
7462 p = tabtab[n].start;
7463 fillchar = tabtab[n].userhl;
7464 }
7465 while (col < Columns)
7466 TabPageIdxs[col++] = fillchar;
7467 }
Bram Moolenaar1d633412013-12-11 15:52:01 +01007468
7469theend:
7470 entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007471}
7472
7473#endif /* FEAT_STL_OPT */
7474
7475/*
7476 * Output a single character directly to the screen and update ScreenLines.
7477 */
7478 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007479screen_putchar(int c, int row, int col, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007480{
Bram Moolenaar071d4272004-06-13 20:20:40 +00007481 char_u buf[MB_MAXBYTES + 1];
7482
Bram Moolenaar9a920d82012-06-01 15:21:02 +02007483#ifdef FEAT_MBYTE
7484 if (has_mbyte)
7485 buf[(*mb_char2bytes)(c, buf)] = NUL;
7486 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007487#endif
Bram Moolenaar9a920d82012-06-01 15:21:02 +02007488 {
7489 buf[0] = c;
7490 buf[1] = NUL;
7491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007492 screen_puts(buf, row, col, attr);
7493}
7494
7495/*
7496 * Get a single character directly from ScreenLines into "bytes[]".
7497 * Also return its attribute in *attrp;
7498 */
7499 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007500screen_getbytes(int row, int col, char_u *bytes, int *attrp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007501{
7502 unsigned off;
7503
7504 /* safety check */
7505 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
7506 {
7507 off = LineOffset[row] + col;
7508 *attrp = ScreenAttrs[off];
7509 bytes[0] = ScreenLines[off];
7510 bytes[1] = NUL;
7511
7512#ifdef FEAT_MBYTE
7513 if (enc_utf8 && ScreenLinesUC[off] != 0)
7514 bytes[utfc_char2bytes(off, bytes)] = NUL;
7515 else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
7516 {
7517 bytes[0] = ScreenLines[off];
7518 bytes[1] = ScreenLines2[off];
7519 bytes[2] = NUL;
7520 }
7521 else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
7522 {
7523 bytes[1] = ScreenLines[off + 1];
7524 bytes[2] = NUL;
7525 }
7526#endif
7527 }
7528}
7529
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007530#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007531/*
7532 * Return TRUE if composing characters for screen posn "off" differs from
7533 * composing characters in "u8cc".
Bram Moolenaar70c49c12010-03-23 15:36:35 +01007534 * Only to be used when ScreenLinesUC[off] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007535 */
7536 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007537screen_comp_differs(int off, int *u8cc)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007538{
7539 int i;
7540
7541 for (i = 0; i < Screen_mco; ++i)
7542 {
7543 if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
7544 return TRUE;
7545 if (u8cc[i] == 0)
7546 break;
7547 }
7548 return FALSE;
7549}
7550#endif
7551
Bram Moolenaar071d4272004-06-13 20:20:40 +00007552/*
7553 * Put string '*text' on the screen at position 'row' and 'col', with
7554 * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
7555 * Note: only outputs within one row, message is truncated at screen boundary!
7556 * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
7557 */
7558 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007559screen_puts(
7560 char_u *text,
7561 int row,
7562 int col,
7563 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007564{
7565 screen_puts_len(text, -1, row, col, attr);
7566}
7567
7568/*
7569 * Like screen_puts(), but output "text[len]". When "len" is -1 output up to
7570 * a NUL.
7571 */
7572 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007573screen_puts_len(
7574 char_u *text,
7575 int textlen,
7576 int row,
7577 int col,
7578 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007579{
7580 unsigned off;
7581 char_u *ptr = text;
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007582 int len = textlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007583 int c;
7584#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00007585 unsigned max_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007586 int mbyte_blen = 1;
7587 int mbyte_cells = 1;
7588 int u8c = 0;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007589 int u8cc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007590 int clear_next_cell = FALSE;
7591# ifdef FEAT_ARABIC
7592 int prev_c = 0; /* previous Arabic character */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007593 int pc, nc, nc1;
7594 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007595# endif
7596#endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007597#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7598 int force_redraw_this;
7599 int force_redraw_next = FALSE;
7600#endif
7601 int need_redraw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007602
7603 if (ScreenLines == NULL || row >= screen_Rows) /* safety check */
7604 return;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007605 off = LineOffset[row] + col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007606
Bram Moolenaarc236c162008-07-13 17:41:49 +00007607#ifdef FEAT_MBYTE
7608 /* When drawing over the right halve of a double-wide char clear out the
7609 * left halve. Only needed in a terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00007610 if (has_mbyte && col > 0 && col < screen_Columns
Bram Moolenaarc236c162008-07-13 17:41:49 +00007611# ifdef FEAT_GUI
7612 && !gui.in_use
7613# endif
7614 && mb_fix_col(col, row) != col)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007615 {
7616 ScreenLines[off - 1] = ' ';
7617 ScreenAttrs[off - 1] = 0;
7618 if (enc_utf8)
7619 {
7620 ScreenLinesUC[off - 1] = 0;
7621 ScreenLinesC[0][off - 1] = 0;
7622 }
7623 /* redraw the previous cell, make it empty */
7624 screen_char(off - 1, row, col - 1);
7625 /* force the cell at "col" to be redrawn */
7626 force_redraw_next = TRUE;
7627 }
Bram Moolenaarc236c162008-07-13 17:41:49 +00007628#endif
7629
Bram Moolenaar367329b2007-08-30 11:53:22 +00007630#ifdef FEAT_MBYTE
7631 max_off = LineOffset[row] + screen_Columns;
7632#endif
Bram Moolenaara064ac82007-08-05 18:10:54 +00007633 while (col < screen_Columns
7634 && (len < 0 || (int)(ptr - text) < len)
7635 && *ptr != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007636 {
7637 c = *ptr;
7638#ifdef FEAT_MBYTE
7639 /* check if this is the first byte of a multibyte */
7640 if (has_mbyte)
7641 {
7642 if (enc_utf8 && len > 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007643 mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007644 else
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007645 mbyte_blen = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007646 if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7647 mbyte_cells = 1;
7648 else if (enc_dbcs != 0)
7649 mbyte_cells = mbyte_blen;
7650 else /* enc_utf8 */
7651 {
7652 if (len >= 0)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007653 u8c = utfc_ptr2char_len(ptr, u8cc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007654 (int)((text + len) - ptr));
7655 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007656 u8c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007657 mbyte_cells = utf_char2cells(u8c);
Bram Moolenaar11936362007-09-17 20:39:42 +00007658# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00007659 /* Non-BMP character: display as ? or fullwidth ?. */
7660 if (u8c >= 0x10000)
7661 {
7662 u8c = (mbyte_cells == 2) ? 0xff1f : (int)'?';
7663 if (attr == 0)
Bram Moolenaar8820b482017-03-16 17:23:31 +01007664 attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007665 }
Bram Moolenaar11936362007-09-17 20:39:42 +00007666# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007667# ifdef FEAT_ARABIC
7668 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
7669 {
7670 /* Do Arabic shaping. */
7671 if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
7672 {
7673 /* Past end of string to be displayed. */
7674 nc = NUL;
7675 nc1 = NUL;
7676 }
7677 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007678 {
Bram Moolenaar54620182009-11-11 16:07:20 +00007679 nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
7680 (int)((text + len) - ptr - mbyte_blen));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007681 nc1 = pcc[0];
7682 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007683 pc = prev_c;
7684 prev_c = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007685 u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007686 }
7687 else
7688 prev_c = u8c;
7689# endif
Bram Moolenaare4ebd292010-01-19 17:40:46 +01007690 if (col + mbyte_cells > screen_Columns)
7691 {
7692 /* Only 1 cell left, but character requires 2 cells:
7693 * display a '>' in the last column to avoid wrapping. */
7694 c = '>';
7695 mbyte_cells = 1;
7696 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007697 }
7698 }
7699#endif
7700
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007701#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7702 force_redraw_this = force_redraw_next;
7703 force_redraw_next = FALSE;
7704#endif
7705
7706 need_redraw = ScreenLines[off] != c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007707#ifdef FEAT_MBYTE
7708 || (mbyte_cells == 2
7709 && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
7710 || (enc_dbcs == DBCS_JPNU
7711 && c == 0x8e
7712 && ScreenLines2[off] != ptr[1])
7713 || (enc_utf8
Bram Moolenaar70c49c12010-03-23 15:36:35 +01007714 && (ScreenLinesUC[off] !=
7715 (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
7716 || (ScreenLinesUC[off] != 0
7717 && screen_comp_differs(off, u8cc))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007718#endif
7719 || ScreenAttrs[off] != attr
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007720 || exmode_active;
7721
7722 if (need_redraw
7723#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7724 || force_redraw_this
7725#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007726 )
7727 {
7728#if defined(FEAT_GUI) || defined(UNIX)
7729 /* The bold trick makes a single row of pixels appear in the next
7730 * character. When a bold character is removed, the next
7731 * character should be redrawn too. This happens for our own GUI
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007732 * and for some xterms. */
7733 if (need_redraw && ScreenLines[off] != ' ' && (
Bram Moolenaar071d4272004-06-13 20:20:40 +00007734# ifdef FEAT_GUI
7735 gui.in_use
7736# endif
7737# if defined(FEAT_GUI) && defined(UNIX)
7738 ||
7739# endif
7740# ifdef UNIX
7741 term_is_xterm
7742# endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007743 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007744 {
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007745 int n = ScreenAttrs[off];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007746
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007747 if (n > HL_ALL)
7748 n = syn_attr2attr(n);
7749 if (n & HL_BOLD)
7750 force_redraw_next = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007751 }
7752#endif
7753#ifdef FEAT_MBYTE
7754 /* When at the end of the text and overwriting a two-cell
7755 * character with a one-cell character, need to clear the next
7756 * cell. Also when overwriting the left halve of a two-cell char
7757 * with the right halve of a two-cell char. Do this only once
7758 * (mb_off2cells() may return 2 on the right halve). */
7759 if (clear_next_cell)
7760 clear_next_cell = FALSE;
7761 else if (has_mbyte
7762 && (len < 0 ? ptr[mbyte_blen] == NUL
7763 : ptr + mbyte_blen >= text + len)
Bram Moolenaar367329b2007-08-30 11:53:22 +00007764 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007765 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00007766 && (*mb_off2cells)(off, max_off) == 1
7767 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007768 clear_next_cell = TRUE;
7769
7770 /* Make sure we never leave a second byte of a double-byte behind,
7771 * it confuses mb_off2cells(). */
7772 if (enc_dbcs
Bram Moolenaar367329b2007-08-30 11:53:22 +00007773 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007774 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00007775 && (*mb_off2cells)(off, max_off) == 1
7776 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007777 ScreenLines[off + mbyte_blen] = 0;
7778#endif
7779 ScreenLines[off] = c;
7780 ScreenAttrs[off] = attr;
7781#ifdef FEAT_MBYTE
7782 if (enc_utf8)
7783 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007784 if (c < 0x80 && u8cc[0] == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007785 ScreenLinesUC[off] = 0;
7786 else
7787 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007788 int i;
7789
Bram Moolenaar071d4272004-06-13 20:20:40 +00007790 ScreenLinesUC[off] = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007791 for (i = 0; i < Screen_mco; ++i)
7792 {
7793 ScreenLinesC[i][off] = u8cc[i];
7794 if (u8cc[i] == 0)
7795 break;
7796 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007797 }
7798 if (mbyte_cells == 2)
7799 {
7800 ScreenLines[off + 1] = 0;
7801 ScreenAttrs[off + 1] = attr;
7802 }
7803 screen_char(off, row, col);
7804 }
7805 else if (mbyte_cells == 2)
7806 {
7807 ScreenLines[off + 1] = ptr[1];
7808 ScreenAttrs[off + 1] = attr;
7809 screen_char_2(off, row, col);
7810 }
7811 else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7812 {
7813 ScreenLines2[off] = ptr[1];
7814 screen_char(off, row, col);
7815 }
7816 else
7817#endif
7818 screen_char(off, row, col);
7819 }
7820#ifdef FEAT_MBYTE
7821 if (has_mbyte)
7822 {
7823 off += mbyte_cells;
7824 col += mbyte_cells;
7825 ptr += mbyte_blen;
7826 if (clear_next_cell)
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007827 {
7828 /* This only happens at the end, display one space next. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007829 ptr = (char_u *)" ";
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007830 len = -1;
7831 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007832 }
7833 else
7834#endif
7835 {
7836 ++off;
7837 ++col;
7838 ++ptr;
7839 }
7840 }
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007841
7842#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7843 /* If we detected the next character needs to be redrawn, but the text
7844 * doesn't extend up to there, update the character here. */
7845 if (force_redraw_next && col < screen_Columns)
7846 {
7847# ifdef FEAT_MBYTE
7848 if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
7849 screen_char_2(off, row, col);
7850 else
7851# endif
7852 screen_char(off, row, col);
7853 }
7854#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007855}
7856
7857#ifdef FEAT_SEARCH_EXTRA
7858/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007859 * Prepare for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007860 */
7861 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007862start_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007863{
7864 if (p_hls && !no_hlsearch)
7865 {
7866 last_pat_prog(&search_hl.rm);
Bram Moolenaar8820b482017-03-16 17:23:31 +01007867 search_hl.attr = HL_ATTR(HLF_L);
Bram Moolenaar91a4e822008-01-19 14:59:58 +00007868# ifdef FEAT_RELTIME
7869 /* Set the time limit to 'redrawtime'. */
7870 profile_setlimit(p_rdt, &search_hl.tm);
7871# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007872 }
7873}
7874
7875/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007876 * Clean up for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007877 */
7878 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007879end_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007880{
7881 if (search_hl.rm.regprog != NULL)
7882 {
Bram Moolenaar473de612013-06-08 18:19:48 +02007883 vim_regfree(search_hl.rm.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007884 search_hl.rm.regprog = NULL;
7885 }
7886}
7887
7888/*
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +02007889 * Init for calling prepare_search_hl().
7890 */
7891 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007892init_search_hl(win_T *wp)
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +02007893{
7894 matchitem_T *cur;
7895
7896 /* Setup for match and 'hlsearch' highlighting. Disable any previous
7897 * match */
7898 cur = wp->w_match_head;
7899 while (cur != NULL)
7900 {
7901 cur->hl.rm = cur->match;
7902 if (cur->hlg_id == 0)
7903 cur->hl.attr = 0;
7904 else
7905 cur->hl.attr = syn_id2attr(cur->hlg_id);
7906 cur->hl.buf = wp->w_buffer;
7907 cur->hl.lnum = 0;
7908 cur->hl.first_lnum = 0;
7909# ifdef FEAT_RELTIME
7910 /* Set the time limit to 'redrawtime'. */
7911 profile_setlimit(p_rdt, &(cur->hl.tm));
7912# endif
7913 cur = cur->next;
7914 }
7915 search_hl.buf = wp->w_buffer;
7916 search_hl.lnum = 0;
7917 search_hl.first_lnum = 0;
7918 /* time limit is set at the toplevel, for all windows */
7919}
7920
7921/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007922 * Advance to the match in window "wp" line "lnum" or past it.
7923 */
7924 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007925prepare_search_hl(win_T *wp, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007926{
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007927 matchitem_T *cur; /* points to the match list */
7928 match_T *shl; /* points to search_hl or a match */
7929 int shl_flag; /* flag to indicate whether search_hl
7930 has been processed or not */
Bram Moolenaarb3414592014-06-17 17:48:32 +02007931 int pos_inprogress; /* marks that position match search is
7932 in progress */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007933 int n;
7934
7935 /*
7936 * When using a multi-line pattern, start searching at the top
7937 * of the window or just after a closed fold.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007938 * Do this both for search_hl and the match list.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007939 */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007940 cur = wp->w_match_head;
7941 shl_flag = FALSE;
7942 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007943 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007944 if (shl_flag == FALSE)
7945 {
7946 shl = &search_hl;
7947 shl_flag = TRUE;
7948 }
7949 else
7950 shl = &cur->hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007951 if (shl->rm.regprog != NULL
7952 && shl->lnum == 0
7953 && re_multiline(shl->rm.regprog))
7954 {
7955 if (shl->first_lnum == 0)
7956 {
7957# ifdef FEAT_FOLDING
7958 for (shl->first_lnum = lnum;
7959 shl->first_lnum > wp->w_topline; --shl->first_lnum)
7960 if (hasFoldingWin(wp, shl->first_lnum - 1,
7961 NULL, NULL, TRUE, NULL))
7962 break;
7963# else
7964 shl->first_lnum = wp->w_topline;
7965# endif
7966 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02007967 if (cur != NULL)
7968 cur->pos.cur = 0;
7969 pos_inprogress = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007970 n = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02007971 while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
7972 || (cur != NULL && pos_inprogress)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007973 {
Bram Moolenaare17bdff2016-08-27 18:34:29 +02007974 next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
7975 shl == &search_hl ? NULL : cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02007976 pos_inprogress = cur == NULL || cur->pos.cur == 0
7977 ? FALSE : TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007978 if (shl->lnum != 0)
7979 {
7980 shl->first_lnum = shl->lnum
7981 + shl->rm.endpos[0].lnum
7982 - shl->rm.startpos[0].lnum;
7983 n = shl->rm.endpos[0].col;
7984 }
7985 else
7986 {
7987 ++shl->first_lnum;
7988 n = 0;
7989 }
7990 }
7991 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007992 if (shl != &search_hl && cur != NULL)
7993 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007994 }
7995}
7996
7997/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007998 * Search for a next 'hlsearch' or match.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007999 * Uses shl->buf.
8000 * Sets shl->lnum and shl->rm contents.
8001 * Note: Assumes a previous match is always before "lnum", unless
8002 * shl->lnum is zero.
8003 * Careful: Any pointers for buffer lines will become invalid.
8004 */
8005 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008006next_search_hl(
8007 win_T *win,
8008 match_T *shl, /* points to search_hl or a match */
8009 linenr_T lnum,
8010 colnr_T mincol, /* minimal column for a match */
8011 matchitem_T *cur) /* to retrieve match positions if any */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008012{
8013 linenr_T l;
8014 colnr_T matchcol;
8015 long nmatched;
Bram Moolenaarbcf94422018-06-23 14:21:42 +02008016 int save_called_emsg = called_emsg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008017
Bram Moolenaarb0acacd2018-08-11 16:40:43 +02008018 // for :{range}s/pat only highlight inside the range
8019 if (lnum < search_first_line || lnum > search_last_line)
8020 {
8021 shl->lnum = 0;
8022 return;
8023 }
8024
Bram Moolenaar071d4272004-06-13 20:20:40 +00008025 if (shl->lnum != 0)
8026 {
8027 /* Check for three situations:
8028 * 1. If the "lnum" is below a previous match, start a new search.
8029 * 2. If the previous match includes "mincol", use it.
8030 * 3. Continue after the previous match.
8031 */
8032 l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
8033 if (lnum > l)
8034 shl->lnum = 0;
8035 else if (lnum < l || shl->rm.endpos[0].col > mincol)
8036 return;
8037 }
8038
8039 /*
8040 * Repeat searching for a match until one is found that includes "mincol"
8041 * or none is found in this line.
8042 */
8043 called_emsg = FALSE;
8044 for (;;)
8045 {
Bram Moolenaar91a4e822008-01-19 14:59:58 +00008046#ifdef FEAT_RELTIME
8047 /* Stop searching after passing the time limit. */
8048 if (profile_passed_limit(&(shl->tm)))
8049 {
8050 shl->lnum = 0; /* no match found in time */
8051 break;
8052 }
8053#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008054 /* Three situations:
8055 * 1. No useful previous match: search from start of line.
8056 * 2. Not Vi compatible or empty match: continue at next character.
8057 * Break the loop if this is beyond the end of the line.
8058 * 3. Vi compatible searching: continue at end of previous match.
8059 */
8060 if (shl->lnum == 0)
8061 matchcol = 0;
8062 else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
8063 || (shl->rm.endpos[0].lnum == 0
Bram Moolenaar32466aa2006-02-24 23:53:04 +00008064 && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008065 {
Bram Moolenaar5c8837f2006-02-25 21:52:33 +00008066 char_u *ml;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00008067
8068 matchcol = shl->rm.startpos[0].col;
Bram Moolenaar5c8837f2006-02-25 21:52:33 +00008069 ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00008070 if (*ml == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008071 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00008072 ++matchcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008073 shl->lnum = 0;
8074 break;
8075 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00008076#ifdef FEAT_MBYTE
8077 if (has_mbyte)
8078 matchcol += mb_ptr2len(ml);
8079 else
8080#endif
8081 ++matchcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008082 }
8083 else
8084 matchcol = shl->rm.endpos[0].col;
8085
8086 shl->lnum = lnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008087 if (shl->rm.regprog != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008088 {
Bram Moolenaarcbdf0a02014-11-27 13:37:10 +01008089 /* Remember whether shl->rm is using a copy of the regprog in
8090 * cur->match. */
8091 int regprog_is_copy = (shl != &search_hl && cur != NULL
8092 && shl == &cur->hl
8093 && cur->match.regprog == cur->hl.rm.regprog);
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02008094 int timed_out = FALSE;
Bram Moolenaarcbdf0a02014-11-27 13:37:10 +01008095
Bram Moolenaarb3414592014-06-17 17:48:32 +02008096 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
8097 matchcol,
8098#ifdef FEAT_RELTIME
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02008099 &(shl->tm), &timed_out
Bram Moolenaarb3414592014-06-17 17:48:32 +02008100#else
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02008101 NULL, NULL
Bram Moolenaarb3414592014-06-17 17:48:32 +02008102#endif
8103 );
Bram Moolenaarcbdf0a02014-11-27 13:37:10 +01008104 /* Copy the regprog, in case it got freed and recompiled. */
8105 if (regprog_is_copy)
8106 cur->match.regprog = cur->hl.rm.regprog;
8107
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02008108 if (called_emsg || got_int || timed_out)
Bram Moolenaar0ddf0a72007-05-01 20:04:53 +00008109 {
Bram Moolenaarb3414592014-06-17 17:48:32 +02008110 /* Error while handling regexp: stop using this regexp. */
8111 if (shl == &search_hl)
8112 {
8113 /* don't free regprog in the match list, it's a copy */
8114 vim_regfree(shl->rm.regprog);
Bram Moolenaar451fc7b2018-04-27 22:53:07 +02008115 set_no_hlsearch(TRUE);
Bram Moolenaarb3414592014-06-17 17:48:32 +02008116 }
8117 shl->rm.regprog = NULL;
8118 shl->lnum = 0;
8119 got_int = FALSE; /* avoid the "Type :quit to exit Vim"
8120 message */
8121 break;
Bram Moolenaar0ddf0a72007-05-01 20:04:53 +00008122 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02008123 }
8124 else if (cur != NULL)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008125 nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
Bram Moolenaardeae0f22014-06-18 21:20:11 +02008126 else
8127 nmatched = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008128 if (nmatched == 0)
8129 {
8130 shl->lnum = 0; /* no match found */
8131 break;
8132 }
8133 if (shl->rm.startpos[0].lnum > 0
8134 || shl->rm.startpos[0].col >= mincol
8135 || nmatched > 1
8136 || shl->rm.endpos[0].col > mincol)
8137 {
8138 shl->lnum += shl->rm.startpos[0].lnum;
8139 break; /* useful match found */
8140 }
8141 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +02008142
8143 // Restore called_emsg for assert_fails().
8144 called_emsg = save_called_emsg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008145}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008146
Bram Moolenaar85077472016-10-16 14:35:48 +02008147/*
8148 * If there is a match fill "shl" and return one.
8149 * Return zero otherwise.
8150 */
Bram Moolenaarb3414592014-06-17 17:48:32 +02008151 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01008152next_search_hl_pos(
8153 match_T *shl, /* points to a match */
8154 linenr_T lnum,
8155 posmatch_T *posmatch, /* match positions */
8156 colnr_T mincol) /* minimal column for a match */
Bram Moolenaarb3414592014-06-17 17:48:32 +02008157{
8158 int i;
Bram Moolenaar85077472016-10-16 14:35:48 +02008159 int found = -1;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008160
Bram Moolenaarb3414592014-06-17 17:48:32 +02008161 for (i = posmatch->cur; i < MAXPOSMATCH; i++)
8162 {
Bram Moolenaara6c27ee2016-10-15 14:56:30 +02008163 llpos_T *pos = &posmatch->pos[i];
8164
8165 if (pos->lnum == 0)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008166 break;
Bram Moolenaar85077472016-10-16 14:35:48 +02008167 if (pos->len == 0 && pos->col < mincol)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008168 continue;
Bram Moolenaara6c27ee2016-10-15 14:56:30 +02008169 if (pos->lnum == lnum)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008170 {
Bram Moolenaar85077472016-10-16 14:35:48 +02008171 if (found >= 0)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008172 {
Bram Moolenaar85077472016-10-16 14:35:48 +02008173 /* if this match comes before the one at "found" then swap
8174 * them */
8175 if (pos->col < posmatch->pos[found].col)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008176 {
Bram Moolenaara6c27ee2016-10-15 14:56:30 +02008177 llpos_T tmp = *pos;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008178
Bram Moolenaar85077472016-10-16 14:35:48 +02008179 *pos = posmatch->pos[found];
8180 posmatch->pos[found] = tmp;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008181 }
8182 }
8183 else
Bram Moolenaar85077472016-10-16 14:35:48 +02008184 found = i;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008185 }
8186 }
8187 posmatch->cur = 0;
Bram Moolenaar85077472016-10-16 14:35:48 +02008188 if (found >= 0)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008189 {
Bram Moolenaar85077472016-10-16 14:35:48 +02008190 colnr_T start = posmatch->pos[found].col == 0
8191 ? 0 : posmatch->pos[found].col - 1;
8192 colnr_T end = posmatch->pos[found].col == 0
8193 ? MAXCOL : start + posmatch->pos[found].len;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008194
Bram Moolenaar85077472016-10-16 14:35:48 +02008195 shl->lnum = lnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008196 shl->rm.startpos[0].lnum = 0;
8197 shl->rm.startpos[0].col = start;
8198 shl->rm.endpos[0].lnum = 0;
8199 shl->rm.endpos[0].col = end;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02008200 shl->is_addpos = TRUE;
Bram Moolenaar85077472016-10-16 14:35:48 +02008201 posmatch->cur = found + 1;
8202 return 1;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008203 }
Bram Moolenaar85077472016-10-16 14:35:48 +02008204 return 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008205}
Bram Moolenaarde993ea2014-06-17 23:18:01 +02008206#endif
Bram Moolenaarb3414592014-06-17 17:48:32 +02008207
Bram Moolenaar071d4272004-06-13 20:20:40 +00008208 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008209screen_start_highlight(int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008210{
8211 attrentry_T *aep = NULL;
8212
8213 screen_attr = attr;
8214 if (full_screen
8215#ifdef WIN3264
8216 && termcap_active
8217#endif
8218 )
8219 {
8220#ifdef FEAT_GUI
8221 if (gui.in_use)
8222 {
8223 char buf[20];
8224
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008225 /* The GUI handles this internally. */
8226 sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008227 OUT_STR(buf);
8228 }
8229 else
8230#endif
8231 {
8232 if (attr > HL_ALL) /* special HL attr. */
8233 {
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008234 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008235 aep = syn_cterm_attr2entry(attr);
8236 else
8237 aep = syn_term_attr2entry(attr);
8238 if (aep == NULL) /* did ":syntax clear" */
8239 attr = 0;
8240 else
8241 attr = aep->ae_attr;
8242 }
Bram Moolenaar45a00002017-12-22 21:12:34 +01008243 if ((attr & HL_BOLD) && *T_MD != NUL) /* bold */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008244 out_str(T_MD);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008245 else if (aep != NULL && cterm_normal_fg_bold && (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008246#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008247 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
8248 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
8249 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008250#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008251 t_colors > 1 && aep->ae_u.cterm.fg_color))
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008252 /* If the Normal FG color has BOLD attribute and the new HL
8253 * has a FG color defined, clear BOLD. */
8254 out_str(T_ME);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008255 if ((attr & HL_STANDOUT) && *T_SO != NUL) /* standout */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008256 out_str(T_SO);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008257 if ((attr & HL_UNDERCURL) && *T_UCS != NUL) /* undercurl */
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01008258 out_str(T_UCS);
8259 if (((attr & HL_UNDERLINE) /* underline or undercurl */
Bram Moolenaar45a00002017-12-22 21:12:34 +01008260 || ((attr & HL_UNDERCURL) && *T_UCS == NUL))
8261 && *T_US != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008262 out_str(T_US);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008263 if ((attr & HL_ITALIC) && *T_CZH != NUL) /* italic */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008264 out_str(T_CZH);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008265 if ((attr & HL_INVERSE) && *T_MR != NUL) /* inverse (reverse) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008266 out_str(T_MR);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008267 if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) /* strike */
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008268 out_str(T_STS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008269
8270 /*
8271 * Output the color or start string after bold etc., in case the
8272 * bold etc. override the color setting.
8273 */
8274 if (aep != NULL)
8275 {
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008276#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008277 /* When 'termguicolors' is set but fg or bg is unset,
8278 * fall back to the cterm colors. This helps for SpellBad,
8279 * where the GUI uses a red undercurl. */
8280 if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008281 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008282 if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008283 term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008284 }
8285 else
8286#endif
8287 if (t_colors > 1)
8288 {
8289 if (aep->ae_u.cterm.fg_color)
8290 term_fg_color(aep->ae_u.cterm.fg_color - 1);
8291 }
8292#ifdef FEAT_TERMGUICOLORS
8293 if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
8294 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008295 if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008296 term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008297 }
8298 else
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008299#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008300 if (t_colors > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008301 {
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008302 if (aep->ae_u.cterm.bg_color)
8303 term_bg_color(aep->ae_u.cterm.bg_color - 1);
8304 }
8305
Bram Moolenaarf708ac52018-03-12 21:48:32 +01008306 if (!IS_CTERM)
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008307 {
8308 if (aep->ae_u.term.start != NULL)
8309 out_str(aep->ae_u.term.start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008310 }
8311 }
8312 }
8313 }
8314}
8315
8316 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008317screen_stop_highlight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008318{
8319 int do_ME = FALSE; /* output T_ME code */
8320
8321 if (screen_attr != 0
8322#ifdef WIN3264
8323 && termcap_active
8324#endif
8325 )
8326 {
8327#ifdef FEAT_GUI
8328 if (gui.in_use)
8329 {
8330 char buf[20];
8331
8332 /* use internal GUI code */
8333 sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
8334 OUT_STR(buf);
8335 }
8336 else
8337#endif
8338 {
8339 if (screen_attr > HL_ALL) /* special HL attr. */
8340 {
8341 attrentry_T *aep;
8342
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008343 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008344 {
8345 /*
8346 * Assume that t_me restores the original colors!
8347 */
8348 aep = syn_cterm_attr2entry(screen_attr);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008349 if (aep != NULL && ((
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008350#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008351 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
8352 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
8353 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008354#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008355 aep->ae_u.cterm.fg_color) || (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008356#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008357 p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
8358 ? aep->ae_u.cterm.bg_rgb != INVALCOLOR
8359 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008360#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008361 aep->ae_u.cterm.bg_color)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008362 do_ME = TRUE;
8363 }
8364 else
8365 {
8366 aep = syn_term_attr2entry(screen_attr);
8367 if (aep != NULL && aep->ae_u.term.stop != NULL)
8368 {
8369 if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
8370 do_ME = TRUE;
8371 else
8372 out_str(aep->ae_u.term.stop);
8373 }
8374 }
8375 if (aep == NULL) /* did ":syntax clear" */
8376 screen_attr = 0;
8377 else
8378 screen_attr = aep->ae_attr;
8379 }
8380
8381 /*
8382 * Often all ending-codes are equal to T_ME. Avoid outputting the
8383 * same sequence several times.
8384 */
8385 if (screen_attr & HL_STANDOUT)
8386 {
8387 if (STRCMP(T_SE, T_ME) == 0)
8388 do_ME = TRUE;
8389 else
8390 out_str(T_SE);
8391 }
Bram Moolenaar45a00002017-12-22 21:12:34 +01008392 if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01008393 {
8394 if (STRCMP(T_UCE, T_ME) == 0)
8395 do_ME = TRUE;
8396 else
8397 out_str(T_UCE);
8398 }
8399 if ((screen_attr & HL_UNDERLINE)
Bram Moolenaar45a00002017-12-22 21:12:34 +01008400 || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008401 {
8402 if (STRCMP(T_UE, T_ME) == 0)
8403 do_ME = TRUE;
8404 else
8405 out_str(T_UE);
8406 }
8407 if (screen_attr & HL_ITALIC)
8408 {
8409 if (STRCMP(T_CZR, T_ME) == 0)
8410 do_ME = TRUE;
8411 else
8412 out_str(T_CZR);
8413 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008414 if (screen_attr & HL_STRIKETHROUGH)
8415 {
8416 if (STRCMP(T_STE, T_ME) == 0)
8417 do_ME = TRUE;
8418 else
8419 out_str(T_STE);
8420 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008421 if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
8422 out_str(T_ME);
8423
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008424#ifdef FEAT_TERMGUICOLORS
8425 if (p_tgc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008426 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008427 if (cterm_normal_fg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008428 term_fg_rgb_color(cterm_normal_fg_gui_color);
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008429 if (cterm_normal_bg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008430 term_bg_rgb_color(cterm_normal_bg_gui_color);
8431 }
8432 else
8433#endif
8434 {
8435 if (t_colors > 1)
8436 {
8437 /* set Normal cterm colors */
8438 if (cterm_normal_fg_color != 0)
8439 term_fg_color(cterm_normal_fg_color - 1);
8440 if (cterm_normal_bg_color != 0)
8441 term_bg_color(cterm_normal_bg_color - 1);
8442 if (cterm_normal_fg_bold)
8443 out_str(T_MD);
8444 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008445 }
8446 }
8447 }
8448 screen_attr = 0;
8449}
8450
8451/*
8452 * Reset the colors for a cterm. Used when leaving Vim.
8453 * The machine specific code may override this again.
8454 */
8455 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008456reset_cterm_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008457{
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008458 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008459 {
8460 /* set Normal cterm colors */
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008461#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008462 if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
8463 || cterm_normal_bg_gui_color != INVALCOLOR)
8464 : (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008465#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008466 if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008467#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008468 {
8469 out_str(T_OP);
8470 screen_attr = -1;
8471 }
8472 if (cterm_normal_fg_bold)
8473 {
8474 out_str(T_ME);
8475 screen_attr = -1;
8476 }
8477 }
8478}
8479
8480/*
8481 * Put character ScreenLines["off"] on the screen at position "row" and "col",
8482 * using the attributes from ScreenAttrs["off"].
8483 */
8484 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008485screen_char(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008486{
8487 int attr;
8488
8489 /* Check for illegal values, just in case (could happen just after
8490 * resizing). */
8491 if (row >= screen_Rows || col >= screen_Columns)
8492 return;
8493
Bram Moolenaar494838a2015-02-10 19:20:37 +01008494 /* Outputting a character in the last cell on the screen may scroll the
8495 * screen up. Only do it when the "xn" termcap property is set, otherwise
8496 * mark the character invalid (update it when scrolled up). */
8497 if (*T_XN == NUL
8498 && row == screen_Rows - 1 && col == screen_Columns - 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00008499#ifdef FEAT_RIGHTLEFT
8500 /* account for first command-line character in rightleft mode */
8501 && !cmdmsg_rl
8502#endif
8503 )
8504 {
8505 ScreenAttrs[off] = (sattr_T)-1;
8506 return;
8507 }
8508
8509 /*
8510 * Stop highlighting first, so it's easier to move the cursor.
8511 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008512 if (screen_char_attr != 0)
8513 attr = screen_char_attr;
8514 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008515 attr = ScreenAttrs[off];
8516 if (screen_attr != attr)
8517 screen_stop_highlight();
8518
8519 windgoto(row, col);
8520
8521 if (screen_attr != attr)
8522 screen_start_highlight(attr);
8523
8524#ifdef FEAT_MBYTE
8525 if (enc_utf8 && ScreenLinesUC[off] != 0)
8526 {
8527 char_u buf[MB_MAXBYTES + 1];
8528
Bram Moolenaarcb070082016-04-02 22:14:51 +02008529 if (utf_ambiguous_width(ScreenLinesUC[off]))
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008530 {
8531 if (*p_ambw == 'd'
8532# ifdef FEAT_GUI
8533 && !gui.in_use
8534# endif
8535 )
8536 {
8537 /* Clear the two screen cells. If the character is actually
8538 * single width it won't change the second cell. */
8539 out_str((char_u *)" ");
8540 term_windgoto(row, col);
8541 }
8542 /* not sure where the cursor is after drawing the ambiguous width
8543 * character */
Bram Moolenaarcb070082016-04-02 22:14:51 +02008544 screen_cur_col = 9999;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008545 }
Bram Moolenaarcb070082016-04-02 22:14:51 +02008546 else if (utf_char2cells(ScreenLinesUC[off]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008547 ++screen_cur_col;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008548
8549 /* Convert the UTF-8 character to bytes and write it. */
8550 buf[utfc_char2bytes(off, buf)] = NUL;
8551 out_str(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008552 }
8553 else
8554#endif
8555 {
8556#ifdef FEAT_MBYTE
8557 out_flush_check();
8558#endif
8559 out_char(ScreenLines[off]);
8560#ifdef FEAT_MBYTE
8561 /* double-byte character in single-width cell */
8562 if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
8563 out_char(ScreenLines2[off]);
8564#endif
8565 }
8566
8567 screen_cur_col++;
8568}
8569
8570#ifdef FEAT_MBYTE
8571
8572/*
8573 * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
8574 * on the screen at position 'row' and 'col'.
8575 * The attributes of the first byte is used for all. This is required to
8576 * output the two bytes of a double-byte character with nothing in between.
8577 */
8578 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008579screen_char_2(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008580{
8581 /* Check for illegal values (could be wrong when screen was resized). */
8582 if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
8583 return;
8584
8585 /* Outputting the last character on the screen may scrollup the screen.
8586 * Don't to it! Mark the character invalid (update it when scrolled up) */
8587 if (row == screen_Rows - 1 && col >= screen_Columns - 2)
8588 {
8589 ScreenAttrs[off] = (sattr_T)-1;
8590 return;
8591 }
8592
8593 /* Output the first byte normally (positions the cursor), then write the
8594 * second byte directly. */
8595 screen_char(off, row, col);
8596 out_char(ScreenLines[off + 1]);
8597 ++screen_cur_col;
8598}
8599#endif
8600
Bram Moolenaar071d4272004-06-13 20:20:40 +00008601/*
8602 * Draw a rectangle of the screen, inverted when "invert" is TRUE.
8603 * This uses the contents of ScreenLines[] and doesn't change it.
8604 */
8605 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008606screen_draw_rectangle(
8607 int row,
8608 int col,
8609 int height,
8610 int width,
8611 int invert)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008612{
8613 int r, c;
8614 int off;
Bram Moolenaar367329b2007-08-30 11:53:22 +00008615#ifdef FEAT_MBYTE
8616 int max_off;
8617#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008618
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008619 /* Can't use ScreenLines unless initialized */
8620 if (ScreenLines == NULL)
8621 return;
8622
Bram Moolenaar071d4272004-06-13 20:20:40 +00008623 if (invert)
8624 screen_char_attr = HL_INVERSE;
8625 for (r = row; r < row + height; ++r)
8626 {
8627 off = LineOffset[r];
Bram Moolenaar367329b2007-08-30 11:53:22 +00008628#ifdef FEAT_MBYTE
8629 max_off = off + screen_Columns;
8630#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008631 for (c = col; c < col + width; ++c)
8632 {
8633#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00008634 if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008635 {
8636 screen_char_2(off + c, r, c);
8637 ++c;
8638 }
8639 else
8640#endif
8641 {
8642 screen_char(off + c, r, c);
8643#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00008644 if (utf_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008645 ++c;
8646#endif
8647 }
8648 }
8649 }
8650 screen_char_attr = 0;
8651}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008652
Bram Moolenaar071d4272004-06-13 20:20:40 +00008653/*
8654 * Redraw the characters for a vertically split window.
8655 */
8656 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008657redraw_block(int row, int end, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008658{
8659 int col;
8660 int width;
8661
8662# ifdef FEAT_CLIPBOARD
8663 clip_may_clear_selection(row, end - 1);
8664# endif
8665
8666 if (wp == NULL)
8667 {
8668 col = 0;
8669 width = Columns;
8670 }
8671 else
8672 {
8673 col = wp->w_wincol;
8674 width = wp->w_width;
8675 }
8676 screen_draw_rectangle(row, col, end - row, width, FALSE);
8677}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008678
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008679 static void
8680space_to_screenline(int off, int attr)
8681{
8682 ScreenLines[off] = ' ';
8683 ScreenAttrs[off] = attr;
8684# ifdef FEAT_MBYTE
8685 if (enc_utf8)
8686 ScreenLinesUC[off] = 0;
8687# endif
8688}
8689
Bram Moolenaar071d4272004-06-13 20:20:40 +00008690/*
8691 * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
8692 * with character 'c1' in first column followed by 'c2' in the other columns.
8693 * Use attributes 'attr'.
8694 */
8695 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008696screen_fill(
8697 int start_row,
8698 int end_row,
8699 int start_col,
8700 int end_col,
8701 int c1,
8702 int c2,
8703 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008704{
8705 int row;
8706 int col;
8707 int off;
8708 int end_off;
8709 int did_delete;
8710 int c;
8711 int norm_term;
8712#if defined(FEAT_GUI) || defined(UNIX)
8713 int force_next = FALSE;
8714#endif
8715
8716 if (end_row > screen_Rows) /* safety check */
8717 end_row = screen_Rows;
8718 if (end_col > screen_Columns) /* safety check */
8719 end_col = screen_Columns;
8720 if (ScreenLines == NULL
8721 || start_row >= end_row
8722 || start_col >= end_col) /* nothing to do */
8723 return;
8724
8725 /* it's a "normal" terminal when not in a GUI or cterm */
8726 norm_term = (
8727#ifdef FEAT_GUI
8728 !gui.in_use &&
8729#endif
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008730 !IS_CTERM);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008731 for (row = start_row; row < end_row; ++row)
8732 {
Bram Moolenaarc236c162008-07-13 17:41:49 +00008733#ifdef FEAT_MBYTE
8734 if (has_mbyte
8735# ifdef FEAT_GUI
8736 && !gui.in_use
8737# endif
8738 )
8739 {
8740 /* When drawing over the right halve of a double-wide char clear
8741 * out the left halve. When drawing over the left halve of a
8742 * double wide-char clear out the right halve. Only needed in a
8743 * terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00008744 if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00008745 screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
Bram Moolenaara1aed622008-07-18 15:14:43 +00008746 if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00008747 screen_puts_len((char_u *)" ", 1, row, end_col, 0);
Bram Moolenaarc236c162008-07-13 17:41:49 +00008748 }
8749#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008750 /*
8751 * Try to use delete-line termcap code, when no attributes or in a
8752 * "normal" terminal, where a bold/italic space is just a
8753 * space.
8754 */
8755 did_delete = FALSE;
8756 if (c2 == ' '
8757 && end_col == Columns
8758 && can_clear(T_CE)
8759 && (attr == 0
8760 || (norm_term
8761 && attr <= HL_ALL
8762 && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
8763 {
8764 /*
8765 * check if we really need to clear something
8766 */
8767 col = start_col;
8768 if (c1 != ' ') /* don't clear first char */
8769 ++col;
8770
8771 off = LineOffset[row] + col;
8772 end_off = LineOffset[row] + end_col;
8773
8774 /* skip blanks (used often, keep it fast!) */
8775#ifdef FEAT_MBYTE
8776 if (enc_utf8)
8777 while (off < end_off && ScreenLines[off] == ' '
8778 && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
8779 ++off;
8780 else
8781#endif
8782 while (off < end_off && ScreenLines[off] == ' '
8783 && ScreenAttrs[off] == 0)
8784 ++off;
8785 if (off < end_off) /* something to be cleared */
8786 {
8787 col = off - LineOffset[row];
8788 screen_stop_highlight();
8789 term_windgoto(row, col);/* clear rest of this screen line */
8790 out_str(T_CE);
8791 screen_start(); /* don't know where cursor is now */
8792 col = end_col - col;
8793 while (col--) /* clear chars in ScreenLines */
8794 {
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008795 space_to_screenline(off, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008796 ++off;
8797 }
8798 }
8799 did_delete = TRUE; /* the chars are cleared now */
8800 }
8801
8802 off = LineOffset[row] + start_col;
8803 c = c1;
8804 for (col = start_col; col < end_col; ++col)
8805 {
8806 if (ScreenLines[off] != c
8807#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008808 || (enc_utf8 && (int)ScreenLinesUC[off]
8809 != (c >= 0x80 ? c : 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008810#endif
8811 || ScreenAttrs[off] != attr
8812#if defined(FEAT_GUI) || defined(UNIX)
8813 || force_next
8814#endif
8815 )
8816 {
8817#if defined(FEAT_GUI) || defined(UNIX)
8818 /* The bold trick may make a single row of pixels appear in
8819 * the next character. When a bold character is removed, the
8820 * next character should be redrawn too. This happens for our
8821 * own GUI and for some xterms. */
8822 if (
8823# ifdef FEAT_GUI
8824 gui.in_use
8825# endif
8826# if defined(FEAT_GUI) && defined(UNIX)
8827 ||
8828# endif
8829# ifdef UNIX
8830 term_is_xterm
8831# endif
8832 )
8833 {
8834 if (ScreenLines[off] != ' '
8835 && (ScreenAttrs[off] > HL_ALL
8836 || ScreenAttrs[off] & HL_BOLD))
8837 force_next = TRUE;
8838 else
8839 force_next = FALSE;
8840 }
8841#endif
8842 ScreenLines[off] = c;
8843#ifdef FEAT_MBYTE
8844 if (enc_utf8)
8845 {
8846 if (c >= 0x80)
8847 {
8848 ScreenLinesUC[off] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008849 ScreenLinesC[0][off] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008850 }
8851 else
8852 ScreenLinesUC[off] = 0;
8853 }
8854#endif
8855 ScreenAttrs[off] = attr;
8856 if (!did_delete || c != ' ')
8857 screen_char(off, row, col);
8858 }
8859 ++off;
8860 if (col == start_col)
8861 {
8862 if (did_delete)
8863 break;
8864 c = c2;
8865 }
8866 }
8867 if (end_col == Columns)
8868 LineWraps[row] = FALSE;
8869 if (row == Rows - 1) /* overwritten the command line */
8870 {
8871 redraw_cmdline = TRUE;
Bram Moolenaar5bab5552018-04-13 20:41:29 +02008872 if (start_col == 0 && end_col == Columns
8873 && c1 == ' ' && c2 == ' ' && attr == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008874 clear_cmdline = FALSE; /* command line has been cleared */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00008875 if (start_col == 0)
8876 mode_displayed = FALSE; /* mode cleared or overwritten */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008877 }
8878 }
8879}
8880
8881/*
8882 * Check if there should be a delay. Used before clearing or redrawing the
8883 * screen or the command line.
8884 */
8885 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008886check_for_delay(int check_msg_scroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008887{
8888 if ((emsg_on_display || (check_msg_scroll && msg_scroll))
8889 && !did_wait_return
8890 && emsg_silent == 0)
8891 {
8892 out_flush();
8893 ui_delay(1000L, TRUE);
8894 emsg_on_display = FALSE;
8895 if (check_msg_scroll)
8896 msg_scroll = FALSE;
8897 }
8898}
8899
8900/*
8901 * screen_valid - allocate screen buffers if size changed
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008902 * If "doclear" is TRUE: clear screen if it has been resized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008903 * Returns TRUE if there is a valid screen to write to.
8904 * Returns FALSE when starting up and screen not initialized yet.
8905 */
8906 int
Bram Moolenaar05540972016-01-30 20:31:25 +01008907screen_valid(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008908{
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008909 screenalloc(doclear); /* allocate screen buffers if size changed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008910 return (ScreenLines != NULL);
8911}
8912
8913/*
8914 * Resize the shell to Rows and Columns.
8915 * Allocate ScreenLines[] and associated items.
8916 *
8917 * There may be some time between setting Rows and Columns and (re)allocating
8918 * ScreenLines[]. This happens when starting up and when (manually) changing
8919 * the shell size. Always use screen_Rows and screen_Columns to access items
8920 * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
8921 * final size of the shell is needed.
8922 */
8923 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008924screenalloc(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008925{
8926 int new_row, old_row;
8927#ifdef FEAT_GUI
8928 int old_Rows;
8929#endif
8930 win_T *wp;
8931 int outofmem = FALSE;
8932 int len;
8933 schar_T *new_ScreenLines;
8934#ifdef FEAT_MBYTE
8935 u8char_T *new_ScreenLinesUC = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008936 u8char_T *new_ScreenLinesC[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008937 schar_T *new_ScreenLines2 = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008938 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008939#endif
8940 sattr_T *new_ScreenAttrs;
8941 unsigned *new_LineOffset;
8942 char_u *new_LineWraps;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008943 short *new_TabPageIdxs;
Bram Moolenaarf740b292006-02-16 22:11:02 +00008944 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008945 static int entered = FALSE; /* avoid recursiveness */
Bram Moolenaar89d40322006-08-29 15:30:07 +00008946 static int done_outofmem_msg = FALSE; /* did outofmem message */
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008947 int retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008948
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008949retry:
Bram Moolenaar071d4272004-06-13 20:20:40 +00008950 /*
8951 * Allocation of the screen buffers is done only when the size changes and
8952 * when Rows and Columns have been set and we have started doing full
8953 * screen stuff.
8954 */
8955 if ((ScreenLines != NULL
8956 && Rows == screen_Rows
8957 && Columns == screen_Columns
8958#ifdef FEAT_MBYTE
8959 && enc_utf8 == (ScreenLinesUC != NULL)
8960 && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008961 && p_mco == Screen_mco
Bram Moolenaar071d4272004-06-13 20:20:40 +00008962#endif
8963 )
8964 || Rows == 0
8965 || Columns == 0
8966 || (!full_screen && ScreenLines == NULL))
8967 return;
8968
8969 /*
8970 * It's possible that we produce an out-of-memory message below, which
8971 * will cause this function to be called again. To break the loop, just
8972 * return here.
8973 */
8974 if (entered)
8975 return;
8976 entered = TRUE;
8977
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00008978 /*
8979 * Note that the window sizes are updated before reallocating the arrays,
8980 * thus we must not redraw here!
8981 */
8982 ++RedrawingDisabled;
8983
Bram Moolenaar071d4272004-06-13 20:20:40 +00008984 win_new_shellsize(); /* fit the windows in the new sized shell */
8985
Bram Moolenaar071d4272004-06-13 20:20:40 +00008986 comp_col(); /* recompute columns for shown command and ruler */
8987
8988 /*
8989 * We're changing the size of the screen.
8990 * - Allocate new arrays for ScreenLines and ScreenAttrs.
8991 * - Move lines from the old arrays into the new arrays, clear extra
8992 * lines (unless the screen is going to be cleared).
8993 * - Free the old arrays.
8994 *
8995 * If anything fails, make ScreenLines NULL, so we don't do anything!
8996 * Continuing with the old ScreenLines may result in a crash, because the
8997 * size is wrong.
8998 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00008999 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009000 win_free_lsize(wp);
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00009001 if (aucmd_win != NULL)
9002 win_free_lsize(aucmd_win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009003
9004 new_ScreenLines = (schar_T *)lalloc((long_u)(
9005 (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
9006#ifdef FEAT_MBYTE
Bram Moolenaar216b7102010-03-23 13:56:59 +01009007 vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009008 if (enc_utf8)
9009 {
9010 new_ScreenLinesUC = (u8char_T *)lalloc((long_u)(
9011 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009012 for (i = 0; i < p_mco; ++i)
Bram Moolenaar70c49c12010-03-23 15:36:35 +01009013 new_ScreenLinesC[i] = (u8char_T *)lalloc_clear((long_u)(
Bram Moolenaar071d4272004-06-13 20:20:40 +00009014 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
9015 }
9016 if (enc_dbcs == DBCS_JPNU)
9017 new_ScreenLines2 = (schar_T *)lalloc((long_u)(
9018 (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
9019#endif
9020 new_ScreenAttrs = (sattr_T *)lalloc((long_u)(
9021 (Rows + 1) * Columns * sizeof(sattr_T)), FALSE);
9022 new_LineOffset = (unsigned *)lalloc((long_u)(
9023 Rows * sizeof(unsigned)), FALSE);
9024 new_LineWraps = (char_u *)lalloc((long_u)(Rows * sizeof(char_u)), FALSE);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00009025 new_TabPageIdxs = (short *)lalloc((long_u)(Columns * sizeof(short)), FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009026
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009027 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009028 {
9029 if (win_alloc_lines(wp) == FAIL)
9030 {
9031 outofmem = TRUE;
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00009032 goto give_up;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009033 }
9034 }
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00009035 if (aucmd_win != NULL && aucmd_win->w_lines == NULL
9036 && win_alloc_lines(aucmd_win) == FAIL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009037 outofmem = TRUE;
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00009038give_up:
Bram Moolenaar071d4272004-06-13 20:20:40 +00009039
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009040#ifdef FEAT_MBYTE
9041 for (i = 0; i < p_mco; ++i)
9042 if (new_ScreenLinesC[i] == NULL)
9043 break;
9044#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009045 if (new_ScreenLines == NULL
9046#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009047 || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009048 || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
9049#endif
9050 || new_ScreenAttrs == NULL
9051 || new_LineOffset == NULL
9052 || new_LineWraps == NULL
Bram Moolenaarf740b292006-02-16 22:11:02 +00009053 || new_TabPageIdxs == NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00009054 || outofmem)
9055 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00009056 if (ScreenLines != NULL || !done_outofmem_msg)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00009057 {
9058 /* guess the size */
9059 do_outofmem_msg((long_u)((Rows + 1) * Columns));
9060
9061 /* Remember we did this to avoid getting outofmem messages over
9062 * and over again. */
Bram Moolenaar89d40322006-08-29 15:30:07 +00009063 done_outofmem_msg = TRUE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00009064 }
Bram Moolenaard23a8232018-02-10 18:45:26 +01009065 VIM_CLEAR(new_ScreenLines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009066#ifdef FEAT_MBYTE
Bram Moolenaard23a8232018-02-10 18:45:26 +01009067 VIM_CLEAR(new_ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009068 for (i = 0; i < p_mco; ++i)
Bram Moolenaard23a8232018-02-10 18:45:26 +01009069 VIM_CLEAR(new_ScreenLinesC[i]);
9070 VIM_CLEAR(new_ScreenLines2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009071#endif
Bram Moolenaard23a8232018-02-10 18:45:26 +01009072 VIM_CLEAR(new_ScreenAttrs);
9073 VIM_CLEAR(new_LineOffset);
9074 VIM_CLEAR(new_LineWraps);
9075 VIM_CLEAR(new_TabPageIdxs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009076 }
9077 else
9078 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00009079 done_outofmem_msg = FALSE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00009080
Bram Moolenaar071d4272004-06-13 20:20:40 +00009081 for (new_row = 0; new_row < Rows; ++new_row)
9082 {
9083 new_LineOffset[new_row] = new_row * Columns;
9084 new_LineWraps[new_row] = FALSE;
9085
9086 /*
9087 * If the screen is not going to be cleared, copy as much as
9088 * possible from the old screen to the new one and clear the rest
9089 * (used when resizing the window at the "--more--" prompt or when
9090 * executing an external command, for the GUI).
9091 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01009092 if (!doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009093 {
9094 (void)vim_memset(new_ScreenLines + new_row * Columns,
9095 ' ', (size_t)Columns * sizeof(schar_T));
9096#ifdef FEAT_MBYTE
9097 if (enc_utf8)
9098 {
9099 (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
9100 0, (size_t)Columns * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009101 for (i = 0; i < p_mco; ++i)
9102 (void)vim_memset(new_ScreenLinesC[i]
9103 + new_row * Columns,
Bram Moolenaar071d4272004-06-13 20:20:40 +00009104 0, (size_t)Columns * sizeof(u8char_T));
9105 }
9106 if (enc_dbcs == DBCS_JPNU)
9107 (void)vim_memset(new_ScreenLines2 + new_row * Columns,
9108 0, (size_t)Columns * sizeof(schar_T));
9109#endif
9110 (void)vim_memset(new_ScreenAttrs + new_row * Columns,
9111 0, (size_t)Columns * sizeof(sattr_T));
9112 old_row = new_row + (screen_Rows - Rows);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00009113 if (old_row >= 0 && ScreenLines != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009114 {
9115 if (screen_Columns < Columns)
9116 len = screen_Columns;
9117 else
9118 len = Columns;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00009119#ifdef FEAT_MBYTE
Bram Moolenaarf4d11452005-12-02 00:46:37 +00009120 /* When switching to utf-8 don't copy characters, they
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009121 * may be invalid now. Also when p_mco changes. */
9122 if (!(enc_utf8 && ScreenLinesUC == NULL)
9123 && p_mco == Screen_mco)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00009124#endif
9125 mch_memmove(new_ScreenLines + new_LineOffset[new_row],
9126 ScreenLines + LineOffset[old_row],
9127 (size_t)len * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00009128#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009129 if (enc_utf8 && ScreenLinesUC != NULL
9130 && p_mco == Screen_mco)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009131 {
9132 mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
9133 ScreenLinesUC + LineOffset[old_row],
9134 (size_t)len * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009135 for (i = 0; i < p_mco; ++i)
9136 mch_memmove(new_ScreenLinesC[i]
9137 + new_LineOffset[new_row],
9138 ScreenLinesC[i] + LineOffset[old_row],
Bram Moolenaar071d4272004-06-13 20:20:40 +00009139 (size_t)len * sizeof(u8char_T));
9140 }
9141 if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
9142 mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
9143 ScreenLines2 + LineOffset[old_row],
9144 (size_t)len * sizeof(schar_T));
9145#endif
9146 mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
9147 ScreenAttrs + LineOffset[old_row],
9148 (size_t)len * sizeof(sattr_T));
9149 }
9150 }
9151 }
9152 /* Use the last line of the screen for the current line. */
9153 current_ScreenLine = new_ScreenLines + Rows * Columns;
9154 }
9155
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009156 free_screenlines();
9157
Bram Moolenaar071d4272004-06-13 20:20:40 +00009158 ScreenLines = new_ScreenLines;
9159#ifdef FEAT_MBYTE
9160 ScreenLinesUC = new_ScreenLinesUC;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009161 for (i = 0; i < p_mco; ++i)
9162 ScreenLinesC[i] = new_ScreenLinesC[i];
9163 Screen_mco = p_mco;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009164 ScreenLines2 = new_ScreenLines2;
9165#endif
9166 ScreenAttrs = new_ScreenAttrs;
9167 LineOffset = new_LineOffset;
9168 LineWraps = new_LineWraps;
Bram Moolenaarf740b292006-02-16 22:11:02 +00009169 TabPageIdxs = new_TabPageIdxs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009170
9171 /* It's important that screen_Rows and screen_Columns reflect the actual
9172 * size of ScreenLines[]. Set them before calling anything. */
9173#ifdef FEAT_GUI
9174 old_Rows = screen_Rows;
9175#endif
9176 screen_Rows = Rows;
9177 screen_Columns = Columns;
9178
9179 must_redraw = CLEAR; /* need to clear the screen later */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01009180 if (doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009181 screenclear2();
9182
9183#ifdef FEAT_GUI
9184 else if (gui.in_use
9185 && !gui.starting
9186 && ScreenLines != NULL
9187 && old_Rows != Rows)
9188 {
9189 (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
9190 /*
9191 * Adjust the position of the cursor, for when executing an external
9192 * command.
9193 */
9194 if (msg_row >= Rows) /* Rows got smaller */
9195 msg_row = Rows - 1; /* put cursor at last row */
9196 else if (Rows > old_Rows) /* Rows got bigger */
9197 msg_row += Rows - old_Rows; /* put cursor in same place */
9198 if (msg_col >= Columns) /* Columns got smaller */
9199 msg_col = Columns - 1; /* put cursor at last column */
9200 }
9201#endif
9202
Bram Moolenaar071d4272004-06-13 20:20:40 +00009203 entered = FALSE;
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00009204 --RedrawingDisabled;
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00009205
Bram Moolenaar87e817c2009-02-22 20:13:39 +00009206 /*
9207 * Do not apply autocommands more than 3 times to avoid an endless loop
9208 * in case applying autocommands always changes Rows or Columns.
9209 */
9210 if (starting == 0 && ++retry_count <= 3)
9211 {
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00009212 apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar87e817c2009-02-22 20:13:39 +00009213 /* In rare cases, autocommands may have altered Rows or Columns,
9214 * jump back to check if we need to allocate the screen again. */
9215 goto retry;
9216 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009217}
9218
9219 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009220free_screenlines(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009221{
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009222#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009223 int i;
9224
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009225 vim_free(ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009226 for (i = 0; i < Screen_mco; ++i)
9227 vim_free(ScreenLinesC[i]);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009228 vim_free(ScreenLines2);
9229#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009230 vim_free(ScreenLines);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009231 vim_free(ScreenAttrs);
9232 vim_free(LineOffset);
9233 vim_free(LineWraps);
Bram Moolenaarf740b292006-02-16 22:11:02 +00009234 vim_free(TabPageIdxs);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009235}
9236
9237 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009238screenclear(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009239{
9240 check_for_delay(FALSE);
9241 screenalloc(FALSE); /* allocate screen buffers if size changed */
9242 screenclear2(); /* clear the screen */
9243}
9244
9245 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009246screenclear2(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009247{
9248 int i;
9249
9250 if (starting == NO_SCREEN || ScreenLines == NULL
9251#ifdef FEAT_GUI
9252 || (gui.in_use && gui.starting)
9253#endif
9254 )
9255 return;
9256
9257#ifdef FEAT_GUI
9258 if (!gui.in_use)
9259#endif
9260 screen_attr = -1; /* force setting the Normal colors */
9261 screen_stop_highlight(); /* don't want highlighting here */
9262
9263#ifdef FEAT_CLIPBOARD
9264 /* disable selection without redrawing it */
9265 clip_scroll_selection(9999);
9266#endif
9267
9268 /* blank out ScreenLines */
9269 for (i = 0; i < Rows; ++i)
9270 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009271 lineclear(LineOffset[i], (int)Columns, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009272 LineWraps[i] = FALSE;
9273 }
9274
9275 if (can_clear(T_CL))
9276 {
9277 out_str(T_CL); /* clear the display */
9278 clear_cmdline = FALSE;
Bram Moolenaard12f5c12006-01-25 22:10:52 +00009279 mode_displayed = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009280 }
9281 else
9282 {
9283 /* can't clear the screen, mark all chars with invalid attributes */
9284 for (i = 0; i < Rows; ++i)
9285 lineinvalid(LineOffset[i], (int)Columns);
9286 clear_cmdline = TRUE;
9287 }
9288
9289 screen_cleared = TRUE; /* can use contents of ScreenLines now */
9290
9291 win_rest_invalid(firstwin);
9292 redraw_cmdline = TRUE;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00009293 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009294 if (must_redraw == CLEAR) /* no need to clear again */
9295 must_redraw = NOT_VALID;
9296 compute_cmdrow();
9297 msg_row = cmdline_row; /* put cursor on last line for messages */
9298 msg_col = 0;
9299 screen_start(); /* don't know where cursor is now */
9300 msg_scrolled = 0; /* can't scroll back */
9301 msg_didany = FALSE;
9302 msg_didout = FALSE;
9303}
9304
9305/*
9306 * Clear one line in ScreenLines.
9307 */
9308 static void
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009309lineclear(unsigned off, int width, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009310{
9311 (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
9312#ifdef FEAT_MBYTE
9313 if (enc_utf8)
9314 (void)vim_memset(ScreenLinesUC + off, 0,
9315 (size_t)width * sizeof(u8char_T));
9316#endif
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009317 (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00009318}
9319
9320/*
9321 * Mark one line in ScreenLines invalid by setting the attributes to an
9322 * invalid value.
9323 */
9324 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009325lineinvalid(unsigned off, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009326{
9327 (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
9328}
9329
Bram Moolenaar071d4272004-06-13 20:20:40 +00009330/*
9331 * Copy part of a Screenline for vertically split window "wp".
9332 */
9333 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009334linecopy(int to, int from, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009335{
9336 unsigned off_to = LineOffset[to] + wp->w_wincol;
9337 unsigned off_from = LineOffset[from] + wp->w_wincol;
9338
9339 mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
9340 wp->w_width * sizeof(schar_T));
Bram Moolenaar4033c552017-09-16 20:54:51 +02009341#ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00009342 if (enc_utf8)
9343 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009344 int i;
9345
Bram Moolenaar071d4272004-06-13 20:20:40 +00009346 mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
9347 wp->w_width * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009348 for (i = 0; i < p_mco; ++i)
9349 mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
9350 wp->w_width * sizeof(u8char_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00009351 }
9352 if (enc_dbcs == DBCS_JPNU)
9353 mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
9354 wp->w_width * sizeof(schar_T));
Bram Moolenaar4033c552017-09-16 20:54:51 +02009355#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009356 mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
9357 wp->w_width * sizeof(sattr_T));
9358}
Bram Moolenaar071d4272004-06-13 20:20:40 +00009359
9360/*
9361 * Return TRUE if clearing with term string "p" would work.
9362 * It can't work when the string is empty or it won't set the right background.
9363 */
9364 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009365can_clear(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009366{
9367 return (*p != NUL && (t_colors <= 1
9368#ifdef FEAT_GUI
9369 || gui.in_use
9370#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +02009371#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02009372 || (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
Bram Moolenaard18f6722016-06-17 13:18:49 +02009373 || (!p_tgc && cterm_normal_bg_color == 0)
9374#else
9375 || cterm_normal_bg_color == 0
Bram Moolenaar8a633e32016-04-21 21:10:14 +02009376#endif
Bram Moolenaard18f6722016-06-17 13:18:49 +02009377 || *T_UT != NUL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00009378}
9379
9380/*
9381 * Reset cursor position. Use whenever cursor was moved because of outputting
9382 * something directly to the screen (shell commands) or a terminal control
9383 * code.
9384 */
9385 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009386screen_start(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009387{
9388 screen_cur_row = screen_cur_col = 9999;
9389}
9390
9391/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00009392 * Move the cursor to position "row","col" in the screen.
9393 * This tries to find the most efficient way to move, minimizing the number of
9394 * characters sent to the terminal.
9395 */
9396 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009397windgoto(int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009398{
Bram Moolenaare2cc9702005-03-15 22:43:58 +00009399 sattr_T *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009400 int i;
9401 int plan;
9402 int cost;
9403 int wouldbe_col;
9404 int noinvcurs;
9405 char_u *bs;
9406 int goto_cost;
9407 int attr;
9408
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00009409#define GOTO_COST 7 /* assume a term_windgoto() takes about 7 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009410#define HIGHL_COST 5 /* assume unhighlight takes 5 chars */
9411
9412#define PLAN_LE 1
9413#define PLAN_CR 2
9414#define PLAN_NL 3
9415#define PLAN_WRITE 4
9416 /* Can't use ScreenLines unless initialized */
9417 if (ScreenLines == NULL)
9418 return;
9419
9420 if (col != screen_cur_col || row != screen_cur_row)
9421 {
9422 /* Check for valid position. */
9423 if (row < 0) /* window without text lines? */
9424 row = 0;
9425 if (row >= screen_Rows)
9426 row = screen_Rows - 1;
9427 if (col >= screen_Columns)
9428 col = screen_Columns - 1;
9429
9430 /* check if no cursor movement is allowed in highlight mode */
9431 if (screen_attr && *T_MS == NUL)
9432 noinvcurs = HIGHL_COST;
9433 else
9434 noinvcurs = 0;
9435 goto_cost = GOTO_COST + noinvcurs;
9436
9437 /*
9438 * Plan how to do the positioning:
9439 * 1. Use CR to move it to column 0, same row.
9440 * 2. Use T_LE to move it a few columns to the left.
9441 * 3. Use NL to move a few lines down, column 0.
9442 * 4. Move a few columns to the right with T_ND or by writing chars.
9443 *
9444 * Don't do this if the cursor went beyond the last column, the cursor
9445 * position is unknown then (some terminals wrap, some don't )
9446 *
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00009447 * First check if the highlighting attributes allow us to write
Bram Moolenaar071d4272004-06-13 20:20:40 +00009448 * characters to move the cursor to the right.
9449 */
9450 if (row >= screen_cur_row && screen_cur_col < Columns)
9451 {
9452 /*
9453 * If the cursor is in the same row, bigger col, we can use CR
9454 * or T_LE.
9455 */
9456 bs = NULL; /* init for GCC */
9457 attr = screen_attr;
9458 if (row == screen_cur_row && col < screen_cur_col)
9459 {
9460 /* "le" is preferred over "bc", because "bc" is obsolete */
9461 if (*T_LE)
9462 bs = T_LE; /* "cursor left" */
9463 else
9464 bs = T_BC; /* "backspace character (old) */
9465 if (*bs)
9466 cost = (screen_cur_col - col) * (int)STRLEN(bs);
9467 else
9468 cost = 999;
9469 if (col + 1 < cost) /* using CR is less characters */
9470 {
9471 plan = PLAN_CR;
9472 wouldbe_col = 0;
9473 cost = 1; /* CR is just one character */
9474 }
9475 else
9476 {
9477 plan = PLAN_LE;
9478 wouldbe_col = col;
9479 }
9480 if (noinvcurs) /* will stop highlighting */
9481 {
9482 cost += noinvcurs;
9483 attr = 0;
9484 }
9485 }
9486
9487 /*
9488 * If the cursor is above where we want to be, we can use CR LF.
9489 */
9490 else if (row > screen_cur_row)
9491 {
9492 plan = PLAN_NL;
9493 wouldbe_col = 0;
9494 cost = (row - screen_cur_row) * 2; /* CR LF */
9495 if (noinvcurs) /* will stop highlighting */
9496 {
9497 cost += noinvcurs;
9498 attr = 0;
9499 }
9500 }
9501
9502 /*
9503 * If the cursor is in the same row, smaller col, just use write.
9504 */
9505 else
9506 {
9507 plan = PLAN_WRITE;
9508 wouldbe_col = screen_cur_col;
9509 cost = 0;
9510 }
9511
9512 /*
9513 * Check if any characters that need to be written have the
9514 * correct attributes. Also avoid UTF-8 characters.
9515 */
9516 i = col - wouldbe_col;
9517 if (i > 0)
9518 cost += i;
9519 if (cost < goto_cost && i > 0)
9520 {
9521 /*
9522 * Check if the attributes are correct without additionally
9523 * stopping highlighting.
9524 */
9525 p = ScreenAttrs + LineOffset[row] + wouldbe_col;
9526 while (i && *p++ == attr)
9527 --i;
9528 if (i != 0)
9529 {
9530 /*
9531 * Try if it works when highlighting is stopped here.
9532 */
9533 if (*--p == 0)
9534 {
9535 cost += noinvcurs;
9536 while (i && *p++ == 0)
9537 --i;
9538 }
9539 if (i != 0)
9540 cost = 999; /* different attributes, don't do it */
9541 }
9542#ifdef FEAT_MBYTE
9543 if (enc_utf8)
9544 {
9545 /* Don't use an UTF-8 char for positioning, it's slow. */
9546 for (i = wouldbe_col; i < col; ++i)
9547 if (ScreenLinesUC[LineOffset[row] + i] != 0)
9548 {
9549 cost = 999;
9550 break;
9551 }
9552 }
9553#endif
9554 }
9555
9556 /*
9557 * We can do it without term_windgoto()!
9558 */
9559 if (cost < goto_cost)
9560 {
9561 if (plan == PLAN_LE)
9562 {
9563 if (noinvcurs)
9564 screen_stop_highlight();
9565 while (screen_cur_col > col)
9566 {
9567 out_str(bs);
9568 --screen_cur_col;
9569 }
9570 }
9571 else if (plan == PLAN_CR)
9572 {
9573 if (noinvcurs)
9574 screen_stop_highlight();
9575 out_char('\r');
9576 screen_cur_col = 0;
9577 }
9578 else if (plan == PLAN_NL)
9579 {
9580 if (noinvcurs)
9581 screen_stop_highlight();
9582 while (screen_cur_row < row)
9583 {
9584 out_char('\n');
9585 ++screen_cur_row;
9586 }
9587 screen_cur_col = 0;
9588 }
9589
9590 i = col - screen_cur_col;
9591 if (i > 0)
9592 {
9593 /*
9594 * Use cursor-right if it's one character only. Avoids
9595 * removing a line of pixels from the last bold char, when
9596 * using the bold trick in the GUI.
9597 */
9598 if (T_ND[0] != NUL && T_ND[1] == NUL)
9599 {
9600 while (i-- > 0)
9601 out_char(*T_ND);
9602 }
9603 else
9604 {
9605 int off;
9606
9607 off = LineOffset[row] + screen_cur_col;
9608 while (i-- > 0)
9609 {
9610 if (ScreenAttrs[off] != screen_attr)
9611 screen_stop_highlight();
9612#ifdef FEAT_MBYTE
9613 out_flush_check();
9614#endif
9615 out_char(ScreenLines[off]);
9616#ifdef FEAT_MBYTE
9617 if (enc_dbcs == DBCS_JPNU
9618 && ScreenLines[off] == 0x8e)
9619 out_char(ScreenLines2[off]);
9620#endif
9621 ++off;
9622 }
9623 }
9624 }
9625 }
9626 }
9627 else
9628 cost = 999;
9629
9630 if (cost >= goto_cost)
9631 {
9632 if (noinvcurs)
9633 screen_stop_highlight();
Bram Moolenaar597a4222014-06-25 14:39:50 +02009634 if (row == screen_cur_row && (col > screen_cur_col)
9635 && *T_CRI != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009636 term_cursor_right(col - screen_cur_col);
9637 else
9638 term_windgoto(row, col);
9639 }
9640 screen_cur_row = row;
9641 screen_cur_col = col;
9642 }
9643}
9644
9645/*
9646 * Set cursor to its position in the current window.
9647 */
9648 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009649setcursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009650{
Bram Moolenaar987723e2018-03-06 11:43:04 +01009651 setcursor_mayforce(FALSE);
9652}
9653
9654/*
9655 * Set cursor to its position in the current window.
9656 * When "force" is TRUE also when not redrawing.
9657 */
9658 void
9659setcursor_mayforce(int force)
9660{
9661 if (force || redrawing())
Bram Moolenaar071d4272004-06-13 20:20:40 +00009662 {
9663 validate_cursor();
9664 windgoto(W_WINROW(curwin) + curwin->w_wrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009665 curwin->w_wincol + (
Bram Moolenaar071d4272004-06-13 20:20:40 +00009666#ifdef FEAT_RIGHTLEFT
Bram Moolenaar561f9db2008-02-20 13:16:29 +00009667 /* With 'rightleft' set and the cursor on a double-wide
9668 * character, position it on the leftmost column. */
Bram Moolenaar02631462017-09-22 15:20:32 +02009669 curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol - (
Bram Moolenaar071d4272004-06-13 20:20:40 +00009670# ifdef FEAT_MBYTE
Bram Moolenaar561f9db2008-02-20 13:16:29 +00009671 (has_mbyte
9672 && (*mb_ptr2cells)(ml_get_cursor()) == 2
9673 && vim_isprintc(gchar_cursor())) ? 2 :
Bram Moolenaar071d4272004-06-13 20:20:40 +00009674# endif
9675 1)) :
9676#endif
9677 curwin->w_wcol));
9678 }
9679}
9680
9681
9682/*
Bram Moolenaar86033562017-07-12 20:24:41 +02009683 * Insert 'line_count' lines at 'row' in window 'wp'.
9684 * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
9685 * If 'mayclear' is TRUE the screen will be cleared if it is faster than
Bram Moolenaar071d4272004-06-13 20:20:40 +00009686 * scrolling.
9687 * Returns FAIL if the lines are not inserted, OK for success.
9688 */
9689 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009690win_ins_lines(
9691 win_T *wp,
9692 int row,
9693 int line_count,
9694 int invalid,
9695 int mayclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009696{
9697 int did_delete;
9698 int nextrow;
9699 int lastrow;
9700 int retval;
9701
9702 if (invalid)
9703 wp->w_lines_valid = 0;
9704
9705 if (wp->w_height < 5)
9706 return FAIL;
9707
9708 if (line_count > wp->w_height - row)
9709 line_count = wp->w_height - row;
9710
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009711 retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009712 if (retval != MAYBE)
9713 return retval;
9714
9715 /*
9716 * If there is a next window or a status line, we first try to delete the
9717 * lines at the bottom to avoid messing what is after the window.
9718 * If this fails and there are following windows, don't do anything to avoid
9719 * messing up those windows, better just redraw.
9720 */
9721 did_delete = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009722 if (wp->w_next != NULL || wp->w_status_height)
9723 {
9724 if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009725 line_count, (int)Rows, FALSE, 0, NULL) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009726 did_delete = TRUE;
9727 else if (wp->w_next)
9728 return FAIL;
9729 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009730 /*
9731 * if no lines deleted, blank the lines that will end up below the window
9732 */
9733 if (!did_delete)
9734 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009735 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009736 redraw_cmdline = TRUE;
Bram Moolenaare0de17d2017-09-24 16:24:34 +02009737 nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009738 lastrow = nextrow + line_count;
9739 if (lastrow > Rows)
9740 lastrow = Rows;
9741 screen_fill(nextrow - line_count, lastrow - line_count,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009742 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00009743 ' ', ' ', 0);
9744 }
9745
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009746 if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009747 == FAIL)
9748 {
9749 /* deletion will have messed up other windows */
9750 if (did_delete)
9751 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009752 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009753 win_rest_invalid(W_NEXT(wp));
9754 }
9755 return FAIL;
9756 }
9757
9758 return OK;
9759}
9760
9761/*
Bram Moolenaar86033562017-07-12 20:24:41 +02009762 * Delete "line_count" window lines at "row" in window "wp".
Bram Moolenaar071d4272004-06-13 20:20:40 +00009763 * If "invalid" is TRUE curwin->w_lines[] is invalidated.
9764 * If "mayclear" is TRUE the screen will be cleared if it is faster than
9765 * scrolling
9766 * Return OK for success, FAIL if the lines are not deleted.
9767 */
9768 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009769win_del_lines(
9770 win_T *wp,
9771 int row,
9772 int line_count,
9773 int invalid,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009774 int mayclear,
9775 int clear_attr) /* for clearing lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009776{
9777 int retval;
9778
9779 if (invalid)
9780 wp->w_lines_valid = 0;
9781
9782 if (line_count > wp->w_height - row)
9783 line_count = wp->w_height - row;
9784
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009785 retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009786 if (retval != MAYBE)
9787 return retval;
9788
9789 if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009790 (int)Rows, FALSE, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009791 return FAIL;
9792
Bram Moolenaar071d4272004-06-13 20:20:40 +00009793 /*
9794 * If there are windows or status lines below, try to put them at the
9795 * correct place. If we can't do that, they have to be redrawn.
9796 */
9797 if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
9798 {
9799 if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009800 line_count, (int)Rows, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009801 {
9802 wp->w_redr_status = TRUE;
9803 win_rest_invalid(wp->w_next);
9804 }
9805 }
9806 /*
9807 * If this is the last window and there is no status line, redraw the
9808 * command line later.
9809 */
9810 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00009811 redraw_cmdline = TRUE;
9812 return OK;
9813}
9814
9815/*
9816 * Common code for win_ins_lines() and win_del_lines().
9817 * Returns OK or FAIL when the work has been done.
9818 * Returns MAYBE when not finished yet.
9819 */
9820 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01009821win_do_lines(
9822 win_T *wp,
9823 int row,
9824 int line_count,
9825 int mayclear,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009826 int del,
9827 int clear_attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009828{
9829 int retval;
9830
9831 if (!redrawing() || line_count <= 0)
9832 return FAIL;
9833
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009834 /* When inserting lines would result in loss of command output, just redraw
9835 * the lines. */
9836 if (no_win_do_lines_ins && !del)
9837 return FAIL;
9838
Bram Moolenaar071d4272004-06-13 20:20:40 +00009839 /* only a few lines left: redraw is faster */
Bram Moolenaar4033c552017-09-16 20:54:51 +02009840 if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009841 {
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009842 if (!no_win_do_lines_ins)
9843 screenclear(); /* will set wp->w_lines_valid to 0 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009844 return FAIL;
9845 }
9846
9847 /*
9848 * Delete all remaining lines
9849 */
9850 if (row + line_count >= wp->w_height)
9851 {
9852 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009853 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00009854 ' ', ' ', 0);
9855 return OK;
9856 }
9857
9858 /*
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009859 * When scrolling, the message on the command line should be cleared,
Bram Moolenaar071d4272004-06-13 20:20:40 +00009860 * otherwise it will stay there forever.
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009861 * Don't do this when avoiding to insert lines.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009862 */
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009863 if (!no_win_do_lines_ins)
9864 clear_cmdline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009865
9866 /*
9867 * If the terminal can set a scroll region, use that.
9868 * Always do this in a vertically split window. This will redraw from
9869 * ScreenLines[] when t_CV isn't defined. That's faster than using
9870 * win_line().
9871 * Don't use a scroll region when we are going to redraw the text, writing
Bram Moolenaar48e330a2016-02-23 14:53:34 +01009872 * a character in the lower right corner of the scroll region may cause a
9873 * scroll-up .
Bram Moolenaar071d4272004-06-13 20:20:40 +00009874 */
Bram Moolenaar02631462017-09-22 15:20:32 +02009875 if (scroll_region || wp->w_width != Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009876 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009877 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009878 scroll_region_set(wp, row);
9879 if (del)
9880 retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009881 wp->w_height - row, FALSE, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009882 else
9883 retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009884 wp->w_height - row, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009885 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009886 scroll_region_reset();
9887 return retval;
9888 }
9889
Bram Moolenaar071d4272004-06-13 20:20:40 +00009890 if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
9891 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009892
9893 return MAYBE;
9894}
9895
9896/*
9897 * window 'wp' and everything after it is messed up, mark it for redraw
9898 */
9899 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009900win_rest_invalid(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009901{
Bram Moolenaar071d4272004-06-13 20:20:40 +00009902 while (wp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009903 {
9904 redraw_win_later(wp, NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009905 wp->w_redr_status = TRUE;
9906 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009907 }
9908 redraw_cmdline = TRUE;
9909}
9910
9911/*
9912 * The rest of the routines in this file perform screen manipulations. The
9913 * given operation is performed physically on the screen. The corresponding
9914 * change is also made to the internal screen image. In this way, the editor
9915 * anticipates the effect of editing changes on the appearance of the screen.
9916 * That way, when we call screenupdate a complete redraw isn't usually
9917 * necessary. Another advantage is that we can keep adding code to anticipate
9918 * screen changes, and in the meantime, everything still works.
9919 */
9920
9921/*
9922 * types for inserting or deleting lines
9923 */
9924#define USE_T_CAL 1
9925#define USE_T_CDL 2
9926#define USE_T_AL 3
9927#define USE_T_CE 4
9928#define USE_T_DL 5
9929#define USE_T_SR 6
9930#define USE_NL 7
9931#define USE_T_CD 8
9932#define USE_REDRAW 9
9933
9934/*
9935 * insert lines on the screen and update ScreenLines[]
9936 * 'end' is the line after the scrolled part. Normally it is Rows.
9937 * When scrolling region used 'off' is the offset from the top for the region.
9938 * 'row' and 'end' are relative to the start of the region.
9939 *
9940 * return FAIL for failure, OK for success.
9941 */
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00009942 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009943screen_ins_lines(
9944 int off,
9945 int row,
9946 int line_count,
9947 int end,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009948 int clear_attr,
Bram Moolenaar05540972016-01-30 20:31:25 +01009949 win_T *wp) /* NULL or window to use width from */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009950{
9951 int i;
9952 int j;
9953 unsigned temp;
9954 int cursor_row;
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009955 int cursor_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009956 int type;
9957 int result_empty;
9958 int can_ce = can_clear(T_CE);
9959
9960 /*
9961 * FAIL if
9962 * - there is no valid screen
9963 * - the screen has to be redrawn completely
9964 * - the line count is less than one
9965 * - the line count is more than 'ttyscroll'
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009966 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar071d4272004-06-13 20:20:40 +00009967 */
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009968 if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll
9969#ifdef FEAT_CLIPBOARD
9970 || (clip_star.state != SELECT_CLEARED
9971 && redrawing_for_callback > 0)
9972#endif
9973 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00009974 return FAIL;
9975
9976 /*
9977 * There are seven ways to insert lines:
9978 * 0. When in a vertically split window and t_CV isn't set, redraw the
9979 * characters from ScreenLines[].
9980 * 1. Use T_CD (clear to end of display) if it exists and the result of
9981 * the insert is just empty lines
9982 * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
9983 * present or line_count > 1. It looks better if we do all the inserts
9984 * at once.
9985 * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
9986 * insert is just empty lines and T_CE is not present or line_count >
9987 * 1.
9988 * 4. Use T_AL (insert line) if it exists.
9989 * 5. Use T_CE (erase line) if it exists and the result of the insert is
9990 * just empty lines.
9991 * 6. Use T_DL (delete line) if it exists and the result of the insert is
9992 * just empty lines.
9993 * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
9994 * the 'da' flag is not set or we have clear line capability.
9995 * 8. redraw the characters from ScreenLines[].
9996 *
9997 * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
9998 * the scrollbar for the window. It does have insert line, use that if it
9999 * exists.
10000 */
10001 result_empty = (row + line_count >= end);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010002 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
10003 type = USE_REDRAW;
Bram Moolenaar4033c552017-09-16 20:54:51 +020010004 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010005 type = USE_T_CD;
10006 else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
10007 type = USE_T_CAL;
10008 else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
10009 type = USE_T_CDL;
10010 else if (*T_AL != NUL)
10011 type = USE_T_AL;
10012 else if (can_ce && result_empty)
10013 type = USE_T_CE;
10014 else if (*T_DL != NUL && result_empty)
10015 type = USE_T_DL;
10016 else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
10017 type = USE_T_SR;
10018 else
10019 return FAIL;
10020
10021 /*
10022 * For clearing the lines screen_del_lines() is used. This will also take
10023 * care of t_db if necessary.
10024 */
10025 if (type == USE_T_CD || type == USE_T_CDL ||
10026 type == USE_T_CE || type == USE_T_DL)
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010027 return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010028
10029 /*
10030 * If text is retained below the screen, first clear or delete as many
10031 * lines at the bottom of the window as are about to be inserted so that
10032 * the deleted lines won't later surface during a screen_del_lines.
10033 */
10034 if (*T_DB)
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010035 screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010036
10037#ifdef FEAT_CLIPBOARD
10038 /* Remove a modeless selection when inserting lines halfway the screen
10039 * or not the full width of the screen. */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010040 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +020010041 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010042 else
10043 clip_scroll_selection(-line_count);
10044#endif
10045
Bram Moolenaar071d4272004-06-13 20:20:40 +000010046#ifdef FEAT_GUI
10047 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
10048 * scrolling is actually carried out. */
Bram Moolenaar107abd22016-08-12 14:08:25 +020010049 gui_dont_update_cursor(row + off <= gui.cursor_row);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010050#endif
10051
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010052 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
10053 cursor_col = wp->w_wincol;
10054
Bram Moolenaar071d4272004-06-13 20:20:40 +000010055 if (*T_CCS != NUL) /* cursor relative to region */
10056 cursor_row = row;
10057 else
10058 cursor_row = row + off;
10059
10060 /*
10061 * Shift LineOffset[] line_count down to reflect the inserted lines.
10062 * Clear the inserted lines in ScreenLines[].
10063 */
10064 row += off;
10065 end += off;
10066 for (i = 0; i < line_count; ++i)
10067 {
Bram Moolenaar071d4272004-06-13 20:20:40 +000010068 if (wp != NULL && wp->w_width != Columns)
10069 {
10070 /* need to copy part of a line */
10071 j = end - 1 - i;
10072 while ((j -= line_count) >= row)
10073 linecopy(j + line_count, j, wp);
10074 j += line_count;
10075 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010076 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
10077 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010078 else
10079 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
10080 LineWraps[j] = FALSE;
10081 }
10082 else
Bram Moolenaar071d4272004-06-13 20:20:40 +000010083 {
10084 j = end - 1 - i;
10085 temp = LineOffset[j];
10086 while ((j -= line_count) >= row)
10087 {
10088 LineOffset[j + line_count] = LineOffset[j];
10089 LineWraps[j + line_count] = LineWraps[j];
10090 }
10091 LineOffset[j + line_count] = temp;
10092 LineWraps[j + line_count] = FALSE;
10093 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010094 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010095 else
10096 lineinvalid(temp, (int)Columns);
10097 }
10098 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010099
10100 screen_stop_highlight();
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010101 windgoto(cursor_row, cursor_col);
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010102 if (clear_attr != 0)
10103 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010104
Bram Moolenaar071d4272004-06-13 20:20:40 +000010105 /* redraw the characters */
10106 if (type == USE_REDRAW)
10107 redraw_block(row, end, wp);
Bram Moolenaar4033c552017-09-16 20:54:51 +020010108 else if (type == USE_T_CAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010109 {
10110 term_append_lines(line_count);
10111 screen_start(); /* don't know where cursor is now */
10112 }
10113 else
10114 {
10115 for (i = 0; i < line_count; i++)
10116 {
10117 if (type == USE_T_AL)
10118 {
10119 if (i && cursor_row != 0)
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010120 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010121 out_str(T_AL);
10122 }
10123 else /* type == USE_T_SR */
10124 out_str(T_SR);
10125 screen_start(); /* don't know where cursor is now */
10126 }
10127 }
10128
10129 /*
10130 * With scroll-reverse and 'da' flag set we need to clear the lines that
10131 * have been scrolled down into the region.
10132 */
10133 if (type == USE_T_SR && *T_DA)
10134 {
10135 for (i = 0; i < line_count; ++i)
10136 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010137 windgoto(off + i, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010138 out_str(T_CE);
10139 screen_start(); /* don't know where cursor is now */
10140 }
10141 }
10142
10143#ifdef FEAT_GUI
10144 gui_can_update_cursor();
10145 if (gui.in_use)
10146 out_flush(); /* always flush after a scroll */
10147#endif
10148 return OK;
10149}
10150
10151/*
Bram Moolenaar107abd22016-08-12 14:08:25 +020010152 * Delete lines on the screen and update ScreenLines[].
10153 * "end" is the line after the scrolled part. Normally it is Rows.
10154 * When scrolling region used "off" is the offset from the top for the region.
10155 * "row" and "end" are relative to the start of the region.
Bram Moolenaar071d4272004-06-13 20:20:40 +000010156 *
10157 * Return OK for success, FAIL if the lines are not deleted.
10158 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010159 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010160screen_del_lines(
10161 int off,
10162 int row,
10163 int line_count,
10164 int end,
10165 int force, /* even when line_count > p_ttyscroll */
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010166 int clear_attr, /* used for clearing lines */
Bram Moolenaar05540972016-01-30 20:31:25 +010010167 win_T *wp UNUSED) /* NULL or window to use width from */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010168{
10169 int j;
10170 int i;
10171 unsigned temp;
10172 int cursor_row;
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010173 int cursor_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010174 int cursor_end;
10175 int result_empty; /* result is empty until end of region */
10176 int can_delete; /* deleting line codes can be used */
10177 int type;
10178
10179 /*
10180 * FAIL if
10181 * - there is no valid screen
10182 * - the screen has to be redrawn completely
10183 * - the line count is less than one
10184 * - the line count is more than 'ttyscroll'
Bram Moolenaar80dd3f92017-07-19 12:51:52 +020010185 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar071d4272004-06-13 20:20:40 +000010186 */
Bram Moolenaar80dd3f92017-07-19 12:51:52 +020010187 if (!screen_valid(TRUE) || line_count <= 0
10188 || (!force && line_count > p_ttyscroll)
10189#ifdef FEAT_CLIPBOARD
10190 || (clip_star.state != SELECT_CLEARED
10191 && redrawing_for_callback > 0)
10192#endif
10193 )
Bram Moolenaar071d4272004-06-13 20:20:40 +000010194 return FAIL;
10195
10196 /*
10197 * Check if the rest of the current region will become empty.
10198 */
10199 result_empty = row + line_count >= end;
10200
10201 /*
10202 * We can delete lines only when 'db' flag not set or when 'ce' option
10203 * available.
10204 */
10205 can_delete = (*T_DB == NUL || can_clear(T_CE));
10206
10207 /*
10208 * There are six ways to delete lines:
10209 * 0. When in a vertically split window and t_CV isn't set, redraw the
10210 * characters from ScreenLines[].
10211 * 1. Use T_CD if it exists and the result is empty.
10212 * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
10213 * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
10214 * none of the other ways work.
10215 * 4. Use T_CE (erase line) if the result is empty.
10216 * 5. Use T_DL (delete line) if it exists.
10217 * 6. redraw the characters from ScreenLines[].
10218 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010219 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
10220 type = USE_REDRAW;
Bram Moolenaar4033c552017-09-16 20:54:51 +020010221 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010222 type = USE_T_CD;
10223#if defined(__BEOS__) && defined(BEOS_DR8)
10224 /*
10225 * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
10226 * its internal termcap... this works okay for tests which test *T_DB !=
10227 * NUL. It has the disadvantage that the user cannot use any :set t_*
10228 * command to get T_DB (back) to empty_option, only :set term=... will do
10229 * the trick...
10230 * Anyway, this hack will hopefully go away with the next OS release.
10231 * (Olaf Seibert)
10232 */
10233 else if (row == 0 && T_DB == empty_option
10234 && (line_count == 1 || *T_CDL == NUL))
10235#else
10236 else if (row == 0 && (
10237#ifndef AMIGA
10238 /* On the Amiga, somehow '\n' on the last line doesn't always scroll
10239 * up, so use delete-line command */
10240 line_count == 1 ||
10241#endif
10242 *T_CDL == NUL))
10243#endif
10244 type = USE_NL;
10245 else if (*T_CDL != NUL && line_count > 1 && can_delete)
10246 type = USE_T_CDL;
10247 else if (can_clear(T_CE) && result_empty
Bram Moolenaar4033c552017-09-16 20:54:51 +020010248 && (wp == NULL || wp->w_width == Columns))
Bram Moolenaar071d4272004-06-13 20:20:40 +000010249 type = USE_T_CE;
10250 else if (*T_DL != NUL && can_delete)
10251 type = USE_T_DL;
10252 else if (*T_CDL != NUL && can_delete)
10253 type = USE_T_CDL;
10254 else
10255 return FAIL;
10256
10257#ifdef FEAT_CLIPBOARD
10258 /* Remove a modeless selection when deleting lines halfway the screen or
10259 * not the full width of the screen. */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010260 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +020010261 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010262 else
10263 clip_scroll_selection(line_count);
10264#endif
10265
Bram Moolenaar071d4272004-06-13 20:20:40 +000010266#ifdef FEAT_GUI
10267 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
10268 * scrolling is actually carried out. */
Bram Moolenaar107abd22016-08-12 14:08:25 +020010269 gui_dont_update_cursor(gui.cursor_row >= row + off
10270 && gui.cursor_row < end + off);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010271#endif
10272
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010273 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
10274 cursor_col = wp->w_wincol;
10275
Bram Moolenaar071d4272004-06-13 20:20:40 +000010276 if (*T_CCS != NUL) /* cursor relative to region */
10277 {
10278 cursor_row = row;
10279 cursor_end = end;
10280 }
10281 else
10282 {
10283 cursor_row = row + off;
10284 cursor_end = end + off;
10285 }
10286
10287 /*
10288 * Now shift LineOffset[] line_count up to reflect the deleted lines.
10289 * Clear the inserted lines in ScreenLines[].
10290 */
10291 row += off;
10292 end += off;
10293 for (i = 0; i < line_count; ++i)
10294 {
Bram Moolenaar071d4272004-06-13 20:20:40 +000010295 if (wp != NULL && wp->w_width != Columns)
10296 {
10297 /* need to copy part of a line */
10298 j = row + i;
10299 while ((j += line_count) <= end - 1)
10300 linecopy(j - line_count, j, wp);
10301 j -= line_count;
10302 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010303 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
10304 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010305 else
10306 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
10307 LineWraps[j] = FALSE;
10308 }
10309 else
Bram Moolenaar071d4272004-06-13 20:20:40 +000010310 {
10311 /* whole width, moving the line pointers is faster */
10312 j = row + i;
10313 temp = LineOffset[j];
10314 while ((j += line_count) <= end - 1)
10315 {
10316 LineOffset[j - line_count] = LineOffset[j];
10317 LineWraps[j - line_count] = LineWraps[j];
10318 }
10319 LineOffset[j - line_count] = temp;
10320 LineWraps[j - line_count] = FALSE;
10321 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010322 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010323 else
10324 lineinvalid(temp, (int)Columns);
10325 }
10326 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010327
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010328 if (screen_attr != clear_attr)
10329 screen_stop_highlight();
10330 if (clear_attr != 0)
10331 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010332
Bram Moolenaar071d4272004-06-13 20:20:40 +000010333 /* redraw the characters */
10334 if (type == USE_REDRAW)
10335 redraw_block(row, end, wp);
Bram Moolenaar4033c552017-09-16 20:54:51 +020010336 else if (type == USE_T_CD) /* delete the lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010337 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010338 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010339 out_str(T_CD);
10340 screen_start(); /* don't know where cursor is now */
10341 }
10342 else if (type == USE_T_CDL)
10343 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010344 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010345 term_delete_lines(line_count);
10346 screen_start(); /* don't know where cursor is now */
10347 }
10348 /*
10349 * Deleting lines at top of the screen or scroll region: Just scroll
10350 * the whole screen (scroll region) up by outputting newlines on the
10351 * last line.
10352 */
10353 else if (type == USE_NL)
10354 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010355 windgoto(cursor_end - 1, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010356 for (i = line_count; --i >= 0; )
10357 out_char('\n'); /* cursor will remain on same line */
10358 }
10359 else
10360 {
10361 for (i = line_count; --i >= 0; )
10362 {
10363 if (type == USE_T_DL)
10364 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010365 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010366 out_str(T_DL); /* delete a line */
10367 }
10368 else /* type == USE_T_CE */
10369 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010370 windgoto(cursor_row + i, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010371 out_str(T_CE); /* erase a line */
10372 }
10373 screen_start(); /* don't know where cursor is now */
10374 }
10375 }
10376
10377 /*
10378 * If the 'db' flag is set, we need to clear the lines that have been
10379 * scrolled up at the bottom of the region.
10380 */
10381 if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
10382 {
10383 for (i = line_count; i > 0; --i)
10384 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +020010385 windgoto(cursor_end - i, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010386 out_str(T_CE); /* erase a line */
10387 screen_start(); /* don't know where cursor is now */
10388 }
10389 }
10390
10391#ifdef FEAT_GUI
10392 gui_can_update_cursor();
10393 if (gui.in_use)
10394 out_flush(); /* always flush after a scroll */
10395#endif
10396
10397 return OK;
10398}
10399
10400/*
Bram Moolenaar81226e02018-02-20 21:44:45 +010010401 * Show the current mode and ruler.
Bram Moolenaar071d4272004-06-13 20:20:40 +000010402 *
10403 * If clear_cmdline is TRUE, clear the rest of the cmdline.
10404 * If clear_cmdline is FALSE there may be a message there that needs to be
10405 * cleared only if a mode is shown.
10406 * Return the length of the message (0 if no message).
10407 */
10408 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010409showmode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010410{
10411 int need_clear;
10412 int length = 0;
10413 int do_mode;
10414 int attr;
10415 int nwr_save;
10416#ifdef FEAT_INS_EXPAND
10417 int sub_attr;
10418#endif
10419
Bram Moolenaar7df351e2006-01-23 22:30:28 +000010420 do_mode = ((p_smd && msg_silent == 0)
10421 && ((State & INSERT)
Bram Moolenaar942b4542018-06-17 16:23:34 +020010422 || restart_edit != NUL
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +010010423 || VIsual_active));
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010424 if (do_mode || reg_recording != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010425 {
10426 /*
10427 * Don't show mode right now, when not redrawing or inside a mapping.
10428 * Call char_avail() only when we are going to show something, because
10429 * it takes a bit of time.
10430 */
10431 if (!redrawing() || (char_avail() && !KeyTyped) || msg_silent != 0)
10432 {
10433 redraw_cmdline = TRUE; /* show mode later */
10434 return 0;
10435 }
10436
10437 nwr_save = need_wait_return;
10438
10439 /* wait a bit before overwriting an important message */
10440 check_for_delay(FALSE);
10441
10442 /* if the cmdline is more than one line high, erase top lines */
10443 need_clear = clear_cmdline;
10444 if (clear_cmdline && cmdline_row < Rows - 1)
10445 msg_clr_cmdline(); /* will reset clear_cmdline */
10446
10447 /* Position on the last line in the window, column 0 */
10448 msg_pos_mode();
10449 cursor_off();
Bram Moolenaar8820b482017-03-16 17:23:31 +010010450 attr = HL_ATTR(HLF_CM); /* Highlight mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010451 if (do_mode)
10452 {
10453 MSG_PUTS_ATTR("--", attr);
10454#if defined(FEAT_XIM)
Bram Moolenaarc236c162008-07-13 17:41:49 +000010455 if (
Bram Moolenaar09092152010-08-08 16:38:42 +020010456# ifdef FEAT_GUI_GTK
Bram Moolenaarc236c162008-07-13 17:41:49 +000010457 preedit_get_status()
Bram Moolenaar09092152010-08-08 16:38:42 +020010458# else
Bram Moolenaarc236c162008-07-13 17:41:49 +000010459 im_get_status()
Bram Moolenaarc236c162008-07-13 17:41:49 +000010460# endif
Bram Moolenaar09092152010-08-08 16:38:42 +020010461 )
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +020010462# ifdef FEAT_GUI_GTK /* most of the time, it's not XIM being used */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010463 MSG_PUTS_ATTR(" IM", attr);
10464# else
10465 MSG_PUTS_ATTR(" XIM", attr);
10466# endif
10467#endif
10468#if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
10469 if (gui.in_use)
10470 {
10471 if (hangul_input_state_get())
Bram Moolenaar72f4cc42015-11-10 14:35:18 +010010472 {
10473 /* HANGUL */
10474 if (enc_utf8)
10475 MSG_PUTS_ATTR(" \355\225\234\352\270\200", attr);
10476 else
10477 MSG_PUTS_ATTR(" \307\321\261\333", attr);
10478 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010479 }
10480#endif
10481#ifdef FEAT_INS_EXPAND
Bram Moolenaarea389e92014-05-28 21:40:52 +020010482 /* CTRL-X in Insert mode */
10483 if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
Bram Moolenaar071d4272004-06-13 20:20:40 +000010484 {
10485 /* These messages can get long, avoid a wrap in a narrow
10486 * window. Prefer showing edit_submode_extra. */
10487 length = (Rows - msg_row) * Columns - 3;
10488 if (edit_submode_extra != NULL)
10489 length -= vim_strsize(edit_submode_extra);
10490 if (length > 0)
10491 {
10492 if (edit_submode_pre != NULL)
10493 length -= vim_strsize(edit_submode_pre);
10494 if (length - vim_strsize(edit_submode) > 0)
10495 {
10496 if (edit_submode_pre != NULL)
10497 msg_puts_attr(edit_submode_pre, attr);
10498 msg_puts_attr(edit_submode, attr);
10499 }
10500 if (edit_submode_extra != NULL)
10501 {
10502 MSG_PUTS_ATTR(" ", attr); /* add a space in between */
10503 if ((int)edit_submode_highl < (int)HLF_COUNT)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010504 sub_attr = HL_ATTR(edit_submode_highl);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010505 else
10506 sub_attr = attr;
10507 msg_puts_attr(edit_submode_extra, sub_attr);
10508 }
10509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010510 }
10511 else
10512#endif
10513 {
Bram Moolenaar071d4272004-06-13 20:20:40 +000010514 if (State & VREPLACE_FLAG)
10515 MSG_PUTS_ATTR(_(" VREPLACE"), attr);
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +020010516 else if (State & REPLACE_FLAG)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010517 MSG_PUTS_ATTR(_(" REPLACE"), attr);
10518 else if (State & INSERT)
10519 {
10520#ifdef FEAT_RIGHTLEFT
10521 if (p_ri)
10522 MSG_PUTS_ATTR(_(" REVERSE"), attr);
10523#endif
10524 MSG_PUTS_ATTR(_(" INSERT"), attr);
10525 }
Bram Moolenaar942b4542018-06-17 16:23:34 +020010526 else if (restart_edit == 'I' || restart_edit == 'A')
Bram Moolenaar071d4272004-06-13 20:20:40 +000010527 MSG_PUTS_ATTR(_(" (insert)"), attr);
10528 else if (restart_edit == 'R')
10529 MSG_PUTS_ATTR(_(" (replace)"), attr);
10530 else if (restart_edit == 'V')
10531 MSG_PUTS_ATTR(_(" (vreplace)"), attr);
10532#ifdef FEAT_RIGHTLEFT
10533 if (p_hkmap)
10534 MSG_PUTS_ATTR(_(" Hebrew"), attr);
10535# ifdef FEAT_FKMAP
10536 if (p_fkmap)
10537 MSG_PUTS_ATTR(farsi_text_5, attr);
10538# endif
10539#endif
10540#ifdef FEAT_KEYMAP
10541 if (State & LANGMAP)
10542 {
10543# ifdef FEAT_ARABIC
10544 if (curwin->w_p_arab)
10545 MSG_PUTS_ATTR(_(" Arabic"), attr);
10546 else
10547# endif
Bram Moolenaar73ac0c42016-07-24 16:17:59 +020010548 if (get_keymap_str(curwin, (char_u *)" (%s)",
10549 NameBuff, MAXPATHL))
10550 MSG_PUTS_ATTR(NameBuff, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010551 }
10552#endif
10553 if ((State & INSERT) && p_paste)
10554 MSG_PUTS_ATTR(_(" (paste)"), attr);
10555
Bram Moolenaar071d4272004-06-13 20:20:40 +000010556 if (VIsual_active)
10557 {
10558 char *p;
10559
10560 /* Don't concatenate separate words to avoid translation
10561 * problems. */
10562 switch ((VIsual_select ? 4 : 0)
10563 + (VIsual_mode == Ctrl_V) * 2
10564 + (VIsual_mode == 'V'))
10565 {
10566 case 0: p = N_(" VISUAL"); break;
10567 case 1: p = N_(" VISUAL LINE"); break;
10568 case 2: p = N_(" VISUAL BLOCK"); break;
10569 case 4: p = N_(" SELECT"); break;
10570 case 5: p = N_(" SELECT LINE"); break;
10571 default: p = N_(" SELECT BLOCK"); break;
10572 }
10573 MSG_PUTS_ATTR(_(p), attr);
10574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010575 MSG_PUTS_ATTR(" --", attr);
10576 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010577
Bram Moolenaar071d4272004-06-13 20:20:40 +000010578 need_clear = TRUE;
10579 }
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010580 if (reg_recording != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +000010581#ifdef FEAT_INS_EXPAND
10582 && edit_submode == NULL /* otherwise it gets too long */
10583#endif
10584 )
10585 {
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010586 recording_mode(attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010587 need_clear = TRUE;
10588 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010589
10590 mode_displayed = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010591 if (need_clear || clear_cmdline)
10592 msg_clr_eos();
10593 msg_didout = FALSE; /* overwrite this message */
10594 length = msg_col;
10595 msg_col = 0;
10596 need_wait_return = nwr_save; /* never ask for hit-return for this */
10597 }
10598 else if (clear_cmdline && msg_silent == 0)
10599 /* Clear the whole command line. Will reset "clear_cmdline". */
10600 msg_clr_cmdline();
10601
10602#ifdef FEAT_CMDL_INFO
Bram Moolenaar071d4272004-06-13 20:20:40 +000010603 /* In Visual mode the size of the selected area must be redrawn. */
10604 if (VIsual_active)
10605 clear_showcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +000010606
10607 /* If the last window has no status line, the ruler is after the mode
10608 * message and must be redrawn */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010609 if (redrawing() && lastwin->w_status_height == 0)
Bram Moolenaar491ac282018-06-17 14:47:55 +020010610 win_redr_ruler(lastwin, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010611#endif
10612 redraw_cmdline = FALSE;
10613 clear_cmdline = FALSE;
10614
10615 return length;
10616}
10617
10618/*
10619 * Position for a mode message.
10620 */
10621 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010622msg_pos_mode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010623{
10624 msg_col = 0;
10625 msg_row = Rows - 1;
10626}
10627
10628/*
10629 * Delete mode message. Used when ESC is typed which is expected to end
10630 * Insert mode (but Insert mode didn't end yet!).
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010631 * Caller should check "mode_displayed".
Bram Moolenaar071d4272004-06-13 20:20:40 +000010632 */
10633 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010634unshowmode(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010635{
10636 /*
Bram Moolenaare4ebd292010-01-19 17:40:46 +010010637 * Don't delete it right now, when not redrawing or inside a mapping.
Bram Moolenaar071d4272004-06-13 20:20:40 +000010638 */
10639 if (!redrawing() || (!force && char_avail() && !KeyTyped))
10640 redraw_cmdline = TRUE; /* delete mode later */
10641 else
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010642 clearmode();
10643}
10644
10645/*
10646 * Clear the mode message.
10647 */
10648 void
Bram Moolenaarcf089462016-06-12 21:18:43 +020010649clearmode(void)
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010650{
Bram Moolenaar2abad542018-05-19 14:43:45 +020010651 int save_msg_row = msg_row;
10652 int save_msg_col = msg_col;
10653
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010654 msg_pos_mode();
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010655 if (reg_recording != 0)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010656 recording_mode(HL_ATTR(HLF_CM));
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010657 msg_clr_eos();
Bram Moolenaar2abad542018-05-19 14:43:45 +020010658
10659 msg_col = save_msg_col;
10660 msg_row = save_msg_row;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010661}
10662
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010663 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010664recording_mode(int attr)
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010665{
10666 MSG_PUTS_ATTR(_("recording"), attr);
10667 if (!shortmess(SHM_RECORDING))
10668 {
10669 char_u s[4];
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010670 sprintf((char *)s, " @%c", reg_recording);
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010671 MSG_PUTS_ATTR(s, attr);
10672 }
10673}
10674
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010675/*
10676 * Draw the tab pages line at the top of the Vim window.
10677 */
Bram Moolenaare12bab32019-01-08 22:02:56 +010010678 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010679draw_tabline(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010680{
10681 int tabcount = 0;
10682 tabpage_T *tp;
10683 int tabwidth;
10684 int col = 0;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010685 int scol = 0;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010686 int attr;
10687 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010688 win_T *cwp;
10689 int wincount;
10690 int modified;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010691 int c;
10692 int len;
Bram Moolenaar8820b482017-03-16 17:23:31 +010010693 int attr_sel = HL_ATTR(HLF_TPS);
10694 int attr_nosel = HL_ATTR(HLF_TP);
10695 int attr_fill = HL_ATTR(HLF_TPF);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010696 char_u *p;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010697 int room;
10698 int use_sep_chars = (t_colors < 8
10699#ifdef FEAT_GUI
10700 && !gui.in_use
10701#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +020010702#ifdef FEAT_TERMGUICOLORS
10703 && !p_tgc
Bram Moolenaar8a633e32016-04-21 21:10:14 +020010704#endif
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010705 );
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010706
Bram Moolenaarc695cec2017-01-08 20:00:04 +010010707 if (ScreenLines == NULL)
10708 return;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010709 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010710
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010711#ifdef FEAT_GUI_TABLINE
Bram Moolenaardb552d602006-03-23 22:59:57 +000010712 /* Take care of a GUI tabline. */
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010713 if (gui_use_tabline())
10714 {
10715 gui_update_tabline();
10716 return;
10717 }
10718#endif
10719
10720 if (tabline_height() < 1)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010721 return;
10722
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010723#if defined(FEAT_STL_OPT)
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010724
10725 /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */
10726 for (scol = 0; scol < Columns; ++scol)
10727 TabPageIdxs[scol] = 0;
10728
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010729 /* Use the 'tabline' option if it's set. */
10730 if (*p_tal != NUL)
10731 {
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010732 int saved_did_emsg = did_emsg;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010733
10734 /* Check for an error. If there is one we would loop in redrawing the
10735 * screen. Avoid that by making 'tabline' empty. */
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010736 did_emsg = FALSE;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010737 win_redr_custom(NULL, FALSE);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010738 if (did_emsg)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010739 set_string_option_direct((char_u *)"tabline", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +000010740 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010741 did_emsg |= saved_did_emsg;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010742 }
Bram Moolenaar238a5642006-02-21 22:12:05 +000010743 else
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010744#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010745 {
Bram Moolenaar29323592016-07-24 22:04:11 +020010746 FOR_ALL_TABPAGES(tp)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010747 ++tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010748
Bram Moolenaar238a5642006-02-21 22:12:05 +000010749 tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
10750 if (tabwidth < 6)
10751 tabwidth = 6;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010752
Bram Moolenaar238a5642006-02-21 22:12:05 +000010753 attr = attr_nosel;
10754 tabcount = 0;
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010755 scol = 0;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010756 for (tp = first_tabpage; tp != NULL && col < Columns - 4;
10757 tp = tp->tp_next)
Bram Moolenaarf740b292006-02-16 22:11:02 +000010758 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010759 scol = col;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010760
Bram Moolenaar238a5642006-02-21 22:12:05 +000010761 if (tp->tp_topframe == topframe)
10762 attr = attr_sel;
10763 if (use_sep_chars && col > 0)
10764 screen_putchar('|', 0, col++, attr);
10765
10766 if (tp->tp_topframe != topframe)
10767 attr = attr_nosel;
10768
10769 screen_putchar(' ', 0, col++, attr);
10770
10771 if (tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +000010772 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010773 cwp = curwin;
10774 wp = firstwin;
10775 }
10776 else
10777 {
10778 cwp = tp->tp_curwin;
10779 wp = tp->tp_firstwin;
10780 }
10781
10782 modified = FALSE;
10783 for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
10784 if (bufIsChanged(wp->w_buffer))
10785 modified = TRUE;
10786 if (modified || wincount > 1)
10787 {
10788 if (wincount > 1)
10789 {
10790 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +000010791 len = (int)STRLEN(NameBuff);
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010792 if (col + len >= Columns - 3)
10793 break;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010794 screen_puts_len(NameBuff, len, 0, col,
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010795#if defined(FEAT_SYN_HL)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010796 hl_combine_attr(attr, HL_ATTR(HLF_T))
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010797#else
Bram Moolenaare0f14822014-08-06 13:20:56 +020010798 attr
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010799#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +000010800 );
10801 col += len;
10802 }
10803 if (modified)
10804 screen_puts_len((char_u *)"+", 1, 0, col++, attr);
10805 screen_putchar(' ', 0, col++, attr);
10806 }
10807
10808 room = scol - col + tabwidth - 1;
10809 if (room > 0)
10810 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010811 /* Get buffer name in NameBuff[] */
10812 get_trans_bufname(cwp->w_buffer);
Bram Moolenaar910f66f2006-04-05 20:41:53 +000010813 shorten_dir(NameBuff);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010814 len = vim_strsize(NameBuff);
10815 p = NameBuff;
10816#ifdef FEAT_MBYTE
10817 if (has_mbyte)
10818 while (len > room)
10819 {
10820 len -= ptr2cells(p);
Bram Moolenaar91acfff2017-03-12 19:22:36 +010010821 MB_PTR_ADV(p);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010822 }
10823 else
10824#endif
10825 if (len > room)
10826 {
10827 p += len - room;
10828 len = room;
10829 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010830 if (len > Columns - col - 1)
10831 len = Columns - col - 1;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010832
Bram Moolenaara93fa7e2006-04-17 22:14:47 +000010833 screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
Bram Moolenaarf740b292006-02-16 22:11:02 +000010834 col += len;
10835 }
Bram Moolenaarf740b292006-02-16 22:11:02 +000010836 screen_putchar(' ', 0, col++, attr);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010837
10838 /* Store the tab page number in TabPageIdxs[], so that
10839 * jump_to_mouse() knows where each one is. */
10840 ++tabcount;
10841 while (scol < col)
10842 TabPageIdxs[scol++] = tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010843 }
10844
Bram Moolenaar238a5642006-02-21 22:12:05 +000010845 if (use_sep_chars)
10846 c = '_';
10847 else
10848 c = ' ';
10849 screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010850
10851 /* Put an "X" for closing the current tab if there are several. */
10852 if (first_tabpage->tp_next != NULL)
10853 {
10854 screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
10855 TabPageIdxs[Columns - 1] = -999;
10856 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010857 }
Bram Moolenaarb21e5842006-04-16 18:30:08 +000010858
10859 /* Reset the flag here again, in case evaluating 'tabline' causes it to be
10860 * set. */
10861 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010862}
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010863
10864/*
10865 * Get buffer name for "buf" into NameBuff[].
10866 * Takes care of special buffer names and translates special characters.
10867 */
10868 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010869get_trans_bufname(buf_T *buf)
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010870{
10871 if (buf_spname(buf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +020010872 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010873 else
10874 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
10875 trans_characters(NameBuff, MAXPATHL);
10876}
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010877
Bram Moolenaar071d4272004-06-13 20:20:40 +000010878/*
10879 * Get the character to use in a status line. Get its attributes in "*attr".
10880 */
10881 static int
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010882fillchar_status(int *attr, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010883{
10884 int fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010885
10886#ifdef FEAT_TERMINAL
10887 if (bt_terminal(wp->w_buffer))
10888 {
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010889 if (wp == curwin)
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010890 {
10891 *attr = HL_ATTR(HLF_ST);
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010892 fill = fill_stl;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010893 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010894 else
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010895 {
10896 *attr = HL_ATTR(HLF_STNC);
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010897 fill = fill_stlnc;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010898 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010899 }
10900 else
10901#endif
10902 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010903 {
Bram Moolenaar8820b482017-03-16 17:23:31 +010010904 *attr = HL_ATTR(HLF_S);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010905 fill = fill_stl;
10906 }
10907 else
10908 {
Bram Moolenaar8820b482017-03-16 17:23:31 +010010909 *attr = HL_ATTR(HLF_SNC);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010910 fill = fill_stlnc;
10911 }
10912 /* Use fill when there is highlighting, and highlighting of current
10913 * window differs, or the fillchars differ, or this is not the
10914 * current window */
Bram Moolenaar8820b482017-03-16 17:23:31 +010010915 if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010916 || wp != curwin || ONE_WINDOW)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010917 || (fill_stl != fill_stlnc)))
10918 return fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010919 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010920 return '^';
10921 return '=';
10922}
Bram Moolenaar071d4272004-06-13 20:20:40 +000010923
Bram Moolenaar071d4272004-06-13 20:20:40 +000010924/*
10925 * Get the character to use in a separator between vertically split windows.
10926 * Get its attributes in "*attr".
10927 */
10928 static int
Bram Moolenaar05540972016-01-30 20:31:25 +010010929fillchar_vsep(int *attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010930{
Bram Moolenaar8820b482017-03-16 17:23:31 +010010931 *attr = HL_ATTR(HLF_C);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010932 if (*attr == 0 && fill_vert == ' ')
10933 return '|';
10934 else
10935 return fill_vert;
10936}
Bram Moolenaar071d4272004-06-13 20:20:40 +000010937
10938/*
10939 * Return TRUE if redrawing should currently be done.
10940 */
10941 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010942redrawing(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010943{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010010944#ifdef FEAT_EVAL
10945 if (disable_redraw_for_testing)
10946 return 0;
10947 else
10948#endif
Bram Moolenaared5a9d62018-09-06 13:14:43 +020010949 return ((!RedrawingDisabled
10950#ifdef FEAT_EVAL
10951 || ignore_redraw_flag_for_testing
10952#endif
10953 ) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
Bram Moolenaar071d4272004-06-13 20:20:40 +000010954}
10955
10956/*
10957 * Return TRUE if printing messages should currently be done.
10958 */
10959 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010960messaging(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010961{
10962 return (!(p_lz && char_avail() && !KeyTyped));
10963}
10964
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010965#ifdef FEAT_MENU
10966/*
10967 * Draw the window toolbar.
10968 */
10969 static void
10970redraw_win_toolbar(win_T *wp)
10971{
10972 vimmenu_T *menu;
10973 int item_idx = 0;
10974 int item_count = 0;
10975 int col = 0;
10976 int next_col;
10977 int off = (int)(current_ScreenLine - ScreenLines);
10978 int fill_attr = syn_name2attr((char_u *)"ToolbarLine");
10979 int button_attr = syn_name2attr((char_u *)"ToolbarButton");
10980
10981 vim_free(wp->w_winbar_items);
10982 for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next)
10983 ++item_count;
10984 wp->w_winbar_items = (winbar_item_T *)alloc_clear(
10985 (unsigned)sizeof(winbar_item_T) * (item_count + 1));
10986
10987 /* TODO: use fewer spaces if there is not enough room */
10988 for (menu = wp->w_winbar->children;
Bram Moolenaar02631462017-09-22 15:20:32 +020010989 menu != NULL && col < wp->w_width; menu = menu->next)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010990 {
10991 space_to_screenline(off + col, fill_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010992 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010993 break;
10994 if (col > 1)
10995 {
10996 space_to_screenline(off + col, fill_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010997 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010998 break;
10999 }
11000
11001 wp->w_winbar_items[item_idx].wb_startcol = col;
11002 space_to_screenline(off + col, button_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020011003 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020011004 break;
11005
11006 next_col = text_to_screenline(wp, menu->name, col);
11007 while (col < next_col)
11008 {
11009 ScreenAttrs[off + col] = button_attr;
11010 ++col;
11011 }
11012 wp->w_winbar_items[item_idx].wb_endcol = col;
11013 wp->w_winbar_items[item_idx].wb_menu = menu;
11014 ++item_idx;
11015
Bram Moolenaar02631462017-09-22 15:20:32 +020011016 if (col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020011017 break;
11018 space_to_screenline(off + col, button_attr);
11019 ++col;
11020 }
Bram Moolenaar02631462017-09-22 15:20:32 +020011021 while (col < wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020011022 {
11023 space_to_screenline(off + col, fill_attr);
11024 ++col;
11025 }
11026 wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */
11027
Bram Moolenaar02631462017-09-22 15:20:32 +020011028 screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
11029 (int)wp->w_width, FALSE);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020011030}
11031#endif
Bram Moolenaar491ac282018-06-17 14:47:55 +020011032
Bram Moolenaar071d4272004-06-13 20:20:40 +000011033/*
11034 * Show current status info in ruler and various other places
11035 * If always is FALSE, only show ruler if position has changed.
11036 */
11037 void
Bram Moolenaar05540972016-01-30 20:31:25 +010011038showruler(int always)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011039{
11040 if (!always && !redrawing())
11041 return;
Bram Moolenaar9372a112005-12-06 19:59:18 +000011042#ifdef FEAT_INS_EXPAND
11043 if (pum_visible())
11044 {
11045 /* Don't redraw right now, do it later. */
11046 curwin->w_redr_status = TRUE;
11047 return;
11048 }
11049#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +020011050#if defined(FEAT_STL_OPT)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +000011051 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
Bram Moolenaar238a5642006-02-21 22:12:05 +000011052 {
Bram Moolenaar362f3562009-11-03 16:20:34 +000011053 redraw_custom_statusline(curwin);
Bram Moolenaar238a5642006-02-21 22:12:05 +000011054 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000011055 else
11056#endif
11057#ifdef FEAT_CMDL_INFO
Bram Moolenaar491ac282018-06-17 14:47:55 +020011058 win_redr_ruler(curwin, always, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011059#endif
11060
11061#ifdef FEAT_TITLE
11062 if (need_maketitle
11063# ifdef FEAT_STL_OPT
11064 || (p_icon && (stl_syntax & STL_IN_ICON))
11065 || (p_title && (stl_syntax & STL_IN_TITLE))
11066# endif
11067 )
11068 maketitle();
11069#endif
Bram Moolenaar497683b2008-05-28 17:02:46 +000011070 /* Redraw the tab pages line if needed. */
11071 if (redraw_tabline)
11072 draw_tabline();
Bram Moolenaar071d4272004-06-13 20:20:40 +000011073}
11074
11075#ifdef FEAT_CMDL_INFO
11076 static void
Bram Moolenaar491ac282018-06-17 14:47:55 +020011077win_redr_ruler(win_T *wp, int always, int ignore_pum)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011078{
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011079#define RULER_BUF_LEN 70
11080 char_u buffer[RULER_BUF_LEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +000011081 int row;
11082 int fillchar;
11083 int attr;
11084 int empty_line = FALSE;
11085 colnr_T virtcol;
11086 int i;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011087 size_t len;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011088 int o;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011089 int this_ru_col;
11090 int off = 0;
11091 int width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011092
11093 /* If 'ruler' off or redrawing disabled, don't do anything */
11094 if (!p_ru)
11095 return;
11096
11097 /*
11098 * Check if cursor.lnum is valid, since win_redr_ruler() may be called
11099 * after deleting lines, before cursor.lnum is corrected.
11100 */
11101 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
11102 return;
11103
11104#ifdef FEAT_INS_EXPAND
11105 /* Don't draw the ruler while doing insert-completion, it might overwrite
11106 * the (long) mode message. */
Bram Moolenaar071d4272004-06-13 20:20:40 +000011107 if (wp == lastwin && lastwin->w_status_height == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011108 if (edit_submode != NULL)
11109 return;
Bram Moolenaar491ac282018-06-17 14:47:55 +020011110 // Don't draw the ruler when the popup menu is visible, it may overlap.
11111 // Except when the popup menu will be redrawn anyway.
11112 if (!ignore_pum && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +000011113 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011114#endif
11115
11116#ifdef FEAT_STL_OPT
11117 if (*p_ruf)
11118 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000011119 int save_called_emsg = called_emsg;
11120
11121 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011122 win_redr_custom(wp, TRUE);
Bram Moolenaar238a5642006-02-21 22:12:05 +000011123 if (called_emsg)
11124 set_string_option_direct((char_u *)"rulerformat", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +000011125 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaar238a5642006-02-21 22:12:05 +000011126 called_emsg |= save_called_emsg;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011127 return;
11128 }
11129#endif
11130
11131 /*
11132 * Check if not in Insert mode and the line is empty (will show "0-1").
11133 */
11134 if (!(State & INSERT)
11135 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
11136 empty_line = TRUE;
11137
11138 /*
11139 * Only draw the ruler when something changed.
11140 */
11141 validate_virtcol_win(wp);
11142 if ( redraw_cmdline
11143 || always
11144 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
11145 || wp->w_cursor.col != wp->w_ru_cursor.col
11146 || wp->w_virtcol != wp->w_ru_virtcol
11147#ifdef FEAT_VIRTUALEDIT
11148 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
11149#endif
11150 || wp->w_topline != wp->w_ru_topline
11151 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
11152#ifdef FEAT_DIFF
11153 || wp->w_topfill != wp->w_ru_topfill
11154#endif
11155 || empty_line != wp->w_ru_empty)
11156 {
11157 cursor_off();
Bram Moolenaar071d4272004-06-13 20:20:40 +000011158 if (wp->w_status_height)
11159 {
11160 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020011161 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar53f81742017-09-22 14:35:51 +020011162 off = wp->w_wincol;
Bram Moolenaar02631462017-09-22 15:20:32 +020011163 width = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011164 }
11165 else
Bram Moolenaar071d4272004-06-13 20:20:40 +000011166 {
11167 row = Rows - 1;
11168 fillchar = ' ';
11169 attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011170 width = Columns;
11171 off = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011172 }
11173
11174 /* In list mode virtcol needs to be recomputed */
11175 virtcol = wp->w_virtcol;
11176 if (wp->w_p_list && lcs_tab1 == NUL)
11177 {
11178 wp->w_p_list = FALSE;
11179 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
11180 wp->w_p_list = TRUE;
11181 }
11182
11183 /*
11184 * Some sprintfs return the length, some return a pointer.
11185 * To avoid portability problems we use strlen() here.
11186 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011187 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
Bram Moolenaar071d4272004-06-13 20:20:40 +000011188 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
11189 ? 0L
11190 : (long)(wp->w_cursor.lnum));
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011191 len = STRLEN(buffer);
11192 col_print(buffer + len, RULER_BUF_LEN - len,
Bram Moolenaar071d4272004-06-13 20:20:40 +000011193 empty_line ? 0 : (int)wp->w_cursor.col + 1,
11194 (int)virtcol + 1);
11195
11196 /*
11197 * Add a "50%" if there is room for it.
11198 * On the last line, don't print in the last column (scrolls the
11199 * screen up on some terminals).
11200 */
11201 i = (int)STRLEN(buffer);
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011202 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011203 o = i + vim_strsize(buffer + i + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011204 if (wp->w_status_height == 0) /* can't use last char of screen */
Bram Moolenaar071d4272004-06-13 20:20:40 +000011205 ++o;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011206 this_ru_col = ru_col - (Columns - width);
11207 if (this_ru_col < 0)
11208 this_ru_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011209 /* Never use more than half the window/screen width, leave the other
11210 * half for the filename. */
Bram Moolenaar4033c552017-09-16 20:54:51 +020011211 if (this_ru_col < (width + 1) / 2)
11212 this_ru_col = (width + 1) / 2;
11213 if (this_ru_col + o < width)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011214 {
Bram Moolenaar0027c212015-01-07 13:31:52 +010011215 /* need at least 3 chars left for get_rel_pos() + NUL */
Bram Moolenaar4033c552017-09-16 20:54:51 +020011216 while (this_ru_col + o < width && RULER_BUF_LEN > i + 4)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011217 {
11218#ifdef FEAT_MBYTE
11219 if (has_mbyte)
11220 i += (*mb_char2bytes)(fillchar, buffer + i);
11221 else
11222#endif
11223 buffer[i++] = fillchar;
11224 ++o;
11225 }
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011226 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011227 }
11228 /* Truncate at window boundary. */
11229#ifdef FEAT_MBYTE
11230 if (has_mbyte)
11231 {
11232 o = 0;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +000011233 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +000011234 {
11235 o += (*mb_ptr2cells)(buffer + i);
Bram Moolenaar4033c552017-09-16 20:54:51 +020011236 if (this_ru_col + o > width)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011237 {
11238 buffer[i] = NUL;
11239 break;
11240 }
11241 }
11242 }
11243 else
11244#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +020011245 if (this_ru_col + (int)STRLEN(buffer) > width)
11246 buffer[width - this_ru_col] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011247
Bram Moolenaar4033c552017-09-16 20:54:51 +020011248 screen_puts(buffer, row, this_ru_col + off, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011249 i = redraw_cmdline;
11250 screen_fill(row, row + 1,
Bram Moolenaar4033c552017-09-16 20:54:51 +020011251 this_ru_col + off + (int)STRLEN(buffer),
11252 (int)(off + width),
Bram Moolenaar071d4272004-06-13 20:20:40 +000011253 fillchar, fillchar, attr);
11254 /* don't redraw the cmdline because of showing the ruler */
11255 redraw_cmdline = i;
11256 wp->w_ru_cursor = wp->w_cursor;
11257 wp->w_ru_virtcol = wp->w_virtcol;
11258 wp->w_ru_empty = empty_line;
11259 wp->w_ru_topline = wp->w_topline;
11260 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
11261#ifdef FEAT_DIFF
11262 wp->w_ru_topfill = wp->w_topfill;
11263#endif
11264 }
11265}
11266#endif
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011267
11268#if defined(FEAT_LINEBREAK) || defined(PROTO)
11269/*
Bram Moolenaar64486672010-05-16 15:46:46 +020011270 * Return the width of the 'number' and 'relativenumber' column.
11271 * Caller may need to check if 'number' or 'relativenumber' is set.
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011272 * Otherwise it depends on 'numberwidth' and the line count.
11273 */
11274 int
Bram Moolenaar05540972016-01-30 20:31:25 +010011275number_width(win_T *wp)
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011276{
11277 int n;
11278 linenr_T lnum;
11279
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +020011280 if (wp->w_p_rnu && !wp->w_p_nu)
11281 /* cursor line shows "0" */
11282 lnum = wp->w_height;
11283 else
11284 /* cursor line shows absolute line number */
11285 lnum = wp->w_buffer->b_ml.ml_line_count;
Bram Moolenaar64486672010-05-16 15:46:46 +020011286
Bram Moolenaar6b314672015-03-20 15:42:10 +010011287 if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011288 return wp->w_nrwidth_width;
11289 wp->w_nrwidth_line_count = lnum;
11290
11291 n = 0;
11292 do
11293 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000011294 lnum /= 10;
11295 ++n;
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011296 } while (lnum > 0);
11297
11298 /* 'numberwidth' gives the minimal width plus one */
11299 if (n < wp->w_p_nuw - 1)
11300 n = wp->w_p_nuw - 1;
11301
11302 wp->w_nrwidth_width = n;
Bram Moolenaar6b314672015-03-20 15:42:10 +010011303 wp->w_nuw_cached = wp->w_p_nuw;
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011304 return n;
11305}
11306#endif
Bram Moolenaar9750bb12012-12-05 16:10:42 +010011307
11308/*
11309 * Return the current cursor column. This is the actual position on the
11310 * screen. First column is 0.
11311 */
11312 int
Bram Moolenaar05540972016-01-30 20:31:25 +010011313screen_screencol(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +010011314{
11315 return screen_cur_col;
11316}
11317
11318/*
11319 * Return the current cursor row. This is the actual position on the screen.
11320 * First row is 0.
11321 */
11322 int
Bram Moolenaar05540972016-01-30 20:31:25 +010011323screen_screenrow(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +010011324{
11325 return screen_cur_row;
11326}