blob: 1ddafb3b37e486b89bfc10f1f2a9b3547c7eec51 [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/*
Bram Moolenaar7528d1f2019-09-19 23:06:20 +020011 * screen.c: Lower level code for displaying on the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +000012 *
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[].
Bram Moolenaar071d4272004-06-13 20:20:40 +000038 */
39
40#include "vim.h"
41
42/*
43 * The attributes that are actually active for writing to the screen.
44 */
45static int screen_attr = 0;
46
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010047static void screen_char_2(unsigned off, int row, int col);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010048static void screenclear2(void);
Bram Moolenaarcfce7172017-08-17 20:31:48 +020049static void lineclear(unsigned off, int width, int attr);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010050static void lineinvalid(unsigned off, int width);
Bram Moolenaarcfce7172017-08-17 20:31:48 +020051static 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 +010052static void win_rest_invalid(win_T *wp);
53static void msg_pos_mode(void);
54static void recording_mode(int attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000055
Bram Moolenaar63d9e732019-12-05 21:10:38 +010056// Ugly global: overrule attribute used by screen_char()
Bram Moolenaar071d4272004-06-13 20:20:40 +000057static int screen_char_attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000058
Bram Moolenaar860cae12010-06-05 23:22:07 +020059#if defined(FEAT_CONCEAL) || defined(PROTO)
Bram Moolenaarf5963f72010-07-23 22:10:27 +020060/*
61 * Return TRUE if the cursor line in window "wp" may be concealed, according
62 * to the 'concealcursor' option.
63 */
64 int
Bram Moolenaar05540972016-01-30 20:31:25 +010065conceal_cursor_line(win_T *wp)
Bram Moolenaarf5963f72010-07-23 22:10:27 +020066{
67 int c;
68
69 if (*wp->w_p_cocu == NUL)
70 return FALSE;
Bram Moolenaar24959102022-05-07 20:01:16 +010071 if (get_real_state() & MODE_VISUAL)
Bram Moolenaarf5963f72010-07-23 22:10:27 +020072 c = 'v';
Bram Moolenaar24959102022-05-07 20:01:16 +010073 else if (State & MODE_INSERT)
Bram Moolenaarf5963f72010-07-23 22:10:27 +020074 c = 'i';
Bram Moolenaar24959102022-05-07 20:01:16 +010075 else if (State & MODE_NORMAL)
Bram Moolenaarf5963f72010-07-23 22:10:27 +020076 c = 'n';
Bram Moolenaar24959102022-05-07 20:01:16 +010077 else if (State & MODE_CMDLINE)
Bram Moolenaarca8c9862010-07-24 15:00:38 +020078 c = 'c';
Bram Moolenaarf5963f72010-07-23 22:10:27 +020079 else
80 return FALSE;
81 return vim_strchr(wp->w_p_cocu, c) != NULL;
82}
83
84/*
85 * Check if the cursor line needs to be redrawn because of 'concealcursor'.
Bram Moolenaarea042672021-06-29 20:22:32 +020086 * To be called after changing the state, "was_concealed" is the value of
87 * "conceal_cursor_line()" before the change.
88 * "
Bram Moolenaarf5963f72010-07-23 22:10:27 +020089 */
90 void
Bram Moolenaarea042672021-06-29 20:22:32 +020091conceal_check_cursor_line(int was_concealed)
Bram Moolenaarf5963f72010-07-23 22:10:27 +020092{
Bram Moolenaarea042672021-06-29 20:22:32 +020093 if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin) != was_concealed)
Bram Moolenaarf5963f72010-07-23 22:10:27 +020094 {
Bram Moolenaarea042672021-06-29 20:22:32 +020095 int wcol = curwin->w_wcol;
96
Bram Moolenaarf5963f72010-07-23 22:10:27 +020097 need_cursor_line_redraw = TRUE;
Bram Moolenaar63d9e732019-12-05 21:10:38 +010098 // Need to recompute cursor column, e.g., when starting Visual mode
99 // without concealing.
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200100 curs_columns(TRUE);
Bram Moolenaarea042672021-06-29 20:22:32 +0200101
102 // When concealing now w_wcol will be computed wrong, keep the previous
103 // value, it will be updated in win_line().
104 if (!was_concealed)
105 curwin->w_wcol = wcol;
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200106 }
107}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108#endif
109
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200110/*
111 * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
112 * window then get the "Pmenu" highlight attribute.
113 */
Bram Moolenaara540f8a2019-06-14 19:23:57 +0200114 int
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200115get_wcr_attr(win_T *wp)
116{
117 int wcr_attr = 0;
118
119 if (*wp->w_p_wcr != NUL)
120 wcr_attr = syn_name2attr(wp->w_p_wcr);
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100121#ifdef FEAT_PROP_POPUP
Bram Moolenaarc363fe12019-08-04 18:13:46 +0200122 else if (WIN_IS_POPUP(wp))
Bram Moolenaar62a0cb42019-08-18 16:35:23 +0200123 {
124 if (wp->w_popup_flags & POPF_INFO)
125 wcr_attr = HL_ATTR(HLF_PSI); // PmenuSel
126 else
127 wcr_attr = HL_ATTR(HLF_PNI); // Pmenu
128 }
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200129#endif
130 return wcr_attr;
131}
132
Bram Moolenaar071d4272004-06-13 20:20:40 +0000133/*
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100134 * Call screen_fill() with the columns adjusted for 'rightleft' if needed.
135 * Return the new offset.
136 */
137 static int
138screen_fill_end(
139 win_T *wp,
140 int c1,
141 int c2,
142 int off,
143 int width,
144 int row,
145 int endrow,
146 int attr)
147{
148 int nn = off + width;
149
150 if (nn > wp->w_width)
151 nn = wp->w_width;
152#ifdef FEAT_RIGHTLEFT
153 if (wp->w_p_rl)
154 {
155 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
156 W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off,
157 c1, c2, attr);
158 }
159 else
160#endif
161 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
162 wp->w_wincol + off, (int)wp->w_wincol + nn,
163 c1, c2, attr);
164 return nn;
165}
166
167/*
168 * Clear lines near the end the window and mark the unused lines with "c1".
169 * use "c2" as the filler character.
170 * When "draw_margin" is TRUE then draw the sign, fold and number columns.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +0200172 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100173win_draw_end(
174 win_T *wp,
175 int c1,
176 int c2,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100177 int draw_margin,
Bram Moolenaar05540972016-01-30 20:31:25 +0100178 int row,
179 int endrow,
180 hlf_T hl)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182 int n = 0;
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200183 int attr = HL_ATTR(hl);
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200184 int wcr_attr = get_wcr_attr(wp);
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200185
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200186 attr = hl_combine_attr(wcr_attr, attr);
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100187
188 if (draw_margin)
189 {
Bram Moolenaar1c934292015-01-27 16:39:29 +0100190#ifdef FEAT_FOLDING
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100191 int fdc = compute_foldcolumn(wp, 0);
192
193 if (fdc > 0)
194 // draw the fold column
195 n = screen_fill_end(wp, ' ', ' ', n, fdc,
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200196 row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)));
Bram Moolenaar1c934292015-01-27 16:39:29 +0100197#endif
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100198#ifdef FEAT_SIGNS
199 if (signcolumn_on(wp))
200 // draw the sign column
201 n = screen_fill_end(wp, ' ', ' ', n, 2,
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200202 row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)));
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100203#endif
204 if ((wp->w_p_nu || wp->w_p_rnu)
205 && vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
206 // draw the number column
207 n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1,
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200208 row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)));
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100209 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210
211#ifdef FEAT_RIGHTLEFT
212 if (wp->w_p_rl)
213 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100215 wp->w_wincol, W_ENDCOL(wp) - 1 - n,
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200216 c2, c2, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100218 W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200219 c1, c2, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 }
221 else
222#endif
223 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100225 wp->w_wincol + n, (int)W_ENDCOL(wp),
Bram Moolenaar193ffd12019-05-25 22:57:30 +0200226 c1, c2, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227 }
Bram Moolenaar8ee4c012019-03-29 18:08:18 +0100228
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229 set_empty_rows(wp, row);
230}
231
Bram Moolenaar7528d1f2019-09-19 23:06:20 +0200232#if defined(FEAT_FOLDING) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233/*
Bram Moolenaar1c934292015-01-27 16:39:29 +0100234 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
235 * space is available for window "wp", minus "col".
236 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +0200237 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100238compute_foldcolumn(win_T *wp, int col)
Bram Moolenaar1c934292015-01-27 16:39:29 +0100239{
240 int fdc = wp->w_p_fdc;
241 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
Bram Moolenaar02631462017-09-22 15:20:32 +0200242 int wwidth = wp->w_width;
Bram Moolenaar1c934292015-01-27 16:39:29 +0100243
244 if (fdc > wwidth - (col + wmw))
245 fdc = wwidth - (col + wmw);
246 return fdc;
247}
248
249/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000250 * Fill the foldcolumn at "p" for window "wp".
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000251 * Only to be called when 'foldcolumn' > 0.
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100252 * Returns the number of bytes stored in 'p'. When non-multibyte characters are
253 * used for the fold column markers, this is equal to 'fdc' setting. Otherwise,
254 * this will be greater than 'fdc'.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 */
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100256 size_t
Bram Moolenaar05540972016-01-30 20:31:25 +0100257fill_foldcolumn(
258 char_u *p,
259 win_T *wp,
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100260 int closed, // TRUE of FALSE
261 linenr_T lnum) // current line number
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262{
263 int i = 0;
264 int level;
265 int first_level;
Bram Moolenaar578b49e2005-09-10 19:22:57 +0000266 int empty;
Bram Moolenaar1c934292015-01-27 16:39:29 +0100267 int fdc = compute_foldcolumn(wp, 0);
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100268 size_t byte_counter = 0;
269 int symbol = 0;
270 int len = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000271
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100272 // Init to all spaces.
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100273 vim_memset(p, ' ', MAX_MCO * fdc + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274
275 level = win_foldinfo.fi_level;
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100276 empty = (fdc == 1) ? 0 : 1;
277
278 // If the column is too narrow, we start at the lowest level that
Bram Moolenaar008bff92021-03-04 21:55:58 +0100279 // fits and use numbers to indicate the depth.
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100280 first_level = level - fdc - closed + 1 + empty;
281 if (first_level < 1)
282 first_level = 1;
283
284 for (i = 0; i < MIN(fdc, level); i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000285 {
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100286 if (win_foldinfo.fi_lnum == lnum
287 && first_level + i >= win_foldinfo.fi_low_level)
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100288 symbol = wp->w_fill_chars.foldopen;
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100289 else if (first_level == 1)
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100290 symbol = wp->w_fill_chars.foldsep;
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100291 else if (first_level + i <= 9)
292 symbol = '0' + first_level + i;
293 else
294 symbol = '>';
Bram Moolenaar578b49e2005-09-10 19:22:57 +0000295
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100296 len = utf_char2bytes(symbol, &p[byte_counter]);
297 byte_counter += len;
298 if (first_level + i >= level)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299 {
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100300 i++;
301 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302 }
303 }
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100304
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 if (closed)
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100306 {
307 if (symbol != 0)
Bram Moolenaar196a1f72021-03-21 14:39:19 +0100308 {
309 // rollback length and the character
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100310 byte_counter -= len;
Bram Moolenaar196a1f72021-03-21 14:39:19 +0100311 if (len > 1)
312 // for a multibyte character, erase all the bytes
313 vim_memset(p + byte_counter, ' ', len);
314 }
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100315 symbol = wp->w_fill_chars.foldclosed;
Bram Moolenaar4fa11752021-03-03 13:26:02 +0100316 len = utf_char2bytes(symbol, &p[byte_counter]);
317 byte_counter += len;
318 }
319
320 return MAX(byte_counter + (fdc - i), (size_t)fdc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000321}
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100322#endif // FEAT_FOLDING
Bram Moolenaar071d4272004-06-13 20:20:40 +0000323
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000324/*
325 * Return if the composing characters at "off_from" and "off_to" differ.
Bram Moolenaar70c49c12010-03-23 15:36:35 +0100326 * Only to be used when ScreenLinesUC[off_from] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000327 */
328 static int
Bram Moolenaar05540972016-01-30 20:31:25 +0100329comp_char_differs(int off_from, int off_to)
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000330{
331 int i;
332
333 for (i = 0; i < Screen_mco; ++i)
334 {
335 if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
336 return TRUE;
337 if (ScreenLinesC[i][off_from] == 0)
338 break;
339 }
340 return FALSE;
341}
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000342
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343/*
344 * Check whether the given character needs redrawing:
345 * - the (first byte of the) character is different
346 * - the attributes are different
347 * - the character is multi-byte and the next byte is different
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +0000348 * - the character is two cells wide and the second cell differs.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000349 */
350 static int
Bram Moolenaar05540972016-01-30 20:31:25 +0100351char_needs_redraw(int off_from, int off_to, int cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352{
353 if (cols > 0
354 && ((ScreenLines[off_from] != ScreenLines[off_to]
355 || ScreenAttrs[off_from] != ScreenAttrs[off_to])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356 || (enc_dbcs != 0
357 && MB_BYTE2LEN(ScreenLines[off_from]) > 1
358 && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
359 ? ScreenLines2[off_from] != ScreenLines2[off_to]
360 : (cols > 1 && ScreenLines[off_from + 1]
361 != ScreenLines[off_to + 1])))
362 || (enc_utf8
363 && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
364 || (ScreenLinesUC[off_from] != 0
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +0000365 && comp_char_differs(off_from, off_to))
Bram Moolenaar451cf632012-08-23 18:58:14 +0200366 || ((*mb_off2cells)(off_from, off_from + cols) > 1
367 && ScreenLines[off_from + 1]
Bram Moolenaara12a1612019-01-24 16:39:02 +0100368 != ScreenLines[off_to + 1])))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000369 return TRUE;
370 return FALSE;
371}
372
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200373#if defined(FEAT_TERMINAL) || defined(PROTO)
374/*
375 * Return the index in ScreenLines[] for the current screen line.
376 */
377 int
378screen_get_current_line_off()
379{
380 return (int)(current_ScreenLine - ScreenLines);
381}
382#endif
383
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100384#ifdef FEAT_PROP_POPUP
Bram Moolenaarc662ec92019-06-23 00:15:57 +0200385/*
386 * Return TRUE if this position has a higher level popup or this cell is
387 * transparent in the current popup.
388 */
389 static int
390blocked_by_popup(int row, int col)
391{
392 int off;
393
394 if (!popup_visible)
395 return FALSE;
396 off = row * screen_Columns + col;
397 return popup_mask[off] > screen_zindex || popup_transparent[off];
398}
399#endif
400
Bram Moolenaar071d4272004-06-13 20:20:40 +0000401/*
Bram Moolenaar7528d1f2019-09-19 23:06:20 +0200402 * Reset the highlighting. Used before clearing the screen.
403 */
404 void
405reset_screen_attr(void)
406{
407#ifdef FEAT_GUI
408 if (gui.in_use)
409 // Use a code that will reset gui.highlight_mask in
410 // gui_stop_highlight().
411 screen_attr = HL_ALL + 1;
412 else
413#endif
414 // Use attributes that is very unlikely to appear in text.
415 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
416}
417
418/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419 * Move one "cooked" screen line to the screen, but only the characters that
420 * have actually changed. Handle insert/delete character.
421 * "coloff" gives the first column on the screen for this line.
422 * "endcol" gives the columns where valid characters are.
423 * "clear_width" is the width of the window. It's > 0 if the rest of the line
424 * needs to be cleared, negative otherwise.
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200425 * "flags" can have bits:
426 * SLF_POPUP popup window
427 * SLF_RIGHTLEFT rightleft window:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 * When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
429 * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
430 */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200431 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100432screen_line(
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100433 win_T *wp,
434 int row,
435 int coloff,
436 int endcol,
437 int clear_width,
438 int flags UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439{
440 unsigned off_from;
441 unsigned off_to;
Bram Moolenaar367329b2007-08-30 11:53:22 +0000442 unsigned max_off_from;
443 unsigned max_off_to;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 int col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445 int hl;
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100446 int force = FALSE; // force update rest of the line
447 int redraw_this // bool: does character need redraw?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448#ifdef FEAT_GUI
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100449 = TRUE // For GUI when while-loop empty
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450#endif
451 ;
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100452 int redraw_next; // redraw_this for next character
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453 int clear_next = FALSE;
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100454 int char_cells; // 1: normal char
455 // 2: occupies two display cells
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456# define CHAR_CELLS char_cells
Bram Moolenaar071d4272004-06-13 20:20:40 +0000457
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100458 // Check for illegal row and col, just in case.
Bram Moolenaar5ad15df2012-03-16 19:07:58 +0100459 if (row >= Rows)
460 row = Rows - 1;
461 if (endcol > Columns)
462 endcol = Columns;
463
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464# ifdef FEAT_CLIPBOARD
465 clip_may_clear_selection(row, row);
466# endif
467
468 off_from = (unsigned)(current_ScreenLine - ScreenLines);
469 off_to = LineOffset[row] + coloff;
Bram Moolenaar367329b2007-08-30 11:53:22 +0000470 max_off_from = off_from + screen_Columns;
471 max_off_to = LineOffset[row] + screen_Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472
473#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200474 if (flags & SLF_RIGHTLEFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100476 // Clear rest first, because it's left of the text.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 if (clear_width > 0)
478 {
479 while (col <= endcol && ScreenLines[off_to] == ' '
480 && ScreenAttrs[off_to] == 0
Bram Moolenaara12a1612019-01-24 16:39:02 +0100481 && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000482 {
483 ++off_to;
484 ++col;
485 }
486 if (col <= endcol)
487 screen_fill(row, row + 1, col + coloff,
488 endcol + coloff + 1, ' ', ' ', 0);
489 }
490 col = endcol + 1;
491 off_to = LineOffset[row] + col + coloff;
492 off_from += col;
493 endcol = (clear_width > 0 ? clear_width : -clear_width);
494 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100495#endif // FEAT_RIGHTLEFT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100497#ifdef FEAT_PROP_POPUP
Bram Moolenaar92e25ab2019-11-26 22:39:10 +0100498 // First char of a popup window may go on top of the right half of a
499 // double-wide character. Clear the left half to avoid it getting the popup
500 // window background color.
Bram Moolenaar927495b2020-11-06 17:58:35 +0100501 if (coloff > 0 && enc_utf8
502 && ScreenLines[off_to] == 0
Bram Moolenaardc0cf1d2020-08-23 15:09:36 +0200503 && ScreenLinesUC[off_to - 1] != 0
504 && (*mb_char2cells)(ScreenLinesUC[off_to - 1]) > 1)
Bram Moolenaar92e25ab2019-11-26 22:39:10 +0100505 {
506 ScreenLines[off_to - 1] = ' ';
507 ScreenLinesUC[off_to - 1] = 0;
508 screen_char(off_to - 1, row, col + coloff - 1);
509 }
510#endif
511
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512 redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
513
514 while (col < endcol)
515 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000516 if (has_mbyte && (col + 1 < endcol))
Bram Moolenaar367329b2007-08-30 11:53:22 +0000517 char_cells = (*mb_off2cells)(off_from, max_off_from);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 else
519 char_cells = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520
521 redraw_this = redraw_next;
522 redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
523 off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
524
525#ifdef FEAT_GUI
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100526 // If the next character was bold, then redraw the current character to
527 // remove any pixels that might have spilt over into us. This only
528 // happens in the GUI.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 if (redraw_next && gui.in_use)
530 {
531 hl = ScreenAttrs[off_to + CHAR_CELLS];
Bram Moolenaar600dddc2006-03-12 22:05:10 +0000532 if (hl > HL_ALL)
533 hl = syn_attr2attr(hl);
534 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535 redraw_this = TRUE;
536 }
537#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100538#ifdef FEAT_PROP_POPUP
Bram Moolenaarc662ec92019-06-23 00:15:57 +0200539 if (blocked_by_popup(row, col + coloff))
Bram Moolenaar33796b32019-06-08 16:01:13 +0200540 redraw_this = FALSE;
541#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 if (redraw_this)
543 {
544 /*
545 * Special handling when 'xs' termcap flag set (hpterm):
546 * Attributes for characters are stored at the position where the
547 * cursor is when writing the highlighting code. The
548 * start-highlighting code must be written with the cursor on the
549 * first highlighted character. The stop-highlighting code must
550 * be written with the cursor just after the last highlighted
551 * character.
Bram Moolenaarc4568ab2018-11-16 16:21:05 +0100552 * Overwriting a character doesn't remove its highlighting. Need
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 * to clear the rest of the line, and force redrawing it
554 * completely.
555 */
556 if ( p_wiv
557 && !force
558#ifdef FEAT_GUI
559 && !gui.in_use
560#endif
561 && ScreenAttrs[off_to] != 0
562 && ScreenAttrs[off_from] != ScreenAttrs[off_to])
563 {
564 /*
565 * Need to remove highlighting attributes here.
566 */
567 windgoto(row, col + coloff);
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100568 out_str(T_CE); // clear rest of this screen line
569 screen_start(); // don't know where cursor is now
570 force = TRUE; // force redraw of rest of the line
571 redraw_next = TRUE; // or else next char would miss out
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572
573 /*
574 * If the previous character was highlighted, need to stop
575 * highlighting at this character.
576 */
577 if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
578 {
579 screen_attr = ScreenAttrs[off_to - 1];
580 term_windgoto(row, col + coloff);
581 screen_stop_highlight();
582 }
583 else
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100584 screen_attr = 0; // highlighting has stopped
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000586 if (enc_dbcs != 0)
587 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100588 // Check if overwriting a double-byte with a single-byte or
589 // the other way around requires another character to be
590 // redrawn. For UTF-8 this isn't needed, because comparing
591 // ScreenLinesUC[] is sufficient.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 if (char_cells == 1
593 && col + 1 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +0000594 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100596 // Writing a single-cell character over a double-cell
597 // character: need to redraw the next cell.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000598 ScreenLines[off_to + 1] = 0;
599 redraw_next = TRUE;
600 }
601 else if (char_cells == 2
602 && col + 2 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +0000603 && (*mb_off2cells)(off_to, max_off_to) == 1
604 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100606 // Writing the second half of a double-cell character over
607 // a double-cell character: need to redraw the second
608 // cell.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609 ScreenLines[off_to + 2] = 0;
610 redraw_next = TRUE;
611 }
612
613 if (enc_dbcs == DBCS_JPNU)
614 ScreenLines2[off_to] = ScreenLines2[off_from];
615 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100616 // When writing a single-width character over a double-width
617 // character and at the end of the redrawn text, need to clear out
Dominique Pelleaf4a61a2021-12-27 17:21:41 +0000618 // the right half of the old character.
619 // Also required when writing the right half of a double-width
620 // char over the left half of an existing one.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621 if (has_mbyte && col + char_cells == endcol
622 && ((char_cells == 1
Bram Moolenaar367329b2007-08-30 11:53:22 +0000623 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 || (char_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +0000625 && (*mb_off2cells)(off_to, max_off_to) == 1
626 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 clear_next = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628
629 ScreenLines[off_to] = ScreenLines[off_from];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 if (enc_utf8)
631 {
632 ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
633 if (ScreenLinesUC[off_from] != 0)
634 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000635 int i;
636
637 for (i = 0; i < Screen_mco; ++i)
638 ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639 }
640 }
641 if (char_cells == 2)
642 ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643
644#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100645 // The bold trick makes a single column of pixels appear in the
646 // next character. When a bold character is removed, the next
647 // character should be redrawn too. This happens for our own GUI
648 // and for some xterms.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 if (
650# ifdef FEAT_GUI
651 gui.in_use
652# endif
653# if defined(FEAT_GUI) && defined(UNIX)
654 ||
655# endif
656# ifdef UNIX
657 term_is_xterm
658# endif
659 )
660 {
661 hl = ScreenAttrs[off_to];
Bram Moolenaar600dddc2006-03-12 22:05:10 +0000662 if (hl > HL_ALL)
663 hl = syn_attr2attr(hl);
664 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 redraw_next = TRUE;
666 }
667#endif
668 ScreenAttrs[off_to] = ScreenAttrs[off_from];
Bram Moolenaara12a1612019-01-24 16:39:02 +0100669
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100670 // For simplicity set the attributes of second half of a
671 // double-wide character equal to the first half.
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000672 if (char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673 ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000674
675 if (enc_dbcs != 0 && char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676 screen_char_2(off_to, row, col + coloff);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678 screen_char(off_to, row, col + coloff);
679 }
680 else if ( p_wiv
681#ifdef FEAT_GUI
682 && !gui.in_use
683#endif
684 && col + coloff > 0)
685 {
686 if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
687 {
688 /*
689 * Don't output stop-highlight when moving the cursor, it will
690 * stop the highlighting when it should continue.
691 */
692 screen_attr = 0;
693 }
694 else if (screen_attr != 0)
695 screen_stop_highlight();
696 }
697
698 off_to += CHAR_CELLS;
699 off_from += CHAR_CELLS;
700 col += CHAR_CELLS;
701 }
702
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703 if (clear_next)
704 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100705 // Clear the second half of a double-wide character of which the left
706 // half was overwritten with a single-wide character.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707 ScreenLines[off_to] = ' ';
708 if (enc_utf8)
709 ScreenLinesUC[off_to] = 0;
710 screen_char(off_to, row, col + coloff);
711 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000712
713 if (clear_width > 0
714#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200715 && !(flags & SLF_RIGHTLEFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716#endif
717 )
718 {
719#ifdef FEAT_GUI
720 int startCol = col;
721#endif
722
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100723 // blank out the rest of the line
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724 while (col < clear_width && ScreenLines[off_to] == ' '
725 && ScreenAttrs[off_to] == 0
Bram Moolenaara12a1612019-01-24 16:39:02 +0100726 && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 {
728 ++off_to;
729 ++col;
730 }
731 if (col < clear_width)
732 {
733#ifdef FEAT_GUI
734 /*
735 * In the GUI, clearing the rest of the line may leave pixels
736 * behind if the first character cleared was bold. Some bold
737 * fonts spill over the left. In this case we redraw the previous
738 * character too. If we didn't skip any blanks above, then we
739 * only redraw if the character wasn't already redrawn anyway.
740 */
Bram Moolenaar9c697322006-10-09 20:11:17 +0000741 if (gui.in_use && (col > startCol || !redraw_this))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 {
743 hl = ScreenAttrs[off_to];
744 if (hl > HL_ALL || (hl & HL_BOLD))
Bram Moolenaar9c697322006-10-09 20:11:17 +0000745 {
746 int prev_cells = 1;
Bram Moolenaara12a1612019-01-24 16:39:02 +0100747
Bram Moolenaar9c697322006-10-09 20:11:17 +0000748 if (enc_utf8)
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100749 // for utf-8, ScreenLines[char_offset + 1] == 0 means
750 // that its width is 2.
Bram Moolenaar9c697322006-10-09 20:11:17 +0000751 prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
752 else if (enc_dbcs != 0)
753 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100754 // find previous character by counting from first
755 // column and get its width.
Bram Moolenaar9c697322006-10-09 20:11:17 +0000756 unsigned off = LineOffset[row];
Bram Moolenaar367329b2007-08-30 11:53:22 +0000757 unsigned max_off = LineOffset[row] + screen_Columns;
Bram Moolenaar9c697322006-10-09 20:11:17 +0000758
759 while (off < off_to)
760 {
Bram Moolenaar367329b2007-08-30 11:53:22 +0000761 prev_cells = (*mb_off2cells)(off, max_off);
Bram Moolenaar9c697322006-10-09 20:11:17 +0000762 off += prev_cells;
763 }
764 }
765
766 if (enc_dbcs != 0 && prev_cells > 1)
767 screen_char_2(off_to - prev_cells, row,
768 col + coloff - prev_cells);
769 else
Bram Moolenaar9c697322006-10-09 20:11:17 +0000770 screen_char(off_to - prev_cells, row,
771 col + coloff - prev_cells);
772 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 }
774#endif
775 screen_fill(row, row + 1, col + coloff, clear_width + coloff,
776 ' ', ' ', 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 off_to += clear_width - col;
778 col = clear_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 }
780 }
781
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200782 if (clear_width > 0
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100783#ifdef FEAT_PROP_POPUP
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200784 && !(flags & SLF_POPUP) // no separator for popup window
785#endif
786 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200788 // For a window that has a right neighbor, draw the separator char
Bram Moolenaaraef5c622019-06-08 17:25:33 +0200789 // right of the window contents. But not on top of a popup window.
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200790 if (coloff + col < Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791 {
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100792#ifdef FEAT_PROP_POPUP
Bram Moolenaarc662ec92019-06-23 00:15:57 +0200793 if (!blocked_by_popup(row, col + coloff))
Bram Moolenaaraef5c622019-06-08 17:25:33 +0200794#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795 {
Bram Moolenaaraef5c622019-06-08 17:25:33 +0200796 int c;
797
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100798 c = fillchar_vsep(&hl, wp);
Bram Moolenaaraef5c622019-06-08 17:25:33 +0200799 if (ScreenLines[off_to] != (schar_T)c
800 || (enc_utf8 && (int)ScreenLinesUC[off_to]
801 != (c >= 0x80 ? c : 0))
802 || ScreenAttrs[off_to] != hl)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803 {
Bram Moolenaaraef5c622019-06-08 17:25:33 +0200804 ScreenLines[off_to] = c;
805 ScreenAttrs[off_to] = hl;
806 if (enc_utf8)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807 {
Bram Moolenaaraef5c622019-06-08 17:25:33 +0200808 if (c >= 0x80)
809 {
810 ScreenLinesUC[off_to] = c;
811 ScreenLinesC[0][off_to] = 0;
812 }
813 else
814 ScreenLinesUC[off_to] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 }
Bram Moolenaaraef5c622019-06-08 17:25:33 +0200816 screen_char(off_to, row, col + coloff);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 }
819 }
820 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 LineWraps[row] = FALSE;
822 }
823}
824
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000825#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826/*
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000827 * Mirror text "str" for right-left displaying.
828 * Only works for single-byte characters (e.g., numbers).
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000830 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100831rl_mirror(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832{
833 char_u *p1, *p2;
834 int t;
835
836 for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
837 {
838 t = *p1;
839 *p1 = *p2;
840 *p2 = t;
841 }
842}
843#endif
844
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 * Draw the verticap separator right of window "wp" starting with line "row".
847 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +0200848 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100849draw_vsep_win(win_T *wp, int row)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850{
851 int hl;
852 int c;
853
854 if (wp->w_vsep_width)
855 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100856 // draw the vertical separator right of this window
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100857 c = fillchar_vsep(&hl, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
859 W_ENDCOL(wp), W_ENDCOL(wp) + 1,
860 c, ' ', hl);
861 }
862}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863
864#ifdef FEAT_WILDMENU
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100865static int skip_status_match_char(expand_T *xp, char_u *s);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866
867/*
Bram Moolenaar367329b2007-08-30 11:53:22 +0000868 * Get the length of an item as it will be shown in the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 */
870 static int
Bram Moolenaar05540972016-01-30 20:31:25 +0100871status_match_len(expand_T *xp, char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872{
873 int len = 0;
874
875#ifdef FEAT_MENU
876 int emenu = (xp->xp_context == EXPAND_MENUS
877 || xp->xp_context == EXPAND_MENUNAMES);
878
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100879 // Check for menu separators - replace with '|'.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 if (emenu && menu_is_separator(s))
881 return 1;
882#endif
883
884 while (*s != NUL)
885 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +0000886 s += skip_status_match_char(xp, s);
Bram Moolenaar81695252004-12-29 20:58:21 +0000887 len += ptr2cells(s);
Bram Moolenaar91acfff2017-03-12 19:22:36 +0100888 MB_PTR_ADV(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 }
890
891 return len;
892}
893
894/*
Bram Moolenaar7693ec62008-07-24 18:29:37 +0000895 * Return the number of characters that should be skipped in a status match.
Bram Moolenaar35c54e52005-05-20 21:25:31 +0000896 * These are backslashes used for escaping. Do show backslashes in help tags.
897 */
898 static int
Bram Moolenaar05540972016-01-30 20:31:25 +0100899skip_status_match_char(expand_T *xp, char_u *s)
Bram Moolenaar35c54e52005-05-20 21:25:31 +0000900{
Bram Moolenaar7693ec62008-07-24 18:29:37 +0000901 if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
Bram Moolenaar35c54e52005-05-20 21:25:31 +0000902#ifdef FEAT_MENU
903 || ((xp->xp_context == EXPAND_MENUS
904 || xp->xp_context == EXPAND_MENUNAMES)
905 && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
906#endif
Bram Moolenaar7693ec62008-07-24 18:29:37 +0000907 )
908 {
909#ifndef BACKSLASH_IN_FILENAME
910 if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
911 return 2;
912#endif
913 return 1;
914 }
915 return 0;
Bram Moolenaar35c54e52005-05-20 21:25:31 +0000916}
917
918/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000919 * Show wildchar matches in the status line.
920 * Show at least the "match" item.
921 * We start at item 'first_match' in the list and show all matches that fit.
922 *
923 * If inversion is possible we use it. Else '=' characters are used.
924 */
925 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100926win_redr_status_matches(
927 expand_T *xp,
928 int num_matches,
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100929 char_u **matches, // list of matches
Bram Moolenaar05540972016-01-30 20:31:25 +0100930 int match,
931 int showtail)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000932{
933#define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
934 int row;
935 char_u *buf;
936 int len;
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100937 int clen; // length in screen cells
Bram Moolenaar071d4272004-06-13 20:20:40 +0000938 int fillchar;
939 int attr;
940 int i;
941 int highlight = TRUE;
942 char_u *selstart = NULL;
943 int selstart_col = 0;
944 char_u *selend = NULL;
945 static int first_match = 0;
946 int add_left = FALSE;
947 char_u *s;
948#ifdef FEAT_MENU
949 int emenu;
950#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000951 int l;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100953 if (matches == NULL) // interrupted completion?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954 return;
955
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000956 if (has_mbyte)
Bram Moolenaar964b3742019-05-24 18:54:09 +0200957 buf = alloc(Columns * MB_MAXBYTES + 1);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000958 else
Bram Moolenaar964b3742019-05-24 18:54:09 +0200959 buf = alloc(Columns + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 if (buf == NULL)
961 return;
962
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100963 if (match == -1) // don't show match but original text
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 {
965 match = 0;
966 highlight = FALSE;
967 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100968 // count 1 for the ending ">"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000969 clen = status_match_len(xp, L_MATCH(match)) + 3;
970 if (match == 0)
971 first_match = 0;
972 else if (match < first_match)
973 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100974 // jumping left, as far as we can go
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975 first_match = match;
976 add_left = TRUE;
977 }
978 else
979 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100980 // check if match fits on the screen
Bram Moolenaar071d4272004-06-13 20:20:40 +0000981 for (i = first_match; i < match; ++i)
982 clen += status_match_len(xp, L_MATCH(i)) + 2;
983 if (first_match > 0)
984 clen += 2;
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100985 // jumping right, put match at the left
Bram Moolenaar071d4272004-06-13 20:20:40 +0000986 if ((long)clen > Columns)
987 {
988 first_match = match;
Bram Moolenaar63d9e732019-12-05 21:10:38 +0100989 // if showing the last match, we can add some on the left
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990 clen = 2;
991 for (i = match; i < num_matches; ++i)
992 {
993 clen += status_match_len(xp, L_MATCH(i)) + 2;
994 if ((long)clen >= Columns)
995 break;
996 }
997 if (i == num_matches)
998 add_left = TRUE;
999 }
1000 }
1001 if (add_left)
1002 while (first_match > 0)
1003 {
1004 clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
1005 if ((long)clen >= Columns)
1006 break;
1007 --first_match;
1008 }
1009
Bram Moolenaar3633cf52017-07-31 22:29:35 +02001010 fillchar = fillchar_status(&attr, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011
1012 if (first_match == 0)
1013 {
1014 *buf = NUL;
1015 len = 0;
1016 }
1017 else
1018 {
1019 STRCPY(buf, "< ");
1020 len = 2;
1021 }
1022 clen = len;
1023
1024 i = first_match;
1025 while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
1026 {
1027 if (i == match)
1028 {
1029 selstart = buf + len;
1030 selstart_col = clen;
1031 }
1032
1033 s = L_MATCH(i);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001034 // Check for menu separators - replace with '|'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035#ifdef FEAT_MENU
1036 emenu = (xp->xp_context == EXPAND_MENUS
1037 || xp->xp_context == EXPAND_MENUNAMES);
1038 if (emenu && menu_is_separator(s))
1039 {
1040 STRCPY(buf + len, transchar('|'));
1041 l = (int)STRLEN(buf + len);
1042 len += l;
1043 clen += l;
1044 }
1045 else
1046#endif
1047 for ( ; *s != NUL; ++s)
1048 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00001049 s += skip_status_match_char(xp, s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050 clen += ptr2cells(s);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001051 if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052 {
1053 STRNCPY(buf + len, s, l);
1054 s += l - 1;
1055 len += l;
1056 }
1057 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 {
1059 STRCPY(buf + len, transchar_byte(*s));
1060 len += (int)STRLEN(buf + len);
1061 }
1062 }
1063 if (i == match)
1064 selend = buf + len;
1065
1066 *(buf + len++) = ' ';
1067 *(buf + len++) = ' ';
1068 clen += 2;
1069 if (++i == num_matches)
1070 break;
1071 }
1072
1073 if (i != num_matches)
1074 {
1075 *(buf + len++) = '>';
1076 ++clen;
1077 }
1078
1079 buf[len] = NUL;
1080
1081 row = cmdline_row - 1;
1082 if (row >= 0)
1083 {
1084 if (wild_menu_showing == 0)
1085 {
1086 if (msg_scrolled > 0)
1087 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001088 // Put the wildmenu just above the command line. If there is
1089 // no room, scroll the screen one line up.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 if (cmdline_row == Rows - 1)
1091 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02001092 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093 ++msg_scrolled;
1094 }
1095 else
1096 {
1097 ++cmdline_row;
1098 ++row;
1099 }
1100 wild_menu_showing = WM_SCROLLED;
1101 }
1102 else
1103 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001104 // Create status line if needed by setting 'laststatus' to 2.
1105 // Set 'winminheight' to zero to avoid that the window is
1106 // resized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 if (lastwin->w_status_height == 0)
1108 {
1109 save_p_ls = p_ls;
1110 save_p_wmh = p_wmh;
1111 p_ls = 2;
1112 p_wmh = 0;
1113 last_status(FALSE);
1114 }
1115 wild_menu_showing = WM_SHOWN;
1116 }
1117 }
1118
1119 screen_puts(buf, row, 0, attr);
1120 if (selstart != NULL && highlight)
1121 {
1122 *selend = NUL;
Bram Moolenaar8820b482017-03-16 17:23:31 +01001123 screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 }
1125
1126 screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
1127 }
1128
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 win_redraw_last_status(topframe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001130 vim_free(buf);
1131}
1132#endif
1133
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001135 * Return TRUE if the status line of window "wp" is connected to the status
1136 * line of the window right of it. If not, then it's a vertical separator.
1137 * Only call if (wp->w_vsep_width != 0).
1138 */
1139 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001140stl_connected(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141{
1142 frame_T *fr;
1143
1144 fr = wp->w_frame;
1145 while (fr->fr_parent != NULL)
1146 {
1147 if (fr->fr_parent->fr_layout == FR_COL)
1148 {
1149 if (fr->fr_next != NULL)
1150 break;
1151 }
1152 else
1153 {
1154 if (fr->fr_next != NULL)
1155 return TRUE;
1156 }
1157 fr = fr->fr_parent;
1158 }
1159 return FALSE;
1160}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163/*
1164 * Get the value to show for the language mappings, active 'keymap'.
1165 */
1166 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001167get_keymap_str(
1168 win_T *wp,
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001169 char_u *fmt, // format string containing one %s item
1170 char_u *buf, // buffer for the result
1171 int len) // length of buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172{
1173 char_u *p;
1174
1175 if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
1176 return FALSE;
1177
1178 {
1179#ifdef FEAT_EVAL
1180 buf_T *old_curbuf = curbuf;
1181 win_T *old_curwin = curwin;
1182 char_u *s;
1183
1184 curbuf = wp->w_buffer;
1185 curwin = wp;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001186 STRCPY(buf, "b:keymap_name"); // must be writable
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187 ++emsg_skip;
Bram Moolenaarb171fb12020-06-24 20:34:03 +02001188 s = p = eval_to_string(buf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001189 --emsg_skip;
1190 curbuf = old_curbuf;
1191 curwin = old_curwin;
1192 if (p == NULL || *p == NUL)
1193#endif
1194 {
1195#ifdef FEAT_KEYMAP
1196 if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
1197 p = wp->w_buffer->b_p_keymap;
1198 else
1199#endif
1200 p = (char_u *)"lang";
1201 }
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02001202 if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203 buf[0] = NUL;
1204#ifdef FEAT_EVAL
1205 vim_free(s);
1206#endif
1207 }
1208 return buf[0] != NUL;
1209}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210
1211#if defined(FEAT_STL_OPT) || defined(PROTO)
1212/*
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001213 * Redraw the status line or ruler of window "wp".
1214 * When "wp" is NULL redraw the tab pages line from 'tabline'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001215 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001216 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001217win_redr_custom(
1218 win_T *wp,
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001219 int draw_ruler) // TRUE or FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220{
Bram Moolenaar1d633412013-12-11 15:52:01 +01001221 static int entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222 int attr;
1223 int curattr;
1224 int row;
1225 int col = 0;
1226 int maxwidth;
1227 int width;
1228 int n;
1229 int len;
1230 int fillchar;
1231 char_u buf[MAXPATHL];
Bram Moolenaar362f3562009-11-03 16:20:34 +00001232 char_u *stl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 char_u *p;
Bram Moolenaar8133cc62020-10-26 21:05:27 +01001234 stl_hlrec_T *hltab;
1235 stl_hlrec_T *tabtab;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001236 int use_sandbox = FALSE;
Bram Moolenaar61452852011-02-01 18:01:11 +01001237 win_T *ewp;
1238 int p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001239
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001240 // There is a tiny chance that this gets called recursively: When
1241 // redrawing a status line triggers redrawing the ruler or tabline.
1242 // Avoid trouble by not allowing recursion.
Bram Moolenaar1d633412013-12-11 15:52:01 +01001243 if (entered)
1244 return;
1245 entered = TRUE;
1246
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001247 // setup environment for the task at hand
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001248 if (wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 {
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001250 // Use 'tabline'. Always at the first line of the screen.
Bram Moolenaar362f3562009-11-03 16:20:34 +00001251 stl = p_tal;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001252 row = 0;
Bram Moolenaar65c923a2006-03-03 22:56:30 +00001253 fillchar = ' ';
Bram Moolenaar8820b482017-03-16 17:23:31 +01001254 attr = HL_ATTR(HLF_TPF);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001255 maxwidth = Columns;
1256# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001257 use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001258# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 }
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001260 else
1261 {
Bram Moolenaar49c51b82021-04-01 16:16:18 +02001262 row = statusline_row(wp);
Bram Moolenaar3633cf52017-07-31 22:29:35 +02001263 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar02631462017-09-22 15:20:32 +02001264 maxwidth = wp->w_width;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001265
1266 if (draw_ruler)
1267 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00001268 stl = p_ruf;
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001269 // advance past any leading group spec - implicit in ru_col
Bram Moolenaar362f3562009-11-03 16:20:34 +00001270 if (*stl == '%')
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001271 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00001272 if (*++stl == '-')
1273 stl++;
1274 if (atoi((char *)stl))
1275 while (VIM_ISDIGIT(*stl))
1276 stl++;
1277 if (*stl++ != '(')
1278 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001279 }
Bram Moolenaar02631462017-09-22 15:20:32 +02001280 col = ru_col - (Columns - wp->w_width);
1281 if (col < (wp->w_width + 1) / 2)
1282 col = (wp->w_width + 1) / 2;
1283 maxwidth = wp->w_width - col;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001284 if (!wp->w_status_height)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001285 {
1286 row = Rows - 1;
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001287 --maxwidth; // writing in last column may cause scrolling
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001288 fillchar = ' ';
1289 attr = 0;
1290 }
1291
1292# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001293 use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001294# endif
1295 }
1296 else
1297 {
1298 if (*wp->w_p_stl != NUL)
Bram Moolenaar362f3562009-11-03 16:20:34 +00001299 stl = wp->w_p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001300 else
Bram Moolenaar362f3562009-11-03 16:20:34 +00001301 stl = p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001302# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001303 use_sandbox = was_set_insecurely((char_u *)"statusline",
1304 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001305# endif
1306 }
1307
Bram Moolenaar53f81742017-09-22 14:35:51 +02001308 col += wp->w_wincol;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001309 }
1310
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311 if (maxwidth <= 0)
Bram Moolenaar1d633412013-12-11 15:52:01 +01001312 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001314 // Temporarily reset 'cursorbind', we don't want a side effect from moving
1315 // the cursor away and back.
Bram Moolenaar61452852011-02-01 18:01:11 +01001316 ewp = wp == NULL ? curwin : wp;
1317 p_crb_save = ewp->w_p_crb;
1318 ewp->w_p_crb = FALSE;
1319
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001320 // Make a copy, because the statusline may include a function call that
1321 // might change the option value and free the memory.
Bram Moolenaar362f3562009-11-03 16:20:34 +00001322 stl = vim_strsave(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01001323 width = build_stl_str_hl(ewp, buf, sizeof(buf),
Bram Moolenaar362f3562009-11-03 16:20:34 +00001324 stl, use_sandbox,
Bram Moolenaar8133cc62020-10-26 21:05:27 +01001325 fillchar, maxwidth, &hltab, &tabtab);
Bram Moolenaar362f3562009-11-03 16:20:34 +00001326 vim_free(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01001327 ewp->w_p_crb = p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001329 // Make all characters printable.
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01001330 p = transstr(buf);
1331 if (p != NULL)
1332 {
1333 vim_strncpy(buf, p, sizeof(buf) - 1);
1334 vim_free(p);
1335 }
1336
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001337 // fill up with "fillchar"
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01001338 len = (int)STRLEN(buf);
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001339 while (width < maxwidth && len < (int)sizeof(buf) - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001340 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341 len += (*mb_char2bytes)(fillchar, buf + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 ++width;
1343 }
1344 buf[len] = NUL;
1345
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001346 /*
1347 * Draw each snippet with the specified highlighting.
1348 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001349 curattr = attr;
1350 p = buf;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001351 for (n = 0; hltab[n].start != NULL; n++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001353 len = (int)(hltab[n].start - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001354 screen_puts_len(p, len, row, col, curattr);
1355 col += vim_strnsize(p, len);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001356 p = hltab[n].start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001357
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001358 if (hltab[n].userhl == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 curattr = attr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001360 else if (hltab[n].userhl < 0)
1361 curattr = syn_id2attr(-hltab[n].userhl);
Bram Moolenaar4033c552017-09-16 20:54:51 +02001362#ifdef FEAT_TERMINAL
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02001363 else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
1364 && wp->w_status_height != 0)
1365 curattr = highlight_stltermnc[hltab[n].userhl - 1];
Bram Moolenaarbce4f622017-08-13 21:37:43 +02001366 else if (wp != NULL && bt_terminal(wp->w_buffer)
1367 && wp->w_status_height != 0)
1368 curattr = highlight_stlterm[hltab[n].userhl - 1];
Bram Moolenaar4033c552017-09-16 20:54:51 +02001369#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +00001370 else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001371 curattr = highlight_stlnc[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372 else
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001373 curattr = highlight_user[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001374 }
1375 screen_puts(p, row, col, curattr);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001376
1377 if (wp == NULL)
1378 {
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001379 // Fill the TabPageIdxs[] array for clicking in the tab pagesline.
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001380 col = 0;
1381 len = 0;
1382 p = buf;
1383 fillchar = 0;
1384 for (n = 0; tabtab[n].start != NULL; n++)
1385 {
1386 len += vim_strnsize(p, (int)(tabtab[n].start - p));
1387 while (col < len)
1388 TabPageIdxs[col++] = fillchar;
1389 p = tabtab[n].start;
1390 fillchar = tabtab[n].userhl;
1391 }
1392 while (col < Columns)
1393 TabPageIdxs[col++] = fillchar;
1394 }
Bram Moolenaar1d633412013-12-11 15:52:01 +01001395
1396theend:
1397 entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398}
1399
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001400#endif // FEAT_STL_OPT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401
1402/*
1403 * Output a single character directly to the screen and update ScreenLines.
1404 */
1405 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001406screen_putchar(int c, int row, int col, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001408 char_u buf[MB_MAXBYTES + 1];
1409
Bram Moolenaar9a920d82012-06-01 15:21:02 +02001410 if (has_mbyte)
1411 buf[(*mb_char2bytes)(c, buf)] = NUL;
1412 else
Bram Moolenaar9a920d82012-06-01 15:21:02 +02001413 {
1414 buf[0] = c;
1415 buf[1] = NUL;
1416 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001417 screen_puts(buf, row, col, attr);
1418}
1419
1420/*
1421 * Get a single character directly from ScreenLines into "bytes[]".
1422 * Also return its attribute in *attrp;
1423 */
1424 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001425screen_getbytes(int row, int col, char_u *bytes, int *attrp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426{
1427 unsigned off;
1428
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001429 // safety check
Bram Moolenaar071d4272004-06-13 20:20:40 +00001430 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
1431 {
1432 off = LineOffset[row] + col;
1433 *attrp = ScreenAttrs[off];
1434 bytes[0] = ScreenLines[off];
1435 bytes[1] = NUL;
1436
Bram Moolenaar071d4272004-06-13 20:20:40 +00001437 if (enc_utf8 && ScreenLinesUC[off] != 0)
1438 bytes[utfc_char2bytes(off, bytes)] = NUL;
1439 else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
1440 {
1441 bytes[0] = ScreenLines[off];
1442 bytes[1] = ScreenLines2[off];
1443 bytes[2] = NUL;
1444 }
1445 else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
1446 {
1447 bytes[1] = ScreenLines[off + 1];
1448 bytes[2] = NUL;
1449 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450 }
1451}
1452
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001453/*
1454 * Return TRUE if composing characters for screen posn "off" differs from
1455 * composing characters in "u8cc".
Bram Moolenaar70c49c12010-03-23 15:36:35 +01001456 * Only to be used when ScreenLinesUC[off] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001457 */
1458 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001459screen_comp_differs(int off, int *u8cc)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001460{
1461 int i;
1462
1463 for (i = 0; i < Screen_mco; ++i)
1464 {
1465 if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
1466 return TRUE;
1467 if (u8cc[i] == 0)
1468 break;
1469 }
1470 return FALSE;
1471}
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001472
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473/*
1474 * Put string '*text' on the screen at position 'row' and 'col', with
1475 * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
1476 * Note: only outputs within one row, message is truncated at screen boundary!
1477 * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
1478 */
1479 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001480screen_puts(
1481 char_u *text,
1482 int row,
1483 int col,
1484 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485{
1486 screen_puts_len(text, -1, row, col, attr);
1487}
1488
1489/*
1490 * Like screen_puts(), but output "text[len]". When "len" is -1 output up to
1491 * a NUL.
1492 */
1493 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001494screen_puts_len(
1495 char_u *text,
1496 int textlen,
1497 int row,
1498 int col,
Bram Moolenaar35d8c202022-03-03 11:46:00 +00001499 int attr_arg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500{
Bram Moolenaar35d8c202022-03-03 11:46:00 +00001501 int attr = attr_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001502 unsigned off;
1503 char_u *ptr = text;
Bram Moolenaare4c21e62014-05-22 16:05:19 +02001504 int len = textlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 int c;
Bram Moolenaar367329b2007-08-30 11:53:22 +00001506 unsigned max_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507 int mbyte_blen = 1;
1508 int mbyte_cells = 1;
1509 int u8c = 0;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001510 int u8cc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511 int clear_next_cell = FALSE;
Bram Moolenaara12a1612019-01-24 16:39:02 +01001512#ifdef FEAT_ARABIC
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001513 int prev_c = 0; // previous Arabic character
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001514 int pc, nc, nc1;
1515 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001516#endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001517 int force_redraw_this;
1518 int force_redraw_next = FALSE;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001519 int need_redraw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520
Bram Moolenaar0b4c9ed2019-06-03 22:04:23 +02001521 // Safety check. The check for negative row and column is to fix issue
1522 // #4102. TODO: find out why row/col could be negative.
1523 if (ScreenLines == NULL
1524 || row >= screen_Rows || row < 0
1525 || col >= screen_Columns || col < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526 return;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001527 off = LineOffset[row] + col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528
Dominique Pelleaf4a61a2021-12-27 17:21:41 +00001529 // When drawing over the right half of a double-wide char clear out the
1530 // left half. Only needed in a terminal.
Bram Moolenaar7693ec62008-07-24 18:29:37 +00001531 if (has_mbyte && col > 0 && col < screen_Columns
Bram Moolenaara12a1612019-01-24 16:39:02 +01001532#ifdef FEAT_GUI
Bram Moolenaarc236c162008-07-13 17:41:49 +00001533 && !gui.in_use
Bram Moolenaara12a1612019-01-24 16:39:02 +01001534#endif
Bram Moolenaarc236c162008-07-13 17:41:49 +00001535 && mb_fix_col(col, row) != col)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001536 {
1537 ScreenLines[off - 1] = ' ';
1538 ScreenAttrs[off - 1] = 0;
1539 if (enc_utf8)
1540 {
1541 ScreenLinesUC[off - 1] = 0;
1542 ScreenLinesC[0][off - 1] = 0;
1543 }
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001544 // redraw the previous cell, make it empty
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001545 screen_char(off - 1, row, col - 1);
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001546 // force the cell at "col" to be redrawn
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001547 force_redraw_next = TRUE;
1548 }
Bram Moolenaarc236c162008-07-13 17:41:49 +00001549
Bram Moolenaar367329b2007-08-30 11:53:22 +00001550 max_off = LineOffset[row] + screen_Columns;
Bram Moolenaara064ac82007-08-05 18:10:54 +00001551 while (col < screen_Columns
1552 && (len < 0 || (int)(ptr - text) < len)
1553 && *ptr != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001554 {
1555 c = *ptr;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001556 // check if this is the first byte of a multibyte
Bram Moolenaar071d4272004-06-13 20:20:40 +00001557 if (has_mbyte)
1558 {
1559 if (enc_utf8 && len > 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001560 mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561 else
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001562 mbyte_blen = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563 if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1564 mbyte_cells = 1;
1565 else if (enc_dbcs != 0)
1566 mbyte_cells = mbyte_blen;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001567 else // enc_utf8
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568 {
1569 if (len >= 0)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001570 u8c = utfc_ptr2char_len(ptr, u8cc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571 (int)((text + len) - ptr));
1572 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001573 u8c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574 mbyte_cells = utf_char2cells(u8c);
Bram Moolenaara12a1612019-01-24 16:39:02 +01001575#ifdef FEAT_ARABIC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
1577 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001578 // Do Arabic shaping.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579 if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
1580 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001581 // Past end of string to be displayed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582 nc = NUL;
1583 nc1 = NUL;
1584 }
1585 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001586 {
Bram Moolenaar54620182009-11-11 16:07:20 +00001587 nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
1588 (int)((text + len) - ptr - mbyte_blen));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001589 nc1 = pcc[0];
1590 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001591 pc = prev_c;
1592 prev_c = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001593 u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594 }
1595 else
1596 prev_c = u8c;
Bram Moolenaara12a1612019-01-24 16:39:02 +01001597#endif
Bram Moolenaare4ebd292010-01-19 17:40:46 +01001598 if (col + mbyte_cells > screen_Columns)
1599 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001600 // Only 1 cell left, but character requires 2 cells:
1601 // display a '>' in the last column to avoid wrapping.
Bram Moolenaare4ebd292010-01-19 17:40:46 +01001602 c = '>';
1603 mbyte_cells = 1;
1604 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605 }
1606 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001607
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001608 force_redraw_this = force_redraw_next;
1609 force_redraw_next = FALSE;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001610
1611 need_redraw = ScreenLines[off] != c
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612 || (mbyte_cells == 2
1613 && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
1614 || (enc_dbcs == DBCS_JPNU
1615 && c == 0x8e
1616 && ScreenLines2[off] != ptr[1])
1617 || (enc_utf8
Bram Moolenaar70c49c12010-03-23 15:36:35 +01001618 && (ScreenLinesUC[off] !=
1619 (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
1620 || (ScreenLinesUC[off] != 0
1621 && screen_comp_differs(off, u8cc))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001622 || ScreenAttrs[off] != attr
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001623 || exmode_active;
1624
Bram Moolenaar24a5ac52019-06-08 19:01:18 +02001625 if ((need_redraw || force_redraw_this)
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01001626#ifdef FEAT_PROP_POPUP
Bram Moolenaarc662ec92019-06-23 00:15:57 +02001627 && !blocked_by_popup(row, col)
Bram Moolenaar24a5ac52019-06-08 19:01:18 +02001628#endif
1629 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630 {
1631#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001632 // The bold trick makes a single row of pixels appear in the next
1633 // character. When a bold character is removed, the next
1634 // character should be redrawn too. This happens for our own GUI
1635 // and for some xterms.
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001636 if (need_redraw && ScreenLines[off] != ' ' && (
Bram Moolenaar071d4272004-06-13 20:20:40 +00001637# ifdef FEAT_GUI
1638 gui.in_use
1639# endif
1640# if defined(FEAT_GUI) && defined(UNIX)
1641 ||
1642# endif
1643# ifdef UNIX
1644 term_is_xterm
1645# endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001646 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001647 {
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001648 int n = ScreenAttrs[off];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001649
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001650 if (n > HL_ALL)
1651 n = syn_attr2attr(n);
1652 if (n & HL_BOLD)
1653 force_redraw_next = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 }
1655#endif
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001656 // When at the end of the text and overwriting a two-cell
1657 // character with a one-cell character, need to clear the next
Dominique Pelleaf4a61a2021-12-27 17:21:41 +00001658 // cell. Also when overwriting the left half of a two-cell char
1659 // with the right half of a two-cell char. Do this only once
1660 // (mb_off2cells() may return 2 on the right half).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661 if (clear_next_cell)
1662 clear_next_cell = FALSE;
1663 else if (has_mbyte
1664 && (len < 0 ? ptr[mbyte_blen] == NUL
1665 : ptr + mbyte_blen >= text + len)
Bram Moolenaar367329b2007-08-30 11:53:22 +00001666 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00001668 && (*mb_off2cells)(off, max_off) == 1
1669 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670 clear_next_cell = TRUE;
1671
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001672 // Make sure we never leave a second byte of a double-byte behind,
1673 // it confuses mb_off2cells().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 if (enc_dbcs
Bram Moolenaar367329b2007-08-30 11:53:22 +00001675 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001676 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00001677 && (*mb_off2cells)(off, max_off) == 1
1678 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679 ScreenLines[off + mbyte_blen] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680 ScreenLines[off] = c;
1681 ScreenAttrs[off] = attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682 if (enc_utf8)
1683 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001684 if (c < 0x80 && u8cc[0] == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685 ScreenLinesUC[off] = 0;
1686 else
1687 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001688 int i;
1689
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 ScreenLinesUC[off] = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001691 for (i = 0; i < Screen_mco; ++i)
1692 {
1693 ScreenLinesC[i][off] = u8cc[i];
1694 if (u8cc[i] == 0)
1695 break;
1696 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697 }
1698 if (mbyte_cells == 2)
1699 {
1700 ScreenLines[off + 1] = 0;
1701 ScreenAttrs[off + 1] = attr;
1702 }
1703 screen_char(off, row, col);
1704 }
1705 else if (mbyte_cells == 2)
1706 {
1707 ScreenLines[off + 1] = ptr[1];
1708 ScreenAttrs[off + 1] = attr;
1709 screen_char_2(off, row, col);
1710 }
1711 else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1712 {
1713 ScreenLines2[off] = ptr[1];
1714 screen_char(off, row, col);
1715 }
1716 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717 screen_char(off, row, col);
1718 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719 if (has_mbyte)
1720 {
1721 off += mbyte_cells;
1722 col += mbyte_cells;
1723 ptr += mbyte_blen;
1724 if (clear_next_cell)
Bram Moolenaare4c21e62014-05-22 16:05:19 +02001725 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001726 // This only happens at the end, display one space next.
Bram Moolenaar35d8c202022-03-03 11:46:00 +00001727 // Keep the attribute from before.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 ptr = (char_u *)" ";
Bram Moolenaare4c21e62014-05-22 16:05:19 +02001729 len = -1;
Bram Moolenaar35d8c202022-03-03 11:46:00 +00001730 attr = ScreenAttrs[off];
Bram Moolenaare4c21e62014-05-22 16:05:19 +02001731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732 }
1733 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 {
1735 ++off;
1736 ++col;
1737 ++ptr;
1738 }
1739 }
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001740
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001741 // If we detected the next character needs to be redrawn, but the text
1742 // doesn't extend up to there, update the character here.
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001743 if (force_redraw_next && col < screen_Columns)
1744 {
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001745 if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
1746 screen_char_2(off, row, col);
1747 else
Bram Moolenaar2bea2912009-03-11 16:58:40 +00001748 screen_char(off, row, col);
1749 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750}
1751
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001752#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001754 * Prepare for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001756 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001757start_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758{
1759 if (p_hls && !no_hlsearch)
1760 {
Bram Moolenaar0b6849e2020-05-02 18:33:25 +02001761 end_search_hl(); // just in case it wasn't called before
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001762 last_pat_prog(&screen_search_hl.rm);
1763 screen_search_hl.attr = HL_ATTR(HLF_L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 }
1765}
1766
1767/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001768 * Clean up for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001769 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001770 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001771end_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772{
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001773 if (screen_search_hl.rm.regprog != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774 {
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02001775 vim_regfree(screen_search_hl.rm.regprog);
1776 screen_search_hl.rm.regprog = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777 }
1778}
Bram Moolenaarde993ea2014-06-17 23:18:01 +02001779#endif
Bram Moolenaarb3414592014-06-17 17:48:32 +02001780
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001782screen_start_highlight(int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783{
1784 attrentry_T *aep = NULL;
1785
1786 screen_attr = attr;
1787 if (full_screen
Bram Moolenaar4f974752019-02-17 17:44:42 +01001788#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 && termcap_active
1790#endif
1791 )
1792 {
1793#ifdef FEAT_GUI
1794 if (gui.in_use)
1795 {
1796 char buf[20];
1797
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001798 // The GUI handles this internally.
Bram Moolenaar424bcae2022-01-31 14:59:41 +00001799 sprintf(buf, "\033|%dh", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 OUT_STR(buf);
1801 }
1802 else
1803#endif
1804 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001805 if (attr > HL_ALL) // special HL attr.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 {
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001807 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 aep = syn_cterm_attr2entry(attr);
1809 else
1810 aep = syn_term_attr2entry(attr);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001811 if (aep == NULL) // did ":syntax clear"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 attr = 0;
1813 else
1814 attr = aep->ae_attr;
1815 }
Bram Moolenaara050b942019-12-02 21:35:31 +01001816#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1817 if (use_vtp())
1818 {
1819 guicolor_T defguifg, defguibg;
1820 int defctermfg, defctermbg;
1821
1822 // If FG and BG are unset, the color is undefined when
1823 // BOLD+INVERSE. Use Normal as the default value.
1824 get_default_console_color(&defctermfg, &defctermbg, &defguifg,
1825 &defguibg);
1826
1827 if (p_tgc)
1828 {
1829 if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.fg_rgb))
1830 term_fg_rgb_color(defguifg);
1831 if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.bg_rgb))
1832 term_bg_rgb_color(defguibg);
1833 }
1834 else if (t_colors >= 256)
1835 {
1836 if (aep == NULL || aep->ae_u.cterm.fg_color == 0)
1837 term_fg_color(defctermfg);
1838 if (aep == NULL || aep->ae_u.cterm.bg_color == 0)
1839 term_bg_color(defctermbg);
1840 }
1841 }
1842#endif
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001843 if ((attr & HL_BOLD) && *T_MD != NUL) // bold
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 out_str(T_MD);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001845 else if (aep != NULL && cterm_normal_fg_bold && (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02001846#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001847 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1848 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
1849 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001850#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001851 t_colors > 1 && aep->ae_u.cterm.fg_color))
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001852 // If the Normal FG color has BOLD attribute and the new HL
1853 // has a FG color defined, clear BOLD.
Bram Moolenaard1f56e62006-02-22 21:25:37 +00001854 out_str(T_ME);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001855 if ((attr & HL_STANDOUT) && *T_SO != NUL) // standout
Bram Moolenaar071d4272004-06-13 20:20:40 +00001856 out_str(T_SO);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001857 if ((attr & HL_UNDERCURL) && *T_UCS != NUL) // undercurl
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01001858 out_str(T_UCS);
Bram Moolenaar84f54632022-06-29 18:39:11 +01001859 if ((attr & HL_UNDERDOUBLE) && *T_USS != NUL) // double underline
1860 out_str(T_USS);
1861 if ((attr & HL_UNDERDOTTED) && *T_DS != NUL) // dotted underline
1862 out_str(T_DS);
1863 if ((attr & HL_UNDERDASHED) && *T_CDS != NUL) // dashed underline
1864 out_str(T_CDS);
1865 if (((attr & HL_UNDERLINE) // underline or undercurl, etc.
1866 || ((attr & HL_UNDERCURL) && *T_UCS == NUL)
1867 || ((attr & HL_UNDERDOUBLE) && *T_USS == NUL)
1868 || ((attr & HL_UNDERDOTTED) && *T_DS == NUL)
1869 || ((attr & HL_UNDERDASHED) && *T_CDS == NUL))
Bram Moolenaar45a00002017-12-22 21:12:34 +01001870 && *T_US != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 out_str(T_US);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001872 if ((attr & HL_ITALIC) && *T_CZH != NUL) // italic
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 out_str(T_CZH);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001874 if ((attr & HL_INVERSE) && *T_MR != NUL) // inverse (reverse)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 out_str(T_MR);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001876 if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) // strike
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02001877 out_str(T_STS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878
1879 /*
1880 * Output the color or start string after bold etc., in case the
1881 * bold etc. override the color setting.
1882 */
1883 if (aep != NULL)
1884 {
Bram Moolenaar61be73b2016-04-29 22:59:22 +02001885#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001886 // When 'termguicolors' is set but fg or bg is unset,
1887 // fall back to the cterm colors. This helps for SpellBad,
1888 // where the GUI uses a red undercurl.
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001889 if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02001891 if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001892 term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001893 }
1894 else
1895#endif
1896 if (t_colors > 1)
1897 {
1898 if (aep->ae_u.cterm.fg_color)
1899 term_fg_color(aep->ae_u.cterm.fg_color - 1);
1900 }
1901#ifdef FEAT_TERMGUICOLORS
1902 if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
1903 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02001904 if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001905 term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906 }
1907 else
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001908#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001909 if (t_colors > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 {
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001911 if (aep->ae_u.cterm.bg_color)
1912 term_bg_color(aep->ae_u.cterm.bg_color - 1);
1913 }
Bram Moolenaare023e882020-05-31 16:42:30 +02001914#ifdef FEAT_TERMGUICOLORS
1915 if (p_tgc && aep->ae_u.cterm.ul_rgb != CTERMCOLOR)
1916 {
1917 if (aep->ae_u.cterm.ul_rgb != INVALCOLOR)
1918 term_ul_rgb_color(aep->ae_u.cterm.ul_rgb);
1919 }
1920 else
1921#endif
1922 if (t_colors > 1)
1923 {
1924 if (aep->ae_u.cterm.ul_color)
1925 term_ul_color(aep->ae_u.cterm.ul_color - 1);
1926 }
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001927
Bram Moolenaarf708ac52018-03-12 21:48:32 +01001928 if (!IS_CTERM)
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001929 {
1930 if (aep->ae_u.term.start != NULL)
1931 out_str(aep->ae_u.term.start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 }
1933 }
1934 }
1935 }
1936}
1937
1938 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001939screen_stop_highlight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940{
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001941 int do_ME = FALSE; // output T_ME code
Bram Moolenaar4e5534f2020-04-30 20:59:57 +02001942#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
Bram Moolenaar09307e32020-05-29 21:42:55 +02001943 int do_ME_fg = FALSE, do_ME_bg = FALSE;
Bram Moolenaar4e5534f2020-04-30 20:59:57 +02001944#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945
1946 if (screen_attr != 0
Bram Moolenaar4f974752019-02-17 17:44:42 +01001947#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 && termcap_active
1949#endif
1950 )
1951 {
1952#ifdef FEAT_GUI
1953 if (gui.in_use)
1954 {
1955 char buf[20];
1956
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001957 // use internal GUI code
Bram Moolenaar424bcae2022-01-31 14:59:41 +00001958 sprintf(buf, "\033|%dH", screen_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 OUT_STR(buf);
1960 }
1961 else
1962#endif
1963 {
Bram Moolenaar84f54632022-06-29 18:39:11 +01001964 int is_under;
1965
Bram Moolenaar63d9e732019-12-05 21:10:38 +01001966 if (screen_attr > HL_ALL) // special HL attr.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967 {
1968 attrentry_T *aep;
1969
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001970 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971 {
1972 /*
1973 * Assume that t_me restores the original colors!
1974 */
1975 aep = syn_cterm_attr2entry(screen_attr);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001976 if (aep != NULL && ((
Bram Moolenaar61be73b2016-04-29 22:59:22 +02001977#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001978 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1979 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
Bram Moolenaar4e5534f2020-04-30 20:59:57 +02001980# ifdef FEAT_VTP
1981 ? !(do_ME_fg = TRUE) : (do_ME_fg = FALSE)
1982# endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001983 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001984#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001985 aep->ae_u.cterm.fg_color) || (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02001986#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001987 p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
1988 ? aep->ae_u.cterm.bg_rgb != INVALCOLOR
Bram Moolenaar4e5534f2020-04-30 20:59:57 +02001989# ifdef FEAT_VTP
1990 ? !(do_ME_bg = TRUE) : (do_ME_bg = FALSE)
1991# endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001992 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02001993#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01001994 aep->ae_u.cterm.bg_color)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995 do_ME = TRUE;
Bram Moolenaar4e5534f2020-04-30 20:59:57 +02001996#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1997 if (use_vtp())
1998 {
1999 if (do_ME_fg && do_ME_bg)
2000 do_ME = TRUE;
2001
2002 // FG and BG cannot be separated in T_ME, which is not
2003 // efficient.
2004 if (!do_ME && do_ME_fg)
2005 out_str((char_u *)"\033|39m"); // restore FG
2006 if (!do_ME && do_ME_bg)
2007 out_str((char_u *)"\033|49m"); // restore BG
2008 }
2009 else
2010 {
2011 // Process FG and BG at once.
2012 if (!do_ME)
2013 do_ME = do_ME_fg | do_ME_bg;
2014 }
2015#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002016 }
2017 else
2018 {
2019 aep = syn_term_attr2entry(screen_attr);
2020 if (aep != NULL && aep->ae_u.term.stop != NULL)
2021 {
2022 if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
2023 do_ME = TRUE;
2024 else
2025 out_str(aep->ae_u.term.stop);
2026 }
2027 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002028 if (aep == NULL) // did ":syntax clear"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029 screen_attr = 0;
2030 else
2031 screen_attr = aep->ae_attr;
2032 }
2033
2034 /*
2035 * Often all ending-codes are equal to T_ME. Avoid outputting the
2036 * same sequence several times.
2037 */
2038 if (screen_attr & HL_STANDOUT)
2039 {
2040 if (STRCMP(T_SE, T_ME) == 0)
2041 do_ME = TRUE;
2042 else
2043 out_str(T_SE);
2044 }
Bram Moolenaar84f54632022-06-29 18:39:11 +01002045 is_under = (screen_attr & (HL_UNDERCURL
2046 | HL_UNDERDOUBLE | HL_UNDERDOTTED | HL_UNDERDASHED));
2047 if (is_under && *T_UCE != NUL)
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01002048 {
2049 if (STRCMP(T_UCE, T_ME) == 0)
2050 do_ME = TRUE;
2051 else
2052 out_str(T_UCE);
2053 }
Bram Moolenaar84f54632022-06-29 18:39:11 +01002054 if ((screen_attr & HL_UNDERLINE) || (is_under && *T_UCE == NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055 {
2056 if (STRCMP(T_UE, T_ME) == 0)
2057 do_ME = TRUE;
2058 else
2059 out_str(T_UE);
2060 }
2061 if (screen_attr & HL_ITALIC)
2062 {
2063 if (STRCMP(T_CZR, T_ME) == 0)
2064 do_ME = TRUE;
2065 else
2066 out_str(T_CZR);
2067 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02002068 if (screen_attr & HL_STRIKETHROUGH)
2069 {
2070 if (STRCMP(T_STE, T_ME) == 0)
2071 do_ME = TRUE;
2072 else
2073 out_str(T_STE);
2074 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
2076 out_str(T_ME);
2077
Bram Moolenaar61be73b2016-04-29 22:59:22 +02002078#ifdef FEAT_TERMGUICOLORS
2079 if (p_tgc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02002081 if (cterm_normal_fg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002082 term_fg_rgb_color(cterm_normal_fg_gui_color);
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02002083 if (cterm_normal_bg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002084 term_bg_rgb_color(cterm_normal_bg_gui_color);
Bram Moolenaare023e882020-05-31 16:42:30 +02002085 if (cterm_normal_ul_gui_color != INVALCOLOR)
2086 term_ul_rgb_color(cterm_normal_ul_gui_color);
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002087 }
2088 else
2089#endif
2090 {
2091 if (t_colors > 1)
2092 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002093 // set Normal cterm colors
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002094 if (cterm_normal_fg_color != 0)
2095 term_fg_color(cterm_normal_fg_color - 1);
2096 if (cterm_normal_bg_color != 0)
2097 term_bg_color(cterm_normal_bg_color - 1);
Bram Moolenaare023e882020-05-31 16:42:30 +02002098 if (cterm_normal_ul_color != 0)
2099 term_ul_color(cterm_normal_ul_color - 1);
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002100 if (cterm_normal_fg_bold)
2101 out_str(T_MD);
2102 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 }
2104 }
2105 }
2106 screen_attr = 0;
2107}
2108
2109/*
2110 * Reset the colors for a cterm. Used when leaving Vim.
2111 * The machine specific code may override this again.
2112 */
2113 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002114reset_cterm_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115{
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002116 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002117 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002118 // set Normal cterm colors
Bram Moolenaar61be73b2016-04-29 22:59:22 +02002119#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02002120 if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
2121 || cterm_normal_bg_gui_color != INVALCOLOR)
2122 : (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002123#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002125#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126 {
2127 out_str(T_OP);
2128 screen_attr = -1;
2129 }
2130 if (cterm_normal_fg_bold)
2131 {
2132 out_str(T_ME);
2133 screen_attr = -1;
2134 }
2135 }
2136}
2137
2138/*
2139 * Put character ScreenLines["off"] on the screen at position "row" and "col",
2140 * using the attributes from ScreenAttrs["off"].
2141 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02002142 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002143screen_char(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144{
2145 int attr;
2146
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002147 // Check for illegal values, just in case (could happen just after
2148 // resizing).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002149 if (row >= screen_Rows || col >= screen_Columns)
2150 return;
2151
Bram Moolenaar33796b32019-06-08 16:01:13 +02002152 // Skip if under the popup menu.
2153 // Popup windows with zindex higher than POPUPMENU_ZINDEX go on top.
Bakudankun65555002021-11-17 20:40:16 +00002154 if (pum_under_menu(row, col, TRUE)
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002155#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002156 && screen_zindex <= POPUPMENU_ZINDEX
Bram Moolenaare2c453d2019-08-21 14:37:09 +02002157#endif
Bram Moolenaar33796b32019-06-08 16:01:13 +02002158 )
Bram Moolenaarae654382019-01-17 21:09:05 +01002159 return;
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002160#ifdef FEAT_PROP_POPUP
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002161 if (blocked_by_popup(row, col))
Bram Moolenaar33796b32019-06-08 16:01:13 +02002162 return;
2163#endif
2164
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002165 // Outputting a character in the last cell on the screen may scroll the
2166 // screen up. Only do it when the "xn" termcap property is set, otherwise
2167 // mark the character invalid (update it when scrolled up).
Bram Moolenaar494838a2015-02-10 19:20:37 +01002168 if (*T_XN == NUL
2169 && row == screen_Rows - 1 && col == screen_Columns - 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170#ifdef FEAT_RIGHTLEFT
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002171 // account for first command-line character in rightleft mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 && !cmdmsg_rl
2173#endif
2174 )
2175 {
2176 ScreenAttrs[off] = (sattr_T)-1;
2177 return;
2178 }
2179
2180 /*
2181 * Stop highlighting first, so it's easier to move the cursor.
2182 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 if (screen_char_attr != 0)
2184 attr = screen_char_attr;
2185 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002186 attr = ScreenAttrs[off];
2187 if (screen_attr != attr)
2188 screen_stop_highlight();
2189
2190 windgoto(row, col);
2191
2192 if (screen_attr != attr)
2193 screen_start_highlight(attr);
2194
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195 if (enc_utf8 && ScreenLinesUC[off] != 0)
2196 {
2197 char_u buf[MB_MAXBYTES + 1];
2198
Bram Moolenaarcb070082016-04-02 22:14:51 +02002199 if (utf_ambiguous_width(ScreenLinesUC[off]))
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01002200 {
2201 if (*p_ambw == 'd'
Bram Moolenaara12a1612019-01-24 16:39:02 +01002202#ifdef FEAT_GUI
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01002203 && !gui.in_use
Bram Moolenaara12a1612019-01-24 16:39:02 +01002204#endif
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01002205 )
2206 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002207 // Clear the two screen cells. If the character is actually
2208 // single width it won't change the second cell.
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01002209 out_str((char_u *)" ");
2210 term_windgoto(row, col);
2211 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002212 // not sure where the cursor is after drawing the ambiguous width
2213 // character
Bram Moolenaarcb070082016-04-02 22:14:51 +02002214 screen_cur_col = 9999;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01002215 }
Bram Moolenaarcb070082016-04-02 22:14:51 +02002216 else if (utf_char2cells(ScreenLinesUC[off]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 ++screen_cur_col;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01002218
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002219 // Convert the UTF-8 character to bytes and write it.
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01002220 buf[utfc_char2bytes(off, buf)] = NUL;
2221 out_str(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002222 }
2223 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 out_flush_check();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 out_char(ScreenLines[off]);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002227 // double-byte character in single-width cell
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
2229 out_char(ScreenLines2[off]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230 }
2231
2232 screen_cur_col++;
2233}
2234
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235/*
2236 * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
2237 * on the screen at position 'row' and 'col'.
2238 * The attributes of the first byte is used for all. This is required to
2239 * output the two bytes of a double-byte character with nothing in between.
2240 */
2241 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002242screen_char_2(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243{
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002244 // Check for illegal values (could be wrong when screen was resized).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245 if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
2246 return;
2247
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002248 // Outputting the last character on the screen may scrollup the screen.
2249 // Don't to it! Mark the character invalid (update it when scrolled up)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002250 if (row == screen_Rows - 1 && col >= screen_Columns - 2)
2251 {
2252 ScreenAttrs[off] = (sattr_T)-1;
2253 return;
2254 }
2255
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002256 // Output the first byte normally (positions the cursor), then write the
2257 // second byte directly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 screen_char(off, row, col);
2259 out_char(ScreenLines[off + 1]);
2260 ++screen_cur_col;
2261}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263/*
2264 * Draw a rectangle of the screen, inverted when "invert" is TRUE.
2265 * This uses the contents of ScreenLines[] and doesn't change it.
2266 */
2267 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002268screen_draw_rectangle(
2269 int row,
2270 int col,
2271 int height,
2272 int width,
2273 int invert)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274{
2275 int r, c;
2276 int off;
Bram Moolenaar367329b2007-08-30 11:53:22 +00002277 int max_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002279 // Can't use ScreenLines unless initialized
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002280 if (ScreenLines == NULL)
2281 return;
2282
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 if (invert)
2284 screen_char_attr = HL_INVERSE;
2285 for (r = row; r < row + height; ++r)
2286 {
2287 off = LineOffset[r];
Bram Moolenaar367329b2007-08-30 11:53:22 +00002288 max_off = off + screen_Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 for (c = col; c < col + width; ++c)
2290 {
Bram Moolenaar367329b2007-08-30 11:53:22 +00002291 if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 {
2293 screen_char_2(off + c, r, c);
2294 ++c;
2295 }
2296 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 {
2298 screen_char(off + c, r, c);
Bram Moolenaar367329b2007-08-30 11:53:22 +00002299 if (utf_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 ++c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 }
2302 }
2303 }
2304 screen_char_attr = 0;
2305}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307/*
2308 * Redraw the characters for a vertically split window.
2309 */
2310 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002311redraw_block(int row, int end, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312{
2313 int col;
2314 int width;
2315
2316# ifdef FEAT_CLIPBOARD
2317 clip_may_clear_selection(row, end - 1);
2318# endif
2319
2320 if (wp == NULL)
2321 {
2322 col = 0;
2323 width = Columns;
2324 }
2325 else
2326 {
2327 col = wp->w_wincol;
2328 width = wp->w_width;
2329 }
2330 screen_draw_rectangle(row, col, end - row, width, FALSE);
2331}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02002333 void
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002334space_to_screenline(int off, int attr)
2335{
2336 ScreenLines[off] = ' ';
2337 ScreenAttrs[off] = attr;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002338 if (enc_utf8)
2339 ScreenLinesUC[off] = 0;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002340}
2341
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342/*
Bram Moolenaarcee9c842022-04-09 12:40:13 +01002343 * Fill the screen from "start_row" to "end_row" (exclusive), from "start_col"
2344 * to "end_col" (exclusive) with character "c1" in first column followed by
2345 * "c2" in the other columns. Use attributes "attr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346 */
2347 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002348screen_fill(
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002349 int start_row,
2350 int end_row,
2351 int start_col,
2352 int end_col,
2353 int c1,
2354 int c2,
2355 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356{
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002357 int row;
2358 int col;
2359 int off;
2360 int end_off;
2361 int did_delete;
2362 int c;
2363 int norm_term;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002365 int force_next = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366#endif
2367
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002368 if (end_row > screen_Rows) // safety check
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 end_row = screen_Rows;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002370 if (end_col > screen_Columns) // safety check
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371 end_col = screen_Columns;
2372 if (ScreenLines == NULL
2373 || start_row >= end_row
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002374 || start_col >= end_col) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 return;
2376
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002377 // it's a "normal" terminal when not in a GUI or cterm
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 norm_term = (
2379#ifdef FEAT_GUI
2380 !gui.in_use &&
2381#endif
Bram Moolenaar8a633e32016-04-21 21:10:14 +02002382 !IS_CTERM);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 for (row = start_row; row < end_row; ++row)
2384 {
Bram Moolenaarc236c162008-07-13 17:41:49 +00002385 if (has_mbyte
Bram Moolenaara12a1612019-01-24 16:39:02 +01002386#ifdef FEAT_GUI
Bram Moolenaarc236c162008-07-13 17:41:49 +00002387 && !gui.in_use
Bram Moolenaara12a1612019-01-24 16:39:02 +01002388#endif
Bram Moolenaarc236c162008-07-13 17:41:49 +00002389 )
2390 {
Dominique Pelleaf4a61a2021-12-27 17:21:41 +00002391 // When drawing over the right half of a double-wide char clear
2392 // out the left half. When drawing over the left half of a
2393 // double wide-char clear out the right half. Only needed in a
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002394 // terminal.
Bram Moolenaar7693ec62008-07-24 18:29:37 +00002395 if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00002396 screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
Bram Moolenaara1aed622008-07-18 15:14:43 +00002397 if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00002398 screen_puts_len((char_u *)" ", 1, row, end_col, 0);
Bram Moolenaarc236c162008-07-13 17:41:49 +00002399 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400 /*
2401 * Try to use delete-line termcap code, when no attributes or in a
2402 * "normal" terminal, where a bold/italic space is just a
2403 * space.
2404 */
2405 did_delete = FALSE;
2406 if (c2 == ' '
2407 && end_col == Columns
2408 && can_clear(T_CE)
2409 && (attr == 0
2410 || (norm_term
2411 && attr <= HL_ALL
2412 && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
2413 {
2414 /*
2415 * check if we really need to clear something
2416 */
2417 col = start_col;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002418 if (c1 != ' ') // don't clear first char
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 ++col;
2420
2421 off = LineOffset[row] + col;
2422 end_off = LineOffset[row] + end_col;
2423
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002424 // skip blanks (used often, keep it fast!)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 if (enc_utf8)
2426 while (off < end_off && ScreenLines[off] == ' '
2427 && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
2428 ++off;
2429 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 while (off < end_off && ScreenLines[off] == ' '
2431 && ScreenAttrs[off] == 0)
2432 ++off;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002433 if (off < end_off) // something to be cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 {
2435 col = off - LineOffset[row];
2436 screen_stop_highlight();
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002437 term_windgoto(row, col);// clear rest of this screen line
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 out_str(T_CE);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002439 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 col = end_col - col;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002441 while (col--) // clear chars in ScreenLines
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442 {
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002443 space_to_screenline(off, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 ++off;
2445 }
2446 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002447 did_delete = TRUE; // the chars are cleared now
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 }
2449
2450 off = LineOffset[row] + start_col;
2451 c = c1;
2452 for (col = start_col; col < end_col; ++col)
2453 {
Bram Moolenaar33796b32019-06-08 16:01:13 +02002454 if ((ScreenLines[off] != c
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002455 || (enc_utf8 && (int)ScreenLinesUC[off]
2456 != (c >= 0x80 ? c : 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457 || ScreenAttrs[off] != attr
2458#if defined(FEAT_GUI) || defined(UNIX)
2459 || force_next
2460#endif
2461 )
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002462#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002463 // Skip if under a(nother) popup.
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002464 && !blocked_by_popup(row, col)
Bram Moolenaar33796b32019-06-08 16:01:13 +02002465#endif
2466 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 {
2468#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002469 // The bold trick may make a single row of pixels appear in
2470 // the next character. When a bold character is removed, the
2471 // next character should be redrawn too. This happens for our
2472 // own GUI and for some xterms.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 if (
2474# ifdef FEAT_GUI
2475 gui.in_use
2476# endif
2477# if defined(FEAT_GUI) && defined(UNIX)
2478 ||
2479# endif
2480# ifdef UNIX
2481 term_is_xterm
2482# endif
2483 )
2484 {
2485 if (ScreenLines[off] != ' '
2486 && (ScreenAttrs[off] > HL_ALL
2487 || ScreenAttrs[off] & HL_BOLD))
2488 force_next = TRUE;
2489 else
2490 force_next = FALSE;
2491 }
2492#endif
2493 ScreenLines[off] = c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 if (enc_utf8)
2495 {
2496 if (c >= 0x80)
2497 {
2498 ScreenLinesUC[off] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002499 ScreenLinesC[0][off] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 }
2501 else
2502 ScreenLinesUC[off] = 0;
2503 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 ScreenAttrs[off] = attr;
2505 if (!did_delete || c != ' ')
2506 screen_char(off, row, col);
2507 }
2508 ++off;
2509 if (col == start_col)
2510 {
2511 if (did_delete)
2512 break;
2513 c = c2;
2514 }
2515 }
2516 if (end_col == Columns)
2517 LineWraps[row] = FALSE;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002518 if (row == Rows - 1) // overwritten the command line
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 {
2520 redraw_cmdline = TRUE;
Bram Moolenaar5bab5552018-04-13 20:41:29 +02002521 if (start_col == 0 && end_col == Columns
2522 && c1 == ' ' && c2 == ' ' && attr == 0)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002523 clear_cmdline = FALSE; // command line has been cleared
Bram Moolenaard12f5c12006-01-25 22:10:52 +00002524 if (start_col == 0)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002525 mode_displayed = FALSE; // mode cleared or overwritten
Bram Moolenaar071d4272004-06-13 20:20:40 +00002526 }
2527 }
2528}
2529
2530/*
2531 * Check if there should be a delay. Used before clearing or redrawing the
2532 * screen or the command line.
2533 */
2534 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002535check_for_delay(int check_msg_scroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536{
2537 if ((emsg_on_display || (check_msg_scroll && msg_scroll))
2538 && !did_wait_return
Bram Moolenaar28ee8922020-10-28 20:20:00 +01002539 && emsg_silent == 0
2540 && !in_assert_fails)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 {
2542 out_flush();
Bram Moolenaareda1da02019-11-17 17:06:33 +01002543 ui_delay(1006L, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 emsg_on_display = FALSE;
2545 if (check_msg_scroll)
2546 msg_scroll = FALSE;
2547 }
2548}
2549
2550/*
Bram Moolenaarca57ab52019-04-13 14:53:16 +02002551 * Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
2552 */
2553 static void
2554clear_TabPageIdxs(void)
2555{
2556 int scol;
2557
2558 for (scol = 0; scol < Columns; ++scol)
2559 TabPageIdxs[scol] = 0;
2560}
2561
2562/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002563 * screen_valid - allocate screen buffers if size changed
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002564 * If "doclear" is TRUE: clear screen if it has been resized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565 * Returns TRUE if there is a valid screen to write to.
2566 * Returns FALSE when starting up and screen not initialized yet.
2567 */
2568 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002569screen_valid(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570{
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002571 screenalloc(doclear); // allocate screen buffers if size changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 return (ScreenLines != NULL);
2573}
2574
2575/*
2576 * Resize the shell to Rows and Columns.
2577 * Allocate ScreenLines[] and associated items.
2578 *
2579 * There may be some time between setting Rows and Columns and (re)allocating
2580 * ScreenLines[]. This happens when starting up and when (manually) changing
2581 * the shell size. Always use screen_Rows and screen_Columns to access items
2582 * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
2583 * final size of the shell is needed.
2584 */
2585 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002586screenalloc(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587{
2588 int new_row, old_row;
2589#ifdef FEAT_GUI
2590 int old_Rows;
2591#endif
2592 win_T *wp;
2593 int outofmem = FALSE;
2594 int len;
2595 schar_T *new_ScreenLines;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 u8char_T *new_ScreenLinesUC = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002597 u8char_T *new_ScreenLinesC[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598 schar_T *new_ScreenLines2 = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002599 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600 sattr_T *new_ScreenAttrs;
2601 unsigned *new_LineOffset;
2602 char_u *new_LineWraps;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002603 short *new_TabPageIdxs;
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002604#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002605 short *new_popup_mask;
Bram Moolenaar4c063a02019-06-10 21:24:12 +02002606 short *new_popup_mask_next;
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002607 char *new_popup_transparent;
Bram Moolenaar33796b32019-06-08 16:01:13 +02002608#endif
Bram Moolenaarf740b292006-02-16 22:11:02 +00002609 tabpage_T *tp;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002610 static int entered = FALSE; // avoid recursiveness
2611 static int done_outofmem_msg = FALSE; // did outofmem message
Bram Moolenaar87e817c2009-02-22 20:13:39 +00002612 int retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613
Bram Moolenaar87e817c2009-02-22 20:13:39 +00002614retry:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615 /*
2616 * Allocation of the screen buffers is done only when the size changes and
2617 * when Rows and Columns have been set and we have started doing full
2618 * screen stuff.
2619 */
2620 if ((ScreenLines != NULL
2621 && Rows == screen_Rows
2622 && Columns == screen_Columns
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 && enc_utf8 == (ScreenLinesUC != NULL)
2624 && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
Bram Moolenaara12a1612019-01-24 16:39:02 +01002625 && p_mco == Screen_mco)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 || Rows == 0
2627 || Columns == 0
2628 || (!full_screen && ScreenLines == NULL))
2629 return;
2630
2631 /*
2632 * It's possible that we produce an out-of-memory message below, which
2633 * will cause this function to be called again. To break the loop, just
2634 * return here.
2635 */
2636 if (entered)
2637 return;
2638 entered = TRUE;
2639
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00002640 /*
2641 * Note that the window sizes are updated before reallocating the arrays,
2642 * thus we must not redraw here!
2643 */
2644 ++RedrawingDisabled;
2645
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002646 win_new_shellsize(); // fit the windows in the new sized shell
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002648#ifdef FEAT_GUI_HAIKU
2649 vim_lock_screen(); // be safe, put it here
2650#endif
2651
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002652 comp_col(); // recompute columns for shown command and ruler
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653
2654 /*
2655 * We're changing the size of the screen.
2656 * - Allocate new arrays for ScreenLines and ScreenAttrs.
2657 * - Move lines from the old arrays into the new arrays, clear extra
2658 * lines (unless the screen is going to be cleared).
2659 * - Free the old arrays.
2660 *
2661 * If anything fails, make ScreenLines NULL, so we don't do anything!
2662 * Continuing with the old ScreenLines may result in a crash, because the
2663 * size is wrong.
2664 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002665 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002666 win_free_lsize(wp);
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00002667 if (aucmd_win != NULL)
2668 win_free_lsize(aucmd_win);
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002669#ifdef FEAT_PROP_POPUP
Bram Moolenaar8caaf822019-06-01 18:11:22 +02002670 // global popup windows
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002671 FOR_ALL_POPUPWINS(wp)
Bram Moolenaar8caaf822019-06-01 18:11:22 +02002672 win_free_lsize(wp);
2673 // tab-local popup windows
2674 FOR_ALL_TABPAGES(tp)
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002675 FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
Bram Moolenaar8caaf822019-06-01 18:11:22 +02002676 win_free_lsize(wp);
2677#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002679 new_ScreenLines = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
Bram Moolenaar216b7102010-03-23 13:56:59 +01002680 vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 if (enc_utf8)
2682 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002683 new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002684 for (i = 0; i < p_mco; ++i)
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002685 new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T,
2686 (Rows + 1) * Columns);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687 }
2688 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002689 new_ScreenLines2 = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
2690 new_ScreenAttrs = LALLOC_MULT(sattr_T, (Rows + 1) * Columns);
2691 new_LineOffset = LALLOC_MULT(unsigned, Rows);
2692 new_LineWraps = LALLOC_MULT(char_u, Rows);
2693 new_TabPageIdxs = LALLOC_MULT(short, Columns);
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002694#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002695 new_popup_mask = LALLOC_MULT(short, Rows * Columns);
Bram Moolenaar4c063a02019-06-10 21:24:12 +02002696 new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002697 new_popup_transparent = LALLOC_MULT(char, Rows * Columns);
Bram Moolenaar33796b32019-06-08 16:01:13 +02002698#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002699
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00002700 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701 {
2702 if (win_alloc_lines(wp) == FAIL)
2703 {
2704 outofmem = TRUE;
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00002705 goto give_up;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706 }
2707 }
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00002708 if (aucmd_win != NULL && aucmd_win->w_lines == NULL
2709 && win_alloc_lines(aucmd_win) == FAIL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002710 outofmem = TRUE;
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002711#ifdef FEAT_PROP_POPUP
Bram Moolenaar8caaf822019-06-01 18:11:22 +02002712 // global popup windows
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002713 FOR_ALL_POPUPWINS(wp)
Bram Moolenaar8caaf822019-06-01 18:11:22 +02002714 if (win_alloc_lines(wp) == FAIL)
2715 {
2716 outofmem = TRUE;
2717 goto give_up;
2718 }
2719 // tab-local popup windows
2720 FOR_ALL_TABPAGES(tp)
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002721 FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
Bram Moolenaar8caaf822019-06-01 18:11:22 +02002722 if (win_alloc_lines(wp) == FAIL)
2723 {
2724 outofmem = TRUE;
2725 goto give_up;
2726 }
2727#endif
2728
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00002729give_up:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002731 for (i = 0; i < p_mco; ++i)
2732 if (new_ScreenLinesC[i] == NULL)
2733 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734 if (new_ScreenLines == NULL
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002735 || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002736 || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 || new_ScreenAttrs == NULL
2738 || new_LineOffset == NULL
2739 || new_LineWraps == NULL
Bram Moolenaarf740b292006-02-16 22:11:02 +00002740 || new_TabPageIdxs == NULL
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002741#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002742 || new_popup_mask == NULL
Bram Moolenaar4c063a02019-06-10 21:24:12 +02002743 || new_popup_mask_next == NULL
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002744 || new_popup_transparent == NULL
Bram Moolenaar33796b32019-06-08 16:01:13 +02002745#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 || outofmem)
2747 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00002748 if (ScreenLines != NULL || !done_outofmem_msg)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002749 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002750 // guess the size
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002751 do_outofmem_msg((long_u)((Rows + 1) * Columns));
2752
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002753 // Remember we did this to avoid getting outofmem messages over
2754 // and over again.
Bram Moolenaar89d40322006-08-29 15:30:07 +00002755 done_outofmem_msg = TRUE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002756 }
Bram Moolenaard23a8232018-02-10 18:45:26 +01002757 VIM_CLEAR(new_ScreenLines);
Bram Moolenaard23a8232018-02-10 18:45:26 +01002758 VIM_CLEAR(new_ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002759 for (i = 0; i < p_mco; ++i)
Bram Moolenaard23a8232018-02-10 18:45:26 +01002760 VIM_CLEAR(new_ScreenLinesC[i]);
2761 VIM_CLEAR(new_ScreenLines2);
Bram Moolenaard23a8232018-02-10 18:45:26 +01002762 VIM_CLEAR(new_ScreenAttrs);
2763 VIM_CLEAR(new_LineOffset);
2764 VIM_CLEAR(new_LineWraps);
2765 VIM_CLEAR(new_TabPageIdxs);
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002766#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002767 VIM_CLEAR(new_popup_mask);
Bram Moolenaar4c063a02019-06-10 21:24:12 +02002768 VIM_CLEAR(new_popup_mask_next);
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002769 VIM_CLEAR(new_popup_transparent);
Bram Moolenaar33796b32019-06-08 16:01:13 +02002770#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771 }
2772 else
2773 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00002774 done_outofmem_msg = FALSE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002775
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 for (new_row = 0; new_row < Rows; ++new_row)
2777 {
2778 new_LineOffset[new_row] = new_row * Columns;
2779 new_LineWraps[new_row] = FALSE;
2780
2781 /*
2782 * If the screen is not going to be cleared, copy as much as
2783 * possible from the old screen to the new one and clear the rest
2784 * (used when resizing the window at the "--more--" prompt or when
2785 * executing an external command, for the GUI).
2786 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002787 if (!doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002788 {
2789 (void)vim_memset(new_ScreenLines + new_row * Columns,
2790 ' ', (size_t)Columns * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791 if (enc_utf8)
2792 {
2793 (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
2794 0, (size_t)Columns * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002795 for (i = 0; i < p_mco; ++i)
2796 (void)vim_memset(new_ScreenLinesC[i]
2797 + new_row * Columns,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798 0, (size_t)Columns * sizeof(u8char_T));
2799 }
2800 if (enc_dbcs == DBCS_JPNU)
2801 (void)vim_memset(new_ScreenLines2 + new_row * Columns,
2802 0, (size_t)Columns * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803 (void)vim_memset(new_ScreenAttrs + new_row * Columns,
2804 0, (size_t)Columns * sizeof(sattr_T));
2805 old_row = new_row + (screen_Rows - Rows);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002806 if (old_row >= 0 && ScreenLines != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 {
2808 if (screen_Columns < Columns)
2809 len = screen_Columns;
2810 else
2811 len = Columns;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002812 // When switching to utf-8 don't copy characters, they
2813 // may be invalid now. Also when p_mco changes.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002814 if (!(enc_utf8 && ScreenLinesUC == NULL)
2815 && p_mco == Screen_mco)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002816 mch_memmove(new_ScreenLines + new_LineOffset[new_row],
2817 ScreenLines + LineOffset[old_row],
2818 (size_t)len * sizeof(schar_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002819 if (enc_utf8 && ScreenLinesUC != NULL
2820 && p_mco == Screen_mco)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821 {
2822 mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
2823 ScreenLinesUC + LineOffset[old_row],
2824 (size_t)len * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002825 for (i = 0; i < p_mco; ++i)
2826 mch_memmove(new_ScreenLinesC[i]
2827 + new_LineOffset[new_row],
2828 ScreenLinesC[i] + LineOffset[old_row],
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829 (size_t)len * sizeof(u8char_T));
2830 }
2831 if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
2832 mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
2833 ScreenLines2 + LineOffset[old_row],
2834 (size_t)len * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
2836 ScreenAttrs + LineOffset[old_row],
2837 (size_t)len * sizeof(sattr_T));
2838 }
2839 }
2840 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002841 // Use the last line of the screen for the current line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002842 current_ScreenLine = new_ScreenLines + Rows * Columns;
Bram Moolenaar6ace95e2019-08-13 23:09:49 +02002843
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002844#ifdef FEAT_PROP_POPUP
Bram Moolenaar6ace95e2019-08-13 23:09:49 +02002845 vim_memset(new_popup_mask, 0, Rows * Columns * sizeof(short));
2846 vim_memset(new_popup_transparent, 0, Rows * Columns * sizeof(char));
2847#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848 }
2849
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00002850 free_screenlines();
2851
Bram Moolenaar6ace95e2019-08-13 23:09:49 +02002852 // NOTE: this may result in all pointers to become NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853 ScreenLines = new_ScreenLines;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854 ScreenLinesUC = new_ScreenLinesUC;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002855 for (i = 0; i < p_mco; ++i)
2856 ScreenLinesC[i] = new_ScreenLinesC[i];
2857 Screen_mco = p_mco;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 ScreenLines2 = new_ScreenLines2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859 ScreenAttrs = new_ScreenAttrs;
2860 LineOffset = new_LineOffset;
2861 LineWraps = new_LineWraps;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002862 TabPageIdxs = new_TabPageIdxs;
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002863#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002864 popup_mask = new_popup_mask;
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002865 popup_mask_next = new_popup_mask_next;
2866 popup_transparent = new_popup_transparent;
Bram Moolenaar33796b32019-06-08 16:01:13 +02002867 popup_mask_refresh = TRUE;
2868#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002870 // It's important that screen_Rows and screen_Columns reflect the actual
2871 // size of ScreenLines[]. Set them before calling anything.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872#ifdef FEAT_GUI
2873 old_Rows = screen_Rows;
2874#endif
2875 screen_Rows = Rows;
2876 screen_Columns = Columns;
2877
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002878 must_redraw = CLEAR; // need to clear the screen later
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002879 if (doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880 screenclear2();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881#ifdef FEAT_GUI
2882 else if (gui.in_use
2883 && !gui.starting
2884 && ScreenLines != NULL
2885 && old_Rows != Rows)
2886 {
Bram Moolenaar7c003aa2020-03-28 20:44:41 +01002887 gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
2888
2889 // Adjust the position of the cursor, for when executing an external
2890 // command.
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002891 if (msg_row >= Rows) // Rows got smaller
2892 msg_row = Rows - 1; // put cursor at last row
2893 else if (Rows > old_Rows) // Rows got bigger
2894 msg_row += Rows - old_Rows; // put cursor in same place
2895 if (msg_col >= Columns) // Columns got smaller
2896 msg_col = Columns - 1; // put cursor at last column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 }
2898#endif
Bram Moolenaarca57ab52019-04-13 14:53:16 +02002899 clear_TabPageIdxs();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002901#ifdef FEAT_GUI_HAIKU
2902 vim_unlock_screen();
2903#endif
2904
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905 entered = FALSE;
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00002906 --RedrawingDisabled;
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00002907
Bram Moolenaar87e817c2009-02-22 20:13:39 +00002908 /*
2909 * Do not apply autocommands more than 3 times to avoid an endless loop
2910 * in case applying autocommands always changes Rows or Columns.
2911 */
2912 if (starting == 0 && ++retry_count <= 3)
2913 {
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00002914 apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002915 // In rare cases, autocommands may have altered Rows or Columns,
2916 // jump back to check if we need to allocate the screen again.
Bram Moolenaar87e817c2009-02-22 20:13:39 +00002917 goto retry;
2918 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919}
2920
2921 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002922free_screenlines(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00002923{
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002924 int i;
2925
Bram Moolenaar33796b32019-06-08 16:01:13 +02002926 VIM_CLEAR(ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002927 for (i = 0; i < Screen_mco; ++i)
Bram Moolenaar33796b32019-06-08 16:01:13 +02002928 VIM_CLEAR(ScreenLinesC[i]);
2929 VIM_CLEAR(ScreenLines2);
2930 VIM_CLEAR(ScreenLines);
2931 VIM_CLEAR(ScreenAttrs);
2932 VIM_CLEAR(LineOffset);
2933 VIM_CLEAR(LineWraps);
2934 VIM_CLEAR(TabPageIdxs);
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002935#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02002936 VIM_CLEAR(popup_mask);
Bram Moolenaar4c063a02019-06-10 21:24:12 +02002937 VIM_CLEAR(popup_mask_next);
Bram Moolenaarc662ec92019-06-23 00:15:57 +02002938 VIM_CLEAR(popup_transparent);
Bram Moolenaar33796b32019-06-08 16:01:13 +02002939#endif
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00002940}
2941
2942 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002943screenclear(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944{
2945 check_for_delay(FALSE);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002946 screenalloc(FALSE); // allocate screen buffers if size changed
2947 screenclear2(); // clear the screen
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948}
2949
2950 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002951screenclear2(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952{
2953 int i;
2954
2955 if (starting == NO_SCREEN || ScreenLines == NULL
2956#ifdef FEAT_GUI
2957 || (gui.in_use && gui.starting)
2958#endif
2959 )
2960 return;
2961
2962#ifdef FEAT_GUI
2963 if (!gui.in_use)
2964#endif
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002965 screen_attr = -1; // force setting the Normal colors
2966 screen_stop_highlight(); // don't want highlighting here
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967
2968#ifdef FEAT_CLIPBOARD
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002969 // disable selection without redrawing it
Bram Moolenaar071d4272004-06-13 20:20:40 +00002970 clip_scroll_selection(9999);
2971#endif
2972
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002973 // blank out ScreenLines
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974 for (i = 0; i < Rows; ++i)
2975 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02002976 lineclear(LineOffset[i], (int)Columns, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002977 LineWraps[i] = FALSE;
2978 }
2979
2980 if (can_clear(T_CL))
2981 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002982 out_str(T_CL); // clear the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 clear_cmdline = FALSE;
Bram Moolenaard12f5c12006-01-25 22:10:52 +00002984 mode_displayed = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985 }
2986 else
2987 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002988 // can't clear the screen, mark all chars with invalid attributes
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989 for (i = 0; i < Rows; ++i)
2990 lineinvalid(LineOffset[i], (int)Columns);
2991 clear_cmdline = TRUE;
2992 }
2993
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002994 screen_cleared = TRUE; // can use contents of ScreenLines now
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995
2996 win_rest_invalid(firstwin);
2997 redraw_cmdline = TRUE;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00002998 redraw_tabline = TRUE;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01002999 if (must_redraw == CLEAR) // no need to clear again
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 must_redraw = NOT_VALID;
3001 compute_cmdrow();
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003002 msg_row = cmdline_row; // put cursor on last line for messages
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003 msg_col = 0;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003004 screen_start(); // don't know where cursor is now
3005 msg_scrolled = 0; // can't scroll back
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 msg_didany = FALSE;
3007 msg_didout = FALSE;
3008}
3009
3010/*
3011 * Clear one line in ScreenLines.
3012 */
3013 static void
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003014lineclear(unsigned off, int width, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015{
3016 (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003017 if (enc_utf8)
3018 (void)vim_memset(ScreenLinesUC + off, 0,
3019 (size_t)width * sizeof(u8char_T));
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003020 (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021}
3022
3023/*
3024 * Mark one line in ScreenLines invalid by setting the attributes to an
3025 * invalid value.
3026 */
3027 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003028lineinvalid(unsigned off, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003029{
3030 (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
3031}
3032
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033/*
Bram Moolenaar96916ac2020-07-08 23:09:28 +02003034 * To be called when characters were sent to the terminal directly, outputting
3035 * test on "screen_lnum".
3036 */
3037 void
3038line_was_clobbered(int screen_lnum)
3039{
3040 lineinvalid(LineOffset[screen_lnum], (int)Columns);
3041}
3042
3043/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044 * Copy part of a Screenline for vertically split window "wp".
3045 */
3046 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003047linecopy(int to, int from, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048{
3049 unsigned off_to = LineOffset[to] + wp->w_wincol;
3050 unsigned off_from = LineOffset[from] + wp->w_wincol;
3051
3052 mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
3053 wp->w_width * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054 if (enc_utf8)
3055 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003056 int i;
3057
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058 mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
3059 wp->w_width * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003060 for (i = 0; i < p_mco; ++i)
3061 mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
3062 wp->w_width * sizeof(u8char_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063 }
3064 if (enc_dbcs == DBCS_JPNU)
3065 mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
3066 wp->w_width * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067 mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
3068 wp->w_width * sizeof(sattr_T));
3069}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070
3071/*
3072 * Return TRUE if clearing with term string "p" would work.
3073 * It can't work when the string is empty or it won't set the right background.
Bram Moolenaar33796b32019-06-08 16:01:13 +02003074 * Don't clear to end-of-line when there are popups, it may cause flicker.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 */
3076 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003077can_clear(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078{
3079 return (*p != NUL && (t_colors <= 1
3080#ifdef FEAT_GUI
3081 || gui.in_use
3082#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +02003083#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02003084 || (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
Bram Moolenaard18f6722016-06-17 13:18:49 +02003085 || (!p_tgc && cterm_normal_bg_color == 0)
3086#else
3087 || cterm_normal_bg_color == 0
Bram Moolenaar8a633e32016-04-21 21:10:14 +02003088#endif
Bram Moolenaar33796b32019-06-08 16:01:13 +02003089 || *T_UT != NUL)
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003090#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02003091 && !(p == T_CE && popup_visible)
3092#endif
3093 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094}
3095
3096/*
3097 * Reset cursor position. Use whenever cursor was moved because of outputting
3098 * something directly to the screen (shell commands) or a terminal control
3099 * code.
3100 */
3101 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003102screen_start(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103{
3104 screen_cur_row = screen_cur_col = 9999;
3105}
3106
3107/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003108 * Move the cursor to position "row","col" in the screen.
3109 * This tries to find the most efficient way to move, minimizing the number of
3110 * characters sent to the terminal.
3111 */
3112 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003113windgoto(int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114{
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003115 sattr_T *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 int i;
3117 int plan;
3118 int cost;
3119 int wouldbe_col;
3120 int noinvcurs;
3121 char_u *bs;
3122 int goto_cost;
3123 int attr;
3124
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003125#define GOTO_COST 7 // assume a term_windgoto() takes about 7 chars
3126#define HIGHL_COST 5 // assume unhighlight takes 5 chars
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127
3128#define PLAN_LE 1
3129#define PLAN_CR 2
3130#define PLAN_NL 3
3131#define PLAN_WRITE 4
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003132 // Can't use ScreenLines unless initialized
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133 if (ScreenLines == NULL)
3134 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 if (col != screen_cur_col || row != screen_cur_row)
3136 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003137 // Check for valid position.
3138 if (row < 0) // window without text lines?
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 row = 0;
3140 if (row >= screen_Rows)
3141 row = screen_Rows - 1;
3142 if (col >= screen_Columns)
3143 col = screen_Columns - 1;
3144
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003145 // check if no cursor movement is allowed in highlight mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 if (screen_attr && *T_MS == NUL)
3147 noinvcurs = HIGHL_COST;
3148 else
3149 noinvcurs = 0;
3150 goto_cost = GOTO_COST + noinvcurs;
3151
3152 /*
3153 * Plan how to do the positioning:
3154 * 1. Use CR to move it to column 0, same row.
3155 * 2. Use T_LE to move it a few columns to the left.
3156 * 3. Use NL to move a few lines down, column 0.
3157 * 4. Move a few columns to the right with T_ND or by writing chars.
3158 *
3159 * Don't do this if the cursor went beyond the last column, the cursor
3160 * position is unknown then (some terminals wrap, some don't )
3161 *
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00003162 * First check if the highlighting attributes allow us to write
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163 * characters to move the cursor to the right.
3164 */
3165 if (row >= screen_cur_row && screen_cur_col < Columns)
3166 {
3167 /*
3168 * If the cursor is in the same row, bigger col, we can use CR
3169 * or T_LE.
3170 */
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003171 bs = NULL; // init for GCC
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172 attr = screen_attr;
3173 if (row == screen_cur_row && col < screen_cur_col)
3174 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003175 // "le" is preferred over "bc", because "bc" is obsolete
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176 if (*T_LE)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003177 bs = T_LE; // "cursor left"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178 else
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003179 bs = T_BC; // "backspace character (old)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180 if (*bs)
3181 cost = (screen_cur_col - col) * (int)STRLEN(bs);
3182 else
3183 cost = 999;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003184 if (col + 1 < cost) // using CR is less characters
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185 {
3186 plan = PLAN_CR;
3187 wouldbe_col = 0;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003188 cost = 1; // CR is just one character
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189 }
3190 else
3191 {
3192 plan = PLAN_LE;
3193 wouldbe_col = col;
3194 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003195 if (noinvcurs) // will stop highlighting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196 {
3197 cost += noinvcurs;
3198 attr = 0;
3199 }
3200 }
3201
3202 /*
3203 * If the cursor is above where we want to be, we can use CR LF.
3204 */
3205 else if (row > screen_cur_row)
3206 {
3207 plan = PLAN_NL;
3208 wouldbe_col = 0;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003209 cost = (row - screen_cur_row) * 2; // CR LF
3210 if (noinvcurs) // will stop highlighting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211 {
3212 cost += noinvcurs;
3213 attr = 0;
3214 }
3215 }
3216
3217 /*
3218 * If the cursor is in the same row, smaller col, just use write.
3219 */
3220 else
3221 {
3222 plan = PLAN_WRITE;
3223 wouldbe_col = screen_cur_col;
3224 cost = 0;
3225 }
3226
3227 /*
3228 * Check if any characters that need to be written have the
3229 * correct attributes. Also avoid UTF-8 characters.
3230 */
3231 i = col - wouldbe_col;
3232 if (i > 0)
3233 cost += i;
3234 if (cost < goto_cost && i > 0)
3235 {
3236 /*
3237 * Check if the attributes are correct without additionally
3238 * stopping highlighting.
3239 */
3240 p = ScreenAttrs + LineOffset[row] + wouldbe_col;
3241 while (i && *p++ == attr)
3242 --i;
3243 if (i != 0)
3244 {
3245 /*
3246 * Try if it works when highlighting is stopped here.
3247 */
3248 if (*--p == 0)
3249 {
3250 cost += noinvcurs;
3251 while (i && *p++ == 0)
3252 --i;
3253 }
3254 if (i != 0)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003255 cost = 999; // different attributes, don't do it
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257 if (enc_utf8)
3258 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003259 // Don't use an UTF-8 char for positioning, it's slow.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260 for (i = wouldbe_col; i < col; ++i)
3261 if (ScreenLinesUC[LineOffset[row] + i] != 0)
3262 {
3263 cost = 999;
3264 break;
3265 }
3266 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 }
3268
3269 /*
3270 * We can do it without term_windgoto()!
3271 */
3272 if (cost < goto_cost)
3273 {
3274 if (plan == PLAN_LE)
3275 {
3276 if (noinvcurs)
3277 screen_stop_highlight();
3278 while (screen_cur_col > col)
3279 {
3280 out_str(bs);
3281 --screen_cur_col;
3282 }
3283 }
3284 else if (plan == PLAN_CR)
3285 {
3286 if (noinvcurs)
3287 screen_stop_highlight();
3288 out_char('\r');
3289 screen_cur_col = 0;
3290 }
3291 else if (plan == PLAN_NL)
3292 {
3293 if (noinvcurs)
3294 screen_stop_highlight();
3295 while (screen_cur_row < row)
3296 {
3297 out_char('\n');
3298 ++screen_cur_row;
3299 }
3300 screen_cur_col = 0;
3301 }
3302
3303 i = col - screen_cur_col;
3304 if (i > 0)
3305 {
3306 /*
3307 * Use cursor-right if it's one character only. Avoids
3308 * removing a line of pixels from the last bold char, when
3309 * using the bold trick in the GUI.
3310 */
3311 if (T_ND[0] != NUL && T_ND[1] == NUL)
3312 {
3313 while (i-- > 0)
3314 out_char(*T_ND);
3315 }
3316 else
3317 {
3318 int off;
3319
3320 off = LineOffset[row] + screen_cur_col;
3321 while (i-- > 0)
3322 {
3323 if (ScreenAttrs[off] != screen_attr)
3324 screen_stop_highlight();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 out_flush_check();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 out_char(ScreenLines[off]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327 if (enc_dbcs == DBCS_JPNU
3328 && ScreenLines[off] == 0x8e)
3329 out_char(ScreenLines2[off]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003330 ++off;
3331 }
3332 }
3333 }
3334 }
3335 }
3336 else
3337 cost = 999;
3338
3339 if (cost >= goto_cost)
3340 {
3341 if (noinvcurs)
3342 screen_stop_highlight();
Bram Moolenaar597a4222014-06-25 14:39:50 +02003343 if (row == screen_cur_row && (col > screen_cur_col)
3344 && *T_CRI != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 term_cursor_right(col - screen_cur_col);
3346 else
3347 term_windgoto(row, col);
3348 }
3349 screen_cur_row = row;
3350 screen_cur_col = col;
3351 }
3352}
3353
3354/*
3355 * Set cursor to its position in the current window.
3356 */
3357 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003358setcursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003359{
Bram Moolenaar987723e2018-03-06 11:43:04 +01003360 setcursor_mayforce(FALSE);
3361}
3362
3363/*
3364 * Set cursor to its position in the current window.
3365 * When "force" is TRUE also when not redrawing.
3366 */
3367 void
3368setcursor_mayforce(int force)
3369{
3370 if (force || redrawing())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 {
3372 validate_cursor();
3373 windgoto(W_WINROW(curwin) + curwin->w_wrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02003374 curwin->w_wincol + (
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375#ifdef FEAT_RIGHTLEFT
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003376 // With 'rightleft' set and the cursor on a double-wide
3377 // character, position it on the leftmost column.
Bram Moolenaara12a1612019-01-24 16:39:02 +01003378 curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol
3379 - ((has_mbyte
Bram Moolenaar561f9db2008-02-20 13:16:29 +00003380 && (*mb_ptr2cells)(ml_get_cursor()) == 2
Bram Moolenaara12a1612019-01-24 16:39:02 +01003381 && vim_isprintc(gchar_cursor())) ? 2 : 1)) :
Bram Moolenaar071d4272004-06-13 20:20:40 +00003382#endif
3383 curwin->w_wcol));
3384 }
3385}
3386
3387
3388/*
Bram Moolenaar86033562017-07-12 20:24:41 +02003389 * Insert 'line_count' lines at 'row' in window 'wp'.
3390 * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
3391 * If 'mayclear' is TRUE the screen will be cleared if it is faster than
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 * scrolling.
3393 * Returns FAIL if the lines are not inserted, OK for success.
3394 */
3395 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003396win_ins_lines(
3397 win_T *wp,
3398 int row,
3399 int line_count,
3400 int invalid,
3401 int mayclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402{
3403 int did_delete;
3404 int nextrow;
3405 int lastrow;
3406 int retval;
3407
3408 if (invalid)
3409 wp->w_lines_valid = 0;
3410
Bram Moolenaarc856ceb2022-06-21 18:10:39 +01003411 // with only a few lines it's not worth the effort
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412 if (wp->w_height < 5)
3413 return FAIL;
3414
Bram Moolenaarc856ceb2022-06-21 18:10:39 +01003415 // with the popup menu visible this might not work correctly
3416 if (pum_visible())
3417 return FAIL;
3418
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419 if (line_count > wp->w_height - row)
3420 line_count = wp->w_height - row;
3421
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003422 retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003423 if (retval != MAYBE)
3424 return retval;
3425
3426 /*
3427 * If there is a next window or a status line, we first try to delete the
3428 * lines at the bottom to avoid messing what is after the window.
Bram Moolenaarc363fe12019-08-04 18:13:46 +02003429 * If this fails and there are following windows, don't do anything to
3430 * avoid messing up those windows, better just redraw.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431 */
3432 did_delete = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433 if (wp->w_next != NULL || wp->w_status_height)
3434 {
3435 if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003436 line_count, (int)Rows, FALSE, 0, NULL) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437 did_delete = TRUE;
3438 else if (wp->w_next)
3439 return FAIL;
3440 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441 /*
3442 * if no lines deleted, blank the lines that will end up below the window
3443 */
3444 if (!did_delete)
3445 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447 redraw_cmdline = TRUE;
Bram Moolenaare0de17d2017-09-24 16:24:34 +02003448 nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449 lastrow = nextrow + line_count;
3450 if (lastrow > Rows)
3451 lastrow = Rows;
3452 screen_fill(nextrow - line_count, lastrow - line_count,
Bram Moolenaar53f81742017-09-22 14:35:51 +02003453 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454 ' ', ' ', 0);
3455 }
3456
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003457 if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458 == FAIL)
3459 {
Bram Moolenaarc363fe12019-08-04 18:13:46 +02003460 // deletion will have messed up other windows
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 if (did_delete)
3462 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 win_rest_invalid(W_NEXT(wp));
3465 }
3466 return FAIL;
3467 }
3468
3469 return OK;
3470}
3471
3472/*
Bram Moolenaar86033562017-07-12 20:24:41 +02003473 * Delete "line_count" window lines at "row" in window "wp".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 * If "invalid" is TRUE curwin->w_lines[] is invalidated.
3475 * If "mayclear" is TRUE the screen will be cleared if it is faster than
3476 * scrolling
3477 * Return OK for success, FAIL if the lines are not deleted.
3478 */
3479 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003480win_del_lines(
3481 win_T *wp,
3482 int row,
3483 int line_count,
3484 int invalid,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003485 int mayclear,
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003486 int clear_attr) // for clearing lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487{
3488 int retval;
3489
3490 if (invalid)
3491 wp->w_lines_valid = 0;
3492
3493 if (line_count > wp->w_height - row)
3494 line_count = wp->w_height - row;
3495
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003496 retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497 if (retval != MAYBE)
3498 return retval;
3499
3500 if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003501 (int)Rows, FALSE, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 return FAIL;
3503
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504 /*
3505 * If there are windows or status lines below, try to put them at the
3506 * correct place. If we can't do that, they have to be redrawn.
3507 */
3508 if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
3509 {
3510 if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003511 line_count, (int)Rows, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512 {
3513 wp->w_redr_status = TRUE;
3514 win_rest_invalid(wp->w_next);
3515 }
3516 }
3517 /*
3518 * If this is the last window and there is no status line, redraw the
3519 * command line later.
3520 */
3521 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522 redraw_cmdline = TRUE;
3523 return OK;
3524}
3525
3526/*
3527 * Common code for win_ins_lines() and win_del_lines().
3528 * Returns OK or FAIL when the work has been done.
3529 * Returns MAYBE when not finished yet.
3530 */
3531 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003532win_do_lines(
3533 win_T *wp,
3534 int row,
3535 int line_count,
3536 int mayclear,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003537 int del,
3538 int clear_attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539{
3540 int retval;
3541
3542 if (!redrawing() || line_count <= 0)
3543 return FAIL;
3544
Bram Moolenaar33796b32019-06-08 16:01:13 +02003545 // When inserting lines would result in loss of command output, just redraw
3546 // the lines.
Bram Moolenaar29ae3772017-04-30 19:39:39 +02003547 if (no_win_do_lines_ins && !del)
3548 return FAIL;
3549
Bram Moolenaar33796b32019-06-08 16:01:13 +02003550 // only a few lines left: redraw is faster
Bram Moolenaar4033c552017-09-16 20:54:51 +02003551 if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 {
Bram Moolenaar29ae3772017-04-30 19:39:39 +02003553 if (!no_win_do_lines_ins)
Bram Moolenaar33796b32019-06-08 16:01:13 +02003554 screenclear(); // will set wp->w_lines_valid to 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 return FAIL;
3556 }
3557
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003558#ifdef FEAT_PROP_POPUP
Bram Moolenaar4c063a02019-06-10 21:24:12 +02003559 // this doesn't work when there are popups visible
Bram Moolenaar33796b32019-06-08 16:01:13 +02003560 if (popup_visible)
3561 return FAIL;
3562#endif
3563
3564 // Delete all remaining lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 if (row + line_count >= wp->w_height)
3566 {
3567 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
Bram Moolenaar53f81742017-09-22 14:35:51 +02003568 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 ' ', ' ', 0);
3570 return OK;
3571 }
3572
3573 /*
Bram Moolenaar29ae3772017-04-30 19:39:39 +02003574 * When scrolling, the message on the command line should be cleared,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575 * otherwise it will stay there forever.
Bram Moolenaar29ae3772017-04-30 19:39:39 +02003576 * Don't do this when avoiding to insert lines.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577 */
Bram Moolenaar29ae3772017-04-30 19:39:39 +02003578 if (!no_win_do_lines_ins)
3579 clear_cmdline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003580
3581 /*
3582 * If the terminal can set a scroll region, use that.
3583 * Always do this in a vertically split window. This will redraw from
3584 * ScreenLines[] when t_CV isn't defined. That's faster than using
3585 * win_line().
3586 * Don't use a scroll region when we are going to redraw the text, writing
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003587 * a character in the lower right corner of the scroll region may cause a
3588 * scroll-up .
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589 */
Bram Moolenaar02631462017-09-22 15:20:32 +02003590 if (scroll_region || wp->w_width != Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593 scroll_region_set(wp, row);
3594 if (del)
3595 retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003596 wp->w_height - row, FALSE, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 else
3598 retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003599 wp->w_height - row, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003600 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 scroll_region_reset();
3602 return retval;
3603 }
3604
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003605 if (wp->w_next != NULL && p_tf) // don't delete/insert on fast terminal
Bram Moolenaar071d4272004-06-13 20:20:40 +00003606 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607
3608 return MAYBE;
3609}
3610
3611/*
3612 * window 'wp' and everything after it is messed up, mark it for redraw
3613 */
3614 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003615win_rest_invalid(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 while (wp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618 {
3619 redraw_win_later(wp, NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620 wp->w_redr_status = TRUE;
3621 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622 }
3623 redraw_cmdline = TRUE;
3624}
3625
3626/*
3627 * The rest of the routines in this file perform screen manipulations. The
3628 * given operation is performed physically on the screen. The corresponding
3629 * change is also made to the internal screen image. In this way, the editor
3630 * anticipates the effect of editing changes on the appearance of the screen.
3631 * That way, when we call screenupdate a complete redraw isn't usually
3632 * necessary. Another advantage is that we can keep adding code to anticipate
3633 * screen changes, and in the meantime, everything still works.
3634 */
3635
3636/*
3637 * types for inserting or deleting lines
3638 */
3639#define USE_T_CAL 1
3640#define USE_T_CDL 2
3641#define USE_T_AL 3
3642#define USE_T_CE 4
3643#define USE_T_DL 5
3644#define USE_T_SR 6
3645#define USE_NL 7
3646#define USE_T_CD 8
3647#define USE_REDRAW 9
3648
3649/*
3650 * insert lines on the screen and update ScreenLines[]
Bram Moolenaar17fa2332022-04-01 19:44:47 +01003651 * "end" is the line after the scrolled part. Normally it is Rows.
3652 * When scrolling region used "off" is the offset from the top for the region.
3653 * "row" and "end" are relative to the start of the region.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 *
3655 * return FAIL for failure, OK for success.
3656 */
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00003657 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003658screen_ins_lines(
3659 int off,
3660 int row,
3661 int line_count,
3662 int end,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003663 int clear_attr,
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003664 win_T *wp) // NULL or window to use width from
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665{
3666 int i;
3667 int j;
3668 unsigned temp;
3669 int cursor_row;
Bram Moolenaarbfa42462018-06-16 16:20:52 +02003670 int cursor_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 int type;
3672 int result_empty;
3673 int can_ce = can_clear(T_CE);
3674
3675 /*
3676 * FAIL if
3677 * - there is no valid screen
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 * - the line count is less than one
3679 * - the line count is more than 'ttyscroll'
Bram Moolenaar17fa2332022-04-01 19:44:47 +01003680 * - "end" is more than "Rows" (safety check, should not happen)
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02003681 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar33796b32019-06-08 16:01:13 +02003682 * - there is a popup window
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683 */
Bram Moolenaar33796b32019-06-08 16:01:13 +02003684 if (!screen_valid(TRUE)
3685 || line_count <= 0 || line_count > p_ttyscroll
Bram Moolenaar17fa2332022-04-01 19:44:47 +01003686 || end > Rows
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02003687#ifdef FEAT_CLIPBOARD
3688 || (clip_star.state != SELECT_CLEARED
3689 && redrawing_for_callback > 0)
3690#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003691#ifdef FEAT_PROP_POPUP
Bram Moolenaar33796b32019-06-08 16:01:13 +02003692 || popup_visible
3693#endif
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02003694 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695 return FAIL;
3696
3697 /*
3698 * There are seven ways to insert lines:
3699 * 0. When in a vertically split window and t_CV isn't set, redraw the
3700 * characters from ScreenLines[].
3701 * 1. Use T_CD (clear to end of display) if it exists and the result of
3702 * the insert is just empty lines
3703 * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
3704 * present or line_count > 1. It looks better if we do all the inserts
3705 * at once.
3706 * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
3707 * insert is just empty lines and T_CE is not present or line_count >
3708 * 1.
3709 * 4. Use T_AL (insert line) if it exists.
3710 * 5. Use T_CE (erase line) if it exists and the result of the insert is
3711 * just empty lines.
3712 * 6. Use T_DL (delete line) if it exists and the result of the insert is
3713 * just empty lines.
3714 * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
3715 * the 'da' flag is not set or we have clear line capability.
3716 * 8. redraw the characters from ScreenLines[].
3717 *
3718 * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
3719 * the scrollbar for the window. It does have insert line, use that if it
3720 * exists.
3721 */
3722 result_empty = (row + line_count >= end);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
Bram Moolenaar8ef69972022-04-03 13:23:22 +01003724 {
3725 // Avoid that lines are first cleared here and then redrawn, which
3726 // results in many characters updated twice. This happens with CTRL-F
3727 // in a vertically split window. With line-by-line scrolling
3728 // USE_REDRAW should be faster.
3729 if (line_count > 3)
3730 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731 type = USE_REDRAW;
Bram Moolenaar8ef69972022-04-03 13:23:22 +01003732 }
Bram Moolenaar4033c552017-09-16 20:54:51 +02003733 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734 type = USE_T_CD;
3735 else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
3736 type = USE_T_CAL;
3737 else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
3738 type = USE_T_CDL;
3739 else if (*T_AL != NUL)
3740 type = USE_T_AL;
3741 else if (can_ce && result_empty)
3742 type = USE_T_CE;
3743 else if (*T_DL != NUL && result_empty)
3744 type = USE_T_DL;
3745 else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
3746 type = USE_T_SR;
3747 else
3748 return FAIL;
3749
3750 /*
3751 * For clearing the lines screen_del_lines() is used. This will also take
3752 * care of t_db if necessary.
3753 */
3754 if (type == USE_T_CD || type == USE_T_CDL ||
3755 type == USE_T_CE || type == USE_T_DL)
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003756 return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757
3758 /*
3759 * If text is retained below the screen, first clear or delete as many
3760 * lines at the bottom of the window as are about to be inserted so that
3761 * the deleted lines won't later surface during a screen_del_lines.
3762 */
3763 if (*T_DB)
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003764 screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765
3766#ifdef FEAT_CLIPBOARD
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003767 // Remove a modeless selection when inserting lines halfway the screen
3768 // or not the full width of the screen.
Bram Moolenaar4033c552017-09-16 20:54:51 +02003769 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02003770 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771 else
3772 clip_scroll_selection(-line_count);
3773#endif
3774
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003775#ifdef FEAT_GUI_HAIKU
3776 vim_lock_screen();
3777#endif
3778
Bram Moolenaar071d4272004-06-13 20:20:40 +00003779#ifdef FEAT_GUI
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003780 // Don't update the GUI cursor here, ScreenLines[] is invalid until the
3781 // scrolling is actually carried out.
Bram Moolenaar107abd22016-08-12 14:08:25 +02003782 gui_dont_update_cursor(row + off <= gui.cursor_row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783#endif
3784
Bram Moolenaarbfa42462018-06-16 16:20:52 +02003785 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
3786 cursor_col = wp->w_wincol;
3787
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003788 if (*T_CCS != NUL) // cursor relative to region
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 cursor_row = row;
3790 else
3791 cursor_row = row + off;
3792
3793 /*
3794 * Shift LineOffset[] line_count down to reflect the inserted lines.
3795 * Clear the inserted lines in ScreenLines[].
3796 */
3797 row += off;
3798 end += off;
3799 for (i = 0; i < line_count; ++i)
3800 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003801 if (wp != NULL && wp->w_width != Columns)
3802 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003803 // need to copy part of a line
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 j = end - 1 - i;
3805 while ((j -= line_count) >= row)
3806 linecopy(j + line_count, j, wp);
3807 j += line_count;
3808 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003809 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
3810 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003811 else
3812 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
3813 LineWraps[j] = FALSE;
3814 }
3815 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816 {
3817 j = end - 1 - i;
3818 temp = LineOffset[j];
3819 while ((j -= line_count) >= row)
3820 {
3821 LineOffset[j + line_count] = LineOffset[j];
3822 LineWraps[j + line_count] = LineWraps[j];
3823 }
3824 LineOffset[j + line_count] = temp;
3825 LineWraps[j + line_count] = FALSE;
3826 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003827 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003828 else
3829 lineinvalid(temp, (int)Columns);
3830 }
3831 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003833#ifdef FEAT_GUI_HAIKU
3834 vim_unlock_screen();
3835#endif
3836
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 screen_stop_highlight();
Bram Moolenaarbfa42462018-06-16 16:20:52 +02003838 windgoto(cursor_row, cursor_col);
Bram Moolenaarcfce7172017-08-17 20:31:48 +02003839 if (clear_attr != 0)
3840 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003842 // redraw the characters
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843 if (type == USE_REDRAW)
3844 redraw_block(row, end, wp);
Bram Moolenaar4033c552017-09-16 20:54:51 +02003845 else if (type == USE_T_CAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846 {
3847 term_append_lines(line_count);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003848 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 }
3850 else
3851 {
3852 for (i = 0; i < line_count; i++)
3853 {
3854 if (type == USE_T_AL)
3855 {
3856 if (i && cursor_row != 0)
Bram Moolenaarbfa42462018-06-16 16:20:52 +02003857 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858 out_str(T_AL);
3859 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003860 else // type == USE_T_SR
Bram Moolenaar071d4272004-06-13 20:20:40 +00003861 out_str(T_SR);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003862 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00003863 }
3864 }
3865
3866 /*
3867 * With scroll-reverse and 'da' flag set we need to clear the lines that
3868 * have been scrolled down into the region.
3869 */
3870 if (type == USE_T_SR && *T_DA)
3871 {
3872 for (i = 0; i < line_count; ++i)
3873 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02003874 windgoto(off + i, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875 out_str(T_CE);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003876 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877 }
3878 }
3879
3880#ifdef FEAT_GUI
3881 gui_can_update_cursor();
3882 if (gui.in_use)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003883 out_flush(); // always flush after a scroll
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884#endif
3885 return OK;
3886}
3887
3888/*
Bram Moolenaar107abd22016-08-12 14:08:25 +02003889 * Delete lines on the screen and update ScreenLines[].
3890 * "end" is the line after the scrolled part. Normally it is Rows.
3891 * When scrolling region used "off" is the offset from the top for the region.
3892 * "row" and "end" are relative to the start of the region.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 *
3894 * Return OK for success, FAIL if the lines are not deleted.
3895 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003897screen_del_lines(
3898 int off,
3899 int row,
3900 int line_count,
3901 int end,
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003902 int force, // even when line_count > p_ttyscroll
3903 int clear_attr, // used for clearing lines
Bram Moolenaar8ef69972022-04-03 13:23:22 +01003904 win_T *wp) // NULL or window to use width from
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905{
3906 int j;
3907 int i;
3908 unsigned temp;
3909 int cursor_row;
Bram Moolenaarbfa42462018-06-16 16:20:52 +02003910 int cursor_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 int cursor_end;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003912 int result_empty; // result is empty until end of region
3913 int can_delete; // deleting line codes can be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00003914 int type;
3915
3916 /*
3917 * FAIL if
3918 * - there is no valid screen
3919 * - the screen has to be redrawn completely
3920 * - the line count is less than one
3921 * - the line count is more than 'ttyscroll'
Bram Moolenaar17fa2332022-04-01 19:44:47 +01003922 * - "end" is more than "Rows" (safety check, should not happen)
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02003923 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar071d4272004-06-13 20:20:40 +00003924 */
Bram Moolenaar17fa2332022-04-01 19:44:47 +01003925 if (!screen_valid(TRUE)
3926 || line_count <= 0
3927 || (!force && line_count > p_ttyscroll)
3928 || end > Rows
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02003929#ifdef FEAT_CLIPBOARD
Bram Moolenaar17fa2332022-04-01 19:44:47 +01003930 || (clip_star.state != SELECT_CLEARED && redrawing_for_callback > 0)
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02003931#endif
3932 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 return FAIL;
3934
3935 /*
3936 * Check if the rest of the current region will become empty.
3937 */
3938 result_empty = row + line_count >= end;
3939
3940 /*
3941 * We can delete lines only when 'db' flag not set or when 'ce' option
3942 * available.
3943 */
3944 can_delete = (*T_DB == NUL || can_clear(T_CE));
3945
3946 /*
3947 * There are six ways to delete lines:
3948 * 0. When in a vertically split window and t_CV isn't set, redraw the
3949 * characters from ScreenLines[].
3950 * 1. Use T_CD if it exists and the result is empty.
3951 * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
3952 * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
3953 * none of the other ways work.
3954 * 4. Use T_CE (erase line) if the result is empty.
3955 * 5. Use T_DL (delete line) if it exists.
3956 * 6. redraw the characters from ScreenLines[].
3957 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
Bram Moolenaar8ef69972022-04-03 13:23:22 +01003959 {
3960 // Avoid that lines are first cleared here and then redrawn, which
3961 // results in many characters updated twice. This happens with CTRL-F
3962 // in a vertically split window. With line-by-line scrolling
3963 // USE_REDRAW should be faster.
3964 if (line_count > 3)
3965 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003966 type = USE_REDRAW;
Bram Moolenaar8ef69972022-04-03 13:23:22 +01003967 }
Bram Moolenaar4033c552017-09-16 20:54:51 +02003968 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003969 type = USE_T_CD;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970 else if (row == 0 && (
3971#ifndef AMIGA
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003972 // On the Amiga, somehow '\n' on the last line doesn't always scroll
3973 // up, so use delete-line command
Bram Moolenaar071d4272004-06-13 20:20:40 +00003974 line_count == 1 ||
3975#endif
3976 *T_CDL == NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977 type = USE_NL;
3978 else if (*T_CDL != NUL && line_count > 1 && can_delete)
3979 type = USE_T_CDL;
3980 else if (can_clear(T_CE) && result_empty
Bram Moolenaar4033c552017-09-16 20:54:51 +02003981 && (wp == NULL || wp->w_width == Columns))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982 type = USE_T_CE;
3983 else if (*T_DL != NUL && can_delete)
3984 type = USE_T_DL;
3985 else if (*T_CDL != NUL && can_delete)
3986 type = USE_T_CDL;
3987 else
3988 return FAIL;
3989
3990#ifdef FEAT_CLIPBOARD
Bram Moolenaar63d9e732019-12-05 21:10:38 +01003991 // Remove a modeless selection when deleting lines halfway the screen or
3992 // not the full width of the screen.
Bram Moolenaar4033c552017-09-16 20:54:51 +02003993 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02003994 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 else
3996 clip_scroll_selection(line_count);
3997#endif
3998
Bram Moolenaar92c461e2020-04-24 22:19:00 +02003999#ifdef FEAT_GUI_HAIKU
4000 vim_lock_screen();
4001#endif
4002
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003#ifdef FEAT_GUI
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004004 // Don't update the GUI cursor here, ScreenLines[] is invalid until the
4005 // scrolling is actually carried out.
Bram Moolenaar107abd22016-08-12 14:08:25 +02004006 gui_dont_update_cursor(gui.cursor_row >= row + off
4007 && gui.cursor_row < end + off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008#endif
4009
Bram Moolenaarbfa42462018-06-16 16:20:52 +02004010 if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
4011 cursor_col = wp->w_wincol;
4012
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004013 if (*T_CCS != NUL) // cursor relative to region
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 {
4015 cursor_row = row;
4016 cursor_end = end;
4017 }
4018 else
4019 {
4020 cursor_row = row + off;
4021 cursor_end = end + off;
4022 }
4023
4024 /*
4025 * Now shift LineOffset[] line_count up to reflect the deleted lines.
4026 * Clear the inserted lines in ScreenLines[].
4027 */
4028 row += off;
4029 end += off;
4030 for (i = 0; i < line_count; ++i)
4031 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004032 if (wp != NULL && wp->w_width != Columns)
4033 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004034 // need to copy part of a line
Bram Moolenaar071d4272004-06-13 20:20:40 +00004035 j = row + i;
4036 while ((j += line_count) <= end - 1)
4037 linecopy(j - line_count, j, wp);
4038 j -= line_count;
4039 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02004040 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
4041 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 else
4043 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
4044 LineWraps[j] = FALSE;
4045 }
4046 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004047 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004048 // whole width, moving the line pointers is faster
Bram Moolenaar071d4272004-06-13 20:20:40 +00004049 j = row + i;
4050 temp = LineOffset[j];
4051 while ((j += line_count) <= end - 1)
4052 {
4053 LineOffset[j - line_count] = LineOffset[j];
4054 LineWraps[j - line_count] = LineWraps[j];
4055 }
4056 LineOffset[j - line_count] = temp;
4057 LineWraps[j - line_count] = FALSE;
4058 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02004059 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004060 else
4061 lineinvalid(temp, (int)Columns);
4062 }
4063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004064
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004065#ifdef FEAT_GUI_HAIKU
4066 vim_unlock_screen();
4067#endif
4068
Bram Moolenaarcfce7172017-08-17 20:31:48 +02004069 if (screen_attr != clear_attr)
4070 screen_stop_highlight();
4071 if (clear_attr != 0)
4072 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004073
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004074 // redraw the characters
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075 if (type == USE_REDRAW)
4076 redraw_block(row, end, wp);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004077 else if (type == USE_T_CD) // delete the lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00004078 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02004079 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080 out_str(T_CD);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004081 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004082 }
4083 else if (type == USE_T_CDL)
4084 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02004085 windgoto(cursor_row, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086 term_delete_lines(line_count);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004087 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004088 }
4089 /*
4090 * Deleting lines at top of the screen or scroll region: Just scroll
4091 * the whole screen (scroll region) up by outputting newlines on the
4092 * last line.
4093 */
4094 else if (type == USE_NL)
4095 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02004096 windgoto(cursor_end - 1, cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 for (i = line_count; --i >= 0; )
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004098 out_char('\n'); // cursor will remain on same line
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 }
4100 else
4101 {
4102 for (i = line_count; --i >= 0; )
4103 {
4104 if (type == USE_T_DL)
4105 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02004106 windgoto(cursor_row, cursor_col);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004107 out_str(T_DL); // delete a line
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004109 else // type == USE_T_CE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02004111 windgoto(cursor_row + i, cursor_col);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004112 out_str(T_CE); // erase a line
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004114 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 }
4116 }
4117
4118 /*
4119 * If the 'db' flag is set, we need to clear the lines that have been
4120 * scrolled up at the bottom of the region.
4121 */
4122 if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
4123 {
4124 for (i = line_count; i > 0; --i)
4125 {
Bram Moolenaarbfa42462018-06-16 16:20:52 +02004126 windgoto(cursor_end - i, cursor_col);
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004127 out_str(T_CE); // erase a line
4128 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004129 }
4130 }
4131
4132#ifdef FEAT_GUI
4133 gui_can_update_cursor();
4134 if (gui.in_use)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004135 out_flush(); // always flush after a scroll
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136#endif
4137
4138 return OK;
4139}
4140
4141/*
Bram Moolenaarcb574f42019-01-25 22:29:57 +01004142 * Return TRUE when postponing displaying the mode message: when not redrawing
4143 * or inside a mapping.
4144 */
4145 int
4146skip_showmode()
4147{
4148 // Call char_avail() only when we are going to show something, because it
Bram Moolenaar944cc9c2022-06-27 22:17:37 +01004149 // takes a bit of time. redrawing() may also call char_avail().
Bram Moolenaarcb574f42019-01-25 22:29:57 +01004150 if (global_busy
4151 || msg_silent != 0
4152 || !redrawing()
4153 || (char_avail() && !KeyTyped))
4154 {
Bram Moolenaar4c25bd72019-04-20 23:38:07 +02004155 redraw_mode = TRUE; // show mode later
Bram Moolenaarcb574f42019-01-25 22:29:57 +01004156 return TRUE;
4157 }
4158 return FALSE;
4159}
4160
4161/*
Bram Moolenaar81226e02018-02-20 21:44:45 +01004162 * Show the current mode and ruler.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 *
4164 * If clear_cmdline is TRUE, clear the rest of the cmdline.
4165 * If clear_cmdline is FALSE there may be a message there that needs to be
4166 * cleared only if a mode is shown.
Bram Moolenaar4c25bd72019-04-20 23:38:07 +02004167 * If redraw_mode is TRUE show or clear the mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 * Return the length of the message (0 if no message).
4169 */
4170 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004171showmode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172{
4173 int need_clear;
4174 int length = 0;
4175 int do_mode;
4176 int attr;
4177 int nwr_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178 int sub_attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179
Bram Moolenaar7df351e2006-01-23 22:30:28 +00004180 do_mode = ((p_smd && msg_silent == 0)
Bram Moolenaar24959102022-05-07 20:01:16 +01004181 && ((State & MODE_INSERT)
Bram Moolenaar942b4542018-06-17 16:23:34 +02004182 || restart_edit != NUL
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01004183 || VIsual_active));
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02004184 if (do_mode || reg_recording != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185 {
Bram Moolenaarcb574f42019-01-25 22:29:57 +01004186 if (skip_showmode())
4187 return 0; // show mode later
Bram Moolenaar071d4272004-06-13 20:20:40 +00004188
4189 nwr_save = need_wait_return;
4190
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004191 // wait a bit before overwriting an important message
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 check_for_delay(FALSE);
4193
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004194 // if the cmdline is more than one line high, erase top lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195 need_clear = clear_cmdline;
4196 if (clear_cmdline && cmdline_row < Rows - 1)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004197 msg_clr_cmdline(); // will reset clear_cmdline
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004199 // Position on the last line in the window, column 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 msg_pos_mode();
4201 cursor_off();
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004202 attr = HL_ATTR(HLF_CM); // Highlight mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 if (do_mode)
4204 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004205 msg_puts_attr("--", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206#if defined(FEAT_XIM)
Bram Moolenaarc236c162008-07-13 17:41:49 +00004207 if (
Bram Moolenaar09092152010-08-08 16:38:42 +02004208# ifdef FEAT_GUI_GTK
Bram Moolenaarc236c162008-07-13 17:41:49 +00004209 preedit_get_status()
Bram Moolenaar09092152010-08-08 16:38:42 +02004210# else
Bram Moolenaarc236c162008-07-13 17:41:49 +00004211 im_get_status()
Bram Moolenaarc236c162008-07-13 17:41:49 +00004212# endif
Bram Moolenaar09092152010-08-08 16:38:42 +02004213 )
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004214# ifdef FEAT_GUI_GTK // most of the time, it's not XIM being used
Bram Moolenaar32526b32019-01-19 17:43:09 +01004215 msg_puts_attr(" IM", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004216# else
Bram Moolenaar32526b32019-01-19 17:43:09 +01004217 msg_puts_attr(" XIM", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004218# endif
4219#endif
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004220 // CTRL-X in Insert mode
Bram Moolenaarea389e92014-05-28 21:40:52 +02004221 if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004223 // These messages can get long, avoid a wrap in a narrow
4224 // window. Prefer showing edit_submode_extra.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 length = (Rows - msg_row) * Columns - 3;
4226 if (edit_submode_extra != NULL)
4227 length -= vim_strsize(edit_submode_extra);
4228 if (length > 0)
4229 {
4230 if (edit_submode_pre != NULL)
4231 length -= vim_strsize(edit_submode_pre);
4232 if (length - vim_strsize(edit_submode) > 0)
4233 {
4234 if (edit_submode_pre != NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004235 msg_puts_attr((char *)edit_submode_pre, attr);
4236 msg_puts_attr((char *)edit_submode, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 }
4238 if (edit_submode_extra != NULL)
4239 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004240 msg_puts_attr(" ", attr); // add a space in between
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 if ((int)edit_submode_highl < (int)HLF_COUNT)
Bram Moolenaar8820b482017-03-16 17:23:31 +01004242 sub_attr = HL_ATTR(edit_submode_highl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243 else
4244 sub_attr = attr;
Bram Moolenaar32526b32019-01-19 17:43:09 +01004245 msg_puts_attr((char *)edit_submode_extra, sub_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246 }
4247 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248 }
4249 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004251 if (State & VREPLACE_FLAG)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004252 msg_puts_attr(_(" VREPLACE"), attr);
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +02004253 else if (State & REPLACE_FLAG)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004254 msg_puts_attr(_(" REPLACE"), attr);
Bram Moolenaar24959102022-05-07 20:01:16 +01004255 else if (State & MODE_INSERT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256 {
4257#ifdef FEAT_RIGHTLEFT
4258 if (p_ri)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004259 msg_puts_attr(_(" REVERSE"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260#endif
Bram Moolenaar32526b32019-01-19 17:43:09 +01004261 msg_puts_attr(_(" INSERT"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 }
Bram Moolenaar957cf672020-11-12 14:21:06 +01004263 else if (restart_edit == 'I' || restart_edit == 'i' ||
4264 restart_edit == 'a' || restart_edit == 'A')
Bram Moolenaar32526b32019-01-19 17:43:09 +01004265 msg_puts_attr(_(" (insert)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266 else if (restart_edit == 'R')
Bram Moolenaar32526b32019-01-19 17:43:09 +01004267 msg_puts_attr(_(" (replace)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268 else if (restart_edit == 'V')
Bram Moolenaar32526b32019-01-19 17:43:09 +01004269 msg_puts_attr(_(" (vreplace)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270#ifdef FEAT_RIGHTLEFT
4271 if (p_hkmap)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004272 msg_puts_attr(_(" Hebrew"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273#endif
4274#ifdef FEAT_KEYMAP
Bram Moolenaar24959102022-05-07 20:01:16 +01004275 if (State & MODE_LANGMAP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004276 {
4277# ifdef FEAT_ARABIC
4278 if (curwin->w_p_arab)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004279 msg_puts_attr(_(" Arabic"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280 else
4281# endif
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02004282 if (get_keymap_str(curwin, (char_u *)" (%s)",
4283 NameBuff, MAXPATHL))
Bram Moolenaar32526b32019-01-19 17:43:09 +01004284 msg_puts_attr((char *)NameBuff, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 }
4286#endif
Bram Moolenaar24959102022-05-07 20:01:16 +01004287 if ((State & MODE_INSERT) && p_paste)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004288 msg_puts_attr(_(" (paste)"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290 if (VIsual_active)
4291 {
4292 char *p;
4293
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004294 // Don't concatenate separate words to avoid translation
4295 // problems.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 switch ((VIsual_select ? 4 : 0)
4297 + (VIsual_mode == Ctrl_V) * 2
4298 + (VIsual_mode == 'V'))
4299 {
4300 case 0: p = N_(" VISUAL"); break;
4301 case 1: p = N_(" VISUAL LINE"); break;
4302 case 2: p = N_(" VISUAL BLOCK"); break;
4303 case 4: p = N_(" SELECT"); break;
4304 case 5: p = N_(" SELECT LINE"); break;
4305 default: p = N_(" SELECT BLOCK"); break;
4306 }
Bram Moolenaar32526b32019-01-19 17:43:09 +01004307 msg_puts_attr(_(p), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308 }
Bram Moolenaar32526b32019-01-19 17:43:09 +01004309 msg_puts_attr(" --", attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004311
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312 need_clear = TRUE;
4313 }
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02004314 if (reg_recording != 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02004315 && edit_submode == NULL) // otherwise it gets too long
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316 {
Bram Moolenaara0ed84a2015-11-19 17:56:13 +01004317 recording_mode(attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004318 need_clear = TRUE;
4319 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004320
4321 mode_displayed = TRUE;
Bram Moolenaar4c25bd72019-04-20 23:38:07 +02004322 if (need_clear || clear_cmdline || redraw_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 msg_clr_eos();
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004324 msg_didout = FALSE; // overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325 length = msg_col;
4326 msg_col = 0;
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004327 need_wait_return = nwr_save; // never ask for hit-return for this
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 }
4329 else if (clear_cmdline && msg_silent == 0)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004330 // Clear the whole command line. Will reset "clear_cmdline".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331 msg_clr_cmdline();
Bram Moolenaar4c25bd72019-04-20 23:38:07 +02004332 else if (redraw_mode)
4333 {
4334 msg_pos_mode();
4335 msg_clr_eos();
4336 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004337
4338#ifdef FEAT_CMDL_INFO
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004339 // In Visual mode the size of the selected area must be redrawn.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340 if (VIsual_active)
4341 clear_showcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004343 // If the last window has no status line, the ruler is after the mode
4344 // message and must be redrawn
Bram Moolenaar4033c552017-09-16 20:54:51 +02004345 if (redrawing() && lastwin->w_status_height == 0)
Bram Moolenaar491ac282018-06-17 14:47:55 +02004346 win_redr_ruler(lastwin, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347#endif
4348 redraw_cmdline = FALSE;
Bram Moolenaar4c25bd72019-04-20 23:38:07 +02004349 redraw_mode = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350 clear_cmdline = FALSE;
4351
4352 return length;
4353}
4354
4355/*
4356 * Position for a mode message.
4357 */
4358 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01004359msg_pos_mode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360{
4361 msg_col = 0;
4362 msg_row = Rows - 1;
4363}
4364
4365/*
4366 * Delete mode message. Used when ESC is typed which is expected to end
4367 * Insert mode (but Insert mode didn't end yet!).
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004368 * Caller should check "mode_displayed".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 */
4370 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004371unshowmode(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372{
4373 /*
Bram Moolenaare4ebd292010-01-19 17:40:46 +01004374 * Don't delete it right now, when not redrawing or inside a mapping.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375 */
4376 if (!redrawing() || (!force && char_avail() && !KeyTyped))
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004377 redraw_cmdline = TRUE; // delete mode later
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378 else
Bram Moolenaarfd773e92016-04-02 19:39:16 +02004379 clearmode();
4380}
4381
4382/*
4383 * Clear the mode message.
4384 */
4385 void
Bram Moolenaarcf089462016-06-12 21:18:43 +02004386clearmode(void)
Bram Moolenaarfd773e92016-04-02 19:39:16 +02004387{
Bram Moolenaar2abad542018-05-19 14:43:45 +02004388 int save_msg_row = msg_row;
4389 int save_msg_col = msg_col;
4390
Bram Moolenaarfd773e92016-04-02 19:39:16 +02004391 msg_pos_mode();
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02004392 if (reg_recording != 0)
Bram Moolenaar8820b482017-03-16 17:23:31 +01004393 recording_mode(HL_ATTR(HLF_CM));
Bram Moolenaarfd773e92016-04-02 19:39:16 +02004394 msg_clr_eos();
Bram Moolenaar2abad542018-05-19 14:43:45 +02004395
4396 msg_col = save_msg_col;
4397 msg_row = save_msg_row;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398}
4399
Bram Moolenaara0ed84a2015-11-19 17:56:13 +01004400 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01004401recording_mode(int attr)
Bram Moolenaara0ed84a2015-11-19 17:56:13 +01004402{
Bram Moolenaar32526b32019-01-19 17:43:09 +01004403 msg_puts_attr(_("recording"), attr);
Bram Moolenaara0ed84a2015-11-19 17:56:13 +01004404 if (!shortmess(SHM_RECORDING))
4405 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004406 char s[4];
4407
4408 sprintf(s, " @%c", reg_recording);
4409 msg_puts_attr(s, attr);
Bram Moolenaara0ed84a2015-11-19 17:56:13 +01004410 }
4411}
4412
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004413/*
4414 * Draw the tab pages line at the top of the Vim window.
4415 */
Bram Moolenaare12bab32019-01-08 22:02:56 +01004416 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004417draw_tabline(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004418{
4419 int tabcount = 0;
4420 tabpage_T *tp;
4421 int tabwidth;
4422 int col = 0;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00004423 int scol = 0;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004424 int attr;
4425 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004426 win_T *cwp;
4427 int wincount;
4428 int modified;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004429 int c;
4430 int len;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004431 int attr_sel = HL_ATTR(HLF_TPS);
4432 int attr_nosel = HL_ATTR(HLF_TP);
4433 int attr_fill = HL_ATTR(HLF_TPF);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00004434 char_u *p;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004435 int room;
4436 int use_sep_chars = (t_colors < 8
4437#ifdef FEAT_GUI
4438 && !gui.in_use
4439#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +02004440#ifdef FEAT_TERMGUICOLORS
4441 && !p_tgc
Bram Moolenaar8a633e32016-04-21 21:10:14 +02004442#endif
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004443 );
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004444
Bram Moolenaarc695cec2017-01-08 20:00:04 +01004445 if (ScreenLines == NULL)
4446 return;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00004447 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004448
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004449#ifdef FEAT_GUI_TABLINE
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004450 // Take care of a GUI tabline.
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004451 if (gui_use_tabline())
4452 {
4453 gui_update_tabline();
4454 return;
4455 }
4456#endif
4457
4458 if (tabline_height() < 1)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004459 return;
4460
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004461#if defined(FEAT_STL_OPT)
Bram Moolenaarca57ab52019-04-13 14:53:16 +02004462 clear_TabPageIdxs();
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004463
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004464 // Use the 'tabline' option if it's set.
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004465 if (*p_tal != NUL)
4466 {
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +02004467 int saved_did_emsg = did_emsg;
Bram Moolenaar238a5642006-02-21 22:12:05 +00004468
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004469 // Check for an error. If there is one we would loop in redrawing the
4470 // screen. Avoid that by making 'tabline' empty.
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +02004471 did_emsg = FALSE;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004472 win_redr_custom(NULL, FALSE);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +02004473 if (did_emsg)
Bram Moolenaar238a5642006-02-21 22:12:05 +00004474 set_string_option_direct((char_u *)"tabline", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00004475 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +02004476 did_emsg |= saved_did_emsg;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004477 }
Bram Moolenaar238a5642006-02-21 22:12:05 +00004478 else
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004479#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004480 {
Bram Moolenaar29323592016-07-24 22:04:11 +02004481 FOR_ALL_TABPAGES(tp)
Bram Moolenaar238a5642006-02-21 22:12:05 +00004482 ++tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004483
Bram Moolenaar238a5642006-02-21 22:12:05 +00004484 tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
4485 if (tabwidth < 6)
4486 tabwidth = 6;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004487
Bram Moolenaar238a5642006-02-21 22:12:05 +00004488 attr = attr_nosel;
4489 tabcount = 0;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004490 for (tp = first_tabpage; tp != NULL && col < Columns - 4;
4491 tp = tp->tp_next)
Bram Moolenaarf740b292006-02-16 22:11:02 +00004492 {
Bram Moolenaar238a5642006-02-21 22:12:05 +00004493 scol = col;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004494
Bram Moolenaar238a5642006-02-21 22:12:05 +00004495 if (tp->tp_topframe == topframe)
4496 attr = attr_sel;
4497 if (use_sep_chars && col > 0)
4498 screen_putchar('|', 0, col++, attr);
4499
4500 if (tp->tp_topframe != topframe)
4501 attr = attr_nosel;
4502
4503 screen_putchar(' ', 0, col++, attr);
4504
4505 if (tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00004506 {
Bram Moolenaar238a5642006-02-21 22:12:05 +00004507 cwp = curwin;
4508 wp = firstwin;
4509 }
4510 else
4511 {
4512 cwp = tp->tp_curwin;
4513 wp = tp->tp_firstwin;
4514 }
4515
4516 modified = FALSE;
4517 for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
4518 if (bufIsChanged(wp->w_buffer))
4519 modified = TRUE;
4520 if (modified || wincount > 1)
4521 {
4522 if (wincount > 1)
4523 {
4524 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004525 len = (int)STRLEN(NameBuff);
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004526 if (col + len >= Columns - 3)
4527 break;
Bram Moolenaar238a5642006-02-21 22:12:05 +00004528 screen_puts_len(NameBuff, len, 0, col,
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004529#if defined(FEAT_SYN_HL)
Bram Moolenaar8820b482017-03-16 17:23:31 +01004530 hl_combine_attr(attr, HL_ATTR(HLF_T))
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004531#else
Bram Moolenaare0f14822014-08-06 13:20:56 +02004532 attr
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00004533#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +00004534 );
4535 col += len;
4536 }
4537 if (modified)
4538 screen_puts_len((char_u *)"+", 1, 0, col++, attr);
4539 screen_putchar(' ', 0, col++, attr);
4540 }
4541
4542 room = scol - col + tabwidth - 1;
4543 if (room > 0)
4544 {
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004545 // Get buffer name in NameBuff[]
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004546 get_trans_bufname(cwp->w_buffer);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004547 shorten_dir(NameBuff);
Bram Moolenaar238a5642006-02-21 22:12:05 +00004548 len = vim_strsize(NameBuff);
4549 p = NameBuff;
Bram Moolenaar238a5642006-02-21 22:12:05 +00004550 if (has_mbyte)
4551 while (len > room)
4552 {
4553 len -= ptr2cells(p);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01004554 MB_PTR_ADV(p);
Bram Moolenaar238a5642006-02-21 22:12:05 +00004555 }
Bram Moolenaara12a1612019-01-24 16:39:02 +01004556 else if (len > room)
Bram Moolenaar238a5642006-02-21 22:12:05 +00004557 {
4558 p += len - room;
4559 len = room;
4560 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004561 if (len > Columns - col - 1)
4562 len = Columns - col - 1;
Bram Moolenaar238a5642006-02-21 22:12:05 +00004563
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004564 screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
Bram Moolenaarf740b292006-02-16 22:11:02 +00004565 col += len;
4566 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00004567 screen_putchar(' ', 0, col++, attr);
Bram Moolenaar238a5642006-02-21 22:12:05 +00004568
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004569 // Store the tab page number in TabPageIdxs[], so that
4570 // jump_to_mouse() knows where each one is.
Bram Moolenaar238a5642006-02-21 22:12:05 +00004571 ++tabcount;
4572 while (scol < col)
4573 TabPageIdxs[scol++] = tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004574 }
4575
Bram Moolenaar238a5642006-02-21 22:12:05 +00004576 if (use_sep_chars)
4577 c = '_';
4578 else
4579 c = ' ';
4580 screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004581
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004582 // Put an "X" for closing the current tab if there are several.
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004583 if (first_tabpage->tp_next != NULL)
4584 {
4585 screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
4586 TabPageIdxs[Columns - 1] = -999;
4587 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004588 }
Bram Moolenaarb21e5842006-04-16 18:30:08 +00004589
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004590 // Reset the flag here again, in case evaluating 'tabline' causes it to be
4591 // set.
Bram Moolenaarb21e5842006-04-16 18:30:08 +00004592 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004593}
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004594
4595/*
4596 * Get buffer name for "buf" into NameBuff[].
4597 * Takes care of special buffer names and translates special characters.
4598 */
4599 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004600get_trans_bufname(buf_T *buf)
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004601{
4602 if (buf_spname(buf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02004603 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004604 else
4605 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
4606 trans_characters(NameBuff, MAXPATHL);
4607}
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004608
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609/*
4610 * Get the character to use in a status line. Get its attributes in "*attr".
4611 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02004612 int
Bram Moolenaar3633cf52017-07-31 22:29:35 +02004613fillchar_status(int *attr, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614{
4615 int fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +02004616
4617#ifdef FEAT_TERMINAL
4618 if (bt_terminal(wp->w_buffer))
4619 {
Bram Moolenaar3633cf52017-07-31 22:29:35 +02004620 if (wp == curwin)
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02004621 {
4622 *attr = HL_ATTR(HLF_ST);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004623 fill = wp->w_fill_chars.stl;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02004624 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +02004625 else
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02004626 {
4627 *attr = HL_ATTR(HLF_STNC);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004628 fill = wp->w_fill_chars.stlnc;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02004629 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +02004630 }
4631 else
4632#endif
4633 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004635 *attr = HL_ATTR(HLF_S);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004636 fill = wp->w_fill_chars.stl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 }
4638 else
4639 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004640 *attr = HL_ATTR(HLF_SNC);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004641 fill = wp->w_fill_chars.stlnc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642 }
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004643 // Use fill when there is highlighting, and highlighting of current
4644 // window differs, or the fillchars differ, or this is not the
4645 // current window
Bram Moolenaar8820b482017-03-16 17:23:31 +01004646 if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
Bram Moolenaar3633cf52017-07-31 22:29:35 +02004647 || wp != curwin || ONE_WINDOW)
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004648 || (wp->w_fill_chars.stl != wp->w_fill_chars.stlnc)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 return fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +02004650 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651 return '^';
4652 return '=';
4653}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655/*
4656 * Get the character to use in a separator between vertically split windows.
4657 * Get its attributes in "*attr".
4658 */
Bram Moolenaar7528d1f2019-09-19 23:06:20 +02004659 int
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004660fillchar_vsep(int *attr, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661{
Bram Moolenaar8820b482017-03-16 17:23:31 +01004662 *attr = HL_ATTR(HLF_C);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004663 if (*attr == 0 && wp->w_fill_chars.vert == ' ')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664 return '|';
4665 else
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004666 return wp->w_fill_chars.vert;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004667}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668
4669/*
4670 * Return TRUE if redrawing should currently be done.
4671 */
4672 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004673redrawing(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004674{
Bram Moolenaareb992cb2017-03-09 18:20:16 +01004675#ifdef FEAT_EVAL
4676 if (disable_redraw_for_testing)
4677 return 0;
4678 else
4679#endif
Bram Moolenaared5a9d62018-09-06 13:14:43 +02004680 return ((!RedrawingDisabled
4681#ifdef FEAT_EVAL
4682 || ignore_redraw_flag_for_testing
4683#endif
4684 ) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685}
4686
4687/*
4688 * Return TRUE if printing messages should currently be done.
4689 */
4690 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004691messaging(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692{
4693 return (!(p_lz && char_avail() && !KeyTyped));
4694}
4695
Bram Moolenaare677df82019-09-02 22:31:11 +02004696/*
4697 * Compute columns for ruler and shown command. 'sc_col' is also used to
4698 * decide what the maximum length of a message on the status line can be.
4699 * If there is a status line for the last window, 'sc_col' is independent
4700 * of 'ru_col'.
4701 */
4702
4703#define COL_RULER 17 // columns needed by standard ruler
4704
4705 void
4706comp_col(void)
4707{
4708#if defined(FEAT_CMDL_INFO)
4709 int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
4710
4711 sc_col = 0;
4712 ru_col = 0;
4713 if (p_ru)
4714 {
4715# ifdef FEAT_STL_OPT
4716 ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
4717# else
4718 ru_col = COL_RULER + 1;
4719# endif
4720 // no last status line, adjust sc_col
4721 if (!last_has_status)
4722 sc_col = ru_col;
4723 }
4724 if (p_sc)
4725 {
4726 sc_col += SHOWCMD_COLS;
4727 if (!p_ru || last_has_status) // no need for separating space
4728 ++sc_col;
4729 }
4730 sc_col = Columns - sc_col;
4731 ru_col = Columns - ru_col;
4732 if (sc_col <= 0) // screen too narrow, will become a mess
4733 sc_col = 1;
4734 if (ru_col <= 0)
4735 ru_col = 1;
4736#else
4737 sc_col = Columns;
4738 ru_col = Columns;
4739#endif
4740#ifdef FEAT_EVAL
4741 set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
4742#endif
4743}
4744
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004745#if defined(FEAT_LINEBREAK) || defined(PROTO)
4746/*
Bram Moolenaar64486672010-05-16 15:46:46 +02004747 * Return the width of the 'number' and 'relativenumber' column.
4748 * Caller may need to check if 'number' or 'relativenumber' is set.
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004749 * Otherwise it depends on 'numberwidth' and the line count.
4750 */
4751 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004752number_width(win_T *wp)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004753{
4754 int n;
4755 linenr_T lnum;
4756
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02004757 if (wp->w_p_rnu && !wp->w_p_nu)
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004758 // cursor line shows "0"
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02004759 lnum = wp->w_height;
4760 else
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004761 // cursor line shows absolute line number
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02004762 lnum = wp->w_buffer->b_ml.ml_line_count;
Bram Moolenaar64486672010-05-16 15:46:46 +02004763
Bram Moolenaar6b314672015-03-20 15:42:10 +01004764 if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004765 return wp->w_nrwidth_width;
4766 wp->w_nrwidth_line_count = lnum;
4767
4768 n = 0;
4769 do
4770 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004771 lnum /= 10;
4772 ++n;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004773 } while (lnum > 0);
4774
Bram Moolenaar63d9e732019-12-05 21:10:38 +01004775 // 'numberwidth' gives the minimal width plus one
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004776 if (n < wp->w_p_nuw - 1)
4777 n = wp->w_p_nuw - 1;
4778
Bram Moolenaare4b407f2019-07-04 11:59:28 +02004779# ifdef FEAT_SIGNS
4780 // If 'signcolumn' is set to 'number' and there is a sign to display, then
4781 // the minimal width for the number column is 2.
Bram Moolenaar4eb7dae2019-11-12 22:33:45 +01004782 if (n < 2 && get_first_valid_sign(wp) != NULL
Bram Moolenaare4b407f2019-07-04 11:59:28 +02004783 && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'))
4784 n = 2;
4785# endif
4786
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004787 wp->w_nrwidth_width = n;
Bram Moolenaar6b314672015-03-20 15:42:10 +01004788 wp->w_nuw_cached = wp->w_p_nuw;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004789 return n;
4790}
4791#endif
Bram Moolenaar9750bb12012-12-05 16:10:42 +01004792
Bram Moolenaar113e1072019-01-20 15:30:40 +01004793#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar9750bb12012-12-05 16:10:42 +01004794/*
4795 * Return the current cursor column. This is the actual position on the
4796 * screen. First column is 0.
4797 */
4798 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004799screen_screencol(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +01004800{
4801 return screen_cur_col;
4802}
4803
4804/*
4805 * Return the current cursor row. This is the actual position on the screen.
4806 * First row is 0.
4807 */
4808 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004809screen_screenrow(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +01004810{
4811 return screen_cur_row;
4812}
Bram Moolenaar113e1072019-01-20 15:30:40 +01004813#endif
Bram Moolenaare677df82019-09-02 22:31:11 +02004814
4815/*
Bram Moolenaar93ff6722021-10-16 17:51:40 +01004816 * Calls mb_ptr2char_adv(p) and returns the character.
4817 * If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
4818 */
4819 static int
4820get_encoded_char_adv(char_u **p)
4821{
4822 char_u *s = *p;
4823
4824 if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U'))
4825 {
4826 varnumber_T num = 0;
4827 int bytes;
4828 int n;
4829
4830 for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; --bytes)
4831 {
4832 *p += 2;
4833 n = hexhex2nr(*p);
4834 if (n < 0)
4835 return 0;
4836 num = num * 256 + n;
4837 }
4838 *p += 2;
4839 return num;
4840 }
4841 return mb_ptr2char_adv(p);
4842}
4843
4844/*
Bram Moolenaare677df82019-09-02 22:31:11 +02004845 * Handle setting 'listchars' or 'fillchars'.
Bram Moolenaareed9d462021-02-15 20:38:25 +01004846 * Assume monocell characters.
Bram Moolenaare677df82019-09-02 22:31:11 +02004847 * Returns error message, NULL if it's OK.
4848 */
4849 char *
Bram Moolenaareed9d462021-02-15 20:38:25 +01004850set_chars_option(win_T *wp, char_u **varp)
Bram Moolenaare677df82019-09-02 22:31:11 +02004851{
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004852 int round, i, len, len2, entries;
4853 char_u *p, *s;
4854 int c1 = 0, c2 = 0, c3 = 0;
4855 char_u *last_multispace = NULL; // Last occurrence of "multispace:"
4856 char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
4857 int multispace_len = 0; // Length of lcs-multispace string
4858 int lead_multispace_len = 0; // Length of lcs-leadmultispace string
Bram Moolenaare677df82019-09-02 22:31:11 +02004859 struct charstab
4860 {
4861 int *cp;
4862 char *name;
4863 };
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004864 static fill_chars_T fill_chars;
Bram Moolenaare677df82019-09-02 22:31:11 +02004865 static struct charstab filltab[] =
4866 {
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004867 {&fill_chars.stl, "stl"},
4868 {&fill_chars.stlnc, "stlnc"},
4869 {&fill_chars.vert, "vert"},
4870 {&fill_chars.fold, "fold"},
4871 {&fill_chars.foldopen, "foldopen"},
4872 {&fill_chars.foldclosed, "foldclose"},
4873 {&fill_chars.foldsep, "foldsep"},
4874 {&fill_chars.diff, "diff"},
4875 {&fill_chars.eob, "eob"},
Bram Moolenaare677df82019-09-02 22:31:11 +02004876 };
Bram Moolenaar333bd562021-02-16 22:22:13 +01004877 static lcs_chars_T lcs_chars;
Bram Moolenaareed9d462021-02-15 20:38:25 +01004878 struct charstab lcstab[] =
Bram Moolenaare677df82019-09-02 22:31:11 +02004879 {
Bram Moolenaar333bd562021-02-16 22:22:13 +01004880 {&lcs_chars.eol, "eol"},
4881 {&lcs_chars.ext, "extends"},
4882 {&lcs_chars.nbsp, "nbsp"},
4883 {&lcs_chars.prec, "precedes"},
4884 {&lcs_chars.space, "space"},
4885 {&lcs_chars.tab2, "tab"},
4886 {&lcs_chars.trail, "trail"},
4887 {&lcs_chars.lead, "lead"},
Bram Moolenaare677df82019-09-02 22:31:11 +02004888#ifdef FEAT_CONCEAL
Bram Moolenaar333bd562021-02-16 22:22:13 +01004889 {&lcs_chars.conceal, "conceal"},
Bram Moolenaare677df82019-09-02 22:31:11 +02004890#else
Bram Moolenaar333bd562021-02-16 22:22:13 +01004891 {NULL, "conceal"},
Bram Moolenaare677df82019-09-02 22:31:11 +02004892#endif
4893 };
4894 struct charstab *tab;
4895
Bram Moolenaareed9d462021-02-15 20:38:25 +01004896 if (varp == &p_lcs || varp == &wp->w_p_lcs)
Bram Moolenaare677df82019-09-02 22:31:11 +02004897 {
4898 tab = lcstab;
Bram Moolenaar333bd562021-02-16 22:22:13 +01004899 CLEAR_FIELD(lcs_chars);
K.Takataeeec2542021-06-02 13:28:16 +02004900 entries = ARRAY_LENGTH(lcstab);
Bram Moolenaareed9d462021-02-15 20:38:25 +01004901 if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL)
4902 varp = &p_lcs;
Bram Moolenaare677df82019-09-02 22:31:11 +02004903 }
4904 else
4905 {
4906 tab = filltab;
K.Takataeeec2542021-06-02 13:28:16 +02004907 entries = ARRAY_LENGTH(filltab);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004908 if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL)
4909 varp = &p_fcs;
Bram Moolenaare677df82019-09-02 22:31:11 +02004910 }
4911
4912 // first round: check for valid value, second round: assign values
4913 for (round = 0; round <= 1; ++round)
4914 {
4915 if (round > 0)
4916 {
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004917 // After checking that the value is valid: set defaults.
Bram Moolenaareed9d462021-02-15 20:38:25 +01004918 if (varp == &p_lcs || varp == &wp->w_p_lcs)
Bram Moolenaare677df82019-09-02 22:31:11 +02004919 {
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004920 for (i = 0; i < entries; ++i)
4921 if (tab[i].cp != NULL)
4922 *(tab[i].cp) = NUL;
Bram Moolenaar333bd562021-02-16 22:22:13 +01004923 lcs_chars.tab1 = NUL;
4924 lcs_chars.tab3 = NUL;
zeertzjqb5f08012022-06-09 13:55:28 +01004925
Mike Williamsf5785cf2021-09-13 22:17:38 +02004926 if (multispace_len > 0)
zeertzjqf14b8ba2021-09-10 16:58:30 +02004927 {
4928 lcs_chars.multispace = ALLOC_MULT(int, multispace_len + 1);
4929 lcs_chars.multispace[multispace_len] = NUL;
4930 }
4931 else
4932 lcs_chars.multispace = NULL;
Bram Moolenaaraca12fd2022-06-07 10:16:15 +01004933
4934 if (lead_multispace_len > 0)
4935 {
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004936 lcs_chars.leadmultispace =
4937 ALLOC_MULT(int, lead_multispace_len + 1);
Bram Moolenaaraca12fd2022-06-07 10:16:15 +01004938 lcs_chars.leadmultispace[lead_multispace_len] = NUL;
4939 }
4940 else
4941 lcs_chars.leadmultispace = NULL;
Bram Moolenaare677df82019-09-02 22:31:11 +02004942 }
4943 else
Bram Moolenaara98f8a22021-02-13 18:24:23 +01004944 {
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01004945 fill_chars.stl = ' ';
4946 fill_chars.stlnc = ' ';
4947 fill_chars.vert = ' ';
4948 fill_chars.fold = '-';
4949 fill_chars.foldopen = '-';
4950 fill_chars.foldclosed = '+';
4951 fill_chars.foldsep = '|';
4952 fill_chars.diff = '-';
4953 fill_chars.eob = '~';
Bram Moolenaara98f8a22021-02-13 18:24:23 +01004954 }
Bram Moolenaare677df82019-09-02 22:31:11 +02004955 }
4956 p = *varp;
4957 while (*p)
4958 {
4959 for (i = 0; i < entries; ++i)
4960 {
4961 len = (int)STRLEN(tab[i].name);
4962 if (STRNCMP(p, tab[i].name, len) == 0
4963 && p[len] == ':'
4964 && p[len + 1] != NUL)
4965 {
4966 c2 = c3 = 0;
4967 s = p + len + 1;
Bram Moolenaar93ff6722021-10-16 17:51:40 +01004968 c1 = get_encoded_char_adv(&s);
zeertzjq60618c82021-12-18 15:32:46 +00004969 if (char2cells(c1) > 1)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004970 return e_invalid_argument;
Bram Moolenaar333bd562021-02-16 22:22:13 +01004971 if (tab[i].cp == &lcs_chars.tab2)
Bram Moolenaare677df82019-09-02 22:31:11 +02004972 {
4973 if (*s == NUL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004974 return e_invalid_argument;
Bram Moolenaar93ff6722021-10-16 17:51:40 +01004975 c2 = get_encoded_char_adv(&s);
zeertzjq60618c82021-12-18 15:32:46 +00004976 if (char2cells(c2) > 1)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004977 return e_invalid_argument;
Bram Moolenaare677df82019-09-02 22:31:11 +02004978 if (!(*s == ',' || *s == NUL))
4979 {
Bram Moolenaar93ff6722021-10-16 17:51:40 +01004980 c3 = get_encoded_char_adv(&s);
zeertzjq60618c82021-12-18 15:32:46 +00004981 if (char2cells(c3) > 1)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004982 return e_invalid_argument;
Bram Moolenaare677df82019-09-02 22:31:11 +02004983 }
4984 }
4985
4986 if (*s == ',' || *s == NUL)
4987 {
Mike Williamsf5785cf2021-09-13 22:17:38 +02004988 if (round > 0)
Bram Moolenaare677df82019-09-02 22:31:11 +02004989 {
Bram Moolenaar333bd562021-02-16 22:22:13 +01004990 if (tab[i].cp == &lcs_chars.tab2)
Bram Moolenaare677df82019-09-02 22:31:11 +02004991 {
Bram Moolenaar333bd562021-02-16 22:22:13 +01004992 lcs_chars.tab1 = c1;
4993 lcs_chars.tab2 = c2;
4994 lcs_chars.tab3 = c3;
Bram Moolenaare677df82019-09-02 22:31:11 +02004995 }
4996 else if (tab[i].cp != NULL)
4997 *(tab[i].cp) = c1;
4998
4999 }
5000 p = s;
5001 break;
5002 }
5003 }
5004 }
5005
5006 if (i == entries)
zeertzjqf14b8ba2021-09-10 16:58:30 +02005007 {
Mike Williamsf5785cf2021-09-13 22:17:38 +02005008 len = (int)STRLEN("multispace");
Bram Moolenaaraca12fd2022-06-07 10:16:15 +01005009 len2 = (int)STRLEN("leadmultispace");
zeertzjqf14b8ba2021-09-10 16:58:30 +02005010 if ((varp == &p_lcs || varp == &wp->w_p_lcs)
5011 && STRNCMP(p, "multispace", len) == 0
5012 && p[len] == ':'
5013 && p[len + 1] != NUL)
5014 {
5015 s = p + len + 1;
5016 if (round == 0)
5017 {
5018 // Get length of lcs-multispace string in first round
5019 last_multispace = p;
5020 multispace_len = 0;
5021 while (*s != NUL && *s != ',')
5022 {
Bram Moolenaar93ff6722021-10-16 17:51:40 +01005023 c1 = get_encoded_char_adv(&s);
zeertzjq60618c82021-12-18 15:32:46 +00005024 if (char2cells(c1) > 1)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00005025 return e_invalid_argument;
zeertzjqf14b8ba2021-09-10 16:58:30 +02005026 ++multispace_len;
5027 }
5028 if (multispace_len == 0)
5029 // lcs-multispace cannot be an empty string
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00005030 return e_invalid_argument;
zeertzjqf14b8ba2021-09-10 16:58:30 +02005031 p = s;
5032 }
5033 else
5034 {
5035 int multispace_pos = 0;
Mike Williamsf5785cf2021-09-13 22:17:38 +02005036
zeertzjqf14b8ba2021-09-10 16:58:30 +02005037 while (*s != NUL && *s != ',')
5038 {
Bram Moolenaar93ff6722021-10-16 17:51:40 +01005039 c1 = get_encoded_char_adv(&s);
zeertzjqf14b8ba2021-09-10 16:58:30 +02005040 if (p == last_multispace)
5041 lcs_chars.multispace[multispace_pos++] = c1;
5042 }
5043 p = s;
5044 }
5045 }
Bram Moolenaaraca12fd2022-06-07 10:16:15 +01005046
5047 else if ((varp == &p_lcs || varp == &wp->w_p_lcs)
5048 && STRNCMP(p, "leadmultispace", len2) == 0
5049 && p[len2] == ':'
5050 && p[len2 + 1] != NUL)
5051 {
5052 s = p + len2 + 1;
5053 if (round == 0)
5054 {
zeertzjqb5f08012022-06-09 13:55:28 +01005055 // get length of lcs-leadmultispace string in first
5056 // round
Bram Moolenaaraca12fd2022-06-07 10:16:15 +01005057 last_lmultispace = p;
5058 lead_multispace_len = 0;
5059 while (*s != NUL && *s != ',')
5060 {
5061 c1 = get_encoded_char_adv(&s);
5062 if (char2cells(c1) > 1)
5063 return e_invalid_argument;
5064 ++lead_multispace_len;
5065 }
5066 if (lead_multispace_len == 0)
zeertzjqb5f08012022-06-09 13:55:28 +01005067 // lcs-leadmultispace cannot be an empty string
Bram Moolenaaraca12fd2022-06-07 10:16:15 +01005068 return e_invalid_argument;
5069 p = s;
5070 }
5071 else
5072 {
5073 int multispace_pos = 0;
5074
5075 while (*s != NUL && *s != ',')
5076 {
5077 c1 = get_encoded_char_adv(&s);
5078 if (p == last_lmultispace)
5079 lcs_chars.leadmultispace[multispace_pos++] = c1;
5080 }
5081 p = s;
5082 }
5083 }
zeertzjqf14b8ba2021-09-10 16:58:30 +02005084 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00005085 return e_invalid_argument;
zeertzjqf14b8ba2021-09-10 16:58:30 +02005086 }
5087
Bram Moolenaare677df82019-09-02 22:31:11 +02005088 if (*p == ',')
5089 ++p;
5090 }
5091 }
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01005092
Bram Moolenaar333bd562021-02-16 22:22:13 +01005093 if (tab == lcstab)
zeertzjqf14b8ba2021-09-10 16:58:30 +02005094 {
zeertzjqb5f08012022-06-09 13:55:28 +01005095 vim_free(wp->w_lcs_chars.multispace);
5096 vim_free(wp->w_lcs_chars.leadmultispace);
Bram Moolenaar333bd562021-02-16 22:22:13 +01005097 wp->w_lcs_chars = lcs_chars;
zeertzjqf14b8ba2021-09-10 16:58:30 +02005098 }
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01005099 else
5100 {
5101 wp->w_fill_chars = fill_chars;
5102 }
Bram Moolenaare677df82019-09-02 22:31:11 +02005103
5104 return NULL; // no error
5105}