blob: cd293159243a1a7bf4774208167787a1241ed16f [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * screen.c: code for displaying on the screen
12 *
13 * Output to the screen (console, terminal emulator or GUI window) is minimized
14 * by remembering what is already on the screen, and only updating the parts
15 * that changed.
16 *
17 * ScreenLines[off] Contains a copy of the whole screen, as it is currently
18 * displayed (excluding text written by external commands).
19 * ScreenAttrs[off] Contains the associated attributes.
20 * LineOffset[row] Contains the offset into ScreenLines*[] and ScreenAttrs[]
21 * for each line.
22 * LineWraps[row] Flag for each line whether it wraps to the next line.
23 *
24 * For double-byte characters, two consecutive bytes in ScreenLines[] can form
25 * one character which occupies two display cells.
26 * For UTF-8 a multi-byte character is converted to Unicode and stored in
27 * ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII
Bram Moolenaar70c49c12010-03-23 15:36:35 +010028 * character without composing chars ScreenLinesUC[] will be 0 and
29 * ScreenLinesC[][] is not used. When the character occupies two display
30 * cells the next byte in ScreenLines[] is 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +000031 * ScreenLinesC[][] contain up to 'maxcombine' composing characters
Bram Moolenaar70c49c12010-03-23 15:36:35 +010032 * (drawn on top of the first character). There is 0 after the last one used.
Bram Moolenaar071d4272004-06-13 20:20:40 +000033 * ScreenLines2[] is only used for euc-jp to store the second byte if the
34 * first byte is 0x8e (single-width character).
35 *
36 * The screen_*() functions write to the screen and handle updating
37 * ScreenLines[].
38 *
39 * update_screen() is the function that updates all windows and status lines.
40 * It is called form the main loop when must_redraw is non-zero. It may be
Bram Moolenaar2c7a7632007-05-10 18:19:11 +000041 * called from other places when an immediate screen update is needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +000042 *
43 * The part of the buffer that is displayed in a window is set with:
44 * - w_topline (first buffer line in window)
Bram Moolenaarea389e92014-05-28 21:40:52 +020045 * - w_topfill (filler lines above the first line)
Bram Moolenaar071d4272004-06-13 20:20:40 +000046 * - w_leftcol (leftmost window cell in window),
47 * - w_skipcol (skipped window cells of first line)
48 *
49 * Commands that only move the cursor around in a window, do not need to take
50 * action to update the display. The main loop will check if w_topline is
51 * valid and update it (scroll the window) when needed.
52 *
53 * Commands that scroll a window change w_topline and must call
54 * check_cursor() to move the cursor into the visible part of the window, and
55 * call redraw_later(VALID) to have the window displayed by update_screen()
56 * later.
57 *
58 * Commands that change text in the buffer must call changed_bytes() or
59 * changed_lines() to mark the area that changed and will require updating
60 * later. The main loop will call update_screen(), which will update each
61 * window that shows the changed buffer. This assumes text above the change
62 * can remain displayed as it is. Text after the change may need updating for
63 * scrolling, folding and syntax highlighting.
64 *
65 * Commands that change how a window is displayed (e.g., setting 'list') or
66 * invalidate the contents of a window in another way (e.g., change fold
67 * settings), must call redraw_later(NOT_VALID) to have the whole window
68 * redisplayed by update_screen() later.
69 *
70 * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
71 * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
72 * buffer redisplayed by update_screen() later.
73 *
Bram Moolenaar600dddc2006-03-12 22:05:10 +000074 * Commands that change highlighting and possibly cause a scroll too must call
75 * redraw_later(SOME_VALID) to update the whole window but still use scrolling
76 * to avoid redrawing everything. But the length of displayed lines must not
77 * change, use NOT_VALID then.
78 *
Bram Moolenaar071d4272004-06-13 20:20:40 +000079 * Commands that move the window position must call redraw_later(NOT_VALID).
80 * TODO: should minimize redrawing by scrolling when possible.
81 *
82 * Commands that change everything (e.g., resizing the screen) must call
83 * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
84 *
85 * Things that are handled indirectly:
86 * - When messages scroll the screen up, msg_scrolled will be set and
87 * update_screen() called to redraw.
88 */
89
90#include "vim.h"
91
Bram Moolenaar5641f382012-06-13 18:06:36 +020092#define MB_FILLER_CHAR '<' /* character used when a double-width character
93 * doesn't fit. */
94
Bram Moolenaar071d4272004-06-13 20:20:40 +000095/*
96 * The attributes that are actually active for writing to the screen.
97 */
98static int screen_attr = 0;
99
100/*
101 * Positioning the cursor is reduced by remembering the last position.
102 * Mostly used by windgoto() and screen_char().
103 */
104static int screen_cur_row, screen_cur_col; /* last known cursor position */
105
106#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar071d4272004-06-13 20:20:40 +0000107static match_T search_hl; /* used for 'hlsearch' highlight matching */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108#endif
109
Bram Moolenaar1b9645d2017-09-17 23:03:31 +0200110#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
111static int text_to_screenline(win_T *wp, char_u *text, int col);
112#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113#ifdef FEAT_FOLDING
114static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100115static int compute_foldcolumn(win_T *wp, int col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116#endif
117
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200118/* Flag that is set when drawing for a callback, not from the main command
119 * loop. */
120static int redrawing_for_callback = 0;
121
Bram Moolenaar071d4272004-06-13 20:20:40 +0000122/*
123 * Buffer for one screen line (characters and attributes).
124 */
125static schar_T *current_ScreenLine;
126
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100127static void win_update(win_T *wp);
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +0200128static void win_redr_status(win_T *wp, int ignore_pum);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100129static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000130#ifdef FEAT_FOLDING
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100131static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row);
132static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
133static void copy_text_attr(int off, char_u *buf, int len, int attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134#endif
Bram Moolenaarf3d769a2017-09-22 13:44:56 +0200135static int win_line(win_T *, linenr_T, int, int, int nochange);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100136static int char_needs_redraw(int off_from, int off_to, int cols);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100137static void draw_vsep_win(win_T *wp, int row);
Bram Moolenaar238a5642006-02-21 22:12:05 +0000138#ifdef FEAT_STL_OPT
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100139static void redraw_custom_statusline(win_T *wp);
Bram Moolenaar238a5642006-02-21 22:12:05 +0000140#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarde993ea2014-06-17 23:18:01 +0200142# define SEARCH_HL_PRIORITY 0
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100143static void start_search_hl(void);
144static void end_search_hl(void);
145static void init_search_hl(win_T *wp);
146static void prepare_search_hl(win_T *wp, linenr_T lnum);
147static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur);
148static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100150static void screen_start_highlight(int attr);
151static void screen_char(unsigned off, int row, int col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152#ifdef FEAT_MBYTE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100153static void screen_char_2(unsigned off, int row, int col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100155static void screenclear2(void);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200156static void lineclear(unsigned off, int width, int attr);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100157static void lineinvalid(unsigned off, int width);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100158static void linecopy(int to, int from, win_T *wp);
159static void redraw_block(int row, int end, win_T *wp);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200160static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100161static void win_rest_invalid(win_T *wp);
162static void msg_pos_mode(void);
163static void recording_mode(int attr);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100164static void draw_tabline(void);
Bram Moolenaar3633cf52017-07-31 22:29:35 +0200165static int fillchar_status(int *attr, win_T *wp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100166static int fillchar_vsep(int *attr);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +0200167#ifdef FEAT_MENU
168static void redraw_win_toolbar(win_T *wp);
169#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170#ifdef FEAT_STL_OPT
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100171static void win_redr_custom(win_T *wp, int draw_ruler);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172#endif
173#ifdef FEAT_CMDL_INFO
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100174static void win_redr_ruler(win_T *wp, int always);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175#endif
176
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177/* Ugly global: overrule attribute used by screen_char() */
178static int screen_char_attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200180#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME)
181/* Can limit syntax highlight time to 'redrawtime'. */
182# define SYN_TIME_LIMIT 1
183#endif
184
Bram Moolenaarc0aa4822017-07-16 14:04:29 +0200185#ifdef FEAT_RIGHTLEFT
186# define HAS_RIGHTLEFT(x) x
187#else
188# define HAS_RIGHTLEFT(x) FALSE
189#endif
190
Bram Moolenaar071d4272004-06-13 20:20:40 +0000191/*
192 * Redraw the current window later, with update_screen(type).
193 * Set must_redraw only if not already set to a higher value.
194 * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
195 */
196 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100197redraw_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198{
199 redraw_win_later(curwin, type);
200}
201
202 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100203redraw_win_later(
204 win_T *wp,
205 int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000206{
Bram Moolenaar4f198282017-10-23 21:53:30 +0200207 if (!exiting && wp->w_redr_type < type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208 {
209 wp->w_redr_type = type;
210 if (type >= NOT_VALID)
211 wp->w_lines_valid = 0;
212 if (must_redraw < type) /* must_redraw is the maximum of all windows */
213 must_redraw = type;
214 }
215}
216
217/*
218 * Force a complete redraw later. Also resets the highlighting. To be used
219 * after executing a shell command that messes up the screen.
220 */
221 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100222redraw_later_clear(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000223{
224 redraw_all_later(CLEAR);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000225#ifdef FEAT_GUI
226 if (gui.in_use)
227 /* Use a code that will reset gui.highlight_mask in
228 * gui_stop_highlight(). */
229 screen_attr = HL_ALL + 1;
230 else
231#endif
232 /* Use attributes that is very unlikely to appear in text. */
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +0200233 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234}
235
236/*
237 * Mark all windows to be redrawn later.
238 */
239 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100240redraw_all_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241{
242 win_T *wp;
243
244 FOR_ALL_WINDOWS(wp)
245 {
246 redraw_win_later(wp, type);
247 }
248}
249
250/*
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000251 * Mark all windows that are editing the current buffer to be updated later.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000252 */
253 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100254redraw_curbuf_later(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255{
256 redraw_buf_later(curbuf, type);
257}
258
259 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100260redraw_buf_later(buf_T *buf, int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261{
262 win_T *wp;
263
264 FOR_ALL_WINDOWS(wp)
265 {
266 if (wp->w_buffer == buf)
267 redraw_win_later(wp, type);
268 }
269}
270
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200271 void
272redraw_buf_and_status_later(buf_T *buf, int type)
273{
274 win_T *wp;
275
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200276#ifdef FEAT_WILDMENU
Bram Moolenaar86033562017-07-12 20:24:41 +0200277 if (wild_menu_showing != 0)
278 /* Don't redraw while the command line completion is displayed, it
279 * would disappear. */
280 return;
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200281#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200282 FOR_ALL_WINDOWS(wp)
283 {
284 if (wp->w_buffer == buf)
285 {
286 redraw_win_later(wp, type);
287 wp->w_redr_status = TRUE;
288 }
289 }
290}
291
Bram Moolenaar071d4272004-06-13 20:20:40 +0000292/*
Bram Moolenaar2951b772013-07-03 12:45:31 +0200293 * Redraw as soon as possible. When the command line is not scrolled redraw
294 * right away and restore what was on the command line.
295 * Return a code indicating what happened.
296 */
297 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100298redraw_asap(int type)
Bram Moolenaar2951b772013-07-03 12:45:31 +0200299{
300 int rows;
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200301 int cols = screen_Columns;
Bram Moolenaar2951b772013-07-03 12:45:31 +0200302 int r;
303 int ret = 0;
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200304 schar_T *screenline; /* copy from ScreenLines[] */
305 sattr_T *screenattr; /* copy from ScreenAttrs[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200306#ifdef FEAT_MBYTE
307 int i;
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200308 u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200309 u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */
Bram Moolenaare1fc4e22013-07-03 13:29:58 +0200310 schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */
Bram Moolenaar2951b772013-07-03 12:45:31 +0200311#endif
312
313 redraw_later(type);
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200314 if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
Bram Moolenaar2951b772013-07-03 12:45:31 +0200315 return ret;
316
317 /* Allocate space to save the text displayed in the command line area. */
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200318 rows = screen_Rows - cmdline_row;
Bram Moolenaar2951b772013-07-03 12:45:31 +0200319 screenline = (schar_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200320 (long_u)(rows * cols * sizeof(schar_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200321 screenattr = (sattr_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200322 (long_u)(rows * cols * sizeof(sattr_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200323 if (screenline == NULL || screenattr == NULL)
324 ret = 2;
325#ifdef FEAT_MBYTE
326 if (enc_utf8)
327 {
328 screenlineUC = (u8char_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200329 (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200330 if (screenlineUC == NULL)
331 ret = 2;
332 for (i = 0; i < p_mco; ++i)
333 {
334 screenlineC[i] = (u8char_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200335 (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200336 if (screenlineC[i] == NULL)
337 ret = 2;
338 }
339 }
340 if (enc_dbcs == DBCS_JPNU)
341 {
342 screenline2 = (schar_T *)lalloc(
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200343 (long_u)(rows * cols * sizeof(schar_T)), FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200344 if (screenline2 == NULL)
345 ret = 2;
346 }
347#endif
348
349 if (ret != 2)
350 {
351 /* Save the text displayed in the command line area. */
352 for (r = 0; r < rows; ++r)
353 {
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200354 mch_memmove(screenline + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200355 ScreenLines + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200356 (size_t)cols * sizeof(schar_T));
357 mch_memmove(screenattr + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200358 ScreenAttrs + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200359 (size_t)cols * sizeof(sattr_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200360#ifdef FEAT_MBYTE
361 if (enc_utf8)
362 {
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200363 mch_memmove(screenlineUC + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200364 ScreenLinesUC + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200365 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200366 for (i = 0; i < p_mco; ++i)
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200367 mch_memmove(screenlineC[i] + r * cols,
368 ScreenLinesC[i] + LineOffset[cmdline_row + r],
369 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200370 }
371 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200372 mch_memmove(screenline2 + r * cols,
Bram Moolenaar2951b772013-07-03 12:45:31 +0200373 ScreenLines2 + LineOffset[cmdline_row + r],
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200374 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200375#endif
376 }
377
378 update_screen(0);
379 ret = 3;
380
381 if (must_redraw == 0)
382 {
383 int off = (int)(current_ScreenLine - ScreenLines);
384
385 /* Restore the text displayed in the command line area. */
386 for (r = 0; r < rows; ++r)
387 {
388 mch_memmove(current_ScreenLine,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200389 screenline + r * cols,
390 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200391 mch_memmove(ScreenAttrs + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200392 screenattr + r * cols,
393 (size_t)cols * sizeof(sattr_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200394#ifdef FEAT_MBYTE
395 if (enc_utf8)
396 {
397 mch_memmove(ScreenLinesUC + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200398 screenlineUC + r * cols,
399 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200400 for (i = 0; i < p_mco; ++i)
401 mch_memmove(ScreenLinesC[i] + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200402 screenlineC[i] + r * cols,
403 (size_t)cols * sizeof(u8char_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200404 }
405 if (enc_dbcs == DBCS_JPNU)
406 mch_memmove(ScreenLines2 + off,
Bram Moolenaar5f95f282015-07-25 22:53:00 +0200407 screenline2 + r * cols,
408 (size_t)cols * sizeof(schar_T));
Bram Moolenaar2951b772013-07-03 12:45:31 +0200409#endif
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200410 screen_line(cmdline_row + r, 0, cols, cols, FALSE);
Bram Moolenaar2951b772013-07-03 12:45:31 +0200411 }
412 ret = 4;
413 }
Bram Moolenaar2951b772013-07-03 12:45:31 +0200414 }
415
416 vim_free(screenline);
417 vim_free(screenattr);
418#ifdef FEAT_MBYTE
419 if (enc_utf8)
420 {
421 vim_free(screenlineUC);
422 for (i = 0; i < p_mco; ++i)
423 vim_free(screenlineC[i]);
424 }
425 if (enc_dbcs == DBCS_JPNU)
426 vim_free(screenline2);
427#endif
428
Bram Moolenaar249f0dd2013-07-04 22:31:03 +0200429 /* Show the intro message when appropriate. */
430 maybe_intro_message();
431
432 setcursor();
433
Bram Moolenaar2951b772013-07-03 12:45:31 +0200434 return ret;
435}
436
437/*
Bram Moolenaar975b5272016-03-15 23:10:59 +0100438 * Invoked after an asynchronous callback is called.
439 * If an echo command was used the cursor needs to be put back where
440 * it belongs. If highlighting was changed a redraw is needed.
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200441 * If "call_update_screen" is FALSE don't call update_screen() when at the
442 * command line.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100443 */
444 void
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200445redraw_after_callback(int call_update_screen)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100446{
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200447 ++redrawing_for_callback;
448
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100449 if (State == HITRETURN || State == ASKMORE)
450 ; /* do nothing */
451 else if (State & CMDLINE)
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200452 {
Bram Moolenaar86033562017-07-12 20:24:41 +0200453 /* Redrawing only works when the screen didn't scroll. Don't clear
454 * wildmenu entries. */
Bram Moolenaar85dad2c2017-07-12 21:12:43 +0200455 if (msg_scrolled == 0
456#ifdef FEAT_WILDMENU
457 && wild_menu_showing == 0
458#endif
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200459 && call_update_screen)
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200460 update_screen(0);
Bram Moolenaar86033562017-07-12 20:24:41 +0200461 /* Redraw in the same position, so that the user can continue
462 * editing the command. */
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200463 redrawcmdline_ex(FALSE);
464 }
Bram Moolenaar1b9645d2017-09-17 23:03:31 +0200465 else if (State & (NORMAL | INSERT | TERMINAL))
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100466 {
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200467 /* keep the command line if possible */
468 update_screen(VALID_NO_UPDATE);
Bram Moolenaarbfb96c02016-03-19 17:05:20 +0100469 setcursor();
470 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100471 cursor_on();
Bram Moolenaar975b5272016-03-15 23:10:59 +0100472#ifdef FEAT_GUI
Bram Moolenaara338adc2018-01-31 20:51:47 +0100473 if (gui.in_use && !gui_mch_is_blink_off())
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +0200474 /* Don't update the cursor when it is blinking and off to avoid
475 * flicker. */
Bram Moolenaara338adc2018-01-31 20:51:47 +0100476 out_flush_cursor(FALSE, FALSE);
477 else
Bram Moolenaar975b5272016-03-15 23:10:59 +0100478#endif
Bram Moolenaaracda04f2018-02-08 09:57:28 +0100479 out_flush();
Bram Moolenaar80dd3f92017-07-19 12:51:52 +0200480
481 --redrawing_for_callback;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100482}
483
484/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485 * Changed something in the current window, at buffer line "lnum", that
486 * requires that line and possibly other lines to be redrawn.
487 * Used when entering/leaving Insert mode with the cursor on a folded line.
488 * Used to remove the "$" from a change command.
489 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
490 * may become invalid and the whole window will have to be redrawn.
491 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000492 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100493redrawWinline(
494 linenr_T lnum,
495 int invalid UNUSED) /* window line height is invalid now */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496{
497#ifdef FEAT_FOLDING
498 int i;
499#endif
500
501 if (curwin->w_redraw_top == 0 || curwin->w_redraw_top > lnum)
502 curwin->w_redraw_top = lnum;
503 if (curwin->w_redraw_bot == 0 || curwin->w_redraw_bot < lnum)
504 curwin->w_redraw_bot = lnum;
505 redraw_later(VALID);
506
507#ifdef FEAT_FOLDING
508 if (invalid)
509 {
510 /* A w_lines[] entry for this lnum has become invalid. */
511 i = find_wl_entry(curwin, lnum);
512 if (i >= 0)
513 curwin->w_lines[i].wl_valid = FALSE;
514 }
515#endif
516}
517
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200518 void
519reset_updating_screen(int may_resize_shell UNUSED)
520{
521 updating_screen = FALSE;
522#ifdef FEAT_GUI
523 if (may_resize_shell)
524 gui_may_resize_shell();
525#endif
526#ifdef FEAT_TERMINAL
527 term_check_channel_closed_recently();
528#endif
529}
530
Bram Moolenaar071d4272004-06-13 20:20:40 +0000531/*
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200532 * Update all windows that are editing the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000533 */
534 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100535update_curbuf(int type)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536{
537 redraw_curbuf_later(type);
538 update_screen(type);
539}
540
541/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 * Based on the current value of curwin->w_topline, transfer a screenfull
543 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
Bram Moolenaar072412e2017-09-13 22:11:35 +0200544 * Return OK when the screen was updated, FAIL if it was not done.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 */
Bram Moolenaar072412e2017-09-13 22:11:35 +0200546 int
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200547update_screen(int type_arg)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548{
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200549 int type = type_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 win_T *wp;
551 static int did_intro = FALSE;
552#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
553 int did_one;
554#endif
Bram Moolenaar144445d2016-07-08 21:41:54 +0200555#ifdef FEAT_GUI
Bram Moolenaar107abd22016-08-12 14:08:25 +0200556 int did_undraw = FALSE;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200557 int gui_cursor_col;
558 int gui_cursor_row;
559#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200560 int no_update = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000562 /* Don't do anything if the screen structures are (not yet) valid. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 if (!screen_valid(TRUE))
Bram Moolenaar072412e2017-09-13 22:11:35 +0200564 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200566 if (type == VALID_NO_UPDATE)
567 {
568 no_update = TRUE;
569 type = 0;
570 }
571
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 if (must_redraw)
573 {
574 if (type < must_redraw) /* use maximal type */
575 type = must_redraw;
Bram Moolenaar943fae42007-07-30 20:00:38 +0000576
577 /* must_redraw is reset here, so that when we run into some weird
578 * reason to redraw while busy redrawing (e.g., asynchronous
579 * scrolling), or update_topline() in win_update() will cause a
580 * scroll, the screen will be redrawn later or in win_update(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581 must_redraw = 0;
582 }
583
Bram Moolenaar6eddadf2018-05-06 16:40:16 +0200584 /* May need to update w_lines[]. */
585 if (curwin->w_lines_valid == 0 && type < NOT_VALID
586#ifdef FEAT_TERMINAL
587 && !term_do_update_window(curwin)
588#endif
589 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 type = NOT_VALID;
591
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000592 /* Postpone the redrawing when it's not needed and when being called
593 * recursively. */
594 if (!redrawing() || updating_screen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595 {
596 redraw_later(type); /* remember type for next time */
597 must_redraw = type;
598 if (type > INVERTED_ALL)
599 curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
Bram Moolenaar072412e2017-09-13 22:11:35 +0200600 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601 }
602
603 updating_screen = TRUE;
604#ifdef FEAT_SYN_HL
605 ++display_tick; /* let syntax code know we're in a next round of
606 * display updating */
607#endif
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200608 if (no_update)
609 ++no_win_do_lines_ins;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610
611 /*
612 * if the screen was scrolled up when displaying a message, scroll it down
613 */
614 if (msg_scrolled)
615 {
616 clear_cmdline = TRUE;
617 if (msg_scrolled > Rows - 5) /* clearing is faster */
618 type = CLEAR;
619 else if (type != CLEAR)
620 {
621 check_for_delay(FALSE);
Bram Moolenaarcfce7172017-08-17 20:31:48 +0200622 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
623 == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 type = CLEAR;
625 FOR_ALL_WINDOWS(wp)
626 {
627 if (W_WINROW(wp) < msg_scrolled)
628 {
629 if (W_WINROW(wp) + wp->w_height > msg_scrolled
630 && wp->w_redr_type < REDRAW_TOP
631 && wp->w_lines_valid > 0
632 && wp->w_topline == wp->w_lines[0].wl_lnum)
633 {
634 wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
635 wp->w_redr_type = REDRAW_TOP;
636 }
637 else
638 {
639 wp->w_redr_type = NOT_VALID;
Bram Moolenaare0de17d2017-09-24 16:24:34 +0200640 if (W_WINROW(wp) + wp->w_height + wp->w_status_height
641 <= msg_scrolled)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000642 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 }
644 }
645 }
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200646 if (!no_update)
647 redraw_cmdline = TRUE;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +0000648 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 }
650 msg_scrolled = 0;
651 need_wait_return = FALSE;
652 }
653
654 /* reset cmdline_row now (may have been changed temporarily) */
655 compute_cmdrow();
656
657 /* Check for changed highlighting */
658 if (need_highlight_changed)
659 highlight_changed();
660
661 if (type == CLEAR) /* first clear screen */
662 {
663 screenclear(); /* will reset clear_cmdline */
664 type = NOT_VALID;
Bram Moolenaar9f5f7bf2017-06-28 20:45:26 +0200665 /* must_redraw may be set indirectly, avoid another redraw later */
666 must_redraw = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667 }
668
669 if (clear_cmdline) /* going to clear cmdline (done below) */
670 check_for_delay(FALSE);
671
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000672#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +0200673 /* Force redraw when width of 'number' or 'relativenumber' column
674 * changes. */
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000675 if (curwin->w_redr_type < NOT_VALID
Bram Moolenaar64486672010-05-16 15:46:46 +0200676 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
677 ? number_width(curwin) : 0))
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000678 curwin->w_redr_type = NOT_VALID;
679#endif
680
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 /*
682 * Only start redrawing if there is really something to do.
683 */
684 if (type == INVERTED)
685 update_curswant();
686 if (curwin->w_redr_type < type
687 && !((type == VALID
688 && curwin->w_lines[0].wl_valid
689#ifdef FEAT_DIFF
690 && curwin->w_topfill == curwin->w_old_topfill
691 && curwin->w_botfill == curwin->w_old_botfill
692#endif
693 && curwin->w_topline == curwin->w_lines[0].wl_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694 || (type == INVERTED
Bram Moolenaarb0c9a852006-11-28 15:14:56 +0000695 && VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
697 && curwin->w_old_visual_mode == VIsual_mode
698 && (curwin->w_valid & VALID_VIRTCOL)
699 && curwin->w_old_curswant == curwin->w_curswant)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700 ))
701 curwin->w_redr_type = type;
702
Bram Moolenaar5a305422006-04-28 22:38:25 +0000703 /* Redraw the tab pages line if needed. */
704 if (redraw_tabline || type >= NOT_VALID)
705 draw_tabline();
Bram Moolenaar5a305422006-04-28 22:38:25 +0000706
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707#ifdef FEAT_SYN_HL
708 /*
709 * Correct stored syntax highlighting info for changes in each displayed
710 * buffer. Each buffer must only be done once.
711 */
712 FOR_ALL_WINDOWS(wp)
713 {
714 if (wp->w_buffer->b_mod_set)
715 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716 win_T *wwp;
717
718 /* Check if we already did this buffer. */
719 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
720 if (wwp->w_buffer == wp->w_buffer)
721 break;
Bram Moolenaar4033c552017-09-16 20:54:51 +0200722 if (wwp == wp && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723 syn_stack_apply_changes(wp->w_buffer);
724 }
725 }
726#endif
727
728 /*
729 * Go from top to bottom through the windows, redrawing the ones that need
730 * it.
731 */
732#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
733 did_one = FALSE;
734#endif
735#ifdef FEAT_SEARCH_EXTRA
736 search_hl.rm.regprog = NULL;
737#endif
738 FOR_ALL_WINDOWS(wp)
739 {
740 if (wp->w_redr_type != 0)
741 {
742 cursor_off();
743#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
744 if (!did_one)
745 {
746 did_one = TRUE;
747# ifdef FEAT_SEARCH_EXTRA
748 start_search_hl();
749# endif
750# ifdef FEAT_CLIPBOARD
751 /* When Visual area changed, may have to update selection. */
Bram Moolenaarc0885aa2012-07-10 16:49:23 +0200752 if (clip_star.available && clip_isautosel_star())
753 clip_update_selection(&clip_star);
754 if (clip_plus.available && clip_isautosel_plus())
755 clip_update_selection(&clip_plus);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756# endif
757#ifdef FEAT_GUI
758 /* Remove the cursor before starting to do anything, because
759 * scrolling may make it difficult to redraw the text under
760 * it. */
Bram Moolenaar107abd22016-08-12 14:08:25 +0200761 if (gui.in_use && wp == curwin)
Bram Moolenaar144445d2016-07-08 21:41:54 +0200762 {
763 gui_cursor_col = gui.cursor_col;
764 gui_cursor_row = gui.cursor_row;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 gui_undraw_cursor();
Bram Moolenaar107abd22016-08-12 14:08:25 +0200766 did_undraw = TRUE;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200767 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768#endif
769 }
770#endif
771 win_update(wp);
772 }
773
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 /* redraw status line after the window to minimize cursor movement */
775 if (wp->w_redr_status)
776 {
777 cursor_off();
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +0200778 win_redr_status(wp, TRUE); // any popup menu will be redrawn below
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 }
781#if defined(FEAT_SEARCH_EXTRA)
782 end_search_hl();
783#endif
Bram Moolenaar51971b32013-02-13 12:16:05 +0100784#ifdef FEAT_INS_EXPAND
785 /* May need to redraw the popup menu. */
786 if (pum_visible())
787 pum_redraw();
788#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 /* Reset b_mod_set flags. Going through all windows is probably faster
791 * than going through all buffers (there could be many buffers). */
Bram Moolenaar29323592016-07-24 22:04:11 +0200792 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 wp->w_buffer->b_mod_set = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200795 reset_updating_screen(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796
797 /* Clear or redraw the command line. Done last, because scrolling may
798 * mess up the command line. */
799 if (clear_cmdline || redraw_cmdline)
800 showmode();
801
Bram Moolenaar29ae3772017-04-30 19:39:39 +0200802 if (no_update)
803 --no_win_do_lines_ins;
804
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 /* May put up an introductory message when not editing a file */
Bram Moolenaar249f0dd2013-07-04 22:31:03 +0200806 if (!did_intro)
807 maybe_intro_message();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 did_intro = TRUE;
809
810#ifdef FEAT_GUI
811 /* Redraw the cursor and update the scrollbars when all screen updating is
812 * done. */
813 if (gui.in_use)
814 {
Bram Moolenaar107abd22016-08-12 14:08:25 +0200815 if (did_undraw && !gui_mch_is_blink_off())
Bram Moolenaar144445d2016-07-08 21:41:54 +0200816 {
Bram Moolenaara338adc2018-01-31 20:51:47 +0100817 mch_disable_flush();
818 out_flush(); /* required before updating the cursor */
819 mch_enable_flush();
820
Bram Moolenaar144445d2016-07-08 21:41:54 +0200821 /* Put the GUI position where the cursor was, gui_update_cursor()
822 * uses that. */
823 gui.col = gui_cursor_col;
824 gui.row = gui_cursor_row;
Bram Moolenaar84dbd492016-10-02 23:09:31 +0200825# ifdef FEAT_MBYTE
826 gui.col = mb_fix_col(gui.col, gui.row);
827# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 gui_update_cursor(FALSE, FALSE);
Bram Moolenaara338adc2018-01-31 20:51:47 +0100829 gui_may_flush();
Bram Moolenaar65549bd2016-07-08 22:52:37 +0200830 screen_cur_col = gui.col;
831 screen_cur_row = gui.row;
Bram Moolenaar144445d2016-07-08 21:41:54 +0200832 }
Bram Moolenaara338adc2018-01-31 20:51:47 +0100833 else
834 out_flush();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 gui_update_scrollbars(FALSE);
836 }
837#endif
Bram Moolenaar072412e2017-09-13 22:11:35 +0200838 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839}
840
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100841#if defined(FEAT_SIGNS) || defined(FEAT_GUI) || defined(FEAT_CONCEAL)
842/*
843 * Prepare for updating one or more windows.
844 * Caller must check for "updating_screen" already set to avoid recursiveness.
845 */
846 static void
847update_prepare(void)
848{
849 cursor_off();
850 updating_screen = TRUE;
851#ifdef FEAT_GUI
852 /* Remove the cursor before starting to do anything, because scrolling may
853 * make it difficult to redraw the text under it. */
854 if (gui.in_use)
855 gui_undraw_cursor();
856#endif
857#ifdef FEAT_SEARCH_EXTRA
858 start_search_hl();
859#endif
860}
861
862/*
863 * Finish updating one or more windows.
864 */
865 static void
866update_finish(void)
867{
868 if (redraw_cmdline)
869 showmode();
870
871# ifdef FEAT_SEARCH_EXTRA
872 end_search_hl();
873# endif
874
Bram Moolenaar0cb8ac72018-05-11 22:01:51 +0200875 reset_updating_screen(TRUE);
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100876
877# ifdef FEAT_GUI
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100878 /* Redraw the cursor and update the scrollbars when all screen updating is
879 * done. */
880 if (gui.in_use)
881 {
Bram Moolenaara338adc2018-01-31 20:51:47 +0100882 out_flush_cursor(FALSE, FALSE);
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100883 gui_update_scrollbars(FALSE);
884 }
885# endif
886}
887#endif
888
Bram Moolenaar860cae12010-06-05 23:22:07 +0200889#if defined(FEAT_CONCEAL) || defined(PROTO)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200890/*
891 * Return TRUE if the cursor line in window "wp" may be concealed, according
892 * to the 'concealcursor' option.
893 */
894 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100895conceal_cursor_line(win_T *wp)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200896{
897 int c;
898
899 if (*wp->w_p_cocu == NUL)
900 return FALSE;
901 if (get_real_state() & VISUAL)
902 c = 'v';
903 else if (State & INSERT)
904 c = 'i';
905 else if (State & NORMAL)
906 c = 'n';
Bram Moolenaarca8c9862010-07-24 15:00:38 +0200907 else if (State & CMDLINE)
908 c = 'c';
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200909 else
910 return FALSE;
911 return vim_strchr(wp->w_p_cocu, c) != NULL;
912}
913
914/*
915 * Check if the cursor line needs to be redrawn because of 'concealcursor'.
916 */
917 void
Bram Moolenaarb9464822018-05-10 15:09:49 +0200918conceal_check_cursor_line(void)
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200919{
920 if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin))
921 {
922 need_cursor_line_redraw = TRUE;
923 /* Need to recompute cursor column, e.g., when starting Visual mode
924 * without concealing. */
925 curs_columns(TRUE);
926 }
927}
928
Bram Moolenaar860cae12010-06-05 23:22:07 +0200929 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100930update_single_line(win_T *wp, linenr_T lnum)
Bram Moolenaar860cae12010-06-05 23:22:07 +0200931{
932 int row;
933 int j;
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200934#ifdef SYN_TIME_LIMIT
935 proftime_T syntax_tm;
936#endif
Bram Moolenaar860cae12010-06-05 23:22:07 +0200937
Bram Moolenaar908be432016-05-24 10:51:30 +0200938 /* Don't do anything if the screen structures are (not yet) valid. */
Bram Moolenaar070b33d2017-01-31 21:53:39 +0100939 if (!screen_valid(TRUE) || updating_screen)
Bram Moolenaar908be432016-05-24 10:51:30 +0200940 return;
941
Bram Moolenaar860cae12010-06-05 23:22:07 +0200942 if (lnum >= wp->w_topline && lnum < wp->w_botline
Bram Moolenaar370df582010-06-22 05:16:38 +0200943 && foldedCount(wp, lnum, &win_foldinfo) == 0)
Bram Moolenaar860cae12010-06-05 23:22:07 +0200944 {
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200945#ifdef SYN_TIME_LIMIT
946 /* Set the time limit to 'redrawtime'. */
947 profile_setlimit(p_rdt, &syntax_tm);
Bram Moolenaarf3d769a2017-09-22 13:44:56 +0200948 syn_set_timeout(&syntax_tm);
Bram Moolenaar06f1ed22017-06-18 22:41:03 +0200949#endif
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100950 update_prepare();
951
Bram Moolenaar860cae12010-06-05 23:22:07 +0200952 row = 0;
953 for (j = 0; j < wp->w_lines_valid; ++j)
954 {
955 if (lnum == wp->w_lines[j].wl_lnum)
956 {
957 screen_start(); /* not sure of screen cursor */
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +0200958# ifdef FEAT_SEARCH_EXTRA
959 init_search_hl(wp);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200960 start_search_hl();
961 prepare_search_hl(wp, lnum);
962# endif
Bram Moolenaarf3d769a2017-09-22 13:44:56 +0200963 win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200964# if defined(FEAT_SEARCH_EXTRA)
965 end_search_hl();
966# endif
967 break;
968 }
969 row += wp->w_lines[j].wl_size;
970 }
Bram Moolenaarc10f0e72017-02-01 18:37:14 +0100971
972 update_finish();
Bram Moolenaarf3d769a2017-09-22 13:44:56 +0200973
974#ifdef SYN_TIME_LIMIT
975 syn_set_timeout(NULL);
976#endif
Bram Moolenaar860cae12010-06-05 23:22:07 +0200977 }
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200978 need_cursor_line_redraw = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979}
980#endif
981
982#if defined(FEAT_SIGNS) || defined(PROTO)
983 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100984update_debug_sign(buf_T *buf, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000985{
986 win_T *wp;
987 int doit = FALSE;
988
989# ifdef FEAT_FOLDING
990 win_foldinfo.fi_level = 0;
991# endif
992
993 /* update/delete a specific mark */
994 FOR_ALL_WINDOWS(wp)
995 {
996 if (buf != NULL && lnum > 0)
997 {
998 if (wp->w_buffer == buf && lnum >= wp->w_topline
999 && lnum < wp->w_botline)
1000 {
1001 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
1002 wp->w_redraw_top = lnum;
1003 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
1004 wp->w_redraw_bot = lnum;
1005 redraw_win_later(wp, VALID);
1006 }
1007 }
1008 else
1009 redraw_win_later(wp, VALID);
1010 if (wp->w_redr_type != 0)
1011 doit = TRUE;
1012 }
1013
Bram Moolenaar738f8fc2012-01-10 12:42:09 +01001014 /* Return when there is nothing to do, screen updating is already
Bram Moolenaar07920482017-08-01 20:53:30 +02001015 * happening (recursive call), messages on the screen or still starting up.
1016 */
Bram Moolenaar738f8fc2012-01-10 12:42:09 +01001017 if (!doit || updating_screen
Bram Moolenaar07920482017-08-01 20:53:30 +02001018 || State == ASKMORE || State == HITRETURN
1019 || msg_scrolled
Bram Moolenaar738f8fc2012-01-10 12:42:09 +01001020#ifdef FEAT_GUI
1021 || gui.starting
1022#endif
1023 || starting)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024 return;
1025
1026 /* update all windows that need updating */
1027 update_prepare();
1028
Bram Moolenaar29323592016-07-24 22:04:11 +02001029 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030 {
1031 if (wp->w_redr_type != 0)
1032 win_update(wp);
1033 if (wp->w_redr_status)
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001034 win_redr_status(wp, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036
1037 update_finish();
1038}
1039#endif
1040
1041
1042#if defined(FEAT_GUI) || defined(PROTO)
1043/*
1044 * Update a single window, its status line and maybe the command line msg.
1045 * Used for the GUI scrollbar.
1046 */
1047 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001048updateWindow(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049{
Bram Moolenaar19f990e2009-11-25 12:08:03 +00001050 /* return if already busy updating */
1051 if (updating_screen)
1052 return;
1053
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054 update_prepare();
1055
1056#ifdef FEAT_CLIPBOARD
1057 /* When Visual area changed, may have to update selection. */
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02001058 if (clip_star.available && clip_isautosel_star())
1059 clip_update_selection(&clip_star);
1060 if (clip_plus.available && clip_isautosel_plus())
1061 clip_update_selection(&clip_plus);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062#endif
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001063
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 win_update(wp);
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001065
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001066 /* When the screen was cleared redraw the tab pages line. */
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00001067 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001068 draw_tabline();
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00001069
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 if (wp->w_redr_status
1071# ifdef FEAT_CMDL_INFO
1072 || p_ru
1073# endif
1074# ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00001075 || *p_stl != NUL || *wp->w_p_stl != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076# endif
1077 )
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001078 win_redr_status(wp, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079
1080 update_finish();
1081}
1082#endif
1083
1084/*
1085 * Update a single window.
1086 *
1087 * This may cause the windows below it also to be redrawn (when clearing the
1088 * screen or scrolling lines).
1089 *
1090 * How the window is redrawn depends on wp->w_redr_type. Each type also
1091 * implies the one below it.
1092 * NOT_VALID redraw the whole window
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001093 * SOME_VALID redraw the whole window but do scroll when possible
Bram Moolenaar071d4272004-06-13 20:20:40 +00001094 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
1095 * INVERTED redraw the changed part of the Visual area
1096 * INVERTED_ALL redraw the whole Visual area
1097 * VALID 1. scroll up/down to adjust for a changed w_topline
1098 * 2. update lines at the top when scrolled down
1099 * 3. redraw changed text:
Bram Moolenaar75c50c42005-06-04 22:06:24 +00001100 * - if wp->w_buffer->b_mod_set set, update lines between
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 * b_mod_top and b_mod_bot.
1102 * - if wp->w_redraw_top non-zero, redraw lines between
1103 * wp->w_redraw_top and wp->w_redr_bot.
1104 * - continue redrawing when syntax status is invalid.
1105 * 4. if scrolled up, update lines at the bottom.
1106 * This results in three areas that may need updating:
1107 * top: from first row to top_end (when scrolled down)
1108 * mid: from mid_start to mid_end (update inversion or changed text)
1109 * bot: from bot_start to last row (when scrolled up)
1110 */
1111 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001112win_update(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001113{
1114 buf_T *buf = wp->w_buffer;
1115 int type;
1116 int top_end = 0; /* Below last row of the top area that needs
1117 updating. 0 when no top area updating. */
1118 int mid_start = 999;/* first row of the mid area that needs
1119 updating. 999 when no mid area updating. */
1120 int mid_end = 0; /* Below last row of the mid area that needs
1121 updating. 0 when no mid area updating. */
1122 int bot_start = 999;/* first row of the bot area that needs
1123 updating. 999 when no bot area updating */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 int scrolled_down = FALSE; /* TRUE when scrolled down when
1125 w_topline got smaller a bit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001127 matchitem_T *cur; /* points to the match list */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 int top_to_mod = FALSE; /* redraw above mod_top */
1129#endif
1130
1131 int row; /* current window row to display */
1132 linenr_T lnum; /* current buffer lnum to display */
1133 int idx; /* current index in w_lines[] */
1134 int srow; /* starting row of the current line */
1135
1136 int eof = FALSE; /* if TRUE, we hit the end of the file */
1137 int didline = FALSE; /* if TRUE, we finished the last line */
1138 int i;
1139 long j;
1140 static int recursive = FALSE; /* being called recursively */
1141 int old_botline = wp->w_botline;
1142#ifdef FEAT_FOLDING
1143 long fold_count;
1144#endif
1145#ifdef FEAT_SYN_HL
1146 /* remember what happened to the previous line, to know if
1147 * check_visual_highlight() can be used */
1148#define DID_NONE 1 /* didn't update a line */
1149#define DID_LINE 2 /* updated a normal line */
1150#define DID_FOLD 3 /* updated a folded line */
1151 int did_update = DID_NONE;
1152 linenr_T syntax_last_parsed = 0; /* last parsed text line */
1153#endif
1154 linenr_T mod_top = 0;
1155 linenr_T mod_bot = 0;
1156#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1157 int save_got_int;
1158#endif
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001159#ifdef SYN_TIME_LIMIT
1160 proftime_T syntax_tm;
1161#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162
1163 type = wp->w_redr_type;
1164
1165 if (type == NOT_VALID)
1166 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168 wp->w_lines_valid = 0;
1169 }
1170
1171 /* Window is zero-height: nothing to draw. */
Bram Moolenaar415a6932017-12-05 20:31:07 +01001172 if (wp->w_height + WINBAR_HEIGHT(wp) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173 {
1174 wp->w_redr_type = 0;
1175 return;
1176 }
1177
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 /* Window is zero-width: Only need to draw the separator. */
1179 if (wp->w_width == 0)
1180 {
1181 /* draw the vertical separator right of this window */
1182 draw_vsep_win(wp, 0);
1183 wp->w_redr_type = 0;
1184 return;
1185 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001187#ifdef FEAT_TERMINAL
Bram Moolenaar6eddadf2018-05-06 16:40:16 +02001188 // If this window contains a terminal, redraw works completely differently.
1189 if (term_do_update_window(wp))
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001190 {
Bram Moolenaar6eddadf2018-05-06 16:40:16 +02001191 term_update_window(wp);
Bram Moolenaar181ca992018-02-13 21:19:21 +01001192# ifdef FEAT_MENU
1193 /* Draw the window toolbar, if there is one. */
1194 if (winbar_height(wp) > 0)
1195 redraw_win_toolbar(wp);
1196# endif
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02001197 wp->w_redr_type = 0;
1198 return;
1199 }
1200#endif
1201
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +02001203 init_search_hl(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204#endif
1205
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001206#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +02001207 /* Force redraw when width of 'number' or 'relativenumber' column
1208 * changes. */
1209 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001210 if (wp->w_nrwidth != i)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001211 {
1212 type = NOT_VALID;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00001213 wp->w_nrwidth = i;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001214 }
1215 else
1216#endif
1217
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
1219 {
1220 /*
1221 * When there are both inserted/deleted lines and specific lines to be
1222 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
1223 * everything (only happens when redrawing is off for while).
1224 */
1225 type = NOT_VALID;
1226 }
1227 else
1228 {
1229 /*
1230 * Set mod_top to the first line that needs displaying because of
1231 * changes. Set mod_bot to the first line after the changes.
1232 */
1233 mod_top = wp->w_redraw_top;
1234 if (wp->w_redraw_bot != 0)
1235 mod_bot = wp->w_redraw_bot + 1;
1236 else
1237 mod_bot = 0;
1238 wp->w_redraw_top = 0; /* reset for next time */
1239 wp->w_redraw_bot = 0;
1240 if (buf->b_mod_set)
1241 {
1242 if (mod_top == 0 || mod_top > buf->b_mod_top)
1243 {
1244 mod_top = buf->b_mod_top;
1245#ifdef FEAT_SYN_HL
1246 /* Need to redraw lines above the change that may be included
1247 * in a pattern match. */
Bram Moolenaar860cae12010-06-05 23:22:07 +02001248 if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02001250 mod_top -= buf->b_s.b_syn_sync_linebreaks;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251 if (mod_top < 1)
1252 mod_top = 1;
1253 }
1254#endif
1255 }
1256 if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
1257 mod_bot = buf->b_mod_bot;
1258
1259#ifdef FEAT_SEARCH_EXTRA
1260 /* When 'hlsearch' is on and using a multi-line search pattern, a
1261 * change in one line may make the Search highlighting in a
1262 * previous line invalid. Simple solution: redraw all visible
1263 * lines above the change.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001264 * Same for a match pattern.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 */
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001266 if (search_hl.rm.regprog != NULL
1267 && re_multiline(search_hl.rm.regprog))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 top_to_mod = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001269 else
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001270 {
1271 cur = wp->w_match_head;
1272 while (cur != NULL)
1273 {
1274 if (cur->match.regprog != NULL
1275 && re_multiline(cur->match.regprog))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00001276 {
1277 top_to_mod = TRUE;
1278 break;
1279 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00001280 cur = cur->next;
1281 }
1282 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001283#endif
1284 }
1285#ifdef FEAT_FOLDING
1286 if (mod_top != 0 && hasAnyFolding(wp))
1287 {
1288 linenr_T lnumt, lnumb;
1289
1290 /*
1291 * A change in a line can cause lines above it to become folded or
1292 * unfolded. Find the top most buffer line that may be affected.
1293 * If the line was previously folded and displayed, get the first
1294 * line of that fold. If the line is folded now, get the first
1295 * folded line. Use the minimum of these two.
1296 */
1297
1298 /* Find last valid w_lines[] entry above mod_top. Set lnumt to
1299 * the line below it. If there is no valid entry, use w_topline.
1300 * Find the first valid w_lines[] entry below mod_bot. Set lnumb
1301 * to this line. If there is no valid entry, use MAXLNUM. */
1302 lnumt = wp->w_topline;
1303 lnumb = MAXLNUM;
1304 for (i = 0; i < wp->w_lines_valid; ++i)
1305 if (wp->w_lines[i].wl_valid)
1306 {
1307 if (wp->w_lines[i].wl_lastlnum < mod_top)
1308 lnumt = wp->w_lines[i].wl_lastlnum + 1;
1309 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1310 {
1311 lnumb = wp->w_lines[i].wl_lnum;
1312 /* When there is a fold column it might need updating
1313 * in the next line ("J" just above an open fold). */
Bram Moolenaar1c934292015-01-27 16:39:29 +01001314 if (compute_foldcolumn(wp, 0) > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 ++lnumb;
1316 }
1317 }
1318
1319 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1320 if (mod_top > lnumt)
1321 mod_top = lnumt;
1322
1323 /* Now do the same for the bottom line (one above mod_bot). */
1324 --mod_bot;
1325 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1326 ++mod_bot;
1327 if (mod_bot < lnumb)
1328 mod_bot = lnumb;
1329 }
1330#endif
1331
1332 /* When a change starts above w_topline and the end is below
1333 * w_topline, start redrawing at w_topline.
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001334 * If the end of the change is above w_topline: do like no change was
1335 * made, but redraw the first line to find changes in syntax. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336 if (mod_top != 0 && mod_top < wp->w_topline)
1337 {
1338 if (mod_bot > wp->w_topline)
1339 mod_top = wp->w_topline;
1340#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02001341 else if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 top_end = 1;
1343#endif
1344 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001345
1346 /* When line numbers are displayed need to redraw all lines below
1347 * inserted/deleted lines. */
1348 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1349 mod_bot = MAXLNUM;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350 }
1351
1352 /*
1353 * When only displaying the lines at the top, set top_end. Used when
1354 * window has scrolled down for msg_scrolled.
1355 */
1356 if (type == REDRAW_TOP)
1357 {
1358 j = 0;
1359 for (i = 0; i < wp->w_lines_valid; ++i)
1360 {
1361 j += wp->w_lines[i].wl_size;
1362 if (j >= wp->w_upd_rows)
1363 {
1364 top_end = j;
1365 break;
1366 }
1367 }
1368 if (top_end == 0)
1369 /* not found (cannot happen?): redraw everything */
1370 type = NOT_VALID;
1371 else
1372 /* top area defined, the rest is VALID */
1373 type = VALID;
1374 }
1375
Bram Moolenaar367329b2007-08-30 11:53:22 +00001376 /* Trick: we want to avoid clearing the screen twice. screenclear() will
Bram Moolenaar943fae42007-07-30 20:00:38 +00001377 * set "screen_cleared" to TRUE. The special value MAYBE (which is still
1378 * non-zero and thus not FALSE) will indicate that screenclear() was not
1379 * called. */
1380 if (screen_cleared)
1381 screen_cleared = MAYBE;
1382
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383 /*
1384 * If there are no changes on the screen that require a complete redraw,
1385 * handle three cases:
1386 * 1: we are off the top of the screen by a few lines: scroll down
1387 * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1388 * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1389 * w_lines[] that needs updating.
1390 */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001391 if ((type == VALID || type == SOME_VALID
1392 || type == INVERTED || type == INVERTED_ALL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001393#ifdef FEAT_DIFF
1394 && !wp->w_botfill && !wp->w_old_botfill
1395#endif
1396 )
1397 {
1398 if (mod_top != 0 && wp->w_topline == mod_top)
1399 {
1400 /*
1401 * w_topline is the first changed line, the scrolling will be done
1402 * further down.
1403 */
1404 }
1405 else if (wp->w_lines[0].wl_valid
1406 && (wp->w_topline < wp->w_lines[0].wl_lnum
1407#ifdef FEAT_DIFF
1408 || (wp->w_topline == wp->w_lines[0].wl_lnum
1409 && wp->w_topfill > wp->w_old_topfill)
1410#endif
1411 ))
1412 {
1413 /*
1414 * New topline is above old topline: May scroll down.
1415 */
1416#ifdef FEAT_FOLDING
1417 if (hasAnyFolding(wp))
1418 {
1419 linenr_T ln;
1420
1421 /* count the number of lines we are off, counting a sequence
1422 * of folded lines as one */
1423 j = 0;
1424 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1425 {
1426 ++j;
1427 if (j >= wp->w_height - 2)
1428 break;
1429 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1430 }
1431 }
1432 else
1433#endif
1434 j = wp->w_lines[0].wl_lnum - wp->w_topline;
1435 if (j < wp->w_height - 2) /* not too far off */
1436 {
1437 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1438#ifdef FEAT_DIFF
1439 /* insert extra lines for previously invisible filler lines */
1440 if (wp->w_lines[0].wl_lnum != wp->w_topline)
1441 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1442 - wp->w_old_topfill;
1443#endif
1444 if (i < wp->w_height - 2) /* less than a screen off */
1445 {
1446 /*
1447 * Try to insert the correct number of lines.
1448 * If not the last window, delete the lines at the bottom.
1449 * win_ins_lines may fail when the terminal can't do it.
1450 */
1451 if (i > 0)
1452 check_for_delay(FALSE);
1453 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1454 {
1455 if (wp->w_lines_valid != 0)
1456 {
1457 /* Need to update rows that are new, stop at the
1458 * first one that scrolled down. */
1459 top_end = i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 scrolled_down = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001461
1462 /* Move the entries that were scrolled, disable
1463 * the entries for the lines to be redrawn. */
1464 if ((wp->w_lines_valid += j) > wp->w_height)
1465 wp->w_lines_valid = wp->w_height;
1466 for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1467 wp->w_lines[idx] = wp->w_lines[idx - j];
1468 while (idx >= 0)
1469 wp->w_lines[idx--].wl_valid = FALSE;
1470 }
1471 }
1472 else
1473 mid_start = 0; /* redraw all lines */
1474 }
1475 else
1476 mid_start = 0; /* redraw all lines */
1477 }
1478 else
1479 mid_start = 0; /* redraw all lines */
1480 }
1481 else
1482 {
1483 /*
1484 * New topline is at or below old topline: May scroll up.
1485 * When topline didn't change, find first entry in w_lines[] that
1486 * needs updating.
1487 */
1488
1489 /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
1490 j = -1;
1491 row = 0;
1492 for (i = 0; i < wp->w_lines_valid; i++)
1493 {
1494 if (wp->w_lines[i].wl_valid
1495 && wp->w_lines[i].wl_lnum == wp->w_topline)
1496 {
1497 j = i;
1498 break;
1499 }
1500 row += wp->w_lines[i].wl_size;
1501 }
1502 if (j == -1)
1503 {
1504 /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1505 * lines */
1506 mid_start = 0;
1507 }
1508 else
1509 {
1510 /*
1511 * Try to delete the correct number of lines.
1512 * wp->w_topline is at wp->w_lines[i].wl_lnum.
1513 */
1514#ifdef FEAT_DIFF
1515 /* If the topline didn't change, delete old filler lines,
1516 * otherwise delete filler lines of the new topline... */
1517 if (wp->w_lines[0].wl_lnum == wp->w_topline)
1518 row += wp->w_old_topfill;
1519 else
1520 row += diff_check_fill(wp, wp->w_topline);
1521 /* ... but don't delete new filler lines. */
1522 row -= wp->w_topfill;
1523#endif
1524 if (row > 0)
1525 {
1526 check_for_delay(FALSE);
Bram Moolenaarcfce7172017-08-17 20:31:48 +02001527 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
1528 == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001529 bot_start = wp->w_height - row;
1530 else
1531 mid_start = 0; /* redraw all lines */
1532 }
1533 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1534 {
1535 /*
1536 * Skip the lines (below the deleted lines) that are still
1537 * valid and don't need redrawing. Copy their info
1538 * upwards, to compensate for the deleted lines. Set
1539 * bot_start to the first row that needs redrawing.
1540 */
1541 bot_start = 0;
1542 idx = 0;
1543 for (;;)
1544 {
1545 wp->w_lines[idx] = wp->w_lines[j];
1546 /* stop at line that didn't fit, unless it is still
1547 * valid (no lines deleted) */
1548 if (row > 0 && bot_start + row
1549 + (int)wp->w_lines[j].wl_size > wp->w_height)
1550 {
1551 wp->w_lines_valid = idx + 1;
1552 break;
1553 }
1554 bot_start += wp->w_lines[idx++].wl_size;
1555
1556 /* stop at the last valid entry in w_lines[].wl_size */
1557 if (++j >= wp->w_lines_valid)
1558 {
1559 wp->w_lines_valid = idx;
1560 break;
1561 }
1562 }
1563#ifdef FEAT_DIFF
1564 /* Correct the first entry for filler lines at the top
1565 * when it won't get updated below. */
1566 if (wp->w_p_diff && bot_start > 0)
1567 wp->w_lines[0].wl_size =
1568 plines_win_nofill(wp, wp->w_topline, TRUE)
1569 + wp->w_topfill;
1570#endif
1571 }
1572 }
1573 }
1574
1575 /* When starting redraw in the first line, redraw all lines. When
1576 * there is only one window it's probably faster to clear the screen
1577 * first. */
1578 if (mid_start == 0)
1579 {
1580 mid_end = wp->w_height;
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01001581 if (ONE_WINDOW)
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001582 {
Bram Moolenaar943fae42007-07-30 20:00:38 +00001583 /* Clear the screen when it was not done by win_del_lines() or
1584 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1585 * then. */
1586 if (screen_cleared != TRUE)
1587 screenclear();
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001588 /* The screen was cleared, redraw the tab pages line. */
1589 if (redraw_tabline)
1590 draw_tabline();
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001591 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592 }
Bram Moolenaar943fae42007-07-30 20:00:38 +00001593
1594 /* When win_del_lines() or win_ins_lines() caused the screen to be
1595 * cleared (only happens for the first window) or when screenclear()
1596 * was called directly above, "must_redraw" will have been set to
1597 * NOT_VALID, need to reset it here to avoid redrawing twice. */
1598 if (screen_cleared == TRUE)
1599 must_redraw = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600 }
1601 else
1602 {
1603 /* Not VALID or INVERTED: redraw all lines. */
1604 mid_start = 0;
1605 mid_end = wp->w_height;
1606 }
1607
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001608 if (type == SOME_VALID)
1609 {
1610 /* SOME_VALID: redraw all lines. */
1611 mid_start = 0;
1612 mid_end = wp->w_height;
1613 type = NOT_VALID;
1614 }
1615
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 /* check if we are updating or removing the inverted part */
1617 if ((VIsual_active && buf == curwin->w_buffer)
1618 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1619 {
1620 linenr_T from, to;
1621
1622 if (VIsual_active)
1623 {
1624 if (VIsual_active
1625 && (VIsual_mode != wp->w_old_visual_mode
1626 || type == INVERTED_ALL))
1627 {
1628 /*
1629 * If the type of Visual selection changed, redraw the whole
1630 * selection. Also when the ownership of the X selection is
1631 * gained or lost.
1632 */
1633 if (curwin->w_cursor.lnum < VIsual.lnum)
1634 {
1635 from = curwin->w_cursor.lnum;
1636 to = VIsual.lnum;
1637 }
1638 else
1639 {
1640 from = VIsual.lnum;
1641 to = curwin->w_cursor.lnum;
1642 }
1643 /* redraw more when the cursor moved as well */
1644 if (wp->w_old_cursor_lnum < from)
1645 from = wp->w_old_cursor_lnum;
1646 if (wp->w_old_cursor_lnum > to)
1647 to = wp->w_old_cursor_lnum;
1648 if (wp->w_old_visual_lnum < from)
1649 from = wp->w_old_visual_lnum;
1650 if (wp->w_old_visual_lnum > to)
1651 to = wp->w_old_visual_lnum;
1652 }
1653 else
1654 {
1655 /*
1656 * Find the line numbers that need to be updated: The lines
1657 * between the old cursor position and the current cursor
1658 * position. Also check if the Visual position changed.
1659 */
1660 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1661 {
1662 from = curwin->w_cursor.lnum;
1663 to = wp->w_old_cursor_lnum;
1664 }
1665 else
1666 {
1667 from = wp->w_old_cursor_lnum;
1668 to = curwin->w_cursor.lnum;
1669 if (from == 0) /* Visual mode just started */
1670 from = to;
1671 }
1672
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001673 if (VIsual.lnum != wp->w_old_visual_lnum
1674 || VIsual.col != wp->w_old_visual_col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675 {
1676 if (wp->w_old_visual_lnum < from
1677 && wp->w_old_visual_lnum != 0)
1678 from = wp->w_old_visual_lnum;
1679 if (wp->w_old_visual_lnum > to)
1680 to = wp->w_old_visual_lnum;
1681 if (VIsual.lnum < from)
1682 from = VIsual.lnum;
1683 if (VIsual.lnum > to)
1684 to = VIsual.lnum;
1685 }
1686 }
1687
1688 /*
1689 * If in block mode and changed column or curwin->w_curswant:
1690 * update all lines.
1691 * First compute the actual start and end column.
1692 */
1693 if (VIsual_mode == Ctrl_V)
1694 {
Bram Moolenaar404406a2014-10-09 13:24:43 +02001695 colnr_T fromc, toc;
1696#if defined(FEAT_VIRTUALEDIT) && defined(FEAT_LINEBREAK)
1697 int save_ve_flags = ve_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698
Bram Moolenaar404406a2014-10-09 13:24:43 +02001699 if (curwin->w_p_lbr)
1700 ve_flags = VE_ALL;
1701#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
Bram Moolenaar404406a2014-10-09 13:24:43 +02001703#if defined(FEAT_VIRTUALEDIT) && defined(FEAT_LINEBREAK)
1704 ve_flags = save_ve_flags;
1705#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001706 ++toc;
1707 if (curwin->w_curswant == MAXCOL)
1708 toc = MAXCOL;
1709
1710 if (fromc != wp->w_old_cursor_fcol
1711 || toc != wp->w_old_cursor_lcol)
1712 {
1713 if (from > VIsual.lnum)
1714 from = VIsual.lnum;
1715 if (to < VIsual.lnum)
1716 to = VIsual.lnum;
1717 }
1718 wp->w_old_cursor_fcol = fromc;
1719 wp->w_old_cursor_lcol = toc;
1720 }
1721 }
1722 else
1723 {
1724 /* Use the line numbers of the old Visual area. */
1725 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
1726 {
1727 from = wp->w_old_cursor_lnum;
1728 to = wp->w_old_visual_lnum;
1729 }
1730 else
1731 {
1732 from = wp->w_old_visual_lnum;
1733 to = wp->w_old_cursor_lnum;
1734 }
1735 }
1736
1737 /*
1738 * There is no need to update lines above the top of the window.
1739 */
1740 if (from < wp->w_topline)
1741 from = wp->w_topline;
1742
1743 /*
1744 * If we know the value of w_botline, use it to restrict the update to
1745 * the lines that are visible in the window.
1746 */
1747 if (wp->w_valid & VALID_BOTLINE)
1748 {
1749 if (from >= wp->w_botline)
1750 from = wp->w_botline - 1;
1751 if (to >= wp->w_botline)
1752 to = wp->w_botline - 1;
1753 }
1754
1755 /*
1756 * Find the minimal part to be updated.
1757 * Watch out for scrolling that made entries in w_lines[] invalid.
1758 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
1759 * top_end; need to redraw from top_end to the "to" line.
1760 * A middle mouse click with a Visual selection may change the text
1761 * above the Visual area and reset wl_valid, do count these for
1762 * mid_end (in srow).
1763 */
1764 if (mid_start > 0)
1765 {
1766 lnum = wp->w_topline;
1767 idx = 0;
1768 srow = 0;
1769 if (scrolled_down)
1770 mid_start = top_end;
1771 else
1772 mid_start = 0;
1773 while (lnum < from && idx < wp->w_lines_valid) /* find start */
1774 {
1775 if (wp->w_lines[idx].wl_valid)
1776 mid_start += wp->w_lines[idx].wl_size;
1777 else if (!scrolled_down)
1778 srow += wp->w_lines[idx].wl_size;
1779 ++idx;
1780# ifdef FEAT_FOLDING
1781 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
1782 lnum = wp->w_lines[idx].wl_lnum;
1783 else
1784# endif
1785 ++lnum;
1786 }
1787 srow += mid_start;
1788 mid_end = wp->w_height;
1789 for ( ; idx < wp->w_lines_valid; ++idx) /* find end */
1790 {
1791 if (wp->w_lines[idx].wl_valid
1792 && wp->w_lines[idx].wl_lnum >= to + 1)
1793 {
1794 /* Only update until first row of this line */
1795 mid_end = srow;
1796 break;
1797 }
1798 srow += wp->w_lines[idx].wl_size;
1799 }
1800 }
1801 }
1802
1803 if (VIsual_active && buf == curwin->w_buffer)
1804 {
1805 wp->w_old_visual_mode = VIsual_mode;
1806 wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
1807 wp->w_old_visual_lnum = VIsual.lnum;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001808 wp->w_old_visual_col = VIsual.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809 wp->w_old_curswant = curwin->w_curswant;
1810 }
1811 else
1812 {
1813 wp->w_old_visual_mode = 0;
1814 wp->w_old_cursor_lnum = 0;
1815 wp->w_old_visual_lnum = 0;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001816 wp->w_old_visual_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818
1819#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1820 /* reset got_int, otherwise regexp won't work */
1821 save_got_int = got_int;
1822 got_int = 0;
1823#endif
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001824#ifdef SYN_TIME_LIMIT
1825 /* Set the time limit to 'redrawtime'. */
1826 profile_setlimit(p_rdt, &syntax_tm);
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02001827 syn_set_timeout(&syntax_tm);
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02001828#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829#ifdef FEAT_FOLDING
1830 win_foldinfo.fi_level = 0;
1831#endif
1832
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02001833#ifdef FEAT_MENU
1834 /*
1835 * Draw the window toolbar, if there is one.
1836 * TODO: only when needed.
1837 */
1838 if (winbar_height(wp) > 0)
1839 redraw_win_toolbar(wp);
1840#endif
1841
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842 /*
1843 * Update all the window rows.
1844 */
1845 idx = 0; /* first entry in w_lines[].wl_size */
1846 row = 0;
1847 srow = 0;
1848 lnum = wp->w_topline; /* first line shown in window */
1849 for (;;)
1850 {
1851 /* stop updating when reached the end of the window (check for _past_
1852 * the end of the window is at the end of the loop) */
1853 if (row == wp->w_height)
1854 {
1855 didline = TRUE;
1856 break;
1857 }
1858
1859 /* stop updating when hit the end of the file */
1860 if (lnum > buf->b_ml.ml_line_count)
1861 {
1862 eof = TRUE;
1863 break;
1864 }
1865
1866 /* Remember the starting row of the line that is going to be dealt
1867 * with. It is used further down when the line doesn't fit. */
1868 srow = row;
1869
1870 /*
1871 * Update a line when it is in an area that needs updating, when it
1872 * has changes or w_lines[idx] is invalid.
1873 * bot_start may be halfway a wrapped line after using
1874 * win_del_lines(), check if the current line includes it.
1875 * When syntax folding is being used, the saved syntax states will
1876 * already have been updated, we can't see where the syntax state is
1877 * the same again, just update until the end of the window.
1878 */
1879 if (row < top_end
1880 || (row >= mid_start && row < mid_end)
1881#ifdef FEAT_SEARCH_EXTRA
1882 || top_to_mod
1883#endif
1884 || idx >= wp->w_lines_valid
1885 || (row + wp->w_lines[idx].wl_size > bot_start)
1886 || (mod_top != 0
1887 && (lnum == mod_top
1888 || (lnum >= mod_top
1889 && (lnum < mod_bot
1890#ifdef FEAT_SYN_HL
1891 || did_update == DID_FOLD
1892 || (did_update == DID_LINE
Bram Moolenaar860cae12010-06-05 23:22:07 +02001893 && syntax_present(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 && (
1895# ifdef FEAT_FOLDING
1896 (foldmethodIsSyntax(wp)
1897 && hasAnyFolding(wp)) ||
1898# endif
1899 syntax_check_changed(lnum)))
1900#endif
Bram Moolenaar4ce239b2013-06-15 23:00:30 +02001901#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaardab70c62014-07-02 17:16:58 +02001902 /* match in fixed position might need redraw
1903 * if lines were inserted or deleted */
1904 || (wp->w_match_head != NULL
1905 && buf->b_mod_xlines != 0)
Bram Moolenaar4ce239b2013-06-15 23:00:30 +02001906#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 )))))
1908 {
1909#ifdef FEAT_SEARCH_EXTRA
1910 if (lnum == mod_top)
1911 top_to_mod = FALSE;
1912#endif
1913
1914 /*
1915 * When at start of changed lines: May scroll following lines
1916 * up or down to minimize redrawing.
1917 * Don't do this when the change continues until the end.
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001918 * Don't scroll when dollar_vcol >= 0, keep the "$".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919 */
1920 if (lnum == mod_top
1921 && mod_bot != MAXLNUM
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001922 && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 {
1924 int old_rows = 0;
1925 int new_rows = 0;
1926 int xtra_rows;
1927 linenr_T l;
1928
1929 /* Count the old number of window rows, using w_lines[], which
1930 * should still contain the sizes for the lines as they are
1931 * currently displayed. */
1932 for (i = idx; i < wp->w_lines_valid; ++i)
1933 {
1934 /* Only valid lines have a meaningful wl_lnum. Invalid
1935 * lines are part of the changed area. */
1936 if (wp->w_lines[i].wl_valid
1937 && wp->w_lines[i].wl_lnum == mod_bot)
1938 break;
1939 old_rows += wp->w_lines[i].wl_size;
1940#ifdef FEAT_FOLDING
1941 if (wp->w_lines[i].wl_valid
1942 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
1943 {
1944 /* Must have found the last valid entry above mod_bot.
1945 * Add following invalid entries. */
1946 ++i;
1947 while (i < wp->w_lines_valid
1948 && !wp->w_lines[i].wl_valid)
1949 old_rows += wp->w_lines[i++].wl_size;
1950 break;
1951 }
1952#endif
1953 }
1954
1955 if (i >= wp->w_lines_valid)
1956 {
1957 /* We can't find a valid line below the changed lines,
1958 * need to redraw until the end of the window.
1959 * Inserting/deleting lines has no use. */
1960 bot_start = 0;
1961 }
1962 else
1963 {
1964 /* Able to count old number of rows: Count new window
1965 * rows, and may insert/delete lines */
1966 j = idx;
1967 for (l = lnum; l < mod_bot; ++l)
1968 {
1969#ifdef FEAT_FOLDING
1970 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
1971 ++new_rows;
1972 else
1973#endif
1974#ifdef FEAT_DIFF
1975 if (l == wp->w_topline)
1976 new_rows += plines_win_nofill(wp, l, TRUE)
1977 + wp->w_topfill;
1978 else
1979#endif
1980 new_rows += plines_win(wp, l, TRUE);
1981 ++j;
1982 if (new_rows > wp->w_height - row - 2)
1983 {
1984 /* it's getting too much, must redraw the rest */
1985 new_rows = 9999;
1986 break;
1987 }
1988 }
1989 xtra_rows = new_rows - old_rows;
1990 if (xtra_rows < 0)
1991 {
1992 /* May scroll text up. If there is not enough
1993 * remaining text or scrolling fails, must redraw the
1994 * rest. If scrolling works, must redraw the text
1995 * below the scrolled text. */
1996 if (row - xtra_rows >= wp->w_height - 2)
1997 mod_bot = MAXLNUM;
1998 else
1999 {
2000 check_for_delay(FALSE);
2001 if (win_del_lines(wp, row,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02002002 -xtra_rows, FALSE, FALSE, 0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003 mod_bot = MAXLNUM;
2004 else
2005 bot_start = wp->w_height + xtra_rows;
2006 }
2007 }
2008 else if (xtra_rows > 0)
2009 {
2010 /* May scroll text down. If there is not enough
2011 * remaining text of scrolling fails, must redraw the
2012 * rest. */
2013 if (row + xtra_rows >= wp->w_height - 2)
2014 mod_bot = MAXLNUM;
2015 else
2016 {
2017 check_for_delay(FALSE);
2018 if (win_ins_lines(wp, row + old_rows,
2019 xtra_rows, FALSE, FALSE) == FAIL)
2020 mod_bot = MAXLNUM;
2021 else if (top_end > row + old_rows)
2022 /* Scrolled the part at the top that requires
2023 * updating down. */
2024 top_end += xtra_rows;
2025 }
2026 }
2027
2028 /* When not updating the rest, may need to move w_lines[]
2029 * entries. */
2030 if (mod_bot != MAXLNUM && i != j)
2031 {
2032 if (j < i)
2033 {
2034 int x = row + new_rows;
2035
2036 /* move entries in w_lines[] upwards */
2037 for (;;)
2038 {
2039 /* stop at last valid entry in w_lines[] */
2040 if (i >= wp->w_lines_valid)
2041 {
2042 wp->w_lines_valid = j;
2043 break;
2044 }
2045 wp->w_lines[j] = wp->w_lines[i];
2046 /* stop at a line that won't fit */
2047 if (x + (int)wp->w_lines[j].wl_size
2048 > wp->w_height)
2049 {
2050 wp->w_lines_valid = j + 1;
2051 break;
2052 }
2053 x += wp->w_lines[j++].wl_size;
2054 ++i;
2055 }
2056 if (bot_start > x)
2057 bot_start = x;
2058 }
2059 else /* j > i */
2060 {
2061 /* move entries in w_lines[] downwards */
2062 j -= i;
2063 wp->w_lines_valid += j;
2064 if (wp->w_lines_valid > wp->w_height)
2065 wp->w_lines_valid = wp->w_height;
2066 for (i = wp->w_lines_valid; i - j >= idx; --i)
2067 wp->w_lines[i] = wp->w_lines[i - j];
2068
2069 /* The w_lines[] entries for inserted lines are
2070 * now invalid, but wl_size may be used above.
2071 * Reset to zero. */
2072 while (i >= idx)
2073 {
2074 wp->w_lines[i].wl_size = 0;
2075 wp->w_lines[i--].wl_valid = FALSE;
2076 }
2077 }
2078 }
2079 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 }
2081
2082#ifdef FEAT_FOLDING
2083 /*
2084 * When lines are folded, display one line for all of them.
2085 * Otherwise, display normally (can be several display lines when
2086 * 'wrap' is on).
2087 */
2088 fold_count = foldedCount(wp, lnum, &win_foldinfo);
2089 if (fold_count != 0)
2090 {
2091 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2092 ++row;
2093 --fold_count;
2094 wp->w_lines[idx].wl_folded = TRUE;
2095 wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
2096# ifdef FEAT_SYN_HL
2097 did_update = DID_FOLD;
2098# endif
2099 }
2100 else
2101#endif
2102 if (idx < wp->w_lines_valid
2103 && wp->w_lines[idx].wl_valid
2104 && wp->w_lines[idx].wl_lnum == lnum
2105 && lnum > wp->w_topline
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002106 && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107 && srow + wp->w_lines[idx].wl_size > wp->w_height
2108#ifdef FEAT_DIFF
2109 && diff_check_fill(wp, lnum) == 0
2110#endif
2111 )
2112 {
2113 /* This line is not going to fit. Don't draw anything here,
2114 * will draw "@ " lines below. */
2115 row = wp->w_height + 1;
2116 }
2117 else
2118 {
2119#ifdef FEAT_SEARCH_EXTRA
2120 prepare_search_hl(wp, lnum);
2121#endif
2122#ifdef FEAT_SYN_HL
2123 /* Let the syntax stuff know we skipped a few lines. */
2124 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
Bram Moolenaar860cae12010-06-05 23:22:07 +02002125 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126 syntax_end_parsing(syntax_last_parsed + 1);
2127#endif
2128
2129 /*
2130 * Display one line.
2131 */
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02002132 row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133
2134#ifdef FEAT_FOLDING
2135 wp->w_lines[idx].wl_folded = FALSE;
2136 wp->w_lines[idx].wl_lastlnum = lnum;
2137#endif
2138#ifdef FEAT_SYN_HL
2139 did_update = DID_LINE;
2140 syntax_last_parsed = lnum;
2141#endif
2142 }
2143
2144 wp->w_lines[idx].wl_lnum = lnum;
2145 wp->w_lines[idx].wl_valid = TRUE;
Bram Moolenaar0e19fc02017-10-28 14:45:16 +02002146
2147 /* Past end of the window or end of the screen. Note that after
2148 * resizing wp->w_height may be end up too big. That's a problem
2149 * elsewhere, but prevent a crash here. */
2150 if (row > wp->w_height || row + wp->w_winrow >= Rows)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151 {
2152 /* we may need the size of that too long line later on */
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002153 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
2155 ++idx;
2156 break;
2157 }
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002158 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002159 wp->w_lines[idx].wl_size = row - srow;
2160 ++idx;
2161#ifdef FEAT_FOLDING
2162 lnum += fold_count + 1;
2163#else
2164 ++lnum;
2165#endif
2166 }
2167 else
2168 {
2169 /* This line does not need updating, advance to the next one */
2170 row += wp->w_lines[idx++].wl_size;
2171 if (row > wp->w_height) /* past end of screen */
2172 break;
2173#ifdef FEAT_FOLDING
2174 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
2175#else
2176 ++lnum;
2177#endif
2178#ifdef FEAT_SYN_HL
2179 did_update = DID_NONE;
2180#endif
2181 }
2182
2183 if (lnum > buf->b_ml.ml_line_count)
2184 {
2185 eof = TRUE;
2186 break;
2187 }
2188 }
2189 /*
2190 * End of loop over all window lines.
2191 */
2192
Bram Moolenaarcafafb32018-02-22 21:07:09 +01002193#ifdef FEAT_VTP
2194 /* Rewrite the character at the end of the screen line. */
2195 if (use_vtp())
2196 {
2197 int i;
2198
2199 for (i = 0; i < Rows; ++i)
2200# ifdef FEAT_MBYTE
2201 if (enc_utf8)
2202 if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
2203 LineOffset[i] + screen_Columns) > 1)
2204 screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
2205 else
2206 screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
2207 else
2208# endif
2209 screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
2210 }
2211#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212
2213 if (idx > wp->w_lines_valid)
2214 wp->w_lines_valid = idx;
2215
2216#ifdef FEAT_SYN_HL
2217 /*
2218 * Let the syntax stuff know we stop parsing here.
2219 */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002220 if (syntax_last_parsed != 0 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 syntax_end_parsing(syntax_last_parsed + 1);
2222#endif
2223
2224 /*
2225 * If we didn't hit the end of the file, and we didn't finish the last
2226 * line we were working on, then the line didn't fit.
2227 */
2228 wp->w_empty_rows = 0;
2229#ifdef FEAT_DIFF
2230 wp->w_filler_rows = 0;
2231#endif
2232 if (!eof && !didline)
2233 {
2234 if (lnum == wp->w_topline)
2235 {
2236 /*
2237 * Single line that does not fit!
2238 * Don't overwrite it, it can be edited.
2239 */
2240 wp->w_botline = lnum + 1;
2241 }
2242#ifdef FEAT_DIFF
2243 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
2244 {
2245 /* Window ends in filler lines. */
2246 wp->w_botline = lnum;
2247 wp->w_filler_rows = wp->w_height - srow;
2248 }
2249#endif
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002250 else if (dy_flags & DY_TRUNCATE) /* 'display' has "truncate" */
2251 {
2252 int scr_row = W_WINROW(wp) + wp->w_height - 1;
2253
2254 /*
2255 * Last line isn't finished: Display "@@@" in the last screen line.
2256 */
Bram Moolenaar53f81742017-09-22 14:35:51 +02002257 screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002258 HL_ATTR(HLF_AT));
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002259 screen_fill(scr_row, scr_row + 1,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002260 (int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002261 '@', ' ', HL_ATTR(HLF_AT));
Bram Moolenaarad9c2a02016-07-27 23:26:04 +02002262 set_empty_rows(wp, srow);
2263 wp->w_botline = lnum;
2264 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */
2266 {
2267 /*
2268 * Last line isn't finished: Display "@@@" at the end.
2269 */
2270 screen_fill(W_WINROW(wp) + wp->w_height - 1,
2271 W_WINROW(wp) + wp->w_height,
2272 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002273 '@', '@', HL_ATTR(HLF_AT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 set_empty_rows(wp, srow);
2275 wp->w_botline = lnum;
2276 }
2277 else
2278 {
2279 win_draw_end(wp, '@', ' ', srow, wp->w_height, HLF_AT);
2280 wp->w_botline = lnum;
2281 }
2282 }
2283 else
2284 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 draw_vsep_win(wp, row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 if (eof) /* we hit the end of the file */
2287 {
2288 wp->w_botline = buf->b_ml.ml_line_count + 1;
2289#ifdef FEAT_DIFF
2290 j = diff_check_fill(wp, wp->w_botline);
2291 if (j > 0 && !wp->w_botfill)
2292 {
2293 /*
2294 * Display filler lines at the end of the file
2295 */
2296 if (char2cells(fill_diff) > 1)
2297 i = '-';
2298 else
2299 i = fill_diff;
2300 if (row + j > wp->w_height)
2301 j = wp->w_height - row;
2302 win_draw_end(wp, i, i, row, row + (int)j, HLF_DED);
2303 row += j;
2304 }
2305#endif
2306 }
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002307 else if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 wp->w_botline = lnum;
2309
2310 /* make sure the rest of the screen is blank */
2311 /* put '~'s on rows that aren't part of the file. */
Bram Moolenaar58b85342016-08-14 19:54:54 +02002312 win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_EOB);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 }
2314
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02002315#ifdef SYN_TIME_LIMIT
2316 syn_set_timeout(NULL);
2317#endif
2318
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 /* Reset the type of redrawing required, the window has been updated. */
2320 wp->w_redr_type = 0;
2321#ifdef FEAT_DIFF
2322 wp->w_old_topfill = wp->w_topfill;
2323 wp->w_old_botfill = wp->w_botfill;
2324#endif
2325
Bram Moolenaar76b9b362012-02-04 23:35:00 +01002326 if (dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327 {
2328 /*
2329 * There is a trick with w_botline. If we invalidate it on each
2330 * change that might modify it, this will cause a lot of expensive
2331 * calls to plines() in update_topline() each time. Therefore the
2332 * value of w_botline is often approximated, and this value is used to
2333 * compute the value of w_topline. If the value of w_botline was
2334 * wrong, check that the value of w_topline is correct (cursor is on
2335 * the visible part of the text). If it's not, we need to redraw
2336 * again. Mostly this just means scrolling up a few lines, so it
2337 * doesn't look too bad. Only do this for the current window (where
2338 * changes are relevant).
2339 */
2340 wp->w_valid |= VALID_BOTLINE;
2341 if (wp == curwin && wp->w_botline != old_botline && !recursive)
2342 {
2343 recursive = TRUE;
2344 curwin->w_valid &= ~VALID_TOPLINE;
2345 update_topline(); /* may invalidate w_botline again */
2346 if (must_redraw != 0)
2347 {
2348 /* Don't update for changes in buffer again. */
2349 i = curbuf->b_mod_set;
2350 curbuf->b_mod_set = FALSE;
2351 win_update(curwin);
2352 must_redraw = 0;
2353 curbuf->b_mod_set = i;
2354 }
2355 recursive = FALSE;
2356 }
2357 }
2358
2359#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2360 /* restore got_int, unless CTRL-C was hit while redrawing */
2361 if (!got_int)
2362 got_int = save_got_int;
2363#endif
2364}
2365
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366/*
2367 * Clear the rest of the window and mark the unused lines with "c1". use "c2"
2368 * as the filler character.
2369 */
2370 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002371win_draw_end(
2372 win_T *wp,
2373 int c1,
2374 int c2,
2375 int row,
2376 int endrow,
2377 hlf_T hl)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378{
2379#if defined(FEAT_FOLDING) || defined(FEAT_SIGNS) || defined(FEAT_CMDWIN)
2380 int n = 0;
2381# define FDC_OFF n
2382#else
2383# define FDC_OFF 0
2384#endif
Bram Moolenaar1c934292015-01-27 16:39:29 +01002385#ifdef FEAT_FOLDING
2386 int fdc = compute_foldcolumn(wp, 0);
2387#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388
2389#ifdef FEAT_RIGHTLEFT
2390 if (wp->w_p_rl)
2391 {
2392 /* No check for cmdline window: should never be right-left. */
2393# ifdef FEAT_FOLDING
Bram Moolenaar1c934292015-01-27 16:39:29 +01002394 n = fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395
2396 if (n > 0)
2397 {
2398 /* draw the fold column at the right */
Bram Moolenaar02631462017-09-22 15:20:32 +02002399 if (n > wp->w_width)
2400 n = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2402 W_ENDCOL(wp) - n, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002403 ' ', ' ', HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 }
2405# endif
2406# ifdef FEAT_SIGNS
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02002407 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 {
2409 int nn = n + 2;
2410
2411 /* draw the sign column left of the fold column */
Bram Moolenaar02631462017-09-22 15:20:32 +02002412 if (nn > wp->w_width)
2413 nn = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2415 W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - n,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002416 ' ', ' ', HL_ATTR(HLF_SC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417 n = nn;
2418 }
2419# endif
2420 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002421 wp->w_wincol, W_ENDCOL(wp) - 1 - FDC_OFF,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002422 c2, c2, HL_ATTR(hl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002423 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2424 W_ENDCOL(wp) - 1 - FDC_OFF, W_ENDCOL(wp) - FDC_OFF,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002425 c1, c2, HL_ATTR(hl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 }
2427 else
2428#endif
2429 {
2430#ifdef FEAT_CMDWIN
2431 if (cmdwin_type != 0 && wp == curwin)
2432 {
2433 /* draw the cmdline character in the leftmost column */
2434 n = 1;
2435 if (n > wp->w_width)
2436 n = wp->w_width;
2437 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002438 wp->w_wincol, (int)wp->w_wincol + n,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002439 cmdwin_type, ' ', HL_ATTR(HLF_AT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 }
2441#endif
2442#ifdef FEAT_FOLDING
Bram Moolenaar1c934292015-01-27 16:39:29 +01002443 if (fdc > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 {
Bram Moolenaar1c934292015-01-27 16:39:29 +01002445 int nn = n + fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446
2447 /* draw the fold column at the left */
Bram Moolenaar02631462017-09-22 15:20:32 +02002448 if (nn > wp->w_width)
2449 nn = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002451 wp->w_wincol + n, (int)wp->w_wincol + nn,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002452 ' ', ' ', HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453 n = nn;
2454 }
2455#endif
2456#ifdef FEAT_SIGNS
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02002457 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002458 {
2459 int nn = n + 2;
2460
2461 /* draw the sign column after the fold column */
Bram Moolenaar02631462017-09-22 15:20:32 +02002462 if (nn > wp->w_width)
2463 nn = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002465 wp->w_wincol + n, (int)wp->w_wincol + nn,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002466 ' ', ' ', HL_ATTR(HLF_SC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 n = nn;
2468 }
2469#endif
2470 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02002471 wp->w_wincol + FDC_OFF, (int)W_ENDCOL(wp),
Bram Moolenaar8820b482017-03-16 17:23:31 +01002472 c1, c2, HL_ATTR(hl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 }
2474 set_empty_rows(wp, row);
2475}
2476
Bram Moolenaar1a384422010-07-14 19:53:30 +02002477#ifdef FEAT_SYN_HL
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01002478static int advance_color_col(int vcol, int **color_cols);
Bram Moolenaar1a384422010-07-14 19:53:30 +02002479
2480/*
2481 * Advance **color_cols and return TRUE when there are columns to draw.
2482 */
2483 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002484advance_color_col(int vcol, int **color_cols)
Bram Moolenaar1a384422010-07-14 19:53:30 +02002485{
2486 while (**color_cols >= 0 && vcol > **color_cols)
2487 ++*color_cols;
2488 return (**color_cols >= 0);
2489}
2490#endif
2491
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002492#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
2493/*
2494 * Copy "text" to ScreenLines using "attr".
2495 * Returns the next screen column.
2496 */
2497 static int
2498text_to_screenline(win_T *wp, char_u *text, int col)
2499{
2500 int off = (int)(current_ScreenLine - ScreenLines);
2501
2502#ifdef FEAT_MBYTE
2503 if (has_mbyte)
2504 {
2505 int cells;
2506 int u8c, u8cc[MAX_MCO];
2507 int i;
2508 int idx;
2509 int c_len;
2510 char_u *p;
2511# ifdef FEAT_ARABIC
2512 int prev_c = 0; /* previous Arabic character */
2513 int prev_c1 = 0; /* first composing char for prev_c */
2514# endif
2515
2516# ifdef FEAT_RIGHTLEFT
2517 if (wp->w_p_rl)
2518 idx = off;
2519 else
2520# endif
2521 idx = off + col;
2522
2523 /* Store multibyte characters in ScreenLines[] et al. correctly. */
2524 for (p = text; *p != NUL; )
2525 {
2526 cells = (*mb_ptr2cells)(p);
2527 c_len = (*mb_ptr2len)(p);
Bram Moolenaar02631462017-09-22 15:20:32 +02002528 if (col + cells > wp->w_width
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002529# ifdef FEAT_RIGHTLEFT
2530 - (wp->w_p_rl ? col : 0)
2531# endif
2532 )
2533 break;
2534 ScreenLines[idx] = *p;
2535 if (enc_utf8)
2536 {
2537 u8c = utfc_ptr2char(p, u8cc);
2538 if (*p < 0x80 && u8cc[0] == 0)
2539 {
2540 ScreenLinesUC[idx] = 0;
2541#ifdef FEAT_ARABIC
2542 prev_c = u8c;
2543#endif
2544 }
2545 else
2546 {
2547#ifdef FEAT_ARABIC
2548 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
2549 {
2550 /* Do Arabic shaping. */
2551 int pc, pc1, nc;
2552 int pcc[MAX_MCO];
2553 int firstbyte = *p;
2554
2555 /* The idea of what is the previous and next
2556 * character depends on 'rightleft'. */
2557 if (wp->w_p_rl)
2558 {
2559 pc = prev_c;
2560 pc1 = prev_c1;
2561 nc = utf_ptr2char(p + c_len);
2562 prev_c1 = u8cc[0];
2563 }
2564 else
2565 {
2566 pc = utfc_ptr2char(p + c_len, pcc);
2567 nc = prev_c;
2568 pc1 = pcc[0];
2569 }
2570 prev_c = u8c;
2571
2572 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
2573 pc, pc1, nc);
2574 ScreenLines[idx] = firstbyte;
2575 }
2576 else
2577 prev_c = u8c;
2578#endif
2579 /* Non-BMP character: display as ? or fullwidth ?. */
2580#ifdef UNICODE16
2581 if (u8c >= 0x10000)
2582 ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?';
2583 else
2584#endif
2585 ScreenLinesUC[idx] = u8c;
2586 for (i = 0; i < Screen_mco; ++i)
2587 {
2588 ScreenLinesC[i][idx] = u8cc[i];
2589 if (u8cc[i] == 0)
2590 break;
2591 }
2592 }
2593 if (cells > 1)
2594 ScreenLines[idx + 1] = 0;
2595 }
2596 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
2597 /* double-byte single width character */
2598 ScreenLines2[idx] = p[1];
2599 else if (cells > 1)
2600 /* double-width character */
2601 ScreenLines[idx + 1] = p[1];
2602 col += cells;
2603 idx += cells;
2604 p += c_len;
2605 }
2606 }
2607 else
2608#endif
2609 {
2610 int len = (int)STRLEN(text);
2611
Bram Moolenaar02631462017-09-22 15:20:32 +02002612 if (len > wp->w_width - col)
2613 len = wp->w_width - col;
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002614 if (len > 0)
2615 {
2616#ifdef FEAT_RIGHTLEFT
2617 if (wp->w_p_rl)
2618 STRNCPY(current_ScreenLine, text, len);
2619 else
2620#endif
2621 STRNCPY(current_ScreenLine + col, text, len);
2622 col += len;
2623 }
2624 }
2625 return col;
2626}
2627#endif
2628
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629#ifdef FEAT_FOLDING
2630/*
Bram Moolenaar1c934292015-01-27 16:39:29 +01002631 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
2632 * space is available for window "wp", minus "col".
2633 */
2634 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002635compute_foldcolumn(win_T *wp, int col)
Bram Moolenaar1c934292015-01-27 16:39:29 +01002636{
2637 int fdc = wp->w_p_fdc;
2638 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
Bram Moolenaar02631462017-09-22 15:20:32 +02002639 int wwidth = wp->w_width;
Bram Moolenaar1c934292015-01-27 16:39:29 +01002640
2641 if (fdc > wwidth - (col + wmw))
2642 fdc = wwidth - (col + wmw);
2643 return fdc;
2644}
2645
2646/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 * Display one folded line.
2648 */
2649 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002650fold_line(
2651 win_T *wp,
2652 long fold_count,
2653 foldinfo_T *foldinfo,
2654 linenr_T lnum,
2655 int row)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656{
Bram Moolenaaree695f72016-08-03 22:08:45 +02002657 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 pos_T *top, *bot;
2659 linenr_T lnume = lnum + fold_count - 1;
2660 int len;
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002661 char_u *text;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662 int fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 int col;
2664 int txtcol;
2665 int off = (int)(current_ScreenLine - ScreenLines);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002666 int ri;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667
2668 /* Build the fold line:
2669 * 1. Add the cmdwin_type for the command-line window
2670 * 2. Add the 'foldcolumn'
Bram Moolenaar64486672010-05-16 15:46:46 +02002671 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672 * 4. Compose the text
2673 * 5. Add the text
2674 * 6. set highlighting for the Visual area an other text
2675 */
2676 col = 0;
2677
2678 /*
2679 * 1. Add the cmdwin_type for the command-line window
2680 * Ignores 'rightleft', this window is never right-left.
2681 */
2682#ifdef FEAT_CMDWIN
2683 if (cmdwin_type != 0 && wp == curwin)
2684 {
2685 ScreenLines[off] = cmdwin_type;
Bram Moolenaar8820b482017-03-16 17:23:31 +01002686 ScreenAttrs[off] = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687#ifdef FEAT_MBYTE
2688 if (enc_utf8)
2689 ScreenLinesUC[off] = 0;
2690#endif
2691 ++col;
2692 }
2693#endif
2694
2695 /*
2696 * 2. Add the 'foldcolumn'
Bram Moolenaar1c934292015-01-27 16:39:29 +01002697 * Reduce the width when there is not enough space.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 */
Bram Moolenaar1c934292015-01-27 16:39:29 +01002699 fdc = compute_foldcolumn(wp, col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 if (fdc > 0)
2701 {
2702 fill_foldcolumn(buf, wp, TRUE, lnum);
2703#ifdef FEAT_RIGHTLEFT
2704 if (wp->w_p_rl)
2705 {
2706 int i;
2707
Bram Moolenaar02631462017-09-22 15:20:32 +02002708 copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002709 HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710 /* reverse the fold column */
2711 for (i = 0; i < fdc; ++i)
Bram Moolenaar02631462017-09-22 15:20:32 +02002712 ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713 }
2714 else
2715#endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002716 copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 col += fdc;
2718 }
2719
2720#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6f470022018-04-10 18:47:20 +02002721# define RL_MEMSET(p, v, l) \
2722 do { \
2723 if (wp->w_p_rl) \
2724 for (ri = 0; ri < l; ++ri) \
2725 ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \
2726 else \
2727 for (ri = 0; ri < l; ++ri) \
2728 ScreenAttrs[off + (p) + ri] = v; \
2729 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730#else
Bram Moolenaar6f470022018-04-10 18:47:20 +02002731# define RL_MEMSET(p, v, l) \
2732 do { \
2733 for (ri = 0; ri < l; ++ri) \
2734 ScreenAttrs[off + (p) + ri] = v; \
2735 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002736#endif
2737
Bram Moolenaar64486672010-05-16 15:46:46 +02002738 /* Set all attributes of the 'number' or 'relativenumber' column and the
2739 * text */
Bram Moolenaar02631462017-09-22 15:20:32 +02002740 RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741
2742#ifdef FEAT_SIGNS
2743 /* If signs are being displayed, add two spaces. */
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02002744 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 {
Bram Moolenaar02631462017-09-22 15:20:32 +02002746 len = wp->w_width - col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747 if (len > 0)
2748 {
2749 if (len > 2)
2750 len = 2;
2751# ifdef FEAT_RIGHTLEFT
2752 if (wp->w_p_rl)
2753 /* the line number isn't reversed */
Bram Moolenaar02631462017-09-22 15:20:32 +02002754 copy_text_attr(off + wp->w_width - len - col,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002755 (char_u *)" ", len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 else
2757# endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002758 copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759 col += len;
2760 }
2761 }
2762#endif
2763
2764 /*
Bram Moolenaar64486672010-05-16 15:46:46 +02002765 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 */
Bram Moolenaar64486672010-05-16 15:46:46 +02002767 if (wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768 {
Bram Moolenaar02631462017-09-22 15:20:32 +02002769 len = wp->w_width - col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770 if (len > 0)
2771 {
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002772 int w = number_width(wp);
Bram Moolenaar24dc2302014-05-13 20:19:58 +02002773 long num;
2774 char *fmt = "%*ld ";
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002775
2776 if (len > w + 1)
2777 len = w + 1;
Bram Moolenaar64486672010-05-16 15:46:46 +02002778
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002779 if (wp->w_p_nu && !wp->w_p_rnu)
2780 /* 'number' + 'norelativenumber' */
Bram Moolenaar64486672010-05-16 15:46:46 +02002781 num = (long)lnum;
2782 else
Bram Moolenaar700e7342013-01-30 12:31:36 +01002783 {
Bram Moolenaar64486672010-05-16 15:46:46 +02002784 /* 'relativenumber', don't use negative numbers */
Bram Moolenaar7eb46522010-12-30 14:57:08 +01002785 num = labs((long)get_cursor_rel_lnum(wp, lnum));
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002786 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01002787 {
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02002788 /* 'number' + 'relativenumber': cursor line shows absolute
2789 * line number */
Bram Moolenaar700e7342013-01-30 12:31:36 +01002790 num = lnum;
2791 fmt = "%-*ld ";
2792 }
2793 }
Bram Moolenaar64486672010-05-16 15:46:46 +02002794
Bram Moolenaar700e7342013-01-30 12:31:36 +01002795 sprintf((char *)buf, fmt, w, num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796#ifdef FEAT_RIGHTLEFT
2797 if (wp->w_p_rl)
2798 /* the line number isn't reversed */
Bram Moolenaar02631462017-09-22 15:20:32 +02002799 copy_text_attr(off + wp->w_width - len - col, buf, len,
Bram Moolenaar8820b482017-03-16 17:23:31 +01002800 HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801 else
2802#endif
Bram Moolenaar8820b482017-03-16 17:23:31 +01002803 copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804 col += len;
2805 }
2806 }
2807
2808 /*
2809 * 4. Compose the folded-line string with 'foldtext', if set.
2810 */
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002811 text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812
2813 txtcol = col; /* remember where text starts */
2814
2815 /*
2816 * 5. move the text to current_ScreenLine. Fill up with "fill_fold".
2817 * Right-left text is put in columns 0 - number-col, normal text is put
2818 * in columns number-col - window-width.
2819 */
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02002820 col = text_to_screenline(wp, text, col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821
2822 /* Fill the rest of the line with the fold filler */
2823#ifdef FEAT_RIGHTLEFT
2824 if (wp->w_p_rl)
2825 col -= txtcol;
2826#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02002827 while (col < wp->w_width
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828#ifdef FEAT_RIGHTLEFT
2829 - (wp->w_p_rl ? txtcol : 0)
2830#endif
2831 )
2832 {
2833#ifdef FEAT_MBYTE
2834 if (enc_utf8)
2835 {
2836 if (fill_fold >= 0x80)
2837 {
2838 ScreenLinesUC[off + col] = fill_fold;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002839 ScreenLinesC[0][off + col] = 0;
Bram Moolenaaracda04f2018-02-08 09:57:28 +01002840 ScreenLines[off + col] = 0x80; /* avoid storing zero */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 }
2842 else
Bram Moolenaar8da1e6c2017-03-29 20:38:59 +02002843 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 ScreenLinesUC[off + col] = 0;
Bram Moolenaar8da1e6c2017-03-29 20:38:59 +02002845 ScreenLines[off + col] = fill_fold;
2846 }
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002847 col++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848 }
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002849 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850#endif
Bram Moolenaarc6cd8402017-03-29 14:40:47 +02002851 ScreenLines[off + col++] = fill_fold;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852 }
2853
2854 if (text != buf)
2855 vim_free(text);
2856
2857 /*
2858 * 6. set highlighting for the Visual area an other text.
2859 * If all folded lines are in the Visual area, highlight the line.
2860 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
2862 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01002863 if (LTOREQ_POS(curwin->w_cursor, VIsual))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864 {
2865 /* Visual is after curwin->w_cursor */
2866 top = &curwin->w_cursor;
2867 bot = &VIsual;
2868 }
2869 else
2870 {
2871 /* Visual is before curwin->w_cursor */
2872 top = &VIsual;
2873 bot = &curwin->w_cursor;
2874 }
2875 if (lnum >= top->lnum
2876 && lnume <= bot->lnum
2877 && (VIsual_mode != 'v'
2878 || ((lnum > top->lnum
2879 || (lnum == top->lnum
2880 && top->col == 0))
2881 && (lnume < bot->lnum
2882 || (lnume == bot->lnum
2883 && (bot->col - (*p_sel == 'e'))
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002884 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002885 {
2886 if (VIsual_mode == Ctrl_V)
2887 {
2888 /* Visual block mode: highlight the chars part of the block */
Bram Moolenaar02631462017-09-22 15:20:32 +02002889 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890 {
Bram Moolenaar6c167c62011-09-02 14:07:36 +02002891 if (wp->w_old_cursor_lcol != MAXCOL
2892 && wp->w_old_cursor_lcol + txtcol
Bram Moolenaar02631462017-09-22 15:20:32 +02002893 < (colnr_T)wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894 len = wp->w_old_cursor_lcol;
2895 else
Bram Moolenaar02631462017-09-22 15:20:32 +02002896 len = wp->w_width - txtcol;
Bram Moolenaar8820b482017-03-16 17:23:31 +01002897 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V),
Bram Moolenaar68b76a62005-03-25 21:53:48 +00002898 len - (int)wp->w_old_cursor_fcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899 }
2900 }
2901 else
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002902 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903 /* Set all attributes of the text */
Bram Moolenaar02631462017-09-22 15:20:32 +02002904 RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002905 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906 }
2907 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002909#ifdef FEAT_SYN_HL
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002910 /* Show colorcolumn in the fold line, but let cursorcolumn override it. */
2911 if (wp->w_p_cc_cols)
2912 {
2913 int i = 0;
2914 int j = wp->w_p_cc_cols[i];
2915 int old_txtcol = txtcol;
2916
2917 while (j > -1)
2918 {
2919 txtcol += j;
2920 if (wp->w_p_wrap)
2921 txtcol -= wp->w_skipcol;
2922 else
2923 txtcol -= wp->w_leftcol;
Bram Moolenaar02631462017-09-22 15:20:32 +02002924 if (txtcol >= 0 && txtcol < wp->w_width)
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002925 ScreenAttrs[off + txtcol] = hl_combine_attr(
Bram Moolenaar8820b482017-03-16 17:23:31 +01002926 ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC));
Bram Moolenaarfbc25b22015-03-20 17:16:27 +01002927 txtcol = old_txtcol;
2928 j = wp->w_p_cc_cols[++i];
2929 }
2930 }
2931
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002932 /* Show 'cursorcolumn' in the fold line. */
Bram Moolenaar85595c52008-10-02 16:04:05 +00002933 if (wp->w_p_cuc)
2934 {
2935 txtcol += wp->w_virtcol;
2936 if (wp->w_p_wrap)
2937 txtcol -= wp->w_skipcol;
2938 else
2939 txtcol -= wp->w_leftcol;
Bram Moolenaar02631462017-09-22 15:20:32 +02002940 if (txtcol >= 0 && txtcol < wp->w_width)
Bram Moolenaar85595c52008-10-02 16:04:05 +00002941 ScreenAttrs[off + txtcol] = hl_combine_attr(
Bram Moolenaar8820b482017-03-16 17:23:31 +01002942 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC));
Bram Moolenaar85595c52008-10-02 16:04:05 +00002943 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002944#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945
Bram Moolenaar02631462017-09-22 15:20:32 +02002946 screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
2947 (int)wp->w_width, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948
2949 /*
2950 * Update w_cline_height and w_cline_folded if the cursor line was
2951 * updated (saves a call to plines() later).
2952 */
2953 if (wp == curwin
2954 && lnum <= curwin->w_cursor.lnum
2955 && lnume >= curwin->w_cursor.lnum)
2956 {
2957 curwin->w_cline_row = row;
2958 curwin->w_cline_height = 1;
2959 curwin->w_cline_folded = TRUE;
2960 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
2961 }
2962}
2963
2964/*
2965 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
2966 */
2967 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002968copy_text_attr(
2969 int off,
2970 char_u *buf,
2971 int len,
2972 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973{
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002974 int i;
2975
Bram Moolenaar071d4272004-06-13 20:20:40 +00002976 mch_memmove(ScreenLines + off, buf, (size_t)len);
2977# ifdef FEAT_MBYTE
2978 if (enc_utf8)
2979 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
2980# endif
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002981 for (i = 0; i < len; ++i)
2982 ScreenAttrs[off + i] = attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983}
2984
2985/*
2986 * Fill the foldcolumn at "p" for window "wp".
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +00002987 * Only to be called when 'foldcolumn' > 0.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002988 */
2989 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002990fill_foldcolumn(
2991 char_u *p,
2992 win_T *wp,
2993 int closed, /* TRUE of FALSE */
2994 linenr_T lnum) /* current line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995{
2996 int i = 0;
2997 int level;
2998 int first_level;
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002999 int empty;
Bram Moolenaar1c934292015-01-27 16:39:29 +01003000 int fdc = compute_foldcolumn(wp, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003001
3002 /* Init to all spaces. */
Bram Moolenaar2536d4f2015-07-17 13:22:51 +02003003 vim_memset(p, ' ', (size_t)fdc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004
3005 level = win_foldinfo.fi_level;
3006 if (level > 0)
3007 {
Bram Moolenaar578b49e2005-09-10 19:22:57 +00003008 /* If there is only one column put more info in it. */
Bram Moolenaar1c934292015-01-27 16:39:29 +01003009 empty = (fdc == 1) ? 0 : 1;
Bram Moolenaar578b49e2005-09-10 19:22:57 +00003010
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011 /* If the column is too narrow, we start at the lowest level that
3012 * fits and use numbers to indicated the depth. */
Bram Moolenaar1c934292015-01-27 16:39:29 +01003013 first_level = level - fdc - closed + 1 + empty;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014 if (first_level < 1)
3015 first_level = 1;
3016
Bram Moolenaar1c934292015-01-27 16:39:29 +01003017 for (i = 0; i + empty < fdc; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 {
3019 if (win_foldinfo.fi_lnum == lnum
3020 && first_level + i >= win_foldinfo.fi_low_level)
3021 p[i] = '-';
3022 else if (first_level == 1)
3023 p[i] = '|';
3024 else if (first_level + i <= 9)
3025 p[i] = '0' + first_level + i;
3026 else
3027 p[i] = '>';
3028 if (first_level + i == level)
3029 break;
3030 }
3031 }
3032 if (closed)
Bram Moolenaar1c934292015-01-27 16:39:29 +01003033 p[i >= fdc ? i - 1 : i] = '+';
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034}
3035#endif /* FEAT_FOLDING */
3036
3037/*
3038 * Display line "lnum" of window 'wp' on the screen.
3039 * Start at row "startrow", stop when "endrow" is reached.
3040 * wp->w_virtcol needs to be valid.
3041 *
3042 * Return the number of last row the line occupies.
3043 */
3044 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003045win_line(
3046 win_T *wp,
3047 linenr_T lnum,
3048 int startrow,
3049 int endrow,
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02003050 int nochange UNUSED) /* not updating for changed text */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051{
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003052 int col = 0; /* visual column on screen */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053 unsigned off; /* offset in ScreenLines/ScreenAttrs */
3054 int c = 0; /* init for GCC */
3055 long vcol = 0; /* virtual column (for tabs) */
Bram Moolenaard574ea22015-01-14 19:35:14 +01003056#ifdef FEAT_LINEBREAK
3057 long vcol_sbr = -1; /* virtual column after showbreak */
3058#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 long vcol_prev = -1; /* "vcol" of previous character */
3060 char_u *line; /* current line */
3061 char_u *ptr; /* current position in "line" */
3062 int row; /* row in the window, excl w_winrow */
3063 int screen_row; /* row on the screen, incl w_winrow */
3064
3065 char_u extra[18]; /* "%ld" and 'fdc' must fit in here */
3066 int n_extra = 0; /* number of extra chars */
Bram Moolenaara064ac82007-08-05 18:10:54 +00003067 char_u *p_extra = NULL; /* string of extra chars, plus NUL */
Bram Moolenaar86b17e92014-07-02 20:00:47 +02003068 char_u *p_extra_free = NULL; /* p_extra needs to be freed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 int c_extra = NUL; /* extra chars, all the same */
3070 int extra_attr = 0; /* attributes when n_extra != 0 */
3071 static char_u *at_end_str = (char_u *)""; /* used for p_extra when
3072 displaying lcs_eol at end-of-line */
3073 int lcs_eol_one = lcs_eol; /* lcs_eol until it's been used */
3074 int lcs_prec_todo = lcs_prec; /* lcs_prec until it's been used */
3075
3076 /* saved "extra" items for when draw_state becomes WL_LINE (again) */
3077 int saved_n_extra = 0;
3078 char_u *saved_p_extra = NULL;
3079 int saved_c_extra = 0;
3080 int saved_char_attr = 0;
3081
3082 int n_attr = 0; /* chars with special attr */
3083 int saved_attr2 = 0; /* char_attr saved for n_attr */
3084 int n_attr3 = 0; /* chars with overruling special attr */
3085 int saved_attr3 = 0; /* char_attr saved for n_attr3 */
3086
3087 int n_skip = 0; /* nr of chars to skip for 'nowrap' */
3088
3089 int fromcol, tocol; /* start/end of inverting */
3090 int fromcol_prev = -2; /* start of inverting after cursor */
3091 int noinvcur = FALSE; /* don't invert the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 pos_T *top, *bot;
Bram Moolenaar54ef7112009-02-21 20:11:41 +00003093 int lnum_in_visual_area = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094 pos_T pos;
3095 long v;
3096
3097 int char_attr = 0; /* attributes for next character */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003098 int attr_pri = FALSE; /* char_attr has priority */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 int area_highlighting = FALSE; /* Visual or incsearch highlighting
3100 in this line */
3101 int attr = 0; /* attributes for area highlighting */
3102 int area_attr = 0; /* attributes desired by highlighting */
3103 int search_attr = 0; /* attributes desired by 'hlsearch' */
3104#ifdef FEAT_SYN_HL
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003105 int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106 int syntax_attr = 0; /* attributes desired by syntax */
3107 int has_syntax = FALSE; /* this buffer has syntax highl. */
3108 int save_did_emsg;
Bram Moolenaara443af82007-11-08 13:51:42 +00003109 int eol_hl_off = 0; /* 1 if highlighted char after EOL */
Bram Moolenaar1a384422010-07-14 19:53:30 +02003110 int draw_color_col = FALSE; /* highlight colorcolumn */
3111 int *color_cols = NULL; /* pointer to according columns array */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003112#endif
3113#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00003114 int has_spell = FALSE; /* this buffer has spell checking */
Bram Moolenaar30abd282005-06-22 22:35:10 +00003115# define SPWORDLEN 150
3116 char_u nextline[SPWORDLEN * 2];/* text with start of the next line */
Bram Moolenaar3b506942005-06-23 22:36:45 +00003117 int nextlinecol = 0; /* column where nextline[] starts */
3118 int nextline_idx = 0; /* index in nextline[] where next line
Bram Moolenaar30abd282005-06-22 22:35:10 +00003119 starts */
Bram Moolenaar217ad922005-03-20 22:37:15 +00003120 int spell_attr = 0; /* attributes desired by spelling */
3121 int word_end = 0; /* last byte with same spell_attr */
Bram Moolenaard042c562005-06-30 22:04:15 +00003122 static linenr_T checked_lnum = 0; /* line number for "checked_col" */
3123 static int checked_col = 0; /* column in "checked_lnum" up to which
Bram Moolenaar30abd282005-06-22 22:35:10 +00003124 * there are no spell errors */
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003125 static int cap_col = -1; /* column to check for Cap word */
3126 static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */
Bram Moolenaar30abd282005-06-22 22:35:10 +00003127 int cur_checked_col = 0; /* checked column for current line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128#endif
3129 int extra_check; /* has syntax or linebreak */
3130#ifdef FEAT_MBYTE
3131 int multi_attr = 0; /* attributes desired by multibyte */
3132 int mb_l = 1; /* multi-byte byte length */
3133 int mb_c = 0; /* decoded multi-byte character */
3134 int mb_utf8 = FALSE; /* screen char is UTF-8 char */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003135 int u8cc[MAX_MCO]; /* composing UTF-8 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136#endif
3137#ifdef FEAT_DIFF
3138 int filler_lines; /* nr of filler lines to be drawn */
3139 int filler_todo; /* nr of filler lines still to do + 1 */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003140 hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 int change_start = MAXCOL; /* first col of changed area */
3142 int change_end = -1; /* last col of changed area */
3143#endif
3144 colnr_T trailcol = MAXCOL; /* start of trailing spaces */
3145#ifdef FEAT_LINEBREAK
Bram Moolenaar6c896862016-11-17 19:46:51 +01003146 int need_showbreak = FALSE; /* overlong line, skipping first x
3147 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02003149#if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00003150 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151# define LINE_ATTR
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003152 int line_attr = 0; /* attribute for the whole line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153#endif
3154#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003155 matchitem_T *cur; /* points to the match list */
3156 match_T *shl; /* points to search_hl or a match */
3157 int shl_flag; /* flag to indicate whether search_hl
3158 has been processed or not */
Bram Moolenaarb3414592014-06-17 17:48:32 +02003159 int pos_inprogress; /* marks that position match search is
3160 in progress */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003161 int prevcol_hl_flag; /* flag to indicate whether prevcol
3162 equals startcol of search_hl or one
3163 of the matches */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164#endif
3165#ifdef FEAT_ARABIC
3166 int prev_c = 0; /* previous Arabic character */
3167 int prev_c1 = 0; /* first composing char for prev_c */
3168#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00003169#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00003170 int did_line_attr = 0;
3171#endif
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003172#ifdef FEAT_TERMINAL
3173 int get_term_attr = FALSE;
Bram Moolenaar238d43b2017-09-11 22:00:51 +02003174 int term_attr = 0; /* background for terminal window */
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003175#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176
3177 /* draw_state: items that are drawn in sequence: */
3178#define WL_START 0 /* nothing done yet */
3179#ifdef FEAT_CMDWIN
3180# define WL_CMDLINE WL_START + 1 /* cmdline window column */
3181#else
3182# define WL_CMDLINE WL_START
3183#endif
3184#ifdef FEAT_FOLDING
3185# define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
3186#else
3187# define WL_FOLD WL_CMDLINE
3188#endif
3189#ifdef FEAT_SIGNS
3190# define WL_SIGN WL_FOLD + 1 /* column for signs */
3191#else
3192# define WL_SIGN WL_FOLD /* column for signs */
3193#endif
3194#define WL_NR WL_SIGN + 1 /* line number */
Bram Moolenaar597a4222014-06-25 14:39:50 +02003195#ifdef FEAT_LINEBREAK
3196# define WL_BRI WL_NR + 1 /* 'breakindent' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197#else
Bram Moolenaar597a4222014-06-25 14:39:50 +02003198# define WL_BRI WL_NR
3199#endif
3200#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3201# define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */
3202#else
3203# define WL_SBR WL_BRI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204#endif
3205#define WL_LINE WL_SBR + 1 /* text in the line */
3206 int draw_state = WL_START; /* what to draw next */
Bram Moolenaar9372a112005-12-06 19:59:18 +00003207#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 int feedback_col = 0;
3209 int feedback_old_attr = -1;
3210#endif
3211
Bram Moolenaar860cae12010-06-05 23:22:07 +02003212#ifdef FEAT_CONCEAL
3213 int syntax_flags = 0;
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02003214 int syntax_seqnr = 0;
Bram Moolenaar27c735b2010-07-22 22:16:29 +02003215 int prev_syntax_id = 0;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003216 int conceal_attr = HL_ATTR(HLF_CONCEAL);
Bram Moolenaar860cae12010-06-05 23:22:07 +02003217 int is_concealing = FALSE;
3218 int boguscols = 0; /* nonexistent columns added to force
3219 wrapping */
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02003220 int vcol_off = 0; /* offset for concealed characters */
Bram Moolenaarf5963f72010-07-23 22:10:27 +02003221 int did_wcol = FALSE;
Bram Moolenaar4d585022016-04-14 19:50:22 +02003222 int match_conc = 0; /* cchar for match functions */
3223 int has_match_conc = 0; /* match wants to conceal */
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01003224 int old_boguscols = 0;
Bram Moolenaarac550fd2010-07-18 13:55:02 +02003225# define VCOL_HLC (vcol - vcol_off)
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02003226# define FIX_FOR_BOGUSCOLS \
3227 { \
3228 n_extra += vcol_off; \
3229 vcol -= vcol_off; \
3230 vcol_off = 0; \
3231 col -= boguscols; \
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01003232 old_boguscols = boguscols; \
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02003233 boguscols = 0; \
3234 }
Bram Moolenaarac550fd2010-07-18 13:55:02 +02003235#else
3236# define VCOL_HLC (vcol)
Bram Moolenaar860cae12010-06-05 23:22:07 +02003237#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238
3239 if (startrow > endrow) /* past the end already! */
3240 return startrow;
3241
3242 row = startrow;
3243 screen_row = row + W_WINROW(wp);
3244
3245 /*
3246 * To speed up the loop below, set extra_check when there is linebreak,
3247 * trailing white space and/or syntax processing to be done.
3248 */
3249#ifdef FEAT_LINEBREAK
3250 extra_check = wp->w_p_lbr;
3251#else
3252 extra_check = 0;
3253#endif
3254#ifdef FEAT_SYN_HL
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003255 if (syntax_present(wp) && !wp->w_s->b_syn_error
3256# ifdef SYN_TIME_LIMIT
3257 && !wp->w_s->b_syn_slow
3258# endif
3259 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260 {
3261 /* Prepare for syntax highlighting in this line. When there is an
3262 * error, stop syntax highlighting. */
3263 save_did_emsg = did_emsg;
3264 did_emsg = FALSE;
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02003265 syntax_start(wp, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266 if (did_emsg)
Bram Moolenaar860cae12010-06-05 23:22:07 +02003267 wp->w_s->b_syn_error = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 else
3269 {
3270 did_emsg = save_did_emsg;
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02003271#ifdef SYN_TIME_LIMIT
3272 if (!wp->w_s->b_syn_slow)
3273#endif
3274 {
3275 has_syntax = TRUE;
3276 extra_check = TRUE;
3277 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 }
3279 }
Bram Moolenaar1a384422010-07-14 19:53:30 +02003280
3281 /* Check for columns to display for 'colorcolumn'. */
3282 color_cols = wp->w_p_cc_cols;
3283 if (color_cols != NULL)
Bram Moolenaarac550fd2010-07-18 13:55:02 +02003284 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003285#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00003286
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003287#ifdef FEAT_TERMINAL
Bram Moolenaar423802d2017-07-30 16:52:24 +02003288 if (term_show_buffer(wp->w_buffer))
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003289 {
3290 extra_check = TRUE;
3291 get_term_attr = TRUE;
Bram Moolenaar49a613f2017-09-11 23:05:44 +02003292 term_attr = term_get_attr(wp->w_buffer, lnum, -1);
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02003293 }
3294#endif
3295
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003296#ifdef FEAT_SPELL
Bram Moolenaar0cb032e2005-04-23 20:52:00 +00003297 if (wp->w_p_spell
Bram Moolenaar860cae12010-06-05 23:22:07 +02003298 && *wp->w_s->b_p_spl != NUL
3299 && wp->w_s->b_langp.ga_len > 0
3300 && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
Bram Moolenaar217ad922005-03-20 22:37:15 +00003301 {
3302 /* Prepare for spell checking. */
3303 has_spell = TRUE;
3304 extra_check = TRUE;
Bram Moolenaar30abd282005-06-22 22:35:10 +00003305
3306 /* Get the start of the next line, so that words that wrap to the next
3307 * line are found too: "et<line-break>al.".
3308 * Trick: skip a few chars for C/shell/Vim comments */
3309 nextline[SPWORDLEN] = NUL;
3310 if (lnum < wp->w_buffer->b_ml.ml_line_count)
3311 {
3312 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
3313 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
3314 }
3315
3316 /* When a word wrapped from the previous line the start of the current
3317 * line is valid. */
3318 if (lnum == checked_lnum)
3319 cur_checked_col = checked_col;
3320 checked_lnum = 0;
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003321
3322 /* When there was a sentence end in the previous line may require a
3323 * word starting with capital in this line. In line 1 always check
3324 * the first word. */
3325 if (lnum != capcol_lnum)
3326 cap_col = -1;
3327 if (lnum == 1)
3328 cap_col = 0;
3329 capcol_lnum = 0;
Bram Moolenaar217ad922005-03-20 22:37:15 +00003330 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331#endif
3332
3333 /*
3334 * handle visual active in this window
3335 */
3336 fromcol = -10;
3337 tocol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
3339 {
3340 /* Visual is after curwin->w_cursor */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01003341 if (LTOREQ_POS(curwin->w_cursor, VIsual))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 {
3343 top = &curwin->w_cursor;
3344 bot = &VIsual;
3345 }
3346 else /* Visual is before curwin->w_cursor */
3347 {
3348 top = &VIsual;
3349 bot = &curwin->w_cursor;
3350 }
Bram Moolenaar54ef7112009-02-21 20:11:41 +00003351 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 if (VIsual_mode == Ctrl_V) /* block mode */
3353 {
Bram Moolenaar54ef7112009-02-21 20:11:41 +00003354 if (lnum_in_visual_area)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 {
3356 fromcol = wp->w_old_cursor_fcol;
3357 tocol = wp->w_old_cursor_lcol;
3358 }
3359 }
3360 else /* non-block mode */
3361 {
3362 if (lnum > top->lnum && lnum <= bot->lnum)
3363 fromcol = 0;
3364 else if (lnum == top->lnum)
3365 {
3366 if (VIsual_mode == 'V') /* linewise */
3367 fromcol = 0;
3368 else
3369 {
3370 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
3371 if (gchar_pos(top) == NUL)
3372 tocol = fromcol + 1;
3373 }
3374 }
3375 if (VIsual_mode != 'V' && lnum == bot->lnum)
3376 {
3377 if (*p_sel == 'e' && bot->col == 0
3378#ifdef FEAT_VIRTUALEDIT
3379 && bot->coladd == 0
3380#endif
3381 )
3382 {
3383 fromcol = -10;
3384 tocol = MAXCOL;
3385 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003386 else if (bot->col == MAXCOL)
3387 tocol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388 else
3389 {
3390 pos = *bot;
3391 if (*p_sel == 'e')
3392 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
3393 else
3394 {
3395 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
3396 ++tocol;
3397 }
3398 }
3399 }
3400 }
3401
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 /* Check if the character under the cursor should not be inverted */
3403 if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003404#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405 && !gui.in_use
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003406#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407 )
3408 noinvcur = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409
3410 /* if inverting in this line set area_highlighting */
3411 if (fromcol >= 0)
3412 {
3413 area_highlighting = TRUE;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003414 attr = HL_ATTR(HLF_V);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003415#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02003416 if ((clip_star.available && !clip_star.owned
3417 && clip_isautosel_star())
3418 || (clip_plus.available && !clip_plus.owned
3419 && clip_isautosel_plus()))
Bram Moolenaar8820b482017-03-16 17:23:31 +01003420 attr = HL_ATTR(HLF_VNC);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421#endif
3422 }
3423 }
3424
3425 /*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003426 * handle 'incsearch' and ":s///c" highlighting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 */
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01003428 else if (highlight_match
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429 && wp == curwin
3430 && lnum >= curwin->w_cursor.lnum
3431 && lnum <= curwin->w_cursor.lnum + search_match_lines)
3432 {
3433 if (lnum == curwin->w_cursor.lnum)
3434 getvcol(curwin, &(curwin->w_cursor),
3435 (colnr_T *)&fromcol, NULL, NULL);
3436 else
3437 fromcol = 0;
3438 if (lnum == curwin->w_cursor.lnum + search_match_lines)
3439 {
3440 pos.lnum = lnum;
3441 pos.col = search_match_endcol;
3442 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
3443 }
3444 else
3445 tocol = MAXCOL;
Bram Moolenaarf3205d12009-03-18 18:09:03 +00003446 /* do at least one character; happens when past end of line */
3447 if (fromcol == tocol)
3448 tocol = fromcol + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449 area_highlighting = TRUE;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003450 attr = HL_ATTR(HLF_I);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451 }
3452
3453#ifdef FEAT_DIFF
3454 filler_lines = diff_check(wp, lnum);
3455 if (filler_lines < 0)
3456 {
3457 if (filler_lines == -1)
3458 {
3459 if (diff_find_change(wp, lnum, &change_start, &change_end))
3460 diff_hlf = HLF_ADD; /* added line */
3461 else if (change_start == 0)
3462 diff_hlf = HLF_TXD; /* changed text */
3463 else
3464 diff_hlf = HLF_CHD; /* changed line */
3465 }
3466 else
3467 diff_hlf = HLF_ADD; /* added line */
3468 filler_lines = 0;
3469 area_highlighting = TRUE;
3470 }
3471 if (lnum == wp->w_topline)
3472 filler_lines = wp->w_topfill;
3473 filler_todo = filler_lines;
3474#endif
3475
3476#ifdef LINE_ATTR
3477# ifdef FEAT_SIGNS
3478 /* If this line has a sign with line highlighting set line_attr. */
3479 v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
3480 if (v != 0)
3481 line_attr = sign_get_attr((int)v, TRUE);
3482# endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02003483# if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 /* Highlight the current line in the quickfix window. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00003485 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
Bram Moolenaar21020352017-06-13 17:21:04 +02003486 line_attr = HL_ATTR(HLF_QFL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487# endif
3488 if (line_attr != 0)
3489 area_highlighting = TRUE;
3490#endif
3491
3492 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3493 ptr = line;
3494
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003495#ifdef FEAT_SPELL
Bram Moolenaar30abd282005-06-22 22:35:10 +00003496 if (has_spell)
3497 {
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003498 /* For checking first word with a capital skip white space. */
3499 if (cap_col == 0)
Bram Moolenaare2e69e42017-09-02 20:30:35 +02003500 cap_col = getwhitecols(line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003501
Bram Moolenaar30abd282005-06-22 22:35:10 +00003502 /* To be able to spell-check over line boundaries copy the end of the
3503 * current line into nextline[]. Above the start of the next line was
3504 * copied to nextline[SPWORDLEN]. */
3505 if (nextline[SPWORDLEN] == NUL)
3506 {
3507 /* No next line or it is empty. */
3508 nextlinecol = MAXCOL;
3509 nextline_idx = 0;
3510 }
3511 else
3512 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003513 v = (long)STRLEN(line);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003514 if (v < SPWORDLEN)
3515 {
3516 /* Short line, use it completely and append the start of the
3517 * next line. */
3518 nextlinecol = 0;
3519 mch_memmove(nextline, line, (size_t)v);
Bram Moolenaar446cb832008-06-24 21:56:24 +00003520 STRMOVE(nextline + v, nextline + SPWORDLEN);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003521 nextline_idx = v + 1;
3522 }
3523 else
3524 {
3525 /* Long line, use only the last SPWORDLEN bytes. */
3526 nextlinecol = v - SPWORDLEN;
3527 mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
3528 nextline_idx = SPWORDLEN + 1;
3529 }
3530 }
3531 }
3532#endif
3533
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003534 if (wp->w_p_list)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535 {
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003536 if (lcs_space || lcs_trail)
3537 extra_check = TRUE;
3538 /* find start of trailing whitespace */
3539 if (lcs_trail)
3540 {
3541 trailcol = (colnr_T)STRLEN(ptr);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003542 while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01003543 --trailcol;
3544 trailcol += (colnr_T) (ptr - line);
3545 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546 }
3547
3548 /*
3549 * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
3550 * first character to be displayed.
3551 */
3552 if (wp->w_p_wrap)
3553 v = wp->w_skipcol;
3554 else
3555 v = wp->w_leftcol;
3556 if (v > 0)
3557 {
3558#ifdef FEAT_MBYTE
3559 char_u *prev_ptr = ptr;
3560#endif
3561 while (vcol < v && *ptr != NUL)
3562 {
Bram Moolenaar597a4222014-06-25 14:39:50 +02003563 c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564 vcol += c;
3565#ifdef FEAT_MBYTE
3566 prev_ptr = ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567#endif
Bram Moolenaar91acfff2017-03-12 19:22:36 +01003568 MB_PTR_ADV(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 }
3570
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003571 /* When:
3572 * - 'cuc' is set, or
Bram Moolenaar1a384422010-07-14 19:53:30 +02003573 * - 'colorcolumn' is set, or
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003574 * - 'virtualedit' is set, or
3575 * - the visual mode is active,
3576 * the end of the line may be before the start of the displayed part.
3577 */
3578 if (vcol < v && (
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01003579#ifdef FEAT_SYN_HL
3580 wp->w_p_cuc || draw_color_col ||
3581#endif
3582#ifdef FEAT_VIRTUALEDIT
3583 virtual_active() ||
3584#endif
3585 (VIsual_active && wp->w_buffer == curwin->w_buffer)))
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003586 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587 vcol = v;
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003588 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589
3590 /* Handle a character that's not completely on the screen: Put ptr at
3591 * that character but skip the first few screen characters. */
3592 if (vcol > v)
3593 {
3594 vcol -= c;
3595#ifdef FEAT_MBYTE
3596 ptr = prev_ptr;
3597#else
3598 --ptr;
3599#endif
Bram Moolenaarabc39ab2017-03-01 18:04:05 +01003600 /* If the character fits on the screen, don't need to skip it.
3601 * Except for a TAB. */
3602 if ((
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003603#ifdef FEAT_MBYTE
Bram Moolenaarabc39ab2017-03-01 18:04:05 +01003604 (*mb_ptr2cells)(ptr) >= c ||
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003605#endif
Bram Moolenaarabc39ab2017-03-01 18:04:05 +01003606 *ptr == TAB) && col == 0)
Bram Moolenaar04e87b72017-02-01 21:23:10 +01003607 n_skip = v - vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 }
3609
3610 /*
3611 * Adjust for when the inverted text is before the screen,
3612 * and when the start of the inverted text is before the screen.
3613 */
3614 if (tocol <= vcol)
3615 fromcol = 0;
3616 else if (fromcol >= 0 && fromcol < vcol)
3617 fromcol = vcol;
3618
3619#ifdef FEAT_LINEBREAK
3620 /* When w_skipcol is non-zero, first line needs 'showbreak' */
3621 if (wp->w_p_wrap)
3622 need_showbreak = TRUE;
3623#endif
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003624#ifdef FEAT_SPELL
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003625 /* When spell checking a word we need to figure out the start of the
3626 * word and if it's badly spelled or not. */
3627 if (has_spell)
3628 {
3629 int len;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003630 colnr_T linecol = (colnr_T)(ptr - line);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003631 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003632
3633 pos = wp->w_cursor;
3634 wp->w_cursor.lnum = lnum;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003635 wp->w_cursor.col = linecol;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003636 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003637
3638 /* spell_move_to() may call ml_get() and make "line" invalid */
3639 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3640 ptr = line + linecol;
3641
Bram Moolenaar60a795a2005-09-16 21:55:43 +00003642 if (len == 0 || (int)wp->w_cursor.col > ptr - line)
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003643 {
3644 /* no bad word found at line start, don't check until end of a
3645 * word */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003646 spell_hlf = HLF_COUNT;
Bram Moolenaar3b393a02012-06-06 19:05:50 +02003647 word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003648 }
3649 else
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003650 {
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003651 /* bad word found, use attributes until end of word */
3652 word_end = wp->w_cursor.col + len + 1;
3653
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003654 /* Turn index into actual attributes. */
3655 if (spell_hlf != HLF_COUNT)
3656 spell_attr = highlight_attr[spell_hlf];
3657 }
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003658 wp->w_cursor = pos;
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003659
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003660# ifdef FEAT_SYN_HL
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003661 /* Need to restart syntax highlighting for this line. */
3662 if (has_syntax)
Bram Moolenaarf3d769a2017-09-22 13:44:56 +02003663 syntax_start(wp, lnum);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003664# endif
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003665 }
3666#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 }
3668
3669 /*
3670 * Correct highlighting for cursor that can't be disabled.
3671 * Avoids having to check this for each character.
3672 */
3673 if (fromcol >= 0)
3674 {
3675 if (noinvcur)
3676 {
3677 if ((colnr_T)fromcol == wp->w_virtcol)
3678 {
3679 /* highlighting starts at cursor, let it start just after the
3680 * cursor */
3681 fromcol_prev = fromcol;
3682 fromcol = -1;
3683 }
3684 else if ((colnr_T)fromcol < wp->w_virtcol)
3685 /* restart highlighting after the cursor */
3686 fromcol_prev = wp->w_virtcol;
3687 }
3688 if (fromcol >= tocol)
3689 fromcol = -1;
3690 }
3691
3692#ifdef FEAT_SEARCH_EXTRA
3693 /*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003694 * Handle highlighting the last used search pattern and matches.
3695 * Do this for both search_hl and the match list.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696 */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003697 cur = wp->w_match_head;
3698 shl_flag = FALSE;
3699 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003700 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003701 if (shl_flag == FALSE)
3702 {
3703 shl = &search_hl;
3704 shl_flag = TRUE;
3705 }
3706 else
3707 shl = &cur->hl;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003708 shl->startcol = MAXCOL;
3709 shl->endcol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710 shl->attr_cur = 0;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02003711 shl->is_addpos = FALSE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02003712 v = (long)(ptr - line);
3713 if (cur != NULL)
3714 cur->pos.cur = 0;
Bram Moolenaare17bdff2016-08-27 18:34:29 +02003715 next_search_hl(wp, shl, lnum, (colnr_T)v,
3716 shl == &search_hl ? NULL : cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02003717
3718 /* Need to get the line again, a multi-line regexp may have made it
3719 * invalid. */
3720 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3721 ptr = line + v;
3722
3723 if (shl->lnum != 0 && shl->lnum <= lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 {
Bram Moolenaarb3414592014-06-17 17:48:32 +02003725 if (shl->lnum == lnum)
3726 shl->startcol = shl->rm.startpos[0].col;
3727 else
3728 shl->startcol = 0;
3729 if (lnum == shl->lnum + shl->rm.endpos[0].lnum
3730 - shl->rm.startpos[0].lnum)
3731 shl->endcol = shl->rm.endpos[0].col;
3732 else
3733 shl->endcol = MAXCOL;
3734 /* Highlight one character for an empty match. */
3735 if (shl->startcol == shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737#ifdef FEAT_MBYTE
Bram Moolenaarb3414592014-06-17 17:48:32 +02003738 if (has_mbyte && line[shl->endcol] != NUL)
3739 shl->endcol += (*mb_ptr2len)(line + shl->endcol);
3740 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741#endif
Bram Moolenaarb3414592014-06-17 17:48:32 +02003742 ++shl->endcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02003744 if ((long)shl->startcol < v) /* match at leftcol */
3745 {
3746 shl->attr_cur = shl->attr;
3747 search_attr = shl->attr;
3748 }
3749 area_highlighting = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003751 if (shl != &search_hl && cur != NULL)
3752 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 }
3754#endif
3755
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003756#ifdef FEAT_SYN_HL
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02003757 /* Cursor line highlighting for 'cursorline' in the current window. Not
3758 * when Visual mode is active, because it's not clear what is selected
3759 * then. */
Bram Moolenaarbd65c462013-07-01 20:18:33 +02003760 if (wp->w_p_cul && lnum == wp->w_cursor.lnum
Bram Moolenaarb3414592014-06-17 17:48:32 +02003761 && !(wp == curwin && VIsual_active))
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003762 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003763 line_attr = HL_ATTR(HLF_CUL);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003764 area_highlighting = TRUE;
3765 }
3766#endif
3767
Bram Moolenaar92d640f2005-09-05 22:11:52 +00003768 off = (unsigned)(current_ScreenLine - ScreenLines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769 col = 0;
3770#ifdef FEAT_RIGHTLEFT
3771 if (wp->w_p_rl)
3772 {
3773 /* Rightleft window: process the text in the normal direction, but put
3774 * it in current_ScreenLine[] from right to left. Start at the
3775 * rightmost column of the window. */
Bram Moolenaar02631462017-09-22 15:20:32 +02003776 col = wp->w_width - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 off += col;
3778 }
3779#endif
3780
3781 /*
3782 * Repeat for the whole displayed line.
3783 */
3784 for (;;)
3785 {
Bram Moolenaar6561d522015-07-21 15:48:27 +02003786#ifdef FEAT_CONCEAL
Bram Moolenaar4d585022016-04-14 19:50:22 +02003787 has_match_conc = 0;
Bram Moolenaar6561d522015-07-21 15:48:27 +02003788#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 /* Skip this quickly when working on the text. */
3790 if (draw_state != WL_LINE)
3791 {
3792#ifdef FEAT_CMDWIN
3793 if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
3794 {
3795 draw_state = WL_CMDLINE;
3796 if (cmdwin_type != 0 && wp == curwin)
3797 {
3798 /* Draw the cmdline character. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 n_extra = 1;
Bram Moolenaara064ac82007-08-05 18:10:54 +00003800 c_extra = cmdwin_type;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003801 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 }
3803 }
3804#endif
3805
3806#ifdef FEAT_FOLDING
3807 if (draw_state == WL_FOLD - 1 && n_extra == 0)
3808 {
Bram Moolenaar1c934292015-01-27 16:39:29 +01003809 int fdc = compute_foldcolumn(wp, 0);
3810
Bram Moolenaar071d4272004-06-13 20:20:40 +00003811 draw_state = WL_FOLD;
Bram Moolenaar1c934292015-01-27 16:39:29 +01003812 if (fdc > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 {
Bram Moolenaar62706602016-12-09 19:28:48 +01003814 /* Draw the 'foldcolumn'. Allocate a buffer, "extra" may
Bram Moolenaarc695cec2017-01-08 20:00:04 +01003815 * already be in use. */
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01003816 vim_free(p_extra_free);
Bram Moolenaar62706602016-12-09 19:28:48 +01003817 p_extra_free = alloc(12 + 1);
3818
3819 if (p_extra_free != NULL)
3820 {
3821 fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
3822 n_extra = fdc;
3823 p_extra_free[n_extra] = NUL;
3824 p_extra = p_extra_free;
3825 c_extra = NUL;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003826 char_attr = HL_ATTR(HLF_FC);
Bram Moolenaar62706602016-12-09 19:28:48 +01003827 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003828 }
3829 }
3830#endif
3831
3832#ifdef FEAT_SIGNS
3833 if (draw_state == WL_SIGN - 1 && n_extra == 0)
3834 {
3835 draw_state = WL_SIGN;
3836 /* Show the sign column when there are any signs in this
3837 * buffer or when using Netbeans. */
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02003838 if (signcolumn_on(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 {
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01003840 int text_sign;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841# ifdef FEAT_SIGN_ICONS
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01003842 int icon_sign;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843# endif
3844
3845 /* Draw two cells with the sign value or blank. */
3846 c_extra = ' ';
Bram Moolenaar8820b482017-03-16 17:23:31 +01003847 char_attr = HL_ATTR(HLF_SC);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 n_extra = 2;
3849
Bram Moolenaarbc6cf6c2014-05-22 15:51:04 +02003850 if (row == startrow
3851#ifdef FEAT_DIFF
3852 + filler_lines && filler_todo <= 0
3853#endif
3854 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003855 {
3856 text_sign = buf_getsigntype(wp->w_buffer, lnum,
3857 SIGN_TEXT);
3858# ifdef FEAT_SIGN_ICONS
3859 icon_sign = buf_getsigntype(wp->w_buffer, lnum,
3860 SIGN_ICON);
3861 if (gui.in_use && icon_sign != 0)
3862 {
3863 /* Use the image in this position. */
3864 c_extra = SIGN_BYTE;
3865# ifdef FEAT_NETBEANS_INTG
3866 if (buf_signcount(wp->w_buffer, lnum) > 1)
3867 c_extra = MULTISIGN_BYTE;
3868# endif
3869 char_attr = icon_sign;
3870 }
3871 else
3872# endif
3873 if (text_sign != 0)
3874 {
3875 p_extra = sign_get_text(text_sign);
3876 if (p_extra != NULL)
3877 {
3878 c_extra = NUL;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003879 n_extra = (int)STRLEN(p_extra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880 }
3881 char_attr = sign_get_attr(text_sign, FALSE);
3882 }
3883 }
3884 }
3885 }
3886#endif
3887
3888 if (draw_state == WL_NR - 1 && n_extra == 0)
3889 {
3890 draw_state = WL_NR;
Bram Moolenaar64486672010-05-16 15:46:46 +02003891 /* Display the absolute or relative line number. After the
3892 * first fill with blanks when the 'n' flag isn't in 'cpo' */
3893 if ((wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003894 && (row == startrow
3895#ifdef FEAT_DIFF
3896 + filler_lines
3897#endif
3898 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
3899 {
3900 /* Draw the line number (empty space after wrapping). */
3901 if (row == startrow
3902#ifdef FEAT_DIFF
3903 + filler_lines
3904#endif
3905 )
3906 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003907 long num;
Bram Moolenaar700e7342013-01-30 12:31:36 +01003908 char *fmt = "%*ld ";
Bram Moolenaar64486672010-05-16 15:46:46 +02003909
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003910 if (wp->w_p_nu && !wp->w_p_rnu)
3911 /* 'number' + 'norelativenumber' */
Bram Moolenaar64486672010-05-16 15:46:46 +02003912 num = (long)lnum;
3913 else
Bram Moolenaar700e7342013-01-30 12:31:36 +01003914 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003915 /* 'relativenumber', don't use negative numbers */
Bram Moolenaar7eb46522010-12-30 14:57:08 +01003916 num = labs((long)get_cursor_rel_lnum(wp, lnum));
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003917 if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01003918 {
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +02003919 /* 'number' + 'relativenumber' */
Bram Moolenaar700e7342013-01-30 12:31:36 +01003920 num = lnum;
3921 fmt = "%-*ld ";
3922 }
3923 }
Bram Moolenaar64486672010-05-16 15:46:46 +02003924
Bram Moolenaar700e7342013-01-30 12:31:36 +01003925 sprintf((char *)extra, fmt,
Bram Moolenaar64486672010-05-16 15:46:46 +02003926 number_width(wp), num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927 if (wp->w_skipcol > 0)
3928 for (p_extra = extra; *p_extra == ' '; ++p_extra)
3929 *p_extra = '-';
3930#ifdef FEAT_RIGHTLEFT
3931 if (wp->w_p_rl) /* reverse line numbers */
3932 rl_mirror(extra);
3933#endif
3934 p_extra = extra;
3935 c_extra = NUL;
3936 }
3937 else
3938 c_extra = ' ';
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003939 n_extra = number_width(wp) + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003940 char_attr = HL_ATTR(HLF_N);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003941#ifdef FEAT_SYN_HL
3942 /* When 'cursorline' is set highlight the line number of
Bram Moolenaar06ca5132012-03-23 16:25:17 +01003943 * the current line differently.
3944 * TODO: Can we use CursorLine instead of CursorLineNr
3945 * when CursorLineNr isn't set? */
Bram Moolenaarbd65c462013-07-01 20:18:33 +02003946 if ((wp->w_p_cul || wp->w_p_rnu)
Bram Moolenaar700e7342013-01-30 12:31:36 +01003947 && lnum == wp->w_cursor.lnum)
Bram Moolenaar8820b482017-03-16 17:23:31 +01003948 char_attr = HL_ATTR(HLF_CLN);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003949#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950 }
3951 }
3952
Bram Moolenaar597a4222014-06-25 14:39:50 +02003953#ifdef FEAT_LINEBREAK
3954 if (wp->w_p_brisbr && draw_state == WL_BRI - 1
3955 && n_extra == 0 && *p_sbr != NUL)
3956 /* draw indent after showbreak value */
3957 draw_state = WL_BRI;
3958 else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0)
3959 /* After the showbreak, draw the breakindent */
3960 draw_state = WL_BRI - 1;
3961
3962 /* draw 'breakindent': indent wrapped text accordingly */
3963 if (draw_state == WL_BRI - 1 && n_extra == 0)
3964 {
3965 draw_state = WL_BRI;
Bram Moolenaar6c896862016-11-17 19:46:51 +01003966 /* if need_showbreak is set, breakindent also applies */
3967 if (wp->w_p_bri && n_extra == 0
3968 && (row != startrow || need_showbreak)
Bram Moolenaard710e0d2015-06-10 12:16:47 +02003969# ifdef FEAT_DIFF
Bram Moolenaar597a4222014-06-25 14:39:50 +02003970 && filler_lines == 0
Bram Moolenaard710e0d2015-06-10 12:16:47 +02003971# endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02003972 )
3973 {
Bram Moolenaar6c896862016-11-17 19:46:51 +01003974 char_attr = 0;
Bram Moolenaard710e0d2015-06-10 12:16:47 +02003975# ifdef FEAT_DIFF
Bram Moolenaar597a4222014-06-25 14:39:50 +02003976 if (diff_hlf != (hlf_T)0)
Bram Moolenaare0f14822014-08-06 13:20:56 +02003977 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003978 char_attr = HL_ATTR(diff_hlf);
Bram Moolenaard710e0d2015-06-10 12:16:47 +02003979# ifdef FEAT_SYN_HL
Bram Moolenaare0f14822014-08-06 13:20:56 +02003980 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
3981 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01003982 HL_ATTR(HLF_CUL));
Bram Moolenaard710e0d2015-06-10 12:16:47 +02003983# endif
Bram Moolenaare0f14822014-08-06 13:20:56 +02003984 }
Bram Moolenaard710e0d2015-06-10 12:16:47 +02003985# endif
Bram Moolenaarb8b57462014-07-03 22:54:08 +02003986 p_extra = NULL;
Bram Moolenaar597a4222014-06-25 14:39:50 +02003987 c_extra = ' ';
3988 n_extra = get_breakindent_win(wp,
3989 ml_get_buf(wp->w_buffer, lnum, FALSE));
3990 /* Correct end of highlighted area for 'breakindent',
3991 * required when 'linebreak' is also set. */
3992 if (tocol == vcol)
3993 tocol += n_extra;
3994 }
3995 }
3996#endif
3997
Bram Moolenaar071d4272004-06-13 20:20:40 +00003998#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3999 if (draw_state == WL_SBR - 1 && n_extra == 0)
4000 {
4001 draw_state = WL_SBR;
4002# ifdef FEAT_DIFF
4003 if (filler_todo > 0)
4004 {
4005 /* Draw "deleted" diff line(s). */
4006 if (char2cells(fill_diff) > 1)
4007 c_extra = '-';
4008 else
4009 c_extra = fill_diff;
4010# ifdef FEAT_RIGHTLEFT
4011 if (wp->w_p_rl)
4012 n_extra = col + 1;
4013 else
4014# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004015 n_extra = wp->w_width - col;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004016 char_attr = HL_ATTR(HLF_DED);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017 }
4018# endif
4019# ifdef FEAT_LINEBREAK
4020 if (*p_sbr != NUL && need_showbreak)
4021 {
4022 /* Draw 'showbreak' at the start of each broken line. */
4023 p_extra = p_sbr;
4024 c_extra = NUL;
4025 n_extra = (int)STRLEN(p_sbr);
Bram Moolenaar8820b482017-03-16 17:23:31 +01004026 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 need_showbreak = FALSE;
Bram Moolenaard574ea22015-01-14 19:35:14 +01004028 vcol_sbr = vcol + MB_CHARLEN(p_sbr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029 /* Correct end of highlighted area for 'showbreak',
4030 * required when 'linebreak' is also set. */
4031 if (tocol == vcol)
4032 tocol += n_extra;
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02004033#ifdef FEAT_SYN_HL
4034 /* combine 'showbreak' with 'cursorline' */
Bram Moolenaarbd65c462013-07-01 20:18:33 +02004035 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
Bram Moolenaare0f14822014-08-06 13:20:56 +02004036 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01004037 HL_ATTR(HLF_CUL));
Bram Moolenaar5a4d51e2013-06-30 17:24:16 +02004038#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 }
4040# endif
4041 }
4042#endif
4043
4044 if (draw_state == WL_LINE - 1 && n_extra == 0)
4045 {
4046 draw_state = WL_LINE;
4047 if (saved_n_extra)
4048 {
4049 /* Continue item from end of wrapped line. */
4050 n_extra = saved_n_extra;
4051 c_extra = saved_c_extra;
4052 p_extra = saved_p_extra;
4053 char_attr = saved_char_attr;
4054 }
4055 else
4056 char_attr = 0;
4057 }
4058 }
4059
4060 /* When still displaying '$' of change command, stop at cursor */
Bram Moolenaar76b9b362012-02-04 23:35:00 +01004061 if (dollar_vcol >= 0 && wp == curwin
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004062 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063#ifdef FEAT_DIFF
4064 && filler_todo <= 0
4065#endif
4066 )
4067 {
Bram Moolenaar02631462017-09-22 15:20:32 +02004068 screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
Bram Moolenaarc0aa4822017-07-16 14:04:29 +02004069 HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004070 /* Pretend we have finished updating the window. Except when
4071 * 'cursorcolumn' is set. */
4072#ifdef FEAT_SYN_HL
4073 if (wp->w_p_cuc)
4074 row = wp->w_cline_row + wp->w_cline_height;
4075 else
4076#endif
4077 row = wp->w_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004078 break;
4079 }
4080
4081 if (draw_state == WL_LINE && area_highlighting)
4082 {
4083 /* handle Visual or match highlighting in this line */
4084 if (vcol == fromcol
4085#ifdef FEAT_MBYTE
4086 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
4087 && (*mb_ptr2cells)(ptr) > 1)
4088#endif
4089 || ((int)vcol_prev == fromcol_prev
Bram Moolenaarfa363cd2009-02-21 20:23:59 +00004090 && vcol_prev < vcol /* not at margin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 && vcol < tocol))
4092 area_attr = attr; /* start highlighting */
4093 else if (area_attr != 0
4094 && (vcol == tocol
4095 || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 area_attr = 0; /* stop highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097
4098#ifdef FEAT_SEARCH_EXTRA
4099 if (!n_extra)
4100 {
4101 /*
4102 * Check for start/end of search pattern match.
4103 * After end, check for start/end of next match.
4104 * When another match, have to check for start again.
4105 * Watch out for matching an empty string!
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004106 * Do this for 'search_hl' and the match list (ordered by
4107 * priority).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004109 v = (long)(ptr - line);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004110 cur = wp->w_match_head;
4111 shl_flag = FALSE;
4112 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004114 if (shl_flag == FALSE
4115 && ((cur != NULL
4116 && cur->priority > SEARCH_HL_PRIORITY)
4117 || cur == NULL))
4118 {
4119 shl = &search_hl;
4120 shl_flag = TRUE;
4121 }
4122 else
4123 shl = &cur->hl;
Bram Moolenaarb3414592014-06-17 17:48:32 +02004124 if (cur != NULL)
4125 cur->pos.cur = 0;
4126 pos_inprogress = TRUE;
4127 while (shl->rm.regprog != NULL
4128 || (cur != NULL && pos_inprogress))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004129 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004130 if (shl->startcol != MAXCOL
4131 && v >= (long)shl->startcol
4132 && v < (long)shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133 {
Bram Moolenaaraff5c3a2014-12-13 03:36:39 +01004134#ifdef FEAT_MBYTE
4135 int tmp_col = v + MB_PTR2LEN(ptr);
4136
4137 if (shl->endcol < tmp_col)
4138 shl->endcol = tmp_col;
4139#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 shl->attr_cur = shl->attr;
Bram Moolenaar6561d522015-07-21 15:48:27 +02004141#ifdef FEAT_CONCEAL
4142 if (cur != NULL && syn_name2id((char_u *)"Conceal")
4143 == cur->hlg_id)
4144 {
Bram Moolenaar4d585022016-04-14 19:50:22 +02004145 has_match_conc =
4146 v == (long)shl->startcol ? 2 : 1;
Bram Moolenaar6561d522015-07-21 15:48:27 +02004147 match_conc = cur->conceal_char;
4148 }
4149 else
Bram Moolenaar4d585022016-04-14 19:50:22 +02004150 has_match_conc = match_conc = 0;
Bram Moolenaar6561d522015-07-21 15:48:27 +02004151#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152 }
Bram Moolenaaraff5c3a2014-12-13 03:36:39 +01004153 else if (v == (long)shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 {
4155 shl->attr_cur = 0;
Bram Moolenaare17bdff2016-08-27 18:34:29 +02004156 next_search_hl(wp, shl, lnum, (colnr_T)v,
4157 shl == &search_hl ? NULL : cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02004158 pos_inprogress = cur == NULL || cur->pos.cur == 0
Bram Moolenaar6561d522015-07-21 15:48:27 +02004159 ? FALSE : TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004160
4161 /* Need to get the line again, a multi-line regexp
4162 * may have made it invalid. */
4163 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4164 ptr = line + v;
4165
4166 if (shl->lnum == lnum)
4167 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004168 shl->startcol = shl->rm.startpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 if (shl->rm.endpos[0].lnum == 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004170 shl->endcol = shl->rm.endpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171 else
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004172 shl->endcol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004174 if (shl->startcol == shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 {
4176 /* highlight empty match, try again after
4177 * it */
4178#ifdef FEAT_MBYTE
4179 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004180 shl->endcol += (*mb_ptr2len)(line
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004181 + shl->endcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182 else
4183#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004184 ++shl->endcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185 }
4186
4187 /* Loop to check if the match starts at the
4188 * current position */
4189 continue;
4190 }
4191 }
4192 break;
4193 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004194 if (shl != &search_hl && cur != NULL)
4195 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004196 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004197
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004198 /* Use attributes from match with highest priority among
4199 * 'search_hl' and the match list. */
4200 search_attr = search_hl.attr_cur;
4201 cur = wp->w_match_head;
4202 shl_flag = FALSE;
4203 while (cur != NULL || shl_flag == FALSE)
4204 {
4205 if (shl_flag == FALSE
4206 && ((cur != NULL
4207 && cur->priority > SEARCH_HL_PRIORITY)
4208 || cur == NULL))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004209 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004210 shl = &search_hl;
4211 shl_flag = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004212 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004213 else
4214 shl = &cur->hl;
4215 if (shl->attr_cur != 0)
4216 search_attr = shl->attr_cur;
4217 if (shl != &search_hl && cur != NULL)
4218 cur = cur->next;
4219 }
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02004220 /* Only highlight one character after the last column. */
Bram Moolenaar5ece3e32017-10-01 14:35:02 +02004221 if (*ptr == NUL && (did_line_attr >= 1
4222 || (wp->w_p_list && lcs_eol_one == -1)))
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02004223 search_attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224 }
4225#endif
4226
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227#ifdef FEAT_DIFF
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004228 if (diff_hlf != (hlf_T)0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229 {
Bram Moolenaar4b80a512007-06-19 15:44:58 +00004230 if (diff_hlf == HLF_CHD && ptr - line >= change_start
4231 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232 diff_hlf = HLF_TXD; /* changed text */
Bram Moolenaar4b80a512007-06-19 15:44:58 +00004233 if (diff_hlf == HLF_TXD && ptr - line > change_end
4234 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 diff_hlf = HLF_CHD; /* changed line */
Bram Moolenaar8820b482017-03-16 17:23:31 +01004236 line_attr = HL_ATTR(diff_hlf);
Bram Moolenaare0f14822014-08-06 13:20:56 +02004237 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
Bram Moolenaar8820b482017-03-16 17:23:31 +01004238 line_attr = hl_combine_attr(line_attr, HL_ATTR(HLF_CUL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239 }
4240#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004241
4242 /* Decide which of the highlight attributes to use. */
4243 attr_pri = TRUE;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004244#ifdef LINE_ATTR
Bram Moolenaar09deeb72015-03-24 18:22:41 +01004245 if (area_attr != 0)
4246 char_attr = hl_combine_attr(line_attr, area_attr);
4247 else if (search_attr != 0)
4248 char_attr = hl_combine_attr(line_attr, search_attr);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004249 /* Use line_attr when not in the Visual or 'incsearch' area
4250 * (area_attr may be 0 when "noinvcur" is set). */
4251 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
Bram Moolenaarf837ef92009-03-11 16:47:21 +00004252 || vcol < fromcol || vcol_prev < fromcol_prev
4253 || vcol >= tocol))
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004254 char_attr = line_attr;
Bram Moolenaar09deeb72015-03-24 18:22:41 +01004255#else
4256 if (area_attr != 0)
4257 char_attr = area_attr;
4258 else if (search_attr != 0)
4259 char_attr = search_attr;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004260#endif
4261 else
4262 {
4263 attr_pri = FALSE;
4264#ifdef FEAT_SYN_HL
4265 if (has_syntax)
4266 char_attr = syntax_attr;
4267 else
4268#endif
4269 char_attr = 0;
4270 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 }
4272
4273 /*
4274 * Get the next character to put on the screen.
4275 */
4276 /*
Bram Moolenaara064ac82007-08-05 18:10:54 +00004277 * The "p_extra" points to the extra stuff that is inserted to
4278 * represent special characters (non-printable stuff) and other
4279 * things. When all characters are the same, c_extra is used.
4280 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
4281 * "p_extra[n_extra]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
4283 */
4284 if (n_extra > 0)
4285 {
4286 if (c_extra != NUL)
4287 {
4288 c = c_extra;
4289#ifdef FEAT_MBYTE
4290 mb_c = c; /* doesn't handle non-utf-8 multi-byte! */
Bram Moolenaarace95982017-03-29 17:30:27 +02004291 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 {
4293 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004294 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004295 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 }
4297 else
4298 mb_utf8 = FALSE;
4299#endif
4300 }
4301 else
4302 {
4303 c = *p_extra;
4304#ifdef FEAT_MBYTE
4305 if (has_mbyte)
4306 {
4307 mb_c = c;
4308 if (enc_utf8)
4309 {
4310 /* If the UTF-8 character is more than one byte:
4311 * Decode it into "mb_c". */
Bram Moolenaarace95982017-03-29 17:30:27 +02004312 mb_l = utfc_ptr2len(p_extra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004313 mb_utf8 = FALSE;
4314 if (mb_l > n_extra)
4315 mb_l = 1;
4316 else if (mb_l > 1)
4317 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004318 mb_c = utfc_ptr2char(p_extra, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 mb_utf8 = TRUE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004320 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 }
4322 }
4323 else
4324 {
4325 /* if this is a DBCS character, put it in "mb_c" */
4326 mb_l = MB_BYTE2LEN(c);
4327 if (mb_l >= n_extra)
4328 mb_l = 1;
4329 else if (mb_l > 1)
4330 mb_c = (c << 8) + p_extra[1];
4331 }
Bram Moolenaar92d640f2005-09-05 22:11:52 +00004332 if (mb_l == 0) /* at the NUL at end-of-line */
4333 mb_l = 1;
4334
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 /* If a double-width char doesn't fit display a '>' in the
4336 * last column. */
Bram Moolenaar92d640f2005-09-05 22:11:52 +00004337 if ((
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338# ifdef FEAT_RIGHTLEFT
4339 wp->w_p_rl ? (col <= 0) :
4340# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004341 (col >= wp->w_width - 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342 && (*mb_char2cells)(mb_c) == 2)
4343 {
4344 c = '>';
4345 mb_c = c;
4346 mb_l = 1;
4347 mb_utf8 = FALSE;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004348 multi_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 /* put the pointer back to output the double-width
4350 * character at the start of the next line. */
4351 ++n_extra;
4352 --p_extra;
4353 }
4354 else
4355 {
4356 n_extra -= mb_l - 1;
4357 p_extra += mb_l - 1;
4358 }
4359 }
4360#endif
4361 ++p_extra;
4362 }
4363 --n_extra;
4364 }
4365 else
4366 {
Bram Moolenaar88e76882017-02-27 20:33:46 +01004367#ifdef FEAT_LINEBREAK
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004368 int c0;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004369#endif
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004370
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004371 if (p_extra_free != NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +01004372 VIM_CLEAR(p_extra_free);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373 /*
4374 * Get a character from the line itself.
4375 */
Bram Moolenaar10a8da02017-02-27 21:11:35 +01004376 c = *ptr;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004377#ifdef FEAT_LINEBREAK
Bram Moolenaar10a8da02017-02-27 21:11:35 +01004378 c0 = *ptr;
Bram Moolenaar88e76882017-02-27 20:33:46 +01004379#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380#ifdef FEAT_MBYTE
4381 if (has_mbyte)
4382 {
4383 mb_c = c;
4384 if (enc_utf8)
4385 {
4386 /* If the UTF-8 character is more than one byte: Decode it
4387 * into "mb_c". */
Bram Moolenaarace95982017-03-29 17:30:27 +02004388 mb_l = utfc_ptr2len(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389 mb_utf8 = FALSE;
4390 if (mb_l > 1)
4391 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004392 mb_c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393 /* Overlong encoded ASCII or ASCII with composing char
4394 * is displayed normally, except a NUL. */
4395 if (mb_c < 0x80)
Bram Moolenaar88e76882017-02-27 20:33:46 +01004396 {
4397 c = mb_c;
4398# ifdef FEAT_LINEBREAK
4399 c0 = mb_c;
4400# endif
4401 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402 mb_utf8 = TRUE;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00004403
4404 /* At start of the line we can have a composing char.
4405 * Draw it as a space with a composing char. */
4406 if (utf_iscomposing(mb_c))
4407 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004408 int i;
4409
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004410 for (i = Screen_mco - 1; i > 0; --i)
4411 u8cc[i] = u8cc[i - 1];
4412 u8cc[0] = mb_c;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00004413 mb_c = ' ';
4414 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004415 }
4416
4417 if ((mb_l == 1 && c >= 0x80)
4418 || (mb_l >= 1 && mb_c == 0)
4419 || (mb_l > 1 && (!vim_isprintc(mb_c)
Bram Moolenaar11936362007-09-17 20:39:42 +00004420# ifdef UNICODE16
4421 || mb_c >= 0x10000
4422# endif
4423 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424 {
4425 /*
4426 * Illegal UTF-8 byte: display as <xx>.
4427 * Non-BMP character : display as ? or fullwidth ?.
4428 */
Bram Moolenaar11936362007-09-17 20:39:42 +00004429# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430 if (mb_c < 0x10000)
Bram Moolenaar11936362007-09-17 20:39:42 +00004431# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432 {
4433 transchar_hex(extra, mb_c);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004434# ifdef FEAT_RIGHTLEFT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435 if (wp->w_p_rl) /* reverse */
4436 rl_mirror(extra);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004437# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438 }
Bram Moolenaar11936362007-09-17 20:39:42 +00004439# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 else if (utf_char2cells(mb_c) != 2)
4441 STRCPY(extra, "?");
4442 else
4443 /* 0xff1f in UTF-8: full-width '?' */
4444 STRCPY(extra, "\357\274\237");
Bram Moolenaar11936362007-09-17 20:39:42 +00004445# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446
4447 p_extra = extra;
4448 c = *p_extra;
4449 mb_c = mb_ptr2char_adv(&p_extra);
4450 mb_utf8 = (c >= 0x80);
4451 n_extra = (int)STRLEN(p_extra);
4452 c_extra = NUL;
4453 if (area_attr == 0 && search_attr == 0)
4454 {
4455 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004456 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457 saved_attr2 = char_attr; /* save current attr */
4458 }
4459 }
4460 else if (mb_l == 0) /* at the NUL at end-of-line */
4461 mb_l = 1;
4462#ifdef FEAT_ARABIC
4463 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
4464 {
4465 /* Do Arabic shaping. */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004466 int pc, pc1, nc;
4467 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004468
4469 /* The idea of what is the previous and next
4470 * character depends on 'rightleft'. */
4471 if (wp->w_p_rl)
4472 {
4473 pc = prev_c;
4474 pc1 = prev_c1;
4475 nc = utf_ptr2char(ptr + mb_l);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004476 prev_c1 = u8cc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 }
4478 else
4479 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004480 pc = utfc_ptr2char(ptr + mb_l, pcc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481 nc = prev_c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004482 pc1 = pcc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483 }
4484 prev_c = mb_c;
4485
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004486 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004487 }
4488 else
4489 prev_c = mb_c;
4490#endif
4491 }
4492 else /* enc_dbcs */
4493 {
4494 mb_l = MB_BYTE2LEN(c);
4495 if (mb_l == 0) /* at the NUL at end-of-line */
4496 mb_l = 1;
4497 else if (mb_l > 1)
4498 {
4499 /* We assume a second byte below 32 is illegal.
4500 * Hopefully this is OK for all double-byte encodings!
4501 */
4502 if (ptr[1] >= 32)
4503 mb_c = (c << 8) + ptr[1];
4504 else
4505 {
4506 if (ptr[1] == NUL)
4507 {
4508 /* head byte at end of line */
4509 mb_l = 1;
4510 transchar_nonprint(extra, c);
4511 }
4512 else
4513 {
4514 /* illegal tail byte */
4515 mb_l = 2;
4516 STRCPY(extra, "XX");
4517 }
4518 p_extra = extra;
4519 n_extra = (int)STRLEN(extra) - 1;
4520 c_extra = NUL;
4521 c = *p_extra++;
4522 if (area_attr == 0 && search_attr == 0)
4523 {
4524 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004525 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526 saved_attr2 = char_attr; /* save current attr */
4527 }
4528 mb_c = c;
4529 }
4530 }
4531 }
4532 /* If a double-width char doesn't fit display a '>' in the
4533 * last column; the character is displayed at the start of the
4534 * next line. */
4535 if ((
4536# ifdef FEAT_RIGHTLEFT
4537 wp->w_p_rl ? (col <= 0) :
4538# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004539 (col >= wp->w_width - 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 && (*mb_char2cells)(mb_c) == 2)
4541 {
4542 c = '>';
4543 mb_c = c;
4544 mb_utf8 = FALSE;
4545 mb_l = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004546 multi_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004547 /* Put pointer back so that the character will be
4548 * displayed at the start of the next line. */
4549 --ptr;
4550 }
4551 else if (*ptr != NUL)
4552 ptr += mb_l - 1;
4553
4554 /* If a double-width char doesn't fit at the left side display
Bram Moolenaar7ba6ed32010-08-07 16:38:13 +02004555 * a '<' in the first column. Don't do this for unprintable
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02004556 * characters. */
Bram Moolenaar7ba6ed32010-08-07 16:38:13 +02004557 if (n_skip > 0 && mb_l > 1 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 n_extra = 1;
Bram Moolenaar5641f382012-06-13 18:06:36 +02004560 c_extra = MB_FILLER_CHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561 c = ' ';
4562 if (area_attr == 0 && search_attr == 0)
4563 {
4564 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004565 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566 saved_attr2 = char_attr; /* save current attr */
4567 }
4568 mb_c = c;
4569 mb_utf8 = FALSE;
4570 mb_l = 1;
4571 }
4572
4573 }
4574#endif
4575 ++ptr;
4576
4577 if (extra_check)
4578 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004579#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00004580 int can_spell = TRUE;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004581#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00004582
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02004583#ifdef FEAT_TERMINAL
4584 if (get_term_attr)
4585 {
Bram Moolenaar68c4bdd2017-07-30 13:57:41 +02004586 syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol);
Bram Moolenaar63ecdda2017-07-28 22:29:35 +02004587
4588 if (!attr_pri)
4589 char_attr = syntax_attr;
4590 else
4591 char_attr = hl_combine_attr(syntax_attr, char_attr);
4592 }
4593#endif
4594
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004595#ifdef FEAT_SYN_HL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004596 /* Get syntax attribute, unless still at the start of the line
4597 * (double-wide char that doesn't fit). */
Bram Moolenaar217ad922005-03-20 22:37:15 +00004598 v = (long)(ptr - line);
4599 if (has_syntax && v > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600 {
4601 /* Get the syntax attribute for the character. If there
4602 * is an error, disable syntax highlighting. */
4603 save_did_emsg = did_emsg;
4604 did_emsg = FALSE;
4605
Bram Moolenaar217ad922005-03-20 22:37:15 +00004606 syntax_attr = get_syntax_attr((colnr_T)v - 1,
Bram Moolenaar860cae12010-06-05 23:22:07 +02004607# ifdef FEAT_SPELL
4608 has_spell ? &can_spell :
4609# endif
4610 NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611
4612 if (did_emsg)
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004613 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02004614 wp->w_s->b_syn_error = TRUE;
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004615 has_syntax = FALSE;
4616 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 else
4618 did_emsg = save_did_emsg;
Bram Moolenaar06f1ed22017-06-18 22:41:03 +02004619#ifdef SYN_TIME_LIMIT
4620 if (wp->w_s->b_syn_slow)
4621 has_syntax = FALSE;
4622#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623
4624 /* Need to get the line again, a multi-line regexp may
4625 * have made it invalid. */
4626 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4627 ptr = line + v;
4628
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004629 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004630 char_attr = syntax_attr;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004631 else
Bram Moolenaarbc045ea2005-06-05 22:01:26 +00004632 char_attr = hl_combine_attr(syntax_attr, char_attr);
Bram Moolenaarc095b282010-07-20 22:33:34 +02004633# ifdef FEAT_CONCEAL
4634 /* no concealing past the end of the line, it interferes
4635 * with line highlighting */
4636 if (c == NUL)
4637 syntax_flags = 0;
Bram Moolenaar27c735b2010-07-22 22:16:29 +02004638 else
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02004639 syntax_flags = get_syntax_info(&syntax_seqnr);
Bram Moolenaarc095b282010-07-20 22:33:34 +02004640# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004642#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00004643
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004644#ifdef FEAT_SPELL
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004645 /* Check spelling (unless at the end of the line).
Bram Moolenaarf3681cc2005-06-08 22:03:13 +00004646 * Only do this when there is no syntax highlighting, the
4647 * @Spell cluster is not used or the current syntax item
4648 * contains the @Spell cluster. */
Bram Moolenaar30abd282005-06-22 22:35:10 +00004649 if (has_spell && v >= word_end && v > cur_checked_col)
Bram Moolenaar217ad922005-03-20 22:37:15 +00004650 {
Bram Moolenaar68b76a62005-03-25 21:53:48 +00004651 spell_attr = 0;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004652# ifdef FEAT_SYN_HL
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004653 if (!attr_pri)
Bram Moolenaar68b76a62005-03-25 21:53:48 +00004654 char_attr = syntax_attr;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004655# endif
4656 if (c != 0 && (
4657# ifdef FEAT_SYN_HL
4658 !has_syntax ||
4659# endif
4660 can_spell))
Bram Moolenaar217ad922005-03-20 22:37:15 +00004661 {
Bram Moolenaar30abd282005-06-22 22:35:10 +00004662 char_u *prev_ptr, *p;
4663 int len;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004664 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004665# ifdef FEAT_MBYTE
Bram Moolenaare7566042005-06-17 22:00:15 +00004666 if (has_mbyte)
4667 {
4668 prev_ptr = ptr - mb_l;
4669 v -= mb_l - 1;
4670 }
4671 else
Bram Moolenaar217ad922005-03-20 22:37:15 +00004672# endif
Bram Moolenaare7566042005-06-17 22:00:15 +00004673 prev_ptr = ptr - 1;
Bram Moolenaar30abd282005-06-22 22:35:10 +00004674
4675 /* Use nextline[] if possible, it has the start of the
4676 * next line concatenated. */
4677 if ((prev_ptr - line) - nextlinecol >= 0)
4678 p = nextline + (prev_ptr - line) - nextlinecol;
4679 else
4680 p = prev_ptr;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004681 cap_col -= (int)(prev_ptr - line);
Bram Moolenaar4770d092006-01-12 23:22:24 +00004682 len = spell_check(wp, p, &spell_hlf, &cap_col,
4683 nochange);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004684 word_end = v + len;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004685
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004686 /* In Insert mode only highlight a word that
4687 * doesn't touch the cursor. */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004688 if (spell_hlf != HLF_COUNT
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004689 && (State & INSERT) != 0
4690 && wp->w_cursor.lnum == lnum
4691 && wp->w_cursor.col >=
Bram Moolenaar217ad922005-03-20 22:37:15 +00004692 (colnr_T)(prev_ptr - line)
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004693 && wp->w_cursor.col < (colnr_T)word_end)
4694 {
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004695 spell_hlf = HLF_COUNT;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004696 spell_redraw_lnum = lnum;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004697 }
Bram Moolenaar30abd282005-06-22 22:35:10 +00004698
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004699 if (spell_hlf == HLF_COUNT && p != prev_ptr
Bram Moolenaar30abd282005-06-22 22:35:10 +00004700 && (p - nextline) + len > nextline_idx)
4701 {
4702 /* Remember that the good word continues at the
4703 * start of the next line. */
4704 checked_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004705 checked_col = (int)((p - nextline) + len - nextline_idx);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004706 }
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004707
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004708 /* Turn index into actual attributes. */
4709 if (spell_hlf != HLF_COUNT)
4710 spell_attr = highlight_attr[spell_hlf];
4711
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004712 if (cap_col > 0)
4713 {
4714 if (p != prev_ptr
4715 && (p - nextline) + cap_col >= nextline_idx)
4716 {
4717 /* Remember that the word in the next line
4718 * must start with a capital. */
4719 capcol_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004720 cap_col = (int)((p - nextline) + cap_col
4721 - nextline_idx);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004722 }
4723 else
4724 /* Compute the actual column. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004725 cap_col += (int)(prev_ptr - line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004726 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004727 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004728 }
4729 if (spell_attr != 0)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004730 {
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004731 if (!attr_pri)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004732 char_attr = hl_combine_attr(char_attr, spell_attr);
4733 else
4734 char_attr = hl_combine_attr(spell_attr, char_attr);
4735 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736#endif
4737#ifdef FEAT_LINEBREAK
4738 /*
Bram Moolenaar217ad922005-03-20 22:37:15 +00004739 * Found last space before word: check for line break.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 */
Bram Moolenaar38632fa2017-02-26 19:40:59 +01004741 if (wp->w_p_lbr && c0 == c
Bram Moolenaar977d0372017-03-12 21:31:58 +01004742 && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743 {
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004744# ifdef FEAT_MBYTE
Bram Moolenaar4df70292015-03-21 14:20:16 +01004745 int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0;
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004746# endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02004747 char_u *p = ptr - (
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748# ifdef FEAT_MBYTE
Bram Moolenaar4df70292015-03-21 14:20:16 +01004749 mb_off +
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750# endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02004751 1);
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004752
Bram Moolenaar597a4222014-06-25 14:39:50 +02004753 /* TODO: is passing p for start of the line OK? */
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004754 n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
Bram Moolenaar597a4222014-06-25 14:39:50 +02004755 NULL) - 1;
Bram Moolenaar02631462017-09-22 15:20:32 +02004756 if (c == TAB && n_extra + col > wp->w_width)
Bram Moolenaara3650912014-11-19 13:21:57 +01004757 n_extra = (int)wp->w_buffer->b_p_ts
4758 - vcol % (int)wp->w_buffer->b_p_ts - 1;
4759
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004760# ifdef FEAT_MBYTE
Bram Moolenaar4df70292015-03-21 14:20:16 +01004761 c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004762# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763 c_extra = ' ';
Bram Moolenaar76feaf12015-03-20 15:58:52 +01004764# endif
Bram Moolenaar1c465442017-03-12 20:10:05 +01004765 if (VIM_ISWHITE(c))
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02004766 {
4767#ifdef FEAT_CONCEAL
4768 if (c == TAB)
4769 /* See "Tab alignment" below. */
4770 FIX_FOR_BOGUSCOLS;
4771#endif
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004772 if (!wp->w_p_list)
4773 c = ' ';
Bram Moolenaar3ff9b182013-07-13 12:36:55 +02004774 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004775 }
4776#endif
4777
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004778 /* 'list': change char 160 to lcs_nbsp and space to lcs_space.
4779 */
4780 if (wp->w_p_list
4781 && (((c == 160
4782#ifdef FEAT_MBYTE
4783 || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f))
4784#endif
4785 ) && lcs_nbsp)
4786 || (c == ' ' && lcs_space && ptr - line <= trailcol)))
4787 {
4788 c = (c == ' ') ? lcs_space : lcs_nbsp;
4789 if (area_attr == 0 && search_attr == 0)
4790 {
4791 n_attr = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004792 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004793 saved_attr2 = char_attr; /* save current attr */
4794 }
4795#ifdef FEAT_MBYTE
4796 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02004797 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar9bc01eb2015-12-17 21:14:58 +01004798 {
4799 mb_utf8 = TRUE;
4800 u8cc[0] = 0;
4801 c = 0xc0;
4802 }
4803 else
4804 mb_utf8 = FALSE;
4805#endif
4806 }
4807
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
4809 {
4810 c = lcs_trail;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004811 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004812 {
4813 n_attr = 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004814 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 saved_attr2 = char_attr; /* save current attr */
4816 }
4817#ifdef FEAT_MBYTE
4818 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02004819 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820 {
4821 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004822 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004823 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 }
4825 else
4826 mb_utf8 = FALSE;
4827#endif
4828 }
4829 }
4830
4831 /*
4832 * Handling of non-printable characters.
4833 */
Bram Moolenaar88e8f9f2016-01-20 22:48:02 +01004834 if (!vim_isprintc(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004835 {
4836 /*
4837 * when getting a character from the file, we may have to
4838 * turn it into something else on the way to putting it
4839 * into "ScreenLines".
4840 */
4841 if (c == TAB && (!wp->w_p_list || lcs_tab1))
4842 {
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004843 int tab_len = 0;
Bram Moolenaard574ea22015-01-14 19:35:14 +01004844 long vcol_adjusted = vcol; /* removed showbreak length */
4845#ifdef FEAT_LINEBREAK
4846 /* only adjust the tab_len, when at the first column
4847 * after the showbreak value was drawn */
4848 if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap)
4849 vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
4850#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851 /* tab amount depends on current column */
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004852 tab_len = (int)wp->w_buffer->b_p_ts
Bram Moolenaard574ea22015-01-14 19:35:14 +01004853 - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
4854
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004855#ifdef FEAT_LINEBREAK
Bram Moolenaarb81c85d2014-07-30 16:44:22 +02004856 if (!wp->w_p_lbr || !wp->w_p_list)
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004857#endif
4858 /* tab amount depends on current column */
4859 n_extra = tab_len;
4860#ifdef FEAT_LINEBREAK
4861 else
4862 {
4863 char_u *p;
4864 int len = n_extra;
4865 int i;
4866 int saved_nextra = n_extra;
4867
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004868#ifdef FEAT_CONCEAL
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004869 if (vcol_off > 0)
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004870 /* there are characters to conceal */
4871 tab_len += vcol_off;
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01004872 /* boguscols before FIX_FOR_BOGUSCOLS macro from above
4873 */
4874 if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
4875 && n_extra > tab_len)
4876 tab_len += n_extra - tab_len;
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004877#endif
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01004878
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004879 /* if n_extra > 0, it gives the number of chars, to
4880 * use for a tab, else we need to calculate the width
4881 * for a tab */
4882#ifdef FEAT_MBYTE
4883 len = (tab_len * mb_char2len(lcs_tab2));
4884 if (n_extra > 0)
4885 len += n_extra - tab_len;
4886#endif
4887 c = lcs_tab1;
4888 p = alloc((unsigned)(len + 1));
4889 vim_memset(p, ' ', len);
4890 p[len] = NUL;
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01004891 vim_free(p_extra_free);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004892 p_extra_free = p;
4893 for (i = 0; i < tab_len; i++)
4894 {
4895#ifdef FEAT_MBYTE
4896 mb_char2bytes(lcs_tab2, p);
4897 p += mb_char2len(lcs_tab2);
4898 n_extra += mb_char2len(lcs_tab2)
4899 - (saved_nextra > 0 ? 1 : 0);
4900#else
4901 p[i] = lcs_tab2;
4902#endif
4903 }
4904 p_extra = p_extra_free;
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004905#ifdef FEAT_CONCEAL
4906 /* n_extra will be increased by FIX_FOX_BOGUSCOLS
4907 * macro below, so need to adjust for that here */
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004908 if (vcol_off > 0)
Bram Moolenaar49f9dd72014-08-29 12:08:43 +02004909 n_extra -= vcol_off;
4910#endif
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004911 }
4912#endif
Bram Moolenaar0f9d0862012-12-05 15:32:30 +01004913#ifdef FEAT_CONCEAL
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004914 {
4915 int vc_saved = vcol_off;
4916
4917 /* Tab alignment should be identical regardless of
4918 * 'conceallevel' value. So tab compensates of all
4919 * previous concealed characters, and thus resets
4920 * vcol_off and boguscols accumulated so far in the
4921 * line. Note that the tab can be longer than
4922 * 'tabstop' when there are concealed characters. */
4923 FIX_FOR_BOGUSCOLS;
4924
4925 /* Make sure, the highlighting for the tab char will be
4926 * correctly set further below (effectively reverts the
4927 * FIX_FOR_BOGSUCOLS macro */
4928 if (n_extra == tab_len + vc_saved && wp->w_p_list
Bram Moolenaar6a6028c2015-01-20 19:01:35 +01004929 && lcs_tab1)
Bram Moolenaar8fc6bc72015-02-17 17:26:10 +01004930 tab_len += vc_saved;
4931 }
Bram Moolenaar0f9d0862012-12-05 15:32:30 +01004932#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933#ifdef FEAT_MBYTE
4934 mb_utf8 = FALSE; /* don't draw as UTF-8 */
4935#endif
4936 if (wp->w_p_list)
4937 {
4938 c = lcs_tab1;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02004939#ifdef FEAT_LINEBREAK
4940 if (wp->w_p_lbr)
4941 c_extra = NUL; /* using p_extra from above */
4942 else
4943#endif
4944 c_extra = lcs_tab2;
4945 n_attr = tab_len + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01004946 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947 saved_attr2 = char_attr; /* save current attr */
4948#ifdef FEAT_MBYTE
4949 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02004950 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951 {
4952 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004953 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004954 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004955 }
4956#endif
4957 }
4958 else
4959 {
4960 c_extra = ' ';
4961 c = ' ';
4962 }
4963 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004964 else if (c == NUL
Bram Moolenaard59c0992015-05-04 16:52:01 +02004965 && (wp->w_p_list
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004966 || ((fromcol >= 0 || fromcol_prev >= 0)
4967 && tocol > vcol
4968 && VIsual_mode != Ctrl_V
4969 && (
4970# ifdef FEAT_RIGHTLEFT
4971 wp->w_p_rl ? (col >= 0) :
4972# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02004973 (col < wp->w_width))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004974 && !(noinvcur
Bram Moolenaarf3205d12009-03-18 18:09:03 +00004975 && lnum == wp->w_cursor.lnum
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004976 && (colnr_T)vcol == wp->w_virtcol)))
Bram Moolenaar0481fee2015-05-14 05:56:09 +02004977 && lcs_eol_one > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004978 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004979 /* Display a '$' after the line or highlight an extra
4980 * character if the line break is included. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981#if defined(FEAT_DIFF) || defined(LINE_ATTR)
4982 /* For a diff line the highlighting continues after the
4983 * "$". */
4984 if (
4985# ifdef FEAT_DIFF
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004986 diff_hlf == (hlf_T)0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004987# ifdef LINE_ATTR
4988 &&
4989# endif
4990# endif
4991# ifdef LINE_ATTR
4992 line_attr == 0
4993# endif
4994 )
4995#endif
4996 {
4997#ifdef FEAT_VIRTUALEDIT
4998 /* In virtualedit, visual selections may extend
4999 * beyond end of line. */
5000 if (area_highlighting && virtual_active()
5001 && tocol != MAXCOL && vcol < tocol)
5002 n_extra = 0;
5003 else
5004#endif
5005 {
5006 p_extra = at_end_str;
5007 n_extra = 1;
5008 c_extra = NUL;
5009 }
5010 }
Bram Moolenaard59c0992015-05-04 16:52:01 +02005011 if (wp->w_p_list && lcs_eol > 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005012 c = lcs_eol;
5013 else
5014 c = ' ';
Bram Moolenaar071d4272004-06-13 20:20:40 +00005015 lcs_eol_one = -1;
5016 --ptr; /* put it back at the NUL */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005017 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01005019 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005020 n_attr = 1;
5021 }
5022#ifdef FEAT_MBYTE
5023 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005024 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025 {
5026 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005027 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005028 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029 }
5030 else
5031 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5032#endif
5033 }
5034 else if (c != NUL)
5035 {
5036 p_extra = transchar(c);
Bram Moolenaar5524aeb2014-07-16 17:29:51 +02005037 if (n_extra == 0)
5038 n_extra = byte2cells(c) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039#ifdef FEAT_RIGHTLEFT
5040 if ((dy_flags & DY_UHEX) && wp->w_p_rl)
5041 rl_mirror(p_extra); /* reverse "<12>" */
5042#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043 c_extra = NUL;
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005044#ifdef FEAT_LINEBREAK
5045 if (wp->w_p_lbr)
5046 {
5047 char_u *p;
5048
5049 c = *p_extra;
5050 p = alloc((unsigned)n_extra + 1);
5051 vim_memset(p, ' ', n_extra);
5052 STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
5053 p[n_extra] = NUL;
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01005054 vim_free(p_extra_free);
Bram Moolenaar86b17e92014-07-02 20:00:47 +02005055 p_extra_free = p_extra = p;
5056 }
5057 else
5058#endif
5059 {
5060 n_extra = byte2cells(c) - 1;
5061 c = *p_extra++;
5062 }
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005063 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064 {
5065 n_attr = n_extra + 1;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005066 extra_attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005067 saved_attr2 = char_attr; /* save current attr */
5068 }
5069#ifdef FEAT_MBYTE
5070 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5071#endif
5072 }
5073#ifdef FEAT_VIRTUALEDIT
5074 else if (VIsual_active
5075 && (VIsual_mode == Ctrl_V
5076 || VIsual_mode == 'v')
5077 && virtual_active()
5078 && tocol != MAXCOL
5079 && vcol < tocol
5080 && (
5081# ifdef FEAT_RIGHTLEFT
5082 wp->w_p_rl ? (col >= 0) :
5083# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005084 (col < wp->w_width)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005085 {
5086 c = ' ';
5087 --ptr; /* put it back at the NUL */
5088 }
5089#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005090#if defined(LINE_ATTR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091 else if ((
5092# ifdef FEAT_DIFF
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005093 diff_hlf != (hlf_T)0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00005094# endif
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005095# ifdef FEAT_TERMINAL
5096 term_attr != 0 ||
5097# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 line_attr != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005099 ) && (
5100# ifdef FEAT_RIGHTLEFT
5101 wp->w_p_rl ? (col >= 0) :
5102# endif
Bram Moolenaar2a988a12010-08-13 15:24:39 +02005103 (col
5104# ifdef FEAT_CONCEAL
5105 - boguscols
5106# endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005107 < wp->w_width)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005108 {
5109 /* Highlight until the right side of the window */
5110 c = ' ';
5111 --ptr; /* put it back at the NUL */
Bram Moolenaar91170f82006-05-05 21:15:17 +00005112
5113 /* Remember we do the char for line highlighting. */
5114 ++did_line_attr;
5115
5116 /* don't do search HL for the rest of the line */
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02005117 if (line_attr != 0 && char_attr == search_attr
5118 && (did_line_attr > 1
5119 || (wp->w_p_list && lcs_eol > 0)))
Bram Moolenaar91170f82006-05-05 21:15:17 +00005120 char_attr = line_attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121# ifdef FEAT_DIFF
5122 if (diff_hlf == HLF_TXD)
5123 {
5124 diff_hlf = HLF_CHD;
5125 if (attr == 0 || char_attr != attr)
Bram Moolenaare0f14822014-08-06 13:20:56 +02005126 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01005127 char_attr = HL_ATTR(diff_hlf);
Bram Moolenaare0f14822014-08-06 13:20:56 +02005128 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
5129 char_attr = hl_combine_attr(char_attr,
Bram Moolenaar8820b482017-03-16 17:23:31 +01005130 HL_ATTR(HLF_CUL));
Bram Moolenaare0f14822014-08-06 13:20:56 +02005131 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132 }
5133# endif
Bram Moolenaar238d43b2017-09-11 22:00:51 +02005134# ifdef FEAT_TERMINAL
5135 if (term_attr != 0)
5136 {
5137 char_attr = term_attr;
5138 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
5139 char_attr = hl_combine_attr(char_attr,
5140 HL_ATTR(HLF_CUL));
5141 }
5142# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 }
5144#endif
5145 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005146
5147#ifdef FEAT_CONCEAL
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005148 if ( wp->w_p_cole > 0
5149 && (wp != curwin || lnum != wp->w_cursor.lnum ||
Bram Moolenaar6561d522015-07-21 15:48:27 +02005150 conceal_cursor_line(wp) )
Bram Moolenaar4d585022016-04-14 19:50:22 +02005151 && ( (syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
Bram Moolenaare6dc5732010-07-24 23:52:26 +02005152 && !(lnum_in_visual_area
5153 && vim_strchr(wp->w_p_cocu, 'v') == NULL))
Bram Moolenaar860cae12010-06-05 23:22:07 +02005154 {
5155 char_attr = conceal_attr;
Bram Moolenaar4d585022016-04-14 19:50:22 +02005156 if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
Bram Moolenaar6561d522015-07-21 15:48:27 +02005157 && (syn_get_sub_char() != NUL || match_conc
5158 || wp->w_p_cole == 1)
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005159 && wp->w_p_cole != 3)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005160 {
Bram Moolenaar27c735b2010-07-22 22:16:29 +02005161 /* First time at this concealed item: display one
5162 * character. */
Bram Moolenaar6561d522015-07-21 15:48:27 +02005163 if (match_conc)
5164 c = match_conc;
5165 else if (syn_get_sub_char() != NUL)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005166 c = syn_get_sub_char();
5167 else if (lcs_conceal != NUL)
5168 c = lcs_conceal;
5169 else
5170 c = ' ';
5171
Bram Moolenaarffbbcb52010-07-24 17:29:03 +02005172 prev_syntax_id = syntax_seqnr;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005173
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005174 if (n_extra > 0)
5175 vcol_off += n_extra;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005176 vcol += n_extra;
5177 if (wp->w_p_wrap && n_extra > 0)
5178 {
5179# ifdef FEAT_RIGHTLEFT
5180 if (wp->w_p_rl)
5181 {
5182 col -= n_extra;
5183 boguscols -= n_extra;
5184 }
5185 else
5186# endif
5187 {
5188 boguscols += n_extra;
5189 col += n_extra;
5190 }
5191 }
5192 n_extra = 0;
5193 n_attr = 0;
5194 }
5195 else if (n_skip == 0)
5196 {
5197 is_concealing = TRUE;
5198 n_skip = 1;
5199 }
5200# ifdef FEAT_MBYTE
5201 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005202 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005203 {
5204 mb_utf8 = TRUE;
5205 u8cc[0] = 0;
5206 c = 0xc0;
5207 }
5208 else
5209 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5210# endif
5211 }
5212 else
5213 {
Bram Moolenaar27c735b2010-07-22 22:16:29 +02005214 prev_syntax_id = 0;
Bram Moolenaarc400cb92010-07-19 19:52:13 +02005215 is_concealing = FALSE;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005216 }
5217#endif /* FEAT_CONCEAL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005218 }
5219
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005220#ifdef FEAT_CONCEAL
5221 /* In the cursor line and we may be concealing characters: correct
5222 * the cursor column when we reach its position. */
Bram Moolenaarf691b842010-07-24 13:31:09 +02005223 if (!did_wcol && draw_state == WL_LINE
5224 && wp == curwin && lnum == wp->w_cursor.lnum
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005225 && conceal_cursor_line(wp)
5226 && (int)wp->w_virtcol <= vcol + n_skip)
5227 {
Bram Moolenaare39b3d92016-01-15 22:52:22 +01005228# ifdef FEAT_RIGHTLEFT
5229 if (wp->w_p_rl)
Bram Moolenaar02631462017-09-22 15:20:32 +02005230 wp->w_wcol = wp->w_width - col + boguscols - 1;
Bram Moolenaare39b3d92016-01-15 22:52:22 +01005231 else
5232# endif
5233 wp->w_wcol = col - boguscols;
Bram Moolenaar72ada0f2010-07-24 17:39:52 +02005234 wp->w_wrow = row;
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005235 did_wcol = TRUE;
5236 }
5237#endif
5238
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239 /* Don't override visual selection highlighting. */
5240 if (n_attr > 0
5241 && draw_state == WL_LINE
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005242 && !attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005243 char_attr = extra_attr;
5244
Bram Moolenaar81695252004-12-29 20:58:21 +00005245#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005246 /* XIM don't send preedit_start and preedit_end, but they send
5247 * preedit_changed and commit. Thus Vim can't set "im_is_active", use
5248 * im_is_preediting() here. */
Bram Moolenaar5c6dbcb2017-08-30 22:00:20 +02005249 if (p_imst == IM_ON_THE_SPOT
5250 && xic != NULL
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005251 && lnum == wp->w_cursor.lnum
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252 && (State & INSERT)
5253 && !p_imdisable
5254 && im_is_preediting()
5255 && draw_state == WL_LINE)
5256 {
5257 colnr_T tcol;
5258
5259 if (preedit_end_col == MAXCOL)
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005260 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005261 else
5262 tcol = preedit_end_col;
5263 if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
5264 {
5265 if (feedback_old_attr < 0)
5266 {
5267 feedback_col = 0;
5268 feedback_old_attr = char_attr;
5269 }
5270 char_attr = im_get_feedback_attr(feedback_col);
5271 if (char_attr < 0)
5272 char_attr = feedback_old_attr;
5273 feedback_col++;
5274 }
5275 else if (feedback_old_attr >= 0)
5276 {
5277 char_attr = feedback_old_attr;
5278 feedback_old_attr = -1;
5279 feedback_col = 0;
5280 }
5281 }
5282#endif
5283 /*
5284 * Handle the case where we are in column 0 but not on the first
5285 * character of the line and the user wants us to show us a
5286 * special character (via 'listchars' option "precedes:<char>".
5287 */
5288 if (lcs_prec_todo != NUL
Bram Moolenaar7425b932014-10-10 15:28:46 +02005289 && wp->w_p_list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005290 && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
5291#ifdef FEAT_DIFF
5292 && filler_todo <= 0
5293#endif
5294 && draw_state > WL_NR
5295 && c != NUL)
5296 {
5297 c = lcs_prec;
5298 lcs_prec_todo = NUL;
5299#ifdef FEAT_MBYTE
Bram Moolenaar5641f382012-06-13 18:06:36 +02005300 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5301 {
5302 /* Double-width character being overwritten by the "precedes"
5303 * character, need to fill up half the character. */
5304 c_extra = MB_FILLER_CHAR;
5305 n_extra = 1;
5306 n_attr = 2;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005307 extra_attr = HL_ATTR(HLF_AT);
Bram Moolenaar5641f382012-06-13 18:06:36 +02005308 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005309 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005310 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005311 {
5312 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005313 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005314 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005315 }
5316 else
5317 mb_utf8 = FALSE; /* don't draw as UTF-8 */
5318#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00005319 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005320 {
5321 saved_attr3 = char_attr; /* save current attr */
Bram Moolenaar8820b482017-03-16 17:23:31 +01005322 char_attr = HL_ATTR(HLF_AT); /* later copied to char_attr */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005323 n_attr3 = 1;
5324 }
5325 }
5326
5327 /*
Bram Moolenaar91170f82006-05-05 21:15:17 +00005328 * At end of the text line or just after the last character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005329 */
Bram Moolenaar91170f82006-05-05 21:15:17 +00005330 if (c == NUL
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005331#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00005332 || did_line_attr == 1
5333#endif
5334 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00005335 {
Bram Moolenaar91170f82006-05-05 21:15:17 +00005336#ifdef FEAT_SEARCH_EXTRA
5337 long prevcol = (long)(ptr - line) - (c == NUL);
Bram Moolenaara443af82007-11-08 13:51:42 +00005338
5339 /* we're not really at that column when skipping some text */
Bram Moolenaar33741a02007-11-08 20:24:19 +00005340 if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
Bram Moolenaara443af82007-11-08 13:51:42 +00005341 ++prevcol;
Bram Moolenaar91170f82006-05-05 21:15:17 +00005342#endif
5343
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005344 /* Invert at least one char, used for Visual and empty line or
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345 * highlight match at end of line. If it's beyond the last
5346 * char on the screen, just overwrite that one (tricky!) Not
5347 * needed when a '$' was displayed for 'list'. */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005348#ifdef FEAT_SEARCH_EXTRA
5349 prevcol_hl_flag = FALSE;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02005350 if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005351 prevcol_hl_flag = TRUE;
5352 else
5353 {
5354 cur = wp->w_match_head;
5355 while (cur != NULL)
5356 {
Bram Moolenaar4f416e42016-08-16 16:08:18 +02005357 if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005358 {
5359 prevcol_hl_flag = TRUE;
5360 break;
5361 }
5362 cur = cur->next;
5363 }
5364 }
5365#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005366 if (lcs_eol == lcs_eol_one
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005367 && ((area_attr != 0 && vcol == fromcol
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005368 && (VIsual_mode != Ctrl_V
5369 || lnum == VIsual.lnum
5370 || lnum == curwin->w_cursor.lnum)
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005371 && c == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372#ifdef FEAT_SEARCH_EXTRA
5373 /* highlight 'hlsearch' match at end of line */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005374 || (prevcol_hl_flag == TRUE
Bram Moolenaar0aa398f2017-09-30 21:23:55 +02005375# ifdef FEAT_SYN_HL
5376 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
5377 && !(wp == curwin && VIsual_active))
5378# endif
5379# ifdef FEAT_DIFF
5380 && diff_hlf == (hlf_T)0
5381# endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00005382# if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00005383 && did_line_attr <= 1
5384# endif
5385 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00005386#endif
5387 ))
5388 {
5389 int n = 0;
5390
5391#ifdef FEAT_RIGHTLEFT
5392 if (wp->w_p_rl)
5393 {
5394 if (col < 0)
5395 n = 1;
5396 }
5397 else
5398#endif
5399 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005400 if (col >= wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005401 n = -1;
5402 }
5403 if (n != 0)
5404 {
5405 /* At the window boundary, highlight the last character
5406 * instead (better than nothing). */
5407 off += n;
5408 col += n;
5409 }
5410 else
5411 {
5412 /* Add a blank character to highlight. */
5413 ScreenLines[off] = ' ';
5414#ifdef FEAT_MBYTE
5415 if (enc_utf8)
5416 ScreenLinesUC[off] = 0;
5417#endif
5418 }
5419#ifdef FEAT_SEARCH_EXTRA
5420 if (area_attr == 0)
5421 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005422 /* Use attributes from match with highest priority among
5423 * 'search_hl' and the match list. */
5424 char_attr = search_hl.attr;
5425 cur = wp->w_match_head;
5426 shl_flag = FALSE;
5427 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005428 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005429 if (shl_flag == FALSE
5430 && ((cur != NULL
5431 && cur->priority > SEARCH_HL_PRIORITY)
5432 || cur == NULL))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005433 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005434 shl = &search_hl;
5435 shl_flag = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005436 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005437 else
5438 shl = &cur->hl;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02005439 if ((ptr - line) - 1 == (long)shl->startcol
5440 && (shl == &search_hl || !shl->is_addpos))
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005441 char_attr = shl->attr;
5442 if (shl != &search_hl && cur != NULL)
5443 cur = cur->next;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00005444 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005445 }
5446#endif
5447 ScreenAttrs[off] = char_attr;
5448#ifdef FEAT_RIGHTLEFT
5449 if (wp->w_p_rl)
Bram Moolenaara443af82007-11-08 13:51:42 +00005450 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005451 --col;
Bram Moolenaara443af82007-11-08 13:51:42 +00005452 --off;
5453 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005454 else
5455#endif
Bram Moolenaara443af82007-11-08 13:51:42 +00005456 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005457 ++col;
Bram Moolenaara443af82007-11-08 13:51:42 +00005458 ++off;
5459 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005460 ++vcol;
Bram Moolenaara443af82007-11-08 13:51:42 +00005461#ifdef FEAT_SYN_HL
5462 eol_hl_off = 1;
5463#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005464 }
Bram Moolenaar91170f82006-05-05 21:15:17 +00005465 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005466
Bram Moolenaar91170f82006-05-05 21:15:17 +00005467 /*
5468 * At end of the text line.
5469 */
5470 if (c == NUL)
5471 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005472#ifdef FEAT_SYN_HL
Bram Moolenaarf3205d12009-03-18 18:09:03 +00005473 if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol
5474 && lnum == wp->w_cursor.lnum)
Bram Moolenaara443af82007-11-08 13:51:42 +00005475 {
5476 /* highlight last char after line */
5477 --col;
5478 --off;
5479 --vcol;
5480 }
5481
Bram Moolenaar1a384422010-07-14 19:53:30 +02005482 /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00005483 if (wp->w_p_wrap)
5484 v = wp->w_skipcol;
5485 else
5486 v = wp->w_leftcol;
Bram Moolenaar1a384422010-07-14 19:53:30 +02005487
Bram Moolenaar8dff8182006-04-06 20:18:50 +00005488 /* check if line ends before left margin */
5489 if (vcol < v + col - win_col_off(wp))
Bram Moolenaar8dff8182006-04-06 20:18:50 +00005490 vcol = v + col - win_col_off(wp);
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005491#ifdef FEAT_CONCEAL
5492 /* Get rid of the boguscols now, we want to draw until the right
5493 * edge for 'cursorcolumn'. */
5494 col -= boguscols;
5495 boguscols = 0;
5496#endif
Bram Moolenaar1a384422010-07-14 19:53:30 +02005497
5498 if (draw_color_col)
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005499 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005500
5501 if (((wp->w_p_cuc
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005502 && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
5503 && (int)wp->w_virtcol <
Bram Moolenaar02631462017-09-22 15:20:32 +02005504 wp->w_width * (row - startrow + 1) + v
Bram Moolenaar1a384422010-07-14 19:53:30 +02005505 && lnum != wp->w_cursor.lnum)
5506 || draw_color_col)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005507# ifdef FEAT_RIGHTLEFT
5508 && !wp->w_p_rl
5509# endif
5510 )
5511 {
Bram Moolenaar1a384422010-07-14 19:53:30 +02005512 int rightmost_vcol = 0;
5513 int i;
5514
5515 if (wp->w_p_cuc)
5516 rightmost_vcol = wp->w_virtcol;
5517 if (draw_color_col)
5518 /* determine rightmost colorcolumn to possibly draw */
5519 for (i = 0; color_cols[i] >= 0; ++i)
5520 if (rightmost_vcol < color_cols[i])
5521 rightmost_vcol = color_cols[i];
5522
Bram Moolenaar02631462017-09-22 15:20:32 +02005523 while (col < wp->w_width)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005524 {
5525 ScreenLines[off] = ' ';
5526#ifdef FEAT_MBYTE
5527 if (enc_utf8)
5528 ScreenLinesUC[off] = 0;
5529#endif
5530 ++col;
Bram Moolenaar973bd472010-07-20 11:29:07 +02005531 if (draw_color_col)
5532 draw_color_col = advance_color_col(VCOL_HLC,
5533 &color_cols);
5534
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005535 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol)
Bram Moolenaar8820b482017-03-16 17:23:31 +01005536 ScreenAttrs[off++] = HL_ATTR(HLF_CUC);
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005537 else if (draw_color_col && VCOL_HLC == *color_cols)
Bram Moolenaar8820b482017-03-16 17:23:31 +01005538 ScreenAttrs[off++] = HL_ATTR(HLF_MC);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005539 else
5540 ScreenAttrs[off++] = 0;
5541
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005542 if (VCOL_HLC >= rightmost_vcol)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005543 break;
Bram Moolenaar1a384422010-07-14 19:53:30 +02005544
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005545 ++vcol;
5546 }
5547 }
5548#endif
5549
Bram Moolenaar53f81742017-09-22 14:35:51 +02005550 screen_line(screen_row, wp->w_wincol, col,
Bram Moolenaar02631462017-09-22 15:20:32 +02005551 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005552 row++;
5553
5554 /*
5555 * Update w_cline_height and w_cline_folded if the cursor line was
5556 * updated (saves a call to plines() later).
5557 */
5558 if (wp == curwin && lnum == curwin->w_cursor.lnum)
5559 {
5560 curwin->w_cline_row = startrow;
5561 curwin->w_cline_height = row - startrow;
5562#ifdef FEAT_FOLDING
5563 curwin->w_cline_folded = FALSE;
5564#endif
5565 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
5566 }
5567
5568 break;
5569 }
5570
5571 /* line continues beyond line end */
5572 if (lcs_ext
5573 && !wp->w_p_wrap
5574#ifdef FEAT_DIFF
5575 && filler_todo <= 0
5576#endif
5577 && (
5578#ifdef FEAT_RIGHTLEFT
5579 wp->w_p_rl ? col == 0 :
5580#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005581 col == wp->w_width - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005582 && (*ptr != NUL
Bram Moolenaar5bbc21d2008-03-09 13:30:56 +00005583 || (wp->w_p_list && lcs_eol_one > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005584 || (n_extra && (c_extra != NUL || *p_extra != NUL))))
5585 {
5586 c = lcs_ext;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005587 char_attr = HL_ATTR(HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005588#ifdef FEAT_MBYTE
5589 mb_c = c;
Bram Moolenaarace95982017-03-29 17:30:27 +02005590 if (enc_utf8 && utf_char2len(c) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005591 {
5592 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005593 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005594 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005595 }
5596 else
5597 mb_utf8 = FALSE;
5598#endif
5599 }
5600
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005601#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02005602 /* advance to the next 'colorcolumn' */
5603 if (draw_color_col)
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005604 draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
Bram Moolenaar1a384422010-07-14 19:53:30 +02005605
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005606 /* Highlight the cursor column if 'cursorcolumn' is set. But don't
Bram Moolenaar1a384422010-07-14 19:53:30 +02005607 * highlight the cursor position itself.
5608 * Also highlight the 'colorcolumn' if it is different than
5609 * 'cursorcolumn' */
5610 vcol_save_attr = -1;
Bram Moolenaar774e5a92017-06-25 18:03:37 +02005611 if (draw_state == WL_LINE && !lnum_in_visual_area
5612 && search_attr == 0 && area_attr == 0)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005613 {
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005614 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
Bram Moolenaar1a384422010-07-14 19:53:30 +02005615 && lnum != wp->w_cursor.lnum)
5616 {
5617 vcol_save_attr = char_attr;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005618 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC));
Bram Moolenaar1a384422010-07-14 19:53:30 +02005619 }
Bram Moolenaard160c342010-07-18 23:30:34 +02005620 else if (draw_color_col && VCOL_HLC == *color_cols)
Bram Moolenaar1a384422010-07-14 19:53:30 +02005621 {
5622 vcol_save_attr = char_attr;
Bram Moolenaar8820b482017-03-16 17:23:31 +01005623 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC));
Bram Moolenaar1a384422010-07-14 19:53:30 +02005624 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005625 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005626#endif
5627
Bram Moolenaar071d4272004-06-13 20:20:40 +00005628 /*
5629 * Store character to be displayed.
5630 * Skip characters that are left of the screen for 'nowrap'.
5631 */
5632 vcol_prev = vcol;
5633 if (draw_state < WL_LINE || n_skip <= 0)
5634 {
5635 /*
5636 * Store the character.
5637 */
5638#if defined(FEAT_RIGHTLEFT) && defined(FEAT_MBYTE)
5639 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
5640 {
5641 /* A double-wide character is: put first halve in left cell. */
5642 --off;
5643 --col;
5644 }
5645#endif
5646 ScreenLines[off] = c;
5647#ifdef FEAT_MBYTE
5648 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaar990bb662010-02-03 15:48:04 +01005649 {
5650 if ((mb_c & 0xff00) == 0x8e00)
5651 ScreenLines[off] = 0x8e;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652 ScreenLines2[off] = mb_c & 0xff;
Bram Moolenaar990bb662010-02-03 15:48:04 +01005653 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005654 else if (enc_utf8)
5655 {
5656 if (mb_utf8)
5657 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00005658 int i;
5659
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660 ScreenLinesUC[off] = mb_c;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005661 if ((c & 0xff) == 0)
5662 ScreenLines[off] = 0x80; /* avoid storing zero */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005663 for (i = 0; i < Screen_mco; ++i)
5664 {
5665 ScreenLinesC[i][off] = u8cc[i];
5666 if (u8cc[i] == 0)
5667 break;
5668 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005669 }
5670 else
5671 ScreenLinesUC[off] = 0;
5672 }
5673 if (multi_attr)
5674 {
5675 ScreenAttrs[off] = multi_attr;
5676 multi_attr = 0;
5677 }
5678 else
5679#endif
5680 ScreenAttrs[off] = char_attr;
5681
5682#ifdef FEAT_MBYTE
5683 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5684 {
5685 /* Need to fill two screen columns. */
5686 ++off;
5687 ++col;
5688 if (enc_utf8)
5689 /* UTF-8: Put a 0 in the second screen char. */
5690 ScreenLines[off] = 0;
5691 else
5692 /* DBCS: Put second byte in the second screen char. */
5693 ScreenLines[off] = mb_c & 0xff;
Bram Moolenaar32a214e2015-12-03 14:29:02 +01005694 if (draw_state > WL_NR
5695#ifdef FEAT_DIFF
5696 && filler_todo <= 0
5697#endif
5698 )
5699 ++vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005700 /* When "tocol" is halfway a character, set it to the end of
5701 * the character, otherwise highlighting won't stop. */
5702 if (tocol == vcol)
5703 ++tocol;
5704#ifdef FEAT_RIGHTLEFT
5705 if (wp->w_p_rl)
5706 {
5707 /* now it's time to backup one cell */
5708 --off;
5709 --col;
5710 }
5711#endif
5712 }
5713#endif
5714#ifdef FEAT_RIGHTLEFT
5715 if (wp->w_p_rl)
5716 {
5717 --off;
5718 --col;
5719 }
5720 else
5721#endif
5722 {
5723 ++off;
5724 ++col;
5725 }
5726 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02005727#ifdef FEAT_CONCEAL
Bram Moolenaarf5963f72010-07-23 22:10:27 +02005728 else if (wp->w_p_cole > 0 && is_concealing)
Bram Moolenaar860cae12010-06-05 23:22:07 +02005729 {
5730 --n_skip;
Bram Moolenaarac550fd2010-07-18 13:55:02 +02005731 ++vcol_off;
5732 if (n_extra > 0)
5733 vcol_off += n_extra;
Bram Moolenaar860cae12010-06-05 23:22:07 +02005734 if (wp->w_p_wrap)
5735 {
5736 /*
5737 * Special voodoo required if 'wrap' is on.
5738 *
5739 * Advance the column indicator to force the line
5740 * drawing to wrap early. This will make the line
5741 * take up the same screen space when parts are concealed,
5742 * so that cursor line computations aren't messed up.
5743 *
5744 * To avoid the fictitious advance of 'col' causing
5745 * trailing junk to be written out of the screen line
5746 * we are building, 'boguscols' keeps track of the number
5747 * of bad columns we have advanced.
5748 */
5749 if (n_extra > 0)
5750 {
5751 vcol += n_extra;
5752# ifdef FEAT_RIGHTLEFT
5753 if (wp->w_p_rl)
5754 {
5755 col -= n_extra;
5756 boguscols -= n_extra;
5757 }
5758 else
5759# endif
5760 {
5761 col += n_extra;
5762 boguscols += n_extra;
5763 }
5764 n_extra = 0;
5765 n_attr = 0;
5766 }
5767
5768
5769# ifdef FEAT_MBYTE
5770 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5771 {
5772 /* Need to fill two screen columns. */
5773# ifdef FEAT_RIGHTLEFT
5774 if (wp->w_p_rl)
5775 {
5776 --boguscols;
5777 --col;
5778 }
5779 else
5780# endif
5781 {
5782 ++boguscols;
5783 ++col;
5784 }
5785 }
5786# endif
5787
5788# ifdef FEAT_RIGHTLEFT
5789 if (wp->w_p_rl)
5790 {
5791 --boguscols;
5792 --col;
5793 }
5794 else
5795# endif
5796 {
5797 ++boguscols;
5798 ++col;
5799 }
5800 }
5801 else
5802 {
5803 if (n_extra > 0)
5804 {
5805 vcol += n_extra;
5806 n_extra = 0;
5807 n_attr = 0;
5808 }
5809 }
5810
5811 }
5812#endif /* FEAT_CONCEAL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005813 else
5814 --n_skip;
5815
Bram Moolenaar64486672010-05-16 15:46:46 +02005816 /* Only advance the "vcol" when after the 'number' or 'relativenumber'
5817 * column. */
Bram Moolenaar1b636fa2009-03-18 15:28:08 +00005818 if (draw_state > WL_NR
Bram Moolenaar071d4272004-06-13 20:20:40 +00005819#ifdef FEAT_DIFF
5820 && filler_todo <= 0
5821#endif
5822 )
5823 ++vcol;
5824
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005825#ifdef FEAT_SYN_HL
5826 if (vcol_save_attr >= 0)
5827 char_attr = vcol_save_attr;
5828#endif
5829
Bram Moolenaar071d4272004-06-13 20:20:40 +00005830 /* restore attributes after "predeces" in 'listchars' */
5831 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
5832 char_attr = saved_attr3;
5833
5834 /* restore attributes after last 'listchars' or 'number' char */
5835 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
5836 char_attr = saved_attr2;
5837
5838 /*
5839 * At end of screen line and there is more to come: Display the line
Bram Moolenaar367329b2007-08-30 11:53:22 +00005840 * so far. If there is no more to display it is caught above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005841 */
5842 if ((
5843#ifdef FEAT_RIGHTLEFT
5844 wp->w_p_rl ? (col < 0) :
5845#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005846 (col >= wp->w_width))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005847 && (*ptr != NUL
5848#ifdef FEAT_DIFF
5849 || filler_todo > 0
5850#endif
Bram Moolenaare9d4b582011-03-22 13:29:24 +01005851 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005852 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
5853 )
5854 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02005855#ifdef FEAT_CONCEAL
Bram Moolenaar53f81742017-09-22 14:35:51 +02005856 screen_line(screen_row, wp->w_wincol, col - boguscols,
Bram Moolenaar02631462017-09-22 15:20:32 +02005857 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar860cae12010-06-05 23:22:07 +02005858 boguscols = 0;
5859#else
Bram Moolenaar53f81742017-09-22 14:35:51 +02005860 screen_line(screen_row, wp->w_wincol, col,
Bram Moolenaar02631462017-09-22 15:20:32 +02005861 (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
Bram Moolenaar860cae12010-06-05 23:22:07 +02005862#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863 ++row;
5864 ++screen_row;
5865
5866 /* When not wrapping and finished diff lines, or when displayed
5867 * '$' and highlighting until last column, break here. */
5868 if ((!wp->w_p_wrap
5869#ifdef FEAT_DIFF
5870 && filler_todo <= 0
5871#endif
5872 ) || lcs_eol_one == -1)
5873 break;
5874
5875 /* When the window is too narrow draw all "@" lines. */
5876 if (draw_state != WL_LINE
5877#ifdef FEAT_DIFF
5878 && filler_todo <= 0
5879#endif
5880 )
5881 {
5882 win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883 draw_vsep_win(wp, row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005884 row = endrow;
5885 }
5886
5887 /* When line got too long for screen break here. */
5888 if (row == endrow)
5889 {
5890 ++row;
5891 break;
5892 }
5893
5894 if (screen_cur_row == screen_row - 1
5895#ifdef FEAT_DIFF
5896 && filler_todo <= 0
5897#endif
Bram Moolenaar02631462017-09-22 15:20:32 +02005898 && wp->w_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005899 {
5900 /* Remember that the line wraps, used for modeless copy. */
5901 LineWraps[screen_row - 1] = TRUE;
5902
5903 /*
5904 * Special trick to make copy/paste of wrapped lines work with
5905 * xterm/screen: write an extra character beyond the end of
5906 * the line. This will work with all terminal types
5907 * (regardless of the xn,am settings).
5908 * Only do this on a fast tty.
5909 * Only do this if the cursor is on the current line
5910 * (something has been written in it).
5911 * Don't do this for the GUI.
5912 * Don't do this for double-width characters.
5913 * Don't do this for a window not at the right screen border.
5914 */
5915 if (p_tf
5916#ifdef FEAT_GUI
5917 && !gui.in_use
5918#endif
5919#ifdef FEAT_MBYTE
5920 && !(has_mbyte
Bram Moolenaar367329b2007-08-30 11:53:22 +00005921 && ((*mb_off2cells)(LineOffset[screen_row],
5922 LineOffset[screen_row] + screen_Columns)
5923 == 2
Bram Moolenaar071d4272004-06-13 20:20:40 +00005924 || (*mb_off2cells)(LineOffset[screen_row - 1]
Bram Moolenaar367329b2007-08-30 11:53:22 +00005925 + (int)Columns - 2,
5926 LineOffset[screen_row] + screen_Columns)
5927 == 2))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005928#endif
5929 )
5930 {
5931 /* First make sure we are at the end of the screen line,
5932 * then output the same character again to let the
5933 * terminal know about the wrap. If the terminal doesn't
5934 * auto-wrap, we overwrite the character. */
Bram Moolenaar02631462017-09-22 15:20:32 +02005935 if (screen_cur_col != wp->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005936 screen_char(LineOffset[screen_row - 1]
5937 + (unsigned)Columns - 1,
5938 screen_row - 1, (int)(Columns - 1));
5939
5940#ifdef FEAT_MBYTE
5941 /* When there is a multi-byte character, just output a
5942 * space to keep it simple. */
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00005943 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
5944 screen_row - 1] + (Columns - 1)]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005945 out_char(' ');
5946 else
5947#endif
5948 out_char(ScreenLines[LineOffset[screen_row - 1]
5949 + (Columns - 1)]);
5950 /* force a redraw of the first char on the next line */
5951 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
5952 screen_start(); /* don't know where cursor is now */
5953 }
5954 }
5955
5956 col = 0;
5957 off = (unsigned)(current_ScreenLine - ScreenLines);
5958#ifdef FEAT_RIGHTLEFT
5959 if (wp->w_p_rl)
5960 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005961 col = wp->w_width - 1; /* col is not used if breaking! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005962 off += col;
5963 }
5964#endif
5965
5966 /* reset the drawing state for the start of a wrapped line */
5967 draw_state = WL_START;
5968 saved_n_extra = n_extra;
5969 saved_p_extra = p_extra;
5970 saved_c_extra = c_extra;
5971 saved_char_attr = char_attr;
5972 n_extra = 0;
5973 lcs_prec_todo = lcs_prec;
5974#ifdef FEAT_LINEBREAK
5975# ifdef FEAT_DIFF
5976 if (filler_todo <= 0)
5977# endif
5978 need_showbreak = TRUE;
5979#endif
5980#ifdef FEAT_DIFF
5981 --filler_todo;
5982 /* When the filler lines are actually below the last line of the
5983 * file, don't draw the line itself, break here. */
5984 if (filler_todo == 0 && wp->w_botfill)
5985 break;
5986#endif
5987 }
5988
5989 } /* for every character in the line */
5990
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005991#ifdef FEAT_SPELL
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00005992 /* After an empty line check first word for capital. */
5993 if (*skipwhite(line) == NUL)
5994 {
5995 capcol_lnum = lnum + 1;
5996 cap_col = 0;
5997 }
5998#endif
5999
Bram Moolenaarb031c4e2017-01-24 20:14:48 +01006000 vim_free(p_extra_free);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006001 return row;
6002}
6003
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006004#ifdef FEAT_MBYTE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01006005static int comp_char_differs(int, int);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006006
6007/*
6008 * Return if the composing characters at "off_from" and "off_to" differ.
Bram Moolenaar70c49c12010-03-23 15:36:35 +01006009 * Only to be used when ScreenLinesUC[off_from] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006010 */
6011 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006012comp_char_differs(int off_from, int off_to)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006013{
6014 int i;
6015
6016 for (i = 0; i < Screen_mco; ++i)
6017 {
6018 if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
6019 return TRUE;
6020 if (ScreenLinesC[i][off_from] == 0)
6021 break;
6022 }
6023 return FALSE;
6024}
6025#endif
6026
Bram Moolenaar071d4272004-06-13 20:20:40 +00006027/*
6028 * Check whether the given character needs redrawing:
6029 * - the (first byte of the) character is different
6030 * - the attributes are different
6031 * - the character is multi-byte and the next byte is different
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00006032 * - the character is two cells wide and the second cell differs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006033 */
6034 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006035char_needs_redraw(int off_from, int off_to, int cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006036{
6037 if (cols > 0
6038 && ((ScreenLines[off_from] != ScreenLines[off_to]
6039 || ScreenAttrs[off_from] != ScreenAttrs[off_to])
6040
6041#ifdef FEAT_MBYTE
6042 || (enc_dbcs != 0
6043 && MB_BYTE2LEN(ScreenLines[off_from]) > 1
6044 && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
6045 ? ScreenLines2[off_from] != ScreenLines2[off_to]
6046 : (cols > 1 && ScreenLines[off_from + 1]
6047 != ScreenLines[off_to + 1])))
6048 || (enc_utf8
6049 && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
6050 || (ScreenLinesUC[off_from] != 0
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00006051 && comp_char_differs(off_from, off_to))
Bram Moolenaar451cf632012-08-23 18:58:14 +02006052 || ((*mb_off2cells)(off_from, off_from + cols) > 1
6053 && ScreenLines[off_from + 1]
6054 != ScreenLines[off_to + 1])))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006055#endif
6056 ))
6057 return TRUE;
6058 return FALSE;
6059}
6060
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006061#if defined(FEAT_TERMINAL) || defined(PROTO)
6062/*
6063 * Return the index in ScreenLines[] for the current screen line.
6064 */
6065 int
6066screen_get_current_line_off()
6067{
6068 return (int)(current_ScreenLine - ScreenLines);
6069}
6070#endif
6071
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072/*
6073 * Move one "cooked" screen line to the screen, but only the characters that
6074 * have actually changed. Handle insert/delete character.
6075 * "coloff" gives the first column on the screen for this line.
6076 * "endcol" gives the columns where valid characters are.
6077 * "clear_width" is the width of the window. It's > 0 if the rest of the line
6078 * needs to be cleared, negative otherwise.
6079 * "rlflag" is TRUE in a rightleft window:
6080 * When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
6081 * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
6082 */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006083 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006084screen_line(
6085 int row,
6086 int coloff,
6087 int endcol,
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006088 int clear_width,
6089 int rlflag UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006090{
6091 unsigned off_from;
6092 unsigned off_to;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006093#ifdef FEAT_MBYTE
6094 unsigned max_off_from;
6095 unsigned max_off_to;
6096#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006097 int col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006098 int hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006099 int force = FALSE; /* force update rest of the line */
6100 int redraw_this /* bool: does character need redraw? */
6101#ifdef FEAT_GUI
6102 = TRUE /* For GUI when while-loop empty */
6103#endif
6104 ;
6105 int redraw_next; /* redraw_this for next character */
6106#ifdef FEAT_MBYTE
6107 int clear_next = FALSE;
6108 int char_cells; /* 1: normal char */
6109 /* 2: occupies two display cells */
6110# define CHAR_CELLS char_cells
6111#else
6112# define CHAR_CELLS 1
6113#endif
6114
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01006115 /* Check for illegal row and col, just in case. */
6116 if (row >= Rows)
6117 row = Rows - 1;
6118 if (endcol > Columns)
6119 endcol = Columns;
6120
Bram Moolenaar071d4272004-06-13 20:20:40 +00006121# ifdef FEAT_CLIPBOARD
6122 clip_may_clear_selection(row, row);
6123# endif
6124
6125 off_from = (unsigned)(current_ScreenLine - ScreenLines);
6126 off_to = LineOffset[row] + coloff;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006127#ifdef FEAT_MBYTE
6128 max_off_from = off_from + screen_Columns;
6129 max_off_to = LineOffset[row] + screen_Columns;
6130#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006131
6132#ifdef FEAT_RIGHTLEFT
6133 if (rlflag)
6134 {
6135 /* Clear rest first, because it's left of the text. */
6136 if (clear_width > 0)
6137 {
6138 while (col <= endcol && ScreenLines[off_to] == ' '
6139 && ScreenAttrs[off_to] == 0
6140# ifdef FEAT_MBYTE
6141 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
6142# endif
6143 )
6144 {
6145 ++off_to;
6146 ++col;
6147 }
6148 if (col <= endcol)
6149 screen_fill(row, row + 1, col + coloff,
6150 endcol + coloff + 1, ' ', ' ', 0);
6151 }
6152 col = endcol + 1;
6153 off_to = LineOffset[row] + col + coloff;
6154 off_from += col;
6155 endcol = (clear_width > 0 ? clear_width : -clear_width);
6156 }
6157#endif /* FEAT_RIGHTLEFT */
6158
6159 redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
6160
6161 while (col < endcol)
6162 {
6163#ifdef FEAT_MBYTE
6164 if (has_mbyte && (col + 1 < endcol))
Bram Moolenaar367329b2007-08-30 11:53:22 +00006165 char_cells = (*mb_off2cells)(off_from, max_off_from);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006166 else
6167 char_cells = 1;
6168#endif
6169
6170 redraw_this = redraw_next;
6171 redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
6172 off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
6173
6174#ifdef FEAT_GUI
6175 /* If the next character was bold, then redraw the current character to
6176 * remove any pixels that might have spilt over into us. This only
6177 * happens in the GUI.
6178 */
6179 if (redraw_next && gui.in_use)
6180 {
6181 hl = ScreenAttrs[off_to + CHAR_CELLS];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00006182 if (hl > HL_ALL)
6183 hl = syn_attr2attr(hl);
6184 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006185 redraw_this = TRUE;
6186 }
6187#endif
6188
6189 if (redraw_this)
6190 {
6191 /*
6192 * Special handling when 'xs' termcap flag set (hpterm):
6193 * Attributes for characters are stored at the position where the
6194 * cursor is when writing the highlighting code. The
6195 * start-highlighting code must be written with the cursor on the
6196 * first highlighted character. The stop-highlighting code must
6197 * be written with the cursor just after the last highlighted
6198 * character.
6199 * Overwriting a character doesn't remove it's highlighting. Need
6200 * to clear the rest of the line, and force redrawing it
6201 * completely.
6202 */
6203 if ( p_wiv
6204 && !force
6205#ifdef FEAT_GUI
6206 && !gui.in_use
6207#endif
6208 && ScreenAttrs[off_to] != 0
6209 && ScreenAttrs[off_from] != ScreenAttrs[off_to])
6210 {
6211 /*
6212 * Need to remove highlighting attributes here.
6213 */
6214 windgoto(row, col + coloff);
6215 out_str(T_CE); /* clear rest of this screen line */
6216 screen_start(); /* don't know where cursor is now */
6217 force = TRUE; /* force redraw of rest of the line */
6218 redraw_next = TRUE; /* or else next char would miss out */
6219
6220 /*
6221 * If the previous character was highlighted, need to stop
6222 * highlighting at this character.
6223 */
6224 if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
6225 {
6226 screen_attr = ScreenAttrs[off_to - 1];
6227 term_windgoto(row, col + coloff);
6228 screen_stop_highlight();
6229 }
6230 else
6231 screen_attr = 0; /* highlighting has stopped */
6232 }
6233#ifdef FEAT_MBYTE
6234 if (enc_dbcs != 0)
6235 {
6236 /* Check if overwriting a double-byte with a single-byte or
6237 * the other way around requires another character to be
6238 * redrawn. For UTF-8 this isn't needed, because comparing
6239 * ScreenLinesUC[] is sufficient. */
6240 if (char_cells == 1
6241 && col + 1 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00006242 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006243 {
6244 /* Writing a single-cell character over a double-cell
6245 * character: need to redraw the next cell. */
6246 ScreenLines[off_to + 1] = 0;
6247 redraw_next = TRUE;
6248 }
6249 else if (char_cells == 2
6250 && col + 2 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00006251 && (*mb_off2cells)(off_to, max_off_to) == 1
6252 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006253 {
6254 /* Writing the second half of a double-cell character over
6255 * a double-cell character: need to redraw the second
6256 * cell. */
6257 ScreenLines[off_to + 2] = 0;
6258 redraw_next = TRUE;
6259 }
6260
6261 if (enc_dbcs == DBCS_JPNU)
6262 ScreenLines2[off_to] = ScreenLines2[off_from];
6263 }
6264 /* When writing a single-width character over a double-width
6265 * character and at the end of the redrawn text, need to clear out
6266 * the right halve of the old character.
6267 * Also required when writing the right halve of a double-width
6268 * char over the left halve of an existing one. */
6269 if (has_mbyte && col + char_cells == endcol
6270 && ((char_cells == 1
Bram Moolenaar367329b2007-08-30 11:53:22 +00006271 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272 || (char_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00006273 && (*mb_off2cells)(off_to, max_off_to) == 1
6274 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275 clear_next = TRUE;
6276#endif
6277
6278 ScreenLines[off_to] = ScreenLines[off_from];
6279#ifdef FEAT_MBYTE
6280 if (enc_utf8)
6281 {
6282 ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
6283 if (ScreenLinesUC[off_from] != 0)
6284 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006285 int i;
6286
6287 for (i = 0; i < Screen_mco; ++i)
6288 ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006289 }
6290 }
6291 if (char_cells == 2)
6292 ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
6293#endif
6294
6295#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006296 /* The bold trick makes a single column of pixels appear in the
6297 * next character. When a bold character is removed, the next
Bram Moolenaar071d4272004-06-13 20:20:40 +00006298 * character should be redrawn too. This happens for our own GUI
6299 * and for some xterms. */
6300 if (
6301# ifdef FEAT_GUI
6302 gui.in_use
6303# endif
6304# if defined(FEAT_GUI) && defined(UNIX)
6305 ||
6306# endif
6307# ifdef UNIX
6308 term_is_xterm
6309# endif
6310 )
6311 {
6312 hl = ScreenAttrs[off_to];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00006313 if (hl > HL_ALL)
6314 hl = syn_attr2attr(hl);
6315 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006316 redraw_next = TRUE;
6317 }
6318#endif
6319 ScreenAttrs[off_to] = ScreenAttrs[off_from];
6320#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00006321 /* For simplicity set the attributes of second half of a
6322 * double-wide character equal to the first half. */
6323 if (char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006324 ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
Bram Moolenaar910f66f2006-04-05 20:41:53 +00006325
6326 if (enc_dbcs != 0 && char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006327 screen_char_2(off_to, row, col + coloff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006328 else
6329#endif
6330 screen_char(off_to, row, col + coloff);
6331 }
6332 else if ( p_wiv
6333#ifdef FEAT_GUI
6334 && !gui.in_use
6335#endif
6336 && col + coloff > 0)
6337 {
6338 if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
6339 {
6340 /*
6341 * Don't output stop-highlight when moving the cursor, it will
6342 * stop the highlighting when it should continue.
6343 */
6344 screen_attr = 0;
6345 }
6346 else if (screen_attr != 0)
6347 screen_stop_highlight();
6348 }
6349
6350 off_to += CHAR_CELLS;
6351 off_from += CHAR_CELLS;
6352 col += CHAR_CELLS;
6353 }
6354
6355#ifdef FEAT_MBYTE
6356 if (clear_next)
6357 {
6358 /* Clear the second half of a double-wide character of which the left
6359 * half was overwritten with a single-wide character. */
6360 ScreenLines[off_to] = ' ';
6361 if (enc_utf8)
6362 ScreenLinesUC[off_to] = 0;
6363 screen_char(off_to, row, col + coloff);
6364 }
6365#endif
6366
6367 if (clear_width > 0
6368#ifdef FEAT_RIGHTLEFT
6369 && !rlflag
6370#endif
6371 )
6372 {
6373#ifdef FEAT_GUI
6374 int startCol = col;
6375#endif
6376
6377 /* blank out the rest of the line */
6378 while (col < clear_width && ScreenLines[off_to] == ' '
6379 && ScreenAttrs[off_to] == 0
6380#ifdef FEAT_MBYTE
6381 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
6382#endif
6383 )
6384 {
6385 ++off_to;
6386 ++col;
6387 }
6388 if (col < clear_width)
6389 {
6390#ifdef FEAT_GUI
6391 /*
6392 * In the GUI, clearing the rest of the line may leave pixels
6393 * behind if the first character cleared was bold. Some bold
6394 * fonts spill over the left. In this case we redraw the previous
6395 * character too. If we didn't skip any blanks above, then we
6396 * only redraw if the character wasn't already redrawn anyway.
6397 */
Bram Moolenaar9c697322006-10-09 20:11:17 +00006398 if (gui.in_use && (col > startCol || !redraw_this))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006399 {
6400 hl = ScreenAttrs[off_to];
6401 if (hl > HL_ALL || (hl & HL_BOLD))
Bram Moolenaar9c697322006-10-09 20:11:17 +00006402 {
6403 int prev_cells = 1;
6404# ifdef FEAT_MBYTE
6405 if (enc_utf8)
6406 /* for utf-8, ScreenLines[char_offset + 1] == 0 means
6407 * that its width is 2. */
6408 prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
6409 else if (enc_dbcs != 0)
6410 {
6411 /* find previous character by counting from first
6412 * column and get its width. */
6413 unsigned off = LineOffset[row];
Bram Moolenaar367329b2007-08-30 11:53:22 +00006414 unsigned max_off = LineOffset[row] + screen_Columns;
Bram Moolenaar9c697322006-10-09 20:11:17 +00006415
6416 while (off < off_to)
6417 {
Bram Moolenaar367329b2007-08-30 11:53:22 +00006418 prev_cells = (*mb_off2cells)(off, max_off);
Bram Moolenaar9c697322006-10-09 20:11:17 +00006419 off += prev_cells;
6420 }
6421 }
6422
6423 if (enc_dbcs != 0 && prev_cells > 1)
6424 screen_char_2(off_to - prev_cells, row,
6425 col + coloff - prev_cells);
6426 else
6427# endif
6428 screen_char(off_to - prev_cells, row,
6429 col + coloff - prev_cells);
6430 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431 }
6432#endif
6433 screen_fill(row, row + 1, col + coloff, clear_width + coloff,
6434 ' ', ' ', 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435 off_to += clear_width - col;
6436 col = clear_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006437 }
6438 }
6439
6440 if (clear_width > 0)
6441 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006442 /* For a window that's left of another, draw the separator char. */
6443 if (col + coloff < Columns)
6444 {
6445 int c;
6446
6447 c = fillchar_vsep(&hl);
Bram Moolenaarc60c4f62015-01-07 19:04:28 +01006448 if (ScreenLines[off_to] != (schar_T)c
Bram Moolenaar4033c552017-09-16 20:54:51 +02006449#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006450 || (enc_utf8 && (int)ScreenLinesUC[off_to]
6451 != (c >= 0x80 ? c : 0))
Bram Moolenaar4033c552017-09-16 20:54:51 +02006452#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006453 || ScreenAttrs[off_to] != hl)
6454 {
6455 ScreenLines[off_to] = c;
6456 ScreenAttrs[off_to] = hl;
Bram Moolenaar4033c552017-09-16 20:54:51 +02006457#ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00006458 if (enc_utf8)
6459 {
6460 if (c >= 0x80)
6461 {
6462 ScreenLinesUC[off_to] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006463 ScreenLinesC[0][off_to] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006464 }
6465 else
6466 ScreenLinesUC[off_to] = 0;
6467 }
Bram Moolenaar4033c552017-09-16 20:54:51 +02006468#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006469 screen_char(off_to, row, col + coloff);
6470 }
6471 }
6472 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006473 LineWraps[row] = FALSE;
6474 }
6475}
6476
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006477#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006478/*
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006479 * Mirror text "str" for right-left displaying.
6480 * Only works for single-byte characters (e.g., numbers).
Bram Moolenaar071d4272004-06-13 20:20:40 +00006481 */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006482 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006483rl_mirror(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006484{
6485 char_u *p1, *p2;
6486 int t;
6487
6488 for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
6489 {
6490 t = *p1;
6491 *p1 = *p2;
6492 *p2 = t;
6493 }
6494}
6495#endif
6496
Bram Moolenaar071d4272004-06-13 20:20:40 +00006497/*
6498 * mark all status lines for redraw; used after first :cd
6499 */
6500 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006501status_redraw_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006502{
6503 win_T *wp;
6504
Bram Moolenaar29323592016-07-24 22:04:11 +02006505 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006506 if (wp->w_status_height)
6507 {
6508 wp->w_redr_status = TRUE;
6509 redraw_later(VALID);
6510 }
6511}
6512
6513/*
6514 * mark all status lines of the current buffer for redraw
6515 */
6516 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006517status_redraw_curbuf(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006518{
6519 win_T *wp;
6520
Bram Moolenaar29323592016-07-24 22:04:11 +02006521 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006522 if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
6523 {
6524 wp->w_redr_status = TRUE;
6525 redraw_later(VALID);
6526 }
6527}
6528
6529/*
6530 * Redraw all status lines that need to be redrawn.
6531 */
6532 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006533redraw_statuslines(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006534{
6535 win_T *wp;
6536
Bram Moolenaar29323592016-07-24 22:04:11 +02006537 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006538 if (wp->w_redr_status)
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006539 win_redr_status(wp, FALSE);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00006540 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006541 draw_tabline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006542}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006543
Bram Moolenaar4033c552017-09-16 20:54:51 +02006544#if defined(FEAT_WILDMENU) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006545/*
6546 * Redraw all status lines at the bottom of frame "frp".
6547 */
6548 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006549win_redraw_last_status(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006550{
6551 if (frp->fr_layout == FR_LEAF)
6552 frp->fr_win->w_redr_status = TRUE;
6553 else if (frp->fr_layout == FR_ROW)
6554 {
6555 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
6556 win_redraw_last_status(frp);
6557 }
6558 else /* frp->fr_layout == FR_COL */
6559 {
6560 frp = frp->fr_child;
6561 while (frp->fr_next != NULL)
6562 frp = frp->fr_next;
6563 win_redraw_last_status(frp);
6564 }
6565}
6566#endif
6567
Bram Moolenaar071d4272004-06-13 20:20:40 +00006568/*
6569 * Draw the verticap separator right of window "wp" starting with line "row".
6570 */
6571 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01006572draw_vsep_win(win_T *wp, int row)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006573{
6574 int hl;
6575 int c;
6576
6577 if (wp->w_vsep_width)
6578 {
6579 /* draw the vertical separator right of this window */
6580 c = fillchar_vsep(&hl);
6581 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
6582 W_ENDCOL(wp), W_ENDCOL(wp) + 1,
6583 c, ' ', hl);
6584 }
6585}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006586
6587#ifdef FEAT_WILDMENU
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01006588static int status_match_len(expand_T *xp, char_u *s);
6589static int skip_status_match_char(expand_T *xp, char_u *s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006590
6591/*
Bram Moolenaar367329b2007-08-30 11:53:22 +00006592 * Get the length of an item as it will be shown in the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006593 */
6594 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006595status_match_len(expand_T *xp, char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006596{
6597 int len = 0;
6598
6599#ifdef FEAT_MENU
6600 int emenu = (xp->xp_context == EXPAND_MENUS
6601 || xp->xp_context == EXPAND_MENUNAMES);
6602
6603 /* Check for menu separators - replace with '|'. */
6604 if (emenu && menu_is_separator(s))
6605 return 1;
6606#endif
6607
6608 while (*s != NUL)
6609 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006610 s += skip_status_match_char(xp, s);
Bram Moolenaar81695252004-12-29 20:58:21 +00006611 len += ptr2cells(s);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006612 MB_PTR_ADV(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006613 }
6614
6615 return len;
6616}
6617
6618/*
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006619 * Return the number of characters that should be skipped in a status match.
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006620 * These are backslashes used for escaping. Do show backslashes in help tags.
6621 */
6622 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006623skip_status_match_char(expand_T *xp, char_u *s)
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006624{
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006625 if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006626#ifdef FEAT_MENU
6627 || ((xp->xp_context == EXPAND_MENUS
6628 || xp->xp_context == EXPAND_MENUNAMES)
6629 && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
6630#endif
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006631 )
6632 {
6633#ifndef BACKSLASH_IN_FILENAME
6634 if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
6635 return 2;
6636#endif
6637 return 1;
6638 }
6639 return 0;
Bram Moolenaar35c54e52005-05-20 21:25:31 +00006640}
6641
6642/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006643 * Show wildchar matches in the status line.
6644 * Show at least the "match" item.
6645 * We start at item 'first_match' in the list and show all matches that fit.
6646 *
6647 * If inversion is possible we use it. Else '=' characters are used.
6648 */
6649 void
Bram Moolenaar05540972016-01-30 20:31:25 +01006650win_redr_status_matches(
6651 expand_T *xp,
6652 int num_matches,
6653 char_u **matches, /* list of matches */
6654 int match,
6655 int showtail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006656{
6657#define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
6658 int row;
6659 char_u *buf;
6660 int len;
Bram Moolenaar367329b2007-08-30 11:53:22 +00006661 int clen; /* length in screen cells */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006662 int fillchar;
6663 int attr;
6664 int i;
6665 int highlight = TRUE;
6666 char_u *selstart = NULL;
6667 int selstart_col = 0;
6668 char_u *selend = NULL;
6669 static int first_match = 0;
6670 int add_left = FALSE;
6671 char_u *s;
6672#ifdef FEAT_MENU
6673 int emenu;
6674#endif
6675#if defined(FEAT_MBYTE) || defined(FEAT_MENU)
6676 int l;
6677#endif
6678
6679 if (matches == NULL) /* interrupted completion? */
6680 return;
6681
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006682#ifdef FEAT_MBYTE
6683 if (has_mbyte)
6684 buf = alloc((unsigned)Columns * MB_MAXBYTES + 1);
6685 else
6686#endif
6687 buf = alloc((unsigned)Columns + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006688 if (buf == NULL)
6689 return;
6690
6691 if (match == -1) /* don't show match but original text */
6692 {
6693 match = 0;
6694 highlight = FALSE;
6695 }
6696 /* count 1 for the ending ">" */
6697 clen = status_match_len(xp, L_MATCH(match)) + 3;
6698 if (match == 0)
6699 first_match = 0;
6700 else if (match < first_match)
6701 {
6702 /* jumping left, as far as we can go */
6703 first_match = match;
6704 add_left = TRUE;
6705 }
6706 else
6707 {
6708 /* check if match fits on the screen */
6709 for (i = first_match; i < match; ++i)
6710 clen += status_match_len(xp, L_MATCH(i)) + 2;
6711 if (first_match > 0)
6712 clen += 2;
6713 /* jumping right, put match at the left */
6714 if ((long)clen > Columns)
6715 {
6716 first_match = match;
6717 /* if showing the last match, we can add some on the left */
6718 clen = 2;
6719 for (i = match; i < num_matches; ++i)
6720 {
6721 clen += status_match_len(xp, L_MATCH(i)) + 2;
6722 if ((long)clen >= Columns)
6723 break;
6724 }
6725 if (i == num_matches)
6726 add_left = TRUE;
6727 }
6728 }
6729 if (add_left)
6730 while (first_match > 0)
6731 {
6732 clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
6733 if ((long)clen >= Columns)
6734 break;
6735 --first_match;
6736 }
6737
Bram Moolenaar3633cf52017-07-31 22:29:35 +02006738 fillchar = fillchar_status(&attr, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006739
6740 if (first_match == 0)
6741 {
6742 *buf = NUL;
6743 len = 0;
6744 }
6745 else
6746 {
6747 STRCPY(buf, "< ");
6748 len = 2;
6749 }
6750 clen = len;
6751
6752 i = first_match;
6753 while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
6754 {
6755 if (i == match)
6756 {
6757 selstart = buf + len;
6758 selstart_col = clen;
6759 }
6760
6761 s = L_MATCH(i);
6762 /* Check for menu separators - replace with '|' */
6763#ifdef FEAT_MENU
6764 emenu = (xp->xp_context == EXPAND_MENUS
6765 || xp->xp_context == EXPAND_MENUNAMES);
6766 if (emenu && menu_is_separator(s))
6767 {
6768 STRCPY(buf + len, transchar('|'));
6769 l = (int)STRLEN(buf + len);
6770 len += l;
6771 clen += l;
6772 }
6773 else
6774#endif
6775 for ( ; *s != NUL; ++s)
6776 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006777 s += skip_status_match_char(xp, s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006778 clen += ptr2cells(s);
6779#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006780 if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006781 {
6782 STRNCPY(buf + len, s, l);
6783 s += l - 1;
6784 len += l;
6785 }
6786 else
6787#endif
6788 {
6789 STRCPY(buf + len, transchar_byte(*s));
6790 len += (int)STRLEN(buf + len);
6791 }
6792 }
6793 if (i == match)
6794 selend = buf + len;
6795
6796 *(buf + len++) = ' ';
6797 *(buf + len++) = ' ';
6798 clen += 2;
6799 if (++i == num_matches)
6800 break;
6801 }
6802
6803 if (i != num_matches)
6804 {
6805 *(buf + len++) = '>';
6806 ++clen;
6807 }
6808
6809 buf[len] = NUL;
6810
6811 row = cmdline_row - 1;
6812 if (row >= 0)
6813 {
6814 if (wild_menu_showing == 0)
6815 {
6816 if (msg_scrolled > 0)
6817 {
6818 /* Put the wildmenu just above the command line. If there is
6819 * no room, scroll the screen one line up. */
6820 if (cmdline_row == Rows - 1)
6821 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02006822 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 ++msg_scrolled;
6824 }
6825 else
6826 {
6827 ++cmdline_row;
6828 ++row;
6829 }
6830 wild_menu_showing = WM_SCROLLED;
6831 }
6832 else
6833 {
6834 /* Create status line if needed by setting 'laststatus' to 2.
6835 * Set 'winminheight' to zero to avoid that the window is
6836 * resized. */
6837 if (lastwin->w_status_height == 0)
6838 {
6839 save_p_ls = p_ls;
6840 save_p_wmh = p_wmh;
6841 p_ls = 2;
6842 p_wmh = 0;
6843 last_status(FALSE);
6844 }
6845 wild_menu_showing = WM_SHOWN;
6846 }
6847 }
6848
6849 screen_puts(buf, row, 0, attr);
6850 if (selstart != NULL && highlight)
6851 {
6852 *selend = NUL;
Bram Moolenaar8820b482017-03-16 17:23:31 +01006853 screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006854 }
6855
6856 screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
6857 }
6858
Bram Moolenaar071d4272004-06-13 20:20:40 +00006859 win_redraw_last_status(topframe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006860 vim_free(buf);
6861}
6862#endif
6863
Bram Moolenaar071d4272004-06-13 20:20:40 +00006864/*
6865 * Redraw the status line of window wp.
6866 *
6867 * If inversion is possible we use it. Else '=' characters are used.
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006868 * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is
6869 * displayed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006870 */
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006871 static void
6872win_redr_status(win_T *wp, int ignore_pum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006873{
6874 int row;
6875 char_u *p;
6876 int len;
6877 int fillchar;
6878 int attr;
6879 int this_ru_col;
Bram Moolenaaradb09c22009-06-16 15:22:12 +00006880 static int busy = FALSE;
6881
6882 /* It's possible to get here recursively when 'statusline' (indirectly)
6883 * invokes ":redrawstatus". Simply ignore the call then. */
6884 if (busy)
6885 return;
6886 busy = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006887
6888 wp->w_redr_status = FALSE;
6889 if (wp->w_status_height == 0)
6890 {
6891 /* no status line, can only be last window */
6892 redraw_cmdline = TRUE;
6893 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00006894 else if (!redrawing()
6895#ifdef FEAT_INS_EXPAND
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02006896 // don't update status line when popup menu is visible and may be
6897 // drawn over it, unless it will be redrawn later
6898 || (!ignore_pum && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00006899#endif
6900 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006901 {
6902 /* Don't redraw right now, do it later. */
6903 wp->w_redr_status = TRUE;
6904 }
6905#ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006906 else if (*p_stl != NUL || *wp->w_p_stl != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006907 {
6908 /* redraw custom status line */
Bram Moolenaar362f3562009-11-03 16:20:34 +00006909 redraw_custom_statusline(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006910 }
6911#endif
6912 else
6913 {
Bram Moolenaar3633cf52017-07-31 22:29:35 +02006914 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006915
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006916 get_trans_bufname(wp->w_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006917 p = NameBuff;
6918 len = (int)STRLEN(p);
6919
Bram Moolenaard85f2712017-07-28 21:51:57 +02006920 if (bt_help(wp->w_buffer)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006921#ifdef FEAT_QUICKFIX
6922 || wp->w_p_pvw
6923#endif
6924 || bufIsChanged(wp->w_buffer)
6925 || wp->w_buffer->b_p_ro)
6926 *(p + len++) = ' ';
Bram Moolenaard85f2712017-07-28 21:51:57 +02006927 if (bt_help(wp->w_buffer))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006928 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +00006929 STRCPY(p + len, _("[Help]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006930 len += (int)STRLEN(p + len);
6931 }
6932#ifdef FEAT_QUICKFIX
6933 if (wp->w_p_pvw)
6934 {
6935 STRCPY(p + len, _("[Preview]"));
6936 len += (int)STRLEN(p + len);
6937 }
6938#endif
Bram Moolenaar086d5352017-08-05 18:19:55 +02006939 if (bufIsChanged(wp->w_buffer)
6940#ifdef FEAT_TERMINAL
6941 && !bt_terminal(wp->w_buffer)
6942#endif
6943 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006944 {
6945 STRCPY(p + len, "[+]");
6946 len += 3;
6947 }
6948 if (wp->w_buffer->b_p_ro)
6949 {
Bram Moolenaar23584032013-06-07 20:17:11 +02006950 STRCPY(p + len, _("[RO]"));
Bram Moolenaar3457d292017-02-23 14:55:59 +01006951 len += (int)STRLEN(p + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006952 }
6953
Bram Moolenaar02631462017-09-22 15:20:32 +02006954 this_ru_col = ru_col - (Columns - wp->w_width);
6955 if (this_ru_col < (wp->w_width + 1) / 2)
6956 this_ru_col = (wp->w_width + 1) / 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006957 if (this_ru_col <= 1)
6958 {
6959 p = (char_u *)"<"; /* No room for file name! */
6960 len = 1;
6961 }
6962 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006963#ifdef FEAT_MBYTE
6964 if (has_mbyte)
6965 {
6966 int clen = 0, i;
6967
6968 /* Count total number of display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02006969 clen = mb_string2cells(p, -1);
6970
Bram Moolenaar071d4272004-06-13 20:20:40 +00006971 /* Find first character that will fit.
6972 * Going from start to end is much faster for DBCS. */
6973 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006974 i += (*mb_ptr2len)(p + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006975 clen -= (*mb_ptr2cells)(p + i);
6976 len = clen;
6977 if (i > 0)
6978 {
6979 p = p + i - 1;
6980 *p = '<';
6981 ++len;
6982 }
6983
6984 }
6985 else
6986#endif
6987 if (len > this_ru_col - 1)
6988 {
6989 p += len - (this_ru_col - 1);
6990 *p = '<';
6991 len = this_ru_col - 1;
6992 }
6993
6994 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar53f81742017-09-22 14:35:51 +02006995 screen_puts(p, row, wp->w_wincol, attr);
6996 screen_fill(row, row + 1, len + wp->w_wincol,
6997 this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006998
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02006999 if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007000 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
7001 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
Bram Moolenaar53f81742017-09-22 14:35:51 +02007002 - 1 + wp->w_wincol), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003
7004#ifdef FEAT_CMDL_INFO
7005 win_redr_ruler(wp, TRUE);
7006#endif
7007 }
7008
Bram Moolenaar071d4272004-06-13 20:20:40 +00007009 /*
7010 * May need to draw the character below the vertical separator.
7011 */
7012 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
7013 {
7014 if (stl_connected(wp))
Bram Moolenaar3633cf52017-07-31 22:29:35 +02007015 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007016 else
7017 fillchar = fillchar_vsep(&attr);
7018 screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
7019 attr);
7020 }
Bram Moolenaaradb09c22009-06-16 15:22:12 +00007021 busy = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007022}
7023
Bram Moolenaar238a5642006-02-21 22:12:05 +00007024#ifdef FEAT_STL_OPT
7025/*
7026 * Redraw the status line according to 'statusline' and take care of any
7027 * errors encountered.
7028 */
7029 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007030redraw_custom_statusline(win_T *wp)
Bram Moolenaar238a5642006-02-21 22:12:05 +00007031{
Bram Moolenaar362f3562009-11-03 16:20:34 +00007032 static int entered = FALSE;
Bram Moolenaara742e082016-04-05 21:10:38 +02007033 int saved_did_emsg = did_emsg;
Bram Moolenaar362f3562009-11-03 16:20:34 +00007034
7035 /* When called recursively return. This can happen when the statusline
7036 * contains an expression that triggers a redraw. */
7037 if (entered)
7038 return;
7039 entered = TRUE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007040
Bram Moolenaara742e082016-04-05 21:10:38 +02007041 did_emsg = FALSE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007042 win_redr_custom(wp, FALSE);
Bram Moolenaara742e082016-04-05 21:10:38 +02007043 if (did_emsg)
Bram Moolenaar362f3562009-11-03 16:20:34 +00007044 {
7045 /* When there is an error disable the statusline, otherwise the
7046 * display is messed up with errors and a redraw triggers the problem
7047 * again and again. */
Bram Moolenaar238a5642006-02-21 22:12:05 +00007048 set_string_option_direct((char_u *)"statusline", -1,
7049 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007050 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
Bram Moolenaar362f3562009-11-03 16:20:34 +00007051 }
Bram Moolenaara742e082016-04-05 21:10:38 +02007052 did_emsg |= saved_did_emsg;
Bram Moolenaar362f3562009-11-03 16:20:34 +00007053 entered = FALSE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00007054}
7055#endif
7056
Bram Moolenaar071d4272004-06-13 20:20:40 +00007057/*
7058 * Return TRUE if the status line of window "wp" is connected to the status
7059 * line of the window right of it. If not, then it's a vertical separator.
7060 * Only call if (wp->w_vsep_width != 0).
7061 */
7062 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007063stl_connected(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007064{
7065 frame_T *fr;
7066
7067 fr = wp->w_frame;
7068 while (fr->fr_parent != NULL)
7069 {
7070 if (fr->fr_parent->fr_layout == FR_COL)
7071 {
7072 if (fr->fr_next != NULL)
7073 break;
7074 }
7075 else
7076 {
7077 if (fr->fr_next != NULL)
7078 return TRUE;
7079 }
7080 fr = fr->fr_parent;
7081 }
7082 return FALSE;
7083}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007084
Bram Moolenaar071d4272004-06-13 20:20:40 +00007085
Bram Moolenaar071d4272004-06-13 20:20:40 +00007086/*
7087 * Get the value to show for the language mappings, active 'keymap'.
7088 */
7089 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007090get_keymap_str(
7091 win_T *wp,
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02007092 char_u *fmt, /* format string containing one %s item */
Bram Moolenaar05540972016-01-30 20:31:25 +01007093 char_u *buf, /* buffer for the result */
7094 int len) /* length of buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095{
7096 char_u *p;
7097
7098 if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
7099 return FALSE;
7100
7101 {
7102#ifdef FEAT_EVAL
7103 buf_T *old_curbuf = curbuf;
7104 win_T *old_curwin = curwin;
7105 char_u *s;
7106
7107 curbuf = wp->w_buffer;
7108 curwin = wp;
7109 STRCPY(buf, "b:keymap_name"); /* must be writable */
7110 ++emsg_skip;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007111 s = p = eval_to_string(buf, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007112 --emsg_skip;
7113 curbuf = old_curbuf;
7114 curwin = old_curwin;
7115 if (p == NULL || *p == NUL)
7116#endif
7117 {
7118#ifdef FEAT_KEYMAP
7119 if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
7120 p = wp->w_buffer->b_p_keymap;
7121 else
7122#endif
7123 p = (char_u *)"lang";
7124 }
Bram Moolenaar73ac0c42016-07-24 16:17:59 +02007125 if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126 buf[0] = NUL;
7127#ifdef FEAT_EVAL
7128 vim_free(s);
7129#endif
7130 }
7131 return buf[0] != NUL;
7132}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007133
7134#if defined(FEAT_STL_OPT) || defined(PROTO)
7135/*
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007136 * Redraw the status line or ruler of window "wp".
7137 * When "wp" is NULL redraw the tab pages line from 'tabline'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007138 */
7139 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007140win_redr_custom(
7141 win_T *wp,
7142 int draw_ruler) /* TRUE or FALSE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007143{
Bram Moolenaar1d633412013-12-11 15:52:01 +01007144 static int entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145 int attr;
7146 int curattr;
7147 int row;
7148 int col = 0;
7149 int maxwidth;
7150 int width;
7151 int n;
7152 int len;
7153 int fillchar;
7154 char_u buf[MAXPATHL];
Bram Moolenaar362f3562009-11-03 16:20:34 +00007155 char_u *stl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007156 char_u *p;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007157 struct stl_hlrec hltab[STL_MAX_ITEM];
7158 struct stl_hlrec tabtab[STL_MAX_ITEM];
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007159 int use_sandbox = FALSE;
Bram Moolenaar61452852011-02-01 18:01:11 +01007160 win_T *ewp;
7161 int p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007162
Bram Moolenaar1d633412013-12-11 15:52:01 +01007163 /* There is a tiny chance that this gets called recursively: When
7164 * redrawing a status line triggers redrawing the ruler or tabline.
7165 * Avoid trouble by not allowing recursion. */
7166 if (entered)
7167 return;
7168 entered = TRUE;
7169
Bram Moolenaar071d4272004-06-13 20:20:40 +00007170 /* setup environment for the task at hand */
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007171 if (wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007172 {
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007173 /* Use 'tabline'. Always at the first line of the screen. */
Bram Moolenaar362f3562009-11-03 16:20:34 +00007174 stl = p_tal;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007175 row = 0;
Bram Moolenaar65c923a2006-03-03 22:56:30 +00007176 fillchar = ' ';
Bram Moolenaar8820b482017-03-16 17:23:31 +01007177 attr = HL_ATTR(HLF_TPF);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007178 maxwidth = Columns;
7179# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007180 use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007181# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007182 }
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007183 else
7184 {
7185 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar3633cf52017-07-31 22:29:35 +02007186 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar02631462017-09-22 15:20:32 +02007187 maxwidth = wp->w_width;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007188
7189 if (draw_ruler)
7190 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00007191 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007192 /* advance past any leading group spec - implicit in ru_col */
Bram Moolenaar362f3562009-11-03 16:20:34 +00007193 if (*stl == '%')
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007194 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00007195 if (*++stl == '-')
7196 stl++;
7197 if (atoi((char *)stl))
7198 while (VIM_ISDIGIT(*stl))
7199 stl++;
7200 if (*stl++ != '(')
7201 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007202 }
Bram Moolenaar02631462017-09-22 15:20:32 +02007203 col = ru_col - (Columns - wp->w_width);
7204 if (col < (wp->w_width + 1) / 2)
7205 col = (wp->w_width + 1) / 2;
7206 maxwidth = wp->w_width - col;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007207 if (!wp->w_status_height)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007208 {
7209 row = Rows - 1;
7210 --maxwidth; /* writing in last column may cause scrolling */
7211 fillchar = ' ';
7212 attr = 0;
7213 }
7214
7215# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007216 use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007217# endif
7218 }
7219 else
7220 {
7221 if (*wp->w_p_stl != NUL)
Bram Moolenaar362f3562009-11-03 16:20:34 +00007222 stl = wp->w_p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007223 else
Bram Moolenaar362f3562009-11-03 16:20:34 +00007224 stl = p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007225# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007226 use_sandbox = was_set_insecurely((char_u *)"statusline",
7227 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007228# endif
7229 }
7230
Bram Moolenaar53f81742017-09-22 14:35:51 +02007231 col += wp->w_wincol;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007232 }
7233
Bram Moolenaar071d4272004-06-13 20:20:40 +00007234 if (maxwidth <= 0)
Bram Moolenaar1d633412013-12-11 15:52:01 +01007235 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007236
Bram Moolenaar61452852011-02-01 18:01:11 +01007237 /* Temporarily reset 'cursorbind', we don't want a side effect from moving
7238 * the cursor away and back. */
7239 ewp = wp == NULL ? curwin : wp;
7240 p_crb_save = ewp->w_p_crb;
7241 ewp->w_p_crb = FALSE;
7242
Bram Moolenaar362f3562009-11-03 16:20:34 +00007243 /* Make a copy, because the statusline may include a function call that
7244 * might change the option value and free the memory. */
7245 stl = vim_strsave(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01007246 width = build_stl_str_hl(ewp, buf, sizeof(buf),
Bram Moolenaar362f3562009-11-03 16:20:34 +00007247 stl, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007248 fillchar, maxwidth, hltab, tabtab);
Bram Moolenaar362f3562009-11-03 16:20:34 +00007249 vim_free(stl);
Bram Moolenaar61452852011-02-01 18:01:11 +01007250 ewp->w_p_crb = p_crb_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007251
Bram Moolenaar7c5676b2010-12-08 19:56:58 +01007252 /* Make all characters printable. */
7253 p = transstr(buf);
7254 if (p != NULL)
7255 {
7256 vim_strncpy(buf, p, sizeof(buf) - 1);
7257 vim_free(p);
7258 }
7259
7260 /* fill up with "fillchar" */
7261 len = (int)STRLEN(buf);
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007262 while (width < maxwidth && len < (int)sizeof(buf) - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007263 {
7264#ifdef FEAT_MBYTE
7265 len += (*mb_char2bytes)(fillchar, buf + len);
7266#else
7267 buf[len++] = fillchar;
7268#endif
7269 ++width;
7270 }
7271 buf[len] = NUL;
7272
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007273 /*
7274 * Draw each snippet with the specified highlighting.
7275 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007276 curattr = attr;
7277 p = buf;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007278 for (n = 0; hltab[n].start != NULL; n++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007279 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007280 len = (int)(hltab[n].start - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007281 screen_puts_len(p, len, row, col, curattr);
7282 col += vim_strnsize(p, len);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007283 p = hltab[n].start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007284
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007285 if (hltab[n].userhl == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007286 curattr = attr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007287 else if (hltab[n].userhl < 0)
7288 curattr = syn_id2attr(-hltab[n].userhl);
Bram Moolenaar4033c552017-09-16 20:54:51 +02007289#ifdef FEAT_TERMINAL
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +02007290 else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
7291 && wp->w_status_height != 0)
7292 curattr = highlight_stltermnc[hltab[n].userhl - 1];
Bram Moolenaarbce4f622017-08-13 21:37:43 +02007293 else if (wp != NULL && bt_terminal(wp->w_buffer)
7294 && wp->w_status_height != 0)
7295 curattr = highlight_stlterm[hltab[n].userhl - 1];
Bram Moolenaar4033c552017-09-16 20:54:51 +02007296#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +00007297 else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007298 curattr = highlight_stlnc[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007299 else
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007300 curattr = highlight_user[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007301 }
7302 screen_puts(p, row, col, curattr);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007303
7304 if (wp == NULL)
7305 {
7306 /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */
7307 col = 0;
7308 len = 0;
7309 p = buf;
7310 fillchar = 0;
7311 for (n = 0; tabtab[n].start != NULL; n++)
7312 {
7313 len += vim_strnsize(p, (int)(tabtab[n].start - p));
7314 while (col < len)
7315 TabPageIdxs[col++] = fillchar;
7316 p = tabtab[n].start;
7317 fillchar = tabtab[n].userhl;
7318 }
7319 while (col < Columns)
7320 TabPageIdxs[col++] = fillchar;
7321 }
Bram Moolenaar1d633412013-12-11 15:52:01 +01007322
7323theend:
7324 entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007325}
7326
7327#endif /* FEAT_STL_OPT */
7328
7329/*
7330 * Output a single character directly to the screen and update ScreenLines.
7331 */
7332 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007333screen_putchar(int c, int row, int col, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007334{
Bram Moolenaar071d4272004-06-13 20:20:40 +00007335 char_u buf[MB_MAXBYTES + 1];
7336
Bram Moolenaar9a920d82012-06-01 15:21:02 +02007337#ifdef FEAT_MBYTE
7338 if (has_mbyte)
7339 buf[(*mb_char2bytes)(c, buf)] = NUL;
7340 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007341#endif
Bram Moolenaar9a920d82012-06-01 15:21:02 +02007342 {
7343 buf[0] = c;
7344 buf[1] = NUL;
7345 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007346 screen_puts(buf, row, col, attr);
7347}
7348
7349/*
7350 * Get a single character directly from ScreenLines into "bytes[]".
7351 * Also return its attribute in *attrp;
7352 */
7353 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007354screen_getbytes(int row, int col, char_u *bytes, int *attrp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007355{
7356 unsigned off;
7357
7358 /* safety check */
7359 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
7360 {
7361 off = LineOffset[row] + col;
7362 *attrp = ScreenAttrs[off];
7363 bytes[0] = ScreenLines[off];
7364 bytes[1] = NUL;
7365
7366#ifdef FEAT_MBYTE
7367 if (enc_utf8 && ScreenLinesUC[off] != 0)
7368 bytes[utfc_char2bytes(off, bytes)] = NUL;
7369 else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
7370 {
7371 bytes[0] = ScreenLines[off];
7372 bytes[1] = ScreenLines2[off];
7373 bytes[2] = NUL;
7374 }
7375 else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
7376 {
7377 bytes[1] = ScreenLines[off + 1];
7378 bytes[2] = NUL;
7379 }
7380#endif
7381 }
7382}
7383
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007384#ifdef FEAT_MBYTE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01007385static int screen_comp_differs(int, int*);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007386
7387/*
7388 * Return TRUE if composing characters for screen posn "off" differs from
7389 * composing characters in "u8cc".
Bram Moolenaar70c49c12010-03-23 15:36:35 +01007390 * Only to be used when ScreenLinesUC[off] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007391 */
7392 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007393screen_comp_differs(int off, int *u8cc)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007394{
7395 int i;
7396
7397 for (i = 0; i < Screen_mco; ++i)
7398 {
7399 if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
7400 return TRUE;
7401 if (u8cc[i] == 0)
7402 break;
7403 }
7404 return FALSE;
7405}
7406#endif
7407
Bram Moolenaar071d4272004-06-13 20:20:40 +00007408/*
7409 * Put string '*text' on the screen at position 'row' and 'col', with
7410 * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
7411 * Note: only outputs within one row, message is truncated at screen boundary!
7412 * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
7413 */
7414 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007415screen_puts(
7416 char_u *text,
7417 int row,
7418 int col,
7419 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007420{
7421 screen_puts_len(text, -1, row, col, attr);
7422}
7423
7424/*
7425 * Like screen_puts(), but output "text[len]". When "len" is -1 output up to
7426 * a NUL.
7427 */
7428 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007429screen_puts_len(
7430 char_u *text,
7431 int textlen,
7432 int row,
7433 int col,
7434 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007435{
7436 unsigned off;
7437 char_u *ptr = text;
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007438 int len = textlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007439 int c;
7440#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00007441 unsigned max_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007442 int mbyte_blen = 1;
7443 int mbyte_cells = 1;
7444 int u8c = 0;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007445 int u8cc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007446 int clear_next_cell = FALSE;
7447# ifdef FEAT_ARABIC
7448 int prev_c = 0; /* previous Arabic character */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007449 int pc, nc, nc1;
7450 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007451# endif
7452#endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007453#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7454 int force_redraw_this;
7455 int force_redraw_next = FALSE;
7456#endif
7457 int need_redraw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007458
7459 if (ScreenLines == NULL || row >= screen_Rows) /* safety check */
7460 return;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007461 off = LineOffset[row] + col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007462
Bram Moolenaarc236c162008-07-13 17:41:49 +00007463#ifdef FEAT_MBYTE
7464 /* When drawing over the right halve of a double-wide char clear out the
7465 * left halve. Only needed in a terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00007466 if (has_mbyte && col > 0 && col < screen_Columns
Bram Moolenaarc236c162008-07-13 17:41:49 +00007467# ifdef FEAT_GUI
7468 && !gui.in_use
7469# endif
7470 && mb_fix_col(col, row) != col)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007471 {
7472 ScreenLines[off - 1] = ' ';
7473 ScreenAttrs[off - 1] = 0;
7474 if (enc_utf8)
7475 {
7476 ScreenLinesUC[off - 1] = 0;
7477 ScreenLinesC[0][off - 1] = 0;
7478 }
7479 /* redraw the previous cell, make it empty */
7480 screen_char(off - 1, row, col - 1);
7481 /* force the cell at "col" to be redrawn */
7482 force_redraw_next = TRUE;
7483 }
Bram Moolenaarc236c162008-07-13 17:41:49 +00007484#endif
7485
Bram Moolenaar367329b2007-08-30 11:53:22 +00007486#ifdef FEAT_MBYTE
7487 max_off = LineOffset[row] + screen_Columns;
7488#endif
Bram Moolenaara064ac82007-08-05 18:10:54 +00007489 while (col < screen_Columns
7490 && (len < 0 || (int)(ptr - text) < len)
7491 && *ptr != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007492 {
7493 c = *ptr;
7494#ifdef FEAT_MBYTE
7495 /* check if this is the first byte of a multibyte */
7496 if (has_mbyte)
7497 {
7498 if (enc_utf8 && len > 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007499 mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007500 else
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007501 mbyte_blen = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007502 if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7503 mbyte_cells = 1;
7504 else if (enc_dbcs != 0)
7505 mbyte_cells = mbyte_blen;
7506 else /* enc_utf8 */
7507 {
7508 if (len >= 0)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007509 u8c = utfc_ptr2char_len(ptr, u8cc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007510 (int)((text + len) - ptr));
7511 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007512 u8c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007513 mbyte_cells = utf_char2cells(u8c);
Bram Moolenaar11936362007-09-17 20:39:42 +00007514# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00007515 /* Non-BMP character: display as ? or fullwidth ?. */
7516 if (u8c >= 0x10000)
7517 {
7518 u8c = (mbyte_cells == 2) ? 0xff1f : (int)'?';
7519 if (attr == 0)
Bram Moolenaar8820b482017-03-16 17:23:31 +01007520 attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007521 }
Bram Moolenaar11936362007-09-17 20:39:42 +00007522# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007523# ifdef FEAT_ARABIC
7524 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
7525 {
7526 /* Do Arabic shaping. */
7527 if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
7528 {
7529 /* Past end of string to be displayed. */
7530 nc = NUL;
7531 nc1 = NUL;
7532 }
7533 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007534 {
Bram Moolenaar54620182009-11-11 16:07:20 +00007535 nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
7536 (int)((text + len) - ptr - mbyte_blen));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007537 nc1 = pcc[0];
7538 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007539 pc = prev_c;
7540 prev_c = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007541 u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007542 }
7543 else
7544 prev_c = u8c;
7545# endif
Bram Moolenaare4ebd292010-01-19 17:40:46 +01007546 if (col + mbyte_cells > screen_Columns)
7547 {
7548 /* Only 1 cell left, but character requires 2 cells:
7549 * display a '>' in the last column to avoid wrapping. */
7550 c = '>';
7551 mbyte_cells = 1;
7552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007553 }
7554 }
7555#endif
7556
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007557#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7558 force_redraw_this = force_redraw_next;
7559 force_redraw_next = FALSE;
7560#endif
7561
7562 need_redraw = ScreenLines[off] != c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007563#ifdef FEAT_MBYTE
7564 || (mbyte_cells == 2
7565 && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
7566 || (enc_dbcs == DBCS_JPNU
7567 && c == 0x8e
7568 && ScreenLines2[off] != ptr[1])
7569 || (enc_utf8
Bram Moolenaar70c49c12010-03-23 15:36:35 +01007570 && (ScreenLinesUC[off] !=
7571 (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
7572 || (ScreenLinesUC[off] != 0
7573 && screen_comp_differs(off, u8cc))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007574#endif
7575 || ScreenAttrs[off] != attr
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007576 || exmode_active;
7577
7578 if (need_redraw
7579#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7580 || force_redraw_this
7581#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007582 )
7583 {
7584#if defined(FEAT_GUI) || defined(UNIX)
7585 /* The bold trick makes a single row of pixels appear in the next
7586 * character. When a bold character is removed, the next
7587 * character should be redrawn too. This happens for our own GUI
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007588 * and for some xterms. */
7589 if (need_redraw && ScreenLines[off] != ' ' && (
Bram Moolenaar071d4272004-06-13 20:20:40 +00007590# ifdef FEAT_GUI
7591 gui.in_use
7592# endif
7593# if defined(FEAT_GUI) && defined(UNIX)
7594 ||
7595# endif
7596# ifdef UNIX
7597 term_is_xterm
7598# endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007599 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007600 {
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007601 int n = ScreenAttrs[off];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007602
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007603 if (n > HL_ALL)
7604 n = syn_attr2attr(n);
7605 if (n & HL_BOLD)
7606 force_redraw_next = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007607 }
7608#endif
7609#ifdef FEAT_MBYTE
7610 /* When at the end of the text and overwriting a two-cell
7611 * character with a one-cell character, need to clear the next
7612 * cell. Also when overwriting the left halve of a two-cell char
7613 * with the right halve of a two-cell char. Do this only once
7614 * (mb_off2cells() may return 2 on the right halve). */
7615 if (clear_next_cell)
7616 clear_next_cell = FALSE;
7617 else if (has_mbyte
7618 && (len < 0 ? ptr[mbyte_blen] == NUL
7619 : ptr + mbyte_blen >= text + len)
Bram Moolenaar367329b2007-08-30 11:53:22 +00007620 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007621 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00007622 && (*mb_off2cells)(off, max_off) == 1
7623 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007624 clear_next_cell = TRUE;
7625
7626 /* Make sure we never leave a second byte of a double-byte behind,
7627 * it confuses mb_off2cells(). */
7628 if (enc_dbcs
Bram Moolenaar367329b2007-08-30 11:53:22 +00007629 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007630 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00007631 && (*mb_off2cells)(off, max_off) == 1
7632 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007633 ScreenLines[off + mbyte_blen] = 0;
7634#endif
7635 ScreenLines[off] = c;
7636 ScreenAttrs[off] = attr;
7637#ifdef FEAT_MBYTE
7638 if (enc_utf8)
7639 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007640 if (c < 0x80 && u8cc[0] == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007641 ScreenLinesUC[off] = 0;
7642 else
7643 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007644 int i;
7645
Bram Moolenaar071d4272004-06-13 20:20:40 +00007646 ScreenLinesUC[off] = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007647 for (i = 0; i < Screen_mco; ++i)
7648 {
7649 ScreenLinesC[i][off] = u8cc[i];
7650 if (u8cc[i] == 0)
7651 break;
7652 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007653 }
7654 if (mbyte_cells == 2)
7655 {
7656 ScreenLines[off + 1] = 0;
7657 ScreenAttrs[off + 1] = attr;
7658 }
7659 screen_char(off, row, col);
7660 }
7661 else if (mbyte_cells == 2)
7662 {
7663 ScreenLines[off + 1] = ptr[1];
7664 ScreenAttrs[off + 1] = attr;
7665 screen_char_2(off, row, col);
7666 }
7667 else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7668 {
7669 ScreenLines2[off] = ptr[1];
7670 screen_char(off, row, col);
7671 }
7672 else
7673#endif
7674 screen_char(off, row, col);
7675 }
7676#ifdef FEAT_MBYTE
7677 if (has_mbyte)
7678 {
7679 off += mbyte_cells;
7680 col += mbyte_cells;
7681 ptr += mbyte_blen;
7682 if (clear_next_cell)
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007683 {
7684 /* This only happens at the end, display one space next. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007685 ptr = (char_u *)" ";
Bram Moolenaare4c21e62014-05-22 16:05:19 +02007686 len = -1;
7687 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007688 }
7689 else
7690#endif
7691 {
7692 ++off;
7693 ++col;
7694 ++ptr;
7695 }
7696 }
Bram Moolenaar2bea2912009-03-11 16:58:40 +00007697
7698#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7699 /* If we detected the next character needs to be redrawn, but the text
7700 * doesn't extend up to there, update the character here. */
7701 if (force_redraw_next && col < screen_Columns)
7702 {
7703# ifdef FEAT_MBYTE
7704 if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
7705 screen_char_2(off, row, col);
7706 else
7707# endif
7708 screen_char(off, row, col);
7709 }
7710#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007711}
7712
7713#ifdef FEAT_SEARCH_EXTRA
7714/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007715 * Prepare for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007716 */
7717 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007718start_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007719{
7720 if (p_hls && !no_hlsearch)
7721 {
7722 last_pat_prog(&search_hl.rm);
Bram Moolenaar8820b482017-03-16 17:23:31 +01007723 search_hl.attr = HL_ATTR(HLF_L);
Bram Moolenaar91a4e822008-01-19 14:59:58 +00007724# ifdef FEAT_RELTIME
7725 /* Set the time limit to 'redrawtime'. */
7726 profile_setlimit(p_rdt, &search_hl.tm);
7727# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007728 }
7729}
7730
7731/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007732 * Clean up for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007733 */
7734 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007735end_search_hl(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007736{
7737 if (search_hl.rm.regprog != NULL)
7738 {
Bram Moolenaar473de612013-06-08 18:19:48 +02007739 vim_regfree(search_hl.rm.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007740 search_hl.rm.regprog = NULL;
7741 }
7742}
7743
7744/*
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +02007745 * Init for calling prepare_search_hl().
7746 */
7747 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007748init_search_hl(win_T *wp)
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +02007749{
7750 matchitem_T *cur;
7751
7752 /* Setup for match and 'hlsearch' highlighting. Disable any previous
7753 * match */
7754 cur = wp->w_match_head;
7755 while (cur != NULL)
7756 {
7757 cur->hl.rm = cur->match;
7758 if (cur->hlg_id == 0)
7759 cur->hl.attr = 0;
7760 else
7761 cur->hl.attr = syn_id2attr(cur->hlg_id);
7762 cur->hl.buf = wp->w_buffer;
7763 cur->hl.lnum = 0;
7764 cur->hl.first_lnum = 0;
7765# ifdef FEAT_RELTIME
7766 /* Set the time limit to 'redrawtime'. */
7767 profile_setlimit(p_rdt, &(cur->hl.tm));
7768# endif
7769 cur = cur->next;
7770 }
7771 search_hl.buf = wp->w_buffer;
7772 search_hl.lnum = 0;
7773 search_hl.first_lnum = 0;
7774 /* time limit is set at the toplevel, for all windows */
7775}
7776
7777/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007778 * Advance to the match in window "wp" line "lnum" or past it.
7779 */
7780 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007781prepare_search_hl(win_T *wp, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007782{
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007783 matchitem_T *cur; /* points to the match list */
7784 match_T *shl; /* points to search_hl or a match */
7785 int shl_flag; /* flag to indicate whether search_hl
7786 has been processed or not */
Bram Moolenaarb3414592014-06-17 17:48:32 +02007787 int pos_inprogress; /* marks that position match search is
7788 in progress */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007789 int n;
7790
7791 /*
7792 * When using a multi-line pattern, start searching at the top
7793 * of the window or just after a closed fold.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007794 * Do this both for search_hl and the match list.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007795 */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007796 cur = wp->w_match_head;
7797 shl_flag = FALSE;
7798 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007799 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007800 if (shl_flag == FALSE)
7801 {
7802 shl = &search_hl;
7803 shl_flag = TRUE;
7804 }
7805 else
7806 shl = &cur->hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007807 if (shl->rm.regprog != NULL
7808 && shl->lnum == 0
7809 && re_multiline(shl->rm.regprog))
7810 {
7811 if (shl->first_lnum == 0)
7812 {
7813# ifdef FEAT_FOLDING
7814 for (shl->first_lnum = lnum;
7815 shl->first_lnum > wp->w_topline; --shl->first_lnum)
7816 if (hasFoldingWin(wp, shl->first_lnum - 1,
7817 NULL, NULL, TRUE, NULL))
7818 break;
7819# else
7820 shl->first_lnum = wp->w_topline;
7821# endif
7822 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02007823 if (cur != NULL)
7824 cur->pos.cur = 0;
7825 pos_inprogress = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007826 n = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02007827 while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
7828 || (cur != NULL && pos_inprogress)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007829 {
Bram Moolenaare17bdff2016-08-27 18:34:29 +02007830 next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
7831 shl == &search_hl ? NULL : cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02007832 pos_inprogress = cur == NULL || cur->pos.cur == 0
7833 ? FALSE : TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007834 if (shl->lnum != 0)
7835 {
7836 shl->first_lnum = shl->lnum
7837 + shl->rm.endpos[0].lnum
7838 - shl->rm.startpos[0].lnum;
7839 n = shl->rm.endpos[0].col;
7840 }
7841 else
7842 {
7843 ++shl->first_lnum;
7844 n = 0;
7845 }
7846 }
7847 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007848 if (shl != &search_hl && cur != NULL)
7849 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007850 }
7851}
7852
7853/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007854 * Search for a next 'hlsearch' or match.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007855 * Uses shl->buf.
7856 * Sets shl->lnum and shl->rm contents.
7857 * Note: Assumes a previous match is always before "lnum", unless
7858 * shl->lnum is zero.
7859 * Careful: Any pointers for buffer lines will become invalid.
7860 */
7861 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007862next_search_hl(
7863 win_T *win,
7864 match_T *shl, /* points to search_hl or a match */
7865 linenr_T lnum,
7866 colnr_T mincol, /* minimal column for a match */
7867 matchitem_T *cur) /* to retrieve match positions if any */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007868{
7869 linenr_T l;
7870 colnr_T matchcol;
7871 long nmatched;
7872
7873 if (shl->lnum != 0)
7874 {
7875 /* Check for three situations:
7876 * 1. If the "lnum" is below a previous match, start a new search.
7877 * 2. If the previous match includes "mincol", use it.
7878 * 3. Continue after the previous match.
7879 */
7880 l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
7881 if (lnum > l)
7882 shl->lnum = 0;
7883 else if (lnum < l || shl->rm.endpos[0].col > mincol)
7884 return;
7885 }
7886
7887 /*
7888 * Repeat searching for a match until one is found that includes "mincol"
7889 * or none is found in this line.
7890 */
7891 called_emsg = FALSE;
7892 for (;;)
7893 {
Bram Moolenaar91a4e822008-01-19 14:59:58 +00007894#ifdef FEAT_RELTIME
7895 /* Stop searching after passing the time limit. */
7896 if (profile_passed_limit(&(shl->tm)))
7897 {
7898 shl->lnum = 0; /* no match found in time */
7899 break;
7900 }
7901#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007902 /* Three situations:
7903 * 1. No useful previous match: search from start of line.
7904 * 2. Not Vi compatible or empty match: continue at next character.
7905 * Break the loop if this is beyond the end of the line.
7906 * 3. Vi compatible searching: continue at end of previous match.
7907 */
7908 if (shl->lnum == 0)
7909 matchcol = 0;
7910 else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
7911 || (shl->rm.endpos[0].lnum == 0
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007912 && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007913 {
Bram Moolenaar5c8837f2006-02-25 21:52:33 +00007914 char_u *ml;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007915
7916 matchcol = shl->rm.startpos[0].col;
Bram Moolenaar5c8837f2006-02-25 21:52:33 +00007917 ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007918 if (*ml == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007919 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007920 ++matchcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007921 shl->lnum = 0;
7922 break;
7923 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007924#ifdef FEAT_MBYTE
7925 if (has_mbyte)
7926 matchcol += mb_ptr2len(ml);
7927 else
7928#endif
7929 ++matchcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007930 }
7931 else
7932 matchcol = shl->rm.endpos[0].col;
7933
7934 shl->lnum = lnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02007935 if (shl->rm.regprog != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007936 {
Bram Moolenaarcbdf0a02014-11-27 13:37:10 +01007937 /* Remember whether shl->rm is using a copy of the regprog in
7938 * cur->match. */
7939 int regprog_is_copy = (shl != &search_hl && cur != NULL
7940 && shl == &cur->hl
7941 && cur->match.regprog == cur->hl.rm.regprog);
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007942 int timed_out = FALSE;
Bram Moolenaarcbdf0a02014-11-27 13:37:10 +01007943
Bram Moolenaarb3414592014-06-17 17:48:32 +02007944 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
7945 matchcol,
7946#ifdef FEAT_RELTIME
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007947 &(shl->tm), &timed_out
Bram Moolenaarb3414592014-06-17 17:48:32 +02007948#else
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007949 NULL, NULL
Bram Moolenaarb3414592014-06-17 17:48:32 +02007950#endif
7951 );
Bram Moolenaarcbdf0a02014-11-27 13:37:10 +01007952 /* Copy the regprog, in case it got freed and recompiled. */
7953 if (regprog_is_copy)
7954 cur->match.regprog = cur->hl.rm.regprog;
7955
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007956 if (called_emsg || got_int || timed_out)
Bram Moolenaar0ddf0a72007-05-01 20:04:53 +00007957 {
Bram Moolenaarb3414592014-06-17 17:48:32 +02007958 /* Error while handling regexp: stop using this regexp. */
7959 if (shl == &search_hl)
7960 {
7961 /* don't free regprog in the match list, it's a copy */
7962 vim_regfree(shl->rm.regprog);
Bram Moolenaar451fc7b2018-04-27 22:53:07 +02007963 set_no_hlsearch(TRUE);
Bram Moolenaarb3414592014-06-17 17:48:32 +02007964 }
7965 shl->rm.regprog = NULL;
7966 shl->lnum = 0;
7967 got_int = FALSE; /* avoid the "Type :quit to exit Vim"
7968 message */
7969 break;
Bram Moolenaar0ddf0a72007-05-01 20:04:53 +00007970 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02007971 }
7972 else if (cur != NULL)
Bram Moolenaarb3414592014-06-17 17:48:32 +02007973 nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
Bram Moolenaardeae0f22014-06-18 21:20:11 +02007974 else
7975 nmatched = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007976 if (nmatched == 0)
7977 {
7978 shl->lnum = 0; /* no match found */
7979 break;
7980 }
7981 if (shl->rm.startpos[0].lnum > 0
7982 || shl->rm.startpos[0].col >= mincol
7983 || nmatched > 1
7984 || shl->rm.endpos[0].col > mincol)
7985 {
7986 shl->lnum += shl->rm.startpos[0].lnum;
7987 break; /* useful match found */
7988 }
7989 }
7990}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007991
Bram Moolenaar85077472016-10-16 14:35:48 +02007992/*
7993 * If there is a match fill "shl" and return one.
7994 * Return zero otherwise.
7995 */
Bram Moolenaarb3414592014-06-17 17:48:32 +02007996 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007997next_search_hl_pos(
7998 match_T *shl, /* points to a match */
7999 linenr_T lnum,
8000 posmatch_T *posmatch, /* match positions */
8001 colnr_T mincol) /* minimal column for a match */
Bram Moolenaarb3414592014-06-17 17:48:32 +02008002{
8003 int i;
Bram Moolenaar85077472016-10-16 14:35:48 +02008004 int found = -1;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008005
Bram Moolenaarb3414592014-06-17 17:48:32 +02008006 for (i = posmatch->cur; i < MAXPOSMATCH; i++)
8007 {
Bram Moolenaara6c27ee2016-10-15 14:56:30 +02008008 llpos_T *pos = &posmatch->pos[i];
8009
8010 if (pos->lnum == 0)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008011 break;
Bram Moolenaar85077472016-10-16 14:35:48 +02008012 if (pos->len == 0 && pos->col < mincol)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008013 continue;
Bram Moolenaara6c27ee2016-10-15 14:56:30 +02008014 if (pos->lnum == lnum)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008015 {
Bram Moolenaar85077472016-10-16 14:35:48 +02008016 if (found >= 0)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008017 {
Bram Moolenaar85077472016-10-16 14:35:48 +02008018 /* if this match comes before the one at "found" then swap
8019 * them */
8020 if (pos->col < posmatch->pos[found].col)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008021 {
Bram Moolenaara6c27ee2016-10-15 14:56:30 +02008022 llpos_T tmp = *pos;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008023
Bram Moolenaar85077472016-10-16 14:35:48 +02008024 *pos = posmatch->pos[found];
8025 posmatch->pos[found] = tmp;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008026 }
8027 }
8028 else
Bram Moolenaar85077472016-10-16 14:35:48 +02008029 found = i;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008030 }
8031 }
8032 posmatch->cur = 0;
Bram Moolenaar85077472016-10-16 14:35:48 +02008033 if (found >= 0)
Bram Moolenaarb3414592014-06-17 17:48:32 +02008034 {
Bram Moolenaar85077472016-10-16 14:35:48 +02008035 colnr_T start = posmatch->pos[found].col == 0
8036 ? 0 : posmatch->pos[found].col - 1;
8037 colnr_T end = posmatch->pos[found].col == 0
8038 ? MAXCOL : start + posmatch->pos[found].len;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008039
Bram Moolenaar85077472016-10-16 14:35:48 +02008040 shl->lnum = lnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008041 shl->rm.startpos[0].lnum = 0;
8042 shl->rm.startpos[0].col = start;
8043 shl->rm.endpos[0].lnum = 0;
8044 shl->rm.endpos[0].col = end;
Bram Moolenaar4f416e42016-08-16 16:08:18 +02008045 shl->is_addpos = TRUE;
Bram Moolenaar85077472016-10-16 14:35:48 +02008046 posmatch->cur = found + 1;
8047 return 1;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008048 }
Bram Moolenaar85077472016-10-16 14:35:48 +02008049 return 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02008050}
Bram Moolenaarde993ea2014-06-17 23:18:01 +02008051#endif
Bram Moolenaarb3414592014-06-17 17:48:32 +02008052
Bram Moolenaar071d4272004-06-13 20:20:40 +00008053 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008054screen_start_highlight(int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008055{
8056 attrentry_T *aep = NULL;
8057
8058 screen_attr = attr;
8059 if (full_screen
8060#ifdef WIN3264
8061 && termcap_active
8062#endif
8063 )
8064 {
8065#ifdef FEAT_GUI
8066 if (gui.in_use)
8067 {
8068 char buf[20];
8069
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008070 /* The GUI handles this internally. */
8071 sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008072 OUT_STR(buf);
8073 }
8074 else
8075#endif
8076 {
8077 if (attr > HL_ALL) /* special HL attr. */
8078 {
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008079 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008080 aep = syn_cterm_attr2entry(attr);
8081 else
8082 aep = syn_term_attr2entry(attr);
8083 if (aep == NULL) /* did ":syntax clear" */
8084 attr = 0;
8085 else
8086 attr = aep->ae_attr;
8087 }
Bram Moolenaar45a00002017-12-22 21:12:34 +01008088 if ((attr & HL_BOLD) && *T_MD != NUL) /* bold */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008089 out_str(T_MD);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008090 else if (aep != NULL && cterm_normal_fg_bold && (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008091#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008092 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
8093 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
8094 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008095#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008096 t_colors > 1 && aep->ae_u.cterm.fg_color))
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008097 /* If the Normal FG color has BOLD attribute and the new HL
8098 * has a FG color defined, clear BOLD. */
8099 out_str(T_ME);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008100 if ((attr & HL_STANDOUT) && *T_SO != NUL) /* standout */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008101 out_str(T_SO);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008102 if ((attr & HL_UNDERCURL) && *T_UCS != NUL) /* undercurl */
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01008103 out_str(T_UCS);
8104 if (((attr & HL_UNDERLINE) /* underline or undercurl */
Bram Moolenaar45a00002017-12-22 21:12:34 +01008105 || ((attr & HL_UNDERCURL) && *T_UCS == NUL))
8106 && *T_US != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008107 out_str(T_US);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008108 if ((attr & HL_ITALIC) && *T_CZH != NUL) /* italic */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008109 out_str(T_CZH);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008110 if ((attr & HL_INVERSE) && *T_MR != NUL) /* inverse (reverse) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008111 out_str(T_MR);
Bram Moolenaar45a00002017-12-22 21:12:34 +01008112 if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) /* strike */
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008113 out_str(T_STS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008114
8115 /*
8116 * Output the color or start string after bold etc., in case the
8117 * bold etc. override the color setting.
8118 */
8119 if (aep != NULL)
8120 {
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008121#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008122 /* When 'termguicolors' is set but fg or bg is unset,
8123 * fall back to the cterm colors. This helps for SpellBad,
8124 * where the GUI uses a red undercurl. */
8125 if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008126 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008127 if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008128 term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008129 }
8130 else
8131#endif
8132 if (t_colors > 1)
8133 {
8134 if (aep->ae_u.cterm.fg_color)
8135 term_fg_color(aep->ae_u.cterm.fg_color - 1);
8136 }
8137#ifdef FEAT_TERMGUICOLORS
8138 if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
8139 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008140 if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008141 term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008142 }
8143 else
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008144#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008145 if (t_colors > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008146 {
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008147 if (aep->ae_u.cterm.bg_color)
8148 term_bg_color(aep->ae_u.cterm.bg_color - 1);
8149 }
8150
Bram Moolenaarf708ac52018-03-12 21:48:32 +01008151 if (!IS_CTERM)
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008152 {
8153 if (aep->ae_u.term.start != NULL)
8154 out_str(aep->ae_u.term.start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008155 }
8156 }
8157 }
8158 }
8159}
8160
8161 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008162screen_stop_highlight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008163{
8164 int do_ME = FALSE; /* output T_ME code */
8165
8166 if (screen_attr != 0
8167#ifdef WIN3264
8168 && termcap_active
8169#endif
8170 )
8171 {
8172#ifdef FEAT_GUI
8173 if (gui.in_use)
8174 {
8175 char buf[20];
8176
8177 /* use internal GUI code */
8178 sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
8179 OUT_STR(buf);
8180 }
8181 else
8182#endif
8183 {
8184 if (screen_attr > HL_ALL) /* special HL attr. */
8185 {
8186 attrentry_T *aep;
8187
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008188 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008189 {
8190 /*
8191 * Assume that t_me restores the original colors!
8192 */
8193 aep = syn_cterm_attr2entry(screen_attr);
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008194 if (aep != NULL && ((
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008195#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008196 p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
8197 ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
8198 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008199#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008200 aep->ae_u.cterm.fg_color) || (
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008201#ifdef FEAT_TERMGUICOLORS
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008202 p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
8203 ? aep->ae_u.cterm.bg_rgb != INVALCOLOR
8204 :
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008205#endif
Bram Moolenaard4fc5772018-02-27 14:39:03 +01008206 aep->ae_u.cterm.bg_color)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008207 do_ME = TRUE;
8208 }
8209 else
8210 {
8211 aep = syn_term_attr2entry(screen_attr);
8212 if (aep != NULL && aep->ae_u.term.stop != NULL)
8213 {
8214 if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
8215 do_ME = TRUE;
8216 else
8217 out_str(aep->ae_u.term.stop);
8218 }
8219 }
8220 if (aep == NULL) /* did ":syntax clear" */
8221 screen_attr = 0;
8222 else
8223 screen_attr = aep->ae_attr;
8224 }
8225
8226 /*
8227 * Often all ending-codes are equal to T_ME. Avoid outputting the
8228 * same sequence several times.
8229 */
8230 if (screen_attr & HL_STANDOUT)
8231 {
8232 if (STRCMP(T_SE, T_ME) == 0)
8233 do_ME = TRUE;
8234 else
8235 out_str(T_SE);
8236 }
Bram Moolenaar45a00002017-12-22 21:12:34 +01008237 if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
Bram Moolenaar8b9e20a2017-11-28 21:25:21 +01008238 {
8239 if (STRCMP(T_UCE, T_ME) == 0)
8240 do_ME = TRUE;
8241 else
8242 out_str(T_UCE);
8243 }
8244 if ((screen_attr & HL_UNDERLINE)
Bram Moolenaar45a00002017-12-22 21:12:34 +01008245 || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008246 {
8247 if (STRCMP(T_UE, T_ME) == 0)
8248 do_ME = TRUE;
8249 else
8250 out_str(T_UE);
8251 }
8252 if (screen_attr & HL_ITALIC)
8253 {
8254 if (STRCMP(T_CZR, T_ME) == 0)
8255 do_ME = TRUE;
8256 else
8257 out_str(T_CZR);
8258 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008259 if (screen_attr & HL_STRIKETHROUGH)
8260 {
8261 if (STRCMP(T_STE, T_ME) == 0)
8262 do_ME = TRUE;
8263 else
8264 out_str(T_STE);
8265 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008266 if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
8267 out_str(T_ME);
8268
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008269#ifdef FEAT_TERMGUICOLORS
8270 if (p_tgc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008271 {
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008272 if (cterm_normal_fg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008273 term_fg_rgb_color(cterm_normal_fg_gui_color);
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008274 if (cterm_normal_bg_gui_color != INVALCOLOR)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008275 term_bg_rgb_color(cterm_normal_bg_gui_color);
8276 }
8277 else
8278#endif
8279 {
8280 if (t_colors > 1)
8281 {
8282 /* set Normal cterm colors */
8283 if (cterm_normal_fg_color != 0)
8284 term_fg_color(cterm_normal_fg_color - 1);
8285 if (cterm_normal_bg_color != 0)
8286 term_bg_color(cterm_normal_bg_color - 1);
8287 if (cterm_normal_fg_bold)
8288 out_str(T_MD);
8289 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008290 }
8291 }
8292 }
8293 screen_attr = 0;
8294}
8295
8296/*
8297 * Reset the colors for a cterm. Used when leaving Vim.
8298 * The machine specific code may override this again.
8299 */
8300 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008301reset_cterm_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008302{
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008303 if (IS_CTERM)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008304 {
8305 /* set Normal cterm colors */
Bram Moolenaar61be73b2016-04-29 22:59:22 +02008306#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02008307 if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
8308 || cterm_normal_bg_gui_color != INVALCOLOR)
8309 : (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008310#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008311 if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008312#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008313 {
8314 out_str(T_OP);
8315 screen_attr = -1;
8316 }
8317 if (cterm_normal_fg_bold)
8318 {
8319 out_str(T_ME);
8320 screen_attr = -1;
8321 }
8322 }
8323}
8324
8325/*
8326 * Put character ScreenLines["off"] on the screen at position "row" and "col",
8327 * using the attributes from ScreenAttrs["off"].
8328 */
8329 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008330screen_char(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008331{
8332 int attr;
8333
8334 /* Check for illegal values, just in case (could happen just after
8335 * resizing). */
8336 if (row >= screen_Rows || col >= screen_Columns)
8337 return;
8338
Bram Moolenaar494838a2015-02-10 19:20:37 +01008339 /* Outputting a character in the last cell on the screen may scroll the
8340 * screen up. Only do it when the "xn" termcap property is set, otherwise
8341 * mark the character invalid (update it when scrolled up). */
8342 if (*T_XN == NUL
8343 && row == screen_Rows - 1 && col == screen_Columns - 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00008344#ifdef FEAT_RIGHTLEFT
8345 /* account for first command-line character in rightleft mode */
8346 && !cmdmsg_rl
8347#endif
8348 )
8349 {
8350 ScreenAttrs[off] = (sattr_T)-1;
8351 return;
8352 }
8353
8354 /*
8355 * Stop highlighting first, so it's easier to move the cursor.
8356 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008357 if (screen_char_attr != 0)
8358 attr = screen_char_attr;
8359 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008360 attr = ScreenAttrs[off];
8361 if (screen_attr != attr)
8362 screen_stop_highlight();
8363
8364 windgoto(row, col);
8365
8366 if (screen_attr != attr)
8367 screen_start_highlight(attr);
8368
8369#ifdef FEAT_MBYTE
8370 if (enc_utf8 && ScreenLinesUC[off] != 0)
8371 {
8372 char_u buf[MB_MAXBYTES + 1];
8373
Bram Moolenaarcb070082016-04-02 22:14:51 +02008374 if (utf_ambiguous_width(ScreenLinesUC[off]))
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008375 {
8376 if (*p_ambw == 'd'
8377# ifdef FEAT_GUI
8378 && !gui.in_use
8379# endif
8380 )
8381 {
8382 /* Clear the two screen cells. If the character is actually
8383 * single width it won't change the second cell. */
8384 out_str((char_u *)" ");
8385 term_windgoto(row, col);
8386 }
8387 /* not sure where the cursor is after drawing the ambiguous width
8388 * character */
Bram Moolenaarcb070082016-04-02 22:14:51 +02008389 screen_cur_col = 9999;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008390 }
Bram Moolenaarcb070082016-04-02 22:14:51 +02008391 else if (utf_char2cells(ScreenLinesUC[off]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008392 ++screen_cur_col;
Bram Moolenaarfae8ed12017-12-12 22:29:30 +01008393
8394 /* Convert the UTF-8 character to bytes and write it. */
8395 buf[utfc_char2bytes(off, buf)] = NUL;
8396 out_str(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008397 }
8398 else
8399#endif
8400 {
8401#ifdef FEAT_MBYTE
8402 out_flush_check();
8403#endif
8404 out_char(ScreenLines[off]);
8405#ifdef FEAT_MBYTE
8406 /* double-byte character in single-width cell */
8407 if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
8408 out_char(ScreenLines2[off]);
8409#endif
8410 }
8411
8412 screen_cur_col++;
8413}
8414
8415#ifdef FEAT_MBYTE
8416
8417/*
8418 * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
8419 * on the screen at position 'row' and 'col'.
8420 * The attributes of the first byte is used for all. This is required to
8421 * output the two bytes of a double-byte character with nothing in between.
8422 */
8423 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008424screen_char_2(unsigned off, int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008425{
8426 /* Check for illegal values (could be wrong when screen was resized). */
8427 if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
8428 return;
8429
8430 /* Outputting the last character on the screen may scrollup the screen.
8431 * Don't to it! Mark the character invalid (update it when scrolled up) */
8432 if (row == screen_Rows - 1 && col >= screen_Columns - 2)
8433 {
8434 ScreenAttrs[off] = (sattr_T)-1;
8435 return;
8436 }
8437
8438 /* Output the first byte normally (positions the cursor), then write the
8439 * second byte directly. */
8440 screen_char(off, row, col);
8441 out_char(ScreenLines[off + 1]);
8442 ++screen_cur_col;
8443}
8444#endif
8445
Bram Moolenaar071d4272004-06-13 20:20:40 +00008446/*
8447 * Draw a rectangle of the screen, inverted when "invert" is TRUE.
8448 * This uses the contents of ScreenLines[] and doesn't change it.
8449 */
8450 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008451screen_draw_rectangle(
8452 int row,
8453 int col,
8454 int height,
8455 int width,
8456 int invert)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008457{
8458 int r, c;
8459 int off;
Bram Moolenaar367329b2007-08-30 11:53:22 +00008460#ifdef FEAT_MBYTE
8461 int max_off;
8462#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008463
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008464 /* Can't use ScreenLines unless initialized */
8465 if (ScreenLines == NULL)
8466 return;
8467
Bram Moolenaar071d4272004-06-13 20:20:40 +00008468 if (invert)
8469 screen_char_attr = HL_INVERSE;
8470 for (r = row; r < row + height; ++r)
8471 {
8472 off = LineOffset[r];
Bram Moolenaar367329b2007-08-30 11:53:22 +00008473#ifdef FEAT_MBYTE
8474 max_off = off + screen_Columns;
8475#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008476 for (c = col; c < col + width; ++c)
8477 {
8478#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00008479 if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008480 {
8481 screen_char_2(off + c, r, c);
8482 ++c;
8483 }
8484 else
8485#endif
8486 {
8487 screen_char(off + c, r, c);
8488#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00008489 if (utf_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008490 ++c;
8491#endif
8492 }
8493 }
8494 }
8495 screen_char_attr = 0;
8496}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008497
Bram Moolenaar071d4272004-06-13 20:20:40 +00008498/*
8499 * Redraw the characters for a vertically split window.
8500 */
8501 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008502redraw_block(int row, int end, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008503{
8504 int col;
8505 int width;
8506
8507# ifdef FEAT_CLIPBOARD
8508 clip_may_clear_selection(row, end - 1);
8509# endif
8510
8511 if (wp == NULL)
8512 {
8513 col = 0;
8514 width = Columns;
8515 }
8516 else
8517 {
8518 col = wp->w_wincol;
8519 width = wp->w_width;
8520 }
8521 screen_draw_rectangle(row, col, end - row, width, FALSE);
8522}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008523
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008524 static void
8525space_to_screenline(int off, int attr)
8526{
8527 ScreenLines[off] = ' ';
8528 ScreenAttrs[off] = attr;
8529# ifdef FEAT_MBYTE
8530 if (enc_utf8)
8531 ScreenLinesUC[off] = 0;
8532# endif
8533}
8534
Bram Moolenaar071d4272004-06-13 20:20:40 +00008535/*
8536 * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
8537 * with character 'c1' in first column followed by 'c2' in the other columns.
8538 * Use attributes 'attr'.
8539 */
8540 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008541screen_fill(
8542 int start_row,
8543 int end_row,
8544 int start_col,
8545 int end_col,
8546 int c1,
8547 int c2,
8548 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008549{
8550 int row;
8551 int col;
8552 int off;
8553 int end_off;
8554 int did_delete;
8555 int c;
8556 int norm_term;
8557#if defined(FEAT_GUI) || defined(UNIX)
8558 int force_next = FALSE;
8559#endif
8560
8561 if (end_row > screen_Rows) /* safety check */
8562 end_row = screen_Rows;
8563 if (end_col > screen_Columns) /* safety check */
8564 end_col = screen_Columns;
8565 if (ScreenLines == NULL
8566 || start_row >= end_row
8567 || start_col >= end_col) /* nothing to do */
8568 return;
8569
8570 /* it's a "normal" terminal when not in a GUI or cterm */
8571 norm_term = (
8572#ifdef FEAT_GUI
8573 !gui.in_use &&
8574#endif
Bram Moolenaar8a633e32016-04-21 21:10:14 +02008575 !IS_CTERM);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008576 for (row = start_row; row < end_row; ++row)
8577 {
Bram Moolenaarc236c162008-07-13 17:41:49 +00008578#ifdef FEAT_MBYTE
8579 if (has_mbyte
8580# ifdef FEAT_GUI
8581 && !gui.in_use
8582# endif
8583 )
8584 {
8585 /* When drawing over the right halve of a double-wide char clear
8586 * out the left halve. When drawing over the left halve of a
8587 * double wide-char clear out the right halve. Only needed in a
8588 * terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00008589 if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00008590 screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
Bram Moolenaara1aed622008-07-18 15:14:43 +00008591 if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00008592 screen_puts_len((char_u *)" ", 1, row, end_col, 0);
Bram Moolenaarc236c162008-07-13 17:41:49 +00008593 }
8594#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008595 /*
8596 * Try to use delete-line termcap code, when no attributes or in a
8597 * "normal" terminal, where a bold/italic space is just a
8598 * space.
8599 */
8600 did_delete = FALSE;
8601 if (c2 == ' '
8602 && end_col == Columns
8603 && can_clear(T_CE)
8604 && (attr == 0
8605 || (norm_term
8606 && attr <= HL_ALL
8607 && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
8608 {
8609 /*
8610 * check if we really need to clear something
8611 */
8612 col = start_col;
8613 if (c1 != ' ') /* don't clear first char */
8614 ++col;
8615
8616 off = LineOffset[row] + col;
8617 end_off = LineOffset[row] + end_col;
8618
8619 /* skip blanks (used often, keep it fast!) */
8620#ifdef FEAT_MBYTE
8621 if (enc_utf8)
8622 while (off < end_off && ScreenLines[off] == ' '
8623 && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
8624 ++off;
8625 else
8626#endif
8627 while (off < end_off && ScreenLines[off] == ' '
8628 && ScreenAttrs[off] == 0)
8629 ++off;
8630 if (off < end_off) /* something to be cleared */
8631 {
8632 col = off - LineOffset[row];
8633 screen_stop_highlight();
8634 term_windgoto(row, col);/* clear rest of this screen line */
8635 out_str(T_CE);
8636 screen_start(); /* don't know where cursor is now */
8637 col = end_col - col;
8638 while (col--) /* clear chars in ScreenLines */
8639 {
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02008640 space_to_screenline(off, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008641 ++off;
8642 }
8643 }
8644 did_delete = TRUE; /* the chars are cleared now */
8645 }
8646
8647 off = LineOffset[row] + start_col;
8648 c = c1;
8649 for (col = start_col; col < end_col; ++col)
8650 {
8651 if (ScreenLines[off] != c
8652#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008653 || (enc_utf8 && (int)ScreenLinesUC[off]
8654 != (c >= 0x80 ? c : 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008655#endif
8656 || ScreenAttrs[off] != attr
8657#if defined(FEAT_GUI) || defined(UNIX)
8658 || force_next
8659#endif
8660 )
8661 {
8662#if defined(FEAT_GUI) || defined(UNIX)
8663 /* The bold trick may make a single row of pixels appear in
8664 * the next character. When a bold character is removed, the
8665 * next character should be redrawn too. This happens for our
8666 * own GUI and for some xterms. */
8667 if (
8668# ifdef FEAT_GUI
8669 gui.in_use
8670# endif
8671# if defined(FEAT_GUI) && defined(UNIX)
8672 ||
8673# endif
8674# ifdef UNIX
8675 term_is_xterm
8676# endif
8677 )
8678 {
8679 if (ScreenLines[off] != ' '
8680 && (ScreenAttrs[off] > HL_ALL
8681 || ScreenAttrs[off] & HL_BOLD))
8682 force_next = TRUE;
8683 else
8684 force_next = FALSE;
8685 }
8686#endif
8687 ScreenLines[off] = c;
8688#ifdef FEAT_MBYTE
8689 if (enc_utf8)
8690 {
8691 if (c >= 0x80)
8692 {
8693 ScreenLinesUC[off] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008694 ScreenLinesC[0][off] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008695 }
8696 else
8697 ScreenLinesUC[off] = 0;
8698 }
8699#endif
8700 ScreenAttrs[off] = attr;
8701 if (!did_delete || c != ' ')
8702 screen_char(off, row, col);
8703 }
8704 ++off;
8705 if (col == start_col)
8706 {
8707 if (did_delete)
8708 break;
8709 c = c2;
8710 }
8711 }
8712 if (end_col == Columns)
8713 LineWraps[row] = FALSE;
8714 if (row == Rows - 1) /* overwritten the command line */
8715 {
8716 redraw_cmdline = TRUE;
Bram Moolenaar5bab5552018-04-13 20:41:29 +02008717 if (start_col == 0 && end_col == Columns
8718 && c1 == ' ' && c2 == ' ' && attr == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008719 clear_cmdline = FALSE; /* command line has been cleared */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00008720 if (start_col == 0)
8721 mode_displayed = FALSE; /* mode cleared or overwritten */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008722 }
8723 }
8724}
8725
8726/*
8727 * Check if there should be a delay. Used before clearing or redrawing the
8728 * screen or the command line.
8729 */
8730 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008731check_for_delay(int check_msg_scroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008732{
8733 if ((emsg_on_display || (check_msg_scroll && msg_scroll))
8734 && !did_wait_return
8735 && emsg_silent == 0)
8736 {
8737 out_flush();
8738 ui_delay(1000L, TRUE);
8739 emsg_on_display = FALSE;
8740 if (check_msg_scroll)
8741 msg_scroll = FALSE;
8742 }
8743}
8744
8745/*
8746 * screen_valid - allocate screen buffers if size changed
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008747 * If "doclear" is TRUE: clear screen if it has been resized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008748 * Returns TRUE if there is a valid screen to write to.
8749 * Returns FALSE when starting up and screen not initialized yet.
8750 */
8751 int
Bram Moolenaar05540972016-01-30 20:31:25 +01008752screen_valid(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008753{
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008754 screenalloc(doclear); /* allocate screen buffers if size changed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008755 return (ScreenLines != NULL);
8756}
8757
8758/*
8759 * Resize the shell to Rows and Columns.
8760 * Allocate ScreenLines[] and associated items.
8761 *
8762 * There may be some time between setting Rows and Columns and (re)allocating
8763 * ScreenLines[]. This happens when starting up and when (manually) changing
8764 * the shell size. Always use screen_Rows and screen_Columns to access items
8765 * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
8766 * final size of the shell is needed.
8767 */
8768 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008769screenalloc(int doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008770{
8771 int new_row, old_row;
8772#ifdef FEAT_GUI
8773 int old_Rows;
8774#endif
8775 win_T *wp;
8776 int outofmem = FALSE;
8777 int len;
8778 schar_T *new_ScreenLines;
8779#ifdef FEAT_MBYTE
8780 u8char_T *new_ScreenLinesUC = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008781 u8char_T *new_ScreenLinesC[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008782 schar_T *new_ScreenLines2 = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008783 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008784#endif
8785 sattr_T *new_ScreenAttrs;
8786 unsigned *new_LineOffset;
8787 char_u *new_LineWraps;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008788 short *new_TabPageIdxs;
Bram Moolenaarf740b292006-02-16 22:11:02 +00008789 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008790 static int entered = FALSE; /* avoid recursiveness */
Bram Moolenaar89d40322006-08-29 15:30:07 +00008791 static int done_outofmem_msg = FALSE; /* did outofmem message */
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008792 int retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008793
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008794retry:
Bram Moolenaar071d4272004-06-13 20:20:40 +00008795 /*
8796 * Allocation of the screen buffers is done only when the size changes and
8797 * when Rows and Columns have been set and we have started doing full
8798 * screen stuff.
8799 */
8800 if ((ScreenLines != NULL
8801 && Rows == screen_Rows
8802 && Columns == screen_Columns
8803#ifdef FEAT_MBYTE
8804 && enc_utf8 == (ScreenLinesUC != NULL)
8805 && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008806 && p_mco == Screen_mco
Bram Moolenaar071d4272004-06-13 20:20:40 +00008807#endif
8808 )
8809 || Rows == 0
8810 || Columns == 0
8811 || (!full_screen && ScreenLines == NULL))
8812 return;
8813
8814 /*
8815 * It's possible that we produce an out-of-memory message below, which
8816 * will cause this function to be called again. To break the loop, just
8817 * return here.
8818 */
8819 if (entered)
8820 return;
8821 entered = TRUE;
8822
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00008823 /*
8824 * Note that the window sizes are updated before reallocating the arrays,
8825 * thus we must not redraw here!
8826 */
8827 ++RedrawingDisabled;
8828
Bram Moolenaar071d4272004-06-13 20:20:40 +00008829 win_new_shellsize(); /* fit the windows in the new sized shell */
8830
Bram Moolenaar071d4272004-06-13 20:20:40 +00008831 comp_col(); /* recompute columns for shown command and ruler */
8832
8833 /*
8834 * We're changing the size of the screen.
8835 * - Allocate new arrays for ScreenLines and ScreenAttrs.
8836 * - Move lines from the old arrays into the new arrays, clear extra
8837 * lines (unless the screen is going to be cleared).
8838 * - Free the old arrays.
8839 *
8840 * If anything fails, make ScreenLines NULL, so we don't do anything!
8841 * Continuing with the old ScreenLines may result in a crash, because the
8842 * size is wrong.
8843 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00008844 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008845 win_free_lsize(wp);
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00008846 if (aucmd_win != NULL)
8847 win_free_lsize(aucmd_win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008848
8849 new_ScreenLines = (schar_T *)lalloc((long_u)(
8850 (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
8851#ifdef FEAT_MBYTE
Bram Moolenaar216b7102010-03-23 13:56:59 +01008852 vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008853 if (enc_utf8)
8854 {
8855 new_ScreenLinesUC = (u8char_T *)lalloc((long_u)(
8856 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008857 for (i = 0; i < p_mco; ++i)
Bram Moolenaar70c49c12010-03-23 15:36:35 +01008858 new_ScreenLinesC[i] = (u8char_T *)lalloc_clear((long_u)(
Bram Moolenaar071d4272004-06-13 20:20:40 +00008859 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
8860 }
8861 if (enc_dbcs == DBCS_JPNU)
8862 new_ScreenLines2 = (schar_T *)lalloc((long_u)(
8863 (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
8864#endif
8865 new_ScreenAttrs = (sattr_T *)lalloc((long_u)(
8866 (Rows + 1) * Columns * sizeof(sattr_T)), FALSE);
8867 new_LineOffset = (unsigned *)lalloc((long_u)(
8868 Rows * sizeof(unsigned)), FALSE);
8869 new_LineWraps = (char_u *)lalloc((long_u)(Rows * sizeof(char_u)), FALSE);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00008870 new_TabPageIdxs = (short *)lalloc((long_u)(Columns * sizeof(short)), FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008871
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00008872 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008873 {
8874 if (win_alloc_lines(wp) == FAIL)
8875 {
8876 outofmem = TRUE;
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00008877 goto give_up;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008878 }
8879 }
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00008880 if (aucmd_win != NULL && aucmd_win->w_lines == NULL
8881 && win_alloc_lines(aucmd_win) == FAIL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008882 outofmem = TRUE;
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00008883give_up:
Bram Moolenaar071d4272004-06-13 20:20:40 +00008884
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008885#ifdef FEAT_MBYTE
8886 for (i = 0; i < p_mco; ++i)
8887 if (new_ScreenLinesC[i] == NULL)
8888 break;
8889#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008890 if (new_ScreenLines == NULL
8891#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008892 || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008893 || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
8894#endif
8895 || new_ScreenAttrs == NULL
8896 || new_LineOffset == NULL
8897 || new_LineWraps == NULL
Bram Moolenaarf740b292006-02-16 22:11:02 +00008898 || new_TabPageIdxs == NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008899 || outofmem)
8900 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00008901 if (ScreenLines != NULL || !done_outofmem_msg)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008902 {
8903 /* guess the size */
8904 do_outofmem_msg((long_u)((Rows + 1) * Columns));
8905
8906 /* Remember we did this to avoid getting outofmem messages over
8907 * and over again. */
Bram Moolenaar89d40322006-08-29 15:30:07 +00008908 done_outofmem_msg = TRUE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008909 }
Bram Moolenaard23a8232018-02-10 18:45:26 +01008910 VIM_CLEAR(new_ScreenLines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008911#ifdef FEAT_MBYTE
Bram Moolenaard23a8232018-02-10 18:45:26 +01008912 VIM_CLEAR(new_ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008913 for (i = 0; i < p_mco; ++i)
Bram Moolenaard23a8232018-02-10 18:45:26 +01008914 VIM_CLEAR(new_ScreenLinesC[i]);
8915 VIM_CLEAR(new_ScreenLines2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008916#endif
Bram Moolenaard23a8232018-02-10 18:45:26 +01008917 VIM_CLEAR(new_ScreenAttrs);
8918 VIM_CLEAR(new_LineOffset);
8919 VIM_CLEAR(new_LineWraps);
8920 VIM_CLEAR(new_TabPageIdxs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008921 }
8922 else
8923 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00008924 done_outofmem_msg = FALSE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008925
Bram Moolenaar071d4272004-06-13 20:20:40 +00008926 for (new_row = 0; new_row < Rows; ++new_row)
8927 {
8928 new_LineOffset[new_row] = new_row * Columns;
8929 new_LineWraps[new_row] = FALSE;
8930
8931 /*
8932 * If the screen is not going to be cleared, copy as much as
8933 * possible from the old screen to the new one and clear the rest
8934 * (used when resizing the window at the "--more--" prompt or when
8935 * executing an external command, for the GUI).
8936 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01008937 if (!doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008938 {
8939 (void)vim_memset(new_ScreenLines + new_row * Columns,
8940 ' ', (size_t)Columns * sizeof(schar_T));
8941#ifdef FEAT_MBYTE
8942 if (enc_utf8)
8943 {
8944 (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
8945 0, (size_t)Columns * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008946 for (i = 0; i < p_mco; ++i)
8947 (void)vim_memset(new_ScreenLinesC[i]
8948 + new_row * Columns,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008949 0, (size_t)Columns * sizeof(u8char_T));
8950 }
8951 if (enc_dbcs == DBCS_JPNU)
8952 (void)vim_memset(new_ScreenLines2 + new_row * Columns,
8953 0, (size_t)Columns * sizeof(schar_T));
8954#endif
8955 (void)vim_memset(new_ScreenAttrs + new_row * Columns,
8956 0, (size_t)Columns * sizeof(sattr_T));
8957 old_row = new_row + (screen_Rows - Rows);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00008958 if (old_row >= 0 && ScreenLines != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008959 {
8960 if (screen_Columns < Columns)
8961 len = screen_Columns;
8962 else
8963 len = Columns;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00008964#ifdef FEAT_MBYTE
Bram Moolenaarf4d11452005-12-02 00:46:37 +00008965 /* When switching to utf-8 don't copy characters, they
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008966 * may be invalid now. Also when p_mco changes. */
8967 if (!(enc_utf8 && ScreenLinesUC == NULL)
8968 && p_mco == Screen_mco)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00008969#endif
8970 mch_memmove(new_ScreenLines + new_LineOffset[new_row],
8971 ScreenLines + LineOffset[old_row],
8972 (size_t)len * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008973#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008974 if (enc_utf8 && ScreenLinesUC != NULL
8975 && p_mco == Screen_mco)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008976 {
8977 mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
8978 ScreenLinesUC + LineOffset[old_row],
8979 (size_t)len * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008980 for (i = 0; i < p_mco; ++i)
8981 mch_memmove(new_ScreenLinesC[i]
8982 + new_LineOffset[new_row],
8983 ScreenLinesC[i] + LineOffset[old_row],
Bram Moolenaar071d4272004-06-13 20:20:40 +00008984 (size_t)len * sizeof(u8char_T));
8985 }
8986 if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
8987 mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
8988 ScreenLines2 + LineOffset[old_row],
8989 (size_t)len * sizeof(schar_T));
8990#endif
8991 mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
8992 ScreenAttrs + LineOffset[old_row],
8993 (size_t)len * sizeof(sattr_T));
8994 }
8995 }
8996 }
8997 /* Use the last line of the screen for the current line. */
8998 current_ScreenLine = new_ScreenLines + Rows * Columns;
8999 }
9000
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009001 free_screenlines();
9002
Bram Moolenaar071d4272004-06-13 20:20:40 +00009003 ScreenLines = new_ScreenLines;
9004#ifdef FEAT_MBYTE
9005 ScreenLinesUC = new_ScreenLinesUC;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009006 for (i = 0; i < p_mco; ++i)
9007 ScreenLinesC[i] = new_ScreenLinesC[i];
9008 Screen_mco = p_mco;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009009 ScreenLines2 = new_ScreenLines2;
9010#endif
9011 ScreenAttrs = new_ScreenAttrs;
9012 LineOffset = new_LineOffset;
9013 LineWraps = new_LineWraps;
Bram Moolenaarf740b292006-02-16 22:11:02 +00009014 TabPageIdxs = new_TabPageIdxs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009015
9016 /* It's important that screen_Rows and screen_Columns reflect the actual
9017 * size of ScreenLines[]. Set them before calling anything. */
9018#ifdef FEAT_GUI
9019 old_Rows = screen_Rows;
9020#endif
9021 screen_Rows = Rows;
9022 screen_Columns = Columns;
9023
9024 must_redraw = CLEAR; /* need to clear the screen later */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01009025 if (doclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009026 screenclear2();
9027
9028#ifdef FEAT_GUI
9029 else if (gui.in_use
9030 && !gui.starting
9031 && ScreenLines != NULL
9032 && old_Rows != Rows)
9033 {
9034 (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
9035 /*
9036 * Adjust the position of the cursor, for when executing an external
9037 * command.
9038 */
9039 if (msg_row >= Rows) /* Rows got smaller */
9040 msg_row = Rows - 1; /* put cursor at last row */
9041 else if (Rows > old_Rows) /* Rows got bigger */
9042 msg_row += Rows - old_Rows; /* put cursor in same place */
9043 if (msg_col >= Columns) /* Columns got smaller */
9044 msg_col = Columns - 1; /* put cursor at last column */
9045 }
9046#endif
9047
Bram Moolenaar071d4272004-06-13 20:20:40 +00009048 entered = FALSE;
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00009049 --RedrawingDisabled;
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00009050
Bram Moolenaar87e817c2009-02-22 20:13:39 +00009051 /*
9052 * Do not apply autocommands more than 3 times to avoid an endless loop
9053 * in case applying autocommands always changes Rows or Columns.
9054 */
9055 if (starting == 0 && ++retry_count <= 3)
9056 {
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00009057 apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar87e817c2009-02-22 20:13:39 +00009058 /* In rare cases, autocommands may have altered Rows or Columns,
9059 * jump back to check if we need to allocate the screen again. */
9060 goto retry;
9061 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009062}
9063
9064 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009065free_screenlines(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009066{
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009067#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009068 int i;
9069
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009070 vim_free(ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009071 for (i = 0; i < Screen_mco; ++i)
9072 vim_free(ScreenLinesC[i]);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009073 vim_free(ScreenLines2);
9074#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009075 vim_free(ScreenLines);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009076 vim_free(ScreenAttrs);
9077 vim_free(LineOffset);
9078 vim_free(LineWraps);
Bram Moolenaarf740b292006-02-16 22:11:02 +00009079 vim_free(TabPageIdxs);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00009080}
9081
9082 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009083screenclear(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009084{
9085 check_for_delay(FALSE);
9086 screenalloc(FALSE); /* allocate screen buffers if size changed */
9087 screenclear2(); /* clear the screen */
9088}
9089
9090 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009091screenclear2(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009092{
9093 int i;
9094
9095 if (starting == NO_SCREEN || ScreenLines == NULL
9096#ifdef FEAT_GUI
9097 || (gui.in_use && gui.starting)
9098#endif
9099 )
9100 return;
9101
9102#ifdef FEAT_GUI
9103 if (!gui.in_use)
9104#endif
9105 screen_attr = -1; /* force setting the Normal colors */
9106 screen_stop_highlight(); /* don't want highlighting here */
9107
9108#ifdef FEAT_CLIPBOARD
9109 /* disable selection without redrawing it */
9110 clip_scroll_selection(9999);
9111#endif
9112
9113 /* blank out ScreenLines */
9114 for (i = 0; i < Rows; ++i)
9115 {
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009116 lineclear(LineOffset[i], (int)Columns, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009117 LineWraps[i] = FALSE;
9118 }
9119
9120 if (can_clear(T_CL))
9121 {
9122 out_str(T_CL); /* clear the display */
9123 clear_cmdline = FALSE;
Bram Moolenaard12f5c12006-01-25 22:10:52 +00009124 mode_displayed = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009125 }
9126 else
9127 {
9128 /* can't clear the screen, mark all chars with invalid attributes */
9129 for (i = 0; i < Rows; ++i)
9130 lineinvalid(LineOffset[i], (int)Columns);
9131 clear_cmdline = TRUE;
9132 }
9133
9134 screen_cleared = TRUE; /* can use contents of ScreenLines now */
9135
9136 win_rest_invalid(firstwin);
9137 redraw_cmdline = TRUE;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00009138 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009139 if (must_redraw == CLEAR) /* no need to clear again */
9140 must_redraw = NOT_VALID;
9141 compute_cmdrow();
9142 msg_row = cmdline_row; /* put cursor on last line for messages */
9143 msg_col = 0;
9144 screen_start(); /* don't know where cursor is now */
9145 msg_scrolled = 0; /* can't scroll back */
9146 msg_didany = FALSE;
9147 msg_didout = FALSE;
9148}
9149
9150/*
9151 * Clear one line in ScreenLines.
9152 */
9153 static void
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009154lineclear(unsigned off, int width, int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009155{
9156 (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
9157#ifdef FEAT_MBYTE
9158 if (enc_utf8)
9159 (void)vim_memset(ScreenLinesUC + off, 0,
9160 (size_t)width * sizeof(u8char_T));
9161#endif
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009162 (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00009163}
9164
9165/*
9166 * Mark one line in ScreenLines invalid by setting the attributes to an
9167 * invalid value.
9168 */
9169 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009170lineinvalid(unsigned off, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009171{
9172 (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
9173}
9174
Bram Moolenaar071d4272004-06-13 20:20:40 +00009175/*
9176 * Copy part of a Screenline for vertically split window "wp".
9177 */
9178 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009179linecopy(int to, int from, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009180{
9181 unsigned off_to = LineOffset[to] + wp->w_wincol;
9182 unsigned off_from = LineOffset[from] + wp->w_wincol;
9183
9184 mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
9185 wp->w_width * sizeof(schar_T));
Bram Moolenaar4033c552017-09-16 20:54:51 +02009186#ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00009187 if (enc_utf8)
9188 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009189 int i;
9190
Bram Moolenaar071d4272004-06-13 20:20:40 +00009191 mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
9192 wp->w_width * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00009193 for (i = 0; i < p_mco; ++i)
9194 mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
9195 wp->w_width * sizeof(u8char_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00009196 }
9197 if (enc_dbcs == DBCS_JPNU)
9198 mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
9199 wp->w_width * sizeof(schar_T));
Bram Moolenaar4033c552017-09-16 20:54:51 +02009200#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009201 mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
9202 wp->w_width * sizeof(sattr_T));
9203}
Bram Moolenaar071d4272004-06-13 20:20:40 +00009204
9205/*
9206 * Return TRUE if clearing with term string "p" would work.
9207 * It can't work when the string is empty or it won't set the right background.
9208 */
9209 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009210can_clear(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009211{
9212 return (*p != NUL && (t_colors <= 1
9213#ifdef FEAT_GUI
9214 || gui.in_use
9215#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +02009216#ifdef FEAT_TERMGUICOLORS
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02009217 || (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
Bram Moolenaard18f6722016-06-17 13:18:49 +02009218 || (!p_tgc && cterm_normal_bg_color == 0)
9219#else
9220 || cterm_normal_bg_color == 0
Bram Moolenaar8a633e32016-04-21 21:10:14 +02009221#endif
Bram Moolenaard18f6722016-06-17 13:18:49 +02009222 || *T_UT != NUL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00009223}
9224
9225/*
9226 * Reset cursor position. Use whenever cursor was moved because of outputting
9227 * something directly to the screen (shell commands) or a terminal control
9228 * code.
9229 */
9230 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009231screen_start(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009232{
9233 screen_cur_row = screen_cur_col = 9999;
9234}
9235
9236/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00009237 * Move the cursor to position "row","col" in the screen.
9238 * This tries to find the most efficient way to move, minimizing the number of
9239 * characters sent to the terminal.
9240 */
9241 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009242windgoto(int row, int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009243{
Bram Moolenaare2cc9702005-03-15 22:43:58 +00009244 sattr_T *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009245 int i;
9246 int plan;
9247 int cost;
9248 int wouldbe_col;
9249 int noinvcurs;
9250 char_u *bs;
9251 int goto_cost;
9252 int attr;
9253
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00009254#define GOTO_COST 7 /* assume a term_windgoto() takes about 7 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009255#define HIGHL_COST 5 /* assume unhighlight takes 5 chars */
9256
9257#define PLAN_LE 1
9258#define PLAN_CR 2
9259#define PLAN_NL 3
9260#define PLAN_WRITE 4
9261 /* Can't use ScreenLines unless initialized */
9262 if (ScreenLines == NULL)
9263 return;
9264
9265 if (col != screen_cur_col || row != screen_cur_row)
9266 {
9267 /* Check for valid position. */
9268 if (row < 0) /* window without text lines? */
9269 row = 0;
9270 if (row >= screen_Rows)
9271 row = screen_Rows - 1;
9272 if (col >= screen_Columns)
9273 col = screen_Columns - 1;
9274
9275 /* check if no cursor movement is allowed in highlight mode */
9276 if (screen_attr && *T_MS == NUL)
9277 noinvcurs = HIGHL_COST;
9278 else
9279 noinvcurs = 0;
9280 goto_cost = GOTO_COST + noinvcurs;
9281
9282 /*
9283 * Plan how to do the positioning:
9284 * 1. Use CR to move it to column 0, same row.
9285 * 2. Use T_LE to move it a few columns to the left.
9286 * 3. Use NL to move a few lines down, column 0.
9287 * 4. Move a few columns to the right with T_ND or by writing chars.
9288 *
9289 * Don't do this if the cursor went beyond the last column, the cursor
9290 * position is unknown then (some terminals wrap, some don't )
9291 *
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00009292 * First check if the highlighting attributes allow us to write
Bram Moolenaar071d4272004-06-13 20:20:40 +00009293 * characters to move the cursor to the right.
9294 */
9295 if (row >= screen_cur_row && screen_cur_col < Columns)
9296 {
9297 /*
9298 * If the cursor is in the same row, bigger col, we can use CR
9299 * or T_LE.
9300 */
9301 bs = NULL; /* init for GCC */
9302 attr = screen_attr;
9303 if (row == screen_cur_row && col < screen_cur_col)
9304 {
9305 /* "le" is preferred over "bc", because "bc" is obsolete */
9306 if (*T_LE)
9307 bs = T_LE; /* "cursor left" */
9308 else
9309 bs = T_BC; /* "backspace character (old) */
9310 if (*bs)
9311 cost = (screen_cur_col - col) * (int)STRLEN(bs);
9312 else
9313 cost = 999;
9314 if (col + 1 < cost) /* using CR is less characters */
9315 {
9316 plan = PLAN_CR;
9317 wouldbe_col = 0;
9318 cost = 1; /* CR is just one character */
9319 }
9320 else
9321 {
9322 plan = PLAN_LE;
9323 wouldbe_col = col;
9324 }
9325 if (noinvcurs) /* will stop highlighting */
9326 {
9327 cost += noinvcurs;
9328 attr = 0;
9329 }
9330 }
9331
9332 /*
9333 * If the cursor is above where we want to be, we can use CR LF.
9334 */
9335 else if (row > screen_cur_row)
9336 {
9337 plan = PLAN_NL;
9338 wouldbe_col = 0;
9339 cost = (row - screen_cur_row) * 2; /* CR LF */
9340 if (noinvcurs) /* will stop highlighting */
9341 {
9342 cost += noinvcurs;
9343 attr = 0;
9344 }
9345 }
9346
9347 /*
9348 * If the cursor is in the same row, smaller col, just use write.
9349 */
9350 else
9351 {
9352 plan = PLAN_WRITE;
9353 wouldbe_col = screen_cur_col;
9354 cost = 0;
9355 }
9356
9357 /*
9358 * Check if any characters that need to be written have the
9359 * correct attributes. Also avoid UTF-8 characters.
9360 */
9361 i = col - wouldbe_col;
9362 if (i > 0)
9363 cost += i;
9364 if (cost < goto_cost && i > 0)
9365 {
9366 /*
9367 * Check if the attributes are correct without additionally
9368 * stopping highlighting.
9369 */
9370 p = ScreenAttrs + LineOffset[row] + wouldbe_col;
9371 while (i && *p++ == attr)
9372 --i;
9373 if (i != 0)
9374 {
9375 /*
9376 * Try if it works when highlighting is stopped here.
9377 */
9378 if (*--p == 0)
9379 {
9380 cost += noinvcurs;
9381 while (i && *p++ == 0)
9382 --i;
9383 }
9384 if (i != 0)
9385 cost = 999; /* different attributes, don't do it */
9386 }
9387#ifdef FEAT_MBYTE
9388 if (enc_utf8)
9389 {
9390 /* Don't use an UTF-8 char for positioning, it's slow. */
9391 for (i = wouldbe_col; i < col; ++i)
9392 if (ScreenLinesUC[LineOffset[row] + i] != 0)
9393 {
9394 cost = 999;
9395 break;
9396 }
9397 }
9398#endif
9399 }
9400
9401 /*
9402 * We can do it without term_windgoto()!
9403 */
9404 if (cost < goto_cost)
9405 {
9406 if (plan == PLAN_LE)
9407 {
9408 if (noinvcurs)
9409 screen_stop_highlight();
9410 while (screen_cur_col > col)
9411 {
9412 out_str(bs);
9413 --screen_cur_col;
9414 }
9415 }
9416 else if (plan == PLAN_CR)
9417 {
9418 if (noinvcurs)
9419 screen_stop_highlight();
9420 out_char('\r');
9421 screen_cur_col = 0;
9422 }
9423 else if (plan == PLAN_NL)
9424 {
9425 if (noinvcurs)
9426 screen_stop_highlight();
9427 while (screen_cur_row < row)
9428 {
9429 out_char('\n');
9430 ++screen_cur_row;
9431 }
9432 screen_cur_col = 0;
9433 }
9434
9435 i = col - screen_cur_col;
9436 if (i > 0)
9437 {
9438 /*
9439 * Use cursor-right if it's one character only. Avoids
9440 * removing a line of pixels from the last bold char, when
9441 * using the bold trick in the GUI.
9442 */
9443 if (T_ND[0] != NUL && T_ND[1] == NUL)
9444 {
9445 while (i-- > 0)
9446 out_char(*T_ND);
9447 }
9448 else
9449 {
9450 int off;
9451
9452 off = LineOffset[row] + screen_cur_col;
9453 while (i-- > 0)
9454 {
9455 if (ScreenAttrs[off] != screen_attr)
9456 screen_stop_highlight();
9457#ifdef FEAT_MBYTE
9458 out_flush_check();
9459#endif
9460 out_char(ScreenLines[off]);
9461#ifdef FEAT_MBYTE
9462 if (enc_dbcs == DBCS_JPNU
9463 && ScreenLines[off] == 0x8e)
9464 out_char(ScreenLines2[off]);
9465#endif
9466 ++off;
9467 }
9468 }
9469 }
9470 }
9471 }
9472 else
9473 cost = 999;
9474
9475 if (cost >= goto_cost)
9476 {
9477 if (noinvcurs)
9478 screen_stop_highlight();
Bram Moolenaar597a4222014-06-25 14:39:50 +02009479 if (row == screen_cur_row && (col > screen_cur_col)
9480 && *T_CRI != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009481 term_cursor_right(col - screen_cur_col);
9482 else
9483 term_windgoto(row, col);
9484 }
9485 screen_cur_row = row;
9486 screen_cur_col = col;
9487 }
9488}
9489
9490/*
9491 * Set cursor to its position in the current window.
9492 */
9493 void
Bram Moolenaar05540972016-01-30 20:31:25 +01009494setcursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009495{
Bram Moolenaar987723e2018-03-06 11:43:04 +01009496 setcursor_mayforce(FALSE);
9497}
9498
9499/*
9500 * Set cursor to its position in the current window.
9501 * When "force" is TRUE also when not redrawing.
9502 */
9503 void
9504setcursor_mayforce(int force)
9505{
9506 if (force || redrawing())
Bram Moolenaar071d4272004-06-13 20:20:40 +00009507 {
9508 validate_cursor();
9509 windgoto(W_WINROW(curwin) + curwin->w_wrow,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009510 curwin->w_wincol + (
Bram Moolenaar071d4272004-06-13 20:20:40 +00009511#ifdef FEAT_RIGHTLEFT
Bram Moolenaar561f9db2008-02-20 13:16:29 +00009512 /* With 'rightleft' set and the cursor on a double-wide
9513 * character, position it on the leftmost column. */
Bram Moolenaar02631462017-09-22 15:20:32 +02009514 curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol - (
Bram Moolenaar071d4272004-06-13 20:20:40 +00009515# ifdef FEAT_MBYTE
Bram Moolenaar561f9db2008-02-20 13:16:29 +00009516 (has_mbyte
9517 && (*mb_ptr2cells)(ml_get_cursor()) == 2
9518 && vim_isprintc(gchar_cursor())) ? 2 :
Bram Moolenaar071d4272004-06-13 20:20:40 +00009519# endif
9520 1)) :
9521#endif
9522 curwin->w_wcol));
9523 }
9524}
9525
9526
9527/*
Bram Moolenaar86033562017-07-12 20:24:41 +02009528 * Insert 'line_count' lines at 'row' in window 'wp'.
9529 * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
9530 * If 'mayclear' is TRUE the screen will be cleared if it is faster than
Bram Moolenaar071d4272004-06-13 20:20:40 +00009531 * scrolling.
9532 * Returns FAIL if the lines are not inserted, OK for success.
9533 */
9534 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009535win_ins_lines(
9536 win_T *wp,
9537 int row,
9538 int line_count,
9539 int invalid,
9540 int mayclear)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009541{
9542 int did_delete;
9543 int nextrow;
9544 int lastrow;
9545 int retval;
9546
9547 if (invalid)
9548 wp->w_lines_valid = 0;
9549
9550 if (wp->w_height < 5)
9551 return FAIL;
9552
9553 if (line_count > wp->w_height - row)
9554 line_count = wp->w_height - row;
9555
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009556 retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009557 if (retval != MAYBE)
9558 return retval;
9559
9560 /*
9561 * If there is a next window or a status line, we first try to delete the
9562 * lines at the bottom to avoid messing what is after the window.
9563 * If this fails and there are following windows, don't do anything to avoid
9564 * messing up those windows, better just redraw.
9565 */
9566 did_delete = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009567 if (wp->w_next != NULL || wp->w_status_height)
9568 {
9569 if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009570 line_count, (int)Rows, FALSE, 0, NULL) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009571 did_delete = TRUE;
9572 else if (wp->w_next)
9573 return FAIL;
9574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009575 /*
9576 * if no lines deleted, blank the lines that will end up below the window
9577 */
9578 if (!did_delete)
9579 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009580 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009581 redraw_cmdline = TRUE;
Bram Moolenaare0de17d2017-09-24 16:24:34 +02009582 nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009583 lastrow = nextrow + line_count;
9584 if (lastrow > Rows)
9585 lastrow = Rows;
9586 screen_fill(nextrow - line_count, lastrow - line_count,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009587 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00009588 ' ', ' ', 0);
9589 }
9590
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009591 if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009592 == FAIL)
9593 {
9594 /* deletion will have messed up other windows */
9595 if (did_delete)
9596 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009597 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009598 win_rest_invalid(W_NEXT(wp));
9599 }
9600 return FAIL;
9601 }
9602
9603 return OK;
9604}
9605
9606/*
Bram Moolenaar86033562017-07-12 20:24:41 +02009607 * Delete "line_count" window lines at "row" in window "wp".
Bram Moolenaar071d4272004-06-13 20:20:40 +00009608 * If "invalid" is TRUE curwin->w_lines[] is invalidated.
9609 * If "mayclear" is TRUE the screen will be cleared if it is faster than
9610 * scrolling
9611 * Return OK for success, FAIL if the lines are not deleted.
9612 */
9613 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009614win_del_lines(
9615 win_T *wp,
9616 int row,
9617 int line_count,
9618 int invalid,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009619 int mayclear,
9620 int clear_attr) /* for clearing lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009621{
9622 int retval;
9623
9624 if (invalid)
9625 wp->w_lines_valid = 0;
9626
9627 if (line_count > wp->w_height - row)
9628 line_count = wp->w_height - row;
9629
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009630 retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009631 if (retval != MAYBE)
9632 return retval;
9633
9634 if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009635 (int)Rows, FALSE, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009636 return FAIL;
9637
Bram Moolenaar071d4272004-06-13 20:20:40 +00009638 /*
9639 * If there are windows or status lines below, try to put them at the
9640 * correct place. If we can't do that, they have to be redrawn.
9641 */
9642 if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
9643 {
9644 if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009645 line_count, (int)Rows, clear_attr, NULL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009646 {
9647 wp->w_redr_status = TRUE;
9648 win_rest_invalid(wp->w_next);
9649 }
9650 }
9651 /*
9652 * If this is the last window and there is no status line, redraw the
9653 * command line later.
9654 */
9655 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00009656 redraw_cmdline = TRUE;
9657 return OK;
9658}
9659
9660/*
9661 * Common code for win_ins_lines() and win_del_lines().
9662 * Returns OK or FAIL when the work has been done.
9663 * Returns MAYBE when not finished yet.
9664 */
9665 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01009666win_do_lines(
9667 win_T *wp,
9668 int row,
9669 int line_count,
9670 int mayclear,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009671 int del,
9672 int clear_attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009673{
9674 int retval;
9675
9676 if (!redrawing() || line_count <= 0)
9677 return FAIL;
9678
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009679 /* When inserting lines would result in loss of command output, just redraw
9680 * the lines. */
9681 if (no_win_do_lines_ins && !del)
9682 return FAIL;
9683
Bram Moolenaar071d4272004-06-13 20:20:40 +00009684 /* only a few lines left: redraw is faster */
Bram Moolenaar4033c552017-09-16 20:54:51 +02009685 if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009686 {
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009687 if (!no_win_do_lines_ins)
9688 screenclear(); /* will set wp->w_lines_valid to 0 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009689 return FAIL;
9690 }
9691
9692 /*
9693 * Delete all remaining lines
9694 */
9695 if (row + line_count >= wp->w_height)
9696 {
9697 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
Bram Moolenaar53f81742017-09-22 14:35:51 +02009698 wp->w_wincol, (int)W_ENDCOL(wp),
Bram Moolenaar071d4272004-06-13 20:20:40 +00009699 ' ', ' ', 0);
9700 return OK;
9701 }
9702
9703 /*
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009704 * When scrolling, the message on the command line should be cleared,
Bram Moolenaar071d4272004-06-13 20:20:40 +00009705 * otherwise it will stay there forever.
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009706 * Don't do this when avoiding to insert lines.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009707 */
Bram Moolenaar29ae3772017-04-30 19:39:39 +02009708 if (!no_win_do_lines_ins)
9709 clear_cmdline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009710
9711 /*
9712 * If the terminal can set a scroll region, use that.
9713 * Always do this in a vertically split window. This will redraw from
9714 * ScreenLines[] when t_CV isn't defined. That's faster than using
9715 * win_line().
9716 * Don't use a scroll region when we are going to redraw the text, writing
Bram Moolenaar48e330a2016-02-23 14:53:34 +01009717 * a character in the lower right corner of the scroll region may cause a
9718 * scroll-up .
Bram Moolenaar071d4272004-06-13 20:20:40 +00009719 */
Bram Moolenaar02631462017-09-22 15:20:32 +02009720 if (scroll_region || wp->w_width != Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009721 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009722 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009723 scroll_region_set(wp, row);
9724 if (del)
9725 retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009726 wp->w_height - row, FALSE, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009727 else
9728 retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009729 wp->w_height - row, clear_attr, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009730 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009731 scroll_region_reset();
9732 return retval;
9733 }
9734
Bram Moolenaar071d4272004-06-13 20:20:40 +00009735 if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
9736 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009737
9738 return MAYBE;
9739}
9740
9741/*
9742 * window 'wp' and everything after it is messed up, mark it for redraw
9743 */
9744 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01009745win_rest_invalid(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009746{
Bram Moolenaar071d4272004-06-13 20:20:40 +00009747 while (wp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009748 {
9749 redraw_win_later(wp, NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009750 wp->w_redr_status = TRUE;
9751 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009752 }
9753 redraw_cmdline = TRUE;
9754}
9755
9756/*
9757 * The rest of the routines in this file perform screen manipulations. The
9758 * given operation is performed physically on the screen. The corresponding
9759 * change is also made to the internal screen image. In this way, the editor
9760 * anticipates the effect of editing changes on the appearance of the screen.
9761 * That way, when we call screenupdate a complete redraw isn't usually
9762 * necessary. Another advantage is that we can keep adding code to anticipate
9763 * screen changes, and in the meantime, everything still works.
9764 */
9765
9766/*
9767 * types for inserting or deleting lines
9768 */
9769#define USE_T_CAL 1
9770#define USE_T_CDL 2
9771#define USE_T_AL 3
9772#define USE_T_CE 4
9773#define USE_T_DL 5
9774#define USE_T_SR 6
9775#define USE_NL 7
9776#define USE_T_CD 8
9777#define USE_REDRAW 9
9778
9779/*
9780 * insert lines on the screen and update ScreenLines[]
9781 * 'end' is the line after the scrolled part. Normally it is Rows.
9782 * When scrolling region used 'off' is the offset from the top for the region.
9783 * 'row' and 'end' are relative to the start of the region.
9784 *
9785 * return FAIL for failure, OK for success.
9786 */
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00009787 int
Bram Moolenaar05540972016-01-30 20:31:25 +01009788screen_ins_lines(
9789 int off,
9790 int row,
9791 int line_count,
9792 int end,
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009793 int clear_attr,
Bram Moolenaar05540972016-01-30 20:31:25 +01009794 win_T *wp) /* NULL or window to use width from */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009795{
9796 int i;
9797 int j;
9798 unsigned temp;
9799 int cursor_row;
9800 int type;
9801 int result_empty;
9802 int can_ce = can_clear(T_CE);
9803
9804 /*
9805 * FAIL if
9806 * - there is no valid screen
9807 * - the screen has to be redrawn completely
9808 * - the line count is less than one
9809 * - the line count is more than 'ttyscroll'
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009810 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar071d4272004-06-13 20:20:40 +00009811 */
Bram Moolenaar80dd3f92017-07-19 12:51:52 +02009812 if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll
9813#ifdef FEAT_CLIPBOARD
9814 || (clip_star.state != SELECT_CLEARED
9815 && redrawing_for_callback > 0)
9816#endif
9817 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00009818 return FAIL;
9819
9820 /*
9821 * There are seven ways to insert lines:
9822 * 0. When in a vertically split window and t_CV isn't set, redraw the
9823 * characters from ScreenLines[].
9824 * 1. Use T_CD (clear to end of display) if it exists and the result of
9825 * the insert is just empty lines
9826 * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
9827 * present or line_count > 1. It looks better if we do all the inserts
9828 * at once.
9829 * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
9830 * insert is just empty lines and T_CE is not present or line_count >
9831 * 1.
9832 * 4. Use T_AL (insert line) if it exists.
9833 * 5. Use T_CE (erase line) if it exists and the result of the insert is
9834 * just empty lines.
9835 * 6. Use T_DL (delete line) if it exists and the result of the insert is
9836 * just empty lines.
9837 * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
9838 * the 'da' flag is not set or we have clear line capability.
9839 * 8. redraw the characters from ScreenLines[].
9840 *
9841 * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
9842 * the scrollbar for the window. It does have insert line, use that if it
9843 * exists.
9844 */
9845 result_empty = (row + line_count >= end);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009846 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
9847 type = USE_REDRAW;
Bram Moolenaar4033c552017-09-16 20:54:51 +02009848 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009849 type = USE_T_CD;
9850 else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
9851 type = USE_T_CAL;
9852 else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
9853 type = USE_T_CDL;
9854 else if (*T_AL != NUL)
9855 type = USE_T_AL;
9856 else if (can_ce && result_empty)
9857 type = USE_T_CE;
9858 else if (*T_DL != NUL && result_empty)
9859 type = USE_T_DL;
9860 else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
9861 type = USE_T_SR;
9862 else
9863 return FAIL;
9864
9865 /*
9866 * For clearing the lines screen_del_lines() is used. This will also take
9867 * care of t_db if necessary.
9868 */
9869 if (type == USE_T_CD || type == USE_T_CDL ||
9870 type == USE_T_CE || type == USE_T_DL)
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009871 return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009872
9873 /*
9874 * If text is retained below the screen, first clear or delete as many
9875 * lines at the bottom of the window as are about to be inserted so that
9876 * the deleted lines won't later surface during a screen_del_lines.
9877 */
9878 if (*T_DB)
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009879 screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009880
9881#ifdef FEAT_CLIPBOARD
9882 /* Remove a modeless selection when inserting lines halfway the screen
9883 * or not the full width of the screen. */
Bram Moolenaar4033c552017-09-16 20:54:51 +02009884 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +02009885 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009886 else
9887 clip_scroll_selection(-line_count);
9888#endif
9889
Bram Moolenaar071d4272004-06-13 20:20:40 +00009890#ifdef FEAT_GUI
9891 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
9892 * scrolling is actually carried out. */
Bram Moolenaar107abd22016-08-12 14:08:25 +02009893 gui_dont_update_cursor(row + off <= gui.cursor_row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009894#endif
9895
9896 if (*T_CCS != NUL) /* cursor relative to region */
9897 cursor_row = row;
9898 else
9899 cursor_row = row + off;
9900
9901 /*
9902 * Shift LineOffset[] line_count down to reflect the inserted lines.
9903 * Clear the inserted lines in ScreenLines[].
9904 */
9905 row += off;
9906 end += off;
9907 for (i = 0; i < line_count; ++i)
9908 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00009909 if (wp != NULL && wp->w_width != Columns)
9910 {
9911 /* need to copy part of a line */
9912 j = end - 1 - i;
9913 while ((j -= line_count) >= row)
9914 linecopy(j + line_count, j, wp);
9915 j += line_count;
9916 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009917 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
9918 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009919 else
9920 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
9921 LineWraps[j] = FALSE;
9922 }
9923 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00009924 {
9925 j = end - 1 - i;
9926 temp = LineOffset[j];
9927 while ((j -= line_count) >= row)
9928 {
9929 LineOffset[j + line_count] = LineOffset[j];
9930 LineWraps[j + line_count] = LineWraps[j];
9931 }
9932 LineOffset[j + line_count] = temp;
9933 LineWraps[j + line_count] = FALSE;
9934 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009935 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009936 else
9937 lineinvalid(temp, (int)Columns);
9938 }
9939 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009940
9941 screen_stop_highlight();
9942 windgoto(cursor_row, 0);
Bram Moolenaarcfce7172017-08-17 20:31:48 +02009943 if (clear_attr != 0)
9944 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009945
Bram Moolenaar071d4272004-06-13 20:20:40 +00009946 /* redraw the characters */
9947 if (type == USE_REDRAW)
9948 redraw_block(row, end, wp);
Bram Moolenaar4033c552017-09-16 20:54:51 +02009949 else if (type == USE_T_CAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009950 {
9951 term_append_lines(line_count);
9952 screen_start(); /* don't know where cursor is now */
9953 }
9954 else
9955 {
9956 for (i = 0; i < line_count; i++)
9957 {
9958 if (type == USE_T_AL)
9959 {
9960 if (i && cursor_row != 0)
9961 windgoto(cursor_row, 0);
9962 out_str(T_AL);
9963 }
9964 else /* type == USE_T_SR */
9965 out_str(T_SR);
9966 screen_start(); /* don't know where cursor is now */
9967 }
9968 }
9969
9970 /*
9971 * With scroll-reverse and 'da' flag set we need to clear the lines that
9972 * have been scrolled down into the region.
9973 */
9974 if (type == USE_T_SR && *T_DA)
9975 {
9976 for (i = 0; i < line_count; ++i)
9977 {
9978 windgoto(off + i, 0);
9979 out_str(T_CE);
9980 screen_start(); /* don't know where cursor is now */
9981 }
9982 }
9983
9984#ifdef FEAT_GUI
9985 gui_can_update_cursor();
9986 if (gui.in_use)
9987 out_flush(); /* always flush after a scroll */
9988#endif
9989 return OK;
9990}
9991
9992/*
Bram Moolenaar107abd22016-08-12 14:08:25 +02009993 * Delete lines on the screen and update ScreenLines[].
9994 * "end" is the line after the scrolled part. Normally it is Rows.
9995 * When scrolling region used "off" is the offset from the top for the region.
9996 * "row" and "end" are relative to the start of the region.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009997 *
9998 * Return OK for success, FAIL if the lines are not deleted.
9999 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010000 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010001screen_del_lines(
10002 int off,
10003 int row,
10004 int line_count,
10005 int end,
10006 int force, /* even when line_count > p_ttyscroll */
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010007 int clear_attr, /* used for clearing lines */
Bram Moolenaar05540972016-01-30 20:31:25 +010010008 win_T *wp UNUSED) /* NULL or window to use width from */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010009{
10010 int j;
10011 int i;
10012 unsigned temp;
10013 int cursor_row;
10014 int cursor_end;
10015 int result_empty; /* result is empty until end of region */
10016 int can_delete; /* deleting line codes can be used */
10017 int type;
10018
10019 /*
10020 * FAIL if
10021 * - there is no valid screen
10022 * - the screen has to be redrawn completely
10023 * - the line count is less than one
10024 * - the line count is more than 'ttyscroll'
Bram Moolenaar80dd3f92017-07-19 12:51:52 +020010025 * - redrawing for a callback and there is a modeless selection
Bram Moolenaar071d4272004-06-13 20:20:40 +000010026 */
Bram Moolenaar80dd3f92017-07-19 12:51:52 +020010027 if (!screen_valid(TRUE) || line_count <= 0
10028 || (!force && line_count > p_ttyscroll)
10029#ifdef FEAT_CLIPBOARD
10030 || (clip_star.state != SELECT_CLEARED
10031 && redrawing_for_callback > 0)
10032#endif
10033 )
Bram Moolenaar071d4272004-06-13 20:20:40 +000010034 return FAIL;
10035
10036 /*
10037 * Check if the rest of the current region will become empty.
10038 */
10039 result_empty = row + line_count >= end;
10040
10041 /*
10042 * We can delete lines only when 'db' flag not set or when 'ce' option
10043 * available.
10044 */
10045 can_delete = (*T_DB == NUL || can_clear(T_CE));
10046
10047 /*
10048 * There are six ways to delete lines:
10049 * 0. When in a vertically split window and t_CV isn't set, redraw the
10050 * characters from ScreenLines[].
10051 * 1. Use T_CD if it exists and the result is empty.
10052 * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
10053 * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
10054 * none of the other ways work.
10055 * 4. Use T_CE (erase line) if the result is empty.
10056 * 5. Use T_DL (delete line) if it exists.
10057 * 6. redraw the characters from ScreenLines[].
10058 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010059 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
10060 type = USE_REDRAW;
Bram Moolenaar4033c552017-09-16 20:54:51 +020010061 else if (can_clear(T_CD) && result_empty)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010062 type = USE_T_CD;
10063#if defined(__BEOS__) && defined(BEOS_DR8)
10064 /*
10065 * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
10066 * its internal termcap... this works okay for tests which test *T_DB !=
10067 * NUL. It has the disadvantage that the user cannot use any :set t_*
10068 * command to get T_DB (back) to empty_option, only :set term=... will do
10069 * the trick...
10070 * Anyway, this hack will hopefully go away with the next OS release.
10071 * (Olaf Seibert)
10072 */
10073 else if (row == 0 && T_DB == empty_option
10074 && (line_count == 1 || *T_CDL == NUL))
10075#else
10076 else if (row == 0 && (
10077#ifndef AMIGA
10078 /* On the Amiga, somehow '\n' on the last line doesn't always scroll
10079 * up, so use delete-line command */
10080 line_count == 1 ||
10081#endif
10082 *T_CDL == NUL))
10083#endif
10084 type = USE_NL;
10085 else if (*T_CDL != NUL && line_count > 1 && can_delete)
10086 type = USE_T_CDL;
10087 else if (can_clear(T_CE) && result_empty
Bram Moolenaar4033c552017-09-16 20:54:51 +020010088 && (wp == NULL || wp->w_width == Columns))
Bram Moolenaar071d4272004-06-13 20:20:40 +000010089 type = USE_T_CE;
10090 else if (*T_DL != NUL && can_delete)
10091 type = USE_T_DL;
10092 else if (*T_CDL != NUL && can_delete)
10093 type = USE_T_CDL;
10094 else
10095 return FAIL;
10096
10097#ifdef FEAT_CLIPBOARD
10098 /* Remove a modeless selection when deleting lines halfway the screen or
10099 * not the full width of the screen. */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010100 if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
Bram Moolenaarc0885aa2012-07-10 16:49:23 +020010101 clip_clear_selection(&clip_star);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010102 else
10103 clip_scroll_selection(line_count);
10104#endif
10105
Bram Moolenaar071d4272004-06-13 20:20:40 +000010106#ifdef FEAT_GUI
10107 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
10108 * scrolling is actually carried out. */
Bram Moolenaar107abd22016-08-12 14:08:25 +020010109 gui_dont_update_cursor(gui.cursor_row >= row + off
10110 && gui.cursor_row < end + off);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010111#endif
10112
10113 if (*T_CCS != NUL) /* cursor relative to region */
10114 {
10115 cursor_row = row;
10116 cursor_end = end;
10117 }
10118 else
10119 {
10120 cursor_row = row + off;
10121 cursor_end = end + off;
10122 }
10123
10124 /*
10125 * Now shift LineOffset[] line_count up to reflect the deleted lines.
10126 * Clear the inserted lines in ScreenLines[].
10127 */
10128 row += off;
10129 end += off;
10130 for (i = 0; i < line_count; ++i)
10131 {
Bram Moolenaar071d4272004-06-13 20:20:40 +000010132 if (wp != NULL && wp->w_width != Columns)
10133 {
10134 /* need to copy part of a line */
10135 j = row + i;
10136 while ((j += line_count) <= end - 1)
10137 linecopy(j - line_count, j, wp);
10138 j -= line_count;
10139 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010140 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
10141 clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010142 else
10143 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
10144 LineWraps[j] = FALSE;
10145 }
10146 else
Bram Moolenaar071d4272004-06-13 20:20:40 +000010147 {
10148 /* whole width, moving the line pointers is faster */
10149 j = row + i;
10150 temp = LineOffset[j];
10151 while ((j += line_count) <= end - 1)
10152 {
10153 LineOffset[j - line_count] = LineOffset[j];
10154 LineWraps[j - line_count] = LineWraps[j];
10155 }
10156 LineOffset[j - line_count] = temp;
10157 LineWraps[j - line_count] = FALSE;
10158 if (can_clear((char_u *)" "))
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010159 lineclear(temp, (int)Columns, clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010160 else
10161 lineinvalid(temp, (int)Columns);
10162 }
10163 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010164
Bram Moolenaarcfce7172017-08-17 20:31:48 +020010165 if (screen_attr != clear_attr)
10166 screen_stop_highlight();
10167 if (clear_attr != 0)
10168 screen_start_highlight(clear_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010169
Bram Moolenaar071d4272004-06-13 20:20:40 +000010170 /* redraw the characters */
10171 if (type == USE_REDRAW)
10172 redraw_block(row, end, wp);
Bram Moolenaar4033c552017-09-16 20:54:51 +020010173 else if (type == USE_T_CD) /* delete the lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010174 {
10175 windgoto(cursor_row, 0);
10176 out_str(T_CD);
10177 screen_start(); /* don't know where cursor is now */
10178 }
10179 else if (type == USE_T_CDL)
10180 {
10181 windgoto(cursor_row, 0);
10182 term_delete_lines(line_count);
10183 screen_start(); /* don't know where cursor is now */
10184 }
10185 /*
10186 * Deleting lines at top of the screen or scroll region: Just scroll
10187 * the whole screen (scroll region) up by outputting newlines on the
10188 * last line.
10189 */
10190 else if (type == USE_NL)
10191 {
10192 windgoto(cursor_end - 1, 0);
10193 for (i = line_count; --i >= 0; )
10194 out_char('\n'); /* cursor will remain on same line */
10195 }
10196 else
10197 {
10198 for (i = line_count; --i >= 0; )
10199 {
10200 if (type == USE_T_DL)
10201 {
10202 windgoto(cursor_row, 0);
10203 out_str(T_DL); /* delete a line */
10204 }
10205 else /* type == USE_T_CE */
10206 {
10207 windgoto(cursor_row + i, 0);
10208 out_str(T_CE); /* erase a line */
10209 }
10210 screen_start(); /* don't know where cursor is now */
10211 }
10212 }
10213
10214 /*
10215 * If the 'db' flag is set, we need to clear the lines that have been
10216 * scrolled up at the bottom of the region.
10217 */
10218 if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
10219 {
10220 for (i = line_count; i > 0; --i)
10221 {
10222 windgoto(cursor_end - i, 0);
10223 out_str(T_CE); /* erase a line */
10224 screen_start(); /* don't know where cursor is now */
10225 }
10226 }
10227
10228#ifdef FEAT_GUI
10229 gui_can_update_cursor();
10230 if (gui.in_use)
10231 out_flush(); /* always flush after a scroll */
10232#endif
10233
10234 return OK;
10235}
10236
10237/*
Bram Moolenaar81226e02018-02-20 21:44:45 +010010238 * Show the current mode and ruler.
Bram Moolenaar071d4272004-06-13 20:20:40 +000010239 *
10240 * If clear_cmdline is TRUE, clear the rest of the cmdline.
10241 * If clear_cmdline is FALSE there may be a message there that needs to be
10242 * cleared only if a mode is shown.
10243 * Return the length of the message (0 if no message).
10244 */
10245 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010246showmode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010247{
10248 int need_clear;
10249 int length = 0;
10250 int do_mode;
10251 int attr;
10252 int nwr_save;
10253#ifdef FEAT_INS_EXPAND
10254 int sub_attr;
10255#endif
10256
Bram Moolenaar7df351e2006-01-23 22:30:28 +000010257 do_mode = ((p_smd && msg_silent == 0)
10258 && ((State & INSERT)
10259 || restart_edit
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +010010260 || VIsual_active));
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010261 if (do_mode || reg_recording != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010262 {
10263 /*
10264 * Don't show mode right now, when not redrawing or inside a mapping.
10265 * Call char_avail() only when we are going to show something, because
10266 * it takes a bit of time.
10267 */
10268 if (!redrawing() || (char_avail() && !KeyTyped) || msg_silent != 0)
10269 {
10270 redraw_cmdline = TRUE; /* show mode later */
10271 return 0;
10272 }
10273
10274 nwr_save = need_wait_return;
10275
10276 /* wait a bit before overwriting an important message */
10277 check_for_delay(FALSE);
10278
10279 /* if the cmdline is more than one line high, erase top lines */
10280 need_clear = clear_cmdline;
10281 if (clear_cmdline && cmdline_row < Rows - 1)
10282 msg_clr_cmdline(); /* will reset clear_cmdline */
10283
10284 /* Position on the last line in the window, column 0 */
10285 msg_pos_mode();
10286 cursor_off();
Bram Moolenaar8820b482017-03-16 17:23:31 +010010287 attr = HL_ATTR(HLF_CM); /* Highlight mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010288 if (do_mode)
10289 {
10290 MSG_PUTS_ATTR("--", attr);
10291#if defined(FEAT_XIM)
Bram Moolenaarc236c162008-07-13 17:41:49 +000010292 if (
Bram Moolenaar09092152010-08-08 16:38:42 +020010293# ifdef FEAT_GUI_GTK
Bram Moolenaarc236c162008-07-13 17:41:49 +000010294 preedit_get_status()
Bram Moolenaar09092152010-08-08 16:38:42 +020010295# else
Bram Moolenaarc236c162008-07-13 17:41:49 +000010296 im_get_status()
Bram Moolenaarc236c162008-07-13 17:41:49 +000010297# endif
Bram Moolenaar09092152010-08-08 16:38:42 +020010298 )
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +020010299# ifdef FEAT_GUI_GTK /* most of the time, it's not XIM being used */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010300 MSG_PUTS_ATTR(" IM", attr);
10301# else
10302 MSG_PUTS_ATTR(" XIM", attr);
10303# endif
10304#endif
10305#if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
10306 if (gui.in_use)
10307 {
10308 if (hangul_input_state_get())
Bram Moolenaar72f4cc42015-11-10 14:35:18 +010010309 {
10310 /* HANGUL */
10311 if (enc_utf8)
10312 MSG_PUTS_ATTR(" \355\225\234\352\270\200", attr);
10313 else
10314 MSG_PUTS_ATTR(" \307\321\261\333", attr);
10315 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010316 }
10317#endif
10318#ifdef FEAT_INS_EXPAND
Bram Moolenaarea389e92014-05-28 21:40:52 +020010319 /* CTRL-X in Insert mode */
10320 if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
Bram Moolenaar071d4272004-06-13 20:20:40 +000010321 {
10322 /* These messages can get long, avoid a wrap in a narrow
10323 * window. Prefer showing edit_submode_extra. */
10324 length = (Rows - msg_row) * Columns - 3;
10325 if (edit_submode_extra != NULL)
10326 length -= vim_strsize(edit_submode_extra);
10327 if (length > 0)
10328 {
10329 if (edit_submode_pre != NULL)
10330 length -= vim_strsize(edit_submode_pre);
10331 if (length - vim_strsize(edit_submode) > 0)
10332 {
10333 if (edit_submode_pre != NULL)
10334 msg_puts_attr(edit_submode_pre, attr);
10335 msg_puts_attr(edit_submode, attr);
10336 }
10337 if (edit_submode_extra != NULL)
10338 {
10339 MSG_PUTS_ATTR(" ", attr); /* add a space in between */
10340 if ((int)edit_submode_highl < (int)HLF_COUNT)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010341 sub_attr = HL_ATTR(edit_submode_highl);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010342 else
10343 sub_attr = attr;
10344 msg_puts_attr(edit_submode_extra, sub_attr);
10345 }
10346 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010347 }
10348 else
10349#endif
10350 {
10351#ifdef FEAT_VREPLACE
10352 if (State & VREPLACE_FLAG)
10353 MSG_PUTS_ATTR(_(" VREPLACE"), attr);
10354 else
10355#endif
10356 if (State & REPLACE_FLAG)
10357 MSG_PUTS_ATTR(_(" REPLACE"), attr);
10358 else if (State & INSERT)
10359 {
10360#ifdef FEAT_RIGHTLEFT
10361 if (p_ri)
10362 MSG_PUTS_ATTR(_(" REVERSE"), attr);
10363#endif
10364 MSG_PUTS_ATTR(_(" INSERT"), attr);
10365 }
10366 else if (restart_edit == 'I')
10367 MSG_PUTS_ATTR(_(" (insert)"), attr);
10368 else if (restart_edit == 'R')
10369 MSG_PUTS_ATTR(_(" (replace)"), attr);
10370 else if (restart_edit == 'V')
10371 MSG_PUTS_ATTR(_(" (vreplace)"), attr);
10372#ifdef FEAT_RIGHTLEFT
10373 if (p_hkmap)
10374 MSG_PUTS_ATTR(_(" Hebrew"), attr);
10375# ifdef FEAT_FKMAP
10376 if (p_fkmap)
10377 MSG_PUTS_ATTR(farsi_text_5, attr);
10378# endif
10379#endif
10380#ifdef FEAT_KEYMAP
10381 if (State & LANGMAP)
10382 {
10383# ifdef FEAT_ARABIC
10384 if (curwin->w_p_arab)
10385 MSG_PUTS_ATTR(_(" Arabic"), attr);
10386 else
10387# endif
Bram Moolenaar73ac0c42016-07-24 16:17:59 +020010388 if (get_keymap_str(curwin, (char_u *)" (%s)",
10389 NameBuff, MAXPATHL))
10390 MSG_PUTS_ATTR(NameBuff, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010391 }
10392#endif
10393 if ((State & INSERT) && p_paste)
10394 MSG_PUTS_ATTR(_(" (paste)"), attr);
10395
Bram Moolenaar071d4272004-06-13 20:20:40 +000010396 if (VIsual_active)
10397 {
10398 char *p;
10399
10400 /* Don't concatenate separate words to avoid translation
10401 * problems. */
10402 switch ((VIsual_select ? 4 : 0)
10403 + (VIsual_mode == Ctrl_V) * 2
10404 + (VIsual_mode == 'V'))
10405 {
10406 case 0: p = N_(" VISUAL"); break;
10407 case 1: p = N_(" VISUAL LINE"); break;
10408 case 2: p = N_(" VISUAL BLOCK"); break;
10409 case 4: p = N_(" SELECT"); break;
10410 case 5: p = N_(" SELECT LINE"); break;
10411 default: p = N_(" SELECT BLOCK"); break;
10412 }
10413 MSG_PUTS_ATTR(_(p), attr);
10414 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010415 MSG_PUTS_ATTR(" --", attr);
10416 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010417
Bram Moolenaar071d4272004-06-13 20:20:40 +000010418 need_clear = TRUE;
10419 }
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010420 if (reg_recording != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +000010421#ifdef FEAT_INS_EXPAND
10422 && edit_submode == NULL /* otherwise it gets too long */
10423#endif
10424 )
10425 {
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010426 recording_mode(attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010427 need_clear = TRUE;
10428 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010429
10430 mode_displayed = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010431 if (need_clear || clear_cmdline)
10432 msg_clr_eos();
10433 msg_didout = FALSE; /* overwrite this message */
10434 length = msg_col;
10435 msg_col = 0;
10436 need_wait_return = nwr_save; /* never ask for hit-return for this */
10437 }
10438 else if (clear_cmdline && msg_silent == 0)
10439 /* Clear the whole command line. Will reset "clear_cmdline". */
10440 msg_clr_cmdline();
10441
10442#ifdef FEAT_CMDL_INFO
Bram Moolenaar071d4272004-06-13 20:20:40 +000010443 /* In Visual mode the size of the selected area must be redrawn. */
10444 if (VIsual_active)
10445 clear_showcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +000010446
10447 /* If the last window has no status line, the ruler is after the mode
10448 * message and must be redrawn */
Bram Moolenaar4033c552017-09-16 20:54:51 +020010449 if (redrawing() && lastwin->w_status_height == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010450 win_redr_ruler(lastwin, TRUE);
10451#endif
10452 redraw_cmdline = FALSE;
10453 clear_cmdline = FALSE;
10454
10455 return length;
10456}
10457
10458/*
10459 * Position for a mode message.
10460 */
10461 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010462msg_pos_mode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010463{
10464 msg_col = 0;
10465 msg_row = Rows - 1;
10466}
10467
10468/*
10469 * Delete mode message. Used when ESC is typed which is expected to end
10470 * Insert mode (but Insert mode didn't end yet!).
Bram Moolenaard12f5c12006-01-25 22:10:52 +000010471 * Caller should check "mode_displayed".
Bram Moolenaar071d4272004-06-13 20:20:40 +000010472 */
10473 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010474unshowmode(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010475{
10476 /*
Bram Moolenaare4ebd292010-01-19 17:40:46 +010010477 * Don't delete it right now, when not redrawing or inside a mapping.
Bram Moolenaar071d4272004-06-13 20:20:40 +000010478 */
10479 if (!redrawing() || (!force && char_avail() && !KeyTyped))
10480 redraw_cmdline = TRUE; /* delete mode later */
10481 else
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010482 clearmode();
10483}
10484
10485/*
10486 * Clear the mode message.
10487 */
10488 void
Bram Moolenaarcf089462016-06-12 21:18:43 +020010489clearmode(void)
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010490{
Bram Moolenaar2abad542018-05-19 14:43:45 +020010491 int save_msg_row = msg_row;
10492 int save_msg_col = msg_col;
10493
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010494 msg_pos_mode();
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010495 if (reg_recording != 0)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010496 recording_mode(HL_ATTR(HLF_CM));
Bram Moolenaarfd773e92016-04-02 19:39:16 +020010497 msg_clr_eos();
Bram Moolenaar2abad542018-05-19 14:43:45 +020010498
10499 msg_col = save_msg_col;
10500 msg_row = save_msg_row;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010501}
10502
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010503 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010504recording_mode(int attr)
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010505{
10506 MSG_PUTS_ATTR(_("recording"), attr);
10507 if (!shortmess(SHM_RECORDING))
10508 {
10509 char_u s[4];
Bram Moolenaar0b6d9112018-05-22 20:35:17 +020010510 sprintf((char *)s, " @%c", reg_recording);
Bram Moolenaara0ed84a2015-11-19 17:56:13 +010010511 MSG_PUTS_ATTR(s, attr);
10512 }
10513}
10514
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010515/*
10516 * Draw the tab pages line at the top of the Vim window.
10517 */
10518 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010519draw_tabline(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010520{
10521 int tabcount = 0;
10522 tabpage_T *tp;
10523 int tabwidth;
10524 int col = 0;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010525 int scol = 0;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010526 int attr;
10527 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010528 win_T *cwp;
10529 int wincount;
10530 int modified;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010531 int c;
10532 int len;
Bram Moolenaar8820b482017-03-16 17:23:31 +010010533 int attr_sel = HL_ATTR(HLF_TPS);
10534 int attr_nosel = HL_ATTR(HLF_TP);
10535 int attr_fill = HL_ATTR(HLF_TPF);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010536 char_u *p;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010537 int room;
10538 int use_sep_chars = (t_colors < 8
10539#ifdef FEAT_GUI
10540 && !gui.in_use
10541#endif
Bram Moolenaar61be73b2016-04-29 22:59:22 +020010542#ifdef FEAT_TERMGUICOLORS
10543 && !p_tgc
Bram Moolenaar8a633e32016-04-21 21:10:14 +020010544#endif
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010545 );
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010546
Bram Moolenaarc695cec2017-01-08 20:00:04 +010010547 if (ScreenLines == NULL)
10548 return;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +000010549 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010550
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010551#ifdef FEAT_GUI_TABLINE
Bram Moolenaardb552d602006-03-23 22:59:57 +000010552 /* Take care of a GUI tabline. */
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010553 if (gui_use_tabline())
10554 {
10555 gui_update_tabline();
10556 return;
10557 }
10558#endif
10559
10560 if (tabline_height() < 1)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010561 return;
10562
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010563#if defined(FEAT_STL_OPT)
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010564
10565 /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */
10566 for (scol = 0; scol < Columns; ++scol)
10567 TabPageIdxs[scol] = 0;
10568
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010569 /* Use the 'tabline' option if it's set. */
10570 if (*p_tal != NUL)
10571 {
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010572 int saved_did_emsg = did_emsg;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010573
10574 /* Check for an error. If there is one we would loop in redrawing the
10575 * screen. Avoid that by making 'tabline' empty. */
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010576 did_emsg = FALSE;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010577 win_redr_custom(NULL, FALSE);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010578 if (did_emsg)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010579 set_string_option_direct((char_u *)"tabline", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +000010580 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaarf73d3bc2016-04-11 21:55:15 +020010581 did_emsg |= saved_did_emsg;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010582 }
Bram Moolenaar238a5642006-02-21 22:12:05 +000010583 else
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010584#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010585 {
Bram Moolenaar29323592016-07-24 22:04:11 +020010586 FOR_ALL_TABPAGES(tp)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010587 ++tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010588
Bram Moolenaar238a5642006-02-21 22:12:05 +000010589 tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
10590 if (tabwidth < 6)
10591 tabwidth = 6;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010592
Bram Moolenaar238a5642006-02-21 22:12:05 +000010593 attr = attr_nosel;
10594 tabcount = 0;
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010595 scol = 0;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010596 for (tp = first_tabpage; tp != NULL && col < Columns - 4;
10597 tp = tp->tp_next)
Bram Moolenaarf740b292006-02-16 22:11:02 +000010598 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010599 scol = col;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010600
Bram Moolenaar238a5642006-02-21 22:12:05 +000010601 if (tp->tp_topframe == topframe)
10602 attr = attr_sel;
10603 if (use_sep_chars && col > 0)
10604 screen_putchar('|', 0, col++, attr);
10605
10606 if (tp->tp_topframe != topframe)
10607 attr = attr_nosel;
10608
10609 screen_putchar(' ', 0, col++, attr);
10610
10611 if (tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +000010612 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010613 cwp = curwin;
10614 wp = firstwin;
10615 }
10616 else
10617 {
10618 cwp = tp->tp_curwin;
10619 wp = tp->tp_firstwin;
10620 }
10621
10622 modified = FALSE;
10623 for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
10624 if (bufIsChanged(wp->w_buffer))
10625 modified = TRUE;
10626 if (modified || wincount > 1)
10627 {
10628 if (wincount > 1)
10629 {
10630 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +000010631 len = (int)STRLEN(NameBuff);
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010632 if (col + len >= Columns - 3)
10633 break;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010634 screen_puts_len(NameBuff, len, 0, col,
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010635#if defined(FEAT_SYN_HL)
Bram Moolenaar8820b482017-03-16 17:23:31 +010010636 hl_combine_attr(attr, HL_ATTR(HLF_T))
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010637#else
Bram Moolenaare0f14822014-08-06 13:20:56 +020010638 attr
Bram Moolenaarfaa959a2006-02-20 21:37:40 +000010639#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +000010640 );
10641 col += len;
10642 }
10643 if (modified)
10644 screen_puts_len((char_u *)"+", 1, 0, col++, attr);
10645 screen_putchar(' ', 0, col++, attr);
10646 }
10647
10648 room = scol - col + tabwidth - 1;
10649 if (room > 0)
10650 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010651 /* Get buffer name in NameBuff[] */
10652 get_trans_bufname(cwp->w_buffer);
Bram Moolenaar910f66f2006-04-05 20:41:53 +000010653 shorten_dir(NameBuff);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010654 len = vim_strsize(NameBuff);
10655 p = NameBuff;
10656#ifdef FEAT_MBYTE
10657 if (has_mbyte)
10658 while (len > room)
10659 {
10660 len -= ptr2cells(p);
Bram Moolenaar91acfff2017-03-12 19:22:36 +010010661 MB_PTR_ADV(p);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010662 }
10663 else
10664#endif
10665 if (len > room)
10666 {
10667 p += len - room;
10668 len = room;
10669 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +000010670 if (len > Columns - col - 1)
10671 len = Columns - col - 1;
Bram Moolenaar238a5642006-02-21 22:12:05 +000010672
Bram Moolenaara93fa7e2006-04-17 22:14:47 +000010673 screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
Bram Moolenaarf740b292006-02-16 22:11:02 +000010674 col += len;
10675 }
Bram Moolenaarf740b292006-02-16 22:11:02 +000010676 screen_putchar(' ', 0, col++, attr);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010677
10678 /* Store the tab page number in TabPageIdxs[], so that
10679 * jump_to_mouse() knows where each one is. */
10680 ++tabcount;
10681 while (scol < col)
10682 TabPageIdxs[scol++] = tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +000010683 }
10684
Bram Moolenaar238a5642006-02-21 22:12:05 +000010685 if (use_sep_chars)
10686 c = '_';
10687 else
10688 c = ' ';
10689 screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
Bram Moolenaard1f56e62006-02-22 21:25:37 +000010690
10691 /* Put an "X" for closing the current tab if there are several. */
10692 if (first_tabpage->tp_next != NULL)
10693 {
10694 screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
10695 TabPageIdxs[Columns - 1] = -999;
10696 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010697 }
Bram Moolenaarb21e5842006-04-16 18:30:08 +000010698
10699 /* Reset the flag here again, in case evaluating 'tabline' causes it to be
10700 * set. */
10701 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010702}
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010703
10704/*
10705 * Get buffer name for "buf" into NameBuff[].
10706 * Takes care of special buffer names and translates special characters.
10707 */
10708 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010709get_trans_bufname(buf_T *buf)
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010710{
10711 if (buf_spname(buf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +020010712 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
Bram Moolenaar32466aa2006-02-24 23:53:04 +000010713 else
10714 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
10715 trans_characters(NameBuff, MAXPATHL);
10716}
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000010717
Bram Moolenaar071d4272004-06-13 20:20:40 +000010718/*
10719 * Get the character to use in a status line. Get its attributes in "*attr".
10720 */
10721 static int
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010722fillchar_status(int *attr, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010723{
10724 int fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010725
10726#ifdef FEAT_TERMINAL
10727 if (bt_terminal(wp->w_buffer))
10728 {
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010729 if (wp == curwin)
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010730 {
10731 *attr = HL_ATTR(HLF_ST);
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010732 fill = fill_stl;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010733 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010734 else
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010735 {
10736 *attr = HL_ATTR(HLF_STNC);
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010737 fill = fill_stlnc;
Bram Moolenaar05fbfdc2017-08-14 22:35:08 +020010738 }
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010739 }
10740 else
10741#endif
10742 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010743 {
Bram Moolenaar8820b482017-03-16 17:23:31 +010010744 *attr = HL_ATTR(HLF_S);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010745 fill = fill_stl;
10746 }
10747 else
10748 {
Bram Moolenaar8820b482017-03-16 17:23:31 +010010749 *attr = HL_ATTR(HLF_SNC);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010750 fill = fill_stlnc;
10751 }
10752 /* Use fill when there is highlighting, and highlighting of current
10753 * window differs, or the fillchars differ, or this is not the
10754 * current window */
Bram Moolenaar8820b482017-03-16 17:23:31 +010010755 if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010756 || wp != curwin || ONE_WINDOW)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010757 || (fill_stl != fill_stlnc)))
10758 return fill;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010759 if (wp == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010760 return '^';
10761 return '=';
10762}
Bram Moolenaar071d4272004-06-13 20:20:40 +000010763
Bram Moolenaar071d4272004-06-13 20:20:40 +000010764/*
10765 * Get the character to use in a separator between vertically split windows.
10766 * Get its attributes in "*attr".
10767 */
10768 static int
Bram Moolenaar05540972016-01-30 20:31:25 +010010769fillchar_vsep(int *attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010770{
Bram Moolenaar8820b482017-03-16 17:23:31 +010010771 *attr = HL_ATTR(HLF_C);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010772 if (*attr == 0 && fill_vert == ' ')
10773 return '|';
10774 else
10775 return fill_vert;
10776}
Bram Moolenaar071d4272004-06-13 20:20:40 +000010777
10778/*
10779 * Return TRUE if redrawing should currently be done.
10780 */
10781 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010782redrawing(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010783{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010010784#ifdef FEAT_EVAL
10785 if (disable_redraw_for_testing)
10786 return 0;
10787 else
10788#endif
10789 return (!RedrawingDisabled
Bram Moolenaar071d4272004-06-13 20:20:40 +000010790 && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
10791}
10792
10793/*
10794 * Return TRUE if printing messages should currently be done.
10795 */
10796 int
Bram Moolenaar05540972016-01-30 20:31:25 +010010797messaging(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010798{
10799 return (!(p_lz && char_avail() && !KeyTyped));
10800}
10801
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010802#ifdef FEAT_MENU
10803/*
10804 * Draw the window toolbar.
10805 */
10806 static void
10807redraw_win_toolbar(win_T *wp)
10808{
10809 vimmenu_T *menu;
10810 int item_idx = 0;
10811 int item_count = 0;
10812 int col = 0;
10813 int next_col;
10814 int off = (int)(current_ScreenLine - ScreenLines);
10815 int fill_attr = syn_name2attr((char_u *)"ToolbarLine");
10816 int button_attr = syn_name2attr((char_u *)"ToolbarButton");
10817
10818 vim_free(wp->w_winbar_items);
10819 for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next)
10820 ++item_count;
10821 wp->w_winbar_items = (winbar_item_T *)alloc_clear(
10822 (unsigned)sizeof(winbar_item_T) * (item_count + 1));
10823
10824 /* TODO: use fewer spaces if there is not enough room */
10825 for (menu = wp->w_winbar->children;
Bram Moolenaar02631462017-09-22 15:20:32 +020010826 menu != NULL && col < wp->w_width; menu = menu->next)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010827 {
10828 space_to_screenline(off + col, fill_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010829 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010830 break;
10831 if (col > 1)
10832 {
10833 space_to_screenline(off + col, fill_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010834 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010835 break;
10836 }
10837
10838 wp->w_winbar_items[item_idx].wb_startcol = col;
10839 space_to_screenline(off + col, button_attr);
Bram Moolenaar02631462017-09-22 15:20:32 +020010840 if (++col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010841 break;
10842
10843 next_col = text_to_screenline(wp, menu->name, col);
10844 while (col < next_col)
10845 {
10846 ScreenAttrs[off + col] = button_attr;
10847 ++col;
10848 }
10849 wp->w_winbar_items[item_idx].wb_endcol = col;
10850 wp->w_winbar_items[item_idx].wb_menu = menu;
10851 ++item_idx;
10852
Bram Moolenaar02631462017-09-22 15:20:32 +020010853 if (col >= wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010854 break;
10855 space_to_screenline(off + col, button_attr);
10856 ++col;
10857 }
Bram Moolenaar02631462017-09-22 15:20:32 +020010858 while (col < wp->w_width)
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010859 {
10860 space_to_screenline(off + col, fill_attr);
10861 ++col;
10862 }
10863 wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */
10864
Bram Moolenaar02631462017-09-22 15:20:32 +020010865 screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
10866 (int)wp->w_width, FALSE);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +020010867}
10868#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000010869/*
10870 * Show current status info in ruler and various other places
10871 * If always is FALSE, only show ruler if position has changed.
10872 */
10873 void
Bram Moolenaar05540972016-01-30 20:31:25 +010010874showruler(int always)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010875{
10876 if (!always && !redrawing())
10877 return;
Bram Moolenaar9372a112005-12-06 19:59:18 +000010878#ifdef FEAT_INS_EXPAND
10879 if (pum_visible())
10880 {
10881 /* Don't redraw right now, do it later. */
10882 curwin->w_redr_status = TRUE;
10883 return;
10884 }
10885#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +020010886#if defined(FEAT_STL_OPT)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +000010887 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
Bram Moolenaar238a5642006-02-21 22:12:05 +000010888 {
Bram Moolenaar362f3562009-11-03 16:20:34 +000010889 redraw_custom_statusline(curwin);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010890 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000010891 else
10892#endif
10893#ifdef FEAT_CMDL_INFO
10894 win_redr_ruler(curwin, always);
10895#endif
10896
10897#ifdef FEAT_TITLE
10898 if (need_maketitle
10899# ifdef FEAT_STL_OPT
10900 || (p_icon && (stl_syntax & STL_IN_ICON))
10901 || (p_title && (stl_syntax & STL_IN_TITLE))
10902# endif
10903 )
10904 maketitle();
10905#endif
Bram Moolenaar497683b2008-05-28 17:02:46 +000010906 /* Redraw the tab pages line if needed. */
10907 if (redraw_tabline)
10908 draw_tabline();
Bram Moolenaar071d4272004-06-13 20:20:40 +000010909}
10910
10911#ifdef FEAT_CMDL_INFO
10912 static void
Bram Moolenaar05540972016-01-30 20:31:25 +010010913win_redr_ruler(win_T *wp, int always)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010914{
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010915#define RULER_BUF_LEN 70
10916 char_u buffer[RULER_BUF_LEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +000010917 int row;
10918 int fillchar;
10919 int attr;
10920 int empty_line = FALSE;
10921 colnr_T virtcol;
10922 int i;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010923 size_t len;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010924 int o;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010925 int this_ru_col;
10926 int off = 0;
10927 int width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010928
10929 /* If 'ruler' off or redrawing disabled, don't do anything */
10930 if (!p_ru)
10931 return;
10932
10933 /*
10934 * Check if cursor.lnum is valid, since win_redr_ruler() may be called
10935 * after deleting lines, before cursor.lnum is corrected.
10936 */
10937 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
10938 return;
10939
10940#ifdef FEAT_INS_EXPAND
10941 /* Don't draw the ruler while doing insert-completion, it might overwrite
10942 * the (long) mode message. */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010943 if (wp == lastwin && lastwin->w_status_height == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010944 if (edit_submode != NULL)
10945 return;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +000010946 /* Don't draw the ruler when the popup menu is visible, it may overlap. */
10947 if (pum_visible())
10948 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010949#endif
10950
10951#ifdef FEAT_STL_OPT
10952 if (*p_ruf)
10953 {
Bram Moolenaar238a5642006-02-21 22:12:05 +000010954 int save_called_emsg = called_emsg;
10955
10956 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010957 win_redr_custom(wp, TRUE);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010958 if (called_emsg)
10959 set_string_option_direct((char_u *)"rulerformat", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +000010960 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaar238a5642006-02-21 22:12:05 +000010961 called_emsg |= save_called_emsg;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010962 return;
10963 }
10964#endif
10965
10966 /*
10967 * Check if not in Insert mode and the line is empty (will show "0-1").
10968 */
10969 if (!(State & INSERT)
10970 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
10971 empty_line = TRUE;
10972
10973 /*
10974 * Only draw the ruler when something changed.
10975 */
10976 validate_virtcol_win(wp);
10977 if ( redraw_cmdline
10978 || always
10979 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
10980 || wp->w_cursor.col != wp->w_ru_cursor.col
10981 || wp->w_virtcol != wp->w_ru_virtcol
10982#ifdef FEAT_VIRTUALEDIT
10983 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
10984#endif
10985 || wp->w_topline != wp->w_ru_topline
10986 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
10987#ifdef FEAT_DIFF
10988 || wp->w_topfill != wp->w_ru_topfill
10989#endif
10990 || empty_line != wp->w_ru_empty)
10991 {
10992 cursor_off();
Bram Moolenaar071d4272004-06-13 20:20:40 +000010993 if (wp->w_status_height)
10994 {
10995 row = W_WINROW(wp) + wp->w_height;
Bram Moolenaar3633cf52017-07-31 22:29:35 +020010996 fillchar = fillchar_status(&attr, wp);
Bram Moolenaar53f81742017-09-22 14:35:51 +020010997 off = wp->w_wincol;
Bram Moolenaar02631462017-09-22 15:20:32 +020010998 width = wp->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010999 }
11000 else
Bram Moolenaar071d4272004-06-13 20:20:40 +000011001 {
11002 row = Rows - 1;
11003 fillchar = ' ';
11004 attr = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011005 width = Columns;
11006 off = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011007 }
11008
11009 /* In list mode virtcol needs to be recomputed */
11010 virtcol = wp->w_virtcol;
11011 if (wp->w_p_list && lcs_tab1 == NUL)
11012 {
11013 wp->w_p_list = FALSE;
11014 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
11015 wp->w_p_list = TRUE;
11016 }
11017
11018 /*
11019 * Some sprintfs return the length, some return a pointer.
11020 * To avoid portability problems we use strlen() here.
11021 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011022 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
Bram Moolenaar071d4272004-06-13 20:20:40 +000011023 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
11024 ? 0L
11025 : (long)(wp->w_cursor.lnum));
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011026 len = STRLEN(buffer);
11027 col_print(buffer + len, RULER_BUF_LEN - len,
Bram Moolenaar071d4272004-06-13 20:20:40 +000011028 empty_line ? 0 : (int)wp->w_cursor.col + 1,
11029 (int)virtcol + 1);
11030
11031 /*
11032 * Add a "50%" if there is room for it.
11033 * On the last line, don't print in the last column (scrolls the
11034 * screen up on some terminals).
11035 */
11036 i = (int)STRLEN(buffer);
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011037 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011038 o = i + vim_strsize(buffer + i + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011039 if (wp->w_status_height == 0) /* can't use last char of screen */
Bram Moolenaar071d4272004-06-13 20:20:40 +000011040 ++o;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011041 this_ru_col = ru_col - (Columns - width);
11042 if (this_ru_col < 0)
11043 this_ru_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011044 /* Never use more than half the window/screen width, leave the other
11045 * half for the filename. */
Bram Moolenaar4033c552017-09-16 20:54:51 +020011046 if (this_ru_col < (width + 1) / 2)
11047 this_ru_col = (width + 1) / 2;
11048 if (this_ru_col + o < width)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011049 {
Bram Moolenaar0027c212015-01-07 13:31:52 +010011050 /* need at least 3 chars left for get_rel_pos() + NUL */
Bram Moolenaar4033c552017-09-16 20:54:51 +020011051 while (this_ru_col + o < width && RULER_BUF_LEN > i + 4)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011052 {
11053#ifdef FEAT_MBYTE
11054 if (has_mbyte)
11055 i += (*mb_char2bytes)(fillchar, buffer + i);
11056 else
11057#endif
11058 buffer[i++] = fillchar;
11059 ++o;
11060 }
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000011061 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011062 }
11063 /* Truncate at window boundary. */
11064#ifdef FEAT_MBYTE
11065 if (has_mbyte)
11066 {
11067 o = 0;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +000011068 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +000011069 {
11070 o += (*mb_ptr2cells)(buffer + i);
Bram Moolenaar4033c552017-09-16 20:54:51 +020011071 if (this_ru_col + o > width)
Bram Moolenaar071d4272004-06-13 20:20:40 +000011072 {
11073 buffer[i] = NUL;
11074 break;
11075 }
11076 }
11077 }
11078 else
11079#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +020011080 if (this_ru_col + (int)STRLEN(buffer) > width)
11081 buffer[width - this_ru_col] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +000011082
Bram Moolenaar4033c552017-09-16 20:54:51 +020011083 screen_puts(buffer, row, this_ru_col + off, attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000011084 i = redraw_cmdline;
11085 screen_fill(row, row + 1,
Bram Moolenaar4033c552017-09-16 20:54:51 +020011086 this_ru_col + off + (int)STRLEN(buffer),
11087 (int)(off + width),
Bram Moolenaar071d4272004-06-13 20:20:40 +000011088 fillchar, fillchar, attr);
11089 /* don't redraw the cmdline because of showing the ruler */
11090 redraw_cmdline = i;
11091 wp->w_ru_cursor = wp->w_cursor;
11092 wp->w_ru_virtcol = wp->w_virtcol;
11093 wp->w_ru_empty = empty_line;
11094 wp->w_ru_topline = wp->w_topline;
11095 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
11096#ifdef FEAT_DIFF
11097 wp->w_ru_topfill = wp->w_topfill;
11098#endif
11099 }
11100}
11101#endif
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011102
11103#if defined(FEAT_LINEBREAK) || defined(PROTO)
11104/*
Bram Moolenaar64486672010-05-16 15:46:46 +020011105 * Return the width of the 'number' and 'relativenumber' column.
11106 * Caller may need to check if 'number' or 'relativenumber' is set.
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011107 * Otherwise it depends on 'numberwidth' and the line count.
11108 */
11109 int
Bram Moolenaar05540972016-01-30 20:31:25 +010011110number_width(win_T *wp)
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011111{
11112 int n;
11113 linenr_T lnum;
11114
Bram Moolenaar5ebc09b2013-06-04 22:13:50 +020011115 if (wp->w_p_rnu && !wp->w_p_nu)
11116 /* cursor line shows "0" */
11117 lnum = wp->w_height;
11118 else
11119 /* cursor line shows absolute line number */
11120 lnum = wp->w_buffer->b_ml.ml_line_count;
Bram Moolenaar64486672010-05-16 15:46:46 +020011121
Bram Moolenaar6b314672015-03-20 15:42:10 +010011122 if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011123 return wp->w_nrwidth_width;
11124 wp->w_nrwidth_line_count = lnum;
11125
11126 n = 0;
11127 do
11128 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000011129 lnum /= 10;
11130 ++n;
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011131 } while (lnum > 0);
11132
11133 /* 'numberwidth' gives the minimal width plus one */
11134 if (n < wp->w_p_nuw - 1)
11135 n = wp->w_p_nuw - 1;
11136
11137 wp->w_nrwidth_width = n;
Bram Moolenaar6b314672015-03-20 15:42:10 +010011138 wp->w_nuw_cached = wp->w_p_nuw;
Bram Moolenaar592e0a22004-07-03 16:05:59 +000011139 return n;
11140}
11141#endif
Bram Moolenaar9750bb12012-12-05 16:10:42 +010011142
11143/*
11144 * Return the current cursor column. This is the actual position on the
11145 * screen. First column is 0.
11146 */
11147 int
Bram Moolenaar05540972016-01-30 20:31:25 +010011148screen_screencol(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +010011149{
11150 return screen_cur_col;
11151}
11152
11153/*
11154 * Return the current cursor row. This is the actual position on the screen.
11155 * First row is 0.
11156 */
11157 int
Bram Moolenaar05540972016-01-30 20:31:25 +010011158screen_screenrow(void)
Bram Moolenaar9750bb12012-12-05 16:10:42 +010011159{
11160 return screen_cur_row;
11161}