blob: cb2d07b027c778831b51381d5b076fb8d64c2fec [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 Moolenaarbbca7732019-07-24 18:13:16 +0200107static 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 Moolenaar8ee4c012019-03-29 18:08:18 +0100126static void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, 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 Moolenaarbaaa7e92016-01-29 22:47:03 +0100138static void start_search_hl(void);
139static void end_search_hl(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100141static void screen_char(unsigned off, int row, int col);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100142static void screen_char_2(unsigned off, int row, int col);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100143static void screenclear2(void);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200144static void lineclear(unsigned off, int width, int attr);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100145static void lineinvalid(unsigned off, int width);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200146static 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 +0100147static void win_rest_invalid(win_T *wp);
148static void msg_pos_mode(void);
149static void recording_mode(int attr);
Bram Moolenaar3633cf52017-07-31 22:29:35 +0200150static int fillchar_status(int *attr, win_T *wp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100151static int fillchar_vsep(int *attr);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +0200152#ifdef FEAT_MENU
153static void redraw_win_toolbar(win_T *wp);
154#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155#ifdef FEAT_STL_OPT
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100156static void win_redr_custom(win_T *wp, int draw_ruler);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157#endif
158#ifdef FEAT_CMDL_INFO
Bram Moolenaar491ac282018-06-17 14:47:55 +0200159static void win_redr_ruler(win_T *wp, int always, int ignore_pum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160#endif
161
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162/* Ugly global: overrule attribute used by screen_char() */
163static int screen_char_attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164
Bram Moolenaarc0aa4822017-07-16 14:04:29 +0200165#ifdef FEAT_RIGHTLEFT
166# define HAS_RIGHTLEFT(x) x
167#else
168# define HAS_RIGHTLEFT(x) FALSE
169#endif
170
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200171// flags for screen_line()
172#define SLF_RIGHTLEFT 1
173#define SLF_POPUP 2
174
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175/*
176 * Redraw the current window later, with update_screen(type).
177 * Set must_redraw only if not already set to a higher value.
Bram Moolenaarae654382019-01-17 21:09:05 +0100178 * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 */
180 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100181redraw_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182{
183 redraw_win_later(curwin, type);
184}
185
186 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100187redraw_win_later(
188 win_T *wp,
189 int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190{
Bram Moolenaar4f198282017-10-23 21:53:30 +0200191 if (!exiting && wp->w_redr_type < type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192 {
193 wp->w_redr_type = type;
194 if (type >= NOT_VALID)
195 wp->w_lines_valid = 0;
196 if (must_redraw < type) /* must_redraw is the maximum of all windows */
197 must_redraw = type;
198 }
199}
200
201/*
202 * Force a complete redraw later. Also resets the highlighting. To be used
203 * after executing a shell command that messes up the screen.
204 */
205 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100206redraw_later_clear(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207{
208 redraw_all_later(CLEAR);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000209#ifdef FEAT_GUI
210 if (gui.in_use)
211 /* Use a code that will reset gui.highlight_mask in
212 * gui_stop_highlight(). */
213 screen_attr = HL_ALL + 1;
214 else
215#endif
216 /* Use attributes that is very unlikely to appear in text. */
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +0200217 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218}
219
220/*
221 * Mark all windows to be redrawn later.
222 */
223 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100224redraw_all_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225{
226 win_T *wp;
227
228 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229 redraw_win_later(wp, type);
Bram Moolenaar04b4e1a2019-01-06 22:22:07 +0100230 // This may be needed when switching tabs.
231 if (must_redraw < type)
232 must_redraw = type;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233}
234
235/*
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000236 * Mark all windows that are editing the current buffer to be updated later.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000237 */
238 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100239redraw_curbuf_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240{
241 redraw_buf_later(curbuf, type);
242}
243
244 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100245redraw_buf_later(buf_T *buf, int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000246{
247 win_T *wp;
248
249 FOR_ALL_WINDOWS(wp)
250 {
251 if (wp->w_buffer == buf)
252 redraw_win_later(wp, type);
253 }
254}
255
Bram Moolenaar113e1072019-01-20 15:30:40 +0100256#if defined(FEAT_SIGNS) || defined(PROTO)
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200257 void
Bram Moolenaar27a472c2019-01-09 21:47:30 +0100258redraw_buf_line_later(buf_T *buf, linenr_T lnum)
259{
260 win_T *wp;
261
262 FOR_ALL_WINDOWS(wp)
263 if (wp->w_buffer == buf && lnum >= wp->w_topline
264 && lnum < wp->w_botline)
265 redrawWinline(wp, lnum);
266}
Bram Moolenaar113e1072019-01-20 15:30:40 +0100267#endif
Bram Moolenaar27a472c2019-01-09 21:47:30 +0100268
Bram Moolenaar113e1072019-01-20 15:30:40 +0100269#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar27a472c2019-01-09 21:47:30 +0100270 void
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200271redraw_buf_and_status_later(buf_T *buf, int type)
272{
273 win_T *wp;
274
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200275#ifdef FEAT_WILDMENU
Bram Moolenaar86033562017-07-12 20:24:41 +0200276 if (wild_menu_showing != 0)
277 /* Don't redraw while the command line completion is displayed, it
278 * would disappear. */
279 return;
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200280#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200281 FOR_ALL_WINDOWS(wp)
282 {
283 if (wp->w_buffer == buf)
284 {
285 redraw_win_later(wp, type);
286 wp->w_redr_status = TRUE;
287 }
288 }
289}
Bram Moolenaar113e1072019-01-20 15:30:40 +0100290#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200291
Bram Moolenaar113e1072019-01-20 15:30:40 +0100292#if defined(FEAT_TERMRESPONSE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000293/*
Bram Moolenaar2951b772013-07-03 12:45:31 +0200294 * Redraw as soon as possible. When the command line is not scrolled redraw
295 * right away and restore what was on the command line.
296 * Return a code indicating what happened.
297 */
298 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100299redraw_asap(int type)
Bram Moolenaar2951b772013-07-03 12:45:31 +0200300{
301 int rows;
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200302 int cols = screen_Columns;
Bram Moolenaar2951b772013-07-03 12:45:31 +0200303 int r;
304 int ret = 0;
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200305 schar_T *screenline; /* copy from ScreenLines[] */
306 sattr_T *screenattr; /* copy from ScreenAttrs[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200307 int i;
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200308 u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200309 u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200310 schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200311
312 redraw_later(type);
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200313 if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
Bram Moolenaar2951b772013-07-03 12:45:31 +0200314 return ret;
315
316 /* Allocate space to save the text displayed in the command line area. */
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200317 rows = screen_Rows - cmdline_row;
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200318 screenline = LALLOC_MULT(schar_T, rows * cols);
319 screenattr = LALLOC_MULT(sattr_T, rows * cols);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200320 if (screenline == NULL || screenattr == NULL)
321 ret = 2;
Bram Moolenaar2951b772013-07-03 12:45:31 +0200322 if (enc_utf8)
323 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200324 screenlineUC = LALLOC_MULT(u8char_T, rows * cols);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200325 if (screenlineUC == NULL)
326 ret = 2;
327 for (i = 0; i < p_mco; ++i)
328 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200329 screenlineC[i] = LALLOC_MULT(u8char_T, rows * cols);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200330 if (screenlineC[i] == NULL)
331 ret = 2;
332 }
333 }
334 if (enc_dbcs == DBCS_JPNU)
335 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200336 screenline2 = LALLOC_MULT(schar_T, rows * cols);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200337 if (screenline2 == NULL)
338 ret = 2;
339 }
Bram Moolenaar2951b772013-07-03 12:45:31 +0200340
341 if (ret != 2)
342 {
343 /* Save the text displayed in the command line area. */
344 for (r = 0; r < rows; ++r)
345 {
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200346 mch_memmove(screenline + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200347 ScreenLines + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200348 (size_t)cols * sizeof(schar_T));
349 mch_memmove(screenattr + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200350 ScreenAttrs + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200351 (size_t)cols * sizeof(sattr_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200352 if (enc_utf8)
353 {
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200354 mch_memmove(screenlineUC + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200355 ScreenLinesUC + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200356 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200357 for (i = 0; i < p_mco; ++i)
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200358 mch_memmove(screenlineC[i] + r * cols,
359 ScreenLinesC[i] + LineOffset[cmdline_row + r],
360 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200361 }
362 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200363 mch_memmove(screenline2 + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200364 ScreenLines2 + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200365 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200366 }
367
368 update_screen(0);
369 ret = 3;
370
371 if (must_redraw == 0)
372 {
373 int off = (int)(current_ScreenLine - ScreenLines);
374
375 /* Restore the text displayed in the command line area. */
376 for (r = 0; r < rows; ++r)
377 {
378 mch_memmove(current_ScreenLine,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200379 screenline + r * cols,
380 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200381 mch_memmove(ScreenAttrs + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200382 screenattr + r * cols,
383 (size_t)cols * sizeof(sattr_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200384 if (enc_utf8)
385 {
386 mch_memmove(ScreenLinesUC + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200387 screenlineUC + r * cols,
388 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200389 for (i = 0; i < p_mco; ++i)
390 mch_memmove(ScreenLinesC[i] + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200391 screenlineC[i] + r * cols,
392 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200393 }
394 if (enc_dbcs == DBCS_JPNU)
395 mch_memmove(ScreenLines2 + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200396 screenline2 + r * cols,
397 (size_t)cols * sizeof(schar_T));
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200398 screen_line(cmdline_row + r, 0, cols, cols, 0);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200399 }
400 ret = 4;
401 }
Bram Moolenaar2951b772013-07-03 12:45:31 +0200402 }
403
404 vim_free(screenline);
405 vim_free(screenattr);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200406 if (enc_utf8)
407 {
408 vim_free(screenlineUC);
409 for (i = 0; i < p_mco; ++i)
410 vim_free(screenlineC[i]);
411 }
412 if (enc_dbcs == DBCS_JPNU)
413 vim_free(screenline2);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200414
Bram Moolenaar249f0dd2013-07-04 22:31:03 +0200415 /* Show the intro message when appropriate. */
416 maybe_intro_message();
417
418 setcursor();
419
Bram Moolenaar2951b772013-07-03 12:45:31 +0200420 return ret;
421}
Bram Moolenaar113e1072019-01-20 15:30:40 +0100422#endif
Bram Moolenaar2951b772013-07-03 12:45:31 +0200423
424/*
Bram Moolenaar975b5272016-03-15 23:10:59 +0100425 * Invoked after an asynchronous callback is called.
426 * If an echo command was used the cursor needs to be put back where
427 * it belongs. If highlighting was changed a redraw is needed.
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200428 * If "call_update_screen" is FALSE don't call update_screen() when at the
429 * command line.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100430 */
431 void
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200432redraw_after_callback(int call_update_screen)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100433{
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200434 ++redrawing_for_callback;
435
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100436 if (State == HITRETURN || State == ASKMORE)
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200437 ; // do nothing
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100438 else if (State & CMDLINE)
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200439 {
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200440 // Don't redraw when in prompt_for_number().
441 if (cmdline_row > 0)
442 {
443 // Redrawing only works when the screen didn't scroll. Don't clear
444 // wildmenu entries.
445 if (msg_scrolled == 0
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200446#ifdef FEAT_WILDMENU
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200447 && wild_menu_showing == 0
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200448#endif
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200449 && call_update_screen)
450 update_screen(0);
451
452 // Redraw in the same position, so that the user can continue
453 // editing the command.
454 redrawcmdline_ex(FALSE);
455 }
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200456 }
Bram Moolenaar1b9645d2017-09-17 23:03:31 +0200457 else if (State & (NORMAL | INSERT | TERMINAL))
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100458 {
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200459 // keep the command line if possible
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200460 update_screen(VALID_NO_UPDATE);
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100461 setcursor();
462 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100463 cursor_on();
Bram Moolenaar975b5272016-03-15 23:10:59 +0100464#ifdef FEAT_GUI
Bram Moolenaara338adc2018-01-31 20:51:47 +0100465 if (gui.in_use && !gui_mch_is_blink_off())
Bram Moolenaar4cbdf152018-08-26 21:23:07 +0200466 // Don't update the cursor when it is blinking and off to avoid
467 // flicker.
Bram Moolenaara338adc2018-01-31 20:51:47 +0100468 out_flush_cursor(FALSE, FALSE);
469 else
Bram Moolenaar975b5272016-03-15 23:10:59 +0100470#endif
Bram Moolenaaracda04f2018-02-08 09:57:28 +0100471 out_flush();
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200472
473 --redrawing_for_callback;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100474}
475
476/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 * Changed something in the current window, at buffer line "lnum", that
478 * requires that line and possibly other lines to be redrawn.
479 * Used when entering/leaving Insert mode with the cursor on a folded line.
480 * Used to remove the "$" from a change command.
481 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
482 * may become invalid and the whole window will have to be redrawn.
483 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000484 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100485redrawWinline(
Bram Moolenaar90a99792018-09-12 21:52:18 +0200486 win_T *wp,
Bram Moolenaarae12f4b2019-01-09 20:51:04 +0100487 linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488{
Bram Moolenaar90a99792018-09-12 21:52:18 +0200489 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
490 wp->w_redraw_top = lnum;
491 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
492 wp->w_redraw_bot = lnum;
493 redraw_win_later(wp, VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000494}
495
Bram Moolenaar68a4b042019-05-29 22:28:29 +0200496/*
497 * To be called when "updating_screen" was set before and now the postponed
498 * side effects may take place.
499 */
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200500 void
Bram Moolenaar68a4b042019-05-29 22:28:29 +0200501after_updating_screen(int may_resize_shell UNUSED)
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200502{
503 updating_screen = FALSE;
504#ifdef FEAT_GUI
505 if (may_resize_shell)
506 gui_may_resize_shell();
507#endif
508#ifdef FEAT_TERMINAL
509 term_check_channel_closed_recently();
510#endif
Bram Moolenaar92d147b2018-07-29 17:35:23 +0200511
512#ifdef HAVE_DROP_FILE
513 // If handle_drop() was called while updating_screen was TRUE need to
514 // handle the drop now.
515 handle_any_postponed_drop();
516#endif
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200517}
518
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519/*
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200520 * Update all windows that are editing the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 */
522 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100523update_curbuf(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524{
525 redraw_curbuf_later(type);
526 update_screen(type);
527}
528
529/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 * Based on the current value of curwin->w_topline, transfer a screenfull
531 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
Bram Moolenaar072412e2017-09-13 22:11:35 +0200532 * Return OK when the screen was updated, FAIL if it was not done.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000533 */
Bram Moolenaar072412e2017-09-13 22:11:35 +0200534 int
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200535update_screen(int type_arg)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536{
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200537 int type = type_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000538 win_T *wp;
539 static int did_intro = FALSE;
540#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
541 int did_one;
542#endif
Bram Moolenaar144445d2016-07-08 21:41:54 +0200543#ifdef FEAT_GUI
Bram Moolenaar107abd22016-08-12 14:08:25 +0200544 int did_undraw = FALSE;
Bram Moolenaar1f3601e2019-04-26 20:33:00 +0200545 int gui_cursor_col = 0;
546 int gui_cursor_row = 0;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200547#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200548 int no_update = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000550 /* Don't do anything if the screen structures are (not yet) valid. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 if (!screen_valid(TRUE))
Bram Moolenaar072412e2017-09-13 22:11:35 +0200552 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200554 if (type == VALID_NO_UPDATE)
555 {
556 no_update = TRUE;
557 type = 0;
558 }
559
Bram Moolenaara3347722019-05-11 21:14:24 +0200560#ifdef FEAT_EVAL
Bram Moolenaarfe1ade02019-05-14 21:20:36 +0200561 {
562 buf_T *buf;
563
564 // Before updating the screen, notify any listeners of changed text.
565 FOR_ALL_BUFFERS(buf)
566 invoke_listeners(buf);
567 }
Bram Moolenaara3347722019-05-11 21:14:24 +0200568#endif
569
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 if (must_redraw)
571 {
572 if (type < must_redraw) /* use maximal type */
573 type = must_redraw;
Bram Moolenaar943fae42007-07-30 20:00:38 +0000574
575 /* must_redraw is reset here, so that when we run into some weird
576 * reason to redraw while busy redrawing (e.g., asynchronous
577 * scrolling), or update_topline() in win_update() will cause a
578 * scroll, the screen will be redrawn later or in win_update(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 must_redraw = 0;
580 }
581
Bram Moolenaar6eddadf2018-05-06 16:40:16 +0200582 /* May need to update w_lines[]. */
583 if (curwin->w_lines_valid == 0 && type < NOT_VALID
584#ifdef FEAT_TERMINAL
585 && !term_do_update_window(curwin)
586#endif
587 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588 type = NOT_VALID;
589
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000590 /* Postpone the redrawing when it's not needed and when being called
591 * recursively. */
592 if (!redrawing() || updating_screen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593 {
594 redraw_later(type); /* remember type for next time */
595 must_redraw = type;
596 if (type > INVERTED_ALL)
597 curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
Bram Moolenaar072412e2017-09-13 22:11:35 +0200598 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599 }
Bram Moolenaarec572ad2019-07-07 14:26:59 +0200600 updating_screen = TRUE;
Bram Moolenaar33796b32019-06-08 16:01:13 +0200601
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200602#ifdef FEAT_TEXT_PROP
Bram Moolenaar4c063a02019-06-10 21:24:12 +0200603 // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot
604 // in some windows.
605 may_update_popup_mask(type);
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608#ifdef FEAT_SYN_HL
609 ++display_tick; /* let syntax code know we're in a next round of
610 * display updating */
611#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200612 if (no_update)
613 ++no_win_do_lines_ins;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614
615 /*
616 * if the screen was scrolled up when displaying a message, scroll it down
617 */
618 if (msg_scrolled)
619 {
620 clear_cmdline = TRUE;
621 if (msg_scrolled > Rows - 5) /* clearing is faster */
622 type = CLEAR;
623 else if (type != CLEAR)
624 {
625 check_for_delay(FALSE);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200626 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
627 == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 type = CLEAR;
629 FOR_ALL_WINDOWS(wp)
630 {
Bram Moolenaar98fb65c2019-06-02 20:33:32 +0200631 if (wp->w_winrow < msg_scrolled)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 {
633 if (W_WINROW(wp) + wp->w_height > msg_scrolled
634 && wp->w_redr_type < REDRAW_TOP
635 && wp->w_lines_valid > 0
636 && wp->w_topline == wp->w_lines[0].wl_lnum)
637 {
638 wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
639 wp->w_redr_type = REDRAW_TOP;
640 }
641 else
642 {
643 wp->w_redr_type = NOT_VALID;
Bram Moolenaare0de17d2017-09-24 16:24:34 +0200644 if (W_WINROW(wp) + wp->w_height + wp->w_status_height
645 <= msg_scrolled)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 }
648 }
649 }
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200650 if (!no_update)
651 redraw_cmdline = TRUE;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +0000652 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000653 }
654 msg_scrolled = 0;
655 need_wait_return = FALSE;
656 }
657
658 /* reset cmdline_row now (may have been changed temporarily) */
659 compute_cmdrow();
660
661 /* Check for changed highlighting */
662 if (need_highlight_changed)
663 highlight_changed();
664
665 if (type == CLEAR) /* first clear screen */
666 {
667 screenclear(); /* will reset clear_cmdline */
668 type = NOT_VALID;
Bram Moolenaar9f5f7bf2017-06-28 20:45:26 +0200669 /* must_redraw may be set indirectly, avoid another redraw later */
670 must_redraw = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000671 }
672
673 if (clear_cmdline) /* going to clear cmdline (done below) */
674 check_for_delay(FALSE);
675
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000676#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +0200677 /* Force redraw when width of 'number' or 'relativenumber' column
678 * changes. */
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000679 if (curwin->w_redr_type < NOT_VALID
Bram Moolenaar64486672010-05-16 15:46:46 +0200680 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
681 ? number_width(curwin) : 0))
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000682 curwin->w_redr_type = NOT_VALID;
683#endif
684
Bram Moolenaar071d4272004-06-13 20:20:40 +0000685 /*
686 * Only start redrawing if there is really something to do.
687 */
688 if (type == INVERTED)
689 update_curswant();
690 if (curwin->w_redr_type < type
691 && !((type == VALID
692 && curwin->w_lines[0].wl_valid
693#ifdef FEAT_DIFF
694 && curwin->w_topfill == curwin->w_old_topfill
695 && curwin->w_botfill == curwin->w_old_botfill
696#endif
697 && curwin->w_topline == curwin->w_lines[0].wl_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698 || (type == INVERTED
Bram Moolenaarb0c9a852006-11-28 15:14:56 +0000699 && VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
701 && curwin->w_old_visual_mode == VIsual_mode
702 && (curwin->w_valid & VALID_VIRTCOL)
703 && curwin->w_old_curswant == curwin->w_curswant)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 ))
705 curwin->w_redr_type = type;
706
Bram Moolenaar5a305422006-04-28 22:38:25 +0000707 /* Redraw the tab pages line if needed. */
708 if (redraw_tabline || type >= NOT_VALID)
709 draw_tabline();
Bram Moolenaar5a305422006-04-28 22:38:25 +0000710
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711#ifdef FEAT_SYN_HL
712 /*
713 * Correct stored syntax highlighting info for changes in each displayed
714 * buffer. Each buffer must only be done once.
715 */
716 FOR_ALL_WINDOWS(wp)
717 {
718 if (wp->w_buffer->b_mod_set)
719 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720 win_T *wwp;
721
722 /* Check if we already did this buffer. */
723 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
724 if (wwp->w_buffer == wp->w_buffer)
725 break;
Bram Moolenaar4033c552017-09-16 20:54:51 +0200726 if (wwp == wp && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 syn_stack_apply_changes(wp->w_buffer);
728 }
729 }
730#endif
731
732 /*
733 * Go from top to bottom through the windows, redrawing the ones that need
734 * it.
735 */
736#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
737 did_one = FALSE;
738#endif
739#ifdef FEAT_SEARCH_EXTRA
740 search_hl.rm.regprog = NULL;
741#endif
742 FOR_ALL_WINDOWS(wp)
743 {
744 if (wp->w_redr_type != 0)
745 {
746 cursor_off();
747#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
748 if (!did_one)
749 {
750 did_one = TRUE;
751# ifdef FEAT_SEARCH_EXTRA
752 start_search_hl();
753# endif
754# ifdef FEAT_CLIPBOARD
755 /* When Visual area changed, may have to update selection. */
Bram Moolenaarc0885aa2012-07-10 16:49:23 +0200756 if (clip_star.available && clip_isautosel_star())
757 clip_update_selection(&clip_star);
758 if (clip_plus.available && clip_isautosel_plus())
759 clip_update_selection(&clip_plus);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760# endif
761#ifdef FEAT_GUI
762 /* Remove the cursor before starting to do anything, because
763 * scrolling may make it difficult to redraw the text under
764 * it. */
Bram Moolenaar107abd22016-08-12 14:08:25 +0200765 if (gui.in_use && wp == curwin)
Bram Moolenaar144445d2016-07-08 21:41:54 +0200766 {
767 gui_cursor_col = gui.cursor_col;
768 gui_cursor_row = gui.cursor_row;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 gui_undraw_cursor();
Bram Moolenaar107abd22016-08-12 14:08:25 +0200770 did_undraw = TRUE;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200771 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772#endif
773 }
774#endif
775 win_update(wp);
776 }
777
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 /* redraw status line after the window to minimize cursor movement */
779 if (wp->w_redr_status)
780 {
781 cursor_off();
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +0200782 win_redr_status(wp, TRUE); // any popup menu will be redrawn below
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 }
785#if defined(FEAT_SEARCH_EXTRA)
786 end_search_hl();
787#endif
Bram Moolenaar51971b32013-02-13 12:16:05 +0100788#ifdef FEAT_INS_EXPAND
789 /* May need to redraw the popup menu. */
Bram Moolenaar491ac282018-06-17 14:47:55 +0200790 pum_may_redraw();
Bram Moolenaar51971b32013-02-13 12:16:05 +0100791#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 /* Reset b_mod_set flags. Going through all windows is probably faster
794 * than going through all buffers (there could be many buffers). */
Bram Moolenaar29323592016-07-24 22:04:11 +0200795 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 wp->w_buffer->b_mod_set = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000797
Bram Moolenaar13d5c3f2019-07-28 21:42:38 +0200798#ifdef FEAT_TEXT_PROP
799 // Display popup windows on top of the windows and command line.
800 update_popups(win_update);
801#endif
802
Bram Moolenaar68a4b042019-05-29 22:28:29 +0200803 after_updating_screen(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804
805 /* Clear or redraw the command line. Done last, because scrolling may
806 * mess up the command line. */
Bram Moolenaar4c25bd72019-04-20 23:38:07 +0200807 if (clear_cmdline || redraw_cmdline || redraw_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 showmode();
809
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200810 if (no_update)
811 --no_win_do_lines_ins;
812
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 /* May put up an introductory message when not editing a file */
Bram Moolenaar249f0dd2013-07-04 22:31:03 +0200814 if (!did_intro)
815 maybe_intro_message();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816 did_intro = TRUE;
817
818#ifdef FEAT_GUI
819 /* Redraw the cursor and update the scrollbars when all screen updating is
820 * done. */
821 if (gui.in_use)
822 {
Bram Moolenaar107abd22016-08-12 14:08:25 +0200823 if (did_undraw && !gui_mch_is_blink_off())
Bram Moolenaar144445d2016-07-08 21:41:54 +0200824 {
Bram Moolenaara338adc2018-01-31 20:51:47 +0100825 mch_disable_flush();
826 out_flush(); /* required before updating the cursor */
827 mch_enable_flush();
828
Bram Moolenaar144445d2016-07-08 21:41:54 +0200829 /* Put the GUI position where the cursor was, gui_update_cursor()
830 * uses that. */
831 gui.col = gui_cursor_col;
832 gui.row = gui_cursor_row;
Bram Moolenaar84dbd492016-10-02 23:09:31 +0200833 gui.col = mb_fix_col(gui.col, gui.row);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834 gui_update_cursor(FALSE, FALSE);
Bram Moolenaara338adc2018-01-31 20:51:47 +0100835 gui_may_flush();
Bram Moolenaar65549bd2016-07-08 22:52:37 +0200836 screen_cur_col = gui.col;
837 screen_cur_row = gui.row;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200838 }
Bram Moolenaara338adc2018-01-31 20:51:47 +0100839 else
840 out_flush();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 gui_update_scrollbars(FALSE);
842 }
843#endif
Bram Moolenaar072412e2017-09-13 22:11:35 +0200844 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845}
846
Bram Moolenaar1fa8fdd2019-02-25 05:41:15 +0100847#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI)
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100848/*
849 * Prepare for updating one or more windows.
850 * Caller must check for "updating_screen" already set to avoid recursiveness.
851 */
852 static void
853update_prepare(void)
854{
855 cursor_off();
856 updating_screen = TRUE;
857#ifdef FEAT_GUI
858 /* Remove the cursor before starting to do anything, because scrolling may
859 * make it difficult to redraw the text under it. */
860 if (gui.in_use)
861 gui_undraw_cursor();
862#endif
863#ifdef FEAT_SEARCH_EXTRA
864 start_search_hl();
865#endif
Bram Moolenaar33796b32019-06-08 16:01:13 +0200866#ifdef FEAT_TEXT_PROP
867 // Update popup_mask if needed.
Bram Moolenaar68acb412019-06-26 03:40:36 +0200868 may_update_popup_mask(must_redraw);
Bram Moolenaar33796b32019-06-08 16:01:13 +0200869#endif
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100870}
871
872/*
873 * Finish updating one or more windows.
874 */
875 static void
876update_finish(void)
877{
Bram Moolenaar4c25bd72019-04-20 23:38:07 +0200878 if (redraw_cmdline || redraw_mode)
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100879 showmode();
880
881# ifdef FEAT_SEARCH_EXTRA
882 end_search_hl();
883# endif
884
Bram Moolenaar68a4b042019-05-29 22:28:29 +0200885 after_updating_screen(TRUE);
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100886
887# ifdef FEAT_GUI
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100888 /* Redraw the cursor and update the scrollbars when all screen updating is
889 * done. */
890 if (gui.in_use)
891 {
Bram Moolenaara338adc2018-01-31 20:51:47 +0100892 out_flush_cursor(FALSE, FALSE);
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100893 gui_update_scrollbars(FALSE);
894 }
895# endif
896}
897#endif
898
Bram Moolenaar860cae12010-06-05 23:22:07 +0200899#if defined(FEAT_CONCEAL) || defined(PROTO)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200900/*
901 * Return TRUE if the cursor line in window "wp" may be concealed, according
902 * to the 'concealcursor' option.
903 */
904 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100905conceal_cursor_line(win_T *wp)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200906{
907 int c;
908
909 if (*wp->w_p_cocu == NUL)
910 return FALSE;
911 if (get_real_state() & VISUAL)
912 c = 'v';
913 else if (State & INSERT)
914 c = 'i';
915 else if (State & NORMAL)
916 c = 'n';
Bram Moolenaarca8c9862010-07-24 15:00:38 +0200917 else if (State & CMDLINE)
918 c = 'c';
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200919 else
920 return FALSE;
921 return vim_strchr(wp->w_p_cocu, c) != NULL;
922}
923
924/*
925 * Check if the cursor line needs to be redrawn because of 'concealcursor'.
926 */
927 void
Bram Moolenaarb9464822018-05-10 15:09:49 +0200928conceal_check_cursor_line(void)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200929{
930 if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin))
931 {
932 need_cursor_line_redraw = TRUE;
933 /* Need to recompute cursor column, e.g., when starting Visual mode
934 * without concealing. */
935 curs_columns(TRUE);
936 }
937}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000938#endif
939
Bram Moolenaar113e1072019-01-20 15:30:40 +0100940#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100942update_debug_sign(buf_T *buf, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943{
944 win_T *wp;
945 int doit = FALSE;
946
947# ifdef FEAT_FOLDING
948 win_foldinfo.fi_level = 0;
949# endif
950
Bram Moolenaar27a472c2019-01-09 21:47:30 +0100951 // update/delete a specific sign
952 redraw_buf_line_later(buf, lnum);
953
954 // check if it resulted in the need to redraw a window
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956 if (wp->w_redr_type != 0)
957 doit = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000958
Bram Moolenaar738f8fc2012-01-10 12:42:09 +0100959 /* Return when there is nothing to do, screen updating is already
Bram Moolenaar07920482017-08-01 20:53:30 +0200960 * happening (recursive call), messages on the screen or still starting up.
961 */
Bram Moolenaar738f8fc2012-01-10 12:42:09 +0100962 if (!doit || updating_screen
Bram Moolenaar07920482017-08-01 20:53:30 +0200963 || State == ASKMORE || State == HITRETURN
964 || msg_scrolled
Bram Moolenaar738f8fc2012-01-10 12:42:09 +0100965#ifdef FEAT_GUI
966 || gui.starting
967#endif
968 || starting)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000969 return;
970
971 /* update all windows that need updating */
972 update_prepare();
973
Bram Moolenaar29323592016-07-24 22:04:11 +0200974 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975 {
976 if (wp->w_redr_type != 0)
977 win_update(wp);
978 if (wp->w_redr_status)
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +0200979 win_redr_status(wp, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000981
982 update_finish();
983}
984#endif
985
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200986/*
987 * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
988 * window then get the "Pmenu" highlight attribute.
989 */
Bram Moolenaara540f8a2019-06-14 19:23:57 +0200990 int
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200991get_wcr_attr(win_T *wp)
992{
993 int wcr_attr = 0;
994
995 if (*wp->w_p_wcr != NUL)
996 wcr_attr = syn_name2attr(wp->w_p_wcr);
997#ifdef FEAT_TEXT_PROP
Bram Moolenaarc363fe12019-08-04 18:13:46 +0200998 else if (WIN_IS_POPUP(wp))
Bram Moolenaar62a0cb42019-08-18 16:35:23 +0200999 {
1000 if (wp->w_popup_flags & POPF_INFO)
1001 wcr_attr = HL_ATTR(HLF_PSI); // PmenuSel
1002 else
1003 wcr_attr = HL_ATTR(HLF_PNI); // Pmenu
1004 }
Bram Moolenaar60cdb302019-05-27 21:54:10 +02001005#endif
1006 return wcr_attr;
1007}
1008
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009#if defined(FEAT_GUI) || defined(PROTO)
1010/*
1011 * Update a single window, its status line and maybe the command line msg.
1012 * Used for the GUI scrollbar.
1013 */
1014 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001015updateWindow(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016{
Bram Moolenaar19f990e2009-11-25 12:08:03 +00001017 /* return if already busy updating */
1018 if (updating_screen)
1019 return;
1020
Bram Moolenaar071d4272004-06-13 20:20:40 +00001021 update_prepare();
1022
1023#ifdef FEAT_CLIPBOARD
1024 /* When Visual area changed, may have to update selection. */
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02001025 if (clip_star.available && clip_isautosel_star())
1026 clip_update_selection(&clip_star);
1027 if (clip_plus.available && clip_isautosel_plus())
1028 clip_update_selection(&clip_plus);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029#endif
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001030
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031 win_update(wp);
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001032
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001033 /* When the screen was cleared redraw the tab pages line. */
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00001034 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001035 draw_tabline();
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001036
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 if (wp->w_redr_status
1038# ifdef FEAT_CMDL_INFO
1039 || p_ru
1040# endif
1041# ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00001042 || *p_stl != NUL || *wp->w_p_stl != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043# endif
1044 )
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001045 win_redr_status(wp, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046
Bram Moolenaar988c4332019-06-02 14:12:11 +02001047#ifdef FEAT_TEXT_PROP
1048 // Display popup windows on top of everything.
Bram Moolenaara540f8a2019-06-14 19:23:57 +02001049 update_popups(win_update);
Bram Moolenaar988c4332019-06-02 14:12:11 +02001050#endif
1051
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052 update_finish();
1053}
1054#endif
1055
1056/*
1057 * Update a single window.
1058 *
1059 * This may cause the windows below it also to be redrawn (when clearing the
1060 * screen or scrolling lines).
1061 *
1062 * How the window is redrawn depends on wp->w_redr_type. Each type also
1063 * implies the one below it.
1064 * NOT_VALID redraw the whole window
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001065 * SOME_VALID redraw the whole window but do scroll when possible
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
1067 * INVERTED redraw the changed part of the Visual area
1068 * INVERTED_ALL redraw the whole Visual area
1069 * VALID 1. scroll up/down to adjust for a changed w_topline
1070 * 2. update lines at the top when scrolled down
1071 * 3. redraw changed text:
Bram Moolenaar75c50c42005-06-04 22:06:24 +00001072 * - if wp->w_buffer->b_mod_set set, update lines between
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073 * b_mod_top and b_mod_bot.
1074 * - if wp->w_redraw_top non-zero, redraw lines between
1075 * wp->w_redraw_top and wp->w_redr_bot.
1076 * - continue redrawing when syntax status is invalid.
1077 * 4. if scrolled up, update lines at the bottom.
1078 * This results in three areas that may need updating:
1079 * top: from first row to top_end (when scrolled down)
1080 * mid: from mid_start to mid_end (update inversion or changed text)
1081 * bot: from bot_start to last row (when scrolled up)
1082 */
1083 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001084win_update(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085{
1086 buf_T *buf = wp->w_buffer;
1087 int type;
1088 int top_end = 0; /* Below last row of the top area that needs
1089 updating. 0 when no top area updating. */
1090 int mid_start = 999;/* first row of the mid area that needs
1091 updating. 999 when no mid area updating. */
1092 int mid_end = 0; /* Below last row of the mid area that needs
1093 updating. 0 when no mid area updating. */
1094 int bot_start = 999;/* first row of the bot area that needs
1095 updating. 999 when no bot area updating */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096 int scrolled_down = FALSE; /* TRUE when scrolled down when
1097 w_topline got smaller a bit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarfbfb7572019-07-25 20:53:03 +02001099 int top_to_mod = FALSE; // redraw above mod_top
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100#endif
1101
1102 int row; /* current window row to display */
1103 linenr_T lnum; /* current buffer lnum to display */
1104 int idx; /* current index in w_lines[] */
1105 int srow; /* starting row of the current line */
1106
1107 int eof = FALSE; /* if TRUE, we hit the end of the file */
1108 int didline = FALSE; /* if TRUE, we finished the last line */
1109 int i;
1110 long j;
1111 static int recursive = FALSE; /* being called recursively */
1112 int old_botline = wp->w_botline;
1113#ifdef FEAT_FOLDING
1114 long fold_count;
1115#endif
1116#ifdef FEAT_SYN_HL
1117 /* remember what happened to the previous line, to know if
1118 * check_visual_highlight() can be used */
1119#define DID_NONE 1 /* didn't update a line */
1120#define DID_LINE 2 /* updated a normal line */
1121#define DID_FOLD 3 /* updated a folded line */
1122 int did_update = DID_NONE;
1123 linenr_T syntax_last_parsed = 0; /* last parsed text line */
1124#endif
1125 linenr_T mod_top = 0;
1126 linenr_T mod_bot = 0;
1127#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1128 int save_got_int;
1129#endif
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001130#ifdef SYN_TIME_LIMIT
1131 proftime_T syntax_tm;
1132#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133
1134 type = wp->w_redr_type;
1135
1136 if (type == NOT_VALID)
1137 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001138 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001139 wp->w_lines_valid = 0;
1140 }
1141
1142 /* Window is zero-height: nothing to draw. */
Bram Moolenaar415a6932017-12-05 20:31:07 +01001143 if (wp->w_height + WINBAR_HEIGHT(wp) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001144 {
1145 wp->w_redr_type = 0;
1146 return;
1147 }
1148
Bram Moolenaar071d4272004-06-13 20:20:40 +00001149 /* Window is zero-width: Only need to draw the separator. */
1150 if (wp->w_width == 0)
1151 {
1152 /* draw the vertical separator right of this window */
1153 draw_vsep_win(wp, 0);
1154 wp->w_redr_type = 0;
1155 return;
1156 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001158#ifdef FEAT_TERMINAL
Bram Moolenaar6eddadf2018-05-06 16:40:16 +02001159 // If this window contains a terminal, redraw works completely differently.
1160 if (term_do_update_window(wp))
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001161 {
Bram Moolenaar6eddadf2018-05-06 16:40:16 +02001162 term_update_window(wp);
Bram Moolenaar181ca992018-02-13 21:19:21 +01001163# ifdef FEAT_MENU
1164 /* Draw the window toolbar, if there is one. */
1165 if (winbar_height(wp) > 0)
1166 redraw_win_toolbar(wp);
1167# endif
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001168 wp->w_redr_type = 0;
1169 return;
1170 }
1171#endif
1172
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarbbca7732019-07-24 18:13:16 +02001174 init_search_hl(wp, &search_hl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175#endif
1176
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001177#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +02001178 /* Force redraw when width of 'number' or 'relativenumber' column
1179 * changes. */
1180 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001181 if (wp->w_nrwidth != i)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001182 {
1183 type = NOT_VALID;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001184 wp->w_nrwidth = i;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001185 }
1186 else
1187#endif
1188
Bram Moolenaar071d4272004-06-13 20:20:40 +00001189 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
1190 {
1191 /*
1192 * When there are both inserted/deleted lines and specific lines to be
1193 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
1194 * everything (only happens when redrawing is off for while).
1195 */
1196 type = NOT_VALID;
1197 }
1198 else
1199 {
1200 /*
1201 * Set mod_top to the first line that needs displaying because of
1202 * changes. Set mod_bot to the first line after the changes.
1203 */
1204 mod_top = wp->w_redraw_top;
1205 if (wp->w_redraw_bot != 0)
1206 mod_bot = wp->w_redraw_bot + 1;
1207 else
1208 mod_bot = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209 if (buf->b_mod_set)
1210 {
1211 if (mod_top == 0 || mod_top > buf->b_mod_top)
1212 {
1213 mod_top = buf->b_mod_top;
1214#ifdef FEAT_SYN_HL
1215 /* Need to redraw lines above the change that may be included
1216 * in a pattern match. */
Bram Moolenaar860cae12010-06-05 23:22:07 +02001217 if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02001219 mod_top -= buf->b_s.b_syn_sync_linebreaks;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220 if (mod_top < 1)
1221 mod_top = 1;
1222 }
1223#endif
1224 }
1225 if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
1226 mod_bot = buf->b_mod_bot;
1227
1228#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarfbfb7572019-07-25 20:53:03 +02001229 // When 'hlsearch' is on and using a multi-line search pattern, a
1230 // change in one line may make the Search highlighting in a
1231 // previous line invalid. Simple solution: redraw all visible
1232 // lines above the change.
1233 // Same for a match pattern.
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001234 if (search_hl.rm.regprog != NULL
1235 && re_multiline(search_hl.rm.regprog))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236 top_to_mod = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001237 else
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001238 {
Bram Moolenaarfbfb7572019-07-25 20:53:03 +02001239 matchitem_T *cur = wp->w_match_head;
1240
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001241 while (cur != NULL)
1242 {
1243 if (cur->match.regprog != NULL
1244 && re_multiline(cur->match.regprog))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001245 {
1246 top_to_mod = TRUE;
1247 break;
1248 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001249 cur = cur->next;
1250 }
1251 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001252#endif
1253 }
1254#ifdef FEAT_FOLDING
1255 if (mod_top != 0 && hasAnyFolding(wp))
1256 {
1257 linenr_T lnumt, lnumb;
1258
1259 /*
1260 * A change in a line can cause lines above it to become folded or
1261 * unfolded. Find the top most buffer line that may be affected.
1262 * If the line was previously folded and displayed, get the first
1263 * line of that fold. If the line is folded now, get the first
1264 * folded line. Use the minimum of these two.
1265 */
1266
1267 /* Find last valid w_lines[] entry above mod_top. Set lnumt to
1268 * the line below it. If there is no valid entry, use w_topline.
1269 * Find the first valid w_lines[] entry below mod_bot. Set lnumb
1270 * to this line. If there is no valid entry, use MAXLNUM. */
1271 lnumt = wp->w_topline;
1272 lnumb = MAXLNUM;
1273 for (i = 0; i < wp->w_lines_valid; ++i)
1274 if (wp->w_lines[i].wl_valid)
1275 {
1276 if (wp->w_lines[i].wl_lastlnum < mod_top)
1277 lnumt = wp->w_lines[i].wl_lastlnum + 1;
1278 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1279 {
1280 lnumb = wp->w_lines[i].wl_lnum;
1281 /* When there is a fold column it might need updating
1282 * in the next line ("J" just above an open fold). */
Bram Moolenaar1c934292015-01-27 16:39:29 +01001283 if (compute_foldcolumn(wp, 0) > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284 ++lnumb;
1285 }
1286 }
1287
1288 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1289 if (mod_top > lnumt)
1290 mod_top = lnumt;
1291
1292 /* Now do the same for the bottom line (one above mod_bot). */
1293 --mod_bot;
1294 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1295 ++mod_bot;
1296 if (mod_bot < lnumb)
1297 mod_bot = lnumb;
1298 }
1299#endif
1300
1301 /* When a change starts above w_topline and the end is below
1302 * w_topline, start redrawing at w_topline.
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001303 * If the end of the change is above w_topline: do like no change was
1304 * made, but redraw the first line to find changes in syntax. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 if (mod_top != 0 && mod_top < wp->w_topline)
1306 {
1307 if (mod_bot > wp->w_topline)
1308 mod_top = wp->w_topline;
1309#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02001310 else if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311 top_end = 1;
1312#endif
1313 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001314
1315 /* When line numbers are displayed need to redraw all lines below
1316 * inserted/deleted lines. */
1317 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1318 mod_bot = MAXLNUM;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319 }
Bram Moolenaar895d9662019-01-31 21:57:21 +01001320 wp->w_redraw_top = 0; // reset for next time
1321 wp->w_redraw_bot = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322
1323 /*
1324 * When only displaying the lines at the top, set top_end. Used when
1325 * window has scrolled down for msg_scrolled.
1326 */
1327 if (type == REDRAW_TOP)
1328 {
1329 j = 0;
1330 for (i = 0; i < wp->w_lines_valid; ++i)
1331 {
1332 j += wp->w_lines[i].wl_size;
1333 if (j >= wp->w_upd_rows)
1334 {
1335 top_end = j;
1336 break;
1337 }
1338 }
1339 if (top_end == 0)
1340 /* not found (cannot happen?): redraw everything */
1341 type = NOT_VALID;
1342 else
1343 /* top area defined, the rest is VALID */
1344 type = VALID;
1345 }
1346
Bram Moolenaar367329b2007-08-30 11:53:22 +00001347 /* Trick: we want to avoid clearing the screen twice. screenclear() will
Bram Moolenaar943fae42007-07-30 20:00:38 +00001348 * set "screen_cleared" to TRUE. The special value MAYBE (which is still
1349 * non-zero and thus not FALSE) will indicate that screenclear() was not
1350 * called. */
1351 if (screen_cleared)
1352 screen_cleared = MAYBE;
1353
Bram Moolenaar071d4272004-06-13 20:20:40 +00001354 /*
1355 * If there are no changes on the screen that require a complete redraw,
1356 * handle three cases:
1357 * 1: we are off the top of the screen by a few lines: scroll down
1358 * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1359 * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1360 * w_lines[] that needs updating.
1361 */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001362 if ((type == VALID || type == SOME_VALID
1363 || type == INVERTED || type == INVERTED_ALL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001364#ifdef FEAT_DIFF
1365 && !wp->w_botfill && !wp->w_old_botfill
1366#endif
1367 )
1368 {
1369 if (mod_top != 0 && wp->w_topline == mod_top)
1370 {
1371 /*
1372 * w_topline is the first changed line, the scrolling will be done
1373 * further down.
1374 */
1375 }
1376 else if (wp->w_lines[0].wl_valid
1377 && (wp->w_topline < wp->w_lines[0].wl_lnum
1378#ifdef FEAT_DIFF
1379 || (wp->w_topline == wp->w_lines[0].wl_lnum
1380 && wp->w_topfill > wp->w_old_topfill)
1381#endif
1382 ))
1383 {
1384 /*
1385 * New topline is above old topline: May scroll down.
1386 */
1387#ifdef FEAT_FOLDING
1388 if (hasAnyFolding(wp))
1389 {
1390 linenr_T ln;
1391
1392 /* count the number of lines we are off, counting a sequence
1393 * of folded lines as one */
1394 j = 0;
1395 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1396 {
1397 ++j;
1398 if (j >= wp->w_height - 2)
1399 break;
1400 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1401 }
1402 }
1403 else
1404#endif
1405 j = wp->w_lines[0].wl_lnum - wp->w_topline;
1406 if (j < wp->w_height - 2) /* not too far off */
1407 {
1408 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1409#ifdef FEAT_DIFF
1410 /* insert extra lines for previously invisible filler lines */
1411 if (wp->w_lines[0].wl_lnum != wp->w_topline)
1412 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1413 - wp->w_old_topfill;
1414#endif
1415 if (i < wp->w_height - 2) /* less than a screen off */
1416 {
1417 /*
1418 * Try to insert the correct number of lines.
1419 * If not the last window, delete the lines at the bottom.
1420 * win_ins_lines may fail when the terminal can't do it.
1421 */
1422 if (i > 0)
1423 check_for_delay(FALSE);
1424 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1425 {
1426 if (wp->w_lines_valid != 0)
1427 {
1428 /* Need to update rows that are new, stop at the
1429 * first one that scrolled down. */
1430 top_end = i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431 scrolled_down = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001432
1433 /* Move the entries that were scrolled, disable
1434 * the entries for the lines to be redrawn. */
1435 if ((wp->w_lines_valid += j) > wp->w_height)
1436 wp->w_lines_valid = wp->w_height;
1437 for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1438 wp->w_lines[idx] = wp->w_lines[idx - j];
1439 while (idx >= 0)
1440 wp->w_lines[idx--].wl_valid = FALSE;
1441 }
1442 }
1443 else
1444 mid_start = 0; /* redraw all lines */
1445 }
1446 else
1447 mid_start = 0; /* redraw all lines */
1448 }
1449 else
1450 mid_start = 0; /* redraw all lines */
1451 }
1452 else
1453 {
1454 /*
1455 * New topline is at or below old topline: May scroll up.
1456 * When topline didn't change, find first entry in w_lines[] that
1457 * needs updating.
1458 */
1459
1460 /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
1461 j = -1;
1462 row = 0;
1463 for (i = 0; i < wp->w_lines_valid; i++)
1464 {
1465 if (wp->w_lines[i].wl_valid
1466 && wp->w_lines[i].wl_lnum == wp->w_topline)
1467 {
1468 j = i;
1469 break;
1470 }
1471 row += wp->w_lines[i].wl_size;
1472 }
1473 if (j == -1)
1474 {
1475 /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1476 * lines */
1477 mid_start = 0;
1478 }
1479 else
1480 {
1481 /*
1482 * Try to delete the correct number of lines.
1483 * wp->w_topline is at wp->w_lines[i].wl_lnum.
1484 */
1485#ifdef FEAT_DIFF
1486 /* If the topline didn't change, delete old filler lines,
1487 * otherwise delete filler lines of the new topline... */
1488 if (wp->w_lines[0].wl_lnum == wp->w_topline)
1489 row += wp->w_old_topfill;
1490 else
1491 row += diff_check_fill(wp, wp->w_topline);
1492 /* ... but don't delete new filler lines. */
1493 row -= wp->w_topfill;
1494#endif
1495 if (row > 0)
1496 {
1497 check_for_delay(FALSE);
Bram Moolenaarcfce7172017-08-17 20:31:48 +02001498 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
1499 == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500 bot_start = wp->w_height - row;
1501 else
1502 mid_start = 0; /* redraw all lines */
1503 }
1504 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1505 {
1506 /*
1507 * Skip the lines (below the deleted lines) that are still
1508 * valid and don't need redrawing. Copy their info
1509 * upwards, to compensate for the deleted lines. Set
1510 * bot_start to the first row that needs redrawing.
1511 */
1512 bot_start = 0;
1513 idx = 0;
1514 for (;;)
1515 {
1516 wp->w_lines[idx] = wp->w_lines[j];
1517 /* stop at line that didn't fit, unless it is still
1518 * valid (no lines deleted) */
1519 if (row > 0 && bot_start + row
1520 + (int)wp->w_lines[j].wl_size > wp->w_height)
1521 {
1522 wp->w_lines_valid = idx + 1;
1523 break;
1524 }
1525 bot_start += wp->w_lines[idx++].wl_size;
1526
1527 /* stop at the last valid entry in w_lines[].wl_size */
1528 if (++j >= wp->w_lines_valid)
1529 {
1530 wp->w_lines_valid = idx;
1531 break;
1532 }
1533 }
1534#ifdef FEAT_DIFF
1535 /* Correct the first entry for filler lines at the top
1536 * when it won't get updated below. */
1537 if (wp->w_p_diff && bot_start > 0)
1538 wp->w_lines[0].wl_size =
1539 plines_win_nofill(wp, wp->w_topline, TRUE)
1540 + wp->w_topfill;
1541#endif
1542 }
1543 }
1544 }
1545
1546 /* When starting redraw in the first line, redraw all lines. When
1547 * there is only one window it's probably faster to clear the screen
1548 * first. */
1549 if (mid_start == 0)
1550 {
1551 mid_end = wp->w_height;
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001552 if (ONE_WINDOW && !WIN_IS_POPUP(wp))
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001553 {
Bram Moolenaar943fae42007-07-30 20:00:38 +00001554 /* Clear the screen when it was not done by win_del_lines() or
1555 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1556 * then. */
1557 if (screen_cleared != TRUE)
1558 screenclear();
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001559 /* The screen was cleared, redraw the tab pages line. */
1560 if (redraw_tabline)
1561 draw_tabline();
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001562 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563 }
Bram Moolenaar943fae42007-07-30 20:00:38 +00001564
1565 /* When win_del_lines() or win_ins_lines() caused the screen to be
1566 * cleared (only happens for the first window) or when screenclear()
1567 * was called directly above, "must_redraw" will have been set to
1568 * NOT_VALID, need to reset it here to avoid redrawing twice. */
1569 if (screen_cleared == TRUE)
1570 must_redraw = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571 }
1572 else
1573 {
1574 /* Not VALID or INVERTED: redraw all lines. */
1575 mid_start = 0;
1576 mid_end = wp->w_height;
1577 }
1578
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001579 if (type == SOME_VALID)
1580 {
1581 /* SOME_VALID: redraw all lines. */
1582 mid_start = 0;
1583 mid_end = wp->w_height;
1584 type = NOT_VALID;
1585 }
1586
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587 /* check if we are updating or removing the inverted part */
1588 if ((VIsual_active && buf == curwin->w_buffer)
1589 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1590 {
1591 linenr_T from, to;
1592
1593 if (VIsual_active)
1594 {
1595 if (VIsual_active
1596 && (VIsual_mode != wp->w_old_visual_mode
1597 || type == INVERTED_ALL))
1598 {
1599 /*
1600 * If the type of Visual selection changed, redraw the whole
1601 * selection. Also when the ownership of the X selection is
1602 * gained or lost.
1603 */
1604 if (curwin->w_cursor.lnum < VIsual.lnum)
1605 {
1606 from = curwin->w_cursor.lnum;
1607 to = VIsual.lnum;
1608 }
1609 else
1610 {
1611 from = VIsual.lnum;
1612 to = curwin->w_cursor.lnum;
1613 }
1614 /* redraw more when the cursor moved as well */
1615 if (wp->w_old_cursor_lnum < from)
1616 from = wp->w_old_cursor_lnum;
1617 if (wp->w_old_cursor_lnum > to)
1618 to = wp->w_old_cursor_lnum;
1619 if (wp->w_old_visual_lnum < from)
1620 from = wp->w_old_visual_lnum;
1621 if (wp->w_old_visual_lnum > to)
1622 to = wp->w_old_visual_lnum;
1623 }
1624 else
1625 {
1626 /*
1627 * Find the line numbers that need to be updated: The lines
1628 * between the old cursor position and the current cursor
1629 * position. Also check if the Visual position changed.
1630 */
1631 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1632 {
1633 from = curwin->w_cursor.lnum;
1634 to = wp->w_old_cursor_lnum;
1635 }
1636 else
1637 {
1638 from = wp->w_old_cursor_lnum;
1639 to = curwin->w_cursor.lnum;
1640 if (from == 0) /* Visual mode just started */
1641 from = to;
1642 }
1643
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001644 if (VIsual.lnum != wp->w_old_visual_lnum
1645 || VIsual.col != wp->w_old_visual_col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646 {
1647 if (wp->w_old_visual_lnum < from
1648 && wp->w_old_visual_lnum != 0)
1649 from = wp->w_old_visual_lnum;
1650 if (wp->w_old_visual_lnum > to)
1651 to = wp->w_old_visual_lnum;
1652 if (VIsual.lnum < from)
1653 from = VIsual.lnum;
1654 if (VIsual.lnum > to)
1655 to = VIsual.lnum;
1656 }
1657 }
1658
1659 /*
1660 * If in block mode and changed column or curwin->w_curswant:
1661 * update all lines.
1662 * First compute the actual start and end column.
1663 */
1664 if (VIsual_mode == Ctrl_V)
1665 {
Bram Moolenaar404406a2014-10-09 13:24:43 +02001666 colnr_T fromc, toc;
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001667#if defined(FEAT_LINEBREAK)
Bram Moolenaar404406a2014-10-09 13:24:43 +02001668 int save_ve_flags = ve_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001669
Bram Moolenaar404406a2014-10-09 13:24:43 +02001670 if (curwin->w_p_lbr)
1671 ve_flags = VE_ALL;
1672#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001673 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001674#if defined(FEAT_LINEBREAK)
Bram Moolenaar404406a2014-10-09 13:24:43 +02001675 ve_flags = save_ve_flags;
1676#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 ++toc;
1678 if (curwin->w_curswant == MAXCOL)
1679 toc = MAXCOL;
1680
1681 if (fromc != wp->w_old_cursor_fcol
1682 || toc != wp->w_old_cursor_lcol)
1683 {
1684 if (from > VIsual.lnum)
1685 from = VIsual.lnum;
1686 if (to < VIsual.lnum)
1687 to = VIsual.lnum;
1688 }
1689 wp->w_old_cursor_fcol = fromc;
1690 wp->w_old_cursor_lcol = toc;
1691 }
1692 }
1693 else
1694 {
1695 /* Use the line numbers of the old Visual area. */
1696 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
1697 {
1698 from = wp->w_old_cursor_lnum;
1699 to = wp->w_old_visual_lnum;
1700 }
1701 else
1702 {
1703 from = wp->w_old_visual_lnum;
1704 to = wp->w_old_cursor_lnum;
1705 }
1706 }
1707
1708 /*
1709 * There is no need to update lines above the top of the window.
1710 */
1711 if (from < wp->w_topline)
1712 from = wp->w_topline;
1713
1714 /*
1715 * If we know the value of w_botline, use it to restrict the update to
1716 * the lines that are visible in the window.
1717 */
1718 if (wp->w_valid & VALID_BOTLINE)
1719 {
1720 if (from >= wp->w_botline)
1721 from = wp->w_botline - 1;
1722 if (to >= wp->w_botline)
1723 to = wp->w_botline - 1;
1724 }
1725
1726 /*
1727 * Find the minimal part to be updated.
1728 * Watch out for scrolling that made entries in w_lines[] invalid.
1729 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
1730 * top_end; need to redraw from top_end to the "to" line.
1731 * A middle mouse click with a Visual selection may change the text
1732 * above the Visual area and reset wl_valid, do count these for
1733 * mid_end (in srow).
1734 */
1735 if (mid_start > 0)
1736 {
1737 lnum = wp->w_topline;
1738 idx = 0;
1739 srow = 0;
1740 if (scrolled_down)
1741 mid_start = top_end;
1742 else
1743 mid_start = 0;
1744 while (lnum < from && idx < wp->w_lines_valid) /* find start */
1745 {
1746 if (wp->w_lines[idx].wl_valid)
1747 mid_start += wp->w_lines[idx].wl_size;
1748 else if (!scrolled_down)
1749 srow += wp->w_lines[idx].wl_size;
1750 ++idx;
1751# ifdef FEAT_FOLDING
1752 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
1753 lnum = wp->w_lines[idx].wl_lnum;
1754 else
1755# endif
1756 ++lnum;
1757 }
1758 srow += mid_start;
1759 mid_end = wp->w_height;
1760 for ( ; idx < wp->w_lines_valid; ++idx) /* find end */
1761 {
1762 if (wp->w_lines[idx].wl_valid
1763 && wp->w_lines[idx].wl_lnum >= to + 1)
1764 {
1765 /* Only update until first row of this line */
1766 mid_end = srow;
1767 break;
1768 }
1769 srow += wp->w_lines[idx].wl_size;
1770 }
1771 }
1772 }
1773
1774 if (VIsual_active && buf == curwin->w_buffer)
1775 {
1776 wp->w_old_visual_mode = VIsual_mode;
1777 wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
1778 wp->w_old_visual_lnum = VIsual.lnum;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001779 wp->w_old_visual_col = VIsual.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780 wp->w_old_curswant = curwin->w_curswant;
1781 }
1782 else
1783 {
1784 wp->w_old_visual_mode = 0;
1785 wp->w_old_cursor_lnum = 0;
1786 wp->w_old_visual_lnum = 0;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001787 wp->w_old_visual_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789
1790#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1791 /* reset got_int, otherwise regexp won't work */
1792 save_got_int = got_int;
1793 got_int = 0;
1794#endif
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001795#ifdef SYN_TIME_LIMIT
1796 /* Set the time limit to 'redrawtime'. */
1797 profile_setlimit(p_rdt, &syntax_tm);
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02001798 syn_set_timeout(&syntax_tm);
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001799#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800#ifdef FEAT_FOLDING
1801 win_foldinfo.fi_level = 0;
1802#endif
1803
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02001804#ifdef FEAT_MENU
1805 /*
1806 * Draw the window toolbar, if there is one.
1807 * TODO: only when needed.
1808 */
1809 if (winbar_height(wp) > 0)
1810 redraw_win_toolbar(wp);
1811#endif
1812
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813 /*
1814 * Update all the window rows.
1815 */
1816 idx = 0; /* first entry in w_lines[].wl_size */
1817 row = 0;
1818 srow = 0;
1819 lnum = wp->w_topline; /* first line shown in window */
1820 for (;;)
1821 {
1822 /* stop updating when reached the end of the window (check for _past_
1823 * the end of the window is at the end of the loop) */
1824 if (row == wp->w_height)
1825 {
1826 didline = TRUE;
1827 break;
1828 }
1829
1830 /* stop updating when hit the end of the file */
1831 if (lnum > buf->b_ml.ml_line_count)
1832 {
1833 eof = TRUE;
1834 break;
1835 }
1836
1837 /* Remember the starting row of the line that is going to be dealt
1838 * with. It is used further down when the line doesn't fit. */
1839 srow = row;
1840
1841 /*
1842 * Update a line when it is in an area that needs updating, when it
1843 * has changes or w_lines[idx] is invalid.
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02001844 * "bot_start" may be halfway a wrapped line after using
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 * win_del_lines(), check if the current line includes it.
1846 * When syntax folding is being used, the saved syntax states will
1847 * already have been updated, we can't see where the syntax state is
1848 * the same again, just update until the end of the window.
1849 */
1850 if (row < top_end
1851 || (row >= mid_start && row < mid_end)
1852#ifdef FEAT_SEARCH_EXTRA
1853 || top_to_mod
1854#endif
1855 || idx >= wp->w_lines_valid
1856 || (row + wp->w_lines[idx].wl_size > bot_start)
1857 || (mod_top != 0
1858 && (lnum == mod_top
1859 || (lnum >= mod_top
1860 && (lnum < mod_bot
1861#ifdef FEAT_SYN_HL
1862 || did_update == DID_FOLD
1863 || (did_update == DID_LINE
Bram Moolenaar860cae12010-06-05 23:22:07 +02001864 && syntax_present(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 && (
1866# ifdef FEAT_FOLDING
1867 (foldmethodIsSyntax(wp)
1868 && hasAnyFolding(wp)) ||
1869# endif
1870 syntax_check_changed(lnum)))
1871#endif
Bram Moolenaar4ce239b2013-06-15 23:00:30 +02001872#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaardab70c62014-07-02 17:16:58 +02001873 /* match in fixed position might need redraw
1874 * if lines were inserted or deleted */
1875 || (wp->w_match_head != NULL
1876 && buf->b_mod_xlines != 0)
Bram Moolenaar4ce239b2013-06-15 23:00:30 +02001877#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878 )))))
1879 {
1880#ifdef FEAT_SEARCH_EXTRA
1881 if (lnum == mod_top)
1882 top_to_mod = FALSE;
1883#endif
1884
1885 /*
1886 * When at start of changed lines: May scroll following lines
1887 * up or down to minimize redrawing.
1888 * Don't do this when the change continues until the end.
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001889 * Don't scroll when dollar_vcol >= 0, keep the "$".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 */
1891 if (lnum == mod_top
1892 && mod_bot != MAXLNUM
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001893 && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 {
1895 int old_rows = 0;
1896 int new_rows = 0;
1897 int xtra_rows;
1898 linenr_T l;
1899
1900 /* Count the old number of window rows, using w_lines[], which
1901 * should still contain the sizes for the lines as they are
1902 * currently displayed. */
1903 for (i = idx; i < wp->w_lines_valid; ++i)
1904 {
1905 /* Only valid lines have a meaningful wl_lnum. Invalid
1906 * lines are part of the changed area. */
1907 if (wp->w_lines[i].wl_valid
1908 && wp->w_lines[i].wl_lnum == mod_bot)
1909 break;
1910 old_rows += wp->w_lines[i].wl_size;
1911#ifdef FEAT_FOLDING
1912 if (wp->w_lines[i].wl_valid
1913 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
1914 {
1915 /* Must have found the last valid entry above mod_bot.
1916 * Add following invalid entries. */
1917 ++i;
1918 while (i < wp->w_lines_valid
1919 && !wp->w_lines[i].wl_valid)
1920 old_rows += wp->w_lines[i++].wl_size;
1921 break;
1922 }
1923#endif
1924 }
1925
1926 if (i >= wp->w_lines_valid)
1927 {
1928 /* We can't find a valid line below the changed lines,
1929 * need to redraw until the end of the window.
1930 * Inserting/deleting lines has no use. */
1931 bot_start = 0;
1932 }
1933 else
1934 {
1935 /* Able to count old number of rows: Count new window
1936 * rows, and may insert/delete lines */
1937 j = idx;
1938 for (l = lnum; l < mod_bot; ++l)
1939 {
1940#ifdef FEAT_FOLDING
1941 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
1942 ++new_rows;
1943 else
1944#endif
1945#ifdef FEAT_DIFF
1946 if (l == wp->w_topline)
1947 new_rows += plines_win_nofill(wp, l, TRUE)
1948 + wp->w_topfill;
1949 else
1950#endif
1951 new_rows += plines_win(wp, l, TRUE);
1952 ++j;
1953 if (new_rows > wp->w_height - row - 2)
1954 {
1955 /* it's getting too much, must redraw the rest */
1956 new_rows = 9999;
1957 break;
1958 }
1959 }
1960 xtra_rows = new_rows - old_rows;
1961 if (xtra_rows < 0)
1962 {
1963 /* May scroll text up. If there is not enough
1964 * remaining text or scrolling fails, must redraw the
1965 * rest. If scrolling works, must redraw the text
1966 * below the scrolled text. */
1967 if (row - xtra_rows >= wp->w_height - 2)
1968 mod_bot = MAXLNUM;
1969 else
1970 {
1971 check_for_delay(FALSE);
1972 if (win_del_lines(wp, row,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02001973 -xtra_rows, FALSE, FALSE, 0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974 mod_bot = MAXLNUM;
1975 else
1976 bot_start = wp->w_height + xtra_rows;
1977 }
1978 }
1979 else if (xtra_rows > 0)
1980 {
1981 /* May scroll text down. If there is not enough
1982 * remaining text of scrolling fails, must redraw the
1983 * rest. */
1984 if (row + xtra_rows >= wp->w_height - 2)
1985 mod_bot = MAXLNUM;
1986 else
1987 {
1988 check_for_delay(FALSE);
1989 if (win_ins_lines(wp, row + old_rows,
1990 xtra_rows, FALSE, FALSE) == FAIL)
1991 mod_bot = MAXLNUM;
1992 else if (top_end > row + old_rows)
1993 /* Scrolled the part at the top that requires
1994 * updating down. */
1995 top_end += xtra_rows;
1996 }
1997 }
1998
1999 /* When not updating the rest, may need to move w_lines[]
2000 * entries. */
2001 if (mod_bot != MAXLNUM && i != j)
2002 {
2003 if (j < i)
2004 {
2005 int x = row + new_rows;
2006
2007 /* move entries in w_lines[] upwards */
2008 for (;;)
2009 {
2010 /* stop at last valid entry in w_lines[] */
2011 if (i >= wp->w_lines_valid)
2012 {
2013 wp->w_lines_valid = j;
2014 break;
2015 }
2016 wp->w_lines[j] = wp->w_lines[i];
2017 /* stop at a line that won't fit */
2018 if (x + (int)wp->w_lines[j].wl_size
2019 > wp->w_height)
2020 {
2021 wp->w_lines_valid = j + 1;
2022 break;
2023 }
2024 x += wp->w_lines[j++].wl_size;
2025 ++i;
2026 }
2027 if (bot_start > x)
2028 bot_start = x;
2029 }
2030 else /* j > i */
2031 {
2032 /* move entries in w_lines[] downwards */
2033 j -= i;
2034 wp->w_lines_valid += j;
2035 if (wp->w_lines_valid > wp->w_height)
2036 wp->w_lines_valid = wp->w_height;
2037 for (i = wp->w_lines_valid; i - j >= idx; --i)
2038 wp->w_lines[i] = wp->w_lines[i - j];
2039
2040 /* The w_lines[] entries for inserted lines are
2041 * now invalid, but wl_size may be used above.
2042 * Reset to zero. */
2043 while (i >= idx)
2044 {
2045 wp->w_lines[i].wl_size = 0;
2046 wp->w_lines[i--].wl_valid = FALSE;
2047 }
2048 }
2049 }
2050 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 }
2052
2053#ifdef FEAT_FOLDING
2054 /*
2055 * When lines are folded, display one line for all of them.
2056 * Otherwise, display normally (can be several display lines when
2057 * 'wrap' is on).
2058 */
2059 fold_count = foldedCount(wp, lnum, &win_foldinfo);
2060 if (fold_count != 0)
2061 {
2062 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2063 ++row;
2064 --fold_count;
2065 wp->w_lines[idx].wl_folded = TRUE;
2066 wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
2067# ifdef FEAT_SYN_HL
2068 did_update = DID_FOLD;
2069# endif
2070 }
2071 else
2072#endif
2073 if (idx < wp->w_lines_valid
2074 && wp->w_lines[idx].wl_valid
2075 && wp->w_lines[idx].wl_lnum == lnum
2076 && lnum > wp->w_topline
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002077 && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02002078 && !WIN_IS_POPUP(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079 && srow + wp->w_lines[idx].wl_size > wp->w_height
2080#ifdef FEAT_DIFF
2081 && diff_check_fill(wp, lnum) == 0
2082#endif
2083 )
2084 {
2085 /* This line is not going to fit. Don't draw anything here,
2086 * will draw "@ " lines below. */
2087 row = wp->w_height + 1;
2088 }
2089 else
2090 {
2091#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarbbca7732019-07-24 18:13:16 +02002092 prepare_search_hl(wp, &search_hl, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093#endif
2094#ifdef FEAT_SYN_HL
2095 /* Let the syntax stuff know we skipped a few lines. */
2096 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
Bram Moolenaar860cae12010-06-05 23:22:07 +02002097 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002098 syntax_end_parsing(syntax_last_parsed + 1);
2099#endif
2100
2101 /*
2102 * Display one line.
2103 */
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002104 row = win_line(wp, lnum, srow, wp->w_height,
2105 mod_top == 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002106
2107#ifdef FEAT_FOLDING
2108 wp->w_lines[idx].wl_folded = FALSE;
2109 wp->w_lines[idx].wl_lastlnum = lnum;
2110#endif
2111#ifdef FEAT_SYN_HL
2112 did_update = DID_LINE;
2113 syntax_last_parsed = lnum;
2114#endif
2115 }
2116
2117 wp->w_lines[idx].wl_lnum = lnum;
2118 wp->w_lines[idx].wl_valid = TRUE;
Bram Moolenaar0e19fc02017-10-28 14:45:16 +02002119
2120 /* Past end of the window or end of the screen. Note that after
2121 * resizing wp->w_height may be end up too big. That's a problem
2122 * elsewhere, but prevent a crash here. */
2123 if (row > wp->w_height || row + wp->w_winrow >= Rows)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 {
2125 /* we may need the size of that too long line later on */
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002126 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
2128 ++idx;
2129 break;
2130 }
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002131 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 wp->w_lines[idx].wl_size = row - srow;
2133 ++idx;
2134#ifdef FEAT_FOLDING
2135 lnum += fold_count + 1;
2136#else
2137 ++lnum;
2138#endif
2139 }
2140 else
2141 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002142 if (wp->w_p_rnu)
2143 {
Bram Moolenaar0e9deef2018-10-02 21:48:34 +02002144#ifdef FEAT_FOLDING
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002145 // 'relativenumber' set: The text doesn't need to be drawn, but
2146 // the number column nearly always does.
Bram Moolenaar7701f302018-10-02 21:20:32 +02002147 fold_count = foldedCount(wp, lnum, &win_foldinfo);
2148 if (fold_count != 0)
Bram Moolenaar7701f302018-10-02 21:20:32 +02002149 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
Bram Moolenaar7701f302018-10-02 21:20:32 +02002150 else
Bram Moolenaar0e9deef2018-10-02 21:48:34 +02002151#endif
Bram Moolenaar7701f302018-10-02 21:20:32 +02002152 (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE);
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02002153 }
2154
2155 // This line does not need to be drawn, advance to the next one.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002156 row += wp->w_lines[idx++].wl_size;
2157 if (row > wp->w_height) /* past end of screen */
2158 break;
2159#ifdef FEAT_FOLDING
2160 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
2161#else
2162 ++lnum;
2163#endif
2164#ifdef FEAT_SYN_HL
2165 did_update = DID_NONE;
2166#endif
2167 }
2168
2169 if (lnum > buf->b_ml.ml_line_count)
2170 {
2171 eof = TRUE;
2172 break;
2173 }
2174 }
2175 /*
2176 * End of loop over all window lines.
2177 */
2178
Bram Moolenaarcafafb32018-02-22 21:07:09 +01002179#ifdef FEAT_VTP
2180 /* Rewrite the character at the end of the screen line. */
2181 if (use_vtp())
2182 {
2183 int i;
2184
2185 for (i = 0; i < Rows; ++i)
Bram Moolenaarcafafb32018-02-22 21:07:09 +01002186 if (enc_utf8)
2187 if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
2188 LineOffset[i] + screen_Columns) > 1)
2189 screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
2190 else
2191 screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
2192 else
Bram Moolenaarcafafb32018-02-22 21:07:09 +01002193 screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
2194 }
2195#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002196
2197 if (idx > wp->w_lines_valid)
2198 wp->w_lines_valid = idx;
2199
2200#ifdef FEAT_SYN_HL
2201 /*
2202 * Let the syntax stuff know we stop parsing here.
2203 */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002204 if (syntax_last_parsed != 0 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205 syntax_end_parsing(syntax_last_parsed + 1);
2206#endif
2207
2208 /*
2209 * If we didn't hit the end of the file, and we didn't finish the last
2210 * line we were working on, then the line didn't fit.
2211 */
2212 wp->w_empty_rows = 0;
2213#ifdef FEAT_DIFF
2214 wp->w_filler_rows = 0;
2215#endif
2216 if (!eof && !didline)
2217 {
2218 if (lnum == wp->w_topline)
2219 {
2220 /*
2221 * Single line that does not fit!
2222 * Don't overwrite it, it can be edited.
2223 */
2224 wp->w_botline = lnum + 1;
2225 }
2226#ifdef FEAT_DIFF
2227 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
2228 {
2229 /* Window ends in filler lines. */
2230 wp->w_botline = lnum;
2231 wp->w_filler_rows = wp->w_height - srow;
2232 }
2233#endif
Bram Moolenaar17146962019-05-30 00:12:11 +02002234#ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02002235 else if (WIN_IS_POPUP(wp))
Bram Moolenaar17146962019-05-30 00:12:11 +02002236 {
2237 // popup line that doesn't fit is left as-is
2238 wp->w_botline = lnum;
2239 }
2240#endif
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002241 else if (dy_flags & DY_TRUNCATE) /* 'display' has "truncate" */
2242 {
2243 int scr_row = W_WINROW(wp) + wp->w_height - 1;
2244
2245 /*
2246 * Last line isn't finished: Display "@@@" in the last screen line.
2247 */
Bram Moolenaar53f81742017-09-22 14:35:51 +02002248 screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002249 HL_ATTR(HLF_AT));
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002250 screen_fill(scr_row, scr_row + 1,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002251 (int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002252 '@', ' ', HL_ATTR(HLF_AT));
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002253 set_empty_rows(wp, srow);
2254 wp->w_botline = lnum;
2255 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256 else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */
2257 {
2258 /*
2259 * Last line isn't finished: Display "@@@" at the end.
2260 */
2261 screen_fill(W_WINROW(wp) + wp->w_height - 1,
2262 W_WINROW(wp) + wp->w_height,
2263 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002264 '@', '@', HL_ATTR(HLF_AT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 set_empty_rows(wp, srow);
2266 wp->w_botline = lnum;
2267 }
2268 else
2269 {
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002270 win_draw_end(wp, '@', ' ', TRUE, srow, wp->w_height, HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 wp->w_botline = lnum;
2272 }
2273 }
2274 else
2275 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 draw_vsep_win(wp, row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277 if (eof) /* we hit the end of the file */
2278 {
2279 wp->w_botline = buf->b_ml.ml_line_count + 1;
2280#ifdef FEAT_DIFF
2281 j = diff_check_fill(wp, wp->w_botline);
2282 if (j > 0 && !wp->w_botfill)
2283 {
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002284 // Display filler lines at the end of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 if (char2cells(fill_diff) > 1)
2286 i = '-';
2287 else
2288 i = fill_diff;
2289 if (row + j > wp->w_height)
2290 j = wp->w_height - row;
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002291 win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 row += j;
2293 }
2294#endif
2295 }
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002296 else if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 wp->w_botline = lnum;
2298
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002299 // Make sure the rest of the screen is blank
2300 // put '~'s on rows that aren't part of the file.
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02002301 win_draw_end(wp, WIN_IS_POPUP(wp) ? ' ' : '~',
2302 ' ', FALSE, row, wp->w_height, HLF_EOB);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303 }
2304
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02002305#ifdef SYN_TIME_LIMIT
2306 syn_set_timeout(NULL);
2307#endif
2308
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309 /* Reset the type of redrawing required, the window has been updated. */
2310 wp->w_redr_type = 0;
2311#ifdef FEAT_DIFF
2312 wp->w_old_topfill = wp->w_topfill;
2313 wp->w_old_botfill = wp->w_botfill;
2314#endif
2315
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002316 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 {
2318 /*
2319 * There is a trick with w_botline. If we invalidate it on each
2320 * change that might modify it, this will cause a lot of expensive
2321 * calls to plines() in update_topline() each time. Therefore the
2322 * value of w_botline is often approximated, and this value is used to
2323 * compute the value of w_topline. If the value of w_botline was
2324 * wrong, check that the value of w_topline is correct (cursor is on
2325 * the visible part of the text). If it's not, we need to redraw
2326 * again. Mostly this just means scrolling up a few lines, so it
2327 * doesn't look too bad. Only do this for the current window (where
2328 * changes are relevant).
2329 */
2330 wp->w_valid |= VALID_BOTLINE;
2331 if (wp == curwin && wp->w_botline != old_botline && !recursive)
2332 {
2333 recursive = TRUE;
2334 curwin->w_valid &= ~VALID_TOPLINE;
2335 update_topline(); /* may invalidate w_botline again */
2336 if (must_redraw != 0)
2337 {
2338 /* Don't update for changes in buffer again. */
2339 i = curbuf->b_mod_set;
2340 curbuf->b_mod_set = FALSE;
2341 win_update(curwin);
2342 must_redraw = 0;
2343 curbuf->b_mod_set = i;
2344 }
2345 recursive = FALSE;
2346 }
2347 }
2348
2349#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2350 /* restore got_int, unless CTRL-C was hit while redrawing */
2351 if (!got_int)
2352 got_int = save_got_int;
2353#endif
2354}
2355
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356/*
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002357 * Call screen_fill() with the columns adjusted for 'rightleft' if needed.
2358 * Return the new offset.
2359 */
2360 static int
2361screen_fill_end(
2362 win_T *wp,
2363 int c1,
2364 int c2,
2365 int off,
2366 int width,
2367 int row,
2368 int endrow,
2369 int attr)
2370{
2371 int nn = off + width;
2372
2373 if (nn > wp->w_width)
2374 nn = wp->w_width;
2375#ifdef FEAT_RIGHTLEFT
2376 if (wp->w_p_rl)
2377 {
2378 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2379 W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off,
2380 c1, c2, attr);
2381 }
2382 else
2383#endif
2384 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2385 wp->w_wincol + off, (int)wp->w_wincol + nn,
2386 c1, c2, attr);
2387 return nn;
2388}
2389
2390/*
2391 * Clear lines near the end the window and mark the unused lines with "c1".
2392 * use "c2" as the filler character.
2393 * When "draw_margin" is TRUE then draw the sign, fold and number columns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 */
2395 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002396win_draw_end(
2397 win_T *wp,
2398 int c1,
2399 int c2,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002400 int draw_margin,
Bram Moolenaar05540972016-01-30 20:31:25 +01002401 int row,
2402 int endrow,
2403 hlf_T hl)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 int n = 0;
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002406 int attr = HL_ATTR(hl);
Bram Moolenaar60cdb302019-05-27 21:54:10 +02002407 int wcr_attr = get_wcr_attr(wp);
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002408
Bram Moolenaar60cdb302019-05-27 21:54:10 +02002409 attr = hl_combine_attr(wcr_attr, attr);
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002410
2411 if (draw_margin)
2412 {
Bram Moolenaar1c934292015-01-27 16:39:29 +01002413#ifdef FEAT_FOLDING
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002414 int fdc = compute_foldcolumn(wp, 0);
2415
2416 if (fdc > 0)
2417 // draw the fold column
2418 n = screen_fill_end(wp, ' ', ' ', n, fdc,
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002419 row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)));
Bram Moolenaar1c934292015-01-27 16:39:29 +01002420#endif
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002421#ifdef FEAT_SIGNS
2422 if (signcolumn_on(wp))
2423 // draw the sign column
2424 n = screen_fill_end(wp, ' ', ' ', n, 2,
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002425 row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)));
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002426#endif
2427 if ((wp->w_p_nu || wp->w_p_rnu)
2428 && vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
2429 // draw the number column
2430 n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1,
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002431 row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)));
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002432 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433
2434#ifdef FEAT_RIGHTLEFT
2435 if (wp->w_p_rl)
2436 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002438 wp->w_wincol, W_ENDCOL(wp) - 1 - n,
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002439 c2, c2, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002441 W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002442 c1, c2, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002443 }
2444 else
2445#endif
2446 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002448 wp->w_wincol + n, (int)W_ENDCOL(wp),
Bram Moolenaar193ffd12019-05-25 22:57:30 +02002449 c1, c2, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450 }
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01002451
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452 set_empty_rows(wp, row);
2453}
2454
Bram Moolenaar1a384422010-07-14 19:53:30 +02002455#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02002456/*
2457 * Advance **color_cols and return TRUE when there are columns to draw.
2458 */
2459 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002460advance_color_col(int vcol, int **color_cols)
Bram Moolenaar1a384422010-07-14 19:53:30 +02002461{
2462 while (**color_cols >= 0 && vcol > **color_cols)
2463 ++*color_cols;
2464 return (**color_cols >= 0);
2465}
2466#endif
2467
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002468#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
2469/*
2470 * Copy "text" to ScreenLines using "attr".
2471 * Returns the next screen column.
2472 */
2473 static int
2474text_to_screenline(win_T *wp, char_u *text, int col)
2475{
2476 int off = (int)(current_ScreenLine - ScreenLines);
2477
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002478 if (has_mbyte)
2479 {
2480 int cells;
2481 int u8c, u8cc[MAX_MCO];
2482 int i;
2483 int idx;
2484 int c_len;
2485 char_u *p;
2486# ifdef FEAT_ARABIC
2487 int prev_c = 0; /* previous Arabic character */
2488 int prev_c1 = 0; /* first composing char for prev_c */
2489# endif
2490
2491# ifdef FEAT_RIGHTLEFT
2492 if (wp->w_p_rl)
2493 idx = off;
2494 else
2495# endif
2496 idx = off + col;
2497
2498 /* Store multibyte characters in ScreenLines[] et al. correctly. */
2499 for (p = text; *p != NUL; )
2500 {
2501 cells = (*mb_ptr2cells)(p);
2502 c_len = (*mb_ptr2len)(p);
Bram Moolenaar02631462017-09-22 15:20:32 +02002503 if (col + cells > wp->w_width
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002504# ifdef FEAT_RIGHTLEFT
2505 - (wp->w_p_rl ? col : 0)
2506# endif
2507 )
2508 break;
2509 ScreenLines[idx] = *p;
2510 if (enc_utf8)
2511 {
2512 u8c = utfc_ptr2char(p, u8cc);
2513 if (*p < 0x80 && u8cc[0] == 0)
2514 {
2515 ScreenLinesUC[idx] = 0;
2516#ifdef FEAT_ARABIC
2517 prev_c = u8c;
2518#endif
2519 }
2520 else
2521 {
2522#ifdef FEAT_ARABIC
2523 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
2524 {
2525 /* Do Arabic shaping. */
2526 int pc, pc1, nc;
2527 int pcc[MAX_MCO];
2528 int firstbyte = *p;
2529
2530 /* The idea of what is the previous and next
2531 * character depends on 'rightleft'. */
2532 if (wp->w_p_rl)
2533 {
2534 pc = prev_c;
2535 pc1 = prev_c1;
2536 nc = utf_ptr2char(p + c_len);
2537 prev_c1 = u8cc[0];
2538 }
2539 else
2540 {
2541 pc = utfc_ptr2char(p + c_len, pcc);
2542 nc = prev_c;
2543 pc1 = pcc[0];
2544 }
2545 prev_c = u8c;
2546
2547 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
2548 pc, pc1, nc);
2549 ScreenLines[idx] = firstbyte;
2550 }
2551 else
2552 prev_c = u8c;
2553#endif
2554 /* Non-BMP character: display as ? or fullwidth ?. */
Bram Moolenaar9ba61172019-01-24 18:20:17 +01002555 ScreenLinesUC[idx] = u8c;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002556 for (i = 0; i < Screen_mco; ++i)
2557 {
2558 ScreenLinesC[i][idx] = u8cc[i];
2559 if (u8cc[i] == 0)
2560 break;
2561 }
2562 }
2563 if (cells > 1)
2564 ScreenLines[idx + 1] = 0;
2565 }
2566 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
2567 /* double-byte single width character */
2568 ScreenLines2[idx] = p[1];
2569 else if (cells > 1)
2570 /* double-width character */
2571 ScreenLines[idx + 1] = p[1];
2572 col += cells;
2573 idx += cells;
2574 p += c_len;
2575 }
2576 }
2577 else
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002578 {
2579 int len = (int)STRLEN(text);
2580
Bram Moolenaar02631462017-09-22 15:20:32 +02002581 if (len > wp->w_width - col)
2582 len = wp->w_width - col;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002583 if (len > 0)
2584 {
2585#ifdef FEAT_RIGHTLEFT
2586 if (wp->w_p_rl)
Bram Moolenaarc6663882019-02-22 19:14:54 +01002587 mch_memmove(current_ScreenLine, text, len);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002588 else
2589#endif
Bram Moolenaarc6663882019-02-22 19:14:54 +01002590 mch_memmove(current_ScreenLine + col, text, len);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002591 col += len;
2592 }
2593 }
2594 return col;
2595}
2596#endif
2597
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598#ifdef FEAT_FOLDING
2599/*
Bram Moolenaar1c934292015-01-27 16:39:29 +01002600 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
2601 * space is available for window "wp", minus "col".
2602 */
2603 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002604compute_foldcolumn(win_T *wp, int col)
Bram Moolenaar1c934292015-01-27 16:39:29 +01002605{
2606 int fdc = wp->w_p_fdc;
2607 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
Bram Moolenaar02631462017-09-22 15:20:32 +02002608 int wwidth = wp->w_width;
Bram Moolenaar1c934292015-01-27 16:39:29 +01002609
2610 if (fdc > wwidth - (col + wmw))
2611 fdc = wwidth - (col + wmw);
2612 return fdc;
2613}
2614
2615/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616 * Display one folded line.
2617 */
2618 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002619fold_line(
2620 win_T *wp,
2621 long fold_count,
2622 foldinfo_T *foldinfo,
2623 linenr_T lnum,
2624 int row)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625{
Bram Moolenaaree695f72016-08-03 22:08:45 +02002626 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627 pos_T *top, *bot;
2628 linenr_T lnume = lnum + fold_count - 1;
2629 int len;
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002630 char_u *text;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002631 int fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 int col;
2633 int txtcol;
2634 int off = (int)(current_ScreenLine - ScreenLines);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002635 int ri;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636
2637 /* Build the fold line:
2638 * 1. Add the cmdwin_type for the command-line window
2639 * 2. Add the 'foldcolumn'
Bram Moolenaar64486672010-05-16 15:46:46 +02002640 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 * 4. Compose the text
2642 * 5. Add the text
2643 * 6. set highlighting for the Visual area an other text
2644 */
2645 col = 0;
2646
2647 /*
2648 * 1. Add the cmdwin_type for the command-line window
2649 * Ignores 'rightleft', this window is never right-left.
2650 */
2651#ifdef FEAT_CMDWIN
2652 if (cmdwin_type != 0 && wp == curwin)
2653 {
2654 ScreenLines[off] = cmdwin_type;
Bram Moolenaar8820b482017-03-16 17:23:31 +01002655 ScreenAttrs[off] = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656 if (enc_utf8)
2657 ScreenLinesUC[off] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 ++col;
2659 }
2660#endif
2661
2662 /*
2663 * 2. Add the 'foldcolumn'
Bram Moolenaar1c934292015-01-27 16:39:29 +01002664 * Reduce the width when there is not enough space.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 */
Bram Moolenaar1c934292015-01-27 16:39:29 +01002666 fdc = compute_foldcolumn(wp, col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 if (fdc > 0)
2668 {
2669 fill_foldcolumn(buf, wp, TRUE, lnum);
2670#ifdef FEAT_RIGHTLEFT
2671 if (wp->w_p_rl)
2672 {
2673 int i;
2674
Bram Moolenaar02631462017-09-22 15:20:32 +02002675 copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002676 HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 /* reverse the fold column */
2678 for (i = 0; i < fdc; ++i)
Bram Moolenaar02631462017-09-22 15:20:32 +02002679 ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680 }
2681 else
2682#endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002683 copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 col += fdc;
2685 }
2686
2687#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6f470022018-04-10 18:47:20 +02002688# define RL_MEMSET(p, v, l) \
2689 do { \
2690 if (wp->w_p_rl) \
2691 for (ri = 0; ri < l; ++ri) \
2692 ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \
2693 else \
2694 for (ri = 0; ri < l; ++ri) \
2695 ScreenAttrs[off + (p) + ri] = v; \
2696 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697#else
Bram Moolenaar6f470022018-04-10 18:47:20 +02002698# define RL_MEMSET(p, v, l) \
2699 do { \
2700 for (ri = 0; ri < l; ++ri) \
2701 ScreenAttrs[off + (p) + ri] = v; \
2702 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703#endif
2704
Bram Moolenaar64486672010-05-16 15:46:46 +02002705 /* Set all attributes of the 'number' or 'relativenumber' column and the
2706 * text */
Bram Moolenaar02631462017-09-22 15:20:32 +02002707 RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708
2709#ifdef FEAT_SIGNS
2710 /* If signs are being displayed, add two spaces. */
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02002711 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 {
Bram Moolenaar02631462017-09-22 15:20:32 +02002713 len = wp->w_width - col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 if (len > 0)
2715 {
2716 if (len > 2)
2717 len = 2;
2718# ifdef FEAT_RIGHTLEFT
2719 if (wp->w_p_rl)
2720 /* the line number isn't reversed */
Bram Moolenaar02631462017-09-22 15:20:32 +02002721 copy_text_attr(off + wp->w_width - len - col,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002722 (char_u *)" ", len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 else
2724# endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002725 copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726 col += len;
2727 }
2728 }
2729#endif
2730
2731 /*
Bram Moolenaar64486672010-05-16 15:46:46 +02002732 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733 */
Bram Moolenaar64486672010-05-16 15:46:46 +02002734 if (wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735 {
Bram Moolenaar02631462017-09-22 15:20:32 +02002736 len = wp->w_width - col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 if (len > 0)
2738 {
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002739 int w = number_width(wp);
Bram Moolenaar24dc2302014-05-13 20:19:58 +02002740 long num;
2741 char *fmt = "%*ld ";
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002742
2743 if (len > w + 1)
2744 len = w + 1;
Bram Moolenaar64486672010-05-16 15:46:46 +02002745
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002746 if (wp->w_p_nu && !wp->w_p_rnu)
2747 /* 'number' + 'norelativenumber' */
Bram Moolenaar64486672010-05-16 15:46:46 +02002748 num = (long)lnum;
2749 else
Bram Moolenaar700e7342013-01-30 12:31:36 +01002750 {
Bram Moolenaar64486672010-05-16 15:46:46 +02002751 /* 'relativenumber', don't use negative numbers */
Bram Moolenaar7eb46522010-12-30 14:57:08 +01002752 num = labs((long)get_cursor_rel_lnum(wp, lnum));
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002753 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01002754 {
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002755 /* 'number' + 'relativenumber': cursor line shows absolute
2756 * line number */
Bram Moolenaar700e7342013-01-30 12:31:36 +01002757 num = lnum;
2758 fmt = "%-*ld ";
2759 }
2760 }
Bram Moolenaar64486672010-05-16 15:46:46 +02002761
Bram Moolenaar700e7342013-01-30 12:31:36 +01002762 sprintf((char *)buf, fmt, w, num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763#ifdef FEAT_RIGHTLEFT
2764 if (wp->w_p_rl)
2765 /* the line number isn't reversed */
Bram Moolenaar02631462017-09-22 15:20:32 +02002766 copy_text_attr(off + wp->w_width - len - col, buf, len,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002767 HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768 else
2769#endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002770 copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771 col += len;
2772 }
2773 }
2774
2775 /*
2776 * 4. Compose the folded-line string with 'foldtext', if set.
2777 */
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002778 text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779
2780 txtcol = col; /* remember where text starts */
2781
2782 /*
2783 * 5. move the text to current_ScreenLine. Fill up with "fill_fold".
2784 * Right-left text is put in columns 0 - number-col, normal text is put
2785 * in columns number-col - window-width.
2786 */
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002787 col = text_to_screenline(wp, text, col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002788
2789 /* Fill the rest of the line with the fold filler */
2790#ifdef FEAT_RIGHTLEFT
2791 if (wp->w_p_rl)
2792 col -= txtcol;
2793#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02002794 while (col < wp->w_width
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795#ifdef FEAT_RIGHTLEFT
2796 - (wp->w_p_rl ? txtcol : 0)
2797#endif
2798 )
2799 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800 if (enc_utf8)
2801 {
2802 if (fill_fold >= 0x80)
2803 {
2804 ScreenLinesUC[off + col] = fill_fold;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002805 ScreenLinesC[0][off + col] = 0;
Bram Moolenaaracda04f2018-02-08 09:57:28 +01002806 ScreenLines[off + col] = 0x80; /* avoid storing zero */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 }
2808 else
Bram Moolenaar8da1e6c2017-03-29 20:38:59 +02002809 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002810 ScreenLinesUC[off + col] = 0;
Bram Moolenaar8da1e6c2017-03-29 20:38:59 +02002811 ScreenLines[off + col] = fill_fold;
2812 }
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002813 col++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814 }
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002815 else
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002816 ScreenLines[off + col++] = fill_fold;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 }
2818
2819 if (text != buf)
2820 vim_free(text);
2821
2822 /*
2823 * 6. set highlighting for the Visual area an other text.
2824 * If all folded lines are in the Visual area, highlight the line.
2825 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
2827 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01002828 if (LTOREQ_POS(curwin->w_cursor, VIsual))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829 {
2830 /* Visual is after curwin->w_cursor */
2831 top = &curwin->w_cursor;
2832 bot = &VIsual;
2833 }
2834 else
2835 {
2836 /* Visual is before curwin->w_cursor */
2837 top = &VIsual;
2838 bot = &curwin->w_cursor;
2839 }
2840 if (lnum >= top->lnum
2841 && lnume <= bot->lnum
2842 && (VIsual_mode != 'v'
2843 || ((lnum > top->lnum
2844 || (lnum == top->lnum
2845 && top->col == 0))
2846 && (lnume < bot->lnum
2847 || (lnume == bot->lnum
2848 && (bot->col - (*p_sel == 'e'))
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002849 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850 {
2851 if (VIsual_mode == Ctrl_V)
2852 {
2853 /* Visual block mode: highlight the chars part of the block */
Bram Moolenaar02631462017-09-22 15:20:32 +02002854 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855 {
Bram Moolenaar6c167c62011-09-02 14:07:36 +02002856 if (wp->w_old_cursor_lcol != MAXCOL
2857 && wp->w_old_cursor_lcol + txtcol
Bram Moolenaar02631462017-09-22 15:20:32 +02002858 < (colnr_T)wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859 len = wp->w_old_cursor_lcol;
2860 else
Bram Moolenaar02631462017-09-22 15:20:32 +02002861 len = wp->w_width - txtcol;
Bram Moolenaar8820b482017-03-16 17:23:31 +01002862 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V),
Bram Moolenaar68b76a62005-03-25 21:53:48 +00002863 len - (int)wp->w_old_cursor_fcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864 }
2865 }
2866 else
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002867 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002868 /* Set all attributes of the text */
Bram Moolenaar02631462017-09-22 15:20:32 +02002869 RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002870 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 }
2872 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002874#ifdef FEAT_SYN_HL
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002875 /* Show colorcolumn in the fold line, but let cursorcolumn override it. */
2876 if (wp->w_p_cc_cols)
2877 {
2878 int i = 0;
2879 int j = wp->w_p_cc_cols[i];
2880 int old_txtcol = txtcol;
2881
2882 while (j > -1)
2883 {
2884 txtcol += j;
2885 if (wp->w_p_wrap)
2886 txtcol -= wp->w_skipcol;
2887 else
2888 txtcol -= wp->w_leftcol;
Bram Moolenaar02631462017-09-22 15:20:32 +02002889 if (txtcol >= 0 && txtcol < wp->w_width)
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002890 ScreenAttrs[off + txtcol] = hl_combine_attr(
Bram Moolenaar8820b482017-03-16 17:23:31 +01002891 ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC));
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002892 txtcol = old_txtcol;
2893 j = wp->w_p_cc_cols[++i];
2894 }
2895 }
2896
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002897 /* Show 'cursorcolumn' in the fold line. */
Bram Moolenaar85595c52008-10-02 16:04:05 +00002898 if (wp->w_p_cuc)
2899 {
2900 txtcol += wp->w_virtcol;
2901 if (wp->w_p_wrap)
2902 txtcol -= wp->w_skipcol;
2903 else
2904 txtcol -= wp->w_leftcol;
Bram Moolenaar02631462017-09-22 15:20:32 +02002905 if (txtcol >= 0 && txtcol < wp->w_width)
Bram Moolenaar85595c52008-10-02 16:04:05 +00002906 ScreenAttrs[off + txtcol] = hl_combine_attr(
Bram Moolenaar8820b482017-03-16 17:23:31 +01002907 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC));
Bram Moolenaar85595c52008-10-02 16:04:05 +00002908 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002909#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910
Bram Moolenaar02631462017-09-22 15:20:32 +02002911 screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
Bram Moolenaar4d784b22019-05-25 19:51:39 +02002912 (int)wp->w_width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913
2914 /*
2915 * Update w_cline_height and w_cline_folded if the cursor line was
2916 * updated (saves a call to plines() later).
2917 */
2918 if (wp == curwin
2919 && lnum <= curwin->w_cursor.lnum
2920 && lnume >= curwin->w_cursor.lnum)
2921 {
2922 curwin->w_cline_row = row;
2923 curwin->w_cline_height = 1;
2924 curwin->w_cline_folded = TRUE;
2925 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
2926 }
2927}
2928
2929/*
2930 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
2931 */
2932 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002933copy_text_attr(
2934 int off,
2935 char_u *buf,
2936 int len,
2937 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938{
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002939 int i;
2940
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 mch_memmove(ScreenLines + off, buf, (size_t)len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 if (enc_utf8)
2943 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002944 for (i = 0; i < len; ++i)
2945 ScreenAttrs[off + i] = attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946}
2947
2948/*
2949 * Fill the foldcolumn at "p" for window "wp".
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +00002950 * Only to be called when 'foldcolumn' > 0.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951 */
2952 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002953fill_foldcolumn(
2954 char_u *p,
2955 win_T *wp,
2956 int closed, /* TRUE of FALSE */
2957 linenr_T lnum) /* current line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958{
2959 int i = 0;
2960 int level;
2961 int first_level;
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002962 int empty;
Bram Moolenaar1c934292015-01-27 16:39:29 +01002963 int fdc = compute_foldcolumn(wp, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964
2965 /* Init to all spaces. */
Bram Moolenaar2536d4f2015-07-17 13:22:51 +02002966 vim_memset(p, ' ', (size_t)fdc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967
2968 level = win_foldinfo.fi_level;
2969 if (level > 0)
2970 {
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002971 /* If there is only one column put more info in it. */
Bram Moolenaar1c934292015-01-27 16:39:29 +01002972 empty = (fdc == 1) ? 0 : 1;
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002973
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974 /* If the column is too narrow, we start at the lowest level that
2975 * fits and use numbers to indicated the depth. */
Bram Moolenaar1c934292015-01-27 16:39:29 +01002976 first_level = level - fdc - closed + 1 + empty;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002977 if (first_level < 1)
2978 first_level = 1;
2979
Bram Moolenaar1c934292015-01-27 16:39:29 +01002980 for (i = 0; i + empty < fdc; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981 {
2982 if (win_foldinfo.fi_lnum == lnum
2983 && first_level + i >= win_foldinfo.fi_low_level)
2984 p[i] = '-';
2985 else if (first_level == 1)
2986 p[i] = '|';
2987 else if (first_level + i <= 9)
2988 p[i] = '0' + first_level + i;
2989 else
2990 p[i] = '>';
2991 if (first_level + i == level)
2992 break;
2993 }
2994 }
2995 if (closed)
Bram Moolenaar1c934292015-01-27 16:39:29 +01002996 p[i >= fdc ? i - 1 : i] = '+';
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997}
2998#endif /* FEAT_FOLDING */
2999
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01003000#ifdef FEAT_TEXT_PROP
3001static textprop_T *current_text_props = NULL;
3002static buf_T *current_buf = NULL;
3003
3004 static int
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01003005text_prop_compare(const void *s1, const void *s2)
3006{
3007 int idx1, idx2;
3008 proptype_T *pt1, *pt2;
3009 colnr_T col1, col2;
3010
3011 idx1 = *(int *)s1;
3012 idx2 = *(int *)s2;
3013 pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type);
3014 pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type);
3015 if (pt1 == pt2)
3016 return 0;
3017 if (pt1 == NULL)
3018 return -1;
3019 if (pt2 == NULL)
3020 return 1;
3021 if (pt1->pt_priority != pt2->pt_priority)
3022 return pt1->pt_priority > pt2->pt_priority ? 1 : -1;
3023 col1 = current_text_props[idx1].tp_col;
3024 col2 = current_text_props[idx2].tp_col;
3025 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1;
3026}
3027#endif
3028
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003029#ifdef FEAT_SIGNS
3030/*
3031 * Get information needed to display the sign in line 'lnum' in window 'wp'.
3032 * If 'nrcol' is TRUE, the sign is going to be displayed in the number column.
3033 * Otherwise the sign is going to be displayed in the sign column.
3034 */
3035 static void
3036get_sign_display_info(
3037 int nrcol,
3038 win_T *wp,
Bram Moolenaar4e038572019-07-04 18:28:35 +02003039 linenr_T lnum UNUSED,
3040 sign_attrs_T *sattr,
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003041 int wcr_attr,
3042 int row,
3043 int startrow,
Bram Moolenaarbf8c3ad2019-06-19 14:28:43 +02003044 int filler_lines UNUSED,
3045 int filler_todo UNUSED,
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003046 int *c_extrap,
3047 int *c_finalp,
3048 char_u *extra,
3049 char_u **pp_extra,
3050 int *n_extrap,
3051 int *char_attrp)
3052{
3053 int text_sign;
3054# ifdef FEAT_SIGN_ICONS
3055 int icon_sign;
3056# endif
3057
3058 // Draw two cells with the sign value or blank.
3059 *c_extrap = ' ';
3060 *c_finalp = NUL;
3061 if (nrcol)
3062 *n_extrap = number_width(wp) + 1;
3063 else
3064 {
3065 *char_attrp = hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC));
3066 *n_extrap = 2;
3067 }
3068
3069 if (row == startrow
3070#ifdef FEAT_DIFF
3071 + filler_lines && filler_todo <= 0
3072#endif
3073 )
3074 {
Bram Moolenaar4e038572019-07-04 18:28:35 +02003075 text_sign = (sattr->text != NULL) ? sattr->typenr : 0;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003076# ifdef FEAT_SIGN_ICONS
Bram Moolenaar4e038572019-07-04 18:28:35 +02003077 icon_sign = (sattr->icon != NULL) ? sattr->typenr : 0;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003078 if (gui.in_use && icon_sign != 0)
3079 {
3080 // Use the image in this position.
Bram Moolenaar4dff4ae2019-06-19 16:31:28 +02003081 if (nrcol)
3082 {
3083 *c_extrap = NUL;
3084 sprintf((char *)extra, "%-*c ", number_width(wp), SIGN_BYTE);
3085 *pp_extra = extra;
3086 *n_extrap = (int)STRLEN(*pp_extra);
3087 }
3088 else
3089 *c_extrap = SIGN_BYTE;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003090# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar4e038572019-07-04 18:28:35 +02003091 if (netbeans_active() && (buf_signcount(wp->w_buffer, lnum) > 1))
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003092 {
Bram Moolenaar4dff4ae2019-06-19 16:31:28 +02003093 if (nrcol)
3094 {
3095 *c_extrap = NUL;
3096 sprintf((char *)extra, "%-*c ", number_width(wp),
3097 MULTISIGN_BYTE);
3098 *pp_extra = extra;
3099 *n_extrap = (int)STRLEN(*pp_extra);
3100 }
3101 else
3102 *c_extrap = MULTISIGN_BYTE;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003103 }
3104# endif
Bram Moolenaar4dff4ae2019-06-19 16:31:28 +02003105 *c_finalp = NUL;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003106 *char_attrp = icon_sign;
3107 }
3108 else
3109# endif
3110 if (text_sign != 0)
3111 {
Bram Moolenaar4e038572019-07-04 18:28:35 +02003112 *pp_extra = sattr->text;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003113 if (*pp_extra != NULL)
3114 {
3115 if (nrcol)
3116 {
Bram Moolenaard6bcff42019-07-18 12:48:16 +02003117 int n, width = number_width(wp) - 2;
3118
3119 for (n = 0; n < width; n++)
3120 extra[n] = ' ';
3121 extra[n] = 0;
3122 STRCAT(extra, *pp_extra);
3123 STRCAT(extra, " ");
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003124 *pp_extra = extra;
3125 }
3126 *c_extrap = NUL;
3127 *c_finalp = NUL;
3128 *n_extrap = (int)STRLEN(*pp_extra);
3129 }
Bram Moolenaar4e038572019-07-04 18:28:35 +02003130 *char_attrp = sattr->texthl;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003131 }
3132 }
3133}
3134#endif
3135
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136/*
3137 * Display line "lnum" of window 'wp' on the screen.
3138 * Start at row "startrow", stop when "endrow" is reached.
3139 * wp->w_virtcol needs to be valid.
3140 *
3141 * Return the number of last row the line occupies.
3142 */
3143 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003144win_line(
3145 win_T *wp,
3146 linenr_T lnum,
3147 int startrow,
3148 int endrow,
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003149 int nochange UNUSED, // not updating for changed text
3150 int number_only) // only update the number column
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151{
Bram Moolenaarf8a07122019-07-01 22:06:07 +02003152 int col = 0; // visual column on screen
3153 unsigned off; // offset in ScreenLines/ScreenAttrs
3154 int c = 0; // init for GCC
3155 long vcol = 0; // virtual column (for tabs)
Bram Moolenaard574ea22015-01-14 19:35:14 +01003156#ifdef FEAT_LINEBREAK
Bram Moolenaarf8a07122019-07-01 22:06:07 +02003157 long vcol_sbr = -1; // virtual column after showbreak
Bram Moolenaard574ea22015-01-14 19:35:14 +01003158#endif
Bram Moolenaarf8a07122019-07-01 22:06:07 +02003159 long vcol_prev = -1; // "vcol" of previous character
3160 char_u *line; // current line
3161 char_u *ptr; // current position in "line"
3162 int row; // row in the window, excl w_winrow
3163 int screen_row; // row on the screen, incl w_winrow
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164
Bram Moolenaarf8a07122019-07-01 22:06:07 +02003165 char_u extra[21]; // "%ld " and 'fdc' must fit in here
3166 int n_extra = 0; // number of extra chars
3167 char_u *p_extra = NULL; // string of extra chars, plus NUL
3168 char_u *p_extra_free = NULL; // p_extra needs to be freed
3169 int c_extra = NUL; // extra chars, all the same
3170 int c_final = NUL; // final char, mandatory if set
3171 int extra_attr = 0; // attributes when n_extra != 0
3172 static char_u *at_end_str = (char_u *)""; // used for p_extra when
3173 // displaying lcs_eol at end-of-line
3174 int lcs_eol_one = lcs_eol; // lcs_eol until it's been used
3175 int lcs_prec_todo = lcs_prec; // lcs_prec until it's been used
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176
Bram Moolenaarf8a07122019-07-01 22:06:07 +02003177 // saved "extra" items for when draw_state becomes WL_LINE (again)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178 int saved_n_extra = 0;
3179 char_u *saved_p_extra = NULL;
3180 int saved_c_extra = 0;
Bram Moolenaar83a52172019-01-16 22:41:54 +01003181 int saved_c_final = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003182 int saved_char_attr = 0;
3183
3184 int n_attr = 0; /* chars with special attr */
3185 int saved_attr2 = 0; /* char_attr saved for n_attr */
3186 int n_attr3 = 0; /* chars with overruling special attr */
3187 int saved_attr3 = 0; /* char_attr saved for n_attr3 */
3188
3189 int n_skip = 0; /* nr of chars to skip for 'nowrap' */
3190
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003191 int fromcol = -10; // start of inverting
3192 int tocol = MAXCOL; // end of inverting
3193 int fromcol_prev = -2; // start of inverting after cursor
3194 int noinvcur = FALSE; // don't invert the cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 pos_T *top, *bot;
Bram Moolenaar54ef7112009-02-21 20:11:41 +00003196 int lnum_in_visual_area = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197 pos_T pos;
3198 long v;
3199
Bram Moolenaar193ffd12019-05-25 22:57:30 +02003200 int char_attr = 0; // attributes for next character
3201 int attr_pri = FALSE; // char_attr has priority
3202 int area_highlighting = FALSE; // Visual or incsearch highlighting
3203 // in this line
3204 int vi_attr = 0; // attributes for Visual and incsearch
3205 // highlighting
3206 int wcr_attr = 0; // attributes from 'wincolor'
Bram Moolenaar60cdb302019-05-27 21:54:10 +02003207 int win_attr = 0; // background for whole window, except
3208 // margins and "~" lines.
Bram Moolenaar193ffd12019-05-25 22:57:30 +02003209 int area_attr = 0; // attributes desired by highlighting
3210 int search_attr = 0; // attributes desired by 'hlsearch'
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211#ifdef FEAT_SYN_HL
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003212 int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 int syntax_attr = 0; /* attributes desired by syntax */
3214 int has_syntax = FALSE; /* this buffer has syntax highl. */
3215 int save_did_emsg;
Bram Moolenaar1a384422010-07-14 19:53:30 +02003216 int draw_color_col = FALSE; /* highlight colorcolumn */
3217 int *color_cols = NULL; /* pointer to according columns array */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003218#endif
Bram Moolenaarf914a332019-07-20 15:09:56 +02003219 int eol_hl_off = 0; /* 1 if highlighted char after EOL */
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003220#ifdef FEAT_TEXT_PROP
3221 int text_prop_count;
3222 int text_prop_next = 0; // next text property to use
3223 textprop_T *text_props = NULL;
3224 int *text_prop_idxs = NULL;
3225 int text_props_active = 0;
3226 proptype_T *text_prop_type = NULL;
3227 int text_prop_attr = 0;
Bram Moolenaarde24a872019-05-05 15:48:00 +02003228 int text_prop_combine = FALSE;
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003229#endif
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003230#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00003231 int has_spell = FALSE; /* this buffer has spell checking */
Bram Moolenaar30abd282005-06-22 22:35:10 +00003232# define SPWORDLEN 150
3233 char_u nextline[SPWORDLEN * 2];/* text with start of the next line */
Bram Moolenaar3b506942005-06-23 22:36:45 +00003234 int nextlinecol = 0; /* column where nextline[] starts */
3235 int nextline_idx = 0; /* index in nextline[] where next line
Bram Moolenaar30abd282005-06-22 22:35:10 +00003236 starts */
Bram Moolenaar217ad922005-03-20 22:37:15 +00003237 int spell_attr = 0; /* attributes desired by spelling */
3238 int word_end = 0; /* last byte with same spell_attr */
Bram Moolenaard042c562005-06-30 22:04:15 +00003239 static linenr_T checked_lnum = 0; /* line number for "checked_col" */
3240 static int checked_col = 0; /* column in "checked_lnum" up to which
Bram Moolenaar30abd282005-06-22 22:35:10 +00003241 * there are no spell errors */
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003242 static int cap_col = -1; /* column to check for Cap word */
3243 static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */
Bram Moolenaar30abd282005-06-22 22:35:10 +00003244 int cur_checked_col = 0; /* checked column for current line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003246 int extra_check = 0; // has extra highlighting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247 int multi_attr = 0; /* attributes desired by multibyte */
3248 int mb_l = 1; /* multi-byte byte length */
3249 int mb_c = 0; /* decoded multi-byte character */
3250 int mb_utf8 = FALSE; /* screen char is UTF-8 char */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003251 int u8cc[MAX_MCO]; /* composing UTF-8 chars */
Bram Moolenaare9726e32019-06-19 18:01:21 +02003252#if defined(FEAT_DIFF) || defined(FEAT_SIGNS)
Bram Moolenaarbf8c3ad2019-06-19 14:28:43 +02003253 int filler_lines = 0; /* nr of filler lines to be drawn */
3254 int filler_todo = 0; /* nr of filler lines still to do + 1 */
Bram Moolenaare9726e32019-06-19 18:01:21 +02003255#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256#ifdef FEAT_DIFF
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003257 hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 int change_start = MAXCOL; /* first col of changed area */
3259 int change_end = -1; /* last col of changed area */
3260#endif
3261 colnr_T trailcol = MAXCOL; /* start of trailing spaces */
3262#ifdef FEAT_LINEBREAK
Bram Moolenaar6c896862016-11-17 19:46:51 +01003263 int need_showbreak = FALSE; /* overlong line, skipping first x
3264 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02003266#if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00003267 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268# define LINE_ATTR
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003269 int line_attr = 0; /* attribute for the whole line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003270#endif
Bram Moolenaarb4d9b892019-07-04 22:59:06 +02003271#ifdef FEAT_SIGNS
3272 int sign_present = FALSE;
3273 sign_attrs_T sattr;
3274#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275#ifdef FEAT_ARABIC
3276 int prev_c = 0; /* previous Arabic character */
3277 int prev_c1 = 0; /* first composing char for prev_c */
3278#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00003279#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00003280 int did_line_attr = 0;
3281#endif
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003282#ifdef FEAT_TERMINAL
3283 int get_term_attr = FALSE;
3284#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285
3286 /* draw_state: items that are drawn in sequence: */
3287#define WL_START 0 /* nothing done yet */
3288#ifdef FEAT_CMDWIN
3289# define WL_CMDLINE WL_START + 1 /* cmdline window column */
3290#else
3291# define WL_CMDLINE WL_START
3292#endif
3293#ifdef FEAT_FOLDING
3294# define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
3295#else
3296# define WL_FOLD WL_CMDLINE
3297#endif
3298#ifdef FEAT_SIGNS
3299# define WL_SIGN WL_FOLD + 1 /* column for signs */
3300#else
3301# define WL_SIGN WL_FOLD /* column for signs */
3302#endif
3303#define WL_NR WL_SIGN + 1 /* line number */
Bram Moolenaar597a4222014-06-25 14:39:50 +02003304#ifdef FEAT_LINEBREAK
3305# define WL_BRI WL_NR + 1 /* 'breakindent' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306#else
Bram Moolenaar597a4222014-06-25 14:39:50 +02003307# define WL_BRI WL_NR
3308#endif
3309#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3310# define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */
3311#else
3312# define WL_SBR WL_BRI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313#endif
3314#define WL_LINE WL_SBR + 1 /* text in the line */
3315 int draw_state = WL_START; /* what to draw next */
Bram Moolenaar9372a112005-12-06 19:59:18 +00003316#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 int feedback_col = 0;
3318 int feedback_old_attr = -1;
3319#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003320 int screen_line_flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321
Bram Moolenaarfbfb7572019-07-25 20:53:03 +02003322#if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA)
Bram Moolenaar07d13562019-07-24 18:43:08 +02003323 int match_conc = 0; // cchar for match functions
Bram Moolenaarfbfb7572019-07-25 20:53:03 +02003324#endif
Bram Moolenaar860cae12010-06-05 23:22:07 +02003325#ifdef FEAT_CONCEAL
3326 int syntax_flags = 0;
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02003327 int syntax_seqnr = 0;
Bram Moolenaar27c735b2010-07-22 22:16:29 +02003328 int prev_syntax_id = 0;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003329 int conceal_attr = HL_ATTR(HLF_CONCEAL);
Bram Moolenaar860cae12010-06-05 23:22:07 +02003330 int is_concealing = FALSE;
Bram Moolenaar07d13562019-07-24 18:43:08 +02003331 int boguscols = 0; // nonexistent columns added to force
3332 // wrapping
3333 int vcol_off = 0; // offset for concealed characters
Bram Moolenaarf5963f72010-07-23 22:10:27 +02003334 int did_wcol = FALSE;
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01003335 int old_boguscols = 0;
Bram Moolenaarac550fd2010-07-18 13:55:02 +02003336# define VCOL_HLC (vcol - vcol_off)
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02003337# define FIX_FOR_BOGUSCOLS \
3338 { \
3339 n_extra += vcol_off; \
3340 vcol -= vcol_off; \
3341 vcol_off = 0; \
3342 col -= boguscols; \
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01003343 old_boguscols = boguscols; \
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02003344 boguscols = 0; \
3345 }
Bram Moolenaarac550fd2010-07-18 13:55:02 +02003346#else
3347# define VCOL_HLC (vcol)
Bram Moolenaar860cae12010-06-05 23:22:07 +02003348#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349
3350 if (startrow > endrow) /* past the end already! */
3351 return startrow;
3352
3353 row = startrow;
3354 screen_row = row + W_WINROW(wp);
3355
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003356 if (!number_only)
3357 {
3358 /*
3359 * To speed up the loop below, set extra_check when there is linebreak,
3360 * trailing white space and/or syntax processing to be done.
3361 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362#ifdef FEAT_LINEBREAK
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003363 extra_check = wp->w_p_lbr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364#endif
3365#ifdef FEAT_SYN_HL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003366 if (syntax_present(wp) && !wp->w_s->b_syn_error
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003367# ifdef SYN_TIME_LIMIT
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003368 && !wp->w_s->b_syn_slow
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003369# endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003370 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003372 /* Prepare for syntax highlighting in this line. When there is an
3373 * error, stop syntax highlighting. */
3374 save_did_emsg = did_emsg;
3375 did_emsg = FALSE;
3376 syntax_start(wp, lnum);
3377 if (did_emsg)
3378 wp->w_s->b_syn_error = TRUE;
3379 else
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003380 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003381 did_emsg = save_did_emsg;
3382#ifdef SYN_TIME_LIMIT
3383 if (!wp->w_s->b_syn_slow)
3384#endif
3385 {
3386 has_syntax = TRUE;
3387 extra_check = TRUE;
3388 }
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003389 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003390 }
Bram Moolenaar1a384422010-07-14 19:53:30 +02003391
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003392 /* Check for columns to display for 'colorcolumn'. */
3393 color_cols = wp->w_p_cc_cols;
3394 if (color_cols != NULL)
3395 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003396#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00003397
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003398#ifdef FEAT_TERMINAL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003399 if (term_show_buffer(wp->w_buffer))
3400 {
3401 extra_check = TRUE;
3402 get_term_attr = TRUE;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003403 win_attr = term_get_attr(wp->w_buffer, lnum, -1);
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003404 }
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003405#endif
3406
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003407#ifdef FEAT_SPELL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003408 if (wp->w_p_spell
3409 && *wp->w_s->b_p_spl != NUL
3410 && wp->w_s->b_langp.ga_len > 0
3411 && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
Bram Moolenaar30abd282005-06-22 22:35:10 +00003412 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003413 /* Prepare for spell checking. */
3414 has_spell = TRUE;
3415 extra_check = TRUE;
3416
Bram Moolenaar7701f302018-10-02 21:20:32 +02003417 /* Get the start of the next line, so that words that wrap to the
3418 * next line are found too: "et<line-break>al.".
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003419 * Trick: skip a few chars for C/shell/Vim comments */
3420 nextline[SPWORDLEN] = NUL;
3421 if (lnum < wp->w_buffer->b_ml.ml_line_count)
3422 {
3423 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
3424 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
3425 }
3426
Bram Moolenaar7701f302018-10-02 21:20:32 +02003427 /* When a word wrapped from the previous line the start of the
3428 * current line is valid. */
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003429 if (lnum == checked_lnum)
3430 cur_checked_col = checked_col;
3431 checked_lnum = 0;
3432
3433 /* When there was a sentence end in the previous line may require a
3434 * word starting with capital in this line. In line 1 always check
3435 * the first word. */
3436 if (lnum != capcol_lnum)
3437 cap_col = -1;
3438 if (lnum == 1)
3439 cap_col = 0;
3440 capcol_lnum = 0;
Bram Moolenaar30abd282005-06-22 22:35:10 +00003441 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442#endif
3443
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003444 /*
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003445 * handle Visual active in this window
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003446 */
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003447 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003449 if (LTOREQ_POS(curwin->w_cursor, VIsual))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003450 {
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003451 // Visual is after curwin->w_cursor
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003452 top = &curwin->w_cursor;
3453 bot = &VIsual;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454 }
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003455 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456 {
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003457 // Visual is before curwin->w_cursor
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003458 top = &VIsual;
3459 bot = &curwin->w_cursor;
3460 }
3461 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003462 if (VIsual_mode == Ctrl_V)
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003463 {
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003464 // block mode
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003465 if (lnum_in_visual_area)
3466 {
3467 fromcol = wp->w_old_cursor_fcol;
3468 tocol = wp->w_old_cursor_lcol;
3469 }
3470 }
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003471 else
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003472 {
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003473 // non-block mode
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003474 if (lnum > top->lnum && lnum <= bot->lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003475 fromcol = 0;
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003476 else if (lnum == top->lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003477 {
Bram Moolenaarec572ad2019-07-07 14:26:59 +02003478 if (VIsual_mode == 'V') // linewise
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003479 fromcol = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480 else
3481 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003482 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
3483 if (gchar_pos(top) == NUL)
3484 tocol = fromcol + 1;
3485 }
3486 }
3487 if (VIsual_mode != 'V' && lnum == bot->lnum)
3488 {
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003489 if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0)
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003490 {
3491 fromcol = -10;
3492 tocol = MAXCOL;
3493 }
3494 else if (bot->col == MAXCOL)
3495 tocol = MAXCOL;
3496 else
3497 {
3498 pos = *bot;
3499 if (*p_sel == 'e')
3500 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
3501 else
3502 {
3503 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
3504 ++tocol;
3505 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506 }
3507 }
3508 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003510 /* Check if the character under the cursor should not be inverted */
3511 if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003512#ifdef FEAT_GUI
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003513 && !gui.in_use
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003514#endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003515 )
3516 noinvcur = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003517
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003518 /* if inverting in this line set area_highlighting */
3519 if (fromcol >= 0)
3520 {
3521 area_highlighting = TRUE;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003522 vi_attr = HL_ATTR(HLF_V);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003523#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003524 if ((clip_star.available && !clip_star.owned
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003525 && clip_isautosel_star())
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003526 || (clip_plus.available && !clip_plus.owned
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003527 && clip_isautosel_plus()))
3528 vi_attr = HL_ATTR(HLF_VNC);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529#endif
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003530 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003533 /*
3534 * handle 'incsearch' and ":s///c" highlighting
3535 */
3536 else if (highlight_match
3537 && wp == curwin
3538 && lnum >= curwin->w_cursor.lnum
3539 && lnum <= curwin->w_cursor.lnum + search_match_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003541 if (lnum == curwin->w_cursor.lnum)
3542 getvcol(curwin, &(curwin->w_cursor),
Bram Moolenaarc6663882019-02-22 19:14:54 +01003543 (colnr_T *)&fromcol, NULL, NULL);
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003544 else
3545 fromcol = 0;
3546 if (lnum == curwin->w_cursor.lnum + search_match_lines)
3547 {
3548 pos.lnum = lnum;
3549 pos.col = search_match_endcol;
3550 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
3551 }
3552 else
3553 tocol = MAXCOL;
3554 /* do at least one character; happens when past end of line */
3555 if (fromcol == tocol)
3556 tocol = fromcol + 1;
3557 area_highlighting = TRUE;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003558 vi_attr = HL_ATTR(HLF_I);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 }
3561
3562#ifdef FEAT_DIFF
3563 filler_lines = diff_check(wp, lnum);
3564 if (filler_lines < 0)
3565 {
3566 if (filler_lines == -1)
3567 {
3568 if (diff_find_change(wp, lnum, &change_start, &change_end))
3569 diff_hlf = HLF_ADD; /* added line */
3570 else if (change_start == 0)
3571 diff_hlf = HLF_TXD; /* changed text */
3572 else
3573 diff_hlf = HLF_CHD; /* changed line */
3574 }
3575 else
3576 diff_hlf = HLF_ADD; /* added line */
3577 filler_lines = 0;
3578 area_highlighting = TRUE;
3579 }
3580 if (lnum == wp->w_topline)
3581 filler_lines = wp->w_topfill;
3582 filler_todo = filler_lines;
3583#endif
3584
Bram Moolenaar4e038572019-07-04 18:28:35 +02003585#ifdef FEAT_SIGNS
3586 sign_present = buf_get_signattrs(wp->w_buffer, lnum, &sattr);
3587#endif
3588
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589#ifdef LINE_ATTR
3590# ifdef FEAT_SIGNS
3591 /* If this line has a sign with line highlighting set line_attr. */
Bram Moolenaar4e038572019-07-04 18:28:35 +02003592 if (sign_present)
3593 line_attr = sattr.linehl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003594# endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02003595# if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003596 /* Highlight the current line in the quickfix window. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00003597 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
Bram Moolenaar21020352017-06-13 17:21:04 +02003598 line_attr = HL_ATTR(HLF_QFL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003599# endif
3600 if (line_attr != 0)
3601 area_highlighting = TRUE;
3602#endif
3603
3604 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3605 ptr = line;
3606
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003607#ifdef FEAT_SPELL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003608 if (has_spell && !number_only)
Bram Moolenaar30abd282005-06-22 22:35:10 +00003609 {
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003610 /* For checking first word with a capital skip white space. */
3611 if (cap_col == 0)
Bram Moolenaare2e69e42017-09-02 20:30:35 +02003612 cap_col = getwhitecols(line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003613
Bram Moolenaar30abd282005-06-22 22:35:10 +00003614 /* To be able to spell-check over line boundaries copy the end of the
3615 * current line into nextline[]. Above the start of the next line was
3616 * copied to nextline[SPWORDLEN]. */
3617 if (nextline[SPWORDLEN] == NUL)
3618 {
3619 /* No next line or it is empty. */
3620 nextlinecol = MAXCOL;
3621 nextline_idx = 0;
3622 }
3623 else
3624 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003625 v = (long)STRLEN(line);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003626 if (v < SPWORDLEN)
3627 {
3628 /* Short line, use it completely and append the start of the
3629 * next line. */
3630 nextlinecol = 0;
3631 mch_memmove(nextline, line, (size_t)v);
Bram Moolenaar446cb832008-06-24 21:56:24 +00003632 STRMOVE(nextline + v, nextline + SPWORDLEN);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003633 nextline_idx = v + 1;
3634 }
3635 else
3636 {
3637 /* Long line, use only the last SPWORDLEN bytes. */
3638 nextlinecol = v - SPWORDLEN;
3639 mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
3640 nextline_idx = SPWORDLEN + 1;
3641 }
3642 }
3643 }
3644#endif
3645
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003646 if (wp->w_p_list)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647 {
Bram Moolenaar895d9662019-01-31 21:57:21 +01003648 if (lcs_space || lcs_trail || lcs_nbsp)
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003649 extra_check = TRUE;
3650 /* find start of trailing whitespace */
3651 if (lcs_trail)
3652 {
3653 trailcol = (colnr_T)STRLEN(ptr);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003654 while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003655 --trailcol;
3656 trailcol += (colnr_T) (ptr - line);
3657 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658 }
3659
Bram Moolenaar60cdb302019-05-27 21:54:10 +02003660 wcr_attr = get_wcr_attr(wp);
3661 if (wcr_attr != 0)
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003662 {
Bram Moolenaar60cdb302019-05-27 21:54:10 +02003663 win_attr = wcr_attr;
3664 area_highlighting = TRUE;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003665 }
3666#ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02003667 if (WIN_IS_POPUP(wp))
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003668 screen_line_flags |= SLF_POPUP;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003669#endif
3670
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 /*
3672 * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
3673 * first character to be displayed.
3674 */
3675 if (wp->w_p_wrap)
3676 v = wp->w_skipcol;
3677 else
3678 v = wp->w_leftcol;
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02003679 if (v > 0 && !number_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681 char_u *prev_ptr = ptr;
Bram Moolenaara12a1612019-01-24 16:39:02 +01003682
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683 while (vcol < v && *ptr != NUL)
3684 {
Bram Moolenaar597a4222014-06-25 14:39:50 +02003685 c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686 vcol += c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687 prev_ptr = ptr;
Bram Moolenaar91acfff2017-03-12 19:22:36 +01003688 MB_PTR_ADV(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 }
3690
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003691 /* When:
3692 * - 'cuc' is set, or
Bram Moolenaar1a384422010-07-14 19:53:30 +02003693 * - 'colorcolumn' is set, or
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003694 * - 'virtualedit' is set, or
3695 * - the visual mode is active,
3696 * the end of the line may be before the start of the displayed part.
3697 */
3698 if (vcol < v && (
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01003699#ifdef FEAT_SYN_HL
3700 wp->w_p_cuc || draw_color_col ||
3701#endif
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01003702 virtual_active() ||
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01003703 (VIsual_active && wp->w_buffer == curwin->w_buffer)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003704 vcol = v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705
3706 /* Handle a character that's not completely on the screen: Put ptr at
3707 * that character but skip the first few screen characters. */
3708 if (vcol > v)
3709 {
3710 vcol -= c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711 ptr = prev_ptr;
Bram Moolenaarabc39ab2017-03-01 18:04:05 +01003712 /* If the character fits on the screen, don't need to skip it.
3713 * Except for a TAB. */
Bram Moolenaara12a1612019-01-24 16:39:02 +01003714 if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0)
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003715 n_skip = v - vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 }
3717
3718 /*
3719 * Adjust for when the inverted text is before the screen,
3720 * and when the start of the inverted text is before the screen.
3721 */
3722 if (tocol <= vcol)
3723 fromcol = 0;
3724 else if (fromcol >= 0 && fromcol < vcol)
3725 fromcol = vcol;
3726
3727#ifdef FEAT_LINEBREAK
3728 /* When w_skipcol is non-zero, first line needs 'showbreak' */
3729 if (wp->w_p_wrap)
3730 need_showbreak = TRUE;
3731#endif
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003732#ifdef FEAT_SPELL
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003733 /* When spell checking a word we need to figure out the start of the
3734 * word and if it's badly spelled or not. */
3735 if (has_spell)
3736 {
3737 int len;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003738 colnr_T linecol = (colnr_T)(ptr - line);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003739 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003740
3741 pos = wp->w_cursor;
3742 wp->w_cursor.lnum = lnum;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003743 wp->w_cursor.col = linecol;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003744 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003745
3746 /* spell_move_to() may call ml_get() and make "line" invalid */
3747 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3748 ptr = line + linecol;
3749
Bram Moolenaar60a795a2005-09-16 21:55:43 +00003750 if (len == 0 || (int)wp->w_cursor.col > ptr - line)
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003751 {
3752 /* no bad word found at line start, don't check until end of a
3753 * word */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003754 spell_hlf = HLF_COUNT;
Bram Moolenaar3b393a02012-06-06 19:05:50 +02003755 word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003756 }
3757 else
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003758 {
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003759 /* bad word found, use attributes until end of word */
3760 word_end = wp->w_cursor.col + len + 1;
3761
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003762 /* Turn index into actual attributes. */
3763 if (spell_hlf != HLF_COUNT)
3764 spell_attr = highlight_attr[spell_hlf];
3765 }
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003766 wp->w_cursor = pos;
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003767
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003768# ifdef FEAT_SYN_HL
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003769 /* Need to restart syntax highlighting for this line. */
3770 if (has_syntax)
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02003771 syntax_start(wp, lnum);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003772# endif
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003773 }
3774#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003775 }
3776
3777 /*
3778 * Correct highlighting for cursor that can't be disabled.
3779 * Avoids having to check this for each character.
3780 */
3781 if (fromcol >= 0)
3782 {
3783 if (noinvcur)
3784 {
3785 if ((colnr_T)fromcol == wp->w_virtcol)
3786 {
3787 /* highlighting starts at cursor, let it start just after the
3788 * cursor */
3789 fromcol_prev = fromcol;
3790 fromcol = -1;
3791 }
3792 else if ((colnr_T)fromcol < wp->w_virtcol)
3793 /* restart highlighting after the cursor */
3794 fromcol_prev = wp->w_virtcol;
3795 }
3796 if (fromcol >= tocol)
3797 fromcol = -1;
3798 }
3799
3800#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarbbca7732019-07-24 18:13:16 +02003801 if (!number_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 {
Bram Moolenaarb3414592014-06-17 17:48:32 +02003803 v = (long)(ptr - line);
Bram Moolenaarbbca7732019-07-24 18:13:16 +02003804 area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
3805 &line, &search_hl, &search_attr);
3806 ptr = line + v; // "line" may have been updated
Bram Moolenaar071d4272004-06-13 20:20:40 +00003807 }
3808#endif
3809
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003810#ifdef FEAT_SYN_HL
Bram Moolenaar8156ed32019-03-09 11:46:15 +01003811 // Cursor line highlighting for 'cursorline' in the current window.
3812 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003813 {
Bram Moolenaar8156ed32019-03-09 11:46:15 +01003814 // Do not show the cursor line when Visual mode is active, because it's
3815 // not clear what is selected then. Do update w_last_cursorline.
3816 if (!(wp == curwin && VIsual_active))
3817 {
3818 line_attr = HL_ATTR(HLF_CUL);
3819 area_highlighting = TRUE;
3820 }
Bram Moolenaarc07ff5c2019-01-30 21:41:14 +01003821 wp->w_last_cursorline = wp->w_cursor.lnum;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003822 }
3823#endif
3824
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003825#ifdef FEAT_TEXT_PROP
3826 {
3827 char_u *prop_start;
3828
3829 text_prop_count = get_text_props(wp->w_buffer, lnum,
3830 &prop_start, FALSE);
3831 if (text_prop_count > 0)
3832 {
3833 // Make a copy of the properties, so that they are properly
3834 // aligned.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003835 text_props = ALLOC_MULT(textprop_T, text_prop_count);
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003836 if (text_props != NULL)
3837 mch_memmove(text_props, prop_start,
3838 text_prop_count * sizeof(textprop_T));
3839
3840 // Allocate an array for the indexes.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003841 text_prop_idxs = ALLOC_MULT(int, text_prop_count);
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003842 area_highlighting = TRUE;
3843 extra_check = TRUE;
3844 }
3845 }
3846#endif
3847
Bram Moolenaar92d640f2005-09-05 22:11:52 +00003848 off = (unsigned)(current_ScreenLine - ScreenLines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 col = 0;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003850
Bram Moolenaar071d4272004-06-13 20:20:40 +00003851#ifdef FEAT_RIGHTLEFT
3852 if (wp->w_p_rl)
3853 {
3854 /* Rightleft window: process the text in the normal direction, but put
3855 * it in current_ScreenLine[] from right to left. Start at the
3856 * rightmost column of the window. */
Bram Moolenaar02631462017-09-22 15:20:32 +02003857 col = wp->w_width - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858 off += col;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02003859 screen_line_flags |= SLF_RIGHTLEFT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003860 }
3861#endif
3862
3863 /*
3864 * Repeat for the whole displayed line.
3865 */
3866 for (;;)
3867 {
Bram Moolenaarfbfb7572019-07-25 20:53:03 +02003868#if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA)
Bram Moolenaar0ebe12b2019-05-17 12:31:44 +02003869 int has_match_conc = 0; // match wants to conceal
Bram Moolenaarfbfb7572019-07-25 20:53:03 +02003870#endif
Bram Moolenaar07d13562019-07-24 18:43:08 +02003871#ifdef FEAT_CONCEAL
Bram Moolenaar0ebe12b2019-05-17 12:31:44 +02003872 int did_decrement_ptr = FALSE;
Bram Moolenaar6561d522015-07-21 15:48:27 +02003873#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 /* Skip this quickly when working on the text. */
3875 if (draw_state != WL_LINE)
3876 {
3877#ifdef FEAT_CMDWIN
3878 if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
3879 {
3880 draw_state = WL_CMDLINE;
3881 if (cmdwin_type != 0 && wp == curwin)
3882 {
3883 /* Draw the cmdline character. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884 n_extra = 1;
Bram Moolenaara064ac82007-08-05 18:10:54 +00003885 c_extra = cmdwin_type;
Bram Moolenaar83a52172019-01-16 22:41:54 +01003886 c_final = NUL;
Bram Moolenaar193ffd12019-05-25 22:57:30 +02003887 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_AT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888 }
3889 }
3890#endif
3891
3892#ifdef FEAT_FOLDING
3893 if (draw_state == WL_FOLD - 1 && n_extra == 0)
3894 {
Bram Moolenaar1c934292015-01-27 16:39:29 +01003895 int fdc = compute_foldcolumn(wp, 0);
3896
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897 draw_state = WL_FOLD;
Bram Moolenaar1c934292015-01-27 16:39:29 +01003898 if (fdc > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899 {
Bram Moolenaar62706602016-12-09 19:28:48 +01003900 /* Draw the 'foldcolumn'. Allocate a buffer, "extra" may
Bram Moolenaarc695cec2017-01-08 20:00:04 +01003901 * already be in use. */
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01003902 vim_free(p_extra_free);
Bram Moolenaar62706602016-12-09 19:28:48 +01003903 p_extra_free = alloc(12 + 1);
3904
3905 if (p_extra_free != NULL)
3906 {
3907 fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
3908 n_extra = fdc;
3909 p_extra_free[n_extra] = NUL;
3910 p_extra = p_extra_free;
3911 c_extra = NUL;
Bram Moolenaar83a52172019-01-16 22:41:54 +01003912 c_final = NUL;
Bram Moolenaar193ffd12019-05-25 22:57:30 +02003913 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC));
Bram Moolenaar62706602016-12-09 19:28:48 +01003914 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003915 }
3916 }
3917#endif
3918
3919#ifdef FEAT_SIGNS
3920 if (draw_state == WL_SIGN - 1 && n_extra == 0)
3921 {
3922 draw_state = WL_SIGN;
3923 /* Show the sign column when there are any signs in this
3924 * buffer or when using Netbeans. */
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02003925 if (signcolumn_on(wp))
Bram Moolenaar4e038572019-07-04 18:28:35 +02003926 get_sign_display_info(FALSE, wp, lnum, &sattr, wcr_attr,
3927 row, startrow, filler_lines, filler_todo, &c_extra,
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003928 &c_final, extra, &p_extra, &n_extra, &char_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003929 }
3930#endif
3931
3932 if (draw_state == WL_NR - 1 && n_extra == 0)
3933 {
3934 draw_state = WL_NR;
Bram Moolenaar64486672010-05-16 15:46:46 +02003935 /* Display the absolute or relative line number. After the
3936 * first fill with blanks when the 'n' flag isn't in 'cpo' */
3937 if ((wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003938 && (row == startrow
3939#ifdef FEAT_DIFF
3940 + filler_lines
3941#endif
3942 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
3943 {
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003944#ifdef FEAT_SIGNS
3945 // If 'signcolumn' is set to 'number' and a sign is present
3946 // in 'lnum', then display the sign instead of the line
3947 // number.
3948 if ((*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')
Bram Moolenaar4e038572019-07-04 18:28:35 +02003949 && sign_present)
3950 get_sign_display_info(TRUE, wp, lnum, &sattr, wcr_attr,
3951 row, startrow, filler_lines, filler_todo,
3952 &c_extra, &c_final, extra, &p_extra, &n_extra,
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003953 &char_attr);
3954 else
3955#endif
3956 {
3957 /* Draw the line number (empty space after wrapping). */
3958 if (row == startrow
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959#ifdef FEAT_DIFF
3960 + filler_lines
3961#endif
3962 )
Bram Moolenaar394c5d82019-06-17 21:48:05 +02003963 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003964 long num;
Bram Moolenaar700e7342013-01-30 12:31:36 +01003965 char *fmt = "%*ld ";
Bram Moolenaar64486672010-05-16 15:46:46 +02003966
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003967 if (wp->w_p_nu && !wp->w_p_rnu)
3968 /* 'number' + 'norelativenumber' */
Bram Moolenaar64486672010-05-16 15:46:46 +02003969 num = (long)lnum;
3970 else
Bram Moolenaar700e7342013-01-30 12:31:36 +01003971 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003972 /* 'relativenumber', don't use negative numbers */
Bram Moolenaar7eb46522010-12-30 14:57:08 +01003973 num = labs((long)get_cursor_rel_lnum(wp, lnum));
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003974 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01003975 {
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003976 /* 'number' + 'relativenumber' */
Bram Moolenaar700e7342013-01-30 12:31:36 +01003977 num = lnum;
3978 fmt = "%-*ld ";
3979 }
3980 }
Bram Moolenaar64486672010-05-16 15:46:46 +02003981
Bram Moolenaar700e7342013-01-30 12:31:36 +01003982 sprintf((char *)extra, fmt,
Bram Moolenaar64486672010-05-16 15:46:46 +02003983 number_width(wp), num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984 if (wp->w_skipcol > 0)
3985 for (p_extra = extra; *p_extra == ' '; ++p_extra)
3986 *p_extra = '-';
3987#ifdef FEAT_RIGHTLEFT
3988 if (wp->w_p_rl) /* reverse line numbers */
Bram Moolenaare73f9112019-03-29 18:29:54 +01003989 {
3990 char_u *p1, *p2;
3991 int t;
3992
3993 // like rl_mirror(), but keep the space at the end
3994 p2 = skiptowhite(extra) - 1;
3995 for (p1 = extra; p1 < p2; ++p1, --p2)
3996 {
3997 t = *p1;
3998 *p1 = *p2;
3999 *p2 = t;
4000 }
4001 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002#endif
4003 p_extra = extra;
4004 c_extra = NUL;
Bram Moolenaar83a52172019-01-16 22:41:54 +01004005 c_final = NUL;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02004006 }
4007 else
4008 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004009 c_extra = ' ';
Bram Moolenaar83a52172019-01-16 22:41:54 +01004010 c_final = NUL;
Bram Moolenaar394c5d82019-06-17 21:48:05 +02004011 }
4012 n_extra = number_width(wp) + 1;
4013 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_N));
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004014#ifdef FEAT_SYN_HL
Bram Moolenaar394c5d82019-06-17 21:48:05 +02004015 /* When 'cursorline' is set highlight the line number of
4016 * the current line differently.
4017 * TODO: Can we use CursorLine instead of CursorLineNr
4018 * when CursorLineNr isn't set? */
4019 if ((wp->w_p_cul || wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01004020 && lnum == wp->w_cursor.lnum)
Bram Moolenaar193ffd12019-05-25 22:57:30 +02004021 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_CLN));
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004022#endif
Bram Moolenaar394c5d82019-06-17 21:48:05 +02004023 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024 }
4025 }
4026
Bram Moolenaar597a4222014-06-25 14:39:50 +02004027#ifdef FEAT_LINEBREAK
4028 if (wp->w_p_brisbr && draw_state == WL_BRI - 1
4029 && n_extra == 0 && *p_sbr != NUL)
4030 /* draw indent after showbreak value */
4031 draw_state = WL_BRI;
4032 else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0)
4033 /* After the showbreak, draw the breakindent */
4034 draw_state = WL_BRI - 1;
4035
4036 /* draw 'breakindent': indent wrapped text accordingly */
4037 if (draw_state == WL_BRI - 1 && n_extra == 0)
4038 {
4039 draw_state = WL_BRI;
Bram Moolenaar6c896862016-11-17 19:46:51 +01004040 /* if need_showbreak is set, breakindent also applies */
4041 if (wp->w_p_bri && n_extra == 0
4042 && (row != startrow || need_showbreak)
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004043# ifdef FEAT_DIFF
Bram Moolenaar597a4222014-06-25 14:39:50 +02004044 && filler_lines == 0
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004045# endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02004046 )
4047 {
Bram Moolenaar6c896862016-11-17 19:46:51 +01004048 char_attr = 0;
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004049# ifdef FEAT_DIFF
Bram Moolenaar597a4222014-06-25 14:39:50 +02004050 if (diff_hlf != (hlf_T)0)
Bram Moolenaare0f14822014-08-06 13:20:56 +02004051 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004052 char_attr = HL_ATTR(diff_hlf);
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004053# ifdef FEAT_SYN_HL
Bram Moolenaare0f14822014-08-06 13:20:56 +02004054 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
4055 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01004056 HL_ATTR(HLF_CUL));
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004057# endif
Bram Moolenaare0f14822014-08-06 13:20:56 +02004058 }
Bram Moolenaard710e0d2015-06-10 12:16:47 +02004059# endif
Bram Moolenaarb8b57462014-07-03 22:54:08 +02004060 p_extra = NULL;
Bram Moolenaar597a4222014-06-25 14:39:50 +02004061 c_extra = ' ';
4062 n_extra = get_breakindent_win(wp,
4063 ml_get_buf(wp->w_buffer, lnum, FALSE));
4064 /* Correct end of highlighted area for 'breakindent',
4065 * required when 'linebreak' is also set. */
4066 if (tocol == vcol)
4067 tocol += n_extra;
4068 }
4069 }
4070#endif
4071
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
4073 if (draw_state == WL_SBR - 1 && n_extra == 0)
4074 {
4075 draw_state = WL_SBR;
4076# ifdef FEAT_DIFF
4077 if (filler_todo > 0)
4078 {
4079 /* Draw "deleted" diff line(s). */
4080 if (char2cells(fill_diff) > 1)
Bram Moolenaar83a52172019-01-16 22:41:54 +01004081 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004082 c_extra = '-';
Bram Moolenaar83a52172019-01-16 22:41:54 +01004083 c_final = NUL;
4084 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085 else
Bram Moolenaar83a52172019-01-16 22:41:54 +01004086 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 c_extra = fill_diff;
Bram Moolenaar83a52172019-01-16 22:41:54 +01004088 c_final = NUL;
4089 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004090# ifdef FEAT_RIGHTLEFT
4091 if (wp->w_p_rl)
4092 n_extra = col + 1;
4093 else
4094# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004095 n_extra = wp->w_width - col;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004096 char_attr = HL_ATTR(HLF_DED);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 }
4098# endif
4099# ifdef FEAT_LINEBREAK
4100 if (*p_sbr != NUL && need_showbreak)
4101 {
4102 /* Draw 'showbreak' at the start of each broken line. */
4103 p_extra = p_sbr;
4104 c_extra = NUL;
Bram Moolenaar83a52172019-01-16 22:41:54 +01004105 c_final = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106 n_extra = (int)STRLEN(p_sbr);
Bram Moolenaar8820b482017-03-16 17:23:31 +01004107 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 need_showbreak = FALSE;
Bram Moolenaard574ea22015-01-14 19:35:14 +01004109 vcol_sbr = vcol + MB_CHARLEN(p_sbr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110 /* Correct end of highlighted area for 'showbreak',
4111 * required when 'linebreak' is also set. */
4112 if (tocol == vcol)
4113 tocol += n_extra;
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02004114#ifdef FEAT_SYN_HL
4115 /* combine 'showbreak' with 'cursorline' */
Bram Moolenaarbd65c462013-07-01 20:18:33 +02004116 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
Bram Moolenaare0f14822014-08-06 13:20:56 +02004117 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01004118 HL_ATTR(HLF_CUL));
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02004119#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120 }
4121# endif
4122 }
4123#endif
4124
4125 if (draw_state == WL_LINE - 1 && n_extra == 0)
4126 {
4127 draw_state = WL_LINE;
4128 if (saved_n_extra)
4129 {
4130 /* Continue item from end of wrapped line. */
4131 n_extra = saved_n_extra;
4132 c_extra = saved_c_extra;
Bram Moolenaar83a52172019-01-16 22:41:54 +01004133 c_final = saved_c_final;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134 p_extra = saved_p_extra;
4135 char_attr = saved_char_attr;
4136 }
4137 else
Bram Moolenaar4d784b22019-05-25 19:51:39 +02004138 char_attr = win_attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004139 }
4140 }
4141
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02004142 // When still displaying '$' of change command, stop at cursor.
4143 // When only displaying the (relative) line number and that's done,
4144 // stop here.
4145 if ((dollar_vcol >= 0 && wp == curwin
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004146 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
Bram Moolenaar071d4272004-06-13 20:20:40 +00004147#ifdef FEAT_DIFF
4148 && filler_todo <= 0
4149#endif
4150 )
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +02004151 || (number_only && draw_state > WL_NR))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152 {
Bram Moolenaar02631462017-09-22 15:20:32 +02004153 screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
Bram Moolenaar4d784b22019-05-25 19:51:39 +02004154 screen_line_flags);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004155 /* Pretend we have finished updating the window. Except when
4156 * 'cursorcolumn' is set. */
4157#ifdef FEAT_SYN_HL
4158 if (wp->w_p_cuc)
4159 row = wp->w_cline_row + wp->w_cline_height;
4160 else
4161#endif
4162 row = wp->w_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 break;
4164 }
4165
Bram Moolenaar637532b2019-01-03 21:44:40 +01004166 if (draw_state == WL_LINE && (area_highlighting
4167#ifdef FEAT_SPELL
4168 || has_spell
4169#endif
4170 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171 {
4172 /* handle Visual or match highlighting in this line */
4173 if (vcol == fromcol
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
4175 && (*mb_ptr2cells)(ptr) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 || ((int)vcol_prev == fromcol_prev
Bram Moolenaarfa363cd2009-02-21 20:23:59 +00004177 && vcol_prev < vcol /* not at margin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178 && vcol < tocol))
Bram Moolenaar4d784b22019-05-25 19:51:39 +02004179 area_attr = vi_attr; /* start highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180 else if (area_attr != 0
4181 && (vcol == tocol
4182 || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183 area_attr = 0; /* stop highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184
4185#ifdef FEAT_SEARCH_EXTRA
4186 if (!n_extra)
4187 {
4188 /*
Bram Moolenaarbbca7732019-07-24 18:13:16 +02004189 * Check for start/end of 'hlsearch' and other matches.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190 * After end, check for start/end of next match.
4191 * When another match, have to check for start again.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004193 v = (long)(ptr - line);
Bram Moolenaarbbca7732019-07-24 18:13:16 +02004194 search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line,
4195 &search_hl, &has_match_conc, &match_conc,
4196 did_line_attr, lcs_eol_one);
4197 ptr = line + v; // "line" may have been changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198 }
4199#endif
4200
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201#ifdef FEAT_DIFF
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004202 if (diff_hlf != (hlf_T)0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 {
Bram Moolenaar4b80a512007-06-19 15:44:58 +00004204 if (diff_hlf == HLF_CHD && ptr - line >= change_start
4205 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206 diff_hlf = HLF_TXD; /* changed text */
Bram Moolenaar4b80a512007-06-19 15:44:58 +00004207 if (diff_hlf == HLF_TXD && ptr - line > change_end
4208 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209 diff_hlf = HLF_CHD; /* changed line */
Bram Moolenaar8820b482017-03-16 17:23:31 +01004210 line_attr = HL_ATTR(diff_hlf);
Bram Moolenaare0f14822014-08-06 13:20:56 +02004211 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
Bram Moolenaar8820b482017-03-16 17:23:31 +01004212 line_attr = hl_combine_attr(line_attr, HL_ATTR(HLF_CUL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213 }
4214#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004215
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004216#ifdef FEAT_TEXT_PROP
4217 if (text_props != NULL)
4218 {
4219 int pi;
Bram Moolenaar5e53ac02019-01-01 20:31:31 +01004220 int bcol = (int)(ptr - line);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004221
Bram Moolenaara956bf62019-06-19 17:34:24 +02004222 if (n_extra > 0)
4223 --bcol; // still working on the previous char, e.g. Tab
4224
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004225 // Check if any active property ends.
4226 for (pi = 0; pi < text_props_active; ++pi)
4227 {
4228 int tpi = text_prop_idxs[pi];
4229
Bram Moolenaar5e53ac02019-01-01 20:31:31 +01004230 if (bcol >= text_props[tpi].tp_col - 1
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004231 + text_props[tpi].tp_len)
4232 {
4233 if (pi + 1 < text_props_active)
4234 mch_memmove(text_prop_idxs + pi,
4235 text_prop_idxs + pi + 1,
4236 sizeof(int)
4237 * (text_props_active - (pi + 1)));
4238 --text_props_active;
4239 --pi;
4240 }
4241 }
4242
4243 // Add any text property that starts in this column.
4244 while (text_prop_next < text_prop_count
Bram Moolenaar5e53ac02019-01-01 20:31:31 +01004245 && bcol >= text_props[text_prop_next].tp_col - 1)
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004246 text_prop_idxs[text_props_active++] = text_prop_next++;
4247
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004248 text_prop_attr = 0;
Bram Moolenaarde24a872019-05-05 15:48:00 +02004249 text_prop_combine = FALSE;
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004250 if (text_props_active > 0)
4251 {
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004252 // Sort the properties on priority and/or starting last.
4253 // Then combine the attributes, highest priority last.
4254 current_text_props = text_props;
4255 current_buf = wp->w_buffer;
4256 qsort((void *)text_prop_idxs, (size_t)text_props_active,
4257 sizeof(int), text_prop_compare);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004258
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004259 for (pi = 0; pi < text_props_active; ++pi)
4260 {
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004261 int tpi = text_prop_idxs[pi];
Bram Moolenaarde24a872019-05-05 15:48:00 +02004262 proptype_T *pt = text_prop_type_by_id(
4263 wp->w_buffer, text_props[tpi].tp_type);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004264
Bram Moolenaard74af422019-06-28 21:38:00 +02004265 if (pt != NULL && pt->pt_hl_id > 0)
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004266 {
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01004267 int pt_attr = syn_id2attr(pt->pt_hl_id);
4268
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004269 text_prop_type = pt;
Bram Moolenaarde24a872019-05-05 15:48:00 +02004270 text_prop_attr =
4271 hl_combine_attr(text_prop_attr, pt_attr);
4272 text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE;
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004273 }
4274 }
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004275 }
4276 }
4277#endif
4278
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004279 /* Decide which of the highlight attributes to use. */
4280 attr_pri = TRUE;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004281#ifdef LINE_ATTR
Bram Moolenaar09deeb72015-03-24 18:22:41 +01004282 if (area_attr != 0)
4283 char_attr = hl_combine_attr(line_attr, area_attr);
4284 else if (search_attr != 0)
4285 char_attr = hl_combine_attr(line_attr, search_attr);
Bram Moolenaarbfd45122019-05-17 13:05:07 +02004286# ifdef FEAT_TEXT_PROP
4287 else if (text_prop_type != NULL)
Bram Moolenaar7a8d0272019-05-26 23:32:06 +02004288 {
4289 char_attr = hl_combine_attr(
4290 line_attr != 0 ? line_attr : win_attr, text_prop_attr);
4291 }
Bram Moolenaarbfd45122019-05-17 13:05:07 +02004292# endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004293 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
Bram Moolenaarf837ef92009-03-11 16:47:21 +00004294 || vcol < fromcol || vcol_prev < fromcol_prev
4295 || vcol >= tocol))
Bram Moolenaarbfd45122019-05-17 13:05:07 +02004296 // Use line_attr when not in the Visual or 'incsearch' area
4297 // (area_attr may be 0 when "noinvcur" is set).
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004298 char_attr = line_attr;
Bram Moolenaar09deeb72015-03-24 18:22:41 +01004299#else
4300 if (area_attr != 0)
4301 char_attr = area_attr;
4302 else if (search_attr != 0)
4303 char_attr = search_attr;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004304#endif
4305 else
4306 {
4307 attr_pri = FALSE;
Bram Moolenaar98aefe72018-12-13 22:20:09 +01004308#ifdef FEAT_TEXT_PROP
4309 if (text_prop_type != NULL)
Bram Moolenaarde24a872019-05-05 15:48:00 +02004310 {
4311 if (text_prop_combine)
4312 char_attr = hl_combine_attr(
4313 syntax_attr, text_prop_attr);
4314 else
Bram Moolenaar7a8d0272019-05-26 23:32:06 +02004315 char_attr = hl_combine_attr(
4316 win_attr, text_prop_attr);
Bram Moolenaarde24a872019-05-05 15:48:00 +02004317 }
Bram Moolenaar98aefe72018-12-13 22:20:09 +01004318 else
4319#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004320#ifdef FEAT_SYN_HL
4321 if (has_syntax)
4322 char_attr = syntax_attr;
4323 else
4324#endif
4325 char_attr = 0;
4326 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327 }
Bram Moolenaar4d784b22019-05-25 19:51:39 +02004328 if (char_attr == 0)
4329 char_attr = win_attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330
4331 /*
4332 * Get the next character to put on the screen.
4333 */
4334 /*
Bram Moolenaara064ac82007-08-05 18:10:54 +00004335 * The "p_extra" points to the extra stuff that is inserted to
4336 * represent special characters (non-printable stuff) and other
4337 * things. When all characters are the same, c_extra is used.
Bram Moolenaar83a52172019-01-16 22:41:54 +01004338 * If c_final is set, it will compulsorily be used at the end.
Bram Moolenaara064ac82007-08-05 18:10:54 +00004339 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
4340 * "p_extra[n_extra]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
4342 */
4343 if (n_extra > 0)
4344 {
Bram Moolenaar83a52172019-01-16 22:41:54 +01004345 if (c_extra != NUL || (n_extra == 1 && c_final != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346 {
Bram Moolenaar83a52172019-01-16 22:41:54 +01004347 c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348 mb_c = c; /* doesn't handle non-utf-8 multi-byte! */
Bram Moolenaarace95982017-03-29 17:30:27 +02004349 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350 {
4351 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004352 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004353 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354 }
4355 else
4356 mb_utf8 = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 }
4358 else
4359 {
4360 c = *p_extra;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 if (has_mbyte)
4362 {
4363 mb_c = c;
4364 if (enc_utf8)
4365 {
4366 /* If the UTF-8 character is more than one byte:
4367 * Decode it into "mb_c". */
Bram Moolenaarace95982017-03-29 17:30:27 +02004368 mb_l = utfc_ptr2len(p_extra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 mb_utf8 = FALSE;
4370 if (mb_l > n_extra)
4371 mb_l = 1;
4372 else if (mb_l > 1)
4373 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004374 mb_c = utfc_ptr2char(p_extra, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375 mb_utf8 = TRUE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004376 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377 }
4378 }
4379 else
4380 {
4381 /* if this is a DBCS character, put it in "mb_c" */
4382 mb_l = MB_BYTE2LEN(c);
4383 if (mb_l >= n_extra)
4384 mb_l = 1;
4385 else if (mb_l > 1)
4386 mb_c = (c << 8) + p_extra[1];
4387 }
Bram Moolenaar92d640f2005-09-05 22:11:52 +00004388 if (mb_l == 0) /* at the NUL at end-of-line */
4389 mb_l = 1;
4390
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 /* If a double-width char doesn't fit display a '>' in the
4392 * last column. */
Bram Moolenaar92d640f2005-09-05 22:11:52 +00004393 if ((
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394# ifdef FEAT_RIGHTLEFT
4395 wp->w_p_rl ? (col <= 0) :
4396# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004397 (col >= wp->w_width - 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398 && (*mb_char2cells)(mb_c) == 2)
4399 {
4400 c = '>';
4401 mb_c = c;
4402 mb_l = 1;
4403 mb_utf8 = FALSE;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004404 multi_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405 /* put the pointer back to output the double-width
4406 * character at the start of the next line. */
4407 ++n_extra;
4408 --p_extra;
4409 }
4410 else
4411 {
4412 n_extra -= mb_l - 1;
4413 p_extra += mb_l - 1;
4414 }
4415 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416 ++p_extra;
4417 }
4418 --n_extra;
4419 }
4420 else
4421 {
Bram Moolenaar88e76882017-02-27 20:33:46 +01004422#ifdef FEAT_LINEBREAK
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004423 int c0;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004424#endif
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004425
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004426 if (p_extra_free != NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +01004427 VIM_CLEAR(p_extra_free);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004428 /*
4429 * Get a character from the line itself.
4430 */
Bram Moolenaar10a8da02017-02-27 21:11:35 +01004431 c = *ptr;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004432#ifdef FEAT_LINEBREAK
Bram Moolenaar10a8da02017-02-27 21:11:35 +01004433 c0 = *ptr;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004434#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435 if (has_mbyte)
4436 {
4437 mb_c = c;
4438 if (enc_utf8)
4439 {
4440 /* If the UTF-8 character is more than one byte: Decode it
4441 * into "mb_c". */
Bram Moolenaarace95982017-03-29 17:30:27 +02004442 mb_l = utfc_ptr2len(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 mb_utf8 = FALSE;
4444 if (mb_l > 1)
4445 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004446 mb_c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447 /* Overlong encoded ASCII or ASCII with composing char
4448 * is displayed normally, except a NUL. */
4449 if (mb_c < 0x80)
Bram Moolenaar88e76882017-02-27 20:33:46 +01004450 {
4451 c = mb_c;
Bram Moolenaara12a1612019-01-24 16:39:02 +01004452#ifdef FEAT_LINEBREAK
Bram Moolenaar88e76882017-02-27 20:33:46 +01004453 c0 = mb_c;
Bram Moolenaara12a1612019-01-24 16:39:02 +01004454#endif
Bram Moolenaar88e76882017-02-27 20:33:46 +01004455 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004456 mb_utf8 = TRUE;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00004457
4458 /* At start of the line we can have a composing char.
4459 * Draw it as a space with a composing char. */
4460 if (utf_iscomposing(mb_c))
4461 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004462 int i;
4463
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004464 for (i = Screen_mco - 1; i > 0; --i)
4465 u8cc[i] = u8cc[i - 1];
4466 u8cc[0] = mb_c;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00004467 mb_c = ' ';
4468 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004469 }
4470
4471 if ((mb_l == 1 && c >= 0x80)
4472 || (mb_l >= 1 && mb_c == 0)
Bram Moolenaar9ba61172019-01-24 18:20:17 +01004473 || (mb_l > 1 && (!vim_isprintc(mb_c))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474 {
4475 /*
4476 * Illegal UTF-8 byte: display as <xx>.
4477 * Non-BMP character : display as ? or fullwidth ?.
4478 */
Bram Moolenaar9ba61172019-01-24 18:20:17 +01004479 transchar_hex(extra, mb_c);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004480# ifdef FEAT_RIGHTLEFT
Bram Moolenaar9ba61172019-01-24 18:20:17 +01004481 if (wp->w_p_rl) /* reverse */
4482 rl_mirror(extra);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004483# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484 p_extra = extra;
4485 c = *p_extra;
4486 mb_c = mb_ptr2char_adv(&p_extra);
4487 mb_utf8 = (c >= 0x80);
4488 n_extra = (int)STRLEN(p_extra);
4489 c_extra = NUL;
Bram Moolenaar83a52172019-01-16 22:41:54 +01004490 c_final = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 if (area_attr == 0 && search_attr == 0)
4492 {
4493 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004494 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495 saved_attr2 = char_attr; /* save current attr */
4496 }
4497 }
4498 else if (mb_l == 0) /* at the NUL at end-of-line */
4499 mb_l = 1;
4500#ifdef FEAT_ARABIC
4501 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
4502 {
4503 /* Do Arabic shaping. */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004504 int pc, pc1, nc;
4505 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506
4507 /* The idea of what is the previous and next
4508 * character depends on 'rightleft'. */
4509 if (wp->w_p_rl)
4510 {
4511 pc = prev_c;
4512 pc1 = prev_c1;
4513 nc = utf_ptr2char(ptr + mb_l);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004514 prev_c1 = u8cc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515 }
4516 else
4517 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004518 pc = utfc_ptr2char(ptr + mb_l, pcc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519 nc = prev_c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004520 pc1 = pcc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521 }
4522 prev_c = mb_c;
4523
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004524 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525 }
4526 else
4527 prev_c = mb_c;
4528#endif
4529 }
4530 else /* enc_dbcs */
4531 {
4532 mb_l = MB_BYTE2LEN(c);
4533 if (mb_l == 0) /* at the NUL at end-of-line */
4534 mb_l = 1;
4535 else if (mb_l > 1)
4536 {
4537 /* We assume a second byte below 32 is illegal.
4538 * Hopefully this is OK for all double-byte encodings!
4539 */
4540 if (ptr[1] >= 32)
4541 mb_c = (c << 8) + ptr[1];
4542 else
4543 {
4544 if (ptr[1] == NUL)
4545 {
4546 /* head byte at end of line */
4547 mb_l = 1;
4548 transchar_nonprint(extra, c);
4549 }
4550 else
4551 {
4552 /* illegal tail byte */
4553 mb_l = 2;
4554 STRCPY(extra, "XX");
4555 }
4556 p_extra = extra;
4557 n_extra = (int)STRLEN(extra) - 1;
4558 c_extra = NUL;
Bram Moolenaar83a52172019-01-16 22:41:54 +01004559 c_final = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560 c = *p_extra++;
4561 if (area_attr == 0 && search_attr == 0)
4562 {
4563 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004564 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565 saved_attr2 = char_attr; /* save current attr */
4566 }
4567 mb_c = c;
4568 }
4569 }
4570 }
4571 /* If a double-width char doesn't fit display a '>' in the
4572 * last column; the character is displayed at the start of the
4573 * next line. */
4574 if ((
4575# ifdef FEAT_RIGHTLEFT
4576 wp->w_p_rl ? (col <= 0) :
4577# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004578 (col >= wp->w_width - 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579 && (*mb_char2cells)(mb_c) == 2)
4580 {
4581 c = '>';
4582 mb_c = c;
4583 mb_utf8 = FALSE;
4584 mb_l = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004585 multi_attr = HL_ATTR(HLF_AT);
Bram Moolenaar0ebe12b2019-05-17 12:31:44 +02004586 // Put pointer back so that the character will be
4587 // displayed at the start of the next line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588 --ptr;
Bram Moolenaar0ebe12b2019-05-17 12:31:44 +02004589#ifdef FEAT_CONCEAL
4590 did_decrement_ptr = TRUE;
4591#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 }
4593 else if (*ptr != NUL)
4594 ptr += mb_l - 1;
4595
4596 /* If a double-width char doesn't fit at the left side display
Bram Moolenaar7ba6ed32010-08-07 16:38:13 +02004597 * a '<' in the first column. Don't do this for unprintable
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02004598 * characters. */
Bram Moolenaar7ba6ed32010-08-07 16:38:13 +02004599 if (n_skip > 0 && mb_l > 1 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004601 n_extra = 1;
Bram Moolenaar5641f382012-06-13 18:06:36 +02004602 c_extra = MB_FILLER_CHAR;
Bram Moolenaar83a52172019-01-16 22:41:54 +01004603 c_final = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604 c = ' ';
4605 if (area_attr == 0 && search_attr == 0)
4606 {
4607 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004608 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609 saved_attr2 = char_attr; /* save current attr */
4610 }
4611 mb_c = c;
4612 mb_utf8 = FALSE;
4613 mb_l = 1;
4614 }
4615
4616 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 ++ptr;
4618
4619 if (extra_check)
4620 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004621#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00004622 int can_spell = TRUE;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004623#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00004624
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02004625#ifdef FEAT_TERMINAL
4626 if (get_term_attr)
4627 {
Bram Moolenaar68c4bdd2017-07-30 13:57:41 +02004628 syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol);
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02004629
4630 if (!attr_pri)
4631 char_attr = syntax_attr;
4632 else
4633 char_attr = hl_combine_attr(syntax_attr, char_attr);
4634 }
4635#endif
4636
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004637#ifdef FEAT_SYN_HL
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004638 // Get syntax attribute, unless still at the start of the line
4639 // (double-wide char that doesn't fit).
Bram Moolenaar217ad922005-03-20 22:37:15 +00004640 v = (long)(ptr - line);
4641 if (has_syntax && v > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642 {
4643 /* Get the syntax attribute for the character. If there
4644 * is an error, disable syntax highlighting. */
4645 save_did_emsg = did_emsg;
4646 did_emsg = FALSE;
4647
Bram Moolenaar217ad922005-03-20 22:37:15 +00004648 syntax_attr = get_syntax_attr((colnr_T)v - 1,
Bram Moolenaar860cae12010-06-05 23:22:07 +02004649# ifdef FEAT_SPELL
4650 has_spell ? &can_spell :
4651# endif
4652 NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653
4654 if (did_emsg)
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004655 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02004656 wp->w_s->b_syn_error = TRUE;
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004657 has_syntax = FALSE;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02004658 syntax_attr = 0;
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004659 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660 else
4661 did_emsg = save_did_emsg;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02004662
4663 // combine syntax attribute with 'wincolor'
4664 if (win_attr != 0)
4665 syntax_attr = hl_combine_attr(win_attr, syntax_attr);
4666
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02004667#ifdef SYN_TIME_LIMIT
4668 if (wp->w_s->b_syn_slow)
4669 has_syntax = FALSE;
4670#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671
4672 /* Need to get the line again, a multi-line regexp may
4673 * have made it invalid. */
4674 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4675 ptr = line + v;
4676
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004677# ifdef FEAT_TEXT_PROP
Bram Moolenaarde24a872019-05-05 15:48:00 +02004678 // Text properties overrule syntax highlighting or combine.
4679 if (text_prop_attr == 0 || text_prop_combine)
4680# endif
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004681 {
Bram Moolenaarde24a872019-05-05 15:48:00 +02004682 int comb_attr = syntax_attr;
4683# ifdef FEAT_TEXT_PROP
4684 comb_attr = hl_combine_attr(text_prop_attr, comb_attr);
4685# endif
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004686 if (!attr_pri)
Bram Moolenaarde24a872019-05-05 15:48:00 +02004687 char_attr = comb_attr;
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004688 else
Bram Moolenaarde24a872019-05-05 15:48:00 +02004689 char_attr = hl_combine_attr(comb_attr, char_attr);
Bram Moolenaar48f88ac2018-12-26 00:25:20 +01004690 }
Bram Moolenaarc095b282010-07-20 22:33:34 +02004691# ifdef FEAT_CONCEAL
4692 /* no concealing past the end of the line, it interferes
4693 * with line highlighting */
4694 if (c == NUL)
4695 syntax_flags = 0;
Bram Moolenaar27c735b2010-07-22 22:16:29 +02004696 else
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02004697 syntax_flags = get_syntax_info(&syntax_seqnr);
Bram Moolenaarc095b282010-07-20 22:33:34 +02004698# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004699 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004700#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00004701
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004702#ifdef FEAT_SPELL
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004703 /* Check spelling (unless at the end of the line).
Bram Moolenaarf3681cc2005-06-08 22:03:13 +00004704 * Only do this when there is no syntax highlighting, the
4705 * @Spell cluster is not used or the current syntax item
4706 * contains the @Spell cluster. */
Bram Moolenaar30abd282005-06-22 22:35:10 +00004707 if (has_spell && v >= word_end && v > cur_checked_col)
Bram Moolenaar217ad922005-03-20 22:37:15 +00004708 {
Bram Moolenaar68b76a62005-03-25 21:53:48 +00004709 spell_attr = 0;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004710 if (c != 0 && (
4711# ifdef FEAT_SYN_HL
4712 !has_syntax ||
4713# endif
4714 can_spell))
Bram Moolenaar217ad922005-03-20 22:37:15 +00004715 {
Bram Moolenaar30abd282005-06-22 22:35:10 +00004716 char_u *prev_ptr, *p;
4717 int len;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004718 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaare7566042005-06-17 22:00:15 +00004719 if (has_mbyte)
4720 {
4721 prev_ptr = ptr - mb_l;
4722 v -= mb_l - 1;
4723 }
4724 else
Bram Moolenaare7566042005-06-17 22:00:15 +00004725 prev_ptr = ptr - 1;
Bram Moolenaar30abd282005-06-22 22:35:10 +00004726
4727 /* Use nextline[] if possible, it has the start of the
4728 * next line concatenated. */
4729 if ((prev_ptr - line) - nextlinecol >= 0)
4730 p = nextline + (prev_ptr - line) - nextlinecol;
4731 else
4732 p = prev_ptr;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004733 cap_col -= (int)(prev_ptr - line);
Bram Moolenaar4770d092006-01-12 23:22:24 +00004734 len = spell_check(wp, p, &spell_hlf, &cap_col,
4735 nochange);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004736 word_end = v + len;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004737
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004738 /* In Insert mode only highlight a word that
4739 * doesn't touch the cursor. */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004740 if (spell_hlf != HLF_COUNT
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004741 && (State & INSERT) != 0
4742 && wp->w_cursor.lnum == lnum
4743 && wp->w_cursor.col >=
Bram Moolenaar217ad922005-03-20 22:37:15 +00004744 (colnr_T)(prev_ptr - line)
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004745 && wp->w_cursor.col < (colnr_T)word_end)
4746 {
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004747 spell_hlf = HLF_COUNT;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004748 spell_redraw_lnum = lnum;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004749 }
Bram Moolenaar30abd282005-06-22 22:35:10 +00004750
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004751 if (spell_hlf == HLF_COUNT && p != prev_ptr
Bram Moolenaar30abd282005-06-22 22:35:10 +00004752 && (p - nextline) + len > nextline_idx)
4753 {
4754 /* Remember that the good word continues at the
4755 * start of the next line. */
4756 checked_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004757 checked_col = (int)((p - nextline) + len - nextline_idx);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004758 }
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004759
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004760 /* Turn index into actual attributes. */
4761 if (spell_hlf != HLF_COUNT)
4762 spell_attr = highlight_attr[spell_hlf];
4763
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004764 if (cap_col > 0)
4765 {
4766 if (p != prev_ptr
4767 && (p - nextline) + cap_col >= nextline_idx)
4768 {
4769 /* Remember that the word in the next line
4770 * must start with a capital. */
4771 capcol_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004772 cap_col = (int)((p - nextline) + cap_col
4773 - nextline_idx);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004774 }
4775 else
4776 /* Compute the actual column. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004777 cap_col += (int)(prev_ptr - line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004778 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004779 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004780 }
4781 if (spell_attr != 0)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004782 {
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004783 if (!attr_pri)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004784 char_attr = hl_combine_attr(char_attr, spell_attr);
4785 else
4786 char_attr = hl_combine_attr(spell_attr, char_attr);
4787 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788#endif
4789#ifdef FEAT_LINEBREAK
4790 /*
Bram Moolenaar217ad922005-03-20 22:37:15 +00004791 * Found last space before word: check for line break.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792 */
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004793 if (wp->w_p_lbr && c0 == c
Bram Moolenaar977d0372017-03-12 21:31:58 +01004794 && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 {
Bram Moolenaar4df70292015-03-21 14:20:16 +01004796 int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0;
Bram Moolenaara12a1612019-01-24 16:39:02 +01004797 char_u *p = ptr - (mb_off + 1);
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004798
Bram Moolenaar597a4222014-06-25 14:39:50 +02004799 /* TODO: is passing p for start of the line OK? */
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004800 n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
Bram Moolenaar597a4222014-06-25 14:39:50 +02004801 NULL) - 1;
Bram Moolenaar02631462017-09-22 15:20:32 +02004802 if (c == TAB && n_extra + col > wp->w_width)
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02004803# ifdef FEAT_VARTABS
Bram Moolenaara87b72c2018-06-25 21:24:51 +02004804 n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02004805 wp->w_buffer->b_p_vts_array) - 1;
4806# else
Bram Moolenaara3650912014-11-19 13:21:57 +01004807 n_extra = (int)wp->w_buffer->b_p_ts
4808 - vcol % (int)wp->w_buffer->b_p_ts - 1;
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02004809# endif
Bram Moolenaara3650912014-11-19 13:21:57 +01004810
Bram Moolenaar4df70292015-03-21 14:20:16 +01004811 c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
Bram Moolenaar83a52172019-01-16 22:41:54 +01004812 c_final = NUL;
Bram Moolenaar1c465442017-03-12 20:10:05 +01004813 if (VIM_ISWHITE(c))
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02004814 {
4815#ifdef FEAT_CONCEAL
4816 if (c == TAB)
4817 /* See "Tab alignment" below. */
4818 FIX_FOR_BOGUSCOLS;
4819#endif
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004820 if (!wp->w_p_list)
4821 c = ' ';
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02004822 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 }
4824#endif
4825
Bram Moolenaare5e4e222019-04-04 13:28:45 +02004826 // 'list': Change char 160 to lcs_nbsp and space to lcs_space.
4827 // But not when the character is followed by a composing
4828 // character (use mb_l to check that).
4829 if (wp->w_p_list
4830 && ((((c == 160 && mb_l == 1)
4831 || (mb_utf8
4832 && ((mb_c == 160 && mb_l == 2)
4833 || (mb_c == 0x202f && mb_l == 3))))
4834 && lcs_nbsp)
4835 || (c == ' '
4836 && mb_l == 1
4837 && lcs_space
4838 && ptr - line <= trailcol)))
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004839 {
Bram Moolenaare5e4e222019-04-04 13:28:45 +02004840 c = (c == ' ') ? lcs_space : lcs_nbsp;
4841 if (area_attr == 0 && search_attr == 0)
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004842 {
Bram Moolenaare5e4e222019-04-04 13:28:45 +02004843 n_attr = 1;
4844 extra_attr = HL_ATTR(HLF_8);
4845 saved_attr2 = char_attr; /* save current attr */
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004846 }
Bram Moolenaare5e4e222019-04-04 13:28:45 +02004847 mb_c = c;
4848 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004849 {
Bram Moolenaare5e4e222019-04-04 13:28:45 +02004850 mb_utf8 = TRUE;
4851 u8cc[0] = 0;
4852 c = 0xc0;
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004853 }
Bram Moolenaare5e4e222019-04-04 13:28:45 +02004854 else
4855 mb_utf8 = FALSE;
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004856 }
4857
Bram Moolenaar071d4272004-06-13 20:20:40 +00004858 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
4859 {
4860 c = lcs_trail;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004861 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 {
4863 n_attr = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004864 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865 saved_attr2 = char_attr; /* save current attr */
4866 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02004868 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869 {
4870 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004871 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004872 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873 }
4874 else
4875 mb_utf8 = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004876 }
4877 }
4878
4879 /*
4880 * Handling of non-printable characters.
4881 */
Bram Moolenaar88e8f9f2016-01-20 22:48:02 +01004882 if (!vim_isprintc(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004883 {
4884 /*
4885 * when getting a character from the file, we may have to
4886 * turn it into something else on the way to putting it
4887 * into "ScreenLines".
4888 */
4889 if (c == TAB && (!wp->w_p_list || lcs_tab1))
4890 {
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004891 int tab_len = 0;
Bram Moolenaard574ea22015-01-14 19:35:14 +01004892 long vcol_adjusted = vcol; /* removed showbreak length */
4893#ifdef FEAT_LINEBREAK
4894 /* only adjust the tab_len, when at the first column
4895 * after the showbreak value was drawn */
4896 if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap)
4897 vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
4898#endif
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004899 // tab amount depends on current column
Bram Moolenaar04958cb2018-06-23 19:23:02 +02004900#ifdef FEAT_VARTABS
4901 tab_len = tabstop_padding(vcol_adjusted,
4902 wp->w_buffer->b_p_ts,
4903 wp->w_buffer->b_p_vts_array) - 1;
4904#else
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004905 tab_len = (int)wp->w_buffer->b_p_ts
Bram Moolenaar04958cb2018-06-23 19:23:02 +02004906 - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
4907#endif
Bram Moolenaard574ea22015-01-14 19:35:14 +01004908
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004909#ifdef FEAT_LINEBREAK
Bram Moolenaarb81c85d2014-07-30 16:44:22 +02004910 if (!wp->w_p_lbr || !wp->w_p_list)
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004911#endif
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004912 // tab amount depends on current column
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004913 n_extra = tab_len;
4914#ifdef FEAT_LINEBREAK
4915 else
4916 {
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004917 char_u *p;
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01004918 int len;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004919 int i;
4920 int saved_nextra = n_extra;
4921
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004922#ifdef FEAT_CONCEAL
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004923 if (vcol_off > 0)
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004924 // there are characters to conceal
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004925 tab_len += vcol_off;
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004926 // boguscols before FIX_FOR_BOGUSCOLS macro from above
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01004927 if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
4928 && n_extra > tab_len)
4929 tab_len += n_extra - tab_len;
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004930#endif
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01004931
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004932 // if n_extra > 0, it gives the number of chars, to
4933 // use for a tab, else we need to calculate the width
4934 // for a tab
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004935 len = (tab_len * mb_char2len(lcs_tab2));
4936 if (n_extra > 0)
4937 len += n_extra - tab_len;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004938 c = lcs_tab1;
Bram Moolenaar964b3742019-05-24 18:54:09 +02004939 p = alloc(len + 1);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004940 vim_memset(p, ' ', len);
4941 p[len] = NUL;
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01004942 vim_free(p_extra_free);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004943 p_extra_free = p;
4944 for (i = 0; i < tab_len; i++)
4945 {
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004946 int lcs = lcs_tab2;
4947
Bram Moolenaar307ac5c2018-06-28 22:23:00 +02004948 if (*p == NUL)
4949 {
4950 tab_len = i;
4951 break;
4952 }
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004953
4954 // if lcs_tab3 is given, need to change the char
4955 // for tab
4956 if (lcs_tab3 && i == tab_len - 1)
4957 lcs = lcs_tab3;
4958 mb_char2bytes(lcs, p);
4959 p += mb_char2len(lcs);
4960 n_extra += mb_char2len(lcs)
4961 - (saved_nextra > 0 ? 1 : 0);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004962 }
4963 p_extra = p_extra_free;
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004964#ifdef FEAT_CONCEAL
Bram Moolenaar69cbbec2019-08-17 14:10:56 +02004965 // n_extra will be increased by FIX_FOX_BOGUSCOLS
4966 // macro below, so need to adjust for that here
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004967 if (vcol_off > 0)
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004968 n_extra -= vcol_off;
4969#endif
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004970 }
4971#endif
Bram Moolenaar0f9d0862012-12-05 15:32:30 +01004972#ifdef FEAT_CONCEAL
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004973 {
4974 int vc_saved = vcol_off;
4975
4976 /* Tab alignment should be identical regardless of
4977 * 'conceallevel' value. So tab compensates of all
4978 * previous concealed characters, and thus resets
4979 * vcol_off and boguscols accumulated so far in the
4980 * line. Note that the tab can be longer than
4981 * 'tabstop' when there are concealed characters. */
4982 FIX_FOR_BOGUSCOLS;
4983
4984 /* Make sure, the highlighting for the tab char will be
4985 * correctly set further below (effectively reverts the
4986 * FIX_FOR_BOGSUCOLS macro */
4987 if (n_extra == tab_len + vc_saved && wp->w_p_list
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01004988 && lcs_tab1)
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004989 tab_len += vc_saved;
4990 }
Bram Moolenaar0f9d0862012-12-05 15:32:30 +01004991#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004992 mb_utf8 = FALSE; /* don't draw as UTF-8 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004993 if (wp->w_p_list)
4994 {
Bram Moolenaar83a52172019-01-16 22:41:54 +01004995 c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004996#ifdef FEAT_LINEBREAK
4997 if (wp->w_p_lbr)
4998 c_extra = NUL; /* using p_extra from above */
4999 else
5000#endif
5001 c_extra = lcs_tab2;
Bram Moolenaar83a52172019-01-16 22:41:54 +01005002 c_final = lcs_tab3;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005003 n_attr = tab_len + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005004 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005 saved_attr2 = char_attr; /* save current attr */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005006 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005007 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008 {
5009 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005010 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005011 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 }
5014 else
5015 {
Bram Moolenaar83a52172019-01-16 22:41:54 +01005016 c_final = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017 c_extra = ' ';
5018 c = ' ';
5019 }
5020 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005021 else if (c == NUL
Bram Moolenaard59c0992015-05-04 16:52:01 +02005022 && (wp->w_p_list
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005023 || ((fromcol >= 0 || fromcol_prev >= 0)
5024 && tocol > vcol
5025 && VIsual_mode != Ctrl_V
5026 && (
5027# ifdef FEAT_RIGHTLEFT
5028 wp->w_p_rl ? (col >= 0) :
5029# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005030 (col < wp->w_width))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005031 && !(noinvcur
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005032 && lnum == wp->w_cursor.lnum
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005033 && (colnr_T)vcol == wp->w_virtcol)))
Bram Moolenaar0481fee2015-05-14 05:56:09 +02005034 && lcs_eol_one > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005035 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005036 /* Display a '$' after the line or highlight an extra
5037 * character if the line break is included. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038#if defined(FEAT_DIFF) || defined(LINE_ATTR)
5039 /* For a diff line the highlighting continues after the
5040 * "$". */
5041 if (
5042# ifdef FEAT_DIFF
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005043 diff_hlf == (hlf_T)0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005044# ifdef LINE_ATTR
5045 &&
5046# endif
5047# endif
5048# ifdef LINE_ATTR
5049 line_attr == 0
5050# endif
5051 )
5052#endif
5053 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005054 /* In virtualedit, visual selections may extend
5055 * beyond end of line. */
5056 if (area_highlighting && virtual_active()
5057 && tocol != MAXCOL && vcol < tocol)
5058 n_extra = 0;
5059 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060 {
5061 p_extra = at_end_str;
5062 n_extra = 1;
5063 c_extra = NUL;
Bram Moolenaar83a52172019-01-16 22:41:54 +01005064 c_final = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065 }
5066 }
Bram Moolenaard59c0992015-05-04 16:52:01 +02005067 if (wp->w_p_list && lcs_eol > 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005068 c = lcs_eol;
5069 else
5070 c = ' ';
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071 lcs_eol_one = -1;
5072 --ptr; /* put it back at the NUL */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005073 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005074 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01005075 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005076 n_attr = 1;
5077 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005079 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005080 {
5081 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005082 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005083 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084 }
5085 else
5086 mb_utf8 = FALSE; /* don't draw as UTF-8 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087 }
5088 else if (c != NUL)
5089 {
5090 p_extra = transchar(c);
Bram Moolenaar5524aeb2014-07-16 17:29:51 +02005091 if (n_extra == 0)
5092 n_extra = byte2cells(c) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093#ifdef FEAT_RIGHTLEFT
5094 if ((dy_flags & DY_UHEX) && wp->w_p_rl)
5095 rl_mirror(p_extra); /* reverse "<12>" */
5096#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005097 c_extra = NUL;
Bram Moolenaar83a52172019-01-16 22:41:54 +01005098 c_final = NUL;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005099#ifdef FEAT_LINEBREAK
5100 if (wp->w_p_lbr)
5101 {
5102 char_u *p;
5103
5104 c = *p_extra;
Bram Moolenaar964b3742019-05-24 18:54:09 +02005105 p = alloc(n_extra + 1);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005106 vim_memset(p, ' ', n_extra);
5107 STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
5108 p[n_extra] = NUL;
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01005109 vim_free(p_extra_free);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005110 p_extra_free = p_extra = p;
5111 }
5112 else
5113#endif
5114 {
5115 n_extra = byte2cells(c) - 1;
5116 c = *p_extra++;
5117 }
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005118 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005119 {
5120 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005121 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005122 saved_attr2 = char_attr; /* save current attr */
5123 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124 mb_utf8 = FALSE; /* don't draw as UTF-8 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005125 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005126 else if (VIsual_active
5127 && (VIsual_mode == Ctrl_V
5128 || VIsual_mode == 'v')
5129 && virtual_active()
5130 && tocol != MAXCOL
5131 && vcol < tocol
5132 && (
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005133#ifdef FEAT_RIGHTLEFT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134 wp->w_p_rl ? (col >= 0) :
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005135#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005136 (col < wp->w_width)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005137 {
5138 c = ' ';
5139 --ptr; /* put it back at the NUL */
5140 }
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005141#if defined(LINE_ATTR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142 else if ((
5143# ifdef FEAT_DIFF
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005144 diff_hlf != (hlf_T)0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145# endif
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005146# ifdef FEAT_TERMINAL
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005147 win_attr != 0 ||
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005148# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 line_attr != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005150 ) && (
5151# ifdef FEAT_RIGHTLEFT
5152 wp->w_p_rl ? (col >= 0) :
5153# endif
Bram Moolenaar2a988a12010-08-13 15:24:39 +02005154 (col
5155# ifdef FEAT_CONCEAL
5156 - boguscols
5157# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005158 < wp->w_width)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005159 {
5160 /* Highlight until the right side of the window */
5161 c = ' ';
5162 --ptr; /* put it back at the NUL */
Bram Moolenaar91170f82006-05-05 21:15:17 +00005163
5164 /* Remember we do the char for line highlighting. */
5165 ++did_line_attr;
5166
5167 /* don't do search HL for the rest of the line */
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02005168 if (line_attr != 0 && char_attr == search_attr
5169 && (did_line_attr > 1
5170 || (wp->w_p_list && lcs_eol > 0)))
Bram Moolenaar91170f82006-05-05 21:15:17 +00005171 char_attr = line_attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172# ifdef FEAT_DIFF
5173 if (diff_hlf == HLF_TXD)
5174 {
5175 diff_hlf = HLF_CHD;
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005176 if (vi_attr == 0 || char_attr != vi_attr)
Bram Moolenaare0f14822014-08-06 13:20:56 +02005177 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01005178 char_attr = HL_ATTR(diff_hlf);
Bram Moolenaare0f14822014-08-06 13:20:56 +02005179 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
5180 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01005181 HL_ATTR(HLF_CUL));
Bram Moolenaare0f14822014-08-06 13:20:56 +02005182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005183 }
5184# endif
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005185# ifdef FEAT_TERMINAL
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005186 if (win_attr != 0)
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005187 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005188 char_attr = win_attr;
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005189 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
5190 char_attr = hl_combine_attr(char_attr,
5191 HL_ATTR(HLF_CUL));
Bram Moolenaarcb5ff342019-07-20 16:51:19 +02005192 else if (line_attr)
5193 char_attr = hl_combine_attr(char_attr, line_attr);
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005194 }
5195# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005196 }
5197#endif
5198 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005199
5200#ifdef FEAT_CONCEAL
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005201 if ( wp->w_p_cole > 0
5202 && (wp != curwin || lnum != wp->w_cursor.lnum ||
Bram Moolenaarab62c192019-03-30 16:39:05 +01005203 conceal_cursor_line(wp))
5204 && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
Bram Moolenaare6dc5732010-07-24 23:52:26 +02005205 && !(lnum_in_visual_area
5206 && vim_strchr(wp->w_p_cocu, 'v') == NULL))
Bram Moolenaar860cae12010-06-05 23:22:07 +02005207 {
5208 char_attr = conceal_attr;
Bram Moolenaar4d585022016-04-14 19:50:22 +02005209 if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
Bram Moolenaar6561d522015-07-21 15:48:27 +02005210 && (syn_get_sub_char() != NUL || match_conc
5211 || wp->w_p_cole == 1)
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005212 && wp->w_p_cole != 3)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005213 {
Bram Moolenaar27c735b2010-07-22 22:16:29 +02005214 /* First time at this concealed item: display one
5215 * character. */
Bram Moolenaar6561d522015-07-21 15:48:27 +02005216 if (match_conc)
5217 c = match_conc;
5218 else if (syn_get_sub_char() != NUL)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005219 c = syn_get_sub_char();
5220 else if (lcs_conceal != NUL)
5221 c = lcs_conceal;
5222 else
5223 c = ' ';
5224
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02005225 prev_syntax_id = syntax_seqnr;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005226
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005227 if (n_extra > 0)
5228 vcol_off += n_extra;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005229 vcol += n_extra;
5230 if (wp->w_p_wrap && n_extra > 0)
5231 {
5232# ifdef FEAT_RIGHTLEFT
5233 if (wp->w_p_rl)
5234 {
5235 col -= n_extra;
5236 boguscols -= n_extra;
5237 }
5238 else
5239# endif
5240 {
5241 boguscols += n_extra;
5242 col += n_extra;
5243 }
5244 }
5245 n_extra = 0;
5246 n_attr = 0;
5247 }
5248 else if (n_skip == 0)
5249 {
5250 is_concealing = TRUE;
5251 n_skip = 1;
5252 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005253 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005254 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005255 {
5256 mb_utf8 = TRUE;
5257 u8cc[0] = 0;
5258 c = 0xc0;
5259 }
5260 else
5261 mb_utf8 = FALSE; /* don't draw as UTF-8 */
Bram Moolenaar860cae12010-06-05 23:22:07 +02005262 }
5263 else
5264 {
Bram Moolenaar27c735b2010-07-22 22:16:29 +02005265 prev_syntax_id = 0;
Bram Moolenaarc400cb92010-07-19 19:52:13 +02005266 is_concealing = FALSE;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005267 }
Bram Moolenaar0ebe12b2019-05-17 12:31:44 +02005268
5269 if (n_skip > 0 && did_decrement_ptr)
5270 // not showing the '>', put pointer back to avoid getting stuck
5271 ++ptr;
5272
5273#endif // FEAT_CONCEAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005274 }
5275
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005276#ifdef FEAT_CONCEAL
5277 /* In the cursor line and we may be concealing characters: correct
5278 * the cursor column when we reach its position. */
Bram Moolenaarf691b842010-07-24 13:31:09 +02005279 if (!did_wcol && draw_state == WL_LINE
5280 && wp == curwin && lnum == wp->w_cursor.lnum
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005281 && conceal_cursor_line(wp)
5282 && (int)wp->w_virtcol <= vcol + n_skip)
5283 {
Bram Moolenaare39b3d92016-01-15 22:52:22 +01005284# ifdef FEAT_RIGHTLEFT
5285 if (wp->w_p_rl)
Bram Moolenaar02631462017-09-22 15:20:32 +02005286 wp->w_wcol = wp->w_width - col + boguscols - 1;
Bram Moolenaare39b3d92016-01-15 22:52:22 +01005287 else
5288# endif
5289 wp->w_wcol = col - boguscols;
Bram Moolenaar72ada0f2010-07-24 17:39:52 +02005290 wp->w_wrow = row;
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005291 did_wcol = TRUE;
5292 }
5293#endif
5294
Bram Moolenaar071d4272004-06-13 20:20:40 +00005295 /* Don't override visual selection highlighting. */
5296 if (n_attr > 0
5297 && draw_state == WL_LINE
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005298 && !attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005299 char_attr = extra_attr;
5300
Bram Moolenaar81695252004-12-29 20:58:21 +00005301#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005302 /* XIM don't send preedit_start and preedit_end, but they send
5303 * preedit_changed and commit. Thus Vim can't set "im_is_active", use
5304 * im_is_preediting() here. */
Bram Moolenaar5c6dbcb2017-08-30 22:00:20 +02005305 if (p_imst == IM_ON_THE_SPOT
5306 && xic != NULL
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005307 && lnum == wp->w_cursor.lnum
Bram Moolenaar071d4272004-06-13 20:20:40 +00005308 && (State & INSERT)
5309 && !p_imdisable
5310 && im_is_preediting()
5311 && draw_state == WL_LINE)
5312 {
5313 colnr_T tcol;
5314
5315 if (preedit_end_col == MAXCOL)
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005316 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005317 else
5318 tcol = preedit_end_col;
5319 if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
5320 {
5321 if (feedback_old_attr < 0)
5322 {
5323 feedback_col = 0;
5324 feedback_old_attr = char_attr;
5325 }
5326 char_attr = im_get_feedback_attr(feedback_col);
5327 if (char_attr < 0)
5328 char_attr = feedback_old_attr;
5329 feedback_col++;
5330 }
5331 else if (feedback_old_attr >= 0)
5332 {
5333 char_attr = feedback_old_attr;
5334 feedback_old_attr = -1;
5335 feedback_col = 0;
5336 }
5337 }
5338#endif
5339 /*
5340 * Handle the case where we are in column 0 but not on the first
5341 * character of the line and the user wants us to show us a
5342 * special character (via 'listchars' option "precedes:<char>".
5343 */
5344 if (lcs_prec_todo != NUL
Bram Moolenaar7425b932014-10-10 15:28:46 +02005345 && wp->w_p_list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005346 && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
5347#ifdef FEAT_DIFF
5348 && filler_todo <= 0
5349#endif
5350 && draw_state > WL_NR
5351 && c != NUL)
5352 {
5353 c = lcs_prec;
5354 lcs_prec_todo = NUL;
Bram Moolenaar5641f382012-06-13 18:06:36 +02005355 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5356 {
5357 /* Double-width character being overwritten by the "precedes"
5358 * character, need to fill up half the character. */
5359 c_extra = MB_FILLER_CHAR;
Bram Moolenaar83a52172019-01-16 22:41:54 +01005360 c_final = NUL;
Bram Moolenaar5641f382012-06-13 18:06:36 +02005361 n_extra = 1;
5362 n_attr = 2;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005363 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar5641f382012-06-13 18:06:36 +02005364 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005365 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005366 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005367 {
5368 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005369 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005370 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371 }
5372 else
5373 mb_utf8 = FALSE; /* don't draw as UTF-8 */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005374 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005375 {
5376 saved_attr3 = char_attr; /* save current attr */
Bram Moolenaar8820b482017-03-16 17:23:31 +01005377 char_attr = HL_ATTR(HLF_AT); /* later copied to char_attr */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378 n_attr3 = 1;
5379 }
5380 }
5381
5382 /*
Bram Moolenaar91170f82006-05-05 21:15:17 +00005383 * At end of the text line or just after the last character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005384 */
Bram Moolenaarf914a332019-07-20 15:09:56 +02005385 if ((c == NUL
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005386#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00005387 || did_line_attr == 1
5388#endif
Bram Moolenaarf914a332019-07-20 15:09:56 +02005389 ) && eol_hl_off == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005390 {
Bram Moolenaar91170f82006-05-05 21:15:17 +00005391#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarbbca7732019-07-24 18:13:16 +02005392 // flag to indicate whether prevcol equals startcol of search_hl or
5393 // one of the matches
5394 int prevcol_hl_flag = get_prevcol_hl_flag(wp, &search_hl,
5395 (long)(ptr - line) - (c == NUL));
Bram Moolenaar91170f82006-05-05 21:15:17 +00005396#endif
Bram Moolenaarbbca7732019-07-24 18:13:16 +02005397 // Invert at least one char, used for Visual and empty line or
5398 // highlight match at end of line. If it's beyond the last
5399 // char on the screen, just overwrite that one (tricky!) Not
5400 // needed when a '$' was displayed for 'list'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005401 if (lcs_eol == lcs_eol_one
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005402 && ((area_attr != 0 && vcol == fromcol
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005403 && (VIsual_mode != Ctrl_V
5404 || lnum == VIsual.lnum
5405 || lnum == curwin->w_cursor.lnum)
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005406 && c == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarbbca7732019-07-24 18:13:16 +02005408 // highlight 'hlsearch' match at end of line
5409 || (prevcol_hl_flag
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02005410# ifdef FEAT_SYN_HL
5411 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
5412 && !(wp == curwin && VIsual_active))
5413# endif
5414# ifdef FEAT_DIFF
5415 && diff_hlf == (hlf_T)0
5416# endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005417# if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00005418 && did_line_attr <= 1
5419# endif
5420 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00005421#endif
5422 ))
5423 {
5424 int n = 0;
5425
5426#ifdef FEAT_RIGHTLEFT
5427 if (wp->w_p_rl)
5428 {
5429 if (col < 0)
5430 n = 1;
5431 }
5432 else
5433#endif
5434 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005435 if (col >= wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005436 n = -1;
5437 }
5438 if (n != 0)
5439 {
5440 /* At the window boundary, highlight the last character
5441 * instead (better than nothing). */
5442 off += n;
5443 col += n;
5444 }
5445 else
5446 {
5447 /* Add a blank character to highlight. */
5448 ScreenLines[off] = ' ';
Bram Moolenaar071d4272004-06-13 20:20:40 +00005449 if (enc_utf8)
5450 ScreenLinesUC[off] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005451 }
5452#ifdef FEAT_SEARCH_EXTRA
5453 if (area_attr == 0)
5454 {
Bram Moolenaarbbca7732019-07-24 18:13:16 +02005455 // Use attributes from match with highest priority among
5456 // 'search_hl' and the match list.
5457 get_search_match_hl(wp, &search_hl,
5458 (long)(ptr - line), &char_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005459 }
5460#endif
5461 ScreenAttrs[off] = char_attr;
5462#ifdef FEAT_RIGHTLEFT
5463 if (wp->w_p_rl)
Bram Moolenaara443af82007-11-08 13:51:42 +00005464 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 --col;
Bram Moolenaara443af82007-11-08 13:51:42 +00005466 --off;
5467 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005468 else
5469#endif
Bram Moolenaara443af82007-11-08 13:51:42 +00005470 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005471 ++col;
Bram Moolenaara443af82007-11-08 13:51:42 +00005472 ++off;
5473 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005474 ++vcol;
Bram Moolenaara443af82007-11-08 13:51:42 +00005475 eol_hl_off = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005476 }
Bram Moolenaar91170f82006-05-05 21:15:17 +00005477 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005478
Bram Moolenaar91170f82006-05-05 21:15:17 +00005479 /*
5480 * At end of the text line.
5481 */
5482 if (c == NUL)
5483 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005484#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02005485 /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00005486 if (wp->w_p_wrap)
5487 v = wp->w_skipcol;
5488 else
5489 v = wp->w_leftcol;
Bram Moolenaar1a384422010-07-14 19:53:30 +02005490
Bram Moolenaar8dff8182006-04-06 20:18:50 +00005491 /* check if line ends before left margin */
5492 if (vcol < v + col - win_col_off(wp))
Bram Moolenaar8dff8182006-04-06 20:18:50 +00005493 vcol = v + col - win_col_off(wp);
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005494#ifdef FEAT_CONCEAL
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01005495 // Get rid of the boguscols now, we want to draw until the right
5496 // edge for 'cursorcolumn'.
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005497 col -= boguscols;
5498 boguscols = 0;
5499#endif
Bram Moolenaar1a384422010-07-14 19:53:30 +02005500
5501 if (draw_color_col)
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005502 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005503
5504 if (((wp->w_p_cuc
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005505 && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
5506 && (int)wp->w_virtcol <
Bram Moolenaar02631462017-09-22 15:20:32 +02005507 wp->w_width * (row - startrow + 1) + v
Bram Moolenaar1a384422010-07-14 19:53:30 +02005508 && lnum != wp->w_cursor.lnum)
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005509 || draw_color_col
5510 || win_attr != 0)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005511# ifdef FEAT_RIGHTLEFT
5512 && !wp->w_p_rl
5513# endif
5514 )
5515 {
Bram Moolenaar1a384422010-07-14 19:53:30 +02005516 int rightmost_vcol = 0;
5517 int i;
5518
5519 if (wp->w_p_cuc)
5520 rightmost_vcol = wp->w_virtcol;
5521 if (draw_color_col)
5522 /* determine rightmost colorcolumn to possibly draw */
5523 for (i = 0; color_cols[i] >= 0; ++i)
5524 if (rightmost_vcol < color_cols[i])
5525 rightmost_vcol = color_cols[i];
5526
Bram Moolenaar02631462017-09-22 15:20:32 +02005527 while (col < wp->w_width)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005528 {
5529 ScreenLines[off] = ' ';
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005530 if (enc_utf8)
5531 ScreenLinesUC[off] = 0;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005532 ++col;
Bram Moolenaar973bd472010-07-20 11:29:07 +02005533 if (draw_color_col)
5534 draw_color_col = advance_color_col(VCOL_HLC,
5535 &color_cols);
5536
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005537 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol)
Bram Moolenaar8820b482017-03-16 17:23:31 +01005538 ScreenAttrs[off++] = HL_ATTR(HLF_CUC);
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005539 else if (draw_color_col && VCOL_HLC == *color_cols)
Bram Moolenaar8820b482017-03-16 17:23:31 +01005540 ScreenAttrs[off++] = HL_ATTR(HLF_MC);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005541 else
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005542 ScreenAttrs[off++] = win_attr;
Bram Moolenaar1a384422010-07-14 19:53:30 +02005543
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005544 if (VCOL_HLC >= rightmost_vcol && win_attr == 0)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005545 break;
Bram Moolenaar1a384422010-07-14 19:53:30 +02005546
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005547 ++vcol;
5548 }
5549 }
5550#endif
5551
Bram Moolenaar53f81742017-09-22 14:35:51 +02005552 screen_line(screen_row, wp->w_wincol, col,
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005553 (int)wp->w_width, screen_line_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005554 row++;
5555
5556 /*
5557 * Update w_cline_height and w_cline_folded if the cursor line was
5558 * updated (saves a call to plines() later).
5559 */
5560 if (wp == curwin && lnum == curwin->w_cursor.lnum)
5561 {
5562 curwin->w_cline_row = startrow;
5563 curwin->w_cline_height = row - startrow;
5564#ifdef FEAT_FOLDING
5565 curwin->w_cline_folded = FALSE;
5566#endif
5567 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
5568 }
5569
5570 break;
5571 }
5572
Bram Moolenaara5c6a0b2019-05-08 20:20:46 +02005573 // Show "extends" character from 'listchars' if beyond the line end and
5574 // 'list' is set.
5575 if (lcs_ext != NUL
5576 && wp->w_p_list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005577 && !wp->w_p_wrap
5578#ifdef FEAT_DIFF
5579 && filler_todo <= 0
5580#endif
5581 && (
5582#ifdef FEAT_RIGHTLEFT
5583 wp->w_p_rl ? col == 0 :
5584#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005585 col == wp->w_width - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005586 && (*ptr != NUL
Bram Moolenaar5bbc21d2008-03-09 13:30:56 +00005587 || (wp->w_p_list && lcs_eol_one > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005588 || (n_extra && (c_extra != NUL || *p_extra != NUL))))
5589 {
5590 c = lcs_ext;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005591 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005592 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005593 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005594 {
5595 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005596 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005597 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005598 }
5599 else
5600 mb_utf8 = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005601 }
5602
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005603#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02005604 /* advance to the next 'colorcolumn' */
5605 if (draw_color_col)
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005606 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005607
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005608 /* Highlight the cursor column if 'cursorcolumn' is set. But don't
Bram Moolenaar1a384422010-07-14 19:53:30 +02005609 * highlight the cursor position itself.
5610 * Also highlight the 'colorcolumn' if it is different than
5611 * 'cursorcolumn' */
5612 vcol_save_attr = -1;
Bram Moolenaar774e5a92017-06-25 18:03:37 +02005613 if (draw_state == WL_LINE && !lnum_in_visual_area
5614 && search_attr == 0 && area_attr == 0)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005615 {
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005616 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
Bram Moolenaar1a384422010-07-14 19:53:30 +02005617 && lnum != wp->w_cursor.lnum)
5618 {
5619 vcol_save_attr = char_attr;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005620 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC));
Bram Moolenaar1a384422010-07-14 19:53:30 +02005621 }
Bram Moolenaard160c342010-07-18 23:30:34 +02005622 else if (draw_color_col && VCOL_HLC == *color_cols)
Bram Moolenaar1a384422010-07-14 19:53:30 +02005623 {
5624 vcol_save_attr = char_attr;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005625 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC));
Bram Moolenaar1a384422010-07-14 19:53:30 +02005626 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005627 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005628#endif
5629
Bram Moolenaar071d4272004-06-13 20:20:40 +00005630 /*
5631 * Store character to be displayed.
5632 * Skip characters that are left of the screen for 'nowrap'.
5633 */
5634 vcol_prev = vcol;
5635 if (draw_state < WL_LINE || n_skip <= 0)
5636 {
5637 /*
5638 * Store the character.
5639 */
Bram Moolenaara12a1612019-01-24 16:39:02 +01005640#if defined(FEAT_RIGHTLEFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005641 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
5642 {
5643 /* A double-wide character is: put first halve in left cell. */
5644 --off;
5645 --col;
5646 }
5647#endif
5648 ScreenLines[off] = c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005649 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaar990bb662010-02-03 15:48:04 +01005650 {
5651 if ((mb_c & 0xff00) == 0x8e00)
5652 ScreenLines[off] = 0x8e;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653 ScreenLines2[off] = mb_c & 0xff;
Bram Moolenaar990bb662010-02-03 15:48:04 +01005654 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005655 else if (enc_utf8)
5656 {
5657 if (mb_utf8)
5658 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005659 int i;
5660
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661 ScreenLinesUC[off] = mb_c;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005662 if ((c & 0xff) == 0)
5663 ScreenLines[off] = 0x80; /* avoid storing zero */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005664 for (i = 0; i < Screen_mco; ++i)
5665 {
5666 ScreenLinesC[i][off] = u8cc[i];
5667 if (u8cc[i] == 0)
5668 break;
5669 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670 }
5671 else
5672 ScreenLinesUC[off] = 0;
5673 }
5674 if (multi_attr)
5675 {
5676 ScreenAttrs[off] = multi_attr;
5677 multi_attr = 0;
5678 }
5679 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680 ScreenAttrs[off] = char_attr;
5681
Bram Moolenaar071d4272004-06-13 20:20:40 +00005682 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5683 {
5684 /* Need to fill two screen columns. */
5685 ++off;
5686 ++col;
5687 if (enc_utf8)
5688 /* UTF-8: Put a 0 in the second screen char. */
5689 ScreenLines[off] = 0;
5690 else
5691 /* DBCS: Put second byte in the second screen char. */
5692 ScreenLines[off] = mb_c & 0xff;
Bram Moolenaar32a214e2015-12-03 14:29:02 +01005693 if (draw_state > WL_NR
5694#ifdef FEAT_DIFF
5695 && filler_todo <= 0
5696#endif
5697 )
5698 ++vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005699 /* When "tocol" is halfway a character, set it to the end of
5700 * the character, otherwise highlighting won't stop. */
5701 if (tocol == vcol)
5702 ++tocol;
5703#ifdef FEAT_RIGHTLEFT
5704 if (wp->w_p_rl)
5705 {
5706 /* now it's time to backup one cell */
5707 --off;
5708 --col;
5709 }
5710#endif
5711 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005712#ifdef FEAT_RIGHTLEFT
5713 if (wp->w_p_rl)
5714 {
5715 --off;
5716 --col;
5717 }
5718 else
5719#endif
5720 {
5721 ++off;
5722 ++col;
5723 }
5724 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005725#ifdef FEAT_CONCEAL
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005726 else if (wp->w_p_cole > 0 && is_concealing)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005727 {
5728 --n_skip;
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005729 ++vcol_off;
5730 if (n_extra > 0)
5731 vcol_off += n_extra;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005732 if (wp->w_p_wrap)
5733 {
5734 /*
5735 * Special voodoo required if 'wrap' is on.
5736 *
5737 * Advance the column indicator to force the line
5738 * drawing to wrap early. This will make the line
5739 * take up the same screen space when parts are concealed,
5740 * so that cursor line computations aren't messed up.
5741 *
5742 * To avoid the fictitious advance of 'col' causing
5743 * trailing junk to be written out of the screen line
5744 * we are building, 'boguscols' keeps track of the number
5745 * of bad columns we have advanced.
5746 */
5747 if (n_extra > 0)
5748 {
5749 vcol += n_extra;
5750# ifdef FEAT_RIGHTLEFT
5751 if (wp->w_p_rl)
5752 {
5753 col -= n_extra;
5754 boguscols -= n_extra;
5755 }
5756 else
5757# endif
5758 {
5759 col += n_extra;
5760 boguscols += n_extra;
5761 }
5762 n_extra = 0;
5763 n_attr = 0;
5764 }
5765
5766
Bram Moolenaar860cae12010-06-05 23:22:07 +02005767 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5768 {
5769 /* Need to fill two screen columns. */
Bram Moolenaara12a1612019-01-24 16:39:02 +01005770# ifdef FEAT_RIGHTLEFT
Bram Moolenaar860cae12010-06-05 23:22:07 +02005771 if (wp->w_p_rl)
5772 {
5773 --boguscols;
5774 --col;
5775 }
5776 else
Bram Moolenaara12a1612019-01-24 16:39:02 +01005777# endif
Bram Moolenaar860cae12010-06-05 23:22:07 +02005778 {
5779 ++boguscols;
5780 ++col;
5781 }
5782 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005783
5784# ifdef FEAT_RIGHTLEFT
5785 if (wp->w_p_rl)
5786 {
5787 --boguscols;
5788 --col;
5789 }
5790 else
5791# endif
5792 {
5793 ++boguscols;
5794 ++col;
5795 }
5796 }
5797 else
5798 {
5799 if (n_extra > 0)
5800 {
5801 vcol += n_extra;
5802 n_extra = 0;
5803 n_attr = 0;
5804 }
5805 }
5806
5807 }
5808#endif /* FEAT_CONCEAL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005809 else
5810 --n_skip;
5811
Bram Moolenaar64486672010-05-16 15:46:46 +02005812 /* Only advance the "vcol" when after the 'number' or 'relativenumber'
5813 * column. */
Bram Moolenaar1b636fa2009-03-18 15:28:08 +00005814 if (draw_state > WL_NR
Bram Moolenaar071d4272004-06-13 20:20:40 +00005815#ifdef FEAT_DIFF
5816 && filler_todo <= 0
5817#endif
5818 )
5819 ++vcol;
5820
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005821#ifdef FEAT_SYN_HL
5822 if (vcol_save_attr >= 0)
5823 char_attr = vcol_save_attr;
5824#endif
5825
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826 /* restore attributes after "predeces" in 'listchars' */
5827 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
5828 char_attr = saved_attr3;
5829
5830 /* restore attributes after last 'listchars' or 'number' char */
5831 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
5832 char_attr = saved_attr2;
5833
5834 /*
5835 * At end of screen line and there is more to come: Display the line
Bram Moolenaar367329b2007-08-30 11:53:22 +00005836 * so far. If there is no more to display it is caught above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005837 */
5838 if ((
5839#ifdef FEAT_RIGHTLEFT
5840 wp->w_p_rl ? (col < 0) :
5841#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005842 (col >= wp->w_width))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005843 && (*ptr != NUL
5844#ifdef FEAT_DIFF
5845 || filler_todo > 0
5846#endif
Bram Moolenaare9d4b582011-03-22 13:29:24 +01005847 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005848 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
5849 )
5850 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02005851#ifdef FEAT_CONCEAL
Bram Moolenaar53f81742017-09-22 14:35:51 +02005852 screen_line(screen_row, wp->w_wincol, col - boguscols,
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005853 (int)wp->w_width, screen_line_flags);
Bram Moolenaar860cae12010-06-05 23:22:07 +02005854 boguscols = 0;
5855#else
Bram Moolenaar53f81742017-09-22 14:35:51 +02005856 screen_line(screen_row, wp->w_wincol, col,
Bram Moolenaar4d784b22019-05-25 19:51:39 +02005857 (int)wp->w_width, screen_line_flags);
Bram Moolenaar860cae12010-06-05 23:22:07 +02005858#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005859 ++row;
5860 ++screen_row;
5861
5862 /* When not wrapping and finished diff lines, or when displayed
5863 * '$' and highlighting until last column, break here. */
5864 if ((!wp->w_p_wrap
5865#ifdef FEAT_DIFF
5866 && filler_todo <= 0
5867#endif
5868 ) || lcs_eol_one == -1)
5869 break;
5870
5871 /* When the window is too narrow draw all "@" lines. */
5872 if (draw_state != WL_LINE
5873#ifdef FEAT_DIFF
5874 && filler_todo <= 0
5875#endif
5876 )
5877 {
Bram Moolenaar8ee4c012019-03-29 18:08:18 +01005878 win_draw_end(wp, '@', ' ', TRUE, row, wp->w_height, HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879 draw_vsep_win(wp, row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880 row = endrow;
5881 }
5882
5883 /* When line got too long for screen break here. */
5884 if (row == endrow)
5885 {
5886 ++row;
5887 break;
5888 }
5889
5890 if (screen_cur_row == screen_row - 1
5891#ifdef FEAT_DIFF
5892 && filler_todo <= 0
5893#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005894 && wp->w_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895 {
5896 /* Remember that the line wraps, used for modeless copy. */
5897 LineWraps[screen_row - 1] = TRUE;
5898
5899 /*
5900 * Special trick to make copy/paste of wrapped lines work with
5901 * xterm/screen: write an extra character beyond the end of
5902 * the line. This will work with all terminal types
5903 * (regardless of the xn,am settings).
5904 * Only do this on a fast tty.
5905 * Only do this if the cursor is on the current line
5906 * (something has been written in it).
5907 * Don't do this for the GUI.
5908 * Don't do this for double-width characters.
5909 * Don't do this for a window not at the right screen border.
5910 */
5911 if (p_tf
5912#ifdef FEAT_GUI
5913 && !gui.in_use
5914#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005915 && !(has_mbyte
Bram Moolenaar367329b2007-08-30 11:53:22 +00005916 && ((*mb_off2cells)(LineOffset[screen_row],
5917 LineOffset[screen_row] + screen_Columns)
5918 == 2
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919 || (*mb_off2cells)(LineOffset[screen_row - 1]
Bram Moolenaar367329b2007-08-30 11:53:22 +00005920 + (int)Columns - 2,
5921 LineOffset[screen_row] + screen_Columns)
Bram Moolenaara12a1612019-01-24 16:39:02 +01005922 == 2)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005923 {
5924 /* First make sure we are at the end of the screen line,
5925 * then output the same character again to let the
5926 * terminal know about the wrap. If the terminal doesn't
5927 * auto-wrap, we overwrite the character. */
Bram Moolenaar02631462017-09-22 15:20:32 +02005928 if (screen_cur_col != wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929 screen_char(LineOffset[screen_row - 1]
5930 + (unsigned)Columns - 1,
5931 screen_row - 1, (int)(Columns - 1));
5932
Bram Moolenaar071d4272004-06-13 20:20:40 +00005933 /* When there is a multi-byte character, just output a
5934 * space to keep it simple. */
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00005935 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
5936 screen_row - 1] + (Columns - 1)]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005937 out_char(' ');
5938 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005939 out_char(ScreenLines[LineOffset[screen_row - 1]
5940 + (Columns - 1)]);
5941 /* force a redraw of the first char on the next line */
5942 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
5943 screen_start(); /* don't know where cursor is now */
5944 }
5945 }
5946
5947 col = 0;
5948 off = (unsigned)(current_ScreenLine - ScreenLines);
5949#ifdef FEAT_RIGHTLEFT
5950 if (wp->w_p_rl)
5951 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005952 col = wp->w_width - 1; /* col is not used if breaking! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953 off += col;
5954 }
5955#endif
5956
5957 /* reset the drawing state for the start of a wrapped line */
5958 draw_state = WL_START;
5959 saved_n_extra = n_extra;
5960 saved_p_extra = p_extra;
5961 saved_c_extra = c_extra;
Bram Moolenaar83a52172019-01-16 22:41:54 +01005962 saved_c_final = c_final;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005963 saved_char_attr = char_attr;
5964 n_extra = 0;
5965 lcs_prec_todo = lcs_prec;
5966#ifdef FEAT_LINEBREAK
5967# ifdef FEAT_DIFF
5968 if (filler_todo <= 0)
5969# endif
5970 need_showbreak = TRUE;
5971#endif
5972#ifdef FEAT_DIFF
5973 --filler_todo;
5974 /* When the filler lines are actually below the last line of the
5975 * file, don't draw the line itself, break here. */
5976 if (filler_todo == 0 && wp->w_botfill)
5977 break;
5978#endif
5979 }
5980
5981 } /* for every character in the line */
5982
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005983#ifdef FEAT_SPELL
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00005984 /* After an empty line check first word for capital. */
5985 if (*skipwhite(line) == NUL)
5986 {
5987 capcol_lnum = lnum + 1;
5988 cap_col = 0;
5989 }
5990#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01005991#ifdef FEAT_TEXT_PROP
5992 vim_free(text_props);
5993 vim_free(text_prop_idxs);
5994#endif
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00005995
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01005996 vim_free(p_extra_free);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005997 return row;
5998}
5999
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006000/*
6001 * Return if the composing characters at "off_from" and "off_to" differ.
Bram Moolenaar70c49c12010-03-23 15:36:35 +01006002 * Only to be used when ScreenLinesUC[off_from] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006003 */
6004 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006005comp_char_differs(int off_from, int off_to)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006006{
6007 int i;
6008
6009 for (i = 0; i < Screen_mco; ++i)
6010 {
6011 if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
6012 return TRUE;
6013 if (ScreenLinesC[i][off_from] == 0)
6014 break;
6015 }
6016 return FALSE;
6017}
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006018
Bram Moolenaar071d4272004-06-13 20:20:40 +00006019/*
6020 * Check whether the given character needs redrawing:
6021 * - the (first byte of the) character is different
6022 * - the attributes are different
6023 * - the character is multi-byte and the next byte is different
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00006024 * - the character is two cells wide and the second cell differs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006025 */
6026 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006027char_needs_redraw(int off_from, int off_to, int cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006028{
6029 if (cols > 0
6030 && ((ScreenLines[off_from] != ScreenLines[off_to]
6031 || ScreenAttrs[off_from] != ScreenAttrs[off_to])
Bram Moolenaar071d4272004-06-13 20:20:40 +00006032 || (enc_dbcs != 0
6033 && MB_BYTE2LEN(ScreenLines[off_from]) > 1
6034 && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
6035 ? ScreenLines2[off_from] != ScreenLines2[off_to]
6036 : (cols > 1 && ScreenLines[off_from + 1]
6037 != ScreenLines[off_to + 1])))
6038 || (enc_utf8
6039 && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
6040 || (ScreenLinesUC[off_from] != 0
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00006041 && comp_char_differs(off_from, off_to))
Bram Moolenaar451cf632012-08-23 18:58:14 +02006042 || ((*mb_off2cells)(off_from, off_from + cols) > 1
6043 && ScreenLines[off_from + 1]
Bram Moolenaara12a1612019-01-24 16:39:02 +01006044 != ScreenLines[off_to + 1])))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006045 return TRUE;
6046 return FALSE;
6047}
6048
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006049#if defined(FEAT_TERMINAL) || defined(PROTO)
6050/*
6051 * Return the index in ScreenLines[] for the current screen line.
6052 */
6053 int
6054screen_get_current_line_off()
6055{
6056 return (int)(current_ScreenLine - ScreenLines);
6057}
6058#endif
6059
Bram Moolenaarc662ec92019-06-23 00:15:57 +02006060#ifdef FEAT_TEXT_PROP
6061/*
6062 * Return TRUE if this position has a higher level popup or this cell is
6063 * transparent in the current popup.
6064 */
6065 static int
6066blocked_by_popup(int row, int col)
6067{
6068 int off;
6069
6070 if (!popup_visible)
6071 return FALSE;
6072 off = row * screen_Columns + col;
6073 return popup_mask[off] > screen_zindex || popup_transparent[off];
6074}
6075#endif
6076
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077/*
6078 * Move one "cooked" screen line to the screen, but only the characters that
6079 * have actually changed. Handle insert/delete character.
6080 * "coloff" gives the first column on the screen for this line.
6081 * "endcol" gives the columns where valid characters are.
6082 * "clear_width" is the width of the window. It's > 0 if the rest of the line
6083 * needs to be cleared, negative otherwise.
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006084 * "flags" can have bits:
6085 * SLF_POPUP popup window
6086 * SLF_RIGHTLEFT rightleft window:
Bram Moolenaar071d4272004-06-13 20:20:40 +00006087 * When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
6088 * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
6089 */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006090 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006091screen_line(
6092 int row,
6093 int coloff,
6094 int endcol,
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006095 int clear_width,
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006096 int flags UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006097{
6098 unsigned off_from;
6099 unsigned off_to;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006100 unsigned max_off_from;
6101 unsigned max_off_to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006102 int col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006103 int hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006104 int force = FALSE; /* force update rest of the line */
6105 int redraw_this /* bool: does character need redraw? */
6106#ifdef FEAT_GUI
6107 = TRUE /* For GUI when while-loop empty */
6108#endif
6109 ;
6110 int redraw_next; /* redraw_this for next character */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006111 int clear_next = FALSE;
6112 int char_cells; /* 1: normal char */
6113 /* 2: occupies two display cells */
6114# define CHAR_CELLS char_cells
Bram Moolenaar071d4272004-06-13 20:20:40 +00006115
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01006116 /* Check for illegal row and col, just in case. */
6117 if (row >= Rows)
6118 row = Rows - 1;
6119 if (endcol > Columns)
6120 endcol = Columns;
6121
Bram Moolenaar071d4272004-06-13 20:20:40 +00006122# ifdef FEAT_CLIPBOARD
6123 clip_may_clear_selection(row, row);
6124# endif
6125
6126 off_from = (unsigned)(current_ScreenLine - ScreenLines);
6127 off_to = LineOffset[row] + coloff;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006128 max_off_from = off_from + screen_Columns;
6129 max_off_to = LineOffset[row] + screen_Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006130
6131#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006132 if (flags & SLF_RIGHTLEFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006133 {
6134 /* Clear rest first, because it's left of the text. */
6135 if (clear_width > 0)
6136 {
6137 while (col <= endcol && ScreenLines[off_to] == ' '
6138 && ScreenAttrs[off_to] == 0
Bram Moolenaara12a1612019-01-24 16:39:02 +01006139 && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140 {
6141 ++off_to;
6142 ++col;
6143 }
6144 if (col <= endcol)
6145 screen_fill(row, row + 1, col + coloff,
6146 endcol + coloff + 1, ' ', ' ', 0);
6147 }
6148 col = endcol + 1;
6149 off_to = LineOffset[row] + col + coloff;
6150 off_from += col;
6151 endcol = (clear_width > 0 ? clear_width : -clear_width);
6152 }
6153#endif /* FEAT_RIGHTLEFT */
6154
6155 redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
6156
6157 while (col < endcol)
6158 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006159 if (has_mbyte && (col + 1 < endcol))
Bram Moolenaar367329b2007-08-30 11:53:22 +00006160 char_cells = (*mb_off2cells)(off_from, max_off_from);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006161 else
6162 char_cells = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006163
6164 redraw_this = redraw_next;
6165 redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
6166 off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
6167
6168#ifdef FEAT_GUI
6169 /* If the next character was bold, then redraw the current character to
6170 * remove any pixels that might have spilt over into us. This only
6171 * happens in the GUI.
6172 */
6173 if (redraw_next && gui.in_use)
6174 {
6175 hl = ScreenAttrs[off_to + CHAR_CELLS];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00006176 if (hl > HL_ALL)
6177 hl = syn_attr2attr(hl);
6178 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179 redraw_this = TRUE;
6180 }
6181#endif
Bram Moolenaar33796b32019-06-08 16:01:13 +02006182#ifdef FEAT_TEXT_PROP
Bram Moolenaarc662ec92019-06-23 00:15:57 +02006183 if (blocked_by_popup(row, col + coloff))
Bram Moolenaar33796b32019-06-08 16:01:13 +02006184 redraw_this = FALSE;
6185#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006186 if (redraw_this)
6187 {
6188 /*
6189 * Special handling when 'xs' termcap flag set (hpterm):
6190 * Attributes for characters are stored at the position where the
6191 * cursor is when writing the highlighting code. The
6192 * start-highlighting code must be written with the cursor on the
6193 * first highlighted character. The stop-highlighting code must
6194 * be written with the cursor just after the last highlighted
6195 * character.
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01006196 * Overwriting a character doesn't remove its highlighting. Need
Bram Moolenaar071d4272004-06-13 20:20:40 +00006197 * to clear the rest of the line, and force redrawing it
6198 * completely.
6199 */
6200 if ( p_wiv
6201 && !force
6202#ifdef FEAT_GUI
6203 && !gui.in_use
6204#endif
6205 && ScreenAttrs[off_to] != 0
6206 && ScreenAttrs[off_from] != ScreenAttrs[off_to])
6207 {
6208 /*
6209 * Need to remove highlighting attributes here.
6210 */
6211 windgoto(row, col + coloff);
6212 out_str(T_CE); /* clear rest of this screen line */
6213 screen_start(); /* don't know where cursor is now */
6214 force = TRUE; /* force redraw of rest of the line */
6215 redraw_next = TRUE; /* or else next char would miss out */
6216
6217 /*
6218 * If the previous character was highlighted, need to stop
6219 * highlighting at this character.
6220 */
6221 if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
6222 {
6223 screen_attr = ScreenAttrs[off_to - 1];
6224 term_windgoto(row, col + coloff);
6225 screen_stop_highlight();
6226 }
6227 else
6228 screen_attr = 0; /* highlighting has stopped */
6229 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006230 if (enc_dbcs != 0)
6231 {
6232 /* Check if overwriting a double-byte with a single-byte or
6233 * the other way around requires another character to be
6234 * redrawn. For UTF-8 this isn't needed, because comparing
6235 * ScreenLinesUC[] is sufficient. */
6236 if (char_cells == 1
6237 && col + 1 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00006238 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239 {
6240 /* Writing a single-cell character over a double-cell
6241 * character: need to redraw the next cell. */
6242 ScreenLines[off_to + 1] = 0;
6243 redraw_next = TRUE;
6244 }
6245 else if (char_cells == 2
6246 && col + 2 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00006247 && (*mb_off2cells)(off_to, max_off_to) == 1
6248 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249 {
6250 /* Writing the second half of a double-cell character over
6251 * a double-cell character: need to redraw the second
6252 * cell. */
6253 ScreenLines[off_to + 2] = 0;
6254 redraw_next = TRUE;
6255 }
6256
6257 if (enc_dbcs == DBCS_JPNU)
6258 ScreenLines2[off_to] = ScreenLines2[off_from];
6259 }
6260 /* When writing a single-width character over a double-width
6261 * character and at the end of the redrawn text, need to clear out
6262 * the right halve of the old character.
6263 * Also required when writing the right halve of a double-width
6264 * char over the left halve of an existing one. */
6265 if (has_mbyte && col + char_cells == endcol
6266 && ((char_cells == 1
Bram Moolenaar367329b2007-08-30 11:53:22 +00006267 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006268 || (char_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00006269 && (*mb_off2cells)(off_to, max_off_to) == 1
6270 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006271 clear_next = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272
6273 ScreenLines[off_to] = ScreenLines[off_from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006274 if (enc_utf8)
6275 {
6276 ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
6277 if (ScreenLinesUC[off_from] != 0)
6278 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006279 int i;
6280
6281 for (i = 0; i < Screen_mco; ++i)
6282 ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006283 }
6284 }
6285 if (char_cells == 2)
6286 ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006287
6288#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006289 /* The bold trick makes a single column of pixels appear in the
6290 * next character. When a bold character is removed, the next
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 * character should be redrawn too. This happens for our own GUI
6292 * and for some xterms. */
6293 if (
6294# ifdef FEAT_GUI
6295 gui.in_use
6296# endif
6297# if defined(FEAT_GUI) && defined(UNIX)
6298 ||
6299# endif
6300# ifdef UNIX
6301 term_is_xterm
6302# endif
6303 )
6304 {
6305 hl = ScreenAttrs[off_to];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00006306 if (hl > HL_ALL)
6307 hl = syn_attr2attr(hl);
6308 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309 redraw_next = TRUE;
6310 }
6311#endif
6312 ScreenAttrs[off_to] = ScreenAttrs[off_from];
Bram Moolenaara12a1612019-01-24 16:39:02 +01006313
Bram Moolenaar910f66f2006-04-05 20:41:53 +00006314 /* For simplicity set the attributes of second half of a
6315 * double-wide character equal to the first half. */
6316 if (char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006317 ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
Bram Moolenaar910f66f2006-04-05 20:41:53 +00006318
6319 if (enc_dbcs != 0 && char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006320 screen_char_2(off_to, row, col + coloff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006321 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006322 screen_char(off_to, row, col + coloff);
6323 }
6324 else if ( p_wiv
6325#ifdef FEAT_GUI
6326 && !gui.in_use
6327#endif
6328 && col + coloff > 0)
6329 {
6330 if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
6331 {
6332 /*
6333 * Don't output stop-highlight when moving the cursor, it will
6334 * stop the highlighting when it should continue.
6335 */
6336 screen_attr = 0;
6337 }
6338 else if (screen_attr != 0)
6339 screen_stop_highlight();
6340 }
6341
6342 off_to += CHAR_CELLS;
6343 off_from += CHAR_CELLS;
6344 col += CHAR_CELLS;
6345 }
6346
Bram Moolenaar071d4272004-06-13 20:20:40 +00006347 if (clear_next)
6348 {
6349 /* Clear the second half of a double-wide character of which the left
6350 * half was overwritten with a single-wide character. */
6351 ScreenLines[off_to] = ' ';
6352 if (enc_utf8)
6353 ScreenLinesUC[off_to] = 0;
6354 screen_char(off_to, row, col + coloff);
6355 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006356
6357 if (clear_width > 0
6358#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006359 && !(flags & SLF_RIGHTLEFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006360#endif
6361 )
6362 {
6363#ifdef FEAT_GUI
6364 int startCol = col;
6365#endif
6366
6367 /* blank out the rest of the line */
6368 while (col < clear_width && ScreenLines[off_to] == ' '
6369 && ScreenAttrs[off_to] == 0
Bram Moolenaara12a1612019-01-24 16:39:02 +01006370 && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006371 {
6372 ++off_to;
6373 ++col;
6374 }
6375 if (col < clear_width)
6376 {
6377#ifdef FEAT_GUI
6378 /*
6379 * In the GUI, clearing the rest of the line may leave pixels
6380 * behind if the first character cleared was bold. Some bold
6381 * fonts spill over the left. In this case we redraw the previous
6382 * character too. If we didn't skip any blanks above, then we
6383 * only redraw if the character wasn't already redrawn anyway.
6384 */
Bram Moolenaar9c697322006-10-09 20:11:17 +00006385 if (gui.in_use && (col > startCol || !redraw_this))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006386 {
6387 hl = ScreenAttrs[off_to];
6388 if (hl > HL_ALL || (hl & HL_BOLD))
Bram Moolenaar9c697322006-10-09 20:11:17 +00006389 {
6390 int prev_cells = 1;
Bram Moolenaara12a1612019-01-24 16:39:02 +01006391
Bram Moolenaar9c697322006-10-09 20:11:17 +00006392 if (enc_utf8)
6393 /* for utf-8, ScreenLines[char_offset + 1] == 0 means
6394 * that its width is 2. */
6395 prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
6396 else if (enc_dbcs != 0)
6397 {
6398 /* find previous character by counting from first
6399 * column and get its width. */
6400 unsigned off = LineOffset[row];
Bram Moolenaar367329b2007-08-30 11:53:22 +00006401 unsigned max_off = LineOffset[row] + screen_Columns;
Bram Moolenaar9c697322006-10-09 20:11:17 +00006402
6403 while (off < off_to)
6404 {
Bram Moolenaar367329b2007-08-30 11:53:22 +00006405 prev_cells = (*mb_off2cells)(off, max_off);
Bram Moolenaar9c697322006-10-09 20:11:17 +00006406 off += prev_cells;
6407 }
6408 }
6409
6410 if (enc_dbcs != 0 && prev_cells > 1)
6411 screen_char_2(off_to - prev_cells, row,
6412 col + coloff - prev_cells);
6413 else
Bram Moolenaar9c697322006-10-09 20:11:17 +00006414 screen_char(off_to - prev_cells, row,
6415 col + coloff - prev_cells);
6416 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006417 }
6418#endif
6419 screen_fill(row, row + 1, col + coloff, clear_width + coloff,
6420 ' ', ' ', 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006421 off_to += clear_width - col;
6422 col = clear_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006423 }
6424 }
6425
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006426 if (clear_width > 0
6427#ifdef FEAT_TEXT_PROP
6428 && !(flags & SLF_POPUP) // no separator for popup window
6429#endif
6430 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006432 // For a window that has a right neighbor, draw the separator char
Bram Moolenaaraef5c622019-06-08 17:25:33 +02006433 // right of the window contents. But not on top of a popup window.
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006434 if (coloff + col < Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435 {
Bram Moolenaaraef5c622019-06-08 17:25:33 +02006436#ifdef FEAT_TEXT_PROP
Bram Moolenaarc662ec92019-06-23 00:15:57 +02006437 if (!blocked_by_popup(row, col + coloff))
Bram Moolenaaraef5c622019-06-08 17:25:33 +02006438#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006439 {
Bram Moolenaaraef5c622019-06-08 17:25:33 +02006440 int c;
6441
6442 c = fillchar_vsep(&hl);
6443 if (ScreenLines[off_to] != (schar_T)c
6444 || (enc_utf8 && (int)ScreenLinesUC[off_to]
6445 != (c >= 0x80 ? c : 0))
6446 || ScreenAttrs[off_to] != hl)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006447 {
Bram Moolenaaraef5c622019-06-08 17:25:33 +02006448 ScreenLines[off_to] = c;
6449 ScreenAttrs[off_to] = hl;
6450 if (enc_utf8)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006451 {
Bram Moolenaaraef5c622019-06-08 17:25:33 +02006452 if (c >= 0x80)
6453 {
6454 ScreenLinesUC[off_to] = c;
6455 ScreenLinesC[0][off_to] = 0;
6456 }
6457 else
6458 ScreenLinesUC[off_to] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006459 }
Bram Moolenaaraef5c622019-06-08 17:25:33 +02006460 screen_char(off_to, row, col + coloff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006461 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006462 }
6463 }
6464 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006465 LineWraps[row] = FALSE;
6466 }
6467}
6468
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006469#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006470/*
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006471 * Mirror text "str" for right-left displaying.
6472 * Only works for single-byte characters (e.g., numbers).
Bram Moolenaar071d4272004-06-13 20:20:40 +00006473 */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006474 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006475rl_mirror(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006476{
6477 char_u *p1, *p2;
6478 int t;
6479
6480 for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
6481 {
6482 t = *p1;
6483 *p1 = *p2;
6484 *p2 = t;
6485 }
6486}
6487#endif
6488
Bram Moolenaar071d4272004-06-13 20:20:40 +00006489/*
6490 * mark all status lines for redraw; used after first :cd
6491 */
6492 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006493status_redraw_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006494{
6495 win_T *wp;
6496
Bram Moolenaar29323592016-07-24 22:04:11 +02006497 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006498 if (wp->w_status_height)
6499 {
6500 wp->w_redr_status = TRUE;
6501 redraw_later(VALID);
6502 }
6503}
6504
6505/*
6506 * mark all status lines of the current buffer for redraw
6507 */
6508 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006509status_redraw_curbuf(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006510{
6511 win_T *wp;
6512
Bram Moolenaar29323592016-07-24 22:04:11 +02006513 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006514 if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
6515 {
6516 wp->w_redr_status = TRUE;
6517 redraw_later(VALID);
6518 }
6519}
6520
6521/*
6522 * Redraw all status lines that need to be redrawn.
6523 */
6524 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006525redraw_statuslines(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006526{
6527 win_T *wp;
6528
Bram Moolenaar29323592016-07-24 22:04:11 +02006529 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006530 if (wp->w_redr_status)
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006531 win_redr_status(wp, FALSE);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00006532 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006533 draw_tabline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006534}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006535
Bram Moolenaar4033c552017-09-16 20:54:51 +02006536#if defined(FEAT_WILDMENU) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006537/*
6538 * Redraw all status lines at the bottom of frame "frp".
6539 */
6540 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006541win_redraw_last_status(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006542{
6543 if (frp->fr_layout == FR_LEAF)
6544 frp->fr_win->w_redr_status = TRUE;
6545 else if (frp->fr_layout == FR_ROW)
6546 {
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01006547 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006548 win_redraw_last_status(frp);
6549 }
6550 else /* frp->fr_layout == FR_COL */
6551 {
6552 frp = frp->fr_child;
6553 while (frp->fr_next != NULL)
6554 frp = frp->fr_next;
6555 win_redraw_last_status(frp);
6556 }
6557}
6558#endif
6559
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560/*
6561 * Draw the verticap separator right of window "wp" starting with line "row".
6562 */
6563 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01006564draw_vsep_win(win_T *wp, int row)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006565{
6566 int hl;
6567 int c;
6568
6569 if (wp->w_vsep_width)
6570 {
6571 /* draw the vertical separator right of this window */
6572 c = fillchar_vsep(&hl);
6573 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
6574 W_ENDCOL(wp), W_ENDCOL(wp) + 1,
6575 c, ' ', hl);
6576 }
6577}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006578
6579#ifdef FEAT_WILDMENU
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01006580static int skip_status_match_char(expand_T *xp, char_u *s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006581
6582/*
Bram Moolenaar367329b2007-08-30 11:53:22 +00006583 * Get the length of an item as it will be shown in the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006584 */
6585 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006586status_match_len(expand_T *xp, char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006587{
6588 int len = 0;
6589
6590#ifdef FEAT_MENU
6591 int emenu = (xp->xp_context == EXPAND_MENUS
6592 || xp->xp_context == EXPAND_MENUNAMES);
6593
6594 /* Check for menu separators - replace with '|'. */
6595 if (emenu && menu_is_separator(s))
6596 return 1;
6597#endif
6598
6599 while (*s != NUL)
6600 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006601 s += skip_status_match_char(xp, s);
Bram Moolenaar81695252004-12-29 20:58:21 +00006602 len += ptr2cells(s);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006603 MB_PTR_ADV(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006604 }
6605
6606 return len;
6607}
6608
6609/*
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006610 * Return the number of characters that should be skipped in a status match.
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006611 * These are backslashes used for escaping. Do show backslashes in help tags.
6612 */
6613 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006614skip_status_match_char(expand_T *xp, char_u *s)
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006615{
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006616 if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006617#ifdef FEAT_MENU
6618 || ((xp->xp_context == EXPAND_MENUS
6619 || xp->xp_context == EXPAND_MENUNAMES)
6620 && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
6621#endif
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006622 )
6623 {
6624#ifndef BACKSLASH_IN_FILENAME
6625 if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
6626 return 2;
6627#endif
6628 return 1;
6629 }
6630 return 0;
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006631}
6632
6633/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006634 * Show wildchar matches in the status line.
6635 * Show at least the "match" item.
6636 * We start at item 'first_match' in the list and show all matches that fit.
6637 *
6638 * If inversion is possible we use it. Else '=' characters are used.
6639 */
6640 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006641win_redr_status_matches(
6642 expand_T *xp,
6643 int num_matches,
6644 char_u **matches, /* list of matches */
6645 int match,
6646 int showtail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006647{
6648#define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
6649 int row;
6650 char_u *buf;
6651 int len;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006652 int clen; /* length in screen cells */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006653 int fillchar;
6654 int attr;
6655 int i;
6656 int highlight = TRUE;
6657 char_u *selstart = NULL;
6658 int selstart_col = 0;
6659 char_u *selend = NULL;
6660 static int first_match = 0;
6661 int add_left = FALSE;
6662 char_u *s;
6663#ifdef FEAT_MENU
6664 int emenu;
6665#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006666 int l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006667
6668 if (matches == NULL) /* interrupted completion? */
6669 return;
6670
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006671 if (has_mbyte)
Bram Moolenaar964b3742019-05-24 18:54:09 +02006672 buf = alloc(Columns * MB_MAXBYTES + 1);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006673 else
Bram Moolenaar964b3742019-05-24 18:54:09 +02006674 buf = alloc(Columns + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006675 if (buf == NULL)
6676 return;
6677
6678 if (match == -1) /* don't show match but original text */
6679 {
6680 match = 0;
6681 highlight = FALSE;
6682 }
6683 /* count 1 for the ending ">" */
6684 clen = status_match_len(xp, L_MATCH(match)) + 3;
6685 if (match == 0)
6686 first_match = 0;
6687 else if (match < first_match)
6688 {
6689 /* jumping left, as far as we can go */
6690 first_match = match;
6691 add_left = TRUE;
6692 }
6693 else
6694 {
6695 /* check if match fits on the screen */
6696 for (i = first_match; i < match; ++i)
6697 clen += status_match_len(xp, L_MATCH(i)) + 2;
6698 if (first_match > 0)
6699 clen += 2;
6700 /* jumping right, put match at the left */
6701 if ((long)clen > Columns)
6702 {
6703 first_match = match;
6704 /* if showing the last match, we can add some on the left */
6705 clen = 2;
6706 for (i = match; i < num_matches; ++i)
6707 {
6708 clen += status_match_len(xp, L_MATCH(i)) + 2;
6709 if ((long)clen >= Columns)
6710 break;
6711 }
6712 if (i == num_matches)
6713 add_left = TRUE;
6714 }
6715 }
6716 if (add_left)
6717 while (first_match > 0)
6718 {
6719 clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
6720 if ((long)clen >= Columns)
6721 break;
6722 --first_match;
6723 }
6724
Bram Moolenaar3633cf52017-07-31 22:29:35 +02006725 fillchar = fillchar_status(&attr, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006726
6727 if (first_match == 0)
6728 {
6729 *buf = NUL;
6730 len = 0;
6731 }
6732 else
6733 {
6734 STRCPY(buf, "< ");
6735 len = 2;
6736 }
6737 clen = len;
6738
6739 i = first_match;
6740 while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
6741 {
6742 if (i == match)
6743 {
6744 selstart = buf + len;
6745 selstart_col = clen;
6746 }
6747
6748 s = L_MATCH(i);
6749 /* Check for menu separators - replace with '|' */
6750#ifdef FEAT_MENU
6751 emenu = (xp->xp_context == EXPAND_MENUS
6752 || xp->xp_context == EXPAND_MENUNAMES);
6753 if (emenu && menu_is_separator(s))
6754 {
6755 STRCPY(buf + len, transchar('|'));
6756 l = (int)STRLEN(buf + len);
6757 len += l;
6758 clen += l;
6759 }
6760 else
6761#endif
6762 for ( ; *s != NUL; ++s)
6763 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006764 s += skip_status_match_char(xp, s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006765 clen += ptr2cells(s);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006766 if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006767 {
6768 STRNCPY(buf + len, s, l);
6769 s += l - 1;
6770 len += l;
6771 }
6772 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006773 {
6774 STRCPY(buf + len, transchar_byte(*s));
6775 len += (int)STRLEN(buf + len);
6776 }
6777 }
6778 if (i == match)
6779 selend = buf + len;
6780
6781 *(buf + len++) = ' ';
6782 *(buf + len++) = ' ';
6783 clen += 2;
6784 if (++i == num_matches)
6785 break;
6786 }
6787
6788 if (i != num_matches)
6789 {
6790 *(buf + len++) = '>';
6791 ++clen;
6792 }
6793
6794 buf[len] = NUL;
6795
6796 row = cmdline_row - 1;
6797 if (row >= 0)
6798 {
6799 if (wild_menu_showing == 0)
6800 {
6801 if (msg_scrolled > 0)
6802 {
6803 /* Put the wildmenu just above the command line. If there is
6804 * no room, scroll the screen one line up. */
6805 if (cmdline_row == Rows - 1)
6806 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02006807 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006808 ++msg_scrolled;
6809 }
6810 else
6811 {
6812 ++cmdline_row;
6813 ++row;
6814 }
6815 wild_menu_showing = WM_SCROLLED;
6816 }
6817 else
6818 {
6819 /* Create status line if needed by setting 'laststatus' to 2.
6820 * Set 'winminheight' to zero to avoid that the window is
6821 * resized. */
6822 if (lastwin->w_status_height == 0)
6823 {
6824 save_p_ls = p_ls;
6825 save_p_wmh = p_wmh;
6826 p_ls = 2;
6827 p_wmh = 0;
6828 last_status(FALSE);
6829 }
6830 wild_menu_showing = WM_SHOWN;
6831 }
6832 }
6833
6834 screen_puts(buf, row, 0, attr);
6835 if (selstart != NULL && highlight)
6836 {
6837 *selend = NUL;
Bram Moolenaar8820b482017-03-16 17:23:31 +01006838 screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006839 }
6840
6841 screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
6842 }
6843
Bram Moolenaar071d4272004-06-13 20:20:40 +00006844 win_redraw_last_status(topframe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006845 vim_free(buf);
6846}
6847#endif
6848
Bram Moolenaar071d4272004-06-13 20:20:40 +00006849/*
6850 * Redraw the status line of window wp.
6851 *
6852 * If inversion is possible we use it. Else '=' characters are used.
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006853 * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is
6854 * displayed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006855 */
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006856 static void
Bram Moolenaar829adb72018-06-24 19:24:03 +02006857win_redr_status(win_T *wp, int ignore_pum UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006858{
6859 int row;
6860 char_u *p;
6861 int len;
6862 int fillchar;
6863 int attr;
6864 int this_ru_col;
Bram Moolenaaradb09c22009-06-16 15:22:12 +00006865 static int busy = FALSE;
6866
6867 /* It's possible to get here recursively when 'statusline' (indirectly)
6868 * invokes ":redrawstatus". Simply ignore the call then. */
6869 if (busy)
6870 return;
6871 busy = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006872
6873 wp->w_redr_status = FALSE;
6874 if (wp->w_status_height == 0)
6875 {
6876 /* no status line, can only be last window */
6877 redraw_cmdline = TRUE;
6878 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00006879 else if (!redrawing()
6880#ifdef FEAT_INS_EXPAND
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006881 // don't update status line when popup menu is visible and may be
6882 // drawn over it, unless it will be redrawn later
6883 || (!ignore_pum && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00006884#endif
6885 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006886 {
6887 /* Don't redraw right now, do it later. */
6888 wp->w_redr_status = TRUE;
6889 }
6890#ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006891 else if (*p_stl != NUL || *wp->w_p_stl != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006892 {
6893 /* redraw custom status line */
Bram Moolenaar362f3562009-11-03 16:20:34 +00006894 redraw_custom_statusline(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006895 }
6896#endif
6897 else
6898 {
Bram Moolenaar3633cf52017-07-31 22:29:35 +02006899 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006900
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006901 get_trans_bufname(wp->w_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006902 p = NameBuff;
6903 len = (int)STRLEN(p);
6904
Bram Moolenaard85f2712017-07-28 21:51:57 +02006905 if (bt_help(wp->w_buffer)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006906#ifdef FEAT_QUICKFIX
6907 || wp->w_p_pvw
6908#endif
6909 || bufIsChanged(wp->w_buffer)
6910 || wp->w_buffer->b_p_ro)
6911 *(p + len++) = ' ';
Bram Moolenaard85f2712017-07-28 21:51:57 +02006912 if (bt_help(wp->w_buffer))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006913 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +00006914 STRCPY(p + len, _("[Help]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006915 len += (int)STRLEN(p + len);
6916 }
6917#ifdef FEAT_QUICKFIX
6918 if (wp->w_p_pvw)
6919 {
6920 STRCPY(p + len, _("[Preview]"));
6921 len += (int)STRLEN(p + len);
6922 }
6923#endif
Bram Moolenaar086d5352017-08-05 18:19:55 +02006924 if (bufIsChanged(wp->w_buffer)
6925#ifdef FEAT_TERMINAL
6926 && !bt_terminal(wp->w_buffer)
6927#endif
6928 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006929 {
6930 STRCPY(p + len, "[+]");
6931 len += 3;
6932 }
6933 if (wp->w_buffer->b_p_ro)
6934 {
Bram Moolenaar23584032013-06-07 20:17:11 +02006935 STRCPY(p + len, _("[RO]"));
Bram Moolenaar3457d292017-02-23 14:55:59 +01006936 len += (int)STRLEN(p + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006937 }
6938
Bram Moolenaar02631462017-09-22 15:20:32 +02006939 this_ru_col = ru_col - (Columns - wp->w_width);
6940 if (this_ru_col < (wp->w_width + 1) / 2)
6941 this_ru_col = (wp->w_width + 1) / 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006942 if (this_ru_col <= 1)
6943 {
6944 p = (char_u *)"<"; /* No room for file name! */
6945 len = 1;
6946 }
Bram Moolenaara12a1612019-01-24 16:39:02 +01006947 else if (has_mbyte)
6948 {
6949 int clen = 0, i;
6950
6951 /* Count total number of display cells. */
6952 clen = mb_string2cells(p, -1);
6953
6954 /* Find first character that will fit.
6955 * Going from start to end is much faster for DBCS. */
6956 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
6957 i += (*mb_ptr2len)(p + i))
6958 clen -= (*mb_ptr2cells)(p + i);
6959 len = clen;
6960 if (i > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 {
Bram Moolenaara12a1612019-01-24 16:39:02 +01006962 p = p + i - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006963 *p = '<';
Bram Moolenaara12a1612019-01-24 16:39:02 +01006964 ++len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006965 }
6966
Bram Moolenaara12a1612019-01-24 16:39:02 +01006967 }
6968 else if (len > this_ru_col - 1)
6969 {
6970 p += len - (this_ru_col - 1);
6971 *p = '<';
6972 len = this_ru_col - 1;
6973 }
6974
Bram Moolenaar071d4272004-06-13 20:20:40 +00006975 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar53f81742017-09-22 14:35:51 +02006976 screen_puts(p, row, wp->w_wincol, attr);
6977 screen_fill(row, row + 1, len + wp->w_wincol,
6978 this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006979
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02006980 if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006981 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
6982 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
Bram Moolenaar53f81742017-09-22 14:35:51 +02006983 - 1 + wp->w_wincol), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006984
6985#ifdef FEAT_CMDL_INFO
Bram Moolenaar491ac282018-06-17 14:47:55 +02006986 win_redr_ruler(wp, TRUE, ignore_pum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006987#endif
6988 }
6989
Bram Moolenaar071d4272004-06-13 20:20:40 +00006990 /*
6991 * May need to draw the character below the vertical separator.
6992 */
6993 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
6994 {
6995 if (stl_connected(wp))
Bram Moolenaar3633cf52017-07-31 22:29:35 +02006996 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006997 else
6998 fillchar = fillchar_vsep(&attr);
6999 screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
7000 attr);
7001 }
Bram Moolenaaradb09c22009-06-16 15:22:12 +00007002 busy = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003}
7004
Bram Moolenaar238a5642006-02-21 22:12:05 +00007005#ifdef FEAT_STL_OPT
7006/*
7007 * Redraw the status line according to 'statusline' and take care of any
7008 * errors encountered.
7009 */
7010 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007011redraw_custom_statusline(win_T *wp)
Bram Moolenaar238a5642006-02-21 22:12:05 +00007012{
Bram Moolenaar362f3562009-11-03 16:20:34 +00007013 static int entered = FALSE;
Bram Moolenaara742e082016-04-05 21:10:38 +02007014 int saved_did_emsg = did_emsg;
Bram Moolenaar362f3562009-11-03 16:20:34 +00007015
7016 /* When called recursively return. This can happen when the statusline
7017 * contains an expression that triggers a redraw. */
7018 if (entered)
7019 return;
7020 entered = TRUE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007021
Bram Moolenaara742e082016-04-05 21:10:38 +02007022 did_emsg = FALSE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007023 win_redr_custom(wp, FALSE);
Bram Moolenaara742e082016-04-05 21:10:38 +02007024 if (did_emsg)
Bram Moolenaar362f3562009-11-03 16:20:34 +00007025 {
7026 /* When there is an error disable the statusline, otherwise the
7027 * display is messed up with errors and a redraw triggers the problem
7028 * again and again. */
Bram Moolenaar238a5642006-02-21 22:12:05 +00007029 set_string_option_direct((char_u *)"statusline", -1,
7030 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007031 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
Bram Moolenaar362f3562009-11-03 16:20:34 +00007032 }
Bram Moolenaara742e082016-04-05 21:10:38 +02007033 did_emsg |= saved_did_emsg;
Bram Moolenaar362f3562009-11-03 16:20:34 +00007034 entered = FALSE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007035}
7036#endif
7037
Bram Moolenaar071d4272004-06-13 20:20:40 +00007038/*
7039 * Return TRUE if the status line of window "wp" is connected to the status
7040 * line of the window right of it. If not, then it's a vertical separator.
7041 * Only call if (wp->w_vsep_width != 0).
7042 */
7043 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007044stl_connected(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007045{
7046 frame_T *fr;
7047
7048 fr = wp->w_frame;
7049 while (fr->fr_parent != NULL)
7050 {
7051 if (fr->fr_parent->fr_layout == FR_COL)
7052 {
7053 if (fr->fr_next != NULL)
7054 break;
7055 }
7056 else
7057 {
7058 if (fr->fr_next != NULL)
7059 return TRUE;
7060 }
7061 fr = fr->fr_parent;
7062 }
7063 return FALSE;
7064}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007065
Bram Moolenaar071d4272004-06-13 20:20:40 +00007066
Bram Moolenaar071d4272004-06-13 20:20:40 +00007067/*
7068 * Get the value to show for the language mappings, active 'keymap'.
7069 */
7070 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007071get_keymap_str(
7072 win_T *wp,
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02007073 char_u *fmt, /* format string containing one %s item */
Bram Moolenaar05540972016-01-30 20:31:25 +01007074 char_u *buf, /* buffer for the result */
7075 int len) /* length of buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007076{
7077 char_u *p;
7078
7079 if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
7080 return FALSE;
7081
7082 {
7083#ifdef FEAT_EVAL
7084 buf_T *old_curbuf = curbuf;
7085 win_T *old_curwin = curwin;
7086 char_u *s;
7087
7088 curbuf = wp->w_buffer;
7089 curwin = wp;
7090 STRCPY(buf, "b:keymap_name"); /* must be writable */
7091 ++emsg_skip;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007092 s = p = eval_to_string(buf, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007093 --emsg_skip;
7094 curbuf = old_curbuf;
7095 curwin = old_curwin;
7096 if (p == NULL || *p == NUL)
7097#endif
7098 {
7099#ifdef FEAT_KEYMAP
7100 if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
7101 p = wp->w_buffer->b_p_keymap;
7102 else
7103#endif
7104 p = (char_u *)"lang";
7105 }
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02007106 if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007107 buf[0] = NUL;
7108#ifdef FEAT_EVAL
7109 vim_free(s);
7110#endif
7111 }
7112 return buf[0] != NUL;
7113}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007114
7115#if defined(FEAT_STL_OPT) || defined(PROTO)
7116/*
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007117 * Redraw the status line or ruler of window "wp".
7118 * When "wp" is NULL redraw the tab pages line from 'tabline'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007119 */
7120 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007121win_redr_custom(
7122 win_T *wp,
7123 int draw_ruler) /* TRUE or FALSE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007124{
Bram Moolenaar1d633412013-12-11 15:52:01 +01007125 static int entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126 int attr;
7127 int curattr;
7128 int row;
7129 int col = 0;
7130 int maxwidth;
7131 int width;
7132 int n;
7133 int len;
7134 int fillchar;
7135 char_u buf[MAXPATHL];
Bram Moolenaar362f3562009-11-03 16:20:34 +00007136 char_u *stl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007137 char_u *p;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007138 struct stl_hlrec hltab[STL_MAX_ITEM];
7139 struct stl_hlrec tabtab[STL_MAX_ITEM];
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007140 int use_sandbox = FALSE;
Bram Moolenaar61452852011-02-01 18:01:11 +01007141 win_T *ewp;
7142 int p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007143
Bram Moolenaar1d633412013-12-11 15:52:01 +01007144 /* There is a tiny chance that this gets called recursively: When
7145 * redrawing a status line triggers redrawing the ruler or tabline.
7146 * Avoid trouble by not allowing recursion. */
7147 if (entered)
7148 return;
7149 entered = TRUE;
7150
Bram Moolenaar071d4272004-06-13 20:20:40 +00007151 /* setup environment for the task at hand */
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007152 if (wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007153 {
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007154 /* Use 'tabline'. Always at the first line of the screen. */
Bram Moolenaar362f3562009-11-03 16:20:34 +00007155 stl = p_tal;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007156 row = 0;
Bram Moolenaar65c923a2006-03-03 22:56:30 +00007157 fillchar = ' ';
Bram Moolenaar8820b482017-03-16 17:23:31 +01007158 attr = HL_ATTR(HLF_TPF);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007159 maxwidth = Columns;
7160# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007161 use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007162# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007163 }
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007164 else
7165 {
7166 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar3633cf52017-07-31 22:29:35 +02007167 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar02631462017-09-22 15:20:32 +02007168 maxwidth = wp->w_width;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007169
7170 if (draw_ruler)
7171 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00007172 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007173 /* advance past any leading group spec - implicit in ru_col */
Bram Moolenaar362f3562009-11-03 16:20:34 +00007174 if (*stl == '%')
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007175 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00007176 if (*++stl == '-')
7177 stl++;
7178 if (atoi((char *)stl))
7179 while (VIM_ISDIGIT(*stl))
7180 stl++;
7181 if (*stl++ != '(')
7182 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007183 }
Bram Moolenaar02631462017-09-22 15:20:32 +02007184 col = ru_col - (Columns - wp->w_width);
7185 if (col < (wp->w_width + 1) / 2)
7186 col = (wp->w_width + 1) / 2;
7187 maxwidth = wp->w_width - col;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007188 if (!wp->w_status_height)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007189 {
7190 row = Rows - 1;
7191 --maxwidth; /* writing in last column may cause scrolling */
7192 fillchar = ' ';
7193 attr = 0;
7194 }
7195
7196# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007197 use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007198# endif
7199 }
7200 else
7201 {
7202 if (*wp->w_p_stl != NUL)
Bram Moolenaar362f3562009-11-03 16:20:34 +00007203 stl = wp->w_p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007204 else
Bram Moolenaar362f3562009-11-03 16:20:34 +00007205 stl = p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007206# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007207 use_sandbox = was_set_insecurely((char_u *)"statusline",
7208 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007209# endif
7210 }
7211
Bram Moolenaar53f81742017-09-22 14:35:51 +02007212 col += wp->w_wincol;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007213 }
7214
Bram Moolenaar071d4272004-06-13 20:20:40 +00007215 if (maxwidth <= 0)
Bram Moolenaar1d633412013-12-11 15:52:01 +01007216 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007217
Bram Moolenaar61452852011-02-01 18:01:11 +01007218 /* Temporarily reset 'cursorbind', we don't want a side effect from moving
7219 * the cursor away and back. */
7220 ewp = wp == NULL ? curwin : wp;
7221 p_crb_save = ewp->w_p_crb;
7222 ewp->w_p_crb = FALSE;
7223
Bram Moolenaar362f3562009-11-03 16:20:34 +00007224 /* Make a copy, because the statusline may include a function call that
7225 * might change the option value and free the memory. */
7226 stl = vim_strsave(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01007227 width = build_stl_str_hl(ewp, buf, sizeof(buf),
Bram Moolenaar362f3562009-11-03 16:20:34 +00007228 stl, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007229 fillchar, maxwidth, hltab, tabtab);
Bram Moolenaar362f3562009-11-03 16:20:34 +00007230 vim_free(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01007231 ewp->w_p_crb = p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007232
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01007233 /* Make all characters printable. */
7234 p = transstr(buf);
7235 if (p != NULL)
7236 {
7237 vim_strncpy(buf, p, sizeof(buf) - 1);
7238 vim_free(p);
7239 }
7240
7241 /* fill up with "fillchar" */
7242 len = (int)STRLEN(buf);
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007243 while (width < maxwidth && len < (int)sizeof(buf) - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007244 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007245 len += (*mb_char2bytes)(fillchar, buf + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007246 ++width;
7247 }
7248 buf[len] = NUL;
7249
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007250 /*
7251 * Draw each snippet with the specified highlighting.
7252 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007253 curattr = attr;
7254 p = buf;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007255 for (n = 0; hltab[n].start != NULL; n++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007256 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007257 len = (int)(hltab[n].start - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007258 screen_puts_len(p, len, row, col, curattr);
7259 col += vim_strnsize(p, len);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007260 p = hltab[n].start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007261
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007262 if (hltab[n].userhl == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007263 curattr = attr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007264 else if (hltab[n].userhl < 0)
7265 curattr = syn_id2attr(-hltab[n].userhl);
Bram Moolenaar4033c552017-09-16 20:54:51 +02007266#ifdef FEAT_TERMINAL
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02007267 else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
7268 && wp->w_status_height != 0)
7269 curattr = highlight_stltermnc[hltab[n].userhl - 1];
Bram Moolenaarbce4f622017-08-13 21:37:43 +02007270 else if (wp != NULL && bt_terminal(wp->w_buffer)
7271 && wp->w_status_height != 0)
7272 curattr = highlight_stlterm[hltab[n].userhl - 1];
Bram Moolenaar4033c552017-09-16 20:54:51 +02007273#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +00007274 else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007275 curattr = highlight_stlnc[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007276 else
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007277 curattr = highlight_user[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007278 }
7279 screen_puts(p, row, col, curattr);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007280
7281 if (wp == NULL)
7282 {
7283 /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */
7284 col = 0;
7285 len = 0;
7286 p = buf;
7287 fillchar = 0;
7288 for (n = 0; tabtab[n].start != NULL; n++)
7289 {
7290 len += vim_strnsize(p, (int)(tabtab[n].start - p));
7291 while (col < len)
7292 TabPageIdxs[col++] = fillchar;
7293 p = tabtab[n].start;
7294 fillchar = tabtab[n].userhl;
7295 }
7296 while (col < Columns)
7297 TabPageIdxs[col++] = fillchar;
7298 }
Bram Moolenaar1d633412013-12-11 15:52:01 +01007299
7300theend:
7301 entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007302}
7303
7304#endif /* FEAT_STL_OPT */
7305
7306/*
7307 * Output a single character directly to the screen and update ScreenLines.
7308 */
7309 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007310screen_putchar(int c, int row, int col, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007311{
Bram Moolenaar071d4272004-06-13 20:20:40 +00007312 char_u buf[MB_MAXBYTES + 1];
7313
Bram Moolenaar9a920d82012-06-01 15:21:02 +02007314 if (has_mbyte)
7315 buf[(*mb_char2bytes)(c, buf)] = NUL;
7316 else
Bram Moolenaar9a920d82012-06-01 15:21:02 +02007317 {
7318 buf[0] = c;
7319 buf[1] = NUL;
7320 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007321 screen_puts(buf, row, col, attr);
7322}
7323
7324/*
7325 * Get a single character directly from ScreenLines into "bytes[]".
7326 * Also return its attribute in *attrp;
7327 */
7328 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007329screen_getbytes(int row, int col, char_u *bytes, int *attrp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007330{
7331 unsigned off;
7332
7333 /* safety check */
7334 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
7335 {
7336 off = LineOffset[row] + col;
7337 *attrp = ScreenAttrs[off];
7338 bytes[0] = ScreenLines[off];
7339 bytes[1] = NUL;
7340
Bram Moolenaar071d4272004-06-13 20:20:40 +00007341 if (enc_utf8 && ScreenLinesUC[off] != 0)
7342 bytes[utfc_char2bytes(off, bytes)] = NUL;
7343 else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
7344 {
7345 bytes[0] = ScreenLines[off];
7346 bytes[1] = ScreenLines2[off];
7347 bytes[2] = NUL;
7348 }
7349 else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
7350 {
7351 bytes[1] = ScreenLines[off + 1];
7352 bytes[2] = NUL;
7353 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007354 }
7355}
7356
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007357/*
7358 * Return TRUE if composing characters for screen posn "off" differs from
7359 * composing characters in "u8cc".
Bram Moolenaar70c49c12010-03-23 15:36:35 +01007360 * Only to be used when ScreenLinesUC[off] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007361 */
7362 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007363screen_comp_differs(int off, int *u8cc)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007364{
7365 int i;
7366
7367 for (i = 0; i < Screen_mco; ++i)
7368 {
7369 if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
7370 return TRUE;
7371 if (u8cc[i] == 0)
7372 break;
7373 }
7374 return FALSE;
7375}
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007376
Bram Moolenaar071d4272004-06-13 20:20:40 +00007377/*
7378 * Put string '*text' on the screen at position 'row' and 'col', with
7379 * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
7380 * Note: only outputs within one row, message is truncated at screen boundary!
7381 * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
7382 */
7383 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007384screen_puts(
7385 char_u *text,
7386 int row,
7387 int col,
7388 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007389{
7390 screen_puts_len(text, -1, row, col, attr);
7391}
7392
7393/*
7394 * Like screen_puts(), but output "text[len]". When "len" is -1 output up to
7395 * a NUL.
7396 */
7397 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007398screen_puts_len(
7399 char_u *text,
7400 int textlen,
7401 int row,
7402 int col,
7403 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007404{
7405 unsigned off;
7406 char_u *ptr = text;
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007407 int len = textlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007408 int c;
Bram Moolenaar367329b2007-08-30 11:53:22 +00007409 unsigned max_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007410 int mbyte_blen = 1;
7411 int mbyte_cells = 1;
7412 int u8c = 0;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007413 int u8cc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007414 int clear_next_cell = FALSE;
Bram Moolenaara12a1612019-01-24 16:39:02 +01007415#ifdef FEAT_ARABIC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007416 int prev_c = 0; /* previous Arabic character */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007417 int pc, nc, nc1;
7418 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007419#endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007420 int force_redraw_this;
7421 int force_redraw_next = FALSE;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007422 int need_redraw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007423
Bram Moolenaar0b4c9ed2019-06-03 22:04:23 +02007424 // Safety check. The check for negative row and column is to fix issue
7425 // #4102. TODO: find out why row/col could be negative.
7426 if (ScreenLines == NULL
7427 || row >= screen_Rows || row < 0
7428 || col >= screen_Columns || col < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007429 return;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007430 off = LineOffset[row] + col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007431
Bram Moolenaarc236c162008-07-13 17:41:49 +00007432 /* When drawing over the right halve of a double-wide char clear out the
7433 * left halve. Only needed in a terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00007434 if (has_mbyte && col > 0 && col < screen_Columns
Bram Moolenaara12a1612019-01-24 16:39:02 +01007435#ifdef FEAT_GUI
Bram Moolenaarc236c162008-07-13 17:41:49 +00007436 && !gui.in_use
Bram Moolenaara12a1612019-01-24 16:39:02 +01007437#endif
Bram Moolenaarc236c162008-07-13 17:41:49 +00007438 && mb_fix_col(col, row) != col)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007439 {
7440 ScreenLines[off - 1] = ' ';
7441 ScreenAttrs[off - 1] = 0;
7442 if (enc_utf8)
7443 {
7444 ScreenLinesUC[off - 1] = 0;
7445 ScreenLinesC[0][off - 1] = 0;
7446 }
7447 /* redraw the previous cell, make it empty */
7448 screen_char(off - 1, row, col - 1);
7449 /* force the cell at "col" to be redrawn */
7450 force_redraw_next = TRUE;
7451 }
Bram Moolenaarc236c162008-07-13 17:41:49 +00007452
Bram Moolenaar367329b2007-08-30 11:53:22 +00007453 max_off = LineOffset[row] + screen_Columns;
Bram Moolenaara064ac82007-08-05 18:10:54 +00007454 while (col < screen_Columns
7455 && (len < 0 || (int)(ptr - text) < len)
7456 && *ptr != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007457 {
7458 c = *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007459 /* check if this is the first byte of a multibyte */
7460 if (has_mbyte)
7461 {
7462 if (enc_utf8 && len > 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007463 mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007464 else
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007465 mbyte_blen = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007466 if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7467 mbyte_cells = 1;
7468 else if (enc_dbcs != 0)
7469 mbyte_cells = mbyte_blen;
7470 else /* enc_utf8 */
7471 {
7472 if (len >= 0)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007473 u8c = utfc_ptr2char_len(ptr, u8cc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007474 (int)((text + len) - ptr));
7475 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007476 u8c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007477 mbyte_cells = utf_char2cells(u8c);
Bram Moolenaara12a1612019-01-24 16:39:02 +01007478#ifdef FEAT_ARABIC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007479 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
7480 {
7481 /* Do Arabic shaping. */
7482 if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
7483 {
7484 /* Past end of string to be displayed. */
7485 nc = NUL;
7486 nc1 = NUL;
7487 }
7488 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007489 {
Bram Moolenaar54620182009-11-11 16:07:20 +00007490 nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
7491 (int)((text + len) - ptr - mbyte_blen));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007492 nc1 = pcc[0];
7493 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007494 pc = prev_c;
7495 prev_c = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007496 u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007497 }
7498 else
7499 prev_c = u8c;
Bram Moolenaara12a1612019-01-24 16:39:02 +01007500#endif
Bram Moolenaare4ebd292010-01-19 17:40:46 +01007501 if (col + mbyte_cells > screen_Columns)
7502 {
7503 /* Only 1 cell left, but character requires 2 cells:
7504 * display a '>' in the last column to avoid wrapping. */
7505 c = '>';
7506 mbyte_cells = 1;
7507 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007508 }
7509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007510
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007511 force_redraw_this = force_redraw_next;
7512 force_redraw_next = FALSE;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007513
7514 need_redraw = ScreenLines[off] != c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007515 || (mbyte_cells == 2
7516 && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
7517 || (enc_dbcs == DBCS_JPNU
7518 && c == 0x8e
7519 && ScreenLines2[off] != ptr[1])
7520 || (enc_utf8
Bram Moolenaar70c49c12010-03-23 15:36:35 +01007521 && (ScreenLinesUC[off] !=
7522 (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
7523 || (ScreenLinesUC[off] != 0
7524 && screen_comp_differs(off, u8cc))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007525 || ScreenAttrs[off] != attr
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007526 || exmode_active;
7527
Bram Moolenaar24a5ac52019-06-08 19:01:18 +02007528 if ((need_redraw || force_redraw_this)
7529#ifdef FEAT_TEXT_PROP
Bram Moolenaarc662ec92019-06-23 00:15:57 +02007530 && !blocked_by_popup(row, col)
Bram Moolenaar24a5ac52019-06-08 19:01:18 +02007531#endif
7532 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00007533 {
7534#if defined(FEAT_GUI) || defined(UNIX)
7535 /* The bold trick makes a single row of pixels appear in the next
7536 * character. When a bold character is removed, the next
7537 * character should be redrawn too. This happens for our own GUI
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007538 * and for some xterms. */
7539 if (need_redraw && ScreenLines[off] != ' ' && (
Bram Moolenaar071d4272004-06-13 20:20:40 +00007540# ifdef FEAT_GUI
7541 gui.in_use
7542# endif
7543# if defined(FEAT_GUI) && defined(UNIX)
7544 ||
7545# endif
7546# ifdef UNIX
7547 term_is_xterm
7548# endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007549 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007550 {
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007551 int n = ScreenAttrs[off];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007552
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007553 if (n > HL_ALL)
7554 n = syn_attr2attr(n);
7555 if (n & HL_BOLD)
7556 force_redraw_next = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007557 }
7558#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007559 /* When at the end of the text and overwriting a two-cell
7560 * character with a one-cell character, need to clear the next
7561 * cell. Also when overwriting the left halve of a two-cell char
7562 * with the right halve of a two-cell char. Do this only once
7563 * (mb_off2cells() may return 2 on the right halve). */
7564 if (clear_next_cell)
7565 clear_next_cell = FALSE;
7566 else if (has_mbyte
7567 && (len < 0 ? ptr[mbyte_blen] == NUL
7568 : ptr + mbyte_blen >= text + len)
Bram Moolenaar367329b2007-08-30 11:53:22 +00007569 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007570 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00007571 && (*mb_off2cells)(off, max_off) == 1
7572 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007573 clear_next_cell = TRUE;
7574
7575 /* Make sure we never leave a second byte of a double-byte behind,
7576 * it confuses mb_off2cells(). */
7577 if (enc_dbcs
Bram Moolenaar367329b2007-08-30 11:53:22 +00007578 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007579 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00007580 && (*mb_off2cells)(off, max_off) == 1
7581 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007582 ScreenLines[off + mbyte_blen] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007583 ScreenLines[off] = c;
7584 ScreenAttrs[off] = attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007585 if (enc_utf8)
7586 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007587 if (c < 0x80 && u8cc[0] == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007588 ScreenLinesUC[off] = 0;
7589 else
7590 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007591 int i;
7592
Bram Moolenaar071d4272004-06-13 20:20:40 +00007593 ScreenLinesUC[off] = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007594 for (i = 0; i < Screen_mco; ++i)
7595 {
7596 ScreenLinesC[i][off] = u8cc[i];
7597 if (u8cc[i] == 0)
7598 break;
7599 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007600 }
7601 if (mbyte_cells == 2)
7602 {
7603 ScreenLines[off + 1] = 0;
7604 ScreenAttrs[off + 1] = attr;
7605 }
7606 screen_char(off, row, col);
7607 }
7608 else if (mbyte_cells == 2)
7609 {
7610 ScreenLines[off + 1] = ptr[1];
7611 ScreenAttrs[off + 1] = attr;
7612 screen_char_2(off, row, col);
7613 }
7614 else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7615 {
7616 ScreenLines2[off] = ptr[1];
7617 screen_char(off, row, col);
7618 }
7619 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007620 screen_char(off, row, col);
7621 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007622 if (has_mbyte)
7623 {
7624 off += mbyte_cells;
7625 col += mbyte_cells;
7626 ptr += mbyte_blen;
7627 if (clear_next_cell)
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007628 {
7629 /* This only happens at the end, display one space next. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007630 ptr = (char_u *)" ";
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007631 len = -1;
7632 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007633 }
7634 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007635 {
7636 ++off;
7637 ++col;
7638 ++ptr;
7639 }
7640 }
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007641
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007642 /* If we detected the next character needs to be redrawn, but the text
7643 * doesn't extend up to there, update the character here. */
7644 if (force_redraw_next && col < screen_Columns)
7645 {
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007646 if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
7647 screen_char_2(off, row, col);
7648 else
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007649 screen_char(off, row, col);
7650 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007651}
7652
7653#ifdef FEAT_SEARCH_EXTRA
7654/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007655 * Prepare for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007656 */
7657 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007658start_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007659{
7660 if (p_hls && !no_hlsearch)
7661 {
7662 last_pat_prog(&search_hl.rm);
Bram Moolenaar8820b482017-03-16 17:23:31 +01007663 search_hl.attr = HL_ATTR(HLF_L);
Bram Moolenaar91a4e822008-01-19 14:59:58 +00007664# ifdef FEAT_RELTIME
7665 /* Set the time limit to 'redrawtime'. */
7666 profile_setlimit(p_rdt, &search_hl.tm);
7667# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007668 }
7669}
7670
7671/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007672 * Clean up for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007673 */
7674 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007675end_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007676{
7677 if (search_hl.rm.regprog != NULL)
7678 {
Bram Moolenaar473de612013-06-08 18:19:48 +02007679 vim_regfree(search_hl.rm.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007680 search_hl.rm.regprog = NULL;
7681 }
7682}
Bram Moolenaarde993ea2014-06-17 23:18:01 +02007683#endif
Bram Moolenaarb3414592014-06-17 17:48:32 +02007684
Bram Moolenaar071d4272004-06-13 20:20:40 +00007685 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007686screen_start_highlight(int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007687{
7688 attrentry_T *aep = NULL;
7689
7690 screen_attr = attr;
7691 if (full_screen
Bram Moolenaar4f974752019-02-17 17:44:42 +01007692#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00007693 && termcap_active
7694#endif
7695 )
7696 {
7697#ifdef FEAT_GUI
7698 if (gui.in_use)
7699 {
7700 char buf[20];
7701
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007702 /* The GUI handles this internally. */
7703 sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007704 OUT_STR(buf);
7705 }
7706 else
7707#endif
7708 {
7709 if (attr > HL_ALL) /* special HL attr. */
7710 {
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007711 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007712 aep = syn_cterm_attr2entry(attr);
7713 else
7714 aep = syn_term_attr2entry(attr);
7715 if (aep == NULL) /* did ":syntax clear" */
7716 attr = 0;
7717 else
7718 attr = aep->ae_attr;
7719 }
Bram Moolenaar45a00002017-12-22 21:12:34 +01007720 if ((attr & HL_BOLD) && *T_MD != NUL) /* bold */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007721 out_str(T_MD);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007722 else if (aep != NULL && cterm_normal_fg_bold && (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02007723#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007724 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
7725 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
7726 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007727#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007728 t_colors > 1 && aep->ae_u.cterm.fg_color))
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007729 /* If the Normal FG color has BOLD attribute and the new HL
7730 * has a FG color defined, clear BOLD. */
7731 out_str(T_ME);
Bram Moolenaar45a00002017-12-22 21:12:34 +01007732 if ((attr & HL_STANDOUT) && *T_SO != NUL) /* standout */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007733 out_str(T_SO);
Bram Moolenaar45a00002017-12-22 21:12:34 +01007734 if ((attr & HL_UNDERCURL) && *T_UCS != NUL) /* undercurl */
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01007735 out_str(T_UCS);
7736 if (((attr & HL_UNDERLINE) /* underline or undercurl */
Bram Moolenaar45a00002017-12-22 21:12:34 +01007737 || ((attr & HL_UNDERCURL) && *T_UCS == NUL))
7738 && *T_US != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007739 out_str(T_US);
Bram Moolenaar45a00002017-12-22 21:12:34 +01007740 if ((attr & HL_ITALIC) && *T_CZH != NUL) /* italic */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007741 out_str(T_CZH);
Bram Moolenaar45a00002017-12-22 21:12:34 +01007742 if ((attr & HL_INVERSE) && *T_MR != NUL) /* inverse (reverse) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007743 out_str(T_MR);
Bram Moolenaar45a00002017-12-22 21:12:34 +01007744 if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) /* strike */
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007745 out_str(T_STS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007746
7747 /*
7748 * Output the color or start string after bold etc., in case the
7749 * bold etc. override the color setting.
7750 */
7751 if (aep != NULL)
7752 {
Bram Moolenaar61be73b2016-04-29 22:59:22 +02007753#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007754 /* When 'termguicolors' is set but fg or bg is unset,
7755 * fall back to the cterm colors. This helps for SpellBad,
7756 * where the GUI uses a red undercurl. */
7757 if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007758 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02007759 if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007760 term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007761 }
7762 else
7763#endif
7764 if (t_colors > 1)
7765 {
7766 if (aep->ae_u.cterm.fg_color)
7767 term_fg_color(aep->ae_u.cterm.fg_color - 1);
7768 }
7769#ifdef FEAT_TERMGUICOLORS
7770 if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
7771 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02007772 if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007773 term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007774 }
7775 else
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007776#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007777 if (t_colors > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007778 {
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007779 if (aep->ae_u.cterm.bg_color)
7780 term_bg_color(aep->ae_u.cterm.bg_color - 1);
7781 }
7782
Bram Moolenaarf708ac52018-03-12 21:48:32 +01007783 if (!IS_CTERM)
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007784 {
7785 if (aep->ae_u.term.start != NULL)
7786 out_str(aep->ae_u.term.start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007787 }
7788 }
7789 }
7790 }
7791}
7792
7793 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007794screen_stop_highlight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007795{
7796 int do_ME = FALSE; /* output T_ME code */
7797
7798 if (screen_attr != 0
Bram Moolenaar4f974752019-02-17 17:44:42 +01007799#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00007800 && termcap_active
7801#endif
7802 )
7803 {
7804#ifdef FEAT_GUI
7805 if (gui.in_use)
7806 {
7807 char buf[20];
7808
7809 /* use internal GUI code */
7810 sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
7811 OUT_STR(buf);
7812 }
7813 else
7814#endif
7815 {
7816 if (screen_attr > HL_ALL) /* special HL attr. */
7817 {
7818 attrentry_T *aep;
7819
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007820 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007821 {
7822 /*
7823 * Assume that t_me restores the original colors!
7824 */
7825 aep = syn_cterm_attr2entry(screen_attr);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007826 if (aep != NULL && ((
Bram Moolenaar61be73b2016-04-29 22:59:22 +02007827#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007828 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
7829 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
7830 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007831#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007832 aep->ae_u.cterm.fg_color) || (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02007833#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007834 p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
7835 ? aep->ae_u.cterm.bg_rgb != INVALCOLOR
7836 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007837#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01007838 aep->ae_u.cterm.bg_color)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007839 do_ME = TRUE;
7840 }
7841 else
7842 {
7843 aep = syn_term_attr2entry(screen_attr);
7844 if (aep != NULL && aep->ae_u.term.stop != NULL)
7845 {
7846 if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
7847 do_ME = TRUE;
7848 else
7849 out_str(aep->ae_u.term.stop);
7850 }
7851 }
7852 if (aep == NULL) /* did ":syntax clear" */
7853 screen_attr = 0;
7854 else
7855 screen_attr = aep->ae_attr;
7856 }
7857
7858 /*
7859 * Often all ending-codes are equal to T_ME. Avoid outputting the
7860 * same sequence several times.
7861 */
7862 if (screen_attr & HL_STANDOUT)
7863 {
7864 if (STRCMP(T_SE, T_ME) == 0)
7865 do_ME = TRUE;
7866 else
7867 out_str(T_SE);
7868 }
Bram Moolenaar45a00002017-12-22 21:12:34 +01007869 if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01007870 {
7871 if (STRCMP(T_UCE, T_ME) == 0)
7872 do_ME = TRUE;
7873 else
7874 out_str(T_UCE);
7875 }
7876 if ((screen_attr & HL_UNDERLINE)
Bram Moolenaar45a00002017-12-22 21:12:34 +01007877 || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007878 {
7879 if (STRCMP(T_UE, T_ME) == 0)
7880 do_ME = TRUE;
7881 else
7882 out_str(T_UE);
7883 }
7884 if (screen_attr & HL_ITALIC)
7885 {
7886 if (STRCMP(T_CZR, T_ME) == 0)
7887 do_ME = TRUE;
7888 else
7889 out_str(T_CZR);
7890 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007891 if (screen_attr & HL_STRIKETHROUGH)
7892 {
7893 if (STRCMP(T_STE, T_ME) == 0)
7894 do_ME = TRUE;
7895 else
7896 out_str(T_STE);
7897 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007898 if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
7899 out_str(T_ME);
7900
Bram Moolenaar61be73b2016-04-29 22:59:22 +02007901#ifdef FEAT_TERMGUICOLORS
7902 if (p_tgc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007903 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02007904 if (cterm_normal_fg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007905 term_fg_rgb_color(cterm_normal_fg_gui_color);
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02007906 if (cterm_normal_bg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007907 term_bg_rgb_color(cterm_normal_bg_gui_color);
7908 }
7909 else
7910#endif
7911 {
7912 if (t_colors > 1)
7913 {
7914 /* set Normal cterm colors */
7915 if (cterm_normal_fg_color != 0)
7916 term_fg_color(cterm_normal_fg_color - 1);
7917 if (cterm_normal_bg_color != 0)
7918 term_bg_color(cterm_normal_bg_color - 1);
7919 if (cterm_normal_fg_bold)
7920 out_str(T_MD);
7921 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007922 }
7923 }
7924 }
7925 screen_attr = 0;
7926}
7927
7928/*
7929 * Reset the colors for a cterm. Used when leaving Vim.
7930 * The machine specific code may override this again.
7931 */
7932 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007933reset_cterm_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007934{
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007935 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007936 {
7937 /* set Normal cterm colors */
Bram Moolenaar61be73b2016-04-29 22:59:22 +02007938#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02007939 if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
7940 || cterm_normal_bg_gui_color != INVALCOLOR)
7941 : (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007942#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007943 if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02007944#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007945 {
7946 out_str(T_OP);
7947 screen_attr = -1;
7948 }
7949 if (cterm_normal_fg_bold)
7950 {
7951 out_str(T_ME);
7952 screen_attr = -1;
7953 }
7954 }
7955}
7956
7957/*
7958 * Put character ScreenLines["off"] on the screen at position "row" and "col",
7959 * using the attributes from ScreenAttrs["off"].
7960 */
7961 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007962screen_char(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007963{
7964 int attr;
7965
7966 /* Check for illegal values, just in case (could happen just after
7967 * resizing). */
7968 if (row >= screen_Rows || col >= screen_Columns)
7969 return;
7970
Bram Moolenaarae654382019-01-17 21:09:05 +01007971#ifdef FEAT_INS_EXPAND
Bram Moolenaar33796b32019-06-08 16:01:13 +02007972 // Skip if under the popup menu.
7973 // Popup windows with zindex higher than POPUPMENU_ZINDEX go on top.
7974 if (pum_under_menu(row, col)
7975# ifdef FEAT_TEXT_PROP
7976 && screen_zindex <= POPUPMENU_ZINDEX
7977# endif
7978 )
Bram Moolenaarae654382019-01-17 21:09:05 +01007979 return;
7980#endif
Bram Moolenaar33796b32019-06-08 16:01:13 +02007981#ifdef FEAT_TEXT_PROP
Bram Moolenaarc662ec92019-06-23 00:15:57 +02007982 if (blocked_by_popup(row, col))
Bram Moolenaar33796b32019-06-08 16:01:13 +02007983 return;
7984#endif
7985
Bram Moolenaar494838a2015-02-10 19:20:37 +01007986 /* Outputting a character in the last cell on the screen may scroll the
7987 * screen up. Only do it when the "xn" termcap property is set, otherwise
7988 * mark the character invalid (update it when scrolled up). */
7989 if (*T_XN == NUL
7990 && row == screen_Rows - 1 && col == screen_Columns - 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00007991#ifdef FEAT_RIGHTLEFT
7992 /* account for first command-line character in rightleft mode */
7993 && !cmdmsg_rl
7994#endif
7995 )
7996 {
7997 ScreenAttrs[off] = (sattr_T)-1;
7998 return;
7999 }
8000
8001 /*
8002 * Stop highlighting first, so it's easier to move the cursor.
8003 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008004 if (screen_char_attr != 0)
8005 attr = screen_char_attr;
8006 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008007 attr = ScreenAttrs[off];
8008 if (screen_attr != attr)
8009 screen_stop_highlight();
8010
8011 windgoto(row, col);
8012
8013 if (screen_attr != attr)
8014 screen_start_highlight(attr);
8015
Bram Moolenaar071d4272004-06-13 20:20:40 +00008016 if (enc_utf8 && ScreenLinesUC[off] != 0)
8017 {
8018 char_u buf[MB_MAXBYTES + 1];
8019
Bram Moolenaarcb070082016-04-02 22:14:51 +02008020 if (utf_ambiguous_width(ScreenLinesUC[off]))
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008021 {
8022 if (*p_ambw == 'd'
Bram Moolenaara12a1612019-01-24 16:39:02 +01008023#ifdef FEAT_GUI
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008024 && !gui.in_use
Bram Moolenaara12a1612019-01-24 16:39:02 +01008025#endif
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008026 )
8027 {
8028 /* Clear the two screen cells. If the character is actually
8029 * single width it won't change the second cell. */
8030 out_str((char_u *)" ");
8031 term_windgoto(row, col);
8032 }
8033 /* not sure where the cursor is after drawing the ambiguous width
8034 * character */
Bram Moolenaarcb070082016-04-02 22:14:51 +02008035 screen_cur_col = 9999;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008036 }
Bram Moolenaarcb070082016-04-02 22:14:51 +02008037 else if (utf_char2cells(ScreenLinesUC[off]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008038 ++screen_cur_col;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008039
8040 /* Convert the UTF-8 character to bytes and write it. */
8041 buf[utfc_char2bytes(off, buf)] = NUL;
8042 out_str(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008043 }
8044 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008045 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00008046 out_flush_check();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008047 out_char(ScreenLines[off]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008048 /* double-byte character in single-width cell */
8049 if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
8050 out_char(ScreenLines2[off]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008051 }
8052
8053 screen_cur_col++;
8054}
8055
Bram Moolenaar071d4272004-06-13 20:20:40 +00008056/*
8057 * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
8058 * on the screen at position 'row' and 'col'.
8059 * The attributes of the first byte is used for all. This is required to
8060 * output the two bytes of a double-byte character with nothing in between.
8061 */
8062 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008063screen_char_2(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008064{
8065 /* Check for illegal values (could be wrong when screen was resized). */
8066 if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
8067 return;
8068
8069 /* Outputting the last character on the screen may scrollup the screen.
8070 * Don't to it! Mark the character invalid (update it when scrolled up) */
8071 if (row == screen_Rows - 1 && col >= screen_Columns - 2)
8072 {
8073 ScreenAttrs[off] = (sattr_T)-1;
8074 return;
8075 }
8076
8077 /* Output the first byte normally (positions the cursor), then write the
8078 * second byte directly. */
8079 screen_char(off, row, col);
8080 out_char(ScreenLines[off + 1]);
8081 ++screen_cur_col;
8082}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008083
Bram Moolenaar071d4272004-06-13 20:20:40 +00008084/*
8085 * Draw a rectangle of the screen, inverted when "invert" is TRUE.
8086 * This uses the contents of ScreenLines[] and doesn't change it.
8087 */
8088 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008089screen_draw_rectangle(
8090 int row,
8091 int col,
8092 int height,
8093 int width,
8094 int invert)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008095{
8096 int r, c;
8097 int off;
Bram Moolenaar367329b2007-08-30 11:53:22 +00008098 int max_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008099
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008100 /* Can't use ScreenLines unless initialized */
8101 if (ScreenLines == NULL)
8102 return;
8103
Bram Moolenaar071d4272004-06-13 20:20:40 +00008104 if (invert)
8105 screen_char_attr = HL_INVERSE;
8106 for (r = row; r < row + height; ++r)
8107 {
8108 off = LineOffset[r];
Bram Moolenaar367329b2007-08-30 11:53:22 +00008109 max_off = off + screen_Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008110 for (c = col; c < col + width; ++c)
8111 {
Bram Moolenaar367329b2007-08-30 11:53:22 +00008112 if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008113 {
8114 screen_char_2(off + c, r, c);
8115 ++c;
8116 }
8117 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008118 {
8119 screen_char(off + c, r, c);
Bram Moolenaar367329b2007-08-30 11:53:22 +00008120 if (utf_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008121 ++c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008122 }
8123 }
8124 }
8125 screen_char_attr = 0;
8126}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008127
Bram Moolenaar071d4272004-06-13 20:20:40 +00008128/*
8129 * Redraw the characters for a vertically split window.
8130 */
8131 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008132redraw_block(int row, int end, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008133{
8134 int col;
8135 int width;
8136
8137# ifdef FEAT_CLIPBOARD
8138 clip_may_clear_selection(row, end - 1);
8139# endif
8140
8141 if (wp == NULL)
8142 {
8143 col = 0;
8144 width = Columns;
8145 }
8146 else
8147 {
8148 col = wp->w_wincol;
8149 width = wp->w_width;
8150 }
8151 screen_draw_rectangle(row, col, end - row, width, FALSE);
8152}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008153
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008154 static void
8155space_to_screenline(int off, int attr)
8156{
8157 ScreenLines[off] = ' ';
8158 ScreenAttrs[off] = attr;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008159 if (enc_utf8)
8160 ScreenLinesUC[off] = 0;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008161}
8162
Bram Moolenaar071d4272004-06-13 20:20:40 +00008163/*
8164 * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
8165 * with character 'c1' in first column followed by 'c2' in the other columns.
8166 * Use attributes 'attr'.
8167 */
8168 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008169screen_fill(
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008170 int start_row,
8171 int end_row,
8172 int start_col,
8173 int end_col,
8174 int c1,
8175 int c2,
8176 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008177{
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008178 int row;
8179 int col;
8180 int off;
8181 int end_off;
8182 int did_delete;
8183 int c;
8184 int norm_term;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008185#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008186 int force_next = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008187#endif
8188
8189 if (end_row > screen_Rows) /* safety check */
8190 end_row = screen_Rows;
8191 if (end_col > screen_Columns) /* safety check */
8192 end_col = screen_Columns;
8193 if (ScreenLines == NULL
8194 || start_row >= end_row
8195 || start_col >= end_col) /* nothing to do */
8196 return;
8197
8198 /* it's a "normal" terminal when not in a GUI or cterm */
8199 norm_term = (
8200#ifdef FEAT_GUI
8201 !gui.in_use &&
8202#endif
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008203 !IS_CTERM);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008204 for (row = start_row; row < end_row; ++row)
8205 {
Bram Moolenaarc236c162008-07-13 17:41:49 +00008206 if (has_mbyte
Bram Moolenaara12a1612019-01-24 16:39:02 +01008207#ifdef FEAT_GUI
Bram Moolenaarc236c162008-07-13 17:41:49 +00008208 && !gui.in_use
Bram Moolenaara12a1612019-01-24 16:39:02 +01008209#endif
Bram Moolenaarc236c162008-07-13 17:41:49 +00008210 )
8211 {
8212 /* When drawing over the right halve of a double-wide char clear
8213 * out the left halve. When drawing over the left halve of a
8214 * double wide-char clear out the right halve. Only needed in a
8215 * terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00008216 if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00008217 screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
Bram Moolenaara1aed622008-07-18 15:14:43 +00008218 if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00008219 screen_puts_len((char_u *)" ", 1, row, end_col, 0);
Bram Moolenaarc236c162008-07-13 17:41:49 +00008220 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008221 /*
8222 * Try to use delete-line termcap code, when no attributes or in a
8223 * "normal" terminal, where a bold/italic space is just a
8224 * space.
8225 */
8226 did_delete = FALSE;
8227 if (c2 == ' '
8228 && end_col == Columns
8229 && can_clear(T_CE)
8230 && (attr == 0
8231 || (norm_term
8232 && attr <= HL_ALL
8233 && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
8234 {
8235 /*
8236 * check if we really need to clear something
8237 */
8238 col = start_col;
8239 if (c1 != ' ') /* don't clear first char */
8240 ++col;
8241
8242 off = LineOffset[row] + col;
8243 end_off = LineOffset[row] + end_col;
8244
8245 /* skip blanks (used often, keep it fast!) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008246 if (enc_utf8)
8247 while (off < end_off && ScreenLines[off] == ' '
8248 && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
8249 ++off;
8250 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008251 while (off < end_off && ScreenLines[off] == ' '
8252 && ScreenAttrs[off] == 0)
8253 ++off;
8254 if (off < end_off) /* something to be cleared */
8255 {
8256 col = off - LineOffset[row];
8257 screen_stop_highlight();
8258 term_windgoto(row, col);/* clear rest of this screen line */
8259 out_str(T_CE);
8260 screen_start(); /* don't know where cursor is now */
8261 col = end_col - col;
8262 while (col--) /* clear chars in ScreenLines */
8263 {
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008264 space_to_screenline(off, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008265 ++off;
8266 }
8267 }
8268 did_delete = TRUE; /* the chars are cleared now */
8269 }
8270
8271 off = LineOffset[row] + start_col;
8272 c = c1;
8273 for (col = start_col; col < end_col; ++col)
8274 {
Bram Moolenaar33796b32019-06-08 16:01:13 +02008275 if ((ScreenLines[off] != c
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008276 || (enc_utf8 && (int)ScreenLinesUC[off]
8277 != (c >= 0x80 ? c : 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008278 || ScreenAttrs[off] != attr
8279#if defined(FEAT_GUI) || defined(UNIX)
8280 || force_next
8281#endif
8282 )
Bram Moolenaar33796b32019-06-08 16:01:13 +02008283#ifdef FEAT_TEXT_PROP
8284 // Skip if under a(nother) popup.
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008285 && !blocked_by_popup(row, col)
Bram Moolenaar33796b32019-06-08 16:01:13 +02008286#endif
8287 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008288 {
8289#if defined(FEAT_GUI) || defined(UNIX)
8290 /* The bold trick may make a single row of pixels appear in
8291 * the next character. When a bold character is removed, the
8292 * next character should be redrawn too. This happens for our
8293 * own GUI and for some xterms. */
8294 if (
8295# ifdef FEAT_GUI
8296 gui.in_use
8297# endif
8298# if defined(FEAT_GUI) && defined(UNIX)
8299 ||
8300# endif
8301# ifdef UNIX
8302 term_is_xterm
8303# endif
8304 )
8305 {
8306 if (ScreenLines[off] != ' '
8307 && (ScreenAttrs[off] > HL_ALL
8308 || ScreenAttrs[off] & HL_BOLD))
8309 force_next = TRUE;
8310 else
8311 force_next = FALSE;
8312 }
8313#endif
8314 ScreenLines[off] = c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008315 if (enc_utf8)
8316 {
8317 if (c >= 0x80)
8318 {
8319 ScreenLinesUC[off] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008320 ScreenLinesC[0][off] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008321 }
8322 else
8323 ScreenLinesUC[off] = 0;
8324 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008325 ScreenAttrs[off] = attr;
8326 if (!did_delete || c != ' ')
8327 screen_char(off, row, col);
8328 }
8329 ++off;
8330 if (col == start_col)
8331 {
8332 if (did_delete)
8333 break;
8334 c = c2;
8335 }
8336 }
8337 if (end_col == Columns)
8338 LineWraps[row] = FALSE;
8339 if (row == Rows - 1) /* overwritten the command line */
8340 {
8341 redraw_cmdline = TRUE;
Bram Moolenaar5bab5552018-04-13 20:41:29 +02008342 if (start_col == 0 && end_col == Columns
8343 && c1 == ' ' && c2 == ' ' && attr == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008344 clear_cmdline = FALSE; /* command line has been cleared */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00008345 if (start_col == 0)
8346 mode_displayed = FALSE; /* mode cleared or overwritten */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008347 }
8348 }
8349}
8350
8351/*
8352 * Check if there should be a delay. Used before clearing or redrawing the
8353 * screen or the command line.
8354 */
8355 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008356check_for_delay(int check_msg_scroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008357{
8358 if ((emsg_on_display || (check_msg_scroll && msg_scroll))
8359 && !did_wait_return
8360 && emsg_silent == 0)
8361 {
8362 out_flush();
8363 ui_delay(1000L, TRUE);
8364 emsg_on_display = FALSE;
8365 if (check_msg_scroll)
8366 msg_scroll = FALSE;
8367 }
8368}
8369
8370/*
Bram Moolenaarca57ab52019-04-13 14:53:16 +02008371 * Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
8372 */
8373 static void
8374clear_TabPageIdxs(void)
8375{
8376 int scol;
8377
8378 for (scol = 0; scol < Columns; ++scol)
8379 TabPageIdxs[scol] = 0;
8380}
8381
8382/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008383 * screen_valid - allocate screen buffers if size changed
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008384 * If "doclear" is TRUE: clear screen if it has been resized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008385 * Returns TRUE if there is a valid screen to write to.
8386 * Returns FALSE when starting up and screen not initialized yet.
8387 */
8388 int
Bram Moolenaar05540972016-01-30 20:31:25 +01008389screen_valid(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008390{
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008391 screenalloc(doclear); /* allocate screen buffers if size changed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008392 return (ScreenLines != NULL);
8393}
8394
8395/*
8396 * Resize the shell to Rows and Columns.
8397 * Allocate ScreenLines[] and associated items.
8398 *
8399 * There may be some time between setting Rows and Columns and (re)allocating
8400 * ScreenLines[]. This happens when starting up and when (manually) changing
8401 * the shell size. Always use screen_Rows and screen_Columns to access items
8402 * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
8403 * final size of the shell is needed.
8404 */
8405 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008406screenalloc(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008407{
8408 int new_row, old_row;
8409#ifdef FEAT_GUI
8410 int old_Rows;
8411#endif
8412 win_T *wp;
8413 int outofmem = FALSE;
8414 int len;
8415 schar_T *new_ScreenLines;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008416 u8char_T *new_ScreenLinesUC = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008417 u8char_T *new_ScreenLinesC[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008418 schar_T *new_ScreenLines2 = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008419 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008420 sattr_T *new_ScreenAttrs;
8421 unsigned *new_LineOffset;
8422 char_u *new_LineWraps;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008423 short *new_TabPageIdxs;
Bram Moolenaar33796b32019-06-08 16:01:13 +02008424#ifdef FEAT_TEXT_PROP
8425 short *new_popup_mask;
Bram Moolenaar4c063a02019-06-10 21:24:12 +02008426 short *new_popup_mask_next;
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008427 char *new_popup_transparent;
Bram Moolenaar33796b32019-06-08 16:01:13 +02008428#endif
Bram Moolenaarf740b292006-02-16 22:11:02 +00008429 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008430 static int entered = FALSE; /* avoid recursiveness */
Bram Moolenaar89d40322006-08-29 15:30:07 +00008431 static int done_outofmem_msg = FALSE; /* did outofmem message */
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008432 int retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008433
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008434retry:
Bram Moolenaar071d4272004-06-13 20:20:40 +00008435 /*
8436 * Allocation of the screen buffers is done only when the size changes and
8437 * when Rows and Columns have been set and we have started doing full
8438 * screen stuff.
8439 */
8440 if ((ScreenLines != NULL
8441 && Rows == screen_Rows
8442 && Columns == screen_Columns
Bram Moolenaar071d4272004-06-13 20:20:40 +00008443 && enc_utf8 == (ScreenLinesUC != NULL)
8444 && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
Bram Moolenaara12a1612019-01-24 16:39:02 +01008445 && p_mco == Screen_mco)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008446 || Rows == 0
8447 || Columns == 0
8448 || (!full_screen && ScreenLines == NULL))
8449 return;
8450
8451 /*
8452 * It's possible that we produce an out-of-memory message below, which
8453 * will cause this function to be called again. To break the loop, just
8454 * return here.
8455 */
8456 if (entered)
8457 return;
8458 entered = TRUE;
8459
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00008460 /*
8461 * Note that the window sizes are updated before reallocating the arrays,
8462 * thus we must not redraw here!
8463 */
8464 ++RedrawingDisabled;
8465
Bram Moolenaar071d4272004-06-13 20:20:40 +00008466 win_new_shellsize(); /* fit the windows in the new sized shell */
8467
Bram Moolenaar071d4272004-06-13 20:20:40 +00008468 comp_col(); /* recompute columns for shown command and ruler */
8469
8470 /*
8471 * We're changing the size of the screen.
8472 * - Allocate new arrays for ScreenLines and ScreenAttrs.
8473 * - Move lines from the old arrays into the new arrays, clear extra
8474 * lines (unless the screen is going to be cleared).
8475 * - Free the old arrays.
8476 *
8477 * If anything fails, make ScreenLines NULL, so we don't do anything!
8478 * Continuing with the old ScreenLines may result in a crash, because the
8479 * size is wrong.
8480 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00008481 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008482 win_free_lsize(wp);
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00008483 if (aucmd_win != NULL)
8484 win_free_lsize(aucmd_win);
Bram Moolenaar8caaf822019-06-01 18:11:22 +02008485#ifdef FEAT_TEXT_PROP
8486 // global popup windows
8487 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
8488 win_free_lsize(wp);
8489 // tab-local popup windows
8490 FOR_ALL_TABPAGES(tp)
8491 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
8492 win_free_lsize(wp);
8493#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008494
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008495 new_ScreenLines = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
Bram Moolenaar216b7102010-03-23 13:56:59 +01008496 vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008497 if (enc_utf8)
8498 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008499 new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008500 for (i = 0; i < p_mco; ++i)
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008501 new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T,
8502 (Rows + 1) * Columns);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008503 }
8504 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008505 new_ScreenLines2 = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
8506 new_ScreenAttrs = LALLOC_MULT(sattr_T, (Rows + 1) * Columns);
8507 new_LineOffset = LALLOC_MULT(unsigned, Rows);
8508 new_LineWraps = LALLOC_MULT(char_u, Rows);
8509 new_TabPageIdxs = LALLOC_MULT(short, Columns);
Bram Moolenaar33796b32019-06-08 16:01:13 +02008510#ifdef FEAT_TEXT_PROP
8511 new_popup_mask = LALLOC_MULT(short, Rows * Columns);
Bram Moolenaar4c063a02019-06-10 21:24:12 +02008512 new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008513 new_popup_transparent = LALLOC_MULT(char, Rows * Columns);
Bram Moolenaar33796b32019-06-08 16:01:13 +02008514#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008515
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00008516 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008517 {
8518 if (win_alloc_lines(wp) == FAIL)
8519 {
8520 outofmem = TRUE;
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00008521 goto give_up;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008522 }
8523 }
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00008524 if (aucmd_win != NULL && aucmd_win->w_lines == NULL
8525 && win_alloc_lines(aucmd_win) == FAIL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008526 outofmem = TRUE;
Bram Moolenaar8caaf822019-06-01 18:11:22 +02008527#ifdef FEAT_TEXT_PROP
8528 // global popup windows
8529 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
8530 if (win_alloc_lines(wp) == FAIL)
8531 {
8532 outofmem = TRUE;
8533 goto give_up;
8534 }
8535 // tab-local popup windows
8536 FOR_ALL_TABPAGES(tp)
8537 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
8538 if (win_alloc_lines(wp) == FAIL)
8539 {
8540 outofmem = TRUE;
8541 goto give_up;
8542 }
8543#endif
8544
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00008545give_up:
Bram Moolenaar071d4272004-06-13 20:20:40 +00008546
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008547 for (i = 0; i < p_mco; ++i)
8548 if (new_ScreenLinesC[i] == NULL)
8549 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008550 if (new_ScreenLines == NULL
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008551 || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008552 || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008553 || new_ScreenAttrs == NULL
8554 || new_LineOffset == NULL
8555 || new_LineWraps == NULL
Bram Moolenaarf740b292006-02-16 22:11:02 +00008556 || new_TabPageIdxs == NULL
Bram Moolenaar33796b32019-06-08 16:01:13 +02008557#ifdef FEAT_TEXT_PROP
8558 || new_popup_mask == NULL
Bram Moolenaar4c063a02019-06-10 21:24:12 +02008559 || new_popup_mask_next == NULL
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008560 || new_popup_transparent == NULL
Bram Moolenaar33796b32019-06-08 16:01:13 +02008561#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008562 || outofmem)
8563 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00008564 if (ScreenLines != NULL || !done_outofmem_msg)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008565 {
8566 /* guess the size */
8567 do_outofmem_msg((long_u)((Rows + 1) * Columns));
8568
8569 /* Remember we did this to avoid getting outofmem messages over
8570 * and over again. */
Bram Moolenaar89d40322006-08-29 15:30:07 +00008571 done_outofmem_msg = TRUE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008572 }
Bram Moolenaard23a8232018-02-10 18:45:26 +01008573 VIM_CLEAR(new_ScreenLines);
Bram Moolenaard23a8232018-02-10 18:45:26 +01008574 VIM_CLEAR(new_ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008575 for (i = 0; i < p_mco; ++i)
Bram Moolenaard23a8232018-02-10 18:45:26 +01008576 VIM_CLEAR(new_ScreenLinesC[i]);
8577 VIM_CLEAR(new_ScreenLines2);
Bram Moolenaard23a8232018-02-10 18:45:26 +01008578 VIM_CLEAR(new_ScreenAttrs);
8579 VIM_CLEAR(new_LineOffset);
8580 VIM_CLEAR(new_LineWraps);
8581 VIM_CLEAR(new_TabPageIdxs);
Bram Moolenaar33796b32019-06-08 16:01:13 +02008582#ifdef FEAT_TEXT_PROP
8583 VIM_CLEAR(new_popup_mask);
Bram Moolenaar4c063a02019-06-10 21:24:12 +02008584 VIM_CLEAR(new_popup_mask_next);
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008585 VIM_CLEAR(new_popup_transparent);
Bram Moolenaar33796b32019-06-08 16:01:13 +02008586#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008587 }
8588 else
8589 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00008590 done_outofmem_msg = FALSE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008591
Bram Moolenaar071d4272004-06-13 20:20:40 +00008592 for (new_row = 0; new_row < Rows; ++new_row)
8593 {
8594 new_LineOffset[new_row] = new_row * Columns;
8595 new_LineWraps[new_row] = FALSE;
8596
8597 /*
8598 * If the screen is not going to be cleared, copy as much as
8599 * possible from the old screen to the new one and clear the rest
8600 * (used when resizing the window at the "--more--" prompt or when
8601 * executing an external command, for the GUI).
8602 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008603 if (!doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008604 {
8605 (void)vim_memset(new_ScreenLines + new_row * Columns,
8606 ' ', (size_t)Columns * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008607 if (enc_utf8)
8608 {
8609 (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
8610 0, (size_t)Columns * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008611 for (i = 0; i < p_mco; ++i)
8612 (void)vim_memset(new_ScreenLinesC[i]
8613 + new_row * Columns,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008614 0, (size_t)Columns * sizeof(u8char_T));
8615 }
8616 if (enc_dbcs == DBCS_JPNU)
8617 (void)vim_memset(new_ScreenLines2 + new_row * Columns,
8618 0, (size_t)Columns * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008619 (void)vim_memset(new_ScreenAttrs + new_row * Columns,
8620 0, (size_t)Columns * sizeof(sattr_T));
8621 old_row = new_row + (screen_Rows - Rows);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008622 if (old_row >= 0 && ScreenLines != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008623 {
8624 if (screen_Columns < Columns)
8625 len = screen_Columns;
8626 else
8627 len = Columns;
Bram Moolenaarf4d11452005-12-02 00:46:37 +00008628 /* When switching to utf-8 don't copy characters, they
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008629 * may be invalid now. Also when p_mco changes. */
8630 if (!(enc_utf8 && ScreenLinesUC == NULL)
8631 && p_mco == Screen_mco)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00008632 mch_memmove(new_ScreenLines + new_LineOffset[new_row],
8633 ScreenLines + LineOffset[old_row],
8634 (size_t)len * sizeof(schar_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008635 if (enc_utf8 && ScreenLinesUC != NULL
8636 && p_mco == Screen_mco)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008637 {
8638 mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
8639 ScreenLinesUC + LineOffset[old_row],
8640 (size_t)len * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008641 for (i = 0; i < p_mco; ++i)
8642 mch_memmove(new_ScreenLinesC[i]
8643 + new_LineOffset[new_row],
8644 ScreenLinesC[i] + LineOffset[old_row],
Bram Moolenaar071d4272004-06-13 20:20:40 +00008645 (size_t)len * sizeof(u8char_T));
8646 }
8647 if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
8648 mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
8649 ScreenLines2 + LineOffset[old_row],
8650 (size_t)len * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008651 mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
8652 ScreenAttrs + LineOffset[old_row],
8653 (size_t)len * sizeof(sattr_T));
8654 }
8655 }
8656 }
8657 /* Use the last line of the screen for the current line. */
8658 current_ScreenLine = new_ScreenLines + Rows * Columns;
Bram Moolenaar6ace95e2019-08-13 23:09:49 +02008659
8660#ifdef FEAT_TEXT_PROP
8661 vim_memset(new_popup_mask, 0, Rows * Columns * sizeof(short));
8662 vim_memset(new_popup_transparent, 0, Rows * Columns * sizeof(char));
8663#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008664 }
8665
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008666 free_screenlines();
8667
Bram Moolenaar6ace95e2019-08-13 23:09:49 +02008668 // NOTE: this may result in all pointers to become NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008669 ScreenLines = new_ScreenLines;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008670 ScreenLinesUC = new_ScreenLinesUC;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008671 for (i = 0; i < p_mco; ++i)
8672 ScreenLinesC[i] = new_ScreenLinesC[i];
8673 Screen_mco = p_mco;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008674 ScreenLines2 = new_ScreenLines2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008675 ScreenAttrs = new_ScreenAttrs;
8676 LineOffset = new_LineOffset;
8677 LineWraps = new_LineWraps;
Bram Moolenaarf740b292006-02-16 22:11:02 +00008678 TabPageIdxs = new_TabPageIdxs;
Bram Moolenaar33796b32019-06-08 16:01:13 +02008679#ifdef FEAT_TEXT_PROP
8680 popup_mask = new_popup_mask;
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008681 popup_mask_next = new_popup_mask_next;
8682 popup_transparent = new_popup_transparent;
Bram Moolenaar33796b32019-06-08 16:01:13 +02008683 popup_mask_refresh = TRUE;
8684#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008685
8686 /* It's important that screen_Rows and screen_Columns reflect the actual
8687 * size of ScreenLines[]. Set them before calling anything. */
8688#ifdef FEAT_GUI
8689 old_Rows = screen_Rows;
8690#endif
8691 screen_Rows = Rows;
8692 screen_Columns = Columns;
8693
8694 must_redraw = CLEAR; /* need to clear the screen later */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008695 if (doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008696 screenclear2();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008697#ifdef FEAT_GUI
8698 else if (gui.in_use
8699 && !gui.starting
8700 && ScreenLines != NULL
8701 && old_Rows != Rows)
8702 {
8703 (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
8704 /*
8705 * Adjust the position of the cursor, for when executing an external
8706 * command.
8707 */
8708 if (msg_row >= Rows) /* Rows got smaller */
8709 msg_row = Rows - 1; /* put cursor at last row */
8710 else if (Rows > old_Rows) /* Rows got bigger */
8711 msg_row += Rows - old_Rows; /* put cursor in same place */
8712 if (msg_col >= Columns) /* Columns got smaller */
8713 msg_col = Columns - 1; /* put cursor at last column */
8714 }
8715#endif
Bram Moolenaarca57ab52019-04-13 14:53:16 +02008716 clear_TabPageIdxs();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008717
Bram Moolenaar071d4272004-06-13 20:20:40 +00008718 entered = FALSE;
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00008719 --RedrawingDisabled;
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00008720
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008721 /*
8722 * Do not apply autocommands more than 3 times to avoid an endless loop
8723 * in case applying autocommands always changes Rows or Columns.
8724 */
8725 if (starting == 0 && ++retry_count <= 3)
8726 {
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00008727 apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008728 /* In rare cases, autocommands may have altered Rows or Columns,
8729 * jump back to check if we need to allocate the screen again. */
8730 goto retry;
8731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008732}
8733
8734 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008735free_screenlines(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008736{
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008737 int i;
8738
Bram Moolenaar33796b32019-06-08 16:01:13 +02008739 VIM_CLEAR(ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008740 for (i = 0; i < Screen_mco; ++i)
Bram Moolenaar33796b32019-06-08 16:01:13 +02008741 VIM_CLEAR(ScreenLinesC[i]);
8742 VIM_CLEAR(ScreenLines2);
8743 VIM_CLEAR(ScreenLines);
8744 VIM_CLEAR(ScreenAttrs);
8745 VIM_CLEAR(LineOffset);
8746 VIM_CLEAR(LineWraps);
8747 VIM_CLEAR(TabPageIdxs);
8748#ifdef FEAT_TEXT_PROP
8749 VIM_CLEAR(popup_mask);
Bram Moolenaar4c063a02019-06-10 21:24:12 +02008750 VIM_CLEAR(popup_mask_next);
Bram Moolenaarc662ec92019-06-23 00:15:57 +02008751 VIM_CLEAR(popup_transparent);
Bram Moolenaar33796b32019-06-08 16:01:13 +02008752#endif
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008753}
8754
8755 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008756screenclear(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008757{
8758 check_for_delay(FALSE);
8759 screenalloc(FALSE); /* allocate screen buffers if size changed */
8760 screenclear2(); /* clear the screen */
8761}
8762
8763 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008764screenclear2(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008765{
8766 int i;
8767
8768 if (starting == NO_SCREEN || ScreenLines == NULL
8769#ifdef FEAT_GUI
8770 || (gui.in_use && gui.starting)
8771#endif
8772 )
8773 return;
8774
8775#ifdef FEAT_GUI
8776 if (!gui.in_use)
8777#endif
8778 screen_attr = -1; /* force setting the Normal colors */
8779 screen_stop_highlight(); /* don't want highlighting here */
8780
8781#ifdef FEAT_CLIPBOARD
8782 /* disable selection without redrawing it */
8783 clip_scroll_selection(9999);
8784#endif
8785
8786 /* blank out ScreenLines */
8787 for (i = 0; i < Rows; ++i)
8788 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02008789 lineclear(LineOffset[i], (int)Columns, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008790 LineWraps[i] = FALSE;
8791 }
8792
8793 if (can_clear(T_CL))
8794 {
8795 out_str(T_CL); /* clear the display */
8796 clear_cmdline = FALSE;
Bram Moolenaard12f5c12006-01-25 22:10:52 +00008797 mode_displayed = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008798 }
8799 else
8800 {
8801 /* can't clear the screen, mark all chars with invalid attributes */
8802 for (i = 0; i < Rows; ++i)
8803 lineinvalid(LineOffset[i], (int)Columns);
8804 clear_cmdline = TRUE;
8805 }
8806
8807 screen_cleared = TRUE; /* can use contents of ScreenLines now */
8808
8809 win_rest_invalid(firstwin);
8810 redraw_cmdline = TRUE;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00008811 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008812 if (must_redraw == CLEAR) /* no need to clear again */
8813 must_redraw = NOT_VALID;
8814 compute_cmdrow();
8815 msg_row = cmdline_row; /* put cursor on last line for messages */
8816 msg_col = 0;
8817 screen_start(); /* don't know where cursor is now */
8818 msg_scrolled = 0; /* can't scroll back */
8819 msg_didany = FALSE;
8820 msg_didout = FALSE;
8821}
8822
8823/*
8824 * Clear one line in ScreenLines.
8825 */
8826 static void
Bram Moolenaarcfce7172017-08-17 20:31:48 +02008827lineclear(unsigned off, int width, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008828{
8829 (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008830 if (enc_utf8)
8831 (void)vim_memset(ScreenLinesUC + off, 0,
8832 (size_t)width * sizeof(u8char_T));
Bram Moolenaarcfce7172017-08-17 20:31:48 +02008833 (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008834}
8835
8836/*
8837 * Mark one line in ScreenLines invalid by setting the attributes to an
8838 * invalid value.
8839 */
8840 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008841lineinvalid(unsigned off, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008842{
8843 (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
8844}
8845
Bram Moolenaar071d4272004-06-13 20:20:40 +00008846/*
8847 * Copy part of a Screenline for vertically split window "wp".
8848 */
8849 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008850linecopy(int to, int from, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008851{
8852 unsigned off_to = LineOffset[to] + wp->w_wincol;
8853 unsigned off_from = LineOffset[from] + wp->w_wincol;
8854
8855 mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
8856 wp->w_width * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008857 if (enc_utf8)
8858 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008859 int i;
8860
Bram Moolenaar071d4272004-06-13 20:20:40 +00008861 mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
8862 wp->w_width * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008863 for (i = 0; i < p_mco; ++i)
8864 mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
8865 wp->w_width * sizeof(u8char_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008866 }
8867 if (enc_dbcs == DBCS_JPNU)
8868 mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
8869 wp->w_width * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008870 mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
8871 wp->w_width * sizeof(sattr_T));
8872}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008873
8874/*
8875 * Return TRUE if clearing with term string "p" would work.
8876 * It can't work when the string is empty or it won't set the right background.
Bram Moolenaar33796b32019-06-08 16:01:13 +02008877 * Don't clear to end-of-line when there are popups, it may cause flicker.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008878 */
8879 int
Bram Moolenaar05540972016-01-30 20:31:25 +01008880can_clear(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008881{
8882 return (*p != NUL && (t_colors <= 1
8883#ifdef FEAT_GUI
8884 || gui.in_use
8885#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008886#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008887 || (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
Bram Moolenaard18f6722016-06-17 13:18:49 +02008888 || (!p_tgc && cterm_normal_bg_color == 0)
8889#else
8890 || cterm_normal_bg_color == 0
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008891#endif
Bram Moolenaar33796b32019-06-08 16:01:13 +02008892 || *T_UT != NUL)
8893#ifdef FEAT_TEXT_PROP
8894 && !(p == T_CE && popup_visible)
8895#endif
8896 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00008897}
8898
8899/*
8900 * Reset cursor position. Use whenever cursor was moved because of outputting
8901 * something directly to the screen (shell commands) or a terminal control
8902 * code.
8903 */
8904 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008905screen_start(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008906{
8907 screen_cur_row = screen_cur_col = 9999;
8908}
8909
8910/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008911 * Move the cursor to position "row","col" in the screen.
8912 * This tries to find the most efficient way to move, minimizing the number of
8913 * characters sent to the terminal.
8914 */
8915 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008916windgoto(int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008917{
Bram Moolenaare2cc9702005-03-15 22:43:58 +00008918 sattr_T *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008919 int i;
8920 int plan;
8921 int cost;
8922 int wouldbe_col;
8923 int noinvcurs;
8924 char_u *bs;
8925 int goto_cost;
8926 int attr;
8927
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00008928#define GOTO_COST 7 /* assume a term_windgoto() takes about 7 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008929#define HIGHL_COST 5 /* assume unhighlight takes 5 chars */
8930
8931#define PLAN_LE 1
8932#define PLAN_CR 2
8933#define PLAN_NL 3
8934#define PLAN_WRITE 4
8935 /* Can't use ScreenLines unless initialized */
8936 if (ScreenLines == NULL)
8937 return;
8938
8939 if (col != screen_cur_col || row != screen_cur_row)
8940 {
8941 /* Check for valid position. */
8942 if (row < 0) /* window without text lines? */
8943 row = 0;
8944 if (row >= screen_Rows)
8945 row = screen_Rows - 1;
8946 if (col >= screen_Columns)
8947 col = screen_Columns - 1;
8948
8949 /* check if no cursor movement is allowed in highlight mode */
8950 if (screen_attr && *T_MS == NUL)
8951 noinvcurs = HIGHL_COST;
8952 else
8953 noinvcurs = 0;
8954 goto_cost = GOTO_COST + noinvcurs;
8955
8956 /*
8957 * Plan how to do the positioning:
8958 * 1. Use CR to move it to column 0, same row.
8959 * 2. Use T_LE to move it a few columns to the left.
8960 * 3. Use NL to move a few lines down, column 0.
8961 * 4. Move a few columns to the right with T_ND or by writing chars.
8962 *
8963 * Don't do this if the cursor went beyond the last column, the cursor
8964 * position is unknown then (some terminals wrap, some don't )
8965 *
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00008966 * First check if the highlighting attributes allow us to write
Bram Moolenaar071d4272004-06-13 20:20:40 +00008967 * characters to move the cursor to the right.
8968 */
8969 if (row >= screen_cur_row && screen_cur_col < Columns)
8970 {
8971 /*
8972 * If the cursor is in the same row, bigger col, we can use CR
8973 * or T_LE.
8974 */
8975 bs = NULL; /* init for GCC */
8976 attr = screen_attr;
8977 if (row == screen_cur_row && col < screen_cur_col)
8978 {
8979 /* "le" is preferred over "bc", because "bc" is obsolete */
8980 if (*T_LE)
8981 bs = T_LE; /* "cursor left" */
8982 else
8983 bs = T_BC; /* "backspace character (old) */
8984 if (*bs)
8985 cost = (screen_cur_col - col) * (int)STRLEN(bs);
8986 else
8987 cost = 999;
8988 if (col + 1 < cost) /* using CR is less characters */
8989 {
8990 plan = PLAN_CR;
8991 wouldbe_col = 0;
8992 cost = 1; /* CR is just one character */
8993 }
8994 else
8995 {
8996 plan = PLAN_LE;
8997 wouldbe_col = col;
8998 }
8999 if (noinvcurs) /* will stop highlighting */
9000 {
9001 cost += noinvcurs;
9002 attr = 0;
9003 }
9004 }
9005
9006 /*
9007 * If the cursor is above where we want to be, we can use CR LF.
9008 */
9009 else if (row > screen_cur_row)
9010 {
9011 plan = PLAN_NL;
9012 wouldbe_col = 0;
9013 cost = (row - screen_cur_row) * 2; /* CR LF */
9014 if (noinvcurs) /* will stop highlighting */
9015 {
9016 cost += noinvcurs;
9017 attr = 0;
9018 }
9019 }
9020
9021 /*
9022 * If the cursor is in the same row, smaller col, just use write.
9023 */
9024 else
9025 {
9026 plan = PLAN_WRITE;
9027 wouldbe_col = screen_cur_col;
9028 cost = 0;
9029 }
9030
9031 /*
9032 * Check if any characters that need to be written have the
9033 * correct attributes. Also avoid UTF-8 characters.
9034 */
9035 i = col - wouldbe_col;
9036 if (i > 0)
9037 cost += i;
9038 if (cost < goto_cost && i > 0)
9039 {
9040 /*
9041 * Check if the attributes are correct without additionally
9042 * stopping highlighting.
9043 */
9044 p = ScreenAttrs + LineOffset[row] + wouldbe_col;
9045 while (i && *p++ == attr)
9046 --i;
9047 if (i != 0)
9048 {
9049 /*
9050 * Try if it works when highlighting is stopped here.
9051 */
9052 if (*--p == 0)
9053 {
9054 cost += noinvcurs;
9055 while (i && *p++ == 0)
9056 --i;
9057 }
9058 if (i != 0)
9059 cost = 999; /* different attributes, don't do it */
9060 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009061 if (enc_utf8)
9062 {
9063 /* Don't use an UTF-8 char for positioning, it's slow. */
9064 for (i = wouldbe_col; i < col; ++i)
9065 if (ScreenLinesUC[LineOffset[row] + i] != 0)
9066 {
9067 cost = 999;
9068 break;
9069 }
9070 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009071 }
9072
9073 /*
9074 * We can do it without term_windgoto()!
9075 */
9076 if (cost < goto_cost)
9077 {
9078 if (plan == PLAN_LE)
9079 {
9080 if (noinvcurs)
9081 screen_stop_highlight();
9082 while (screen_cur_col > col)
9083 {
9084 out_str(bs);
9085 --screen_cur_col;
9086 }
9087 }
9088 else if (plan == PLAN_CR)
9089 {
9090 if (noinvcurs)
9091 screen_stop_highlight();
9092 out_char('\r');
9093 screen_cur_col = 0;
9094 }
9095 else if (plan == PLAN_NL)
9096 {
9097 if (noinvcurs)
9098 screen_stop_highlight();
9099 while (screen_cur_row < row)
9100 {
9101 out_char('\n');
9102 ++screen_cur_row;
9103 }
9104 screen_cur_col = 0;
9105 }
9106
9107 i = col - screen_cur_col;
9108 if (i > 0)
9109 {
9110 /*
9111 * Use cursor-right if it's one character only. Avoids
9112 * removing a line of pixels from the last bold char, when
9113 * using the bold trick in the GUI.
9114 */
9115 if (T_ND[0] != NUL && T_ND[1] == NUL)
9116 {
9117 while (i-- > 0)
9118 out_char(*T_ND);
9119 }
9120 else
9121 {
9122 int off;
9123
9124 off = LineOffset[row] + screen_cur_col;
9125 while (i-- > 0)
9126 {
9127 if (ScreenAttrs[off] != screen_attr)
9128 screen_stop_highlight();
Bram Moolenaar071d4272004-06-13 20:20:40 +00009129 out_flush_check();
Bram Moolenaar071d4272004-06-13 20:20:40 +00009130 out_char(ScreenLines[off]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009131 if (enc_dbcs == DBCS_JPNU
9132 && ScreenLines[off] == 0x8e)
9133 out_char(ScreenLines2[off]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009134 ++off;
9135 }
9136 }
9137 }
9138 }
9139 }
9140 else
9141 cost = 999;
9142
9143 if (cost >= goto_cost)
9144 {
9145 if (noinvcurs)
9146 screen_stop_highlight();
Bram Moolenaar597a4222014-06-25 14:39:50 +02009147 if (row == screen_cur_row && (col > screen_cur_col)
9148 && *T_CRI != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009149 term_cursor_right(col - screen_cur_col);
9150 else
9151 term_windgoto(row, col);
9152 }
9153 screen_cur_row = row;
9154 screen_cur_col = col;
9155 }
9156}
9157
9158/*
9159 * Set cursor to its position in the current window.
9160 */
9161 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009162setcursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009163{
Bram Moolenaar987723e2018-03-06 11:43:04 +01009164 setcursor_mayforce(FALSE);
9165}
9166
9167/*
9168 * Set cursor to its position in the current window.
9169 * When "force" is TRUE also when not redrawing.
9170 */
9171 void
9172setcursor_mayforce(int force)
9173{
9174 if (force || redrawing())
Bram Moolenaar071d4272004-06-13 20:20:40 +00009175 {
9176 validate_cursor();
9177 windgoto(W_WINROW(curwin) + curwin->w_wrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009178 curwin->w_wincol + (
Bram Moolenaar071d4272004-06-13 20:20:40 +00009179#ifdef FEAT_RIGHTLEFT
Bram Moolenaar561f9db2008-02-20 13:16:29 +00009180 /* With 'rightleft' set and the cursor on a double-wide
9181 * character, position it on the leftmost column. */
Bram Moolenaara12a1612019-01-24 16:39:02 +01009182 curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol
9183 - ((has_mbyte
Bram Moolenaar561f9db2008-02-20 13:16:29 +00009184 && (*mb_ptr2cells)(ml_get_cursor()) == 2
Bram Moolenaara12a1612019-01-24 16:39:02 +01009185 && vim_isprintc(gchar_cursor())) ? 2 : 1)) :
Bram Moolenaar071d4272004-06-13 20:20:40 +00009186#endif
9187 curwin->w_wcol));
9188 }
9189}
9190
9191
9192/*
Bram Moolenaar86033562017-07-12 20:24:41 +02009193 * Insert 'line_count' lines at 'row' in window 'wp'.
9194 * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
9195 * If 'mayclear' is TRUE the screen will be cleared if it is faster than
Bram Moolenaar071d4272004-06-13 20:20:40 +00009196 * scrolling.
9197 * Returns FAIL if the lines are not inserted, OK for success.
9198 */
9199 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009200win_ins_lines(
9201 win_T *wp,
9202 int row,
9203 int line_count,
9204 int invalid,
9205 int mayclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009206{
9207 int did_delete;
9208 int nextrow;
9209 int lastrow;
9210 int retval;
9211
9212 if (invalid)
9213 wp->w_lines_valid = 0;
9214
9215 if (wp->w_height < 5)
9216 return FAIL;
9217
9218 if (line_count > wp->w_height - row)
9219 line_count = wp->w_height - row;
9220
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009221 retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009222 if (retval != MAYBE)
9223 return retval;
9224
9225 /*
9226 * If there is a next window or a status line, we first try to delete the
9227 * lines at the bottom to avoid messing what is after the window.
Bram Moolenaarc363fe12019-08-04 18:13:46 +02009228 * If this fails and there are following windows, don't do anything to
9229 * avoid messing up those windows, better just redraw.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009230 */
9231 did_delete = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009232 if (wp->w_next != NULL || wp->w_status_height)
9233 {
9234 if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009235 line_count, (int)Rows, FALSE, 0, NULL) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009236 did_delete = TRUE;
9237 else if (wp->w_next)
9238 return FAIL;
9239 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009240 /*
9241 * if no lines deleted, blank the lines that will end up below the window
9242 */
9243 if (!did_delete)
9244 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009245 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009246 redraw_cmdline = TRUE;
Bram Moolenaare0de17d2017-09-24 16:24:34 +02009247 nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009248 lastrow = nextrow + line_count;
9249 if (lastrow > Rows)
9250 lastrow = Rows;
9251 screen_fill(nextrow - line_count, lastrow - line_count,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009252 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00009253 ' ', ' ', 0);
9254 }
9255
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009256 if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009257 == FAIL)
9258 {
Bram Moolenaarc363fe12019-08-04 18:13:46 +02009259 // deletion will have messed up other windows
Bram Moolenaar071d4272004-06-13 20:20:40 +00009260 if (did_delete)
9261 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009262 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009263 win_rest_invalid(W_NEXT(wp));
9264 }
9265 return FAIL;
9266 }
9267
9268 return OK;
9269}
9270
9271/*
Bram Moolenaar86033562017-07-12 20:24:41 +02009272 * Delete "line_count" window lines at "row" in window "wp".
Bram Moolenaar071d4272004-06-13 20:20:40 +00009273 * If "invalid" is TRUE curwin->w_lines[] is invalidated.
9274 * If "mayclear" is TRUE the screen will be cleared if it is faster than
9275 * scrolling
9276 * Return OK for success, FAIL if the lines are not deleted.
9277 */
9278 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009279win_del_lines(
9280 win_T *wp,
9281 int row,
9282 int line_count,
9283 int invalid,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009284 int mayclear,
9285 int clear_attr) /* for clearing lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009286{
9287 int retval;
9288
9289 if (invalid)
9290 wp->w_lines_valid = 0;
9291
9292 if (line_count > wp->w_height - row)
9293 line_count = wp->w_height - row;
9294
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009295 retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009296 if (retval != MAYBE)
9297 return retval;
9298
9299 if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009300 (int)Rows, FALSE, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009301 return FAIL;
9302
Bram Moolenaar071d4272004-06-13 20:20:40 +00009303 /*
9304 * If there are windows or status lines below, try to put them at the
9305 * correct place. If we can't do that, they have to be redrawn.
9306 */
9307 if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
9308 {
9309 if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009310 line_count, (int)Rows, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009311 {
9312 wp->w_redr_status = TRUE;
9313 win_rest_invalid(wp->w_next);
9314 }
9315 }
9316 /*
9317 * If this is the last window and there is no status line, redraw the
9318 * command line later.
9319 */
9320 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00009321 redraw_cmdline = TRUE;
9322 return OK;
9323}
9324
9325/*
9326 * Common code for win_ins_lines() and win_del_lines().
9327 * Returns OK or FAIL when the work has been done.
9328 * Returns MAYBE when not finished yet.
9329 */
9330 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01009331win_do_lines(
9332 win_T *wp,
9333 int row,
9334 int line_count,
9335 int mayclear,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009336 int del,
9337 int clear_attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009338{
9339 int retval;
9340
9341 if (!redrawing() || line_count <= 0)
9342 return FAIL;
9343
Bram Moolenaar33796b32019-06-08 16:01:13 +02009344 // When inserting lines would result in loss of command output, just redraw
9345 // the lines.
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009346 if (no_win_do_lines_ins && !del)
9347 return FAIL;
9348
Bram Moolenaar33796b32019-06-08 16:01:13 +02009349 // only a few lines left: redraw is faster
Bram Moolenaar4033c552017-09-16 20:54:51 +02009350 if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009351 {
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009352 if (!no_win_do_lines_ins)
Bram Moolenaar33796b32019-06-08 16:01:13 +02009353 screenclear(); // will set wp->w_lines_valid to 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00009354 return FAIL;
9355 }
9356
Bram Moolenaar33796b32019-06-08 16:01:13 +02009357#ifdef FEAT_TEXT_PROP
Bram Moolenaar4c063a02019-06-10 21:24:12 +02009358 // this doesn't work when there are popups visible
Bram Moolenaar33796b32019-06-08 16:01:13 +02009359 if (popup_visible)
9360 return FAIL;
9361#endif
9362
9363 // Delete all remaining lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00009364 if (row + line_count >= wp->w_height)
9365 {
9366 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009367 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00009368 ' ', ' ', 0);
9369 return OK;
9370 }
9371
9372 /*
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009373 * When scrolling, the message on the command line should be cleared,
Bram Moolenaar071d4272004-06-13 20:20:40 +00009374 * otherwise it will stay there forever.
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009375 * Don't do this when avoiding to insert lines.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009376 */
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009377 if (!no_win_do_lines_ins)
9378 clear_cmdline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009379
9380 /*
9381 * If the terminal can set a scroll region, use that.
9382 * Always do this in a vertically split window. This will redraw from
9383 * ScreenLines[] when t_CV isn't defined. That's faster than using
9384 * win_line().
9385 * Don't use a scroll region when we are going to redraw the text, writing
Bram Moolenaar48e330a2016-02-23 14:53:34 +01009386 * a character in the lower right corner of the scroll region may cause a
9387 * scroll-up .
Bram Moolenaar071d4272004-06-13 20:20:40 +00009388 */
Bram Moolenaar02631462017-09-22 15:20:32 +02009389 if (scroll_region || wp->w_width != Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009390 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009391 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009392 scroll_region_set(wp, row);
9393 if (del)
9394 retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009395 wp->w_height - row, FALSE, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009396 else
9397 retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009398 wp->w_height - row, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009399 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009400 scroll_region_reset();
9401 return retval;
9402 }
9403
Bram Moolenaar071d4272004-06-13 20:20:40 +00009404 if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
9405 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009406
9407 return MAYBE;
9408}
9409
9410/*
9411 * window 'wp' and everything after it is messed up, mark it for redraw
9412 */
9413 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009414win_rest_invalid(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009415{
Bram Moolenaar071d4272004-06-13 20:20:40 +00009416 while (wp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009417 {
9418 redraw_win_later(wp, NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009419 wp->w_redr_status = TRUE;
9420 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009421 }
9422 redraw_cmdline = TRUE;
9423}
9424
9425/*
9426 * The rest of the routines in this file perform screen manipulations. The
9427 * given operation is performed physically on the screen. The corresponding
9428 * change is also made to the internal screen image. In this way, the editor
9429 * anticipates the effect of editing changes on the appearance of the screen.
9430 * That way, when we call screenupdate a complete redraw isn't usually
9431 * necessary. Another advantage is that we can keep adding code to anticipate
9432 * screen changes, and in the meantime, everything still works.
9433 */
9434
9435/*
9436 * types for inserting or deleting lines
9437 */
9438#define USE_T_CAL 1
9439#define USE_T_CDL 2
9440#define USE_T_AL 3
9441#define USE_T_CE 4
9442#define USE_T_DL 5
9443#define USE_T_SR 6
9444#define USE_NL 7
9445#define USE_T_CD 8
9446#define USE_REDRAW 9
9447
9448/*
9449 * insert lines on the screen and update ScreenLines[]
9450 * 'end' is the line after the scrolled part. Normally it is Rows.
9451 * When scrolling region used 'off' is the offset from the top for the region.
9452 * 'row' and 'end' are relative to the start of the region.
9453 *
9454 * return FAIL for failure, OK for success.
9455 */
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00009456 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009457screen_ins_lines(
9458 int off,
9459 int row,
9460 int line_count,
9461 int end,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009462 int clear_attr,
Bram Moolenaar05540972016-01-30 20:31:25 +01009463 win_T *wp) /* NULL or window to use width from */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009464{
9465 int i;
9466 int j;
9467 unsigned temp;
9468 int cursor_row;
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009469 int cursor_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009470 int type;
9471 int result_empty;
9472 int can_ce = can_clear(T_CE);
9473
9474 /*
9475 * FAIL if
9476 * - there is no valid screen
9477 * - the screen has to be redrawn completely
9478 * - the line count is less than one
9479 * - the line count is more than 'ttyscroll'
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009480 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar33796b32019-06-08 16:01:13 +02009481 * - there is a popup window
Bram Moolenaar071d4272004-06-13 20:20:40 +00009482 */
Bram Moolenaar33796b32019-06-08 16:01:13 +02009483 if (!screen_valid(TRUE)
9484 || line_count <= 0 || line_count > p_ttyscroll
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009485#ifdef FEAT_CLIPBOARD
9486 || (clip_star.state != SELECT_CLEARED
9487 && redrawing_for_callback > 0)
9488#endif
Bram Moolenaar33796b32019-06-08 16:01:13 +02009489#ifdef FEAT_TEXT_PROP
9490 || popup_visible
9491#endif
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009492 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00009493 return FAIL;
9494
9495 /*
9496 * There are seven ways to insert lines:
9497 * 0. When in a vertically split window and t_CV isn't set, redraw the
9498 * characters from ScreenLines[].
9499 * 1. Use T_CD (clear to end of display) if it exists and the result of
9500 * the insert is just empty lines
9501 * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
9502 * present or line_count > 1. It looks better if we do all the inserts
9503 * at once.
9504 * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
9505 * insert is just empty lines and T_CE is not present or line_count >
9506 * 1.
9507 * 4. Use T_AL (insert line) if it exists.
9508 * 5. Use T_CE (erase line) if it exists and the result of the insert is
9509 * just empty lines.
9510 * 6. Use T_DL (delete line) if it exists and the result of the insert is
9511 * just empty lines.
9512 * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
9513 * the 'da' flag is not set or we have clear line capability.
9514 * 8. redraw the characters from ScreenLines[].
9515 *
9516 * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
9517 * the scrollbar for the window. It does have insert line, use that if it
9518 * exists.
9519 */
9520 result_empty = (row + line_count >= end);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009521 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
9522 type = USE_REDRAW;
Bram Moolenaar4033c552017-09-16 20:54:51 +02009523 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009524 type = USE_T_CD;
9525 else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
9526 type = USE_T_CAL;
9527 else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
9528 type = USE_T_CDL;
9529 else if (*T_AL != NUL)
9530 type = USE_T_AL;
9531 else if (can_ce && result_empty)
9532 type = USE_T_CE;
9533 else if (*T_DL != NUL && result_empty)
9534 type = USE_T_DL;
9535 else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
9536 type = USE_T_SR;
9537 else
9538 return FAIL;
9539
9540 /*
9541 * For clearing the lines screen_del_lines() is used. This will also take
9542 * care of t_db if necessary.
9543 */
9544 if (type == USE_T_CD || type == USE_T_CDL ||
9545 type == USE_T_CE || type == USE_T_DL)
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009546 return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009547
9548 /*
9549 * If text is retained below the screen, first clear or delete as many
9550 * lines at the bottom of the window as are about to be inserted so that
9551 * the deleted lines won't later surface during a screen_del_lines.
9552 */
9553 if (*T_DB)
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009554 screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009555
9556#ifdef FEAT_CLIPBOARD
9557 /* Remove a modeless selection when inserting lines halfway the screen
9558 * or not the full width of the screen. */
Bram Moolenaar4033c552017-09-16 20:54:51 +02009559 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02009560 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009561 else
9562 clip_scroll_selection(-line_count);
9563#endif
9564
Bram Moolenaar071d4272004-06-13 20:20:40 +00009565#ifdef FEAT_GUI
9566 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
9567 * scrolling is actually carried out. */
Bram Moolenaar107abd22016-08-12 14:08:25 +02009568 gui_dont_update_cursor(row + off <= gui.cursor_row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009569#endif
9570
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009571 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
9572 cursor_col = wp->w_wincol;
9573
Bram Moolenaar071d4272004-06-13 20:20:40 +00009574 if (*T_CCS != NUL) /* cursor relative to region */
9575 cursor_row = row;
9576 else
9577 cursor_row = row + off;
9578
9579 /*
9580 * Shift LineOffset[] line_count down to reflect the inserted lines.
9581 * Clear the inserted lines in ScreenLines[].
9582 */
9583 row += off;
9584 end += off;
9585 for (i = 0; i < line_count; ++i)
9586 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009587 if (wp != NULL && wp->w_width != Columns)
9588 {
9589 /* need to copy part of a line */
9590 j = end - 1 - i;
9591 while ((j -= line_count) >= row)
9592 linecopy(j + line_count, j, wp);
9593 j += line_count;
9594 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009595 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
9596 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009597 else
9598 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
9599 LineWraps[j] = FALSE;
9600 }
9601 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00009602 {
9603 j = end - 1 - i;
9604 temp = LineOffset[j];
9605 while ((j -= line_count) >= row)
9606 {
9607 LineOffset[j + line_count] = LineOffset[j];
9608 LineWraps[j + line_count] = LineWraps[j];
9609 }
9610 LineOffset[j + line_count] = temp;
9611 LineWraps[j + line_count] = FALSE;
9612 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009613 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009614 else
9615 lineinvalid(temp, (int)Columns);
9616 }
9617 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009618
9619 screen_stop_highlight();
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009620 windgoto(cursor_row, cursor_col);
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009621 if (clear_attr != 0)
9622 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009623
Bram Moolenaar071d4272004-06-13 20:20:40 +00009624 /* redraw the characters */
9625 if (type == USE_REDRAW)
9626 redraw_block(row, end, wp);
Bram Moolenaar4033c552017-09-16 20:54:51 +02009627 else if (type == USE_T_CAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009628 {
9629 term_append_lines(line_count);
9630 screen_start(); /* don't know where cursor is now */
9631 }
9632 else
9633 {
9634 for (i = 0; i < line_count; i++)
9635 {
9636 if (type == USE_T_AL)
9637 {
9638 if (i && cursor_row != 0)
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009639 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009640 out_str(T_AL);
9641 }
9642 else /* type == USE_T_SR */
9643 out_str(T_SR);
9644 screen_start(); /* don't know where cursor is now */
9645 }
9646 }
9647
9648 /*
9649 * With scroll-reverse and 'da' flag set we need to clear the lines that
9650 * have been scrolled down into the region.
9651 */
9652 if (type == USE_T_SR && *T_DA)
9653 {
9654 for (i = 0; i < line_count; ++i)
9655 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009656 windgoto(off + i, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009657 out_str(T_CE);
9658 screen_start(); /* don't know where cursor is now */
9659 }
9660 }
9661
9662#ifdef FEAT_GUI
9663 gui_can_update_cursor();
9664 if (gui.in_use)
9665 out_flush(); /* always flush after a scroll */
9666#endif
9667 return OK;
9668}
9669
9670/*
Bram Moolenaar107abd22016-08-12 14:08:25 +02009671 * Delete lines on the screen and update ScreenLines[].
9672 * "end" is the line after the scrolled part. Normally it is Rows.
9673 * When scrolling region used "off" is the offset from the top for the region.
9674 * "row" and "end" are relative to the start of the region.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009675 *
9676 * Return OK for success, FAIL if the lines are not deleted.
9677 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009678 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009679screen_del_lines(
9680 int off,
9681 int row,
9682 int line_count,
9683 int end,
9684 int force, /* even when line_count > p_ttyscroll */
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009685 int clear_attr, /* used for clearing lines */
Bram Moolenaar05540972016-01-30 20:31:25 +01009686 win_T *wp UNUSED) /* NULL or window to use width from */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009687{
9688 int j;
9689 int i;
9690 unsigned temp;
9691 int cursor_row;
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009692 int cursor_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009693 int cursor_end;
9694 int result_empty; /* result is empty until end of region */
9695 int can_delete; /* deleting line codes can be used */
9696 int type;
9697
9698 /*
9699 * FAIL if
9700 * - there is no valid screen
9701 * - the screen has to be redrawn completely
9702 * - the line count is less than one
9703 * - the line count is more than 'ttyscroll'
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009704 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar071d4272004-06-13 20:20:40 +00009705 */
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009706 if (!screen_valid(TRUE) || line_count <= 0
9707 || (!force && line_count > p_ttyscroll)
9708#ifdef FEAT_CLIPBOARD
9709 || (clip_star.state != SELECT_CLEARED
9710 && redrawing_for_callback > 0)
9711#endif
9712 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00009713 return FAIL;
9714
9715 /*
9716 * Check if the rest of the current region will become empty.
9717 */
9718 result_empty = row + line_count >= end;
9719
9720 /*
9721 * We can delete lines only when 'db' flag not set or when 'ce' option
9722 * available.
9723 */
9724 can_delete = (*T_DB == NUL || can_clear(T_CE));
9725
9726 /*
9727 * There are six ways to delete lines:
9728 * 0. When in a vertically split window and t_CV isn't set, redraw the
9729 * characters from ScreenLines[].
9730 * 1. Use T_CD if it exists and the result is empty.
9731 * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
9732 * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
9733 * none of the other ways work.
9734 * 4. Use T_CE (erase line) if the result is empty.
9735 * 5. Use T_DL (delete line) if it exists.
9736 * 6. redraw the characters from ScreenLines[].
9737 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009738 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
9739 type = USE_REDRAW;
Bram Moolenaar4033c552017-09-16 20:54:51 +02009740 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009741 type = USE_T_CD;
9742#if defined(__BEOS__) && defined(BEOS_DR8)
9743 /*
9744 * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
9745 * its internal termcap... this works okay for tests which test *T_DB !=
9746 * NUL. It has the disadvantage that the user cannot use any :set t_*
9747 * command to get T_DB (back) to empty_option, only :set term=... will do
9748 * the trick...
9749 * Anyway, this hack will hopefully go away with the next OS release.
9750 * (Olaf Seibert)
9751 */
9752 else if (row == 0 && T_DB == empty_option
9753 && (line_count == 1 || *T_CDL == NUL))
9754#else
9755 else if (row == 0 && (
9756#ifndef AMIGA
9757 /* On the Amiga, somehow '\n' on the last line doesn't always scroll
9758 * up, so use delete-line command */
9759 line_count == 1 ||
9760#endif
9761 *T_CDL == NUL))
9762#endif
9763 type = USE_NL;
9764 else if (*T_CDL != NUL && line_count > 1 && can_delete)
9765 type = USE_T_CDL;
9766 else if (can_clear(T_CE) && result_empty
Bram Moolenaar4033c552017-09-16 20:54:51 +02009767 && (wp == NULL || wp->w_width == Columns))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009768 type = USE_T_CE;
9769 else if (*T_DL != NUL && can_delete)
9770 type = USE_T_DL;
9771 else if (*T_CDL != NUL && can_delete)
9772 type = USE_T_CDL;
9773 else
9774 return FAIL;
9775
9776#ifdef FEAT_CLIPBOARD
9777 /* Remove a modeless selection when deleting lines halfway the screen or
9778 * not the full width of the screen. */
Bram Moolenaar4033c552017-09-16 20:54:51 +02009779 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02009780 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009781 else
9782 clip_scroll_selection(line_count);
9783#endif
9784
Bram Moolenaar071d4272004-06-13 20:20:40 +00009785#ifdef FEAT_GUI
9786 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
9787 * scrolling is actually carried out. */
Bram Moolenaar107abd22016-08-12 14:08:25 +02009788 gui_dont_update_cursor(gui.cursor_row >= row + off
9789 && gui.cursor_row < end + off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009790#endif
9791
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009792 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
9793 cursor_col = wp->w_wincol;
9794
Bram Moolenaar071d4272004-06-13 20:20:40 +00009795 if (*T_CCS != NUL) /* cursor relative to region */
9796 {
9797 cursor_row = row;
9798 cursor_end = end;
9799 }
9800 else
9801 {
9802 cursor_row = row + off;
9803 cursor_end = end + off;
9804 }
9805
9806 /*
9807 * Now shift LineOffset[] line_count up to reflect the deleted lines.
9808 * Clear the inserted lines in ScreenLines[].
9809 */
9810 row += off;
9811 end += off;
9812 for (i = 0; i < line_count; ++i)
9813 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009814 if (wp != NULL && wp->w_width != Columns)
9815 {
9816 /* need to copy part of a line */
9817 j = row + i;
9818 while ((j += line_count) <= end - 1)
9819 linecopy(j - line_count, j, wp);
9820 j -= line_count;
9821 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009822 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
9823 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009824 else
9825 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
9826 LineWraps[j] = FALSE;
9827 }
9828 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00009829 {
9830 /* whole width, moving the line pointers is faster */
9831 j = row + i;
9832 temp = LineOffset[j];
9833 while ((j += line_count) <= end - 1)
9834 {
9835 LineOffset[j - line_count] = LineOffset[j];
9836 LineWraps[j - line_count] = LineWraps[j];
9837 }
9838 LineOffset[j - line_count] = temp;
9839 LineWraps[j - line_count] = FALSE;
9840 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009841 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009842 else
9843 lineinvalid(temp, (int)Columns);
9844 }
9845 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009846
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009847 if (screen_attr != clear_attr)
9848 screen_stop_highlight();
9849 if (clear_attr != 0)
9850 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009851
Bram Moolenaar071d4272004-06-13 20:20:40 +00009852 /* redraw the characters */
9853 if (type == USE_REDRAW)
9854 redraw_block(row, end, wp);
Bram Moolenaar4033c552017-09-16 20:54:51 +02009855 else if (type == USE_T_CD) /* delete the lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009856 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009857 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009858 out_str(T_CD);
9859 screen_start(); /* don't know where cursor is now */
9860 }
9861 else if (type == USE_T_CDL)
9862 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009863 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009864 term_delete_lines(line_count);
9865 screen_start(); /* don't know where cursor is now */
9866 }
9867 /*
9868 * Deleting lines at top of the screen or scroll region: Just scroll
9869 * the whole screen (scroll region) up by outputting newlines on the
9870 * last line.
9871 */
9872 else if (type == USE_NL)
9873 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009874 windgoto(cursor_end - 1, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009875 for (i = line_count; --i >= 0; )
9876 out_char('\n'); /* cursor will remain on same line */
9877 }
9878 else
9879 {
9880 for (i = line_count; --i >= 0; )
9881 {
9882 if (type == USE_T_DL)
9883 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009884 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009885 out_str(T_DL); /* delete a line */
9886 }
9887 else /* type == USE_T_CE */
9888 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009889 windgoto(cursor_row + i, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009890 out_str(T_CE); /* erase a line */
9891 }
9892 screen_start(); /* don't know where cursor is now */
9893 }
9894 }
9895
9896 /*
9897 * If the 'db' flag is set, we need to clear the lines that have been
9898 * scrolled up at the bottom of the region.
9899 */
9900 if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
9901 {
9902 for (i = line_count; i > 0; --i)
9903 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02009904 windgoto(cursor_end - i, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009905 out_str(T_CE); /* erase a line */
9906 screen_start(); /* don't know where cursor is now */
9907 }
9908 }
9909
9910#ifdef FEAT_GUI
9911 gui_can_update_cursor();
9912 if (gui.in_use)
9913 out_flush(); /* always flush after a scroll */
9914#endif
9915
9916 return OK;
9917}
9918
9919/*
Bram Moolenaarcb574f42019-01-25 22:29:57 +01009920 * Return TRUE when postponing displaying the mode message: when not redrawing
9921 * or inside a mapping.
9922 */
9923 int
9924skip_showmode()
9925{
9926 // Call char_avail() only when we are going to show something, because it
9927 // takes a bit of time. redrawing() may also call char_avail_avail().
9928 if (global_busy
9929 || msg_silent != 0
9930 || !redrawing()
9931 || (char_avail() && !KeyTyped))
9932 {
Bram Moolenaar4c25bd72019-04-20 23:38:07 +02009933 redraw_mode = TRUE; // show mode later
Bram Moolenaarcb574f42019-01-25 22:29:57 +01009934 return TRUE;
9935 }
9936 return FALSE;
9937}
9938
9939/*
Bram Moolenaar81226e02018-02-20 21:44:45 +01009940 * Show the current mode and ruler.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009941 *
9942 * If clear_cmdline is TRUE, clear the rest of the cmdline.
9943 * If clear_cmdline is FALSE there may be a message there that needs to be
9944 * cleared only if a mode is shown.
Bram Moolenaar4c25bd72019-04-20 23:38:07 +02009945 * If redraw_mode is TRUE show or clear the mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009946 * Return the length of the message (0 if no message).
9947 */
9948 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009949showmode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009950{
9951 int need_clear;
9952 int length = 0;
9953 int do_mode;
9954 int attr;
9955 int nwr_save;
9956#ifdef FEAT_INS_EXPAND
9957 int sub_attr;
9958#endif
9959
Bram Moolenaar7df351e2006-01-23 22:30:28 +00009960 do_mode = ((p_smd && msg_silent == 0)
9961 && ((State & INSERT)
Bram Moolenaar942b4542018-06-17 16:23:34 +02009962 || restart_edit != NUL
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01009963 || VIsual_active));
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009964 if (do_mode || reg_recording != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009965 {
Bram Moolenaarcb574f42019-01-25 22:29:57 +01009966 if (skip_showmode())
9967 return 0; // show mode later
Bram Moolenaar071d4272004-06-13 20:20:40 +00009968
9969 nwr_save = need_wait_return;
9970
9971 /* wait a bit before overwriting an important message */
9972 check_for_delay(FALSE);
9973
9974 /* if the cmdline is more than one line high, erase top lines */
9975 need_clear = clear_cmdline;
9976 if (clear_cmdline && cmdline_row < Rows - 1)
9977 msg_clr_cmdline(); /* will reset clear_cmdline */
9978
9979 /* Position on the last line in the window, column 0 */
9980 msg_pos_mode();
9981 cursor_off();
Bram Moolenaar8820b482017-03-16 17:23:31 +01009982 attr = HL_ATTR(HLF_CM); /* Highlight mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009983 if (do_mode)
9984 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01009985 msg_puts_attr("--", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009986#if defined(FEAT_XIM)
Bram Moolenaarc236c162008-07-13 17:41:49 +00009987 if (
Bram Moolenaar09092152010-08-08 16:38:42 +02009988# ifdef FEAT_GUI_GTK
Bram Moolenaarc236c162008-07-13 17:41:49 +00009989 preedit_get_status()
Bram Moolenaar09092152010-08-08 16:38:42 +02009990# else
Bram Moolenaarc236c162008-07-13 17:41:49 +00009991 im_get_status()
Bram Moolenaarc236c162008-07-13 17:41:49 +00009992# endif
Bram Moolenaar09092152010-08-08 16:38:42 +02009993 )
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02009994# ifdef FEAT_GUI_GTK /* most of the time, it's not XIM being used */
Bram Moolenaar32526b32019-01-19 17:43:09 +01009995 msg_puts_attr(" IM", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009996# else
Bram Moolenaar32526b32019-01-19 17:43:09 +01009997 msg_puts_attr(" XIM", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009998# endif
9999#endif
10000#if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
10001 if (gui.in_use)
10002 {
10003 if (hangul_input_state_get())
Bram Moolenaar72f4cc42015-11-10 14:35:18 +010010004 {
10005 /* HANGUL */
10006 if (enc_utf8)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010007 msg_puts_attr(" \355\225\234\352\270\200", attr);
Bram Moolenaar72f4cc42015-11-10 14:35:18 +010010008 else
Bram Moolenaar32526b32019-01-19 17:43:09 +010010009 msg_puts_attr(" \307\321\261\333", attr);
Bram Moolenaar72f4cc42015-11-10 14:35:18 +010010010 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010011 }
10012#endif
10013#ifdef FEAT_INS_EXPAND
Bram Moolenaarea389e92014-05-28 21:40:52 +020010014 /* CTRL-X in Insert mode */
10015 if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
Bram Moolenaar071d4272004-06-13 20:20:40 +000010016 {
10017 /* These messages can get long, avoid a wrap in a narrow
10018 * window. Prefer showing edit_submode_extra. */
10019 length = (Rows - msg_row) * Columns - 3;
10020 if (edit_submode_extra != NULL)
10021 length -= vim_strsize(edit_submode_extra);
10022 if (length > 0)
10023 {
10024 if (edit_submode_pre != NULL)
10025 length -= vim_strsize(edit_submode_pre);
10026 if (length - vim_strsize(edit_submode) > 0)
10027 {
10028 if (edit_submode_pre != NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010029 msg_puts_attr((char *)edit_submode_pre, attr);
10030 msg_puts_attr((char *)edit_submode, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010031 }
10032 if (edit_submode_extra != NULL)
10033 {
Bram Moolenaar32526b32019-01-19 17:43:09 +010010034 msg_puts_attr(" ", attr); /* add a space in between */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010035 if ((int)edit_submode_highl < (int)HLF_COUNT)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010036 sub_attr = HL_ATTR(edit_submode_highl);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010037 else
10038 sub_attr = attr;
Bram Moolenaar32526b32019-01-19 17:43:09 +010010039 msg_puts_attr((char *)edit_submode_extra, sub_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010040 }
10041 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010042 }
10043 else
10044#endif
10045 {
Bram Moolenaar071d4272004-06-13 20:20:40 +000010046 if (State & VREPLACE_FLAG)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010047 msg_puts_attr(_(" VREPLACE"), attr);
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +020010048 else if (State & REPLACE_FLAG)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010049 msg_puts_attr(_(" REPLACE"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010050 else if (State & INSERT)
10051 {
10052#ifdef FEAT_RIGHTLEFT
10053 if (p_ri)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010054 msg_puts_attr(_(" REVERSE"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010055#endif
Bram Moolenaar32526b32019-01-19 17:43:09 +010010056 msg_puts_attr(_(" INSERT"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010057 }
Bram Moolenaar942b4542018-06-17 16:23:34 +020010058 else if (restart_edit == 'I' || restart_edit == 'A')
Bram Moolenaar32526b32019-01-19 17:43:09 +010010059 msg_puts_attr(_(" (insert)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010060 else if (restart_edit == 'R')
Bram Moolenaar32526b32019-01-19 17:43:09 +010010061 msg_puts_attr(_(" (replace)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010062 else if (restart_edit == 'V')
Bram Moolenaar32526b32019-01-19 17:43:09 +010010063 msg_puts_attr(_(" (vreplace)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010064#ifdef FEAT_RIGHTLEFT
10065 if (p_hkmap)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010066 msg_puts_attr(_(" Hebrew"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010067#endif
10068#ifdef FEAT_KEYMAP
10069 if (State & LANGMAP)
10070 {
10071# ifdef FEAT_ARABIC
10072 if (curwin->w_p_arab)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010073 msg_puts_attr(_(" Arabic"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010074 else
10075# endif
Bram Moolenaar73ac0c42016-07-24 16:17:59 +020010076 if (get_keymap_str(curwin, (char_u *)" (%s)",
10077 NameBuff, MAXPATHL))
Bram Moolenaar32526b32019-01-19 17:43:09 +010010078 msg_puts_attr((char *)NameBuff, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010079 }
10080#endif
10081 if ((State & INSERT) && p_paste)
Bram Moolenaar32526b32019-01-19 17:43:09 +010010082 msg_puts_attr(_(" (paste)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010083
Bram Moolenaar071d4272004-06-13 20:20:40 +000010084 if (VIsual_active)
10085 {
10086 char *p;
10087
10088 /* Don't concatenate separate words to avoid translation
10089 * problems. */
10090 switch ((VIsual_select ? 4 : 0)
10091 + (VIsual_mode == Ctrl_V) * 2
10092 + (VIsual_mode == 'V'))
10093 {
10094 case 0: p = N_(" VISUAL"); break;
10095 case 1: p = N_(" VISUAL LINE"); break;
10096 case 2: p = N_(" VISUAL BLOCK"); break;
10097 case 4: p = N_(" SELECT"); break;
10098 case 5: p = N_(" SELECT LINE"); break;
10099 default: p = N_(" SELECT BLOCK"); break;
10100 }
Bram Moolenaar32526b32019-01-19 17:43:09 +010010101 msg_puts_attr(_(p), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010102 }
Bram Moolenaar32526b32019-01-19 17:43:09 +010010103 msg_puts_attr(" --", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010104 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010105
Bram Moolenaar071d4272004-06-13 20:20:40 +000010106 need_clear = TRUE;
10107 }
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010108 if (reg_recording != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +000010109#ifdef FEAT_INS_EXPAND
10110 && edit_submode == NULL /* otherwise it gets too long */
10111#endif
10112 )
10113 {
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010114 recording_mode(attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010115 need_clear = TRUE;
10116 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010117
10118 mode_displayed = TRUE;
Bram Moolenaar4c25bd72019-04-20 23:38:07 +020010119 if (need_clear || clear_cmdline || redraw_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010120 msg_clr_eos();
10121 msg_didout = FALSE; /* overwrite this message */
10122 length = msg_col;
10123 msg_col = 0;
10124 need_wait_return = nwr_save; /* never ask for hit-return for this */
10125 }
10126 else if (clear_cmdline && msg_silent == 0)
10127 /* Clear the whole command line. Will reset "clear_cmdline". */
10128 msg_clr_cmdline();
Bram Moolenaar4c25bd72019-04-20 23:38:07 +020010129 else if (redraw_mode)
10130 {
10131 msg_pos_mode();
10132 msg_clr_eos();
10133 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010134
10135#ifdef FEAT_CMDL_INFO
Bram Moolenaar071d4272004-06-13 20:20:40 +000010136 /* In Visual mode the size of the selected area must be redrawn. */
10137 if (VIsual_active)
10138 clear_showcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +000010139
10140 /* If the last window has no status line, the ruler is after the mode
10141 * message and must be redrawn */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010142 if (redrawing() && lastwin->w_status_height == 0)
Bram Moolenaar491ac282018-06-17 14:47:55 +020010143 win_redr_ruler(lastwin, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010144#endif
10145 redraw_cmdline = FALSE;
Bram Moolenaar4c25bd72019-04-20 23:38:07 +020010146 redraw_mode = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010147 clear_cmdline = FALSE;
10148
10149 return length;
10150}
10151
10152/*
10153 * Position for a mode message.
10154 */
10155 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010156msg_pos_mode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010157{
10158 msg_col = 0;
10159 msg_row = Rows - 1;
10160}
10161
10162/*
10163 * Delete mode message. Used when ESC is typed which is expected to end
10164 * Insert mode (but Insert mode didn't end yet!).
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010165 * Caller should check "mode_displayed".
Bram Moolenaar071d4272004-06-13 20:20:40 +000010166 */
10167 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010168unshowmode(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010169{
10170 /*
Bram Moolenaare4ebd292010-01-19 17:40:46 +010010171 * Don't delete it right now, when not redrawing or inside a mapping.
Bram Moolenaar071d4272004-06-13 20:20:40 +000010172 */
10173 if (!redrawing() || (!force && char_avail() && !KeyTyped))
10174 redraw_cmdline = TRUE; /* delete mode later */
10175 else
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010176 clearmode();
10177}
10178
10179/*
10180 * Clear the mode message.
10181 */
10182 void
Bram Moolenaarcf089462016-06-12 21:18:43 +020010183clearmode(void)
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010184{
Bram Moolenaar2abad542018-05-19 14:43:45 +020010185 int save_msg_row = msg_row;
10186 int save_msg_col = msg_col;
10187
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010188 msg_pos_mode();
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010189 if (reg_recording != 0)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010190 recording_mode(HL_ATTR(HLF_CM));
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010191 msg_clr_eos();
Bram Moolenaar2abad542018-05-19 14:43:45 +020010192
10193 msg_col = save_msg_col;
10194 msg_row = save_msg_row;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010195}
10196
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010197 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010198recording_mode(int attr)
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010199{
Bram Moolenaar32526b32019-01-19 17:43:09 +010010200 msg_puts_attr(_("recording"), attr);
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010201 if (!shortmess(SHM_RECORDING))
10202 {
Bram Moolenaar32526b32019-01-19 17:43:09 +010010203 char s[4];
10204
10205 sprintf(s, " @%c", reg_recording);
10206 msg_puts_attr(s, attr);
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010207 }
10208}
10209
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010210/*
10211 * Draw the tab pages line at the top of the Vim window.
10212 */
Bram Moolenaare12bab32019-01-08 22:02:56 +010010213 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010214draw_tabline(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010215{
10216 int tabcount = 0;
10217 tabpage_T *tp;
10218 int tabwidth;
10219 int col = 0;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010220 int scol = 0;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010221 int attr;
10222 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010223 win_T *cwp;
10224 int wincount;
10225 int modified;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010226 int c;
10227 int len;
Bram Moolenaar8820b482017-03-16 17:23:31 +010010228 int attr_sel = HL_ATTR(HLF_TPS);
10229 int attr_nosel = HL_ATTR(HLF_TP);
10230 int attr_fill = HL_ATTR(HLF_TPF);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010231 char_u *p;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010232 int room;
10233 int use_sep_chars = (t_colors < 8
10234#ifdef FEAT_GUI
10235 && !gui.in_use
10236#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +020010237#ifdef FEAT_TERMGUICOLORS
10238 && !p_tgc
Bram Moolenaar8a633e32016-04-21 21:10:14 +020010239#endif
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010240 );
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010241
Bram Moolenaarc695cec2017-01-08 20:00:04 +010010242 if (ScreenLines == NULL)
10243 return;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010244 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010245
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010246#ifdef FEAT_GUI_TABLINE
Bram Moolenaardb552d602006-03-23 22:59:57 +000010247 /* Take care of a GUI tabline. */
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010248 if (gui_use_tabline())
10249 {
10250 gui_update_tabline();
10251 return;
10252 }
10253#endif
10254
10255 if (tabline_height() < 1)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010256 return;
10257
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010258#if defined(FEAT_STL_OPT)
Bram Moolenaarca57ab52019-04-13 14:53:16 +020010259 clear_TabPageIdxs();
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010260
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010261 /* Use the 'tabline' option if it's set. */
10262 if (*p_tal != NUL)
10263 {
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010264 int saved_did_emsg = did_emsg;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010265
10266 /* Check for an error. If there is one we would loop in redrawing the
10267 * screen. Avoid that by making 'tabline' empty. */
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010268 did_emsg = FALSE;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010269 win_redr_custom(NULL, FALSE);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010270 if (did_emsg)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010271 set_string_option_direct((char_u *)"tabline", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +000010272 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010273 did_emsg |= saved_did_emsg;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010274 }
Bram Moolenaar238a5642006-02-21 22:12:05 +000010275 else
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010276#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010277 {
Bram Moolenaar29323592016-07-24 22:04:11 +020010278 FOR_ALL_TABPAGES(tp)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010279 ++tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010280
Bram Moolenaar238a5642006-02-21 22:12:05 +000010281 tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
10282 if (tabwidth < 6)
10283 tabwidth = 6;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010284
Bram Moolenaar238a5642006-02-21 22:12:05 +000010285 attr = attr_nosel;
10286 tabcount = 0;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010287 for (tp = first_tabpage; tp != NULL && col < Columns - 4;
10288 tp = tp->tp_next)
Bram Moolenaarf740b292006-02-16 22:11:02 +000010289 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010290 scol = col;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010291
Bram Moolenaar238a5642006-02-21 22:12:05 +000010292 if (tp->tp_topframe == topframe)
10293 attr = attr_sel;
10294 if (use_sep_chars && col > 0)
10295 screen_putchar('|', 0, col++, attr);
10296
10297 if (tp->tp_topframe != topframe)
10298 attr = attr_nosel;
10299
10300 screen_putchar(' ', 0, col++, attr);
10301
10302 if (tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +000010303 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010304 cwp = curwin;
10305 wp = firstwin;
10306 }
10307 else
10308 {
10309 cwp = tp->tp_curwin;
10310 wp = tp->tp_firstwin;
10311 }
10312
10313 modified = FALSE;
10314 for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
10315 if (bufIsChanged(wp->w_buffer))
10316 modified = TRUE;
10317 if (modified || wincount > 1)
10318 {
10319 if (wincount > 1)
10320 {
10321 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +000010322 len = (int)STRLEN(NameBuff);
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010323 if (col + len >= Columns - 3)
10324 break;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010325 screen_puts_len(NameBuff, len, 0, col,
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010326#if defined(FEAT_SYN_HL)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010327 hl_combine_attr(attr, HL_ATTR(HLF_T))
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010328#else
Bram Moolenaare0f14822014-08-06 13:20:56 +020010329 attr
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010330#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +000010331 );
10332 col += len;
10333 }
10334 if (modified)
10335 screen_puts_len((char_u *)"+", 1, 0, col++, attr);
10336 screen_putchar(' ', 0, col++, attr);
10337 }
10338
10339 room = scol - col + tabwidth - 1;
10340 if (room > 0)
10341 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010342 /* Get buffer name in NameBuff[] */
10343 get_trans_bufname(cwp->w_buffer);
Bram Moolenaar910f66f2006-04-05 20:41:53 +000010344 shorten_dir(NameBuff);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010345 len = vim_strsize(NameBuff);
10346 p = NameBuff;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010347 if (has_mbyte)
10348 while (len > room)
10349 {
10350 len -= ptr2cells(p);
Bram Moolenaar91acfff2017-03-12 19:22:36 +010010351 MB_PTR_ADV(p);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010352 }
Bram Moolenaara12a1612019-01-24 16:39:02 +010010353 else if (len > room)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010354 {
10355 p += len - room;
10356 len = room;
10357 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010358 if (len > Columns - col - 1)
10359 len = Columns - col - 1;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010360
Bram Moolenaara93fa7e2006-04-17 22:14:47 +000010361 screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
Bram Moolenaarf740b292006-02-16 22:11:02 +000010362 col += len;
10363 }
Bram Moolenaarf740b292006-02-16 22:11:02 +000010364 screen_putchar(' ', 0, col++, attr);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010365
10366 /* Store the tab page number in TabPageIdxs[], so that
10367 * jump_to_mouse() knows where each one is. */
10368 ++tabcount;
10369 while (scol < col)
10370 TabPageIdxs[scol++] = tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010371 }
10372
Bram Moolenaar238a5642006-02-21 22:12:05 +000010373 if (use_sep_chars)
10374 c = '_';
10375 else
10376 c = ' ';
10377 screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010378
10379 /* Put an "X" for closing the current tab if there are several. */
10380 if (first_tabpage->tp_next != NULL)
10381 {
10382 screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
10383 TabPageIdxs[Columns - 1] = -999;
10384 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010385 }
Bram Moolenaarb21e5842006-04-16 18:30:08 +000010386
10387 /* Reset the flag here again, in case evaluating 'tabline' causes it to be
10388 * set. */
10389 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010390}
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010391
10392/*
10393 * Get buffer name for "buf" into NameBuff[].
10394 * Takes care of special buffer names and translates special characters.
10395 */
10396 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010397get_trans_bufname(buf_T *buf)
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010398{
10399 if (buf_spname(buf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +020010400 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010401 else
10402 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
10403 trans_characters(NameBuff, MAXPATHL);
10404}
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010405
Bram Moolenaar071d4272004-06-13 20:20:40 +000010406/*
10407 * Get the character to use in a status line. Get its attributes in "*attr".
10408 */
10409 static int
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010410fillchar_status(int *attr, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010411{
10412 int fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010413
10414#ifdef FEAT_TERMINAL
10415 if (bt_terminal(wp->w_buffer))
10416 {
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010417 if (wp == curwin)
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010418 {
10419 *attr = HL_ATTR(HLF_ST);
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010420 fill = fill_stl;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010421 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010422 else
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010423 {
10424 *attr = HL_ATTR(HLF_STNC);
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010425 fill = fill_stlnc;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010426 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010427 }
10428 else
10429#endif
10430 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010431 {
Bram Moolenaar8820b482017-03-16 17:23:31 +010010432 *attr = HL_ATTR(HLF_S);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010433 fill = fill_stl;
10434 }
10435 else
10436 {
Bram Moolenaar8820b482017-03-16 17:23:31 +010010437 *attr = HL_ATTR(HLF_SNC);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010438 fill = fill_stlnc;
10439 }
10440 /* Use fill when there is highlighting, and highlighting of current
10441 * window differs, or the fillchars differ, or this is not the
10442 * current window */
Bram Moolenaar8820b482017-03-16 17:23:31 +010010443 if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010444 || wp != curwin || ONE_WINDOW)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010445 || (fill_stl != fill_stlnc)))
10446 return fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010447 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010448 return '^';
10449 return '=';
10450}
Bram Moolenaar071d4272004-06-13 20:20:40 +000010451
Bram Moolenaar071d4272004-06-13 20:20:40 +000010452/*
10453 * Get the character to use in a separator between vertically split windows.
10454 * Get its attributes in "*attr".
10455 */
10456 static int
Bram Moolenaar05540972016-01-30 20:31:25 +010010457fillchar_vsep(int *attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010458{
Bram Moolenaar8820b482017-03-16 17:23:31 +010010459 *attr = HL_ATTR(HLF_C);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010460 if (*attr == 0 && fill_vert == ' ')
10461 return '|';
10462 else
10463 return fill_vert;
10464}
Bram Moolenaar071d4272004-06-13 20:20:40 +000010465
10466/*
10467 * Return TRUE if redrawing should currently be done.
10468 */
10469 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010470redrawing(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010471{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010010472#ifdef FEAT_EVAL
10473 if (disable_redraw_for_testing)
10474 return 0;
10475 else
10476#endif
Bram Moolenaared5a9d62018-09-06 13:14:43 +020010477 return ((!RedrawingDisabled
10478#ifdef FEAT_EVAL
10479 || ignore_redraw_flag_for_testing
10480#endif
10481 ) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
Bram Moolenaar071d4272004-06-13 20:20:40 +000010482}
10483
10484/*
10485 * Return TRUE if printing messages should currently be done.
10486 */
10487 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010488messaging(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010489{
10490 return (!(p_lz && char_avail() && !KeyTyped));
10491}
10492
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010493#ifdef FEAT_MENU
10494/*
10495 * Draw the window toolbar.
10496 */
10497 static void
10498redraw_win_toolbar(win_T *wp)
10499{
10500 vimmenu_T *menu;
10501 int item_idx = 0;
10502 int item_count = 0;
10503 int col = 0;
10504 int next_col;
10505 int off = (int)(current_ScreenLine - ScreenLines);
10506 int fill_attr = syn_name2attr((char_u *)"ToolbarLine");
10507 int button_attr = syn_name2attr((char_u *)"ToolbarButton");
10508
10509 vim_free(wp->w_winbar_items);
10510 for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next)
10511 ++item_count;
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010512 wp->w_winbar_items = ALLOC_CLEAR_MULT(winbar_item_T, item_count + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010513
10514 /* TODO: use fewer spaces if there is not enough room */
10515 for (menu = wp->w_winbar->children;
Bram Moolenaar02631462017-09-22 15:20:32 +020010516 menu != NULL && col < wp->w_width; menu = menu->next)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010517 {
10518 space_to_screenline(off + col, fill_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010519 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010520 break;
10521 if (col > 1)
10522 {
10523 space_to_screenline(off + col, fill_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010524 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010525 break;
10526 }
10527
10528 wp->w_winbar_items[item_idx].wb_startcol = col;
10529 space_to_screenline(off + col, button_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010530 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010531 break;
10532
10533 next_col = text_to_screenline(wp, menu->name, col);
10534 while (col < next_col)
10535 {
10536 ScreenAttrs[off + col] = button_attr;
10537 ++col;
10538 }
10539 wp->w_winbar_items[item_idx].wb_endcol = col;
10540 wp->w_winbar_items[item_idx].wb_menu = menu;
10541 ++item_idx;
10542
Bram Moolenaar02631462017-09-22 15:20:32 +020010543 if (col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010544 break;
10545 space_to_screenline(off + col, button_attr);
10546 ++col;
10547 }
Bram Moolenaar02631462017-09-22 15:20:32 +020010548 while (col < wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010549 {
10550 space_to_screenline(off + col, fill_attr);
10551 ++col;
10552 }
10553 wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */
10554
Bram Moolenaar02631462017-09-22 15:20:32 +020010555 screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
Bram Moolenaar4d784b22019-05-25 19:51:39 +020010556 (int)wp->w_width, 0);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010557}
10558#endif
Bram Moolenaar491ac282018-06-17 14:47:55 +020010559
Bram Moolenaar071d4272004-06-13 20:20:40 +000010560/*
10561 * Show current status info in ruler and various other places
10562 * If always is FALSE, only show ruler if position has changed.
10563 */
10564 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010565showruler(int always)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010566{
10567 if (!always && !redrawing())
10568 return;
Bram Moolenaar9372a112005-12-06 19:59:18 +000010569#ifdef FEAT_INS_EXPAND
10570 if (pum_visible())
10571 {
10572 /* Don't redraw right now, do it later. */
10573 curwin->w_redr_status = TRUE;
10574 return;
10575 }
10576#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +020010577#if defined(FEAT_STL_OPT)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +000010578 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
Bram Moolenaar362f3562009-11-03 16:20:34 +000010579 redraw_custom_statusline(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010580 else
10581#endif
10582#ifdef FEAT_CMDL_INFO
Bram Moolenaar491ac282018-06-17 14:47:55 +020010583 win_redr_ruler(curwin, always, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010584#endif
10585
10586#ifdef FEAT_TITLE
10587 if (need_maketitle
10588# ifdef FEAT_STL_OPT
10589 || (p_icon && (stl_syntax & STL_IN_ICON))
10590 || (p_title && (stl_syntax & STL_IN_TITLE))
10591# endif
10592 )
10593 maketitle();
10594#endif
Bram Moolenaar497683b2008-05-28 17:02:46 +000010595 /* Redraw the tab pages line if needed. */
10596 if (redraw_tabline)
10597 draw_tabline();
Bram Moolenaar071d4272004-06-13 20:20:40 +000010598}
10599
10600#ifdef FEAT_CMDL_INFO
10601 static void
Bram Moolenaar491ac282018-06-17 14:47:55 +020010602win_redr_ruler(win_T *wp, int always, int ignore_pum)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010603{
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010604#define RULER_BUF_LEN 70
10605 char_u buffer[RULER_BUF_LEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +000010606 int row;
10607 int fillchar;
10608 int attr;
10609 int empty_line = FALSE;
10610 colnr_T virtcol;
10611 int i;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010612 size_t len;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010613 int o;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010614 int this_ru_col;
10615 int off = 0;
Bram Moolenaar2c519cf2019-03-21 21:45:34 +010010616 int width;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010617
10618 /* If 'ruler' off or redrawing disabled, don't do anything */
10619 if (!p_ru)
10620 return;
10621
10622 /*
10623 * Check if cursor.lnum is valid, since win_redr_ruler() may be called
10624 * after deleting lines, before cursor.lnum is corrected.
10625 */
10626 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
10627 return;
10628
10629#ifdef FEAT_INS_EXPAND
10630 /* Don't draw the ruler while doing insert-completion, it might overwrite
10631 * the (long) mode message. */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010632 if (wp == lastwin && lastwin->w_status_height == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010633 if (edit_submode != NULL)
10634 return;
Bram Moolenaar491ac282018-06-17 14:47:55 +020010635 // Don't draw the ruler when the popup menu is visible, it may overlap.
10636 // Except when the popup menu will be redrawn anyway.
10637 if (!ignore_pum && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +000010638 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010639#endif
10640
10641#ifdef FEAT_STL_OPT
10642 if (*p_ruf)
10643 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010644 int save_called_emsg = called_emsg;
10645
10646 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010647 win_redr_custom(wp, TRUE);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010648 if (called_emsg)
10649 set_string_option_direct((char_u *)"rulerformat", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +000010650 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010651 called_emsg |= save_called_emsg;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010652 return;
10653 }
10654#endif
10655
10656 /*
10657 * Check if not in Insert mode and the line is empty (will show "0-1").
10658 */
10659 if (!(State & INSERT)
10660 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
10661 empty_line = TRUE;
10662
10663 /*
10664 * Only draw the ruler when something changed.
10665 */
10666 validate_virtcol_win(wp);
10667 if ( redraw_cmdline
10668 || always
10669 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
10670 || wp->w_cursor.col != wp->w_ru_cursor.col
10671 || wp->w_virtcol != wp->w_ru_virtcol
Bram Moolenaar071d4272004-06-13 20:20:40 +000010672 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
Bram Moolenaar071d4272004-06-13 20:20:40 +000010673 || wp->w_topline != wp->w_ru_topline
10674 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
10675#ifdef FEAT_DIFF
10676 || wp->w_topfill != wp->w_ru_topfill
10677#endif
10678 || empty_line != wp->w_ru_empty)
10679 {
10680 cursor_off();
Bram Moolenaar071d4272004-06-13 20:20:40 +000010681 if (wp->w_status_height)
10682 {
10683 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010684 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar53f81742017-09-22 14:35:51 +020010685 off = wp->w_wincol;
Bram Moolenaar02631462017-09-22 15:20:32 +020010686 width = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010687 }
10688 else
Bram Moolenaar071d4272004-06-13 20:20:40 +000010689 {
10690 row = Rows - 1;
10691 fillchar = ' ';
10692 attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010693 width = Columns;
10694 off = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010695 }
10696
10697 /* In list mode virtcol needs to be recomputed */
10698 virtcol = wp->w_virtcol;
10699 if (wp->w_p_list && lcs_tab1 == NUL)
10700 {
10701 wp->w_p_list = FALSE;
10702 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
10703 wp->w_p_list = TRUE;
10704 }
10705
10706 /*
10707 * Some sprintfs return the length, some return a pointer.
10708 * To avoid portability problems we use strlen() here.
10709 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010710 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
Bram Moolenaar071d4272004-06-13 20:20:40 +000010711 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
10712 ? 0L
10713 : (long)(wp->w_cursor.lnum));
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010714 len = STRLEN(buffer);
10715 col_print(buffer + len, RULER_BUF_LEN - len,
Bram Moolenaar071d4272004-06-13 20:20:40 +000010716 empty_line ? 0 : (int)wp->w_cursor.col + 1,
10717 (int)virtcol + 1);
10718
10719 /*
10720 * Add a "50%" if there is room for it.
10721 * On the last line, don't print in the last column (scrolls the
10722 * screen up on some terminals).
10723 */
10724 i = (int)STRLEN(buffer);
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010725 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010726 o = i + vim_strsize(buffer + i + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010727 if (wp->w_status_height == 0) /* can't use last char of screen */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010728 ++o;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010729 this_ru_col = ru_col - (Columns - width);
10730 if (this_ru_col < 0)
10731 this_ru_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010732 /* Never use more than half the window/screen width, leave the other
10733 * half for the filename. */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010734 if (this_ru_col < (width + 1) / 2)
10735 this_ru_col = (width + 1) / 2;
10736 if (this_ru_col + o < width)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010737 {
Bram Moolenaar0027c212015-01-07 13:31:52 +010010738 /* need at least 3 chars left for get_rel_pos() + NUL */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010739 while (this_ru_col + o < width && RULER_BUF_LEN > i + 4)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010740 {
Bram Moolenaar071d4272004-06-13 20:20:40 +000010741 if (has_mbyte)
10742 i += (*mb_char2bytes)(fillchar, buffer + i);
10743 else
Bram Moolenaar071d4272004-06-13 20:20:40 +000010744 buffer[i++] = fillchar;
10745 ++o;
10746 }
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010747 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010748 }
10749 /* Truncate at window boundary. */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010750 if (has_mbyte)
10751 {
10752 o = 0;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +000010753 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +000010754 {
10755 o += (*mb_ptr2cells)(buffer + i);
Bram Moolenaar4033c552017-09-16 20:54:51 +020010756 if (this_ru_col + o > width)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010757 {
10758 buffer[i] = NUL;
10759 break;
10760 }
10761 }
10762 }
Bram Moolenaara12a1612019-01-24 16:39:02 +010010763 else if (this_ru_col + (int)STRLEN(buffer) > width)
Bram Moolenaar4033c552017-09-16 20:54:51 +020010764 buffer[width - this_ru_col] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010765
Bram Moolenaar4033c552017-09-16 20:54:51 +020010766 screen_puts(buffer, row, this_ru_col + off, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010767 i = redraw_cmdline;
10768 screen_fill(row, row + 1,
Bram Moolenaar4033c552017-09-16 20:54:51 +020010769 this_ru_col + off + (int)STRLEN(buffer),
10770 (int)(off + width),
Bram Moolenaar071d4272004-06-13 20:20:40 +000010771 fillchar, fillchar, attr);
10772 /* don't redraw the cmdline because of showing the ruler */
10773 redraw_cmdline = i;
10774 wp->w_ru_cursor = wp->w_cursor;
10775 wp->w_ru_virtcol = wp->w_virtcol;
10776 wp->w_ru_empty = empty_line;
10777 wp->w_ru_topline = wp->w_topline;
10778 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
10779#ifdef FEAT_DIFF
10780 wp->w_ru_topfill = wp->w_topfill;
10781#endif
10782 }
10783}
10784#endif
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010785
10786#if defined(FEAT_LINEBREAK) || defined(PROTO)
10787/*
Bram Moolenaar64486672010-05-16 15:46:46 +020010788 * Return the width of the 'number' and 'relativenumber' column.
10789 * Caller may need to check if 'number' or 'relativenumber' is set.
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010790 * Otherwise it depends on 'numberwidth' and the line count.
10791 */
10792 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010793number_width(win_T *wp)
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010794{
10795 int n;
10796 linenr_T lnum;
10797
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +020010798 if (wp->w_p_rnu && !wp->w_p_nu)
10799 /* cursor line shows "0" */
10800 lnum = wp->w_height;
10801 else
10802 /* cursor line shows absolute line number */
10803 lnum = wp->w_buffer->b_ml.ml_line_count;
Bram Moolenaar64486672010-05-16 15:46:46 +020010804
Bram Moolenaar6b314672015-03-20 15:42:10 +010010805 if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010806 return wp->w_nrwidth_width;
10807 wp->w_nrwidth_line_count = lnum;
10808
10809 n = 0;
10810 do
10811 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000010812 lnum /= 10;
10813 ++n;
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010814 } while (lnum > 0);
10815
10816 /* 'numberwidth' gives the minimal width plus one */
10817 if (n < wp->w_p_nuw - 1)
10818 n = wp->w_p_nuw - 1;
10819
Bram Moolenaare4b407f2019-07-04 11:59:28 +020010820# ifdef FEAT_SIGNS
10821 // If 'signcolumn' is set to 'number' and there is a sign to display, then
10822 // the minimal width for the number column is 2.
10823 if (n < 2 && (wp->w_buffer->b_signlist != NULL)
10824 && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'))
10825 n = 2;
10826# endif
10827
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010828 wp->w_nrwidth_width = n;
Bram Moolenaar6b314672015-03-20 15:42:10 +010010829 wp->w_nuw_cached = wp->w_p_nuw;
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010830 return n;
10831}
10832#endif
Bram Moolenaar9750bb12012-12-05 16:10:42 +010010833
Bram Moolenaar113e1072019-01-20 15:30:40 +010010834#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar9750bb12012-12-05 16:10:42 +010010835/*
10836 * Return the current cursor column. This is the actual position on the
10837 * screen. First column is 0.
10838 */
10839 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010840screen_screencol(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +010010841{
10842 return screen_cur_col;
10843}
10844
10845/*
10846 * Return the current cursor row. This is the actual position on the screen.
10847 * First row is 0.
10848 */
10849 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010850screen_screenrow(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +010010851{
10852 return screen_cur_row;
10853}
Bram Moolenaar113e1072019-01-20 15:30:40 +010010854#endif