blob: 3df7f665d3123436b85405af3171c72d2c2481b8 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
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)
45 * - w_topfill (filler line above the first line)
46 * - 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
92/*
93 * The attributes that are actually active for writing to the screen.
94 */
95static int screen_attr = 0;
96
97/*
98 * Positioning the cursor is reduced by remembering the last position.
99 * Mostly used by windgoto() and screen_char().
100 */
101static int screen_cur_row, screen_cur_col; /* last known cursor position */
102
103#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104static match_T search_hl; /* used for 'hlsearch' highlight matching */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105#endif
106
107#ifdef FEAT_FOLDING
108static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
109#endif
110
111/*
112 * Buffer for one screen line (characters and attributes).
113 */
114static schar_T *current_ScreenLine;
115
116static void win_update __ARGS((win_T *wp));
Bram Moolenaar482aaeb2005-09-29 18:26:07 +0000117static void win_draw_end __ARGS((win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118#ifdef FEAT_FOLDING
119static void fold_line __ARGS((win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row));
120static void fill_foldcolumn __ARGS((char_u *p, win_T *wp, int closed, linenr_T lnum));
121static void copy_text_attr __ARGS((int off, char_u *buf, int len, int attr));
122#endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000123static int win_line __ARGS((win_T *, linenr_T, int, int, int nochange));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000124static int char_needs_redraw __ARGS((int off_from, int off_to, int cols));
125#ifdef FEAT_RIGHTLEFT
126static void screen_line __ARGS((int row, int coloff, int endcol, int clear_width, int rlflag));
127# define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c), (rl))
128#else
129static void screen_line __ARGS((int row, int coloff, int endcol, int clear_width));
130# define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c))
131#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132#ifdef FEAT_VERTSPLIT
133static void draw_vsep_win __ARGS((win_T *wp, int row));
134#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +0000135#ifdef FEAT_STL_OPT
Bram Moolenaar362f3562009-11-03 16:20:34 +0000136static void redraw_custom_statusline __ARGS((win_T *wp));
Bram Moolenaar238a5642006-02-21 22:12:05 +0000137#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +0000139#define SEARCH_HL_PRIORITY 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140static void start_search_hl __ARGS((void));
141static void end_search_hl __ARGS((void));
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +0200142static void init_search_hl __ARGS((win_T *wp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
144static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol));
145#endif
146static void screen_start_highlight __ARGS((int attr));
147static void screen_char __ARGS((unsigned off, int row, int col));
148#ifdef FEAT_MBYTE
149static void screen_char_2 __ARGS((unsigned off, int row, int col));
150#endif
151static void screenclear2 __ARGS((void));
152static void lineclear __ARGS((unsigned off, int width));
153static void lineinvalid __ARGS((unsigned off, int width));
154#ifdef FEAT_VERTSPLIT
155static void linecopy __ARGS((int to, int from, win_T *wp));
156static void redraw_block __ARGS((int row, int end, win_T *wp));
157#endif
158static int win_do_lines __ARGS((win_T *wp, int row, int line_count, int mayclear, int del));
159static void win_rest_invalid __ARGS((win_T *wp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160static void msg_pos_mode __ARGS((void));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000161#if defined(FEAT_WINDOWS)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000162static void draw_tabline __ARGS((void));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000163#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164#if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
165static int fillchar_status __ARGS((int *attr, int is_curwin));
166#endif
167#ifdef FEAT_VERTSPLIT
168static int fillchar_vsep __ARGS((int *attr));
169#endif
170#ifdef FEAT_STL_OPT
Bram Moolenaar9372a112005-12-06 19:59:18 +0000171static void win_redr_custom __ARGS((win_T *wp, int draw_ruler));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172#endif
173#ifdef FEAT_CMDL_INFO
174static void win_redr_ruler __ARGS((win_T *wp, int always));
175#endif
176
177#if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT)
178/* Ugly global: overrule attribute used by screen_char() */
179static int screen_char_attr = 0;
180#endif
181
182/*
183 * Redraw the current window later, with update_screen(type).
184 * Set must_redraw only if not already set to a higher value.
185 * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
186 */
187 void
188redraw_later(type)
189 int type;
190{
191 redraw_win_later(curwin, type);
192}
193
194 void
195redraw_win_later(wp, type)
196 win_T *wp;
197 int type;
198{
199 if (wp->w_redr_type < type)
200 {
201 wp->w_redr_type = type;
202 if (type >= NOT_VALID)
203 wp->w_lines_valid = 0;
204 if (must_redraw < type) /* must_redraw is the maximum of all windows */
205 must_redraw = type;
206 }
207}
208
209/*
210 * Force a complete redraw later. Also resets the highlighting. To be used
211 * after executing a shell command that messes up the screen.
212 */
213 void
214redraw_later_clear()
215{
216 redraw_all_later(CLEAR);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000217#ifdef FEAT_GUI
218 if (gui.in_use)
219 /* Use a code that will reset gui.highlight_mask in
220 * gui_stop_highlight(). */
221 screen_attr = HL_ALL + 1;
222 else
223#endif
224 /* Use attributes that is very unlikely to appear in text. */
225 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226}
227
228/*
229 * Mark all windows to be redrawn later.
230 */
231 void
232redraw_all_later(type)
233 int type;
234{
235 win_T *wp;
236
237 FOR_ALL_WINDOWS(wp)
238 {
239 redraw_win_later(wp, type);
240 }
241}
242
243/*
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000244 * Mark all windows that are editing the current buffer to be updated later.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245 */
246 void
247redraw_curbuf_later(type)
248 int type;
249{
250 redraw_buf_later(curbuf, type);
251}
252
253 void
254redraw_buf_later(buf, type)
255 buf_T *buf;
256 int type;
257{
258 win_T *wp;
259
260 FOR_ALL_WINDOWS(wp)
261 {
262 if (wp->w_buffer == buf)
263 redraw_win_later(wp, type);
264 }
265}
266
267/*
268 * Changed something in the current window, at buffer line "lnum", that
269 * requires that line and possibly other lines to be redrawn.
270 * Used when entering/leaving Insert mode with the cursor on a folded line.
271 * Used to remove the "$" from a change command.
272 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
273 * may become invalid and the whole window will have to be redrawn.
274 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000275 void
276redrawWinline(lnum, invalid)
277 linenr_T lnum;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +0000278 int invalid UNUSED; /* window line height is invalid now */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279{
280#ifdef FEAT_FOLDING
281 int i;
282#endif
283
284 if (curwin->w_redraw_top == 0 || curwin->w_redraw_top > lnum)
285 curwin->w_redraw_top = lnum;
286 if (curwin->w_redraw_bot == 0 || curwin->w_redraw_bot < lnum)
287 curwin->w_redraw_bot = lnum;
288 redraw_later(VALID);
289
290#ifdef FEAT_FOLDING
291 if (invalid)
292 {
293 /* A w_lines[] entry for this lnum has become invalid. */
294 i = find_wl_entry(curwin, lnum);
295 if (i >= 0)
296 curwin->w_lines[i].wl_valid = FALSE;
297 }
298#endif
299}
300
Bram Moolenaar9d6650f2010-06-06 23:04:47 +0200301#if defined(FEAT_RUBY) || defined(FEAT_PERL) || defined(FEAT_VISUAL) || \
Bram Moolenaarfd3e5dc2010-05-30 19:00:15 +0200302 (defined(FEAT_CLIPBOARD) && defined(FEAT_X11)) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000303/*
304 * update all windows that are editing the current buffer
305 */
306 void
307update_curbuf(type)
308 int type;
309{
310 redraw_curbuf_later(type);
311 update_screen(type);
312}
Bram Moolenaarfd3e5dc2010-05-30 19:00:15 +0200313#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000314
315/*
316 * update_screen()
317 *
318 * Based on the current value of curwin->w_topline, transfer a screenfull
319 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
320 */
321 void
322update_screen(type)
323 int type;
324{
325 win_T *wp;
326 static int did_intro = FALSE;
327#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
328 int did_one;
329#endif
330
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000331 /* Don't do anything if the screen structures are (not yet) valid. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000332 if (!screen_valid(TRUE))
333 return;
334
335 if (must_redraw)
336 {
337 if (type < must_redraw) /* use maximal type */
338 type = must_redraw;
Bram Moolenaar943fae42007-07-30 20:00:38 +0000339
340 /* must_redraw is reset here, so that when we run into some weird
341 * reason to redraw while busy redrawing (e.g., asynchronous
342 * scrolling), or update_topline() in win_update() will cause a
343 * scroll, the screen will be redrawn later or in win_update(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 must_redraw = 0;
345 }
346
347 /* Need to update w_lines[]. */
348 if (curwin->w_lines_valid == 0 && type < NOT_VALID)
349 type = NOT_VALID;
350
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000351 /* Postpone the redrawing when it's not needed and when being called
352 * recursively. */
353 if (!redrawing() || updating_screen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354 {
355 redraw_later(type); /* remember type for next time */
356 must_redraw = type;
357 if (type > INVERTED_ALL)
358 curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
359 return;
360 }
361
362 updating_screen = TRUE;
363#ifdef FEAT_SYN_HL
364 ++display_tick; /* let syntax code know we're in a next round of
365 * display updating */
366#endif
367
368 /*
369 * if the screen was scrolled up when displaying a message, scroll it down
370 */
371 if (msg_scrolled)
372 {
373 clear_cmdline = TRUE;
374 if (msg_scrolled > Rows - 5) /* clearing is faster */
375 type = CLEAR;
376 else if (type != CLEAR)
377 {
378 check_for_delay(FALSE);
379 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL)
380 type = CLEAR;
381 FOR_ALL_WINDOWS(wp)
382 {
383 if (W_WINROW(wp) < msg_scrolled)
384 {
385 if (W_WINROW(wp) + wp->w_height > msg_scrolled
386 && wp->w_redr_type < REDRAW_TOP
387 && wp->w_lines_valid > 0
388 && wp->w_topline == wp->w_lines[0].wl_lnum)
389 {
390 wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
391 wp->w_redr_type = REDRAW_TOP;
392 }
393 else
394 {
395 wp->w_redr_type = NOT_VALID;
396#ifdef FEAT_WINDOWS
397 if (W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp)
398 <= msg_scrolled)
399 wp->w_redr_status = TRUE;
400#endif
401 }
402 }
403 }
404 redraw_cmdline = TRUE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000405#ifdef FEAT_WINDOWS
Bram Moolenaar997fb4b2006-02-17 21:53:23 +0000406 redraw_tabline = TRUE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000407#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 }
409 msg_scrolled = 0;
410 need_wait_return = FALSE;
411 }
412
413 /* reset cmdline_row now (may have been changed temporarily) */
414 compute_cmdrow();
415
416 /* Check for changed highlighting */
417 if (need_highlight_changed)
418 highlight_changed();
419
420 if (type == CLEAR) /* first clear screen */
421 {
422 screenclear(); /* will reset clear_cmdline */
423 type = NOT_VALID;
424 }
425
426 if (clear_cmdline) /* going to clear cmdline (done below) */
427 check_for_delay(FALSE);
428
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000429#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +0200430 /* Force redraw when width of 'number' or 'relativenumber' column
431 * changes. */
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000432 if (curwin->w_redr_type < NOT_VALID
Bram Moolenaar64486672010-05-16 15:46:46 +0200433 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
434 ? number_width(curwin) : 0))
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000435 curwin->w_redr_type = NOT_VALID;
436#endif
437
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 /*
439 * Only start redrawing if there is really something to do.
440 */
441 if (type == INVERTED)
442 update_curswant();
443 if (curwin->w_redr_type < type
444 && !((type == VALID
445 && curwin->w_lines[0].wl_valid
446#ifdef FEAT_DIFF
447 && curwin->w_topfill == curwin->w_old_topfill
448 && curwin->w_botfill == curwin->w_old_botfill
449#endif
450 && curwin->w_topline == curwin->w_lines[0].wl_lnum)
451#ifdef FEAT_VISUAL
452 || (type == INVERTED
Bram Moolenaarb0c9a852006-11-28 15:14:56 +0000453 && VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
455 && curwin->w_old_visual_mode == VIsual_mode
456 && (curwin->w_valid & VALID_VIRTCOL)
457 && curwin->w_old_curswant == curwin->w_curswant)
458#endif
459 ))
460 curwin->w_redr_type = type;
461
Bram Moolenaar5a305422006-04-28 22:38:25 +0000462#ifdef FEAT_WINDOWS
463 /* Redraw the tab pages line if needed. */
464 if (redraw_tabline || type >= NOT_VALID)
465 draw_tabline();
466#endif
467
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468#ifdef FEAT_SYN_HL
469 /*
470 * Correct stored syntax highlighting info for changes in each displayed
471 * buffer. Each buffer must only be done once.
472 */
473 FOR_ALL_WINDOWS(wp)
474 {
475 if (wp->w_buffer->b_mod_set)
476 {
477# ifdef FEAT_WINDOWS
478 win_T *wwp;
479
480 /* Check if we already did this buffer. */
481 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
482 if (wwp->w_buffer == wp->w_buffer)
483 break;
484# endif
485 if (
486# ifdef FEAT_WINDOWS
487 wwp == wp &&
488# endif
Bram Moolenaar860cae12010-06-05 23:22:07 +0200489 syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000490 syn_stack_apply_changes(wp->w_buffer);
491 }
492 }
493#endif
494
495 /*
496 * Go from top to bottom through the windows, redrawing the ones that need
497 * it.
498 */
499#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
500 did_one = FALSE;
501#endif
502#ifdef FEAT_SEARCH_EXTRA
503 search_hl.rm.regprog = NULL;
504#endif
505 FOR_ALL_WINDOWS(wp)
506 {
507 if (wp->w_redr_type != 0)
508 {
509 cursor_off();
510#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
511 if (!did_one)
512 {
513 did_one = TRUE;
514# ifdef FEAT_SEARCH_EXTRA
515 start_search_hl();
516# endif
517# ifdef FEAT_CLIPBOARD
518 /* When Visual area changed, may have to update selection. */
519 if (clip_star.available && clip_isautosel())
520 clip_update_selection();
521# endif
522#ifdef FEAT_GUI
523 /* Remove the cursor before starting to do anything, because
524 * scrolling may make it difficult to redraw the text under
525 * it. */
526 if (gui.in_use)
527 gui_undraw_cursor();
528#endif
529 }
530#endif
531 win_update(wp);
532 }
533
534#ifdef FEAT_WINDOWS
535 /* redraw status line after the window to minimize cursor movement */
536 if (wp->w_redr_status)
537 {
538 cursor_off();
539 win_redr_status(wp);
540 }
541#endif
542 }
543#if defined(FEAT_SEARCH_EXTRA)
544 end_search_hl();
545#endif
546
547#ifdef FEAT_WINDOWS
548 /* Reset b_mod_set flags. Going through all windows is probably faster
549 * than going through all buffers (there could be many buffers). */
550 for (wp = firstwin; wp != NULL; wp = wp->w_next)
551 wp->w_buffer->b_mod_set = FALSE;
552#else
553 curbuf->b_mod_set = FALSE;
554#endif
555
556 updating_screen = FALSE;
557#ifdef FEAT_GUI
558 gui_may_resize_shell();
559#endif
560
561 /* Clear or redraw the command line. Done last, because scrolling may
562 * mess up the command line. */
563 if (clear_cmdline || redraw_cmdline)
564 showmode();
565
566 /* May put up an introductory message when not editing a file */
567 if (!did_intro && bufempty()
568 && curbuf->b_fname == NULL
569#ifdef FEAT_WINDOWS
570 && firstwin->w_next == NULL
571#endif
572 && vim_strchr(p_shm, SHM_INTRO) == NULL)
573 intro_message(FALSE);
574 did_intro = TRUE;
575
576#ifdef FEAT_GUI
577 /* Redraw the cursor and update the scrollbars when all screen updating is
578 * done. */
579 if (gui.in_use)
580 {
581 out_flush(); /* required before updating the cursor */
582 if (did_one)
583 gui_update_cursor(FALSE, FALSE);
584 gui_update_scrollbars(FALSE);
585 }
586#endif
587}
588
Bram Moolenaar860cae12010-06-05 23:22:07 +0200589#if defined(FEAT_CONCEAL) || defined(PROTO)
590 void
591update_single_line(wp, lnum)
592 win_T *wp;
593 linenr_T lnum;
594{
595 int row;
596 int j;
597
598 if (lnum >= wp->w_topline && lnum < wp->w_botline
Bram Moolenaar370df582010-06-22 05:16:38 +0200599 && foldedCount(wp, lnum, &win_foldinfo) == 0)
Bram Moolenaar860cae12010-06-05 23:22:07 +0200600 {
601# ifdef FEAT_GUI
602 /* Remove the cursor before starting to do anything, because scrolling
603 * may make it difficult to redraw the text under it. */
604 if (gui.in_use)
605 gui_undraw_cursor();
606# endif
607 row = 0;
608 for (j = 0; j < wp->w_lines_valid; ++j)
609 {
610 if (lnum == wp->w_lines[j].wl_lnum)
611 {
612 screen_start(); /* not sure of screen cursor */
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +0200613# ifdef FEAT_SEARCH_EXTRA
614 init_search_hl(wp);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200615 start_search_hl();
616 prepare_search_hl(wp, lnum);
617# endif
618 win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE);
619# if defined(FEAT_SEARCH_EXTRA)
620 end_search_hl();
621# endif
622 break;
623 }
624 row += wp->w_lines[j].wl_size;
625 }
626# ifdef FEAT_GUI
627 /* Redraw the cursor */
628 if (gui.in_use)
629 {
630 out_flush(); /* required before updating the cursor */
631 gui_update_cursor(FALSE, FALSE);
632 }
633# endif
634 }
635}
636#endif
637
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638#if defined(FEAT_SIGNS) || defined(FEAT_GUI)
639static void update_prepare __ARGS((void));
640static void update_finish __ARGS((void));
641
642/*
643 * Prepare for updating one or more windows.
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000644 * Caller must check for "updating_screen" already set to avoid recursiveness.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 */
646 static void
647update_prepare()
648{
649 cursor_off();
650 updating_screen = TRUE;
651#ifdef FEAT_GUI
652 /* Remove the cursor before starting to do anything, because scrolling may
653 * make it difficult to redraw the text under it. */
654 if (gui.in_use)
655 gui_undraw_cursor();
656#endif
657#ifdef FEAT_SEARCH_EXTRA
658 start_search_hl();
659#endif
660}
661
662/*
663 * Finish updating one or more windows.
664 */
665 static void
666update_finish()
667{
668 if (redraw_cmdline)
669 showmode();
670
671# ifdef FEAT_SEARCH_EXTRA
672 end_search_hl();
673# endif
674
675 updating_screen = FALSE;
676
677# ifdef FEAT_GUI
678 gui_may_resize_shell();
679
680 /* Redraw the cursor and update the scrollbars when all screen updating is
681 * done. */
682 if (gui.in_use)
683 {
684 out_flush(); /* required before updating the cursor */
685 gui_update_cursor(FALSE, FALSE);
686 gui_update_scrollbars(FALSE);
687 }
688# endif
689}
690#endif
691
692#if defined(FEAT_SIGNS) || defined(PROTO)
693 void
694update_debug_sign(buf, lnum)
695 buf_T *buf;
696 linenr_T lnum;
697{
698 win_T *wp;
699 int doit = FALSE;
700
701# ifdef FEAT_FOLDING
702 win_foldinfo.fi_level = 0;
703# endif
704
705 /* update/delete a specific mark */
706 FOR_ALL_WINDOWS(wp)
707 {
708 if (buf != NULL && lnum > 0)
709 {
710 if (wp->w_buffer == buf && lnum >= wp->w_topline
711 && lnum < wp->w_botline)
712 {
713 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
714 wp->w_redraw_top = lnum;
715 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
716 wp->w_redraw_bot = lnum;
717 redraw_win_later(wp, VALID);
718 }
719 }
720 else
721 redraw_win_later(wp, VALID);
722 if (wp->w_redr_type != 0)
723 doit = TRUE;
724 }
725
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000726 /* Return when there is nothing to do or screen updating already
727 * happening. */
728 if (!doit || updating_screen)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729 return;
730
731 /* update all windows that need updating */
732 update_prepare();
733
734# ifdef FEAT_WINDOWS
735 for (wp = firstwin; wp; wp = wp->w_next)
736 {
737 if (wp->w_redr_type != 0)
738 win_update(wp);
739 if (wp->w_redr_status)
740 win_redr_status(wp);
741 }
742# else
743 if (curwin->w_redr_type != 0)
744 win_update(curwin);
745# endif
746
747 update_finish();
748}
749#endif
750
751
752#if defined(FEAT_GUI) || defined(PROTO)
753/*
754 * Update a single window, its status line and maybe the command line msg.
755 * Used for the GUI scrollbar.
756 */
757 void
758updateWindow(wp)
759 win_T *wp;
760{
Bram Moolenaar19f990e2009-11-25 12:08:03 +0000761 /* return if already busy updating */
762 if (updating_screen)
763 return;
764
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 update_prepare();
766
767#ifdef FEAT_CLIPBOARD
768 /* When Visual area changed, may have to update selection. */
769 if (clip_star.available && clip_isautosel())
770 clip_update_selection();
771#endif
Bram Moolenaar4c7ed462006-02-15 22:18:42 +0000772
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 win_update(wp);
Bram Moolenaar4c7ed462006-02-15 22:18:42 +0000774
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775#ifdef FEAT_WINDOWS
Bram Moolenaar4c7ed462006-02-15 22:18:42 +0000776 /* When the screen was cleared redraw the tab pages line. */
Bram Moolenaar997fb4b2006-02-17 21:53:23 +0000777 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000778 draw_tabline();
Bram Moolenaar4c7ed462006-02-15 22:18:42 +0000779
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 if (wp->w_redr_status
781# ifdef FEAT_CMDL_INFO
782 || p_ru
783# endif
784# ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +0000785 || *p_stl != NUL || *wp->w_p_stl != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786# endif
787 )
788 win_redr_status(wp);
789#endif
790
791 update_finish();
792}
793#endif
794
795/*
796 * Update a single window.
797 *
798 * This may cause the windows below it also to be redrawn (when clearing the
799 * screen or scrolling lines).
800 *
801 * How the window is redrawn depends on wp->w_redr_type. Each type also
802 * implies the one below it.
803 * NOT_VALID redraw the whole window
Bram Moolenaar600dddc2006-03-12 22:05:10 +0000804 * SOME_VALID redraw the whole window but do scroll when possible
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
806 * INVERTED redraw the changed part of the Visual area
807 * INVERTED_ALL redraw the whole Visual area
808 * VALID 1. scroll up/down to adjust for a changed w_topline
809 * 2. update lines at the top when scrolled down
810 * 3. redraw changed text:
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000811 * - if wp->w_buffer->b_mod_set set, update lines between
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 * b_mod_top and b_mod_bot.
813 * - if wp->w_redraw_top non-zero, redraw lines between
814 * wp->w_redraw_top and wp->w_redr_bot.
815 * - continue redrawing when syntax status is invalid.
816 * 4. if scrolled up, update lines at the bottom.
817 * This results in three areas that may need updating:
818 * top: from first row to top_end (when scrolled down)
819 * mid: from mid_start to mid_end (update inversion or changed text)
820 * bot: from bot_start to last row (when scrolled up)
821 */
822 static void
823win_update(wp)
824 win_T *wp;
825{
826 buf_T *buf = wp->w_buffer;
827 int type;
828 int top_end = 0; /* Below last row of the top area that needs
829 updating. 0 when no top area updating. */
830 int mid_start = 999;/* first row of the mid area that needs
831 updating. 999 when no mid area updating. */
832 int mid_end = 0; /* Below last row of the mid area that needs
833 updating. 0 when no mid area updating. */
834 int bot_start = 999;/* first row of the bot area that needs
835 updating. 999 when no bot area updating */
836#ifdef FEAT_VISUAL
837 int scrolled_down = FALSE; /* TRUE when scrolled down when
838 w_topline got smaller a bit */
839#endif
840#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +0000841 matchitem_T *cur; /* points to the match list */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842 int top_to_mod = FALSE; /* redraw above mod_top */
843#endif
844
845 int row; /* current window row to display */
846 linenr_T lnum; /* current buffer lnum to display */
847 int idx; /* current index in w_lines[] */
848 int srow; /* starting row of the current line */
849
850 int eof = FALSE; /* if TRUE, we hit the end of the file */
851 int didline = FALSE; /* if TRUE, we finished the last line */
852 int i;
853 long j;
854 static int recursive = FALSE; /* being called recursively */
855 int old_botline = wp->w_botline;
856#ifdef FEAT_FOLDING
857 long fold_count;
858#endif
859#ifdef FEAT_SYN_HL
860 /* remember what happened to the previous line, to know if
861 * check_visual_highlight() can be used */
862#define DID_NONE 1 /* didn't update a line */
863#define DID_LINE 2 /* updated a normal line */
864#define DID_FOLD 3 /* updated a folded line */
865 int did_update = DID_NONE;
866 linenr_T syntax_last_parsed = 0; /* last parsed text line */
867#endif
868 linenr_T mod_top = 0;
869 linenr_T mod_bot = 0;
870#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
871 int save_got_int;
872#endif
873
874 type = wp->w_redr_type;
875
876 if (type == NOT_VALID)
877 {
878#ifdef FEAT_WINDOWS
879 wp->w_redr_status = TRUE;
880#endif
881 wp->w_lines_valid = 0;
882 }
883
884 /* Window is zero-height: nothing to draw. */
885 if (wp->w_height == 0)
886 {
887 wp->w_redr_type = 0;
888 return;
889 }
890
891#ifdef FEAT_VERTSPLIT
892 /* Window is zero-width: Only need to draw the separator. */
893 if (wp->w_width == 0)
894 {
895 /* draw the vertical separator right of this window */
896 draw_vsep_win(wp, 0);
897 wp->w_redr_type = 0;
898 return;
899 }
900#endif
901
902#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +0200903 init_search_hl(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904#endif
905
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000906#ifdef FEAT_LINEBREAK
Bram Moolenaar64486672010-05-16 15:46:46 +0200907 /* Force redraw when width of 'number' or 'relativenumber' column
908 * changes. */
909 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000910 if (wp->w_nrwidth != i)
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000911 {
912 type = NOT_VALID;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000913 wp->w_nrwidth = i;
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000914 }
915 else
916#endif
917
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
919 {
920 /*
921 * When there are both inserted/deleted lines and specific lines to be
922 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
923 * everything (only happens when redrawing is off for while).
924 */
925 type = NOT_VALID;
926 }
927 else
928 {
929 /*
930 * Set mod_top to the first line that needs displaying because of
931 * changes. Set mod_bot to the first line after the changes.
932 */
933 mod_top = wp->w_redraw_top;
934 if (wp->w_redraw_bot != 0)
935 mod_bot = wp->w_redraw_bot + 1;
936 else
937 mod_bot = 0;
938 wp->w_redraw_top = 0; /* reset for next time */
939 wp->w_redraw_bot = 0;
940 if (buf->b_mod_set)
941 {
942 if (mod_top == 0 || mod_top > buf->b_mod_top)
943 {
944 mod_top = buf->b_mod_top;
945#ifdef FEAT_SYN_HL
946 /* Need to redraw lines above the change that may be included
947 * in a pattern match. */
Bram Moolenaar860cae12010-06-05 23:22:07 +0200948 if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949 {
Bram Moolenaar860cae12010-06-05 23:22:07 +0200950 mod_top -= buf->b_s.b_syn_sync_linebreaks;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000951 if (mod_top < 1)
952 mod_top = 1;
953 }
954#endif
955 }
956 if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
957 mod_bot = buf->b_mod_bot;
958
959#ifdef FEAT_SEARCH_EXTRA
960 /* When 'hlsearch' is on and using a multi-line search pattern, a
961 * change in one line may make the Search highlighting in a
962 * previous line invalid. Simple solution: redraw all visible
963 * lines above the change.
Bram Moolenaar6ee10162007-07-26 20:58:42 +0000964 * Same for a match pattern.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000965 */
Bram Moolenaarfd2ac762006-03-01 22:09:21 +0000966 if (search_hl.rm.regprog != NULL
967 && re_multiline(search_hl.rm.regprog))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000968 top_to_mod = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +0000969 else
Bram Moolenaar6ee10162007-07-26 20:58:42 +0000970 {
971 cur = wp->w_match_head;
972 while (cur != NULL)
973 {
974 if (cur->match.regprog != NULL
975 && re_multiline(cur->match.regprog))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +0000976 {
977 top_to_mod = TRUE;
978 break;
979 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +0000980 cur = cur->next;
981 }
982 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000983#endif
984 }
985#ifdef FEAT_FOLDING
986 if (mod_top != 0 && hasAnyFolding(wp))
987 {
988 linenr_T lnumt, lnumb;
989
990 /*
991 * A change in a line can cause lines above it to become folded or
992 * unfolded. Find the top most buffer line that may be affected.
993 * If the line was previously folded and displayed, get the first
994 * line of that fold. If the line is folded now, get the first
995 * folded line. Use the minimum of these two.
996 */
997
998 /* Find last valid w_lines[] entry above mod_top. Set lnumt to
999 * the line below it. If there is no valid entry, use w_topline.
1000 * Find the first valid w_lines[] entry below mod_bot. Set lnumb
1001 * to this line. If there is no valid entry, use MAXLNUM. */
1002 lnumt = wp->w_topline;
1003 lnumb = MAXLNUM;
1004 for (i = 0; i < wp->w_lines_valid; ++i)
1005 if (wp->w_lines[i].wl_valid)
1006 {
1007 if (wp->w_lines[i].wl_lastlnum < mod_top)
1008 lnumt = wp->w_lines[i].wl_lastlnum + 1;
1009 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1010 {
1011 lnumb = wp->w_lines[i].wl_lnum;
1012 /* When there is a fold column it might need updating
1013 * in the next line ("J" just above an open fold). */
1014 if (wp->w_p_fdc > 0)
1015 ++lnumb;
1016 }
1017 }
1018
1019 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1020 if (mod_top > lnumt)
1021 mod_top = lnumt;
1022
1023 /* Now do the same for the bottom line (one above mod_bot). */
1024 --mod_bot;
1025 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1026 ++mod_bot;
1027 if (mod_bot < lnumb)
1028 mod_bot = lnumb;
1029 }
1030#endif
1031
1032 /* When a change starts above w_topline and the end is below
1033 * w_topline, start redrawing at w_topline.
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001034 * If the end of the change is above w_topline: do like no change was
1035 * made, but redraw the first line to find changes in syntax. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 if (mod_top != 0 && mod_top < wp->w_topline)
1037 {
1038 if (mod_bot > wp->w_topline)
1039 mod_top = wp->w_topline;
1040#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02001041 else if (syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001042 top_end = 1;
1043#endif
1044 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001045
1046 /* When line numbers are displayed need to redraw all lines below
1047 * inserted/deleted lines. */
1048 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1049 mod_bot = MAXLNUM;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050 }
1051
1052 /*
1053 * When only displaying the lines at the top, set top_end. Used when
1054 * window has scrolled down for msg_scrolled.
1055 */
1056 if (type == REDRAW_TOP)
1057 {
1058 j = 0;
1059 for (i = 0; i < wp->w_lines_valid; ++i)
1060 {
1061 j += wp->w_lines[i].wl_size;
1062 if (j >= wp->w_upd_rows)
1063 {
1064 top_end = j;
1065 break;
1066 }
1067 }
1068 if (top_end == 0)
1069 /* not found (cannot happen?): redraw everything */
1070 type = NOT_VALID;
1071 else
1072 /* top area defined, the rest is VALID */
1073 type = VALID;
1074 }
1075
Bram Moolenaar367329b2007-08-30 11:53:22 +00001076 /* Trick: we want to avoid clearing the screen twice. screenclear() will
Bram Moolenaar943fae42007-07-30 20:00:38 +00001077 * set "screen_cleared" to TRUE. The special value MAYBE (which is still
1078 * non-zero and thus not FALSE) will indicate that screenclear() was not
1079 * called. */
1080 if (screen_cleared)
1081 screen_cleared = MAYBE;
1082
Bram Moolenaar071d4272004-06-13 20:20:40 +00001083 /*
1084 * If there are no changes on the screen that require a complete redraw,
1085 * handle three cases:
1086 * 1: we are off the top of the screen by a few lines: scroll down
1087 * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1088 * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1089 * w_lines[] that needs updating.
1090 */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001091 if ((type == VALID || type == SOME_VALID
1092 || type == INVERTED || type == INVERTED_ALL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093#ifdef FEAT_DIFF
1094 && !wp->w_botfill && !wp->w_old_botfill
1095#endif
1096 )
1097 {
1098 if (mod_top != 0 && wp->w_topline == mod_top)
1099 {
1100 /*
1101 * w_topline is the first changed line, the scrolling will be done
1102 * further down.
1103 */
1104 }
1105 else if (wp->w_lines[0].wl_valid
1106 && (wp->w_topline < wp->w_lines[0].wl_lnum
1107#ifdef FEAT_DIFF
1108 || (wp->w_topline == wp->w_lines[0].wl_lnum
1109 && wp->w_topfill > wp->w_old_topfill)
1110#endif
1111 ))
1112 {
1113 /*
1114 * New topline is above old topline: May scroll down.
1115 */
1116#ifdef FEAT_FOLDING
1117 if (hasAnyFolding(wp))
1118 {
1119 linenr_T ln;
1120
1121 /* count the number of lines we are off, counting a sequence
1122 * of folded lines as one */
1123 j = 0;
1124 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1125 {
1126 ++j;
1127 if (j >= wp->w_height - 2)
1128 break;
1129 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1130 }
1131 }
1132 else
1133#endif
1134 j = wp->w_lines[0].wl_lnum - wp->w_topline;
1135 if (j < wp->w_height - 2) /* not too far off */
1136 {
1137 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1138#ifdef FEAT_DIFF
1139 /* insert extra lines for previously invisible filler lines */
1140 if (wp->w_lines[0].wl_lnum != wp->w_topline)
1141 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1142 - wp->w_old_topfill;
1143#endif
1144 if (i < wp->w_height - 2) /* less than a screen off */
1145 {
1146 /*
1147 * Try to insert the correct number of lines.
1148 * If not the last window, delete the lines at the bottom.
1149 * win_ins_lines may fail when the terminal can't do it.
1150 */
1151 if (i > 0)
1152 check_for_delay(FALSE);
1153 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1154 {
1155 if (wp->w_lines_valid != 0)
1156 {
1157 /* Need to update rows that are new, stop at the
1158 * first one that scrolled down. */
1159 top_end = i;
1160#ifdef FEAT_VISUAL
1161 scrolled_down = TRUE;
1162#endif
1163
1164 /* Move the entries that were scrolled, disable
1165 * the entries for the lines to be redrawn. */
1166 if ((wp->w_lines_valid += j) > wp->w_height)
1167 wp->w_lines_valid = wp->w_height;
1168 for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1169 wp->w_lines[idx] = wp->w_lines[idx - j];
1170 while (idx >= 0)
1171 wp->w_lines[idx--].wl_valid = FALSE;
1172 }
1173 }
1174 else
1175 mid_start = 0; /* redraw all lines */
1176 }
1177 else
1178 mid_start = 0; /* redraw all lines */
1179 }
1180 else
1181 mid_start = 0; /* redraw all lines */
1182 }
1183 else
1184 {
1185 /*
1186 * New topline is at or below old topline: May scroll up.
1187 * When topline didn't change, find first entry in w_lines[] that
1188 * needs updating.
1189 */
1190
1191 /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
1192 j = -1;
1193 row = 0;
1194 for (i = 0; i < wp->w_lines_valid; i++)
1195 {
1196 if (wp->w_lines[i].wl_valid
1197 && wp->w_lines[i].wl_lnum == wp->w_topline)
1198 {
1199 j = i;
1200 break;
1201 }
1202 row += wp->w_lines[i].wl_size;
1203 }
1204 if (j == -1)
1205 {
1206 /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1207 * lines */
1208 mid_start = 0;
1209 }
1210 else
1211 {
1212 /*
1213 * Try to delete the correct number of lines.
1214 * wp->w_topline is at wp->w_lines[i].wl_lnum.
1215 */
1216#ifdef FEAT_DIFF
1217 /* If the topline didn't change, delete old filler lines,
1218 * otherwise delete filler lines of the new topline... */
1219 if (wp->w_lines[0].wl_lnum == wp->w_topline)
1220 row += wp->w_old_topfill;
1221 else
1222 row += diff_check_fill(wp, wp->w_topline);
1223 /* ... but don't delete new filler lines. */
1224 row -= wp->w_topfill;
1225#endif
1226 if (row > 0)
1227 {
1228 check_for_delay(FALSE);
1229 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin) == OK)
1230 bot_start = wp->w_height - row;
1231 else
1232 mid_start = 0; /* redraw all lines */
1233 }
1234 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1235 {
1236 /*
1237 * Skip the lines (below the deleted lines) that are still
1238 * valid and don't need redrawing. Copy their info
1239 * upwards, to compensate for the deleted lines. Set
1240 * bot_start to the first row that needs redrawing.
1241 */
1242 bot_start = 0;
1243 idx = 0;
1244 for (;;)
1245 {
1246 wp->w_lines[idx] = wp->w_lines[j];
1247 /* stop at line that didn't fit, unless it is still
1248 * valid (no lines deleted) */
1249 if (row > 0 && bot_start + row
1250 + (int)wp->w_lines[j].wl_size > wp->w_height)
1251 {
1252 wp->w_lines_valid = idx + 1;
1253 break;
1254 }
1255 bot_start += wp->w_lines[idx++].wl_size;
1256
1257 /* stop at the last valid entry in w_lines[].wl_size */
1258 if (++j >= wp->w_lines_valid)
1259 {
1260 wp->w_lines_valid = idx;
1261 break;
1262 }
1263 }
1264#ifdef FEAT_DIFF
1265 /* Correct the first entry for filler lines at the top
1266 * when it won't get updated below. */
1267 if (wp->w_p_diff && bot_start > 0)
1268 wp->w_lines[0].wl_size =
1269 plines_win_nofill(wp, wp->w_topline, TRUE)
1270 + wp->w_topfill;
1271#endif
1272 }
1273 }
1274 }
1275
1276 /* When starting redraw in the first line, redraw all lines. When
1277 * there is only one window it's probably faster to clear the screen
1278 * first. */
1279 if (mid_start == 0)
1280 {
1281 mid_end = wp->w_height;
1282 if (lastwin == firstwin)
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001283 {
Bram Moolenaar943fae42007-07-30 20:00:38 +00001284 /* Clear the screen when it was not done by win_del_lines() or
1285 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1286 * then. */
1287 if (screen_cleared != TRUE)
1288 screenclear();
Bram Moolenaarbc1a7c32006-09-14 19:04:14 +00001289#ifdef FEAT_WINDOWS
1290 /* The screen was cleared, redraw the tab pages line. */
1291 if (redraw_tabline)
1292 draw_tabline();
1293#endif
1294 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001295 }
Bram Moolenaar943fae42007-07-30 20:00:38 +00001296
1297 /* When win_del_lines() or win_ins_lines() caused the screen to be
1298 * cleared (only happens for the first window) or when screenclear()
1299 * was called directly above, "must_redraw" will have been set to
1300 * NOT_VALID, need to reset it here to avoid redrawing twice. */
1301 if (screen_cleared == TRUE)
1302 must_redraw = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303 }
1304 else
1305 {
1306 /* Not VALID or INVERTED: redraw all lines. */
1307 mid_start = 0;
1308 mid_end = wp->w_height;
1309 }
1310
Bram Moolenaar600dddc2006-03-12 22:05:10 +00001311 if (type == SOME_VALID)
1312 {
1313 /* SOME_VALID: redraw all lines. */
1314 mid_start = 0;
1315 mid_end = wp->w_height;
1316 type = NOT_VALID;
1317 }
1318
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319#ifdef FEAT_VISUAL
1320 /* check if we are updating or removing the inverted part */
1321 if ((VIsual_active && buf == curwin->w_buffer)
1322 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1323 {
1324 linenr_T from, to;
1325
1326 if (VIsual_active)
1327 {
1328 if (VIsual_active
1329 && (VIsual_mode != wp->w_old_visual_mode
1330 || type == INVERTED_ALL))
1331 {
1332 /*
1333 * If the type of Visual selection changed, redraw the whole
1334 * selection. Also when the ownership of the X selection is
1335 * gained or lost.
1336 */
1337 if (curwin->w_cursor.lnum < VIsual.lnum)
1338 {
1339 from = curwin->w_cursor.lnum;
1340 to = VIsual.lnum;
1341 }
1342 else
1343 {
1344 from = VIsual.lnum;
1345 to = curwin->w_cursor.lnum;
1346 }
1347 /* redraw more when the cursor moved as well */
1348 if (wp->w_old_cursor_lnum < from)
1349 from = wp->w_old_cursor_lnum;
1350 if (wp->w_old_cursor_lnum > to)
1351 to = wp->w_old_cursor_lnum;
1352 if (wp->w_old_visual_lnum < from)
1353 from = wp->w_old_visual_lnum;
1354 if (wp->w_old_visual_lnum > to)
1355 to = wp->w_old_visual_lnum;
1356 }
1357 else
1358 {
1359 /*
1360 * Find the line numbers that need to be updated: The lines
1361 * between the old cursor position and the current cursor
1362 * position. Also check if the Visual position changed.
1363 */
1364 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1365 {
1366 from = curwin->w_cursor.lnum;
1367 to = wp->w_old_cursor_lnum;
1368 }
1369 else
1370 {
1371 from = wp->w_old_cursor_lnum;
1372 to = curwin->w_cursor.lnum;
1373 if (from == 0) /* Visual mode just started */
1374 from = to;
1375 }
1376
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001377 if (VIsual.lnum != wp->w_old_visual_lnum
1378 || VIsual.col != wp->w_old_visual_col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001379 {
1380 if (wp->w_old_visual_lnum < from
1381 && wp->w_old_visual_lnum != 0)
1382 from = wp->w_old_visual_lnum;
1383 if (wp->w_old_visual_lnum > to)
1384 to = wp->w_old_visual_lnum;
1385 if (VIsual.lnum < from)
1386 from = VIsual.lnum;
1387 if (VIsual.lnum > to)
1388 to = VIsual.lnum;
1389 }
1390 }
1391
1392 /*
1393 * If in block mode and changed column or curwin->w_curswant:
1394 * update all lines.
1395 * First compute the actual start and end column.
1396 */
1397 if (VIsual_mode == Ctrl_V)
1398 {
1399 colnr_T fromc, toc;
1400
1401 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
1402 ++toc;
1403 if (curwin->w_curswant == MAXCOL)
1404 toc = MAXCOL;
1405
1406 if (fromc != wp->w_old_cursor_fcol
1407 || toc != wp->w_old_cursor_lcol)
1408 {
1409 if (from > VIsual.lnum)
1410 from = VIsual.lnum;
1411 if (to < VIsual.lnum)
1412 to = VIsual.lnum;
1413 }
1414 wp->w_old_cursor_fcol = fromc;
1415 wp->w_old_cursor_lcol = toc;
1416 }
1417 }
1418 else
1419 {
1420 /* Use the line numbers of the old Visual area. */
1421 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
1422 {
1423 from = wp->w_old_cursor_lnum;
1424 to = wp->w_old_visual_lnum;
1425 }
1426 else
1427 {
1428 from = wp->w_old_visual_lnum;
1429 to = wp->w_old_cursor_lnum;
1430 }
1431 }
1432
1433 /*
1434 * There is no need to update lines above the top of the window.
1435 */
1436 if (from < wp->w_topline)
1437 from = wp->w_topline;
1438
1439 /*
1440 * If we know the value of w_botline, use it to restrict the update to
1441 * the lines that are visible in the window.
1442 */
1443 if (wp->w_valid & VALID_BOTLINE)
1444 {
1445 if (from >= wp->w_botline)
1446 from = wp->w_botline - 1;
1447 if (to >= wp->w_botline)
1448 to = wp->w_botline - 1;
1449 }
1450
1451 /*
1452 * Find the minimal part to be updated.
1453 * Watch out for scrolling that made entries in w_lines[] invalid.
1454 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
1455 * top_end; need to redraw from top_end to the "to" line.
1456 * A middle mouse click with a Visual selection may change the text
1457 * above the Visual area and reset wl_valid, do count these for
1458 * mid_end (in srow).
1459 */
1460 if (mid_start > 0)
1461 {
1462 lnum = wp->w_topline;
1463 idx = 0;
1464 srow = 0;
1465 if (scrolled_down)
1466 mid_start = top_end;
1467 else
1468 mid_start = 0;
1469 while (lnum < from && idx < wp->w_lines_valid) /* find start */
1470 {
1471 if (wp->w_lines[idx].wl_valid)
1472 mid_start += wp->w_lines[idx].wl_size;
1473 else if (!scrolled_down)
1474 srow += wp->w_lines[idx].wl_size;
1475 ++idx;
1476# ifdef FEAT_FOLDING
1477 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
1478 lnum = wp->w_lines[idx].wl_lnum;
1479 else
1480# endif
1481 ++lnum;
1482 }
1483 srow += mid_start;
1484 mid_end = wp->w_height;
1485 for ( ; idx < wp->w_lines_valid; ++idx) /* find end */
1486 {
1487 if (wp->w_lines[idx].wl_valid
1488 && wp->w_lines[idx].wl_lnum >= to + 1)
1489 {
1490 /* Only update until first row of this line */
1491 mid_end = srow;
1492 break;
1493 }
1494 srow += wp->w_lines[idx].wl_size;
1495 }
1496 }
1497 }
1498
1499 if (VIsual_active && buf == curwin->w_buffer)
1500 {
1501 wp->w_old_visual_mode = VIsual_mode;
1502 wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
1503 wp->w_old_visual_lnum = VIsual.lnum;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001504 wp->w_old_visual_col = VIsual.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 wp->w_old_curswant = curwin->w_curswant;
1506 }
1507 else
1508 {
1509 wp->w_old_visual_mode = 0;
1510 wp->w_old_cursor_lnum = 0;
1511 wp->w_old_visual_lnum = 0;
Bram Moolenaar6c131c42005-07-19 22:17:30 +00001512 wp->w_old_visual_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001513 }
1514#endif /* FEAT_VISUAL */
1515
1516#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1517 /* reset got_int, otherwise regexp won't work */
1518 save_got_int = got_int;
1519 got_int = 0;
1520#endif
1521#ifdef FEAT_FOLDING
1522 win_foldinfo.fi_level = 0;
1523#endif
1524
1525 /*
1526 * Update all the window rows.
1527 */
1528 idx = 0; /* first entry in w_lines[].wl_size */
1529 row = 0;
1530 srow = 0;
1531 lnum = wp->w_topline; /* first line shown in window */
1532 for (;;)
1533 {
1534 /* stop updating when reached the end of the window (check for _past_
1535 * the end of the window is at the end of the loop) */
1536 if (row == wp->w_height)
1537 {
1538 didline = TRUE;
1539 break;
1540 }
1541
1542 /* stop updating when hit the end of the file */
1543 if (lnum > buf->b_ml.ml_line_count)
1544 {
1545 eof = TRUE;
1546 break;
1547 }
1548
1549 /* Remember the starting row of the line that is going to be dealt
1550 * with. It is used further down when the line doesn't fit. */
1551 srow = row;
1552
1553 /*
1554 * Update a line when it is in an area that needs updating, when it
1555 * has changes or w_lines[idx] is invalid.
1556 * bot_start may be halfway a wrapped line after using
1557 * win_del_lines(), check if the current line includes it.
1558 * When syntax folding is being used, the saved syntax states will
1559 * already have been updated, we can't see where the syntax state is
1560 * the same again, just update until the end of the window.
1561 */
1562 if (row < top_end
1563 || (row >= mid_start && row < mid_end)
1564#ifdef FEAT_SEARCH_EXTRA
1565 || top_to_mod
1566#endif
1567 || idx >= wp->w_lines_valid
1568 || (row + wp->w_lines[idx].wl_size > bot_start)
1569 || (mod_top != 0
1570 && (lnum == mod_top
1571 || (lnum >= mod_top
1572 && (lnum < mod_bot
1573#ifdef FEAT_SYN_HL
1574 || did_update == DID_FOLD
1575 || (did_update == DID_LINE
Bram Moolenaar860cae12010-06-05 23:22:07 +02001576 && syntax_present(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001577 && (
1578# ifdef FEAT_FOLDING
1579 (foldmethodIsSyntax(wp)
1580 && hasAnyFolding(wp)) ||
1581# endif
1582 syntax_check_changed(lnum)))
1583#endif
1584 )))))
1585 {
1586#ifdef FEAT_SEARCH_EXTRA
1587 if (lnum == mod_top)
1588 top_to_mod = FALSE;
1589#endif
1590
1591 /*
1592 * When at start of changed lines: May scroll following lines
1593 * up or down to minimize redrawing.
1594 * Don't do this when the change continues until the end.
1595 * Don't scroll when dollar_vcol is non-zero, keep the "$".
1596 */
1597 if (lnum == mod_top
1598 && mod_bot != MAXLNUM
1599 && !(dollar_vcol != 0 && mod_bot == mod_top + 1))
1600 {
1601 int old_rows = 0;
1602 int new_rows = 0;
1603 int xtra_rows;
1604 linenr_T l;
1605
1606 /* Count the old number of window rows, using w_lines[], which
1607 * should still contain the sizes for the lines as they are
1608 * currently displayed. */
1609 for (i = idx; i < wp->w_lines_valid; ++i)
1610 {
1611 /* Only valid lines have a meaningful wl_lnum. Invalid
1612 * lines are part of the changed area. */
1613 if (wp->w_lines[i].wl_valid
1614 && wp->w_lines[i].wl_lnum == mod_bot)
1615 break;
1616 old_rows += wp->w_lines[i].wl_size;
1617#ifdef FEAT_FOLDING
1618 if (wp->w_lines[i].wl_valid
1619 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
1620 {
1621 /* Must have found the last valid entry above mod_bot.
1622 * Add following invalid entries. */
1623 ++i;
1624 while (i < wp->w_lines_valid
1625 && !wp->w_lines[i].wl_valid)
1626 old_rows += wp->w_lines[i++].wl_size;
1627 break;
1628 }
1629#endif
1630 }
1631
1632 if (i >= wp->w_lines_valid)
1633 {
1634 /* We can't find a valid line below the changed lines,
1635 * need to redraw until the end of the window.
1636 * Inserting/deleting lines has no use. */
1637 bot_start = 0;
1638 }
1639 else
1640 {
1641 /* Able to count old number of rows: Count new window
1642 * rows, and may insert/delete lines */
1643 j = idx;
1644 for (l = lnum; l < mod_bot; ++l)
1645 {
1646#ifdef FEAT_FOLDING
1647 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
1648 ++new_rows;
1649 else
1650#endif
1651#ifdef FEAT_DIFF
1652 if (l == wp->w_topline)
1653 new_rows += plines_win_nofill(wp, l, TRUE)
1654 + wp->w_topfill;
1655 else
1656#endif
1657 new_rows += plines_win(wp, l, TRUE);
1658 ++j;
1659 if (new_rows > wp->w_height - row - 2)
1660 {
1661 /* it's getting too much, must redraw the rest */
1662 new_rows = 9999;
1663 break;
1664 }
1665 }
1666 xtra_rows = new_rows - old_rows;
1667 if (xtra_rows < 0)
1668 {
1669 /* May scroll text up. If there is not enough
1670 * remaining text or scrolling fails, must redraw the
1671 * rest. If scrolling works, must redraw the text
1672 * below the scrolled text. */
1673 if (row - xtra_rows >= wp->w_height - 2)
1674 mod_bot = MAXLNUM;
1675 else
1676 {
1677 check_for_delay(FALSE);
1678 if (win_del_lines(wp, row,
1679 -xtra_rows, FALSE, FALSE) == FAIL)
1680 mod_bot = MAXLNUM;
1681 else
1682 bot_start = wp->w_height + xtra_rows;
1683 }
1684 }
1685 else if (xtra_rows > 0)
1686 {
1687 /* May scroll text down. If there is not enough
1688 * remaining text of scrolling fails, must redraw the
1689 * rest. */
1690 if (row + xtra_rows >= wp->w_height - 2)
1691 mod_bot = MAXLNUM;
1692 else
1693 {
1694 check_for_delay(FALSE);
1695 if (win_ins_lines(wp, row + old_rows,
1696 xtra_rows, FALSE, FALSE) == FAIL)
1697 mod_bot = MAXLNUM;
1698 else if (top_end > row + old_rows)
1699 /* Scrolled the part at the top that requires
1700 * updating down. */
1701 top_end += xtra_rows;
1702 }
1703 }
1704
1705 /* When not updating the rest, may need to move w_lines[]
1706 * entries. */
1707 if (mod_bot != MAXLNUM && i != j)
1708 {
1709 if (j < i)
1710 {
1711 int x = row + new_rows;
1712
1713 /* move entries in w_lines[] upwards */
1714 for (;;)
1715 {
1716 /* stop at last valid entry in w_lines[] */
1717 if (i >= wp->w_lines_valid)
1718 {
1719 wp->w_lines_valid = j;
1720 break;
1721 }
1722 wp->w_lines[j] = wp->w_lines[i];
1723 /* stop at a line that won't fit */
1724 if (x + (int)wp->w_lines[j].wl_size
1725 > wp->w_height)
1726 {
1727 wp->w_lines_valid = j + 1;
1728 break;
1729 }
1730 x += wp->w_lines[j++].wl_size;
1731 ++i;
1732 }
1733 if (bot_start > x)
1734 bot_start = x;
1735 }
1736 else /* j > i */
1737 {
1738 /* move entries in w_lines[] downwards */
1739 j -= i;
1740 wp->w_lines_valid += j;
1741 if (wp->w_lines_valid > wp->w_height)
1742 wp->w_lines_valid = wp->w_height;
1743 for (i = wp->w_lines_valid; i - j >= idx; --i)
1744 wp->w_lines[i] = wp->w_lines[i - j];
1745
1746 /* The w_lines[] entries for inserted lines are
1747 * now invalid, but wl_size may be used above.
1748 * Reset to zero. */
1749 while (i >= idx)
1750 {
1751 wp->w_lines[i].wl_size = 0;
1752 wp->w_lines[i--].wl_valid = FALSE;
1753 }
1754 }
1755 }
1756 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 }
1758
1759#ifdef FEAT_FOLDING
1760 /*
1761 * When lines are folded, display one line for all of them.
1762 * Otherwise, display normally (can be several display lines when
1763 * 'wrap' is on).
1764 */
1765 fold_count = foldedCount(wp, lnum, &win_foldinfo);
1766 if (fold_count != 0)
1767 {
1768 fold_line(wp, fold_count, &win_foldinfo, lnum, row);
1769 ++row;
1770 --fold_count;
1771 wp->w_lines[idx].wl_folded = TRUE;
1772 wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
1773# ifdef FEAT_SYN_HL
1774 did_update = DID_FOLD;
1775# endif
1776 }
1777 else
1778#endif
1779 if (idx < wp->w_lines_valid
1780 && wp->w_lines[idx].wl_valid
1781 && wp->w_lines[idx].wl_lnum == lnum
1782 && lnum > wp->w_topline
1783 && !(dy_flags & DY_LASTLINE)
1784 && srow + wp->w_lines[idx].wl_size > wp->w_height
1785#ifdef FEAT_DIFF
1786 && diff_check_fill(wp, lnum) == 0
1787#endif
1788 )
1789 {
1790 /* This line is not going to fit. Don't draw anything here,
1791 * will draw "@ " lines below. */
1792 row = wp->w_height + 1;
1793 }
1794 else
1795 {
1796#ifdef FEAT_SEARCH_EXTRA
1797 prepare_search_hl(wp, lnum);
1798#endif
1799#ifdef FEAT_SYN_HL
1800 /* Let the syntax stuff know we skipped a few lines. */
1801 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
Bram Moolenaar860cae12010-06-05 23:22:07 +02001802 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 syntax_end_parsing(syntax_last_parsed + 1);
1804#endif
1805
1806 /*
1807 * Display one line.
1808 */
Bram Moolenaar4770d092006-01-12 23:22:24 +00001809 row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810
1811#ifdef FEAT_FOLDING
1812 wp->w_lines[idx].wl_folded = FALSE;
1813 wp->w_lines[idx].wl_lastlnum = lnum;
1814#endif
1815#ifdef FEAT_SYN_HL
1816 did_update = DID_LINE;
1817 syntax_last_parsed = lnum;
1818#endif
1819 }
1820
1821 wp->w_lines[idx].wl_lnum = lnum;
1822 wp->w_lines[idx].wl_valid = TRUE;
1823 if (row > wp->w_height) /* past end of screen */
1824 {
1825 /* we may need the size of that too long line later on */
1826 if (dollar_vcol == 0)
1827 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
1828 ++idx;
1829 break;
1830 }
1831 if (dollar_vcol == 0)
1832 wp->w_lines[idx].wl_size = row - srow;
1833 ++idx;
1834#ifdef FEAT_FOLDING
1835 lnum += fold_count + 1;
1836#else
1837 ++lnum;
1838#endif
1839 }
1840 else
1841 {
1842 /* This line does not need updating, advance to the next one */
1843 row += wp->w_lines[idx++].wl_size;
1844 if (row > wp->w_height) /* past end of screen */
1845 break;
1846#ifdef FEAT_FOLDING
1847 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
1848#else
1849 ++lnum;
1850#endif
1851#ifdef FEAT_SYN_HL
1852 did_update = DID_NONE;
1853#endif
1854 }
1855
1856 if (lnum > buf->b_ml.ml_line_count)
1857 {
1858 eof = TRUE;
1859 break;
1860 }
1861 }
1862 /*
1863 * End of loop over all window lines.
1864 */
1865
1866
1867 if (idx > wp->w_lines_valid)
1868 wp->w_lines_valid = idx;
1869
1870#ifdef FEAT_SYN_HL
1871 /*
1872 * Let the syntax stuff know we stop parsing here.
1873 */
Bram Moolenaar860cae12010-06-05 23:22:07 +02001874 if (syntax_last_parsed != 0 && syntax_present(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 syntax_end_parsing(syntax_last_parsed + 1);
1876#endif
1877
1878 /*
1879 * If we didn't hit the end of the file, and we didn't finish the last
1880 * line we were working on, then the line didn't fit.
1881 */
1882 wp->w_empty_rows = 0;
1883#ifdef FEAT_DIFF
1884 wp->w_filler_rows = 0;
1885#endif
1886 if (!eof && !didline)
1887 {
1888 if (lnum == wp->w_topline)
1889 {
1890 /*
1891 * Single line that does not fit!
1892 * Don't overwrite it, it can be edited.
1893 */
1894 wp->w_botline = lnum + 1;
1895 }
1896#ifdef FEAT_DIFF
1897 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
1898 {
1899 /* Window ends in filler lines. */
1900 wp->w_botline = lnum;
1901 wp->w_filler_rows = wp->w_height - srow;
1902 }
1903#endif
1904 else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */
1905 {
1906 /*
1907 * Last line isn't finished: Display "@@@" at the end.
1908 */
1909 screen_fill(W_WINROW(wp) + wp->w_height - 1,
1910 W_WINROW(wp) + wp->w_height,
1911 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
1912 '@', '@', hl_attr(HLF_AT));
1913 set_empty_rows(wp, srow);
1914 wp->w_botline = lnum;
1915 }
1916 else
1917 {
1918 win_draw_end(wp, '@', ' ', srow, wp->w_height, HLF_AT);
1919 wp->w_botline = lnum;
1920 }
1921 }
1922 else
1923 {
1924#ifdef FEAT_VERTSPLIT
1925 draw_vsep_win(wp, row);
1926#endif
1927 if (eof) /* we hit the end of the file */
1928 {
1929 wp->w_botline = buf->b_ml.ml_line_count + 1;
1930#ifdef FEAT_DIFF
1931 j = diff_check_fill(wp, wp->w_botline);
1932 if (j > 0 && !wp->w_botfill)
1933 {
1934 /*
1935 * Display filler lines at the end of the file
1936 */
1937 if (char2cells(fill_diff) > 1)
1938 i = '-';
1939 else
1940 i = fill_diff;
1941 if (row + j > wp->w_height)
1942 j = wp->w_height - row;
1943 win_draw_end(wp, i, i, row, row + (int)j, HLF_DED);
1944 row += j;
1945 }
1946#endif
1947 }
1948 else if (dollar_vcol == 0)
1949 wp->w_botline = lnum;
1950
1951 /* make sure the rest of the screen is blank */
1952 /* put '~'s on rows that aren't part of the file. */
1953 win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_AT);
1954 }
1955
1956 /* Reset the type of redrawing required, the window has been updated. */
1957 wp->w_redr_type = 0;
1958#ifdef FEAT_DIFF
1959 wp->w_old_topfill = wp->w_topfill;
1960 wp->w_old_botfill = wp->w_botfill;
1961#endif
1962
1963 if (dollar_vcol == 0)
1964 {
1965 /*
1966 * There is a trick with w_botline. If we invalidate it on each
1967 * change that might modify it, this will cause a lot of expensive
1968 * calls to plines() in update_topline() each time. Therefore the
1969 * value of w_botline is often approximated, and this value is used to
1970 * compute the value of w_topline. If the value of w_botline was
1971 * wrong, check that the value of w_topline is correct (cursor is on
1972 * the visible part of the text). If it's not, we need to redraw
1973 * again. Mostly this just means scrolling up a few lines, so it
1974 * doesn't look too bad. Only do this for the current window (where
1975 * changes are relevant).
1976 */
1977 wp->w_valid |= VALID_BOTLINE;
1978 if (wp == curwin && wp->w_botline != old_botline && !recursive)
1979 {
1980 recursive = TRUE;
1981 curwin->w_valid &= ~VALID_TOPLINE;
1982 update_topline(); /* may invalidate w_botline again */
1983 if (must_redraw != 0)
1984 {
1985 /* Don't update for changes in buffer again. */
1986 i = curbuf->b_mod_set;
1987 curbuf->b_mod_set = FALSE;
1988 win_update(curwin);
1989 must_redraw = 0;
1990 curbuf->b_mod_set = i;
1991 }
1992 recursive = FALSE;
1993 }
1994 }
1995
1996#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1997 /* restore got_int, unless CTRL-C was hit while redrawing */
1998 if (!got_int)
1999 got_int = save_got_int;
2000#endif
2001}
2002
2003#ifdef FEAT_SIGNS
2004static int draw_signcolumn __ARGS((win_T *wp));
2005
2006/*
2007 * Return TRUE when window "wp" has a column to draw signs in.
2008 */
2009 static int
2010draw_signcolumn(wp)
2011 win_T *wp;
2012{
2013 return (wp->w_buffer->b_signlist != NULL
2014# ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002015 || netbeans_active()
Bram Moolenaar071d4272004-06-13 20:20:40 +00002016# endif
2017 );
2018}
2019#endif
2020
2021/*
2022 * Clear the rest of the window and mark the unused lines with "c1". use "c2"
2023 * as the filler character.
2024 */
2025 static void
2026win_draw_end(wp, c1, c2, row, endrow, hl)
2027 win_T *wp;
2028 int c1;
2029 int c2;
2030 int row;
2031 int endrow;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002032 hlf_T hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033{
2034#if defined(FEAT_FOLDING) || defined(FEAT_SIGNS) || defined(FEAT_CMDWIN)
2035 int n = 0;
2036# define FDC_OFF n
2037#else
2038# define FDC_OFF 0
2039#endif
2040
2041#ifdef FEAT_RIGHTLEFT
2042 if (wp->w_p_rl)
2043 {
2044 /* No check for cmdline window: should never be right-left. */
2045# ifdef FEAT_FOLDING
2046 n = wp->w_p_fdc;
2047
2048 if (n > 0)
2049 {
2050 /* draw the fold column at the right */
Bram Moolenaar383f9bc2005-01-19 22:18:32 +00002051 if (n > W_WIDTH(wp))
2052 n = W_WIDTH(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2054 W_ENDCOL(wp) - n, (int)W_ENDCOL(wp),
2055 ' ', ' ', hl_attr(HLF_FC));
2056 }
2057# endif
2058# ifdef FEAT_SIGNS
2059 if (draw_signcolumn(wp))
2060 {
2061 int nn = n + 2;
2062
2063 /* draw the sign column left of the fold column */
Bram Moolenaar383f9bc2005-01-19 22:18:32 +00002064 if (nn > W_WIDTH(wp))
2065 nn = W_WIDTH(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2067 W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - n,
2068 ' ', ' ', hl_attr(HLF_SC));
2069 n = nn;
2070 }
2071# endif
2072 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2073 W_WINCOL(wp), W_ENDCOL(wp) - 1 - FDC_OFF,
2074 c2, c2, hl_attr(hl));
2075 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2076 W_ENDCOL(wp) - 1 - FDC_OFF, W_ENDCOL(wp) - FDC_OFF,
2077 c1, c2, hl_attr(hl));
2078 }
2079 else
2080#endif
2081 {
2082#ifdef FEAT_CMDWIN
2083 if (cmdwin_type != 0 && wp == curwin)
2084 {
2085 /* draw the cmdline character in the leftmost column */
2086 n = 1;
2087 if (n > wp->w_width)
2088 n = wp->w_width;
2089 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2090 W_WINCOL(wp), (int)W_WINCOL(wp) + n,
2091 cmdwin_type, ' ', hl_attr(HLF_AT));
2092 }
2093#endif
2094#ifdef FEAT_FOLDING
2095 if (wp->w_p_fdc > 0)
2096 {
2097 int nn = n + wp->w_p_fdc;
2098
2099 /* draw the fold column at the left */
2100 if (nn > W_WIDTH(wp))
2101 nn = W_WIDTH(wp);
2102 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2103 W_WINCOL(wp) + n, (int)W_WINCOL(wp) + nn,
2104 ' ', ' ', hl_attr(HLF_FC));
2105 n = nn;
2106 }
2107#endif
2108#ifdef FEAT_SIGNS
2109 if (draw_signcolumn(wp))
2110 {
2111 int nn = n + 2;
2112
2113 /* draw the sign column after the fold column */
2114 if (nn > W_WIDTH(wp))
2115 nn = W_WIDTH(wp);
2116 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2117 W_WINCOL(wp) + n, (int)W_WINCOL(wp) + nn,
2118 ' ', ' ', hl_attr(HLF_SC));
2119 n = nn;
2120 }
2121#endif
2122 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2123 W_WINCOL(wp) + FDC_OFF, (int)W_ENDCOL(wp),
2124 c1, c2, hl_attr(hl));
2125 }
2126 set_empty_rows(wp, row);
2127}
2128
2129#ifdef FEAT_FOLDING
2130/*
2131 * Display one folded line.
2132 */
2133 static void
2134fold_line(wp, fold_count, foldinfo, lnum, row)
2135 win_T *wp;
2136 long fold_count;
2137 foldinfo_T *foldinfo;
2138 linenr_T lnum;
2139 int row;
2140{
2141 char_u buf[51];
2142 pos_T *top, *bot;
2143 linenr_T lnume = lnum + fold_count - 1;
2144 int len;
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002145 char_u *text;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146 int fdc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 int col;
2148 int txtcol;
2149 int off = (int)(current_ScreenLine - ScreenLines);
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002150 int ri;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151
2152 /* Build the fold line:
2153 * 1. Add the cmdwin_type for the command-line window
2154 * 2. Add the 'foldcolumn'
Bram Moolenaar64486672010-05-16 15:46:46 +02002155 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002156 * 4. Compose the text
2157 * 5. Add the text
2158 * 6. set highlighting for the Visual area an other text
2159 */
2160 col = 0;
2161
2162 /*
2163 * 1. Add the cmdwin_type for the command-line window
2164 * Ignores 'rightleft', this window is never right-left.
2165 */
2166#ifdef FEAT_CMDWIN
2167 if (cmdwin_type != 0 && wp == curwin)
2168 {
2169 ScreenLines[off] = cmdwin_type;
2170 ScreenAttrs[off] = hl_attr(HLF_AT);
2171#ifdef FEAT_MBYTE
2172 if (enc_utf8)
2173 ScreenLinesUC[off] = 0;
2174#endif
2175 ++col;
2176 }
2177#endif
2178
2179 /*
2180 * 2. Add the 'foldcolumn'
2181 */
2182 fdc = wp->w_p_fdc;
2183 if (fdc > W_WIDTH(wp) - col)
2184 fdc = W_WIDTH(wp) - col;
2185 if (fdc > 0)
2186 {
2187 fill_foldcolumn(buf, wp, TRUE, lnum);
2188#ifdef FEAT_RIGHTLEFT
2189 if (wp->w_p_rl)
2190 {
2191 int i;
2192
2193 copy_text_attr(off + W_WIDTH(wp) - fdc - col, buf, fdc,
2194 hl_attr(HLF_FC));
2195 /* reverse the fold column */
2196 for (i = 0; i < fdc; ++i)
2197 ScreenLines[off + W_WIDTH(wp) - i - 1 - col] = buf[i];
2198 }
2199 else
2200#endif
2201 copy_text_attr(off + col, buf, fdc, hl_attr(HLF_FC));
2202 col += fdc;
2203 }
2204
2205#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002206# define RL_MEMSET(p, v, l) if (wp->w_p_rl) \
2207 for (ri = 0; ri < l; ++ri) \
2208 ScreenAttrs[off + (W_WIDTH(wp) - (p) - (l)) + ri] = v; \
2209 else \
2210 for (ri = 0; ri < l; ++ri) \
2211 ScreenAttrs[off + (p) + ri] = v
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212#else
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002213# define RL_MEMSET(p, v, l) for (ri = 0; ri < l; ++ri) \
2214 ScreenAttrs[off + (p) + ri] = v
Bram Moolenaar071d4272004-06-13 20:20:40 +00002215#endif
2216
Bram Moolenaar64486672010-05-16 15:46:46 +02002217 /* Set all attributes of the 'number' or 'relativenumber' column and the
2218 * text */
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002219 RL_MEMSET(col, hl_attr(HLF_FL), W_WIDTH(wp) - col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220
2221#ifdef FEAT_SIGNS
2222 /* If signs are being displayed, add two spaces. */
2223 if (draw_signcolumn(wp))
2224 {
2225 len = W_WIDTH(wp) - col;
2226 if (len > 0)
2227 {
2228 if (len > 2)
2229 len = 2;
2230# ifdef FEAT_RIGHTLEFT
2231 if (wp->w_p_rl)
2232 /* the line number isn't reversed */
2233 copy_text_attr(off + W_WIDTH(wp) - len - col,
2234 (char_u *)" ", len, hl_attr(HLF_FL));
2235 else
2236# endif
2237 copy_text_attr(off + col, (char_u *)" ", len, hl_attr(HLF_FL));
2238 col += len;
2239 }
2240 }
2241#endif
2242
2243 /*
Bram Moolenaar64486672010-05-16 15:46:46 +02002244 * 3. Add the 'number' or 'relativenumber' column
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245 */
Bram Moolenaar64486672010-05-16 15:46:46 +02002246 if (wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002247 {
2248 len = W_WIDTH(wp) - col;
2249 if (len > 0)
2250 {
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002251 int w = number_width(wp);
Bram Moolenaar64486672010-05-16 15:46:46 +02002252 long num;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002253
2254 if (len > w + 1)
2255 len = w + 1;
Bram Moolenaar64486672010-05-16 15:46:46 +02002256
2257 if (wp->w_p_nu)
2258 /* 'number' */
2259 num = (long)lnum;
2260 else
2261 /* 'relativenumber', don't use negative numbers */
2262 num = (long)abs((int)get_cursor_rel_lnum(wp, lnum));
2263
2264 sprintf((char *)buf, "%*ld ", w, num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265#ifdef FEAT_RIGHTLEFT
2266 if (wp->w_p_rl)
2267 /* the line number isn't reversed */
2268 copy_text_attr(off + W_WIDTH(wp) - len - col, buf, len,
2269 hl_attr(HLF_FL));
2270 else
2271#endif
2272 copy_text_attr(off + col, buf, len, hl_attr(HLF_FL));
2273 col += len;
2274 }
2275 }
2276
2277 /*
2278 * 4. Compose the folded-line string with 'foldtext', if set.
2279 */
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002280 text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281
2282 txtcol = col; /* remember where text starts */
2283
2284 /*
2285 * 5. move the text to current_ScreenLine. Fill up with "fill_fold".
2286 * Right-left text is put in columns 0 - number-col, normal text is put
2287 * in columns number-col - window-width.
2288 */
2289#ifdef FEAT_MBYTE
2290 if (has_mbyte)
2291 {
2292 int cells;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002293 int u8c, u8cc[MAX_MCO];
2294 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295 int idx;
2296 int c_len;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002297 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298# ifdef FEAT_ARABIC
2299 int prev_c = 0; /* previous Arabic character */
2300 int prev_c1 = 0; /* first composing char for prev_c */
2301# endif
2302
2303# ifdef FEAT_RIGHTLEFT
2304 if (wp->w_p_rl)
2305 idx = off;
2306 else
2307# endif
2308 idx = off + col;
2309
2310 /* Store multibyte characters in ScreenLines[] et al. correctly. */
2311 for (p = text; *p != NUL; )
2312 {
2313 cells = (*mb_ptr2cells)(p);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002314 c_len = (*mb_ptr2len)(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315 if (col + cells > W_WIDTH(wp)
2316# ifdef FEAT_RIGHTLEFT
2317 - (wp->w_p_rl ? col : 0)
2318# endif
2319 )
2320 break;
2321 ScreenLines[idx] = *p;
2322 if (enc_utf8)
2323 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002324 u8c = utfc_ptr2char(p, u8cc);
2325 if (*p < 0x80 && u8cc[0] == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326 {
2327 ScreenLinesUC[idx] = 0;
2328#ifdef FEAT_ARABIC
2329 prev_c = u8c;
2330#endif
2331 }
2332 else
2333 {
2334#ifdef FEAT_ARABIC
2335 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
2336 {
2337 /* Do Arabic shaping. */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002338 int pc, pc1, nc;
2339 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340 int firstbyte = *p;
2341
2342 /* The idea of what is the previous and next
2343 * character depends on 'rightleft'. */
2344 if (wp->w_p_rl)
2345 {
2346 pc = prev_c;
2347 pc1 = prev_c1;
2348 nc = utf_ptr2char(p + c_len);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002349 prev_c1 = u8cc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 }
2351 else
2352 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002353 pc = utfc_ptr2char(p + c_len, pcc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 nc = prev_c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002355 pc1 = pcc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356 }
2357 prev_c = u8c;
2358
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002359 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 pc, pc1, nc);
2361 ScreenLines[idx] = firstbyte;
2362 }
2363 else
2364 prev_c = u8c;
2365#endif
2366 /* Non-BMP character: display as ? or fullwidth ?. */
Bram Moolenaar11936362007-09-17 20:39:42 +00002367#ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 if (u8c >= 0x10000)
2369 ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?';
2370 else
Bram Moolenaar11936362007-09-17 20:39:42 +00002371#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 ScreenLinesUC[idx] = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002373 for (i = 0; i < Screen_mco; ++i)
2374 {
2375 ScreenLinesC[i][idx] = u8cc[i];
2376 if (u8cc[i] == 0)
2377 break;
2378 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 }
2380 if (cells > 1)
2381 ScreenLines[idx + 1] = 0;
2382 }
Bram Moolenaar990bb662010-02-03 15:48:04 +01002383 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
2384 /* double-byte single width character */
2385 ScreenLines2[idx] = p[1];
2386 else if (cells > 1)
2387 /* double-width character */
2388 ScreenLines[idx + 1] = p[1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 col += cells;
2390 idx += cells;
2391 p += c_len;
2392 }
2393 }
2394 else
2395#endif
2396 {
2397 len = (int)STRLEN(text);
2398 if (len > W_WIDTH(wp) - col)
2399 len = W_WIDTH(wp) - col;
2400 if (len > 0)
2401 {
2402#ifdef FEAT_RIGHTLEFT
2403 if (wp->w_p_rl)
2404 STRNCPY(current_ScreenLine, text, len);
2405 else
2406#endif
2407 STRNCPY(current_ScreenLine + col, text, len);
2408 col += len;
2409 }
2410 }
2411
2412 /* Fill the rest of the line with the fold filler */
2413#ifdef FEAT_RIGHTLEFT
2414 if (wp->w_p_rl)
2415 col -= txtcol;
2416#endif
2417 while (col < W_WIDTH(wp)
2418#ifdef FEAT_RIGHTLEFT
2419 - (wp->w_p_rl ? txtcol : 0)
2420#endif
2421 )
2422 {
2423#ifdef FEAT_MBYTE
2424 if (enc_utf8)
2425 {
2426 if (fill_fold >= 0x80)
2427 {
2428 ScreenLinesUC[off + col] = fill_fold;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002429 ScreenLinesC[0][off + col] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 }
2431 else
2432 ScreenLinesUC[off + col] = 0;
2433 }
2434#endif
2435 ScreenLines[off + col++] = fill_fold;
2436 }
2437
2438 if (text != buf)
2439 vim_free(text);
2440
2441 /*
2442 * 6. set highlighting for the Visual area an other text.
2443 * If all folded lines are in the Visual area, highlight the line.
2444 */
2445#ifdef FEAT_VISUAL
2446 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
2447 {
2448 if (ltoreq(curwin->w_cursor, VIsual))
2449 {
2450 /* Visual is after curwin->w_cursor */
2451 top = &curwin->w_cursor;
2452 bot = &VIsual;
2453 }
2454 else
2455 {
2456 /* Visual is before curwin->w_cursor */
2457 top = &VIsual;
2458 bot = &curwin->w_cursor;
2459 }
2460 if (lnum >= top->lnum
2461 && lnume <= bot->lnum
2462 && (VIsual_mode != 'v'
2463 || ((lnum > top->lnum
2464 || (lnum == top->lnum
2465 && top->col == 0))
2466 && (lnume < bot->lnum
2467 || (lnume == bot->lnum
2468 && (bot->col - (*p_sel == 'e'))
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002469 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 {
2471 if (VIsual_mode == Ctrl_V)
2472 {
2473 /* Visual block mode: highlight the chars part of the block */
2474 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)W_WIDTH(wp))
2475 {
2476 if (wp->w_old_cursor_lcol + txtcol < (colnr_T)W_WIDTH(wp))
2477 len = wp->w_old_cursor_lcol;
2478 else
2479 len = W_WIDTH(wp) - txtcol;
2480 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, hl_attr(HLF_V),
Bram Moolenaar68b76a62005-03-25 21:53:48 +00002481 len - (int)wp->w_old_cursor_fcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 }
2483 }
2484 else
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002485 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486 /* Set all attributes of the text */
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002487 RL_MEMSET(txtcol, hl_attr(HLF_V), W_WIDTH(wp) - txtcol);
2488 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489 }
2490 }
2491#endif
2492
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002493#ifdef FEAT_SYN_HL
2494 /* Show 'cursorcolumn' in the fold line. */
Bram Moolenaar85595c52008-10-02 16:04:05 +00002495 if (wp->w_p_cuc)
2496 {
2497 txtcol += wp->w_virtcol;
2498 if (wp->w_p_wrap)
2499 txtcol -= wp->w_skipcol;
2500 else
2501 txtcol -= wp->w_leftcol;
2502 if (txtcol >= 0 && txtcol < W_WIDTH(wp))
2503 ScreenAttrs[off + txtcol] = hl_combine_attr(
2504 ScreenAttrs[off + txtcol], hl_attr(HLF_CUC));
2505 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002506#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507
2508 SCREEN_LINE(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp),
2509 (int)W_WIDTH(wp), FALSE);
2510
2511 /*
2512 * Update w_cline_height and w_cline_folded if the cursor line was
2513 * updated (saves a call to plines() later).
2514 */
2515 if (wp == curwin
2516 && lnum <= curwin->w_cursor.lnum
2517 && lnume >= curwin->w_cursor.lnum)
2518 {
2519 curwin->w_cline_row = row;
2520 curwin->w_cline_height = 1;
2521 curwin->w_cline_folded = TRUE;
2522 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
2523 }
2524}
2525
2526/*
2527 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
2528 */
2529 static void
2530copy_text_attr(off, buf, len, attr)
2531 int off;
2532 char_u *buf;
2533 int len;
2534 int attr;
2535{
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002536 int i;
2537
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538 mch_memmove(ScreenLines + off, buf, (size_t)len);
2539# ifdef FEAT_MBYTE
2540 if (enc_utf8)
2541 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
2542# endif
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00002543 for (i = 0; i < len; ++i)
2544 ScreenAttrs[off + i] = attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545}
2546
2547/*
2548 * Fill the foldcolumn at "p" for window "wp".
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +00002549 * Only to be called when 'foldcolumn' > 0.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 */
2551 static void
2552fill_foldcolumn(p, wp, closed, lnum)
2553 char_u *p;
2554 win_T *wp;
2555 int closed; /* TRUE of FALSE */
2556 linenr_T lnum; /* current line number */
2557{
2558 int i = 0;
2559 int level;
2560 int first_level;
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002561 int empty;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562
2563 /* Init to all spaces. */
2564 copy_spaces(p, (size_t)wp->w_p_fdc);
2565
2566 level = win_foldinfo.fi_level;
2567 if (level > 0)
2568 {
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002569 /* If there is only one column put more info in it. */
2570 empty = (wp->w_p_fdc == 1) ? 0 : 1;
2571
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 /* If the column is too narrow, we start at the lowest level that
2573 * fits and use numbers to indicated the depth. */
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002574 first_level = level - wp->w_p_fdc - closed + 1 + empty;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575 if (first_level < 1)
2576 first_level = 1;
2577
Bram Moolenaar578b49e2005-09-10 19:22:57 +00002578 for (i = 0; i + empty < wp->w_p_fdc; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002579 {
2580 if (win_foldinfo.fi_lnum == lnum
2581 && first_level + i >= win_foldinfo.fi_low_level)
2582 p[i] = '-';
2583 else if (first_level == 1)
2584 p[i] = '|';
2585 else if (first_level + i <= 9)
2586 p[i] = '0' + first_level + i;
2587 else
2588 p[i] = '>';
2589 if (first_level + i == level)
2590 break;
2591 }
2592 }
2593 if (closed)
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +00002594 p[i >= wp->w_p_fdc ? i - 1 : i] = '+';
Bram Moolenaar071d4272004-06-13 20:20:40 +00002595}
2596#endif /* FEAT_FOLDING */
2597
2598/*
2599 * Display line "lnum" of window 'wp' on the screen.
2600 * Start at row "startrow", stop when "endrow" is reached.
2601 * wp->w_virtcol needs to be valid.
2602 *
2603 * Return the number of last row the line occupies.
2604 */
2605 static int
Bram Moolenaar4770d092006-01-12 23:22:24 +00002606win_line(wp, lnum, startrow, endrow, nochange)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 win_T *wp;
2608 linenr_T lnum;
2609 int startrow;
2610 int endrow;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002611 int nochange UNUSED; /* not updating for changed text */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612{
2613 int col; /* visual column on screen */
2614 unsigned off; /* offset in ScreenLines/ScreenAttrs */
2615 int c = 0; /* init for GCC */
2616 long vcol = 0; /* virtual column (for tabs) */
2617 long vcol_prev = -1; /* "vcol" of previous character */
2618 char_u *line; /* current line */
2619 char_u *ptr; /* current position in "line" */
2620 int row; /* row in the window, excl w_winrow */
2621 int screen_row; /* row on the screen, incl w_winrow */
2622
2623 char_u extra[18]; /* "%ld" and 'fdc' must fit in here */
2624 int n_extra = 0; /* number of extra chars */
Bram Moolenaara064ac82007-08-05 18:10:54 +00002625 char_u *p_extra = NULL; /* string of extra chars, plus NUL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 int c_extra = NUL; /* extra chars, all the same */
2627 int extra_attr = 0; /* attributes when n_extra != 0 */
2628 static char_u *at_end_str = (char_u *)""; /* used for p_extra when
2629 displaying lcs_eol at end-of-line */
2630 int lcs_eol_one = lcs_eol; /* lcs_eol until it's been used */
2631 int lcs_prec_todo = lcs_prec; /* lcs_prec until it's been used */
2632
2633 /* saved "extra" items for when draw_state becomes WL_LINE (again) */
2634 int saved_n_extra = 0;
2635 char_u *saved_p_extra = NULL;
2636 int saved_c_extra = 0;
2637 int saved_char_attr = 0;
2638
2639 int n_attr = 0; /* chars with special attr */
2640 int saved_attr2 = 0; /* char_attr saved for n_attr */
2641 int n_attr3 = 0; /* chars with overruling special attr */
2642 int saved_attr3 = 0; /* char_attr saved for n_attr3 */
2643
2644 int n_skip = 0; /* nr of chars to skip for 'nowrap' */
2645
2646 int fromcol, tocol; /* start/end of inverting */
2647 int fromcol_prev = -2; /* start of inverting after cursor */
2648 int noinvcur = FALSE; /* don't invert the cursor */
2649#ifdef FEAT_VISUAL
2650 pos_T *top, *bot;
Bram Moolenaar54ef7112009-02-21 20:11:41 +00002651 int lnum_in_visual_area = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652#endif
2653 pos_T pos;
2654 long v;
2655
2656 int char_attr = 0; /* attributes for next character */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002657 int attr_pri = FALSE; /* char_attr has priority */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 int area_highlighting = FALSE; /* Visual or incsearch highlighting
2659 in this line */
2660 int attr = 0; /* attributes for area highlighting */
2661 int area_attr = 0; /* attributes desired by highlighting */
2662 int search_attr = 0; /* attributes desired by 'hlsearch' */
2663#ifdef FEAT_SYN_HL
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002664 int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 int syntax_attr = 0; /* attributes desired by syntax */
2666 int has_syntax = FALSE; /* this buffer has syntax highl. */
2667 int save_did_emsg;
Bram Moolenaara443af82007-11-08 13:51:42 +00002668 int eol_hl_off = 0; /* 1 if highlighted char after EOL */
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002669#endif
2670#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00002671 int has_spell = FALSE; /* this buffer has spell checking */
Bram Moolenaar30abd282005-06-22 22:35:10 +00002672# define SPWORDLEN 150
2673 char_u nextline[SPWORDLEN * 2];/* text with start of the next line */
Bram Moolenaar3b506942005-06-23 22:36:45 +00002674 int nextlinecol = 0; /* column where nextline[] starts */
2675 int nextline_idx = 0; /* index in nextline[] where next line
Bram Moolenaar30abd282005-06-22 22:35:10 +00002676 starts */
Bram Moolenaar217ad922005-03-20 22:37:15 +00002677 int spell_attr = 0; /* attributes desired by spelling */
2678 int word_end = 0; /* last byte with same spell_attr */
Bram Moolenaard042c562005-06-30 22:04:15 +00002679 static linenr_T checked_lnum = 0; /* line number for "checked_col" */
2680 static int checked_col = 0; /* column in "checked_lnum" up to which
Bram Moolenaar30abd282005-06-22 22:35:10 +00002681 * there are no spell errors */
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00002682 static int cap_col = -1; /* column to check for Cap word */
2683 static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */
Bram Moolenaar30abd282005-06-22 22:35:10 +00002684 int cur_checked_col = 0; /* checked column for current line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685#endif
2686 int extra_check; /* has syntax or linebreak */
2687#ifdef FEAT_MBYTE
2688 int multi_attr = 0; /* attributes desired by multibyte */
2689 int mb_l = 1; /* multi-byte byte length */
2690 int mb_c = 0; /* decoded multi-byte character */
2691 int mb_utf8 = FALSE; /* screen char is UTF-8 char */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002692 int u8cc[MAX_MCO]; /* composing UTF-8 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693#endif
2694#ifdef FEAT_DIFF
2695 int filler_lines; /* nr of filler lines to be drawn */
2696 int filler_todo; /* nr of filler lines still to do + 1 */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002697 hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 int change_start = MAXCOL; /* first col of changed area */
2699 int change_end = -1; /* last col of changed area */
2700#endif
2701 colnr_T trailcol = MAXCOL; /* start of trailing spaces */
2702#ifdef FEAT_LINEBREAK
2703 int need_showbreak = FALSE;
2704#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00002705#if defined(FEAT_SIGNS) || (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
2706 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707# define LINE_ATTR
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00002708 int line_attr = 0; /* attribute for the whole line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709#endif
2710#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00002711 matchitem_T *cur; /* points to the match list */
2712 match_T *shl; /* points to search_hl or a match */
2713 int shl_flag; /* flag to indicate whether search_hl
2714 has been processed or not */
2715 int prevcol_hl_flag; /* flag to indicate whether prevcol
2716 equals startcol of search_hl or one
2717 of the matches */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718#endif
2719#ifdef FEAT_ARABIC
2720 int prev_c = 0; /* previous Arabic character */
2721 int prev_c1 = 0; /* first composing char for prev_c */
2722#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00002723#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00002724 int did_line_attr = 0;
2725#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726
2727 /* draw_state: items that are drawn in sequence: */
2728#define WL_START 0 /* nothing done yet */
2729#ifdef FEAT_CMDWIN
2730# define WL_CMDLINE WL_START + 1 /* cmdline window column */
2731#else
2732# define WL_CMDLINE WL_START
2733#endif
2734#ifdef FEAT_FOLDING
2735# define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
2736#else
2737# define WL_FOLD WL_CMDLINE
2738#endif
2739#ifdef FEAT_SIGNS
2740# define WL_SIGN WL_FOLD + 1 /* column for signs */
2741#else
2742# define WL_SIGN WL_FOLD /* column for signs */
2743#endif
2744#define WL_NR WL_SIGN + 1 /* line number */
2745#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
2746# define WL_SBR WL_NR + 1 /* 'showbreak' or 'diff' */
2747#else
2748# define WL_SBR WL_NR
2749#endif
2750#define WL_LINE WL_SBR + 1 /* text in the line */
2751 int draw_state = WL_START; /* what to draw next */
Bram Moolenaar9372a112005-12-06 19:59:18 +00002752#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753 int feedback_col = 0;
2754 int feedback_old_attr = -1;
2755#endif
2756
Bram Moolenaar860cae12010-06-05 23:22:07 +02002757#ifdef FEAT_CONCEAL
2758 int syntax_flags = 0;
2759 int conceal_attr = hl_attr(HLF_CONCEAL);
2760 int first_conceal = (wp->w_p_conceal != 3);
2761 int is_concealing = FALSE;
2762 int boguscols = 0; /* nonexistent columns added to force
2763 wrapping */
2764#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002765
2766 if (startrow > endrow) /* past the end already! */
2767 return startrow;
2768
2769 row = startrow;
2770 screen_row = row + W_WINROW(wp);
2771
2772 /*
2773 * To speed up the loop below, set extra_check when there is linebreak,
2774 * trailing white space and/or syntax processing to be done.
2775 */
2776#ifdef FEAT_LINEBREAK
2777 extra_check = wp->w_p_lbr;
2778#else
2779 extra_check = 0;
2780#endif
2781#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02002782 if (syntax_present(wp) && !wp->w_s->b_syn_error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783 {
2784 /* Prepare for syntax highlighting in this line. When there is an
2785 * error, stop syntax highlighting. */
2786 save_did_emsg = did_emsg;
2787 did_emsg = FALSE;
2788 syntax_start(wp, lnum);
2789 if (did_emsg)
Bram Moolenaar860cae12010-06-05 23:22:07 +02002790 wp->w_s->b_syn_error = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791 else
2792 {
2793 did_emsg = save_did_emsg;
2794 has_syntax = TRUE;
2795 extra_check = TRUE;
2796 }
2797 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002798#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00002799
Bram Moolenaar600dddc2006-03-12 22:05:10 +00002800#ifdef FEAT_SPELL
Bram Moolenaar0cb032e2005-04-23 20:52:00 +00002801 if (wp->w_p_spell
Bram Moolenaar860cae12010-06-05 23:22:07 +02002802 && *wp->w_s->b_p_spl != NUL
2803 && wp->w_s->b_langp.ga_len > 0
2804 && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
Bram Moolenaar217ad922005-03-20 22:37:15 +00002805 {
2806 /* Prepare for spell checking. */
2807 has_spell = TRUE;
2808 extra_check = TRUE;
Bram Moolenaar30abd282005-06-22 22:35:10 +00002809
2810 /* Get the start of the next line, so that words that wrap to the next
2811 * line are found too: "et<line-break>al.".
2812 * Trick: skip a few chars for C/shell/Vim comments */
2813 nextline[SPWORDLEN] = NUL;
2814 if (lnum < wp->w_buffer->b_ml.ml_line_count)
2815 {
2816 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
2817 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
2818 }
2819
2820 /* When a word wrapped from the previous line the start of the current
2821 * line is valid. */
2822 if (lnum == checked_lnum)
2823 cur_checked_col = checked_col;
2824 checked_lnum = 0;
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00002825
2826 /* When there was a sentence end in the previous line may require a
2827 * word starting with capital in this line. In line 1 always check
2828 * the first word. */
2829 if (lnum != capcol_lnum)
2830 cap_col = -1;
2831 if (lnum == 1)
2832 cap_col = 0;
2833 capcol_lnum = 0;
Bram Moolenaar217ad922005-03-20 22:37:15 +00002834 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835#endif
2836
2837 /*
2838 * handle visual active in this window
2839 */
2840 fromcol = -10;
2841 tocol = MAXCOL;
2842#ifdef FEAT_VISUAL
2843 if (VIsual_active && wp->w_buffer == curwin->w_buffer)
2844 {
2845 /* Visual is after curwin->w_cursor */
2846 if (ltoreq(curwin->w_cursor, VIsual))
2847 {
2848 top = &curwin->w_cursor;
2849 bot = &VIsual;
2850 }
2851 else /* Visual is before curwin->w_cursor */
2852 {
2853 top = &VIsual;
2854 bot = &curwin->w_cursor;
2855 }
Bram Moolenaar54ef7112009-02-21 20:11:41 +00002856 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857 if (VIsual_mode == Ctrl_V) /* block mode */
2858 {
Bram Moolenaar54ef7112009-02-21 20:11:41 +00002859 if (lnum_in_visual_area)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860 {
2861 fromcol = wp->w_old_cursor_fcol;
2862 tocol = wp->w_old_cursor_lcol;
2863 }
2864 }
2865 else /* non-block mode */
2866 {
2867 if (lnum > top->lnum && lnum <= bot->lnum)
2868 fromcol = 0;
2869 else if (lnum == top->lnum)
2870 {
2871 if (VIsual_mode == 'V') /* linewise */
2872 fromcol = 0;
2873 else
2874 {
2875 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
2876 if (gchar_pos(top) == NUL)
2877 tocol = fromcol + 1;
2878 }
2879 }
2880 if (VIsual_mode != 'V' && lnum == bot->lnum)
2881 {
2882 if (*p_sel == 'e' && bot->col == 0
2883#ifdef FEAT_VIRTUALEDIT
2884 && bot->coladd == 0
2885#endif
2886 )
2887 {
2888 fromcol = -10;
2889 tocol = MAXCOL;
2890 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00002891 else if (bot->col == MAXCOL)
2892 tocol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 else
2894 {
2895 pos = *bot;
2896 if (*p_sel == 'e')
2897 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
2898 else
2899 {
2900 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
2901 ++tocol;
2902 }
2903 }
2904 }
2905 }
2906
2907#ifndef MSDOS
2908 /* Check if the character under the cursor should not be inverted */
2909 if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
2910# ifdef FEAT_GUI
2911 && !gui.in_use
2912# endif
2913 )
2914 noinvcur = TRUE;
2915#endif
2916
2917 /* if inverting in this line set area_highlighting */
2918 if (fromcol >= 0)
2919 {
2920 area_highlighting = TRUE;
2921 attr = hl_attr(HLF_V);
2922#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2923 if (clip_star.available && !clip_star.owned && clip_isautosel())
2924 attr = hl_attr(HLF_VNC);
2925#endif
2926 }
2927 }
2928
2929 /*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002930 * handle 'incsearch' and ":s///c" highlighting
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 */
2932 else
2933#endif /* FEAT_VISUAL */
2934 if (highlight_match
2935 && wp == curwin
2936 && lnum >= curwin->w_cursor.lnum
2937 && lnum <= curwin->w_cursor.lnum + search_match_lines)
2938 {
2939 if (lnum == curwin->w_cursor.lnum)
2940 getvcol(curwin, &(curwin->w_cursor),
2941 (colnr_T *)&fromcol, NULL, NULL);
2942 else
2943 fromcol = 0;
2944 if (lnum == curwin->w_cursor.lnum + search_match_lines)
2945 {
2946 pos.lnum = lnum;
2947 pos.col = search_match_endcol;
2948 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
2949 }
2950 else
2951 tocol = MAXCOL;
Bram Moolenaarf3205d12009-03-18 18:09:03 +00002952 /* do at least one character; happens when past end of line */
2953 if (fromcol == tocol)
2954 tocol = fromcol + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955 area_highlighting = TRUE;
2956 attr = hl_attr(HLF_I);
2957 }
2958
2959#ifdef FEAT_DIFF
2960 filler_lines = diff_check(wp, lnum);
2961 if (filler_lines < 0)
2962 {
2963 if (filler_lines == -1)
2964 {
2965 if (diff_find_change(wp, lnum, &change_start, &change_end))
2966 diff_hlf = HLF_ADD; /* added line */
2967 else if (change_start == 0)
2968 diff_hlf = HLF_TXD; /* changed text */
2969 else
2970 diff_hlf = HLF_CHD; /* changed line */
2971 }
2972 else
2973 diff_hlf = HLF_ADD; /* added line */
2974 filler_lines = 0;
2975 area_highlighting = TRUE;
2976 }
2977 if (lnum == wp->w_topline)
2978 filler_lines = wp->w_topfill;
2979 filler_todo = filler_lines;
2980#endif
2981
2982#ifdef LINE_ATTR
2983# ifdef FEAT_SIGNS
2984 /* If this line has a sign with line highlighting set line_attr. */
2985 v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
2986 if (v != 0)
2987 line_attr = sign_get_attr((int)v, TRUE);
2988# endif
2989# if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
2990 /* Highlight the current line in the quickfix window. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00002991 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002992 line_attr = hl_attr(HLF_L);
2993# endif
2994 if (line_attr != 0)
2995 area_highlighting = TRUE;
2996#endif
2997
2998 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
2999 ptr = line;
3000
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003001#ifdef FEAT_SPELL
Bram Moolenaar30abd282005-06-22 22:35:10 +00003002 if (has_spell)
3003 {
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003004 /* For checking first word with a capital skip white space. */
3005 if (cap_col == 0)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003006 cap_col = (int)(skipwhite(line) - line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00003007
Bram Moolenaar30abd282005-06-22 22:35:10 +00003008 /* To be able to spell-check over line boundaries copy the end of the
3009 * current line into nextline[]. Above the start of the next line was
3010 * copied to nextline[SPWORDLEN]. */
3011 if (nextline[SPWORDLEN] == NUL)
3012 {
3013 /* No next line or it is empty. */
3014 nextlinecol = MAXCOL;
3015 nextline_idx = 0;
3016 }
3017 else
3018 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003019 v = (long)STRLEN(line);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003020 if (v < SPWORDLEN)
3021 {
3022 /* Short line, use it completely and append the start of the
3023 * next line. */
3024 nextlinecol = 0;
3025 mch_memmove(nextline, line, (size_t)v);
Bram Moolenaar446cb832008-06-24 21:56:24 +00003026 STRMOVE(nextline + v, nextline + SPWORDLEN);
Bram Moolenaar30abd282005-06-22 22:35:10 +00003027 nextline_idx = v + 1;
3028 }
3029 else
3030 {
3031 /* Long line, use only the last SPWORDLEN bytes. */
3032 nextlinecol = v - SPWORDLEN;
3033 mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
3034 nextline_idx = SPWORDLEN + 1;
3035 }
3036 }
3037 }
3038#endif
3039
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 /* find start of trailing whitespace */
3041 if (wp->w_p_list && lcs_trail)
3042 {
3043 trailcol = (colnr_T)STRLEN(ptr);
3044 while (trailcol > (colnr_T)0 && vim_iswhite(ptr[trailcol - 1]))
3045 --trailcol;
3046 trailcol += (colnr_T) (ptr - line);
3047 extra_check = TRUE;
3048 }
3049
3050 /*
3051 * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
3052 * first character to be displayed.
3053 */
3054 if (wp->w_p_wrap)
3055 v = wp->w_skipcol;
3056 else
3057 v = wp->w_leftcol;
3058 if (v > 0)
3059 {
3060#ifdef FEAT_MBYTE
3061 char_u *prev_ptr = ptr;
3062#endif
3063 while (vcol < v && *ptr != NUL)
3064 {
3065 c = win_lbr_chartabsize(wp, ptr, (colnr_T)vcol, NULL);
3066 vcol += c;
3067#ifdef FEAT_MBYTE
3068 prev_ptr = ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003070 mb_ptr_adv(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 }
3072
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003073#if defined(FEAT_SYN_HL) || defined(FEAT_VIRTUALEDIT) || defined(FEAT_VISUAL)
3074 /* When:
3075 * - 'cuc' is set, or
3076 * - 'virtualedit' is set, or
3077 * - the visual mode is active,
3078 * the end of the line may be before the start of the displayed part.
3079 */
3080 if (vcol < v && (
3081# ifdef FEAT_SYN_HL
3082 wp->w_p_cuc
3083# if defined(FEAT_VIRTUALEDIT) || defined(FEAT_VISUAL)
3084 ||
3085# endif
3086# endif
3087# ifdef FEAT_VIRTUALEDIT
3088 virtual_active()
3089# ifdef FEAT_VISUAL
3090 ||
3091# endif
3092# endif
3093# ifdef FEAT_VISUAL
3094 (VIsual_active && wp->w_buffer == curwin->w_buffer)
3095# endif
3096 ))
3097 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098 vcol = v;
Bram Moolenaarbb6a7052009-11-03 16:36:44 +00003099 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100#endif
3101
3102 /* Handle a character that's not completely on the screen: Put ptr at
3103 * that character but skip the first few screen characters. */
3104 if (vcol > v)
3105 {
3106 vcol -= c;
3107#ifdef FEAT_MBYTE
3108 ptr = prev_ptr;
3109#else
3110 --ptr;
3111#endif
3112 n_skip = v - vcol;
3113 }
3114
3115 /*
3116 * Adjust for when the inverted text is before the screen,
3117 * and when the start of the inverted text is before the screen.
3118 */
3119 if (tocol <= vcol)
3120 fromcol = 0;
3121 else if (fromcol >= 0 && fromcol < vcol)
3122 fromcol = vcol;
3123
3124#ifdef FEAT_LINEBREAK
3125 /* When w_skipcol is non-zero, first line needs 'showbreak' */
3126 if (wp->w_p_wrap)
3127 need_showbreak = TRUE;
3128#endif
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003129#ifdef FEAT_SPELL
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003130 /* When spell checking a word we need to figure out the start of the
3131 * word and if it's badly spelled or not. */
3132 if (has_spell)
3133 {
3134 int len;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003135 colnr_T linecol = (colnr_T)(ptr - line);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003136 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003137
3138 pos = wp->w_cursor;
3139 wp->w_cursor.lnum = lnum;
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003140 wp->w_cursor.col = linecol;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003141 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003142
3143 /* spell_move_to() may call ml_get() and make "line" invalid */
3144 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3145 ptr = line + linecol;
3146
Bram Moolenaar60a795a2005-09-16 21:55:43 +00003147 if (len == 0 || (int)wp->w_cursor.col > ptr - line)
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003148 {
3149 /* no bad word found at line start, don't check until end of a
3150 * word */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003151 spell_hlf = HLF_COUNT;
Bram Moolenaar860cae12010-06-05 23:22:07 +02003152 word_end = (int)(spell_to_word_end(ptr, wp)
Bram Moolenaar4ef9e492008-02-13 20:49:04 +00003153 - line + 1);
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003154 }
3155 else
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003156 {
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003157 /* bad word found, use attributes until end of word */
3158 word_end = wp->w_cursor.col + len + 1;
3159
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003160 /* Turn index into actual attributes. */
3161 if (spell_hlf != HLF_COUNT)
3162 spell_attr = highlight_attr[spell_hlf];
3163 }
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003164 wp->w_cursor = pos;
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003165
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003166# ifdef FEAT_SYN_HL
Bram Moolenaarda2303d2005-08-30 21:55:26 +00003167 /* Need to restart syntax highlighting for this line. */
3168 if (has_syntax)
3169 syntax_start(wp, lnum);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003170# endif
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00003171 }
3172#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003173 }
3174
3175 /*
3176 * Correct highlighting for cursor that can't be disabled.
3177 * Avoids having to check this for each character.
3178 */
3179 if (fromcol >= 0)
3180 {
3181 if (noinvcur)
3182 {
3183 if ((colnr_T)fromcol == wp->w_virtcol)
3184 {
3185 /* highlighting starts at cursor, let it start just after the
3186 * cursor */
3187 fromcol_prev = fromcol;
3188 fromcol = -1;
3189 }
3190 else if ((colnr_T)fromcol < wp->w_virtcol)
3191 /* restart highlighting after the cursor */
3192 fromcol_prev = wp->w_virtcol;
3193 }
3194 if (fromcol >= tocol)
3195 fromcol = -1;
3196 }
3197
3198#ifdef FEAT_SEARCH_EXTRA
3199 /*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003200 * Handle highlighting the last used search pattern and matches.
3201 * Do this for both search_hl and the match list.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202 */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003203 cur = wp->w_match_head;
3204 shl_flag = FALSE;
3205 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003207 if (shl_flag == FALSE)
3208 {
3209 shl = &search_hl;
3210 shl_flag = TRUE;
3211 }
3212 else
3213 shl = &cur->hl;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003214 shl->startcol = MAXCOL;
3215 shl->endcol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 shl->attr_cur = 0;
3217 if (shl->rm.regprog != NULL)
3218 {
3219 v = (long)(ptr - line);
3220 next_search_hl(wp, shl, lnum, (colnr_T)v);
3221
3222 /* Need to get the line again, a multi-line regexp may have made it
3223 * invalid. */
3224 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3225 ptr = line + v;
3226
3227 if (shl->lnum != 0 && shl->lnum <= lnum)
3228 {
3229 if (shl->lnum == lnum)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003230 shl->startcol = shl->rm.startpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 else
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003232 shl->startcol = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233 if (lnum == shl->lnum + shl->rm.endpos[0].lnum
3234 - shl->rm.startpos[0].lnum)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003235 shl->endcol = shl->rm.endpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236 else
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003237 shl->endcol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238 /* Highlight one character for an empty match. */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003239 if (shl->startcol == shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240 {
3241#ifdef FEAT_MBYTE
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003242 if (has_mbyte && line[shl->endcol] != NUL)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003243 shl->endcol += (*mb_ptr2len)(line + shl->endcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244 else
3245#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003246 ++shl->endcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003248 if ((long)shl->startcol < v) /* match at leftcol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249 {
3250 shl->attr_cur = shl->attr;
3251 search_attr = shl->attr;
3252 }
3253 area_highlighting = TRUE;
3254 }
3255 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003256 if (shl != &search_hl && cur != NULL)
3257 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 }
3259#endif
3260
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003261#ifdef FEAT_SYN_HL
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003262 /* Cursor line highlighting for 'cursorline'. Not when Visual mode is
3263 * active, because it's not clear what is selected then. */
3264 if (wp->w_p_cul && lnum == wp->w_cursor.lnum && !VIsual_active)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003265 {
3266 line_attr = hl_attr(HLF_CUL);
3267 area_highlighting = TRUE;
3268 }
3269#endif
3270
Bram Moolenaar92d640f2005-09-05 22:11:52 +00003271 off = (unsigned)(current_ScreenLine - ScreenLines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 col = 0;
3273#ifdef FEAT_RIGHTLEFT
3274 if (wp->w_p_rl)
3275 {
3276 /* Rightleft window: process the text in the normal direction, but put
3277 * it in current_ScreenLine[] from right to left. Start at the
3278 * rightmost column of the window. */
3279 col = W_WIDTH(wp) - 1;
3280 off += col;
3281 }
3282#endif
3283
3284 /*
3285 * Repeat for the whole displayed line.
3286 */
3287 for (;;)
3288 {
3289 /* Skip this quickly when working on the text. */
3290 if (draw_state != WL_LINE)
3291 {
3292#ifdef FEAT_CMDWIN
3293 if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
3294 {
3295 draw_state = WL_CMDLINE;
3296 if (cmdwin_type != 0 && wp == curwin)
3297 {
3298 /* Draw the cmdline character. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 n_extra = 1;
Bram Moolenaara064ac82007-08-05 18:10:54 +00003300 c_extra = cmdwin_type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 char_attr = hl_attr(HLF_AT);
3302 }
3303 }
3304#endif
3305
3306#ifdef FEAT_FOLDING
3307 if (draw_state == WL_FOLD - 1 && n_extra == 0)
3308 {
3309 draw_state = WL_FOLD;
3310 if (wp->w_p_fdc > 0)
3311 {
3312 /* Draw the 'foldcolumn'. */
3313 fill_foldcolumn(extra, wp, FALSE, lnum);
3314 n_extra = wp->w_p_fdc;
3315 p_extra = extra;
Bram Moolenaara064ac82007-08-05 18:10:54 +00003316 p_extra[n_extra] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 c_extra = NUL;
3318 char_attr = hl_attr(HLF_FC);
3319 }
3320 }
3321#endif
3322
3323#ifdef FEAT_SIGNS
3324 if (draw_state == WL_SIGN - 1 && n_extra == 0)
3325 {
3326 draw_state = WL_SIGN;
3327 /* Show the sign column when there are any signs in this
3328 * buffer or when using Netbeans. */
3329 if (draw_signcolumn(wp)
3330# ifdef FEAT_DIFF
3331 && filler_todo <= 0
3332# endif
3333 )
3334 {
3335 int_u text_sign;
3336# ifdef FEAT_SIGN_ICONS
3337 int_u icon_sign;
3338# endif
3339
3340 /* Draw two cells with the sign value or blank. */
3341 c_extra = ' ';
3342 char_attr = hl_attr(HLF_SC);
3343 n_extra = 2;
3344
3345 if (row == startrow)
3346 {
3347 text_sign = buf_getsigntype(wp->w_buffer, lnum,
3348 SIGN_TEXT);
3349# ifdef FEAT_SIGN_ICONS
3350 icon_sign = buf_getsigntype(wp->w_buffer, lnum,
3351 SIGN_ICON);
3352 if (gui.in_use && icon_sign != 0)
3353 {
3354 /* Use the image in this position. */
3355 c_extra = SIGN_BYTE;
3356# ifdef FEAT_NETBEANS_INTG
3357 if (buf_signcount(wp->w_buffer, lnum) > 1)
3358 c_extra = MULTISIGN_BYTE;
3359# endif
3360 char_attr = icon_sign;
3361 }
3362 else
3363# endif
3364 if (text_sign != 0)
3365 {
3366 p_extra = sign_get_text(text_sign);
3367 if (p_extra != NULL)
3368 {
3369 c_extra = NUL;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003370 n_extra = (int)STRLEN(p_extra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 }
3372 char_attr = sign_get_attr(text_sign, FALSE);
3373 }
3374 }
3375 }
3376 }
3377#endif
3378
3379 if (draw_state == WL_NR - 1 && n_extra == 0)
3380 {
3381 draw_state = WL_NR;
Bram Moolenaar64486672010-05-16 15:46:46 +02003382 /* Display the absolute or relative line number. After the
3383 * first fill with blanks when the 'n' flag isn't in 'cpo' */
3384 if ((wp->w_p_nu || wp->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385 && (row == startrow
3386#ifdef FEAT_DIFF
3387 + filler_lines
3388#endif
3389 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
3390 {
3391 /* Draw the line number (empty space after wrapping). */
3392 if (row == startrow
3393#ifdef FEAT_DIFF
3394 + filler_lines
3395#endif
3396 )
3397 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003398 long num;
3399
3400 if (wp->w_p_nu)
3401 /* 'number' */
3402 num = (long)lnum;
3403 else
3404 /* 'relativenumber', don't use negative numbers */
3405 num = (long)abs((int)get_cursor_rel_lnum(wp,
3406 lnum));
3407
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003408 sprintf((char *)extra, "%*ld ",
Bram Moolenaar64486672010-05-16 15:46:46 +02003409 number_width(wp), num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003410 if (wp->w_skipcol > 0)
3411 for (p_extra = extra; *p_extra == ' '; ++p_extra)
3412 *p_extra = '-';
3413#ifdef FEAT_RIGHTLEFT
3414 if (wp->w_p_rl) /* reverse line numbers */
3415 rl_mirror(extra);
3416#endif
3417 p_extra = extra;
3418 c_extra = NUL;
3419 }
3420 else
3421 c_extra = ' ';
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003422 n_extra = number_width(wp) + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003423 char_attr = hl_attr(HLF_N);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003424#ifdef FEAT_SYN_HL
3425 /* When 'cursorline' is set highlight the line number of
3426 * the current line differently. */
3427 if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
3428 char_attr = hl_combine_attr(hl_attr(HLF_CUL), char_attr);
3429#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003430 }
3431 }
3432
3433#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3434 if (draw_state == WL_SBR - 1 && n_extra == 0)
3435 {
3436 draw_state = WL_SBR;
3437# ifdef FEAT_DIFF
3438 if (filler_todo > 0)
3439 {
3440 /* Draw "deleted" diff line(s). */
3441 if (char2cells(fill_diff) > 1)
3442 c_extra = '-';
3443 else
3444 c_extra = fill_diff;
3445# ifdef FEAT_RIGHTLEFT
3446 if (wp->w_p_rl)
3447 n_extra = col + 1;
3448 else
3449# endif
3450 n_extra = W_WIDTH(wp) - col;
3451 char_attr = hl_attr(HLF_DED);
3452 }
3453# endif
3454# ifdef FEAT_LINEBREAK
3455 if (*p_sbr != NUL && need_showbreak)
3456 {
3457 /* Draw 'showbreak' at the start of each broken line. */
3458 p_extra = p_sbr;
3459 c_extra = NUL;
3460 n_extra = (int)STRLEN(p_sbr);
3461 char_attr = hl_attr(HLF_AT);
3462 need_showbreak = FALSE;
3463 /* Correct end of highlighted area for 'showbreak',
3464 * required when 'linebreak' is also set. */
3465 if (tocol == vcol)
3466 tocol += n_extra;
3467 }
3468# endif
3469 }
3470#endif
3471
3472 if (draw_state == WL_LINE - 1 && n_extra == 0)
3473 {
3474 draw_state = WL_LINE;
3475 if (saved_n_extra)
3476 {
3477 /* Continue item from end of wrapped line. */
3478 n_extra = saved_n_extra;
3479 c_extra = saved_c_extra;
3480 p_extra = saved_p_extra;
3481 char_attr = saved_char_attr;
3482 }
3483 else
3484 char_attr = 0;
3485 }
3486 }
3487
3488 /* When still displaying '$' of change command, stop at cursor */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003489 if (dollar_vcol != 0 && wp == curwin
3490 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491#ifdef FEAT_DIFF
3492 && filler_todo <= 0
3493#endif
3494 )
3495 {
3496 SCREEN_LINE(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp),
3497 wp->w_p_rl);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003498 /* Pretend we have finished updating the window. Except when
3499 * 'cursorcolumn' is set. */
3500#ifdef FEAT_SYN_HL
3501 if (wp->w_p_cuc)
3502 row = wp->w_cline_row + wp->w_cline_height;
3503 else
3504#endif
3505 row = wp->w_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506 break;
3507 }
3508
3509 if (draw_state == WL_LINE && area_highlighting)
3510 {
3511 /* handle Visual or match highlighting in this line */
3512 if (vcol == fromcol
3513#ifdef FEAT_MBYTE
3514 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
3515 && (*mb_ptr2cells)(ptr) > 1)
3516#endif
3517 || ((int)vcol_prev == fromcol_prev
Bram Moolenaarfa363cd2009-02-21 20:23:59 +00003518 && vcol_prev < vcol /* not at margin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 && vcol < tocol))
3520 area_attr = attr; /* start highlighting */
3521 else if (area_attr != 0
3522 && (vcol == tocol
3523 || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 area_attr = 0; /* stop highlighting */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525
3526#ifdef FEAT_SEARCH_EXTRA
3527 if (!n_extra)
3528 {
3529 /*
3530 * Check for start/end of search pattern match.
3531 * After end, check for start/end of next match.
3532 * When another match, have to check for start again.
3533 * Watch out for matching an empty string!
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003534 * Do this for 'search_hl' and the match list (ordered by
3535 * priority).
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536 */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003537 v = (long)(ptr - line);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003538 cur = wp->w_match_head;
3539 shl_flag = FALSE;
3540 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003542 if (shl_flag == FALSE
3543 && ((cur != NULL
3544 && cur->priority > SEARCH_HL_PRIORITY)
3545 || cur == NULL))
3546 {
3547 shl = &search_hl;
3548 shl_flag = TRUE;
3549 }
3550 else
3551 shl = &cur->hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 while (shl->rm.regprog != NULL)
3553 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003554 if (shl->startcol != MAXCOL
3555 && v >= (long)shl->startcol
3556 && v < (long)shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557 {
3558 shl->attr_cur = shl->attr;
3559 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003560 else if (v == (long)shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561 {
3562 shl->attr_cur = 0;
3563
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564 next_search_hl(wp, shl, lnum, (colnr_T)v);
3565
3566 /* Need to get the line again, a multi-line regexp
3567 * may have made it invalid. */
3568 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3569 ptr = line + v;
3570
3571 if (shl->lnum == lnum)
3572 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003573 shl->startcol = shl->rm.startpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003574 if (shl->rm.endpos[0].lnum == 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003575 shl->endcol = shl->rm.endpos[0].col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576 else
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003577 shl->endcol = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003579 if (shl->startcol == shl->endcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003580 {
3581 /* highlight empty match, try again after
3582 * it */
3583#ifdef FEAT_MBYTE
3584 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003585 shl->endcol += (*mb_ptr2len)(line
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003586 + shl->endcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587 else
3588#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003589 ++shl->endcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 }
3591
3592 /* Loop to check if the match starts at the
3593 * current position */
3594 continue;
3595 }
3596 }
3597 break;
3598 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003599 if (shl != &search_hl && cur != NULL)
3600 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00003602
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003603 /* Use attributes from match with highest priority among
3604 * 'search_hl' and the match list. */
3605 search_attr = search_hl.attr_cur;
3606 cur = wp->w_match_head;
3607 shl_flag = FALSE;
3608 while (cur != NULL || shl_flag == FALSE)
3609 {
3610 if (shl_flag == FALSE
3611 && ((cur != NULL
3612 && cur->priority > SEARCH_HL_PRIORITY)
3613 || cur == NULL))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00003614 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003615 shl = &search_hl;
3616 shl_flag = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00003617 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003618 else
3619 shl = &cur->hl;
3620 if (shl->attr_cur != 0)
3621 search_attr = shl->attr_cur;
3622 if (shl != &search_hl && cur != NULL)
3623 cur = cur->next;
3624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003625 }
3626#endif
3627
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628#ifdef FEAT_DIFF
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003629 if (diff_hlf != (hlf_T)0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630 {
Bram Moolenaar4b80a512007-06-19 15:44:58 +00003631 if (diff_hlf == HLF_CHD && ptr - line >= change_start
3632 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633 diff_hlf = HLF_TXD; /* changed text */
Bram Moolenaar4b80a512007-06-19 15:44:58 +00003634 if (diff_hlf == HLF_TXD && ptr - line > change_end
3635 && n_extra == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636 diff_hlf = HLF_CHD; /* changed line */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003637 line_attr = hl_attr(diff_hlf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638 }
3639#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003640
3641 /* Decide which of the highlight attributes to use. */
3642 attr_pri = TRUE;
3643 if (area_attr != 0)
3644 char_attr = area_attr;
3645 else if (search_attr != 0)
3646 char_attr = search_attr;
3647#ifdef LINE_ATTR
3648 /* Use line_attr when not in the Visual or 'incsearch' area
3649 * (area_attr may be 0 when "noinvcur" is set). */
3650 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
Bram Moolenaarf837ef92009-03-11 16:47:21 +00003651 || vcol < fromcol || vcol_prev < fromcol_prev
3652 || vcol >= tocol))
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003653 char_attr = line_attr;
3654#endif
3655 else
3656 {
3657 attr_pri = FALSE;
3658#ifdef FEAT_SYN_HL
3659 if (has_syntax)
3660 char_attr = syntax_attr;
3661 else
3662#endif
3663 char_attr = 0;
3664 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 }
3666
3667 /*
3668 * Get the next character to put on the screen.
3669 */
3670 /*
Bram Moolenaara064ac82007-08-05 18:10:54 +00003671 * The "p_extra" points to the extra stuff that is inserted to
3672 * represent special characters (non-printable stuff) and other
3673 * things. When all characters are the same, c_extra is used.
3674 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
3675 * "p_extra[n_extra]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
3677 */
3678 if (n_extra > 0)
3679 {
3680 if (c_extra != NUL)
3681 {
3682 c = c_extra;
3683#ifdef FEAT_MBYTE
3684 mb_c = c; /* doesn't handle non-utf-8 multi-byte! */
3685 if (enc_utf8 && (*mb_char2len)(c) > 1)
3686 {
3687 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003688 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003689 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 }
3691 else
3692 mb_utf8 = FALSE;
3693#endif
3694 }
3695 else
3696 {
3697 c = *p_extra;
3698#ifdef FEAT_MBYTE
3699 if (has_mbyte)
3700 {
3701 mb_c = c;
3702 if (enc_utf8)
3703 {
3704 /* If the UTF-8 character is more than one byte:
3705 * Decode it into "mb_c". */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003706 mb_l = (*mb_ptr2len)(p_extra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 mb_utf8 = FALSE;
3708 if (mb_l > n_extra)
3709 mb_l = 1;
3710 else if (mb_l > 1)
3711 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003712 mb_c = utfc_ptr2char(p_extra, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003713 mb_utf8 = TRUE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003714 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003715 }
3716 }
3717 else
3718 {
3719 /* if this is a DBCS character, put it in "mb_c" */
3720 mb_l = MB_BYTE2LEN(c);
3721 if (mb_l >= n_extra)
3722 mb_l = 1;
3723 else if (mb_l > 1)
3724 mb_c = (c << 8) + p_extra[1];
3725 }
Bram Moolenaar92d640f2005-09-05 22:11:52 +00003726 if (mb_l == 0) /* at the NUL at end-of-line */
3727 mb_l = 1;
3728
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729 /* If a double-width char doesn't fit display a '>' in the
3730 * last column. */
Bram Moolenaar92d640f2005-09-05 22:11:52 +00003731 if ((
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732# ifdef FEAT_RIGHTLEFT
3733 wp->w_p_rl ? (col <= 0) :
3734# endif
Bram Moolenaar92d640f2005-09-05 22:11:52 +00003735 (col >= W_WIDTH(wp) - 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 && (*mb_char2cells)(mb_c) == 2)
3737 {
3738 c = '>';
3739 mb_c = c;
3740 mb_l = 1;
3741 mb_utf8 = FALSE;
3742 multi_attr = hl_attr(HLF_AT);
3743 /* put the pointer back to output the double-width
3744 * character at the start of the next line. */
3745 ++n_extra;
3746 --p_extra;
3747 }
3748 else
3749 {
3750 n_extra -= mb_l - 1;
3751 p_extra += mb_l - 1;
3752 }
3753 }
3754#endif
3755 ++p_extra;
3756 }
3757 --n_extra;
3758 }
3759 else
3760 {
3761 /*
3762 * Get a character from the line itself.
3763 */
3764 c = *ptr;
3765#ifdef FEAT_MBYTE
3766 if (has_mbyte)
3767 {
3768 mb_c = c;
3769 if (enc_utf8)
3770 {
3771 /* If the UTF-8 character is more than one byte: Decode it
3772 * into "mb_c". */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003773 mb_l = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774 mb_utf8 = FALSE;
3775 if (mb_l > 1)
3776 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003777 mb_c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003778 /* Overlong encoded ASCII or ASCII with composing char
3779 * is displayed normally, except a NUL. */
3780 if (mb_c < 0x80)
3781 c = mb_c;
3782 mb_utf8 = TRUE;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00003783
3784 /* At start of the line we can have a composing char.
3785 * Draw it as a space with a composing char. */
3786 if (utf_iscomposing(mb_c))
3787 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00003788 int i;
3789
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003790 for (i = Screen_mco - 1; i > 0; --i)
3791 u8cc[i] = u8cc[i - 1];
3792 u8cc[0] = mb_c;
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00003793 mb_c = ' ';
3794 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 }
3796
3797 if ((mb_l == 1 && c >= 0x80)
3798 || (mb_l >= 1 && mb_c == 0)
3799 || (mb_l > 1 && (!vim_isprintc(mb_c)
Bram Moolenaar11936362007-09-17 20:39:42 +00003800# ifdef UNICODE16
3801 || mb_c >= 0x10000
3802# endif
3803 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 {
3805 /*
3806 * Illegal UTF-8 byte: display as <xx>.
3807 * Non-BMP character : display as ? or fullwidth ?.
3808 */
Bram Moolenaar11936362007-09-17 20:39:42 +00003809# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810 if (mb_c < 0x10000)
Bram Moolenaar11936362007-09-17 20:39:42 +00003811# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 {
3813 transchar_hex(extra, mb_c);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003814# ifdef FEAT_RIGHTLEFT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 if (wp->w_p_rl) /* reverse */
3816 rl_mirror(extra);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003817# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818 }
Bram Moolenaar11936362007-09-17 20:39:42 +00003819# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 else if (utf_char2cells(mb_c) != 2)
3821 STRCPY(extra, "?");
3822 else
3823 /* 0xff1f in UTF-8: full-width '?' */
3824 STRCPY(extra, "\357\274\237");
Bram Moolenaar11936362007-09-17 20:39:42 +00003825# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826
3827 p_extra = extra;
3828 c = *p_extra;
3829 mb_c = mb_ptr2char_adv(&p_extra);
3830 mb_utf8 = (c >= 0x80);
3831 n_extra = (int)STRLEN(p_extra);
3832 c_extra = NUL;
3833 if (area_attr == 0 && search_attr == 0)
3834 {
3835 n_attr = n_extra + 1;
3836 extra_attr = hl_attr(HLF_8);
3837 saved_attr2 = char_attr; /* save current attr */
3838 }
3839 }
3840 else if (mb_l == 0) /* at the NUL at end-of-line */
3841 mb_l = 1;
3842#ifdef FEAT_ARABIC
3843 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
3844 {
3845 /* Do Arabic shaping. */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003846 int pc, pc1, nc;
3847 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848
3849 /* The idea of what is the previous and next
3850 * character depends on 'rightleft'. */
3851 if (wp->w_p_rl)
3852 {
3853 pc = prev_c;
3854 pc1 = prev_c1;
3855 nc = utf_ptr2char(ptr + mb_l);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003856 prev_c1 = u8cc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003857 }
3858 else
3859 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003860 pc = utfc_ptr2char(ptr + mb_l, pcc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003861 nc = prev_c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003862 pc1 = pcc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003863 }
3864 prev_c = mb_c;
3865
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003866 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867 }
3868 else
3869 prev_c = mb_c;
3870#endif
3871 }
3872 else /* enc_dbcs */
3873 {
3874 mb_l = MB_BYTE2LEN(c);
3875 if (mb_l == 0) /* at the NUL at end-of-line */
3876 mb_l = 1;
3877 else if (mb_l > 1)
3878 {
3879 /* We assume a second byte below 32 is illegal.
3880 * Hopefully this is OK for all double-byte encodings!
3881 */
3882 if (ptr[1] >= 32)
3883 mb_c = (c << 8) + ptr[1];
3884 else
3885 {
3886 if (ptr[1] == NUL)
3887 {
3888 /* head byte at end of line */
3889 mb_l = 1;
3890 transchar_nonprint(extra, c);
3891 }
3892 else
3893 {
3894 /* illegal tail byte */
3895 mb_l = 2;
3896 STRCPY(extra, "XX");
3897 }
3898 p_extra = extra;
3899 n_extra = (int)STRLEN(extra) - 1;
3900 c_extra = NUL;
3901 c = *p_extra++;
3902 if (area_attr == 0 && search_attr == 0)
3903 {
3904 n_attr = n_extra + 1;
3905 extra_attr = hl_attr(HLF_8);
3906 saved_attr2 = char_attr; /* save current attr */
3907 }
3908 mb_c = c;
3909 }
3910 }
3911 }
3912 /* If a double-width char doesn't fit display a '>' in the
3913 * last column; the character is displayed at the start of the
3914 * next line. */
3915 if ((
3916# ifdef FEAT_RIGHTLEFT
3917 wp->w_p_rl ? (col <= 0) :
3918# endif
3919 (col >= W_WIDTH(wp) - 1))
3920 && (*mb_char2cells)(mb_c) == 2)
3921 {
3922 c = '>';
3923 mb_c = c;
3924 mb_utf8 = FALSE;
3925 mb_l = 1;
3926 multi_attr = hl_attr(HLF_AT);
3927 /* Put pointer back so that the character will be
3928 * displayed at the start of the next line. */
3929 --ptr;
3930 }
3931 else if (*ptr != NUL)
3932 ptr += mb_l - 1;
3933
3934 /* If a double-width char doesn't fit at the left side display
3935 * a '<' in the first column. */
3936 if (n_skip > 0 && mb_l > 1)
3937 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003938 n_extra = 1;
Bram Moolenaara064ac82007-08-05 18:10:54 +00003939 c_extra = '<';
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 c = ' ';
3941 if (area_attr == 0 && search_attr == 0)
3942 {
3943 n_attr = n_extra + 1;
3944 extra_attr = hl_attr(HLF_AT);
3945 saved_attr2 = char_attr; /* save current attr */
3946 }
3947 mb_c = c;
3948 mb_utf8 = FALSE;
3949 mb_l = 1;
3950 }
3951
3952 }
3953#endif
3954 ++ptr;
3955
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003956 /* 'list' : change char 160 to lcs_nbsp. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003957 if (wp->w_p_list && (c == 160
3958#ifdef FEAT_MBYTE
3959 || (mb_utf8 && mb_c == 160)
3960#endif
3961 ) && lcs_nbsp)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003962 {
3963 c = lcs_nbsp;
3964 if (area_attr == 0 && search_attr == 0)
3965 {
3966 n_attr = 1;
3967 extra_attr = hl_attr(HLF_8);
3968 saved_attr2 = char_attr; /* save current attr */
3969 }
3970#ifdef FEAT_MBYTE
3971 mb_c = c;
3972 if (enc_utf8 && (*mb_char2len)(c) > 1)
3973 {
3974 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003975 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003976 c = 0xc0;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003977 }
3978 else
3979 mb_utf8 = FALSE;
3980#endif
3981 }
3982
Bram Moolenaar071d4272004-06-13 20:20:40 +00003983 if (extra_check)
3984 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003985#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00003986 int can_spell = TRUE;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003987#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00003988
Bram Moolenaar600dddc2006-03-12 22:05:10 +00003989#ifdef FEAT_SYN_HL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990 /* Get syntax attribute, unless still at the start of the line
3991 * (double-wide char that doesn't fit). */
Bram Moolenaar217ad922005-03-20 22:37:15 +00003992 v = (long)(ptr - line);
3993 if (has_syntax && v > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994 {
3995 /* Get the syntax attribute for the character. If there
3996 * is an error, disable syntax highlighting. */
3997 save_did_emsg = did_emsg;
3998 did_emsg = FALSE;
3999
Bram Moolenaar217ad922005-03-20 22:37:15 +00004000 syntax_attr = get_syntax_attr((colnr_T)v - 1,
Bram Moolenaar860cae12010-06-05 23:22:07 +02004001# ifdef FEAT_CONCEAL
4002 &syntax_flags,
4003# else
4004 NULL,
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004005# endif
Bram Moolenaar860cae12010-06-05 23:22:07 +02004006# ifdef FEAT_SPELL
4007 has_spell ? &can_spell :
4008# endif
4009 NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004010
4011 if (did_emsg)
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004012 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02004013 wp->w_s->b_syn_error = TRUE;
Bram Moolenaar5b8d8fd2005-08-16 23:01:50 +00004014 has_syntax = FALSE;
4015 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 else
4017 did_emsg = save_did_emsg;
4018
4019 /* Need to get the line again, a multi-line regexp may
4020 * have made it invalid. */
4021 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4022 ptr = line + v;
4023
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004024 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025 char_attr = syntax_attr;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004026 else
Bram Moolenaarbc045ea2005-06-05 22:01:26 +00004027 char_attr = hl_combine_attr(syntax_attr, char_attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004029#endif
Bram Moolenaar217ad922005-03-20 22:37:15 +00004030
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004031#ifdef FEAT_SPELL
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004032 /* Check spelling (unless at the end of the line).
Bram Moolenaarf3681cc2005-06-08 22:03:13 +00004033 * Only do this when there is no syntax highlighting, the
4034 * @Spell cluster is not used or the current syntax item
4035 * contains the @Spell cluster. */
Bram Moolenaar30abd282005-06-22 22:35:10 +00004036 if (has_spell && v >= word_end && v > cur_checked_col)
Bram Moolenaar217ad922005-03-20 22:37:15 +00004037 {
Bram Moolenaar68b76a62005-03-25 21:53:48 +00004038 spell_attr = 0;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004039# ifdef FEAT_SYN_HL
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004040 if (!attr_pri)
Bram Moolenaar68b76a62005-03-25 21:53:48 +00004041 char_attr = syntax_attr;
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004042# endif
4043 if (c != 0 && (
4044# ifdef FEAT_SYN_HL
4045 !has_syntax ||
4046# endif
4047 can_spell))
Bram Moolenaar217ad922005-03-20 22:37:15 +00004048 {
Bram Moolenaar30abd282005-06-22 22:35:10 +00004049 char_u *prev_ptr, *p;
4050 int len;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004051 hlf_T spell_hlf = HLF_COUNT;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004052# ifdef FEAT_MBYTE
Bram Moolenaare7566042005-06-17 22:00:15 +00004053 if (has_mbyte)
4054 {
4055 prev_ptr = ptr - mb_l;
4056 v -= mb_l - 1;
4057 }
4058 else
Bram Moolenaar217ad922005-03-20 22:37:15 +00004059# endif
Bram Moolenaare7566042005-06-17 22:00:15 +00004060 prev_ptr = ptr - 1;
Bram Moolenaar30abd282005-06-22 22:35:10 +00004061
4062 /* Use nextline[] if possible, it has the start of the
4063 * next line concatenated. */
4064 if ((prev_ptr - line) - nextlinecol >= 0)
4065 p = nextline + (prev_ptr - line) - nextlinecol;
4066 else
4067 p = prev_ptr;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004068 cap_col -= (int)(prev_ptr - line);
Bram Moolenaar4770d092006-01-12 23:22:24 +00004069 len = spell_check(wp, p, &spell_hlf, &cap_col,
4070 nochange);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004071 word_end = v + len;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004072
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004073 /* In Insert mode only highlight a word that
4074 * doesn't touch the cursor. */
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004075 if (spell_hlf != HLF_COUNT
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004076 && (State & INSERT) != 0
4077 && wp->w_cursor.lnum == lnum
4078 && wp->w_cursor.col >=
Bram Moolenaar217ad922005-03-20 22:37:15 +00004079 (colnr_T)(prev_ptr - line)
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004080 && wp->w_cursor.col < (colnr_T)word_end)
4081 {
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004082 spell_hlf = HLF_COUNT;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004083 spell_redraw_lnum = lnum;
Bram Moolenaar217ad922005-03-20 22:37:15 +00004084 }
Bram Moolenaar30abd282005-06-22 22:35:10 +00004085
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004086 if (spell_hlf == HLF_COUNT && p != prev_ptr
Bram Moolenaar30abd282005-06-22 22:35:10 +00004087 && (p - nextline) + len > nextline_idx)
4088 {
4089 /* Remember that the good word continues at the
4090 * start of the next line. */
4091 checked_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004092 checked_col = (int)((p - nextline) + len - nextline_idx);
Bram Moolenaar30abd282005-06-22 22:35:10 +00004093 }
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004094
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004095 /* Turn index into actual attributes. */
4096 if (spell_hlf != HLF_COUNT)
4097 spell_attr = highlight_attr[spell_hlf];
4098
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004099 if (cap_col > 0)
4100 {
4101 if (p != prev_ptr
4102 && (p - nextline) + cap_col >= nextline_idx)
4103 {
4104 /* Remember that the word in the next line
4105 * must start with a capital. */
4106 capcol_lnum = lnum + 1;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004107 cap_col = (int)((p - nextline) + cap_col
4108 - nextline_idx);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004109 }
4110 else
4111 /* Compute the actual column. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004112 cap_col += (int)(prev_ptr - line);
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00004113 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004114 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004115 }
4116 if (spell_attr != 0)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004117 {
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004118 if (!attr_pri)
Bram Moolenaar30abd282005-06-22 22:35:10 +00004119 char_attr = hl_combine_attr(char_attr, spell_attr);
4120 else
4121 char_attr = hl_combine_attr(spell_attr, char_attr);
4122 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123#endif
4124#ifdef FEAT_LINEBREAK
4125 /*
Bram Moolenaar217ad922005-03-20 22:37:15 +00004126 * Found last space before word: check for line break.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004127 */
4128 if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004129 && !wp->w_p_list)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004130 {
4131 n_extra = win_lbr_chartabsize(wp, ptr - (
4132# ifdef FEAT_MBYTE
4133 has_mbyte ? mb_l :
4134# endif
4135 1), (colnr_T)vcol, NULL) - 1;
4136 c_extra = ' ';
4137 if (vim_iswhite(c))
4138 c = ' ';
4139 }
4140#endif
4141
4142 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
4143 {
4144 c = lcs_trail;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004145 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 {
4147 n_attr = 1;
4148 extra_attr = hl_attr(HLF_8);
4149 saved_attr2 = char_attr; /* save current attr */
4150 }
4151#ifdef FEAT_MBYTE
4152 mb_c = c;
4153 if (enc_utf8 && (*mb_char2len)(c) > 1)
4154 {
4155 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004156 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004157 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158 }
4159 else
4160 mb_utf8 = FALSE;
4161#endif
4162 }
4163 }
4164
4165 /*
4166 * Handling of non-printable characters.
4167 */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004168 if (!(chartab[c & 0xff] & CT_PRINT_CHAR))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 {
4170 /*
4171 * when getting a character from the file, we may have to
4172 * turn it into something else on the way to putting it
4173 * into "ScreenLines".
4174 */
4175 if (c == TAB && (!wp->w_p_list || lcs_tab1))
4176 {
4177 /* tab amount depends on current column */
4178 n_extra = (int)wp->w_buffer->b_p_ts
4179 - vcol % (int)wp->w_buffer->b_p_ts - 1;
4180#ifdef FEAT_MBYTE
4181 mb_utf8 = FALSE; /* don't draw as UTF-8 */
4182#endif
4183 if (wp->w_p_list)
4184 {
4185 c = lcs_tab1;
4186 c_extra = lcs_tab2;
4187 n_attr = n_extra + 1;
4188 extra_attr = hl_attr(HLF_8);
4189 saved_attr2 = char_attr; /* save current attr */
4190#ifdef FEAT_MBYTE
4191 mb_c = c;
4192 if (enc_utf8 && (*mb_char2len)(c) > 1)
4193 {
4194 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004195 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004196 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004197 }
4198#endif
4199 }
4200 else
4201 {
4202 c_extra = ' ';
4203 c = ' ';
4204 }
4205 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004206 else if (c == NUL
4207 && ((wp->w_p_list && lcs_eol > 0)
4208 || ((fromcol >= 0 || fromcol_prev >= 0)
4209 && tocol > vcol
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004210#ifdef FEAT_VISUAL
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004211 && VIsual_mode != Ctrl_V
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004212#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004213 && (
4214# ifdef FEAT_RIGHTLEFT
4215 wp->w_p_rl ? (col >= 0) :
4216# endif
4217 (col < W_WIDTH(wp)))
4218 && !(noinvcur
Bram Moolenaarf3205d12009-03-18 18:09:03 +00004219 && lnum == wp->w_cursor.lnum
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004220 && (colnr_T)vcol == wp->w_virtcol)))
4221 && lcs_eol_one >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004223 /* Display a '$' after the line or highlight an extra
4224 * character if the line break is included. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225#if defined(FEAT_DIFF) || defined(LINE_ATTR)
4226 /* For a diff line the highlighting continues after the
4227 * "$". */
4228 if (
4229# ifdef FEAT_DIFF
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004230 diff_hlf == (hlf_T)0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231# ifdef LINE_ATTR
4232 &&
4233# endif
4234# endif
4235# ifdef LINE_ATTR
4236 line_attr == 0
4237# endif
4238 )
4239#endif
4240 {
4241#ifdef FEAT_VIRTUALEDIT
4242 /* In virtualedit, visual selections may extend
4243 * beyond end of line. */
4244 if (area_highlighting && virtual_active()
4245 && tocol != MAXCOL && vcol < tocol)
4246 n_extra = 0;
4247 else
4248#endif
4249 {
4250 p_extra = at_end_str;
4251 n_extra = 1;
4252 c_extra = NUL;
4253 }
4254 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004255 if (wp->w_p_list)
4256 c = lcs_eol;
4257 else
4258 c = ' ';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004259 lcs_eol_one = -1;
4260 --ptr; /* put it back at the NUL */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004261 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 {
4263 extra_attr = hl_attr(HLF_AT);
4264 n_attr = 1;
4265 }
4266#ifdef FEAT_MBYTE
4267 mb_c = c;
4268 if (enc_utf8 && (*mb_char2len)(c) > 1)
4269 {
4270 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004271 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004272 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273 }
4274 else
4275 mb_utf8 = FALSE; /* don't draw as UTF-8 */
4276#endif
4277 }
4278 else if (c != NUL)
4279 {
4280 p_extra = transchar(c);
4281#ifdef FEAT_RIGHTLEFT
4282 if ((dy_flags & DY_UHEX) && wp->w_p_rl)
4283 rl_mirror(p_extra); /* reverse "<12>" */
4284#endif
4285 n_extra = byte2cells(c) - 1;
4286 c_extra = NUL;
4287 c = *p_extra++;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004288 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289 {
4290 n_attr = n_extra + 1;
4291 extra_attr = hl_attr(HLF_8);
4292 saved_attr2 = char_attr; /* save current attr */
4293 }
4294#ifdef FEAT_MBYTE
4295 mb_utf8 = FALSE; /* don't draw as UTF-8 */
4296#endif
4297 }
4298#ifdef FEAT_VIRTUALEDIT
4299 else if (VIsual_active
4300 && (VIsual_mode == Ctrl_V
4301 || VIsual_mode == 'v')
4302 && virtual_active()
4303 && tocol != MAXCOL
4304 && vcol < tocol
4305 && (
4306# ifdef FEAT_RIGHTLEFT
4307 wp->w_p_rl ? (col >= 0) :
4308# endif
4309 (col < W_WIDTH(wp))))
4310 {
4311 c = ' ';
4312 --ptr; /* put it back at the NUL */
4313 }
4314#endif
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00004315#if defined(LINE_ATTR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316 else if ((
4317# ifdef FEAT_DIFF
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00004318 diff_hlf != (hlf_T)0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320 line_attr != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 ) && (
4322# ifdef FEAT_RIGHTLEFT
4323 wp->w_p_rl ? (col >= 0) :
4324# endif
4325 (col < W_WIDTH(wp))))
4326 {
4327 /* Highlight until the right side of the window */
4328 c = ' ';
4329 --ptr; /* put it back at the NUL */
Bram Moolenaar91170f82006-05-05 21:15:17 +00004330
4331 /* Remember we do the char for line highlighting. */
4332 ++did_line_attr;
4333
4334 /* don't do search HL for the rest of the line */
4335 if (line_attr != 0 && char_attr == search_attr && col > 0)
4336 char_attr = line_attr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004337# ifdef FEAT_DIFF
4338 if (diff_hlf == HLF_TXD)
4339 {
4340 diff_hlf = HLF_CHD;
4341 if (attr == 0 || char_attr != attr)
4342 char_attr = hl_attr(diff_hlf);
4343 }
4344# endif
4345 }
4346#endif
4347 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02004348
4349#ifdef FEAT_CONCEAL
4350 if ( wp->w_p_conceal
Bram Moolenaare667c952010-07-05 22:57:59 +02004351 && !area_highlighting
4352 && (lnum != wp->w_cursor.lnum
4353 || curwin != wp || wp->w_buffer->b_p_ma == FALSE)
4354 && (syntax_flags & HL_CONCEAL) != 0)
Bram Moolenaar860cae12010-06-05 23:22:07 +02004355
4356 {
4357 char_attr = conceal_attr;
4358 if (first_conceal
4359 && (syn_get_sub_char() != NUL || wp->w_p_conceal == 1))
4360 {
4361 if (syn_get_sub_char() != NUL)
4362 c = syn_get_sub_char();
4363 else if (lcs_conceal != NUL)
4364 c = lcs_conceal;
4365 else
4366 c = ' ';
4367
4368 first_conceal = FALSE;
4369
4370# ifdef FEAT_HLCOLUMN
4371 if (hlc > 0 && n_extra > 0)
4372 hlc += n_extra;
4373# endif
4374 vcol += n_extra;
4375 if (wp->w_p_wrap && n_extra > 0)
4376 {
4377# ifdef FEAT_RIGHTLEFT
4378 if (wp->w_p_rl)
4379 {
4380 col -= n_extra;
4381 boguscols -= n_extra;
4382 }
4383 else
4384# endif
4385 {
4386 boguscols += n_extra;
4387 col += n_extra;
4388 }
4389 }
4390 n_extra = 0;
4391 n_attr = 0;
4392 }
4393 else if (n_skip == 0)
4394 {
4395 is_concealing = TRUE;
4396 n_skip = 1;
4397 }
4398# ifdef FEAT_MBYTE
4399 mb_c = c;
4400 if (enc_utf8 && (*mb_char2len)(c) > 1)
4401 {
4402 mb_utf8 = TRUE;
4403 u8cc[0] = 0;
4404 c = 0xc0;
4405 }
4406 else
4407 mb_utf8 = FALSE; /* don't draw as UTF-8 */
4408# endif
4409 }
4410 else
4411 {
4412 first_conceal = (wp->w_p_conceal != 3);
4413 is_concealing = FALSE;
4414 }
4415#endif /* FEAT_CONCEAL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416 }
4417
4418 /* Don't override visual selection highlighting. */
4419 if (n_attr > 0
4420 && draw_state == WL_LINE
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004421 && !attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422 char_attr = extra_attr;
4423
Bram Moolenaar81695252004-12-29 20:58:21 +00004424#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425 /* XIM don't send preedit_start and preedit_end, but they send
4426 * preedit_changed and commit. Thus Vim can't set "im_is_active", use
4427 * im_is_preediting() here. */
4428 if (xic != NULL
Bram Moolenaarf3205d12009-03-18 18:09:03 +00004429 && lnum == wp->w_cursor.lnum
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430 && (State & INSERT)
4431 && !p_imdisable
4432 && im_is_preediting()
4433 && draw_state == WL_LINE)
4434 {
4435 colnr_T tcol;
4436
4437 if (preedit_end_col == MAXCOL)
Bram Moolenaarf3205d12009-03-18 18:09:03 +00004438 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004439 else
4440 tcol = preedit_end_col;
4441 if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
4442 {
4443 if (feedback_old_attr < 0)
4444 {
4445 feedback_col = 0;
4446 feedback_old_attr = char_attr;
4447 }
4448 char_attr = im_get_feedback_attr(feedback_col);
4449 if (char_attr < 0)
4450 char_attr = feedback_old_attr;
4451 feedback_col++;
4452 }
4453 else if (feedback_old_attr >= 0)
4454 {
4455 char_attr = feedback_old_attr;
4456 feedback_old_attr = -1;
4457 feedback_col = 0;
4458 }
4459 }
4460#endif
4461 /*
4462 * Handle the case where we are in column 0 but not on the first
4463 * character of the line and the user wants us to show us a
4464 * special character (via 'listchars' option "precedes:<char>".
4465 */
4466 if (lcs_prec_todo != NUL
4467 && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
4468#ifdef FEAT_DIFF
4469 && filler_todo <= 0
4470#endif
4471 && draw_state > WL_NR
4472 && c != NUL)
4473 {
4474 c = lcs_prec;
4475 lcs_prec_todo = NUL;
4476#ifdef FEAT_MBYTE
4477 mb_c = c;
4478 if (enc_utf8 && (*mb_char2len)(c) > 1)
4479 {
4480 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004481 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004482 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483 }
4484 else
4485 mb_utf8 = FALSE; /* don't draw as UTF-8 */
4486#endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004487 if (!attr_pri)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 {
4489 saved_attr3 = char_attr; /* save current attr */
4490 char_attr = hl_attr(HLF_AT); /* later copied to char_attr */
4491 n_attr3 = 1;
4492 }
4493 }
4494
4495 /*
Bram Moolenaar91170f82006-05-05 21:15:17 +00004496 * At end of the text line or just after the last character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497 */
Bram Moolenaar91170f82006-05-05 21:15:17 +00004498 if (c == NUL
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00004499#if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00004500 || did_line_attr == 1
4501#endif
4502 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 {
Bram Moolenaar91170f82006-05-05 21:15:17 +00004504#ifdef FEAT_SEARCH_EXTRA
4505 long prevcol = (long)(ptr - line) - (c == NUL);
Bram Moolenaara443af82007-11-08 13:51:42 +00004506
4507 /* we're not really at that column when skipping some text */
Bram Moolenaar33741a02007-11-08 20:24:19 +00004508 if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
Bram Moolenaara443af82007-11-08 13:51:42 +00004509 ++prevcol;
Bram Moolenaar91170f82006-05-05 21:15:17 +00004510#endif
4511
Bram Moolenaar071d4272004-06-13 20:20:40 +00004512 /* invert at least one char, used for Visual and empty line or
4513 * highlight match at end of line. If it's beyond the last
4514 * char on the screen, just overwrite that one (tricky!) Not
4515 * needed when a '$' was displayed for 'list'. */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004516#ifdef FEAT_SEARCH_EXTRA
4517 prevcol_hl_flag = FALSE;
4518 if (prevcol == (long)search_hl.startcol)
4519 prevcol_hl_flag = TRUE;
4520 else
4521 {
4522 cur = wp->w_match_head;
4523 while (cur != NULL)
4524 {
4525 if (prevcol == (long)cur->hl.startcol)
4526 {
4527 prevcol_hl_flag = TRUE;
4528 break;
4529 }
4530 cur = cur->next;
4531 }
4532 }
4533#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 if (lcs_eol == lcs_eol_one
Bram Moolenaarf3205d12009-03-18 18:09:03 +00004535 && ((area_attr != 0 && vcol == fromcol
4536#ifdef FEAT_VISUAL
4537 && (VIsual_mode != Ctrl_V
4538 || lnum == VIsual.lnum
4539 || lnum == curwin->w_cursor.lnum)
4540#endif
4541 && c == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542#ifdef FEAT_SEARCH_EXTRA
4543 /* highlight 'hlsearch' match at end of line */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004544 || (prevcol_hl_flag == TRUE
Bram Moolenaar6c60ea22006-07-11 20:36:45 +00004545# if defined(LINE_ATTR)
Bram Moolenaar91170f82006-05-05 21:15:17 +00004546 && did_line_attr <= 1
4547# endif
4548 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549#endif
4550 ))
4551 {
4552 int n = 0;
4553
4554#ifdef FEAT_RIGHTLEFT
4555 if (wp->w_p_rl)
4556 {
4557 if (col < 0)
4558 n = 1;
4559 }
4560 else
4561#endif
4562 {
4563 if (col >= W_WIDTH(wp))
4564 n = -1;
4565 }
4566 if (n != 0)
4567 {
4568 /* At the window boundary, highlight the last character
4569 * instead (better than nothing). */
4570 off += n;
4571 col += n;
4572 }
4573 else
4574 {
4575 /* Add a blank character to highlight. */
4576 ScreenLines[off] = ' ';
4577#ifdef FEAT_MBYTE
4578 if (enc_utf8)
4579 ScreenLinesUC[off] = 0;
4580#endif
4581 }
4582#ifdef FEAT_SEARCH_EXTRA
4583 if (area_attr == 0)
4584 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004585 /* Use attributes from match with highest priority among
4586 * 'search_hl' and the match list. */
4587 char_attr = search_hl.attr;
4588 cur = wp->w_match_head;
4589 shl_flag = FALSE;
4590 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004591 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004592 if (shl_flag == FALSE
4593 && ((cur != NULL
4594 && cur->priority > SEARCH_HL_PRIORITY)
4595 || cur == NULL))
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004596 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004597 shl = &search_hl;
4598 shl_flag = TRUE;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004599 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004600 else
4601 shl = &cur->hl;
4602 if ((ptr - line) - 1 == (long)shl->startcol)
4603 char_attr = shl->attr;
4604 if (shl != &search_hl && cur != NULL)
4605 cur = cur->next;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00004606 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607 }
4608#endif
4609 ScreenAttrs[off] = char_attr;
4610#ifdef FEAT_RIGHTLEFT
4611 if (wp->w_p_rl)
Bram Moolenaara443af82007-11-08 13:51:42 +00004612 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613 --col;
Bram Moolenaara443af82007-11-08 13:51:42 +00004614 --off;
4615 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 else
4617#endif
Bram Moolenaara443af82007-11-08 13:51:42 +00004618 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619 ++col;
Bram Moolenaara443af82007-11-08 13:51:42 +00004620 ++off;
4621 }
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004622 ++vcol;
Bram Moolenaara443af82007-11-08 13:51:42 +00004623#ifdef FEAT_SYN_HL
4624 eol_hl_off = 1;
4625#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 }
Bram Moolenaar91170f82006-05-05 21:15:17 +00004627 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628
Bram Moolenaar91170f82006-05-05 21:15:17 +00004629 /*
4630 * At end of the text line.
4631 */
4632 if (c == NUL)
4633 {
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004634#ifdef FEAT_SYN_HL
Bram Moolenaarf3205d12009-03-18 18:09:03 +00004635 if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol
4636 && lnum == wp->w_cursor.lnum)
Bram Moolenaara443af82007-11-08 13:51:42 +00004637 {
4638 /* highlight last char after line */
4639 --col;
4640 --off;
4641 --vcol;
4642 }
4643
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004644 /* Highlight 'cursorcolumn' past end of the line. */
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00004645 if (wp->w_p_wrap)
4646 v = wp->w_skipcol;
4647 else
4648 v = wp->w_leftcol;
Bram Moolenaar8dff8182006-04-06 20:18:50 +00004649 /* check if line ends before left margin */
4650 if (vcol < v + col - win_col_off(wp))
4651
4652 vcol = v + col - win_col_off(wp);
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004653 if (wp->w_p_cuc
Bram Moolenaara443af82007-11-08 13:51:42 +00004654 && (int)wp->w_virtcol >= vcol - eol_hl_off
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004655 && (int)wp->w_virtcol < W_WIDTH(wp) * (row - startrow + 1)
4656 + v
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004657 && lnum != wp->w_cursor.lnum
4658# ifdef FEAT_RIGHTLEFT
4659 && !wp->w_p_rl
4660# endif
4661 )
4662 {
4663 while (col < W_WIDTH(wp))
4664 {
4665 ScreenLines[off] = ' ';
4666#ifdef FEAT_MBYTE
4667 if (enc_utf8)
4668 ScreenLinesUC[off] = 0;
4669#endif
4670 ++col;
Bram Moolenaarca003e12006-03-17 23:19:38 +00004671 if (vcol == (long)wp->w_virtcol)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004672 {
4673 ScreenAttrs[off] = hl_attr(HLF_CUC);
4674 break;
4675 }
4676 ScreenAttrs[off++] = 0;
4677 ++vcol;
4678 }
4679 }
4680#endif
4681
Bram Moolenaar860cae12010-06-05 23:22:07 +02004682#ifdef FEAT_CONCEAL
4683 SCREEN_LINE(screen_row, W_WINCOL(wp), col - boguscols,
4684 (int)W_WIDTH(wp), wp->w_p_rl);
4685 boguscols = 0;
4686#else
4687 SCREEN_LINE(screen_row, W_WINCOL(wp), col,
4688 (int)W_WIDTH(wp), wp->w_p_rl);
4689#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 row++;
4691
4692 /*
4693 * Update w_cline_height and w_cline_folded if the cursor line was
4694 * updated (saves a call to plines() later).
4695 */
4696 if (wp == curwin && lnum == curwin->w_cursor.lnum)
4697 {
4698 curwin->w_cline_row = startrow;
4699 curwin->w_cline_height = row - startrow;
4700#ifdef FEAT_FOLDING
4701 curwin->w_cline_folded = FALSE;
4702#endif
4703 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
4704 }
4705
4706 break;
4707 }
4708
4709 /* line continues beyond line end */
4710 if (lcs_ext
4711 && !wp->w_p_wrap
4712#ifdef FEAT_DIFF
4713 && filler_todo <= 0
4714#endif
4715 && (
4716#ifdef FEAT_RIGHTLEFT
4717 wp->w_p_rl ? col == 0 :
4718#endif
4719 col == W_WIDTH(wp) - 1)
4720 && (*ptr != NUL
Bram Moolenaar5bbc21d2008-03-09 13:30:56 +00004721 || (wp->w_p_list && lcs_eol_one > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004722 || (n_extra && (c_extra != NUL || *p_extra != NUL))))
4723 {
4724 c = lcs_ext;
4725 char_attr = hl_attr(HLF_AT);
4726#ifdef FEAT_MBYTE
4727 mb_c = c;
4728 if (enc_utf8 && (*mb_char2len)(c) > 1)
4729 {
4730 mb_utf8 = TRUE;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004731 u8cc[0] = 0;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004732 c = 0xc0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733 }
4734 else
4735 mb_utf8 = FALSE;
4736#endif
4737 }
4738
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004739#ifdef FEAT_SYN_HL
4740 /* Highlight the cursor column if 'cursorcolumn' is set. But don't
4741 * highlight the cursor position itself. */
Bram Moolenaarca003e12006-03-17 23:19:38 +00004742 if (wp->w_p_cuc && vcol == (long)wp->w_virtcol
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004743 && lnum != wp->w_cursor.lnum
Bram Moolenaar54ef7112009-02-21 20:11:41 +00004744 && draw_state == WL_LINE
4745 && !lnum_in_visual_area)
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004746 {
4747 vcol_save_attr = char_attr;
4748 char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUC));
4749 }
4750 else
4751 vcol_save_attr = -1;
4752#endif
4753
Bram Moolenaar071d4272004-06-13 20:20:40 +00004754 /*
4755 * Store character to be displayed.
4756 * Skip characters that are left of the screen for 'nowrap'.
4757 */
4758 vcol_prev = vcol;
4759 if (draw_state < WL_LINE || n_skip <= 0)
4760 {
4761 /*
4762 * Store the character.
4763 */
4764#if defined(FEAT_RIGHTLEFT) && defined(FEAT_MBYTE)
4765 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
4766 {
4767 /* A double-wide character is: put first halve in left cell. */
4768 --off;
4769 --col;
4770 }
4771#endif
4772 ScreenLines[off] = c;
4773#ifdef FEAT_MBYTE
4774 if (enc_dbcs == DBCS_JPNU)
Bram Moolenaar990bb662010-02-03 15:48:04 +01004775 {
4776 if ((mb_c & 0xff00) == 0x8e00)
4777 ScreenLines[off] = 0x8e;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 ScreenLines2[off] = mb_c & 0xff;
Bram Moolenaar990bb662010-02-03 15:48:04 +01004779 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780 else if (enc_utf8)
4781 {
4782 if (mb_utf8)
4783 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004784 int i;
4785
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 ScreenLinesUC[off] = mb_c;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004787 if ((c & 0xff) == 0)
4788 ScreenLines[off] = 0x80; /* avoid storing zero */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004789 for (i = 0; i < Screen_mco; ++i)
4790 {
4791 ScreenLinesC[i][off] = u8cc[i];
4792 if (u8cc[i] == 0)
4793 break;
4794 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 }
4796 else
4797 ScreenLinesUC[off] = 0;
4798 }
4799 if (multi_attr)
4800 {
4801 ScreenAttrs[off] = multi_attr;
4802 multi_attr = 0;
4803 }
4804 else
4805#endif
4806 ScreenAttrs[off] = char_attr;
4807
4808#ifdef FEAT_MBYTE
4809 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
4810 {
4811 /* Need to fill two screen columns. */
4812 ++off;
4813 ++col;
4814 if (enc_utf8)
4815 /* UTF-8: Put a 0 in the second screen char. */
4816 ScreenLines[off] = 0;
4817 else
4818 /* DBCS: Put second byte in the second screen char. */
4819 ScreenLines[off] = mb_c & 0xff;
4820 ++vcol;
4821 /* When "tocol" is halfway a character, set it to the end of
4822 * the character, otherwise highlighting won't stop. */
4823 if (tocol == vcol)
4824 ++tocol;
4825#ifdef FEAT_RIGHTLEFT
4826 if (wp->w_p_rl)
4827 {
4828 /* now it's time to backup one cell */
4829 --off;
4830 --col;
4831 }
4832#endif
4833 }
4834#endif
4835#ifdef FEAT_RIGHTLEFT
4836 if (wp->w_p_rl)
4837 {
4838 --off;
4839 --col;
4840 }
4841 else
4842#endif
4843 {
4844 ++off;
4845 ++col;
4846 }
4847 }
Bram Moolenaar860cae12010-06-05 23:22:07 +02004848#ifdef FEAT_CONCEAL
4849 else if (wp->w_p_conceal && is_concealing)
4850 {
4851 --n_skip;
4852# ifdef FEAT_HLCOLUMN
4853 if (hlc)
4854 {
4855 ++hlc;
4856 if (n_extra > 0)
4857 hlc += n_extra;
4858 }
4859# endif
4860 if (wp->w_p_wrap)
4861 {
4862 /*
4863 * Special voodoo required if 'wrap' is on.
4864 *
4865 * Advance the column indicator to force the line
4866 * drawing to wrap early. This will make the line
4867 * take up the same screen space when parts are concealed,
4868 * so that cursor line computations aren't messed up.
4869 *
4870 * To avoid the fictitious advance of 'col' causing
4871 * trailing junk to be written out of the screen line
4872 * we are building, 'boguscols' keeps track of the number
4873 * of bad columns we have advanced.
4874 */
4875 if (n_extra > 0)
4876 {
4877 vcol += n_extra;
4878# ifdef FEAT_RIGHTLEFT
4879 if (wp->w_p_rl)
4880 {
4881 col -= n_extra;
4882 boguscols -= n_extra;
4883 }
4884 else
4885# endif
4886 {
4887 col += n_extra;
4888 boguscols += n_extra;
4889 }
4890 n_extra = 0;
4891 n_attr = 0;
4892 }
4893
4894
4895# ifdef FEAT_MBYTE
4896 if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
4897 {
4898 /* Need to fill two screen columns. */
4899# ifdef FEAT_RIGHTLEFT
4900 if (wp->w_p_rl)
4901 {
4902 --boguscols;
4903 --col;
4904 }
4905 else
4906# endif
4907 {
4908 ++boguscols;
4909 ++col;
4910 }
4911 }
4912# endif
4913
4914# ifdef FEAT_RIGHTLEFT
4915 if (wp->w_p_rl)
4916 {
4917 --boguscols;
4918 --col;
4919 }
4920 else
4921# endif
4922 {
4923 ++boguscols;
4924 ++col;
4925 }
4926 }
4927 else
4928 {
4929 if (n_extra > 0)
4930 {
4931 vcol += n_extra;
4932 n_extra = 0;
4933 n_attr = 0;
4934 }
4935 }
4936
4937 }
4938#endif /* FEAT_CONCEAL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004939 else
4940 --n_skip;
4941
Bram Moolenaar64486672010-05-16 15:46:46 +02004942 /* Only advance the "vcol" when after the 'number' or 'relativenumber'
4943 * column. */
Bram Moolenaar1b636fa2009-03-18 15:28:08 +00004944 if (draw_state > WL_NR
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945#ifdef FEAT_DIFF
4946 && filler_todo <= 0
4947#endif
4948 )
4949 ++vcol;
4950
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004951#ifdef FEAT_SYN_HL
4952 if (vcol_save_attr >= 0)
4953 char_attr = vcol_save_attr;
4954#endif
4955
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956 /* restore attributes after "predeces" in 'listchars' */
4957 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
4958 char_attr = saved_attr3;
4959
4960 /* restore attributes after last 'listchars' or 'number' char */
4961 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
4962 char_attr = saved_attr2;
4963
4964 /*
4965 * At end of screen line and there is more to come: Display the line
Bram Moolenaar367329b2007-08-30 11:53:22 +00004966 * so far. If there is no more to display it is caught above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967 */
4968 if ((
4969#ifdef FEAT_RIGHTLEFT
4970 wp->w_p_rl ? (col < 0) :
4971#endif
4972 (col >= W_WIDTH(wp)))
4973 && (*ptr != NUL
4974#ifdef FEAT_DIFF
4975 || filler_todo > 0
4976#endif
4977 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
4978 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
4979 )
4980 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02004981#ifdef FEAT_CONCEAL
4982 SCREEN_LINE(screen_row, W_WINCOL(wp), col - boguscols,
4983 (int)W_WIDTH(wp), wp->w_p_rl);
4984 boguscols = 0;
4985#else
4986 SCREEN_LINE(screen_row, W_WINCOL(wp), col,
4987 (int)W_WIDTH(wp), wp->w_p_rl);
4988#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989 ++row;
4990 ++screen_row;
4991
4992 /* When not wrapping and finished diff lines, or when displayed
4993 * '$' and highlighting until last column, break here. */
4994 if ((!wp->w_p_wrap
4995#ifdef FEAT_DIFF
4996 && filler_todo <= 0
4997#endif
4998 ) || lcs_eol_one == -1)
4999 break;
5000
5001 /* When the window is too narrow draw all "@" lines. */
5002 if (draw_state != WL_LINE
5003#ifdef FEAT_DIFF
5004 && filler_todo <= 0
5005#endif
5006 )
5007 {
5008 win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
5009#ifdef FEAT_VERTSPLIT
5010 draw_vsep_win(wp, row);
5011#endif
5012 row = endrow;
5013 }
5014
5015 /* When line got too long for screen break here. */
5016 if (row == endrow)
5017 {
5018 ++row;
5019 break;
5020 }
5021
5022 if (screen_cur_row == screen_row - 1
5023#ifdef FEAT_DIFF
5024 && filler_todo <= 0
5025#endif
5026 && W_WIDTH(wp) == Columns)
5027 {
5028 /* Remember that the line wraps, used for modeless copy. */
5029 LineWraps[screen_row - 1] = TRUE;
5030
5031 /*
5032 * Special trick to make copy/paste of wrapped lines work with
5033 * xterm/screen: write an extra character beyond the end of
5034 * the line. This will work with all terminal types
5035 * (regardless of the xn,am settings).
5036 * Only do this on a fast tty.
5037 * Only do this if the cursor is on the current line
5038 * (something has been written in it).
5039 * Don't do this for the GUI.
5040 * Don't do this for double-width characters.
5041 * Don't do this for a window not at the right screen border.
5042 */
5043 if (p_tf
5044#ifdef FEAT_GUI
5045 && !gui.in_use
5046#endif
5047#ifdef FEAT_MBYTE
5048 && !(has_mbyte
Bram Moolenaar367329b2007-08-30 11:53:22 +00005049 && ((*mb_off2cells)(LineOffset[screen_row],
5050 LineOffset[screen_row] + screen_Columns)
5051 == 2
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052 || (*mb_off2cells)(LineOffset[screen_row - 1]
Bram Moolenaar367329b2007-08-30 11:53:22 +00005053 + (int)Columns - 2,
5054 LineOffset[screen_row] + screen_Columns)
5055 == 2))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005056#endif
5057 )
5058 {
5059 /* First make sure we are at the end of the screen line,
5060 * then output the same character again to let the
5061 * terminal know about the wrap. If the terminal doesn't
5062 * auto-wrap, we overwrite the character. */
5063 if (screen_cur_col != W_WIDTH(wp))
5064 screen_char(LineOffset[screen_row - 1]
5065 + (unsigned)Columns - 1,
5066 screen_row - 1, (int)(Columns - 1));
5067
5068#ifdef FEAT_MBYTE
5069 /* When there is a multi-byte character, just output a
5070 * space to keep it simple. */
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00005071 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
5072 screen_row - 1] + (Columns - 1)]) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005073 out_char(' ');
5074 else
5075#endif
5076 out_char(ScreenLines[LineOffset[screen_row - 1]
5077 + (Columns - 1)]);
5078 /* force a redraw of the first char on the next line */
5079 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
5080 screen_start(); /* don't know where cursor is now */
5081 }
5082 }
5083
5084 col = 0;
5085 off = (unsigned)(current_ScreenLine - ScreenLines);
5086#ifdef FEAT_RIGHTLEFT
5087 if (wp->w_p_rl)
5088 {
5089 col = W_WIDTH(wp) - 1; /* col is not used if breaking! */
5090 off += col;
5091 }
5092#endif
5093
5094 /* reset the drawing state for the start of a wrapped line */
5095 draw_state = WL_START;
5096 saved_n_extra = n_extra;
5097 saved_p_extra = p_extra;
5098 saved_c_extra = c_extra;
5099 saved_char_attr = char_attr;
5100 n_extra = 0;
5101 lcs_prec_todo = lcs_prec;
5102#ifdef FEAT_LINEBREAK
5103# ifdef FEAT_DIFF
5104 if (filler_todo <= 0)
5105# endif
5106 need_showbreak = TRUE;
5107#endif
5108#ifdef FEAT_DIFF
5109 --filler_todo;
5110 /* When the filler lines are actually below the last line of the
5111 * file, don't draw the line itself, break here. */
5112 if (filler_todo == 0 && wp->w_botfill)
5113 break;
5114#endif
5115 }
5116
5117 } /* for every character in the line */
5118
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005119#ifdef FEAT_SPELL
Bram Moolenaar0d9c26d2005-07-02 23:19:16 +00005120 /* After an empty line check first word for capital. */
5121 if (*skipwhite(line) == NUL)
5122 {
5123 capcol_lnum = lnum + 1;
5124 cap_col = 0;
5125 }
5126#endif
5127
Bram Moolenaar071d4272004-06-13 20:20:40 +00005128 return row;
5129}
5130
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005131#ifdef FEAT_MBYTE
5132static int comp_char_differs __ARGS((int, int));
5133
5134/*
5135 * Return if the composing characters at "off_from" and "off_to" differ.
Bram Moolenaar70c49c12010-03-23 15:36:35 +01005136 * Only to be used when ScreenLinesUC[off_from] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005137 */
5138 static int
5139comp_char_differs(off_from, off_to)
5140 int off_from;
5141 int off_to;
5142{
5143 int i;
5144
5145 for (i = 0; i < Screen_mco; ++i)
5146 {
5147 if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
5148 return TRUE;
5149 if (ScreenLinesC[i][off_from] == 0)
5150 break;
5151 }
5152 return FALSE;
5153}
5154#endif
5155
Bram Moolenaar071d4272004-06-13 20:20:40 +00005156/*
5157 * Check whether the given character needs redrawing:
5158 * - the (first byte of the) character is different
5159 * - the attributes are different
5160 * - the character is multi-byte and the next byte is different
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00005161 * - the character is two cells wide and the second cell differs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005162 */
5163 static int
5164char_needs_redraw(off_from, off_to, cols)
5165 int off_from;
5166 int off_to;
5167 int cols;
5168{
5169 if (cols > 0
5170 && ((ScreenLines[off_from] != ScreenLines[off_to]
5171 || ScreenAttrs[off_from] != ScreenAttrs[off_to])
5172
5173#ifdef FEAT_MBYTE
5174 || (enc_dbcs != 0
5175 && MB_BYTE2LEN(ScreenLines[off_from]) > 1
5176 && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
5177 ? ScreenLines2[off_from] != ScreenLines2[off_to]
5178 : (cols > 1 && ScreenLines[off_from + 1]
5179 != ScreenLines[off_to + 1])))
5180 || (enc_utf8
5181 && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
5182 || (ScreenLinesUC[off_from] != 0
Bram Moolenaar88f3d3a2008-06-21 12:14:30 +00005183 && comp_char_differs(off_from, off_to))
5184 || (cols > 1 && ScreenLines[off_from + 1]
5185 != ScreenLines[off_to + 1])))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005186#endif
5187 ))
5188 return TRUE;
5189 return FALSE;
5190}
5191
5192/*
5193 * Move one "cooked" screen line to the screen, but only the characters that
5194 * have actually changed. Handle insert/delete character.
5195 * "coloff" gives the first column on the screen for this line.
5196 * "endcol" gives the columns where valid characters are.
5197 * "clear_width" is the width of the window. It's > 0 if the rest of the line
5198 * needs to be cleared, negative otherwise.
5199 * "rlflag" is TRUE in a rightleft window:
5200 * When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
5201 * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
5202 */
5203 static void
5204screen_line(row, coloff, endcol, clear_width
5205#ifdef FEAT_RIGHTLEFT
5206 , rlflag
5207#endif
5208 )
5209 int row;
5210 int coloff;
5211 int endcol;
5212 int clear_width;
5213#ifdef FEAT_RIGHTLEFT
5214 int rlflag;
5215#endif
5216{
5217 unsigned off_from;
5218 unsigned off_to;
Bram Moolenaar367329b2007-08-30 11:53:22 +00005219#ifdef FEAT_MBYTE
5220 unsigned max_off_from;
5221 unsigned max_off_to;
5222#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005223 int col = 0;
5224#if defined(FEAT_GUI) || defined(UNIX) || defined(FEAT_VERTSPLIT)
5225 int hl;
5226#endif
5227 int force = FALSE; /* force update rest of the line */
5228 int redraw_this /* bool: does character need redraw? */
5229#ifdef FEAT_GUI
5230 = TRUE /* For GUI when while-loop empty */
5231#endif
5232 ;
5233 int redraw_next; /* redraw_this for next character */
5234#ifdef FEAT_MBYTE
5235 int clear_next = FALSE;
5236 int char_cells; /* 1: normal char */
5237 /* 2: occupies two display cells */
5238# define CHAR_CELLS char_cells
5239#else
5240# define CHAR_CELLS 1
5241#endif
5242
5243# ifdef FEAT_CLIPBOARD
5244 clip_may_clear_selection(row, row);
5245# endif
5246
5247 off_from = (unsigned)(current_ScreenLine - ScreenLines);
5248 off_to = LineOffset[row] + coloff;
Bram Moolenaar367329b2007-08-30 11:53:22 +00005249#ifdef FEAT_MBYTE
5250 max_off_from = off_from + screen_Columns;
5251 max_off_to = LineOffset[row] + screen_Columns;
5252#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253
5254#ifdef FEAT_RIGHTLEFT
5255 if (rlflag)
5256 {
5257 /* Clear rest first, because it's left of the text. */
5258 if (clear_width > 0)
5259 {
5260 while (col <= endcol && ScreenLines[off_to] == ' '
5261 && ScreenAttrs[off_to] == 0
5262# ifdef FEAT_MBYTE
5263 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
5264# endif
5265 )
5266 {
5267 ++off_to;
5268 ++col;
5269 }
5270 if (col <= endcol)
5271 screen_fill(row, row + 1, col + coloff,
5272 endcol + coloff + 1, ' ', ' ', 0);
5273 }
5274 col = endcol + 1;
5275 off_to = LineOffset[row] + col + coloff;
5276 off_from += col;
5277 endcol = (clear_width > 0 ? clear_width : -clear_width);
5278 }
5279#endif /* FEAT_RIGHTLEFT */
5280
5281 redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
5282
5283 while (col < endcol)
5284 {
5285#ifdef FEAT_MBYTE
5286 if (has_mbyte && (col + 1 < endcol))
Bram Moolenaar367329b2007-08-30 11:53:22 +00005287 char_cells = (*mb_off2cells)(off_from, max_off_from);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288 else
5289 char_cells = 1;
5290#endif
5291
5292 redraw_this = redraw_next;
5293 redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
5294 off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
5295
5296#ifdef FEAT_GUI
5297 /* If the next character was bold, then redraw the current character to
5298 * remove any pixels that might have spilt over into us. This only
5299 * happens in the GUI.
5300 */
5301 if (redraw_next && gui.in_use)
5302 {
5303 hl = ScreenAttrs[off_to + CHAR_CELLS];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005304 if (hl > HL_ALL)
5305 hl = syn_attr2attr(hl);
5306 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005307 redraw_this = TRUE;
5308 }
5309#endif
5310
5311 if (redraw_this)
5312 {
5313 /*
5314 * Special handling when 'xs' termcap flag set (hpterm):
5315 * Attributes for characters are stored at the position where the
5316 * cursor is when writing the highlighting code. The
5317 * start-highlighting code must be written with the cursor on the
5318 * first highlighted character. The stop-highlighting code must
5319 * be written with the cursor just after the last highlighted
5320 * character.
5321 * Overwriting a character doesn't remove it's highlighting. Need
5322 * to clear the rest of the line, and force redrawing it
5323 * completely.
5324 */
5325 if ( p_wiv
5326 && !force
5327#ifdef FEAT_GUI
5328 && !gui.in_use
5329#endif
5330 && ScreenAttrs[off_to] != 0
5331 && ScreenAttrs[off_from] != ScreenAttrs[off_to])
5332 {
5333 /*
5334 * Need to remove highlighting attributes here.
5335 */
5336 windgoto(row, col + coloff);
5337 out_str(T_CE); /* clear rest of this screen line */
5338 screen_start(); /* don't know where cursor is now */
5339 force = TRUE; /* force redraw of rest of the line */
5340 redraw_next = TRUE; /* or else next char would miss out */
5341
5342 /*
5343 * If the previous character was highlighted, need to stop
5344 * highlighting at this character.
5345 */
5346 if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
5347 {
5348 screen_attr = ScreenAttrs[off_to - 1];
5349 term_windgoto(row, col + coloff);
5350 screen_stop_highlight();
5351 }
5352 else
5353 screen_attr = 0; /* highlighting has stopped */
5354 }
5355#ifdef FEAT_MBYTE
5356 if (enc_dbcs != 0)
5357 {
5358 /* Check if overwriting a double-byte with a single-byte or
5359 * the other way around requires another character to be
5360 * redrawn. For UTF-8 this isn't needed, because comparing
5361 * ScreenLinesUC[] is sufficient. */
5362 if (char_cells == 1
5363 && col + 1 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00005364 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005365 {
5366 /* Writing a single-cell character over a double-cell
5367 * character: need to redraw the next cell. */
5368 ScreenLines[off_to + 1] = 0;
5369 redraw_next = TRUE;
5370 }
5371 else if (char_cells == 2
5372 && col + 2 < endcol
Bram Moolenaar367329b2007-08-30 11:53:22 +00005373 && (*mb_off2cells)(off_to, max_off_to) == 1
5374 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005375 {
5376 /* Writing the second half of a double-cell character over
5377 * a double-cell character: need to redraw the second
5378 * cell. */
5379 ScreenLines[off_to + 2] = 0;
5380 redraw_next = TRUE;
5381 }
5382
5383 if (enc_dbcs == DBCS_JPNU)
5384 ScreenLines2[off_to] = ScreenLines2[off_from];
5385 }
5386 /* When writing a single-width character over a double-width
5387 * character and at the end of the redrawn text, need to clear out
5388 * the right halve of the old character.
5389 * Also required when writing the right halve of a double-width
5390 * char over the left halve of an existing one. */
5391 if (has_mbyte && col + char_cells == endcol
5392 && ((char_cells == 1
Bram Moolenaar367329b2007-08-30 11:53:22 +00005393 && (*mb_off2cells)(off_to, max_off_to) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005394 || (char_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00005395 && (*mb_off2cells)(off_to, max_off_to) == 1
5396 && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397 clear_next = TRUE;
5398#endif
5399
5400 ScreenLines[off_to] = ScreenLines[off_from];
5401#ifdef FEAT_MBYTE
5402 if (enc_utf8)
5403 {
5404 ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
5405 if (ScreenLinesUC[off_from] != 0)
5406 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005407 int i;
5408
5409 for (i = 0; i < Screen_mco; ++i)
5410 ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005411 }
5412 }
5413 if (char_cells == 2)
5414 ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
5415#endif
5416
5417#if defined(FEAT_GUI) || defined(UNIX)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00005418 /* The bold trick makes a single column of pixels appear in the
5419 * next character. When a bold character is removed, the next
Bram Moolenaar071d4272004-06-13 20:20:40 +00005420 * character should be redrawn too. This happens for our own GUI
5421 * and for some xterms. */
5422 if (
5423# ifdef FEAT_GUI
5424 gui.in_use
5425# endif
5426# if defined(FEAT_GUI) && defined(UNIX)
5427 ||
5428# endif
5429# ifdef UNIX
5430 term_is_xterm
5431# endif
5432 )
5433 {
5434 hl = ScreenAttrs[off_to];
Bram Moolenaar600dddc2006-03-12 22:05:10 +00005435 if (hl > HL_ALL)
5436 hl = syn_attr2attr(hl);
5437 if (hl & HL_BOLD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005438 redraw_next = TRUE;
5439 }
5440#endif
5441 ScreenAttrs[off_to] = ScreenAttrs[off_from];
5442#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005443 /* For simplicity set the attributes of second half of a
5444 * double-wide character equal to the first half. */
5445 if (char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005447
5448 if (enc_dbcs != 0 && char_cells == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005449 screen_char_2(off_to, row, col + coloff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005450 else
5451#endif
5452 screen_char(off_to, row, col + coloff);
5453 }
5454 else if ( p_wiv
5455#ifdef FEAT_GUI
5456 && !gui.in_use
5457#endif
5458 && col + coloff > 0)
5459 {
5460 if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
5461 {
5462 /*
5463 * Don't output stop-highlight when moving the cursor, it will
5464 * stop the highlighting when it should continue.
5465 */
5466 screen_attr = 0;
5467 }
5468 else if (screen_attr != 0)
5469 screen_stop_highlight();
5470 }
5471
5472 off_to += CHAR_CELLS;
5473 off_from += CHAR_CELLS;
5474 col += CHAR_CELLS;
5475 }
5476
5477#ifdef FEAT_MBYTE
5478 if (clear_next)
5479 {
5480 /* Clear the second half of a double-wide character of which the left
5481 * half was overwritten with a single-wide character. */
5482 ScreenLines[off_to] = ' ';
5483 if (enc_utf8)
5484 ScreenLinesUC[off_to] = 0;
5485 screen_char(off_to, row, col + coloff);
5486 }
5487#endif
5488
5489 if (clear_width > 0
5490#ifdef FEAT_RIGHTLEFT
5491 && !rlflag
5492#endif
5493 )
5494 {
5495#ifdef FEAT_GUI
5496 int startCol = col;
5497#endif
5498
5499 /* blank out the rest of the line */
5500 while (col < clear_width && ScreenLines[off_to] == ' '
5501 && ScreenAttrs[off_to] == 0
5502#ifdef FEAT_MBYTE
5503 && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
5504#endif
5505 )
5506 {
5507 ++off_to;
5508 ++col;
5509 }
5510 if (col < clear_width)
5511 {
5512#ifdef FEAT_GUI
5513 /*
5514 * In the GUI, clearing the rest of the line may leave pixels
5515 * behind if the first character cleared was bold. Some bold
5516 * fonts spill over the left. In this case we redraw the previous
5517 * character too. If we didn't skip any blanks above, then we
5518 * only redraw if the character wasn't already redrawn anyway.
5519 */
Bram Moolenaar9c697322006-10-09 20:11:17 +00005520 if (gui.in_use && (col > startCol || !redraw_this))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005521 {
5522 hl = ScreenAttrs[off_to];
5523 if (hl > HL_ALL || (hl & HL_BOLD))
Bram Moolenaar9c697322006-10-09 20:11:17 +00005524 {
5525 int prev_cells = 1;
5526# ifdef FEAT_MBYTE
5527 if (enc_utf8)
5528 /* for utf-8, ScreenLines[char_offset + 1] == 0 means
5529 * that its width is 2. */
5530 prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
5531 else if (enc_dbcs != 0)
5532 {
5533 /* find previous character by counting from first
5534 * column and get its width. */
5535 unsigned off = LineOffset[row];
Bram Moolenaar367329b2007-08-30 11:53:22 +00005536 unsigned max_off = LineOffset[row] + screen_Columns;
Bram Moolenaar9c697322006-10-09 20:11:17 +00005537
5538 while (off < off_to)
5539 {
Bram Moolenaar367329b2007-08-30 11:53:22 +00005540 prev_cells = (*mb_off2cells)(off, max_off);
Bram Moolenaar9c697322006-10-09 20:11:17 +00005541 off += prev_cells;
5542 }
5543 }
5544
5545 if (enc_dbcs != 0 && prev_cells > 1)
5546 screen_char_2(off_to - prev_cells, row,
5547 col + coloff - prev_cells);
5548 else
5549# endif
5550 screen_char(off_to - prev_cells, row,
5551 col + coloff - prev_cells);
5552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005553 }
5554#endif
5555 screen_fill(row, row + 1, col + coloff, clear_width + coloff,
5556 ' ', ' ', 0);
5557#ifdef FEAT_VERTSPLIT
5558 off_to += clear_width - col;
5559 col = clear_width;
5560#endif
5561 }
5562 }
5563
5564 if (clear_width > 0)
5565 {
5566#ifdef FEAT_VERTSPLIT
5567 /* For a window that's left of another, draw the separator char. */
5568 if (col + coloff < Columns)
5569 {
5570 int c;
5571
5572 c = fillchar_vsep(&hl);
5573 if (ScreenLines[off_to] != c
5574# ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005575 || (enc_utf8 && (int)ScreenLinesUC[off_to]
5576 != (c >= 0x80 ? c : 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005577# endif
5578 || ScreenAttrs[off_to] != hl)
5579 {
5580 ScreenLines[off_to] = c;
5581 ScreenAttrs[off_to] = hl;
5582# ifdef FEAT_MBYTE
5583 if (enc_utf8)
5584 {
5585 if (c >= 0x80)
5586 {
5587 ScreenLinesUC[off_to] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00005588 ScreenLinesC[0][off_to] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005589 }
5590 else
5591 ScreenLinesUC[off_to] = 0;
5592 }
5593# endif
5594 screen_char(off_to, row, col + coloff);
5595 }
5596 }
5597 else
5598#endif
5599 LineWraps[row] = FALSE;
5600 }
5601}
5602
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005603#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005604/*
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005605 * Mirror text "str" for right-left displaying.
5606 * Only works for single-byte characters (e.g., numbers).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005607 */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005608 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00005609rl_mirror(str)
5610 char_u *str;
5611{
5612 char_u *p1, *p2;
5613 int t;
5614
5615 for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
5616 {
5617 t = *p1;
5618 *p1 = *p2;
5619 *p2 = t;
5620 }
5621}
5622#endif
5623
5624#if defined(FEAT_WINDOWS) || defined(PROTO)
5625/*
5626 * mark all status lines for redraw; used after first :cd
5627 */
5628 void
5629status_redraw_all()
5630{
5631 win_T *wp;
5632
5633 for (wp = firstwin; wp; wp = wp->w_next)
5634 if (wp->w_status_height)
5635 {
5636 wp->w_redr_status = TRUE;
5637 redraw_later(VALID);
5638 }
5639}
5640
5641/*
5642 * mark all status lines of the current buffer for redraw
5643 */
5644 void
5645status_redraw_curbuf()
5646{
5647 win_T *wp;
5648
5649 for (wp = firstwin; wp; wp = wp->w_next)
5650 if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
5651 {
5652 wp->w_redr_status = TRUE;
5653 redraw_later(VALID);
5654 }
5655}
5656
5657/*
5658 * Redraw all status lines that need to be redrawn.
5659 */
5660 void
5661redraw_statuslines()
5662{
5663 win_T *wp;
5664
5665 for (wp = firstwin; wp; wp = wp->w_next)
5666 if (wp->w_redr_status)
5667 win_redr_status(wp);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00005668 if (redraw_tabline)
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00005669 draw_tabline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670}
5671#endif
5672
5673#if (defined(FEAT_WILDMENU) && defined(FEAT_VERTSPLIT)) || defined(PROTO)
5674/*
5675 * Redraw all status lines at the bottom of frame "frp".
5676 */
5677 void
5678win_redraw_last_status(frp)
5679 frame_T *frp;
5680{
5681 if (frp->fr_layout == FR_LEAF)
5682 frp->fr_win->w_redr_status = TRUE;
5683 else if (frp->fr_layout == FR_ROW)
5684 {
5685 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
5686 win_redraw_last_status(frp);
5687 }
5688 else /* frp->fr_layout == FR_COL */
5689 {
5690 frp = frp->fr_child;
5691 while (frp->fr_next != NULL)
5692 frp = frp->fr_next;
5693 win_redraw_last_status(frp);
5694 }
5695}
5696#endif
5697
5698#ifdef FEAT_VERTSPLIT
5699/*
5700 * Draw the verticap separator right of window "wp" starting with line "row".
5701 */
5702 static void
5703draw_vsep_win(wp, row)
5704 win_T *wp;
5705 int row;
5706{
5707 int hl;
5708 int c;
5709
5710 if (wp->w_vsep_width)
5711 {
5712 /* draw the vertical separator right of this window */
5713 c = fillchar_vsep(&hl);
5714 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
5715 W_ENDCOL(wp), W_ENDCOL(wp) + 1,
5716 c, ' ', hl);
5717 }
5718}
5719#endif
5720
5721#ifdef FEAT_WILDMENU
5722static int status_match_len __ARGS((expand_T *xp, char_u *s));
Bram Moolenaar35c54e52005-05-20 21:25:31 +00005723static int skip_status_match_char __ARGS((expand_T *xp, char_u *s));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724
5725/*
Bram Moolenaar367329b2007-08-30 11:53:22 +00005726 * Get the length of an item as it will be shown in the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005727 */
5728 static int
5729status_match_len(xp, s)
5730 expand_T *xp;
5731 char_u *s;
5732{
5733 int len = 0;
5734
5735#ifdef FEAT_MENU
5736 int emenu = (xp->xp_context == EXPAND_MENUS
5737 || xp->xp_context == EXPAND_MENUNAMES);
5738
5739 /* Check for menu separators - replace with '|'. */
5740 if (emenu && menu_is_separator(s))
5741 return 1;
5742#endif
5743
5744 while (*s != NUL)
5745 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00005746 s += skip_status_match_char(xp, s);
Bram Moolenaar81695252004-12-29 20:58:21 +00005747 len += ptr2cells(s);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005748 mb_ptr_adv(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005749 }
5750
5751 return len;
5752}
5753
5754/*
Bram Moolenaar7693ec62008-07-24 18:29:37 +00005755 * Return the number of characters that should be skipped in a status match.
Bram Moolenaar35c54e52005-05-20 21:25:31 +00005756 * These are backslashes used for escaping. Do show backslashes in help tags.
5757 */
5758 static int
5759skip_status_match_char(xp, s)
5760 expand_T *xp;
5761 char_u *s;
5762{
Bram Moolenaar7693ec62008-07-24 18:29:37 +00005763 if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
Bram Moolenaar35c54e52005-05-20 21:25:31 +00005764#ifdef FEAT_MENU
5765 || ((xp->xp_context == EXPAND_MENUS
5766 || xp->xp_context == EXPAND_MENUNAMES)
5767 && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
5768#endif
Bram Moolenaar7693ec62008-07-24 18:29:37 +00005769 )
5770 {
5771#ifndef BACKSLASH_IN_FILENAME
5772 if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
5773 return 2;
5774#endif
5775 return 1;
5776 }
5777 return 0;
Bram Moolenaar35c54e52005-05-20 21:25:31 +00005778}
5779
5780/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781 * Show wildchar matches in the status line.
5782 * Show at least the "match" item.
5783 * We start at item 'first_match' in the list and show all matches that fit.
5784 *
5785 * If inversion is possible we use it. Else '=' characters are used.
5786 */
5787 void
5788win_redr_status_matches(xp, num_matches, matches, match, showtail)
5789 expand_T *xp;
5790 int num_matches;
5791 char_u **matches; /* list of matches */
5792 int match;
5793 int showtail;
5794{
5795#define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
5796 int row;
5797 char_u *buf;
5798 int len;
Bram Moolenaar367329b2007-08-30 11:53:22 +00005799 int clen; /* length in screen cells */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005800 int fillchar;
5801 int attr;
5802 int i;
5803 int highlight = TRUE;
5804 char_u *selstart = NULL;
5805 int selstart_col = 0;
5806 char_u *selend = NULL;
5807 static int first_match = 0;
5808 int add_left = FALSE;
5809 char_u *s;
5810#ifdef FEAT_MENU
5811 int emenu;
5812#endif
5813#if defined(FEAT_MBYTE) || defined(FEAT_MENU)
5814 int l;
5815#endif
5816
5817 if (matches == NULL) /* interrupted completion? */
5818 return;
5819
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005820#ifdef FEAT_MBYTE
5821 if (has_mbyte)
5822 buf = alloc((unsigned)Columns * MB_MAXBYTES + 1);
5823 else
5824#endif
5825 buf = alloc((unsigned)Columns + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826 if (buf == NULL)
5827 return;
5828
5829 if (match == -1) /* don't show match but original text */
5830 {
5831 match = 0;
5832 highlight = FALSE;
5833 }
5834 /* count 1 for the ending ">" */
5835 clen = status_match_len(xp, L_MATCH(match)) + 3;
5836 if (match == 0)
5837 first_match = 0;
5838 else if (match < first_match)
5839 {
5840 /* jumping left, as far as we can go */
5841 first_match = match;
5842 add_left = TRUE;
5843 }
5844 else
5845 {
5846 /* check if match fits on the screen */
5847 for (i = first_match; i < match; ++i)
5848 clen += status_match_len(xp, L_MATCH(i)) + 2;
5849 if (first_match > 0)
5850 clen += 2;
5851 /* jumping right, put match at the left */
5852 if ((long)clen > Columns)
5853 {
5854 first_match = match;
5855 /* if showing the last match, we can add some on the left */
5856 clen = 2;
5857 for (i = match; i < num_matches; ++i)
5858 {
5859 clen += status_match_len(xp, L_MATCH(i)) + 2;
5860 if ((long)clen >= Columns)
5861 break;
5862 }
5863 if (i == num_matches)
5864 add_left = TRUE;
5865 }
5866 }
5867 if (add_left)
5868 while (first_match > 0)
5869 {
5870 clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
5871 if ((long)clen >= Columns)
5872 break;
5873 --first_match;
5874 }
5875
5876 fillchar = fillchar_status(&attr, TRUE);
5877
5878 if (first_match == 0)
5879 {
5880 *buf = NUL;
5881 len = 0;
5882 }
5883 else
5884 {
5885 STRCPY(buf, "< ");
5886 len = 2;
5887 }
5888 clen = len;
5889
5890 i = first_match;
5891 while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
5892 {
5893 if (i == match)
5894 {
5895 selstart = buf + len;
5896 selstart_col = clen;
5897 }
5898
5899 s = L_MATCH(i);
5900 /* Check for menu separators - replace with '|' */
5901#ifdef FEAT_MENU
5902 emenu = (xp->xp_context == EXPAND_MENUS
5903 || xp->xp_context == EXPAND_MENUNAMES);
5904 if (emenu && menu_is_separator(s))
5905 {
5906 STRCPY(buf + len, transchar('|'));
5907 l = (int)STRLEN(buf + len);
5908 len += l;
5909 clen += l;
5910 }
5911 else
5912#endif
5913 for ( ; *s != NUL; ++s)
5914 {
Bram Moolenaar7693ec62008-07-24 18:29:37 +00005915 s += skip_status_match_char(xp, s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005916 clen += ptr2cells(s);
5917#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005918 if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919 {
5920 STRNCPY(buf + len, s, l);
5921 s += l - 1;
5922 len += l;
5923 }
5924 else
5925#endif
5926 {
5927 STRCPY(buf + len, transchar_byte(*s));
5928 len += (int)STRLEN(buf + len);
5929 }
5930 }
5931 if (i == match)
5932 selend = buf + len;
5933
5934 *(buf + len++) = ' ';
5935 *(buf + len++) = ' ';
5936 clen += 2;
5937 if (++i == num_matches)
5938 break;
5939 }
5940
5941 if (i != num_matches)
5942 {
5943 *(buf + len++) = '>';
5944 ++clen;
5945 }
5946
5947 buf[len] = NUL;
5948
5949 row = cmdline_row - 1;
5950 if (row >= 0)
5951 {
5952 if (wild_menu_showing == 0)
5953 {
5954 if (msg_scrolled > 0)
5955 {
5956 /* Put the wildmenu just above the command line. If there is
5957 * no room, scroll the screen one line up. */
5958 if (cmdline_row == Rows - 1)
5959 {
5960 screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
5961 ++msg_scrolled;
5962 }
5963 else
5964 {
5965 ++cmdline_row;
5966 ++row;
5967 }
5968 wild_menu_showing = WM_SCROLLED;
5969 }
5970 else
5971 {
5972 /* Create status line if needed by setting 'laststatus' to 2.
5973 * Set 'winminheight' to zero to avoid that the window is
5974 * resized. */
5975 if (lastwin->w_status_height == 0)
5976 {
5977 save_p_ls = p_ls;
5978 save_p_wmh = p_wmh;
5979 p_ls = 2;
5980 p_wmh = 0;
5981 last_status(FALSE);
5982 }
5983 wild_menu_showing = WM_SHOWN;
5984 }
5985 }
5986
5987 screen_puts(buf, row, 0, attr);
5988 if (selstart != NULL && highlight)
5989 {
5990 *selend = NUL;
5991 screen_puts(selstart, row, selstart_col, hl_attr(HLF_WM));
5992 }
5993
5994 screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
5995 }
5996
5997#ifdef FEAT_VERTSPLIT
5998 win_redraw_last_status(topframe);
5999#else
6000 lastwin->w_redr_status = TRUE;
6001#endif
6002 vim_free(buf);
6003}
6004#endif
6005
6006#if defined(FEAT_WINDOWS) || defined(PROTO)
6007/*
6008 * Redraw the status line of window wp.
6009 *
6010 * If inversion is possible we use it. Else '=' characters are used.
6011 */
6012 void
6013win_redr_status(wp)
6014 win_T *wp;
6015{
6016 int row;
6017 char_u *p;
6018 int len;
6019 int fillchar;
6020 int attr;
6021 int this_ru_col;
Bram Moolenaaradb09c22009-06-16 15:22:12 +00006022 static int busy = FALSE;
6023
6024 /* It's possible to get here recursively when 'statusline' (indirectly)
6025 * invokes ":redrawstatus". Simply ignore the call then. */
6026 if (busy)
6027 return;
6028 busy = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006029
6030 wp->w_redr_status = FALSE;
6031 if (wp->w_status_height == 0)
6032 {
6033 /* no status line, can only be last window */
6034 redraw_cmdline = TRUE;
6035 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00006036 else if (!redrawing()
6037#ifdef FEAT_INS_EXPAND
6038 /* don't update status line when popup menu is visible and may be
6039 * drawn over it */
6040 || pum_visible()
6041#endif
6042 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006043 {
6044 /* Don't redraw right now, do it later. */
6045 wp->w_redr_status = TRUE;
6046 }
6047#ifdef FEAT_STL_OPT
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006048 else if (*p_stl != NUL || *wp->w_p_stl != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006049 {
6050 /* redraw custom status line */
Bram Moolenaar362f3562009-11-03 16:20:34 +00006051 redraw_custom_statusline(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006052 }
6053#endif
6054 else
6055 {
6056 fillchar = fillchar_status(&attr, wp == curwin);
6057
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006058 get_trans_bufname(wp->w_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059 p = NameBuff;
6060 len = (int)STRLEN(p);
6061
6062 if (wp->w_buffer->b_help
6063#ifdef FEAT_QUICKFIX
6064 || wp->w_p_pvw
6065#endif
6066 || bufIsChanged(wp->w_buffer)
6067 || wp->w_buffer->b_p_ro)
6068 *(p + len++) = ' ';
6069 if (wp->w_buffer->b_help)
6070 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +00006071 STRCPY(p + len, _("[Help]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072 len += (int)STRLEN(p + len);
6073 }
6074#ifdef FEAT_QUICKFIX
6075 if (wp->w_p_pvw)
6076 {
6077 STRCPY(p + len, _("[Preview]"));
6078 len += (int)STRLEN(p + len);
6079 }
6080#endif
6081 if (bufIsChanged(wp->w_buffer))
6082 {
6083 STRCPY(p + len, "[+]");
6084 len += 3;
6085 }
6086 if (wp->w_buffer->b_p_ro)
6087 {
6088 STRCPY(p + len, "[RO]");
6089 len += 4;
6090 }
6091
6092#ifndef FEAT_VERTSPLIT
6093 this_ru_col = ru_col;
6094 if (this_ru_col < (Columns + 1) / 2)
6095 this_ru_col = (Columns + 1) / 2;
6096#else
6097 this_ru_col = ru_col - (Columns - W_WIDTH(wp));
6098 if (this_ru_col < (W_WIDTH(wp) + 1) / 2)
6099 this_ru_col = (W_WIDTH(wp) + 1) / 2;
6100 if (this_ru_col <= 1)
6101 {
6102 p = (char_u *)"<"; /* No room for file name! */
6103 len = 1;
6104 }
6105 else
6106#endif
6107#ifdef FEAT_MBYTE
6108 if (has_mbyte)
6109 {
6110 int clen = 0, i;
6111
6112 /* Count total number of display cells. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006113 for (i = 0; p[i] != NUL; i += (*mb_ptr2len)(p + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006114 clen += (*mb_ptr2cells)(p + i);
6115 /* Find first character that will fit.
6116 * Going from start to end is much faster for DBCS. */
6117 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006118 i += (*mb_ptr2len)(p + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006119 clen -= (*mb_ptr2cells)(p + i);
6120 len = clen;
6121 if (i > 0)
6122 {
6123 p = p + i - 1;
6124 *p = '<';
6125 ++len;
6126 }
6127
6128 }
6129 else
6130#endif
6131 if (len > this_ru_col - 1)
6132 {
6133 p += len - (this_ru_col - 1);
6134 *p = '<';
6135 len = this_ru_col - 1;
6136 }
6137
6138 row = W_WINROW(wp) + wp->w_height;
6139 screen_puts(p, row, W_WINCOL(wp), attr);
6140 screen_fill(row, row + 1, len + W_WINCOL(wp),
6141 this_ru_col + W_WINCOL(wp), fillchar, fillchar, attr);
6142
6143 if (get_keymap_str(wp, NameBuff, MAXPATHL)
6144 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
6145 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
6146 - 1 + W_WINCOL(wp)), attr);
6147
6148#ifdef FEAT_CMDL_INFO
6149 win_redr_ruler(wp, TRUE);
6150#endif
6151 }
6152
6153#ifdef FEAT_VERTSPLIT
6154 /*
6155 * May need to draw the character below the vertical separator.
6156 */
6157 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
6158 {
6159 if (stl_connected(wp))
6160 fillchar = fillchar_status(&attr, wp == curwin);
6161 else
6162 fillchar = fillchar_vsep(&attr);
6163 screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
6164 attr);
6165 }
6166#endif
Bram Moolenaaradb09c22009-06-16 15:22:12 +00006167 busy = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006168}
6169
Bram Moolenaar238a5642006-02-21 22:12:05 +00006170#ifdef FEAT_STL_OPT
6171/*
6172 * Redraw the status line according to 'statusline' and take care of any
6173 * errors encountered.
6174 */
6175 static void
Bram Moolenaar362f3562009-11-03 16:20:34 +00006176redraw_custom_statusline(wp)
Bram Moolenaar238a5642006-02-21 22:12:05 +00006177 win_T *wp;
6178{
Bram Moolenaar362f3562009-11-03 16:20:34 +00006179 static int entered = FALSE;
6180 int save_called_emsg = called_emsg;
6181
6182 /* When called recursively return. This can happen when the statusline
6183 * contains an expression that triggers a redraw. */
6184 if (entered)
6185 return;
6186 entered = TRUE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00006187
6188 called_emsg = FALSE;
6189 win_redr_custom(wp, FALSE);
6190 if (called_emsg)
Bram Moolenaar362f3562009-11-03 16:20:34 +00006191 {
6192 /* When there is an error disable the statusline, otherwise the
6193 * display is messed up with errors and a redraw triggers the problem
6194 * again and again. */
Bram Moolenaar238a5642006-02-21 22:12:05 +00006195 set_string_option_direct((char_u *)"statusline", -1,
6196 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006197 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
Bram Moolenaar362f3562009-11-03 16:20:34 +00006198 }
Bram Moolenaar238a5642006-02-21 22:12:05 +00006199 called_emsg |= save_called_emsg;
Bram Moolenaar362f3562009-11-03 16:20:34 +00006200 entered = FALSE;
Bram Moolenaar238a5642006-02-21 22:12:05 +00006201}
6202#endif
6203
Bram Moolenaar071d4272004-06-13 20:20:40 +00006204# ifdef FEAT_VERTSPLIT
6205/*
6206 * Return TRUE if the status line of window "wp" is connected to the status
6207 * line of the window right of it. If not, then it's a vertical separator.
6208 * Only call if (wp->w_vsep_width != 0).
6209 */
6210 int
6211stl_connected(wp)
6212 win_T *wp;
6213{
6214 frame_T *fr;
6215
6216 fr = wp->w_frame;
6217 while (fr->fr_parent != NULL)
6218 {
6219 if (fr->fr_parent->fr_layout == FR_COL)
6220 {
6221 if (fr->fr_next != NULL)
6222 break;
6223 }
6224 else
6225 {
6226 if (fr->fr_next != NULL)
6227 return TRUE;
6228 }
6229 fr = fr->fr_parent;
6230 }
6231 return FALSE;
6232}
6233# endif
6234
6235#endif /* FEAT_WINDOWS */
6236
6237#if defined(FEAT_WINDOWS) || defined(FEAT_STL_OPT) || defined(PROTO)
6238/*
6239 * Get the value to show for the language mappings, active 'keymap'.
6240 */
6241 int
6242get_keymap_str(wp, buf, len)
6243 win_T *wp;
6244 char_u *buf; /* buffer for the result */
6245 int len; /* length of buffer */
6246{
6247 char_u *p;
6248
6249 if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
6250 return FALSE;
6251
6252 {
6253#ifdef FEAT_EVAL
6254 buf_T *old_curbuf = curbuf;
6255 win_T *old_curwin = curwin;
6256 char_u *s;
6257
6258 curbuf = wp->w_buffer;
6259 curwin = wp;
6260 STRCPY(buf, "b:keymap_name"); /* must be writable */
6261 ++emsg_skip;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006262 s = p = eval_to_string(buf, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006263 --emsg_skip;
6264 curbuf = old_curbuf;
6265 curwin = old_curwin;
6266 if (p == NULL || *p == NUL)
6267#endif
6268 {
6269#ifdef FEAT_KEYMAP
6270 if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
6271 p = wp->w_buffer->b_p_keymap;
6272 else
6273#endif
6274 p = (char_u *)"lang";
6275 }
6276 if ((int)(STRLEN(p) + 3) < len)
6277 sprintf((char *)buf, "<%s>", p);
6278 else
6279 buf[0] = NUL;
6280#ifdef FEAT_EVAL
6281 vim_free(s);
6282#endif
6283 }
6284 return buf[0] != NUL;
6285}
6286#endif
6287
6288#if defined(FEAT_STL_OPT) || defined(PROTO)
6289/*
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006290 * Redraw the status line or ruler of window "wp".
6291 * When "wp" is NULL redraw the tab pages line from 'tabline'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006292 */
6293 static void
Bram Moolenaar9372a112005-12-06 19:59:18 +00006294win_redr_custom(wp, draw_ruler)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006295 win_T *wp;
Bram Moolenaar9372a112005-12-06 19:59:18 +00006296 int draw_ruler; /* TRUE or FALSE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006297{
6298 int attr;
6299 int curattr;
6300 int row;
6301 int col = 0;
6302 int maxwidth;
6303 int width;
6304 int n;
6305 int len;
6306 int fillchar;
6307 char_u buf[MAXPATHL];
Bram Moolenaar362f3562009-11-03 16:20:34 +00006308 char_u *stl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309 char_u *p;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006310 struct stl_hlrec hltab[STL_MAX_ITEM];
6311 struct stl_hlrec tabtab[STL_MAX_ITEM];
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006312 int use_sandbox = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006313
6314 /* setup environment for the task at hand */
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006315 if (wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006316 {
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006317 /* Use 'tabline'. Always at the first line of the screen. */
Bram Moolenaar362f3562009-11-03 16:20:34 +00006318 stl = p_tal;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006319 row = 0;
Bram Moolenaar65c923a2006-03-03 22:56:30 +00006320 fillchar = ' ';
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006321 attr = hl_attr(HLF_TPF);
6322 maxwidth = Columns;
6323# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006324 use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006325# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006326 }
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006327 else
6328 {
6329 row = W_WINROW(wp) + wp->w_height;
6330 fillchar = fillchar_status(&attr, wp == curwin);
6331 maxwidth = W_WIDTH(wp);
6332
6333 if (draw_ruler)
6334 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00006335 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006336 /* advance past any leading group spec - implicit in ru_col */
Bram Moolenaar362f3562009-11-03 16:20:34 +00006337 if (*stl == '%')
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006338 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00006339 if (*++stl == '-')
6340 stl++;
6341 if (atoi((char *)stl))
6342 while (VIM_ISDIGIT(*stl))
6343 stl++;
6344 if (*stl++ != '(')
6345 stl = p_ruf;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006346 }
6347#ifdef FEAT_VERTSPLIT
6348 col = ru_col - (Columns - W_WIDTH(wp));
6349 if (col < (W_WIDTH(wp) + 1) / 2)
6350 col = (W_WIDTH(wp) + 1) / 2;
6351#else
6352 col = ru_col;
6353 if (col > (Columns + 1) / 2)
6354 col = (Columns + 1) / 2;
6355#endif
6356 maxwidth = W_WIDTH(wp) - col;
6357#ifdef FEAT_WINDOWS
6358 if (!wp->w_status_height)
6359#endif
6360 {
6361 row = Rows - 1;
6362 --maxwidth; /* writing in last column may cause scrolling */
6363 fillchar = ' ';
6364 attr = 0;
6365 }
6366
6367# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006368 use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006369# endif
6370 }
6371 else
6372 {
6373 if (*wp->w_p_stl != NUL)
Bram Moolenaar362f3562009-11-03 16:20:34 +00006374 stl = wp->w_p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006375 else
Bram Moolenaar362f3562009-11-03 16:20:34 +00006376 stl = p_stl;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006377# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006378 use_sandbox = was_set_insecurely((char_u *)"statusline",
6379 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006380# endif
6381 }
6382
6383#ifdef FEAT_VERTSPLIT
6384 col += W_WINCOL(wp);
6385#endif
6386 }
6387
Bram Moolenaar071d4272004-06-13 20:20:40 +00006388 if (maxwidth <= 0)
6389 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390
Bram Moolenaar362f3562009-11-03 16:20:34 +00006391 /* Make a copy, because the statusline may include a function call that
6392 * might change the option value and free the memory. */
6393 stl = vim_strsave(stl);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00006394 width = build_stl_str_hl(wp == NULL ? curwin : wp,
6395 buf, sizeof(buf),
Bram Moolenaar362f3562009-11-03 16:20:34 +00006396 stl, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006397 fillchar, maxwidth, hltab, tabtab);
Bram Moolenaar362f3562009-11-03 16:20:34 +00006398 vim_free(stl);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006399 len = (int)STRLEN(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006400
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006401 while (width < maxwidth && len < (int)sizeof(buf) - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006402 {
6403#ifdef FEAT_MBYTE
6404 len += (*mb_char2bytes)(fillchar, buf + len);
6405#else
6406 buf[len++] = fillchar;
6407#endif
6408 ++width;
6409 }
6410 buf[len] = NUL;
6411
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006412 /*
6413 * Draw each snippet with the specified highlighting.
6414 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006415 curattr = attr;
6416 p = buf;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006417 for (n = 0; hltab[n].start != NULL; n++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006418 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006419 len = (int)(hltab[n].start - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006420 screen_puts_len(p, len, row, col, curattr);
6421 col += vim_strnsize(p, len);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006422 p = hltab[n].start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006423
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006424 if (hltab[n].userhl == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006425 curattr = attr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006426 else if (hltab[n].userhl < 0)
6427 curattr = syn_id2attr(-hltab[n].userhl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006428#ifdef FEAT_WINDOWS
Bram Moolenaar238a5642006-02-21 22:12:05 +00006429 else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006430 curattr = highlight_stlnc[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431#endif
6432 else
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006433 curattr = highlight_user[hltab[n].userhl - 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006434 }
6435 screen_puts(p, row, col, curattr);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006436
6437 if (wp == NULL)
6438 {
6439 /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */
6440 col = 0;
6441 len = 0;
6442 p = buf;
6443 fillchar = 0;
6444 for (n = 0; tabtab[n].start != NULL; n++)
6445 {
6446 len += vim_strnsize(p, (int)(tabtab[n].start - p));
6447 while (col < len)
6448 TabPageIdxs[col++] = fillchar;
6449 p = tabtab[n].start;
6450 fillchar = tabtab[n].userhl;
6451 }
6452 while (col < Columns)
6453 TabPageIdxs[col++] = fillchar;
6454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006455}
6456
6457#endif /* FEAT_STL_OPT */
6458
6459/*
6460 * Output a single character directly to the screen and update ScreenLines.
6461 */
6462 void
6463screen_putchar(c, row, col, attr)
6464 int c;
6465 int row, col;
6466 int attr;
6467{
6468#ifdef FEAT_MBYTE
6469 char_u buf[MB_MAXBYTES + 1];
6470
6471 buf[(*mb_char2bytes)(c, buf)] = NUL;
6472#else
6473 char_u buf[2];
6474
6475 buf[0] = c;
6476 buf[1] = NUL;
6477#endif
6478 screen_puts(buf, row, col, attr);
6479}
6480
6481/*
6482 * Get a single character directly from ScreenLines into "bytes[]".
6483 * Also return its attribute in *attrp;
6484 */
6485 void
6486screen_getbytes(row, col, bytes, attrp)
6487 int row, col;
6488 char_u *bytes;
6489 int *attrp;
6490{
6491 unsigned off;
6492
6493 /* safety check */
6494 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
6495 {
6496 off = LineOffset[row] + col;
6497 *attrp = ScreenAttrs[off];
6498 bytes[0] = ScreenLines[off];
6499 bytes[1] = NUL;
6500
6501#ifdef FEAT_MBYTE
6502 if (enc_utf8 && ScreenLinesUC[off] != 0)
6503 bytes[utfc_char2bytes(off, bytes)] = NUL;
6504 else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
6505 {
6506 bytes[0] = ScreenLines[off];
6507 bytes[1] = ScreenLines2[off];
6508 bytes[2] = NUL;
6509 }
6510 else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
6511 {
6512 bytes[1] = ScreenLines[off + 1];
6513 bytes[2] = NUL;
6514 }
6515#endif
6516 }
6517}
6518
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006519#ifdef FEAT_MBYTE
6520static int screen_comp_differs __ARGS((int, int*));
6521
6522/*
6523 * Return TRUE if composing characters for screen posn "off" differs from
6524 * composing characters in "u8cc".
Bram Moolenaar70c49c12010-03-23 15:36:35 +01006525 * Only to be used when ScreenLinesUC[off] != 0.
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006526 */
6527 static int
6528screen_comp_differs(off, u8cc)
6529 int off;
6530 int *u8cc;
6531{
6532 int i;
6533
6534 for (i = 0; i < Screen_mco; ++i)
6535 {
6536 if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
6537 return TRUE;
6538 if (u8cc[i] == 0)
6539 break;
6540 }
6541 return FALSE;
6542}
6543#endif
6544
Bram Moolenaar071d4272004-06-13 20:20:40 +00006545/*
6546 * Put string '*text' on the screen at position 'row' and 'col', with
6547 * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
6548 * Note: only outputs within one row, message is truncated at screen boundary!
6549 * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
6550 */
6551 void
6552screen_puts(text, row, col, attr)
6553 char_u *text;
6554 int row;
6555 int col;
6556 int attr;
6557{
6558 screen_puts_len(text, -1, row, col, attr);
6559}
6560
6561/*
6562 * Like screen_puts(), but output "text[len]". When "len" is -1 output up to
6563 * a NUL.
6564 */
6565 void
6566screen_puts_len(text, len, row, col, attr)
6567 char_u *text;
6568 int len;
6569 int row;
6570 int col;
6571 int attr;
6572{
6573 unsigned off;
6574 char_u *ptr = text;
6575 int c;
6576#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00006577 unsigned max_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006578 int mbyte_blen = 1;
6579 int mbyte_cells = 1;
6580 int u8c = 0;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006581 int u8cc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582 int clear_next_cell = FALSE;
6583# ifdef FEAT_ARABIC
6584 int prev_c = 0; /* previous Arabic character */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006585 int pc, nc, nc1;
6586 int pcc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006587# endif
6588#endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006589#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
6590 int force_redraw_this;
6591 int force_redraw_next = FALSE;
6592#endif
6593 int need_redraw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006594
6595 if (ScreenLines == NULL || row >= screen_Rows) /* safety check */
6596 return;
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006597 off = LineOffset[row] + col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006598
Bram Moolenaarc236c162008-07-13 17:41:49 +00006599#ifdef FEAT_MBYTE
6600 /* When drawing over the right halve of a double-wide char clear out the
6601 * left halve. Only needed in a terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00006602 if (has_mbyte && col > 0 && col < screen_Columns
Bram Moolenaarc236c162008-07-13 17:41:49 +00006603# ifdef FEAT_GUI
6604 && !gui.in_use
6605# endif
6606 && mb_fix_col(col, row) != col)
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006607 {
6608 ScreenLines[off - 1] = ' ';
6609 ScreenAttrs[off - 1] = 0;
6610 if (enc_utf8)
6611 {
6612 ScreenLinesUC[off - 1] = 0;
6613 ScreenLinesC[0][off - 1] = 0;
6614 }
6615 /* redraw the previous cell, make it empty */
6616 screen_char(off - 1, row, col - 1);
6617 /* force the cell at "col" to be redrawn */
6618 force_redraw_next = TRUE;
6619 }
Bram Moolenaarc236c162008-07-13 17:41:49 +00006620#endif
6621
Bram Moolenaar367329b2007-08-30 11:53:22 +00006622#ifdef FEAT_MBYTE
6623 max_off = LineOffset[row] + screen_Columns;
6624#endif
Bram Moolenaara064ac82007-08-05 18:10:54 +00006625 while (col < screen_Columns
6626 && (len < 0 || (int)(ptr - text) < len)
6627 && *ptr != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006628 {
6629 c = *ptr;
6630#ifdef FEAT_MBYTE
6631 /* check if this is the first byte of a multibyte */
6632 if (has_mbyte)
6633 {
6634 if (enc_utf8 && len > 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006635 mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006636 else
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006637 mbyte_blen = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006638 if (enc_dbcs == DBCS_JPNU && c == 0x8e)
6639 mbyte_cells = 1;
6640 else if (enc_dbcs != 0)
6641 mbyte_cells = mbyte_blen;
6642 else /* enc_utf8 */
6643 {
6644 if (len >= 0)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006645 u8c = utfc_ptr2char_len(ptr, u8cc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00006646 (int)((text + len) - ptr));
6647 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006648 u8c = utfc_ptr2char(ptr, u8cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649 mbyte_cells = utf_char2cells(u8c);
Bram Moolenaar11936362007-09-17 20:39:42 +00006650# ifdef UNICODE16
Bram Moolenaar071d4272004-06-13 20:20:40 +00006651 /* Non-BMP character: display as ? or fullwidth ?. */
6652 if (u8c >= 0x10000)
6653 {
6654 u8c = (mbyte_cells == 2) ? 0xff1f : (int)'?';
6655 if (attr == 0)
6656 attr = hl_attr(HLF_8);
6657 }
Bram Moolenaar11936362007-09-17 20:39:42 +00006658# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006659# ifdef FEAT_ARABIC
6660 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
6661 {
6662 /* Do Arabic shaping. */
6663 if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
6664 {
6665 /* Past end of string to be displayed. */
6666 nc = NUL;
6667 nc1 = NUL;
6668 }
6669 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006670 {
Bram Moolenaar54620182009-11-11 16:07:20 +00006671 nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
6672 (int)((text + len) - ptr - mbyte_blen));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006673 nc1 = pcc[0];
6674 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006675 pc = prev_c;
6676 prev_c = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006677 u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006678 }
6679 else
6680 prev_c = u8c;
6681# endif
Bram Moolenaare4ebd292010-01-19 17:40:46 +01006682 if (col + mbyte_cells > screen_Columns)
6683 {
6684 /* Only 1 cell left, but character requires 2 cells:
6685 * display a '>' in the last column to avoid wrapping. */
6686 c = '>';
6687 mbyte_cells = 1;
6688 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006689 }
6690 }
6691#endif
6692
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006693#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
6694 force_redraw_this = force_redraw_next;
6695 force_redraw_next = FALSE;
6696#endif
6697
6698 need_redraw = ScreenLines[off] != c
Bram Moolenaar071d4272004-06-13 20:20:40 +00006699#ifdef FEAT_MBYTE
6700 || (mbyte_cells == 2
6701 && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
6702 || (enc_dbcs == DBCS_JPNU
6703 && c == 0x8e
6704 && ScreenLines2[off] != ptr[1])
6705 || (enc_utf8
Bram Moolenaar70c49c12010-03-23 15:36:35 +01006706 && (ScreenLinesUC[off] !=
6707 (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
6708 || (ScreenLinesUC[off] != 0
6709 && screen_comp_differs(off, u8cc))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006710#endif
6711 || ScreenAttrs[off] != attr
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006712 || exmode_active;
6713
6714 if (need_redraw
6715#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
6716 || force_redraw_this
6717#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006718 )
6719 {
6720#if defined(FEAT_GUI) || defined(UNIX)
6721 /* The bold trick makes a single row of pixels appear in the next
6722 * character. When a bold character is removed, the next
6723 * character should be redrawn too. This happens for our own GUI
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006724 * and for some xterms. */
6725 if (need_redraw && ScreenLines[off] != ' ' && (
Bram Moolenaar071d4272004-06-13 20:20:40 +00006726# ifdef FEAT_GUI
6727 gui.in_use
6728# endif
6729# if defined(FEAT_GUI) && defined(UNIX)
6730 ||
6731# endif
6732# ifdef UNIX
6733 term_is_xterm
6734# endif
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006735 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006736 {
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006737 int n = ScreenAttrs[off];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006738
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006739 if (n > HL_ALL)
6740 n = syn_attr2attr(n);
6741 if (n & HL_BOLD)
6742 force_redraw_next = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006743 }
6744#endif
6745#ifdef FEAT_MBYTE
6746 /* When at the end of the text and overwriting a two-cell
6747 * character with a one-cell character, need to clear the next
6748 * cell. Also when overwriting the left halve of a two-cell char
6749 * with the right halve of a two-cell char. Do this only once
6750 * (mb_off2cells() may return 2 on the right halve). */
6751 if (clear_next_cell)
6752 clear_next_cell = FALSE;
6753 else if (has_mbyte
6754 && (len < 0 ? ptr[mbyte_blen] == NUL
6755 : ptr + mbyte_blen >= text + len)
Bram Moolenaar367329b2007-08-30 11:53:22 +00006756 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006757 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00006758 && (*mb_off2cells)(off, max_off) == 1
6759 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006760 clear_next_cell = TRUE;
6761
6762 /* Make sure we never leave a second byte of a double-byte behind,
6763 * it confuses mb_off2cells(). */
6764 if (enc_dbcs
Bram Moolenaar367329b2007-08-30 11:53:22 +00006765 && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006766 || (mbyte_cells == 2
Bram Moolenaar367329b2007-08-30 11:53:22 +00006767 && (*mb_off2cells)(off, max_off) == 1
6768 && (*mb_off2cells)(off + 1, max_off) > 1)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006769 ScreenLines[off + mbyte_blen] = 0;
6770#endif
6771 ScreenLines[off] = c;
6772 ScreenAttrs[off] = attr;
6773#ifdef FEAT_MBYTE
6774 if (enc_utf8)
6775 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006776 if (c < 0x80 && u8cc[0] == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006777 ScreenLinesUC[off] = 0;
6778 else
6779 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006780 int i;
6781
Bram Moolenaar071d4272004-06-13 20:20:40 +00006782 ScreenLinesUC[off] = u8c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006783 for (i = 0; i < Screen_mco; ++i)
6784 {
6785 ScreenLinesC[i][off] = u8cc[i];
6786 if (u8cc[i] == 0)
6787 break;
6788 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006789 }
6790 if (mbyte_cells == 2)
6791 {
6792 ScreenLines[off + 1] = 0;
6793 ScreenAttrs[off + 1] = attr;
6794 }
6795 screen_char(off, row, col);
6796 }
6797 else if (mbyte_cells == 2)
6798 {
6799 ScreenLines[off + 1] = ptr[1];
6800 ScreenAttrs[off + 1] = attr;
6801 screen_char_2(off, row, col);
6802 }
6803 else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
6804 {
6805 ScreenLines2[off] = ptr[1];
6806 screen_char(off, row, col);
6807 }
6808 else
6809#endif
6810 screen_char(off, row, col);
6811 }
6812#ifdef FEAT_MBYTE
6813 if (has_mbyte)
6814 {
6815 off += mbyte_cells;
6816 col += mbyte_cells;
6817 ptr += mbyte_blen;
6818 if (clear_next_cell)
6819 ptr = (char_u *)" ";
6820 }
6821 else
6822#endif
6823 {
6824 ++off;
6825 ++col;
6826 ++ptr;
6827 }
6828 }
Bram Moolenaar2bea2912009-03-11 16:58:40 +00006829
6830#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
6831 /* If we detected the next character needs to be redrawn, but the text
6832 * doesn't extend up to there, update the character here. */
6833 if (force_redraw_next && col < screen_Columns)
6834 {
6835# ifdef FEAT_MBYTE
6836 if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
6837 screen_char_2(off, row, col);
6838 else
6839# endif
6840 screen_char(off, row, col);
6841 }
6842#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006843}
6844
6845#ifdef FEAT_SEARCH_EXTRA
6846/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006847 * Prepare for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006848 */
6849 static void
6850start_search_hl()
6851{
6852 if (p_hls && !no_hlsearch)
6853 {
6854 last_pat_prog(&search_hl.rm);
6855 search_hl.attr = hl_attr(HLF_L);
Bram Moolenaar91a4e822008-01-19 14:59:58 +00006856# ifdef FEAT_RELTIME
6857 /* Set the time limit to 'redrawtime'. */
6858 profile_setlimit(p_rdt, &search_hl.tm);
6859# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006860 }
6861}
6862
6863/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006864 * Clean up for 'hlsearch' highlighting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006865 */
6866 static void
6867end_search_hl()
6868{
6869 if (search_hl.rm.regprog != NULL)
6870 {
6871 vim_free(search_hl.rm.regprog);
6872 search_hl.rm.regprog = NULL;
6873 }
6874}
6875
6876/*
Bram Moolenaar0af8ceb2010-07-05 22:22:57 +02006877 * Init for calling prepare_search_hl().
6878 */
6879 static void
6880init_search_hl(wp)
6881 win_T *wp;
6882{
6883 matchitem_T *cur;
6884
6885 /* Setup for match and 'hlsearch' highlighting. Disable any previous
6886 * match */
6887 cur = wp->w_match_head;
6888 while (cur != NULL)
6889 {
6890 cur->hl.rm = cur->match;
6891 if (cur->hlg_id == 0)
6892 cur->hl.attr = 0;
6893 else
6894 cur->hl.attr = syn_id2attr(cur->hlg_id);
6895 cur->hl.buf = wp->w_buffer;
6896 cur->hl.lnum = 0;
6897 cur->hl.first_lnum = 0;
6898# ifdef FEAT_RELTIME
6899 /* Set the time limit to 'redrawtime'. */
6900 profile_setlimit(p_rdt, &(cur->hl.tm));
6901# endif
6902 cur = cur->next;
6903 }
6904 search_hl.buf = wp->w_buffer;
6905 search_hl.lnum = 0;
6906 search_hl.first_lnum = 0;
6907 /* time limit is set at the toplevel, for all windows */
6908}
6909
6910/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006911 * Advance to the match in window "wp" line "lnum" or past it.
6912 */
6913 static void
6914prepare_search_hl(wp, lnum)
6915 win_T *wp;
6916 linenr_T lnum;
6917{
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006918 matchitem_T *cur; /* points to the match list */
6919 match_T *shl; /* points to search_hl or a match */
6920 int shl_flag; /* flag to indicate whether search_hl
6921 has been processed or not */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006922 int n;
6923
6924 /*
6925 * When using a multi-line pattern, start searching at the top
6926 * of the window or just after a closed fold.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006927 * Do this both for search_hl and the match list.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006928 */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006929 cur = wp->w_match_head;
6930 shl_flag = FALSE;
6931 while (cur != NULL || shl_flag == FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006932 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006933 if (shl_flag == FALSE)
6934 {
6935 shl = &search_hl;
6936 shl_flag = TRUE;
6937 }
6938 else
6939 shl = &cur->hl;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006940 if (shl->rm.regprog != NULL
6941 && shl->lnum == 0
6942 && re_multiline(shl->rm.regprog))
6943 {
6944 if (shl->first_lnum == 0)
6945 {
6946# ifdef FEAT_FOLDING
6947 for (shl->first_lnum = lnum;
6948 shl->first_lnum > wp->w_topline; --shl->first_lnum)
6949 if (hasFoldingWin(wp, shl->first_lnum - 1,
6950 NULL, NULL, TRUE, NULL))
6951 break;
6952# else
6953 shl->first_lnum = wp->w_topline;
6954# endif
6955 }
6956 n = 0;
6957 while (shl->first_lnum < lnum && shl->rm.regprog != NULL)
6958 {
6959 next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n);
6960 if (shl->lnum != 0)
6961 {
6962 shl->first_lnum = shl->lnum
6963 + shl->rm.endpos[0].lnum
6964 - shl->rm.startpos[0].lnum;
6965 n = shl->rm.endpos[0].col;
6966 }
6967 else
6968 {
6969 ++shl->first_lnum;
6970 n = 0;
6971 }
6972 }
6973 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006974 if (shl != &search_hl && cur != NULL)
6975 cur = cur->next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006976 }
6977}
6978
6979/*
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006980 * Search for a next 'hlsearch' or match.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006981 * Uses shl->buf.
6982 * Sets shl->lnum and shl->rm contents.
6983 * Note: Assumes a previous match is always before "lnum", unless
6984 * shl->lnum is zero.
6985 * Careful: Any pointers for buffer lines will become invalid.
6986 */
6987 static void
6988next_search_hl(win, shl, lnum, mincol)
6989 win_T *win;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006990 match_T *shl; /* points to search_hl or a match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006991 linenr_T lnum;
6992 colnr_T mincol; /* minimal column for a match */
6993{
6994 linenr_T l;
6995 colnr_T matchcol;
6996 long nmatched;
6997
6998 if (shl->lnum != 0)
6999 {
7000 /* Check for three situations:
7001 * 1. If the "lnum" is below a previous match, start a new search.
7002 * 2. If the previous match includes "mincol", use it.
7003 * 3. Continue after the previous match.
7004 */
7005 l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
7006 if (lnum > l)
7007 shl->lnum = 0;
7008 else if (lnum < l || shl->rm.endpos[0].col > mincol)
7009 return;
7010 }
7011
7012 /*
7013 * Repeat searching for a match until one is found that includes "mincol"
7014 * or none is found in this line.
7015 */
7016 called_emsg = FALSE;
7017 for (;;)
7018 {
Bram Moolenaar91a4e822008-01-19 14:59:58 +00007019#ifdef FEAT_RELTIME
7020 /* Stop searching after passing the time limit. */
7021 if (profile_passed_limit(&(shl->tm)))
7022 {
7023 shl->lnum = 0; /* no match found in time */
7024 break;
7025 }
7026#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007027 /* Three situations:
7028 * 1. No useful previous match: search from start of line.
7029 * 2. Not Vi compatible or empty match: continue at next character.
7030 * Break the loop if this is beyond the end of the line.
7031 * 3. Vi compatible searching: continue at end of previous match.
7032 */
7033 if (shl->lnum == 0)
7034 matchcol = 0;
7035 else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
7036 || (shl->rm.endpos[0].lnum == 0
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007037 && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007038 {
Bram Moolenaar5c8837f2006-02-25 21:52:33 +00007039 char_u *ml;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007040
7041 matchcol = shl->rm.startpos[0].col;
Bram Moolenaar5c8837f2006-02-25 21:52:33 +00007042 ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007043 if (*ml == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007044 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007045 ++matchcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007046 shl->lnum = 0;
7047 break;
7048 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00007049#ifdef FEAT_MBYTE
7050 if (has_mbyte)
7051 matchcol += mb_ptr2len(ml);
7052 else
7053#endif
7054 ++matchcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055 }
7056 else
7057 matchcol = shl->rm.endpos[0].col;
7058
7059 shl->lnum = lnum;
Bram Moolenaar91a4e822008-01-19 14:59:58 +00007060 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol,
7061#ifdef FEAT_RELTIME
7062 &(shl->tm)
7063#else
7064 NULL
7065#endif
7066 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00007067 if (called_emsg)
7068 {
7069 /* Error while handling regexp: stop using this regexp. */
Bram Moolenaar0ddf0a72007-05-01 20:04:53 +00007070 if (shl == &search_hl)
7071 {
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007072 /* don't free regprog in the match list, it's a copy */
Bram Moolenaar0ddf0a72007-05-01 20:04:53 +00007073 vim_free(shl->rm.regprog);
7074 no_hlsearch = TRUE;
7075 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007076 shl->rm.regprog = NULL;
Bram Moolenaar0ddf0a72007-05-01 20:04:53 +00007077 shl->lnum = 0;
7078 got_int = FALSE; /* avoid the "Type :quit to exit Vim" message */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007079 break;
7080 }
7081 if (nmatched == 0)
7082 {
7083 shl->lnum = 0; /* no match found */
7084 break;
7085 }
7086 if (shl->rm.startpos[0].lnum > 0
7087 || shl->rm.startpos[0].col >= mincol
7088 || nmatched > 1
7089 || shl->rm.endpos[0].col > mincol)
7090 {
7091 shl->lnum += shl->rm.startpos[0].lnum;
7092 break; /* useful match found */
7093 }
7094 }
7095}
7096#endif
7097
7098 static void
7099screen_start_highlight(attr)
7100 int attr;
7101{
7102 attrentry_T *aep = NULL;
7103
7104 screen_attr = attr;
7105 if (full_screen
7106#ifdef WIN3264
7107 && termcap_active
7108#endif
7109 )
7110 {
7111#ifdef FEAT_GUI
7112 if (gui.in_use)
7113 {
7114 char buf[20];
7115
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007116 /* The GUI handles this internally. */
7117 sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007118 OUT_STR(buf);
7119 }
7120 else
7121#endif
7122 {
7123 if (attr > HL_ALL) /* special HL attr. */
7124 {
7125 if (t_colors > 1)
7126 aep = syn_cterm_attr2entry(attr);
7127 else
7128 aep = syn_term_attr2entry(attr);
7129 if (aep == NULL) /* did ":syntax clear" */
7130 attr = 0;
7131 else
7132 attr = aep->ae_attr;
7133 }
7134 if ((attr & HL_BOLD) && T_MD != NULL) /* bold */
7135 out_str(T_MD);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007136 else if (aep != NULL && t_colors > 1 && aep->ae_u.cterm.fg_color
7137 && cterm_normal_fg_bold)
7138 /* If the Normal FG color has BOLD attribute and the new HL
7139 * has a FG color defined, clear BOLD. */
7140 out_str(T_ME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141 if ((attr & HL_STANDOUT) && T_SO != NULL) /* standout */
7142 out_str(T_SO);
Bram Moolenaare2cc9702005-03-15 22:43:58 +00007143 if ((attr & (HL_UNDERLINE | HL_UNDERCURL)) && T_US != NULL)
7144 /* underline or undercurl */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145 out_str(T_US);
7146 if ((attr & HL_ITALIC) && T_CZH != NULL) /* italic */
7147 out_str(T_CZH);
7148 if ((attr & HL_INVERSE) && T_MR != NULL) /* inverse (reverse) */
7149 out_str(T_MR);
7150
7151 /*
7152 * Output the color or start string after bold etc., in case the
7153 * bold etc. override the color setting.
7154 */
7155 if (aep != NULL)
7156 {
7157 if (t_colors > 1)
7158 {
7159 if (aep->ae_u.cterm.fg_color)
7160 term_fg_color(aep->ae_u.cterm.fg_color - 1);
7161 if (aep->ae_u.cterm.bg_color)
7162 term_bg_color(aep->ae_u.cterm.bg_color - 1);
7163 }
7164 else
7165 {
7166 if (aep->ae_u.term.start != NULL)
7167 out_str(aep->ae_u.term.start);
7168 }
7169 }
7170 }
7171 }
7172}
7173
7174 void
7175screen_stop_highlight()
7176{
7177 int do_ME = FALSE; /* output T_ME code */
7178
7179 if (screen_attr != 0
7180#ifdef WIN3264
7181 && termcap_active
7182#endif
7183 )
7184 {
7185#ifdef FEAT_GUI
7186 if (gui.in_use)
7187 {
7188 char buf[20];
7189
7190 /* use internal GUI code */
7191 sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
7192 OUT_STR(buf);
7193 }
7194 else
7195#endif
7196 {
7197 if (screen_attr > HL_ALL) /* special HL attr. */
7198 {
7199 attrentry_T *aep;
7200
7201 if (t_colors > 1)
7202 {
7203 /*
7204 * Assume that t_me restores the original colors!
7205 */
7206 aep = syn_cterm_attr2entry(screen_attr);
7207 if (aep != NULL && (aep->ae_u.cterm.fg_color
7208 || aep->ae_u.cterm.bg_color))
7209 do_ME = TRUE;
7210 }
7211 else
7212 {
7213 aep = syn_term_attr2entry(screen_attr);
7214 if (aep != NULL && aep->ae_u.term.stop != NULL)
7215 {
7216 if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
7217 do_ME = TRUE;
7218 else
7219 out_str(aep->ae_u.term.stop);
7220 }
7221 }
7222 if (aep == NULL) /* did ":syntax clear" */
7223 screen_attr = 0;
7224 else
7225 screen_attr = aep->ae_attr;
7226 }
7227
7228 /*
7229 * Often all ending-codes are equal to T_ME. Avoid outputting the
7230 * same sequence several times.
7231 */
7232 if (screen_attr & HL_STANDOUT)
7233 {
7234 if (STRCMP(T_SE, T_ME) == 0)
7235 do_ME = TRUE;
7236 else
7237 out_str(T_SE);
7238 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00007239 if (screen_attr & (HL_UNDERLINE | HL_UNDERCURL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007240 {
7241 if (STRCMP(T_UE, T_ME) == 0)
7242 do_ME = TRUE;
7243 else
7244 out_str(T_UE);
7245 }
7246 if (screen_attr & HL_ITALIC)
7247 {
7248 if (STRCMP(T_CZR, T_ME) == 0)
7249 do_ME = TRUE;
7250 else
7251 out_str(T_CZR);
7252 }
7253 if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
7254 out_str(T_ME);
7255
7256 if (t_colors > 1)
7257 {
7258 /* set Normal cterm colors */
7259 if (cterm_normal_fg_color != 0)
7260 term_fg_color(cterm_normal_fg_color - 1);
7261 if (cterm_normal_bg_color != 0)
7262 term_bg_color(cterm_normal_bg_color - 1);
7263 if (cterm_normal_fg_bold)
7264 out_str(T_MD);
7265 }
7266 }
7267 }
7268 screen_attr = 0;
7269}
7270
7271/*
7272 * Reset the colors for a cterm. Used when leaving Vim.
7273 * The machine specific code may override this again.
7274 */
7275 void
7276reset_cterm_colors()
7277{
7278 if (t_colors > 1)
7279 {
7280 /* set Normal cterm colors */
7281 if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
7282 {
7283 out_str(T_OP);
7284 screen_attr = -1;
7285 }
7286 if (cterm_normal_fg_bold)
7287 {
7288 out_str(T_ME);
7289 screen_attr = -1;
7290 }
7291 }
7292}
7293
7294/*
7295 * Put character ScreenLines["off"] on the screen at position "row" and "col",
7296 * using the attributes from ScreenAttrs["off"].
7297 */
7298 static void
7299screen_char(off, row, col)
7300 unsigned off;
7301 int row;
7302 int col;
7303{
7304 int attr;
7305
7306 /* Check for illegal values, just in case (could happen just after
7307 * resizing). */
7308 if (row >= screen_Rows || col >= screen_Columns)
7309 return;
7310
7311 /* Outputting the last character on the screen may scrollup the screen.
7312 * Don't to it! Mark the character invalid (update it when scrolled up) */
7313 if (row == screen_Rows - 1 && col == screen_Columns - 1
7314#ifdef FEAT_RIGHTLEFT
7315 /* account for first command-line character in rightleft mode */
7316 && !cmdmsg_rl
7317#endif
7318 )
7319 {
7320 ScreenAttrs[off] = (sattr_T)-1;
7321 return;
7322 }
7323
7324 /*
7325 * Stop highlighting first, so it's easier to move the cursor.
7326 */
7327#if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT)
7328 if (screen_char_attr != 0)
7329 attr = screen_char_attr;
7330 else
7331#endif
7332 attr = ScreenAttrs[off];
7333 if (screen_attr != attr)
7334 screen_stop_highlight();
7335
7336 windgoto(row, col);
7337
7338 if (screen_attr != attr)
7339 screen_start_highlight(attr);
7340
7341#ifdef FEAT_MBYTE
7342 if (enc_utf8 && ScreenLinesUC[off] != 0)
7343 {
7344 char_u buf[MB_MAXBYTES + 1];
7345
7346 /* Convert UTF-8 character to bytes and write it. */
7347
7348 buf[utfc_char2bytes(off, buf)] = NUL;
7349
7350 out_str(buf);
7351 if (utf_char2cells(ScreenLinesUC[off]) > 1)
7352 ++screen_cur_col;
7353 }
7354 else
7355#endif
7356 {
7357#ifdef FEAT_MBYTE
7358 out_flush_check();
7359#endif
7360 out_char(ScreenLines[off]);
7361#ifdef FEAT_MBYTE
7362 /* double-byte character in single-width cell */
7363 if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
7364 out_char(ScreenLines2[off]);
7365#endif
7366 }
7367
7368 screen_cur_col++;
7369}
7370
7371#ifdef FEAT_MBYTE
7372
7373/*
7374 * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
7375 * on the screen at position 'row' and 'col'.
7376 * The attributes of the first byte is used for all. This is required to
7377 * output the two bytes of a double-byte character with nothing in between.
7378 */
7379 static void
7380screen_char_2(off, row, col)
7381 unsigned off;
7382 int row;
7383 int col;
7384{
7385 /* Check for illegal values (could be wrong when screen was resized). */
7386 if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
7387 return;
7388
7389 /* Outputting the last character on the screen may scrollup the screen.
7390 * Don't to it! Mark the character invalid (update it when scrolled up) */
7391 if (row == screen_Rows - 1 && col >= screen_Columns - 2)
7392 {
7393 ScreenAttrs[off] = (sattr_T)-1;
7394 return;
7395 }
7396
7397 /* Output the first byte normally (positions the cursor), then write the
7398 * second byte directly. */
7399 screen_char(off, row, col);
7400 out_char(ScreenLines[off + 1]);
7401 ++screen_cur_col;
7402}
7403#endif
7404
7405#if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT) || defined(PROTO)
7406/*
7407 * Draw a rectangle of the screen, inverted when "invert" is TRUE.
7408 * This uses the contents of ScreenLines[] and doesn't change it.
7409 */
7410 void
7411screen_draw_rectangle(row, col, height, width, invert)
7412 int row;
7413 int col;
7414 int height;
7415 int width;
7416 int invert;
7417{
7418 int r, c;
7419 int off;
Bram Moolenaar367329b2007-08-30 11:53:22 +00007420#ifdef FEAT_MBYTE
7421 int max_off;
7422#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007423
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00007424 /* Can't use ScreenLines unless initialized */
7425 if (ScreenLines == NULL)
7426 return;
7427
Bram Moolenaar071d4272004-06-13 20:20:40 +00007428 if (invert)
7429 screen_char_attr = HL_INVERSE;
7430 for (r = row; r < row + height; ++r)
7431 {
7432 off = LineOffset[r];
Bram Moolenaar367329b2007-08-30 11:53:22 +00007433#ifdef FEAT_MBYTE
7434 max_off = off + screen_Columns;
7435#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007436 for (c = col; c < col + width; ++c)
7437 {
7438#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00007439 if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007440 {
7441 screen_char_2(off + c, r, c);
7442 ++c;
7443 }
7444 else
7445#endif
7446 {
7447 screen_char(off + c, r, c);
7448#ifdef FEAT_MBYTE
Bram Moolenaar367329b2007-08-30 11:53:22 +00007449 if (utf_off2cells(off + c, max_off) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007450 ++c;
7451#endif
7452 }
7453 }
7454 }
7455 screen_char_attr = 0;
7456}
7457#endif
7458
7459#ifdef FEAT_VERTSPLIT
7460/*
7461 * Redraw the characters for a vertically split window.
7462 */
7463 static void
7464redraw_block(row, end, wp)
7465 int row;
7466 int end;
7467 win_T *wp;
7468{
7469 int col;
7470 int width;
7471
7472# ifdef FEAT_CLIPBOARD
7473 clip_may_clear_selection(row, end - 1);
7474# endif
7475
7476 if (wp == NULL)
7477 {
7478 col = 0;
7479 width = Columns;
7480 }
7481 else
7482 {
7483 col = wp->w_wincol;
7484 width = wp->w_width;
7485 }
7486 screen_draw_rectangle(row, col, end - row, width, FALSE);
7487}
7488#endif
7489
7490/*
7491 * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
7492 * with character 'c1' in first column followed by 'c2' in the other columns.
7493 * Use attributes 'attr'.
7494 */
7495 void
7496screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr)
7497 int start_row, end_row;
7498 int start_col, end_col;
7499 int c1, c2;
7500 int attr;
7501{
7502 int row;
7503 int col;
7504 int off;
7505 int end_off;
7506 int did_delete;
7507 int c;
7508 int norm_term;
7509#if defined(FEAT_GUI) || defined(UNIX)
7510 int force_next = FALSE;
7511#endif
7512
7513 if (end_row > screen_Rows) /* safety check */
7514 end_row = screen_Rows;
7515 if (end_col > screen_Columns) /* safety check */
7516 end_col = screen_Columns;
7517 if (ScreenLines == NULL
7518 || start_row >= end_row
7519 || start_col >= end_col) /* nothing to do */
7520 return;
7521
7522 /* it's a "normal" terminal when not in a GUI or cterm */
7523 norm_term = (
7524#ifdef FEAT_GUI
7525 !gui.in_use &&
7526#endif
7527 t_colors <= 1);
7528 for (row = start_row; row < end_row; ++row)
7529 {
Bram Moolenaarc236c162008-07-13 17:41:49 +00007530#ifdef FEAT_MBYTE
7531 if (has_mbyte
7532# ifdef FEAT_GUI
7533 && !gui.in_use
7534# endif
7535 )
7536 {
7537 /* When drawing over the right halve of a double-wide char clear
7538 * out the left halve. When drawing over the left halve of a
7539 * double wide-char clear out the right halve. Only needed in a
7540 * terminal. */
Bram Moolenaar7693ec62008-07-24 18:29:37 +00007541 if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00007542 screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
Bram Moolenaara1aed622008-07-18 15:14:43 +00007543 if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
Bram Moolenaard91ffe92008-07-14 17:51:11 +00007544 screen_puts_len((char_u *)" ", 1, row, end_col, 0);
Bram Moolenaarc236c162008-07-13 17:41:49 +00007545 }
7546#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007547 /*
7548 * Try to use delete-line termcap code, when no attributes or in a
7549 * "normal" terminal, where a bold/italic space is just a
7550 * space.
7551 */
7552 did_delete = FALSE;
7553 if (c2 == ' '
7554 && end_col == Columns
7555 && can_clear(T_CE)
7556 && (attr == 0
7557 || (norm_term
7558 && attr <= HL_ALL
7559 && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
7560 {
7561 /*
7562 * check if we really need to clear something
7563 */
7564 col = start_col;
7565 if (c1 != ' ') /* don't clear first char */
7566 ++col;
7567
7568 off = LineOffset[row] + col;
7569 end_off = LineOffset[row] + end_col;
7570
7571 /* skip blanks (used often, keep it fast!) */
7572#ifdef FEAT_MBYTE
7573 if (enc_utf8)
7574 while (off < end_off && ScreenLines[off] == ' '
7575 && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
7576 ++off;
7577 else
7578#endif
7579 while (off < end_off && ScreenLines[off] == ' '
7580 && ScreenAttrs[off] == 0)
7581 ++off;
7582 if (off < end_off) /* something to be cleared */
7583 {
7584 col = off - LineOffset[row];
7585 screen_stop_highlight();
7586 term_windgoto(row, col);/* clear rest of this screen line */
7587 out_str(T_CE);
7588 screen_start(); /* don't know where cursor is now */
7589 col = end_col - col;
7590 while (col--) /* clear chars in ScreenLines */
7591 {
7592 ScreenLines[off] = ' ';
7593#ifdef FEAT_MBYTE
7594 if (enc_utf8)
7595 ScreenLinesUC[off] = 0;
7596#endif
7597 ScreenAttrs[off] = 0;
7598 ++off;
7599 }
7600 }
7601 did_delete = TRUE; /* the chars are cleared now */
7602 }
7603
7604 off = LineOffset[row] + start_col;
7605 c = c1;
7606 for (col = start_col; col < end_col; ++col)
7607 {
7608 if (ScreenLines[off] != c
7609#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007610 || (enc_utf8 && (int)ScreenLinesUC[off]
7611 != (c >= 0x80 ? c : 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007612#endif
7613 || ScreenAttrs[off] != attr
7614#if defined(FEAT_GUI) || defined(UNIX)
7615 || force_next
7616#endif
7617 )
7618 {
7619#if defined(FEAT_GUI) || defined(UNIX)
7620 /* The bold trick may make a single row of pixels appear in
7621 * the next character. When a bold character is removed, the
7622 * next character should be redrawn too. This happens for our
7623 * own GUI and for some xterms. */
7624 if (
7625# ifdef FEAT_GUI
7626 gui.in_use
7627# endif
7628# if defined(FEAT_GUI) && defined(UNIX)
7629 ||
7630# endif
7631# ifdef UNIX
7632 term_is_xterm
7633# endif
7634 )
7635 {
7636 if (ScreenLines[off] != ' '
7637 && (ScreenAttrs[off] > HL_ALL
7638 || ScreenAttrs[off] & HL_BOLD))
7639 force_next = TRUE;
7640 else
7641 force_next = FALSE;
7642 }
7643#endif
7644 ScreenLines[off] = c;
7645#ifdef FEAT_MBYTE
7646 if (enc_utf8)
7647 {
7648 if (c >= 0x80)
7649 {
7650 ScreenLinesUC[off] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007651 ScreenLinesC[0][off] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007652 }
7653 else
7654 ScreenLinesUC[off] = 0;
7655 }
7656#endif
7657 ScreenAttrs[off] = attr;
7658 if (!did_delete || c != ' ')
7659 screen_char(off, row, col);
7660 }
7661 ++off;
7662 if (col == start_col)
7663 {
7664 if (did_delete)
7665 break;
7666 c = c2;
7667 }
7668 }
7669 if (end_col == Columns)
7670 LineWraps[row] = FALSE;
7671 if (row == Rows - 1) /* overwritten the command line */
7672 {
7673 redraw_cmdline = TRUE;
7674 if (c1 == ' ' && c2 == ' ')
7675 clear_cmdline = FALSE; /* command line has been cleared */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00007676 if (start_col == 0)
7677 mode_displayed = FALSE; /* mode cleared or overwritten */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007678 }
7679 }
7680}
7681
7682/*
7683 * Check if there should be a delay. Used before clearing or redrawing the
7684 * screen or the command line.
7685 */
7686 void
7687check_for_delay(check_msg_scroll)
7688 int check_msg_scroll;
7689{
7690 if ((emsg_on_display || (check_msg_scroll && msg_scroll))
7691 && !did_wait_return
7692 && emsg_silent == 0)
7693 {
7694 out_flush();
7695 ui_delay(1000L, TRUE);
7696 emsg_on_display = FALSE;
7697 if (check_msg_scroll)
7698 msg_scroll = FALSE;
7699 }
7700}
7701
7702/*
7703 * screen_valid - allocate screen buffers if size changed
7704 * If "clear" is TRUE: clear screen if it has been resized.
7705 * Returns TRUE if there is a valid screen to write to.
7706 * Returns FALSE when starting up and screen not initialized yet.
7707 */
7708 int
7709screen_valid(clear)
7710 int clear;
7711{
7712 screenalloc(clear); /* allocate screen buffers if size changed */
7713 return (ScreenLines != NULL);
7714}
7715
7716/*
7717 * Resize the shell to Rows and Columns.
7718 * Allocate ScreenLines[] and associated items.
7719 *
7720 * There may be some time between setting Rows and Columns and (re)allocating
7721 * ScreenLines[]. This happens when starting up and when (manually) changing
7722 * the shell size. Always use screen_Rows and screen_Columns to access items
7723 * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
7724 * final size of the shell is needed.
7725 */
7726 void
7727screenalloc(clear)
7728 int clear;
7729{
7730 int new_row, old_row;
7731#ifdef FEAT_GUI
7732 int old_Rows;
7733#endif
7734 win_T *wp;
7735 int outofmem = FALSE;
7736 int len;
7737 schar_T *new_ScreenLines;
7738#ifdef FEAT_MBYTE
7739 u8char_T *new_ScreenLinesUC = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007740 u8char_T *new_ScreenLinesC[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007741 schar_T *new_ScreenLines2 = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007742 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007743#endif
7744 sattr_T *new_ScreenAttrs;
7745 unsigned *new_LineOffset;
7746 char_u *new_LineWraps;
Bram Moolenaarf740b292006-02-16 22:11:02 +00007747#ifdef FEAT_WINDOWS
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007748 short *new_TabPageIdxs;
Bram Moolenaarf740b292006-02-16 22:11:02 +00007749 tabpage_T *tp;
7750#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007751 static int entered = FALSE; /* avoid recursiveness */
Bram Moolenaar89d40322006-08-29 15:30:07 +00007752 static int done_outofmem_msg = FALSE; /* did outofmem message */
Bram Moolenaar87e817c2009-02-22 20:13:39 +00007753#ifdef FEAT_AUTOCMD
7754 int retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007755
Bram Moolenaar87e817c2009-02-22 20:13:39 +00007756retry:
7757#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007758 /*
7759 * Allocation of the screen buffers is done only when the size changes and
7760 * when Rows and Columns have been set and we have started doing full
7761 * screen stuff.
7762 */
7763 if ((ScreenLines != NULL
7764 && Rows == screen_Rows
7765 && Columns == screen_Columns
7766#ifdef FEAT_MBYTE
7767 && enc_utf8 == (ScreenLinesUC != NULL)
7768 && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007769 && p_mco == Screen_mco
Bram Moolenaar071d4272004-06-13 20:20:40 +00007770#endif
7771 )
7772 || Rows == 0
7773 || Columns == 0
7774 || (!full_screen && ScreenLines == NULL))
7775 return;
7776
7777 /*
7778 * It's possible that we produce an out-of-memory message below, which
7779 * will cause this function to be called again. To break the loop, just
7780 * return here.
7781 */
7782 if (entered)
7783 return;
7784 entered = TRUE;
7785
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00007786 /*
7787 * Note that the window sizes are updated before reallocating the arrays,
7788 * thus we must not redraw here!
7789 */
7790 ++RedrawingDisabled;
7791
Bram Moolenaar071d4272004-06-13 20:20:40 +00007792 win_new_shellsize(); /* fit the windows in the new sized shell */
7793
Bram Moolenaar071d4272004-06-13 20:20:40 +00007794 comp_col(); /* recompute columns for shown command and ruler */
7795
7796 /*
7797 * We're changing the size of the screen.
7798 * - Allocate new arrays for ScreenLines and ScreenAttrs.
7799 * - Move lines from the old arrays into the new arrays, clear extra
7800 * lines (unless the screen is going to be cleared).
7801 * - Free the old arrays.
7802 *
7803 * If anything fails, make ScreenLines NULL, so we don't do anything!
7804 * Continuing with the old ScreenLines may result in a crash, because the
7805 * size is wrong.
7806 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00007807 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007808 win_free_lsize(wp);
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00007809#ifdef FEAT_AUTOCMD
7810 if (aucmd_win != NULL)
7811 win_free_lsize(aucmd_win);
7812#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007813
7814 new_ScreenLines = (schar_T *)lalloc((long_u)(
7815 (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
7816#ifdef FEAT_MBYTE
Bram Moolenaar216b7102010-03-23 13:56:59 +01007817 vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007818 if (enc_utf8)
7819 {
7820 new_ScreenLinesUC = (u8char_T *)lalloc((long_u)(
7821 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007822 for (i = 0; i < p_mco; ++i)
Bram Moolenaar70c49c12010-03-23 15:36:35 +01007823 new_ScreenLinesC[i] = (u8char_T *)lalloc_clear((long_u)(
Bram Moolenaar071d4272004-06-13 20:20:40 +00007824 (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
7825 }
7826 if (enc_dbcs == DBCS_JPNU)
7827 new_ScreenLines2 = (schar_T *)lalloc((long_u)(
7828 (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
7829#endif
7830 new_ScreenAttrs = (sattr_T *)lalloc((long_u)(
7831 (Rows + 1) * Columns * sizeof(sattr_T)), FALSE);
7832 new_LineOffset = (unsigned *)lalloc((long_u)(
7833 Rows * sizeof(unsigned)), FALSE);
7834 new_LineWraps = (char_u *)lalloc((long_u)(Rows * sizeof(char_u)), FALSE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00007835#ifdef FEAT_WINDOWS
Bram Moolenaard1f56e62006-02-22 21:25:37 +00007836 new_TabPageIdxs = (short *)lalloc((long_u)(Columns * sizeof(short)), FALSE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00007837#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007838
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00007839 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007840 {
7841 if (win_alloc_lines(wp) == FAIL)
7842 {
7843 outofmem = TRUE;
7844#ifdef FEAT_WINDOWS
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00007845 goto give_up;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007846#endif
7847 }
7848 }
Bram Moolenaar746ebd32009-06-16 14:01:43 +00007849#ifdef FEAT_AUTOCMD
Bram Moolenaar5e9b4542009-07-29 14:24:36 +00007850 if (aucmd_win != NULL && aucmd_win->w_lines == NULL
7851 && win_alloc_lines(aucmd_win) == FAIL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00007852 outofmem = TRUE;
7853#endif
Bram Moolenaarbb9c7d12009-02-21 23:03:09 +00007854#ifdef FEAT_WINDOWS
7855give_up:
7856#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007857
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007858#ifdef FEAT_MBYTE
7859 for (i = 0; i < p_mco; ++i)
7860 if (new_ScreenLinesC[i] == NULL)
7861 break;
7862#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007863 if (new_ScreenLines == NULL
7864#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007865 || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007866 || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
7867#endif
7868 || new_ScreenAttrs == NULL
7869 || new_LineOffset == NULL
7870 || new_LineWraps == NULL
Bram Moolenaarf740b292006-02-16 22:11:02 +00007871#ifdef FEAT_WINDOWS
7872 || new_TabPageIdxs == NULL
7873#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007874 || outofmem)
7875 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00007876 if (ScreenLines != NULL || !done_outofmem_msg)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00007877 {
7878 /* guess the size */
7879 do_outofmem_msg((long_u)((Rows + 1) * Columns));
7880
7881 /* Remember we did this to avoid getting outofmem messages over
7882 * and over again. */
Bram Moolenaar89d40322006-08-29 15:30:07 +00007883 done_outofmem_msg = TRUE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00007884 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007885 vim_free(new_ScreenLines);
7886 new_ScreenLines = NULL;
7887#ifdef FEAT_MBYTE
7888 vim_free(new_ScreenLinesUC);
7889 new_ScreenLinesUC = NULL;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007890 for (i = 0; i < p_mco; ++i)
7891 {
7892 vim_free(new_ScreenLinesC[i]);
7893 new_ScreenLinesC[i] = NULL;
7894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007895 vim_free(new_ScreenLines2);
7896 new_ScreenLines2 = NULL;
7897#endif
7898 vim_free(new_ScreenAttrs);
7899 new_ScreenAttrs = NULL;
7900 vim_free(new_LineOffset);
7901 new_LineOffset = NULL;
7902 vim_free(new_LineWraps);
7903 new_LineWraps = NULL;
Bram Moolenaarf740b292006-02-16 22:11:02 +00007904#ifdef FEAT_WINDOWS
7905 vim_free(new_TabPageIdxs);
7906 new_TabPageIdxs = NULL;
7907#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007908 }
7909 else
7910 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00007911 done_outofmem_msg = FALSE;
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00007912
Bram Moolenaar071d4272004-06-13 20:20:40 +00007913 for (new_row = 0; new_row < Rows; ++new_row)
7914 {
7915 new_LineOffset[new_row] = new_row * Columns;
7916 new_LineWraps[new_row] = FALSE;
7917
7918 /*
7919 * If the screen is not going to be cleared, copy as much as
7920 * possible from the old screen to the new one and clear the rest
7921 * (used when resizing the window at the "--more--" prompt or when
7922 * executing an external command, for the GUI).
7923 */
7924 if (!clear)
7925 {
7926 (void)vim_memset(new_ScreenLines + new_row * Columns,
7927 ' ', (size_t)Columns * sizeof(schar_T));
7928#ifdef FEAT_MBYTE
7929 if (enc_utf8)
7930 {
7931 (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
7932 0, (size_t)Columns * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007933 for (i = 0; i < p_mco; ++i)
7934 (void)vim_memset(new_ScreenLinesC[i]
7935 + new_row * Columns,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007936 0, (size_t)Columns * sizeof(u8char_T));
7937 }
7938 if (enc_dbcs == DBCS_JPNU)
7939 (void)vim_memset(new_ScreenLines2 + new_row * Columns,
7940 0, (size_t)Columns * sizeof(schar_T));
7941#endif
7942 (void)vim_memset(new_ScreenAttrs + new_row * Columns,
7943 0, (size_t)Columns * sizeof(sattr_T));
7944 old_row = new_row + (screen_Rows - Rows);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00007945 if (old_row >= 0 && ScreenLines != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007946 {
7947 if (screen_Columns < Columns)
7948 len = screen_Columns;
7949 else
7950 len = Columns;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00007951#ifdef FEAT_MBYTE
Bram Moolenaarf4d11452005-12-02 00:46:37 +00007952 /* When switching to utf-8 don't copy characters, they
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007953 * may be invalid now. Also when p_mco changes. */
7954 if (!(enc_utf8 && ScreenLinesUC == NULL)
7955 && p_mco == Screen_mco)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00007956#endif
7957 mch_memmove(new_ScreenLines + new_LineOffset[new_row],
7958 ScreenLines + LineOffset[old_row],
7959 (size_t)len * sizeof(schar_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007960#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007961 if (enc_utf8 && ScreenLinesUC != NULL
7962 && p_mco == Screen_mco)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007963 {
7964 mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
7965 ScreenLinesUC + LineOffset[old_row],
7966 (size_t)len * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007967 for (i = 0; i < p_mco; ++i)
7968 mch_memmove(new_ScreenLinesC[i]
7969 + new_LineOffset[new_row],
7970 ScreenLinesC[i] + LineOffset[old_row],
Bram Moolenaar071d4272004-06-13 20:20:40 +00007971 (size_t)len * sizeof(u8char_T));
7972 }
7973 if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
7974 mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
7975 ScreenLines2 + LineOffset[old_row],
7976 (size_t)len * sizeof(schar_T));
7977#endif
7978 mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
7979 ScreenAttrs + LineOffset[old_row],
7980 (size_t)len * sizeof(sattr_T));
7981 }
7982 }
7983 }
7984 /* Use the last line of the screen for the current line. */
7985 current_ScreenLine = new_ScreenLines + Rows * Columns;
7986 }
7987
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00007988 free_screenlines();
7989
Bram Moolenaar071d4272004-06-13 20:20:40 +00007990 ScreenLines = new_ScreenLines;
7991#ifdef FEAT_MBYTE
7992 ScreenLinesUC = new_ScreenLinesUC;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007993 for (i = 0; i < p_mco; ++i)
7994 ScreenLinesC[i] = new_ScreenLinesC[i];
7995 Screen_mco = p_mco;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007996 ScreenLines2 = new_ScreenLines2;
7997#endif
7998 ScreenAttrs = new_ScreenAttrs;
7999 LineOffset = new_LineOffset;
8000 LineWraps = new_LineWraps;
Bram Moolenaarf740b292006-02-16 22:11:02 +00008001#ifdef FEAT_WINDOWS
8002 TabPageIdxs = new_TabPageIdxs;
8003#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008004
8005 /* It's important that screen_Rows and screen_Columns reflect the actual
8006 * size of ScreenLines[]. Set them before calling anything. */
8007#ifdef FEAT_GUI
8008 old_Rows = screen_Rows;
8009#endif
8010 screen_Rows = Rows;
8011 screen_Columns = Columns;
8012
8013 must_redraw = CLEAR; /* need to clear the screen later */
8014 if (clear)
8015 screenclear2();
8016
8017#ifdef FEAT_GUI
8018 else if (gui.in_use
8019 && !gui.starting
8020 && ScreenLines != NULL
8021 && old_Rows != Rows)
8022 {
8023 (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
8024 /*
8025 * Adjust the position of the cursor, for when executing an external
8026 * command.
8027 */
8028 if (msg_row >= Rows) /* Rows got smaller */
8029 msg_row = Rows - 1; /* put cursor at last row */
8030 else if (Rows > old_Rows) /* Rows got bigger */
8031 msg_row += Rows - old_Rows; /* put cursor in same place */
8032 if (msg_col >= Columns) /* Columns got smaller */
8033 msg_col = Columns - 1; /* put cursor at last column */
8034 }
8035#endif
8036
Bram Moolenaar071d4272004-06-13 20:20:40 +00008037 entered = FALSE;
Bram Moolenaara3f2ecd2006-07-11 21:01:01 +00008038 --RedrawingDisabled;
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00008039
8040#ifdef FEAT_AUTOCMD
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008041 /*
8042 * Do not apply autocommands more than 3 times to avoid an endless loop
8043 * in case applying autocommands always changes Rows or Columns.
8044 */
8045 if (starting == 0 && ++retry_count <= 3)
8046 {
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00008047 apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar87e817c2009-02-22 20:13:39 +00008048 /* In rare cases, autocommands may have altered Rows or Columns,
8049 * jump back to check if we need to allocate the screen again. */
8050 goto retry;
8051 }
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00008052#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008053}
8054
8055 void
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008056free_screenlines()
8057{
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008058#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008059 int i;
8060
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008061 vim_free(ScreenLinesUC);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008062 for (i = 0; i < Screen_mco; ++i)
8063 vim_free(ScreenLinesC[i]);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008064 vim_free(ScreenLines2);
8065#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008066 vim_free(ScreenLines);
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008067 vim_free(ScreenAttrs);
8068 vim_free(LineOffset);
8069 vim_free(LineWraps);
Bram Moolenaarf740b292006-02-16 22:11:02 +00008070#ifdef FEAT_WINDOWS
8071 vim_free(TabPageIdxs);
8072#endif
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00008073}
8074
8075 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00008076screenclear()
8077{
8078 check_for_delay(FALSE);
8079 screenalloc(FALSE); /* allocate screen buffers if size changed */
8080 screenclear2(); /* clear the screen */
8081}
8082
8083 static void
8084screenclear2()
8085{
8086 int i;
8087
8088 if (starting == NO_SCREEN || ScreenLines == NULL
8089#ifdef FEAT_GUI
8090 || (gui.in_use && gui.starting)
8091#endif
8092 )
8093 return;
8094
8095#ifdef FEAT_GUI
8096 if (!gui.in_use)
8097#endif
8098 screen_attr = -1; /* force setting the Normal colors */
8099 screen_stop_highlight(); /* don't want highlighting here */
8100
8101#ifdef FEAT_CLIPBOARD
8102 /* disable selection without redrawing it */
8103 clip_scroll_selection(9999);
8104#endif
8105
8106 /* blank out ScreenLines */
8107 for (i = 0; i < Rows; ++i)
8108 {
8109 lineclear(LineOffset[i], (int)Columns);
8110 LineWraps[i] = FALSE;
8111 }
8112
8113 if (can_clear(T_CL))
8114 {
8115 out_str(T_CL); /* clear the display */
8116 clear_cmdline = FALSE;
Bram Moolenaard12f5c12006-01-25 22:10:52 +00008117 mode_displayed = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008118 }
8119 else
8120 {
8121 /* can't clear the screen, mark all chars with invalid attributes */
8122 for (i = 0; i < Rows; ++i)
8123 lineinvalid(LineOffset[i], (int)Columns);
8124 clear_cmdline = TRUE;
8125 }
8126
8127 screen_cleared = TRUE; /* can use contents of ScreenLines now */
8128
8129 win_rest_invalid(firstwin);
8130 redraw_cmdline = TRUE;
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00008131#ifdef FEAT_WINDOWS
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00008132 redraw_tabline = TRUE;
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00008133#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008134 if (must_redraw == CLEAR) /* no need to clear again */
8135 must_redraw = NOT_VALID;
8136 compute_cmdrow();
8137 msg_row = cmdline_row; /* put cursor on last line for messages */
8138 msg_col = 0;
8139 screen_start(); /* don't know where cursor is now */
8140 msg_scrolled = 0; /* can't scroll back */
8141 msg_didany = FALSE;
8142 msg_didout = FALSE;
8143}
8144
8145/*
8146 * Clear one line in ScreenLines.
8147 */
8148 static void
8149lineclear(off, width)
8150 unsigned off;
8151 int width;
8152{
8153 (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
8154#ifdef FEAT_MBYTE
8155 if (enc_utf8)
8156 (void)vim_memset(ScreenLinesUC + off, 0,
8157 (size_t)width * sizeof(u8char_T));
8158#endif
8159 (void)vim_memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
8160}
8161
8162/*
8163 * Mark one line in ScreenLines invalid by setting the attributes to an
8164 * invalid value.
8165 */
8166 static void
8167lineinvalid(off, width)
8168 unsigned off;
8169 int width;
8170{
8171 (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
8172}
8173
8174#ifdef FEAT_VERTSPLIT
8175/*
8176 * Copy part of a Screenline for vertically split window "wp".
8177 */
8178 static void
8179linecopy(to, from, wp)
8180 int to;
8181 int from;
8182 win_T *wp;
8183{
8184 unsigned off_to = LineOffset[to] + wp->w_wincol;
8185 unsigned off_from = LineOffset[from] + wp->w_wincol;
8186
8187 mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
8188 wp->w_width * sizeof(schar_T));
8189# ifdef FEAT_MBYTE
8190 if (enc_utf8)
8191 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008192 int i;
8193
Bram Moolenaar071d4272004-06-13 20:20:40 +00008194 mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
8195 wp->w_width * sizeof(u8char_T));
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008196 for (i = 0; i < p_mco; ++i)
8197 mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
8198 wp->w_width * sizeof(u8char_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008199 }
8200 if (enc_dbcs == DBCS_JPNU)
8201 mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
8202 wp->w_width * sizeof(schar_T));
8203# endif
8204 mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
8205 wp->w_width * sizeof(sattr_T));
8206}
8207#endif
8208
8209/*
8210 * Return TRUE if clearing with term string "p" would work.
8211 * It can't work when the string is empty or it won't set the right background.
8212 */
8213 int
8214can_clear(p)
8215 char_u *p;
8216{
8217 return (*p != NUL && (t_colors <= 1
8218#ifdef FEAT_GUI
8219 || gui.in_use
8220#endif
8221 || cterm_normal_bg_color == 0 || *T_UT != NUL));
8222}
8223
8224/*
8225 * Reset cursor position. Use whenever cursor was moved because of outputting
8226 * something directly to the screen (shell commands) or a terminal control
8227 * code.
8228 */
8229 void
8230screen_start()
8231{
8232 screen_cur_row = screen_cur_col = 9999;
8233}
8234
8235/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008236 * Move the cursor to position "row","col" in the screen.
8237 * This tries to find the most efficient way to move, minimizing the number of
8238 * characters sent to the terminal.
8239 */
8240 void
8241windgoto(row, col)
8242 int row;
8243 int col;
8244{
Bram Moolenaare2cc9702005-03-15 22:43:58 +00008245 sattr_T *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008246 int i;
8247 int plan;
8248 int cost;
8249 int wouldbe_col;
8250 int noinvcurs;
8251 char_u *bs;
8252 int goto_cost;
8253 int attr;
8254
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00008255#define GOTO_COST 7 /* assume a term_windgoto() takes about 7 chars */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008256#define HIGHL_COST 5 /* assume unhighlight takes 5 chars */
8257
8258#define PLAN_LE 1
8259#define PLAN_CR 2
8260#define PLAN_NL 3
8261#define PLAN_WRITE 4
8262 /* Can't use ScreenLines unless initialized */
8263 if (ScreenLines == NULL)
8264 return;
8265
8266 if (col != screen_cur_col || row != screen_cur_row)
8267 {
8268 /* Check for valid position. */
8269 if (row < 0) /* window without text lines? */
8270 row = 0;
8271 if (row >= screen_Rows)
8272 row = screen_Rows - 1;
8273 if (col >= screen_Columns)
8274 col = screen_Columns - 1;
8275
8276 /* check if no cursor movement is allowed in highlight mode */
8277 if (screen_attr && *T_MS == NUL)
8278 noinvcurs = HIGHL_COST;
8279 else
8280 noinvcurs = 0;
8281 goto_cost = GOTO_COST + noinvcurs;
8282
8283 /*
8284 * Plan how to do the positioning:
8285 * 1. Use CR to move it to column 0, same row.
8286 * 2. Use T_LE to move it a few columns to the left.
8287 * 3. Use NL to move a few lines down, column 0.
8288 * 4. Move a few columns to the right with T_ND or by writing chars.
8289 *
8290 * Don't do this if the cursor went beyond the last column, the cursor
8291 * position is unknown then (some terminals wrap, some don't )
8292 *
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00008293 * First check if the highlighting attributes allow us to write
Bram Moolenaar071d4272004-06-13 20:20:40 +00008294 * characters to move the cursor to the right.
8295 */
8296 if (row >= screen_cur_row && screen_cur_col < Columns)
8297 {
8298 /*
8299 * If the cursor is in the same row, bigger col, we can use CR
8300 * or T_LE.
8301 */
8302 bs = NULL; /* init for GCC */
8303 attr = screen_attr;
8304 if (row == screen_cur_row && col < screen_cur_col)
8305 {
8306 /* "le" is preferred over "bc", because "bc" is obsolete */
8307 if (*T_LE)
8308 bs = T_LE; /* "cursor left" */
8309 else
8310 bs = T_BC; /* "backspace character (old) */
8311 if (*bs)
8312 cost = (screen_cur_col - col) * (int)STRLEN(bs);
8313 else
8314 cost = 999;
8315 if (col + 1 < cost) /* using CR is less characters */
8316 {
8317 plan = PLAN_CR;
8318 wouldbe_col = 0;
8319 cost = 1; /* CR is just one character */
8320 }
8321 else
8322 {
8323 plan = PLAN_LE;
8324 wouldbe_col = col;
8325 }
8326 if (noinvcurs) /* will stop highlighting */
8327 {
8328 cost += noinvcurs;
8329 attr = 0;
8330 }
8331 }
8332
8333 /*
8334 * If the cursor is above where we want to be, we can use CR LF.
8335 */
8336 else if (row > screen_cur_row)
8337 {
8338 plan = PLAN_NL;
8339 wouldbe_col = 0;
8340 cost = (row - screen_cur_row) * 2; /* CR LF */
8341 if (noinvcurs) /* will stop highlighting */
8342 {
8343 cost += noinvcurs;
8344 attr = 0;
8345 }
8346 }
8347
8348 /*
8349 * If the cursor is in the same row, smaller col, just use write.
8350 */
8351 else
8352 {
8353 plan = PLAN_WRITE;
8354 wouldbe_col = screen_cur_col;
8355 cost = 0;
8356 }
8357
8358 /*
8359 * Check if any characters that need to be written have the
8360 * correct attributes. Also avoid UTF-8 characters.
8361 */
8362 i = col - wouldbe_col;
8363 if (i > 0)
8364 cost += i;
8365 if (cost < goto_cost && i > 0)
8366 {
8367 /*
8368 * Check if the attributes are correct without additionally
8369 * stopping highlighting.
8370 */
8371 p = ScreenAttrs + LineOffset[row] + wouldbe_col;
8372 while (i && *p++ == attr)
8373 --i;
8374 if (i != 0)
8375 {
8376 /*
8377 * Try if it works when highlighting is stopped here.
8378 */
8379 if (*--p == 0)
8380 {
8381 cost += noinvcurs;
8382 while (i && *p++ == 0)
8383 --i;
8384 }
8385 if (i != 0)
8386 cost = 999; /* different attributes, don't do it */
8387 }
8388#ifdef FEAT_MBYTE
8389 if (enc_utf8)
8390 {
8391 /* Don't use an UTF-8 char for positioning, it's slow. */
8392 for (i = wouldbe_col; i < col; ++i)
8393 if (ScreenLinesUC[LineOffset[row] + i] != 0)
8394 {
8395 cost = 999;
8396 break;
8397 }
8398 }
8399#endif
8400 }
8401
8402 /*
8403 * We can do it without term_windgoto()!
8404 */
8405 if (cost < goto_cost)
8406 {
8407 if (plan == PLAN_LE)
8408 {
8409 if (noinvcurs)
8410 screen_stop_highlight();
8411 while (screen_cur_col > col)
8412 {
8413 out_str(bs);
8414 --screen_cur_col;
8415 }
8416 }
8417 else if (plan == PLAN_CR)
8418 {
8419 if (noinvcurs)
8420 screen_stop_highlight();
8421 out_char('\r');
8422 screen_cur_col = 0;
8423 }
8424 else if (plan == PLAN_NL)
8425 {
8426 if (noinvcurs)
8427 screen_stop_highlight();
8428 while (screen_cur_row < row)
8429 {
8430 out_char('\n');
8431 ++screen_cur_row;
8432 }
8433 screen_cur_col = 0;
8434 }
8435
8436 i = col - screen_cur_col;
8437 if (i > 0)
8438 {
8439 /*
8440 * Use cursor-right if it's one character only. Avoids
8441 * removing a line of pixels from the last bold char, when
8442 * using the bold trick in the GUI.
8443 */
8444 if (T_ND[0] != NUL && T_ND[1] == NUL)
8445 {
8446 while (i-- > 0)
8447 out_char(*T_ND);
8448 }
8449 else
8450 {
8451 int off;
8452
8453 off = LineOffset[row] + screen_cur_col;
8454 while (i-- > 0)
8455 {
8456 if (ScreenAttrs[off] != screen_attr)
8457 screen_stop_highlight();
8458#ifdef FEAT_MBYTE
8459 out_flush_check();
8460#endif
8461 out_char(ScreenLines[off]);
8462#ifdef FEAT_MBYTE
8463 if (enc_dbcs == DBCS_JPNU
8464 && ScreenLines[off] == 0x8e)
8465 out_char(ScreenLines2[off]);
8466#endif
8467 ++off;
8468 }
8469 }
8470 }
8471 }
8472 }
8473 else
8474 cost = 999;
8475
8476 if (cost >= goto_cost)
8477 {
8478 if (noinvcurs)
8479 screen_stop_highlight();
8480 if (row == screen_cur_row && (col > screen_cur_col) &&
8481 *T_CRI != NUL)
8482 term_cursor_right(col - screen_cur_col);
8483 else
8484 term_windgoto(row, col);
8485 }
8486 screen_cur_row = row;
8487 screen_cur_col = col;
8488 }
8489}
8490
8491/*
8492 * Set cursor to its position in the current window.
8493 */
8494 void
8495setcursor()
8496{
8497 if (redrawing())
8498 {
8499 validate_cursor();
8500 windgoto(W_WINROW(curwin) + curwin->w_wrow,
8501 W_WINCOL(curwin) + (
8502#ifdef FEAT_RIGHTLEFT
Bram Moolenaar561f9db2008-02-20 13:16:29 +00008503 /* With 'rightleft' set and the cursor on a double-wide
8504 * character, position it on the leftmost column. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008505 curwin->w_p_rl ? ((int)W_WIDTH(curwin) - curwin->w_wcol - (
8506# ifdef FEAT_MBYTE
Bram Moolenaar561f9db2008-02-20 13:16:29 +00008507 (has_mbyte
8508 && (*mb_ptr2cells)(ml_get_cursor()) == 2
8509 && vim_isprintc(gchar_cursor())) ? 2 :
Bram Moolenaar071d4272004-06-13 20:20:40 +00008510# endif
8511 1)) :
8512#endif
8513 curwin->w_wcol));
8514 }
8515}
8516
8517
8518/*
8519 * insert 'line_count' lines at 'row' in window 'wp'
8520 * if 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
8521 * if 'mayclear' is TRUE the screen will be cleared if it is faster than
8522 * scrolling.
8523 * Returns FAIL if the lines are not inserted, OK for success.
8524 */
8525 int
8526win_ins_lines(wp, row, line_count, invalid, mayclear)
8527 win_T *wp;
8528 int row;
8529 int line_count;
8530 int invalid;
8531 int mayclear;
8532{
8533 int did_delete;
8534 int nextrow;
8535 int lastrow;
8536 int retval;
8537
8538 if (invalid)
8539 wp->w_lines_valid = 0;
8540
8541 if (wp->w_height < 5)
8542 return FAIL;
8543
8544 if (line_count > wp->w_height - row)
8545 line_count = wp->w_height - row;
8546
8547 retval = win_do_lines(wp, row, line_count, mayclear, FALSE);
8548 if (retval != MAYBE)
8549 return retval;
8550
8551 /*
8552 * If there is a next window or a status line, we first try to delete the
8553 * lines at the bottom to avoid messing what is after the window.
8554 * If this fails and there are following windows, don't do anything to avoid
8555 * messing up those windows, better just redraw.
8556 */
8557 did_delete = FALSE;
8558#ifdef FEAT_WINDOWS
8559 if (wp->w_next != NULL || wp->w_status_height)
8560 {
8561 if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
8562 line_count, (int)Rows, FALSE, NULL) == OK)
8563 did_delete = TRUE;
8564 else if (wp->w_next)
8565 return FAIL;
8566 }
8567#endif
8568 /*
8569 * if no lines deleted, blank the lines that will end up below the window
8570 */
8571 if (!did_delete)
8572 {
8573#ifdef FEAT_WINDOWS
8574 wp->w_redr_status = TRUE;
8575#endif
8576 redraw_cmdline = TRUE;
8577 nextrow = W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp);
8578 lastrow = nextrow + line_count;
8579 if (lastrow > Rows)
8580 lastrow = Rows;
8581 screen_fill(nextrow - line_count, lastrow - line_count,
8582 W_WINCOL(wp), (int)W_ENDCOL(wp),
8583 ' ', ' ', 0);
8584 }
8585
8586 if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, NULL)
8587 == FAIL)
8588 {
8589 /* deletion will have messed up other windows */
8590 if (did_delete)
8591 {
8592#ifdef FEAT_WINDOWS
8593 wp->w_redr_status = TRUE;
8594#endif
8595 win_rest_invalid(W_NEXT(wp));
8596 }
8597 return FAIL;
8598 }
8599
8600 return OK;
8601}
8602
8603/*
8604 * delete "line_count" window lines at "row" in window "wp"
8605 * If "invalid" is TRUE curwin->w_lines[] is invalidated.
8606 * If "mayclear" is TRUE the screen will be cleared if it is faster than
8607 * scrolling
8608 * Return OK for success, FAIL if the lines are not deleted.
8609 */
8610 int
8611win_del_lines(wp, row, line_count, invalid, mayclear)
8612 win_T *wp;
8613 int row;
8614 int line_count;
8615 int invalid;
8616 int mayclear;
8617{
8618 int retval;
8619
8620 if (invalid)
8621 wp->w_lines_valid = 0;
8622
8623 if (line_count > wp->w_height - row)
8624 line_count = wp->w_height - row;
8625
8626 retval = win_do_lines(wp, row, line_count, mayclear, TRUE);
8627 if (retval != MAYBE)
8628 return retval;
8629
8630 if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
8631 (int)Rows, FALSE, NULL) == FAIL)
8632 return FAIL;
8633
8634#ifdef FEAT_WINDOWS
8635 /*
8636 * If there are windows or status lines below, try to put them at the
8637 * correct place. If we can't do that, they have to be redrawn.
8638 */
8639 if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
8640 {
8641 if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
8642 line_count, (int)Rows, NULL) == FAIL)
8643 {
8644 wp->w_redr_status = TRUE;
8645 win_rest_invalid(wp->w_next);
8646 }
8647 }
8648 /*
8649 * If this is the last window and there is no status line, redraw the
8650 * command line later.
8651 */
8652 else
8653#endif
8654 redraw_cmdline = TRUE;
8655 return OK;
8656}
8657
8658/*
8659 * Common code for win_ins_lines() and win_del_lines().
8660 * Returns OK or FAIL when the work has been done.
8661 * Returns MAYBE when not finished yet.
8662 */
8663 static int
8664win_do_lines(wp, row, line_count, mayclear, del)
8665 win_T *wp;
8666 int row;
8667 int line_count;
8668 int mayclear;
8669 int del;
8670{
8671 int retval;
8672
8673 if (!redrawing() || line_count <= 0)
8674 return FAIL;
8675
8676 /* only a few lines left: redraw is faster */
8677 if (mayclear && Rows - line_count < 5
8678#ifdef FEAT_VERTSPLIT
8679 && wp->w_width == Columns
8680#endif
8681 )
8682 {
8683 screenclear(); /* will set wp->w_lines_valid to 0 */
8684 return FAIL;
8685 }
8686
8687 /*
8688 * Delete all remaining lines
8689 */
8690 if (row + line_count >= wp->w_height)
8691 {
8692 screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
8693 W_WINCOL(wp), (int)W_ENDCOL(wp),
8694 ' ', ' ', 0);
8695 return OK;
8696 }
8697
8698 /*
8699 * when scrolling, the message on the command line should be cleared,
8700 * otherwise it will stay there forever.
8701 */
8702 clear_cmdline = TRUE;
8703
8704 /*
8705 * If the terminal can set a scroll region, use that.
8706 * Always do this in a vertically split window. This will redraw from
8707 * ScreenLines[] when t_CV isn't defined. That's faster than using
8708 * win_line().
8709 * Don't use a scroll region when we are going to redraw the text, writing
8710 * a character in the lower right corner of the scroll region causes a
8711 * scroll-up in the DJGPP version.
8712 */
8713 if (scroll_region
8714#ifdef FEAT_VERTSPLIT
8715 || W_WIDTH(wp) != Columns
8716#endif
8717 )
8718 {
8719#ifdef FEAT_VERTSPLIT
8720 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
8721#endif
8722 scroll_region_set(wp, row);
8723 if (del)
8724 retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
8725 wp->w_height - row, FALSE, wp);
8726 else
8727 retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
8728 wp->w_height - row, wp);
8729#ifdef FEAT_VERTSPLIT
8730 if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
8731#endif
8732 scroll_region_reset();
8733 return retval;
8734 }
8735
8736#ifdef FEAT_WINDOWS
8737 if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
8738 return FAIL;
8739#endif
8740
8741 return MAYBE;
8742}
8743
8744/*
8745 * window 'wp' and everything after it is messed up, mark it for redraw
8746 */
8747 static void
8748win_rest_invalid(wp)
8749 win_T *wp;
8750{
8751#ifdef FEAT_WINDOWS
8752 while (wp != NULL)
8753#else
8754 if (wp != NULL)
8755#endif
8756 {
8757 redraw_win_later(wp, NOT_VALID);
8758#ifdef FEAT_WINDOWS
8759 wp->w_redr_status = TRUE;
8760 wp = wp->w_next;
8761#endif
8762 }
8763 redraw_cmdline = TRUE;
8764}
8765
8766/*
8767 * The rest of the routines in this file perform screen manipulations. The
8768 * given operation is performed physically on the screen. The corresponding
8769 * change is also made to the internal screen image. In this way, the editor
8770 * anticipates the effect of editing changes on the appearance of the screen.
8771 * That way, when we call screenupdate a complete redraw isn't usually
8772 * necessary. Another advantage is that we can keep adding code to anticipate
8773 * screen changes, and in the meantime, everything still works.
8774 */
8775
8776/*
8777 * types for inserting or deleting lines
8778 */
8779#define USE_T_CAL 1
8780#define USE_T_CDL 2
8781#define USE_T_AL 3
8782#define USE_T_CE 4
8783#define USE_T_DL 5
8784#define USE_T_SR 6
8785#define USE_NL 7
8786#define USE_T_CD 8
8787#define USE_REDRAW 9
8788
8789/*
8790 * insert lines on the screen and update ScreenLines[]
8791 * 'end' is the line after the scrolled part. Normally it is Rows.
8792 * When scrolling region used 'off' is the offset from the top for the region.
8793 * 'row' and 'end' are relative to the start of the region.
8794 *
8795 * return FAIL for failure, OK for success.
8796 */
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00008797 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00008798screen_ins_lines(off, row, line_count, end, wp)
8799 int off;
8800 int row;
8801 int line_count;
8802 int end;
8803 win_T *wp; /* NULL or window to use width from */
8804{
8805 int i;
8806 int j;
8807 unsigned temp;
8808 int cursor_row;
8809 int type;
8810 int result_empty;
8811 int can_ce = can_clear(T_CE);
8812
8813 /*
8814 * FAIL if
8815 * - there is no valid screen
8816 * - the screen has to be redrawn completely
8817 * - the line count is less than one
8818 * - the line count is more than 'ttyscroll'
8819 */
8820 if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
8821 return FAIL;
8822
8823 /*
8824 * There are seven ways to insert lines:
8825 * 0. When in a vertically split window and t_CV isn't set, redraw the
8826 * characters from ScreenLines[].
8827 * 1. Use T_CD (clear to end of display) if it exists and the result of
8828 * the insert is just empty lines
8829 * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
8830 * present or line_count > 1. It looks better if we do all the inserts
8831 * at once.
8832 * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
8833 * insert is just empty lines and T_CE is not present or line_count >
8834 * 1.
8835 * 4. Use T_AL (insert line) if it exists.
8836 * 5. Use T_CE (erase line) if it exists and the result of the insert is
8837 * just empty lines.
8838 * 6. Use T_DL (delete line) if it exists and the result of the insert is
8839 * just empty lines.
8840 * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
8841 * the 'da' flag is not set or we have clear line capability.
8842 * 8. redraw the characters from ScreenLines[].
8843 *
8844 * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
8845 * the scrollbar for the window. It does have insert line, use that if it
8846 * exists.
8847 */
8848 result_empty = (row + line_count >= end);
8849#ifdef FEAT_VERTSPLIT
8850 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
8851 type = USE_REDRAW;
8852 else
8853#endif
8854 if (can_clear(T_CD) && result_empty)
8855 type = USE_T_CD;
8856 else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
8857 type = USE_T_CAL;
8858 else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
8859 type = USE_T_CDL;
8860 else if (*T_AL != NUL)
8861 type = USE_T_AL;
8862 else if (can_ce && result_empty)
8863 type = USE_T_CE;
8864 else if (*T_DL != NUL && result_empty)
8865 type = USE_T_DL;
8866 else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
8867 type = USE_T_SR;
8868 else
8869 return FAIL;
8870
8871 /*
8872 * For clearing the lines screen_del_lines() is used. This will also take
8873 * care of t_db if necessary.
8874 */
8875 if (type == USE_T_CD || type == USE_T_CDL ||
8876 type == USE_T_CE || type == USE_T_DL)
8877 return screen_del_lines(off, row, line_count, end, FALSE, wp);
8878
8879 /*
8880 * If text is retained below the screen, first clear or delete as many
8881 * lines at the bottom of the window as are about to be inserted so that
8882 * the deleted lines won't later surface during a screen_del_lines.
8883 */
8884 if (*T_DB)
8885 screen_del_lines(off, end - line_count, line_count, end, FALSE, wp);
8886
8887#ifdef FEAT_CLIPBOARD
8888 /* Remove a modeless selection when inserting lines halfway the screen
8889 * or not the full width of the screen. */
8890 if (off + row > 0
8891# ifdef FEAT_VERTSPLIT
8892 || (wp != NULL && wp->w_width != Columns)
8893# endif
8894 )
8895 clip_clear_selection();
8896 else
8897 clip_scroll_selection(-line_count);
8898#endif
8899
Bram Moolenaar071d4272004-06-13 20:20:40 +00008900#ifdef FEAT_GUI
8901 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
8902 * scrolling is actually carried out. */
8903 gui_dont_update_cursor();
8904#endif
8905
8906 if (*T_CCS != NUL) /* cursor relative to region */
8907 cursor_row = row;
8908 else
8909 cursor_row = row + off;
8910
8911 /*
8912 * Shift LineOffset[] line_count down to reflect the inserted lines.
8913 * Clear the inserted lines in ScreenLines[].
8914 */
8915 row += off;
8916 end += off;
8917 for (i = 0; i < line_count; ++i)
8918 {
8919#ifdef FEAT_VERTSPLIT
8920 if (wp != NULL && wp->w_width != Columns)
8921 {
8922 /* need to copy part of a line */
8923 j = end - 1 - i;
8924 while ((j -= line_count) >= row)
8925 linecopy(j + line_count, j, wp);
8926 j += line_count;
8927 if (can_clear((char_u *)" "))
8928 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
8929 else
8930 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
8931 LineWraps[j] = FALSE;
8932 }
8933 else
8934#endif
8935 {
8936 j = end - 1 - i;
8937 temp = LineOffset[j];
8938 while ((j -= line_count) >= row)
8939 {
8940 LineOffset[j + line_count] = LineOffset[j];
8941 LineWraps[j + line_count] = LineWraps[j];
8942 }
8943 LineOffset[j + line_count] = temp;
8944 LineWraps[j + line_count] = FALSE;
8945 if (can_clear((char_u *)" "))
8946 lineclear(temp, (int)Columns);
8947 else
8948 lineinvalid(temp, (int)Columns);
8949 }
8950 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008951
8952 screen_stop_highlight();
8953 windgoto(cursor_row, 0);
8954
8955#ifdef FEAT_VERTSPLIT
8956 /* redraw the characters */
8957 if (type == USE_REDRAW)
8958 redraw_block(row, end, wp);
8959 else
8960#endif
8961 if (type == USE_T_CAL)
8962 {
8963 term_append_lines(line_count);
8964 screen_start(); /* don't know where cursor is now */
8965 }
8966 else
8967 {
8968 for (i = 0; i < line_count; i++)
8969 {
8970 if (type == USE_T_AL)
8971 {
8972 if (i && cursor_row != 0)
8973 windgoto(cursor_row, 0);
8974 out_str(T_AL);
8975 }
8976 else /* type == USE_T_SR */
8977 out_str(T_SR);
8978 screen_start(); /* don't know where cursor is now */
8979 }
8980 }
8981
8982 /*
8983 * With scroll-reverse and 'da' flag set we need to clear the lines that
8984 * have been scrolled down into the region.
8985 */
8986 if (type == USE_T_SR && *T_DA)
8987 {
8988 for (i = 0; i < line_count; ++i)
8989 {
8990 windgoto(off + i, 0);
8991 out_str(T_CE);
8992 screen_start(); /* don't know where cursor is now */
8993 }
8994 }
8995
8996#ifdef FEAT_GUI
8997 gui_can_update_cursor();
8998 if (gui.in_use)
8999 out_flush(); /* always flush after a scroll */
9000#endif
9001 return OK;
9002}
9003
9004/*
9005 * delete lines on the screen and update ScreenLines[]
9006 * 'end' is the line after the scrolled part. Normally it is Rows.
9007 * When scrolling region used 'off' is the offset from the top for the region.
9008 * 'row' and 'end' are relative to the start of the region.
9009 *
9010 * Return OK for success, FAIL if the lines are not deleted.
9011 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009012 int
9013screen_del_lines(off, row, line_count, end, force, wp)
9014 int off;
9015 int row;
9016 int line_count;
9017 int end;
9018 int force; /* even when line_count > p_ttyscroll */
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00009019 win_T *wp UNUSED; /* NULL or window to use width from */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009020{
9021 int j;
9022 int i;
9023 unsigned temp;
9024 int cursor_row;
9025 int cursor_end;
9026 int result_empty; /* result is empty until end of region */
9027 int can_delete; /* deleting line codes can be used */
9028 int type;
9029
9030 /*
9031 * FAIL if
9032 * - there is no valid screen
9033 * - the screen has to be redrawn completely
9034 * - the line count is less than one
9035 * - the line count is more than 'ttyscroll'
9036 */
9037 if (!screen_valid(TRUE) || line_count <= 0 ||
9038 (!force && line_count > p_ttyscroll))
9039 return FAIL;
9040
9041 /*
9042 * Check if the rest of the current region will become empty.
9043 */
9044 result_empty = row + line_count >= end;
9045
9046 /*
9047 * We can delete lines only when 'db' flag not set or when 'ce' option
9048 * available.
9049 */
9050 can_delete = (*T_DB == NUL || can_clear(T_CE));
9051
9052 /*
9053 * There are six ways to delete lines:
9054 * 0. When in a vertically split window and t_CV isn't set, redraw the
9055 * characters from ScreenLines[].
9056 * 1. Use T_CD if it exists and the result is empty.
9057 * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
9058 * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
9059 * none of the other ways work.
9060 * 4. Use T_CE (erase line) if the result is empty.
9061 * 5. Use T_DL (delete line) if it exists.
9062 * 6. redraw the characters from ScreenLines[].
9063 */
9064#ifdef FEAT_VERTSPLIT
9065 if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
9066 type = USE_REDRAW;
9067 else
9068#endif
9069 if (can_clear(T_CD) && result_empty)
9070 type = USE_T_CD;
9071#if defined(__BEOS__) && defined(BEOS_DR8)
9072 /*
9073 * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
9074 * its internal termcap... this works okay for tests which test *T_DB !=
9075 * NUL. It has the disadvantage that the user cannot use any :set t_*
9076 * command to get T_DB (back) to empty_option, only :set term=... will do
9077 * the trick...
9078 * Anyway, this hack will hopefully go away with the next OS release.
9079 * (Olaf Seibert)
9080 */
9081 else if (row == 0 && T_DB == empty_option
9082 && (line_count == 1 || *T_CDL == NUL))
9083#else
9084 else if (row == 0 && (
9085#ifndef AMIGA
9086 /* On the Amiga, somehow '\n' on the last line doesn't always scroll
9087 * up, so use delete-line command */
9088 line_count == 1 ||
9089#endif
9090 *T_CDL == NUL))
9091#endif
9092 type = USE_NL;
9093 else if (*T_CDL != NUL && line_count > 1 && can_delete)
9094 type = USE_T_CDL;
9095 else if (can_clear(T_CE) && result_empty
9096#ifdef FEAT_VERTSPLIT
9097 && (wp == NULL || wp->w_width == Columns)
9098#endif
9099 )
9100 type = USE_T_CE;
9101 else if (*T_DL != NUL && can_delete)
9102 type = USE_T_DL;
9103 else if (*T_CDL != NUL && can_delete)
9104 type = USE_T_CDL;
9105 else
9106 return FAIL;
9107
9108#ifdef FEAT_CLIPBOARD
9109 /* Remove a modeless selection when deleting lines halfway the screen or
9110 * not the full width of the screen. */
9111 if (off + row > 0
9112# ifdef FEAT_VERTSPLIT
9113 || (wp != NULL && wp->w_width != Columns)
9114# endif
9115 )
9116 clip_clear_selection();
9117 else
9118 clip_scroll_selection(line_count);
9119#endif
9120
Bram Moolenaar071d4272004-06-13 20:20:40 +00009121#ifdef FEAT_GUI
9122 /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
9123 * scrolling is actually carried out. */
9124 gui_dont_update_cursor();
9125#endif
9126
9127 if (*T_CCS != NUL) /* cursor relative to region */
9128 {
9129 cursor_row = row;
9130 cursor_end = end;
9131 }
9132 else
9133 {
9134 cursor_row = row + off;
9135 cursor_end = end + off;
9136 }
9137
9138 /*
9139 * Now shift LineOffset[] line_count up to reflect the deleted lines.
9140 * Clear the inserted lines in ScreenLines[].
9141 */
9142 row += off;
9143 end += off;
9144 for (i = 0; i < line_count; ++i)
9145 {
9146#ifdef FEAT_VERTSPLIT
9147 if (wp != NULL && wp->w_width != Columns)
9148 {
9149 /* need to copy part of a line */
9150 j = row + i;
9151 while ((j += line_count) <= end - 1)
9152 linecopy(j - line_count, j, wp);
9153 j -= line_count;
9154 if (can_clear((char_u *)" "))
9155 lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
9156 else
9157 lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
9158 LineWraps[j] = FALSE;
9159 }
9160 else
9161#endif
9162 {
9163 /* whole width, moving the line pointers is faster */
9164 j = row + i;
9165 temp = LineOffset[j];
9166 while ((j += line_count) <= end - 1)
9167 {
9168 LineOffset[j - line_count] = LineOffset[j];
9169 LineWraps[j - line_count] = LineWraps[j];
9170 }
9171 LineOffset[j - line_count] = temp;
9172 LineWraps[j - line_count] = FALSE;
9173 if (can_clear((char_u *)" "))
9174 lineclear(temp, (int)Columns);
9175 else
9176 lineinvalid(temp, (int)Columns);
9177 }
9178 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009179
9180 screen_stop_highlight();
9181
9182#ifdef FEAT_VERTSPLIT
9183 /* redraw the characters */
9184 if (type == USE_REDRAW)
9185 redraw_block(row, end, wp);
9186 else
9187#endif
9188 if (type == USE_T_CD) /* delete the lines */
9189 {
9190 windgoto(cursor_row, 0);
9191 out_str(T_CD);
9192 screen_start(); /* don't know where cursor is now */
9193 }
9194 else if (type == USE_T_CDL)
9195 {
9196 windgoto(cursor_row, 0);
9197 term_delete_lines(line_count);
9198 screen_start(); /* don't know where cursor is now */
9199 }
9200 /*
9201 * Deleting lines at top of the screen or scroll region: Just scroll
9202 * the whole screen (scroll region) up by outputting newlines on the
9203 * last line.
9204 */
9205 else if (type == USE_NL)
9206 {
9207 windgoto(cursor_end - 1, 0);
9208 for (i = line_count; --i >= 0; )
9209 out_char('\n'); /* cursor will remain on same line */
9210 }
9211 else
9212 {
9213 for (i = line_count; --i >= 0; )
9214 {
9215 if (type == USE_T_DL)
9216 {
9217 windgoto(cursor_row, 0);
9218 out_str(T_DL); /* delete a line */
9219 }
9220 else /* type == USE_T_CE */
9221 {
9222 windgoto(cursor_row + i, 0);
9223 out_str(T_CE); /* erase a line */
9224 }
9225 screen_start(); /* don't know where cursor is now */
9226 }
9227 }
9228
9229 /*
9230 * If the 'db' flag is set, we need to clear the lines that have been
9231 * scrolled up at the bottom of the region.
9232 */
9233 if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
9234 {
9235 for (i = line_count; i > 0; --i)
9236 {
9237 windgoto(cursor_end - i, 0);
9238 out_str(T_CE); /* erase a line */
9239 screen_start(); /* don't know where cursor is now */
9240 }
9241 }
9242
9243#ifdef FEAT_GUI
9244 gui_can_update_cursor();
9245 if (gui.in_use)
9246 out_flush(); /* always flush after a scroll */
9247#endif
9248
9249 return OK;
9250}
9251
9252/*
9253 * show the current mode and ruler
9254 *
9255 * If clear_cmdline is TRUE, clear the rest of the cmdline.
9256 * If clear_cmdline is FALSE there may be a message there that needs to be
9257 * cleared only if a mode is shown.
9258 * Return the length of the message (0 if no message).
9259 */
9260 int
9261showmode()
9262{
9263 int need_clear;
9264 int length = 0;
9265 int do_mode;
9266 int attr;
9267 int nwr_save;
9268#ifdef FEAT_INS_EXPAND
9269 int sub_attr;
9270#endif
9271
Bram Moolenaar7df351e2006-01-23 22:30:28 +00009272 do_mode = ((p_smd && msg_silent == 0)
9273 && ((State & INSERT)
9274 || restart_edit
Bram Moolenaar071d4272004-06-13 20:20:40 +00009275#ifdef FEAT_VISUAL
9276 || VIsual_active
9277#endif
9278 ));
9279 if (do_mode || Recording)
9280 {
9281 /*
9282 * Don't show mode right now, when not redrawing or inside a mapping.
9283 * Call char_avail() only when we are going to show something, because
9284 * it takes a bit of time.
9285 */
9286 if (!redrawing() || (char_avail() && !KeyTyped) || msg_silent != 0)
9287 {
9288 redraw_cmdline = TRUE; /* show mode later */
9289 return 0;
9290 }
9291
9292 nwr_save = need_wait_return;
9293
9294 /* wait a bit before overwriting an important message */
9295 check_for_delay(FALSE);
9296
9297 /* if the cmdline is more than one line high, erase top lines */
9298 need_clear = clear_cmdline;
9299 if (clear_cmdline && cmdline_row < Rows - 1)
9300 msg_clr_cmdline(); /* will reset clear_cmdline */
9301
9302 /* Position on the last line in the window, column 0 */
9303 msg_pos_mode();
9304 cursor_off();
9305 attr = hl_attr(HLF_CM); /* Highlight mode */
9306 if (do_mode)
9307 {
9308 MSG_PUTS_ATTR("--", attr);
9309#if defined(FEAT_XIM)
Bram Moolenaarc236c162008-07-13 17:41:49 +00009310# if 0 /* old version, changed by SungHyun Nam July 2008 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009311 if (xic != NULL && im_get_status() && !p_imdisable
9312 && curbuf->b_p_iminsert == B_IMODE_IM)
Bram Moolenaarc236c162008-07-13 17:41:49 +00009313# else
9314 if (
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02009315# ifdef FEAT_GUI_GTK
Bram Moolenaarc236c162008-07-13 17:41:49 +00009316 preedit_get_status()
9317# else
9318 im_get_status()
9319# endif
9320 )
9321# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02009322# ifdef FEAT_GUI_GTK /* most of the time, it's not XIM being used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009323 MSG_PUTS_ATTR(" IM", attr);
9324# else
9325 MSG_PUTS_ATTR(" XIM", attr);
9326# endif
9327#endif
9328#if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
9329 if (gui.in_use)
9330 {
9331 if (hangul_input_state_get())
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00009332 MSG_PUTS_ATTR(" \307\321\261\333", attr); /* HANGUL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009333 }
9334#endif
9335#ifdef FEAT_INS_EXPAND
9336 if (edit_submode != NULL) /* CTRL-X in Insert mode */
9337 {
9338 /* These messages can get long, avoid a wrap in a narrow
9339 * window. Prefer showing edit_submode_extra. */
9340 length = (Rows - msg_row) * Columns - 3;
9341 if (edit_submode_extra != NULL)
9342 length -= vim_strsize(edit_submode_extra);
9343 if (length > 0)
9344 {
9345 if (edit_submode_pre != NULL)
9346 length -= vim_strsize(edit_submode_pre);
9347 if (length - vim_strsize(edit_submode) > 0)
9348 {
9349 if (edit_submode_pre != NULL)
9350 msg_puts_attr(edit_submode_pre, attr);
9351 msg_puts_attr(edit_submode, attr);
9352 }
9353 if (edit_submode_extra != NULL)
9354 {
9355 MSG_PUTS_ATTR(" ", attr); /* add a space in between */
9356 if ((int)edit_submode_highl < (int)HLF_COUNT)
9357 sub_attr = hl_attr(edit_submode_highl);
9358 else
9359 sub_attr = attr;
9360 msg_puts_attr(edit_submode_extra, sub_attr);
9361 }
9362 }
9363 length = 0;
9364 }
9365 else
9366#endif
9367 {
9368#ifdef FEAT_VREPLACE
9369 if (State & VREPLACE_FLAG)
9370 MSG_PUTS_ATTR(_(" VREPLACE"), attr);
9371 else
9372#endif
9373 if (State & REPLACE_FLAG)
9374 MSG_PUTS_ATTR(_(" REPLACE"), attr);
9375 else if (State & INSERT)
9376 {
9377#ifdef FEAT_RIGHTLEFT
9378 if (p_ri)
9379 MSG_PUTS_ATTR(_(" REVERSE"), attr);
9380#endif
9381 MSG_PUTS_ATTR(_(" INSERT"), attr);
9382 }
9383 else if (restart_edit == 'I')
9384 MSG_PUTS_ATTR(_(" (insert)"), attr);
9385 else if (restart_edit == 'R')
9386 MSG_PUTS_ATTR(_(" (replace)"), attr);
9387 else if (restart_edit == 'V')
9388 MSG_PUTS_ATTR(_(" (vreplace)"), attr);
9389#ifdef FEAT_RIGHTLEFT
9390 if (p_hkmap)
9391 MSG_PUTS_ATTR(_(" Hebrew"), attr);
9392# ifdef FEAT_FKMAP
9393 if (p_fkmap)
9394 MSG_PUTS_ATTR(farsi_text_5, attr);
9395# endif
9396#endif
9397#ifdef FEAT_KEYMAP
9398 if (State & LANGMAP)
9399 {
9400# ifdef FEAT_ARABIC
9401 if (curwin->w_p_arab)
9402 MSG_PUTS_ATTR(_(" Arabic"), attr);
9403 else
9404# endif
9405 MSG_PUTS_ATTR(_(" (lang)"), attr);
9406 }
9407#endif
9408 if ((State & INSERT) && p_paste)
9409 MSG_PUTS_ATTR(_(" (paste)"), attr);
9410
9411#ifdef FEAT_VISUAL
9412 if (VIsual_active)
9413 {
9414 char *p;
9415
9416 /* Don't concatenate separate words to avoid translation
9417 * problems. */
9418 switch ((VIsual_select ? 4 : 0)
9419 + (VIsual_mode == Ctrl_V) * 2
9420 + (VIsual_mode == 'V'))
9421 {
9422 case 0: p = N_(" VISUAL"); break;
9423 case 1: p = N_(" VISUAL LINE"); break;
9424 case 2: p = N_(" VISUAL BLOCK"); break;
9425 case 4: p = N_(" SELECT"); break;
9426 case 5: p = N_(" SELECT LINE"); break;
9427 default: p = N_(" SELECT BLOCK"); break;
9428 }
9429 MSG_PUTS_ATTR(_(p), attr);
9430 }
9431#endif
9432 MSG_PUTS_ATTR(" --", attr);
9433 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +00009434
Bram Moolenaar071d4272004-06-13 20:20:40 +00009435 need_clear = TRUE;
9436 }
9437 if (Recording
9438#ifdef FEAT_INS_EXPAND
9439 && edit_submode == NULL /* otherwise it gets too long */
9440#endif
9441 )
9442 {
9443 MSG_PUTS_ATTR(_("recording"), attr);
9444 need_clear = TRUE;
9445 }
Bram Moolenaard12f5c12006-01-25 22:10:52 +00009446
9447 mode_displayed = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009448 if (need_clear || clear_cmdline)
9449 msg_clr_eos();
9450 msg_didout = FALSE; /* overwrite this message */
9451 length = msg_col;
9452 msg_col = 0;
9453 need_wait_return = nwr_save; /* never ask for hit-return for this */
9454 }
9455 else if (clear_cmdline && msg_silent == 0)
9456 /* Clear the whole command line. Will reset "clear_cmdline". */
9457 msg_clr_cmdline();
9458
9459#ifdef FEAT_CMDL_INFO
9460# ifdef FEAT_VISUAL
9461 /* In Visual mode the size of the selected area must be redrawn. */
9462 if (VIsual_active)
9463 clear_showcmd();
9464# endif
9465
9466 /* If the last window has no status line, the ruler is after the mode
9467 * message and must be redrawn */
9468 if (redrawing()
9469# ifdef FEAT_WINDOWS
9470 && lastwin->w_status_height == 0
9471# endif
9472 )
9473 win_redr_ruler(lastwin, TRUE);
9474#endif
9475 redraw_cmdline = FALSE;
9476 clear_cmdline = FALSE;
9477
9478 return length;
9479}
9480
9481/*
9482 * Position for a mode message.
9483 */
9484 static void
9485msg_pos_mode()
9486{
9487 msg_col = 0;
9488 msg_row = Rows - 1;
9489}
9490
9491/*
9492 * Delete mode message. Used when ESC is typed which is expected to end
9493 * Insert mode (but Insert mode didn't end yet!).
Bram Moolenaard12f5c12006-01-25 22:10:52 +00009494 * Caller should check "mode_displayed".
Bram Moolenaar071d4272004-06-13 20:20:40 +00009495 */
9496 void
9497unshowmode(force)
9498 int force;
9499{
9500 /*
Bram Moolenaare4ebd292010-01-19 17:40:46 +01009501 * Don't delete it right now, when not redrawing or inside a mapping.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009502 */
9503 if (!redrawing() || (!force && char_avail() && !KeyTyped))
9504 redraw_cmdline = TRUE; /* delete mode later */
9505 else
9506 {
9507 msg_pos_mode();
9508 if (Recording)
9509 MSG_PUTS_ATTR(_("recording"), hl_attr(HLF_CM));
9510 msg_clr_eos();
9511 }
9512}
9513
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009514#if defined(FEAT_WINDOWS)
9515/*
9516 * Draw the tab pages line at the top of the Vim window.
9517 */
9518 static void
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009519draw_tabline()
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009520{
9521 int tabcount = 0;
9522 tabpage_T *tp;
9523 int tabwidth;
9524 int col = 0;
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00009525 int scol = 0;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009526 int attr;
9527 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00009528 win_T *cwp;
9529 int wincount;
9530 int modified;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009531 int c;
9532 int len;
9533 int attr_sel = hl_attr(HLF_TPS);
9534 int attr_nosel = hl_attr(HLF_TP);
9535 int attr_fill = hl_attr(HLF_TPF);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00009536 char_u *p;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009537 int room;
9538 int use_sep_chars = (t_colors < 8
9539#ifdef FEAT_GUI
9540 && !gui.in_use
9541#endif
9542 );
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009543
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00009544 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009545
Bram Moolenaar32466aa2006-02-24 23:53:04 +00009546#ifdef FEAT_GUI_TABLINE
Bram Moolenaardb552d602006-03-23 22:59:57 +00009547 /* Take care of a GUI tabline. */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00009548 if (gui_use_tabline())
9549 {
9550 gui_update_tabline();
9551 return;
9552 }
9553#endif
9554
9555 if (tabline_height() < 1)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009556 return;
9557
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009558#if defined(FEAT_STL_OPT)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00009559
9560 /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */
9561 for (scol = 0; scol < Columns; ++scol)
9562 TabPageIdxs[scol] = 0;
9563
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009564 /* Use the 'tabline' option if it's set. */
9565 if (*p_tal != NUL)
9566 {
Bram Moolenaar238a5642006-02-21 22:12:05 +00009567 int save_called_emsg = called_emsg;
9568
9569 /* Check for an error. If there is one we would loop in redrawing the
9570 * screen. Avoid that by making 'tabline' empty. */
9571 called_emsg = FALSE;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009572 win_redr_custom(NULL, FALSE);
Bram Moolenaar238a5642006-02-21 22:12:05 +00009573 if (called_emsg)
9574 set_string_option_direct((char_u *)"tabline", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00009575 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaar238a5642006-02-21 22:12:05 +00009576 called_emsg |= save_called_emsg;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009577 }
Bram Moolenaar238a5642006-02-21 22:12:05 +00009578 else
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009579#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009580 {
Bram Moolenaar238a5642006-02-21 22:12:05 +00009581 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
9582 ++tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +00009583
Bram Moolenaar238a5642006-02-21 22:12:05 +00009584 tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
9585 if (tabwidth < 6)
9586 tabwidth = 6;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009587
Bram Moolenaar238a5642006-02-21 22:12:05 +00009588 attr = attr_nosel;
9589 tabcount = 0;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00009590 scol = 0;
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00009591 for (tp = first_tabpage; tp != NULL && col < Columns - 4;
9592 tp = tp->tp_next)
Bram Moolenaarf740b292006-02-16 22:11:02 +00009593 {
Bram Moolenaar238a5642006-02-21 22:12:05 +00009594 scol = col;
Bram Moolenaarf740b292006-02-16 22:11:02 +00009595
Bram Moolenaar238a5642006-02-21 22:12:05 +00009596 if (tp->tp_topframe == topframe)
9597 attr = attr_sel;
9598 if (use_sep_chars && col > 0)
9599 screen_putchar('|', 0, col++, attr);
9600
9601 if (tp->tp_topframe != topframe)
9602 attr = attr_nosel;
9603
9604 screen_putchar(' ', 0, col++, attr);
9605
9606 if (tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00009607 {
Bram Moolenaar238a5642006-02-21 22:12:05 +00009608 cwp = curwin;
9609 wp = firstwin;
9610 }
9611 else
9612 {
9613 cwp = tp->tp_curwin;
9614 wp = tp->tp_firstwin;
9615 }
9616
9617 modified = FALSE;
9618 for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
9619 if (bufIsChanged(wp->w_buffer))
9620 modified = TRUE;
9621 if (modified || wincount > 1)
9622 {
9623 if (wincount > 1)
9624 {
9625 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00009626 len = (int)STRLEN(NameBuff);
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00009627 if (col + len >= Columns - 3)
9628 break;
Bram Moolenaar238a5642006-02-21 22:12:05 +00009629 screen_puts_len(NameBuff, len, 0, col,
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009630#if defined(FEAT_SYN_HL)
Bram Moolenaar238a5642006-02-21 22:12:05 +00009631 hl_combine_attr(attr, hl_attr(HLF_T))
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009632#else
Bram Moolenaar238a5642006-02-21 22:12:05 +00009633 attr
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00009634#endif
Bram Moolenaar238a5642006-02-21 22:12:05 +00009635 );
9636 col += len;
9637 }
9638 if (modified)
9639 screen_puts_len((char_u *)"+", 1, 0, col++, attr);
9640 screen_putchar(' ', 0, col++, attr);
9641 }
9642
9643 room = scol - col + tabwidth - 1;
9644 if (room > 0)
9645 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00009646 /* Get buffer name in NameBuff[] */
9647 get_trans_bufname(cwp->w_buffer);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00009648 shorten_dir(NameBuff);
Bram Moolenaar238a5642006-02-21 22:12:05 +00009649 len = vim_strsize(NameBuff);
9650 p = NameBuff;
9651#ifdef FEAT_MBYTE
9652 if (has_mbyte)
9653 while (len > room)
9654 {
9655 len -= ptr2cells(p);
9656 mb_ptr_adv(p);
9657 }
9658 else
9659#endif
9660 if (len > room)
9661 {
9662 p += len - room;
9663 len = room;
9664 }
Bram Moolenaarfd2ac762006-03-01 22:09:21 +00009665 if (len > Columns - col - 1)
9666 len = Columns - col - 1;
Bram Moolenaar238a5642006-02-21 22:12:05 +00009667
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00009668 screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
Bram Moolenaarf740b292006-02-16 22:11:02 +00009669 col += len;
9670 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00009671 screen_putchar(' ', 0, col++, attr);
Bram Moolenaar238a5642006-02-21 22:12:05 +00009672
9673 /* Store the tab page number in TabPageIdxs[], so that
9674 * jump_to_mouse() knows where each one is. */
9675 ++tabcount;
9676 while (scol < col)
9677 TabPageIdxs[scol++] = tabcount;
Bram Moolenaarf740b292006-02-16 22:11:02 +00009678 }
9679
Bram Moolenaar238a5642006-02-21 22:12:05 +00009680 if (use_sep_chars)
9681 c = '_';
9682 else
9683 c = ' ';
9684 screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00009685
9686 /* Put an "X" for closing the current tab if there are several. */
9687 if (first_tabpage->tp_next != NULL)
9688 {
9689 screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
9690 TabPageIdxs[Columns - 1] = -999;
9691 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009692 }
Bram Moolenaarb21e5842006-04-16 18:30:08 +00009693
9694 /* Reset the flag here again, in case evaluating 'tabline' causes it to be
9695 * set. */
9696 redraw_tabline = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009697}
Bram Moolenaar32466aa2006-02-24 23:53:04 +00009698
9699/*
9700 * Get buffer name for "buf" into NameBuff[].
9701 * Takes care of special buffer names and translates special characters.
9702 */
9703 void
9704get_trans_bufname(buf)
9705 buf_T *buf;
9706{
9707 if (buf_spname(buf) != NULL)
9708 STRCPY(NameBuff, buf_spname(buf));
9709 else
9710 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
9711 trans_characters(NameBuff, MAXPATHL);
9712}
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00009713#endif
9714
Bram Moolenaar071d4272004-06-13 20:20:40 +00009715#if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
9716/*
9717 * Get the character to use in a status line. Get its attributes in "*attr".
9718 */
9719 static int
9720fillchar_status(attr, is_curwin)
9721 int *attr;
9722 int is_curwin;
9723{
9724 int fill;
9725 if (is_curwin)
9726 {
9727 *attr = hl_attr(HLF_S);
9728 fill = fill_stl;
9729 }
9730 else
9731 {
9732 *attr = hl_attr(HLF_SNC);
9733 fill = fill_stlnc;
9734 }
9735 /* Use fill when there is highlighting, and highlighting of current
9736 * window differs, or the fillchars differ, or this is not the
9737 * current window */
9738 if (*attr != 0 && ((hl_attr(HLF_S) != hl_attr(HLF_SNC)
9739 || !is_curwin || firstwin == lastwin)
9740 || (fill_stl != fill_stlnc)))
9741 return fill;
9742 if (is_curwin)
9743 return '^';
9744 return '=';
9745}
9746#endif
9747
9748#ifdef FEAT_VERTSPLIT
9749/*
9750 * Get the character to use in a separator between vertically split windows.
9751 * Get its attributes in "*attr".
9752 */
9753 static int
9754fillchar_vsep(attr)
9755 int *attr;
9756{
9757 *attr = hl_attr(HLF_C);
9758 if (*attr == 0 && fill_vert == ' ')
9759 return '|';
9760 else
9761 return fill_vert;
9762}
9763#endif
9764
9765/*
9766 * Return TRUE if redrawing should currently be done.
9767 */
9768 int
9769redrawing()
9770{
9771 return (!RedrawingDisabled
9772 && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
9773}
9774
9775/*
9776 * Return TRUE if printing messages should currently be done.
9777 */
9778 int
9779messaging()
9780{
9781 return (!(p_lz && char_avail() && !KeyTyped));
9782}
9783
9784/*
9785 * Show current status info in ruler and various other places
9786 * If always is FALSE, only show ruler if position has changed.
9787 */
9788 void
9789showruler(always)
9790 int always;
9791{
9792 if (!always && !redrawing())
9793 return;
Bram Moolenaar9372a112005-12-06 19:59:18 +00009794#ifdef FEAT_INS_EXPAND
9795 if (pum_visible())
9796 {
Bram Moolenaar71fe80d2006-01-22 23:25:56 +00009797# ifdef FEAT_WINDOWS
Bram Moolenaar9372a112005-12-06 19:59:18 +00009798 /* Don't redraw right now, do it later. */
9799 curwin->w_redr_status = TRUE;
Bram Moolenaar71fe80d2006-01-22 23:25:56 +00009800# endif
Bram Moolenaar9372a112005-12-06 19:59:18 +00009801 return;
9802 }
9803#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009804#if defined(FEAT_STL_OPT) && defined(FEAT_WINDOWS)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009805 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
Bram Moolenaar238a5642006-02-21 22:12:05 +00009806 {
Bram Moolenaar362f3562009-11-03 16:20:34 +00009807 redraw_custom_statusline(curwin);
Bram Moolenaar238a5642006-02-21 22:12:05 +00009808 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009809 else
9810#endif
9811#ifdef FEAT_CMDL_INFO
9812 win_redr_ruler(curwin, always);
9813#endif
9814
9815#ifdef FEAT_TITLE
9816 if (need_maketitle
9817# ifdef FEAT_STL_OPT
9818 || (p_icon && (stl_syntax & STL_IN_ICON))
9819 || (p_title && (stl_syntax & STL_IN_TITLE))
9820# endif
9821 )
9822 maketitle();
9823#endif
Bram Moolenaar497683b2008-05-28 17:02:46 +00009824#ifdef FEAT_WINDOWS
9825 /* Redraw the tab pages line if needed. */
9826 if (redraw_tabline)
9827 draw_tabline();
9828#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009829}
9830
9831#ifdef FEAT_CMDL_INFO
9832 static void
9833win_redr_ruler(wp, always)
9834 win_T *wp;
9835 int always;
9836{
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00009837#define RULER_BUF_LEN 70
9838 char_u buffer[RULER_BUF_LEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +00009839 int row;
9840 int fillchar;
9841 int attr;
9842 int empty_line = FALSE;
9843 colnr_T virtcol;
9844 int i;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00009845 size_t len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009846 int o;
9847#ifdef FEAT_VERTSPLIT
9848 int this_ru_col;
9849 int off = 0;
9850 int width = Columns;
9851# define WITH_OFF(x) x
9852# define WITH_WIDTH(x) x
9853#else
9854# define WITH_OFF(x) 0
9855# define WITH_WIDTH(x) Columns
9856# define this_ru_col ru_col
9857#endif
9858
9859 /* If 'ruler' off or redrawing disabled, don't do anything */
9860 if (!p_ru)
9861 return;
9862
9863 /*
9864 * Check if cursor.lnum is valid, since win_redr_ruler() may be called
9865 * after deleting lines, before cursor.lnum is corrected.
9866 */
9867 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
9868 return;
9869
9870#ifdef FEAT_INS_EXPAND
9871 /* Don't draw the ruler while doing insert-completion, it might overwrite
9872 * the (long) mode message. */
9873# ifdef FEAT_WINDOWS
9874 if (wp == lastwin && lastwin->w_status_height == 0)
9875# endif
9876 if (edit_submode != NULL)
9877 return;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00009878 /* Don't draw the ruler when the popup menu is visible, it may overlap. */
9879 if (pum_visible())
9880 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009881#endif
9882
9883#ifdef FEAT_STL_OPT
9884 if (*p_ruf)
9885 {
Bram Moolenaar238a5642006-02-21 22:12:05 +00009886 int save_called_emsg = called_emsg;
9887
9888 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009889 win_redr_custom(wp, TRUE);
Bram Moolenaar238a5642006-02-21 22:12:05 +00009890 if (called_emsg)
9891 set_string_option_direct((char_u *)"rulerformat", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00009892 (char_u *)"", OPT_FREE, SID_ERROR);
Bram Moolenaar238a5642006-02-21 22:12:05 +00009893 called_emsg |= save_called_emsg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009894 return;
9895 }
9896#endif
9897
9898 /*
9899 * Check if not in Insert mode and the line is empty (will show "0-1").
9900 */
9901 if (!(State & INSERT)
9902 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
9903 empty_line = TRUE;
9904
9905 /*
9906 * Only draw the ruler when something changed.
9907 */
9908 validate_virtcol_win(wp);
9909 if ( redraw_cmdline
9910 || always
9911 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
9912 || wp->w_cursor.col != wp->w_ru_cursor.col
9913 || wp->w_virtcol != wp->w_ru_virtcol
9914#ifdef FEAT_VIRTUALEDIT
9915 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
9916#endif
9917 || wp->w_topline != wp->w_ru_topline
9918 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
9919#ifdef FEAT_DIFF
9920 || wp->w_topfill != wp->w_ru_topfill
9921#endif
9922 || empty_line != wp->w_ru_empty)
9923 {
9924 cursor_off();
9925#ifdef FEAT_WINDOWS
9926 if (wp->w_status_height)
9927 {
9928 row = W_WINROW(wp) + wp->w_height;
9929 fillchar = fillchar_status(&attr, wp == curwin);
9930# ifdef FEAT_VERTSPLIT
9931 off = W_WINCOL(wp);
9932 width = W_WIDTH(wp);
9933# endif
9934 }
9935 else
9936#endif
9937 {
9938 row = Rows - 1;
9939 fillchar = ' ';
9940 attr = 0;
9941#ifdef FEAT_VERTSPLIT
9942 width = Columns;
9943 off = 0;
9944#endif
9945 }
9946
9947 /* In list mode virtcol needs to be recomputed */
9948 virtcol = wp->w_virtcol;
9949 if (wp->w_p_list && lcs_tab1 == NUL)
9950 {
9951 wp->w_p_list = FALSE;
9952 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
9953 wp->w_p_list = TRUE;
9954 }
9955
9956 /*
9957 * Some sprintfs return the length, some return a pointer.
9958 * To avoid portability problems we use strlen() here.
9959 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00009960 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
Bram Moolenaar071d4272004-06-13 20:20:40 +00009961 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
9962 ? 0L
9963 : (long)(wp->w_cursor.lnum));
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00009964 len = STRLEN(buffer);
9965 col_print(buffer + len, RULER_BUF_LEN - len,
Bram Moolenaar071d4272004-06-13 20:20:40 +00009966 empty_line ? 0 : (int)wp->w_cursor.col + 1,
9967 (int)virtcol + 1);
9968
9969 /*
9970 * Add a "50%" if there is room for it.
9971 * On the last line, don't print in the last column (scrolls the
9972 * screen up on some terminals).
9973 */
9974 i = (int)STRLEN(buffer);
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00009975 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009976 o = i + vim_strsize(buffer + i + 1);
9977#ifdef FEAT_WINDOWS
9978 if (wp->w_status_height == 0) /* can't use last char of screen */
9979#endif
9980 ++o;
9981#ifdef FEAT_VERTSPLIT
9982 this_ru_col = ru_col - (Columns - width);
9983 if (this_ru_col < 0)
9984 this_ru_col = 0;
9985#endif
9986 /* Never use more than half the window/screen width, leave the other
9987 * half for the filename. */
9988 if (this_ru_col < (WITH_WIDTH(width) + 1) / 2)
9989 this_ru_col = (WITH_WIDTH(width) + 1) / 2;
9990 if (this_ru_col + o < WITH_WIDTH(width))
9991 {
9992 while (this_ru_col + o < WITH_WIDTH(width))
9993 {
9994#ifdef FEAT_MBYTE
9995 if (has_mbyte)
9996 i += (*mb_char2bytes)(fillchar, buffer + i);
9997 else
9998#endif
9999 buffer[i++] = fillchar;
10000 ++o;
10001 }
Bram Moolenaar0ab2a882009-05-13 10:51:08 +000010002 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010003 }
10004 /* Truncate at window boundary. */
10005#ifdef FEAT_MBYTE
10006 if (has_mbyte)
10007 {
10008 o = 0;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +000010009 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +000010010 {
10011 o += (*mb_ptr2cells)(buffer + i);
10012 if (this_ru_col + o > WITH_WIDTH(width))
10013 {
10014 buffer[i] = NUL;
10015 break;
10016 }
10017 }
10018 }
10019 else
10020#endif
10021 if (this_ru_col + (int)STRLEN(buffer) > WITH_WIDTH(width))
10022 buffer[WITH_WIDTH(width) - this_ru_col] = NUL;
10023
10024 screen_puts(buffer, row, this_ru_col + WITH_OFF(off), attr);
10025 i = redraw_cmdline;
10026 screen_fill(row, row + 1,
10027 this_ru_col + WITH_OFF(off) + (int)STRLEN(buffer),
10028 (int)(WITH_OFF(off) + WITH_WIDTH(width)),
10029 fillchar, fillchar, attr);
10030 /* don't redraw the cmdline because of showing the ruler */
10031 redraw_cmdline = i;
10032 wp->w_ru_cursor = wp->w_cursor;
10033 wp->w_ru_virtcol = wp->w_virtcol;
10034 wp->w_ru_empty = empty_line;
10035 wp->w_ru_topline = wp->w_topline;
10036 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
10037#ifdef FEAT_DIFF
10038 wp->w_ru_topfill = wp->w_topfill;
10039#endif
10040 }
10041}
10042#endif
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010043
10044#if defined(FEAT_LINEBREAK) || defined(PROTO)
10045/*
Bram Moolenaar64486672010-05-16 15:46:46 +020010046 * Return the width of the 'number' and 'relativenumber' column.
10047 * Caller may need to check if 'number' or 'relativenumber' is set.
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010048 * Otherwise it depends on 'numberwidth' and the line count.
10049 */
10050 int
10051number_width(wp)
10052 win_T *wp;
10053{
10054 int n;
10055 linenr_T lnum;
10056
Bram Moolenaar64486672010-05-16 15:46:46 +020010057 if (wp->w_p_nu)
10058 /* 'number' */
10059 lnum = wp->w_buffer->b_ml.ml_line_count;
10060 else
10061 /* 'relativenumber' */
10062 lnum = wp->w_height;
10063
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010064 if (lnum == wp->w_nrwidth_line_count)
10065 return wp->w_nrwidth_width;
10066 wp->w_nrwidth_line_count = lnum;
10067
10068 n = 0;
10069 do
10070 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000010071 lnum /= 10;
10072 ++n;
Bram Moolenaar592e0a22004-07-03 16:05:59 +000010073 } while (lnum > 0);
10074
10075 /* 'numberwidth' gives the minimal width plus one */
10076 if (n < wp->w_p_nuw - 1)
10077 n = wp->w_p_nuw - 1;
10078
10079 wp->w_nrwidth_width = n;
10080 return n;
10081}
10082#endif