1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar *
3071d4279SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4071d4279SBram Moolenaar *
5071d4279SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar */
9071d4279SBram Moolenaar
10071d4279SBram Moolenaar /*
117528d1f6SBram Moolenaar * screen.c: Lower level code for displaying on the screen.
12071d4279SBram Moolenaar *
13071d4279SBram Moolenaar * Output to the screen (console, terminal emulator or GUI window) is minimized
14071d4279SBram Moolenaar * by remembering what is already on the screen, and only updating the parts
15071d4279SBram Moolenaar * that changed.
16071d4279SBram Moolenaar *
17071d4279SBram Moolenaar * ScreenLines[off] Contains a copy of the whole screen, as it is currently
18071d4279SBram Moolenaar * displayed (excluding text written by external commands).
19071d4279SBram Moolenaar * ScreenAttrs[off] Contains the associated attributes.
20071d4279SBram Moolenaar * LineOffset[row] Contains the offset into ScreenLines*[] and ScreenAttrs[]
21071d4279SBram Moolenaar * for each line.
22071d4279SBram Moolenaar * LineWraps[row] Flag for each line whether it wraps to the next line.
23071d4279SBram Moolenaar *
24071d4279SBram Moolenaar * For double-byte characters, two consecutive bytes in ScreenLines[] can form
25071d4279SBram Moolenaar * one character which occupies two display cells.
26071d4279SBram Moolenaar * For UTF-8 a multi-byte character is converted to Unicode and stored in
27071d4279SBram Moolenaar * ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII
2870c49c1aSBram Moolenaar * character without composing chars ScreenLinesUC[] will be 0 and
2970c49c1aSBram Moolenaar * ScreenLinesC[][] is not used. When the character occupies two display
3070c49c1aSBram Moolenaar * cells the next byte in ScreenLines[] is 0.
31362e1a30SBram Moolenaar * ScreenLinesC[][] contain up to 'maxcombine' composing characters
3270c49c1aSBram Moolenaar * (drawn on top of the first character). There is 0 after the last one used.
33071d4279SBram Moolenaar * ScreenLines2[] is only used for euc-jp to store the second byte if the
34071d4279SBram Moolenaar * first byte is 0x8e (single-width character).
35071d4279SBram Moolenaar *
36071d4279SBram Moolenaar * The screen_*() functions write to the screen and handle updating
37071d4279SBram Moolenaar * ScreenLines[].
38071d4279SBram Moolenaar */
39071d4279SBram Moolenaar
40071d4279SBram Moolenaar #include "vim.h"
41071d4279SBram Moolenaar
42071d4279SBram Moolenaar /*
43071d4279SBram Moolenaar * The attributes that are actually active for writing to the screen.
44071d4279SBram Moolenaar */
45071d4279SBram Moolenaar static int screen_attr = 0;
46071d4279SBram Moolenaar
47baaa7e9eSBram Moolenaar static void screen_char_2(unsigned off, int row, int col);
48baaa7e9eSBram Moolenaar static void screenclear2(void);
49cfce7171SBram Moolenaar static void lineclear(unsigned off, int width, int attr);
50baaa7e9eSBram Moolenaar static void lineinvalid(unsigned off, int width);
51cfce7171SBram Moolenaar static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
52baaa7e9eSBram Moolenaar static void win_rest_invalid(win_T *wp);
53baaa7e9eSBram Moolenaar static void msg_pos_mode(void);
54baaa7e9eSBram Moolenaar static void recording_mode(int attr);
55071d4279SBram Moolenaar
5663d9e730SBram Moolenaar // Ugly global: overrule attribute used by screen_char()
57071d4279SBram Moolenaar static int screen_char_attr = 0;
58071d4279SBram Moolenaar
59860cae1cSBram Moolenaar #if defined(FEAT_CONCEAL) || defined(PROTO)
60f5963f71SBram Moolenaar /*
61f5963f71SBram Moolenaar * Return TRUE if the cursor line in window "wp" may be concealed, according
62f5963f71SBram Moolenaar * to the 'concealcursor' option.
63f5963f71SBram Moolenaar */
64f5963f71SBram Moolenaar int
conceal_cursor_line(win_T * wp)6505540976SBram Moolenaar conceal_cursor_line(win_T *wp)
66f5963f71SBram Moolenaar {
67f5963f71SBram Moolenaar int c;
68f5963f71SBram Moolenaar
69f5963f71SBram Moolenaar if (*wp->w_p_cocu == NUL)
70f5963f71SBram Moolenaar return FALSE;
71f5963f71SBram Moolenaar if (get_real_state() & VISUAL)
72f5963f71SBram Moolenaar c = 'v';
73f5963f71SBram Moolenaar else if (State & INSERT)
74f5963f71SBram Moolenaar c = 'i';
75f5963f71SBram Moolenaar else if (State & NORMAL)
76f5963f71SBram Moolenaar c = 'n';
77ca8c9867SBram Moolenaar else if (State & CMDLINE)
78ca8c9867SBram Moolenaar c = 'c';
79f5963f71SBram Moolenaar else
80f5963f71SBram Moolenaar return FALSE;
81f5963f71SBram Moolenaar return vim_strchr(wp->w_p_cocu, c) != NULL;
82f5963f71SBram Moolenaar }
83f5963f71SBram Moolenaar
84f5963f71SBram Moolenaar /*
85f5963f71SBram Moolenaar * Check if the cursor line needs to be redrawn because of 'concealcursor'.
86ea042677SBram Moolenaar * To be called after changing the state, "was_concealed" is the value of
87ea042677SBram Moolenaar * "conceal_cursor_line()" before the change.
88ea042677SBram Moolenaar * "
89f5963f71SBram Moolenaar */
90f5963f71SBram Moolenaar void
conceal_check_cursor_line(int was_concealed)91ea042677SBram Moolenaar conceal_check_cursor_line(int was_concealed)
92f5963f71SBram Moolenaar {
93ea042677SBram Moolenaar if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin) != was_concealed)
94f5963f71SBram Moolenaar {
95ea042677SBram Moolenaar int wcol = curwin->w_wcol;
96ea042677SBram Moolenaar
97f5963f71SBram Moolenaar need_cursor_line_redraw = TRUE;
9863d9e730SBram Moolenaar // Need to recompute cursor column, e.g., when starting Visual mode
9963d9e730SBram Moolenaar // without concealing.
100f5963f71SBram Moolenaar curs_columns(TRUE);
101ea042677SBram Moolenaar
102ea042677SBram Moolenaar // When concealing now w_wcol will be computed wrong, keep the previous
103ea042677SBram Moolenaar // value, it will be updated in win_line().
104ea042677SBram Moolenaar if (!was_concealed)
105ea042677SBram Moolenaar curwin->w_wcol = wcol;
106f5963f71SBram Moolenaar }
107f5963f71SBram Moolenaar }
108071d4279SBram Moolenaar #endif
109071d4279SBram Moolenaar
11060cdb300SBram Moolenaar /*
11160cdb300SBram Moolenaar * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
11260cdb300SBram Moolenaar * window then get the "Pmenu" highlight attribute.
11360cdb300SBram Moolenaar */
114a540f8aaSBram Moolenaar int
get_wcr_attr(win_T * wp)11560cdb300SBram Moolenaar get_wcr_attr(win_T *wp)
11660cdb300SBram Moolenaar {
11760cdb300SBram Moolenaar int wcr_attr = 0;
11860cdb300SBram Moolenaar
11960cdb300SBram Moolenaar if (*wp->w_p_wcr != NUL)
12060cdb300SBram Moolenaar wcr_attr = syn_name2attr(wp->w_p_wcr);
12105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
122c363fe15SBram Moolenaar else if (WIN_IS_POPUP(wp))
12362a0cb44SBram Moolenaar {
12462a0cb44SBram Moolenaar if (wp->w_popup_flags & POPF_INFO)
12562a0cb44SBram Moolenaar wcr_attr = HL_ATTR(HLF_PSI); // PmenuSel
12662a0cb44SBram Moolenaar else
12762a0cb44SBram Moolenaar wcr_attr = HL_ATTR(HLF_PNI); // Pmenu
12862a0cb44SBram Moolenaar }
12960cdb300SBram Moolenaar #endif
13060cdb300SBram Moolenaar return wcr_attr;
13160cdb300SBram Moolenaar }
13260cdb300SBram Moolenaar
133071d4279SBram Moolenaar /*
1348ee4c01bSBram Moolenaar * Call screen_fill() with the columns adjusted for 'rightleft' if needed.
1358ee4c01bSBram Moolenaar * Return the new offset.
1368ee4c01bSBram Moolenaar */
1378ee4c01bSBram Moolenaar static int
screen_fill_end(win_T * wp,int c1,int c2,int off,int width,int row,int endrow,int attr)1388ee4c01bSBram Moolenaar screen_fill_end(
1398ee4c01bSBram Moolenaar win_T *wp,
1408ee4c01bSBram Moolenaar int c1,
1418ee4c01bSBram Moolenaar int c2,
1428ee4c01bSBram Moolenaar int off,
1438ee4c01bSBram Moolenaar int width,
1448ee4c01bSBram Moolenaar int row,
1458ee4c01bSBram Moolenaar int endrow,
1468ee4c01bSBram Moolenaar int attr)
1478ee4c01bSBram Moolenaar {
1488ee4c01bSBram Moolenaar int nn = off + width;
1498ee4c01bSBram Moolenaar
1508ee4c01bSBram Moolenaar if (nn > wp->w_width)
1518ee4c01bSBram Moolenaar nn = wp->w_width;
1528ee4c01bSBram Moolenaar #ifdef FEAT_RIGHTLEFT
1538ee4c01bSBram Moolenaar if (wp->w_p_rl)
1548ee4c01bSBram Moolenaar {
1558ee4c01bSBram Moolenaar screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
1568ee4c01bSBram Moolenaar W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off,
1578ee4c01bSBram Moolenaar c1, c2, attr);
1588ee4c01bSBram Moolenaar }
1598ee4c01bSBram Moolenaar else
1608ee4c01bSBram Moolenaar #endif
1618ee4c01bSBram Moolenaar screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
1628ee4c01bSBram Moolenaar wp->w_wincol + off, (int)wp->w_wincol + nn,
1638ee4c01bSBram Moolenaar c1, c2, attr);
1648ee4c01bSBram Moolenaar return nn;
1658ee4c01bSBram Moolenaar }
1668ee4c01bSBram Moolenaar
1678ee4c01bSBram Moolenaar /*
1688ee4c01bSBram Moolenaar * Clear lines near the end the window and mark the unused lines with "c1".
1698ee4c01bSBram Moolenaar * use "c2" as the filler character.
1708ee4c01bSBram Moolenaar * When "draw_margin" is TRUE then draw the sign, fold and number columns.
171071d4279SBram Moolenaar */
1727528d1f6SBram Moolenaar void
win_draw_end(win_T * wp,int c1,int c2,int draw_margin,int row,int endrow,hlf_T hl)17305540976SBram Moolenaar win_draw_end(
17405540976SBram Moolenaar win_T *wp,
17505540976SBram Moolenaar int c1,
17605540976SBram Moolenaar int c2,
1778ee4c01bSBram Moolenaar int draw_margin,
17805540976SBram Moolenaar int row,
17905540976SBram Moolenaar int endrow,
18005540976SBram Moolenaar hlf_T hl)
181071d4279SBram Moolenaar {
182071d4279SBram Moolenaar int n = 0;
183193ffd1dSBram Moolenaar int attr = HL_ATTR(hl);
18460cdb300SBram Moolenaar int wcr_attr = get_wcr_attr(wp);
185193ffd1dSBram Moolenaar
186193ffd1dSBram Moolenaar attr = hl_combine_attr(wcr_attr, attr);
1878ee4c01bSBram Moolenaar
1888ee4c01bSBram Moolenaar if (draw_margin)
1898ee4c01bSBram Moolenaar {
1901c93429cSBram Moolenaar #ifdef FEAT_FOLDING
1911c93429cSBram Moolenaar int fdc = compute_foldcolumn(wp, 0);
1928ee4c01bSBram Moolenaar
1938ee4c01bSBram Moolenaar if (fdc > 0)
1948ee4c01bSBram Moolenaar // draw the fold column
1958ee4c01bSBram Moolenaar n = screen_fill_end(wp, ' ', ' ', n, fdc,
196193ffd1dSBram Moolenaar row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)));
1971c93429cSBram Moolenaar #endif
1988ee4c01bSBram Moolenaar #ifdef FEAT_SIGNS
1998ee4c01bSBram Moolenaar if (signcolumn_on(wp))
2008ee4c01bSBram Moolenaar // draw the sign column
2018ee4c01bSBram Moolenaar n = screen_fill_end(wp, ' ', ' ', n, 2,
202193ffd1dSBram Moolenaar row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)));
2038ee4c01bSBram Moolenaar #endif
2048ee4c01bSBram Moolenaar if ((wp->w_p_nu || wp->w_p_rnu)
2058ee4c01bSBram Moolenaar && vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
2068ee4c01bSBram Moolenaar // draw the number column
2078ee4c01bSBram Moolenaar n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1,
208193ffd1dSBram Moolenaar row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)));
2098ee4c01bSBram Moolenaar }
210071d4279SBram Moolenaar
211071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
212071d4279SBram Moolenaar if (wp->w_p_rl)
213071d4279SBram Moolenaar {
214071d4279SBram Moolenaar screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2158ee4c01bSBram Moolenaar wp->w_wincol, W_ENDCOL(wp) - 1 - n,
216193ffd1dSBram Moolenaar c2, c2, attr);
217071d4279SBram Moolenaar screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2188ee4c01bSBram Moolenaar W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
219193ffd1dSBram Moolenaar c1, c2, attr);
220071d4279SBram Moolenaar }
221071d4279SBram Moolenaar else
222071d4279SBram Moolenaar #endif
223071d4279SBram Moolenaar {
224071d4279SBram Moolenaar screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2258ee4c01bSBram Moolenaar wp->w_wincol + n, (int)W_ENDCOL(wp),
226193ffd1dSBram Moolenaar c1, c2, attr);
227071d4279SBram Moolenaar }
2288ee4c01bSBram Moolenaar
229071d4279SBram Moolenaar set_empty_rows(wp, row);
230071d4279SBram Moolenaar }
231071d4279SBram Moolenaar
2327528d1f6SBram Moolenaar #if defined(FEAT_FOLDING) || defined(PROTO)
233071d4279SBram Moolenaar /*
2341c93429cSBram Moolenaar * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
2351c93429cSBram Moolenaar * space is available for window "wp", minus "col".
2361c93429cSBram Moolenaar */
2377528d1f6SBram Moolenaar int
compute_foldcolumn(win_T * wp,int col)23805540976SBram Moolenaar compute_foldcolumn(win_T *wp, int col)
2391c93429cSBram Moolenaar {
2401c93429cSBram Moolenaar int fdc = wp->w_p_fdc;
2411c93429cSBram Moolenaar int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
2420263146bSBram Moolenaar int wwidth = wp->w_width;
2431c93429cSBram Moolenaar
2441c93429cSBram Moolenaar if (fdc > wwidth - (col + wmw))
2451c93429cSBram Moolenaar fdc = wwidth - (col + wmw);
2461c93429cSBram Moolenaar return fdc;
2471c93429cSBram Moolenaar }
2481c93429cSBram Moolenaar
2491c93429cSBram Moolenaar /*
250071d4279SBram Moolenaar * Fill the foldcolumn at "p" for window "wp".
251d5cdbeb8SBram Moolenaar * Only to be called when 'foldcolumn' > 0.
2524fa11757SBram Moolenaar * Returns the number of bytes stored in 'p'. When non-multibyte characters are
2534fa11757SBram Moolenaar * used for the fold column markers, this is equal to 'fdc' setting. Otherwise,
2544fa11757SBram Moolenaar * this will be greater than 'fdc'.
255071d4279SBram Moolenaar */
2564fa11757SBram Moolenaar size_t
fill_foldcolumn(char_u * p,win_T * wp,int closed,linenr_T lnum)25705540976SBram Moolenaar fill_foldcolumn(
25805540976SBram Moolenaar char_u *p,
25905540976SBram Moolenaar win_T *wp,
26063d9e730SBram Moolenaar int closed, // TRUE of FALSE
26163d9e730SBram Moolenaar linenr_T lnum) // current line number
262071d4279SBram Moolenaar {
263071d4279SBram Moolenaar int i = 0;
264071d4279SBram Moolenaar int level;
265071d4279SBram Moolenaar int first_level;
266578b49e4SBram Moolenaar int empty;
2671c93429cSBram Moolenaar int fdc = compute_foldcolumn(wp, 0);
2684fa11757SBram Moolenaar size_t byte_counter = 0;
2694fa11757SBram Moolenaar int symbol = 0;
2704fa11757SBram Moolenaar int len = 0;
271071d4279SBram Moolenaar
27263d9e730SBram Moolenaar // Init to all spaces.
2734fa11757SBram Moolenaar vim_memset(p, ' ', MAX_MCO * fdc + 1);
274071d4279SBram Moolenaar
275071d4279SBram Moolenaar level = win_foldinfo.fi_level;
2761c93429cSBram Moolenaar empty = (fdc == 1) ? 0 : 1;
277578b49e4SBram Moolenaar
27863d9e730SBram Moolenaar // If the column is too narrow, we start at the lowest level that
279008bff96SBram Moolenaar // fits and use numbers to indicate the depth.
2801c93429cSBram Moolenaar first_level = level - fdc - closed + 1 + empty;
281071d4279SBram Moolenaar if (first_level < 1)
282071d4279SBram Moolenaar first_level = 1;
283071d4279SBram Moolenaar
2844fa11757SBram Moolenaar for (i = 0; i < MIN(fdc, level); i++)
285071d4279SBram Moolenaar {
286071d4279SBram Moolenaar if (win_foldinfo.fi_lnum == lnum
287071d4279SBram Moolenaar && first_level + i >= win_foldinfo.fi_low_level)
2884fa11757SBram Moolenaar symbol = fill_foldopen;
289071d4279SBram Moolenaar else if (first_level == 1)
2904fa11757SBram Moolenaar symbol = fill_foldsep;
291071d4279SBram Moolenaar else if (first_level + i <= 9)
2924fa11757SBram Moolenaar symbol = '0' + first_level + i;
293071d4279SBram Moolenaar else
2944fa11757SBram Moolenaar symbol = '>';
2954fa11757SBram Moolenaar
2964fa11757SBram Moolenaar len = utf_char2bytes(symbol, &p[byte_counter]);
2974fa11757SBram Moolenaar byte_counter += len;
2984fa11757SBram Moolenaar if (first_level + i >= level)
2994fa11757SBram Moolenaar {
3004fa11757SBram Moolenaar i++;
301071d4279SBram Moolenaar break;
302071d4279SBram Moolenaar }
303071d4279SBram Moolenaar }
3044fa11757SBram Moolenaar
305071d4279SBram Moolenaar if (closed)
3064fa11757SBram Moolenaar {
3074fa11757SBram Moolenaar if (symbol != 0)
308196a1f74SBram Moolenaar {
309196a1f74SBram Moolenaar // rollback length and the character
3104fa11757SBram Moolenaar byte_counter -= len;
311196a1f74SBram Moolenaar if (len > 1)
312196a1f74SBram Moolenaar // for a multibyte character, erase all the bytes
313196a1f74SBram Moolenaar vim_memset(p + byte_counter, ' ', len);
314196a1f74SBram Moolenaar }
3154fa11757SBram Moolenaar symbol = fill_foldclosed;
3164fa11757SBram Moolenaar len = utf_char2bytes(symbol, &p[byte_counter]);
3174fa11757SBram Moolenaar byte_counter += len;
3184fa11757SBram Moolenaar }
3194fa11757SBram Moolenaar
3204fa11757SBram Moolenaar return MAX(byte_counter + (fdc - i), (size_t)fdc);
321071d4279SBram Moolenaar }
32263d9e730SBram Moolenaar #endif // FEAT_FOLDING
323071d4279SBram Moolenaar
324362e1a30SBram Moolenaar /*
325362e1a30SBram Moolenaar * Return if the composing characters at "off_from" and "off_to" differ.
32670c49c1aSBram Moolenaar * Only to be used when ScreenLinesUC[off_from] != 0.
327362e1a30SBram Moolenaar */
328362e1a30SBram Moolenaar static int
comp_char_differs(int off_from,int off_to)32905540976SBram Moolenaar comp_char_differs(int off_from, int off_to)
330362e1a30SBram Moolenaar {
331362e1a30SBram Moolenaar int i;
332362e1a30SBram Moolenaar
333362e1a30SBram Moolenaar for (i = 0; i < Screen_mco; ++i)
334362e1a30SBram Moolenaar {
335362e1a30SBram Moolenaar if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
336362e1a30SBram Moolenaar return TRUE;
337362e1a30SBram Moolenaar if (ScreenLinesC[i][off_from] == 0)
338362e1a30SBram Moolenaar break;
339362e1a30SBram Moolenaar }
340362e1a30SBram Moolenaar return FALSE;
341362e1a30SBram Moolenaar }
342362e1a30SBram Moolenaar
343071d4279SBram Moolenaar /*
344071d4279SBram Moolenaar * Check whether the given character needs redrawing:
345071d4279SBram Moolenaar * - the (first byte of the) character is different
346071d4279SBram Moolenaar * - the attributes are different
347071d4279SBram Moolenaar * - the character is multi-byte and the next byte is different
34888f3d3a2SBram Moolenaar * - the character is two cells wide and the second cell differs.
349071d4279SBram Moolenaar */
350071d4279SBram Moolenaar static int
char_needs_redraw(int off_from,int off_to,int cols)35105540976SBram Moolenaar char_needs_redraw(int off_from, int off_to, int cols)
352071d4279SBram Moolenaar {
353071d4279SBram Moolenaar if (cols > 0
354071d4279SBram Moolenaar && ((ScreenLines[off_from] != ScreenLines[off_to]
355071d4279SBram Moolenaar || ScreenAttrs[off_from] != ScreenAttrs[off_to])
356071d4279SBram Moolenaar || (enc_dbcs != 0
357071d4279SBram Moolenaar && MB_BYTE2LEN(ScreenLines[off_from]) > 1
358071d4279SBram Moolenaar && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
359071d4279SBram Moolenaar ? ScreenLines2[off_from] != ScreenLines2[off_to]
360071d4279SBram Moolenaar : (cols > 1 && ScreenLines[off_from + 1]
361071d4279SBram Moolenaar != ScreenLines[off_to + 1])))
362071d4279SBram Moolenaar || (enc_utf8
363071d4279SBram Moolenaar && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
364071d4279SBram Moolenaar || (ScreenLinesUC[off_from] != 0
36588f3d3a2SBram Moolenaar && comp_char_differs(off_from, off_to))
366451cf637SBram Moolenaar || ((*mb_off2cells)(off_from, off_from + cols) > 1
367451cf637SBram Moolenaar && ScreenLines[off_from + 1]
368a12a161bSBram Moolenaar != ScreenLines[off_to + 1])))))
369071d4279SBram Moolenaar return TRUE;
370071d4279SBram Moolenaar return FALSE;
371071d4279SBram Moolenaar }
372071d4279SBram Moolenaar
373cb8bbe9bSBram Moolenaar #if defined(FEAT_TERMINAL) || defined(PROTO)
374cb8bbe9bSBram Moolenaar /*
375cb8bbe9bSBram Moolenaar * Return the index in ScreenLines[] for the current screen line.
376cb8bbe9bSBram Moolenaar */
377cb8bbe9bSBram Moolenaar int
screen_get_current_line_off()378cb8bbe9bSBram Moolenaar screen_get_current_line_off()
379cb8bbe9bSBram Moolenaar {
380cb8bbe9bSBram Moolenaar return (int)(current_ScreenLine - ScreenLines);
381cb8bbe9bSBram Moolenaar }
382cb8bbe9bSBram Moolenaar #endif
383cb8bbe9bSBram Moolenaar
38405ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
385c662ec99SBram Moolenaar /*
386c662ec99SBram Moolenaar * Return TRUE if this position has a higher level popup or this cell is
387c662ec99SBram Moolenaar * transparent in the current popup.
388c662ec99SBram Moolenaar */
389c662ec99SBram Moolenaar static int
blocked_by_popup(int row,int col)390c662ec99SBram Moolenaar blocked_by_popup(int row, int col)
391c662ec99SBram Moolenaar {
392c662ec99SBram Moolenaar int off;
393c662ec99SBram Moolenaar
394c662ec99SBram Moolenaar if (!popup_visible)
395c662ec99SBram Moolenaar return FALSE;
396c662ec99SBram Moolenaar off = row * screen_Columns + col;
397c662ec99SBram Moolenaar return popup_mask[off] > screen_zindex || popup_transparent[off];
398c662ec99SBram Moolenaar }
399c662ec99SBram Moolenaar #endif
400c662ec99SBram Moolenaar
401071d4279SBram Moolenaar /*
4027528d1f6SBram Moolenaar * Reset the highlighting. Used before clearing the screen.
4037528d1f6SBram Moolenaar */
4047528d1f6SBram Moolenaar void
reset_screen_attr(void)4057528d1f6SBram Moolenaar reset_screen_attr(void)
4067528d1f6SBram Moolenaar {
4077528d1f6SBram Moolenaar #ifdef FEAT_GUI
4087528d1f6SBram Moolenaar if (gui.in_use)
4097528d1f6SBram Moolenaar // Use a code that will reset gui.highlight_mask in
4107528d1f6SBram Moolenaar // gui_stop_highlight().
4117528d1f6SBram Moolenaar screen_attr = HL_ALL + 1;
4127528d1f6SBram Moolenaar else
4137528d1f6SBram Moolenaar #endif
4147528d1f6SBram Moolenaar // Use attributes that is very unlikely to appear in text.
4157528d1f6SBram Moolenaar screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
4167528d1f6SBram Moolenaar }
4177528d1f6SBram Moolenaar
4187528d1f6SBram Moolenaar /*
419071d4279SBram Moolenaar * Move one "cooked" screen line to the screen, but only the characters that
420071d4279SBram Moolenaar * have actually changed. Handle insert/delete character.
421071d4279SBram Moolenaar * "coloff" gives the first column on the screen for this line.
422071d4279SBram Moolenaar * "endcol" gives the columns where valid characters are.
423071d4279SBram Moolenaar * "clear_width" is the width of the window. It's > 0 if the rest of the line
424071d4279SBram Moolenaar * needs to be cleared, negative otherwise.
4254d784b21SBram Moolenaar * "flags" can have bits:
4264d784b21SBram Moolenaar * SLF_POPUP popup window
4274d784b21SBram Moolenaar * SLF_RIGHTLEFT rightleft window:
428071d4279SBram Moolenaar * When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
429071d4279SBram Moolenaar * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
430071d4279SBram Moolenaar */
431cb8bbe9bSBram Moolenaar void
screen_line(int row,int coloff,int endcol,int clear_width,int flags UNUSED)43205540976SBram Moolenaar screen_line(
43305540976SBram Moolenaar int row,
43405540976SBram Moolenaar int coloff,
43505540976SBram Moolenaar int endcol,
436cb8bbe9bSBram Moolenaar int clear_width,
4374d784b21SBram Moolenaar int flags UNUSED)
438071d4279SBram Moolenaar {
439071d4279SBram Moolenaar unsigned off_from;
440071d4279SBram Moolenaar unsigned off_to;
441367329baSBram Moolenaar unsigned max_off_from;
442367329baSBram Moolenaar unsigned max_off_to;
443071d4279SBram Moolenaar int col = 0;
444071d4279SBram Moolenaar int hl;
44563d9e730SBram Moolenaar int force = FALSE; // force update rest of the line
44663d9e730SBram Moolenaar int redraw_this // bool: does character need redraw?
447071d4279SBram Moolenaar #ifdef FEAT_GUI
44863d9e730SBram Moolenaar = TRUE // For GUI when while-loop empty
449071d4279SBram Moolenaar #endif
450071d4279SBram Moolenaar ;
45163d9e730SBram Moolenaar int redraw_next; // redraw_this for next character
452071d4279SBram Moolenaar int clear_next = FALSE;
45363d9e730SBram Moolenaar int char_cells; // 1: normal char
45463d9e730SBram Moolenaar // 2: occupies two display cells
455071d4279SBram Moolenaar # define CHAR_CELLS char_cells
456071d4279SBram Moolenaar
45763d9e730SBram Moolenaar // Check for illegal row and col, just in case.
4585ad15df9SBram Moolenaar if (row >= Rows)
4595ad15df9SBram Moolenaar row = Rows - 1;
4605ad15df9SBram Moolenaar if (endcol > Columns)
4615ad15df9SBram Moolenaar endcol = Columns;
4625ad15df9SBram Moolenaar
463071d4279SBram Moolenaar # ifdef FEAT_CLIPBOARD
464071d4279SBram Moolenaar clip_may_clear_selection(row, row);
465071d4279SBram Moolenaar # endif
466071d4279SBram Moolenaar
467071d4279SBram Moolenaar off_from = (unsigned)(current_ScreenLine - ScreenLines);
468071d4279SBram Moolenaar off_to = LineOffset[row] + coloff;
469367329baSBram Moolenaar max_off_from = off_from + screen_Columns;
470367329baSBram Moolenaar max_off_to = LineOffset[row] + screen_Columns;
471071d4279SBram Moolenaar
472071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
4734d784b21SBram Moolenaar if (flags & SLF_RIGHTLEFT)
474071d4279SBram Moolenaar {
47563d9e730SBram Moolenaar // Clear rest first, because it's left of the text.
476071d4279SBram Moolenaar if (clear_width > 0)
477071d4279SBram Moolenaar {
478071d4279SBram Moolenaar while (col <= endcol && ScreenLines[off_to] == ' '
479071d4279SBram Moolenaar && ScreenAttrs[off_to] == 0
480a12a161bSBram Moolenaar && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
481071d4279SBram Moolenaar {
482071d4279SBram Moolenaar ++off_to;
483071d4279SBram Moolenaar ++col;
484071d4279SBram Moolenaar }
485071d4279SBram Moolenaar if (col <= endcol)
486071d4279SBram Moolenaar screen_fill(row, row + 1, col + coloff,
487071d4279SBram Moolenaar endcol + coloff + 1, ' ', ' ', 0);
488071d4279SBram Moolenaar }
489071d4279SBram Moolenaar col = endcol + 1;
490071d4279SBram Moolenaar off_to = LineOffset[row] + col + coloff;
491071d4279SBram Moolenaar off_from += col;
492071d4279SBram Moolenaar endcol = (clear_width > 0 ? clear_width : -clear_width);
493071d4279SBram Moolenaar }
49463d9e730SBram Moolenaar #endif // FEAT_RIGHTLEFT
495071d4279SBram Moolenaar
49605ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
49792e25ab2SBram Moolenaar // First char of a popup window may go on top of the right half of a
49892e25ab2SBram Moolenaar // double-wide character. Clear the left half to avoid it getting the popup
49992e25ab2SBram Moolenaar // window background color.
500927495b1SBram Moolenaar if (coloff > 0 && enc_utf8
501927495b1SBram Moolenaar && ScreenLines[off_to] == 0
502dc0cf1dbSBram Moolenaar && ScreenLinesUC[off_to - 1] != 0
503dc0cf1dbSBram Moolenaar && (*mb_char2cells)(ScreenLinesUC[off_to - 1]) > 1)
50492e25ab2SBram Moolenaar {
50592e25ab2SBram Moolenaar ScreenLines[off_to - 1] = ' ';
50692e25ab2SBram Moolenaar ScreenLinesUC[off_to - 1] = 0;
50792e25ab2SBram Moolenaar screen_char(off_to - 1, row, col + coloff - 1);
50892e25ab2SBram Moolenaar }
50992e25ab2SBram Moolenaar #endif
51092e25ab2SBram Moolenaar
511071d4279SBram Moolenaar redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
512071d4279SBram Moolenaar
513071d4279SBram Moolenaar while (col < endcol)
514071d4279SBram Moolenaar {
515071d4279SBram Moolenaar if (has_mbyte && (col + 1 < endcol))
516367329baSBram Moolenaar char_cells = (*mb_off2cells)(off_from, max_off_from);
517071d4279SBram Moolenaar else
518071d4279SBram Moolenaar char_cells = 1;
519071d4279SBram Moolenaar
520071d4279SBram Moolenaar redraw_this = redraw_next;
521071d4279SBram Moolenaar redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
522071d4279SBram Moolenaar off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
523071d4279SBram Moolenaar
524071d4279SBram Moolenaar #ifdef FEAT_GUI
52563d9e730SBram Moolenaar // If the next character was bold, then redraw the current character to
52663d9e730SBram Moolenaar // remove any pixels that might have spilt over into us. This only
52763d9e730SBram Moolenaar // happens in the GUI.
528071d4279SBram Moolenaar if (redraw_next && gui.in_use)
529071d4279SBram Moolenaar {
530071d4279SBram Moolenaar hl = ScreenAttrs[off_to + CHAR_CELLS];
531600dddcfSBram Moolenaar if (hl > HL_ALL)
532600dddcfSBram Moolenaar hl = syn_attr2attr(hl);
533600dddcfSBram Moolenaar if (hl & HL_BOLD)
534071d4279SBram Moolenaar redraw_this = TRUE;
535071d4279SBram Moolenaar }
536071d4279SBram Moolenaar #endif
53705ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
538c662ec99SBram Moolenaar if (blocked_by_popup(row, col + coloff))
53933796b39SBram Moolenaar redraw_this = FALSE;
54033796b39SBram Moolenaar #endif
541071d4279SBram Moolenaar if (redraw_this)
542071d4279SBram Moolenaar {
543071d4279SBram Moolenaar /*
544071d4279SBram Moolenaar * Special handling when 'xs' termcap flag set (hpterm):
545071d4279SBram Moolenaar * Attributes for characters are stored at the position where the
546071d4279SBram Moolenaar * cursor is when writing the highlighting code. The
547071d4279SBram Moolenaar * start-highlighting code must be written with the cursor on the
548071d4279SBram Moolenaar * first highlighted character. The stop-highlighting code must
549071d4279SBram Moolenaar * be written with the cursor just after the last highlighted
550071d4279SBram Moolenaar * character.
551c4568ab3SBram Moolenaar * Overwriting a character doesn't remove its highlighting. Need
552071d4279SBram Moolenaar * to clear the rest of the line, and force redrawing it
553071d4279SBram Moolenaar * completely.
554071d4279SBram Moolenaar */
555071d4279SBram Moolenaar if ( p_wiv
556071d4279SBram Moolenaar && !force
557071d4279SBram Moolenaar #ifdef FEAT_GUI
558071d4279SBram Moolenaar && !gui.in_use
559071d4279SBram Moolenaar #endif
560071d4279SBram Moolenaar && ScreenAttrs[off_to] != 0
561071d4279SBram Moolenaar && ScreenAttrs[off_from] != ScreenAttrs[off_to])
562071d4279SBram Moolenaar {
563071d4279SBram Moolenaar /*
564071d4279SBram Moolenaar * Need to remove highlighting attributes here.
565071d4279SBram Moolenaar */
566071d4279SBram Moolenaar windgoto(row, col + coloff);
56763d9e730SBram Moolenaar out_str(T_CE); // clear rest of this screen line
56863d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
56963d9e730SBram Moolenaar force = TRUE; // force redraw of rest of the line
57063d9e730SBram Moolenaar redraw_next = TRUE; // or else next char would miss out
571071d4279SBram Moolenaar
572071d4279SBram Moolenaar /*
573071d4279SBram Moolenaar * If the previous character was highlighted, need to stop
574071d4279SBram Moolenaar * highlighting at this character.
575071d4279SBram Moolenaar */
576071d4279SBram Moolenaar if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
577071d4279SBram Moolenaar {
578071d4279SBram Moolenaar screen_attr = ScreenAttrs[off_to - 1];
579071d4279SBram Moolenaar term_windgoto(row, col + coloff);
580071d4279SBram Moolenaar screen_stop_highlight();
581071d4279SBram Moolenaar }
582071d4279SBram Moolenaar else
58363d9e730SBram Moolenaar screen_attr = 0; // highlighting has stopped
584071d4279SBram Moolenaar }
585071d4279SBram Moolenaar if (enc_dbcs != 0)
586071d4279SBram Moolenaar {
58763d9e730SBram Moolenaar // Check if overwriting a double-byte with a single-byte or
58863d9e730SBram Moolenaar // the other way around requires another character to be
58963d9e730SBram Moolenaar // redrawn. For UTF-8 this isn't needed, because comparing
59063d9e730SBram Moolenaar // ScreenLinesUC[] is sufficient.
591071d4279SBram Moolenaar if (char_cells == 1
592071d4279SBram Moolenaar && col + 1 < endcol
593367329baSBram Moolenaar && (*mb_off2cells)(off_to, max_off_to) > 1)
594071d4279SBram Moolenaar {
59563d9e730SBram Moolenaar // Writing a single-cell character over a double-cell
59663d9e730SBram Moolenaar // character: need to redraw the next cell.
597071d4279SBram Moolenaar ScreenLines[off_to + 1] = 0;
598071d4279SBram Moolenaar redraw_next = TRUE;
599071d4279SBram Moolenaar }
600071d4279SBram Moolenaar else if (char_cells == 2
601071d4279SBram Moolenaar && col + 2 < endcol
602367329baSBram Moolenaar && (*mb_off2cells)(off_to, max_off_to) == 1
603367329baSBram Moolenaar && (*mb_off2cells)(off_to + 1, max_off_to) > 1)
604071d4279SBram Moolenaar {
60563d9e730SBram Moolenaar // Writing the second half of a double-cell character over
60663d9e730SBram Moolenaar // a double-cell character: need to redraw the second
60763d9e730SBram Moolenaar // cell.
608071d4279SBram Moolenaar ScreenLines[off_to + 2] = 0;
609071d4279SBram Moolenaar redraw_next = TRUE;
610071d4279SBram Moolenaar }
611071d4279SBram Moolenaar
612071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU)
613071d4279SBram Moolenaar ScreenLines2[off_to] = ScreenLines2[off_from];
614071d4279SBram Moolenaar }
61563d9e730SBram Moolenaar // When writing a single-width character over a double-width
61663d9e730SBram Moolenaar // character and at the end of the redrawn text, need to clear out
61763d9e730SBram Moolenaar // the right halve of the old character.
61863d9e730SBram Moolenaar // Also required when writing the right halve of a double-width
61963d9e730SBram Moolenaar // char over the left halve of an existing one.
620071d4279SBram Moolenaar if (has_mbyte && col + char_cells == endcol
621071d4279SBram Moolenaar && ((char_cells == 1
622367329baSBram Moolenaar && (*mb_off2cells)(off_to, max_off_to) > 1)
623071d4279SBram Moolenaar || (char_cells == 2
624367329baSBram Moolenaar && (*mb_off2cells)(off_to, max_off_to) == 1
625367329baSBram Moolenaar && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
626071d4279SBram Moolenaar clear_next = TRUE;
627071d4279SBram Moolenaar
628071d4279SBram Moolenaar ScreenLines[off_to] = ScreenLines[off_from];
629071d4279SBram Moolenaar if (enc_utf8)
630071d4279SBram Moolenaar {
631071d4279SBram Moolenaar ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
632071d4279SBram Moolenaar if (ScreenLinesUC[off_from] != 0)
633071d4279SBram Moolenaar {
634362e1a30SBram Moolenaar int i;
635362e1a30SBram Moolenaar
636362e1a30SBram Moolenaar for (i = 0; i < Screen_mco; ++i)
637362e1a30SBram Moolenaar ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
638071d4279SBram Moolenaar }
639071d4279SBram Moolenaar }
640071d4279SBram Moolenaar if (char_cells == 2)
641071d4279SBram Moolenaar ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
642071d4279SBram Moolenaar
643071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
64463d9e730SBram Moolenaar // The bold trick makes a single column of pixels appear in the
64563d9e730SBram Moolenaar // next character. When a bold character is removed, the next
64663d9e730SBram Moolenaar // character should be redrawn too. This happens for our own GUI
64763d9e730SBram Moolenaar // and for some xterms.
648071d4279SBram Moolenaar if (
649071d4279SBram Moolenaar # ifdef FEAT_GUI
650071d4279SBram Moolenaar gui.in_use
651071d4279SBram Moolenaar # endif
652071d4279SBram Moolenaar # if defined(FEAT_GUI) && defined(UNIX)
653071d4279SBram Moolenaar ||
654071d4279SBram Moolenaar # endif
655071d4279SBram Moolenaar # ifdef UNIX
656071d4279SBram Moolenaar term_is_xterm
657071d4279SBram Moolenaar # endif
658071d4279SBram Moolenaar )
659071d4279SBram Moolenaar {
660071d4279SBram Moolenaar hl = ScreenAttrs[off_to];
661600dddcfSBram Moolenaar if (hl > HL_ALL)
662600dddcfSBram Moolenaar hl = syn_attr2attr(hl);
663600dddcfSBram Moolenaar if (hl & HL_BOLD)
664071d4279SBram Moolenaar redraw_next = TRUE;
665071d4279SBram Moolenaar }
666071d4279SBram Moolenaar #endif
667071d4279SBram Moolenaar ScreenAttrs[off_to] = ScreenAttrs[off_from];
668a12a161bSBram Moolenaar
66963d9e730SBram Moolenaar // For simplicity set the attributes of second half of a
67063d9e730SBram Moolenaar // double-wide character equal to the first half.
671910f66f9SBram Moolenaar if (char_cells == 2)
672071d4279SBram Moolenaar ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
673910f66f9SBram Moolenaar
674910f66f9SBram Moolenaar if (enc_dbcs != 0 && char_cells == 2)
675071d4279SBram Moolenaar screen_char_2(off_to, row, col + coloff);
676071d4279SBram Moolenaar else
677071d4279SBram Moolenaar screen_char(off_to, row, col + coloff);
678071d4279SBram Moolenaar }
679071d4279SBram Moolenaar else if ( p_wiv
680071d4279SBram Moolenaar #ifdef FEAT_GUI
681071d4279SBram Moolenaar && !gui.in_use
682071d4279SBram Moolenaar #endif
683071d4279SBram Moolenaar && col + coloff > 0)
684071d4279SBram Moolenaar {
685071d4279SBram Moolenaar if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
686071d4279SBram Moolenaar {
687071d4279SBram Moolenaar /*
688071d4279SBram Moolenaar * Don't output stop-highlight when moving the cursor, it will
689071d4279SBram Moolenaar * stop the highlighting when it should continue.
690071d4279SBram Moolenaar */
691071d4279SBram Moolenaar screen_attr = 0;
692071d4279SBram Moolenaar }
693071d4279SBram Moolenaar else if (screen_attr != 0)
694071d4279SBram Moolenaar screen_stop_highlight();
695071d4279SBram Moolenaar }
696071d4279SBram Moolenaar
697071d4279SBram Moolenaar off_to += CHAR_CELLS;
698071d4279SBram Moolenaar off_from += CHAR_CELLS;
699071d4279SBram Moolenaar col += CHAR_CELLS;
700071d4279SBram Moolenaar }
701071d4279SBram Moolenaar
702071d4279SBram Moolenaar if (clear_next)
703071d4279SBram Moolenaar {
70463d9e730SBram Moolenaar // Clear the second half of a double-wide character of which the left
70563d9e730SBram Moolenaar // half was overwritten with a single-wide character.
706071d4279SBram Moolenaar ScreenLines[off_to] = ' ';
707071d4279SBram Moolenaar if (enc_utf8)
708071d4279SBram Moolenaar ScreenLinesUC[off_to] = 0;
709071d4279SBram Moolenaar screen_char(off_to, row, col + coloff);
710071d4279SBram Moolenaar }
711071d4279SBram Moolenaar
712071d4279SBram Moolenaar if (clear_width > 0
713071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
7144d784b21SBram Moolenaar && !(flags & SLF_RIGHTLEFT)
715071d4279SBram Moolenaar #endif
716071d4279SBram Moolenaar )
717071d4279SBram Moolenaar {
718071d4279SBram Moolenaar #ifdef FEAT_GUI
719071d4279SBram Moolenaar int startCol = col;
720071d4279SBram Moolenaar #endif
721071d4279SBram Moolenaar
72263d9e730SBram Moolenaar // blank out the rest of the line
723071d4279SBram Moolenaar while (col < clear_width && ScreenLines[off_to] == ' '
724071d4279SBram Moolenaar && ScreenAttrs[off_to] == 0
725a12a161bSBram Moolenaar && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
726071d4279SBram Moolenaar {
727071d4279SBram Moolenaar ++off_to;
728071d4279SBram Moolenaar ++col;
729071d4279SBram Moolenaar }
730071d4279SBram Moolenaar if (col < clear_width)
731071d4279SBram Moolenaar {
732071d4279SBram Moolenaar #ifdef FEAT_GUI
733071d4279SBram Moolenaar /*
734071d4279SBram Moolenaar * In the GUI, clearing the rest of the line may leave pixels
735071d4279SBram Moolenaar * behind if the first character cleared was bold. Some bold
736071d4279SBram Moolenaar * fonts spill over the left. In this case we redraw the previous
737071d4279SBram Moolenaar * character too. If we didn't skip any blanks above, then we
738071d4279SBram Moolenaar * only redraw if the character wasn't already redrawn anyway.
739071d4279SBram Moolenaar */
7409c697322SBram Moolenaar if (gui.in_use && (col > startCol || !redraw_this))
741071d4279SBram Moolenaar {
742071d4279SBram Moolenaar hl = ScreenAttrs[off_to];
743071d4279SBram Moolenaar if (hl > HL_ALL || (hl & HL_BOLD))
7449c697322SBram Moolenaar {
7459c697322SBram Moolenaar int prev_cells = 1;
746a12a161bSBram Moolenaar
7479c697322SBram Moolenaar if (enc_utf8)
74863d9e730SBram Moolenaar // for utf-8, ScreenLines[char_offset + 1] == 0 means
74963d9e730SBram Moolenaar // that its width is 2.
7509c697322SBram Moolenaar prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
7519c697322SBram Moolenaar else if (enc_dbcs != 0)
7529c697322SBram Moolenaar {
75363d9e730SBram Moolenaar // find previous character by counting from first
75463d9e730SBram Moolenaar // column and get its width.
7559c697322SBram Moolenaar unsigned off = LineOffset[row];
756367329baSBram Moolenaar unsigned max_off = LineOffset[row] + screen_Columns;
7579c697322SBram Moolenaar
7589c697322SBram Moolenaar while (off < off_to)
7599c697322SBram Moolenaar {
760367329baSBram Moolenaar prev_cells = (*mb_off2cells)(off, max_off);
7619c697322SBram Moolenaar off += prev_cells;
7629c697322SBram Moolenaar }
7639c697322SBram Moolenaar }
7649c697322SBram Moolenaar
7659c697322SBram Moolenaar if (enc_dbcs != 0 && prev_cells > 1)
7669c697322SBram Moolenaar screen_char_2(off_to - prev_cells, row,
7679c697322SBram Moolenaar col + coloff - prev_cells);
7689c697322SBram Moolenaar else
7699c697322SBram Moolenaar screen_char(off_to - prev_cells, row,
7709c697322SBram Moolenaar col + coloff - prev_cells);
7719c697322SBram Moolenaar }
772071d4279SBram Moolenaar }
773071d4279SBram Moolenaar #endif
774071d4279SBram Moolenaar screen_fill(row, row + 1, col + coloff, clear_width + coloff,
775071d4279SBram Moolenaar ' ', ' ', 0);
776071d4279SBram Moolenaar off_to += clear_width - col;
777071d4279SBram Moolenaar col = clear_width;
778071d4279SBram Moolenaar }
779071d4279SBram Moolenaar }
780071d4279SBram Moolenaar
7814d784b21SBram Moolenaar if (clear_width > 0
78205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
7834d784b21SBram Moolenaar && !(flags & SLF_POPUP) // no separator for popup window
7844d784b21SBram Moolenaar #endif
7854d784b21SBram Moolenaar )
786071d4279SBram Moolenaar {
7874d784b21SBram Moolenaar // For a window that has a right neighbor, draw the separator char
788aef5c62aSBram Moolenaar // right of the window contents. But not on top of a popup window.
7894d784b21SBram Moolenaar if (coloff + col < Columns)
790071d4279SBram Moolenaar {
79105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
792c662ec99SBram Moolenaar if (!blocked_by_popup(row, col + coloff))
793aef5c62aSBram Moolenaar #endif
794aef5c62aSBram Moolenaar {
795071d4279SBram Moolenaar int c;
796071d4279SBram Moolenaar
797071d4279SBram Moolenaar c = fillchar_vsep(&hl);
798c60c4f6eSBram Moolenaar if (ScreenLines[off_to] != (schar_T)c
799362e1a30SBram Moolenaar || (enc_utf8 && (int)ScreenLinesUC[off_to]
800362e1a30SBram Moolenaar != (c >= 0x80 ? c : 0))
801071d4279SBram Moolenaar || ScreenAttrs[off_to] != hl)
802071d4279SBram Moolenaar {
803071d4279SBram Moolenaar ScreenLines[off_to] = c;
804071d4279SBram Moolenaar ScreenAttrs[off_to] = hl;
805071d4279SBram Moolenaar if (enc_utf8)
806071d4279SBram Moolenaar {
807071d4279SBram Moolenaar if (c >= 0x80)
808071d4279SBram Moolenaar {
809071d4279SBram Moolenaar ScreenLinesUC[off_to] = c;
810362e1a30SBram Moolenaar ScreenLinesC[0][off_to] = 0;
811071d4279SBram Moolenaar }
812071d4279SBram Moolenaar else
813071d4279SBram Moolenaar ScreenLinesUC[off_to] = 0;
814071d4279SBram Moolenaar }
815071d4279SBram Moolenaar screen_char(off_to, row, col + coloff);
816071d4279SBram Moolenaar }
817071d4279SBram Moolenaar }
818aef5c62aSBram Moolenaar }
819071d4279SBram Moolenaar else
820071d4279SBram Moolenaar LineWraps[row] = FALSE;
821071d4279SBram Moolenaar }
822071d4279SBram Moolenaar }
823071d4279SBram Moolenaar
8240fa313a7SBram Moolenaar #if defined(FEAT_RIGHTLEFT) || defined(PROTO)
825071d4279SBram Moolenaar /*
8260fa313a7SBram Moolenaar * Mirror text "str" for right-left displaying.
8270fa313a7SBram Moolenaar * Only works for single-byte characters (e.g., numbers).
828071d4279SBram Moolenaar */
8290fa313a7SBram Moolenaar void
rl_mirror(char_u * str)83005540976SBram Moolenaar rl_mirror(char_u *str)
831071d4279SBram Moolenaar {
832071d4279SBram Moolenaar char_u *p1, *p2;
833071d4279SBram Moolenaar int t;
834071d4279SBram Moolenaar
835071d4279SBram Moolenaar for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
836071d4279SBram Moolenaar {
837071d4279SBram Moolenaar t = *p1;
838071d4279SBram Moolenaar *p1 = *p2;
839071d4279SBram Moolenaar *p2 = t;
840071d4279SBram Moolenaar }
841071d4279SBram Moolenaar }
842071d4279SBram Moolenaar #endif
843071d4279SBram Moolenaar
844071d4279SBram Moolenaar /*
845071d4279SBram Moolenaar * Draw the verticap separator right of window "wp" starting with line "row".
846071d4279SBram Moolenaar */
8477528d1f6SBram Moolenaar void
draw_vsep_win(win_T * wp,int row)84805540976SBram Moolenaar draw_vsep_win(win_T *wp, int row)
849071d4279SBram Moolenaar {
850071d4279SBram Moolenaar int hl;
851071d4279SBram Moolenaar int c;
852071d4279SBram Moolenaar
853071d4279SBram Moolenaar if (wp->w_vsep_width)
854071d4279SBram Moolenaar {
85563d9e730SBram Moolenaar // draw the vertical separator right of this window
856071d4279SBram Moolenaar c = fillchar_vsep(&hl);
857071d4279SBram Moolenaar screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
858071d4279SBram Moolenaar W_ENDCOL(wp), W_ENDCOL(wp) + 1,
859071d4279SBram Moolenaar c, ' ', hl);
860071d4279SBram Moolenaar }
861071d4279SBram Moolenaar }
862071d4279SBram Moolenaar
863071d4279SBram Moolenaar #ifdef FEAT_WILDMENU
864baaa7e9eSBram Moolenaar static int skip_status_match_char(expand_T *xp, char_u *s);
865071d4279SBram Moolenaar
866071d4279SBram Moolenaar /*
867367329baSBram Moolenaar * Get the length of an item as it will be shown in the status line.
868071d4279SBram Moolenaar */
869071d4279SBram Moolenaar static int
status_match_len(expand_T * xp,char_u * s)87005540976SBram Moolenaar status_match_len(expand_T *xp, char_u *s)
871071d4279SBram Moolenaar {
872071d4279SBram Moolenaar int len = 0;
873071d4279SBram Moolenaar
874071d4279SBram Moolenaar #ifdef FEAT_MENU
875071d4279SBram Moolenaar int emenu = (xp->xp_context == EXPAND_MENUS
876071d4279SBram Moolenaar || xp->xp_context == EXPAND_MENUNAMES);
877071d4279SBram Moolenaar
87863d9e730SBram Moolenaar // Check for menu separators - replace with '|'.
879071d4279SBram Moolenaar if (emenu && menu_is_separator(s))
880071d4279SBram Moolenaar return 1;
881071d4279SBram Moolenaar #endif
882071d4279SBram Moolenaar
883071d4279SBram Moolenaar while (*s != NUL)
884071d4279SBram Moolenaar {
8857693ec6eSBram Moolenaar s += skip_status_match_char(xp, s);
88681695250SBram Moolenaar len += ptr2cells(s);
88791acfffcSBram Moolenaar MB_PTR_ADV(s);
888071d4279SBram Moolenaar }
889071d4279SBram Moolenaar
890071d4279SBram Moolenaar return len;
891071d4279SBram Moolenaar }
892071d4279SBram Moolenaar
893071d4279SBram Moolenaar /*
8947693ec6eSBram Moolenaar * Return the number of characters that should be skipped in a status match.
89535c54e56SBram Moolenaar * These are backslashes used for escaping. Do show backslashes in help tags.
89635c54e56SBram Moolenaar */
89735c54e56SBram Moolenaar static int
skip_status_match_char(expand_T * xp,char_u * s)89805540976SBram Moolenaar skip_status_match_char(expand_T *xp, char_u *s)
89935c54e56SBram Moolenaar {
9007693ec6eSBram Moolenaar if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
90135c54e56SBram Moolenaar #ifdef FEAT_MENU
90235c54e56SBram Moolenaar || ((xp->xp_context == EXPAND_MENUS
90335c54e56SBram Moolenaar || xp->xp_context == EXPAND_MENUNAMES)
90435c54e56SBram Moolenaar && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
90535c54e56SBram Moolenaar #endif
9067693ec6eSBram Moolenaar )
9077693ec6eSBram Moolenaar {
9087693ec6eSBram Moolenaar #ifndef BACKSLASH_IN_FILENAME
9097693ec6eSBram Moolenaar if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
9107693ec6eSBram Moolenaar return 2;
9117693ec6eSBram Moolenaar #endif
9127693ec6eSBram Moolenaar return 1;
9137693ec6eSBram Moolenaar }
9147693ec6eSBram Moolenaar return 0;
91535c54e56SBram Moolenaar }
91635c54e56SBram Moolenaar
91735c54e56SBram Moolenaar /*
918071d4279SBram Moolenaar * Show wildchar matches in the status line.
919071d4279SBram Moolenaar * Show at least the "match" item.
920071d4279SBram Moolenaar * We start at item 'first_match' in the list and show all matches that fit.
921071d4279SBram Moolenaar *
922071d4279SBram Moolenaar * If inversion is possible we use it. Else '=' characters are used.
923071d4279SBram Moolenaar */
924071d4279SBram Moolenaar void
win_redr_status_matches(expand_T * xp,int num_matches,char_u ** matches,int match,int showtail)92505540976SBram Moolenaar win_redr_status_matches(
92605540976SBram Moolenaar expand_T *xp,
92705540976SBram Moolenaar int num_matches,
92863d9e730SBram Moolenaar char_u **matches, // list of matches
92905540976SBram Moolenaar int match,
93005540976SBram Moolenaar int showtail)
931071d4279SBram Moolenaar {
932071d4279SBram Moolenaar #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
933071d4279SBram Moolenaar int row;
934071d4279SBram Moolenaar char_u *buf;
935071d4279SBram Moolenaar int len;
93663d9e730SBram Moolenaar int clen; // length in screen cells
937071d4279SBram Moolenaar int fillchar;
938071d4279SBram Moolenaar int attr;
939071d4279SBram Moolenaar int i;
940071d4279SBram Moolenaar int highlight = TRUE;
941071d4279SBram Moolenaar char_u *selstart = NULL;
942071d4279SBram Moolenaar int selstart_col = 0;
943071d4279SBram Moolenaar char_u *selend = NULL;
944071d4279SBram Moolenaar static int first_match = 0;
945071d4279SBram Moolenaar int add_left = FALSE;
946071d4279SBram Moolenaar char_u *s;
947071d4279SBram Moolenaar #ifdef FEAT_MENU
948071d4279SBram Moolenaar int emenu;
949071d4279SBram Moolenaar #endif
950071d4279SBram Moolenaar int l;
951071d4279SBram Moolenaar
95263d9e730SBram Moolenaar if (matches == NULL) // interrupted completion?
953071d4279SBram Moolenaar return;
954071d4279SBram Moolenaar
9551cd871b5SBram Moolenaar if (has_mbyte)
956964b3746SBram Moolenaar buf = alloc(Columns * MB_MAXBYTES + 1);
9571cd871b5SBram Moolenaar else
958964b3746SBram Moolenaar buf = alloc(Columns + 1);
959071d4279SBram Moolenaar if (buf == NULL)
960071d4279SBram Moolenaar return;
961071d4279SBram Moolenaar
96263d9e730SBram Moolenaar if (match == -1) // don't show match but original text
963071d4279SBram Moolenaar {
964071d4279SBram Moolenaar match = 0;
965071d4279SBram Moolenaar highlight = FALSE;
966071d4279SBram Moolenaar }
96763d9e730SBram Moolenaar // count 1 for the ending ">"
968071d4279SBram Moolenaar clen = status_match_len(xp, L_MATCH(match)) + 3;
969071d4279SBram Moolenaar if (match == 0)
970071d4279SBram Moolenaar first_match = 0;
971071d4279SBram Moolenaar else if (match < first_match)
972071d4279SBram Moolenaar {
97363d9e730SBram Moolenaar // jumping left, as far as we can go
974071d4279SBram Moolenaar first_match = match;
975071d4279SBram Moolenaar add_left = TRUE;
976071d4279SBram Moolenaar }
977071d4279SBram Moolenaar else
978071d4279SBram Moolenaar {
97963d9e730SBram Moolenaar // check if match fits on the screen
980071d4279SBram Moolenaar for (i = first_match; i < match; ++i)
981071d4279SBram Moolenaar clen += status_match_len(xp, L_MATCH(i)) + 2;
982071d4279SBram Moolenaar if (first_match > 0)
983071d4279SBram Moolenaar clen += 2;
98463d9e730SBram Moolenaar // jumping right, put match at the left
985071d4279SBram Moolenaar if ((long)clen > Columns)
986071d4279SBram Moolenaar {
987071d4279SBram Moolenaar first_match = match;
98863d9e730SBram Moolenaar // if showing the last match, we can add some on the left
989071d4279SBram Moolenaar clen = 2;
990071d4279SBram Moolenaar for (i = match; i < num_matches; ++i)
991071d4279SBram Moolenaar {
992071d4279SBram Moolenaar clen += status_match_len(xp, L_MATCH(i)) + 2;
993071d4279SBram Moolenaar if ((long)clen >= Columns)
994071d4279SBram Moolenaar break;
995071d4279SBram Moolenaar }
996071d4279SBram Moolenaar if (i == num_matches)
997071d4279SBram Moolenaar add_left = TRUE;
998071d4279SBram Moolenaar }
999071d4279SBram Moolenaar }
1000071d4279SBram Moolenaar if (add_left)
1001071d4279SBram Moolenaar while (first_match > 0)
1002071d4279SBram Moolenaar {
1003071d4279SBram Moolenaar clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
1004071d4279SBram Moolenaar if ((long)clen >= Columns)
1005071d4279SBram Moolenaar break;
1006071d4279SBram Moolenaar --first_match;
1007071d4279SBram Moolenaar }
1008071d4279SBram Moolenaar
10093633cf52SBram Moolenaar fillchar = fillchar_status(&attr, curwin);
1010071d4279SBram Moolenaar
1011071d4279SBram Moolenaar if (first_match == 0)
1012071d4279SBram Moolenaar {
1013071d4279SBram Moolenaar *buf = NUL;
1014071d4279SBram Moolenaar len = 0;
1015071d4279SBram Moolenaar }
1016071d4279SBram Moolenaar else
1017071d4279SBram Moolenaar {
1018071d4279SBram Moolenaar STRCPY(buf, "< ");
1019071d4279SBram Moolenaar len = 2;
1020071d4279SBram Moolenaar }
1021071d4279SBram Moolenaar clen = len;
1022071d4279SBram Moolenaar
1023071d4279SBram Moolenaar i = first_match;
1024071d4279SBram Moolenaar while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
1025071d4279SBram Moolenaar {
1026071d4279SBram Moolenaar if (i == match)
1027071d4279SBram Moolenaar {
1028071d4279SBram Moolenaar selstart = buf + len;
1029071d4279SBram Moolenaar selstart_col = clen;
1030071d4279SBram Moolenaar }
1031071d4279SBram Moolenaar
1032071d4279SBram Moolenaar s = L_MATCH(i);
103363d9e730SBram Moolenaar // Check for menu separators - replace with '|'
1034071d4279SBram Moolenaar #ifdef FEAT_MENU
1035071d4279SBram Moolenaar emenu = (xp->xp_context == EXPAND_MENUS
1036071d4279SBram Moolenaar || xp->xp_context == EXPAND_MENUNAMES);
1037071d4279SBram Moolenaar if (emenu && menu_is_separator(s))
1038071d4279SBram Moolenaar {
1039071d4279SBram Moolenaar STRCPY(buf + len, transchar('|'));
1040071d4279SBram Moolenaar l = (int)STRLEN(buf + len);
1041071d4279SBram Moolenaar len += l;
1042071d4279SBram Moolenaar clen += l;
1043071d4279SBram Moolenaar }
1044071d4279SBram Moolenaar else
1045071d4279SBram Moolenaar #endif
1046071d4279SBram Moolenaar for ( ; *s != NUL; ++s)
1047071d4279SBram Moolenaar {
10487693ec6eSBram Moolenaar s += skip_status_match_char(xp, s);
1049071d4279SBram Moolenaar clen += ptr2cells(s);
10500fa313a7SBram Moolenaar if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
1051071d4279SBram Moolenaar {
1052071d4279SBram Moolenaar STRNCPY(buf + len, s, l);
1053071d4279SBram Moolenaar s += l - 1;
1054071d4279SBram Moolenaar len += l;
1055071d4279SBram Moolenaar }
1056071d4279SBram Moolenaar else
1057071d4279SBram Moolenaar {
1058071d4279SBram Moolenaar STRCPY(buf + len, transchar_byte(*s));
1059071d4279SBram Moolenaar len += (int)STRLEN(buf + len);
1060071d4279SBram Moolenaar }
1061071d4279SBram Moolenaar }
1062071d4279SBram Moolenaar if (i == match)
1063071d4279SBram Moolenaar selend = buf + len;
1064071d4279SBram Moolenaar
1065071d4279SBram Moolenaar *(buf + len++) = ' ';
1066071d4279SBram Moolenaar *(buf + len++) = ' ';
1067071d4279SBram Moolenaar clen += 2;
1068071d4279SBram Moolenaar if (++i == num_matches)
1069071d4279SBram Moolenaar break;
1070071d4279SBram Moolenaar }
1071071d4279SBram Moolenaar
1072071d4279SBram Moolenaar if (i != num_matches)
1073071d4279SBram Moolenaar {
1074071d4279SBram Moolenaar *(buf + len++) = '>';
1075071d4279SBram Moolenaar ++clen;
1076071d4279SBram Moolenaar }
1077071d4279SBram Moolenaar
1078071d4279SBram Moolenaar buf[len] = NUL;
1079071d4279SBram Moolenaar
1080071d4279SBram Moolenaar row = cmdline_row - 1;
1081071d4279SBram Moolenaar if (row >= 0)
1082071d4279SBram Moolenaar {
1083071d4279SBram Moolenaar if (wild_menu_showing == 0)
1084071d4279SBram Moolenaar {
1085071d4279SBram Moolenaar if (msg_scrolled > 0)
1086071d4279SBram Moolenaar {
108763d9e730SBram Moolenaar // Put the wildmenu just above the command line. If there is
108863d9e730SBram Moolenaar // no room, scroll the screen one line up.
1089071d4279SBram Moolenaar if (cmdline_row == Rows - 1)
1090071d4279SBram Moolenaar {
1091cfce7171SBram Moolenaar screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
1092071d4279SBram Moolenaar ++msg_scrolled;
1093071d4279SBram Moolenaar }
1094071d4279SBram Moolenaar else
1095071d4279SBram Moolenaar {
1096071d4279SBram Moolenaar ++cmdline_row;
1097071d4279SBram Moolenaar ++row;
1098071d4279SBram Moolenaar }
1099071d4279SBram Moolenaar wild_menu_showing = WM_SCROLLED;
1100071d4279SBram Moolenaar }
1101071d4279SBram Moolenaar else
1102071d4279SBram Moolenaar {
110363d9e730SBram Moolenaar // Create status line if needed by setting 'laststatus' to 2.
110463d9e730SBram Moolenaar // Set 'winminheight' to zero to avoid that the window is
110563d9e730SBram Moolenaar // resized.
1106071d4279SBram Moolenaar if (lastwin->w_status_height == 0)
1107071d4279SBram Moolenaar {
1108071d4279SBram Moolenaar save_p_ls = p_ls;
1109071d4279SBram Moolenaar save_p_wmh = p_wmh;
1110071d4279SBram Moolenaar p_ls = 2;
1111071d4279SBram Moolenaar p_wmh = 0;
1112071d4279SBram Moolenaar last_status(FALSE);
1113071d4279SBram Moolenaar }
1114071d4279SBram Moolenaar wild_menu_showing = WM_SHOWN;
1115071d4279SBram Moolenaar }
1116071d4279SBram Moolenaar }
1117071d4279SBram Moolenaar
1118071d4279SBram Moolenaar screen_puts(buf, row, 0, attr);
1119071d4279SBram Moolenaar if (selstart != NULL && highlight)
1120071d4279SBram Moolenaar {
1121071d4279SBram Moolenaar *selend = NUL;
11228820b486SBram Moolenaar screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
1123071d4279SBram Moolenaar }
1124071d4279SBram Moolenaar
1125071d4279SBram Moolenaar screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
1126071d4279SBram Moolenaar }
1127071d4279SBram Moolenaar
1128071d4279SBram Moolenaar win_redraw_last_status(topframe);
1129071d4279SBram Moolenaar vim_free(buf);
1130071d4279SBram Moolenaar }
1131071d4279SBram Moolenaar #endif
1132071d4279SBram Moolenaar
1133071d4279SBram Moolenaar /*
1134071d4279SBram Moolenaar * Return TRUE if the status line of window "wp" is connected to the status
1135071d4279SBram Moolenaar * line of the window right of it. If not, then it's a vertical separator.
1136071d4279SBram Moolenaar * Only call if (wp->w_vsep_width != 0).
1137071d4279SBram Moolenaar */
1138071d4279SBram Moolenaar int
stl_connected(win_T * wp)113905540976SBram Moolenaar stl_connected(win_T *wp)
1140071d4279SBram Moolenaar {
1141071d4279SBram Moolenaar frame_T *fr;
1142071d4279SBram Moolenaar
1143071d4279SBram Moolenaar fr = wp->w_frame;
1144071d4279SBram Moolenaar while (fr->fr_parent != NULL)
1145071d4279SBram Moolenaar {
1146071d4279SBram Moolenaar if (fr->fr_parent->fr_layout == FR_COL)
1147071d4279SBram Moolenaar {
1148071d4279SBram Moolenaar if (fr->fr_next != NULL)
1149071d4279SBram Moolenaar break;
1150071d4279SBram Moolenaar }
1151071d4279SBram Moolenaar else
1152071d4279SBram Moolenaar {
1153071d4279SBram Moolenaar if (fr->fr_next != NULL)
1154071d4279SBram Moolenaar return TRUE;
1155071d4279SBram Moolenaar }
1156071d4279SBram Moolenaar fr = fr->fr_parent;
1157071d4279SBram Moolenaar }
1158071d4279SBram Moolenaar return FALSE;
1159071d4279SBram Moolenaar }
1160071d4279SBram Moolenaar
1161071d4279SBram Moolenaar
1162071d4279SBram Moolenaar /*
1163071d4279SBram Moolenaar * Get the value to show for the language mappings, active 'keymap'.
1164071d4279SBram Moolenaar */
1165071d4279SBram Moolenaar int
get_keymap_str(win_T * wp,char_u * fmt,char_u * buf,int len)116605540976SBram Moolenaar get_keymap_str(
116705540976SBram Moolenaar win_T *wp,
116863d9e730SBram Moolenaar char_u *fmt, // format string containing one %s item
116963d9e730SBram Moolenaar char_u *buf, // buffer for the result
117063d9e730SBram Moolenaar int len) // length of buffer
1171071d4279SBram Moolenaar {
1172071d4279SBram Moolenaar char_u *p;
1173071d4279SBram Moolenaar
1174071d4279SBram Moolenaar if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
1175071d4279SBram Moolenaar return FALSE;
1176071d4279SBram Moolenaar
1177071d4279SBram Moolenaar {
1178071d4279SBram Moolenaar #ifdef FEAT_EVAL
1179071d4279SBram Moolenaar buf_T *old_curbuf = curbuf;
1180071d4279SBram Moolenaar win_T *old_curwin = curwin;
1181071d4279SBram Moolenaar char_u *s;
1182071d4279SBram Moolenaar
1183071d4279SBram Moolenaar curbuf = wp->w_buffer;
1184071d4279SBram Moolenaar curwin = wp;
118563d9e730SBram Moolenaar STRCPY(buf, "b:keymap_name"); // must be writable
1186071d4279SBram Moolenaar ++emsg_skip;
1187b171fb17SBram Moolenaar s = p = eval_to_string(buf, FALSE);
1188071d4279SBram Moolenaar --emsg_skip;
1189071d4279SBram Moolenaar curbuf = old_curbuf;
1190071d4279SBram Moolenaar curwin = old_curwin;
1191071d4279SBram Moolenaar if (p == NULL || *p == NUL)
1192071d4279SBram Moolenaar #endif
1193071d4279SBram Moolenaar {
1194071d4279SBram Moolenaar #ifdef FEAT_KEYMAP
1195071d4279SBram Moolenaar if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
1196071d4279SBram Moolenaar p = wp->w_buffer->b_p_keymap;
1197071d4279SBram Moolenaar else
1198071d4279SBram Moolenaar #endif
1199071d4279SBram Moolenaar p = (char_u *)"lang";
1200071d4279SBram Moolenaar }
120173ac0c42SBram Moolenaar if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
1202071d4279SBram Moolenaar buf[0] = NUL;
1203071d4279SBram Moolenaar #ifdef FEAT_EVAL
1204071d4279SBram Moolenaar vim_free(s);
1205071d4279SBram Moolenaar #endif
1206071d4279SBram Moolenaar }
1207071d4279SBram Moolenaar return buf[0] != NUL;
1208071d4279SBram Moolenaar }
1209071d4279SBram Moolenaar
1210071d4279SBram Moolenaar #if defined(FEAT_STL_OPT) || defined(PROTO)
1211071d4279SBram Moolenaar /*
1212faa959a8SBram Moolenaar * Redraw the status line or ruler of window "wp".
1213faa959a8SBram Moolenaar * When "wp" is NULL redraw the tab pages line from 'tabline'.
1214071d4279SBram Moolenaar */
12157528d1f6SBram Moolenaar void
win_redr_custom(win_T * wp,int draw_ruler)121605540976SBram Moolenaar win_redr_custom(
121705540976SBram Moolenaar win_T *wp,
12187528d1f6SBram Moolenaar int draw_ruler) // TRUE or FALSE
1219071d4279SBram Moolenaar {
12201d633413SBram Moolenaar static int entered = FALSE;
1221071d4279SBram Moolenaar int attr;
1222071d4279SBram Moolenaar int curattr;
1223071d4279SBram Moolenaar int row;
1224071d4279SBram Moolenaar int col = 0;
1225071d4279SBram Moolenaar int maxwidth;
1226071d4279SBram Moolenaar int width;
1227071d4279SBram Moolenaar int n;
1228071d4279SBram Moolenaar int len;
1229071d4279SBram Moolenaar int fillchar;
1230071d4279SBram Moolenaar char_u buf[MAXPATHL];
1231362f3569SBram Moolenaar char_u *stl;
1232071d4279SBram Moolenaar char_u *p;
12338133cc6bSBram Moolenaar stl_hlrec_T *hltab;
12348133cc6bSBram Moolenaar stl_hlrec_T *tabtab;
1235faa959a8SBram Moolenaar int use_sandbox = FALSE;
12366145285cSBram Moolenaar win_T *ewp;
12376145285cSBram Moolenaar int p_crb_save;
1238071d4279SBram Moolenaar
12397528d1f6SBram Moolenaar // There is a tiny chance that this gets called recursively: When
12407528d1f6SBram Moolenaar // redrawing a status line triggers redrawing the ruler or tabline.
12417528d1f6SBram Moolenaar // Avoid trouble by not allowing recursion.
12421d633413SBram Moolenaar if (entered)
12431d633413SBram Moolenaar return;
12441d633413SBram Moolenaar entered = TRUE;
12451d633413SBram Moolenaar
12467528d1f6SBram Moolenaar // setup environment for the task at hand
1247faa959a8SBram Moolenaar if (wp == NULL)
1248faa959a8SBram Moolenaar {
12497528d1f6SBram Moolenaar // Use 'tabline'. Always at the first line of the screen.
1250362f3569SBram Moolenaar stl = p_tal;
1251faa959a8SBram Moolenaar row = 0;
125265c923adSBram Moolenaar fillchar = ' ';
12538820b486SBram Moolenaar attr = HL_ATTR(HLF_TPF);
1254faa959a8SBram Moolenaar maxwidth = Columns;
1255faa959a8SBram Moolenaar # ifdef FEAT_EVAL
1256d1f56e68SBram Moolenaar use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
1257faa959a8SBram Moolenaar # endif
1258faa959a8SBram Moolenaar }
1259faa959a8SBram Moolenaar else
1260faa959a8SBram Moolenaar {
126149c51b82SBram Moolenaar row = statusline_row(wp);
12623633cf52SBram Moolenaar fillchar = fillchar_status(&attr, wp);
12630263146bSBram Moolenaar maxwidth = wp->w_width;
1264faa959a8SBram Moolenaar
12659372a11cSBram Moolenaar if (draw_ruler)
1266071d4279SBram Moolenaar {
1267362f3569SBram Moolenaar stl = p_ruf;
12687528d1f6SBram Moolenaar // advance past any leading group spec - implicit in ru_col
1269362f3569SBram Moolenaar if (*stl == '%')
1270071d4279SBram Moolenaar {
1271362f3569SBram Moolenaar if (*++stl == '-')
1272362f3569SBram Moolenaar stl++;
1273362f3569SBram Moolenaar if (atoi((char *)stl))
1274362f3569SBram Moolenaar while (VIM_ISDIGIT(*stl))
1275362f3569SBram Moolenaar stl++;
1276362f3569SBram Moolenaar if (*stl++ != '(')
1277362f3569SBram Moolenaar stl = p_ruf;
1278071d4279SBram Moolenaar }
12790263146bSBram Moolenaar col = ru_col - (Columns - wp->w_width);
12800263146bSBram Moolenaar if (col < (wp->w_width + 1) / 2)
12810263146bSBram Moolenaar col = (wp->w_width + 1) / 2;
12820263146bSBram Moolenaar maxwidth = wp->w_width - col;
1283071d4279SBram Moolenaar if (!wp->w_status_height)
1284071d4279SBram Moolenaar {
1285071d4279SBram Moolenaar row = Rows - 1;
12867528d1f6SBram Moolenaar --maxwidth; // writing in last column may cause scrolling
1287071d4279SBram Moolenaar fillchar = ' ';
1288071d4279SBram Moolenaar attr = 0;
1289071d4279SBram Moolenaar }
1290faa959a8SBram Moolenaar
1291faa959a8SBram Moolenaar # ifdef FEAT_EVAL
1292d1f56e68SBram Moolenaar use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
1293faa959a8SBram Moolenaar # endif
1294071d4279SBram Moolenaar }
1295faa959a8SBram Moolenaar else
1296faa959a8SBram Moolenaar {
1297faa959a8SBram Moolenaar if (*wp->w_p_stl != NUL)
1298362f3569SBram Moolenaar stl = wp->w_p_stl;
1299faa959a8SBram Moolenaar else
1300362f3569SBram Moolenaar stl = p_stl;
1301faa959a8SBram Moolenaar # ifdef FEAT_EVAL
1302d1f56e68SBram Moolenaar use_sandbox = was_set_insecurely((char_u *)"statusline",
1303d1f56e68SBram Moolenaar *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
1304faa959a8SBram Moolenaar # endif
1305faa959a8SBram Moolenaar }
1306faa959a8SBram Moolenaar
130753f8174eSBram Moolenaar col += wp->w_wincol;
1308faa959a8SBram Moolenaar }
1309071d4279SBram Moolenaar
1310faa959a8SBram Moolenaar if (maxwidth <= 0)
13111d633413SBram Moolenaar goto theend;
1312faa959a8SBram Moolenaar
13137528d1f6SBram Moolenaar // Temporarily reset 'cursorbind', we don't want a side effect from moving
13147528d1f6SBram Moolenaar // the cursor away and back.
13156145285cSBram Moolenaar ewp = wp == NULL ? curwin : wp;
13166145285cSBram Moolenaar p_crb_save = ewp->w_p_crb;
13176145285cSBram Moolenaar ewp->w_p_crb = FALSE;
13186145285cSBram Moolenaar
13197528d1f6SBram Moolenaar // Make a copy, because the statusline may include a function call that
13207528d1f6SBram Moolenaar // might change the option value and free the memory.
1321362f3569SBram Moolenaar stl = vim_strsave(stl);
13226145285cSBram Moolenaar width = build_stl_str_hl(ewp, buf, sizeof(buf),
1323362f3569SBram Moolenaar stl, use_sandbox,
13248133cc6bSBram Moolenaar fillchar, maxwidth, &hltab, &tabtab);
1325362f3569SBram Moolenaar vim_free(stl);
13266145285cSBram Moolenaar ewp->w_p_crb = p_crb_save;
1327071d4279SBram Moolenaar
13287528d1f6SBram Moolenaar // Make all characters printable.
13297c5676b5SBram Moolenaar p = transstr(buf);
13307c5676b5SBram Moolenaar if (p != NULL)
13317c5676b5SBram Moolenaar {
13327c5676b5SBram Moolenaar vim_strncpy(buf, p, sizeof(buf) - 1);
13337c5676b5SBram Moolenaar vim_free(p);
13347c5676b5SBram Moolenaar }
13357c5676b5SBram Moolenaar
13367528d1f6SBram Moolenaar // fill up with "fillchar"
13377c5676b5SBram Moolenaar len = (int)STRLEN(buf);
13382c4278fcSBram Moolenaar while (width < maxwidth && len < (int)sizeof(buf) - 1)
1339071d4279SBram Moolenaar {
1340071d4279SBram Moolenaar len += (*mb_char2bytes)(fillchar, buf + len);
1341071d4279SBram Moolenaar ++width;
1342071d4279SBram Moolenaar }
1343071d4279SBram Moolenaar buf[len] = NUL;
1344071d4279SBram Moolenaar
1345d1f56e68SBram Moolenaar /*
1346d1f56e68SBram Moolenaar * Draw each snippet with the specified highlighting.
1347d1f56e68SBram Moolenaar */
1348071d4279SBram Moolenaar curattr = attr;
1349071d4279SBram Moolenaar p = buf;
1350d1f56e68SBram Moolenaar for (n = 0; hltab[n].start != NULL; n++)
1351071d4279SBram Moolenaar {
1352d1f56e68SBram Moolenaar len = (int)(hltab[n].start - p);
1353071d4279SBram Moolenaar screen_puts_len(p, len, row, col, curattr);
1354071d4279SBram Moolenaar col += vim_strnsize(p, len);
1355d1f56e68SBram Moolenaar p = hltab[n].start;
1356071d4279SBram Moolenaar
1357d1f56e68SBram Moolenaar if (hltab[n].userhl == 0)
1358071d4279SBram Moolenaar curattr = attr;
1359d1f56e68SBram Moolenaar else if (hltab[n].userhl < 0)
1360d1f56e68SBram Moolenaar curattr = syn_id2attr(-hltab[n].userhl);
1361bce4f62dSBram Moolenaar #ifdef FEAT_TERMINAL
136205fbfdcdSBram Moolenaar else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
136305fbfdcdSBram Moolenaar && wp->w_status_height != 0)
136405fbfdcdSBram Moolenaar curattr = highlight_stltermnc[hltab[n].userhl - 1];
1365bce4f62dSBram Moolenaar else if (wp != NULL && bt_terminal(wp->w_buffer)
1366bce4f62dSBram Moolenaar && wp->w_status_height != 0)
1367bce4f62dSBram Moolenaar curattr = highlight_stlterm[hltab[n].userhl - 1];
1368bce4f62dSBram Moolenaar #endif
1369238a5649SBram Moolenaar else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
1370d1f56e68SBram Moolenaar curattr = highlight_stlnc[hltab[n].userhl - 1];
1371071d4279SBram Moolenaar else
1372d1f56e68SBram Moolenaar curattr = highlight_user[hltab[n].userhl - 1];
1373071d4279SBram Moolenaar }
1374071d4279SBram Moolenaar screen_puts(p, row, col, curattr);
1375d1f56e68SBram Moolenaar
1376d1f56e68SBram Moolenaar if (wp == NULL)
1377d1f56e68SBram Moolenaar {
13787528d1f6SBram Moolenaar // Fill the TabPageIdxs[] array for clicking in the tab pagesline.
1379d1f56e68SBram Moolenaar col = 0;
1380d1f56e68SBram Moolenaar len = 0;
1381d1f56e68SBram Moolenaar p = buf;
1382d1f56e68SBram Moolenaar fillchar = 0;
1383d1f56e68SBram Moolenaar for (n = 0; tabtab[n].start != NULL; n++)
1384d1f56e68SBram Moolenaar {
1385d1f56e68SBram Moolenaar len += vim_strnsize(p, (int)(tabtab[n].start - p));
1386d1f56e68SBram Moolenaar while (col < len)
1387d1f56e68SBram Moolenaar TabPageIdxs[col++] = fillchar;
1388d1f56e68SBram Moolenaar p = tabtab[n].start;
1389d1f56e68SBram Moolenaar fillchar = tabtab[n].userhl;
1390d1f56e68SBram Moolenaar }
1391d1f56e68SBram Moolenaar while (col < Columns)
1392d1f56e68SBram Moolenaar TabPageIdxs[col++] = fillchar;
1393d1f56e68SBram Moolenaar }
13941d633413SBram Moolenaar
13951d633413SBram Moolenaar theend:
13961d633413SBram Moolenaar entered = FALSE;
1397071d4279SBram Moolenaar }
1398071d4279SBram Moolenaar
13997528d1f6SBram Moolenaar #endif // FEAT_STL_OPT
1400071d4279SBram Moolenaar
1401071d4279SBram Moolenaar /*
1402071d4279SBram Moolenaar * Output a single character directly to the screen and update ScreenLines.
1403071d4279SBram Moolenaar */
1404071d4279SBram Moolenaar void
screen_putchar(int c,int row,int col,int attr)140505540976SBram Moolenaar screen_putchar(int c, int row, int col, int attr)
1406071d4279SBram Moolenaar {
1407071d4279SBram Moolenaar char_u buf[MB_MAXBYTES + 1];
1408071d4279SBram Moolenaar
14099a920d8cSBram Moolenaar if (has_mbyte)
1410071d4279SBram Moolenaar buf[(*mb_char2bytes)(c, buf)] = NUL;
14119a920d8cSBram Moolenaar else
14129a920d8cSBram Moolenaar {
1413071d4279SBram Moolenaar buf[0] = c;
1414071d4279SBram Moolenaar buf[1] = NUL;
14159a920d8cSBram Moolenaar }
1416071d4279SBram Moolenaar screen_puts(buf, row, col, attr);
1417071d4279SBram Moolenaar }
1418071d4279SBram Moolenaar
1419071d4279SBram Moolenaar /*
1420071d4279SBram Moolenaar * Get a single character directly from ScreenLines into "bytes[]".
1421071d4279SBram Moolenaar * Also return its attribute in *attrp;
1422071d4279SBram Moolenaar */
1423071d4279SBram Moolenaar void
screen_getbytes(int row,int col,char_u * bytes,int * attrp)142405540976SBram Moolenaar screen_getbytes(int row, int col, char_u *bytes, int *attrp)
1425071d4279SBram Moolenaar {
1426071d4279SBram Moolenaar unsigned off;
1427071d4279SBram Moolenaar
14287528d1f6SBram Moolenaar // safety check
1429071d4279SBram Moolenaar if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
1430071d4279SBram Moolenaar {
1431071d4279SBram Moolenaar off = LineOffset[row] + col;
1432071d4279SBram Moolenaar *attrp = ScreenAttrs[off];
1433071d4279SBram Moolenaar bytes[0] = ScreenLines[off];
1434071d4279SBram Moolenaar bytes[1] = NUL;
1435071d4279SBram Moolenaar
1436071d4279SBram Moolenaar if (enc_utf8 && ScreenLinesUC[off] != 0)
1437071d4279SBram Moolenaar bytes[utfc_char2bytes(off, bytes)] = NUL;
1438071d4279SBram Moolenaar else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
1439071d4279SBram Moolenaar {
1440071d4279SBram Moolenaar bytes[0] = ScreenLines[off];
1441071d4279SBram Moolenaar bytes[1] = ScreenLines2[off];
1442071d4279SBram Moolenaar bytes[2] = NUL;
1443071d4279SBram Moolenaar }
1444071d4279SBram Moolenaar else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
1445071d4279SBram Moolenaar {
1446071d4279SBram Moolenaar bytes[1] = ScreenLines[off + 1];
1447071d4279SBram Moolenaar bytes[2] = NUL;
1448071d4279SBram Moolenaar }
1449071d4279SBram Moolenaar }
1450071d4279SBram Moolenaar }
1451071d4279SBram Moolenaar
1452362e1a30SBram Moolenaar /*
1453362e1a30SBram Moolenaar * Return TRUE if composing characters for screen posn "off" differs from
1454362e1a30SBram Moolenaar * composing characters in "u8cc".
145570c49c1aSBram Moolenaar * Only to be used when ScreenLinesUC[off] != 0.
1456362e1a30SBram Moolenaar */
1457362e1a30SBram Moolenaar static int
screen_comp_differs(int off,int * u8cc)145805540976SBram Moolenaar screen_comp_differs(int off, int *u8cc)
1459362e1a30SBram Moolenaar {
1460362e1a30SBram Moolenaar int i;
1461362e1a30SBram Moolenaar
1462362e1a30SBram Moolenaar for (i = 0; i < Screen_mco; ++i)
1463362e1a30SBram Moolenaar {
1464362e1a30SBram Moolenaar if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
1465362e1a30SBram Moolenaar return TRUE;
1466362e1a30SBram Moolenaar if (u8cc[i] == 0)
1467362e1a30SBram Moolenaar break;
1468362e1a30SBram Moolenaar }
1469362e1a30SBram Moolenaar return FALSE;
1470362e1a30SBram Moolenaar }
1471362e1a30SBram Moolenaar
1472071d4279SBram Moolenaar /*
1473071d4279SBram Moolenaar * Put string '*text' on the screen at position 'row' and 'col', with
1474071d4279SBram Moolenaar * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
1475071d4279SBram Moolenaar * Note: only outputs within one row, message is truncated at screen boundary!
1476071d4279SBram Moolenaar * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
1477071d4279SBram Moolenaar */
1478071d4279SBram Moolenaar void
screen_puts(char_u * text,int row,int col,int attr)147905540976SBram Moolenaar screen_puts(
148005540976SBram Moolenaar char_u *text,
148105540976SBram Moolenaar int row,
148205540976SBram Moolenaar int col,
148305540976SBram Moolenaar int attr)
1484071d4279SBram Moolenaar {
1485071d4279SBram Moolenaar screen_puts_len(text, -1, row, col, attr);
1486071d4279SBram Moolenaar }
1487071d4279SBram Moolenaar
1488071d4279SBram Moolenaar /*
1489071d4279SBram Moolenaar * Like screen_puts(), but output "text[len]". When "len" is -1 output up to
1490071d4279SBram Moolenaar * a NUL.
1491071d4279SBram Moolenaar */
1492071d4279SBram Moolenaar void
screen_puts_len(char_u * text,int textlen,int row,int col,int attr)149305540976SBram Moolenaar screen_puts_len(
149405540976SBram Moolenaar char_u *text,
149505540976SBram Moolenaar int textlen,
149605540976SBram Moolenaar int row,
149705540976SBram Moolenaar int col,
149805540976SBram Moolenaar int attr)
1499071d4279SBram Moolenaar {
1500071d4279SBram Moolenaar unsigned off;
1501071d4279SBram Moolenaar char_u *ptr = text;
1502e4c21e68SBram Moolenaar int len = textlen;
1503071d4279SBram Moolenaar int c;
1504367329baSBram Moolenaar unsigned max_off;
1505071d4279SBram Moolenaar int mbyte_blen = 1;
1506071d4279SBram Moolenaar int mbyte_cells = 1;
1507071d4279SBram Moolenaar int u8c = 0;
1508362e1a30SBram Moolenaar int u8cc[MAX_MCO];
1509071d4279SBram Moolenaar int clear_next_cell = FALSE;
1510071d4279SBram Moolenaar #ifdef FEAT_ARABIC
15117528d1f6SBram Moolenaar int prev_c = 0; // previous Arabic character
1512362e1a30SBram Moolenaar int pc, nc, nc1;
1513362e1a30SBram Moolenaar int pcc[MAX_MCO];
1514071d4279SBram Moolenaar #endif
15152bea291aSBram Moolenaar int force_redraw_this;
15162bea291aSBram Moolenaar int force_redraw_next = FALSE;
15172bea291aSBram Moolenaar int need_redraw;
1518071d4279SBram Moolenaar
15190b4c9eddSBram Moolenaar // Safety check. The check for negative row and column is to fix issue
15200b4c9eddSBram Moolenaar // #4102. TODO: find out why row/col could be negative.
15210b4c9eddSBram Moolenaar if (ScreenLines == NULL
15220b4c9eddSBram Moolenaar || row >= screen_Rows || row < 0
15230b4c9eddSBram Moolenaar || col >= screen_Columns || col < 0)
1524071d4279SBram Moolenaar return;
15252bea291aSBram Moolenaar off = LineOffset[row] + col;
1526071d4279SBram Moolenaar
15277528d1f6SBram Moolenaar // When drawing over the right halve of a double-wide char clear out the
15287528d1f6SBram Moolenaar // left halve. Only needed in a terminal.
15297693ec6eSBram Moolenaar if (has_mbyte && col > 0 && col < screen_Columns
1530c236c16dSBram Moolenaar #ifdef FEAT_GUI
1531c236c16dSBram Moolenaar && !gui.in_use
1532c236c16dSBram Moolenaar #endif
1533c236c16dSBram Moolenaar && mb_fix_col(col, row) != col)
15342bea291aSBram Moolenaar {
15352bea291aSBram Moolenaar ScreenLines[off - 1] = ' ';
15362bea291aSBram Moolenaar ScreenAttrs[off - 1] = 0;
15372bea291aSBram Moolenaar if (enc_utf8)
15382bea291aSBram Moolenaar {
15392bea291aSBram Moolenaar ScreenLinesUC[off - 1] = 0;
15402bea291aSBram Moolenaar ScreenLinesC[0][off - 1] = 0;
15412bea291aSBram Moolenaar }
15427528d1f6SBram Moolenaar // redraw the previous cell, make it empty
15432bea291aSBram Moolenaar screen_char(off - 1, row, col - 1);
15447528d1f6SBram Moolenaar // force the cell at "col" to be redrawn
15452bea291aSBram Moolenaar force_redraw_next = TRUE;
15462bea291aSBram Moolenaar }
1547c236c16dSBram Moolenaar
1548367329baSBram Moolenaar max_off = LineOffset[row] + screen_Columns;
1549a064ac85SBram Moolenaar while (col < screen_Columns
1550a064ac85SBram Moolenaar && (len < 0 || (int)(ptr - text) < len)
1551a064ac85SBram Moolenaar && *ptr != NUL)
1552071d4279SBram Moolenaar {
1553071d4279SBram Moolenaar c = *ptr;
155463d9e730SBram Moolenaar // check if this is the first byte of a multibyte
1555071d4279SBram Moolenaar if (has_mbyte)
1556071d4279SBram Moolenaar {
1557071d4279SBram Moolenaar if (enc_utf8 && len > 0)
15580fa313a7SBram Moolenaar mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
1559071d4279SBram Moolenaar else
15600fa313a7SBram Moolenaar mbyte_blen = (*mb_ptr2len)(ptr);
1561071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1562071d4279SBram Moolenaar mbyte_cells = 1;
1563071d4279SBram Moolenaar else if (enc_dbcs != 0)
1564071d4279SBram Moolenaar mbyte_cells = mbyte_blen;
156563d9e730SBram Moolenaar else // enc_utf8
1566071d4279SBram Moolenaar {
1567071d4279SBram Moolenaar if (len >= 0)
1568362e1a30SBram Moolenaar u8c = utfc_ptr2char_len(ptr, u8cc,
1569071d4279SBram Moolenaar (int)((text + len) - ptr));
1570071d4279SBram Moolenaar else
1571362e1a30SBram Moolenaar u8c = utfc_ptr2char(ptr, u8cc);
1572071d4279SBram Moolenaar mbyte_cells = utf_char2cells(u8c);
1573071d4279SBram Moolenaar #ifdef FEAT_ARABIC
1574071d4279SBram Moolenaar if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
1575071d4279SBram Moolenaar {
157663d9e730SBram Moolenaar // Do Arabic shaping.
1577071d4279SBram Moolenaar if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
1578071d4279SBram Moolenaar {
157963d9e730SBram Moolenaar // Past end of string to be displayed.
1580071d4279SBram Moolenaar nc = NUL;
1581071d4279SBram Moolenaar nc1 = NUL;
1582071d4279SBram Moolenaar }
1583071d4279SBram Moolenaar else
1584362e1a30SBram Moolenaar {
158554620188SBram Moolenaar nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
158654620188SBram Moolenaar (int)((text + len) - ptr - mbyte_blen));
1587362e1a30SBram Moolenaar nc1 = pcc[0];
1588362e1a30SBram Moolenaar }
1589071d4279SBram Moolenaar pc = prev_c;
1590071d4279SBram Moolenaar prev_c = u8c;
1591362e1a30SBram Moolenaar u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
1592071d4279SBram Moolenaar }
1593071d4279SBram Moolenaar else
1594071d4279SBram Moolenaar prev_c = u8c;
1595071d4279SBram Moolenaar #endif
1596e4ebd29eSBram Moolenaar if (col + mbyte_cells > screen_Columns)
1597e4ebd29eSBram Moolenaar {
159863d9e730SBram Moolenaar // Only 1 cell left, but character requires 2 cells:
159963d9e730SBram Moolenaar // display a '>' in the last column to avoid wrapping.
1600e4ebd29eSBram Moolenaar c = '>';
1601e4ebd29eSBram Moolenaar mbyte_cells = 1;
1602e4ebd29eSBram Moolenaar }
1603071d4279SBram Moolenaar }
1604071d4279SBram Moolenaar }
1605071d4279SBram Moolenaar
16062bea291aSBram Moolenaar force_redraw_this = force_redraw_next;
16072bea291aSBram Moolenaar force_redraw_next = FALSE;
16082bea291aSBram Moolenaar
16092bea291aSBram Moolenaar need_redraw = ScreenLines[off] != c
1610071d4279SBram Moolenaar || (mbyte_cells == 2
1611071d4279SBram Moolenaar && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
1612071d4279SBram Moolenaar || (enc_dbcs == DBCS_JPNU
1613071d4279SBram Moolenaar && c == 0x8e
1614071d4279SBram Moolenaar && ScreenLines2[off] != ptr[1])
1615071d4279SBram Moolenaar || (enc_utf8
161670c49c1aSBram Moolenaar && (ScreenLinesUC[off] !=
161770c49c1aSBram Moolenaar (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
161870c49c1aSBram Moolenaar || (ScreenLinesUC[off] != 0
161970c49c1aSBram Moolenaar && screen_comp_differs(off, u8cc))))
1620071d4279SBram Moolenaar || ScreenAttrs[off] != attr
16212bea291aSBram Moolenaar || exmode_active;
16222bea291aSBram Moolenaar
162324a5ac5dSBram Moolenaar if ((need_redraw || force_redraw_this)
162405ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
1625c662ec99SBram Moolenaar && !blocked_by_popup(row, col)
162624a5ac5dSBram Moolenaar #endif
162724a5ac5dSBram Moolenaar )
1628071d4279SBram Moolenaar {
1629071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
163063d9e730SBram Moolenaar // The bold trick makes a single row of pixels appear in the next
163163d9e730SBram Moolenaar // character. When a bold character is removed, the next
163263d9e730SBram Moolenaar // character should be redrawn too. This happens for our own GUI
163363d9e730SBram Moolenaar // and for some xterms.
16342bea291aSBram Moolenaar if (need_redraw && ScreenLines[off] != ' ' && (
1635071d4279SBram Moolenaar # ifdef FEAT_GUI
1636071d4279SBram Moolenaar gui.in_use
1637071d4279SBram Moolenaar # endif
1638071d4279SBram Moolenaar # if defined(FEAT_GUI) && defined(UNIX)
1639071d4279SBram Moolenaar ||
1640071d4279SBram Moolenaar # endif
1641071d4279SBram Moolenaar # ifdef UNIX
1642071d4279SBram Moolenaar term_is_xterm
1643071d4279SBram Moolenaar # endif
16442bea291aSBram Moolenaar ))
1645071d4279SBram Moolenaar {
16462bea291aSBram Moolenaar int n = ScreenAttrs[off];
1647071d4279SBram Moolenaar
16482bea291aSBram Moolenaar if (n > HL_ALL)
16492bea291aSBram Moolenaar n = syn_attr2attr(n);
16502bea291aSBram Moolenaar if (n & HL_BOLD)
16512bea291aSBram Moolenaar force_redraw_next = TRUE;
1652071d4279SBram Moolenaar }
1653071d4279SBram Moolenaar #endif
165463d9e730SBram Moolenaar // When at the end of the text and overwriting a two-cell
165563d9e730SBram Moolenaar // character with a one-cell character, need to clear the next
165663d9e730SBram Moolenaar // cell. Also when overwriting the left halve of a two-cell char
165763d9e730SBram Moolenaar // with the right halve of a two-cell char. Do this only once
165863d9e730SBram Moolenaar // (mb_off2cells() may return 2 on the right halve).
1659071d4279SBram Moolenaar if (clear_next_cell)
1660071d4279SBram Moolenaar clear_next_cell = FALSE;
1661071d4279SBram Moolenaar else if (has_mbyte
1662071d4279SBram Moolenaar && (len < 0 ? ptr[mbyte_blen] == NUL
1663071d4279SBram Moolenaar : ptr + mbyte_blen >= text + len)
1664367329baSBram Moolenaar && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
1665071d4279SBram Moolenaar || (mbyte_cells == 2
1666367329baSBram Moolenaar && (*mb_off2cells)(off, max_off) == 1
1667367329baSBram Moolenaar && (*mb_off2cells)(off + 1, max_off) > 1)))
1668071d4279SBram Moolenaar clear_next_cell = TRUE;
1669071d4279SBram Moolenaar
167063d9e730SBram Moolenaar // Make sure we never leave a second byte of a double-byte behind,
167163d9e730SBram Moolenaar // it confuses mb_off2cells().
1672071d4279SBram Moolenaar if (enc_dbcs
1673367329baSBram Moolenaar && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
1674071d4279SBram Moolenaar || (mbyte_cells == 2
1675367329baSBram Moolenaar && (*mb_off2cells)(off, max_off) == 1
1676367329baSBram Moolenaar && (*mb_off2cells)(off + 1, max_off) > 1)))
1677071d4279SBram Moolenaar ScreenLines[off + mbyte_blen] = 0;
1678071d4279SBram Moolenaar ScreenLines[off] = c;
1679071d4279SBram Moolenaar ScreenAttrs[off] = attr;
1680071d4279SBram Moolenaar if (enc_utf8)
1681071d4279SBram Moolenaar {
1682362e1a30SBram Moolenaar if (c < 0x80 && u8cc[0] == 0)
1683071d4279SBram Moolenaar ScreenLinesUC[off] = 0;
1684071d4279SBram Moolenaar else
1685071d4279SBram Moolenaar {
1686362e1a30SBram Moolenaar int i;
1687362e1a30SBram Moolenaar
1688071d4279SBram Moolenaar ScreenLinesUC[off] = u8c;
1689362e1a30SBram Moolenaar for (i = 0; i < Screen_mco; ++i)
1690362e1a30SBram Moolenaar {
1691362e1a30SBram Moolenaar ScreenLinesC[i][off] = u8cc[i];
1692362e1a30SBram Moolenaar if (u8cc[i] == 0)
1693362e1a30SBram Moolenaar break;
1694362e1a30SBram Moolenaar }
1695071d4279SBram Moolenaar }
1696071d4279SBram Moolenaar if (mbyte_cells == 2)
1697071d4279SBram Moolenaar {
1698071d4279SBram Moolenaar ScreenLines[off + 1] = 0;
1699071d4279SBram Moolenaar ScreenAttrs[off + 1] = attr;
1700071d4279SBram Moolenaar }
1701071d4279SBram Moolenaar screen_char(off, row, col);
1702071d4279SBram Moolenaar }
1703071d4279SBram Moolenaar else if (mbyte_cells == 2)
1704071d4279SBram Moolenaar {
1705071d4279SBram Moolenaar ScreenLines[off + 1] = ptr[1];
1706071d4279SBram Moolenaar ScreenAttrs[off + 1] = attr;
1707071d4279SBram Moolenaar screen_char_2(off, row, col);
1708071d4279SBram Moolenaar }
1709071d4279SBram Moolenaar else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1710071d4279SBram Moolenaar {
1711071d4279SBram Moolenaar ScreenLines2[off] = ptr[1];
1712071d4279SBram Moolenaar screen_char(off, row, col);
1713071d4279SBram Moolenaar }
1714071d4279SBram Moolenaar else
1715071d4279SBram Moolenaar screen_char(off, row, col);
1716071d4279SBram Moolenaar }
1717071d4279SBram Moolenaar if (has_mbyte)
1718071d4279SBram Moolenaar {
1719071d4279SBram Moolenaar off += mbyte_cells;
1720071d4279SBram Moolenaar col += mbyte_cells;
1721071d4279SBram Moolenaar ptr += mbyte_blen;
1722071d4279SBram Moolenaar if (clear_next_cell)
1723e4c21e68SBram Moolenaar {
172463d9e730SBram Moolenaar // This only happens at the end, display one space next.
1725071d4279SBram Moolenaar ptr = (char_u *)" ";
1726e4c21e68SBram Moolenaar len = -1;
1727e4c21e68SBram Moolenaar }
1728071d4279SBram Moolenaar }
1729071d4279SBram Moolenaar else
1730071d4279SBram Moolenaar {
1731071d4279SBram Moolenaar ++off;
1732071d4279SBram Moolenaar ++col;
1733071d4279SBram Moolenaar ++ptr;
1734071d4279SBram Moolenaar }
1735071d4279SBram Moolenaar }
17362bea291aSBram Moolenaar
173763d9e730SBram Moolenaar // If we detected the next character needs to be redrawn, but the text
173863d9e730SBram Moolenaar // doesn't extend up to there, update the character here.
17392bea291aSBram Moolenaar if (force_redraw_next && col < screen_Columns)
17402bea291aSBram Moolenaar {
17412bea291aSBram Moolenaar if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
17422bea291aSBram Moolenaar screen_char_2(off, row, col);
17432bea291aSBram Moolenaar else
17442bea291aSBram Moolenaar screen_char(off, row, col);
17452bea291aSBram Moolenaar }
1746071d4279SBram Moolenaar }
1747071d4279SBram Moolenaar
17487528d1f6SBram Moolenaar #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
1749071d4279SBram Moolenaar /*
17506ee10162SBram Moolenaar * Prepare for 'hlsearch' highlighting.
1751071d4279SBram Moolenaar */
17527528d1f6SBram Moolenaar void
start_search_hl(void)175305540976SBram Moolenaar start_search_hl(void)
1754071d4279SBram Moolenaar {
1755071d4279SBram Moolenaar if (p_hls && !no_hlsearch)
1756071d4279SBram Moolenaar {
17570b6849e9SBram Moolenaar end_search_hl(); // just in case it wasn't called before
17587528d1f6SBram Moolenaar last_pat_prog(&screen_search_hl.rm);
17597528d1f6SBram Moolenaar screen_search_hl.attr = HL_ATTR(HLF_L);
176091a4e822SBram Moolenaar # ifdef FEAT_RELTIME
176163d9e730SBram Moolenaar // Set the time limit to 'redrawtime'.
17627528d1f6SBram Moolenaar profile_setlimit(p_rdt, &screen_search_hl.tm);
176391a4e822SBram Moolenaar # endif
1764071d4279SBram Moolenaar }
1765071d4279SBram Moolenaar }
1766071d4279SBram Moolenaar
1767071d4279SBram Moolenaar /*
17686ee10162SBram Moolenaar * Clean up for 'hlsearch' highlighting.
1769071d4279SBram Moolenaar */
17707528d1f6SBram Moolenaar void
end_search_hl(void)177105540976SBram Moolenaar end_search_hl(void)
1772071d4279SBram Moolenaar {
17737528d1f6SBram Moolenaar if (screen_search_hl.rm.regprog != NULL)
1774071d4279SBram Moolenaar {
17757528d1f6SBram Moolenaar vim_regfree(screen_search_hl.rm.regprog);
17767528d1f6SBram Moolenaar screen_search_hl.rm.regprog = NULL;
1777071d4279SBram Moolenaar }
1778071d4279SBram Moolenaar }
1779de993ea6SBram Moolenaar #endif
1780b3414595SBram Moolenaar
1781071d4279SBram Moolenaar static void
screen_start_highlight(int attr)178205540976SBram Moolenaar screen_start_highlight(int attr)
1783071d4279SBram Moolenaar {
1784071d4279SBram Moolenaar attrentry_T *aep = NULL;
1785071d4279SBram Moolenaar
1786071d4279SBram Moolenaar screen_attr = attr;
1787071d4279SBram Moolenaar if (full_screen
17884f97475dSBram Moolenaar #ifdef MSWIN
1789071d4279SBram Moolenaar && termcap_active
1790071d4279SBram Moolenaar #endif
1791071d4279SBram Moolenaar )
1792071d4279SBram Moolenaar {
1793071d4279SBram Moolenaar #ifdef FEAT_GUI
1794071d4279SBram Moolenaar if (gui.in_use)
1795071d4279SBram Moolenaar {
1796071d4279SBram Moolenaar char buf[20];
1797071d4279SBram Moolenaar
179863d9e730SBram Moolenaar // The GUI handles this internally.
1799d1f56e68SBram Moolenaar sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
1800071d4279SBram Moolenaar OUT_STR(buf);
1801071d4279SBram Moolenaar }
1802071d4279SBram Moolenaar else
1803071d4279SBram Moolenaar #endif
1804071d4279SBram Moolenaar {
180563d9e730SBram Moolenaar if (attr > HL_ALL) // special HL attr.
1806071d4279SBram Moolenaar {
18078a633e34SBram Moolenaar if (IS_CTERM)
1808071d4279SBram Moolenaar aep = syn_cterm_attr2entry(attr);
1809071d4279SBram Moolenaar else
1810071d4279SBram Moolenaar aep = syn_term_attr2entry(attr);
181163d9e730SBram Moolenaar if (aep == NULL) // did ":syntax clear"
1812071d4279SBram Moolenaar attr = 0;
1813071d4279SBram Moolenaar else
1814071d4279SBram Moolenaar attr = aep->ae_attr;
1815071d4279SBram Moolenaar }
1816a050b947SBram Moolenaar #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1817a050b947SBram Moolenaar if (use_vtp())
1818a050b947SBram Moolenaar {
1819a050b947SBram Moolenaar guicolor_T defguifg, defguibg;
1820a050b947SBram Moolenaar int defctermfg, defctermbg;
1821a050b947SBram Moolenaar
1822a050b947SBram Moolenaar // If FG and BG are unset, the color is undefined when
1823a050b947SBram Moolenaar // BOLD+INVERSE. Use Normal as the default value.
1824a050b947SBram Moolenaar get_default_console_color(&defctermfg, &defctermbg, &defguifg,
1825a050b947SBram Moolenaar &defguibg);
1826a050b947SBram Moolenaar
1827a050b947SBram Moolenaar if (p_tgc)
1828a050b947SBram Moolenaar {
1829a050b947SBram Moolenaar if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.fg_rgb))
1830a050b947SBram Moolenaar term_fg_rgb_color(defguifg);
1831a050b947SBram Moolenaar if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.bg_rgb))
1832a050b947SBram Moolenaar term_bg_rgb_color(defguibg);
1833a050b947SBram Moolenaar }
1834a050b947SBram Moolenaar else if (t_colors >= 256)
1835a050b947SBram Moolenaar {
1836a050b947SBram Moolenaar if (aep == NULL || aep->ae_u.cterm.fg_color == 0)
1837a050b947SBram Moolenaar term_fg_color(defctermfg);
1838a050b947SBram Moolenaar if (aep == NULL || aep->ae_u.cterm.bg_color == 0)
1839a050b947SBram Moolenaar term_bg_color(defctermbg);
1840a050b947SBram Moolenaar }
1841a050b947SBram Moolenaar }
1842a050b947SBram Moolenaar #endif
184363d9e730SBram Moolenaar if ((attr & HL_BOLD) && *T_MD != NUL) // bold
1844071d4279SBram Moolenaar out_str(T_MD);
1845d4fc577eSBram Moolenaar else if (aep != NULL && cterm_normal_fg_bold && (
184661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1847d4fc577eSBram Moolenaar p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1848d4fc577eSBram Moolenaar ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
1849d4fc577eSBram Moolenaar :
18508a633e34SBram Moolenaar #endif
1851d4fc577eSBram Moolenaar t_colors > 1 && aep->ae_u.cterm.fg_color))
185263d9e730SBram Moolenaar // If the Normal FG color has BOLD attribute and the new HL
185363d9e730SBram Moolenaar // has a FG color defined, clear BOLD.
1854d1f56e68SBram Moolenaar out_str(T_ME);
185563d9e730SBram Moolenaar if ((attr & HL_STANDOUT) && *T_SO != NUL) // standout
1856071d4279SBram Moolenaar out_str(T_SO);
185763d9e730SBram Moolenaar if ((attr & HL_UNDERCURL) && *T_UCS != NUL) // undercurl
18588b9e20afSBram Moolenaar out_str(T_UCS);
185963d9e730SBram Moolenaar if (((attr & HL_UNDERLINE) // underline or undercurl
186045a0000dSBram Moolenaar || ((attr & HL_UNDERCURL) && *T_UCS == NUL))
186145a0000dSBram Moolenaar && *T_US != NUL)
1862071d4279SBram Moolenaar out_str(T_US);
186363d9e730SBram Moolenaar if ((attr & HL_ITALIC) && *T_CZH != NUL) // italic
1864071d4279SBram Moolenaar out_str(T_CZH);
186563d9e730SBram Moolenaar if ((attr & HL_INVERSE) && *T_MR != NUL) // inverse (reverse)
1866071d4279SBram Moolenaar out_str(T_MR);
186763d9e730SBram Moolenaar if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) // strike
1868cf4b00c8SBram Moolenaar out_str(T_STS);
1869071d4279SBram Moolenaar
1870071d4279SBram Moolenaar /*
1871071d4279SBram Moolenaar * Output the color or start string after bold etc., in case the
1872071d4279SBram Moolenaar * bold etc. override the color setting.
1873071d4279SBram Moolenaar */
1874071d4279SBram Moolenaar if (aep != NULL)
1875071d4279SBram Moolenaar {
187661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
187763d9e730SBram Moolenaar // When 'termguicolors' is set but fg or bg is unset,
187863d9e730SBram Moolenaar // fall back to the cterm colors. This helps for SpellBad,
187963d9e730SBram Moolenaar // where the GUI uses a red undercurl.
1880d4fc577eSBram Moolenaar if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
18818a633e34SBram Moolenaar {
18821b58cdd1SBram Moolenaar if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
18838a633e34SBram Moolenaar term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
1884d4fc577eSBram Moolenaar }
1885d4fc577eSBram Moolenaar else
1886d4fc577eSBram Moolenaar #endif
1887d4fc577eSBram Moolenaar if (t_colors > 1)
1888d4fc577eSBram Moolenaar {
1889d4fc577eSBram Moolenaar if (aep->ae_u.cterm.fg_color)
1890d4fc577eSBram Moolenaar term_fg_color(aep->ae_u.cterm.fg_color - 1);
1891d4fc577eSBram Moolenaar }
1892d4fc577eSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1893d4fc577eSBram Moolenaar if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
1894d4fc577eSBram Moolenaar {
18951b58cdd1SBram Moolenaar if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
18968a633e34SBram Moolenaar term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
18978a633e34SBram Moolenaar }
18988a633e34SBram Moolenaar else
18998a633e34SBram Moolenaar #endif
1900071d4279SBram Moolenaar if (t_colors > 1)
1901071d4279SBram Moolenaar {
1902071d4279SBram Moolenaar if (aep->ae_u.cterm.bg_color)
1903071d4279SBram Moolenaar term_bg_color(aep->ae_u.cterm.bg_color - 1);
1904071d4279SBram Moolenaar }
1905e023e88bSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1906e023e88bSBram Moolenaar if (p_tgc && aep->ae_u.cterm.ul_rgb != CTERMCOLOR)
1907e023e88bSBram Moolenaar {
1908e023e88bSBram Moolenaar if (aep->ae_u.cterm.ul_rgb != INVALCOLOR)
1909e023e88bSBram Moolenaar term_ul_rgb_color(aep->ae_u.cterm.ul_rgb);
1910e023e88bSBram Moolenaar }
1911e023e88bSBram Moolenaar else
1912e023e88bSBram Moolenaar #endif
1913e023e88bSBram Moolenaar if (t_colors > 1)
1914e023e88bSBram Moolenaar {
1915e023e88bSBram Moolenaar if (aep->ae_u.cterm.ul_color)
1916e023e88bSBram Moolenaar term_ul_color(aep->ae_u.cterm.ul_color - 1);
1917e023e88bSBram Moolenaar }
1918d4fc577eSBram Moolenaar
1919f708ac59SBram Moolenaar if (!IS_CTERM)
1920071d4279SBram Moolenaar {
1921071d4279SBram Moolenaar if (aep->ae_u.term.start != NULL)
1922071d4279SBram Moolenaar out_str(aep->ae_u.term.start);
1923071d4279SBram Moolenaar }
1924071d4279SBram Moolenaar }
1925071d4279SBram Moolenaar }
1926071d4279SBram Moolenaar }
1927071d4279SBram Moolenaar }
1928071d4279SBram Moolenaar
1929071d4279SBram Moolenaar void
screen_stop_highlight(void)193005540976SBram Moolenaar screen_stop_highlight(void)
1931071d4279SBram Moolenaar {
193263d9e730SBram Moolenaar int do_ME = FALSE; // output T_ME code
19334e5534faSBram Moolenaar #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
193409307e3bSBram Moolenaar int do_ME_fg = FALSE, do_ME_bg = FALSE;
19354e5534faSBram Moolenaar #endif
1936071d4279SBram Moolenaar
1937071d4279SBram Moolenaar if (screen_attr != 0
19384f97475dSBram Moolenaar #ifdef MSWIN
1939071d4279SBram Moolenaar && termcap_active
1940071d4279SBram Moolenaar #endif
1941071d4279SBram Moolenaar )
1942071d4279SBram Moolenaar {
1943071d4279SBram Moolenaar #ifdef FEAT_GUI
1944071d4279SBram Moolenaar if (gui.in_use)
1945071d4279SBram Moolenaar {
1946071d4279SBram Moolenaar char buf[20];
1947071d4279SBram Moolenaar
194863d9e730SBram Moolenaar // use internal GUI code
1949071d4279SBram Moolenaar sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
1950071d4279SBram Moolenaar OUT_STR(buf);
1951071d4279SBram Moolenaar }
1952071d4279SBram Moolenaar else
1953071d4279SBram Moolenaar #endif
1954071d4279SBram Moolenaar {
195563d9e730SBram Moolenaar if (screen_attr > HL_ALL) // special HL attr.
1956071d4279SBram Moolenaar {
1957071d4279SBram Moolenaar attrentry_T *aep;
1958071d4279SBram Moolenaar
19598a633e34SBram Moolenaar if (IS_CTERM)
1960071d4279SBram Moolenaar {
1961071d4279SBram Moolenaar /*
1962071d4279SBram Moolenaar * Assume that t_me restores the original colors!
1963071d4279SBram Moolenaar */
1964071d4279SBram Moolenaar aep = syn_cterm_attr2entry(screen_attr);
1965d4fc577eSBram Moolenaar if (aep != NULL && ((
196661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1967d4fc577eSBram Moolenaar p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1968d4fc577eSBram Moolenaar ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
19694e5534faSBram Moolenaar # ifdef FEAT_VTP
19704e5534faSBram Moolenaar ? !(do_ME_fg = TRUE) : (do_ME_fg = FALSE)
19714e5534faSBram Moolenaar # endif
1972d4fc577eSBram Moolenaar :
19738a633e34SBram Moolenaar #endif
1974d4fc577eSBram Moolenaar aep->ae_u.cterm.fg_color) || (
197561be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1976d4fc577eSBram Moolenaar p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
1977d4fc577eSBram Moolenaar ? aep->ae_u.cterm.bg_rgb != INVALCOLOR
19784e5534faSBram Moolenaar # ifdef FEAT_VTP
19794e5534faSBram Moolenaar ? !(do_ME_bg = TRUE) : (do_ME_bg = FALSE)
19804e5534faSBram Moolenaar # endif
1981d4fc577eSBram Moolenaar :
19828a633e34SBram Moolenaar #endif
1983d4fc577eSBram Moolenaar aep->ae_u.cterm.bg_color)))
1984071d4279SBram Moolenaar do_ME = TRUE;
19854e5534faSBram Moolenaar #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
19864e5534faSBram Moolenaar if (use_vtp())
19874e5534faSBram Moolenaar {
19884e5534faSBram Moolenaar if (do_ME_fg && do_ME_bg)
19894e5534faSBram Moolenaar do_ME = TRUE;
19904e5534faSBram Moolenaar
19914e5534faSBram Moolenaar // FG and BG cannot be separated in T_ME, which is not
19924e5534faSBram Moolenaar // efficient.
19934e5534faSBram Moolenaar if (!do_ME && do_ME_fg)
19944e5534faSBram Moolenaar out_str((char_u *)"\033|39m"); // restore FG
19954e5534faSBram Moolenaar if (!do_ME && do_ME_bg)
19964e5534faSBram Moolenaar out_str((char_u *)"\033|49m"); // restore BG
19974e5534faSBram Moolenaar }
19984e5534faSBram Moolenaar else
19994e5534faSBram Moolenaar {
20004e5534faSBram Moolenaar // Process FG and BG at once.
20014e5534faSBram Moolenaar if (!do_ME)
20024e5534faSBram Moolenaar do_ME = do_ME_fg | do_ME_bg;
20034e5534faSBram Moolenaar }
20044e5534faSBram Moolenaar #endif
2005071d4279SBram Moolenaar }
2006071d4279SBram Moolenaar else
2007071d4279SBram Moolenaar {
2008071d4279SBram Moolenaar aep = syn_term_attr2entry(screen_attr);
2009071d4279SBram Moolenaar if (aep != NULL && aep->ae_u.term.stop != NULL)
2010071d4279SBram Moolenaar {
2011071d4279SBram Moolenaar if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
2012071d4279SBram Moolenaar do_ME = TRUE;
2013071d4279SBram Moolenaar else
2014071d4279SBram Moolenaar out_str(aep->ae_u.term.stop);
2015071d4279SBram Moolenaar }
2016071d4279SBram Moolenaar }
201763d9e730SBram Moolenaar if (aep == NULL) // did ":syntax clear"
2018071d4279SBram Moolenaar screen_attr = 0;
2019071d4279SBram Moolenaar else
2020071d4279SBram Moolenaar screen_attr = aep->ae_attr;
2021071d4279SBram Moolenaar }
2022071d4279SBram Moolenaar
2023071d4279SBram Moolenaar /*
2024071d4279SBram Moolenaar * Often all ending-codes are equal to T_ME. Avoid outputting the
2025071d4279SBram Moolenaar * same sequence several times.
2026071d4279SBram Moolenaar */
2027071d4279SBram Moolenaar if (screen_attr & HL_STANDOUT)
2028071d4279SBram Moolenaar {
2029071d4279SBram Moolenaar if (STRCMP(T_SE, T_ME) == 0)
2030071d4279SBram Moolenaar do_ME = TRUE;
2031071d4279SBram Moolenaar else
2032071d4279SBram Moolenaar out_str(T_SE);
2033071d4279SBram Moolenaar }
203445a0000dSBram Moolenaar if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
20358b9e20afSBram Moolenaar {
20368b9e20afSBram Moolenaar if (STRCMP(T_UCE, T_ME) == 0)
20378b9e20afSBram Moolenaar do_ME = TRUE;
20388b9e20afSBram Moolenaar else
20398b9e20afSBram Moolenaar out_str(T_UCE);
20408b9e20afSBram Moolenaar }
20418b9e20afSBram Moolenaar if ((screen_attr & HL_UNDERLINE)
204245a0000dSBram Moolenaar || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
2043071d4279SBram Moolenaar {
2044071d4279SBram Moolenaar if (STRCMP(T_UE, T_ME) == 0)
2045071d4279SBram Moolenaar do_ME = TRUE;
2046071d4279SBram Moolenaar else
2047071d4279SBram Moolenaar out_str(T_UE);
2048071d4279SBram Moolenaar }
2049071d4279SBram Moolenaar if (screen_attr & HL_ITALIC)
2050071d4279SBram Moolenaar {
2051071d4279SBram Moolenaar if (STRCMP(T_CZR, T_ME) == 0)
2052071d4279SBram Moolenaar do_ME = TRUE;
2053071d4279SBram Moolenaar else
2054071d4279SBram Moolenaar out_str(T_CZR);
2055071d4279SBram Moolenaar }
2056cf4b00c8SBram Moolenaar if (screen_attr & HL_STRIKETHROUGH)
2057cf4b00c8SBram Moolenaar {
2058cf4b00c8SBram Moolenaar if (STRCMP(T_STE, T_ME) == 0)
2059cf4b00c8SBram Moolenaar do_ME = TRUE;
2060cf4b00c8SBram Moolenaar else
2061cf4b00c8SBram Moolenaar out_str(T_STE);
2062cf4b00c8SBram Moolenaar }
2063071d4279SBram Moolenaar if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
2064071d4279SBram Moolenaar out_str(T_ME);
2065071d4279SBram Moolenaar
206661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
206761be73bbSBram Moolenaar if (p_tgc)
20688a633e34SBram Moolenaar {
20691b58cdd1SBram Moolenaar if (cterm_normal_fg_gui_color != INVALCOLOR)
20708a633e34SBram Moolenaar term_fg_rgb_color(cterm_normal_fg_gui_color);
20711b58cdd1SBram Moolenaar if (cterm_normal_bg_gui_color != INVALCOLOR)
20728a633e34SBram Moolenaar term_bg_rgb_color(cterm_normal_bg_gui_color);
2073e023e88bSBram Moolenaar if (cterm_normal_ul_gui_color != INVALCOLOR)
2074e023e88bSBram Moolenaar term_ul_rgb_color(cterm_normal_ul_gui_color);
20758a633e34SBram Moolenaar }
20768a633e34SBram Moolenaar else
20778a633e34SBram Moolenaar #endif
20788a633e34SBram Moolenaar {
2079071d4279SBram Moolenaar if (t_colors > 1)
2080071d4279SBram Moolenaar {
208163d9e730SBram Moolenaar // set Normal cterm colors
2082071d4279SBram Moolenaar if (cterm_normal_fg_color != 0)
2083071d4279SBram Moolenaar term_fg_color(cterm_normal_fg_color - 1);
2084071d4279SBram Moolenaar if (cterm_normal_bg_color != 0)
2085071d4279SBram Moolenaar term_bg_color(cterm_normal_bg_color - 1);
2086e023e88bSBram Moolenaar if (cterm_normal_ul_color != 0)
2087e023e88bSBram Moolenaar term_ul_color(cterm_normal_ul_color - 1);
2088071d4279SBram Moolenaar if (cterm_normal_fg_bold)
2089071d4279SBram Moolenaar out_str(T_MD);
2090071d4279SBram Moolenaar }
2091071d4279SBram Moolenaar }
2092071d4279SBram Moolenaar }
20938a633e34SBram Moolenaar }
2094071d4279SBram Moolenaar screen_attr = 0;
2095071d4279SBram Moolenaar }
2096071d4279SBram Moolenaar
2097071d4279SBram Moolenaar /*
2098071d4279SBram Moolenaar * Reset the colors for a cterm. Used when leaving Vim.
2099071d4279SBram Moolenaar * The machine specific code may override this again.
2100071d4279SBram Moolenaar */
2101071d4279SBram Moolenaar void
reset_cterm_colors(void)210205540976SBram Moolenaar reset_cterm_colors(void)
2103071d4279SBram Moolenaar {
21048a633e34SBram Moolenaar if (IS_CTERM)
2105071d4279SBram Moolenaar {
210663d9e730SBram Moolenaar // set Normal cterm colors
210761be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
21081b58cdd1SBram Moolenaar if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
21091b58cdd1SBram Moolenaar || cterm_normal_bg_gui_color != INVALCOLOR)
21101b58cdd1SBram Moolenaar : (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
21118a633e34SBram Moolenaar #else
2112071d4279SBram Moolenaar if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
21138a633e34SBram Moolenaar #endif
2114071d4279SBram Moolenaar {
2115071d4279SBram Moolenaar out_str(T_OP);
2116071d4279SBram Moolenaar screen_attr = -1;
2117071d4279SBram Moolenaar }
2118071d4279SBram Moolenaar if (cterm_normal_fg_bold)
2119071d4279SBram Moolenaar {
2120071d4279SBram Moolenaar out_str(T_ME);
2121071d4279SBram Moolenaar screen_attr = -1;
2122071d4279SBram Moolenaar }
2123071d4279SBram Moolenaar }
2124071d4279SBram Moolenaar }
2125071d4279SBram Moolenaar
2126071d4279SBram Moolenaar /*
2127071d4279SBram Moolenaar * Put character ScreenLines["off"] on the screen at position "row" and "col",
2128071d4279SBram Moolenaar * using the attributes from ScreenAttrs["off"].
2129071d4279SBram Moolenaar */
21307528d1f6SBram Moolenaar void
screen_char(unsigned off,int row,int col)213105540976SBram Moolenaar screen_char(unsigned off, int row, int col)
2132071d4279SBram Moolenaar {
2133071d4279SBram Moolenaar int attr;
2134071d4279SBram Moolenaar
213563d9e730SBram Moolenaar // Check for illegal values, just in case (could happen just after
213663d9e730SBram Moolenaar // resizing).
2137071d4279SBram Moolenaar if (row >= screen_Rows || col >= screen_Columns)
2138071d4279SBram Moolenaar return;
2139071d4279SBram Moolenaar
214033796b39SBram Moolenaar // Skip if under the popup menu.
214133796b39SBram Moolenaar // Popup windows with zindex higher than POPUPMENU_ZINDEX go on top.
2142*6555500bSBakudankun if (pum_under_menu(row, col, TRUE)
214305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
214433796b39SBram Moolenaar && screen_zindex <= POPUPMENU_ZINDEX
214533796b39SBram Moolenaar #endif
214633796b39SBram Moolenaar )
2147ae654385SBram Moolenaar return;
214805ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
2149c662ec99SBram Moolenaar if (blocked_by_popup(row, col))
215033796b39SBram Moolenaar return;
215133796b39SBram Moolenaar #endif
215233796b39SBram Moolenaar
215363d9e730SBram Moolenaar // Outputting a character in the last cell on the screen may scroll the
215463d9e730SBram Moolenaar // screen up. Only do it when the "xn" termcap property is set, otherwise
215563d9e730SBram Moolenaar // mark the character invalid (update it when scrolled up).
2156494838a3SBram Moolenaar if (*T_XN == NUL
2157494838a3SBram Moolenaar && row == screen_Rows - 1 && col == screen_Columns - 1
2158071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
215963d9e730SBram Moolenaar // account for first command-line character in rightleft mode
2160071d4279SBram Moolenaar && !cmdmsg_rl
2161071d4279SBram Moolenaar #endif
2162071d4279SBram Moolenaar )
2163071d4279SBram Moolenaar {
2164071d4279SBram Moolenaar ScreenAttrs[off] = (sattr_T)-1;
2165071d4279SBram Moolenaar return;
2166071d4279SBram Moolenaar }
2167071d4279SBram Moolenaar
2168071d4279SBram Moolenaar /*
2169071d4279SBram Moolenaar * Stop highlighting first, so it's easier to move the cursor.
2170071d4279SBram Moolenaar */
2171071d4279SBram Moolenaar if (screen_char_attr != 0)
2172071d4279SBram Moolenaar attr = screen_char_attr;
2173071d4279SBram Moolenaar else
2174071d4279SBram Moolenaar attr = ScreenAttrs[off];
2175071d4279SBram Moolenaar if (screen_attr != attr)
2176071d4279SBram Moolenaar screen_stop_highlight();
2177071d4279SBram Moolenaar
2178071d4279SBram Moolenaar windgoto(row, col);
2179071d4279SBram Moolenaar
2180071d4279SBram Moolenaar if (screen_attr != attr)
2181071d4279SBram Moolenaar screen_start_highlight(attr);
2182071d4279SBram Moolenaar
2183071d4279SBram Moolenaar if (enc_utf8 && ScreenLinesUC[off] != 0)
2184071d4279SBram Moolenaar {
2185071d4279SBram Moolenaar char_u buf[MB_MAXBYTES + 1];
2186071d4279SBram Moolenaar
2187cb070084SBram Moolenaar if (utf_ambiguous_width(ScreenLinesUC[off]))
2188fae8ed1fSBram Moolenaar {
2189fae8ed1fSBram Moolenaar if (*p_ambw == 'd'
2190fae8ed1fSBram Moolenaar #ifdef FEAT_GUI
2191fae8ed1fSBram Moolenaar && !gui.in_use
2192fae8ed1fSBram Moolenaar #endif
2193fae8ed1fSBram Moolenaar )
2194fae8ed1fSBram Moolenaar {
219563d9e730SBram Moolenaar // Clear the two screen cells. If the character is actually
219663d9e730SBram Moolenaar // single width it won't change the second cell.
2197fae8ed1fSBram Moolenaar out_str((char_u *)" ");
2198fae8ed1fSBram Moolenaar term_windgoto(row, col);
2199fae8ed1fSBram Moolenaar }
220063d9e730SBram Moolenaar // not sure where the cursor is after drawing the ambiguous width
220163d9e730SBram Moolenaar // character
2202cb070084SBram Moolenaar screen_cur_col = 9999;
2203fae8ed1fSBram Moolenaar }
2204cb070084SBram Moolenaar else if (utf_char2cells(ScreenLinesUC[off]) > 1)
2205071d4279SBram Moolenaar ++screen_cur_col;
2206fae8ed1fSBram Moolenaar
220763d9e730SBram Moolenaar // Convert the UTF-8 character to bytes and write it.
2208fae8ed1fSBram Moolenaar buf[utfc_char2bytes(off, buf)] = NUL;
2209fae8ed1fSBram Moolenaar out_str(buf);
2210071d4279SBram Moolenaar }
2211071d4279SBram Moolenaar else
2212071d4279SBram Moolenaar {
2213071d4279SBram Moolenaar out_flush_check();
2214071d4279SBram Moolenaar out_char(ScreenLines[off]);
221563d9e730SBram Moolenaar // double-byte character in single-width cell
2216071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
2217071d4279SBram Moolenaar out_char(ScreenLines2[off]);
2218071d4279SBram Moolenaar }
2219071d4279SBram Moolenaar
2220071d4279SBram Moolenaar screen_cur_col++;
2221071d4279SBram Moolenaar }
2222071d4279SBram Moolenaar
2223071d4279SBram Moolenaar /*
2224071d4279SBram Moolenaar * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
2225071d4279SBram Moolenaar * on the screen at position 'row' and 'col'.
2226071d4279SBram Moolenaar * The attributes of the first byte is used for all. This is required to
2227071d4279SBram Moolenaar * output the two bytes of a double-byte character with nothing in between.
2228071d4279SBram Moolenaar */
2229071d4279SBram Moolenaar static void
screen_char_2(unsigned off,int row,int col)223005540976SBram Moolenaar screen_char_2(unsigned off, int row, int col)
2231071d4279SBram Moolenaar {
223263d9e730SBram Moolenaar // Check for illegal values (could be wrong when screen was resized).
2233071d4279SBram Moolenaar if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
2234071d4279SBram Moolenaar return;
2235071d4279SBram Moolenaar
223663d9e730SBram Moolenaar // Outputting the last character on the screen may scrollup the screen.
223763d9e730SBram Moolenaar // Don't to it! Mark the character invalid (update it when scrolled up)
2238071d4279SBram Moolenaar if (row == screen_Rows - 1 && col >= screen_Columns - 2)
2239071d4279SBram Moolenaar {
2240071d4279SBram Moolenaar ScreenAttrs[off] = (sattr_T)-1;
2241071d4279SBram Moolenaar return;
2242071d4279SBram Moolenaar }
2243071d4279SBram Moolenaar
224463d9e730SBram Moolenaar // Output the first byte normally (positions the cursor), then write the
224563d9e730SBram Moolenaar // second byte directly.
2246071d4279SBram Moolenaar screen_char(off, row, col);
2247071d4279SBram Moolenaar out_char(ScreenLines[off + 1]);
2248071d4279SBram Moolenaar ++screen_cur_col;
2249071d4279SBram Moolenaar }
2250071d4279SBram Moolenaar
2251071d4279SBram Moolenaar /*
2252071d4279SBram Moolenaar * Draw a rectangle of the screen, inverted when "invert" is TRUE.
2253071d4279SBram Moolenaar * This uses the contents of ScreenLines[] and doesn't change it.
2254071d4279SBram Moolenaar */
2255071d4279SBram Moolenaar void
screen_draw_rectangle(int row,int col,int height,int width,int invert)225605540976SBram Moolenaar screen_draw_rectangle(
225705540976SBram Moolenaar int row,
225805540976SBram Moolenaar int col,
225905540976SBram Moolenaar int height,
226005540976SBram Moolenaar int width,
226105540976SBram Moolenaar int invert)
2262071d4279SBram Moolenaar {
2263071d4279SBram Moolenaar int r, c;
2264071d4279SBram Moolenaar int off;
2265367329baSBram Moolenaar int max_off;
2266071d4279SBram Moolenaar
226763d9e730SBram Moolenaar // Can't use ScreenLines unless initialized
2268482aaeb0SBram Moolenaar if (ScreenLines == NULL)
2269482aaeb0SBram Moolenaar return;
2270482aaeb0SBram Moolenaar
2271071d4279SBram Moolenaar if (invert)
2272071d4279SBram Moolenaar screen_char_attr = HL_INVERSE;
2273071d4279SBram Moolenaar for (r = row; r < row + height; ++r)
2274071d4279SBram Moolenaar {
2275071d4279SBram Moolenaar off = LineOffset[r];
2276367329baSBram Moolenaar max_off = off + screen_Columns;
2277071d4279SBram Moolenaar for (c = col; c < col + width; ++c)
2278071d4279SBram Moolenaar {
2279367329baSBram Moolenaar if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
2280071d4279SBram Moolenaar {
2281071d4279SBram Moolenaar screen_char_2(off + c, r, c);
2282071d4279SBram Moolenaar ++c;
2283071d4279SBram Moolenaar }
2284071d4279SBram Moolenaar else
2285071d4279SBram Moolenaar {
2286071d4279SBram Moolenaar screen_char(off + c, r, c);
2287367329baSBram Moolenaar if (utf_off2cells(off + c, max_off) > 1)
2288071d4279SBram Moolenaar ++c;
2289071d4279SBram Moolenaar }
2290071d4279SBram Moolenaar }
2291071d4279SBram Moolenaar }
2292071d4279SBram Moolenaar screen_char_attr = 0;
2293071d4279SBram Moolenaar }
2294071d4279SBram Moolenaar
2295071d4279SBram Moolenaar /*
2296071d4279SBram Moolenaar * Redraw the characters for a vertically split window.
2297071d4279SBram Moolenaar */
2298071d4279SBram Moolenaar static void
redraw_block(int row,int end,win_T * wp)229905540976SBram Moolenaar redraw_block(int row, int end, win_T *wp)
2300071d4279SBram Moolenaar {
2301071d4279SBram Moolenaar int col;
2302071d4279SBram Moolenaar int width;
2303071d4279SBram Moolenaar
2304071d4279SBram Moolenaar # ifdef FEAT_CLIPBOARD
2305071d4279SBram Moolenaar clip_may_clear_selection(row, end - 1);
2306071d4279SBram Moolenaar # endif
2307071d4279SBram Moolenaar
2308071d4279SBram Moolenaar if (wp == NULL)
2309071d4279SBram Moolenaar {
2310071d4279SBram Moolenaar col = 0;
2311071d4279SBram Moolenaar width = Columns;
2312071d4279SBram Moolenaar }
2313071d4279SBram Moolenaar else
2314071d4279SBram Moolenaar {
2315071d4279SBram Moolenaar col = wp->w_wincol;
2316071d4279SBram Moolenaar width = wp->w_width;
2317071d4279SBram Moolenaar }
2318071d4279SBram Moolenaar screen_draw_rectangle(row, col, end - row, width, FALSE);
2319071d4279SBram Moolenaar }
2320071d4279SBram Moolenaar
23217528d1f6SBram Moolenaar void
space_to_screenline(int off,int attr)23221b9645deSBram Moolenaar space_to_screenline(int off, int attr)
23231b9645deSBram Moolenaar {
23241b9645deSBram Moolenaar ScreenLines[off] = ' ';
23251b9645deSBram Moolenaar ScreenAttrs[off] = attr;
23261b9645deSBram Moolenaar if (enc_utf8)
23271b9645deSBram Moolenaar ScreenLinesUC[off] = 0;
23281b9645deSBram Moolenaar }
23291b9645deSBram Moolenaar
2330071d4279SBram Moolenaar /*
2331071d4279SBram Moolenaar * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
2332071d4279SBram Moolenaar * with character 'c1' in first column followed by 'c2' in the other columns.
2333071d4279SBram Moolenaar * Use attributes 'attr'.
2334071d4279SBram Moolenaar */
2335071d4279SBram Moolenaar void
screen_fill(int start_row,int end_row,int start_col,int end_col,int c1,int c2,int attr)233605540976SBram Moolenaar screen_fill(
233705540976SBram Moolenaar int start_row,
233805540976SBram Moolenaar int end_row,
233905540976SBram Moolenaar int start_col,
234005540976SBram Moolenaar int end_col,
234105540976SBram Moolenaar int c1,
234205540976SBram Moolenaar int c2,
234305540976SBram Moolenaar int attr)
2344071d4279SBram Moolenaar {
2345071d4279SBram Moolenaar int row;
2346071d4279SBram Moolenaar int col;
2347071d4279SBram Moolenaar int off;
2348071d4279SBram Moolenaar int end_off;
2349071d4279SBram Moolenaar int did_delete;
2350071d4279SBram Moolenaar int c;
2351071d4279SBram Moolenaar int norm_term;
2352071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
2353071d4279SBram Moolenaar int force_next = FALSE;
2354071d4279SBram Moolenaar #endif
2355071d4279SBram Moolenaar
235663d9e730SBram Moolenaar if (end_row > screen_Rows) // safety check
2357071d4279SBram Moolenaar end_row = screen_Rows;
235863d9e730SBram Moolenaar if (end_col > screen_Columns) // safety check
2359071d4279SBram Moolenaar end_col = screen_Columns;
2360071d4279SBram Moolenaar if (ScreenLines == NULL
2361071d4279SBram Moolenaar || start_row >= end_row
236263d9e730SBram Moolenaar || start_col >= end_col) // nothing to do
2363071d4279SBram Moolenaar return;
2364071d4279SBram Moolenaar
236563d9e730SBram Moolenaar // it's a "normal" terminal when not in a GUI or cterm
2366071d4279SBram Moolenaar norm_term = (
2367071d4279SBram Moolenaar #ifdef FEAT_GUI
2368071d4279SBram Moolenaar !gui.in_use &&
2369071d4279SBram Moolenaar #endif
23708a633e34SBram Moolenaar !IS_CTERM);
2371071d4279SBram Moolenaar for (row = start_row; row < end_row; ++row)
2372071d4279SBram Moolenaar {
2373c236c16dSBram Moolenaar if (has_mbyte
2374c236c16dSBram Moolenaar #ifdef FEAT_GUI
2375c236c16dSBram Moolenaar && !gui.in_use
2376c236c16dSBram Moolenaar #endif
2377c236c16dSBram Moolenaar )
2378c236c16dSBram Moolenaar {
237963d9e730SBram Moolenaar // When drawing over the right halve of a double-wide char clear
238063d9e730SBram Moolenaar // out the left halve. When drawing over the left halve of a
238163d9e730SBram Moolenaar // double wide-char clear out the right halve. Only needed in a
238263d9e730SBram Moolenaar // terminal.
23837693ec6eSBram Moolenaar if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
2384d91ffe98SBram Moolenaar screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
2385a1aed629SBram Moolenaar if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
2386d91ffe98SBram Moolenaar screen_puts_len((char_u *)" ", 1, row, end_col, 0);
2387c236c16dSBram Moolenaar }
2388071d4279SBram Moolenaar /*
2389071d4279SBram Moolenaar * Try to use delete-line termcap code, when no attributes or in a
2390071d4279SBram Moolenaar * "normal" terminal, where a bold/italic space is just a
2391071d4279SBram Moolenaar * space.
2392071d4279SBram Moolenaar */
2393071d4279SBram Moolenaar did_delete = FALSE;
2394071d4279SBram Moolenaar if (c2 == ' '
2395071d4279SBram Moolenaar && end_col == Columns
2396071d4279SBram Moolenaar && can_clear(T_CE)
2397071d4279SBram Moolenaar && (attr == 0
2398071d4279SBram Moolenaar || (norm_term
2399071d4279SBram Moolenaar && attr <= HL_ALL
2400071d4279SBram Moolenaar && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
2401071d4279SBram Moolenaar {
2402071d4279SBram Moolenaar /*
2403071d4279SBram Moolenaar * check if we really need to clear something
2404071d4279SBram Moolenaar */
2405071d4279SBram Moolenaar col = start_col;
240663d9e730SBram Moolenaar if (c1 != ' ') // don't clear first char
2407071d4279SBram Moolenaar ++col;
2408071d4279SBram Moolenaar
2409071d4279SBram Moolenaar off = LineOffset[row] + col;
2410071d4279SBram Moolenaar end_off = LineOffset[row] + end_col;
2411071d4279SBram Moolenaar
241263d9e730SBram Moolenaar // skip blanks (used often, keep it fast!)
2413071d4279SBram Moolenaar if (enc_utf8)
2414071d4279SBram Moolenaar while (off < end_off && ScreenLines[off] == ' '
2415071d4279SBram Moolenaar && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
2416071d4279SBram Moolenaar ++off;
2417071d4279SBram Moolenaar else
2418071d4279SBram Moolenaar while (off < end_off && ScreenLines[off] == ' '
2419071d4279SBram Moolenaar && ScreenAttrs[off] == 0)
2420071d4279SBram Moolenaar ++off;
242163d9e730SBram Moolenaar if (off < end_off) // something to be cleared
2422071d4279SBram Moolenaar {
2423071d4279SBram Moolenaar col = off - LineOffset[row];
2424071d4279SBram Moolenaar screen_stop_highlight();
242563d9e730SBram Moolenaar term_windgoto(row, col);// clear rest of this screen line
2426071d4279SBram Moolenaar out_str(T_CE);
242763d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
2428071d4279SBram Moolenaar col = end_col - col;
242963d9e730SBram Moolenaar while (col--) // clear chars in ScreenLines
2430071d4279SBram Moolenaar {
24311b9645deSBram Moolenaar space_to_screenline(off, 0);
2432071d4279SBram Moolenaar ++off;
2433071d4279SBram Moolenaar }
2434071d4279SBram Moolenaar }
243563d9e730SBram Moolenaar did_delete = TRUE; // the chars are cleared now
2436071d4279SBram Moolenaar }
2437071d4279SBram Moolenaar
2438071d4279SBram Moolenaar off = LineOffset[row] + start_col;
2439071d4279SBram Moolenaar c = c1;
2440071d4279SBram Moolenaar for (col = start_col; col < end_col; ++col)
2441071d4279SBram Moolenaar {
244233796b39SBram Moolenaar if ((ScreenLines[off] != c
2443362e1a30SBram Moolenaar || (enc_utf8 && (int)ScreenLinesUC[off]
2444362e1a30SBram Moolenaar != (c >= 0x80 ? c : 0))
2445071d4279SBram Moolenaar || ScreenAttrs[off] != attr
2446071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
2447071d4279SBram Moolenaar || force_next
2448071d4279SBram Moolenaar #endif
2449071d4279SBram Moolenaar )
245005ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
245133796b39SBram Moolenaar // Skip if under a(nother) popup.
2452c662ec99SBram Moolenaar && !blocked_by_popup(row, col)
245333796b39SBram Moolenaar #endif
245433796b39SBram Moolenaar )
2455071d4279SBram Moolenaar {
2456071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
245763d9e730SBram Moolenaar // The bold trick may make a single row of pixels appear in
245863d9e730SBram Moolenaar // the next character. When a bold character is removed, the
245963d9e730SBram Moolenaar // next character should be redrawn too. This happens for our
246063d9e730SBram Moolenaar // own GUI and for some xterms.
2461071d4279SBram Moolenaar if (
2462071d4279SBram Moolenaar # ifdef FEAT_GUI
2463071d4279SBram Moolenaar gui.in_use
2464071d4279SBram Moolenaar # endif
2465071d4279SBram Moolenaar # if defined(FEAT_GUI) && defined(UNIX)
2466071d4279SBram Moolenaar ||
2467071d4279SBram Moolenaar # endif
2468071d4279SBram Moolenaar # ifdef UNIX
2469071d4279SBram Moolenaar term_is_xterm
2470071d4279SBram Moolenaar # endif
2471071d4279SBram Moolenaar )
2472071d4279SBram Moolenaar {
2473071d4279SBram Moolenaar if (ScreenLines[off] != ' '
2474071d4279SBram Moolenaar && (ScreenAttrs[off] > HL_ALL
2475071d4279SBram Moolenaar || ScreenAttrs[off] & HL_BOLD))
2476071d4279SBram Moolenaar force_next = TRUE;
2477071d4279SBram Moolenaar else
2478071d4279SBram Moolenaar force_next = FALSE;
2479071d4279SBram Moolenaar }
2480071d4279SBram Moolenaar #endif
2481071d4279SBram Moolenaar ScreenLines[off] = c;
2482071d4279SBram Moolenaar if (enc_utf8)
2483071d4279SBram Moolenaar {
2484071d4279SBram Moolenaar if (c >= 0x80)
2485071d4279SBram Moolenaar {
2486071d4279SBram Moolenaar ScreenLinesUC[off] = c;
2487362e1a30SBram Moolenaar ScreenLinesC[0][off] = 0;
2488071d4279SBram Moolenaar }
2489071d4279SBram Moolenaar else
2490071d4279SBram Moolenaar ScreenLinesUC[off] = 0;
2491071d4279SBram Moolenaar }
2492071d4279SBram Moolenaar ScreenAttrs[off] = attr;
2493071d4279SBram Moolenaar if (!did_delete || c != ' ')
2494071d4279SBram Moolenaar screen_char(off, row, col);
2495071d4279SBram Moolenaar }
2496071d4279SBram Moolenaar ++off;
2497071d4279SBram Moolenaar if (col == start_col)
2498071d4279SBram Moolenaar {
2499071d4279SBram Moolenaar if (did_delete)
2500071d4279SBram Moolenaar break;
2501071d4279SBram Moolenaar c = c2;
2502071d4279SBram Moolenaar }
2503071d4279SBram Moolenaar }
2504071d4279SBram Moolenaar if (end_col == Columns)
2505071d4279SBram Moolenaar LineWraps[row] = FALSE;
250663d9e730SBram Moolenaar if (row == Rows - 1) // overwritten the command line
2507071d4279SBram Moolenaar {
2508071d4279SBram Moolenaar redraw_cmdline = TRUE;
25095bab555cSBram Moolenaar if (start_col == 0 && end_col == Columns
25105bab555cSBram Moolenaar && c1 == ' ' && c2 == ' ' && attr == 0)
251163d9e730SBram Moolenaar clear_cmdline = FALSE; // command line has been cleared
2512d12f5c17SBram Moolenaar if (start_col == 0)
251363d9e730SBram Moolenaar mode_displayed = FALSE; // mode cleared or overwritten
2514071d4279SBram Moolenaar }
2515071d4279SBram Moolenaar }
2516071d4279SBram Moolenaar }
2517071d4279SBram Moolenaar
2518071d4279SBram Moolenaar /*
2519071d4279SBram Moolenaar * Check if there should be a delay. Used before clearing or redrawing the
2520071d4279SBram Moolenaar * screen or the command line.
2521071d4279SBram Moolenaar */
2522071d4279SBram Moolenaar void
check_for_delay(int check_msg_scroll)252305540976SBram Moolenaar check_for_delay(int check_msg_scroll)
2524071d4279SBram Moolenaar {
2525071d4279SBram Moolenaar if ((emsg_on_display || (check_msg_scroll && msg_scroll))
2526071d4279SBram Moolenaar && !did_wait_return
252728ee892aSBram Moolenaar && emsg_silent == 0
252828ee892aSBram Moolenaar && !in_assert_fails)
2529071d4279SBram Moolenaar {
2530071d4279SBram Moolenaar out_flush();
2531eda1da0cSBram Moolenaar ui_delay(1006L, TRUE);
2532071d4279SBram Moolenaar emsg_on_display = FALSE;
2533071d4279SBram Moolenaar if (check_msg_scroll)
2534071d4279SBram Moolenaar msg_scroll = FALSE;
2535071d4279SBram Moolenaar }
2536071d4279SBram Moolenaar }
2537071d4279SBram Moolenaar
2538071d4279SBram Moolenaar /*
2539ca57ab54SBram Moolenaar * Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
2540ca57ab54SBram Moolenaar */
2541ca57ab54SBram Moolenaar static void
clear_TabPageIdxs(void)2542ca57ab54SBram Moolenaar clear_TabPageIdxs(void)
2543ca57ab54SBram Moolenaar {
2544ca57ab54SBram Moolenaar int scol;
2545ca57ab54SBram Moolenaar
2546ca57ab54SBram Moolenaar for (scol = 0; scol < Columns; ++scol)
2547ca57ab54SBram Moolenaar TabPageIdxs[scol] = 0;
2548ca57ab54SBram Moolenaar }
2549ca57ab54SBram Moolenaar
2550ca57ab54SBram Moolenaar /*
2551071d4279SBram Moolenaar * screen_valid - allocate screen buffers if size changed
255270b2a56dSBram Moolenaar * If "doclear" is TRUE: clear screen if it has been resized.
2553071d4279SBram Moolenaar * Returns TRUE if there is a valid screen to write to.
2554071d4279SBram Moolenaar * Returns FALSE when starting up and screen not initialized yet.
2555071d4279SBram Moolenaar */
2556071d4279SBram Moolenaar int
screen_valid(int doclear)255705540976SBram Moolenaar screen_valid(int doclear)
2558071d4279SBram Moolenaar {
255963d9e730SBram Moolenaar screenalloc(doclear); // allocate screen buffers if size changed
2560071d4279SBram Moolenaar return (ScreenLines != NULL);
2561071d4279SBram Moolenaar }
2562071d4279SBram Moolenaar
2563071d4279SBram Moolenaar /*
2564071d4279SBram Moolenaar * Resize the shell to Rows and Columns.
2565071d4279SBram Moolenaar * Allocate ScreenLines[] and associated items.
2566071d4279SBram Moolenaar *
2567071d4279SBram Moolenaar * There may be some time between setting Rows and Columns and (re)allocating
2568071d4279SBram Moolenaar * ScreenLines[]. This happens when starting up and when (manually) changing
2569071d4279SBram Moolenaar * the shell size. Always use screen_Rows and screen_Columns to access items
2570071d4279SBram Moolenaar * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
2571071d4279SBram Moolenaar * final size of the shell is needed.
2572071d4279SBram Moolenaar */
2573071d4279SBram Moolenaar void
screenalloc(int doclear)257405540976SBram Moolenaar screenalloc(int doclear)
2575071d4279SBram Moolenaar {
2576071d4279SBram Moolenaar int new_row, old_row;
2577071d4279SBram Moolenaar #ifdef FEAT_GUI
2578071d4279SBram Moolenaar int old_Rows;
2579071d4279SBram Moolenaar #endif
2580071d4279SBram Moolenaar win_T *wp;
2581071d4279SBram Moolenaar int outofmem = FALSE;
2582071d4279SBram Moolenaar int len;
2583071d4279SBram Moolenaar schar_T *new_ScreenLines;
2584071d4279SBram Moolenaar u8char_T *new_ScreenLinesUC = NULL;
2585362e1a30SBram Moolenaar u8char_T *new_ScreenLinesC[MAX_MCO];
2586071d4279SBram Moolenaar schar_T *new_ScreenLines2 = NULL;
2587362e1a30SBram Moolenaar int i;
2588071d4279SBram Moolenaar sattr_T *new_ScreenAttrs;
2589071d4279SBram Moolenaar unsigned *new_LineOffset;
2590071d4279SBram Moolenaar char_u *new_LineWraps;
2591d1f56e68SBram Moolenaar short *new_TabPageIdxs;
259205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
259333796b39SBram Moolenaar short *new_popup_mask;
25944c063a0dSBram Moolenaar short *new_popup_mask_next;
2595c662ec99SBram Moolenaar char *new_popup_transparent;
259633796b39SBram Moolenaar #endif
2597f740b29aSBram Moolenaar tabpage_T *tp;
259863d9e730SBram Moolenaar static int entered = FALSE; // avoid recursiveness
259963d9e730SBram Moolenaar static int done_outofmem_msg = FALSE; // did outofmem message
260087e817c5SBram Moolenaar int retry_count = 0;
2601071d4279SBram Moolenaar
260287e817c5SBram Moolenaar retry:
2603071d4279SBram Moolenaar /*
2604071d4279SBram Moolenaar * Allocation of the screen buffers is done only when the size changes and
2605071d4279SBram Moolenaar * when Rows and Columns have been set and we have started doing full
2606071d4279SBram Moolenaar * screen stuff.
2607071d4279SBram Moolenaar */
2608071d4279SBram Moolenaar if ((ScreenLines != NULL
2609071d4279SBram Moolenaar && Rows == screen_Rows
2610071d4279SBram Moolenaar && Columns == screen_Columns
2611071d4279SBram Moolenaar && enc_utf8 == (ScreenLinesUC != NULL)
2612071d4279SBram Moolenaar && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
2613a12a161bSBram Moolenaar && p_mco == Screen_mco)
2614071d4279SBram Moolenaar || Rows == 0
2615071d4279SBram Moolenaar || Columns == 0
2616071d4279SBram Moolenaar || (!full_screen && ScreenLines == NULL))
2617071d4279SBram Moolenaar return;
2618071d4279SBram Moolenaar
2619071d4279SBram Moolenaar /*
2620071d4279SBram Moolenaar * It's possible that we produce an out-of-memory message below, which
2621071d4279SBram Moolenaar * will cause this function to be called again. To break the loop, just
2622071d4279SBram Moolenaar * return here.
2623071d4279SBram Moolenaar */
2624071d4279SBram Moolenaar if (entered)
2625071d4279SBram Moolenaar return;
2626071d4279SBram Moolenaar entered = TRUE;
2627071d4279SBram Moolenaar
2628a3f2ecdeSBram Moolenaar /*
2629a3f2ecdeSBram Moolenaar * Note that the window sizes are updated before reallocating the arrays,
2630a3f2ecdeSBram Moolenaar * thus we must not redraw here!
2631a3f2ecdeSBram Moolenaar */
2632a3f2ecdeSBram Moolenaar ++RedrawingDisabled;
2633a3f2ecdeSBram Moolenaar
263463d9e730SBram Moolenaar win_new_shellsize(); // fit the windows in the new sized shell
2635071d4279SBram Moolenaar
2636b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
2637b3f74069SBram Moolenaar vim_lock_screen(); // be safe, put it here
2638b3f74069SBram Moolenaar #endif
2639b3f74069SBram Moolenaar
264063d9e730SBram Moolenaar comp_col(); // recompute columns for shown command and ruler
2641071d4279SBram Moolenaar
2642071d4279SBram Moolenaar /*
2643071d4279SBram Moolenaar * We're changing the size of the screen.
2644071d4279SBram Moolenaar * - Allocate new arrays for ScreenLines and ScreenAttrs.
2645071d4279SBram Moolenaar * - Move lines from the old arrays into the new arrays, clear extra
2646071d4279SBram Moolenaar * lines (unless the screen is going to be cleared).
2647071d4279SBram Moolenaar * - Free the old arrays.
2648071d4279SBram Moolenaar *
2649071d4279SBram Moolenaar * If anything fails, make ScreenLines NULL, so we don't do anything!
2650071d4279SBram Moolenaar * Continuing with the old ScreenLines may result in a crash, because the
2651071d4279SBram Moolenaar * size is wrong.
2652071d4279SBram Moolenaar */
2653f740b29aSBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, wp)
2654071d4279SBram Moolenaar win_free_lsize(wp);
26555e9b4540SBram Moolenaar if (aucmd_win != NULL)
26565e9b4540SBram Moolenaar win_free_lsize(aucmd_win);
265705ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
26588caaf825SBram Moolenaar // global popup windows
2659aeea7215SBram Moolenaar FOR_ALL_POPUPWINS(wp)
26608caaf825SBram Moolenaar win_free_lsize(wp);
26618caaf825SBram Moolenaar // tab-local popup windows
26628caaf825SBram Moolenaar FOR_ALL_TABPAGES(tp)
2663aeea7215SBram Moolenaar FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
26648caaf825SBram Moolenaar win_free_lsize(wp);
26658caaf825SBram Moolenaar #endif
2666071d4279SBram Moolenaar
2667c799fe20SBram Moolenaar new_ScreenLines = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
2668216b7106SBram Moolenaar vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
2669071d4279SBram Moolenaar if (enc_utf8)
2670071d4279SBram Moolenaar {
2671c799fe20SBram Moolenaar new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns);
2672362e1a30SBram Moolenaar for (i = 0; i < p_mco; ++i)
2673c799fe20SBram Moolenaar new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T,
2674c799fe20SBram Moolenaar (Rows + 1) * Columns);
2675071d4279SBram Moolenaar }
2676071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU)
2677c799fe20SBram Moolenaar new_ScreenLines2 = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
2678c799fe20SBram Moolenaar new_ScreenAttrs = LALLOC_MULT(sattr_T, (Rows + 1) * Columns);
2679c799fe20SBram Moolenaar new_LineOffset = LALLOC_MULT(unsigned, Rows);
2680c799fe20SBram Moolenaar new_LineWraps = LALLOC_MULT(char_u, Rows);
2681c799fe20SBram Moolenaar new_TabPageIdxs = LALLOC_MULT(short, Columns);
268205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
268333796b39SBram Moolenaar new_popup_mask = LALLOC_MULT(short, Rows * Columns);
26844c063a0dSBram Moolenaar new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
2685c662ec99SBram Moolenaar new_popup_transparent = LALLOC_MULT(char, Rows * Columns);
268633796b39SBram Moolenaar #endif
2687071d4279SBram Moolenaar
2688faa959a8SBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, wp)
2689071d4279SBram Moolenaar {
2690071d4279SBram Moolenaar if (win_alloc_lines(wp) == FAIL)
2691071d4279SBram Moolenaar {
2692071d4279SBram Moolenaar outofmem = TRUE;
2693bb9c7d1cSBram Moolenaar goto give_up;
2694071d4279SBram Moolenaar }
2695071d4279SBram Moolenaar }
26965e9b4540SBram Moolenaar if (aucmd_win != NULL && aucmd_win->w_lines == NULL
26975e9b4540SBram Moolenaar && win_alloc_lines(aucmd_win) == FAIL)
2698746ebd3bSBram Moolenaar outofmem = TRUE;
269905ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
27008caaf825SBram Moolenaar // global popup windows
2701aeea7215SBram Moolenaar FOR_ALL_POPUPWINS(wp)
27028caaf825SBram Moolenaar if (win_alloc_lines(wp) == FAIL)
27038caaf825SBram Moolenaar {
27048caaf825SBram Moolenaar outofmem = TRUE;
27058caaf825SBram Moolenaar goto give_up;
27068caaf825SBram Moolenaar }
27078caaf825SBram Moolenaar // tab-local popup windows
27088caaf825SBram Moolenaar FOR_ALL_TABPAGES(tp)
2709aeea7215SBram Moolenaar FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
27108caaf825SBram Moolenaar if (win_alloc_lines(wp) == FAIL)
27118caaf825SBram Moolenaar {
27128caaf825SBram Moolenaar outofmem = TRUE;
27138caaf825SBram Moolenaar goto give_up;
27148caaf825SBram Moolenaar }
27158caaf825SBram Moolenaar #endif
27168caaf825SBram Moolenaar
2717bb9c7d1cSBram Moolenaar give_up:
2718071d4279SBram Moolenaar
2719362e1a30SBram Moolenaar for (i = 0; i < p_mco; ++i)
2720362e1a30SBram Moolenaar if (new_ScreenLinesC[i] == NULL)
2721362e1a30SBram Moolenaar break;
2722071d4279SBram Moolenaar if (new_ScreenLines == NULL
2723362e1a30SBram Moolenaar || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
2724071d4279SBram Moolenaar || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
2725071d4279SBram Moolenaar || new_ScreenAttrs == NULL
2726071d4279SBram Moolenaar || new_LineOffset == NULL
2727071d4279SBram Moolenaar || new_LineWraps == NULL
2728f740b29aSBram Moolenaar || new_TabPageIdxs == NULL
272905ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
273033796b39SBram Moolenaar || new_popup_mask == NULL
27314c063a0dSBram Moolenaar || new_popup_mask_next == NULL
2732c662ec99SBram Moolenaar || new_popup_transparent == NULL
273333796b39SBram Moolenaar #endif
2734071d4279SBram Moolenaar || outofmem)
2735071d4279SBram Moolenaar {
273689d4032cSBram Moolenaar if (ScreenLines != NULL || !done_outofmem_msg)
2737482aaeb0SBram Moolenaar {
273863d9e730SBram Moolenaar // guess the size
2739482aaeb0SBram Moolenaar do_outofmem_msg((long_u)((Rows + 1) * Columns));
2740482aaeb0SBram Moolenaar
274163d9e730SBram Moolenaar // Remember we did this to avoid getting outofmem messages over
274263d9e730SBram Moolenaar // and over again.
274389d4032cSBram Moolenaar done_outofmem_msg = TRUE;
2744482aaeb0SBram Moolenaar }
2745d23a8236SBram Moolenaar VIM_CLEAR(new_ScreenLines);
2746d23a8236SBram Moolenaar VIM_CLEAR(new_ScreenLinesUC);
2747362e1a30SBram Moolenaar for (i = 0; i < p_mco; ++i)
2748d23a8236SBram Moolenaar VIM_CLEAR(new_ScreenLinesC[i]);
2749d23a8236SBram Moolenaar VIM_CLEAR(new_ScreenLines2);
2750d23a8236SBram Moolenaar VIM_CLEAR(new_ScreenAttrs);
2751d23a8236SBram Moolenaar VIM_CLEAR(new_LineOffset);
2752d23a8236SBram Moolenaar VIM_CLEAR(new_LineWraps);
2753d23a8236SBram Moolenaar VIM_CLEAR(new_TabPageIdxs);
275405ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
275533796b39SBram Moolenaar VIM_CLEAR(new_popup_mask);
27564c063a0dSBram Moolenaar VIM_CLEAR(new_popup_mask_next);
2757c662ec99SBram Moolenaar VIM_CLEAR(new_popup_transparent);
275833796b39SBram Moolenaar #endif
2759071d4279SBram Moolenaar }
2760071d4279SBram Moolenaar else
2761071d4279SBram Moolenaar {
276289d4032cSBram Moolenaar done_outofmem_msg = FALSE;
2763482aaeb0SBram Moolenaar
2764071d4279SBram Moolenaar for (new_row = 0; new_row < Rows; ++new_row)
2765071d4279SBram Moolenaar {
2766071d4279SBram Moolenaar new_LineOffset[new_row] = new_row * Columns;
2767071d4279SBram Moolenaar new_LineWraps[new_row] = FALSE;
2768071d4279SBram Moolenaar
2769071d4279SBram Moolenaar /*
2770071d4279SBram Moolenaar * If the screen is not going to be cleared, copy as much as
2771071d4279SBram Moolenaar * possible from the old screen to the new one and clear the rest
2772071d4279SBram Moolenaar * (used when resizing the window at the "--more--" prompt or when
2773071d4279SBram Moolenaar * executing an external command, for the GUI).
2774071d4279SBram Moolenaar */
277570b2a56dSBram Moolenaar if (!doclear)
2776071d4279SBram Moolenaar {
2777071d4279SBram Moolenaar (void)vim_memset(new_ScreenLines + new_row * Columns,
2778071d4279SBram Moolenaar ' ', (size_t)Columns * sizeof(schar_T));
2779071d4279SBram Moolenaar if (enc_utf8)
2780071d4279SBram Moolenaar {
2781071d4279SBram Moolenaar (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
2782071d4279SBram Moolenaar 0, (size_t)Columns * sizeof(u8char_T));
2783362e1a30SBram Moolenaar for (i = 0; i < p_mco; ++i)
2784362e1a30SBram Moolenaar (void)vim_memset(new_ScreenLinesC[i]
2785362e1a30SBram Moolenaar + new_row * Columns,
2786071d4279SBram Moolenaar 0, (size_t)Columns * sizeof(u8char_T));
2787071d4279SBram Moolenaar }
2788071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU)
2789071d4279SBram Moolenaar (void)vim_memset(new_ScreenLines2 + new_row * Columns,
2790071d4279SBram Moolenaar 0, (size_t)Columns * sizeof(schar_T));
2791071d4279SBram Moolenaar (void)vim_memset(new_ScreenAttrs + new_row * Columns,
2792071d4279SBram Moolenaar 0, (size_t)Columns * sizeof(sattr_T));
2793071d4279SBram Moolenaar old_row = new_row + (screen_Rows - Rows);
2794482aaeb0SBram Moolenaar if (old_row >= 0 && ScreenLines != NULL)
2795071d4279SBram Moolenaar {
2796071d4279SBram Moolenaar if (screen_Columns < Columns)
2797071d4279SBram Moolenaar len = screen_Columns;
2798071d4279SBram Moolenaar else
2799071d4279SBram Moolenaar len = Columns;
280063d9e730SBram Moolenaar // When switching to utf-8 don't copy characters, they
280163d9e730SBram Moolenaar // may be invalid now. Also when p_mco changes.
2802362e1a30SBram Moolenaar if (!(enc_utf8 && ScreenLinesUC == NULL)
2803362e1a30SBram Moolenaar && p_mco == Screen_mco)
2804071d4279SBram Moolenaar mch_memmove(new_ScreenLines + new_LineOffset[new_row],
2805071d4279SBram Moolenaar ScreenLines + LineOffset[old_row],
2806071d4279SBram Moolenaar (size_t)len * sizeof(schar_T));
2807362e1a30SBram Moolenaar if (enc_utf8 && ScreenLinesUC != NULL
2808362e1a30SBram Moolenaar && p_mco == Screen_mco)
2809071d4279SBram Moolenaar {
2810071d4279SBram Moolenaar mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
2811071d4279SBram Moolenaar ScreenLinesUC + LineOffset[old_row],
2812071d4279SBram Moolenaar (size_t)len * sizeof(u8char_T));
2813362e1a30SBram Moolenaar for (i = 0; i < p_mco; ++i)
2814362e1a30SBram Moolenaar mch_memmove(new_ScreenLinesC[i]
2815362e1a30SBram Moolenaar + new_LineOffset[new_row],
2816362e1a30SBram Moolenaar ScreenLinesC[i] + LineOffset[old_row],
2817071d4279SBram Moolenaar (size_t)len * sizeof(u8char_T));
2818071d4279SBram Moolenaar }
2819071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
2820071d4279SBram Moolenaar mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
2821071d4279SBram Moolenaar ScreenLines2 + LineOffset[old_row],
2822071d4279SBram Moolenaar (size_t)len * sizeof(schar_T));
2823071d4279SBram Moolenaar mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
2824071d4279SBram Moolenaar ScreenAttrs + LineOffset[old_row],
2825071d4279SBram Moolenaar (size_t)len * sizeof(sattr_T));
2826071d4279SBram Moolenaar }
2827071d4279SBram Moolenaar }
2828071d4279SBram Moolenaar }
282963d9e730SBram Moolenaar // Use the last line of the screen for the current line.
2830071d4279SBram Moolenaar current_ScreenLine = new_ScreenLines + Rows * Columns;
28316ace95e9SBram Moolenaar
283205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
28336ace95e9SBram Moolenaar vim_memset(new_popup_mask, 0, Rows * Columns * sizeof(short));
28346ace95e9SBram Moolenaar vim_memset(new_popup_transparent, 0, Rows * Columns * sizeof(char));
28356ace95e9SBram Moolenaar #endif
2836071d4279SBram Moolenaar }
2837071d4279SBram Moolenaar
28381ec484f5SBram Moolenaar free_screenlines();
28391ec484f5SBram Moolenaar
28406ace95e9SBram Moolenaar // NOTE: this may result in all pointers to become NULL.
2841071d4279SBram Moolenaar ScreenLines = new_ScreenLines;
2842071d4279SBram Moolenaar ScreenLinesUC = new_ScreenLinesUC;
2843362e1a30SBram Moolenaar for (i = 0; i < p_mco; ++i)
2844362e1a30SBram Moolenaar ScreenLinesC[i] = new_ScreenLinesC[i];
2845362e1a30SBram Moolenaar Screen_mco = p_mco;
2846071d4279SBram Moolenaar ScreenLines2 = new_ScreenLines2;
2847071d4279SBram Moolenaar ScreenAttrs = new_ScreenAttrs;
2848071d4279SBram Moolenaar LineOffset = new_LineOffset;
2849071d4279SBram Moolenaar LineWraps = new_LineWraps;
2850f740b29aSBram Moolenaar TabPageIdxs = new_TabPageIdxs;
285105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
285233796b39SBram Moolenaar popup_mask = new_popup_mask;
2853c662ec99SBram Moolenaar popup_mask_next = new_popup_mask_next;
2854c662ec99SBram Moolenaar popup_transparent = new_popup_transparent;
285533796b39SBram Moolenaar popup_mask_refresh = TRUE;
285633796b39SBram Moolenaar #endif
2857071d4279SBram Moolenaar
285863d9e730SBram Moolenaar // It's important that screen_Rows and screen_Columns reflect the actual
285963d9e730SBram Moolenaar // size of ScreenLines[]. Set them before calling anything.
2860071d4279SBram Moolenaar #ifdef FEAT_GUI
2861071d4279SBram Moolenaar old_Rows = screen_Rows;
2862071d4279SBram Moolenaar #endif
2863071d4279SBram Moolenaar screen_Rows = Rows;
2864071d4279SBram Moolenaar screen_Columns = Columns;
2865071d4279SBram Moolenaar
286663d9e730SBram Moolenaar must_redraw = CLEAR; // need to clear the screen later
286770b2a56dSBram Moolenaar if (doclear)
2868071d4279SBram Moolenaar screenclear2();
2869071d4279SBram Moolenaar #ifdef FEAT_GUI
2870071d4279SBram Moolenaar else if (gui.in_use
2871071d4279SBram Moolenaar && !gui.starting
2872071d4279SBram Moolenaar && ScreenLines != NULL
2873071d4279SBram Moolenaar && old_Rows != Rows)
2874071d4279SBram Moolenaar {
28757c003aa3SBram Moolenaar gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
28767c003aa3SBram Moolenaar
28777c003aa3SBram Moolenaar // Adjust the position of the cursor, for when executing an external
28787c003aa3SBram Moolenaar // command.
287963d9e730SBram Moolenaar if (msg_row >= Rows) // Rows got smaller
288063d9e730SBram Moolenaar msg_row = Rows - 1; // put cursor at last row
288163d9e730SBram Moolenaar else if (Rows > old_Rows) // Rows got bigger
288263d9e730SBram Moolenaar msg_row += Rows - old_Rows; // put cursor in same place
288363d9e730SBram Moolenaar if (msg_col >= Columns) // Columns got smaller
288463d9e730SBram Moolenaar msg_col = Columns - 1; // put cursor at last column
2885071d4279SBram Moolenaar }
2886071d4279SBram Moolenaar #endif
2887ca57ab54SBram Moolenaar clear_TabPageIdxs();
2888071d4279SBram Moolenaar
2889b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
2890b3f74069SBram Moolenaar vim_unlock_screen();
2891b3f74069SBram Moolenaar #endif
2892b3f74069SBram Moolenaar
2893071d4279SBram Moolenaar entered = FALSE;
2894a3f2ecdeSBram Moolenaar --RedrawingDisabled;
28957d47b6eeSBram Moolenaar
289687e817c5SBram Moolenaar /*
289787e817c5SBram Moolenaar * Do not apply autocommands more than 3 times to avoid an endless loop
289887e817c5SBram Moolenaar * in case applying autocommands always changes Rows or Columns.
289987e817c5SBram Moolenaar */
290087e817c5SBram Moolenaar if (starting == 0 && ++retry_count <= 3)
290187e817c5SBram Moolenaar {
29027d47b6eeSBram Moolenaar apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
290363d9e730SBram Moolenaar // In rare cases, autocommands may have altered Rows or Columns,
290463d9e730SBram Moolenaar // jump back to check if we need to allocate the screen again.
290587e817c5SBram Moolenaar goto retry;
290687e817c5SBram Moolenaar }
2907071d4279SBram Moolenaar }
2908071d4279SBram Moolenaar
2909071d4279SBram Moolenaar void
free_screenlines(void)291005540976SBram Moolenaar free_screenlines(void)
29111ec484f5SBram Moolenaar {
2912362e1a30SBram Moolenaar int i;
2913362e1a30SBram Moolenaar
291433796b39SBram Moolenaar VIM_CLEAR(ScreenLinesUC);
2915362e1a30SBram Moolenaar for (i = 0; i < Screen_mco; ++i)
291633796b39SBram Moolenaar VIM_CLEAR(ScreenLinesC[i]);
291733796b39SBram Moolenaar VIM_CLEAR(ScreenLines2);
291833796b39SBram Moolenaar VIM_CLEAR(ScreenLines);
291933796b39SBram Moolenaar VIM_CLEAR(ScreenAttrs);
292033796b39SBram Moolenaar VIM_CLEAR(LineOffset);
292133796b39SBram Moolenaar VIM_CLEAR(LineWraps);
292233796b39SBram Moolenaar VIM_CLEAR(TabPageIdxs);
292305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
292433796b39SBram Moolenaar VIM_CLEAR(popup_mask);
29254c063a0dSBram Moolenaar VIM_CLEAR(popup_mask_next);
2926c662ec99SBram Moolenaar VIM_CLEAR(popup_transparent);
292733796b39SBram Moolenaar #endif
29281ec484f5SBram Moolenaar }
29291ec484f5SBram Moolenaar
29301ec484f5SBram Moolenaar void
screenclear(void)293105540976SBram Moolenaar screenclear(void)
2932071d4279SBram Moolenaar {
2933071d4279SBram Moolenaar check_for_delay(FALSE);
293463d9e730SBram Moolenaar screenalloc(FALSE); // allocate screen buffers if size changed
293563d9e730SBram Moolenaar screenclear2(); // clear the screen
2936071d4279SBram Moolenaar }
2937071d4279SBram Moolenaar
2938071d4279SBram Moolenaar static void
screenclear2(void)293905540976SBram Moolenaar screenclear2(void)
2940071d4279SBram Moolenaar {
2941071d4279SBram Moolenaar int i;
2942071d4279SBram Moolenaar
2943071d4279SBram Moolenaar if (starting == NO_SCREEN || ScreenLines == NULL
2944071d4279SBram Moolenaar #ifdef FEAT_GUI
2945071d4279SBram Moolenaar || (gui.in_use && gui.starting)
2946071d4279SBram Moolenaar #endif
2947071d4279SBram Moolenaar )
2948071d4279SBram Moolenaar return;
2949071d4279SBram Moolenaar
2950071d4279SBram Moolenaar #ifdef FEAT_GUI
2951071d4279SBram Moolenaar if (!gui.in_use)
2952071d4279SBram Moolenaar #endif
295363d9e730SBram Moolenaar screen_attr = -1; // force setting the Normal colors
295463d9e730SBram Moolenaar screen_stop_highlight(); // don't want highlighting here
2955071d4279SBram Moolenaar
2956071d4279SBram Moolenaar #ifdef FEAT_CLIPBOARD
295763d9e730SBram Moolenaar // disable selection without redrawing it
2958071d4279SBram Moolenaar clip_scroll_selection(9999);
2959071d4279SBram Moolenaar #endif
2960071d4279SBram Moolenaar
296163d9e730SBram Moolenaar // blank out ScreenLines
2962071d4279SBram Moolenaar for (i = 0; i < Rows; ++i)
2963071d4279SBram Moolenaar {
2964cfce7171SBram Moolenaar lineclear(LineOffset[i], (int)Columns, 0);
2965071d4279SBram Moolenaar LineWraps[i] = FALSE;
2966071d4279SBram Moolenaar }
2967071d4279SBram Moolenaar
2968071d4279SBram Moolenaar if (can_clear(T_CL))
2969071d4279SBram Moolenaar {
297063d9e730SBram Moolenaar out_str(T_CL); // clear the display
2971071d4279SBram Moolenaar clear_cmdline = FALSE;
2972d12f5c17SBram Moolenaar mode_displayed = FALSE;
2973071d4279SBram Moolenaar }
2974071d4279SBram Moolenaar else
2975071d4279SBram Moolenaar {
297663d9e730SBram Moolenaar // can't clear the screen, mark all chars with invalid attributes
2977071d4279SBram Moolenaar for (i = 0; i < Rows; ++i)
2978071d4279SBram Moolenaar lineinvalid(LineOffset[i], (int)Columns);
2979071d4279SBram Moolenaar clear_cmdline = TRUE;
2980071d4279SBram Moolenaar }
2981071d4279SBram Moolenaar
298263d9e730SBram Moolenaar screen_cleared = TRUE; // can use contents of ScreenLines now
2983071d4279SBram Moolenaar
2984071d4279SBram Moolenaar win_rest_invalid(firstwin);
2985071d4279SBram Moolenaar redraw_cmdline = TRUE;
2986997fb4baSBram Moolenaar redraw_tabline = TRUE;
298763d9e730SBram Moolenaar if (must_redraw == CLEAR) // no need to clear again
2988071d4279SBram Moolenaar must_redraw = NOT_VALID;
2989071d4279SBram Moolenaar compute_cmdrow();
299063d9e730SBram Moolenaar msg_row = cmdline_row; // put cursor on last line for messages
2991071d4279SBram Moolenaar msg_col = 0;
299263d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
299363d9e730SBram Moolenaar msg_scrolled = 0; // can't scroll back
2994071d4279SBram Moolenaar msg_didany = FALSE;
2995071d4279SBram Moolenaar msg_didout = FALSE;
2996071d4279SBram Moolenaar }
2997071d4279SBram Moolenaar
2998071d4279SBram Moolenaar /*
2999071d4279SBram Moolenaar * Clear one line in ScreenLines.
3000071d4279SBram Moolenaar */
3001071d4279SBram Moolenaar static void
lineclear(unsigned off,int width,int attr)3002cfce7171SBram Moolenaar lineclear(unsigned off, int width, int attr)
3003071d4279SBram Moolenaar {
3004071d4279SBram Moolenaar (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
3005071d4279SBram Moolenaar if (enc_utf8)
3006071d4279SBram Moolenaar (void)vim_memset(ScreenLinesUC + off, 0,
3007071d4279SBram Moolenaar (size_t)width * sizeof(u8char_T));
3008cfce7171SBram Moolenaar (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
3009071d4279SBram Moolenaar }
3010071d4279SBram Moolenaar
3011071d4279SBram Moolenaar /*
3012071d4279SBram Moolenaar * Mark one line in ScreenLines invalid by setting the attributes to an
3013071d4279SBram Moolenaar * invalid value.
3014071d4279SBram Moolenaar */
3015071d4279SBram Moolenaar static void
lineinvalid(unsigned off,int width)301605540976SBram Moolenaar lineinvalid(unsigned off, int width)
3017071d4279SBram Moolenaar {
3018071d4279SBram Moolenaar (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
3019071d4279SBram Moolenaar }
3020071d4279SBram Moolenaar
3021071d4279SBram Moolenaar /*
302296916ac6SBram Moolenaar * To be called when characters were sent to the terminal directly, outputting
302396916ac6SBram Moolenaar * test on "screen_lnum".
302496916ac6SBram Moolenaar */
302596916ac6SBram Moolenaar void
line_was_clobbered(int screen_lnum)302696916ac6SBram Moolenaar line_was_clobbered(int screen_lnum)
302796916ac6SBram Moolenaar {
302896916ac6SBram Moolenaar lineinvalid(LineOffset[screen_lnum], (int)Columns);
302996916ac6SBram Moolenaar }
303096916ac6SBram Moolenaar
303196916ac6SBram Moolenaar /*
3032071d4279SBram Moolenaar * Copy part of a Screenline for vertically split window "wp".
3033071d4279SBram Moolenaar */
3034071d4279SBram Moolenaar static void
linecopy(int to,int from,win_T * wp)303505540976SBram Moolenaar linecopy(int to, int from, win_T *wp)
3036071d4279SBram Moolenaar {
3037071d4279SBram Moolenaar unsigned off_to = LineOffset[to] + wp->w_wincol;
3038071d4279SBram Moolenaar unsigned off_from = LineOffset[from] + wp->w_wincol;
3039071d4279SBram Moolenaar
3040071d4279SBram Moolenaar mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
3041071d4279SBram Moolenaar wp->w_width * sizeof(schar_T));
3042071d4279SBram Moolenaar if (enc_utf8)
3043071d4279SBram Moolenaar {
3044362e1a30SBram Moolenaar int i;
3045362e1a30SBram Moolenaar
3046071d4279SBram Moolenaar mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
3047071d4279SBram Moolenaar wp->w_width * sizeof(u8char_T));
3048362e1a30SBram Moolenaar for (i = 0; i < p_mco; ++i)
3049362e1a30SBram Moolenaar mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
3050071d4279SBram Moolenaar wp->w_width * sizeof(u8char_T));
3051071d4279SBram Moolenaar }
3052071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU)
3053071d4279SBram Moolenaar mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
3054071d4279SBram Moolenaar wp->w_width * sizeof(schar_T));
3055071d4279SBram Moolenaar mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
3056071d4279SBram Moolenaar wp->w_width * sizeof(sattr_T));
3057071d4279SBram Moolenaar }
3058071d4279SBram Moolenaar
3059071d4279SBram Moolenaar /*
3060071d4279SBram Moolenaar * Return TRUE if clearing with term string "p" would work.
3061071d4279SBram Moolenaar * It can't work when the string is empty or it won't set the right background.
306233796b39SBram Moolenaar * Don't clear to end-of-line when there are popups, it may cause flicker.
3063071d4279SBram Moolenaar */
3064071d4279SBram Moolenaar int
can_clear(char_u * p)306505540976SBram Moolenaar can_clear(char_u *p)
3066071d4279SBram Moolenaar {
3067071d4279SBram Moolenaar return (*p != NUL && (t_colors <= 1
3068071d4279SBram Moolenaar #ifdef FEAT_GUI
3069071d4279SBram Moolenaar || gui.in_use
3070071d4279SBram Moolenaar #endif
307161be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
30721b58cdd1SBram Moolenaar || (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
3073d18f672fSBram Moolenaar || (!p_tgc && cterm_normal_bg_color == 0)
3074d18f672fSBram Moolenaar #else
3075d18f672fSBram Moolenaar || cterm_normal_bg_color == 0
30768a633e34SBram Moolenaar #endif
307733796b39SBram Moolenaar || *T_UT != NUL)
307805ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
307933796b39SBram Moolenaar && !(p == T_CE && popup_visible)
308033796b39SBram Moolenaar #endif
308133796b39SBram Moolenaar );
3082071d4279SBram Moolenaar }
3083071d4279SBram Moolenaar
3084071d4279SBram Moolenaar /*
3085071d4279SBram Moolenaar * Reset cursor position. Use whenever cursor was moved because of outputting
3086071d4279SBram Moolenaar * something directly to the screen (shell commands) or a terminal control
3087071d4279SBram Moolenaar * code.
3088071d4279SBram Moolenaar */
3089071d4279SBram Moolenaar void
screen_start(void)309005540976SBram Moolenaar screen_start(void)
3091071d4279SBram Moolenaar {
3092071d4279SBram Moolenaar screen_cur_row = screen_cur_col = 9999;
3093071d4279SBram Moolenaar }
3094071d4279SBram Moolenaar
3095071d4279SBram Moolenaar /*
3096071d4279SBram Moolenaar * Move the cursor to position "row","col" in the screen.
3097071d4279SBram Moolenaar * This tries to find the most efficient way to move, minimizing the number of
3098071d4279SBram Moolenaar * characters sent to the terminal.
3099071d4279SBram Moolenaar */
3100071d4279SBram Moolenaar void
windgoto(int row,int col)310105540976SBram Moolenaar windgoto(int row, int col)
3102071d4279SBram Moolenaar {
3103e2cc9702SBram Moolenaar sattr_T *p;
3104071d4279SBram Moolenaar int i;
3105071d4279SBram Moolenaar int plan;
3106071d4279SBram Moolenaar int cost;
3107071d4279SBram Moolenaar int wouldbe_col;
3108071d4279SBram Moolenaar int noinvcurs;
3109071d4279SBram Moolenaar char_u *bs;
3110071d4279SBram Moolenaar int goto_cost;
3111071d4279SBram Moolenaar int attr;
3112071d4279SBram Moolenaar
311363d9e730SBram Moolenaar #define GOTO_COST 7 // assume a term_windgoto() takes about 7 chars
311463d9e730SBram Moolenaar #define HIGHL_COST 5 // assume unhighlight takes 5 chars
3115071d4279SBram Moolenaar
3116071d4279SBram Moolenaar #define PLAN_LE 1
3117071d4279SBram Moolenaar #define PLAN_CR 2
3118071d4279SBram Moolenaar #define PLAN_NL 3
3119071d4279SBram Moolenaar #define PLAN_WRITE 4
312063d9e730SBram Moolenaar // Can't use ScreenLines unless initialized
3121071d4279SBram Moolenaar if (ScreenLines == NULL)
3122071d4279SBram Moolenaar return;
3123071d4279SBram Moolenaar if (col != screen_cur_col || row != screen_cur_row)
3124071d4279SBram Moolenaar {
312563d9e730SBram Moolenaar // Check for valid position.
312663d9e730SBram Moolenaar if (row < 0) // window without text lines?
3127071d4279SBram Moolenaar row = 0;
3128071d4279SBram Moolenaar if (row >= screen_Rows)
3129071d4279SBram Moolenaar row = screen_Rows - 1;
3130071d4279SBram Moolenaar if (col >= screen_Columns)
3131071d4279SBram Moolenaar col = screen_Columns - 1;
3132071d4279SBram Moolenaar
313363d9e730SBram Moolenaar // check if no cursor movement is allowed in highlight mode
3134071d4279SBram Moolenaar if (screen_attr && *T_MS == NUL)
3135071d4279SBram Moolenaar noinvcurs = HIGHL_COST;
3136071d4279SBram Moolenaar else
3137071d4279SBram Moolenaar noinvcurs = 0;
3138071d4279SBram Moolenaar goto_cost = GOTO_COST + noinvcurs;
3139071d4279SBram Moolenaar
3140071d4279SBram Moolenaar /*
3141071d4279SBram Moolenaar * Plan how to do the positioning:
3142071d4279SBram Moolenaar * 1. Use CR to move it to column 0, same row.
3143071d4279SBram Moolenaar * 2. Use T_LE to move it a few columns to the left.
3144071d4279SBram Moolenaar * 3. Use NL to move a few lines down, column 0.
3145071d4279SBram Moolenaar * 4. Move a few columns to the right with T_ND or by writing chars.
3146071d4279SBram Moolenaar *
3147071d4279SBram Moolenaar * Don't do this if the cursor went beyond the last column, the cursor
3148071d4279SBram Moolenaar * position is unknown then (some terminals wrap, some don't )
3149071d4279SBram Moolenaar *
31502c7a7638SBram Moolenaar * First check if the highlighting attributes allow us to write
3151071d4279SBram Moolenaar * characters to move the cursor to the right.
3152071d4279SBram Moolenaar */
3153071d4279SBram Moolenaar if (row >= screen_cur_row && screen_cur_col < Columns)
3154071d4279SBram Moolenaar {
3155071d4279SBram Moolenaar /*
3156071d4279SBram Moolenaar * If the cursor is in the same row, bigger col, we can use CR
3157071d4279SBram Moolenaar * or T_LE.
3158071d4279SBram Moolenaar */
315963d9e730SBram Moolenaar bs = NULL; // init for GCC
3160071d4279SBram Moolenaar attr = screen_attr;
3161071d4279SBram Moolenaar if (row == screen_cur_row && col < screen_cur_col)
3162071d4279SBram Moolenaar {
316363d9e730SBram Moolenaar // "le" is preferred over "bc", because "bc" is obsolete
3164071d4279SBram Moolenaar if (*T_LE)
316563d9e730SBram Moolenaar bs = T_LE; // "cursor left"
3166071d4279SBram Moolenaar else
316763d9e730SBram Moolenaar bs = T_BC; // "backspace character (old)
3168071d4279SBram Moolenaar if (*bs)
3169071d4279SBram Moolenaar cost = (screen_cur_col - col) * (int)STRLEN(bs);
3170071d4279SBram Moolenaar else
3171071d4279SBram Moolenaar cost = 999;
317263d9e730SBram Moolenaar if (col + 1 < cost) // using CR is less characters
3173071d4279SBram Moolenaar {
3174071d4279SBram Moolenaar plan = PLAN_CR;
3175071d4279SBram Moolenaar wouldbe_col = 0;
317663d9e730SBram Moolenaar cost = 1; // CR is just one character
3177071d4279SBram Moolenaar }
3178071d4279SBram Moolenaar else
3179071d4279SBram Moolenaar {
3180071d4279SBram Moolenaar plan = PLAN_LE;
3181071d4279SBram Moolenaar wouldbe_col = col;
3182071d4279SBram Moolenaar }
318363d9e730SBram Moolenaar if (noinvcurs) // will stop highlighting
3184071d4279SBram Moolenaar {
3185071d4279SBram Moolenaar cost += noinvcurs;
3186071d4279SBram Moolenaar attr = 0;
3187071d4279SBram Moolenaar }
3188071d4279SBram Moolenaar }
3189071d4279SBram Moolenaar
3190071d4279SBram Moolenaar /*
3191071d4279SBram Moolenaar * If the cursor is above where we want to be, we can use CR LF.
3192071d4279SBram Moolenaar */
3193071d4279SBram Moolenaar else if (row > screen_cur_row)
3194071d4279SBram Moolenaar {
3195071d4279SBram Moolenaar plan = PLAN_NL;
3196071d4279SBram Moolenaar wouldbe_col = 0;
319763d9e730SBram Moolenaar cost = (row - screen_cur_row) * 2; // CR LF
319863d9e730SBram Moolenaar if (noinvcurs) // will stop highlighting
3199071d4279SBram Moolenaar {
3200071d4279SBram Moolenaar cost += noinvcurs;
3201071d4279SBram Moolenaar attr = 0;
3202071d4279SBram Moolenaar }
3203071d4279SBram Moolenaar }
3204071d4279SBram Moolenaar
3205071d4279SBram Moolenaar /*
3206071d4279SBram Moolenaar * If the cursor is in the same row, smaller col, just use write.
3207071d4279SBram Moolenaar */
3208071d4279SBram Moolenaar else
3209071d4279SBram Moolenaar {
3210071d4279SBram Moolenaar plan = PLAN_WRITE;
3211071d4279SBram Moolenaar wouldbe_col = screen_cur_col;
3212071d4279SBram Moolenaar cost = 0;
3213071d4279SBram Moolenaar }
3214071d4279SBram Moolenaar
3215071d4279SBram Moolenaar /*
3216071d4279SBram Moolenaar * Check if any characters that need to be written have the
3217071d4279SBram Moolenaar * correct attributes. Also avoid UTF-8 characters.
3218071d4279SBram Moolenaar */
3219071d4279SBram Moolenaar i = col - wouldbe_col;
3220071d4279SBram Moolenaar if (i > 0)
3221071d4279SBram Moolenaar cost += i;
3222071d4279SBram Moolenaar if (cost < goto_cost && i > 0)
3223071d4279SBram Moolenaar {
3224071d4279SBram Moolenaar /*
3225071d4279SBram Moolenaar * Check if the attributes are correct without additionally
3226071d4279SBram Moolenaar * stopping highlighting.
3227071d4279SBram Moolenaar */
3228071d4279SBram Moolenaar p = ScreenAttrs + LineOffset[row] + wouldbe_col;
3229071d4279SBram Moolenaar while (i && *p++ == attr)
3230071d4279SBram Moolenaar --i;
3231071d4279SBram Moolenaar if (i != 0)
3232071d4279SBram Moolenaar {
3233071d4279SBram Moolenaar /*
3234071d4279SBram Moolenaar * Try if it works when highlighting is stopped here.
3235071d4279SBram Moolenaar */
3236071d4279SBram Moolenaar if (*--p == 0)
3237071d4279SBram Moolenaar {
3238071d4279SBram Moolenaar cost += noinvcurs;
3239071d4279SBram Moolenaar while (i && *p++ == 0)
3240071d4279SBram Moolenaar --i;
3241071d4279SBram Moolenaar }
3242071d4279SBram Moolenaar if (i != 0)
324363d9e730SBram Moolenaar cost = 999; // different attributes, don't do it
3244071d4279SBram Moolenaar }
3245071d4279SBram Moolenaar if (enc_utf8)
3246071d4279SBram Moolenaar {
324763d9e730SBram Moolenaar // Don't use an UTF-8 char for positioning, it's slow.
3248071d4279SBram Moolenaar for (i = wouldbe_col; i < col; ++i)
3249071d4279SBram Moolenaar if (ScreenLinesUC[LineOffset[row] + i] != 0)
3250071d4279SBram Moolenaar {
3251071d4279SBram Moolenaar cost = 999;
3252071d4279SBram Moolenaar break;
3253071d4279SBram Moolenaar }
3254071d4279SBram Moolenaar }
3255071d4279SBram Moolenaar }
3256071d4279SBram Moolenaar
3257071d4279SBram Moolenaar /*
3258071d4279SBram Moolenaar * We can do it without term_windgoto()!
3259071d4279SBram Moolenaar */
3260071d4279SBram Moolenaar if (cost < goto_cost)
3261071d4279SBram Moolenaar {
3262071d4279SBram Moolenaar if (plan == PLAN_LE)
3263071d4279SBram Moolenaar {
3264071d4279SBram Moolenaar if (noinvcurs)
3265071d4279SBram Moolenaar screen_stop_highlight();
3266071d4279SBram Moolenaar while (screen_cur_col > col)
3267071d4279SBram Moolenaar {
3268071d4279SBram Moolenaar out_str(bs);
3269071d4279SBram Moolenaar --screen_cur_col;
3270071d4279SBram Moolenaar }
3271071d4279SBram Moolenaar }
3272071d4279SBram Moolenaar else if (plan == PLAN_CR)
3273071d4279SBram Moolenaar {
3274071d4279SBram Moolenaar if (noinvcurs)
3275071d4279SBram Moolenaar screen_stop_highlight();
3276071d4279SBram Moolenaar out_char('\r');
3277071d4279SBram Moolenaar screen_cur_col = 0;
3278071d4279SBram Moolenaar }
3279071d4279SBram Moolenaar else if (plan == PLAN_NL)
3280071d4279SBram Moolenaar {
3281071d4279SBram Moolenaar if (noinvcurs)
3282071d4279SBram Moolenaar screen_stop_highlight();
3283071d4279SBram Moolenaar while (screen_cur_row < row)
3284071d4279SBram Moolenaar {
3285071d4279SBram Moolenaar out_char('\n');
3286071d4279SBram Moolenaar ++screen_cur_row;
3287071d4279SBram Moolenaar }
3288071d4279SBram Moolenaar screen_cur_col = 0;
3289071d4279SBram Moolenaar }
3290071d4279SBram Moolenaar
3291071d4279SBram Moolenaar i = col - screen_cur_col;
3292071d4279SBram Moolenaar if (i > 0)
3293071d4279SBram Moolenaar {
3294071d4279SBram Moolenaar /*
3295071d4279SBram Moolenaar * Use cursor-right if it's one character only. Avoids
3296071d4279SBram Moolenaar * removing a line of pixels from the last bold char, when
3297071d4279SBram Moolenaar * using the bold trick in the GUI.
3298071d4279SBram Moolenaar */
3299071d4279SBram Moolenaar if (T_ND[0] != NUL && T_ND[1] == NUL)
3300071d4279SBram Moolenaar {
3301071d4279SBram Moolenaar while (i-- > 0)
3302071d4279SBram Moolenaar out_char(*T_ND);
3303071d4279SBram Moolenaar }
3304071d4279SBram Moolenaar else
3305071d4279SBram Moolenaar {
3306071d4279SBram Moolenaar int off;
3307071d4279SBram Moolenaar
3308071d4279SBram Moolenaar off = LineOffset[row] + screen_cur_col;
3309071d4279SBram Moolenaar while (i-- > 0)
3310071d4279SBram Moolenaar {
3311071d4279SBram Moolenaar if (ScreenAttrs[off] != screen_attr)
3312071d4279SBram Moolenaar screen_stop_highlight();
3313071d4279SBram Moolenaar out_flush_check();
3314071d4279SBram Moolenaar out_char(ScreenLines[off]);
3315071d4279SBram Moolenaar if (enc_dbcs == DBCS_JPNU
3316071d4279SBram Moolenaar && ScreenLines[off] == 0x8e)
3317071d4279SBram Moolenaar out_char(ScreenLines2[off]);
3318071d4279SBram Moolenaar ++off;
3319071d4279SBram Moolenaar }
3320071d4279SBram Moolenaar }
3321071d4279SBram Moolenaar }
3322071d4279SBram Moolenaar }
3323071d4279SBram Moolenaar }
3324071d4279SBram Moolenaar else
3325071d4279SBram Moolenaar cost = 999;
3326071d4279SBram Moolenaar
3327071d4279SBram Moolenaar if (cost >= goto_cost)
3328071d4279SBram Moolenaar {
3329071d4279SBram Moolenaar if (noinvcurs)
3330071d4279SBram Moolenaar screen_stop_highlight();
3331597a4224SBram Moolenaar if (row == screen_cur_row && (col > screen_cur_col)
3332597a4224SBram Moolenaar && *T_CRI != NUL)
3333071d4279SBram Moolenaar term_cursor_right(col - screen_cur_col);
3334071d4279SBram Moolenaar else
3335071d4279SBram Moolenaar term_windgoto(row, col);
3336071d4279SBram Moolenaar }
3337071d4279SBram Moolenaar screen_cur_row = row;
3338071d4279SBram Moolenaar screen_cur_col = col;
3339071d4279SBram Moolenaar }
3340071d4279SBram Moolenaar }
3341071d4279SBram Moolenaar
3342071d4279SBram Moolenaar /*
3343071d4279SBram Moolenaar * Set cursor to its position in the current window.
3344071d4279SBram Moolenaar */
3345071d4279SBram Moolenaar void
setcursor(void)334605540976SBram Moolenaar setcursor(void)
3347071d4279SBram Moolenaar {
3348987723e0SBram Moolenaar setcursor_mayforce(FALSE);
3349987723e0SBram Moolenaar }
3350987723e0SBram Moolenaar
3351987723e0SBram Moolenaar /*
3352987723e0SBram Moolenaar * Set cursor to its position in the current window.
3353987723e0SBram Moolenaar * When "force" is TRUE also when not redrawing.
3354987723e0SBram Moolenaar */
3355987723e0SBram Moolenaar void
setcursor_mayforce(int force)3356987723e0SBram Moolenaar setcursor_mayforce(int force)
3357987723e0SBram Moolenaar {
3358987723e0SBram Moolenaar if (force || redrawing())
3359071d4279SBram Moolenaar {
3360071d4279SBram Moolenaar validate_cursor();
3361071d4279SBram Moolenaar windgoto(W_WINROW(curwin) + curwin->w_wrow,
336253f8174eSBram Moolenaar curwin->w_wincol + (
3363071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
336463d9e730SBram Moolenaar // With 'rightleft' set and the cursor on a double-wide
336563d9e730SBram Moolenaar // character, position it on the leftmost column.
3366a12a161bSBram Moolenaar curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol
3367a12a161bSBram Moolenaar - ((has_mbyte
3368561f9db8SBram Moolenaar && (*mb_ptr2cells)(ml_get_cursor()) == 2
3369a12a161bSBram Moolenaar && vim_isprintc(gchar_cursor())) ? 2 : 1)) :
3370071d4279SBram Moolenaar #endif
3371071d4279SBram Moolenaar curwin->w_wcol));
3372071d4279SBram Moolenaar }
3373071d4279SBram Moolenaar }
3374071d4279SBram Moolenaar
3375071d4279SBram Moolenaar
3376071d4279SBram Moolenaar /*
33778603356bSBram Moolenaar * Insert 'line_count' lines at 'row' in window 'wp'.
33788603356bSBram Moolenaar * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
33798603356bSBram Moolenaar * If 'mayclear' is TRUE the screen will be cleared if it is faster than
3380071d4279SBram Moolenaar * scrolling.
3381071d4279SBram Moolenaar * Returns FAIL if the lines are not inserted, OK for success.
3382071d4279SBram Moolenaar */
3383071d4279SBram Moolenaar int
win_ins_lines(win_T * wp,int row,int line_count,int invalid,int mayclear)338405540976SBram Moolenaar win_ins_lines(
338505540976SBram Moolenaar win_T *wp,
338605540976SBram Moolenaar int row,
338705540976SBram Moolenaar int line_count,
338805540976SBram Moolenaar int invalid,
338905540976SBram Moolenaar int mayclear)
3390071d4279SBram Moolenaar {
3391071d4279SBram Moolenaar int did_delete;
3392071d4279SBram Moolenaar int nextrow;
3393071d4279SBram Moolenaar int lastrow;
3394071d4279SBram Moolenaar int retval;
3395071d4279SBram Moolenaar
3396071d4279SBram Moolenaar if (invalid)
3397071d4279SBram Moolenaar wp->w_lines_valid = 0;
3398071d4279SBram Moolenaar
3399071d4279SBram Moolenaar if (wp->w_height < 5)
3400071d4279SBram Moolenaar return FAIL;
3401071d4279SBram Moolenaar
3402071d4279SBram Moolenaar if (line_count > wp->w_height - row)
3403071d4279SBram Moolenaar line_count = wp->w_height - row;
3404071d4279SBram Moolenaar
3405cfce7171SBram Moolenaar retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
3406071d4279SBram Moolenaar if (retval != MAYBE)
3407071d4279SBram Moolenaar return retval;
3408071d4279SBram Moolenaar
3409071d4279SBram Moolenaar /*
3410071d4279SBram Moolenaar * If there is a next window or a status line, we first try to delete the
3411071d4279SBram Moolenaar * lines at the bottom to avoid messing what is after the window.
3412c363fe15SBram Moolenaar * If this fails and there are following windows, don't do anything to
3413c363fe15SBram Moolenaar * avoid messing up those windows, better just redraw.
3414071d4279SBram Moolenaar */
3415071d4279SBram Moolenaar did_delete = FALSE;
3416071d4279SBram Moolenaar if (wp->w_next != NULL || wp->w_status_height)
3417071d4279SBram Moolenaar {
3418071d4279SBram Moolenaar if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
3419cfce7171SBram Moolenaar line_count, (int)Rows, FALSE, 0, NULL) == OK)
3420071d4279SBram Moolenaar did_delete = TRUE;
3421071d4279SBram Moolenaar else if (wp->w_next)
3422071d4279SBram Moolenaar return FAIL;
3423071d4279SBram Moolenaar }
3424071d4279SBram Moolenaar /*
3425071d4279SBram Moolenaar * if no lines deleted, blank the lines that will end up below the window
3426071d4279SBram Moolenaar */
3427071d4279SBram Moolenaar if (!did_delete)
3428071d4279SBram Moolenaar {
3429071d4279SBram Moolenaar wp->w_redr_status = TRUE;
3430071d4279SBram Moolenaar redraw_cmdline = TRUE;
3431e0de17d8SBram Moolenaar nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
3432071d4279SBram Moolenaar lastrow = nextrow + line_count;
3433071d4279SBram Moolenaar if (lastrow > Rows)
3434071d4279SBram Moolenaar lastrow = Rows;
3435071d4279SBram Moolenaar screen_fill(nextrow - line_count, lastrow - line_count,
343653f8174eSBram Moolenaar wp->w_wincol, (int)W_ENDCOL(wp),
3437071d4279SBram Moolenaar ' ', ' ', 0);
3438071d4279SBram Moolenaar }
3439071d4279SBram Moolenaar
3440cfce7171SBram Moolenaar if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
3441071d4279SBram Moolenaar == FAIL)
3442071d4279SBram Moolenaar {
3443c363fe15SBram Moolenaar // deletion will have messed up other windows
3444071d4279SBram Moolenaar if (did_delete)
3445071d4279SBram Moolenaar {
3446071d4279SBram Moolenaar wp->w_redr_status = TRUE;
3447071d4279SBram Moolenaar win_rest_invalid(W_NEXT(wp));
3448071d4279SBram Moolenaar }
3449071d4279SBram Moolenaar return FAIL;
3450071d4279SBram Moolenaar }
3451071d4279SBram Moolenaar
3452071d4279SBram Moolenaar return OK;
3453071d4279SBram Moolenaar }
3454071d4279SBram Moolenaar
3455071d4279SBram Moolenaar /*
34568603356bSBram Moolenaar * Delete "line_count" window lines at "row" in window "wp".
3457071d4279SBram Moolenaar * If "invalid" is TRUE curwin->w_lines[] is invalidated.
3458071d4279SBram Moolenaar * If "mayclear" is TRUE the screen will be cleared if it is faster than
3459071d4279SBram Moolenaar * scrolling
3460071d4279SBram Moolenaar * Return OK for success, FAIL if the lines are not deleted.
3461071d4279SBram Moolenaar */
3462071d4279SBram Moolenaar int
win_del_lines(win_T * wp,int row,int line_count,int invalid,int mayclear,int clear_attr)346305540976SBram Moolenaar win_del_lines(
346405540976SBram Moolenaar win_T *wp,
346505540976SBram Moolenaar int row,
346605540976SBram Moolenaar int line_count,
346705540976SBram Moolenaar int invalid,
3468cfce7171SBram Moolenaar int mayclear,
346963d9e730SBram Moolenaar int clear_attr) // for clearing lines
3470071d4279SBram Moolenaar {
3471071d4279SBram Moolenaar int retval;
3472071d4279SBram Moolenaar
3473071d4279SBram Moolenaar if (invalid)
3474071d4279SBram Moolenaar wp->w_lines_valid = 0;
3475071d4279SBram Moolenaar
3476071d4279SBram Moolenaar if (line_count > wp->w_height - row)
3477071d4279SBram Moolenaar line_count = wp->w_height - row;
3478071d4279SBram Moolenaar
3479cfce7171SBram Moolenaar retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
3480071d4279SBram Moolenaar if (retval != MAYBE)
3481071d4279SBram Moolenaar return retval;
3482071d4279SBram Moolenaar
3483071d4279SBram Moolenaar if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
3484cfce7171SBram Moolenaar (int)Rows, FALSE, clear_attr, NULL) == FAIL)
3485071d4279SBram Moolenaar return FAIL;
3486071d4279SBram Moolenaar
3487071d4279SBram Moolenaar /*
3488071d4279SBram Moolenaar * If there are windows or status lines below, try to put them at the
3489071d4279SBram Moolenaar * correct place. If we can't do that, they have to be redrawn.
3490071d4279SBram Moolenaar */
3491071d4279SBram Moolenaar if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
3492071d4279SBram Moolenaar {
3493071d4279SBram Moolenaar if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
3494cfce7171SBram Moolenaar line_count, (int)Rows, clear_attr, NULL) == FAIL)
3495071d4279SBram Moolenaar {
3496071d4279SBram Moolenaar wp->w_redr_status = TRUE;
3497071d4279SBram Moolenaar win_rest_invalid(wp->w_next);
3498071d4279SBram Moolenaar }
3499071d4279SBram Moolenaar }
3500071d4279SBram Moolenaar /*
3501071d4279SBram Moolenaar * If this is the last window and there is no status line, redraw the
3502071d4279SBram Moolenaar * command line later.
3503071d4279SBram Moolenaar */
3504071d4279SBram Moolenaar else
3505071d4279SBram Moolenaar redraw_cmdline = TRUE;
3506071d4279SBram Moolenaar return OK;
3507071d4279SBram Moolenaar }
3508071d4279SBram Moolenaar
3509071d4279SBram Moolenaar /*
3510071d4279SBram Moolenaar * Common code for win_ins_lines() and win_del_lines().
3511071d4279SBram Moolenaar * Returns OK or FAIL when the work has been done.
3512071d4279SBram Moolenaar * Returns MAYBE when not finished yet.
3513071d4279SBram Moolenaar */
3514071d4279SBram Moolenaar static int
win_do_lines(win_T * wp,int row,int line_count,int mayclear,int del,int clear_attr)351505540976SBram Moolenaar win_do_lines(
351605540976SBram Moolenaar win_T *wp,
351705540976SBram Moolenaar int row,
351805540976SBram Moolenaar int line_count,
351905540976SBram Moolenaar int mayclear,
3520cfce7171SBram Moolenaar int del,
3521cfce7171SBram Moolenaar int clear_attr)
3522071d4279SBram Moolenaar {
3523071d4279SBram Moolenaar int retval;
3524071d4279SBram Moolenaar
3525071d4279SBram Moolenaar if (!redrawing() || line_count <= 0)
3526071d4279SBram Moolenaar return FAIL;
3527071d4279SBram Moolenaar
352833796b39SBram Moolenaar // When inserting lines would result in loss of command output, just redraw
352933796b39SBram Moolenaar // the lines.
353029ae377eSBram Moolenaar if (no_win_do_lines_ins && !del)
353129ae377eSBram Moolenaar return FAIL;
353229ae377eSBram Moolenaar
353333796b39SBram Moolenaar // only a few lines left: redraw is faster
35344033c55eSBram Moolenaar if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
3535071d4279SBram Moolenaar {
353629ae377eSBram Moolenaar if (!no_win_do_lines_ins)
353733796b39SBram Moolenaar screenclear(); // will set wp->w_lines_valid to 0
3538071d4279SBram Moolenaar return FAIL;
3539071d4279SBram Moolenaar }
3540071d4279SBram Moolenaar
354105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
35424c063a0dSBram Moolenaar // this doesn't work when there are popups visible
354333796b39SBram Moolenaar if (popup_visible)
354433796b39SBram Moolenaar return FAIL;
354533796b39SBram Moolenaar #endif
354633796b39SBram Moolenaar
354733796b39SBram Moolenaar // Delete all remaining lines
3548071d4279SBram Moolenaar if (row + line_count >= wp->w_height)
3549071d4279SBram Moolenaar {
3550071d4279SBram Moolenaar screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
355153f8174eSBram Moolenaar wp->w_wincol, (int)W_ENDCOL(wp),
3552071d4279SBram Moolenaar ' ', ' ', 0);
3553071d4279SBram Moolenaar return OK;
3554071d4279SBram Moolenaar }
3555071d4279SBram Moolenaar
3556071d4279SBram Moolenaar /*
355729ae377eSBram Moolenaar * When scrolling, the message on the command line should be cleared,
3558071d4279SBram Moolenaar * otherwise it will stay there forever.
355929ae377eSBram Moolenaar * Don't do this when avoiding to insert lines.
3560071d4279SBram Moolenaar */
356129ae377eSBram Moolenaar if (!no_win_do_lines_ins)
3562071d4279SBram Moolenaar clear_cmdline = TRUE;
3563071d4279SBram Moolenaar
3564071d4279SBram Moolenaar /*
3565071d4279SBram Moolenaar * If the terminal can set a scroll region, use that.
3566071d4279SBram Moolenaar * Always do this in a vertically split window. This will redraw from
3567071d4279SBram Moolenaar * ScreenLines[] when t_CV isn't defined. That's faster than using
3568071d4279SBram Moolenaar * win_line().
3569071d4279SBram Moolenaar * Don't use a scroll region when we are going to redraw the text, writing
357048e330afSBram Moolenaar * a character in the lower right corner of the scroll region may cause a
357148e330afSBram Moolenaar * scroll-up .
3572071d4279SBram Moolenaar */
35730263146bSBram Moolenaar if (scroll_region || wp->w_width != Columns)
3574071d4279SBram Moolenaar {
3575071d4279SBram Moolenaar if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
3576071d4279SBram Moolenaar scroll_region_set(wp, row);
3577071d4279SBram Moolenaar if (del)
3578071d4279SBram Moolenaar retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
3579cfce7171SBram Moolenaar wp->w_height - row, FALSE, clear_attr, wp);
3580071d4279SBram Moolenaar else
3581071d4279SBram Moolenaar retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
3582cfce7171SBram Moolenaar wp->w_height - row, clear_attr, wp);
3583071d4279SBram Moolenaar if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
3584071d4279SBram Moolenaar scroll_region_reset();
3585071d4279SBram Moolenaar return retval;
3586071d4279SBram Moolenaar }
3587071d4279SBram Moolenaar
358863d9e730SBram Moolenaar if (wp->w_next != NULL && p_tf) // don't delete/insert on fast terminal
3589071d4279SBram Moolenaar return FAIL;
3590071d4279SBram Moolenaar
3591071d4279SBram Moolenaar return MAYBE;
3592071d4279SBram Moolenaar }
3593071d4279SBram Moolenaar
3594071d4279SBram Moolenaar /*
3595071d4279SBram Moolenaar * window 'wp' and everything after it is messed up, mark it for redraw
3596071d4279SBram Moolenaar */
3597071d4279SBram Moolenaar static void
win_rest_invalid(win_T * wp)359805540976SBram Moolenaar win_rest_invalid(win_T *wp)
3599071d4279SBram Moolenaar {
3600071d4279SBram Moolenaar while (wp != NULL)
3601071d4279SBram Moolenaar {
3602071d4279SBram Moolenaar redraw_win_later(wp, NOT_VALID);
3603071d4279SBram Moolenaar wp->w_redr_status = TRUE;
3604071d4279SBram Moolenaar wp = wp->w_next;
3605071d4279SBram Moolenaar }
3606071d4279SBram Moolenaar redraw_cmdline = TRUE;
3607071d4279SBram Moolenaar }
3608071d4279SBram Moolenaar
3609071d4279SBram Moolenaar /*
3610071d4279SBram Moolenaar * The rest of the routines in this file perform screen manipulations. The
3611071d4279SBram Moolenaar * given operation is performed physically on the screen. The corresponding
3612071d4279SBram Moolenaar * change is also made to the internal screen image. In this way, the editor
3613071d4279SBram Moolenaar * anticipates the effect of editing changes on the appearance of the screen.
3614071d4279SBram Moolenaar * That way, when we call screenupdate a complete redraw isn't usually
3615071d4279SBram Moolenaar * necessary. Another advantage is that we can keep adding code to anticipate
3616071d4279SBram Moolenaar * screen changes, and in the meantime, everything still works.
3617071d4279SBram Moolenaar */
3618071d4279SBram Moolenaar
3619071d4279SBram Moolenaar /*
3620071d4279SBram Moolenaar * types for inserting or deleting lines
3621071d4279SBram Moolenaar */
3622071d4279SBram Moolenaar #define USE_T_CAL 1
3623071d4279SBram Moolenaar #define USE_T_CDL 2
3624071d4279SBram Moolenaar #define USE_T_AL 3
3625071d4279SBram Moolenaar #define USE_T_CE 4
3626071d4279SBram Moolenaar #define USE_T_DL 5
3627071d4279SBram Moolenaar #define USE_T_SR 6
3628071d4279SBram Moolenaar #define USE_NL 7
3629071d4279SBram Moolenaar #define USE_T_CD 8
3630071d4279SBram Moolenaar #define USE_REDRAW 9
3631071d4279SBram Moolenaar
3632071d4279SBram Moolenaar /*
3633071d4279SBram Moolenaar * insert lines on the screen and update ScreenLines[]
3634071d4279SBram Moolenaar * 'end' is the line after the scrolled part. Normally it is Rows.
3635071d4279SBram Moolenaar * When scrolling region used 'off' is the offset from the top for the region.
3636071d4279SBram Moolenaar * 'row' and 'end' are relative to the start of the region.
3637071d4279SBram Moolenaar *
3638071d4279SBram Moolenaar * return FAIL for failure, OK for success.
3639071d4279SBram Moolenaar */
364087e25fdfSBram Moolenaar int
screen_ins_lines(int off,int row,int line_count,int end,int clear_attr,win_T * wp)364105540976SBram Moolenaar screen_ins_lines(
364205540976SBram Moolenaar int off,
364305540976SBram Moolenaar int row,
364405540976SBram Moolenaar int line_count,
364505540976SBram Moolenaar int end,
3646cfce7171SBram Moolenaar int clear_attr,
364763d9e730SBram Moolenaar win_T *wp) // NULL or window to use width from
3648071d4279SBram Moolenaar {
3649071d4279SBram Moolenaar int i;
3650071d4279SBram Moolenaar int j;
3651071d4279SBram Moolenaar unsigned temp;
3652071d4279SBram Moolenaar int cursor_row;
3653bfa42467SBram Moolenaar int cursor_col = 0;
3654071d4279SBram Moolenaar int type;
3655071d4279SBram Moolenaar int result_empty;
3656071d4279SBram Moolenaar int can_ce = can_clear(T_CE);
3657071d4279SBram Moolenaar
3658071d4279SBram Moolenaar /*
3659071d4279SBram Moolenaar * FAIL if
3660071d4279SBram Moolenaar * - there is no valid screen
3661071d4279SBram Moolenaar * - the screen has to be redrawn completely
3662071d4279SBram Moolenaar * - the line count is less than one
3663071d4279SBram Moolenaar * - the line count is more than 'ttyscroll'
366480dd3f9dSBram Moolenaar * - redrawing for a callback and there is a modeless selection
366533796b39SBram Moolenaar * - there is a popup window
3666071d4279SBram Moolenaar */
366733796b39SBram Moolenaar if (!screen_valid(TRUE)
366833796b39SBram Moolenaar || line_count <= 0 || line_count > p_ttyscroll
366980dd3f9dSBram Moolenaar #ifdef FEAT_CLIPBOARD
367080dd3f9dSBram Moolenaar || (clip_star.state != SELECT_CLEARED
367180dd3f9dSBram Moolenaar && redrawing_for_callback > 0)
367280dd3f9dSBram Moolenaar #endif
367305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
367433796b39SBram Moolenaar || popup_visible
367533796b39SBram Moolenaar #endif
367680dd3f9dSBram Moolenaar )
3677071d4279SBram Moolenaar return FAIL;
3678071d4279SBram Moolenaar
3679071d4279SBram Moolenaar /*
3680071d4279SBram Moolenaar * There are seven ways to insert lines:
3681071d4279SBram Moolenaar * 0. When in a vertically split window and t_CV isn't set, redraw the
3682071d4279SBram Moolenaar * characters from ScreenLines[].
3683071d4279SBram Moolenaar * 1. Use T_CD (clear to end of display) if it exists and the result of
3684071d4279SBram Moolenaar * the insert is just empty lines
3685071d4279SBram Moolenaar * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
3686071d4279SBram Moolenaar * present or line_count > 1. It looks better if we do all the inserts
3687071d4279SBram Moolenaar * at once.
3688071d4279SBram Moolenaar * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
3689071d4279SBram Moolenaar * insert is just empty lines and T_CE is not present or line_count >
3690071d4279SBram Moolenaar * 1.
3691071d4279SBram Moolenaar * 4. Use T_AL (insert line) if it exists.
3692071d4279SBram Moolenaar * 5. Use T_CE (erase line) if it exists and the result of the insert is
3693071d4279SBram Moolenaar * just empty lines.
3694071d4279SBram Moolenaar * 6. Use T_DL (delete line) if it exists and the result of the insert is
3695071d4279SBram Moolenaar * just empty lines.
3696071d4279SBram Moolenaar * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
3697071d4279SBram Moolenaar * the 'da' flag is not set or we have clear line capability.
3698071d4279SBram Moolenaar * 8. redraw the characters from ScreenLines[].
3699071d4279SBram Moolenaar *
3700071d4279SBram Moolenaar * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
3701071d4279SBram Moolenaar * the scrollbar for the window. It does have insert line, use that if it
3702071d4279SBram Moolenaar * exists.
3703071d4279SBram Moolenaar */
3704071d4279SBram Moolenaar result_empty = (row + line_count >= end);
3705071d4279SBram Moolenaar if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
3706071d4279SBram Moolenaar type = USE_REDRAW;
37074033c55eSBram Moolenaar else if (can_clear(T_CD) && result_empty)
3708071d4279SBram Moolenaar type = USE_T_CD;
3709071d4279SBram Moolenaar else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
3710071d4279SBram Moolenaar type = USE_T_CAL;
3711071d4279SBram Moolenaar else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
3712071d4279SBram Moolenaar type = USE_T_CDL;
3713071d4279SBram Moolenaar else if (*T_AL != NUL)
3714071d4279SBram Moolenaar type = USE_T_AL;
3715071d4279SBram Moolenaar else if (can_ce && result_empty)
3716071d4279SBram Moolenaar type = USE_T_CE;
3717071d4279SBram Moolenaar else if (*T_DL != NUL && result_empty)
3718071d4279SBram Moolenaar type = USE_T_DL;
3719071d4279SBram Moolenaar else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
3720071d4279SBram Moolenaar type = USE_T_SR;
3721071d4279SBram Moolenaar else
3722071d4279SBram Moolenaar return FAIL;
3723071d4279SBram Moolenaar
3724071d4279SBram Moolenaar /*
3725071d4279SBram Moolenaar * For clearing the lines screen_del_lines() is used. This will also take
3726071d4279SBram Moolenaar * care of t_db if necessary.
3727071d4279SBram Moolenaar */
3728071d4279SBram Moolenaar if (type == USE_T_CD || type == USE_T_CDL ||
3729071d4279SBram Moolenaar type == USE_T_CE || type == USE_T_DL)
3730cfce7171SBram Moolenaar return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
3731071d4279SBram Moolenaar
3732071d4279SBram Moolenaar /*
3733071d4279SBram Moolenaar * If text is retained below the screen, first clear or delete as many
3734071d4279SBram Moolenaar * lines at the bottom of the window as are about to be inserted so that
3735071d4279SBram Moolenaar * the deleted lines won't later surface during a screen_del_lines.
3736071d4279SBram Moolenaar */
3737071d4279SBram Moolenaar if (*T_DB)
3738cfce7171SBram Moolenaar screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
3739071d4279SBram Moolenaar
3740071d4279SBram Moolenaar #ifdef FEAT_CLIPBOARD
374163d9e730SBram Moolenaar // Remove a modeless selection when inserting lines halfway the screen
374263d9e730SBram Moolenaar // or not the full width of the screen.
37434033c55eSBram Moolenaar if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
3744c0885aadSBram Moolenaar clip_clear_selection(&clip_star);
3745071d4279SBram Moolenaar else
3746071d4279SBram Moolenaar clip_scroll_selection(-line_count);
3747071d4279SBram Moolenaar #endif
3748071d4279SBram Moolenaar
3749b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
3750b3f74069SBram Moolenaar vim_lock_screen();
3751b3f74069SBram Moolenaar #endif
3752b3f74069SBram Moolenaar
3753071d4279SBram Moolenaar #ifdef FEAT_GUI
375463d9e730SBram Moolenaar // Don't update the GUI cursor here, ScreenLines[] is invalid until the
375563d9e730SBram Moolenaar // scrolling is actually carried out.
3756107abd2cSBram Moolenaar gui_dont_update_cursor(row + off <= gui.cursor_row);
3757071d4279SBram Moolenaar #endif
3758071d4279SBram Moolenaar
3759bfa42467SBram Moolenaar if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
3760bfa42467SBram Moolenaar cursor_col = wp->w_wincol;
3761bfa42467SBram Moolenaar
376263d9e730SBram Moolenaar if (*T_CCS != NUL) // cursor relative to region
3763071d4279SBram Moolenaar cursor_row = row;
3764071d4279SBram Moolenaar else
3765071d4279SBram Moolenaar cursor_row = row + off;
3766071d4279SBram Moolenaar
3767071d4279SBram Moolenaar /*
3768071d4279SBram Moolenaar * Shift LineOffset[] line_count down to reflect the inserted lines.
3769071d4279SBram Moolenaar * Clear the inserted lines in ScreenLines[].
3770071d4279SBram Moolenaar */
3771071d4279SBram Moolenaar row += off;
3772071d4279SBram Moolenaar end += off;
3773071d4279SBram Moolenaar for (i = 0; i < line_count; ++i)
3774071d4279SBram Moolenaar {
3775071d4279SBram Moolenaar if (wp != NULL && wp->w_width != Columns)
3776071d4279SBram Moolenaar {
377763d9e730SBram Moolenaar // need to copy part of a line
3778071d4279SBram Moolenaar j = end - 1 - i;
3779071d4279SBram Moolenaar while ((j -= line_count) >= row)
3780071d4279SBram Moolenaar linecopy(j + line_count, j, wp);
3781071d4279SBram Moolenaar j += line_count;
3782071d4279SBram Moolenaar if (can_clear((char_u *)" "))
3783cfce7171SBram Moolenaar lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
3784cfce7171SBram Moolenaar clear_attr);
3785071d4279SBram Moolenaar else
3786071d4279SBram Moolenaar lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
3787071d4279SBram Moolenaar LineWraps[j] = FALSE;
3788071d4279SBram Moolenaar }
3789071d4279SBram Moolenaar else
3790071d4279SBram Moolenaar {
3791071d4279SBram Moolenaar j = end - 1 - i;
3792071d4279SBram Moolenaar temp = LineOffset[j];
3793071d4279SBram Moolenaar while ((j -= line_count) >= row)
3794071d4279SBram Moolenaar {
3795071d4279SBram Moolenaar LineOffset[j + line_count] = LineOffset[j];
3796071d4279SBram Moolenaar LineWraps[j + line_count] = LineWraps[j];
3797071d4279SBram Moolenaar }
3798071d4279SBram Moolenaar LineOffset[j + line_count] = temp;
3799071d4279SBram Moolenaar LineWraps[j + line_count] = FALSE;
3800071d4279SBram Moolenaar if (can_clear((char_u *)" "))
3801cfce7171SBram Moolenaar lineclear(temp, (int)Columns, clear_attr);
3802071d4279SBram Moolenaar else
3803071d4279SBram Moolenaar lineinvalid(temp, (int)Columns);
3804071d4279SBram Moolenaar }
3805071d4279SBram Moolenaar }
3806071d4279SBram Moolenaar
3807b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
3808b3f74069SBram Moolenaar vim_unlock_screen();
3809b3f74069SBram Moolenaar #endif
3810b3f74069SBram Moolenaar
3811071d4279SBram Moolenaar screen_stop_highlight();
3812bfa42467SBram Moolenaar windgoto(cursor_row, cursor_col);
3813cfce7171SBram Moolenaar if (clear_attr != 0)
3814cfce7171SBram Moolenaar screen_start_highlight(clear_attr);
3815071d4279SBram Moolenaar
381663d9e730SBram Moolenaar // redraw the characters
3817071d4279SBram Moolenaar if (type == USE_REDRAW)
3818071d4279SBram Moolenaar redraw_block(row, end, wp);
38194033c55eSBram Moolenaar else if (type == USE_T_CAL)
3820071d4279SBram Moolenaar {
3821071d4279SBram Moolenaar term_append_lines(line_count);
382263d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
3823071d4279SBram Moolenaar }
3824071d4279SBram Moolenaar else
3825071d4279SBram Moolenaar {
3826071d4279SBram Moolenaar for (i = 0; i < line_count; i++)
3827071d4279SBram Moolenaar {
3828071d4279SBram Moolenaar if (type == USE_T_AL)
3829071d4279SBram Moolenaar {
3830071d4279SBram Moolenaar if (i && cursor_row != 0)
3831bfa42467SBram Moolenaar windgoto(cursor_row, cursor_col);
3832071d4279SBram Moolenaar out_str(T_AL);
3833071d4279SBram Moolenaar }
383463d9e730SBram Moolenaar else // type == USE_T_SR
3835071d4279SBram Moolenaar out_str(T_SR);
383663d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
3837071d4279SBram Moolenaar }
3838071d4279SBram Moolenaar }
3839071d4279SBram Moolenaar
3840071d4279SBram Moolenaar /*
3841071d4279SBram Moolenaar * With scroll-reverse and 'da' flag set we need to clear the lines that
3842071d4279SBram Moolenaar * have been scrolled down into the region.
3843071d4279SBram Moolenaar */
3844071d4279SBram Moolenaar if (type == USE_T_SR && *T_DA)
3845071d4279SBram Moolenaar {
3846071d4279SBram Moolenaar for (i = 0; i < line_count; ++i)
3847071d4279SBram Moolenaar {
3848bfa42467SBram Moolenaar windgoto(off + i, cursor_col);
3849071d4279SBram Moolenaar out_str(T_CE);
385063d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
3851071d4279SBram Moolenaar }
3852071d4279SBram Moolenaar }
3853071d4279SBram Moolenaar
3854071d4279SBram Moolenaar #ifdef FEAT_GUI
3855071d4279SBram Moolenaar gui_can_update_cursor();
3856071d4279SBram Moolenaar if (gui.in_use)
385763d9e730SBram Moolenaar out_flush(); // always flush after a scroll
3858071d4279SBram Moolenaar #endif
3859071d4279SBram Moolenaar return OK;
3860071d4279SBram Moolenaar }
3861071d4279SBram Moolenaar
3862071d4279SBram Moolenaar /*
3863107abd2cSBram Moolenaar * Delete lines on the screen and update ScreenLines[].
3864107abd2cSBram Moolenaar * "end" is the line after the scrolled part. Normally it is Rows.
3865107abd2cSBram Moolenaar * When scrolling region used "off" is the offset from the top for the region.
3866107abd2cSBram Moolenaar * "row" and "end" are relative to the start of the region.
3867071d4279SBram Moolenaar *
3868071d4279SBram Moolenaar * Return OK for success, FAIL if the lines are not deleted.
3869071d4279SBram Moolenaar */
3870071d4279SBram Moolenaar int
screen_del_lines(int off,int row,int line_count,int end,int force,int clear_attr,win_T * wp UNUSED)387105540976SBram Moolenaar screen_del_lines(
387205540976SBram Moolenaar int off,
387305540976SBram Moolenaar int row,
387405540976SBram Moolenaar int line_count,
387505540976SBram Moolenaar int end,
387663d9e730SBram Moolenaar int force, // even when line_count > p_ttyscroll
387763d9e730SBram Moolenaar int clear_attr, // used for clearing lines
387863d9e730SBram Moolenaar win_T *wp UNUSED) // NULL or window to use width from
3879071d4279SBram Moolenaar {
3880071d4279SBram Moolenaar int j;
3881071d4279SBram Moolenaar int i;
3882071d4279SBram Moolenaar unsigned temp;
3883071d4279SBram Moolenaar int cursor_row;
3884bfa42467SBram Moolenaar int cursor_col = 0;
3885071d4279SBram Moolenaar int cursor_end;
388663d9e730SBram Moolenaar int result_empty; // result is empty until end of region
388763d9e730SBram Moolenaar int can_delete; // deleting line codes can be used
3888071d4279SBram Moolenaar int type;
3889071d4279SBram Moolenaar
3890071d4279SBram Moolenaar /*
3891071d4279SBram Moolenaar * FAIL if
3892071d4279SBram Moolenaar * - there is no valid screen
3893071d4279SBram Moolenaar * - the screen has to be redrawn completely
3894071d4279SBram Moolenaar * - the line count is less than one
3895071d4279SBram Moolenaar * - the line count is more than 'ttyscroll'
389680dd3f9dSBram Moolenaar * - redrawing for a callback and there is a modeless selection
3897071d4279SBram Moolenaar */
389880dd3f9dSBram Moolenaar if (!screen_valid(TRUE) || line_count <= 0
389980dd3f9dSBram Moolenaar || (!force && line_count > p_ttyscroll)
390080dd3f9dSBram Moolenaar #ifdef FEAT_CLIPBOARD
390180dd3f9dSBram Moolenaar || (clip_star.state != SELECT_CLEARED
390280dd3f9dSBram Moolenaar && redrawing_for_callback > 0)
390380dd3f9dSBram Moolenaar #endif
390480dd3f9dSBram Moolenaar )
3905071d4279SBram Moolenaar return FAIL;
3906071d4279SBram Moolenaar
3907071d4279SBram Moolenaar /*
3908071d4279SBram Moolenaar * Check if the rest of the current region will become empty.
3909071d4279SBram Moolenaar */
3910071d4279SBram Moolenaar result_empty = row + line_count >= end;
3911071d4279SBram Moolenaar
3912071d4279SBram Moolenaar /*
3913071d4279SBram Moolenaar * We can delete lines only when 'db' flag not set or when 'ce' option
3914071d4279SBram Moolenaar * available.
3915071d4279SBram Moolenaar */
3916071d4279SBram Moolenaar can_delete = (*T_DB == NUL || can_clear(T_CE));
3917071d4279SBram Moolenaar
3918071d4279SBram Moolenaar /*
3919071d4279SBram Moolenaar * There are six ways to delete lines:
3920071d4279SBram Moolenaar * 0. When in a vertically split window and t_CV isn't set, redraw the
3921071d4279SBram Moolenaar * characters from ScreenLines[].
3922071d4279SBram Moolenaar * 1. Use T_CD if it exists and the result is empty.
3923071d4279SBram Moolenaar * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
3924071d4279SBram Moolenaar * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
3925071d4279SBram Moolenaar * none of the other ways work.
3926071d4279SBram Moolenaar * 4. Use T_CE (erase line) if the result is empty.
3927071d4279SBram Moolenaar * 5. Use T_DL (delete line) if it exists.
3928071d4279SBram Moolenaar * 6. redraw the characters from ScreenLines[].
3929071d4279SBram Moolenaar */
3930071d4279SBram Moolenaar if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
3931071d4279SBram Moolenaar type = USE_REDRAW;
39324033c55eSBram Moolenaar else if (can_clear(T_CD) && result_empty)
3933071d4279SBram Moolenaar type = USE_T_CD;
3934071d4279SBram Moolenaar else if (row == 0 && (
3935071d4279SBram Moolenaar #ifndef AMIGA
393663d9e730SBram Moolenaar // On the Amiga, somehow '\n' on the last line doesn't always scroll
393763d9e730SBram Moolenaar // up, so use delete-line command
3938071d4279SBram Moolenaar line_count == 1 ||
3939071d4279SBram Moolenaar #endif
3940071d4279SBram Moolenaar *T_CDL == NUL))
3941071d4279SBram Moolenaar type = USE_NL;
3942071d4279SBram Moolenaar else if (*T_CDL != NUL && line_count > 1 && can_delete)
3943071d4279SBram Moolenaar type = USE_T_CDL;
3944071d4279SBram Moolenaar else if (can_clear(T_CE) && result_empty
39454033c55eSBram Moolenaar && (wp == NULL || wp->w_width == Columns))
3946071d4279SBram Moolenaar type = USE_T_CE;
3947071d4279SBram Moolenaar else if (*T_DL != NUL && can_delete)
3948071d4279SBram Moolenaar type = USE_T_DL;
3949071d4279SBram Moolenaar else if (*T_CDL != NUL && can_delete)
3950071d4279SBram Moolenaar type = USE_T_CDL;
3951071d4279SBram Moolenaar else
3952071d4279SBram Moolenaar return FAIL;
3953071d4279SBram Moolenaar
3954071d4279SBram Moolenaar #ifdef FEAT_CLIPBOARD
395563d9e730SBram Moolenaar // Remove a modeless selection when deleting lines halfway the screen or
395663d9e730SBram Moolenaar // not the full width of the screen.
39574033c55eSBram Moolenaar if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
3958c0885aadSBram Moolenaar clip_clear_selection(&clip_star);
3959071d4279SBram Moolenaar else
3960071d4279SBram Moolenaar clip_scroll_selection(line_count);
3961071d4279SBram Moolenaar #endif
3962071d4279SBram Moolenaar
396392c461efSBram Moolenaar #ifdef FEAT_GUI_HAIKU
396492c461efSBram Moolenaar vim_lock_screen();
396592c461efSBram Moolenaar #endif
396692c461efSBram Moolenaar
3967071d4279SBram Moolenaar #ifdef FEAT_GUI
396863d9e730SBram Moolenaar // Don't update the GUI cursor here, ScreenLines[] is invalid until the
396963d9e730SBram Moolenaar // scrolling is actually carried out.
3970107abd2cSBram Moolenaar gui_dont_update_cursor(gui.cursor_row >= row + off
3971107abd2cSBram Moolenaar && gui.cursor_row < end + off);
3972071d4279SBram Moolenaar #endif
3973071d4279SBram Moolenaar
3974bfa42467SBram Moolenaar if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
3975bfa42467SBram Moolenaar cursor_col = wp->w_wincol;
3976bfa42467SBram Moolenaar
397763d9e730SBram Moolenaar if (*T_CCS != NUL) // cursor relative to region
3978071d4279SBram Moolenaar {
3979071d4279SBram Moolenaar cursor_row = row;
3980071d4279SBram Moolenaar cursor_end = end;
3981071d4279SBram Moolenaar }
3982071d4279SBram Moolenaar else
3983071d4279SBram Moolenaar {
3984071d4279SBram Moolenaar cursor_row = row + off;
3985071d4279SBram Moolenaar cursor_end = end + off;
3986071d4279SBram Moolenaar }
3987071d4279SBram Moolenaar
3988071d4279SBram Moolenaar /*
3989071d4279SBram Moolenaar * Now shift LineOffset[] line_count up to reflect the deleted lines.
3990071d4279SBram Moolenaar * Clear the inserted lines in ScreenLines[].
3991071d4279SBram Moolenaar */
3992071d4279SBram Moolenaar row += off;
3993071d4279SBram Moolenaar end += off;
3994071d4279SBram Moolenaar for (i = 0; i < line_count; ++i)
3995071d4279SBram Moolenaar {
3996071d4279SBram Moolenaar if (wp != NULL && wp->w_width != Columns)
3997071d4279SBram Moolenaar {
399863d9e730SBram Moolenaar // need to copy part of a line
3999071d4279SBram Moolenaar j = row + i;
4000071d4279SBram Moolenaar while ((j += line_count) <= end - 1)
4001071d4279SBram Moolenaar linecopy(j - line_count, j, wp);
4002071d4279SBram Moolenaar j -= line_count;
4003071d4279SBram Moolenaar if (can_clear((char_u *)" "))
4004cfce7171SBram Moolenaar lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
4005cfce7171SBram Moolenaar clear_attr);
4006071d4279SBram Moolenaar else
4007071d4279SBram Moolenaar lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
4008071d4279SBram Moolenaar LineWraps[j] = FALSE;
4009071d4279SBram Moolenaar }
4010071d4279SBram Moolenaar else
4011071d4279SBram Moolenaar {
401263d9e730SBram Moolenaar // whole width, moving the line pointers is faster
4013071d4279SBram Moolenaar j = row + i;
4014071d4279SBram Moolenaar temp = LineOffset[j];
4015071d4279SBram Moolenaar while ((j += line_count) <= end - 1)
4016071d4279SBram Moolenaar {
4017071d4279SBram Moolenaar LineOffset[j - line_count] = LineOffset[j];
4018071d4279SBram Moolenaar LineWraps[j - line_count] = LineWraps[j];
4019071d4279SBram Moolenaar }
4020071d4279SBram Moolenaar LineOffset[j - line_count] = temp;
4021071d4279SBram Moolenaar LineWraps[j - line_count] = FALSE;
4022071d4279SBram Moolenaar if (can_clear((char_u *)" "))
4023cfce7171SBram Moolenaar lineclear(temp, (int)Columns, clear_attr);
4024071d4279SBram Moolenaar else
4025071d4279SBram Moolenaar lineinvalid(temp, (int)Columns);
4026071d4279SBram Moolenaar }
4027071d4279SBram Moolenaar }
4028071d4279SBram Moolenaar
4029b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
4030b3f74069SBram Moolenaar vim_unlock_screen();
4031b3f74069SBram Moolenaar #endif
4032b3f74069SBram Moolenaar
4033cfce7171SBram Moolenaar if (screen_attr != clear_attr)
4034071d4279SBram Moolenaar screen_stop_highlight();
4035cfce7171SBram Moolenaar if (clear_attr != 0)
4036cfce7171SBram Moolenaar screen_start_highlight(clear_attr);
4037071d4279SBram Moolenaar
403863d9e730SBram Moolenaar // redraw the characters
4039071d4279SBram Moolenaar if (type == USE_REDRAW)
4040071d4279SBram Moolenaar redraw_block(row, end, wp);
404163d9e730SBram Moolenaar else if (type == USE_T_CD) // delete the lines
4042071d4279SBram Moolenaar {
4043bfa42467SBram Moolenaar windgoto(cursor_row, cursor_col);
4044071d4279SBram Moolenaar out_str(T_CD);
404563d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
4046071d4279SBram Moolenaar }
4047071d4279SBram Moolenaar else if (type == USE_T_CDL)
4048071d4279SBram Moolenaar {
4049bfa42467SBram Moolenaar windgoto(cursor_row, cursor_col);
4050071d4279SBram Moolenaar term_delete_lines(line_count);
405163d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
4052071d4279SBram Moolenaar }
4053071d4279SBram Moolenaar /*
4054071d4279SBram Moolenaar * Deleting lines at top of the screen or scroll region: Just scroll
4055071d4279SBram Moolenaar * the whole screen (scroll region) up by outputting newlines on the
4056071d4279SBram Moolenaar * last line.
4057071d4279SBram Moolenaar */
4058071d4279SBram Moolenaar else if (type == USE_NL)
4059071d4279SBram Moolenaar {
4060bfa42467SBram Moolenaar windgoto(cursor_end - 1, cursor_col);
4061071d4279SBram Moolenaar for (i = line_count; --i >= 0; )
406263d9e730SBram Moolenaar out_char('\n'); // cursor will remain on same line
4063071d4279SBram Moolenaar }
4064071d4279SBram Moolenaar else
4065071d4279SBram Moolenaar {
4066071d4279SBram Moolenaar for (i = line_count; --i >= 0; )
4067071d4279SBram Moolenaar {
4068071d4279SBram Moolenaar if (type == USE_T_DL)
4069071d4279SBram Moolenaar {
4070bfa42467SBram Moolenaar windgoto(cursor_row, cursor_col);
407163d9e730SBram Moolenaar out_str(T_DL); // delete a line
4072071d4279SBram Moolenaar }
407363d9e730SBram Moolenaar else // type == USE_T_CE
4074071d4279SBram Moolenaar {
4075bfa42467SBram Moolenaar windgoto(cursor_row + i, cursor_col);
407663d9e730SBram Moolenaar out_str(T_CE); // erase a line
4077071d4279SBram Moolenaar }
407863d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
4079071d4279SBram Moolenaar }
4080071d4279SBram Moolenaar }
4081071d4279SBram Moolenaar
4082071d4279SBram Moolenaar /*
4083071d4279SBram Moolenaar * If the 'db' flag is set, we need to clear the lines that have been
4084071d4279SBram Moolenaar * scrolled up at the bottom of the region.
4085071d4279SBram Moolenaar */
4086071d4279SBram Moolenaar if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
4087071d4279SBram Moolenaar {
4088071d4279SBram Moolenaar for (i = line_count; i > 0; --i)
4089071d4279SBram Moolenaar {
4090bfa42467SBram Moolenaar windgoto(cursor_end - i, cursor_col);
409163d9e730SBram Moolenaar out_str(T_CE); // erase a line
409263d9e730SBram Moolenaar screen_start(); // don't know where cursor is now
4093071d4279SBram Moolenaar }
4094071d4279SBram Moolenaar }
4095071d4279SBram Moolenaar
4096071d4279SBram Moolenaar #ifdef FEAT_GUI
4097071d4279SBram Moolenaar gui_can_update_cursor();
4098071d4279SBram Moolenaar if (gui.in_use)
409963d9e730SBram Moolenaar out_flush(); // always flush after a scroll
4100071d4279SBram Moolenaar #endif
4101071d4279SBram Moolenaar
4102071d4279SBram Moolenaar return OK;
4103071d4279SBram Moolenaar }
4104071d4279SBram Moolenaar
4105071d4279SBram Moolenaar /*
4106cb574f41SBram Moolenaar * Return TRUE when postponing displaying the mode message: when not redrawing
4107cb574f41SBram Moolenaar * or inside a mapping.
4108cb574f41SBram Moolenaar */
4109cb574f41SBram Moolenaar int
skip_showmode()4110cb574f41SBram Moolenaar skip_showmode()
4111cb574f41SBram Moolenaar {
4112cb574f41SBram Moolenaar // Call char_avail() only when we are going to show something, because it
4113cb574f41SBram Moolenaar // takes a bit of time. redrawing() may also call char_avail_avail().
4114cb574f41SBram Moolenaar if (global_busy
4115cb574f41SBram Moolenaar || msg_silent != 0
4116cb574f41SBram Moolenaar || !redrawing()
4117cb574f41SBram Moolenaar || (char_avail() && !KeyTyped))
4118cb574f41SBram Moolenaar {
41194c25bd78SBram Moolenaar redraw_mode = TRUE; // show mode later
4120cb574f41SBram Moolenaar return TRUE;
4121cb574f41SBram Moolenaar }
4122cb574f41SBram Moolenaar return FALSE;
4123cb574f41SBram Moolenaar }
4124cb574f41SBram Moolenaar
4125cb574f41SBram Moolenaar /*
412681226e03SBram Moolenaar * Show the current mode and ruler.
4127071d4279SBram Moolenaar *
4128071d4279SBram Moolenaar * If clear_cmdline is TRUE, clear the rest of the cmdline.
4129071d4279SBram Moolenaar * If clear_cmdline is FALSE there may be a message there that needs to be
4130071d4279SBram Moolenaar * cleared only if a mode is shown.
41314c25bd78SBram Moolenaar * If redraw_mode is TRUE show or clear the mode.
4132071d4279SBram Moolenaar * Return the length of the message (0 if no message).
4133071d4279SBram Moolenaar */
4134071d4279SBram Moolenaar int
showmode(void)413505540976SBram Moolenaar showmode(void)
4136071d4279SBram Moolenaar {
4137071d4279SBram Moolenaar int need_clear;
4138071d4279SBram Moolenaar int length = 0;
4139071d4279SBram Moolenaar int do_mode;
4140071d4279SBram Moolenaar int attr;
4141071d4279SBram Moolenaar int nwr_save;
4142071d4279SBram Moolenaar int sub_attr;
4143071d4279SBram Moolenaar
41447df351ebSBram Moolenaar do_mode = ((p_smd && msg_silent == 0)
41457df351ebSBram Moolenaar && ((State & INSERT)
4146942b4541SBram Moolenaar || restart_edit != NUL
4147f7ff6e85SBram Moolenaar || VIsual_active));
41480b6d911eSBram Moolenaar if (do_mode || reg_recording != 0)
4149071d4279SBram Moolenaar {
4150cb574f41SBram Moolenaar if (skip_showmode())
4151cb574f41SBram Moolenaar return 0; // show mode later
4152071d4279SBram Moolenaar
4153071d4279SBram Moolenaar nwr_save = need_wait_return;
4154071d4279SBram Moolenaar
415563d9e730SBram Moolenaar // wait a bit before overwriting an important message
4156071d4279SBram Moolenaar check_for_delay(FALSE);
4157071d4279SBram Moolenaar
415863d9e730SBram Moolenaar // if the cmdline is more than one line high, erase top lines
4159071d4279SBram Moolenaar need_clear = clear_cmdline;
4160071d4279SBram Moolenaar if (clear_cmdline && cmdline_row < Rows - 1)
416163d9e730SBram Moolenaar msg_clr_cmdline(); // will reset clear_cmdline
4162071d4279SBram Moolenaar
416363d9e730SBram Moolenaar // Position on the last line in the window, column 0
4164071d4279SBram Moolenaar msg_pos_mode();
4165071d4279SBram Moolenaar cursor_off();
416663d9e730SBram Moolenaar attr = HL_ATTR(HLF_CM); // Highlight mode
4167071d4279SBram Moolenaar if (do_mode)
4168071d4279SBram Moolenaar {
416932526b3cSBram Moolenaar msg_puts_attr("--", attr);
4170071d4279SBram Moolenaar #if defined(FEAT_XIM)
4171c236c16dSBram Moolenaar if (
41720eda7ac7SBram Moolenaar # ifdef FEAT_GUI_GTK
4173c236c16dSBram Moolenaar preedit_get_status()
4174c236c16dSBram Moolenaar # else
4175c236c16dSBram Moolenaar im_get_status()
4176c236c16dSBram Moolenaar # endif
4177c236c16dSBram Moolenaar )
417863d9e730SBram Moolenaar # ifdef FEAT_GUI_GTK // most of the time, it's not XIM being used
417932526b3cSBram Moolenaar msg_puts_attr(" IM", attr);
4180071d4279SBram Moolenaar # else
418132526b3cSBram Moolenaar msg_puts_attr(" XIM", attr);
4182071d4279SBram Moolenaar # endif
4183071d4279SBram Moolenaar #endif
418463d9e730SBram Moolenaar // CTRL-X in Insert mode
4185ea389e91SBram Moolenaar if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
4186071d4279SBram Moolenaar {
418763d9e730SBram Moolenaar // These messages can get long, avoid a wrap in a narrow
418863d9e730SBram Moolenaar // window. Prefer showing edit_submode_extra.
4189071d4279SBram Moolenaar length = (Rows - msg_row) * Columns - 3;
4190071d4279SBram Moolenaar if (edit_submode_extra != NULL)
4191071d4279SBram Moolenaar length -= vim_strsize(edit_submode_extra);
4192071d4279SBram Moolenaar if (length > 0)
4193071d4279SBram Moolenaar {
4194071d4279SBram Moolenaar if (edit_submode_pre != NULL)
4195071d4279SBram Moolenaar length -= vim_strsize(edit_submode_pre);
4196071d4279SBram Moolenaar if (length - vim_strsize(edit_submode) > 0)
4197071d4279SBram Moolenaar {
4198071d4279SBram Moolenaar if (edit_submode_pre != NULL)
419932526b3cSBram Moolenaar msg_puts_attr((char *)edit_submode_pre, attr);
420032526b3cSBram Moolenaar msg_puts_attr((char *)edit_submode, attr);
4201071d4279SBram Moolenaar }
4202071d4279SBram Moolenaar if (edit_submode_extra != NULL)
4203071d4279SBram Moolenaar {
420463d9e730SBram Moolenaar msg_puts_attr(" ", attr); // add a space in between
4205071d4279SBram Moolenaar if ((int)edit_submode_highl < (int)HLF_COUNT)
42068820b486SBram Moolenaar sub_attr = HL_ATTR(edit_submode_highl);
4207071d4279SBram Moolenaar else
4208071d4279SBram Moolenaar sub_attr = attr;
420932526b3cSBram Moolenaar msg_puts_attr((char *)edit_submode_extra, sub_attr);
4210071d4279SBram Moolenaar }
4211071d4279SBram Moolenaar }
4212071d4279SBram Moolenaar }
4213071d4279SBram Moolenaar else
4214071d4279SBram Moolenaar {
4215071d4279SBram Moolenaar if (State & VREPLACE_FLAG)
421632526b3cSBram Moolenaar msg_puts_attr(_(" VREPLACE"), attr);
42171f0bfe56SBram Moolenaar else if (State & REPLACE_FLAG)
421832526b3cSBram Moolenaar msg_puts_attr(_(" REPLACE"), attr);
4219071d4279SBram Moolenaar else if (State & INSERT)
4220071d4279SBram Moolenaar {
4221071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
4222071d4279SBram Moolenaar if (p_ri)
422332526b3cSBram Moolenaar msg_puts_attr(_(" REVERSE"), attr);
4224071d4279SBram Moolenaar #endif
422532526b3cSBram Moolenaar msg_puts_attr(_(" INSERT"), attr);
4226071d4279SBram Moolenaar }
4227957cf67dSBram Moolenaar else if (restart_edit == 'I' || restart_edit == 'i' ||
4228957cf67dSBram Moolenaar restart_edit == 'a' || restart_edit == 'A')
422932526b3cSBram Moolenaar msg_puts_attr(_(" (insert)"), attr);
4230071d4279SBram Moolenaar else if (restart_edit == 'R')
423132526b3cSBram Moolenaar msg_puts_attr(_(" (replace)"), attr);
4232071d4279SBram Moolenaar else if (restart_edit == 'V')
423332526b3cSBram Moolenaar msg_puts_attr(_(" (vreplace)"), attr);
4234071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
4235071d4279SBram Moolenaar if (p_hkmap)
423632526b3cSBram Moolenaar msg_puts_attr(_(" Hebrew"), attr);
4237071d4279SBram Moolenaar #endif
4238071d4279SBram Moolenaar #ifdef FEAT_KEYMAP
4239071d4279SBram Moolenaar if (State & LANGMAP)
4240071d4279SBram Moolenaar {
4241071d4279SBram Moolenaar # ifdef FEAT_ARABIC
4242071d4279SBram Moolenaar if (curwin->w_p_arab)
424332526b3cSBram Moolenaar msg_puts_attr(_(" Arabic"), attr);
4244071d4279SBram Moolenaar else
4245071d4279SBram Moolenaar # endif
424673ac0c42SBram Moolenaar if (get_keymap_str(curwin, (char_u *)" (%s)",
424773ac0c42SBram Moolenaar NameBuff, MAXPATHL))
424832526b3cSBram Moolenaar msg_puts_attr((char *)NameBuff, attr);
4249071d4279SBram Moolenaar }
4250071d4279SBram Moolenaar #endif
4251071d4279SBram Moolenaar if ((State & INSERT) && p_paste)
425232526b3cSBram Moolenaar msg_puts_attr(_(" (paste)"), attr);
4253071d4279SBram Moolenaar
4254071d4279SBram Moolenaar if (VIsual_active)
4255071d4279SBram Moolenaar {
4256071d4279SBram Moolenaar char *p;
4257071d4279SBram Moolenaar
425863d9e730SBram Moolenaar // Don't concatenate separate words to avoid translation
425963d9e730SBram Moolenaar // problems.
4260071d4279SBram Moolenaar switch ((VIsual_select ? 4 : 0)
4261071d4279SBram Moolenaar + (VIsual_mode == Ctrl_V) * 2
4262071d4279SBram Moolenaar + (VIsual_mode == 'V'))
4263071d4279SBram Moolenaar {
4264071d4279SBram Moolenaar case 0: p = N_(" VISUAL"); break;
4265071d4279SBram Moolenaar case 1: p = N_(" VISUAL LINE"); break;
4266071d4279SBram Moolenaar case 2: p = N_(" VISUAL BLOCK"); break;
4267071d4279SBram Moolenaar case 4: p = N_(" SELECT"); break;
4268071d4279SBram Moolenaar case 5: p = N_(" SELECT LINE"); break;
4269071d4279SBram Moolenaar default: p = N_(" SELECT BLOCK"); break;
4270071d4279SBram Moolenaar }
427132526b3cSBram Moolenaar msg_puts_attr(_(p), attr);
4272071d4279SBram Moolenaar }
427332526b3cSBram Moolenaar msg_puts_attr(" --", attr);
4274071d4279SBram Moolenaar }
4275d12f5c17SBram Moolenaar
4276071d4279SBram Moolenaar need_clear = TRUE;
4277071d4279SBram Moolenaar }
42780b6d911eSBram Moolenaar if (reg_recording != 0
4279e2c453d3SBram Moolenaar && edit_submode == NULL) // otherwise it gets too long
4280071d4279SBram Moolenaar {
4281a0ed84a2SBram Moolenaar recording_mode(attr);
4282071d4279SBram Moolenaar need_clear = TRUE;
4283071d4279SBram Moolenaar }
4284d12f5c17SBram Moolenaar
4285d12f5c17SBram Moolenaar mode_displayed = TRUE;
42864c25bd78SBram Moolenaar if (need_clear || clear_cmdline || redraw_mode)
4287071d4279SBram Moolenaar msg_clr_eos();
428863d9e730SBram Moolenaar msg_didout = FALSE; // overwrite this message
4289071d4279SBram Moolenaar length = msg_col;
4290071d4279SBram Moolenaar msg_col = 0;
429163d9e730SBram Moolenaar need_wait_return = nwr_save; // never ask for hit-return for this
4292071d4279SBram Moolenaar }
4293071d4279SBram Moolenaar else if (clear_cmdline && msg_silent == 0)
429463d9e730SBram Moolenaar // Clear the whole command line. Will reset "clear_cmdline".
4295071d4279SBram Moolenaar msg_clr_cmdline();
42964c25bd78SBram Moolenaar else if (redraw_mode)
42974c25bd78SBram Moolenaar {
42984c25bd78SBram Moolenaar msg_pos_mode();
42994c25bd78SBram Moolenaar msg_clr_eos();
43004c25bd78SBram Moolenaar }
4301071d4279SBram Moolenaar
4302071d4279SBram Moolenaar #ifdef FEAT_CMDL_INFO
430363d9e730SBram Moolenaar // In Visual mode the size of the selected area must be redrawn.
4304071d4279SBram Moolenaar if (VIsual_active)
4305071d4279SBram Moolenaar clear_showcmd();
4306071d4279SBram Moolenaar
430763d9e730SBram Moolenaar // If the last window has no status line, the ruler is after the mode
430863d9e730SBram Moolenaar // message and must be redrawn
43094033c55eSBram Moolenaar if (redrawing() && lastwin->w_status_height == 0)
4310491ac28dSBram Moolenaar win_redr_ruler(lastwin, TRUE, FALSE);
4311071d4279SBram Moolenaar #endif
4312071d4279SBram Moolenaar redraw_cmdline = FALSE;
43134c25bd78SBram Moolenaar redraw_mode = FALSE;
4314071d4279SBram Moolenaar clear_cmdline = FALSE;
4315071d4279SBram Moolenaar
4316071d4279SBram Moolenaar return length;
4317071d4279SBram Moolenaar }
4318071d4279SBram Moolenaar
4319071d4279SBram Moolenaar /*
4320071d4279SBram Moolenaar * Position for a mode message.
4321071d4279SBram Moolenaar */
4322071d4279SBram Moolenaar static void
msg_pos_mode(void)432305540976SBram Moolenaar msg_pos_mode(void)
4324071d4279SBram Moolenaar {
4325071d4279SBram Moolenaar msg_col = 0;
4326071d4279SBram Moolenaar msg_row = Rows - 1;
4327071d4279SBram Moolenaar }
4328071d4279SBram Moolenaar
4329071d4279SBram Moolenaar /*
4330071d4279SBram Moolenaar * Delete mode message. Used when ESC is typed which is expected to end
4331071d4279SBram Moolenaar * Insert mode (but Insert mode didn't end yet!).
4332d12f5c17SBram Moolenaar * Caller should check "mode_displayed".
4333071d4279SBram Moolenaar */
4334071d4279SBram Moolenaar void
unshowmode(int force)433505540976SBram Moolenaar unshowmode(int force)
4336071d4279SBram Moolenaar {
4337071d4279SBram Moolenaar /*
4338e4ebd29eSBram Moolenaar * Don't delete it right now, when not redrawing or inside a mapping.
4339071d4279SBram Moolenaar */
4340071d4279SBram Moolenaar if (!redrawing() || (!force && char_avail() && !KeyTyped))
434163d9e730SBram Moolenaar redraw_cmdline = TRUE; // delete mode later
4342071d4279SBram Moolenaar else
4343fd773e9eSBram Moolenaar clearmode();
4344fd773e9eSBram Moolenaar }
4345fd773e9eSBram Moolenaar
4346fd773e9eSBram Moolenaar /*
4347fd773e9eSBram Moolenaar * Clear the mode message.
4348fd773e9eSBram Moolenaar */
4349fd773e9eSBram Moolenaar void
clearmode(void)4350cf089463SBram Moolenaar clearmode(void)
4351071d4279SBram Moolenaar {
43522abad54cSBram Moolenaar int save_msg_row = msg_row;
43532abad54cSBram Moolenaar int save_msg_col = msg_col;
43542abad54cSBram Moolenaar
4355071d4279SBram Moolenaar msg_pos_mode();
43560b6d911eSBram Moolenaar if (reg_recording != 0)
43578820b486SBram Moolenaar recording_mode(HL_ATTR(HLF_CM));
4358071d4279SBram Moolenaar msg_clr_eos();
43592abad54cSBram Moolenaar
43602abad54cSBram Moolenaar msg_col = save_msg_col;
43612abad54cSBram Moolenaar msg_row = save_msg_row;
4362071d4279SBram Moolenaar }
4363071d4279SBram Moolenaar
4364a0ed84a2SBram Moolenaar static void
recording_mode(int attr)436505540976SBram Moolenaar recording_mode(int attr)
4366a0ed84a2SBram Moolenaar {
436732526b3cSBram Moolenaar msg_puts_attr(_("recording"), attr);
4368a0ed84a2SBram Moolenaar if (!shortmess(SHM_RECORDING))
4369a0ed84a2SBram Moolenaar {
437032526b3cSBram Moolenaar char s[4];
437132526b3cSBram Moolenaar
437232526b3cSBram Moolenaar sprintf(s, " @%c", reg_recording);
437332526b3cSBram Moolenaar msg_puts_attr(s, attr);
4374a0ed84a2SBram Moolenaar }
4375a0ed84a2SBram Moolenaar }
4376a0ed84a2SBram Moolenaar
43771d2ba7faSBram Moolenaar /*
43781d2ba7faSBram Moolenaar * Draw the tab pages line at the top of the Vim window.
43791d2ba7faSBram Moolenaar */
4380e12bab31SBram Moolenaar void
draw_tabline(void)438105540976SBram Moolenaar draw_tabline(void)
43821d2ba7faSBram Moolenaar {
43831d2ba7faSBram Moolenaar int tabcount = 0;
43841d2ba7faSBram Moolenaar tabpage_T *tp;
43851d2ba7faSBram Moolenaar int tabwidth;
43861d2ba7faSBram Moolenaar int col = 0;
4387997fb4baSBram Moolenaar int scol = 0;
43881d2ba7faSBram Moolenaar int attr;
43891d2ba7faSBram Moolenaar win_T *wp;
4390f740b29aSBram Moolenaar win_T *cwp;
4391f740b29aSBram Moolenaar int wincount;
4392f740b29aSBram Moolenaar int modified;
43931d2ba7faSBram Moolenaar int c;
43941d2ba7faSBram Moolenaar int len;
43958820b486SBram Moolenaar int attr_sel = HL_ATTR(HLF_TPS);
43968820b486SBram Moolenaar int attr_nosel = HL_ATTR(HLF_TP);
43978820b486SBram Moolenaar int attr_fill = HL_ATTR(HLF_TPF);
4398997fb4baSBram Moolenaar char_u *p;
4399faa959a8SBram Moolenaar int room;
4400faa959a8SBram Moolenaar int use_sep_chars = (t_colors < 8
4401faa959a8SBram Moolenaar #ifdef FEAT_GUI
4402faa959a8SBram Moolenaar && !gui.in_use
4403faa959a8SBram Moolenaar #endif
440461be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
440561be73bbSBram Moolenaar && !p_tgc
44068a633e34SBram Moolenaar #endif
4407faa959a8SBram Moolenaar );
44081d2ba7faSBram Moolenaar
4409c695cec4SBram Moolenaar if (ScreenLines == NULL)
4410c695cec4SBram Moolenaar return;
4411997fb4baSBram Moolenaar redraw_tabline = FALSE;
44121d2ba7faSBram Moolenaar
441332466aa2SBram Moolenaar #ifdef FEAT_GUI_TABLINE
441463d9e730SBram Moolenaar // Take care of a GUI tabline.
441532466aa2SBram Moolenaar if (gui_use_tabline())
441632466aa2SBram Moolenaar {
441732466aa2SBram Moolenaar gui_update_tabline();
441832466aa2SBram Moolenaar return;
441932466aa2SBram Moolenaar }
442032466aa2SBram Moolenaar #endif
442132466aa2SBram Moolenaar
442232466aa2SBram Moolenaar if (tabline_height() < 1)
44231d2ba7faSBram Moolenaar return;
44241d2ba7faSBram Moolenaar
4425faa959a8SBram Moolenaar #if defined(FEAT_STL_OPT)
4426ca57ab54SBram Moolenaar clear_TabPageIdxs();
4427d1f56e68SBram Moolenaar
442863d9e730SBram Moolenaar // Use the 'tabline' option if it's set.
4429faa959a8SBram Moolenaar if (*p_tal != NUL)
4430faa959a8SBram Moolenaar {
4431f73d3bc2SBram Moolenaar int saved_did_emsg = did_emsg;
4432faa959a8SBram Moolenaar
443363d9e730SBram Moolenaar // Check for an error. If there is one we would loop in redrawing the
443463d9e730SBram Moolenaar // screen. Avoid that by making 'tabline' empty.
4435f73d3bc2SBram Moolenaar did_emsg = FALSE;
4436238a5649SBram Moolenaar win_redr_custom(NULL, FALSE);
4437f73d3bc2SBram Moolenaar if (did_emsg)
4438238a5649SBram Moolenaar set_string_option_direct((char_u *)"tabline", -1,
44395e3cb7e8SBram Moolenaar (char_u *)"", OPT_FREE, SID_ERROR);
4440f73d3bc2SBram Moolenaar did_emsg |= saved_did_emsg;
4441238a5649SBram Moolenaar }
4442238a5649SBram Moolenaar else
4443238a5649SBram Moolenaar #endif
4444238a5649SBram Moolenaar {
444529323590SBram Moolenaar FOR_ALL_TABPAGES(tp)
44461d2ba7faSBram Moolenaar ++tabcount;
44471d2ba7faSBram Moolenaar
4448f740b29aSBram Moolenaar tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
44491d2ba7faSBram Moolenaar if (tabwidth < 6)
44501d2ba7faSBram Moolenaar tabwidth = 6;
44511d2ba7faSBram Moolenaar
44521d2ba7faSBram Moolenaar attr = attr_nosel;
4453f740b29aSBram Moolenaar tabcount = 0;
4454fd2ac767SBram Moolenaar for (tp = first_tabpage; tp != NULL && col < Columns - 4;
4455fd2ac767SBram Moolenaar tp = tp->tp_next)
44561d2ba7faSBram Moolenaar {
4457f740b29aSBram Moolenaar scol = col;
4458f740b29aSBram Moolenaar
44591d2ba7faSBram Moolenaar if (tp->tp_topframe == topframe)
44601d2ba7faSBram Moolenaar attr = attr_sel;
4461faa959a8SBram Moolenaar if (use_sep_chars && col > 0)
4462faa959a8SBram Moolenaar screen_putchar('|', 0, col++, attr);
44631d2ba7faSBram Moolenaar
44641d2ba7faSBram Moolenaar if (tp->tp_topframe != topframe)
44651d2ba7faSBram Moolenaar attr = attr_nosel;
44661d2ba7faSBram Moolenaar
44674c7ed462SBram Moolenaar screen_putchar(' ', 0, col++, attr);
44684c7ed462SBram Moolenaar
4469238a5649SBram Moolenaar if (tp == curtab)
4470f740b29aSBram Moolenaar {
4471f740b29aSBram Moolenaar cwp = curwin;
4472f740b29aSBram Moolenaar wp = firstwin;
4473f740b29aSBram Moolenaar }
44741d2ba7faSBram Moolenaar else
4475f740b29aSBram Moolenaar {
4476f740b29aSBram Moolenaar cwp = tp->tp_curwin;
4477f740b29aSBram Moolenaar wp = tp->tp_firstwin;
4478f740b29aSBram Moolenaar }
4479f740b29aSBram Moolenaar
4480f740b29aSBram Moolenaar modified = FALSE;
4481f740b29aSBram Moolenaar for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
4482f740b29aSBram Moolenaar if (bufIsChanged(wp->w_buffer))
4483f740b29aSBram Moolenaar modified = TRUE;
4484f740b29aSBram Moolenaar if (modified || wincount > 1)
4485f740b29aSBram Moolenaar {
4486f740b29aSBram Moolenaar if (wincount > 1)
4487f740b29aSBram Moolenaar {
4488faa959a8SBram Moolenaar vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
4489a93fa7eeSBram Moolenaar len = (int)STRLEN(NameBuff);
4490fd2ac767SBram Moolenaar if (col + len >= Columns - 3)
4491fd2ac767SBram Moolenaar break;
4492faa959a8SBram Moolenaar screen_puts_len(NameBuff, len, 0, col,
4493faa959a8SBram Moolenaar #if defined(FEAT_SYN_HL)
44948820b486SBram Moolenaar hl_combine_attr(attr, HL_ATTR(HLF_T))
4495faa959a8SBram Moolenaar #else
4496faa959a8SBram Moolenaar attr
4497faa959a8SBram Moolenaar #endif
4498faa959a8SBram Moolenaar );
4499f740b29aSBram Moolenaar col += len;
4500f740b29aSBram Moolenaar }
4501f740b29aSBram Moolenaar if (modified)
4502faa959a8SBram Moolenaar screen_puts_len((char_u *)"+", 1, 0, col++, attr);
4503f740b29aSBram Moolenaar screen_putchar(' ', 0, col++, attr);
4504f740b29aSBram Moolenaar }
4505f740b29aSBram Moolenaar
4506faa959a8SBram Moolenaar room = scol - col + tabwidth - 1;
4507faa959a8SBram Moolenaar if (room > 0)
4508faa959a8SBram Moolenaar {
450963d9e730SBram Moolenaar // Get buffer name in NameBuff[]
451032466aa2SBram Moolenaar get_trans_bufname(cwp->w_buffer);
4511910f66f9SBram Moolenaar shorten_dir(NameBuff);
4512faa959a8SBram Moolenaar len = vim_strsize(NameBuff);
4513997fb4baSBram Moolenaar p = NameBuff;
4514faa959a8SBram Moolenaar if (has_mbyte)
4515faa959a8SBram Moolenaar while (len > room)
4516997fb4baSBram Moolenaar {
4517faa959a8SBram Moolenaar len -= ptr2cells(p);
451891acfffcSBram Moolenaar MB_PTR_ADV(p);
4519997fb4baSBram Moolenaar }
4520a12a161bSBram Moolenaar else if (len > room)
4521f740b29aSBram Moolenaar {
4522faa959a8SBram Moolenaar p += len - room;
4523faa959a8SBram Moolenaar len = room;
4524faa959a8SBram Moolenaar }
4525fd2ac767SBram Moolenaar if (len > Columns - col - 1)
4526fd2ac767SBram Moolenaar len = Columns - col - 1;
4527faa959a8SBram Moolenaar
4528a93fa7eeSBram Moolenaar screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
45291d2ba7faSBram Moolenaar col += len;
4530f740b29aSBram Moolenaar }
45314c7ed462SBram Moolenaar screen_putchar(' ', 0, col++, attr);
4532f740b29aSBram Moolenaar
453363d9e730SBram Moolenaar // Store the tab page number in TabPageIdxs[], so that
453463d9e730SBram Moolenaar // jump_to_mouse() knows where each one is.
4535f740b29aSBram Moolenaar ++tabcount;
4536f740b29aSBram Moolenaar while (scol < col)
4537f740b29aSBram Moolenaar TabPageIdxs[scol++] = tabcount;
45381d2ba7faSBram Moolenaar }
45391d2ba7faSBram Moolenaar
4540faa959a8SBram Moolenaar if (use_sep_chars)
45414c7ed462SBram Moolenaar c = '_';
45424c7ed462SBram Moolenaar else
45434c7ed462SBram Moolenaar c = ' ';
45444c7ed462SBram Moolenaar screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
4545f740b29aSBram Moolenaar
454663d9e730SBram Moolenaar // Put an "X" for closing the current tab if there are several.
4547f740b29aSBram Moolenaar if (first_tabpage->tp_next != NULL)
4548d1f56e68SBram Moolenaar {
4549f740b29aSBram Moolenaar screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
4550d1f56e68SBram Moolenaar TabPageIdxs[Columns - 1] = -999;
4551d1f56e68SBram Moolenaar }
4552d1f56e68SBram Moolenaar }
4553b21e5843SBram Moolenaar
455463d9e730SBram Moolenaar // Reset the flag here again, in case evaluating 'tabline' causes it to be
455563d9e730SBram Moolenaar // set.
4556b21e5843SBram Moolenaar redraw_tabline = FALSE;
45571d2ba7faSBram Moolenaar }
455832466aa2SBram Moolenaar
455932466aa2SBram Moolenaar /*
456032466aa2SBram Moolenaar * Get buffer name for "buf" into NameBuff[].
456132466aa2SBram Moolenaar * Takes care of special buffer names and translates special characters.
456232466aa2SBram Moolenaar */
456332466aa2SBram Moolenaar void
get_trans_bufname(buf_T * buf)456405540976SBram Moolenaar get_trans_bufname(buf_T *buf)
456532466aa2SBram Moolenaar {
456632466aa2SBram Moolenaar if (buf_spname(buf) != NULL)
4567e1704badSBram Moolenaar vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
456832466aa2SBram Moolenaar else
456932466aa2SBram Moolenaar home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
457032466aa2SBram Moolenaar trans_characters(NameBuff, MAXPATHL);
457132466aa2SBram Moolenaar }
45721d2ba7faSBram Moolenaar
4573071d4279SBram Moolenaar /*
4574071d4279SBram Moolenaar * Get the character to use in a status line. Get its attributes in "*attr".
4575071d4279SBram Moolenaar */
45767528d1f6SBram Moolenaar int
fillchar_status(int * attr,win_T * wp)45773633cf52SBram Moolenaar fillchar_status(int *attr, win_T *wp)
4578071d4279SBram Moolenaar {
4579071d4279SBram Moolenaar int fill;
45803633cf52SBram Moolenaar
45813633cf52SBram Moolenaar #ifdef FEAT_TERMINAL
45823633cf52SBram Moolenaar if (bt_terminal(wp->w_buffer))
45833633cf52SBram Moolenaar {
45843633cf52SBram Moolenaar if (wp == curwin)
458505fbfdcdSBram Moolenaar {
458605fbfdcdSBram Moolenaar *attr = HL_ATTR(HLF_ST);
45873633cf52SBram Moolenaar fill = fill_stl;
458805fbfdcdSBram Moolenaar }
45893633cf52SBram Moolenaar else
459005fbfdcdSBram Moolenaar {
459105fbfdcdSBram Moolenaar *attr = HL_ATTR(HLF_STNC);
45923633cf52SBram Moolenaar fill = fill_stlnc;
45933633cf52SBram Moolenaar }
459405fbfdcdSBram Moolenaar }
45953633cf52SBram Moolenaar else
45963633cf52SBram Moolenaar #endif
45973633cf52SBram Moolenaar if (wp == curwin)
4598071d4279SBram Moolenaar {
45998820b486SBram Moolenaar *attr = HL_ATTR(HLF_S);
4600071d4279SBram Moolenaar fill = fill_stl;
4601071d4279SBram Moolenaar }
4602071d4279SBram Moolenaar else
4603071d4279SBram Moolenaar {
46048820b486SBram Moolenaar *attr = HL_ATTR(HLF_SNC);
4605071d4279SBram Moolenaar fill = fill_stlnc;
4606071d4279SBram Moolenaar }
460763d9e730SBram Moolenaar // Use fill when there is highlighting, and highlighting of current
460863d9e730SBram Moolenaar // window differs, or the fillchars differ, or this is not the
460963d9e730SBram Moolenaar // current window
46108820b486SBram Moolenaar if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
46113633cf52SBram Moolenaar || wp != curwin || ONE_WINDOW)
4612071d4279SBram Moolenaar || (fill_stl != fill_stlnc)))
4613071d4279SBram Moolenaar return fill;
46143633cf52SBram Moolenaar if (wp == curwin)
4615071d4279SBram Moolenaar return '^';
4616071d4279SBram Moolenaar return '=';
4617071d4279SBram Moolenaar }
4618071d4279SBram Moolenaar
4619071d4279SBram Moolenaar /*
4620071d4279SBram Moolenaar * Get the character to use in a separator between vertically split windows.
4621071d4279SBram Moolenaar * Get its attributes in "*attr".
4622071d4279SBram Moolenaar */
46237528d1f6SBram Moolenaar int
fillchar_vsep(int * attr)462405540976SBram Moolenaar fillchar_vsep(int *attr)
4625071d4279SBram Moolenaar {
46268820b486SBram Moolenaar *attr = HL_ATTR(HLF_C);
4627071d4279SBram Moolenaar if (*attr == 0 && fill_vert == ' ')
4628071d4279SBram Moolenaar return '|';
4629071d4279SBram Moolenaar else
4630071d4279SBram Moolenaar return fill_vert;
4631071d4279SBram Moolenaar }
4632071d4279SBram Moolenaar
4633071d4279SBram Moolenaar /*
4634071d4279SBram Moolenaar * Return TRUE if redrawing should currently be done.
4635071d4279SBram Moolenaar */
4636071d4279SBram Moolenaar int
redrawing(void)463705540976SBram Moolenaar redrawing(void)
4638071d4279SBram Moolenaar {
4639eb992cb9SBram Moolenaar #ifdef FEAT_EVAL
4640eb992cb9SBram Moolenaar if (disable_redraw_for_testing)
4641eb992cb9SBram Moolenaar return 0;
4642eb992cb9SBram Moolenaar else
4643eb992cb9SBram Moolenaar #endif
4644ed5a9d66SBram Moolenaar return ((!RedrawingDisabled
4645ed5a9d66SBram Moolenaar #ifdef FEAT_EVAL
4646ed5a9d66SBram Moolenaar || ignore_redraw_flag_for_testing
4647ed5a9d66SBram Moolenaar #endif
4648ed5a9d66SBram Moolenaar ) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
4649071d4279SBram Moolenaar }
4650071d4279SBram Moolenaar
4651071d4279SBram Moolenaar /*
4652071d4279SBram Moolenaar * Return TRUE if printing messages should currently be done.
4653071d4279SBram Moolenaar */
4654071d4279SBram Moolenaar int
messaging(void)465505540976SBram Moolenaar messaging(void)
4656071d4279SBram Moolenaar {
4657071d4279SBram Moolenaar return (!(p_lz && char_avail() && !KeyTyped));
4658071d4279SBram Moolenaar }
4659071d4279SBram Moolenaar
4660e677df8dSBram Moolenaar /*
4661e677df8dSBram Moolenaar * Compute columns for ruler and shown command. 'sc_col' is also used to
4662e677df8dSBram Moolenaar * decide what the maximum length of a message on the status line can be.
4663e677df8dSBram Moolenaar * If there is a status line for the last window, 'sc_col' is independent
4664e677df8dSBram Moolenaar * of 'ru_col'.
4665e677df8dSBram Moolenaar */
4666e677df8dSBram Moolenaar
4667e677df8dSBram Moolenaar #define COL_RULER 17 // columns needed by standard ruler
4668e677df8dSBram Moolenaar
4669e677df8dSBram Moolenaar void
comp_col(void)4670e677df8dSBram Moolenaar comp_col(void)
4671e677df8dSBram Moolenaar {
4672e677df8dSBram Moolenaar #if defined(FEAT_CMDL_INFO)
4673e677df8dSBram Moolenaar int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
4674e677df8dSBram Moolenaar
4675e677df8dSBram Moolenaar sc_col = 0;
4676e677df8dSBram Moolenaar ru_col = 0;
4677e677df8dSBram Moolenaar if (p_ru)
4678e677df8dSBram Moolenaar {
4679e677df8dSBram Moolenaar # ifdef FEAT_STL_OPT
4680e677df8dSBram Moolenaar ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
4681e677df8dSBram Moolenaar # else
4682e677df8dSBram Moolenaar ru_col = COL_RULER + 1;
4683e677df8dSBram Moolenaar # endif
4684e677df8dSBram Moolenaar // no last status line, adjust sc_col
4685e677df8dSBram Moolenaar if (!last_has_status)
4686e677df8dSBram Moolenaar sc_col = ru_col;
4687e677df8dSBram Moolenaar }
4688e677df8dSBram Moolenaar if (p_sc)
4689e677df8dSBram Moolenaar {
4690e677df8dSBram Moolenaar sc_col += SHOWCMD_COLS;
4691e677df8dSBram Moolenaar if (!p_ru || last_has_status) // no need for separating space
4692e677df8dSBram Moolenaar ++sc_col;
4693e677df8dSBram Moolenaar }
4694e677df8dSBram Moolenaar sc_col = Columns - sc_col;
4695e677df8dSBram Moolenaar ru_col = Columns - ru_col;
4696e677df8dSBram Moolenaar if (sc_col <= 0) // screen too narrow, will become a mess
4697e677df8dSBram Moolenaar sc_col = 1;
4698e677df8dSBram Moolenaar if (ru_col <= 0)
4699e677df8dSBram Moolenaar ru_col = 1;
4700e677df8dSBram Moolenaar #else
4701e677df8dSBram Moolenaar sc_col = Columns;
4702e677df8dSBram Moolenaar ru_col = Columns;
4703e677df8dSBram Moolenaar #endif
4704e677df8dSBram Moolenaar #ifdef FEAT_EVAL
4705e677df8dSBram Moolenaar set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
4706e677df8dSBram Moolenaar #endif
4707e677df8dSBram Moolenaar }
4708e677df8dSBram Moolenaar
4709592e0a2aSBram Moolenaar #if defined(FEAT_LINEBREAK) || defined(PROTO)
4710592e0a2aSBram Moolenaar /*
471164486671SBram Moolenaar * Return the width of the 'number' and 'relativenumber' column.
471264486671SBram Moolenaar * Caller may need to check if 'number' or 'relativenumber' is set.
4713592e0a2aSBram Moolenaar * Otherwise it depends on 'numberwidth' and the line count.
4714592e0a2aSBram Moolenaar */
4715592e0a2aSBram Moolenaar int
number_width(win_T * wp)471605540976SBram Moolenaar number_width(win_T *wp)
4717592e0a2aSBram Moolenaar {
4718592e0a2aSBram Moolenaar int n;
4719592e0a2aSBram Moolenaar linenr_T lnum;
4720592e0a2aSBram Moolenaar
47215ebc09b4SBram Moolenaar if (wp->w_p_rnu && !wp->w_p_nu)
472263d9e730SBram Moolenaar // cursor line shows "0"
47235ebc09b4SBram Moolenaar lnum = wp->w_height;
47245ebc09b4SBram Moolenaar else
472563d9e730SBram Moolenaar // cursor line shows absolute line number
4726592e0a2aSBram Moolenaar lnum = wp->w_buffer->b_ml.ml_line_count;
472764486671SBram Moolenaar
47286b31467aSBram Moolenaar if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
4729592e0a2aSBram Moolenaar return wp->w_nrwidth_width;
4730592e0a2aSBram Moolenaar wp->w_nrwidth_line_count = lnum;
4731592e0a2aSBram Moolenaar
4732592e0a2aSBram Moolenaar n = 0;
4733592e0a2aSBram Moolenaar do
4734592e0a2aSBram Moolenaar {
4735592e0a2aSBram Moolenaar lnum /= 10;
4736592e0a2aSBram Moolenaar ++n;
4737592e0a2aSBram Moolenaar } while (lnum > 0);
4738592e0a2aSBram Moolenaar
473963d9e730SBram Moolenaar // 'numberwidth' gives the minimal width plus one
4740592e0a2aSBram Moolenaar if (n < wp->w_p_nuw - 1)
4741592e0a2aSBram Moolenaar n = wp->w_p_nuw - 1;
4742592e0a2aSBram Moolenaar
4743e4b407f5SBram Moolenaar # ifdef FEAT_SIGNS
4744e4b407f5SBram Moolenaar // If 'signcolumn' is set to 'number' and there is a sign to display, then
4745e4b407f5SBram Moolenaar // the minimal width for the number column is 2.
47464eb7dae2SBram Moolenaar if (n < 2 && get_first_valid_sign(wp) != NULL
4747e4b407f5SBram Moolenaar && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'))
4748e4b407f5SBram Moolenaar n = 2;
4749e4b407f5SBram Moolenaar # endif
4750e4b407f5SBram Moolenaar
4751592e0a2aSBram Moolenaar wp->w_nrwidth_width = n;
47526b31467aSBram Moolenaar wp->w_nuw_cached = wp->w_p_nuw;
4753592e0a2aSBram Moolenaar return n;
4754592e0a2aSBram Moolenaar }
4755592e0a2aSBram Moolenaar #endif
47569750bb19SBram Moolenaar
4757113e1072SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
47589750bb19SBram Moolenaar /*
47599750bb19SBram Moolenaar * Return the current cursor column. This is the actual position on the
47609750bb19SBram Moolenaar * screen. First column is 0.
47619750bb19SBram Moolenaar */
47629750bb19SBram Moolenaar int
screen_screencol(void)476305540976SBram Moolenaar screen_screencol(void)
47649750bb19SBram Moolenaar {
47659750bb19SBram Moolenaar return screen_cur_col;
47669750bb19SBram Moolenaar }
47679750bb19SBram Moolenaar
47689750bb19SBram Moolenaar /*
47699750bb19SBram Moolenaar * Return the current cursor row. This is the actual position on the screen.
47709750bb19SBram Moolenaar * First row is 0.
47719750bb19SBram Moolenaar */
47729750bb19SBram Moolenaar int
screen_screenrow(void)477305540976SBram Moolenaar screen_screenrow(void)
47749750bb19SBram Moolenaar {
47759750bb19SBram Moolenaar return screen_cur_row;
47769750bb19SBram Moolenaar }
4777113e1072SBram Moolenaar #endif
4778e677df8dSBram Moolenaar
4779e677df8dSBram Moolenaar /*
478093ff6720SBram Moolenaar * Calls mb_ptr2char_adv(p) and returns the character.
478193ff6720SBram Moolenaar * If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
478293ff6720SBram Moolenaar */
478393ff6720SBram Moolenaar static int
get_encoded_char_adv(char_u ** p)478493ff6720SBram Moolenaar get_encoded_char_adv(char_u **p)
478593ff6720SBram Moolenaar {
478693ff6720SBram Moolenaar char_u *s = *p;
478793ff6720SBram Moolenaar
478893ff6720SBram Moolenaar if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U'))
478993ff6720SBram Moolenaar {
479093ff6720SBram Moolenaar varnumber_T num = 0;
479193ff6720SBram Moolenaar int bytes;
479293ff6720SBram Moolenaar int n;
479393ff6720SBram Moolenaar
479493ff6720SBram Moolenaar for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; --bytes)
479593ff6720SBram Moolenaar {
479693ff6720SBram Moolenaar *p += 2;
479793ff6720SBram Moolenaar n = hexhex2nr(*p);
479893ff6720SBram Moolenaar if (n < 0)
479993ff6720SBram Moolenaar return 0;
480093ff6720SBram Moolenaar num = num * 256 + n;
480193ff6720SBram Moolenaar }
480293ff6720SBram Moolenaar *p += 2;
480393ff6720SBram Moolenaar return num;
480493ff6720SBram Moolenaar }
480593ff6720SBram Moolenaar return mb_ptr2char_adv(p);
480693ff6720SBram Moolenaar }
480793ff6720SBram Moolenaar
480893ff6720SBram Moolenaar /*
4809e677df8dSBram Moolenaar * Handle setting 'listchars' or 'fillchars'.
4810eed9d462SBram Moolenaar * Assume monocell characters.
4811e677df8dSBram Moolenaar * Returns error message, NULL if it's OK.
4812e677df8dSBram Moolenaar */
4813e677df8dSBram Moolenaar char *
set_chars_option(win_T * wp,char_u ** varp)4814eed9d462SBram Moolenaar set_chars_option(win_T *wp, char_u **varp)
4815e677df8dSBram Moolenaar {
4816e677df8dSBram Moolenaar int round, i, len, entries;
4817e677df8dSBram Moolenaar char_u *p, *s;
4818e677df8dSBram Moolenaar int c1 = 0, c2 = 0, c3 = 0;
481956e14698SBram Moolenaar char_u *last_multispace = NULL; // Last occurrence of "multispace:"
4820f14b8ba1Szeertzjq int multispace_len = 0; // Length of lcs-multispace string
4821e677df8dSBram Moolenaar struct charstab
4822e677df8dSBram Moolenaar {
4823e677df8dSBram Moolenaar int *cp;
4824e677df8dSBram Moolenaar char *name;
4825e677df8dSBram Moolenaar };
4826e677df8dSBram Moolenaar static struct charstab filltab[] =
4827e677df8dSBram Moolenaar {
4828e677df8dSBram Moolenaar {&fill_stl, "stl"},
4829e677df8dSBram Moolenaar {&fill_stlnc, "stlnc"},
4830e677df8dSBram Moolenaar {&fill_vert, "vert"},
4831e677df8dSBram Moolenaar {&fill_fold, "fold"},
48323aca5a6fSBram Moolenaar {&fill_foldopen, "foldopen"},
48333aca5a6fSBram Moolenaar {&fill_foldclosed, "foldclose"},
48343aca5a6fSBram Moolenaar {&fill_foldsep, "foldsep"},
4835e677df8dSBram Moolenaar {&fill_diff, "diff"},
4836a98f8a23SBram Moolenaar {&fill_eob, "eob"},
4837e677df8dSBram Moolenaar };
4838333bd564SBram Moolenaar static lcs_chars_T lcs_chars;
4839eed9d462SBram Moolenaar struct charstab lcstab[] =
4840e677df8dSBram Moolenaar {
4841333bd564SBram Moolenaar {&lcs_chars.eol, "eol"},
4842333bd564SBram Moolenaar {&lcs_chars.ext, "extends"},
4843333bd564SBram Moolenaar {&lcs_chars.nbsp, "nbsp"},
4844333bd564SBram Moolenaar {&lcs_chars.prec, "precedes"},
4845333bd564SBram Moolenaar {&lcs_chars.space, "space"},
4846333bd564SBram Moolenaar {&lcs_chars.tab2, "tab"},
4847333bd564SBram Moolenaar {&lcs_chars.trail, "trail"},
4848333bd564SBram Moolenaar {&lcs_chars.lead, "lead"},
4849e677df8dSBram Moolenaar #ifdef FEAT_CONCEAL
4850333bd564SBram Moolenaar {&lcs_chars.conceal, "conceal"},
4851e677df8dSBram Moolenaar #else
4852e677df8dSBram Moolenaar {NULL, "conceal"},
4853e677df8dSBram Moolenaar #endif
4854e677df8dSBram Moolenaar };
4855e677df8dSBram Moolenaar struct charstab *tab;
4856e677df8dSBram Moolenaar
4857eed9d462SBram Moolenaar if (varp == &p_lcs || varp == &wp->w_p_lcs)
4858e677df8dSBram Moolenaar {
4859e677df8dSBram Moolenaar tab = lcstab;
4860333bd564SBram Moolenaar CLEAR_FIELD(lcs_chars);
4861eeec2548SK.Takata entries = ARRAY_LENGTH(lcstab);
4862eed9d462SBram Moolenaar if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL)
4863eed9d462SBram Moolenaar varp = &p_lcs;
4864e677df8dSBram Moolenaar }
4865e677df8dSBram Moolenaar else
4866e677df8dSBram Moolenaar {
4867e677df8dSBram Moolenaar tab = filltab;
4868eeec2548SK.Takata entries = ARRAY_LENGTH(filltab);
4869e677df8dSBram Moolenaar }
4870e677df8dSBram Moolenaar
4871e677df8dSBram Moolenaar // first round: check for valid value, second round: assign values
4872e677df8dSBram Moolenaar for (round = 0; round <= 1; ++round)
4873e677df8dSBram Moolenaar {
4874e677df8dSBram Moolenaar if (round > 0)
4875e677df8dSBram Moolenaar {
4876e677df8dSBram Moolenaar // After checking that the value is valid: set defaults: space for
4877e677df8dSBram Moolenaar // 'fillchars', NUL for 'listchars'
4878e677df8dSBram Moolenaar for (i = 0; i < entries; ++i)
4879e677df8dSBram Moolenaar if (tab[i].cp != NULL)
4880eed9d462SBram Moolenaar *(tab[i].cp) =
4881eed9d462SBram Moolenaar ((varp == &p_lcs || varp == &wp->w_p_lcs) ? NUL : ' ');
4882e677df8dSBram Moolenaar
4883eed9d462SBram Moolenaar if (varp == &p_lcs || varp == &wp->w_p_lcs)
4884e677df8dSBram Moolenaar {
4885333bd564SBram Moolenaar lcs_chars.tab1 = NUL;
4886333bd564SBram Moolenaar lcs_chars.tab3 = NUL;
4887f5785cf0SMike Williams if (multispace_len > 0)
4888f14b8ba1Szeertzjq {
4889f14b8ba1Szeertzjq lcs_chars.multispace = ALLOC_MULT(int, multispace_len + 1);
4890f14b8ba1Szeertzjq lcs_chars.multispace[multispace_len] = NUL;
4891f14b8ba1Szeertzjq }
4892f14b8ba1Szeertzjq else
4893f14b8ba1Szeertzjq lcs_chars.multispace = NULL;
4894e677df8dSBram Moolenaar }
4895e677df8dSBram Moolenaar else
4896a98f8a23SBram Moolenaar {
4897e677df8dSBram Moolenaar fill_diff = '-';
48983aca5a6fSBram Moolenaar fill_foldopen = '-';
48993aca5a6fSBram Moolenaar fill_foldclosed = '+';
49003aca5a6fSBram Moolenaar fill_foldsep = '|';
4901a98f8a23SBram Moolenaar fill_eob = '~';
4902a98f8a23SBram Moolenaar }
4903e677df8dSBram Moolenaar }
4904e677df8dSBram Moolenaar p = *varp;
4905e677df8dSBram Moolenaar while (*p)
4906e677df8dSBram Moolenaar {
4907e677df8dSBram Moolenaar for (i = 0; i < entries; ++i)
4908e677df8dSBram Moolenaar {
4909e677df8dSBram Moolenaar len = (int)STRLEN(tab[i].name);
4910e677df8dSBram Moolenaar if (STRNCMP(p, tab[i].name, len) == 0
4911e677df8dSBram Moolenaar && p[len] == ':'
4912e677df8dSBram Moolenaar && p[len + 1] != NUL)
4913e677df8dSBram Moolenaar {
4914e677df8dSBram Moolenaar c2 = c3 = 0;
4915e677df8dSBram Moolenaar s = p + len + 1;
491693ff6720SBram Moolenaar c1 = get_encoded_char_adv(&s);
4917e677df8dSBram Moolenaar if (mb_char2cells(c1) > 1)
4918f14b8ba1Szeertzjq return e_invarg;
4919333bd564SBram Moolenaar if (tab[i].cp == &lcs_chars.tab2)
4920e677df8dSBram Moolenaar {
4921e677df8dSBram Moolenaar if (*s == NUL)
4922f14b8ba1Szeertzjq return e_invarg;
492393ff6720SBram Moolenaar c2 = get_encoded_char_adv(&s);
4924e677df8dSBram Moolenaar if (mb_char2cells(c2) > 1)
4925f14b8ba1Szeertzjq return e_invarg;
4926e677df8dSBram Moolenaar if (!(*s == ',' || *s == NUL))
4927e677df8dSBram Moolenaar {
492893ff6720SBram Moolenaar c3 = get_encoded_char_adv(&s);
4929e677df8dSBram Moolenaar if (mb_char2cells(c3) > 1)
4930f14b8ba1Szeertzjq return e_invarg;
4931e677df8dSBram Moolenaar }
4932e677df8dSBram Moolenaar }
4933e677df8dSBram Moolenaar
4934e677df8dSBram Moolenaar if (*s == ',' || *s == NUL)
4935e677df8dSBram Moolenaar {
4936f5785cf0SMike Williams if (round > 0)
4937e677df8dSBram Moolenaar {
4938333bd564SBram Moolenaar if (tab[i].cp == &lcs_chars.tab2)
4939e677df8dSBram Moolenaar {
4940333bd564SBram Moolenaar lcs_chars.tab1 = c1;
4941333bd564SBram Moolenaar lcs_chars.tab2 = c2;
4942333bd564SBram Moolenaar lcs_chars.tab3 = c3;
4943e677df8dSBram Moolenaar }
4944e677df8dSBram Moolenaar else if (tab[i].cp != NULL)
4945e677df8dSBram Moolenaar *(tab[i].cp) = c1;
4946e677df8dSBram Moolenaar
4947e677df8dSBram Moolenaar }
4948e677df8dSBram Moolenaar p = s;
4949e677df8dSBram Moolenaar break;
4950e677df8dSBram Moolenaar }
4951e677df8dSBram Moolenaar }
4952e677df8dSBram Moolenaar }
4953e677df8dSBram Moolenaar
4954e677df8dSBram Moolenaar if (i == entries)
4955f14b8ba1Szeertzjq {
4956f5785cf0SMike Williams len = (int)STRLEN("multispace");
4957f14b8ba1Szeertzjq if ((varp == &p_lcs || varp == &wp->w_p_lcs)
4958f14b8ba1Szeertzjq && STRNCMP(p, "multispace", len) == 0
4959f14b8ba1Szeertzjq && p[len] == ':'
4960f14b8ba1Szeertzjq && p[len + 1] != NUL)
4961f14b8ba1Szeertzjq {
4962f14b8ba1Szeertzjq s = p + len + 1;
4963f14b8ba1Szeertzjq if (round == 0)
4964f14b8ba1Szeertzjq {
4965f14b8ba1Szeertzjq // Get length of lcs-multispace string in first round
4966f14b8ba1Szeertzjq last_multispace = p;
4967f14b8ba1Szeertzjq multispace_len = 0;
4968f14b8ba1Szeertzjq while (*s != NUL && *s != ',')
4969f14b8ba1Szeertzjq {
497093ff6720SBram Moolenaar c1 = get_encoded_char_adv(&s);
4971f14b8ba1Szeertzjq if (mb_char2cells(c1) > 1)
4972e677df8dSBram Moolenaar return e_invarg;
4973f14b8ba1Szeertzjq ++multispace_len;
4974f14b8ba1Szeertzjq }
4975f14b8ba1Szeertzjq if (multispace_len == 0)
4976f14b8ba1Szeertzjq // lcs-multispace cannot be an empty string
4977f14b8ba1Szeertzjq return e_invarg;
4978f14b8ba1Szeertzjq p = s;
4979f14b8ba1Szeertzjq }
4980f14b8ba1Szeertzjq else
4981f14b8ba1Szeertzjq {
4982f14b8ba1Szeertzjq int multispace_pos = 0;
4983f5785cf0SMike Williams
4984f14b8ba1Szeertzjq while (*s != NUL && *s != ',')
4985f14b8ba1Szeertzjq {
498693ff6720SBram Moolenaar c1 = get_encoded_char_adv(&s);
4987f14b8ba1Szeertzjq if (p == last_multispace)
4988f14b8ba1Szeertzjq lcs_chars.multispace[multispace_pos++] = c1;
4989f14b8ba1Szeertzjq }
4990f14b8ba1Szeertzjq p = s;
4991f14b8ba1Szeertzjq }
4992f14b8ba1Szeertzjq }
4993f14b8ba1Szeertzjq else
4994f14b8ba1Szeertzjq return e_invarg;
4995f14b8ba1Szeertzjq }
4996f14b8ba1Szeertzjq
4997e677df8dSBram Moolenaar if (*p == ',')
4998e677df8dSBram Moolenaar ++p;
4999e677df8dSBram Moolenaar }
5000e677df8dSBram Moolenaar }
5001333bd564SBram Moolenaar if (tab == lcstab)
5002f14b8ba1Szeertzjq {
5003f14b8ba1Szeertzjq if (wp->w_lcs_chars.multispace != NULL)
5004f14b8ba1Szeertzjq vim_free(wp->w_lcs_chars.multispace);
5005333bd564SBram Moolenaar wp->w_lcs_chars = lcs_chars;
5006f14b8ba1Szeertzjq }
5007e677df8dSBram Moolenaar
5008e677df8dSBram Moolenaar return NULL; // no error
5009e677df8dSBram Moolenaar }
5010017ba07fSBram Moolenaar
5011