Mercurial > vim
comparison src/screen.c @ 18124:2a806e3c39f6 v8.1.2057
patch 8.1.2057: the screen.c file is much too big
Commit: https://github.com/vim/vim/commit/7528d1f6b5422750eb778dfb550cfd0b0e540964
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Sep 19 23:06:20 2019 +0200
patch 8.1.2057: the screen.c file is much too big
Problem: The screen.c file is much too big.
Solution: Split it in three parts. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/4943)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 19 Sep 2019 23:15:05 +0200 |
parents | a6c74689fb97 |
children | f249b44039e0 |
comparison
equal
deleted
inserted
replaced
18123:ceb4be0b23c7 | 18124:2a806e3c39f6 |
---|---|
6 * Do ":help credits" in Vim to see a list of people who contributed. | 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. | 7 * See README.txt for an overview of the Vim source code. |
8 */ | 8 */ |
9 | 9 |
10 /* | 10 /* |
11 * screen.c: code for displaying on the screen | 11 * screen.c: Lower level code for displaying on the screen. |
12 * | 12 * |
13 * Output to the screen (console, terminal emulator or GUI window) is minimized | 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 | 14 * by remembering what is already on the screen, and only updating the parts |
15 * that changed. | 15 * that changed. |
16 * | 16 * |
33 * ScreenLines2[] is only used for euc-jp to store the second byte if the | 33 * ScreenLines2[] is only used for euc-jp to store the second byte if the |
34 * first byte is 0x8e (single-width character). | 34 * first byte is 0x8e (single-width character). |
35 * | 35 * |
36 * The screen_*() functions write to the screen and handle updating | 36 * The screen_*() functions write to the screen and handle updating |
37 * ScreenLines[]. | 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 | |
41 * called from other places when an immediate screen update is needed. | |
42 * | |
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 lines 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 * | |
74 * 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 * | |
79 * 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 */ | 38 */ |
89 | 39 |
90 #include "vim.h" | 40 #include "vim.h" |
91 | 41 |
92 #define MB_FILLER_CHAR '<' /* character used when a double-width character | |
93 * doesn't fit. */ | |
94 | |
95 /* | 42 /* |
96 * The attributes that are actually active for writing to the screen. | 43 * The attributes that are actually active for writing to the screen. |
97 */ | 44 */ |
98 static int screen_attr = 0; | 45 static int screen_attr = 0; |
99 | 46 |
100 /* | |
101 * Positioning the cursor is reduced by remembering the last position. | |
102 * Mostly used by windgoto() and screen_char(). | |
103 */ | |
104 static int screen_cur_row, screen_cur_col; /* last known cursor position */ | |
105 | |
106 #ifdef FEAT_SEARCH_EXTRA | |
107 static match_T search_hl; // used for 'hlsearch' highlight matching | |
108 #endif | |
109 | |
110 #ifdef FEAT_FOLDING | |
111 static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */ | |
112 static int compute_foldcolumn(win_T *wp, int col); | |
113 #endif | |
114 | |
115 /* Flag that is set when drawing for a callback, not from the main command | |
116 * loop. */ | |
117 static int redrawing_for_callback = 0; | |
118 | |
119 /* | |
120 * Buffer for one screen line (characters and attributes). | |
121 */ | |
122 static schar_T *current_ScreenLine; | |
123 | |
124 static void win_update(win_T *wp); | |
125 static void win_redr_status(win_T *wp, int ignore_pum); | |
126 static void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl); | |
127 #ifdef FEAT_FOLDING | |
128 static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row); | |
129 static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum); | |
130 static void copy_text_attr(int off, char_u *buf, int len, int attr); | |
131 #endif | |
132 static int win_line(win_T *, linenr_T, int, int, int nochange, int number_only); | |
133 static void draw_vsep_win(win_T *wp, int row); | |
134 #ifdef FEAT_STL_OPT | |
135 static void redraw_custom_statusline(win_T *wp); | |
136 #endif | |
137 #ifdef FEAT_SEARCH_EXTRA | |
138 static void start_search_hl(void); | |
139 static void end_search_hl(void); | |
140 #endif | |
141 static void screen_char(unsigned off, int row, int col); | |
142 static void screen_char_2(unsigned off, int row, int col); | 47 static void screen_char_2(unsigned off, int row, int col); |
143 static void screenclear2(void); | 48 static void screenclear2(void); |
144 static void lineclear(unsigned off, int width, int attr); | 49 static void lineclear(unsigned off, int width, int attr); |
145 static void lineinvalid(unsigned off, int width); | 50 static void lineinvalid(unsigned off, int width); |
146 static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr); | 51 static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr); |
147 static void win_rest_invalid(win_T *wp); | 52 static void win_rest_invalid(win_T *wp); |
148 static void msg_pos_mode(void); | 53 static void msg_pos_mode(void); |
149 static void recording_mode(int attr); | 54 static void recording_mode(int attr); |
150 static int fillchar_status(int *attr, win_T *wp); | |
151 static int fillchar_vsep(int *attr); | |
152 #ifdef FEAT_MENU | |
153 static void redraw_win_toolbar(win_T *wp); | |
154 #endif | |
155 #ifdef FEAT_STL_OPT | |
156 static void win_redr_custom(win_T *wp, int draw_ruler); | |
157 #endif | |
158 #ifdef FEAT_CMDL_INFO | |
159 static void win_redr_ruler(win_T *wp, int always, int ignore_pum); | |
160 #endif | |
161 #ifdef FEAT_SYN_HL | |
162 static void margin_columns_win(win_T *wp, int *left_col, int *right_col); | |
163 #endif | |
164 | 55 |
165 /* Ugly global: overrule attribute used by screen_char() */ | 56 /* Ugly global: overrule attribute used by screen_char() */ |
166 static int screen_char_attr = 0; | 57 static int screen_char_attr = 0; |
167 | |
168 #ifdef FEAT_RIGHTLEFT | |
169 # define HAS_RIGHTLEFT(x) x | |
170 #else | |
171 # define HAS_RIGHTLEFT(x) FALSE | |
172 #endif | |
173 | |
174 // flags for screen_line() | |
175 #define SLF_RIGHTLEFT 1 | |
176 #define SLF_POPUP 2 | |
177 | |
178 /* | |
179 * Redraw the current window later, with update_screen(type). | |
180 * Set must_redraw only if not already set to a higher value. | |
181 * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. | |
182 */ | |
183 void | |
184 redraw_later(int type) | |
185 { | |
186 redraw_win_later(curwin, type); | |
187 } | |
188 | |
189 void | |
190 redraw_win_later( | |
191 win_T *wp, | |
192 int type) | |
193 { | |
194 if (!exiting && wp->w_redr_type < type) | |
195 { | |
196 wp->w_redr_type = type; | |
197 if (type >= NOT_VALID) | |
198 wp->w_lines_valid = 0; | |
199 if (must_redraw < type) /* must_redraw is the maximum of all windows */ | |
200 must_redraw = type; | |
201 } | |
202 } | |
203 | |
204 /* | |
205 * Force a complete redraw later. Also resets the highlighting. To be used | |
206 * after executing a shell command that messes up the screen. | |
207 */ | |
208 void | |
209 redraw_later_clear(void) | |
210 { | |
211 redraw_all_later(CLEAR); | |
212 #ifdef FEAT_GUI | |
213 if (gui.in_use) | |
214 /* Use a code that will reset gui.highlight_mask in | |
215 * gui_stop_highlight(). */ | |
216 screen_attr = HL_ALL + 1; | |
217 else | |
218 #endif | |
219 /* Use attributes that is very unlikely to appear in text. */ | |
220 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH; | |
221 } | |
222 | |
223 /* | |
224 * Mark all windows to be redrawn later. | |
225 */ | |
226 void | |
227 redraw_all_later(int type) | |
228 { | |
229 win_T *wp; | |
230 | |
231 FOR_ALL_WINDOWS(wp) | |
232 redraw_win_later(wp, type); | |
233 // This may be needed when switching tabs. | |
234 if (must_redraw < type) | |
235 must_redraw = type; | |
236 } | |
237 | |
238 /* | |
239 * Mark all windows that are editing the current buffer to be updated later. | |
240 */ | |
241 void | |
242 redraw_curbuf_later(int type) | |
243 { | |
244 redraw_buf_later(curbuf, type); | |
245 } | |
246 | |
247 void | |
248 redraw_buf_later(buf_T *buf, int type) | |
249 { | |
250 win_T *wp; | |
251 | |
252 FOR_ALL_WINDOWS(wp) | |
253 { | |
254 if (wp->w_buffer == buf) | |
255 redraw_win_later(wp, type); | |
256 } | |
257 } | |
258 | |
259 #if defined(FEAT_SIGNS) || defined(PROTO) | |
260 void | |
261 redraw_buf_line_later(buf_T *buf, linenr_T lnum) | |
262 { | |
263 win_T *wp; | |
264 | |
265 FOR_ALL_WINDOWS(wp) | |
266 if (wp->w_buffer == buf && lnum >= wp->w_topline | |
267 && lnum < wp->w_botline) | |
268 redrawWinline(wp, lnum); | |
269 } | |
270 #endif | |
271 | |
272 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) | |
273 void | |
274 redraw_buf_and_status_later(buf_T *buf, int type) | |
275 { | |
276 win_T *wp; | |
277 | |
278 #ifdef FEAT_WILDMENU | |
279 if (wild_menu_showing != 0) | |
280 /* Don't redraw while the command line completion is displayed, it | |
281 * would disappear. */ | |
282 return; | |
283 #endif | |
284 FOR_ALL_WINDOWS(wp) | |
285 { | |
286 if (wp->w_buffer == buf) | |
287 { | |
288 redraw_win_later(wp, type); | |
289 wp->w_redr_status = TRUE; | |
290 } | |
291 } | |
292 } | |
293 #endif | |
294 | |
295 #if defined(FEAT_TERMRESPONSE) || defined(PROTO) | |
296 /* | |
297 * Redraw as soon as possible. When the command line is not scrolled redraw | |
298 * right away and restore what was on the command line. | |
299 * Return a code indicating what happened. | |
300 */ | |
301 int | |
302 redraw_asap(int type) | |
303 { | |
304 int rows; | |
305 int cols = screen_Columns; | |
306 int r; | |
307 int ret = 0; | |
308 schar_T *screenline; /* copy from ScreenLines[] */ | |
309 sattr_T *screenattr; /* copy from ScreenAttrs[] */ | |
310 int i; | |
311 u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */ | |
312 u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */ | |
313 schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */ | |
314 | |
315 redraw_later(type); | |
316 if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting) | |
317 return ret; | |
318 | |
319 /* Allocate space to save the text displayed in the command line area. */ | |
320 rows = screen_Rows - cmdline_row; | |
321 screenline = LALLOC_MULT(schar_T, rows * cols); | |
322 screenattr = LALLOC_MULT(sattr_T, rows * cols); | |
323 if (screenline == NULL || screenattr == NULL) | |
324 ret = 2; | |
325 if (enc_utf8) | |
326 { | |
327 screenlineUC = LALLOC_MULT(u8char_T, rows * cols); | |
328 if (screenlineUC == NULL) | |
329 ret = 2; | |
330 for (i = 0; i < p_mco; ++i) | |
331 { | |
332 screenlineC[i] = LALLOC_MULT(u8char_T, rows * cols); | |
333 if (screenlineC[i] == NULL) | |
334 ret = 2; | |
335 } | |
336 } | |
337 if (enc_dbcs == DBCS_JPNU) | |
338 { | |
339 screenline2 = LALLOC_MULT(schar_T, rows * cols); | |
340 if (screenline2 == NULL) | |
341 ret = 2; | |
342 } | |
343 | |
344 if (ret != 2) | |
345 { | |
346 /* Save the text displayed in the command line area. */ | |
347 for (r = 0; r < rows; ++r) | |
348 { | |
349 mch_memmove(screenline + r * cols, | |
350 ScreenLines + LineOffset[cmdline_row + r], | |
351 (size_t)cols * sizeof(schar_T)); | |
352 mch_memmove(screenattr + r * cols, | |
353 ScreenAttrs + LineOffset[cmdline_row + r], | |
354 (size_t)cols * sizeof(sattr_T)); | |
355 if (enc_utf8) | |
356 { | |
357 mch_memmove(screenlineUC + r * cols, | |
358 ScreenLinesUC + LineOffset[cmdline_row + r], | |
359 (size_t)cols * sizeof(u8char_T)); | |
360 for (i = 0; i < p_mco; ++i) | |
361 mch_memmove(screenlineC[i] + r * cols, | |
362 ScreenLinesC[i] + LineOffset[cmdline_row + r], | |
363 (size_t)cols * sizeof(u8char_T)); | |
364 } | |
365 if (enc_dbcs == DBCS_JPNU) | |
366 mch_memmove(screenline2 + r * cols, | |
367 ScreenLines2 + LineOffset[cmdline_row + r], | |
368 (size_t)cols * sizeof(schar_T)); | |
369 } | |
370 | |
371 update_screen(0); | |
372 ret = 3; | |
373 | |
374 if (must_redraw == 0) | |
375 { | |
376 int off = (int)(current_ScreenLine - ScreenLines); | |
377 | |
378 /* Restore the text displayed in the command line area. */ | |
379 for (r = 0; r < rows; ++r) | |
380 { | |
381 mch_memmove(current_ScreenLine, | |
382 screenline + r * cols, | |
383 (size_t)cols * sizeof(schar_T)); | |
384 mch_memmove(ScreenAttrs + off, | |
385 screenattr + r * cols, | |
386 (size_t)cols * sizeof(sattr_T)); | |
387 if (enc_utf8) | |
388 { | |
389 mch_memmove(ScreenLinesUC + off, | |
390 screenlineUC + r * cols, | |
391 (size_t)cols * sizeof(u8char_T)); | |
392 for (i = 0; i < p_mco; ++i) | |
393 mch_memmove(ScreenLinesC[i] + off, | |
394 screenlineC[i] + r * cols, | |
395 (size_t)cols * sizeof(u8char_T)); | |
396 } | |
397 if (enc_dbcs == DBCS_JPNU) | |
398 mch_memmove(ScreenLines2 + off, | |
399 screenline2 + r * cols, | |
400 (size_t)cols * sizeof(schar_T)); | |
401 screen_line(cmdline_row + r, 0, cols, cols, 0); | |
402 } | |
403 ret = 4; | |
404 } | |
405 } | |
406 | |
407 vim_free(screenline); | |
408 vim_free(screenattr); | |
409 if (enc_utf8) | |
410 { | |
411 vim_free(screenlineUC); | |
412 for (i = 0; i < p_mco; ++i) | |
413 vim_free(screenlineC[i]); | |
414 } | |
415 if (enc_dbcs == DBCS_JPNU) | |
416 vim_free(screenline2); | |
417 | |
418 /* Show the intro message when appropriate. */ | |
419 maybe_intro_message(); | |
420 | |
421 setcursor(); | |
422 | |
423 return ret; | |
424 } | |
425 #endif | |
426 | |
427 /* | |
428 * Invoked after an asynchronous callback is called. | |
429 * If an echo command was used the cursor needs to be put back where | |
430 * it belongs. If highlighting was changed a redraw is needed. | |
431 * If "call_update_screen" is FALSE don't call update_screen() when at the | |
432 * command line. | |
433 */ | |
434 void | |
435 redraw_after_callback(int call_update_screen) | |
436 { | |
437 ++redrawing_for_callback; | |
438 | |
439 if (State == HITRETURN || State == ASKMORE) | |
440 ; // do nothing | |
441 else if (State & CMDLINE) | |
442 { | |
443 // Don't redraw when in prompt_for_number(). | |
444 if (cmdline_row > 0) | |
445 { | |
446 // Redrawing only works when the screen didn't scroll. Don't clear | |
447 // wildmenu entries. | |
448 if (msg_scrolled == 0 | |
449 #ifdef FEAT_WILDMENU | |
450 && wild_menu_showing == 0 | |
451 #endif | |
452 && call_update_screen) | |
453 update_screen(0); | |
454 | |
455 // Redraw in the same position, so that the user can continue | |
456 // editing the command. | |
457 redrawcmdline_ex(FALSE); | |
458 } | |
459 } | |
460 else if (State & (NORMAL | INSERT | TERMINAL)) | |
461 { | |
462 // keep the command line if possible | |
463 update_screen(VALID_NO_UPDATE); | |
464 setcursor(); | |
465 } | |
466 cursor_on(); | |
467 #ifdef FEAT_GUI | |
468 if (gui.in_use && !gui_mch_is_blink_off()) | |
469 // Don't update the cursor when it is blinking and off to avoid | |
470 // flicker. | |
471 out_flush_cursor(FALSE, FALSE); | |
472 else | |
473 #endif | |
474 out_flush(); | |
475 | |
476 --redrawing_for_callback; | |
477 } | |
478 | |
479 /* | |
480 * Changed something in the current window, at buffer line "lnum", that | |
481 * requires that line and possibly other lines to be redrawn. | |
482 * Used when entering/leaving Insert mode with the cursor on a folded line. | |
483 * Used to remove the "$" from a change command. | |
484 * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot | |
485 * may become invalid and the whole window will have to be redrawn. | |
486 */ | |
487 void | |
488 redrawWinline( | |
489 win_T *wp, | |
490 linenr_T lnum) | |
491 { | |
492 if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) | |
493 wp->w_redraw_top = lnum; | |
494 if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) | |
495 wp->w_redraw_bot = lnum; | |
496 redraw_win_later(wp, VALID); | |
497 } | |
498 | |
499 /* | |
500 * To be called when "updating_screen" was set before and now the postponed | |
501 * side effects may take place. | |
502 */ | |
503 void | |
504 after_updating_screen(int may_resize_shell UNUSED) | |
505 { | |
506 updating_screen = FALSE; | |
507 #ifdef FEAT_GUI | |
508 if (may_resize_shell) | |
509 gui_may_resize_shell(); | |
510 #endif | |
511 #ifdef FEAT_TERMINAL | |
512 term_check_channel_closed_recently(); | |
513 #endif | |
514 | |
515 #ifdef HAVE_DROP_FILE | |
516 // If handle_drop() was called while updating_screen was TRUE need to | |
517 // handle the drop now. | |
518 handle_any_postponed_drop(); | |
519 #endif | |
520 } | |
521 | |
522 /* | |
523 * Update all windows that are editing the current buffer. | |
524 */ | |
525 void | |
526 update_curbuf(int type) | |
527 { | |
528 redraw_curbuf_later(type); | |
529 update_screen(type); | |
530 } | |
531 | |
532 /* | |
533 * Based on the current value of curwin->w_topline, transfer a screenfull | |
534 * of stuff from Filemem to ScreenLines[], and update curwin->w_botline. | |
535 * Return OK when the screen was updated, FAIL if it was not done. | |
536 */ | |
537 int | |
538 update_screen(int type_arg) | |
539 { | |
540 int type = type_arg; | |
541 win_T *wp; | |
542 static int did_intro = FALSE; | |
543 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) | |
544 int did_one; | |
545 #endif | |
546 #ifdef FEAT_GUI | |
547 int did_undraw = FALSE; | |
548 int gui_cursor_col = 0; | |
549 int gui_cursor_row = 0; | |
550 #endif | |
551 int no_update = FALSE; | |
552 | |
553 /* Don't do anything if the screen structures are (not yet) valid. */ | |
554 if (!screen_valid(TRUE)) | |
555 return FAIL; | |
556 | |
557 if (type == VALID_NO_UPDATE) | |
558 { | |
559 no_update = TRUE; | |
560 type = 0; | |
561 } | |
562 | |
563 #ifdef FEAT_EVAL | |
564 { | |
565 buf_T *buf; | |
566 | |
567 // Before updating the screen, notify any listeners of changed text. | |
568 FOR_ALL_BUFFERS(buf) | |
569 invoke_listeners(buf); | |
570 } | |
571 #endif | |
572 | |
573 #ifdef FEAT_DIFF | |
574 // May have postponed updating diffs. | |
575 if (need_diff_redraw) | |
576 diff_redraw(TRUE); | |
577 #endif | |
578 | |
579 if (must_redraw) | |
580 { | |
581 if (type < must_redraw) /* use maximal type */ | |
582 type = must_redraw; | |
583 | |
584 /* must_redraw is reset here, so that when we run into some weird | |
585 * reason to redraw while busy redrawing (e.g., asynchronous | |
586 * scrolling), or update_topline() in win_update() will cause a | |
587 * scroll, the screen will be redrawn later or in win_update(). */ | |
588 must_redraw = 0; | |
589 } | |
590 | |
591 /* May need to update w_lines[]. */ | |
592 if (curwin->w_lines_valid == 0 && type < NOT_VALID | |
593 #ifdef FEAT_TERMINAL | |
594 && !term_do_update_window(curwin) | |
595 #endif | |
596 ) | |
597 type = NOT_VALID; | |
598 | |
599 /* Postpone the redrawing when it's not needed and when being called | |
600 * recursively. */ | |
601 if (!redrawing() || updating_screen) | |
602 { | |
603 redraw_later(type); /* remember type for next time */ | |
604 must_redraw = type; | |
605 if (type > INVERTED_ALL) | |
606 curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */ | |
607 return FAIL; | |
608 } | |
609 updating_screen = TRUE; | |
610 | |
611 #ifdef FEAT_TEXT_PROP | |
612 // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot | |
613 // in some windows. | |
614 may_update_popup_mask(type); | |
615 #endif | |
616 | |
617 #ifdef FEAT_SYN_HL | |
618 ++display_tick; /* let syntax code know we're in a next round of | |
619 * display updating */ | |
620 #endif | |
621 if (no_update) | |
622 ++no_win_do_lines_ins; | |
623 | |
624 /* | |
625 * if the screen was scrolled up when displaying a message, scroll it down | |
626 */ | |
627 if (msg_scrolled) | |
628 { | |
629 clear_cmdline = TRUE; | |
630 if (msg_scrolled > Rows - 5) /* clearing is faster */ | |
631 type = CLEAR; | |
632 else if (type != CLEAR) | |
633 { | |
634 check_for_delay(FALSE); | |
635 if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL) | |
636 == FAIL) | |
637 type = CLEAR; | |
638 FOR_ALL_WINDOWS(wp) | |
639 { | |
640 if (wp->w_winrow < msg_scrolled) | |
641 { | |
642 if (W_WINROW(wp) + wp->w_height > msg_scrolled | |
643 && wp->w_redr_type < REDRAW_TOP | |
644 && wp->w_lines_valid > 0 | |
645 && wp->w_topline == wp->w_lines[0].wl_lnum) | |
646 { | |
647 wp->w_upd_rows = msg_scrolled - W_WINROW(wp); | |
648 wp->w_redr_type = REDRAW_TOP; | |
649 } | |
650 else | |
651 { | |
652 wp->w_redr_type = NOT_VALID; | |
653 if (W_WINROW(wp) + wp->w_height + wp->w_status_height | |
654 <= msg_scrolled) | |
655 wp->w_redr_status = TRUE; | |
656 } | |
657 } | |
658 } | |
659 if (!no_update) | |
660 redraw_cmdline = TRUE; | |
661 redraw_tabline = TRUE; | |
662 } | |
663 msg_scrolled = 0; | |
664 need_wait_return = FALSE; | |
665 } | |
666 | |
667 /* reset cmdline_row now (may have been changed temporarily) */ | |
668 compute_cmdrow(); | |
669 | |
670 /* Check for changed highlighting */ | |
671 if (need_highlight_changed) | |
672 highlight_changed(); | |
673 | |
674 if (type == CLEAR) /* first clear screen */ | |
675 { | |
676 screenclear(); /* will reset clear_cmdline */ | |
677 type = NOT_VALID; | |
678 /* must_redraw may be set indirectly, avoid another redraw later */ | |
679 must_redraw = 0; | |
680 } | |
681 | |
682 if (clear_cmdline) /* going to clear cmdline (done below) */ | |
683 check_for_delay(FALSE); | |
684 | |
685 #ifdef FEAT_LINEBREAK | |
686 /* Force redraw when width of 'number' or 'relativenumber' column | |
687 * changes. */ | |
688 if (curwin->w_redr_type < NOT_VALID | |
689 && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu) | |
690 ? number_width(curwin) : 0)) | |
691 curwin->w_redr_type = NOT_VALID; | |
692 #endif | |
693 | |
694 /* | |
695 * Only start redrawing if there is really something to do. | |
696 */ | |
697 if (type == INVERTED) | |
698 update_curswant(); | |
699 if (curwin->w_redr_type < type | |
700 && !((type == VALID | |
701 && curwin->w_lines[0].wl_valid | |
702 #ifdef FEAT_DIFF | |
703 && curwin->w_topfill == curwin->w_old_topfill | |
704 && curwin->w_botfill == curwin->w_old_botfill | |
705 #endif | |
706 && curwin->w_topline == curwin->w_lines[0].wl_lnum) | |
707 || (type == INVERTED | |
708 && VIsual_active | |
709 && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum | |
710 && curwin->w_old_visual_mode == VIsual_mode | |
711 && (curwin->w_valid & VALID_VIRTCOL) | |
712 && curwin->w_old_curswant == curwin->w_curswant) | |
713 )) | |
714 curwin->w_redr_type = type; | |
715 | |
716 /* Redraw the tab pages line if needed. */ | |
717 if (redraw_tabline || type >= NOT_VALID) | |
718 draw_tabline(); | |
719 | |
720 #ifdef FEAT_SYN_HL | |
721 /* | |
722 * Correct stored syntax highlighting info for changes in each displayed | |
723 * buffer. Each buffer must only be done once. | |
724 */ | |
725 FOR_ALL_WINDOWS(wp) | |
726 { | |
727 if (wp->w_buffer->b_mod_set) | |
728 { | |
729 win_T *wwp; | |
730 | |
731 /* Check if we already did this buffer. */ | |
732 for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) | |
733 if (wwp->w_buffer == wp->w_buffer) | |
734 break; | |
735 if (wwp == wp && syntax_present(wp)) | |
736 syn_stack_apply_changes(wp->w_buffer); | |
737 } | |
738 } | |
739 #endif | |
740 | |
741 /* | |
742 * Go from top to bottom through the windows, redrawing the ones that need | |
743 * it. | |
744 */ | |
745 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) | |
746 did_one = FALSE; | |
747 #endif | |
748 #ifdef FEAT_SEARCH_EXTRA | |
749 search_hl.rm.regprog = NULL; | |
750 #endif | |
751 FOR_ALL_WINDOWS(wp) | |
752 { | |
753 if (wp->w_redr_type != 0) | |
754 { | |
755 cursor_off(); | |
756 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) | |
757 if (!did_one) | |
758 { | |
759 did_one = TRUE; | |
760 # ifdef FEAT_SEARCH_EXTRA | |
761 start_search_hl(); | |
762 # endif | |
763 # ifdef FEAT_CLIPBOARD | |
764 /* When Visual area changed, may have to update selection. */ | |
765 if (clip_star.available && clip_isautosel_star()) | |
766 clip_update_selection(&clip_star); | |
767 if (clip_plus.available && clip_isautosel_plus()) | |
768 clip_update_selection(&clip_plus); | |
769 # endif | |
770 #ifdef FEAT_GUI | |
771 /* Remove the cursor before starting to do anything, because | |
772 * scrolling may make it difficult to redraw the text under | |
773 * it. */ | |
774 if (gui.in_use && wp == curwin) | |
775 { | |
776 gui_cursor_col = gui.cursor_col; | |
777 gui_cursor_row = gui.cursor_row; | |
778 gui_undraw_cursor(); | |
779 did_undraw = TRUE; | |
780 } | |
781 #endif | |
782 } | |
783 #endif | |
784 win_update(wp); | |
785 } | |
786 | |
787 /* redraw status line after the window to minimize cursor movement */ | |
788 if (wp->w_redr_status) | |
789 { | |
790 cursor_off(); | |
791 win_redr_status(wp, TRUE); // any popup menu will be redrawn below | |
792 } | |
793 } | |
794 #if defined(FEAT_SEARCH_EXTRA) | |
795 end_search_hl(); | |
796 #endif | |
797 /* May need to redraw the popup menu. */ | |
798 pum_may_redraw(); | |
799 | |
800 /* Reset b_mod_set flags. Going through all windows is probably faster | |
801 * than going through all buffers (there could be many buffers). */ | |
802 FOR_ALL_WINDOWS(wp) | |
803 wp->w_buffer->b_mod_set = FALSE; | |
804 | |
805 #ifdef FEAT_TEXT_PROP | |
806 // Display popup windows on top of the windows and command line. | |
807 update_popups(win_update); | |
808 #endif | |
809 | |
810 after_updating_screen(TRUE); | |
811 | |
812 /* Clear or redraw the command line. Done last, because scrolling may | |
813 * mess up the command line. */ | |
814 if (clear_cmdline || redraw_cmdline || redraw_mode) | |
815 showmode(); | |
816 | |
817 if (no_update) | |
818 --no_win_do_lines_ins; | |
819 | |
820 /* May put up an introductory message when not editing a file */ | |
821 if (!did_intro) | |
822 maybe_intro_message(); | |
823 did_intro = TRUE; | |
824 | |
825 #ifdef FEAT_GUI | |
826 /* Redraw the cursor and update the scrollbars when all screen updating is | |
827 * done. */ | |
828 if (gui.in_use) | |
829 { | |
830 if (did_undraw && !gui_mch_is_blink_off()) | |
831 { | |
832 mch_disable_flush(); | |
833 out_flush(); /* required before updating the cursor */ | |
834 mch_enable_flush(); | |
835 | |
836 /* Put the GUI position where the cursor was, gui_update_cursor() | |
837 * uses that. */ | |
838 gui.col = gui_cursor_col; | |
839 gui.row = gui_cursor_row; | |
840 gui.col = mb_fix_col(gui.col, gui.row); | |
841 gui_update_cursor(FALSE, FALSE); | |
842 gui_may_flush(); | |
843 screen_cur_col = gui.col; | |
844 screen_cur_row = gui.row; | |
845 } | |
846 else | |
847 out_flush(); | |
848 gui_update_scrollbars(FALSE); | |
849 } | |
850 #endif | |
851 return OK; | |
852 } | |
853 | |
854 #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI) | |
855 /* | |
856 * Prepare for updating one or more windows. | |
857 * Caller must check for "updating_screen" already set to avoid recursiveness. | |
858 */ | |
859 static void | |
860 update_prepare(void) | |
861 { | |
862 cursor_off(); | |
863 updating_screen = TRUE; | |
864 #ifdef FEAT_GUI | |
865 /* Remove the cursor before starting to do anything, because scrolling may | |
866 * make it difficult to redraw the text under it. */ | |
867 if (gui.in_use) | |
868 gui_undraw_cursor(); | |
869 #endif | |
870 #ifdef FEAT_SEARCH_EXTRA | |
871 start_search_hl(); | |
872 #endif | |
873 #ifdef FEAT_TEXT_PROP | |
874 // Update popup_mask if needed. | |
875 may_update_popup_mask(must_redraw); | |
876 #endif | |
877 } | |
878 | |
879 /* | |
880 * Finish updating one or more windows. | |
881 */ | |
882 static void | |
883 update_finish(void) | |
884 { | |
885 if (redraw_cmdline || redraw_mode) | |
886 showmode(); | |
887 | |
888 # ifdef FEAT_SEARCH_EXTRA | |
889 end_search_hl(); | |
890 # endif | |
891 | |
892 after_updating_screen(TRUE); | |
893 | |
894 # ifdef FEAT_GUI | |
895 /* Redraw the cursor and update the scrollbars when all screen updating is | |
896 * done. */ | |
897 if (gui.in_use) | |
898 { | |
899 out_flush_cursor(FALSE, FALSE); | |
900 gui_update_scrollbars(FALSE); | |
901 } | |
902 # endif | |
903 } | |
904 #endif | |
905 | 58 |
906 #if defined(FEAT_CONCEAL) || defined(PROTO) | 59 #if defined(FEAT_CONCEAL) || defined(PROTO) |
907 /* | 60 /* |
908 * Return TRUE if the cursor line in window "wp" may be concealed, according | 61 * Return TRUE if the cursor line in window "wp" may be concealed, according |
909 * to the 'concealcursor' option. | 62 * to the 'concealcursor' option. |
942 curs_columns(TRUE); | 95 curs_columns(TRUE); |
943 } | 96 } |
944 } | 97 } |
945 #endif | 98 #endif |
946 | 99 |
947 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO) | |
948 void | |
949 update_debug_sign(buf_T *buf, linenr_T lnum) | |
950 { | |
951 win_T *wp; | |
952 int doit = FALSE; | |
953 | |
954 # ifdef FEAT_FOLDING | |
955 win_foldinfo.fi_level = 0; | |
956 # endif | |
957 | |
958 // update/delete a specific sign | |
959 redraw_buf_line_later(buf, lnum); | |
960 | |
961 // check if it resulted in the need to redraw a window | |
962 FOR_ALL_WINDOWS(wp) | |
963 if (wp->w_redr_type != 0) | |
964 doit = TRUE; | |
965 | |
966 /* Return when there is nothing to do, screen updating is already | |
967 * happening (recursive call), messages on the screen or still starting up. | |
968 */ | |
969 if (!doit || updating_screen | |
970 || State == ASKMORE || State == HITRETURN | |
971 || msg_scrolled | |
972 #ifdef FEAT_GUI | |
973 || gui.starting | |
974 #endif | |
975 || starting) | |
976 return; | |
977 | |
978 /* update all windows that need updating */ | |
979 update_prepare(); | |
980 | |
981 FOR_ALL_WINDOWS(wp) | |
982 { | |
983 if (wp->w_redr_type != 0) | |
984 win_update(wp); | |
985 if (wp->w_redr_status) | |
986 win_redr_status(wp, FALSE); | |
987 } | |
988 | |
989 update_finish(); | |
990 } | |
991 #endif | |
992 | |
993 /* | 100 /* |
994 * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup | 101 * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup |
995 * window then get the "Pmenu" highlight attribute. | 102 * window then get the "Pmenu" highlight attribute. |
996 */ | 103 */ |
997 int | 104 int |
1009 else | 116 else |
1010 wcr_attr = HL_ATTR(HLF_PNI); // Pmenu | 117 wcr_attr = HL_ATTR(HLF_PNI); // Pmenu |
1011 } | 118 } |
1012 #endif | 119 #endif |
1013 return wcr_attr; | 120 return wcr_attr; |
1014 } | |
1015 | |
1016 #if defined(FEAT_GUI) || defined(PROTO) | |
1017 /* | |
1018 * Update a single window, its status line and maybe the command line msg. | |
1019 * Used for the GUI scrollbar. | |
1020 */ | |
1021 void | |
1022 updateWindow(win_T *wp) | |
1023 { | |
1024 /* return if already busy updating */ | |
1025 if (updating_screen) | |
1026 return; | |
1027 | |
1028 update_prepare(); | |
1029 | |
1030 #ifdef FEAT_CLIPBOARD | |
1031 /* When Visual area changed, may have to update selection. */ | |
1032 if (clip_star.available && clip_isautosel_star()) | |
1033 clip_update_selection(&clip_star); | |
1034 if (clip_plus.available && clip_isautosel_plus()) | |
1035 clip_update_selection(&clip_plus); | |
1036 #endif | |
1037 | |
1038 win_update(wp); | |
1039 | |
1040 /* When the screen was cleared redraw the tab pages line. */ | |
1041 if (redraw_tabline) | |
1042 draw_tabline(); | |
1043 | |
1044 if (wp->w_redr_status | |
1045 # ifdef FEAT_CMDL_INFO | |
1046 || p_ru | |
1047 # endif | |
1048 # ifdef FEAT_STL_OPT | |
1049 || *p_stl != NUL || *wp->w_p_stl != NUL | |
1050 # endif | |
1051 ) | |
1052 win_redr_status(wp, FALSE); | |
1053 | |
1054 #ifdef FEAT_TEXT_PROP | |
1055 // Display popup windows on top of everything. | |
1056 update_popups(win_update); | |
1057 #endif | |
1058 | |
1059 update_finish(); | |
1060 } | |
1061 #endif | |
1062 | |
1063 /* | |
1064 * Update a single window. | |
1065 * | |
1066 * This may cause the windows below it also to be redrawn (when clearing the | |
1067 * screen or scrolling lines). | |
1068 * | |
1069 * How the window is redrawn depends on wp->w_redr_type. Each type also | |
1070 * implies the one below it. | |
1071 * NOT_VALID redraw the whole window | |
1072 * SOME_VALID redraw the whole window but do scroll when possible | |
1073 * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID | |
1074 * INVERTED redraw the changed part of the Visual area | |
1075 * INVERTED_ALL redraw the whole Visual area | |
1076 * VALID 1. scroll up/down to adjust for a changed w_topline | |
1077 * 2. update lines at the top when scrolled down | |
1078 * 3. redraw changed text: | |
1079 * - if wp->w_buffer->b_mod_set set, update lines between | |
1080 * b_mod_top and b_mod_bot. | |
1081 * - if wp->w_redraw_top non-zero, redraw lines between | |
1082 * wp->w_redraw_top and wp->w_redr_bot. | |
1083 * - continue redrawing when syntax status is invalid. | |
1084 * 4. if scrolled up, update lines at the bottom. | |
1085 * This results in three areas that may need updating: | |
1086 * top: from first row to top_end (when scrolled down) | |
1087 * mid: from mid_start to mid_end (update inversion or changed text) | |
1088 * bot: from bot_start to last row (when scrolled up) | |
1089 */ | |
1090 static void | |
1091 win_update(win_T *wp) | |
1092 { | |
1093 buf_T *buf = wp->w_buffer; | |
1094 int type; | |
1095 int top_end = 0; /* Below last row of the top area that needs | |
1096 updating. 0 when no top area updating. */ | |
1097 int mid_start = 999;/* first row of the mid area that needs | |
1098 updating. 999 when no mid area updating. */ | |
1099 int mid_end = 0; /* Below last row of the mid area that needs | |
1100 updating. 0 when no mid area updating. */ | |
1101 int bot_start = 999;/* first row of the bot area that needs | |
1102 updating. 999 when no bot area updating */ | |
1103 int scrolled_down = FALSE; /* TRUE when scrolled down when | |
1104 w_topline got smaller a bit */ | |
1105 #ifdef FEAT_SEARCH_EXTRA | |
1106 int top_to_mod = FALSE; // redraw above mod_top | |
1107 #endif | |
1108 | |
1109 int row; /* current window row to display */ | |
1110 linenr_T lnum; /* current buffer lnum to display */ | |
1111 int idx; /* current index in w_lines[] */ | |
1112 int srow; /* starting row of the current line */ | |
1113 | |
1114 int eof = FALSE; /* if TRUE, we hit the end of the file */ | |
1115 int didline = FALSE; /* if TRUE, we finished the last line */ | |
1116 int i; | |
1117 long j; | |
1118 static int recursive = FALSE; /* being called recursively */ | |
1119 int old_botline = wp->w_botline; | |
1120 #ifdef FEAT_FOLDING | |
1121 long fold_count; | |
1122 #endif | |
1123 #ifdef FEAT_SYN_HL | |
1124 /* remember what happened to the previous line, to know if | |
1125 * check_visual_highlight() can be used */ | |
1126 #define DID_NONE 1 /* didn't update a line */ | |
1127 #define DID_LINE 2 /* updated a normal line */ | |
1128 #define DID_FOLD 3 /* updated a folded line */ | |
1129 int did_update = DID_NONE; | |
1130 linenr_T syntax_last_parsed = 0; /* last parsed text line */ | |
1131 #endif | |
1132 linenr_T mod_top = 0; | |
1133 linenr_T mod_bot = 0; | |
1134 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) | |
1135 int save_got_int; | |
1136 #endif | |
1137 #ifdef SYN_TIME_LIMIT | |
1138 proftime_T syntax_tm; | |
1139 #endif | |
1140 | |
1141 type = wp->w_redr_type; | |
1142 | |
1143 if (type == NOT_VALID) | |
1144 { | |
1145 wp->w_redr_status = TRUE; | |
1146 wp->w_lines_valid = 0; | |
1147 } | |
1148 | |
1149 /* Window is zero-height: nothing to draw. */ | |
1150 if (wp->w_height + WINBAR_HEIGHT(wp) == 0) | |
1151 { | |
1152 wp->w_redr_type = 0; | |
1153 return; | |
1154 } | |
1155 | |
1156 /* Window is zero-width: Only need to draw the separator. */ | |
1157 if (wp->w_width == 0) | |
1158 { | |
1159 /* draw the vertical separator right of this window */ | |
1160 draw_vsep_win(wp, 0); | |
1161 wp->w_redr_type = 0; | |
1162 return; | |
1163 } | |
1164 | |
1165 #ifdef FEAT_TERMINAL | |
1166 // If this window contains a terminal, redraw works completely differently. | |
1167 if (term_do_update_window(wp)) | |
1168 { | |
1169 term_update_window(wp); | |
1170 # ifdef FEAT_MENU | |
1171 /* Draw the window toolbar, if there is one. */ | |
1172 if (winbar_height(wp) > 0) | |
1173 redraw_win_toolbar(wp); | |
1174 # endif | |
1175 wp->w_redr_type = 0; | |
1176 return; | |
1177 } | |
1178 #endif | |
1179 | |
1180 #ifdef FEAT_SEARCH_EXTRA | |
1181 init_search_hl(wp, &search_hl); | |
1182 #endif | |
1183 | |
1184 #ifdef FEAT_LINEBREAK | |
1185 /* Force redraw when width of 'number' or 'relativenumber' column | |
1186 * changes. */ | |
1187 i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0; | |
1188 if (wp->w_nrwidth != i) | |
1189 { | |
1190 type = NOT_VALID; | |
1191 wp->w_nrwidth = i; | |
1192 } | |
1193 else | |
1194 #endif | |
1195 | |
1196 if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0) | |
1197 { | |
1198 /* | |
1199 * When there are both inserted/deleted lines and specific lines to be | |
1200 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw | |
1201 * everything (only happens when redrawing is off for while). | |
1202 */ | |
1203 type = NOT_VALID; | |
1204 } | |
1205 else | |
1206 { | |
1207 /* | |
1208 * Set mod_top to the first line that needs displaying because of | |
1209 * changes. Set mod_bot to the first line after the changes. | |
1210 */ | |
1211 mod_top = wp->w_redraw_top; | |
1212 if (wp->w_redraw_bot != 0) | |
1213 mod_bot = wp->w_redraw_bot + 1; | |
1214 else | |
1215 mod_bot = 0; | |
1216 if (buf->b_mod_set) | |
1217 { | |
1218 if (mod_top == 0 || mod_top > buf->b_mod_top) | |
1219 { | |
1220 mod_top = buf->b_mod_top; | |
1221 #ifdef FEAT_SYN_HL | |
1222 /* Need to redraw lines above the change that may be included | |
1223 * in a pattern match. */ | |
1224 if (syntax_present(wp)) | |
1225 { | |
1226 mod_top -= buf->b_s.b_syn_sync_linebreaks; | |
1227 if (mod_top < 1) | |
1228 mod_top = 1; | |
1229 } | |
1230 #endif | |
1231 } | |
1232 if (mod_bot == 0 || mod_bot < buf->b_mod_bot) | |
1233 mod_bot = buf->b_mod_bot; | |
1234 | |
1235 #ifdef FEAT_SEARCH_EXTRA | |
1236 // When 'hlsearch' is on and using a multi-line search pattern, a | |
1237 // change in one line may make the Search highlighting in a | |
1238 // previous line invalid. Simple solution: redraw all visible | |
1239 // lines above the change. | |
1240 // Same for a match pattern. | |
1241 if (search_hl.rm.regprog != NULL | |
1242 && re_multiline(search_hl.rm.regprog)) | |
1243 top_to_mod = TRUE; | |
1244 else | |
1245 { | |
1246 matchitem_T *cur = wp->w_match_head; | |
1247 | |
1248 while (cur != NULL) | |
1249 { | |
1250 if (cur->match.regprog != NULL | |
1251 && re_multiline(cur->match.regprog)) | |
1252 { | |
1253 top_to_mod = TRUE; | |
1254 break; | |
1255 } | |
1256 cur = cur->next; | |
1257 } | |
1258 } | |
1259 #endif | |
1260 } | |
1261 #ifdef FEAT_FOLDING | |
1262 if (mod_top != 0 && hasAnyFolding(wp)) | |
1263 { | |
1264 linenr_T lnumt, lnumb; | |
1265 | |
1266 /* | |
1267 * A change in a line can cause lines above it to become folded or | |
1268 * unfolded. Find the top most buffer line that may be affected. | |
1269 * If the line was previously folded and displayed, get the first | |
1270 * line of that fold. If the line is folded now, get the first | |
1271 * folded line. Use the minimum of these two. | |
1272 */ | |
1273 | |
1274 /* Find last valid w_lines[] entry above mod_top. Set lnumt to | |
1275 * the line below it. If there is no valid entry, use w_topline. | |
1276 * Find the first valid w_lines[] entry below mod_bot. Set lnumb | |
1277 * to this line. If there is no valid entry, use MAXLNUM. */ | |
1278 lnumt = wp->w_topline; | |
1279 lnumb = MAXLNUM; | |
1280 for (i = 0; i < wp->w_lines_valid; ++i) | |
1281 if (wp->w_lines[i].wl_valid) | |
1282 { | |
1283 if (wp->w_lines[i].wl_lastlnum < mod_top) | |
1284 lnumt = wp->w_lines[i].wl_lastlnum + 1; | |
1285 if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot) | |
1286 { | |
1287 lnumb = wp->w_lines[i].wl_lnum; | |
1288 /* When there is a fold column it might need updating | |
1289 * in the next line ("J" just above an open fold). */ | |
1290 if (compute_foldcolumn(wp, 0) > 0) | |
1291 ++lnumb; | |
1292 } | |
1293 } | |
1294 | |
1295 (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL); | |
1296 if (mod_top > lnumt) | |
1297 mod_top = lnumt; | |
1298 | |
1299 /* Now do the same for the bottom line (one above mod_bot). */ | |
1300 --mod_bot; | |
1301 (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL); | |
1302 ++mod_bot; | |
1303 if (mod_bot < lnumb) | |
1304 mod_bot = lnumb; | |
1305 } | |
1306 #endif | |
1307 | |
1308 /* When a change starts above w_topline and the end is below | |
1309 * w_topline, start redrawing at w_topline. | |
1310 * If the end of the change is above w_topline: do like no change was | |
1311 * made, but redraw the first line to find changes in syntax. */ | |
1312 if (mod_top != 0 && mod_top < wp->w_topline) | |
1313 { | |
1314 if (mod_bot > wp->w_topline) | |
1315 mod_top = wp->w_topline; | |
1316 #ifdef FEAT_SYN_HL | |
1317 else if (syntax_present(wp)) | |
1318 top_end = 1; | |
1319 #endif | |
1320 } | |
1321 | |
1322 /* When line numbers are displayed need to redraw all lines below | |
1323 * inserted/deleted lines. */ | |
1324 if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu) | |
1325 mod_bot = MAXLNUM; | |
1326 } | |
1327 wp->w_redraw_top = 0; // reset for next time | |
1328 wp->w_redraw_bot = 0; | |
1329 | |
1330 /* | |
1331 * When only displaying the lines at the top, set top_end. Used when | |
1332 * window has scrolled down for msg_scrolled. | |
1333 */ | |
1334 if (type == REDRAW_TOP) | |
1335 { | |
1336 j = 0; | |
1337 for (i = 0; i < wp->w_lines_valid; ++i) | |
1338 { | |
1339 j += wp->w_lines[i].wl_size; | |
1340 if (j >= wp->w_upd_rows) | |
1341 { | |
1342 top_end = j; | |
1343 break; | |
1344 } | |
1345 } | |
1346 if (top_end == 0) | |
1347 /* not found (cannot happen?): redraw everything */ | |
1348 type = NOT_VALID; | |
1349 else | |
1350 /* top area defined, the rest is VALID */ | |
1351 type = VALID; | |
1352 } | |
1353 | |
1354 /* Trick: we want to avoid clearing the screen twice. screenclear() will | |
1355 * set "screen_cleared" to TRUE. The special value MAYBE (which is still | |
1356 * non-zero and thus not FALSE) will indicate that screenclear() was not | |
1357 * called. */ | |
1358 if (screen_cleared) | |
1359 screen_cleared = MAYBE; | |
1360 | |
1361 /* | |
1362 * If there are no changes on the screen that require a complete redraw, | |
1363 * handle three cases: | |
1364 * 1: we are off the top of the screen by a few lines: scroll down | |
1365 * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up | |
1366 * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in | |
1367 * w_lines[] that needs updating. | |
1368 */ | |
1369 if ((type == VALID || type == SOME_VALID | |
1370 || type == INVERTED || type == INVERTED_ALL) | |
1371 #ifdef FEAT_DIFF | |
1372 && !wp->w_botfill && !wp->w_old_botfill | |
1373 #endif | |
1374 ) | |
1375 { | |
1376 if (mod_top != 0 && wp->w_topline == mod_top) | |
1377 { | |
1378 /* | |
1379 * w_topline is the first changed line, the scrolling will be done | |
1380 * further down. | |
1381 */ | |
1382 } | |
1383 else if (wp->w_lines[0].wl_valid | |
1384 && (wp->w_topline < wp->w_lines[0].wl_lnum | |
1385 #ifdef FEAT_DIFF | |
1386 || (wp->w_topline == wp->w_lines[0].wl_lnum | |
1387 && wp->w_topfill > wp->w_old_topfill) | |
1388 #endif | |
1389 )) | |
1390 { | |
1391 /* | |
1392 * New topline is above old topline: May scroll down. | |
1393 */ | |
1394 #ifdef FEAT_FOLDING | |
1395 if (hasAnyFolding(wp)) | |
1396 { | |
1397 linenr_T ln; | |
1398 | |
1399 /* count the number of lines we are off, counting a sequence | |
1400 * of folded lines as one */ | |
1401 j = 0; | |
1402 for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln) | |
1403 { | |
1404 ++j; | |
1405 if (j >= wp->w_height - 2) | |
1406 break; | |
1407 (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL); | |
1408 } | |
1409 } | |
1410 else | |
1411 #endif | |
1412 j = wp->w_lines[0].wl_lnum - wp->w_topline; | |
1413 if (j < wp->w_height - 2) /* not too far off */ | |
1414 { | |
1415 i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); | |
1416 #ifdef FEAT_DIFF | |
1417 /* insert extra lines for previously invisible filler lines */ | |
1418 if (wp->w_lines[0].wl_lnum != wp->w_topline) | |
1419 i += diff_check_fill(wp, wp->w_lines[0].wl_lnum) | |
1420 - wp->w_old_topfill; | |
1421 #endif | |
1422 if (i < wp->w_height - 2) /* less than a screen off */ | |
1423 { | |
1424 /* | |
1425 * Try to insert the correct number of lines. | |
1426 * If not the last window, delete the lines at the bottom. | |
1427 * win_ins_lines may fail when the terminal can't do it. | |
1428 */ | |
1429 if (i > 0) | |
1430 check_for_delay(FALSE); | |
1431 if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK) | |
1432 { | |
1433 if (wp->w_lines_valid != 0) | |
1434 { | |
1435 /* Need to update rows that are new, stop at the | |
1436 * first one that scrolled down. */ | |
1437 top_end = i; | |
1438 scrolled_down = TRUE; | |
1439 | |
1440 /* Move the entries that were scrolled, disable | |
1441 * the entries for the lines to be redrawn. */ | |
1442 if ((wp->w_lines_valid += j) > wp->w_height) | |
1443 wp->w_lines_valid = wp->w_height; | |
1444 for (idx = wp->w_lines_valid; idx - j >= 0; idx--) | |
1445 wp->w_lines[idx] = wp->w_lines[idx - j]; | |
1446 while (idx >= 0) | |
1447 wp->w_lines[idx--].wl_valid = FALSE; | |
1448 } | |
1449 } | |
1450 else | |
1451 mid_start = 0; /* redraw all lines */ | |
1452 } | |
1453 else | |
1454 mid_start = 0; /* redraw all lines */ | |
1455 } | |
1456 else | |
1457 mid_start = 0; /* redraw all lines */ | |
1458 } | |
1459 else | |
1460 { | |
1461 /* | |
1462 * New topline is at or below old topline: May scroll up. | |
1463 * When topline didn't change, find first entry in w_lines[] that | |
1464 * needs updating. | |
1465 */ | |
1466 | |
1467 /* try to find wp->w_topline in wp->w_lines[].wl_lnum */ | |
1468 j = -1; | |
1469 row = 0; | |
1470 for (i = 0; i < wp->w_lines_valid; i++) | |
1471 { | |
1472 if (wp->w_lines[i].wl_valid | |
1473 && wp->w_lines[i].wl_lnum == wp->w_topline) | |
1474 { | |
1475 j = i; | |
1476 break; | |
1477 } | |
1478 row += wp->w_lines[i].wl_size; | |
1479 } | |
1480 if (j == -1) | |
1481 { | |
1482 /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all | |
1483 * lines */ | |
1484 mid_start = 0; | |
1485 } | |
1486 else | |
1487 { | |
1488 /* | |
1489 * Try to delete the correct number of lines. | |
1490 * wp->w_topline is at wp->w_lines[i].wl_lnum. | |
1491 */ | |
1492 #ifdef FEAT_DIFF | |
1493 /* If the topline didn't change, delete old filler lines, | |
1494 * otherwise delete filler lines of the new topline... */ | |
1495 if (wp->w_lines[0].wl_lnum == wp->w_topline) | |
1496 row += wp->w_old_topfill; | |
1497 else | |
1498 row += diff_check_fill(wp, wp->w_topline); | |
1499 /* ... but don't delete new filler lines. */ | |
1500 row -= wp->w_topfill; | |
1501 #endif | |
1502 if (row > 0) | |
1503 { | |
1504 check_for_delay(FALSE); | |
1505 if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0) | |
1506 == OK) | |
1507 bot_start = wp->w_height - row; | |
1508 else | |
1509 mid_start = 0; /* redraw all lines */ | |
1510 } | |
1511 if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) | |
1512 { | |
1513 /* | |
1514 * Skip the lines (below the deleted lines) that are still | |
1515 * valid and don't need redrawing. Copy their info | |
1516 * upwards, to compensate for the deleted lines. Set | |
1517 * bot_start to the first row that needs redrawing. | |
1518 */ | |
1519 bot_start = 0; | |
1520 idx = 0; | |
1521 for (;;) | |
1522 { | |
1523 wp->w_lines[idx] = wp->w_lines[j]; | |
1524 /* stop at line that didn't fit, unless it is still | |
1525 * valid (no lines deleted) */ | |
1526 if (row > 0 && bot_start + row | |
1527 + (int)wp->w_lines[j].wl_size > wp->w_height) | |
1528 { | |
1529 wp->w_lines_valid = idx + 1; | |
1530 break; | |
1531 } | |
1532 bot_start += wp->w_lines[idx++].wl_size; | |
1533 | |
1534 /* stop at the last valid entry in w_lines[].wl_size */ | |
1535 if (++j >= wp->w_lines_valid) | |
1536 { | |
1537 wp->w_lines_valid = idx; | |
1538 break; | |
1539 } | |
1540 } | |
1541 #ifdef FEAT_DIFF | |
1542 /* Correct the first entry for filler lines at the top | |
1543 * when it won't get updated below. */ | |
1544 if (wp->w_p_diff && bot_start > 0) | |
1545 wp->w_lines[0].wl_size = | |
1546 plines_win_nofill(wp, wp->w_topline, TRUE) | |
1547 + wp->w_topfill; | |
1548 #endif | |
1549 } | |
1550 } | |
1551 } | |
1552 | |
1553 /* When starting redraw in the first line, redraw all lines. When | |
1554 * there is only one window it's probably faster to clear the screen | |
1555 * first. */ | |
1556 if (mid_start == 0) | |
1557 { | |
1558 mid_end = wp->w_height; | |
1559 if (ONE_WINDOW && !WIN_IS_POPUP(wp)) | |
1560 { | |
1561 /* Clear the screen when it was not done by win_del_lines() or | |
1562 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE | |
1563 * then. */ | |
1564 if (screen_cleared != TRUE) | |
1565 screenclear(); | |
1566 /* The screen was cleared, redraw the tab pages line. */ | |
1567 if (redraw_tabline) | |
1568 draw_tabline(); | |
1569 } | |
1570 } | |
1571 | |
1572 /* When win_del_lines() or win_ins_lines() caused the screen to be | |
1573 * cleared (only happens for the first window) or when screenclear() | |
1574 * was called directly above, "must_redraw" will have been set to | |
1575 * NOT_VALID, need to reset it here to avoid redrawing twice. */ | |
1576 if (screen_cleared == TRUE) | |
1577 must_redraw = 0; | |
1578 } | |
1579 else | |
1580 { | |
1581 /* Not VALID or INVERTED: redraw all lines. */ | |
1582 mid_start = 0; | |
1583 mid_end = wp->w_height; | |
1584 } | |
1585 | |
1586 if (type == SOME_VALID) | |
1587 { | |
1588 /* SOME_VALID: redraw all lines. */ | |
1589 mid_start = 0; | |
1590 mid_end = wp->w_height; | |
1591 type = NOT_VALID; | |
1592 } | |
1593 | |
1594 /* check if we are updating or removing the inverted part */ | |
1595 if ((VIsual_active && buf == curwin->w_buffer) | |
1596 || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID)) | |
1597 { | |
1598 linenr_T from, to; | |
1599 | |
1600 if (VIsual_active) | |
1601 { | |
1602 if (VIsual_active | |
1603 && (VIsual_mode != wp->w_old_visual_mode | |
1604 || type == INVERTED_ALL)) | |
1605 { | |
1606 /* | |
1607 * If the type of Visual selection changed, redraw the whole | |
1608 * selection. Also when the ownership of the X selection is | |
1609 * gained or lost. | |
1610 */ | |
1611 if (curwin->w_cursor.lnum < VIsual.lnum) | |
1612 { | |
1613 from = curwin->w_cursor.lnum; | |
1614 to = VIsual.lnum; | |
1615 } | |
1616 else | |
1617 { | |
1618 from = VIsual.lnum; | |
1619 to = curwin->w_cursor.lnum; | |
1620 } | |
1621 /* redraw more when the cursor moved as well */ | |
1622 if (wp->w_old_cursor_lnum < from) | |
1623 from = wp->w_old_cursor_lnum; | |
1624 if (wp->w_old_cursor_lnum > to) | |
1625 to = wp->w_old_cursor_lnum; | |
1626 if (wp->w_old_visual_lnum < from) | |
1627 from = wp->w_old_visual_lnum; | |
1628 if (wp->w_old_visual_lnum > to) | |
1629 to = wp->w_old_visual_lnum; | |
1630 } | |
1631 else | |
1632 { | |
1633 /* | |
1634 * Find the line numbers that need to be updated: The lines | |
1635 * between the old cursor position and the current cursor | |
1636 * position. Also check if the Visual position changed. | |
1637 */ | |
1638 if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum) | |
1639 { | |
1640 from = curwin->w_cursor.lnum; | |
1641 to = wp->w_old_cursor_lnum; | |
1642 } | |
1643 else | |
1644 { | |
1645 from = wp->w_old_cursor_lnum; | |
1646 to = curwin->w_cursor.lnum; | |
1647 if (from == 0) /* Visual mode just started */ | |
1648 from = to; | |
1649 } | |
1650 | |
1651 if (VIsual.lnum != wp->w_old_visual_lnum | |
1652 || VIsual.col != wp->w_old_visual_col) | |
1653 { | |
1654 if (wp->w_old_visual_lnum < from | |
1655 && wp->w_old_visual_lnum != 0) | |
1656 from = wp->w_old_visual_lnum; | |
1657 if (wp->w_old_visual_lnum > to) | |
1658 to = wp->w_old_visual_lnum; | |
1659 if (VIsual.lnum < from) | |
1660 from = VIsual.lnum; | |
1661 if (VIsual.lnum > to) | |
1662 to = VIsual.lnum; | |
1663 } | |
1664 } | |
1665 | |
1666 /* | |
1667 * If in block mode and changed column or curwin->w_curswant: | |
1668 * update all lines. | |
1669 * First compute the actual start and end column. | |
1670 */ | |
1671 if (VIsual_mode == Ctrl_V) | |
1672 { | |
1673 colnr_T fromc, toc; | |
1674 #if defined(FEAT_LINEBREAK) | |
1675 int save_ve_flags = ve_flags; | |
1676 | |
1677 if (curwin->w_p_lbr) | |
1678 ve_flags = VE_ALL; | |
1679 #endif | |
1680 getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc); | |
1681 #if defined(FEAT_LINEBREAK) | |
1682 ve_flags = save_ve_flags; | |
1683 #endif | |
1684 ++toc; | |
1685 if (curwin->w_curswant == MAXCOL) | |
1686 toc = MAXCOL; | |
1687 | |
1688 if (fromc != wp->w_old_cursor_fcol | |
1689 || toc != wp->w_old_cursor_lcol) | |
1690 { | |
1691 if (from > VIsual.lnum) | |
1692 from = VIsual.lnum; | |
1693 if (to < VIsual.lnum) | |
1694 to = VIsual.lnum; | |
1695 } | |
1696 wp->w_old_cursor_fcol = fromc; | |
1697 wp->w_old_cursor_lcol = toc; | |
1698 } | |
1699 } | |
1700 else | |
1701 { | |
1702 /* Use the line numbers of the old Visual area. */ | |
1703 if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum) | |
1704 { | |
1705 from = wp->w_old_cursor_lnum; | |
1706 to = wp->w_old_visual_lnum; | |
1707 } | |
1708 else | |
1709 { | |
1710 from = wp->w_old_visual_lnum; | |
1711 to = wp->w_old_cursor_lnum; | |
1712 } | |
1713 } | |
1714 | |
1715 /* | |
1716 * There is no need to update lines above the top of the window. | |
1717 */ | |
1718 if (from < wp->w_topline) | |
1719 from = wp->w_topline; | |
1720 | |
1721 /* | |
1722 * If we know the value of w_botline, use it to restrict the update to | |
1723 * the lines that are visible in the window. | |
1724 */ | |
1725 if (wp->w_valid & VALID_BOTLINE) | |
1726 { | |
1727 if (from >= wp->w_botline) | |
1728 from = wp->w_botline - 1; | |
1729 if (to >= wp->w_botline) | |
1730 to = wp->w_botline - 1; | |
1731 } | |
1732 | |
1733 /* | |
1734 * Find the minimal part to be updated. | |
1735 * Watch out for scrolling that made entries in w_lines[] invalid. | |
1736 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets | |
1737 * top_end; need to redraw from top_end to the "to" line. | |
1738 * A middle mouse click with a Visual selection may change the text | |
1739 * above the Visual area and reset wl_valid, do count these for | |
1740 * mid_end (in srow). | |
1741 */ | |
1742 if (mid_start > 0) | |
1743 { | |
1744 lnum = wp->w_topline; | |
1745 idx = 0; | |
1746 srow = 0; | |
1747 if (scrolled_down) | |
1748 mid_start = top_end; | |
1749 else | |
1750 mid_start = 0; | |
1751 while (lnum < from && idx < wp->w_lines_valid) /* find start */ | |
1752 { | |
1753 if (wp->w_lines[idx].wl_valid) | |
1754 mid_start += wp->w_lines[idx].wl_size; | |
1755 else if (!scrolled_down) | |
1756 srow += wp->w_lines[idx].wl_size; | |
1757 ++idx; | |
1758 # ifdef FEAT_FOLDING | |
1759 if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid) | |
1760 lnum = wp->w_lines[idx].wl_lnum; | |
1761 else | |
1762 # endif | |
1763 ++lnum; | |
1764 } | |
1765 srow += mid_start; | |
1766 mid_end = wp->w_height; | |
1767 for ( ; idx < wp->w_lines_valid; ++idx) /* find end */ | |
1768 { | |
1769 if (wp->w_lines[idx].wl_valid | |
1770 && wp->w_lines[idx].wl_lnum >= to + 1) | |
1771 { | |
1772 /* Only update until first row of this line */ | |
1773 mid_end = srow; | |
1774 break; | |
1775 } | |
1776 srow += wp->w_lines[idx].wl_size; | |
1777 } | |
1778 } | |
1779 } | |
1780 | |
1781 if (VIsual_active && buf == curwin->w_buffer) | |
1782 { | |
1783 wp->w_old_visual_mode = VIsual_mode; | |
1784 wp->w_old_cursor_lnum = curwin->w_cursor.lnum; | |
1785 wp->w_old_visual_lnum = VIsual.lnum; | |
1786 wp->w_old_visual_col = VIsual.col; | |
1787 wp->w_old_curswant = curwin->w_curswant; | |
1788 } | |
1789 else | |
1790 { | |
1791 wp->w_old_visual_mode = 0; | |
1792 wp->w_old_cursor_lnum = 0; | |
1793 wp->w_old_visual_lnum = 0; | |
1794 wp->w_old_visual_col = 0; | |
1795 } | |
1796 | |
1797 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) | |
1798 /* reset got_int, otherwise regexp won't work */ | |
1799 save_got_int = got_int; | |
1800 got_int = 0; | |
1801 #endif | |
1802 #ifdef SYN_TIME_LIMIT | |
1803 /* Set the time limit to 'redrawtime'. */ | |
1804 profile_setlimit(p_rdt, &syntax_tm); | |
1805 syn_set_timeout(&syntax_tm); | |
1806 #endif | |
1807 #ifdef FEAT_FOLDING | |
1808 win_foldinfo.fi_level = 0; | |
1809 #endif | |
1810 | |
1811 #ifdef FEAT_MENU | |
1812 /* | |
1813 * Draw the window toolbar, if there is one. | |
1814 * TODO: only when needed. | |
1815 */ | |
1816 if (winbar_height(wp) > 0) | |
1817 redraw_win_toolbar(wp); | |
1818 #endif | |
1819 | |
1820 /* | |
1821 * Update all the window rows. | |
1822 */ | |
1823 idx = 0; /* first entry in w_lines[].wl_size */ | |
1824 row = 0; | |
1825 srow = 0; | |
1826 lnum = wp->w_topline; /* first line shown in window */ | |
1827 for (;;) | |
1828 { | |
1829 /* stop updating when reached the end of the window (check for _past_ | |
1830 * the end of the window is at the end of the loop) */ | |
1831 if (row == wp->w_height) | |
1832 { | |
1833 didline = TRUE; | |
1834 break; | |
1835 } | |
1836 | |
1837 /* stop updating when hit the end of the file */ | |
1838 if (lnum > buf->b_ml.ml_line_count) | |
1839 { | |
1840 eof = TRUE; | |
1841 break; | |
1842 } | |
1843 | |
1844 /* Remember the starting row of the line that is going to be dealt | |
1845 * with. It is used further down when the line doesn't fit. */ | |
1846 srow = row; | |
1847 | |
1848 /* | |
1849 * Update a line when it is in an area that needs updating, when it | |
1850 * has changes or w_lines[idx] is invalid. | |
1851 * "bot_start" may be halfway a wrapped line after using | |
1852 * win_del_lines(), check if the current line includes it. | |
1853 * When syntax folding is being used, the saved syntax states will | |
1854 * already have been updated, we can't see where the syntax state is | |
1855 * the same again, just update until the end of the window. | |
1856 */ | |
1857 if (row < top_end | |
1858 || (row >= mid_start && row < mid_end) | |
1859 #ifdef FEAT_SEARCH_EXTRA | |
1860 || top_to_mod | |
1861 #endif | |
1862 || idx >= wp->w_lines_valid | |
1863 || (row + wp->w_lines[idx].wl_size > bot_start) | |
1864 || (mod_top != 0 | |
1865 && (lnum == mod_top | |
1866 || (lnum >= mod_top | |
1867 && (lnum < mod_bot | |
1868 #ifdef FEAT_SYN_HL | |
1869 || did_update == DID_FOLD | |
1870 || (did_update == DID_LINE | |
1871 && syntax_present(wp) | |
1872 && ( | |
1873 # ifdef FEAT_FOLDING | |
1874 (foldmethodIsSyntax(wp) | |
1875 && hasAnyFolding(wp)) || | |
1876 # endif | |
1877 syntax_check_changed(lnum))) | |
1878 #endif | |
1879 #ifdef FEAT_SEARCH_EXTRA | |
1880 /* match in fixed position might need redraw | |
1881 * if lines were inserted or deleted */ | |
1882 || (wp->w_match_head != NULL | |
1883 && buf->b_mod_xlines != 0) | |
1884 #endif | |
1885 ))))) | |
1886 { | |
1887 #ifdef FEAT_SEARCH_EXTRA | |
1888 if (lnum == mod_top) | |
1889 top_to_mod = FALSE; | |
1890 #endif | |
1891 | |
1892 /* | |
1893 * When at start of changed lines: May scroll following lines | |
1894 * up or down to minimize redrawing. | |
1895 * Don't do this when the change continues until the end. | |
1896 * Don't scroll when dollar_vcol >= 0, keep the "$". | |
1897 */ | |
1898 if (lnum == mod_top | |
1899 && mod_bot != MAXLNUM | |
1900 && !(dollar_vcol >= 0 && mod_bot == mod_top + 1)) | |
1901 { | |
1902 int old_rows = 0; | |
1903 int new_rows = 0; | |
1904 int xtra_rows; | |
1905 linenr_T l; | |
1906 | |
1907 /* Count the old number of window rows, using w_lines[], which | |
1908 * should still contain the sizes for the lines as they are | |
1909 * currently displayed. */ | |
1910 for (i = idx; i < wp->w_lines_valid; ++i) | |
1911 { | |
1912 /* Only valid lines have a meaningful wl_lnum. Invalid | |
1913 * lines are part of the changed area. */ | |
1914 if (wp->w_lines[i].wl_valid | |
1915 && wp->w_lines[i].wl_lnum == mod_bot) | |
1916 break; | |
1917 old_rows += wp->w_lines[i].wl_size; | |
1918 #ifdef FEAT_FOLDING | |
1919 if (wp->w_lines[i].wl_valid | |
1920 && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) | |
1921 { | |
1922 /* Must have found the last valid entry above mod_bot. | |
1923 * Add following invalid entries. */ | |
1924 ++i; | |
1925 while (i < wp->w_lines_valid | |
1926 && !wp->w_lines[i].wl_valid) | |
1927 old_rows += wp->w_lines[i++].wl_size; | |
1928 break; | |
1929 } | |
1930 #endif | |
1931 } | |
1932 | |
1933 if (i >= wp->w_lines_valid) | |
1934 { | |
1935 /* We can't find a valid line below the changed lines, | |
1936 * need to redraw until the end of the window. | |
1937 * Inserting/deleting lines has no use. */ | |
1938 bot_start = 0; | |
1939 } | |
1940 else | |
1941 { | |
1942 /* Able to count old number of rows: Count new window | |
1943 * rows, and may insert/delete lines */ | |
1944 j = idx; | |
1945 for (l = lnum; l < mod_bot; ++l) | |
1946 { | |
1947 #ifdef FEAT_FOLDING | |
1948 if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL)) | |
1949 ++new_rows; | |
1950 else | |
1951 #endif | |
1952 #ifdef FEAT_DIFF | |
1953 if (l == wp->w_topline) | |
1954 new_rows += plines_win_nofill(wp, l, TRUE) | |
1955 + wp->w_topfill; | |
1956 else | |
1957 #endif | |
1958 new_rows += plines_win(wp, l, TRUE); | |
1959 ++j; | |
1960 if (new_rows > wp->w_height - row - 2) | |
1961 { | |
1962 /* it's getting too much, must redraw the rest */ | |
1963 new_rows = 9999; | |
1964 break; | |
1965 } | |
1966 } | |
1967 xtra_rows = new_rows - old_rows; | |
1968 if (xtra_rows < 0) | |
1969 { | |
1970 /* May scroll text up. If there is not enough | |
1971 * remaining text or scrolling fails, must redraw the | |
1972 * rest. If scrolling works, must redraw the text | |
1973 * below the scrolled text. */ | |
1974 if (row - xtra_rows >= wp->w_height - 2) | |
1975 mod_bot = MAXLNUM; | |
1976 else | |
1977 { | |
1978 check_for_delay(FALSE); | |
1979 if (win_del_lines(wp, row, | |
1980 -xtra_rows, FALSE, FALSE, 0) == FAIL) | |
1981 mod_bot = MAXLNUM; | |
1982 else | |
1983 bot_start = wp->w_height + xtra_rows; | |
1984 } | |
1985 } | |
1986 else if (xtra_rows > 0) | |
1987 { | |
1988 /* May scroll text down. If there is not enough | |
1989 * remaining text of scrolling fails, must redraw the | |
1990 * rest. */ | |
1991 if (row + xtra_rows >= wp->w_height - 2) | |
1992 mod_bot = MAXLNUM; | |
1993 else | |
1994 { | |
1995 check_for_delay(FALSE); | |
1996 if (win_ins_lines(wp, row + old_rows, | |
1997 xtra_rows, FALSE, FALSE) == FAIL) | |
1998 mod_bot = MAXLNUM; | |
1999 else if (top_end > row + old_rows) | |
2000 /* Scrolled the part at the top that requires | |
2001 * updating down. */ | |
2002 top_end += xtra_rows; | |
2003 } | |
2004 } | |
2005 | |
2006 /* When not updating the rest, may need to move w_lines[] | |
2007 * entries. */ | |
2008 if (mod_bot != MAXLNUM && i != j) | |
2009 { | |
2010 if (j < i) | |
2011 { | |
2012 int x = row + new_rows; | |
2013 | |
2014 /* move entries in w_lines[] upwards */ | |
2015 for (;;) | |
2016 { | |
2017 /* stop at last valid entry in w_lines[] */ | |
2018 if (i >= wp->w_lines_valid) | |
2019 { | |
2020 wp->w_lines_valid = j; | |
2021 break; | |
2022 } | |
2023 wp->w_lines[j] = wp->w_lines[i]; | |
2024 /* stop at a line that won't fit */ | |
2025 if (x + (int)wp->w_lines[j].wl_size | |
2026 > wp->w_height) | |
2027 { | |
2028 wp->w_lines_valid = j + 1; | |
2029 break; | |
2030 } | |
2031 x += wp->w_lines[j++].wl_size; | |
2032 ++i; | |
2033 } | |
2034 if (bot_start > x) | |
2035 bot_start = x; | |
2036 } | |
2037 else /* j > i */ | |
2038 { | |
2039 /* move entries in w_lines[] downwards */ | |
2040 j -= i; | |
2041 wp->w_lines_valid += j; | |
2042 if (wp->w_lines_valid > wp->w_height) | |
2043 wp->w_lines_valid = wp->w_height; | |
2044 for (i = wp->w_lines_valid; i - j >= idx; --i) | |
2045 wp->w_lines[i] = wp->w_lines[i - j]; | |
2046 | |
2047 /* The w_lines[] entries for inserted lines are | |
2048 * now invalid, but wl_size may be used above. | |
2049 * Reset to zero. */ | |
2050 while (i >= idx) | |
2051 { | |
2052 wp->w_lines[i].wl_size = 0; | |
2053 wp->w_lines[i--].wl_valid = FALSE; | |
2054 } | |
2055 } | |
2056 } | |
2057 } | |
2058 } | |
2059 | |
2060 #ifdef FEAT_FOLDING | |
2061 /* | |
2062 * When lines are folded, display one line for all of them. | |
2063 * Otherwise, display normally (can be several display lines when | |
2064 * 'wrap' is on). | |
2065 */ | |
2066 fold_count = foldedCount(wp, lnum, &win_foldinfo); | |
2067 if (fold_count != 0) | |
2068 { | |
2069 fold_line(wp, fold_count, &win_foldinfo, lnum, row); | |
2070 ++row; | |
2071 --fold_count; | |
2072 wp->w_lines[idx].wl_folded = TRUE; | |
2073 wp->w_lines[idx].wl_lastlnum = lnum + fold_count; | |
2074 # ifdef FEAT_SYN_HL | |
2075 did_update = DID_FOLD; | |
2076 # endif | |
2077 } | |
2078 else | |
2079 #endif | |
2080 if (idx < wp->w_lines_valid | |
2081 && wp->w_lines[idx].wl_valid | |
2082 && wp->w_lines[idx].wl_lnum == lnum | |
2083 && lnum > wp->w_topline | |
2084 && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) | |
2085 && !WIN_IS_POPUP(wp) | |
2086 && srow + wp->w_lines[idx].wl_size > wp->w_height | |
2087 #ifdef FEAT_DIFF | |
2088 && diff_check_fill(wp, lnum) == 0 | |
2089 #endif | |
2090 ) | |
2091 { | |
2092 /* This line is not going to fit. Don't draw anything here, | |
2093 * will draw "@ " lines below. */ | |
2094 row = wp->w_height + 1; | |
2095 } | |
2096 else | |
2097 { | |
2098 #ifdef FEAT_SEARCH_EXTRA | |
2099 prepare_search_hl(wp, &search_hl, lnum); | |
2100 #endif | |
2101 #ifdef FEAT_SYN_HL | |
2102 /* Let the syntax stuff know we skipped a few lines. */ | |
2103 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum | |
2104 && syntax_present(wp)) | |
2105 syntax_end_parsing(syntax_last_parsed + 1); | |
2106 #endif | |
2107 | |
2108 /* | |
2109 * Display one line. | |
2110 */ | |
2111 row = win_line(wp, lnum, srow, wp->w_height, | |
2112 mod_top == 0, FALSE); | |
2113 | |
2114 #ifdef FEAT_FOLDING | |
2115 wp->w_lines[idx].wl_folded = FALSE; | |
2116 wp->w_lines[idx].wl_lastlnum = lnum; | |
2117 #endif | |
2118 #ifdef FEAT_SYN_HL | |
2119 did_update = DID_LINE; | |
2120 syntax_last_parsed = lnum; | |
2121 #endif | |
2122 } | |
2123 | |
2124 wp->w_lines[idx].wl_lnum = lnum; | |
2125 wp->w_lines[idx].wl_valid = TRUE; | |
2126 | |
2127 /* Past end of the window or end of the screen. Note that after | |
2128 * resizing wp->w_height may be end up too big. That's a problem | |
2129 * elsewhere, but prevent a crash here. */ | |
2130 if (row > wp->w_height || row + wp->w_winrow >= Rows) | |
2131 { | |
2132 /* we may need the size of that too long line later on */ | |
2133 if (dollar_vcol == -1) | |
2134 wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE); | |
2135 ++idx; | |
2136 break; | |
2137 } | |
2138 if (dollar_vcol == -1) | |
2139 wp->w_lines[idx].wl_size = row - srow; | |
2140 ++idx; | |
2141 #ifdef FEAT_FOLDING | |
2142 lnum += fold_count + 1; | |
2143 #else | |
2144 ++lnum; | |
2145 #endif | |
2146 } | |
2147 else | |
2148 { | |
2149 if (wp->w_p_rnu) | |
2150 { | |
2151 #ifdef FEAT_FOLDING | |
2152 // 'relativenumber' set: The text doesn't need to be drawn, but | |
2153 // the number column nearly always does. | |
2154 fold_count = foldedCount(wp, lnum, &win_foldinfo); | |
2155 if (fold_count != 0) | |
2156 fold_line(wp, fold_count, &win_foldinfo, lnum, row); | |
2157 else | |
2158 #endif | |
2159 (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE); | |
2160 } | |
2161 | |
2162 // This line does not need to be drawn, advance to the next one. | |
2163 row += wp->w_lines[idx++].wl_size; | |
2164 if (row > wp->w_height) /* past end of screen */ | |
2165 break; | |
2166 #ifdef FEAT_FOLDING | |
2167 lnum = wp->w_lines[idx - 1].wl_lastlnum + 1; | |
2168 #else | |
2169 ++lnum; | |
2170 #endif | |
2171 #ifdef FEAT_SYN_HL | |
2172 did_update = DID_NONE; | |
2173 #endif | |
2174 } | |
2175 | |
2176 if (lnum > buf->b_ml.ml_line_count) | |
2177 { | |
2178 eof = TRUE; | |
2179 break; | |
2180 } | |
2181 } | |
2182 /* | |
2183 * End of loop over all window lines. | |
2184 */ | |
2185 | |
2186 #ifdef FEAT_VTP | |
2187 /* Rewrite the character at the end of the screen line. */ | |
2188 if (use_vtp()) | |
2189 { | |
2190 int i; | |
2191 | |
2192 for (i = 0; i < Rows; ++i) | |
2193 if (enc_utf8) | |
2194 if ((*mb_off2cells)(LineOffset[i] + Columns - 2, | |
2195 LineOffset[i] + screen_Columns) > 1) | |
2196 screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE); | |
2197 else | |
2198 screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE); | |
2199 else | |
2200 screen_char(LineOffset[i] + Columns - 1, i, Columns - 1); | |
2201 } | |
2202 #endif | |
2203 | |
2204 if (idx > wp->w_lines_valid) | |
2205 wp->w_lines_valid = idx; | |
2206 | |
2207 #ifdef FEAT_SYN_HL | |
2208 /* | |
2209 * Let the syntax stuff know we stop parsing here. | |
2210 */ | |
2211 if (syntax_last_parsed != 0 && syntax_present(wp)) | |
2212 syntax_end_parsing(syntax_last_parsed + 1); | |
2213 #endif | |
2214 | |
2215 /* | |
2216 * If we didn't hit the end of the file, and we didn't finish the last | |
2217 * line we were working on, then the line didn't fit. | |
2218 */ | |
2219 wp->w_empty_rows = 0; | |
2220 #ifdef FEAT_DIFF | |
2221 wp->w_filler_rows = 0; | |
2222 #endif | |
2223 if (!eof && !didline) | |
2224 { | |
2225 if (lnum == wp->w_topline) | |
2226 { | |
2227 /* | |
2228 * Single line that does not fit! | |
2229 * Don't overwrite it, it can be edited. | |
2230 */ | |
2231 wp->w_botline = lnum + 1; | |
2232 } | |
2233 #ifdef FEAT_DIFF | |
2234 else if (diff_check_fill(wp, lnum) >= wp->w_height - srow) | |
2235 { | |
2236 /* Window ends in filler lines. */ | |
2237 wp->w_botline = lnum; | |
2238 wp->w_filler_rows = wp->w_height - srow; | |
2239 } | |
2240 #endif | |
2241 #ifdef FEAT_TEXT_PROP | |
2242 else if (WIN_IS_POPUP(wp)) | |
2243 { | |
2244 // popup line that doesn't fit is left as-is | |
2245 wp->w_botline = lnum; | |
2246 } | |
2247 #endif | |
2248 else if (dy_flags & DY_TRUNCATE) /* 'display' has "truncate" */ | |
2249 { | |
2250 int scr_row = W_WINROW(wp) + wp->w_height - 1; | |
2251 | |
2252 /* | |
2253 * Last line isn't finished: Display "@@@" in the last screen line. | |
2254 */ | |
2255 screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol, | |
2256 HL_ATTR(HLF_AT)); | |
2257 screen_fill(scr_row, scr_row + 1, | |
2258 (int)wp->w_wincol + 2, (int)W_ENDCOL(wp), | |
2259 '@', ' ', HL_ATTR(HLF_AT)); | |
2260 set_empty_rows(wp, srow); | |
2261 wp->w_botline = lnum; | |
2262 } | |
2263 else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */ | |
2264 { | |
2265 /* | |
2266 * Last line isn't finished: Display "@@@" at the end. | |
2267 */ | |
2268 screen_fill(W_WINROW(wp) + wp->w_height - 1, | |
2269 W_WINROW(wp) + wp->w_height, | |
2270 (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp), | |
2271 '@', '@', HL_ATTR(HLF_AT)); | |
2272 set_empty_rows(wp, srow); | |
2273 wp->w_botline = lnum; | |
2274 } | |
2275 else | |
2276 { | |
2277 win_draw_end(wp, '@', ' ', TRUE, srow, wp->w_height, HLF_AT); | |
2278 wp->w_botline = lnum; | |
2279 } | |
2280 } | |
2281 else | |
2282 { | |
2283 draw_vsep_win(wp, row); | |
2284 if (eof) /* we hit the end of the file */ | |
2285 { | |
2286 wp->w_botline = buf->b_ml.ml_line_count + 1; | |
2287 #ifdef FEAT_DIFF | |
2288 j = diff_check_fill(wp, wp->w_botline); | |
2289 if (j > 0 && !wp->w_botfill) | |
2290 { | |
2291 // Display filler lines at the end of the file. | |
2292 if (char2cells(fill_diff) > 1) | |
2293 i = '-'; | |
2294 else | |
2295 i = fill_diff; | |
2296 if (row + j > wp->w_height) | |
2297 j = wp->w_height - row; | |
2298 win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED); | |
2299 row += j; | |
2300 } | |
2301 #endif | |
2302 } | |
2303 else if (dollar_vcol == -1) | |
2304 wp->w_botline = lnum; | |
2305 | |
2306 // Make sure the rest of the screen is blank | |
2307 // put '~'s on rows that aren't part of the file. | |
2308 win_draw_end(wp, WIN_IS_POPUP(wp) ? ' ' : '~', | |
2309 ' ', FALSE, row, wp->w_height, HLF_EOB); | |
2310 } | |
2311 | |
2312 #ifdef SYN_TIME_LIMIT | |
2313 syn_set_timeout(NULL); | |
2314 #endif | |
2315 | |
2316 /* Reset the type of redrawing required, the window has been updated. */ | |
2317 wp->w_redr_type = 0; | |
2318 #ifdef FEAT_DIFF | |
2319 wp->w_old_topfill = wp->w_topfill; | |
2320 wp->w_old_botfill = wp->w_botfill; | |
2321 #endif | |
2322 | |
2323 if (dollar_vcol == -1) | |
2324 { | |
2325 /* | |
2326 * There is a trick with w_botline. If we invalidate it on each | |
2327 * change that might modify it, this will cause a lot of expensive | |
2328 * calls to plines() in update_topline() each time. Therefore the | |
2329 * value of w_botline is often approximated, and this value is used to | |
2330 * compute the value of w_topline. If the value of w_botline was | |
2331 * wrong, check that the value of w_topline is correct (cursor is on | |
2332 * the visible part of the text). If it's not, we need to redraw | |
2333 * again. Mostly this just means scrolling up a few lines, so it | |
2334 * doesn't look too bad. Only do this for the current window (where | |
2335 * changes are relevant). | |
2336 */ | |
2337 wp->w_valid |= VALID_BOTLINE; | |
2338 if (wp == curwin && wp->w_botline != old_botline && !recursive) | |
2339 { | |
2340 recursive = TRUE; | |
2341 curwin->w_valid &= ~VALID_TOPLINE; | |
2342 update_topline(); /* may invalidate w_botline again */ | |
2343 if (must_redraw != 0) | |
2344 { | |
2345 /* Don't update for changes in buffer again. */ | |
2346 i = curbuf->b_mod_set; | |
2347 curbuf->b_mod_set = FALSE; | |
2348 win_update(curwin); | |
2349 must_redraw = 0; | |
2350 curbuf->b_mod_set = i; | |
2351 } | |
2352 recursive = FALSE; | |
2353 } | |
2354 } | |
2355 | |
2356 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) | |
2357 /* restore got_int, unless CTRL-C was hit while redrawing */ | |
2358 if (!got_int) | |
2359 got_int = save_got_int; | |
2360 #endif | |
2361 } | 121 } |
2362 | 122 |
2363 /* | 123 /* |
2364 * Call screen_fill() with the columns adjusted for 'rightleft' if needed. | 124 * Call screen_fill() with the columns adjusted for 'rightleft' if needed. |
2365 * Return the new offset. | 125 * Return the new offset. |
2397 /* | 157 /* |
2398 * Clear lines near the end the window and mark the unused lines with "c1". | 158 * Clear lines near the end the window and mark the unused lines with "c1". |
2399 * use "c2" as the filler character. | 159 * use "c2" as the filler character. |
2400 * When "draw_margin" is TRUE then draw the sign, fold and number columns. | 160 * When "draw_margin" is TRUE then draw the sign, fold and number columns. |
2401 */ | 161 */ |
2402 static void | 162 void |
2403 win_draw_end( | 163 win_draw_end( |
2404 win_T *wp, | 164 win_T *wp, |
2405 int c1, | 165 int c1, |
2406 int c2, | 166 int c2, |
2407 int draw_margin, | 167 int draw_margin, |
2457 } | 217 } |
2458 | 218 |
2459 set_empty_rows(wp, row); | 219 set_empty_rows(wp, row); |
2460 } | 220 } |
2461 | 221 |
2462 #ifdef FEAT_SYN_HL | 222 #if defined(FEAT_FOLDING) || defined(PROTO) |
2463 /* | |
2464 * Advance **color_cols and return TRUE when there are columns to draw. | |
2465 */ | |
2466 static int | |
2467 advance_color_col(int vcol, int **color_cols) | |
2468 { | |
2469 while (**color_cols >= 0 && vcol > **color_cols) | |
2470 ++*color_cols; | |
2471 return (**color_cols >= 0); | |
2472 } | |
2473 #endif | |
2474 | |
2475 #if defined(FEAT_MENU) || defined(FEAT_FOLDING) | |
2476 /* | |
2477 * Copy "text" to ScreenLines using "attr". | |
2478 * Returns the next screen column. | |
2479 */ | |
2480 static int | |
2481 text_to_screenline(win_T *wp, char_u *text, int col) | |
2482 { | |
2483 int off = (int)(current_ScreenLine - ScreenLines); | |
2484 | |
2485 if (has_mbyte) | |
2486 { | |
2487 int cells; | |
2488 int u8c, u8cc[MAX_MCO]; | |
2489 int i; | |
2490 int idx; | |
2491 int c_len; | |
2492 char_u *p; | |
2493 # ifdef FEAT_ARABIC | |
2494 int prev_c = 0; /* previous Arabic character */ | |
2495 int prev_c1 = 0; /* first composing char for prev_c */ | |
2496 # endif | |
2497 | |
2498 # ifdef FEAT_RIGHTLEFT | |
2499 if (wp->w_p_rl) | |
2500 idx = off; | |
2501 else | |
2502 # endif | |
2503 idx = off + col; | |
2504 | |
2505 /* Store multibyte characters in ScreenLines[] et al. correctly. */ | |
2506 for (p = text; *p != NUL; ) | |
2507 { | |
2508 cells = (*mb_ptr2cells)(p); | |
2509 c_len = (*mb_ptr2len)(p); | |
2510 if (col + cells > wp->w_width | |
2511 # ifdef FEAT_RIGHTLEFT | |
2512 - (wp->w_p_rl ? col : 0) | |
2513 # endif | |
2514 ) | |
2515 break; | |
2516 ScreenLines[idx] = *p; | |
2517 if (enc_utf8) | |
2518 { | |
2519 u8c = utfc_ptr2char(p, u8cc); | |
2520 if (*p < 0x80 && u8cc[0] == 0) | |
2521 { | |
2522 ScreenLinesUC[idx] = 0; | |
2523 #ifdef FEAT_ARABIC | |
2524 prev_c = u8c; | |
2525 #endif | |
2526 } | |
2527 else | |
2528 { | |
2529 #ifdef FEAT_ARABIC | |
2530 if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) | |
2531 { | |
2532 /* Do Arabic shaping. */ | |
2533 int pc, pc1, nc; | |
2534 int pcc[MAX_MCO]; | |
2535 int firstbyte = *p; | |
2536 | |
2537 /* The idea of what is the previous and next | |
2538 * character depends on 'rightleft'. */ | |
2539 if (wp->w_p_rl) | |
2540 { | |
2541 pc = prev_c; | |
2542 pc1 = prev_c1; | |
2543 nc = utf_ptr2char(p + c_len); | |
2544 prev_c1 = u8cc[0]; | |
2545 } | |
2546 else | |
2547 { | |
2548 pc = utfc_ptr2char(p + c_len, pcc); | |
2549 nc = prev_c; | |
2550 pc1 = pcc[0]; | |
2551 } | |
2552 prev_c = u8c; | |
2553 | |
2554 u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], | |
2555 pc, pc1, nc); | |
2556 ScreenLines[idx] = firstbyte; | |
2557 } | |
2558 else | |
2559 prev_c = u8c; | |
2560 #endif | |
2561 /* Non-BMP character: display as ? or fullwidth ?. */ | |
2562 ScreenLinesUC[idx] = u8c; | |
2563 for (i = 0; i < Screen_mco; ++i) | |
2564 { | |
2565 ScreenLinesC[i][idx] = u8cc[i]; | |
2566 if (u8cc[i] == 0) | |
2567 break; | |
2568 } | |
2569 } | |
2570 if (cells > 1) | |
2571 ScreenLines[idx + 1] = 0; | |
2572 } | |
2573 else if (enc_dbcs == DBCS_JPNU && *p == 0x8e) | |
2574 /* double-byte single width character */ | |
2575 ScreenLines2[idx] = p[1]; | |
2576 else if (cells > 1) | |
2577 /* double-width character */ | |
2578 ScreenLines[idx + 1] = p[1]; | |
2579 col += cells; | |
2580 idx += cells; | |
2581 p += c_len; | |
2582 } | |
2583 } | |
2584 else | |
2585 { | |
2586 int len = (int)STRLEN(text); | |
2587 | |
2588 if (len > wp->w_width - col) | |
2589 len = wp->w_width - col; | |
2590 if (len > 0) | |
2591 { | |
2592 #ifdef FEAT_RIGHTLEFT | |
2593 if (wp->w_p_rl) | |
2594 mch_memmove(current_ScreenLine, text, len); | |
2595 else | |
2596 #endif | |
2597 mch_memmove(current_ScreenLine + col, text, len); | |
2598 col += len; | |
2599 } | |
2600 } | |
2601 return col; | |
2602 } | |
2603 #endif | |
2604 | |
2605 #ifdef FEAT_FOLDING | |
2606 /* | 223 /* |
2607 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much | 224 * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much |
2608 * space is available for window "wp", minus "col". | 225 * space is available for window "wp", minus "col". |
2609 */ | 226 */ |
2610 static int | 227 int |
2611 compute_foldcolumn(win_T *wp, int col) | 228 compute_foldcolumn(win_T *wp, int col) |
2612 { | 229 { |
2613 int fdc = wp->w_p_fdc; | 230 int fdc = wp->w_p_fdc; |
2614 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw; | 231 int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw; |
2615 int wwidth = wp->w_width; | 232 int wwidth = wp->w_width; |
2618 fdc = wwidth - (col + wmw); | 235 fdc = wwidth - (col + wmw); |
2619 return fdc; | 236 return fdc; |
2620 } | 237 } |
2621 | 238 |
2622 /* | 239 /* |
2623 * Display one folded line. | |
2624 */ | |
2625 static void | |
2626 fold_line( | |
2627 win_T *wp, | |
2628 long fold_count, | |
2629 foldinfo_T *foldinfo, | |
2630 linenr_T lnum, | |
2631 int row) | |
2632 { | |
2633 char_u buf[FOLD_TEXT_LEN]; | |
2634 pos_T *top, *bot; | |
2635 linenr_T lnume = lnum + fold_count - 1; | |
2636 int len; | |
2637 char_u *text; | |
2638 int fdc; | |
2639 int col; | |
2640 int txtcol; | |
2641 int off = (int)(current_ScreenLine - ScreenLines); | |
2642 int ri; | |
2643 | |
2644 /* Build the fold line: | |
2645 * 1. Add the cmdwin_type for the command-line window | |
2646 * 2. Add the 'foldcolumn' | |
2647 * 3. Add the 'number' or 'relativenumber' column | |
2648 * 4. Compose the text | |
2649 * 5. Add the text | |
2650 * 6. set highlighting for the Visual area an other text | |
2651 */ | |
2652 col = 0; | |
2653 | |
2654 /* | |
2655 * 1. Add the cmdwin_type for the command-line window | |
2656 * Ignores 'rightleft', this window is never right-left. | |
2657 */ | |
2658 #ifdef FEAT_CMDWIN | |
2659 if (cmdwin_type != 0 && wp == curwin) | |
2660 { | |
2661 ScreenLines[off] = cmdwin_type; | |
2662 ScreenAttrs[off] = HL_ATTR(HLF_AT); | |
2663 if (enc_utf8) | |
2664 ScreenLinesUC[off] = 0; | |
2665 ++col; | |
2666 } | |
2667 #endif | |
2668 | |
2669 /* | |
2670 * 2. Add the 'foldcolumn' | |
2671 * Reduce the width when there is not enough space. | |
2672 */ | |
2673 fdc = compute_foldcolumn(wp, col); | |
2674 if (fdc > 0) | |
2675 { | |
2676 fill_foldcolumn(buf, wp, TRUE, lnum); | |
2677 #ifdef FEAT_RIGHTLEFT | |
2678 if (wp->w_p_rl) | |
2679 { | |
2680 int i; | |
2681 | |
2682 copy_text_attr(off + wp->w_width - fdc - col, buf, fdc, | |
2683 HL_ATTR(HLF_FC)); | |
2684 /* reverse the fold column */ | |
2685 for (i = 0; i < fdc; ++i) | |
2686 ScreenLines[off + wp->w_width - i - 1 - col] = buf[i]; | |
2687 } | |
2688 else | |
2689 #endif | |
2690 copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC)); | |
2691 col += fdc; | |
2692 } | |
2693 | |
2694 #ifdef FEAT_RIGHTLEFT | |
2695 # define RL_MEMSET(p, v, l) \ | |
2696 do { \ | |
2697 if (wp->w_p_rl) \ | |
2698 for (ri = 0; ri < l; ++ri) \ | |
2699 ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \ | |
2700 else \ | |
2701 for (ri = 0; ri < l; ++ri) \ | |
2702 ScreenAttrs[off + (p) + ri] = v; \ | |
2703 } while (0) | |
2704 #else | |
2705 # define RL_MEMSET(p, v, l) \ | |
2706 do { \ | |
2707 for (ri = 0; ri < l; ++ri) \ | |
2708 ScreenAttrs[off + (p) + ri] = v; \ | |
2709 } while (0) | |
2710 #endif | |
2711 | |
2712 /* Set all attributes of the 'number' or 'relativenumber' column and the | |
2713 * text */ | |
2714 RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col); | |
2715 | |
2716 #ifdef FEAT_SIGNS | |
2717 /* If signs are being displayed, add two spaces. */ | |
2718 if (signcolumn_on(wp)) | |
2719 { | |
2720 len = wp->w_width - col; | |
2721 if (len > 0) | |
2722 { | |
2723 if (len > 2) | |
2724 len = 2; | |
2725 # ifdef FEAT_RIGHTLEFT | |
2726 if (wp->w_p_rl) | |
2727 /* the line number isn't reversed */ | |
2728 copy_text_attr(off + wp->w_width - len - col, | |
2729 (char_u *)" ", len, HL_ATTR(HLF_FL)); | |
2730 else | |
2731 # endif | |
2732 copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL)); | |
2733 col += len; | |
2734 } | |
2735 } | |
2736 #endif | |
2737 | |
2738 /* | |
2739 * 3. Add the 'number' or 'relativenumber' column | |
2740 */ | |
2741 if (wp->w_p_nu || wp->w_p_rnu) | |
2742 { | |
2743 len = wp->w_width - col; | |
2744 if (len > 0) | |
2745 { | |
2746 int w = number_width(wp); | |
2747 long num; | |
2748 char *fmt = "%*ld "; | |
2749 | |
2750 if (len > w + 1) | |
2751 len = w + 1; | |
2752 | |
2753 if (wp->w_p_nu && !wp->w_p_rnu) | |
2754 /* 'number' + 'norelativenumber' */ | |
2755 num = (long)lnum; | |
2756 else | |
2757 { | |
2758 /* 'relativenumber', don't use negative numbers */ | |
2759 num = labs((long)get_cursor_rel_lnum(wp, lnum)); | |
2760 if (num == 0 && wp->w_p_nu && wp->w_p_rnu) | |
2761 { | |
2762 /* 'number' + 'relativenumber': cursor line shows absolute | |
2763 * line number */ | |
2764 num = lnum; | |
2765 fmt = "%-*ld "; | |
2766 } | |
2767 } | |
2768 | |
2769 sprintf((char *)buf, fmt, w, num); | |
2770 #ifdef FEAT_RIGHTLEFT | |
2771 if (wp->w_p_rl) | |
2772 /* the line number isn't reversed */ | |
2773 copy_text_attr(off + wp->w_width - len - col, buf, len, | |
2774 HL_ATTR(HLF_FL)); | |
2775 else | |
2776 #endif | |
2777 copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL)); | |
2778 col += len; | |
2779 } | |
2780 } | |
2781 | |
2782 /* | |
2783 * 4. Compose the folded-line string with 'foldtext', if set. | |
2784 */ | |
2785 text = get_foldtext(wp, lnum, lnume, foldinfo, buf); | |
2786 | |
2787 txtcol = col; /* remember where text starts */ | |
2788 | |
2789 /* | |
2790 * 5. move the text to current_ScreenLine. Fill up with "fill_fold". | |
2791 * Right-left text is put in columns 0 - number-col, normal text is put | |
2792 * in columns number-col - window-width. | |
2793 */ | |
2794 col = text_to_screenline(wp, text, col); | |
2795 | |
2796 /* Fill the rest of the line with the fold filler */ | |
2797 #ifdef FEAT_RIGHTLEFT | |
2798 if (wp->w_p_rl) | |
2799 col -= txtcol; | |
2800 #endif | |
2801 while (col < wp->w_width | |
2802 #ifdef FEAT_RIGHTLEFT | |
2803 - (wp->w_p_rl ? txtcol : 0) | |
2804 #endif | |
2805 ) | |
2806 { | |
2807 if (enc_utf8) | |
2808 { | |
2809 if (fill_fold >= 0x80) | |
2810 { | |
2811 ScreenLinesUC[off + col] = fill_fold; | |
2812 ScreenLinesC[0][off + col] = 0; | |
2813 ScreenLines[off + col] = 0x80; /* avoid storing zero */ | |
2814 } | |
2815 else | |
2816 { | |
2817 ScreenLinesUC[off + col] = 0; | |
2818 ScreenLines[off + col] = fill_fold; | |
2819 } | |
2820 col++; | |
2821 } | |
2822 else | |
2823 ScreenLines[off + col++] = fill_fold; | |
2824 } | |
2825 | |
2826 if (text != buf) | |
2827 vim_free(text); | |
2828 | |
2829 /* | |
2830 * 6. set highlighting for the Visual area an other text. | |
2831 * If all folded lines are in the Visual area, highlight the line. | |
2832 */ | |
2833 if (VIsual_active && wp->w_buffer == curwin->w_buffer) | |
2834 { | |
2835 if (LTOREQ_POS(curwin->w_cursor, VIsual)) | |
2836 { | |
2837 /* Visual is after curwin->w_cursor */ | |
2838 top = &curwin->w_cursor; | |
2839 bot = &VIsual; | |
2840 } | |
2841 else | |
2842 { | |
2843 /* Visual is before curwin->w_cursor */ | |
2844 top = &VIsual; | |
2845 bot = &curwin->w_cursor; | |
2846 } | |
2847 if (lnum >= top->lnum | |
2848 && lnume <= bot->lnum | |
2849 && (VIsual_mode != 'v' | |
2850 || ((lnum > top->lnum | |
2851 || (lnum == top->lnum | |
2852 && top->col == 0)) | |
2853 && (lnume < bot->lnum | |
2854 || (lnume == bot->lnum | |
2855 && (bot->col - (*p_sel == 'e')) | |
2856 >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE))))))) | |
2857 { | |
2858 if (VIsual_mode == Ctrl_V) | |
2859 { | |
2860 /* Visual block mode: highlight the chars part of the block */ | |
2861 if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width) | |
2862 { | |
2863 if (wp->w_old_cursor_lcol != MAXCOL | |
2864 && wp->w_old_cursor_lcol + txtcol | |
2865 < (colnr_T)wp->w_width) | |
2866 len = wp->w_old_cursor_lcol; | |
2867 else | |
2868 len = wp->w_width - txtcol; | |
2869 RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V), | |
2870 len - (int)wp->w_old_cursor_fcol); | |
2871 } | |
2872 } | |
2873 else | |
2874 { | |
2875 /* Set all attributes of the text */ | |
2876 RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol); | |
2877 } | |
2878 } | |
2879 } | |
2880 | |
2881 #ifdef FEAT_SYN_HL | |
2882 /* Show colorcolumn in the fold line, but let cursorcolumn override it. */ | |
2883 if (wp->w_p_cc_cols) | |
2884 { | |
2885 int i = 0; | |
2886 int j = wp->w_p_cc_cols[i]; | |
2887 int old_txtcol = txtcol; | |
2888 | |
2889 while (j > -1) | |
2890 { | |
2891 txtcol += j; | |
2892 if (wp->w_p_wrap) | |
2893 txtcol -= wp->w_skipcol; | |
2894 else | |
2895 txtcol -= wp->w_leftcol; | |
2896 if (txtcol >= 0 && txtcol < wp->w_width) | |
2897 ScreenAttrs[off + txtcol] = hl_combine_attr( | |
2898 ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC)); | |
2899 txtcol = old_txtcol; | |
2900 j = wp->w_p_cc_cols[++i]; | |
2901 } | |
2902 } | |
2903 | |
2904 /* Show 'cursorcolumn' in the fold line. */ | |
2905 if (wp->w_p_cuc) | |
2906 { | |
2907 txtcol += wp->w_virtcol; | |
2908 if (wp->w_p_wrap) | |
2909 txtcol -= wp->w_skipcol; | |
2910 else | |
2911 txtcol -= wp->w_leftcol; | |
2912 if (txtcol >= 0 && txtcol < wp->w_width) | |
2913 ScreenAttrs[off + txtcol] = hl_combine_attr( | |
2914 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC)); | |
2915 } | |
2916 #endif | |
2917 | |
2918 screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width, | |
2919 (int)wp->w_width, 0); | |
2920 | |
2921 /* | |
2922 * Update w_cline_height and w_cline_folded if the cursor line was | |
2923 * updated (saves a call to plines() later). | |
2924 */ | |
2925 if (wp == curwin | |
2926 && lnum <= curwin->w_cursor.lnum | |
2927 && lnume >= curwin->w_cursor.lnum) | |
2928 { | |
2929 curwin->w_cline_row = row; | |
2930 curwin->w_cline_height = 1; | |
2931 curwin->w_cline_folded = TRUE; | |
2932 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); | |
2933 } | |
2934 } | |
2935 | |
2936 /* | |
2937 * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr". | |
2938 */ | |
2939 static void | |
2940 copy_text_attr( | |
2941 int off, | |
2942 char_u *buf, | |
2943 int len, | |
2944 int attr) | |
2945 { | |
2946 int i; | |
2947 | |
2948 mch_memmove(ScreenLines + off, buf, (size_t)len); | |
2949 if (enc_utf8) | |
2950 vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len); | |
2951 for (i = 0; i < len; ++i) | |
2952 ScreenAttrs[off + i] = attr; | |
2953 } | |
2954 | |
2955 /* | |
2956 * Fill the foldcolumn at "p" for window "wp". | 240 * Fill the foldcolumn at "p" for window "wp". |
2957 * Only to be called when 'foldcolumn' > 0. | 241 * Only to be called when 'foldcolumn' > 0. |
2958 */ | 242 */ |
2959 static void | 243 void |
2960 fill_foldcolumn( | 244 fill_foldcolumn( |
2961 char_u *p, | 245 char_u *p, |
2962 win_T *wp, | 246 win_T *wp, |
2963 int closed, /* TRUE of FALSE */ | 247 int closed, /* TRUE of FALSE */ |
2964 linenr_T lnum) /* current line number */ | 248 linenr_T lnum) /* current line number */ |
3001 } | 285 } |
3002 if (closed) | 286 if (closed) |
3003 p[i >= fdc ? i - 1 : i] = '+'; | 287 p[i >= fdc ? i - 1 : i] = '+'; |
3004 } | 288 } |
3005 #endif /* FEAT_FOLDING */ | 289 #endif /* FEAT_FOLDING */ |
3006 | |
3007 #ifdef FEAT_TEXT_PROP | |
3008 static textprop_T *current_text_props = NULL; | |
3009 static buf_T *current_buf = NULL; | |
3010 | |
3011 static int | |
3012 text_prop_compare(const void *s1, const void *s2) | |
3013 { | |
3014 int idx1, idx2; | |
3015 proptype_T *pt1, *pt2; | |
3016 colnr_T col1, col2; | |
3017 | |
3018 idx1 = *(int *)s1; | |
3019 idx2 = *(int *)s2; | |
3020 pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type); | |
3021 pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type); | |
3022 if (pt1 == pt2) | |
3023 return 0; | |
3024 if (pt1 == NULL) | |
3025 return -1; | |
3026 if (pt2 == NULL) | |
3027 return 1; | |
3028 if (pt1->pt_priority != pt2->pt_priority) | |
3029 return pt1->pt_priority > pt2->pt_priority ? 1 : -1; | |
3030 col1 = current_text_props[idx1].tp_col; | |
3031 col2 = current_text_props[idx2].tp_col; | |
3032 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1; | |
3033 } | |
3034 #endif | |
3035 | |
3036 #ifdef FEAT_SIGNS | |
3037 /* | |
3038 * Get information needed to display the sign in line 'lnum' in window 'wp'. | |
3039 * If 'nrcol' is TRUE, the sign is going to be displayed in the number column. | |
3040 * Otherwise the sign is going to be displayed in the sign column. | |
3041 */ | |
3042 static void | |
3043 get_sign_display_info( | |
3044 int nrcol, | |
3045 win_T *wp, | |
3046 linenr_T lnum UNUSED, | |
3047 sign_attrs_T *sattr, | |
3048 int wcr_attr, | |
3049 int row, | |
3050 int startrow, | |
3051 int filler_lines UNUSED, | |
3052 int filler_todo UNUSED, | |
3053 int *c_extrap, | |
3054 int *c_finalp, | |
3055 char_u *extra, | |
3056 char_u **pp_extra, | |
3057 int *n_extrap, | |
3058 int *char_attrp) | |
3059 { | |
3060 int text_sign; | |
3061 # ifdef FEAT_SIGN_ICONS | |
3062 int icon_sign; | |
3063 # endif | |
3064 | |
3065 // Draw two cells with the sign value or blank. | |
3066 *c_extrap = ' '; | |
3067 *c_finalp = NUL; | |
3068 if (nrcol) | |
3069 *n_extrap = number_width(wp) + 1; | |
3070 else | |
3071 { | |
3072 *char_attrp = hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)); | |
3073 *n_extrap = 2; | |
3074 } | |
3075 | |
3076 if (row == startrow | |
3077 #ifdef FEAT_DIFF | |
3078 + filler_lines && filler_todo <= 0 | |
3079 #endif | |
3080 ) | |
3081 { | |
3082 text_sign = (sattr->text != NULL) ? sattr->typenr : 0; | |
3083 # ifdef FEAT_SIGN_ICONS | |
3084 icon_sign = (sattr->icon != NULL) ? sattr->typenr : 0; | |
3085 if (gui.in_use && icon_sign != 0) | |
3086 { | |
3087 // Use the image in this position. | |
3088 if (nrcol) | |
3089 { | |
3090 *c_extrap = NUL; | |
3091 sprintf((char *)extra, "%-*c ", number_width(wp), SIGN_BYTE); | |
3092 *pp_extra = extra; | |
3093 *n_extrap = (int)STRLEN(*pp_extra); | |
3094 } | |
3095 else | |
3096 *c_extrap = SIGN_BYTE; | |
3097 # ifdef FEAT_NETBEANS_INTG | |
3098 if (netbeans_active() && (buf_signcount(wp->w_buffer, lnum) > 1)) | |
3099 { | |
3100 if (nrcol) | |
3101 { | |
3102 *c_extrap = NUL; | |
3103 sprintf((char *)extra, "%-*c ", number_width(wp), | |
3104 MULTISIGN_BYTE); | |
3105 *pp_extra = extra; | |
3106 *n_extrap = (int)STRLEN(*pp_extra); | |
3107 } | |
3108 else | |
3109 *c_extrap = MULTISIGN_BYTE; | |
3110 } | |
3111 # endif | |
3112 *c_finalp = NUL; | |
3113 *char_attrp = icon_sign; | |
3114 } | |
3115 else | |
3116 # endif | |
3117 if (text_sign != 0) | |
3118 { | |
3119 *pp_extra = sattr->text; | |
3120 if (*pp_extra != NULL) | |
3121 { | |
3122 if (nrcol) | |
3123 { | |
3124 int n, width = number_width(wp) - 2; | |
3125 | |
3126 for (n = 0; n < width; n++) | |
3127 extra[n] = ' '; | |
3128 extra[n] = 0; | |
3129 STRCAT(extra, *pp_extra); | |
3130 STRCAT(extra, " "); | |
3131 *pp_extra = extra; | |
3132 } | |
3133 *c_extrap = NUL; | |
3134 *c_finalp = NUL; | |
3135 *n_extrap = (int)STRLEN(*pp_extra); | |
3136 } | |
3137 *char_attrp = sattr->texthl; | |
3138 } | |
3139 } | |
3140 } | |
3141 #endif | |
3142 | |
3143 /* | |
3144 * Display line "lnum" of window 'wp' on the screen. | |
3145 * Start at row "startrow", stop when "endrow" is reached. | |
3146 * wp->w_virtcol needs to be valid. | |
3147 * | |
3148 * Return the number of last row the line occupies. | |
3149 */ | |
3150 static int | |
3151 win_line( | |
3152 win_T *wp, | |
3153 linenr_T lnum, | |
3154 int startrow, | |
3155 int endrow, | |
3156 int nochange UNUSED, // not updating for changed text | |
3157 int number_only) // only update the number column | |
3158 { | |
3159 int col = 0; // visual column on screen | |
3160 unsigned off; // offset in ScreenLines/ScreenAttrs | |
3161 int c = 0; // init for GCC | |
3162 long vcol = 0; // virtual column (for tabs) | |
3163 #ifdef FEAT_LINEBREAK | |
3164 long vcol_sbr = -1; // virtual column after showbreak | |
3165 #endif | |
3166 long vcol_prev = -1; // "vcol" of previous character | |
3167 char_u *line; // current line | |
3168 char_u *ptr; // current position in "line" | |
3169 int row; // row in the window, excl w_winrow | |
3170 int screen_row; // row on the screen, incl w_winrow | |
3171 | |
3172 char_u extra[21]; // "%ld " and 'fdc' must fit in here | |
3173 int n_extra = 0; // number of extra chars | |
3174 char_u *p_extra = NULL; // string of extra chars, plus NUL | |
3175 char_u *p_extra_free = NULL; // p_extra needs to be freed | |
3176 int c_extra = NUL; // extra chars, all the same | |
3177 int c_final = NUL; // final char, mandatory if set | |
3178 int extra_attr = 0; // attributes when n_extra != 0 | |
3179 static char_u *at_end_str = (char_u *)""; // used for p_extra when | |
3180 // displaying lcs_eol at end-of-line | |
3181 int lcs_eol_one = lcs_eol; // lcs_eol until it's been used | |
3182 int lcs_prec_todo = lcs_prec; // lcs_prec until it's been used | |
3183 | |
3184 // saved "extra" items for when draw_state becomes WL_LINE (again) | |
3185 int saved_n_extra = 0; | |
3186 char_u *saved_p_extra = NULL; | |
3187 int saved_c_extra = 0; | |
3188 int saved_c_final = 0; | |
3189 int saved_char_attr = 0; | |
3190 | |
3191 int n_attr = 0; /* chars with special attr */ | |
3192 int saved_attr2 = 0; /* char_attr saved for n_attr */ | |
3193 int n_attr3 = 0; /* chars with overruling special attr */ | |
3194 int saved_attr3 = 0; /* char_attr saved for n_attr3 */ | |
3195 | |
3196 int n_skip = 0; /* nr of chars to skip for 'nowrap' */ | |
3197 | |
3198 int fromcol = -10; // start of inverting | |
3199 int tocol = MAXCOL; // end of inverting | |
3200 int fromcol_prev = -2; // start of inverting after cursor | |
3201 int noinvcur = FALSE; // don't invert the cursor | |
3202 pos_T *top, *bot; | |
3203 int lnum_in_visual_area = FALSE; | |
3204 pos_T pos; | |
3205 long v; | |
3206 | |
3207 int char_attr = 0; // attributes for next character | |
3208 int attr_pri = FALSE; // char_attr has priority | |
3209 int area_highlighting = FALSE; // Visual or incsearch highlighting | |
3210 // in this line | |
3211 int vi_attr = 0; // attributes for Visual and incsearch | |
3212 // highlighting | |
3213 int wcr_attr = 0; // attributes from 'wincolor' | |
3214 int win_attr = 0; // background for whole window, except | |
3215 // margins and "~" lines. | |
3216 int area_attr = 0; // attributes desired by highlighting | |
3217 int search_attr = 0; // attributes desired by 'hlsearch' | |
3218 #ifdef FEAT_SYN_HL | |
3219 int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */ | |
3220 int syntax_attr = 0; /* attributes desired by syntax */ | |
3221 int has_syntax = FALSE; /* this buffer has syntax highl. */ | |
3222 int save_did_emsg; | |
3223 int draw_color_col = FALSE; /* highlight colorcolumn */ | |
3224 int *color_cols = NULL; /* pointer to according columns array */ | |
3225 #endif | |
3226 int eol_hl_off = 0; /* 1 if highlighted char after EOL */ | |
3227 #ifdef FEAT_TEXT_PROP | |
3228 int text_prop_count; | |
3229 int text_prop_next = 0; // next text property to use | |
3230 textprop_T *text_props = NULL; | |
3231 int *text_prop_idxs = NULL; | |
3232 int text_props_active = 0; | |
3233 proptype_T *text_prop_type = NULL; | |
3234 int text_prop_attr = 0; | |
3235 int text_prop_combine = FALSE; | |
3236 #endif | |
3237 #ifdef FEAT_SPELL | |
3238 int has_spell = FALSE; /* this buffer has spell checking */ | |
3239 # define SPWORDLEN 150 | |
3240 char_u nextline[SPWORDLEN * 2];/* text with start of the next line */ | |
3241 int nextlinecol = 0; /* column where nextline[] starts */ | |
3242 int nextline_idx = 0; /* index in nextline[] where next line | |
3243 starts */ | |
3244 int spell_attr = 0; /* attributes desired by spelling */ | |
3245 int word_end = 0; /* last byte with same spell_attr */ | |
3246 static linenr_T checked_lnum = 0; /* line number for "checked_col" */ | |
3247 static int checked_col = 0; /* column in "checked_lnum" up to which | |
3248 * there are no spell errors */ | |
3249 static int cap_col = -1; /* column to check for Cap word */ | |
3250 static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */ | |
3251 int cur_checked_col = 0; /* checked column for current line */ | |
3252 #endif | |
3253 int extra_check = 0; // has extra highlighting | |
3254 int multi_attr = 0; /* attributes desired by multibyte */ | |
3255 int mb_l = 1; /* multi-byte byte length */ | |
3256 int mb_c = 0; /* decoded multi-byte character */ | |
3257 int mb_utf8 = FALSE; /* screen char is UTF-8 char */ | |
3258 int u8cc[MAX_MCO]; /* composing UTF-8 chars */ | |
3259 #if defined(FEAT_DIFF) || defined(FEAT_SIGNS) | |
3260 int filler_lines = 0; /* nr of filler lines to be drawn */ | |
3261 int filler_todo = 0; /* nr of filler lines still to do + 1 */ | |
3262 #endif | |
3263 #ifdef FEAT_DIFF | |
3264 hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */ | |
3265 int change_start = MAXCOL; /* first col of changed area */ | |
3266 int change_end = -1; /* last col of changed area */ | |
3267 #endif | |
3268 colnr_T trailcol = MAXCOL; /* start of trailing spaces */ | |
3269 #ifdef FEAT_LINEBREAK | |
3270 int need_showbreak = FALSE; /* overlong line, skipping first x | |
3271 chars */ | |
3272 #endif | |
3273 #if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \ | |
3274 || defined(FEAT_SYN_HL) || defined(FEAT_DIFF) | |
3275 # define LINE_ATTR | |
3276 int line_attr = 0; // attribute for the whole line | |
3277 int line_attr_save; | |
3278 #endif | |
3279 #ifdef FEAT_SIGNS | |
3280 int sign_present = FALSE; | |
3281 sign_attrs_T sattr; | |
3282 #endif | |
3283 #ifdef FEAT_ARABIC | |
3284 int prev_c = 0; /* previous Arabic character */ | |
3285 int prev_c1 = 0; /* first composing char for prev_c */ | |
3286 #endif | |
3287 #if defined(LINE_ATTR) | |
3288 int did_line_attr = 0; | |
3289 #endif | |
3290 #ifdef FEAT_TERMINAL | |
3291 int get_term_attr = FALSE; | |
3292 #endif | |
3293 #ifdef FEAT_SYN_HL | |
3294 int cul_attr = 0; // set when 'cursorline' active | |
3295 | |
3296 // 'cursorlineopt' has "screenline" and cursor is in this line | |
3297 int cul_screenline = FALSE; | |
3298 | |
3299 // margin columns for the screen line, needed for when 'cursorlineopt' | |
3300 // contains "screenline" | |
3301 int left_curline_col = 0; | |
3302 int right_curline_col = 0; | |
3303 #endif | |
3304 | |
3305 /* draw_state: items that are drawn in sequence: */ | |
3306 #define WL_START 0 /* nothing done yet */ | |
3307 #ifdef FEAT_CMDWIN | |
3308 # define WL_CMDLINE WL_START + 1 /* cmdline window column */ | |
3309 #else | |
3310 # define WL_CMDLINE WL_START | |
3311 #endif | |
3312 #ifdef FEAT_FOLDING | |
3313 # define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */ | |
3314 #else | |
3315 # define WL_FOLD WL_CMDLINE | |
3316 #endif | |
3317 #ifdef FEAT_SIGNS | |
3318 # define WL_SIGN WL_FOLD + 1 /* column for signs */ | |
3319 #else | |
3320 # define WL_SIGN WL_FOLD /* column for signs */ | |
3321 #endif | |
3322 #define WL_NR WL_SIGN + 1 /* line number */ | |
3323 #ifdef FEAT_LINEBREAK | |
3324 # define WL_BRI WL_NR + 1 /* 'breakindent' */ | |
3325 #else | |
3326 # define WL_BRI WL_NR | |
3327 #endif | |
3328 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) | |
3329 # define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */ | |
3330 #else | |
3331 # define WL_SBR WL_BRI | |
3332 #endif | |
3333 #define WL_LINE WL_SBR + 1 /* text in the line */ | |
3334 int draw_state = WL_START; /* what to draw next */ | |
3335 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) | |
3336 int feedback_col = 0; | |
3337 int feedback_old_attr = -1; | |
3338 #endif | |
3339 int screen_line_flags = 0; | |
3340 | |
3341 #if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) | |
3342 int match_conc = 0; // cchar for match functions | |
3343 #endif | |
3344 #ifdef FEAT_CONCEAL | |
3345 int syntax_flags = 0; | |
3346 int syntax_seqnr = 0; | |
3347 int prev_syntax_id = 0; | |
3348 int conceal_attr = HL_ATTR(HLF_CONCEAL); | |
3349 int is_concealing = FALSE; | |
3350 int boguscols = 0; // nonexistent columns added to force | |
3351 // wrapping | |
3352 int vcol_off = 0; // offset for concealed characters | |
3353 int did_wcol = FALSE; | |
3354 int old_boguscols = 0; | |
3355 # define VCOL_HLC (vcol - vcol_off) | |
3356 # define FIX_FOR_BOGUSCOLS \ | |
3357 { \ | |
3358 n_extra += vcol_off; \ | |
3359 vcol -= vcol_off; \ | |
3360 vcol_off = 0; \ | |
3361 col -= boguscols; \ | |
3362 old_boguscols = boguscols; \ | |
3363 boguscols = 0; \ | |
3364 } | |
3365 #else | |
3366 # define VCOL_HLC (vcol) | |
3367 #endif | |
3368 | |
3369 if (startrow > endrow) /* past the end already! */ | |
3370 return startrow; | |
3371 | |
3372 row = startrow; | |
3373 screen_row = row + W_WINROW(wp); | |
3374 | |
3375 if (!number_only) | |
3376 { | |
3377 /* | |
3378 * To speed up the loop below, set extra_check when there is linebreak, | |
3379 * trailing white space and/or syntax processing to be done. | |
3380 */ | |
3381 #ifdef FEAT_LINEBREAK | |
3382 extra_check = wp->w_p_lbr; | |
3383 #endif | |
3384 #ifdef FEAT_SYN_HL | |
3385 if (syntax_present(wp) && !wp->w_s->b_syn_error | |
3386 # ifdef SYN_TIME_LIMIT | |
3387 && !wp->w_s->b_syn_slow | |
3388 # endif | |
3389 ) | |
3390 { | |
3391 /* Prepare for syntax highlighting in this line. When there is an | |
3392 * error, stop syntax highlighting. */ | |
3393 save_did_emsg = did_emsg; | |
3394 did_emsg = FALSE; | |
3395 syntax_start(wp, lnum); | |
3396 if (did_emsg) | |
3397 wp->w_s->b_syn_error = TRUE; | |
3398 else | |
3399 { | |
3400 did_emsg = save_did_emsg; | |
3401 #ifdef SYN_TIME_LIMIT | |
3402 if (!wp->w_s->b_syn_slow) | |
3403 #endif | |
3404 { | |
3405 has_syntax = TRUE; | |
3406 extra_check = TRUE; | |
3407 } | |
3408 } | |
3409 } | |
3410 | |
3411 /* Check for columns to display for 'colorcolumn'. */ | |
3412 color_cols = wp->w_p_cc_cols; | |
3413 if (color_cols != NULL) | |
3414 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); | |
3415 #endif | |
3416 | |
3417 #ifdef FEAT_TERMINAL | |
3418 if (term_show_buffer(wp->w_buffer)) | |
3419 { | |
3420 extra_check = TRUE; | |
3421 get_term_attr = TRUE; | |
3422 win_attr = term_get_attr(wp->w_buffer, lnum, -1); | |
3423 } | |
3424 #endif | |
3425 | |
3426 #ifdef FEAT_SPELL | |
3427 if (wp->w_p_spell | |
3428 && *wp->w_s->b_p_spl != NUL | |
3429 && wp->w_s->b_langp.ga_len > 0 | |
3430 && *(char **)(wp->w_s->b_langp.ga_data) != NULL) | |
3431 { | |
3432 /* Prepare for spell checking. */ | |
3433 has_spell = TRUE; | |
3434 extra_check = TRUE; | |
3435 | |
3436 /* Get the start of the next line, so that words that wrap to the | |
3437 * next line are found too: "et<line-break>al.". | |
3438 * Trick: skip a few chars for C/shell/Vim comments */ | |
3439 nextline[SPWORDLEN] = NUL; | |
3440 if (lnum < wp->w_buffer->b_ml.ml_line_count) | |
3441 { | |
3442 line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE); | |
3443 spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); | |
3444 } | |
3445 | |
3446 /* When a word wrapped from the previous line the start of the | |
3447 * current line is valid. */ | |
3448 if (lnum == checked_lnum) | |
3449 cur_checked_col = checked_col; | |
3450 checked_lnum = 0; | |
3451 | |
3452 /* When there was a sentence end in the previous line may require a | |
3453 * word starting with capital in this line. In line 1 always check | |
3454 * the first word. */ | |
3455 if (lnum != capcol_lnum) | |
3456 cap_col = -1; | |
3457 if (lnum == 1) | |
3458 cap_col = 0; | |
3459 capcol_lnum = 0; | |
3460 } | |
3461 #endif | |
3462 | |
3463 /* | |
3464 * handle Visual active in this window | |
3465 */ | |
3466 if (VIsual_active && wp->w_buffer == curwin->w_buffer) | |
3467 { | |
3468 if (LTOREQ_POS(curwin->w_cursor, VIsual)) | |
3469 { | |
3470 // Visual is after curwin->w_cursor | |
3471 top = &curwin->w_cursor; | |
3472 bot = &VIsual; | |
3473 } | |
3474 else | |
3475 { | |
3476 // Visual is before curwin->w_cursor | |
3477 top = &VIsual; | |
3478 bot = &curwin->w_cursor; | |
3479 } | |
3480 lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum); | |
3481 if (VIsual_mode == Ctrl_V) | |
3482 { | |
3483 // block mode | |
3484 if (lnum_in_visual_area) | |
3485 { | |
3486 fromcol = wp->w_old_cursor_fcol; | |
3487 tocol = wp->w_old_cursor_lcol; | |
3488 } | |
3489 } | |
3490 else | |
3491 { | |
3492 // non-block mode | |
3493 if (lnum > top->lnum && lnum <= bot->lnum) | |
3494 fromcol = 0; | |
3495 else if (lnum == top->lnum) | |
3496 { | |
3497 if (VIsual_mode == 'V') // linewise | |
3498 fromcol = 0; | |
3499 else | |
3500 { | |
3501 getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL); | |
3502 if (gchar_pos(top) == NUL) | |
3503 tocol = fromcol + 1; | |
3504 } | |
3505 } | |
3506 if (VIsual_mode != 'V' && lnum == bot->lnum) | |
3507 { | |
3508 if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0) | |
3509 { | |
3510 fromcol = -10; | |
3511 tocol = MAXCOL; | |
3512 } | |
3513 else if (bot->col == MAXCOL) | |
3514 tocol = MAXCOL; | |
3515 else | |
3516 { | |
3517 pos = *bot; | |
3518 if (*p_sel == 'e') | |
3519 getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL); | |
3520 else | |
3521 { | |
3522 getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol); | |
3523 ++tocol; | |
3524 } | |
3525 } | |
3526 } | |
3527 } | |
3528 | |
3529 /* Check if the character under the cursor should not be inverted */ | |
3530 if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin | |
3531 #ifdef FEAT_GUI | |
3532 && !gui.in_use | |
3533 #endif | |
3534 ) | |
3535 noinvcur = TRUE; | |
3536 | |
3537 /* if inverting in this line set area_highlighting */ | |
3538 if (fromcol >= 0) | |
3539 { | |
3540 area_highlighting = TRUE; | |
3541 vi_attr = HL_ATTR(HLF_V); | |
3542 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) | |
3543 if ((clip_star.available && !clip_star.owned | |
3544 && clip_isautosel_star()) | |
3545 || (clip_plus.available && !clip_plus.owned | |
3546 && clip_isautosel_plus())) | |
3547 vi_attr = HL_ATTR(HLF_VNC); | |
3548 #endif | |
3549 } | |
3550 } | |
3551 | |
3552 /* | |
3553 * handle 'incsearch' and ":s///c" highlighting | |
3554 */ | |
3555 else if (highlight_match | |
3556 && wp == curwin | |
3557 && lnum >= curwin->w_cursor.lnum | |
3558 && lnum <= curwin->w_cursor.lnum + search_match_lines) | |
3559 { | |
3560 if (lnum == curwin->w_cursor.lnum) | |
3561 getvcol(curwin, &(curwin->w_cursor), | |
3562 (colnr_T *)&fromcol, NULL, NULL); | |
3563 else | |
3564 fromcol = 0; | |
3565 if (lnum == curwin->w_cursor.lnum + search_match_lines) | |
3566 { | |
3567 pos.lnum = lnum; | |
3568 pos.col = search_match_endcol; | |
3569 getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL); | |
3570 } | |
3571 else | |
3572 tocol = MAXCOL; | |
3573 /* do at least one character; happens when past end of line */ | |
3574 if (fromcol == tocol) | |
3575 tocol = fromcol + 1; | |
3576 area_highlighting = TRUE; | |
3577 vi_attr = HL_ATTR(HLF_I); | |
3578 } | |
3579 } | |
3580 | |
3581 #ifdef FEAT_DIFF | |
3582 filler_lines = diff_check(wp, lnum); | |
3583 if (filler_lines < 0) | |
3584 { | |
3585 if (filler_lines == -1) | |
3586 { | |
3587 if (diff_find_change(wp, lnum, &change_start, &change_end)) | |
3588 diff_hlf = HLF_ADD; /* added line */ | |
3589 else if (change_start == 0) | |
3590 diff_hlf = HLF_TXD; /* changed text */ | |
3591 else | |
3592 diff_hlf = HLF_CHD; /* changed line */ | |
3593 } | |
3594 else | |
3595 diff_hlf = HLF_ADD; /* added line */ | |
3596 filler_lines = 0; | |
3597 area_highlighting = TRUE; | |
3598 } | |
3599 if (lnum == wp->w_topline) | |
3600 filler_lines = wp->w_topfill; | |
3601 filler_todo = filler_lines; | |
3602 #endif | |
3603 | |
3604 #ifdef FEAT_SIGNS | |
3605 sign_present = buf_get_signattrs(wp->w_buffer, lnum, &sattr); | |
3606 #endif | |
3607 | |
3608 #ifdef LINE_ATTR | |
3609 # ifdef FEAT_SIGNS | |
3610 /* If this line has a sign with line highlighting set line_attr. */ | |
3611 if (sign_present) | |
3612 line_attr = sattr.linehl; | |
3613 # endif | |
3614 # if defined(FEAT_QUICKFIX) | |
3615 /* Highlight the current line in the quickfix window. */ | |
3616 if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) | |
3617 line_attr = HL_ATTR(HLF_QFL); | |
3618 # endif | |
3619 if (line_attr != 0) | |
3620 area_highlighting = TRUE; | |
3621 #endif | |
3622 | |
3623 line = ml_get_buf(wp->w_buffer, lnum, FALSE); | |
3624 ptr = line; | |
3625 | |
3626 #ifdef FEAT_SPELL | |
3627 if (has_spell && !number_only) | |
3628 { | |
3629 /* For checking first word with a capital skip white space. */ | |
3630 if (cap_col == 0) | |
3631 cap_col = getwhitecols(line); | |
3632 | |
3633 /* To be able to spell-check over line boundaries copy the end of the | |
3634 * current line into nextline[]. Above the start of the next line was | |
3635 * copied to nextline[SPWORDLEN]. */ | |
3636 if (nextline[SPWORDLEN] == NUL) | |
3637 { | |
3638 /* No next line or it is empty. */ | |
3639 nextlinecol = MAXCOL; | |
3640 nextline_idx = 0; | |
3641 } | |
3642 else | |
3643 { | |
3644 v = (long)STRLEN(line); | |
3645 if (v < SPWORDLEN) | |
3646 { | |
3647 /* Short line, use it completely and append the start of the | |
3648 * next line. */ | |
3649 nextlinecol = 0; | |
3650 mch_memmove(nextline, line, (size_t)v); | |
3651 STRMOVE(nextline + v, nextline + SPWORDLEN); | |
3652 nextline_idx = v + 1; | |
3653 } | |
3654 else | |
3655 { | |
3656 /* Long line, use only the last SPWORDLEN bytes. */ | |
3657 nextlinecol = v - SPWORDLEN; | |
3658 mch_memmove(nextline, line + nextlinecol, SPWORDLEN); | |
3659 nextline_idx = SPWORDLEN + 1; | |
3660 } | |
3661 } | |
3662 } | |
3663 #endif | |
3664 | |
3665 if (wp->w_p_list) | |
3666 { | |
3667 if (lcs_space || lcs_trail || lcs_nbsp) | |
3668 extra_check = TRUE; | |
3669 /* find start of trailing whitespace */ | |
3670 if (lcs_trail) | |
3671 { | |
3672 trailcol = (colnr_T)STRLEN(ptr); | |
3673 while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1])) | |
3674 --trailcol; | |
3675 trailcol += (colnr_T) (ptr - line); | |
3676 } | |
3677 } | |
3678 | |
3679 wcr_attr = get_wcr_attr(wp); | |
3680 if (wcr_attr != 0) | |
3681 { | |
3682 win_attr = wcr_attr; | |
3683 area_highlighting = TRUE; | |
3684 } | |
3685 #ifdef FEAT_TEXT_PROP | |
3686 if (WIN_IS_POPUP(wp)) | |
3687 screen_line_flags |= SLF_POPUP; | |
3688 #endif | |
3689 | |
3690 /* | |
3691 * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the | |
3692 * first character to be displayed. | |
3693 */ | |
3694 if (wp->w_p_wrap) | |
3695 v = wp->w_skipcol; | |
3696 else | |
3697 v = wp->w_leftcol; | |
3698 if (v > 0 && !number_only) | |
3699 { | |
3700 char_u *prev_ptr = ptr; | |
3701 | |
3702 while (vcol < v && *ptr != NUL) | |
3703 { | |
3704 c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL); | |
3705 vcol += c; | |
3706 prev_ptr = ptr; | |
3707 MB_PTR_ADV(ptr); | |
3708 } | |
3709 | |
3710 /* When: | |
3711 * - 'cuc' is set, or | |
3712 * - 'colorcolumn' is set, or | |
3713 * - 'virtualedit' is set, or | |
3714 * - the visual mode is active, | |
3715 * the end of the line may be before the start of the displayed part. | |
3716 */ | |
3717 if (vcol < v && ( | |
3718 #ifdef FEAT_SYN_HL | |
3719 wp->w_p_cuc || draw_color_col || | |
3720 #endif | |
3721 virtual_active() || | |
3722 (VIsual_active && wp->w_buffer == curwin->w_buffer))) | |
3723 vcol = v; | |
3724 | |
3725 /* Handle a character that's not completely on the screen: Put ptr at | |
3726 * that character but skip the first few screen characters. */ | |
3727 if (vcol > v) | |
3728 { | |
3729 vcol -= c; | |
3730 ptr = prev_ptr; | |
3731 /* If the character fits on the screen, don't need to skip it. | |
3732 * Except for a TAB. */ | |
3733 if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0) | |
3734 n_skip = v - vcol; | |
3735 } | |
3736 | |
3737 /* | |
3738 * Adjust for when the inverted text is before the screen, | |
3739 * and when the start of the inverted text is before the screen. | |
3740 */ | |
3741 if (tocol <= vcol) | |
3742 fromcol = 0; | |
3743 else if (fromcol >= 0 && fromcol < vcol) | |
3744 fromcol = vcol; | |
3745 | |
3746 #ifdef FEAT_LINEBREAK | |
3747 /* When w_skipcol is non-zero, first line needs 'showbreak' */ | |
3748 if (wp->w_p_wrap) | |
3749 need_showbreak = TRUE; | |
3750 #endif | |
3751 #ifdef FEAT_SPELL | |
3752 /* When spell checking a word we need to figure out the start of the | |
3753 * word and if it's badly spelled or not. */ | |
3754 if (has_spell) | |
3755 { | |
3756 int len; | |
3757 colnr_T linecol = (colnr_T)(ptr - line); | |
3758 hlf_T spell_hlf = HLF_COUNT; | |
3759 | |
3760 pos = wp->w_cursor; | |
3761 wp->w_cursor.lnum = lnum; | |
3762 wp->w_cursor.col = linecol; | |
3763 len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf); | |
3764 | |
3765 /* spell_move_to() may call ml_get() and make "line" invalid */ | |
3766 line = ml_get_buf(wp->w_buffer, lnum, FALSE); | |
3767 ptr = line + linecol; | |
3768 | |
3769 if (len == 0 || (int)wp->w_cursor.col > ptr - line) | |
3770 { | |
3771 /* no bad word found at line start, don't check until end of a | |
3772 * word */ | |
3773 spell_hlf = HLF_COUNT; | |
3774 word_end = (int)(spell_to_word_end(ptr, wp) - line + 1); | |
3775 } | |
3776 else | |
3777 { | |
3778 /* bad word found, use attributes until end of word */ | |
3779 word_end = wp->w_cursor.col + len + 1; | |
3780 | |
3781 /* Turn index into actual attributes. */ | |
3782 if (spell_hlf != HLF_COUNT) | |
3783 spell_attr = highlight_attr[spell_hlf]; | |
3784 } | |
3785 wp->w_cursor = pos; | |
3786 | |
3787 # ifdef FEAT_SYN_HL | |
3788 /* Need to restart syntax highlighting for this line. */ | |
3789 if (has_syntax) | |
3790 syntax_start(wp, lnum); | |
3791 # endif | |
3792 } | |
3793 #endif | |
3794 } | |
3795 | |
3796 /* | |
3797 * Correct highlighting for cursor that can't be disabled. | |
3798 * Avoids having to check this for each character. | |
3799 */ | |
3800 if (fromcol >= 0) | |
3801 { | |
3802 if (noinvcur) | |
3803 { | |
3804 if ((colnr_T)fromcol == wp->w_virtcol) | |
3805 { | |
3806 /* highlighting starts at cursor, let it start just after the | |
3807 * cursor */ | |
3808 fromcol_prev = fromcol; | |
3809 fromcol = -1; | |
3810 } | |
3811 else if ((colnr_T)fromcol < wp->w_virtcol) | |
3812 /* restart highlighting after the cursor */ | |
3813 fromcol_prev = wp->w_virtcol; | |
3814 } | |
3815 if (fromcol >= tocol) | |
3816 fromcol = -1; | |
3817 } | |
3818 | |
3819 #ifdef FEAT_SEARCH_EXTRA | |
3820 if (!number_only) | |
3821 { | |
3822 v = (long)(ptr - line); | |
3823 area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v, | |
3824 &line, &search_hl, &search_attr); | |
3825 ptr = line + v; // "line" may have been updated | |
3826 } | |
3827 #endif | |
3828 | |
3829 #ifdef FEAT_SYN_HL | |
3830 // Cursor line highlighting for 'cursorline' in the current window. | |
3831 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) | |
3832 { | |
3833 // Do not show the cursor line in the text when Visual mode is active, | |
3834 // because it's not clear what is selected then. Do update | |
3835 // w_last_cursorline. | |
3836 if (!(wp == curwin && VIsual_active) | |
3837 && wp->w_p_culopt_flags != CULOPT_NBR) | |
3838 { | |
3839 cul_screenline = (wp->w_p_wrap | |
3840 && (wp->w_p_culopt_flags & CULOPT_SCRLINE)); | |
3841 | |
3842 // Only set line_attr here when "screenline" is not present in | |
3843 // 'cursorlineopt'. Otherwise it's done later. | |
3844 if (!cul_screenline) | |
3845 { | |
3846 cul_attr = HL_ATTR(HLF_CUL); | |
3847 line_attr = cul_attr; | |
3848 wp->w_last_cursorline = wp->w_cursor.lnum; | |
3849 } | |
3850 else | |
3851 { | |
3852 line_attr_save = line_attr; | |
3853 wp->w_last_cursorline = 0; | |
3854 margin_columns_win(wp, &left_curline_col, &right_curline_col); | |
3855 } | |
3856 area_highlighting = TRUE; | |
3857 } | |
3858 else | |
3859 wp->w_last_cursorline = wp->w_cursor.lnum; | |
3860 } | |
3861 #endif | |
3862 | |
3863 #ifdef FEAT_TEXT_PROP | |
3864 { | |
3865 char_u *prop_start; | |
3866 | |
3867 text_prop_count = get_text_props(wp->w_buffer, lnum, | |
3868 &prop_start, FALSE); | |
3869 if (text_prop_count > 0) | |
3870 { | |
3871 // Make a copy of the properties, so that they are properly | |
3872 // aligned. | |
3873 text_props = ALLOC_MULT(textprop_T, text_prop_count); | |
3874 if (text_props != NULL) | |
3875 mch_memmove(text_props, prop_start, | |
3876 text_prop_count * sizeof(textprop_T)); | |
3877 | |
3878 // Allocate an array for the indexes. | |
3879 text_prop_idxs = ALLOC_MULT(int, text_prop_count); | |
3880 area_highlighting = TRUE; | |
3881 extra_check = TRUE; | |
3882 } | |
3883 } | |
3884 #endif | |
3885 | |
3886 off = (unsigned)(current_ScreenLine - ScreenLines); | |
3887 col = 0; | |
3888 | |
3889 #ifdef FEAT_RIGHTLEFT | |
3890 if (wp->w_p_rl) | |
3891 { | |
3892 /* Rightleft window: process the text in the normal direction, but put | |
3893 * it in current_ScreenLine[] from right to left. Start at the | |
3894 * rightmost column of the window. */ | |
3895 col = wp->w_width - 1; | |
3896 off += col; | |
3897 screen_line_flags |= SLF_RIGHTLEFT; | |
3898 } | |
3899 #endif | |
3900 | |
3901 /* | |
3902 * Repeat for the whole displayed line. | |
3903 */ | |
3904 for (;;) | |
3905 { | |
3906 #if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) | |
3907 int has_match_conc = 0; // match wants to conceal | |
3908 #endif | |
3909 #ifdef FEAT_CONCEAL | |
3910 int did_decrement_ptr = FALSE; | |
3911 #endif | |
3912 /* Skip this quickly when working on the text. */ | |
3913 if (draw_state != WL_LINE) | |
3914 { | |
3915 #ifdef FEAT_CMDWIN | |
3916 if (draw_state == WL_CMDLINE - 1 && n_extra == 0) | |
3917 { | |
3918 draw_state = WL_CMDLINE; | |
3919 if (cmdwin_type != 0 && wp == curwin) | |
3920 { | |
3921 /* Draw the cmdline character. */ | |
3922 n_extra = 1; | |
3923 c_extra = cmdwin_type; | |
3924 c_final = NUL; | |
3925 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_AT)); | |
3926 } | |
3927 } | |
3928 #endif | |
3929 | |
3930 #ifdef FEAT_FOLDING | |
3931 if (draw_state == WL_FOLD - 1 && n_extra == 0) | |
3932 { | |
3933 int fdc = compute_foldcolumn(wp, 0); | |
3934 | |
3935 draw_state = WL_FOLD; | |
3936 if (fdc > 0) | |
3937 { | |
3938 /* Draw the 'foldcolumn'. Allocate a buffer, "extra" may | |
3939 * already be in use. */ | |
3940 vim_free(p_extra_free); | |
3941 p_extra_free = alloc(12 + 1); | |
3942 | |
3943 if (p_extra_free != NULL) | |
3944 { | |
3945 fill_foldcolumn(p_extra_free, wp, FALSE, lnum); | |
3946 n_extra = fdc; | |
3947 p_extra_free[n_extra] = NUL; | |
3948 p_extra = p_extra_free; | |
3949 c_extra = NUL; | |
3950 c_final = NUL; | |
3951 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)); | |
3952 } | |
3953 } | |
3954 } | |
3955 #endif | |
3956 | |
3957 #ifdef FEAT_SIGNS | |
3958 if (draw_state == WL_SIGN - 1 && n_extra == 0) | |
3959 { | |
3960 draw_state = WL_SIGN; | |
3961 /* Show the sign column when there are any signs in this | |
3962 * buffer or when using Netbeans. */ | |
3963 if (signcolumn_on(wp)) | |
3964 get_sign_display_info(FALSE, wp, lnum, &sattr, wcr_attr, | |
3965 row, startrow, filler_lines, filler_todo, &c_extra, | |
3966 &c_final, extra, &p_extra, &n_extra, &char_attr); | |
3967 } | |
3968 #endif | |
3969 | |
3970 if (draw_state == WL_NR - 1 && n_extra == 0) | |
3971 { | |
3972 draw_state = WL_NR; | |
3973 /* Display the absolute or relative line number. After the | |
3974 * first fill with blanks when the 'n' flag isn't in 'cpo' */ | |
3975 if ((wp->w_p_nu || wp->w_p_rnu) | |
3976 && (row == startrow | |
3977 #ifdef FEAT_DIFF | |
3978 + filler_lines | |
3979 #endif | |
3980 || vim_strchr(p_cpo, CPO_NUMCOL) == NULL)) | |
3981 { | |
3982 #ifdef FEAT_SIGNS | |
3983 // If 'signcolumn' is set to 'number' and a sign is present | |
3984 // in 'lnum', then display the sign instead of the line | |
3985 // number. | |
3986 if ((*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u') | |
3987 && sign_present) | |
3988 get_sign_display_info(TRUE, wp, lnum, &sattr, wcr_attr, | |
3989 row, startrow, filler_lines, filler_todo, | |
3990 &c_extra, &c_final, extra, &p_extra, &n_extra, | |
3991 &char_attr); | |
3992 else | |
3993 #endif | |
3994 { | |
3995 /* Draw the line number (empty space after wrapping). */ | |
3996 if (row == startrow | |
3997 #ifdef FEAT_DIFF | |
3998 + filler_lines | |
3999 #endif | |
4000 ) | |
4001 { | |
4002 long num; | |
4003 char *fmt = "%*ld "; | |
4004 | |
4005 if (wp->w_p_nu && !wp->w_p_rnu) | |
4006 /* 'number' + 'norelativenumber' */ | |
4007 num = (long)lnum; | |
4008 else | |
4009 { | |
4010 /* 'relativenumber', don't use negative numbers */ | |
4011 num = labs((long)get_cursor_rel_lnum(wp, lnum)); | |
4012 if (num == 0 && wp->w_p_nu && wp->w_p_rnu) | |
4013 { | |
4014 /* 'number' + 'relativenumber' */ | |
4015 num = lnum; | |
4016 fmt = "%-*ld "; | |
4017 } | |
4018 } | |
4019 | |
4020 sprintf((char *)extra, fmt, | |
4021 number_width(wp), num); | |
4022 if (wp->w_skipcol > 0) | |
4023 for (p_extra = extra; *p_extra == ' '; ++p_extra) | |
4024 *p_extra = '-'; | |
4025 #ifdef FEAT_RIGHTLEFT | |
4026 if (wp->w_p_rl) /* reverse line numbers */ | |
4027 { | |
4028 char_u *p1, *p2; | |
4029 int t; | |
4030 | |
4031 // like rl_mirror(), but keep the space at the end | |
4032 p2 = skiptowhite(extra) - 1; | |
4033 for (p1 = extra; p1 < p2; ++p1, --p2) | |
4034 { | |
4035 t = *p1; | |
4036 *p1 = *p2; | |
4037 *p2 = t; | |
4038 } | |
4039 } | |
4040 #endif | |
4041 p_extra = extra; | |
4042 c_extra = NUL; | |
4043 c_final = NUL; | |
4044 } | |
4045 else | |
4046 { | |
4047 c_extra = ' '; | |
4048 c_final = NUL; | |
4049 } | |
4050 n_extra = number_width(wp) + 1; | |
4051 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)); | |
4052 #ifdef FEAT_SYN_HL | |
4053 // When 'cursorline' is set highlight the line number of | |
4054 // the current line differently. | |
4055 // When 'cursorlineopt' has "screenline" only highlight | |
4056 // the line number itself. | |
4057 // TODO: Can we use CursorLine instead of CursorLineNr | |
4058 // when CursorLineNr isn't set? | |
4059 if ((wp->w_p_cul || wp->w_p_rnu) | |
4060 && (wp->w_p_culopt_flags & CULOPT_NBR) | |
4061 && (row == startrow | |
4062 || wp->w_p_culopt_flags & CULOPT_LINE) | |
4063 && lnum == wp->w_cursor.lnum) | |
4064 char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_CLN)); | |
4065 #endif | |
4066 } | |
4067 } | |
4068 } | |
4069 | |
4070 #ifdef FEAT_LINEBREAK | |
4071 if (wp->w_p_brisbr && draw_state == WL_BRI - 1 | |
4072 && n_extra == 0 && *p_sbr != NUL) | |
4073 /* draw indent after showbreak value */ | |
4074 draw_state = WL_BRI; | |
4075 else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0) | |
4076 /* After the showbreak, draw the breakindent */ | |
4077 draw_state = WL_BRI - 1; | |
4078 | |
4079 /* draw 'breakindent': indent wrapped text accordingly */ | |
4080 if (draw_state == WL_BRI - 1 && n_extra == 0) | |
4081 { | |
4082 draw_state = WL_BRI; | |
4083 /* if need_showbreak is set, breakindent also applies */ | |
4084 if (wp->w_p_bri && n_extra == 0 | |
4085 && (row != startrow || need_showbreak) | |
4086 # ifdef FEAT_DIFF | |
4087 && filler_lines == 0 | |
4088 # endif | |
4089 ) | |
4090 { | |
4091 char_attr = 0; | |
4092 # ifdef FEAT_DIFF | |
4093 if (diff_hlf != (hlf_T)0) | |
4094 { | |
4095 char_attr = HL_ATTR(diff_hlf); | |
4096 # ifdef FEAT_SYN_HL | |
4097 if (cul_attr != 0) | |
4098 char_attr = hl_combine_attr(char_attr, cul_attr); | |
4099 # endif | |
4100 } | |
4101 # endif | |
4102 p_extra = NULL; | |
4103 c_extra = ' '; | |
4104 n_extra = get_breakindent_win(wp, | |
4105 ml_get_buf(wp->w_buffer, lnum, FALSE)); | |
4106 /* Correct end of highlighted area for 'breakindent', | |
4107 * required when 'linebreak' is also set. */ | |
4108 if (tocol == vcol) | |
4109 tocol += n_extra; | |
4110 } | |
4111 } | |
4112 #endif | |
4113 | |
4114 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) | |
4115 if (draw_state == WL_SBR - 1 && n_extra == 0) | |
4116 { | |
4117 draw_state = WL_SBR; | |
4118 # ifdef FEAT_DIFF | |
4119 if (filler_todo > 0) | |
4120 { | |
4121 /* Draw "deleted" diff line(s). */ | |
4122 if (char2cells(fill_diff) > 1) | |
4123 { | |
4124 c_extra = '-'; | |
4125 c_final = NUL; | |
4126 } | |
4127 else | |
4128 { | |
4129 c_extra = fill_diff; | |
4130 c_final = NUL; | |
4131 } | |
4132 # ifdef FEAT_RIGHTLEFT | |
4133 if (wp->w_p_rl) | |
4134 n_extra = col + 1; | |
4135 else | |
4136 # endif | |
4137 n_extra = wp->w_width - col; | |
4138 char_attr = HL_ATTR(HLF_DED); | |
4139 } | |
4140 # endif | |
4141 # ifdef FEAT_LINEBREAK | |
4142 if (*p_sbr != NUL && need_showbreak) | |
4143 { | |
4144 /* Draw 'showbreak' at the start of each broken line. */ | |
4145 p_extra = p_sbr; | |
4146 c_extra = NUL; | |
4147 c_final = NUL; | |
4148 n_extra = (int)STRLEN(p_sbr); | |
4149 char_attr = HL_ATTR(HLF_AT); | |
4150 need_showbreak = FALSE; | |
4151 vcol_sbr = vcol + MB_CHARLEN(p_sbr); | |
4152 /* Correct end of highlighted area for 'showbreak', | |
4153 * required when 'linebreak' is also set. */ | |
4154 if (tocol == vcol) | |
4155 tocol += n_extra; | |
4156 // combine 'showbreak' with 'wincolor' | |
4157 if (win_attr != 0) | |
4158 char_attr = hl_combine_attr(win_attr, char_attr); | |
4159 # ifdef FEAT_SYN_HL | |
4160 // combine 'showbreak' with 'cursorline' | |
4161 if (cul_attr != 0) | |
4162 char_attr = hl_combine_attr(char_attr, cul_attr); | |
4163 # endif | |
4164 } | |
4165 # endif | |
4166 } | |
4167 #endif | |
4168 | |
4169 if (draw_state == WL_LINE - 1 && n_extra == 0) | |
4170 { | |
4171 draw_state = WL_LINE; | |
4172 if (saved_n_extra) | |
4173 { | |
4174 /* Continue item from end of wrapped line. */ | |
4175 n_extra = saved_n_extra; | |
4176 c_extra = saved_c_extra; | |
4177 c_final = saved_c_final; | |
4178 p_extra = saved_p_extra; | |
4179 char_attr = saved_char_attr; | |
4180 } | |
4181 else | |
4182 char_attr = win_attr; | |
4183 } | |
4184 } | |
4185 #ifdef FEAT_SYN_HL | |
4186 if (cul_screenline) | |
4187 { | |
4188 if (draw_state == WL_LINE | |
4189 && vcol >= left_curline_col | |
4190 && vcol < right_curline_col) | |
4191 { | |
4192 cul_attr = HL_ATTR(HLF_CUL); | |
4193 line_attr = cul_attr; | |
4194 } | |
4195 else | |
4196 { | |
4197 cul_attr = 0; | |
4198 line_attr = line_attr_save; | |
4199 } | |
4200 } | |
4201 #endif | |
4202 | |
4203 // When still displaying '$' of change command, stop at cursor. | |
4204 // When only displaying the (relative) line number and that's done, | |
4205 // stop here. | |
4206 if ((dollar_vcol >= 0 && wp == curwin | |
4207 && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol | |
4208 #ifdef FEAT_DIFF | |
4209 && filler_todo <= 0 | |
4210 #endif | |
4211 ) | |
4212 || (number_only && draw_state > WL_NR)) | |
4213 { | |
4214 screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width, | |
4215 screen_line_flags); | |
4216 /* Pretend we have finished updating the window. Except when | |
4217 * 'cursorcolumn' is set. */ | |
4218 #ifdef FEAT_SYN_HL | |
4219 if (wp->w_p_cuc) | |
4220 row = wp->w_cline_row + wp->w_cline_height; | |
4221 else | |
4222 #endif | |
4223 row = wp->w_height; | |
4224 break; | |
4225 } | |
4226 | |
4227 if (draw_state == WL_LINE && (area_highlighting | |
4228 #ifdef FEAT_SPELL | |
4229 || has_spell | |
4230 #endif | |
4231 )) | |
4232 { | |
4233 /* handle Visual or match highlighting in this line */ | |
4234 if (vcol == fromcol | |
4235 || (has_mbyte && vcol + 1 == fromcol && n_extra == 0 | |
4236 && (*mb_ptr2cells)(ptr) > 1) | |
4237 || ((int)vcol_prev == fromcol_prev | |
4238 && vcol_prev < vcol /* not at margin */ | |
4239 && vcol < tocol)) | |
4240 area_attr = vi_attr; /* start highlighting */ | |
4241 else if (area_attr != 0 | |
4242 && (vcol == tocol | |
4243 || (noinvcur && (colnr_T)vcol == wp->w_virtcol))) | |
4244 area_attr = 0; /* stop highlighting */ | |
4245 | |
4246 #ifdef FEAT_SEARCH_EXTRA | |
4247 if (!n_extra) | |
4248 { | |
4249 /* | |
4250 * Check for start/end of 'hlsearch' and other matches. | |
4251 * After end, check for start/end of next match. | |
4252 * When another match, have to check for start again. | |
4253 */ | |
4254 v = (long)(ptr - line); | |
4255 search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, | |
4256 &search_hl, &has_match_conc, &match_conc, | |
4257 did_line_attr, lcs_eol_one); | |
4258 ptr = line + v; // "line" may have been changed | |
4259 } | |
4260 #endif | |
4261 | |
4262 #ifdef FEAT_DIFF | |
4263 if (diff_hlf != (hlf_T)0) | |
4264 { | |
4265 if (diff_hlf == HLF_CHD && ptr - line >= change_start | |
4266 && n_extra == 0) | |
4267 diff_hlf = HLF_TXD; /* changed text */ | |
4268 if (diff_hlf == HLF_TXD && ptr - line > change_end | |
4269 && n_extra == 0) | |
4270 diff_hlf = HLF_CHD; /* changed line */ | |
4271 line_attr = HL_ATTR(diff_hlf); | |
4272 if (wp->w_p_cul && lnum == wp->w_cursor.lnum | |
4273 && wp->w_p_culopt_flags != CULOPT_NBR | |
4274 && (!cul_screenline || (vcol >= left_curline_col | |
4275 && vcol <= right_curline_col))) | |
4276 line_attr = hl_combine_attr( | |
4277 line_attr, HL_ATTR(HLF_CUL)); | |
4278 } | |
4279 #endif | |
4280 | |
4281 #ifdef FEAT_TEXT_PROP | |
4282 if (text_props != NULL) | |
4283 { | |
4284 int pi; | |
4285 int bcol = (int)(ptr - line); | |
4286 | |
4287 if (n_extra > 0) | |
4288 --bcol; // still working on the previous char, e.g. Tab | |
4289 | |
4290 // Check if any active property ends. | |
4291 for (pi = 0; pi < text_props_active; ++pi) | |
4292 { | |
4293 int tpi = text_prop_idxs[pi]; | |
4294 | |
4295 if (bcol >= text_props[tpi].tp_col - 1 | |
4296 + text_props[tpi].tp_len) | |
4297 { | |
4298 if (pi + 1 < text_props_active) | |
4299 mch_memmove(text_prop_idxs + pi, | |
4300 text_prop_idxs + pi + 1, | |
4301 sizeof(int) | |
4302 * (text_props_active - (pi + 1))); | |
4303 --text_props_active; | |
4304 --pi; | |
4305 } | |
4306 } | |
4307 | |
4308 // Add any text property that starts in this column. | |
4309 while (text_prop_next < text_prop_count | |
4310 && bcol >= text_props[text_prop_next].tp_col - 1) | |
4311 text_prop_idxs[text_props_active++] = text_prop_next++; | |
4312 | |
4313 text_prop_attr = 0; | |
4314 text_prop_combine = FALSE; | |
4315 if (text_props_active > 0) | |
4316 { | |
4317 // Sort the properties on priority and/or starting last. | |
4318 // Then combine the attributes, highest priority last. | |
4319 current_text_props = text_props; | |
4320 current_buf = wp->w_buffer; | |
4321 qsort((void *)text_prop_idxs, (size_t)text_props_active, | |
4322 sizeof(int), text_prop_compare); | |
4323 | |
4324 for (pi = 0; pi < text_props_active; ++pi) | |
4325 { | |
4326 int tpi = text_prop_idxs[pi]; | |
4327 proptype_T *pt = text_prop_type_by_id( | |
4328 wp->w_buffer, text_props[tpi].tp_type); | |
4329 | |
4330 if (pt != NULL && pt->pt_hl_id > 0) | |
4331 { | |
4332 int pt_attr = syn_id2attr(pt->pt_hl_id); | |
4333 | |
4334 text_prop_type = pt; | |
4335 text_prop_attr = | |
4336 hl_combine_attr(text_prop_attr, pt_attr); | |
4337 text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE; | |
4338 } | |
4339 } | |
4340 } | |
4341 } | |
4342 #endif | |
4343 | |
4344 /* Decide which of the highlight attributes to use. */ | |
4345 attr_pri = TRUE; | |
4346 #ifdef LINE_ATTR | |
4347 if (area_attr != 0) | |
4348 char_attr = hl_combine_attr(line_attr, area_attr); | |
4349 else if (search_attr != 0) | |
4350 char_attr = hl_combine_attr(line_attr, search_attr); | |
4351 # ifdef FEAT_TEXT_PROP | |
4352 else if (text_prop_type != NULL) | |
4353 { | |
4354 char_attr = hl_combine_attr( | |
4355 line_attr != 0 ? line_attr : win_attr, text_prop_attr); | |
4356 } | |
4357 # endif | |
4358 else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL) | |
4359 || vcol < fromcol || vcol_prev < fromcol_prev | |
4360 || vcol >= tocol)) | |
4361 { | |
4362 // Use line_attr when not in the Visual or 'incsearch' area | |
4363 // (area_attr may be 0 when "noinvcur" is set). | |
4364 char_attr = line_attr; | |
4365 attr_pri = FALSE; | |
4366 } | |
4367 #else | |
4368 if (area_attr != 0) | |
4369 char_attr = area_attr; | |
4370 else if (search_attr != 0) | |
4371 char_attr = search_attr; | |
4372 #endif | |
4373 else | |
4374 { | |
4375 attr_pri = FALSE; | |
4376 #ifdef FEAT_TEXT_PROP | |
4377 if (text_prop_type != NULL) | |
4378 { | |
4379 if (text_prop_combine) | |
4380 char_attr = hl_combine_attr( | |
4381 syntax_attr, text_prop_attr); | |
4382 else | |
4383 char_attr = hl_combine_attr( | |
4384 win_attr, text_prop_attr); | |
4385 } | |
4386 else | |
4387 #endif | |
4388 #ifdef FEAT_SYN_HL | |
4389 if (has_syntax) | |
4390 char_attr = syntax_attr; | |
4391 else | |
4392 #endif | |
4393 char_attr = 0; | |
4394 } | |
4395 } | |
4396 if (char_attr == 0) | |
4397 char_attr = win_attr; | |
4398 | |
4399 /* | |
4400 * Get the next character to put on the screen. | |
4401 */ | |
4402 /* | |
4403 * The "p_extra" points to the extra stuff that is inserted to | |
4404 * represent special characters (non-printable stuff) and other | |
4405 * things. When all characters are the same, c_extra is used. | |
4406 * If c_final is set, it will compulsorily be used at the end. | |
4407 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past | |
4408 * "p_extra[n_extra]". | |
4409 * For the '$' of the 'list' option, n_extra == 1, p_extra == "". | |
4410 */ | |
4411 if (n_extra > 0) | |
4412 { | |
4413 if (c_extra != NUL || (n_extra == 1 && c_final != NUL)) | |
4414 { | |
4415 c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra; | |
4416 mb_c = c; /* doesn't handle non-utf-8 multi-byte! */ | |
4417 if (enc_utf8 && utf_char2len(c) > 1) | |
4418 { | |
4419 mb_utf8 = TRUE; | |
4420 u8cc[0] = 0; | |
4421 c = 0xc0; | |
4422 } | |
4423 else | |
4424 mb_utf8 = FALSE; | |
4425 } | |
4426 else | |
4427 { | |
4428 c = *p_extra; | |
4429 if (has_mbyte) | |
4430 { | |
4431 mb_c = c; | |
4432 if (enc_utf8) | |
4433 { | |
4434 /* If the UTF-8 character is more than one byte: | |
4435 * Decode it into "mb_c". */ | |
4436 mb_l = utfc_ptr2len(p_extra); | |
4437 mb_utf8 = FALSE; | |
4438 if (mb_l > n_extra) | |
4439 mb_l = 1; | |
4440 else if (mb_l > 1) | |
4441 { | |
4442 mb_c = utfc_ptr2char(p_extra, u8cc); | |
4443 mb_utf8 = TRUE; | |
4444 c = 0xc0; | |
4445 } | |
4446 } | |
4447 else | |
4448 { | |
4449 /* if this is a DBCS character, put it in "mb_c" */ | |
4450 mb_l = MB_BYTE2LEN(c); | |
4451 if (mb_l >= n_extra) | |
4452 mb_l = 1; | |
4453 else if (mb_l > 1) | |
4454 mb_c = (c << 8) + p_extra[1]; | |
4455 } | |
4456 if (mb_l == 0) /* at the NUL at end-of-line */ | |
4457 mb_l = 1; | |
4458 | |
4459 /* If a double-width char doesn't fit display a '>' in the | |
4460 * last column. */ | |
4461 if (( | |
4462 # ifdef FEAT_RIGHTLEFT | |
4463 wp->w_p_rl ? (col <= 0) : | |
4464 # endif | |
4465 (col >= wp->w_width - 1)) | |
4466 && (*mb_char2cells)(mb_c) == 2) | |
4467 { | |
4468 c = '>'; | |
4469 mb_c = c; | |
4470 mb_l = 1; | |
4471 mb_utf8 = FALSE; | |
4472 multi_attr = HL_ATTR(HLF_AT); | |
4473 #ifdef FEAT_SYN_HL | |
4474 if (cul_attr) | |
4475 multi_attr = hl_combine_attr(multi_attr, cul_attr); | |
4476 #endif | |
4477 /* put the pointer back to output the double-width | |
4478 * character at the start of the next line. */ | |
4479 ++n_extra; | |
4480 --p_extra; | |
4481 } | |
4482 else | |
4483 { | |
4484 n_extra -= mb_l - 1; | |
4485 p_extra += mb_l - 1; | |
4486 } | |
4487 } | |
4488 ++p_extra; | |
4489 } | |
4490 --n_extra; | |
4491 } | |
4492 else | |
4493 { | |
4494 #ifdef FEAT_LINEBREAK | |
4495 int c0; | |
4496 #endif | |
4497 | |
4498 if (p_extra_free != NULL) | |
4499 VIM_CLEAR(p_extra_free); | |
4500 /* | |
4501 * Get a character from the line itself. | |
4502 */ | |
4503 c = *ptr; | |
4504 #ifdef FEAT_LINEBREAK | |
4505 c0 = *ptr; | |
4506 #endif | |
4507 if (has_mbyte) | |
4508 { | |
4509 mb_c = c; | |
4510 if (enc_utf8) | |
4511 { | |
4512 /* If the UTF-8 character is more than one byte: Decode it | |
4513 * into "mb_c". */ | |
4514 mb_l = utfc_ptr2len(ptr); | |
4515 mb_utf8 = FALSE; | |
4516 if (mb_l > 1) | |
4517 { | |
4518 mb_c = utfc_ptr2char(ptr, u8cc); | |
4519 /* Overlong encoded ASCII or ASCII with composing char | |
4520 * is displayed normally, except a NUL. */ | |
4521 if (mb_c < 0x80) | |
4522 { | |
4523 c = mb_c; | |
4524 #ifdef FEAT_LINEBREAK | |
4525 c0 = mb_c; | |
4526 #endif | |
4527 } | |
4528 mb_utf8 = TRUE; | |
4529 | |
4530 /* At start of the line we can have a composing char. | |
4531 * Draw it as a space with a composing char. */ | |
4532 if (utf_iscomposing(mb_c)) | |
4533 { | |
4534 int i; | |
4535 | |
4536 for (i = Screen_mco - 1; i > 0; --i) | |
4537 u8cc[i] = u8cc[i - 1]; | |
4538 u8cc[0] = mb_c; | |
4539 mb_c = ' '; | |
4540 } | |
4541 } | |
4542 | |
4543 if ((mb_l == 1 && c >= 0x80) | |
4544 || (mb_l >= 1 && mb_c == 0) | |
4545 || (mb_l > 1 && (!vim_isprintc(mb_c)))) | |
4546 { | |
4547 /* | |
4548 * Illegal UTF-8 byte: display as <xx>. | |
4549 * Non-BMP character : display as ? or fullwidth ?. | |
4550 */ | |
4551 transchar_hex(extra, mb_c); | |
4552 # ifdef FEAT_RIGHTLEFT | |
4553 if (wp->w_p_rl) /* reverse */ | |
4554 rl_mirror(extra); | |
4555 # endif | |
4556 p_extra = extra; | |
4557 c = *p_extra; | |
4558 mb_c = mb_ptr2char_adv(&p_extra); | |
4559 mb_utf8 = (c >= 0x80); | |
4560 n_extra = (int)STRLEN(p_extra); | |
4561 c_extra = NUL; | |
4562 c_final = NUL; | |
4563 if (area_attr == 0 && search_attr == 0) | |
4564 { | |
4565 n_attr = n_extra + 1; | |
4566 extra_attr = HL_ATTR(HLF_8); | |
4567 saved_attr2 = char_attr; /* save current attr */ | |
4568 } | |
4569 } | |
4570 else if (mb_l == 0) /* at the NUL at end-of-line */ | |
4571 mb_l = 1; | |
4572 #ifdef FEAT_ARABIC | |
4573 else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c)) | |
4574 { | |
4575 /* Do Arabic shaping. */ | |
4576 int pc, pc1, nc; | |
4577 int pcc[MAX_MCO]; | |
4578 | |
4579 /* The idea of what is the previous and next | |
4580 * character depends on 'rightleft'. */ | |
4581 if (wp->w_p_rl) | |
4582 { | |
4583 pc = prev_c; | |
4584 pc1 = prev_c1; | |
4585 nc = utf_ptr2char(ptr + mb_l); | |
4586 prev_c1 = u8cc[0]; | |
4587 } | |
4588 else | |
4589 { | |
4590 pc = utfc_ptr2char(ptr + mb_l, pcc); | |
4591 nc = prev_c; | |
4592 pc1 = pcc[0]; | |
4593 } | |
4594 prev_c = mb_c; | |
4595 | |
4596 mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc); | |
4597 } | |
4598 else | |
4599 prev_c = mb_c; | |
4600 #endif | |
4601 } | |
4602 else /* enc_dbcs */ | |
4603 { | |
4604 mb_l = MB_BYTE2LEN(c); | |
4605 if (mb_l == 0) /* at the NUL at end-of-line */ | |
4606 mb_l = 1; | |
4607 else if (mb_l > 1) | |
4608 { | |
4609 /* We assume a second byte below 32 is illegal. | |
4610 * Hopefully this is OK for all double-byte encodings! | |
4611 */ | |
4612 if (ptr[1] >= 32) | |
4613 mb_c = (c << 8) + ptr[1]; | |
4614 else | |
4615 { | |
4616 if (ptr[1] == NUL) | |
4617 { | |
4618 /* head byte at end of line */ | |
4619 mb_l = 1; | |
4620 transchar_nonprint(extra, c); | |
4621 } | |
4622 else | |
4623 { | |
4624 /* illegal tail byte */ | |
4625 mb_l = 2; | |
4626 STRCPY(extra, "XX"); | |
4627 } | |
4628 p_extra = extra; | |
4629 n_extra = (int)STRLEN(extra) - 1; | |
4630 c_extra = NUL; | |
4631 c_final = NUL; | |
4632 c = *p_extra++; | |
4633 if (area_attr == 0 && search_attr == 0) | |
4634 { | |
4635 n_attr = n_extra + 1; | |
4636 extra_attr = HL_ATTR(HLF_8); | |
4637 saved_attr2 = char_attr; /* save current attr */ | |
4638 } | |
4639 mb_c = c; | |
4640 } | |
4641 } | |
4642 } | |
4643 /* If a double-width char doesn't fit display a '>' in the | |
4644 * last column; the character is displayed at the start of the | |
4645 * next line. */ | |
4646 if (( | |
4647 # ifdef FEAT_RIGHTLEFT | |
4648 wp->w_p_rl ? (col <= 0) : | |
4649 # endif | |
4650 (col >= wp->w_width - 1)) | |
4651 && (*mb_char2cells)(mb_c) == 2) | |
4652 { | |
4653 c = '>'; | |
4654 mb_c = c; | |
4655 mb_utf8 = FALSE; | |
4656 mb_l = 1; | |
4657 multi_attr = HL_ATTR(HLF_AT); | |
4658 // Put pointer back so that the character will be | |
4659 // displayed at the start of the next line. | |
4660 --ptr; | |
4661 #ifdef FEAT_CONCEAL | |
4662 did_decrement_ptr = TRUE; | |
4663 #endif | |
4664 } | |
4665 else if (*ptr != NUL) | |
4666 ptr += mb_l - 1; | |
4667 | |
4668 /* If a double-width char doesn't fit at the left side display | |
4669 * a '<' in the first column. Don't do this for unprintable | |
4670 * characters. */ | |
4671 if (n_skip > 0 && mb_l > 1 && n_extra == 0) | |
4672 { | |
4673 n_extra = 1; | |
4674 c_extra = MB_FILLER_CHAR; | |
4675 c_final = NUL; | |
4676 c = ' '; | |
4677 if (area_attr == 0 && search_attr == 0) | |
4678 { | |
4679 n_attr = n_extra + 1; | |
4680 extra_attr = HL_ATTR(HLF_AT); | |
4681 saved_attr2 = char_attr; /* save current attr */ | |
4682 } | |
4683 mb_c = c; | |
4684 mb_utf8 = FALSE; | |
4685 mb_l = 1; | |
4686 } | |
4687 | |
4688 } | |
4689 ++ptr; | |
4690 | |
4691 if (extra_check) | |
4692 { | |
4693 #ifdef FEAT_SPELL | |
4694 int can_spell = TRUE; | |
4695 #endif | |
4696 | |
4697 #ifdef FEAT_TERMINAL | |
4698 if (get_term_attr) | |
4699 { | |
4700 syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol); | |
4701 | |
4702 if (!attr_pri) | |
4703 char_attr = syntax_attr; | |
4704 else | |
4705 char_attr = hl_combine_attr(syntax_attr, char_attr); | |
4706 } | |
4707 #endif | |
4708 | |
4709 #ifdef FEAT_SYN_HL | |
4710 // Get syntax attribute, unless still at the start of the line | |
4711 // (double-wide char that doesn't fit). | |
4712 v = (long)(ptr - line); | |
4713 if (has_syntax && v > 0) | |
4714 { | |
4715 /* Get the syntax attribute for the character. If there | |
4716 * is an error, disable syntax highlighting. */ | |
4717 save_did_emsg = did_emsg; | |
4718 did_emsg = FALSE; | |
4719 | |
4720 syntax_attr = get_syntax_attr((colnr_T)v - 1, | |
4721 # ifdef FEAT_SPELL | |
4722 has_spell ? &can_spell : | |
4723 # endif | |
4724 NULL, FALSE); | |
4725 | |
4726 if (did_emsg) | |
4727 { | |
4728 wp->w_s->b_syn_error = TRUE; | |
4729 has_syntax = FALSE; | |
4730 syntax_attr = 0; | |
4731 } | |
4732 else | |
4733 did_emsg = save_did_emsg; | |
4734 | |
4735 // combine syntax attribute with 'wincolor' | |
4736 if (win_attr != 0) | |
4737 syntax_attr = hl_combine_attr(win_attr, syntax_attr); | |
4738 | |
4739 # ifdef SYN_TIME_LIMIT | |
4740 if (wp->w_s->b_syn_slow) | |
4741 has_syntax = FALSE; | |
4742 # endif | |
4743 | |
4744 /* Need to get the line again, a multi-line regexp may | |
4745 * have made it invalid. */ | |
4746 line = ml_get_buf(wp->w_buffer, lnum, FALSE); | |
4747 ptr = line + v; | |
4748 | |
4749 # ifdef FEAT_TEXT_PROP | |
4750 // Text properties overrule syntax highlighting or combine. | |
4751 if (text_prop_attr == 0 || text_prop_combine) | |
4752 # endif | |
4753 { | |
4754 int comb_attr = syntax_attr; | |
4755 # ifdef FEAT_TEXT_PROP | |
4756 comb_attr = hl_combine_attr(text_prop_attr, comb_attr); | |
4757 # endif | |
4758 if (!attr_pri) | |
4759 { | |
4760 #ifdef FEAT_SYN_HL | |
4761 if (cul_attr) | |
4762 char_attr = hl_combine_attr( | |
4763 comb_attr, cul_attr); | |
4764 else | |
4765 #endif | |
4766 if (line_attr) | |
4767 char_attr = hl_combine_attr( | |
4768 comb_attr, line_attr); | |
4769 else | |
4770 char_attr = comb_attr; | |
4771 } | |
4772 else | |
4773 char_attr = hl_combine_attr(comb_attr, char_attr); | |
4774 } | |
4775 # ifdef FEAT_CONCEAL | |
4776 // no concealing past the end of the line, it interferes | |
4777 // with line highlighting | |
4778 if (c == NUL) | |
4779 syntax_flags = 0; | |
4780 else | |
4781 syntax_flags = get_syntax_info(&syntax_seqnr); | |
4782 # endif | |
4783 } | |
4784 #endif | |
4785 | |
4786 #ifdef FEAT_SPELL | |
4787 /* Check spelling (unless at the end of the line). | |
4788 * Only do this when there is no syntax highlighting, the | |
4789 * @Spell cluster is not used or the current syntax item | |
4790 * contains the @Spell cluster. */ | |
4791 if (has_spell && v >= word_end && v > cur_checked_col) | |
4792 { | |
4793 spell_attr = 0; | |
4794 if (c != 0 && ( | |
4795 # ifdef FEAT_SYN_HL | |
4796 !has_syntax || | |
4797 # endif | |
4798 can_spell)) | |
4799 { | |
4800 char_u *prev_ptr, *p; | |
4801 int len; | |
4802 hlf_T spell_hlf = HLF_COUNT; | |
4803 if (has_mbyte) | |
4804 { | |
4805 prev_ptr = ptr - mb_l; | |
4806 v -= mb_l - 1; | |
4807 } | |
4808 else | |
4809 prev_ptr = ptr - 1; | |
4810 | |
4811 /* Use nextline[] if possible, it has the start of the | |
4812 * next line concatenated. */ | |
4813 if ((prev_ptr - line) - nextlinecol >= 0) | |
4814 p = nextline + (prev_ptr - line) - nextlinecol; | |
4815 else | |
4816 p = prev_ptr; | |
4817 cap_col -= (int)(prev_ptr - line); | |
4818 len = spell_check(wp, p, &spell_hlf, &cap_col, | |
4819 nochange); | |
4820 word_end = v + len; | |
4821 | |
4822 /* In Insert mode only highlight a word that | |
4823 * doesn't touch the cursor. */ | |
4824 if (spell_hlf != HLF_COUNT | |
4825 && (State & INSERT) != 0 | |
4826 && wp->w_cursor.lnum == lnum | |
4827 && wp->w_cursor.col >= | |
4828 (colnr_T)(prev_ptr - line) | |
4829 && wp->w_cursor.col < (colnr_T)word_end) | |
4830 { | |
4831 spell_hlf = HLF_COUNT; | |
4832 spell_redraw_lnum = lnum; | |
4833 } | |
4834 | |
4835 if (spell_hlf == HLF_COUNT && p != prev_ptr | |
4836 && (p - nextline) + len > nextline_idx) | |
4837 { | |
4838 /* Remember that the good word continues at the | |
4839 * start of the next line. */ | |
4840 checked_lnum = lnum + 1; | |
4841 checked_col = (int)((p - nextline) + len - nextline_idx); | |
4842 } | |
4843 | |
4844 /* Turn index into actual attributes. */ | |
4845 if (spell_hlf != HLF_COUNT) | |
4846 spell_attr = highlight_attr[spell_hlf]; | |
4847 | |
4848 if (cap_col > 0) | |
4849 { | |
4850 if (p != prev_ptr | |
4851 && (p - nextline) + cap_col >= nextline_idx) | |
4852 { | |
4853 /* Remember that the word in the next line | |
4854 * must start with a capital. */ | |
4855 capcol_lnum = lnum + 1; | |
4856 cap_col = (int)((p - nextline) + cap_col | |
4857 - nextline_idx); | |
4858 } | |
4859 else | |
4860 /* Compute the actual column. */ | |
4861 cap_col += (int)(prev_ptr - line); | |
4862 } | |
4863 } | |
4864 } | |
4865 if (spell_attr != 0) | |
4866 { | |
4867 if (!attr_pri) | |
4868 char_attr = hl_combine_attr(char_attr, spell_attr); | |
4869 else | |
4870 char_attr = hl_combine_attr(spell_attr, char_attr); | |
4871 } | |
4872 #endif | |
4873 #ifdef FEAT_LINEBREAK | |
4874 /* | |
4875 * Found last space before word: check for line break. | |
4876 */ | |
4877 if (wp->w_p_lbr && c0 == c | |
4878 && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr)) | |
4879 { | |
4880 int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0; | |
4881 char_u *p = ptr - (mb_off + 1); | |
4882 | |
4883 /* TODO: is passing p for start of the line OK? */ | |
4884 n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, | |
4885 NULL) - 1; | |
4886 if (c == TAB && n_extra + col > wp->w_width) | |
4887 # ifdef FEAT_VARTABS | |
4888 n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts, | |
4889 wp->w_buffer->b_p_vts_array) - 1; | |
4890 # else | |
4891 n_extra = (int)wp->w_buffer->b_p_ts | |
4892 - vcol % (int)wp->w_buffer->b_p_ts - 1; | |
4893 # endif | |
4894 | |
4895 c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; | |
4896 c_final = NUL; | |
4897 if (VIM_ISWHITE(c)) | |
4898 { | |
4899 #ifdef FEAT_CONCEAL | |
4900 if (c == TAB) | |
4901 /* See "Tab alignment" below. */ | |
4902 FIX_FOR_BOGUSCOLS; | |
4903 #endif | |
4904 if (!wp->w_p_list) | |
4905 c = ' '; | |
4906 } | |
4907 } | |
4908 #endif | |
4909 | |
4910 // 'list': Change char 160 to lcs_nbsp and space to lcs_space. | |
4911 // But not when the character is followed by a composing | |
4912 // character (use mb_l to check that). | |
4913 if (wp->w_p_list | |
4914 && ((((c == 160 && mb_l == 1) | |
4915 || (mb_utf8 | |
4916 && ((mb_c == 160 && mb_l == 2) | |
4917 || (mb_c == 0x202f && mb_l == 3)))) | |
4918 && lcs_nbsp) | |
4919 || (c == ' ' | |
4920 && mb_l == 1 | |
4921 && lcs_space | |
4922 && ptr - line <= trailcol))) | |
4923 { | |
4924 c = (c == ' ') ? lcs_space : lcs_nbsp; | |
4925 if (area_attr == 0 && search_attr == 0) | |
4926 { | |
4927 n_attr = 1; | |
4928 extra_attr = HL_ATTR(HLF_8); | |
4929 saved_attr2 = char_attr; /* save current attr */ | |
4930 } | |
4931 mb_c = c; | |
4932 if (enc_utf8 && utf_char2len(c) > 1) | |
4933 { | |
4934 mb_utf8 = TRUE; | |
4935 u8cc[0] = 0; | |
4936 c = 0xc0; | |
4937 } | |
4938 else | |
4939 mb_utf8 = FALSE; | |
4940 } | |
4941 | |
4942 if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') | |
4943 { | |
4944 c = lcs_trail; | |
4945 if (!attr_pri) | |
4946 { | |
4947 n_attr = 1; | |
4948 extra_attr = HL_ATTR(HLF_8); | |
4949 saved_attr2 = char_attr; /* save current attr */ | |
4950 } | |
4951 mb_c = c; | |
4952 if (enc_utf8 && utf_char2len(c) > 1) | |
4953 { | |
4954 mb_utf8 = TRUE; | |
4955 u8cc[0] = 0; | |
4956 c = 0xc0; | |
4957 } | |
4958 else | |
4959 mb_utf8 = FALSE; | |
4960 } | |
4961 } | |
4962 | |
4963 /* | |
4964 * Handling of non-printable characters. | |
4965 */ | |
4966 if (!vim_isprintc(c)) | |
4967 { | |
4968 /* | |
4969 * when getting a character from the file, we may have to | |
4970 * turn it into something else on the way to putting it | |
4971 * into "ScreenLines". | |
4972 */ | |
4973 if (c == TAB && (!wp->w_p_list || lcs_tab1)) | |
4974 { | |
4975 int tab_len = 0; | |
4976 long vcol_adjusted = vcol; /* removed showbreak length */ | |
4977 #ifdef FEAT_LINEBREAK | |
4978 /* only adjust the tab_len, when at the first column | |
4979 * after the showbreak value was drawn */ | |
4980 if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) | |
4981 vcol_adjusted = vcol - MB_CHARLEN(p_sbr); | |
4982 #endif | |
4983 // tab amount depends on current column | |
4984 #ifdef FEAT_VARTABS | |
4985 tab_len = tabstop_padding(vcol_adjusted, | |
4986 wp->w_buffer->b_p_ts, | |
4987 wp->w_buffer->b_p_vts_array) - 1; | |
4988 #else | |
4989 tab_len = (int)wp->w_buffer->b_p_ts | |
4990 - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1; | |
4991 #endif | |
4992 | |
4993 #ifdef FEAT_LINEBREAK | |
4994 if (!wp->w_p_lbr || !wp->w_p_list) | |
4995 #endif | |
4996 // tab amount depends on current column | |
4997 n_extra = tab_len; | |
4998 #ifdef FEAT_LINEBREAK | |
4999 else | |
5000 { | |
5001 char_u *p; | |
5002 int len; | |
5003 int i; | |
5004 int saved_nextra = n_extra; | |
5005 | |
5006 #ifdef FEAT_CONCEAL | |
5007 if (vcol_off > 0) | |
5008 // there are characters to conceal | |
5009 tab_len += vcol_off; | |
5010 // boguscols before FIX_FOR_BOGUSCOLS macro from above | |
5011 if (wp->w_p_list && lcs_tab1 && old_boguscols > 0 | |
5012 && n_extra > tab_len) | |
5013 tab_len += n_extra - tab_len; | |
5014 #endif | |
5015 | |
5016 // if n_extra > 0, it gives the number of chars, to | |
5017 // use for a tab, else we need to calculate the width | |
5018 // for a tab | |
5019 len = (tab_len * mb_char2len(lcs_tab2)); | |
5020 if (n_extra > 0) | |
5021 len += n_extra - tab_len; | |
5022 c = lcs_tab1; | |
5023 p = alloc(len + 1); | |
5024 vim_memset(p, ' ', len); | |
5025 p[len] = NUL; | |
5026 vim_free(p_extra_free); | |
5027 p_extra_free = p; | |
5028 for (i = 0; i < tab_len; i++) | |
5029 { | |
5030 int lcs = lcs_tab2; | |
5031 | |
5032 if (*p == NUL) | |
5033 { | |
5034 tab_len = i; | |
5035 break; | |
5036 } | |
5037 | |
5038 // if lcs_tab3 is given, need to change the char | |
5039 // for tab | |
5040 if (lcs_tab3 && i == tab_len - 1) | |
5041 lcs = lcs_tab3; | |
5042 mb_char2bytes(lcs, p); | |
5043 p += mb_char2len(lcs); | |
5044 n_extra += mb_char2len(lcs) | |
5045 - (saved_nextra > 0 ? 1 : 0); | |
5046 } | |
5047 p_extra = p_extra_free; | |
5048 #ifdef FEAT_CONCEAL | |
5049 // n_extra will be increased by FIX_FOX_BOGUSCOLS | |
5050 // macro below, so need to adjust for that here | |
5051 if (vcol_off > 0) | |
5052 n_extra -= vcol_off; | |
5053 #endif | |
5054 } | |
5055 #endif | |
5056 #ifdef FEAT_CONCEAL | |
5057 { | |
5058 int vc_saved = vcol_off; | |
5059 | |
5060 /* Tab alignment should be identical regardless of | |
5061 * 'conceallevel' value. So tab compensates of all | |
5062 * previous concealed characters, and thus resets | |
5063 * vcol_off and boguscols accumulated so far in the | |
5064 * line. Note that the tab can be longer than | |
5065 * 'tabstop' when there are concealed characters. */ | |
5066 FIX_FOR_BOGUSCOLS; | |
5067 | |
5068 /* Make sure, the highlighting for the tab char will be | |
5069 * correctly set further below (effectively reverts the | |
5070 * FIX_FOR_BOGSUCOLS macro */ | |
5071 if (n_extra == tab_len + vc_saved && wp->w_p_list | |
5072 && lcs_tab1) | |
5073 tab_len += vc_saved; | |
5074 } | |
5075 #endif | |
5076 mb_utf8 = FALSE; /* don't draw as UTF-8 */ | |
5077 if (wp->w_p_list) | |
5078 { | |
5079 c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1; | |
5080 #ifdef FEAT_LINEBREAK | |
5081 if (wp->w_p_lbr) | |
5082 c_extra = NUL; /* using p_extra from above */ | |
5083 else | |
5084 #endif | |
5085 c_extra = lcs_tab2; | |
5086 c_final = lcs_tab3; | |
5087 n_attr = tab_len + 1; | |
5088 extra_attr = HL_ATTR(HLF_8); | |
5089 saved_attr2 = char_attr; /* save current attr */ | |
5090 mb_c = c; | |
5091 if (enc_utf8 && utf_char2len(c) > 1) | |
5092 { | |
5093 mb_utf8 = TRUE; | |
5094 u8cc[0] = 0; | |
5095 c = 0xc0; | |
5096 } | |
5097 } | |
5098 else | |
5099 { | |
5100 c_final = NUL; | |
5101 c_extra = ' '; | |
5102 c = ' '; | |
5103 } | |
5104 } | |
5105 else if (c == NUL | |
5106 && (wp->w_p_list | |
5107 || ((fromcol >= 0 || fromcol_prev >= 0) | |
5108 && tocol > vcol | |
5109 && VIsual_mode != Ctrl_V | |
5110 && ( | |
5111 # ifdef FEAT_RIGHTLEFT | |
5112 wp->w_p_rl ? (col >= 0) : | |
5113 # endif | |
5114 (col < wp->w_width)) | |
5115 && !(noinvcur | |
5116 && lnum == wp->w_cursor.lnum | |
5117 && (colnr_T)vcol == wp->w_virtcol))) | |
5118 && lcs_eol_one > 0) | |
5119 { | |
5120 /* Display a '$' after the line or highlight an extra | |
5121 * character if the line break is included. */ | |
5122 #if defined(FEAT_DIFF) || defined(LINE_ATTR) | |
5123 /* For a diff line the highlighting continues after the | |
5124 * "$". */ | |
5125 if ( | |
5126 # ifdef FEAT_DIFF | |
5127 diff_hlf == (hlf_T)0 | |
5128 # ifdef LINE_ATTR | |
5129 && | |
5130 # endif | |
5131 # endif | |
5132 # ifdef LINE_ATTR | |
5133 line_attr == 0 | |
5134 # endif | |
5135 ) | |
5136 #endif | |
5137 { | |
5138 /* In virtualedit, visual selections may extend | |
5139 * beyond end of line. */ | |
5140 if (area_highlighting && virtual_active() | |
5141 && tocol != MAXCOL && vcol < tocol) | |
5142 n_extra = 0; | |
5143 else | |
5144 { | |
5145 p_extra = at_end_str; | |
5146 n_extra = 1; | |
5147 c_extra = NUL; | |
5148 c_final = NUL; | |
5149 } | |
5150 } | |
5151 if (wp->w_p_list && lcs_eol > 0) | |
5152 c = lcs_eol; | |
5153 else | |
5154 c = ' '; | |
5155 lcs_eol_one = -1; | |
5156 --ptr; /* put it back at the NUL */ | |
5157 if (!attr_pri) | |
5158 { | |
5159 extra_attr = HL_ATTR(HLF_AT); | |
5160 n_attr = 1; | |
5161 } | |
5162 mb_c = c; | |
5163 if (enc_utf8 && utf_char2len(c) > 1) | |
5164 { | |
5165 mb_utf8 = TRUE; | |
5166 u8cc[0] = 0; | |
5167 c = 0xc0; | |
5168 } | |
5169 else | |
5170 mb_utf8 = FALSE; /* don't draw as UTF-8 */ | |
5171 } | |
5172 else if (c != NUL) | |
5173 { | |
5174 p_extra = transchar(c); | |
5175 if (n_extra == 0) | |
5176 n_extra = byte2cells(c) - 1; | |
5177 #ifdef FEAT_RIGHTLEFT | |
5178 if ((dy_flags & DY_UHEX) && wp->w_p_rl) | |
5179 rl_mirror(p_extra); /* reverse "<12>" */ | |
5180 #endif | |
5181 c_extra = NUL; | |
5182 c_final = NUL; | |
5183 #ifdef FEAT_LINEBREAK | |
5184 if (wp->w_p_lbr) | |
5185 { | |
5186 char_u *p; | |
5187 | |
5188 c = *p_extra; | |
5189 p = alloc(n_extra + 1); | |
5190 vim_memset(p, ' ', n_extra); | |
5191 STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1); | |
5192 p[n_extra] = NUL; | |
5193 vim_free(p_extra_free); | |
5194 p_extra_free = p_extra = p; | |
5195 } | |
5196 else | |
5197 #endif | |
5198 { | |
5199 n_extra = byte2cells(c) - 1; | |
5200 c = *p_extra++; | |
5201 } | |
5202 if (!attr_pri) | |
5203 { | |
5204 n_attr = n_extra + 1; | |
5205 extra_attr = HL_ATTR(HLF_8); | |
5206 saved_attr2 = char_attr; /* save current attr */ | |
5207 } | |
5208 mb_utf8 = FALSE; /* don't draw as UTF-8 */ | |
5209 } | |
5210 else if (VIsual_active | |
5211 && (VIsual_mode == Ctrl_V | |
5212 || VIsual_mode == 'v') | |
5213 && virtual_active() | |
5214 && tocol != MAXCOL | |
5215 && vcol < tocol | |
5216 && ( | |
5217 #ifdef FEAT_RIGHTLEFT | |
5218 wp->w_p_rl ? (col >= 0) : | |
5219 #endif | |
5220 (col < wp->w_width))) | |
5221 { | |
5222 c = ' '; | |
5223 --ptr; /* put it back at the NUL */ | |
5224 } | |
5225 #if defined(LINE_ATTR) | |
5226 else if (( | |
5227 # ifdef FEAT_DIFF | |
5228 diff_hlf != (hlf_T)0 || | |
5229 # endif | |
5230 # ifdef FEAT_TERMINAL | |
5231 win_attr != 0 || | |
5232 # endif | |
5233 line_attr != 0 | |
5234 ) && ( | |
5235 # ifdef FEAT_RIGHTLEFT | |
5236 wp->w_p_rl ? (col >= 0) : | |
5237 # endif | |
5238 (col | |
5239 # ifdef FEAT_CONCEAL | |
5240 - boguscols | |
5241 # endif | |
5242 < wp->w_width))) | |
5243 { | |
5244 /* Highlight until the right side of the window */ | |
5245 c = ' '; | |
5246 --ptr; /* put it back at the NUL */ | |
5247 | |
5248 /* Remember we do the char for line highlighting. */ | |
5249 ++did_line_attr; | |
5250 | |
5251 /* don't do search HL for the rest of the line */ | |
5252 if (line_attr != 0 && char_attr == search_attr | |
5253 && (did_line_attr > 1 | |
5254 || (wp->w_p_list && lcs_eol > 0))) | |
5255 char_attr = line_attr; | |
5256 # ifdef FEAT_DIFF | |
5257 if (diff_hlf == HLF_TXD) | |
5258 { | |
5259 diff_hlf = HLF_CHD; | |
5260 if (vi_attr == 0 || char_attr != vi_attr) | |
5261 { | |
5262 char_attr = HL_ATTR(diff_hlf); | |
5263 if (wp->w_p_cul && lnum == wp->w_cursor.lnum | |
5264 && wp->w_p_culopt_flags != CULOPT_NBR | |
5265 && (!cul_screenline | |
5266 || (vcol >= left_curline_col | |
5267 && vcol <= right_curline_col))) | |
5268 char_attr = hl_combine_attr( | |
5269 char_attr, HL_ATTR(HLF_CUL)); | |
5270 } | |
5271 } | |
5272 # endif | |
5273 # ifdef FEAT_TERMINAL | |
5274 if (win_attr != 0) | |
5275 { | |
5276 char_attr = win_attr; | |
5277 if (wp->w_p_cul && lnum == wp->w_cursor.lnum) | |
5278 { | |
5279 if (!cul_screenline || (vcol >= left_curline_col | |
5280 && vcol <= right_curline_col)) | |
5281 char_attr = hl_combine_attr( | |
5282 char_attr, HL_ATTR(HLF_CUL)); | |
5283 } | |
5284 else if (line_attr) | |
5285 char_attr = hl_combine_attr(char_attr, line_attr); | |
5286 } | |
5287 # endif | |
5288 } | |
5289 #endif | |
5290 } | |
5291 | |
5292 #ifdef FEAT_CONCEAL | |
5293 if ( wp->w_p_cole > 0 | |
5294 && (wp != curwin || lnum != wp->w_cursor.lnum || | |
5295 conceal_cursor_line(wp)) | |
5296 && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0) | |
5297 && !(lnum_in_visual_area | |
5298 && vim_strchr(wp->w_p_cocu, 'v') == NULL)) | |
5299 { | |
5300 char_attr = conceal_attr; | |
5301 if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1) | |
5302 && (syn_get_sub_char() != NUL || match_conc | |
5303 || wp->w_p_cole == 1) | |
5304 && wp->w_p_cole != 3) | |
5305 { | |
5306 /* First time at this concealed item: display one | |
5307 * character. */ | |
5308 if (match_conc) | |
5309 c = match_conc; | |
5310 else if (syn_get_sub_char() != NUL) | |
5311 c = syn_get_sub_char(); | |
5312 else if (lcs_conceal != NUL) | |
5313 c = lcs_conceal; | |
5314 else | |
5315 c = ' '; | |
5316 | |
5317 prev_syntax_id = syntax_seqnr; | |
5318 | |
5319 if (n_extra > 0) | |
5320 vcol_off += n_extra; | |
5321 vcol += n_extra; | |
5322 if (wp->w_p_wrap && n_extra > 0) | |
5323 { | |
5324 # ifdef FEAT_RIGHTLEFT | |
5325 if (wp->w_p_rl) | |
5326 { | |
5327 col -= n_extra; | |
5328 boguscols -= n_extra; | |
5329 } | |
5330 else | |
5331 # endif | |
5332 { | |
5333 boguscols += n_extra; | |
5334 col += n_extra; | |
5335 } | |
5336 } | |
5337 n_extra = 0; | |
5338 n_attr = 0; | |
5339 } | |
5340 else if (n_skip == 0) | |
5341 { | |
5342 is_concealing = TRUE; | |
5343 n_skip = 1; | |
5344 } | |
5345 mb_c = c; | |
5346 if (enc_utf8 && utf_char2len(c) > 1) | |
5347 { | |
5348 mb_utf8 = TRUE; | |
5349 u8cc[0] = 0; | |
5350 c = 0xc0; | |
5351 } | |
5352 else | |
5353 mb_utf8 = FALSE; /* don't draw as UTF-8 */ | |
5354 } | |
5355 else | |
5356 { | |
5357 prev_syntax_id = 0; | |
5358 is_concealing = FALSE; | |
5359 } | |
5360 | |
5361 if (n_skip > 0 && did_decrement_ptr) | |
5362 // not showing the '>', put pointer back to avoid getting stuck | |
5363 ++ptr; | |
5364 | |
5365 #endif // FEAT_CONCEAL | |
5366 } | |
5367 | |
5368 #ifdef FEAT_CONCEAL | |
5369 /* In the cursor line and we may be concealing characters: correct | |
5370 * the cursor column when we reach its position. */ | |
5371 if (!did_wcol && draw_state == WL_LINE | |
5372 && wp == curwin && lnum == wp->w_cursor.lnum | |
5373 && conceal_cursor_line(wp) | |
5374 && (int)wp->w_virtcol <= vcol + n_skip) | |
5375 { | |
5376 # ifdef FEAT_RIGHTLEFT | |
5377 if (wp->w_p_rl) | |
5378 wp->w_wcol = wp->w_width - col + boguscols - 1; | |
5379 else | |
5380 # endif | |
5381 wp->w_wcol = col - boguscols; | |
5382 wp->w_wrow = row; | |
5383 did_wcol = TRUE; | |
5384 curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; | |
5385 } | |
5386 #endif | |
5387 | |
5388 /* Don't override visual selection highlighting. */ | |
5389 if (n_attr > 0 | |
5390 && draw_state == WL_LINE | |
5391 && !attr_pri) | |
5392 { | |
5393 #ifdef LINE_ATTR | |
5394 if (line_attr) | |
5395 char_attr = hl_combine_attr(extra_attr, line_attr); | |
5396 else | |
5397 #endif | |
5398 char_attr = extra_attr; | |
5399 } | |
5400 | |
5401 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) | |
5402 /* XIM don't send preedit_start and preedit_end, but they send | |
5403 * preedit_changed and commit. Thus Vim can't set "im_is_active", use | |
5404 * im_is_preediting() here. */ | |
5405 if (p_imst == IM_ON_THE_SPOT | |
5406 && xic != NULL | |
5407 && lnum == wp->w_cursor.lnum | |
5408 && (State & INSERT) | |
5409 && !p_imdisable | |
5410 && im_is_preediting() | |
5411 && draw_state == WL_LINE) | |
5412 { | |
5413 colnr_T tcol; | |
5414 | |
5415 if (preedit_end_col == MAXCOL) | |
5416 getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL); | |
5417 else | |
5418 tcol = preedit_end_col; | |
5419 if ((long)preedit_start_col <= vcol && vcol < (long)tcol) | |
5420 { | |
5421 if (feedback_old_attr < 0) | |
5422 { | |
5423 feedback_col = 0; | |
5424 feedback_old_attr = char_attr; | |
5425 } | |
5426 char_attr = im_get_feedback_attr(feedback_col); | |
5427 if (char_attr < 0) | |
5428 char_attr = feedback_old_attr; | |
5429 feedback_col++; | |
5430 } | |
5431 else if (feedback_old_attr >= 0) | |
5432 { | |
5433 char_attr = feedback_old_attr; | |
5434 feedback_old_attr = -1; | |
5435 feedback_col = 0; | |
5436 } | |
5437 } | |
5438 #endif | |
5439 /* | |
5440 * Handle the case where we are in column 0 but not on the first | |
5441 * character of the line and the user wants us to show us a | |
5442 * special character (via 'listchars' option "precedes:<char>". | |
5443 */ | |
5444 if (lcs_prec_todo != NUL | |
5445 && wp->w_p_list | |
5446 && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0) | |
5447 #ifdef FEAT_DIFF | |
5448 && filler_todo <= 0 | |
5449 #endif | |
5450 && draw_state > WL_NR | |
5451 && c != NUL) | |
5452 { | |
5453 c = lcs_prec; | |
5454 lcs_prec_todo = NUL; | |
5455 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) | |
5456 { | |
5457 /* Double-width character being overwritten by the "precedes" | |
5458 * character, need to fill up half the character. */ | |
5459 c_extra = MB_FILLER_CHAR; | |
5460 c_final = NUL; | |
5461 n_extra = 1; | |
5462 n_attr = 2; | |
5463 extra_attr = HL_ATTR(HLF_AT); | |
5464 } | |
5465 mb_c = c; | |
5466 if (enc_utf8 && utf_char2len(c) > 1) | |
5467 { | |
5468 mb_utf8 = TRUE; | |
5469 u8cc[0] = 0; | |
5470 c = 0xc0; | |
5471 } | |
5472 else | |
5473 mb_utf8 = FALSE; /* don't draw as UTF-8 */ | |
5474 if (!attr_pri) | |
5475 { | |
5476 saved_attr3 = char_attr; /* save current attr */ | |
5477 char_attr = HL_ATTR(HLF_AT); /* later copied to char_attr */ | |
5478 n_attr3 = 1; | |
5479 } | |
5480 } | |
5481 | |
5482 /* | |
5483 * At end of the text line or just after the last character. | |
5484 */ | |
5485 if ((c == NUL | |
5486 #if defined(LINE_ATTR) | |
5487 || did_line_attr == 1 | |
5488 #endif | |
5489 ) && eol_hl_off == 0) | |
5490 { | |
5491 #ifdef FEAT_SEARCH_EXTRA | |
5492 // flag to indicate whether prevcol equals startcol of search_hl or | |
5493 // one of the matches | |
5494 int prevcol_hl_flag = get_prevcol_hl_flag(wp, &search_hl, | |
5495 (long)(ptr - line) - (c == NUL)); | |
5496 #endif | |
5497 // Invert at least one char, used for Visual and empty line or | |
5498 // highlight match at end of line. If it's beyond the last | |
5499 // char on the screen, just overwrite that one (tricky!) Not | |
5500 // needed when a '$' was displayed for 'list'. | |
5501 if (lcs_eol == lcs_eol_one | |
5502 && ((area_attr != 0 && vcol == fromcol | |
5503 && (VIsual_mode != Ctrl_V | |
5504 || lnum == VIsual.lnum | |
5505 || lnum == curwin->w_cursor.lnum) | |
5506 && c == NUL) | |
5507 #ifdef FEAT_SEARCH_EXTRA | |
5508 // highlight 'hlsearch' match at end of line | |
5509 || (prevcol_hl_flag | |
5510 # ifdef FEAT_SYN_HL | |
5511 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum | |
5512 && !(wp == curwin && VIsual_active)) | |
5513 # endif | |
5514 # ifdef FEAT_DIFF | |
5515 && diff_hlf == (hlf_T)0 | |
5516 # endif | |
5517 # if defined(LINE_ATTR) | |
5518 && did_line_attr <= 1 | |
5519 # endif | |
5520 ) | |
5521 #endif | |
5522 )) | |
5523 { | |
5524 int n = 0; | |
5525 | |
5526 #ifdef FEAT_RIGHTLEFT | |
5527 if (wp->w_p_rl) | |
5528 { | |
5529 if (col < 0) | |
5530 n = 1; | |
5531 } | |
5532 else | |
5533 #endif | |
5534 { | |
5535 if (col >= wp->w_width) | |
5536 n = -1; | |
5537 } | |
5538 if (n != 0) | |
5539 { | |
5540 /* At the window boundary, highlight the last character | |
5541 * instead (better than nothing). */ | |
5542 off += n; | |
5543 col += n; | |
5544 } | |
5545 else | |
5546 { | |
5547 /* Add a blank character to highlight. */ | |
5548 ScreenLines[off] = ' '; | |
5549 if (enc_utf8) | |
5550 ScreenLinesUC[off] = 0; | |
5551 } | |
5552 #ifdef FEAT_SEARCH_EXTRA | |
5553 if (area_attr == 0) | |
5554 { | |
5555 // Use attributes from match with highest priority among | |
5556 // 'search_hl' and the match list. | |
5557 get_search_match_hl(wp, &search_hl, | |
5558 (long)(ptr - line), &char_attr); | |
5559 } | |
5560 #endif | |
5561 ScreenAttrs[off] = char_attr; | |
5562 #ifdef FEAT_RIGHTLEFT | |
5563 if (wp->w_p_rl) | |
5564 { | |
5565 --col; | |
5566 --off; | |
5567 } | |
5568 else | |
5569 #endif | |
5570 { | |
5571 ++col; | |
5572 ++off; | |
5573 } | |
5574 ++vcol; | |
5575 eol_hl_off = 1; | |
5576 } | |
5577 } | |
5578 | |
5579 /* | |
5580 * At end of the text line. | |
5581 */ | |
5582 if (c == NUL) | |
5583 { | |
5584 #ifdef FEAT_SYN_HL | |
5585 /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */ | |
5586 if (wp->w_p_wrap) | |
5587 v = wp->w_skipcol; | |
5588 else | |
5589 v = wp->w_leftcol; | |
5590 | |
5591 /* check if line ends before left margin */ | |
5592 if (vcol < v + col - win_col_off(wp)) | |
5593 vcol = v + col - win_col_off(wp); | |
5594 #ifdef FEAT_CONCEAL | |
5595 // Get rid of the boguscols now, we want to draw until the right | |
5596 // edge for 'cursorcolumn'. | |
5597 col -= boguscols; | |
5598 boguscols = 0; | |
5599 #endif | |
5600 | |
5601 if (draw_color_col) | |
5602 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); | |
5603 | |
5604 if (((wp->w_p_cuc | |
5605 && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off | |
5606 && (int)wp->w_virtcol < | |
5607 wp->w_width * (row - startrow + 1) + v | |
5608 && lnum != wp->w_cursor.lnum) | |
5609 || draw_color_col | |
5610 || win_attr != 0) | |
5611 # ifdef FEAT_RIGHTLEFT | |
5612 && !wp->w_p_rl | |
5613 # endif | |
5614 ) | |
5615 { | |
5616 int rightmost_vcol = 0; | |
5617 int i; | |
5618 | |
5619 if (wp->w_p_cuc) | |
5620 rightmost_vcol = wp->w_virtcol; | |
5621 if (draw_color_col) | |
5622 /* determine rightmost colorcolumn to possibly draw */ | |
5623 for (i = 0; color_cols[i] >= 0; ++i) | |
5624 if (rightmost_vcol < color_cols[i]) | |
5625 rightmost_vcol = color_cols[i]; | |
5626 | |
5627 while (col < wp->w_width) | |
5628 { | |
5629 ScreenLines[off] = ' '; | |
5630 if (enc_utf8) | |
5631 ScreenLinesUC[off] = 0; | |
5632 ++col; | |
5633 if (draw_color_col) | |
5634 draw_color_col = advance_color_col(VCOL_HLC, | |
5635 &color_cols); | |
5636 | |
5637 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) | |
5638 ScreenAttrs[off++] = HL_ATTR(HLF_CUC); | |
5639 else if (draw_color_col && VCOL_HLC == *color_cols) | |
5640 ScreenAttrs[off++] = HL_ATTR(HLF_MC); | |
5641 else | |
5642 ScreenAttrs[off++] = win_attr; | |
5643 | |
5644 if (VCOL_HLC >= rightmost_vcol && win_attr == 0) | |
5645 break; | |
5646 | |
5647 ++vcol; | |
5648 } | |
5649 } | |
5650 #endif | |
5651 | |
5652 screen_line(screen_row, wp->w_wincol, col, | |
5653 (int)wp->w_width, screen_line_flags); | |
5654 row++; | |
5655 | |
5656 /* | |
5657 * Update w_cline_height and w_cline_folded if the cursor line was | |
5658 * updated (saves a call to plines() later). | |
5659 */ | |
5660 if (wp == curwin && lnum == curwin->w_cursor.lnum) | |
5661 { | |
5662 curwin->w_cline_row = startrow; | |
5663 curwin->w_cline_height = row - startrow; | |
5664 #ifdef FEAT_FOLDING | |
5665 curwin->w_cline_folded = FALSE; | |
5666 #endif | |
5667 curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); | |
5668 } | |
5669 | |
5670 break; | |
5671 } | |
5672 | |
5673 // Show "extends" character from 'listchars' if beyond the line end and | |
5674 // 'list' is set. | |
5675 if (lcs_ext != NUL | |
5676 && wp->w_p_list | |
5677 && !wp->w_p_wrap | |
5678 #ifdef FEAT_DIFF | |
5679 && filler_todo <= 0 | |
5680 #endif | |
5681 && ( | |
5682 #ifdef FEAT_RIGHTLEFT | |
5683 wp->w_p_rl ? col == 0 : | |
5684 #endif | |
5685 col == wp->w_width - 1) | |
5686 && (*ptr != NUL | |
5687 || (wp->w_p_list && lcs_eol_one > 0) | |
5688 || (n_extra && (c_extra != NUL || *p_extra != NUL)))) | |
5689 { | |
5690 c = lcs_ext; | |
5691 char_attr = HL_ATTR(HLF_AT); | |
5692 mb_c = c; | |
5693 if (enc_utf8 && utf_char2len(c) > 1) | |
5694 { | |
5695 mb_utf8 = TRUE; | |
5696 u8cc[0] = 0; | |
5697 c = 0xc0; | |
5698 } | |
5699 else | |
5700 mb_utf8 = FALSE; | |
5701 } | |
5702 | |
5703 #ifdef FEAT_SYN_HL | |
5704 /* advance to the next 'colorcolumn' */ | |
5705 if (draw_color_col) | |
5706 draw_color_col = advance_color_col(VCOL_HLC, &color_cols); | |
5707 | |
5708 /* Highlight the cursor column if 'cursorcolumn' is set. But don't | |
5709 * highlight the cursor position itself. | |
5710 * Also highlight the 'colorcolumn' if it is different than | |
5711 * 'cursorcolumn' */ | |
5712 vcol_save_attr = -1; | |
5713 if (draw_state == WL_LINE && !lnum_in_visual_area | |
5714 && search_attr == 0 && area_attr == 0) | |
5715 { | |
5716 if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol | |
5717 && lnum != wp->w_cursor.lnum) | |
5718 { | |
5719 vcol_save_attr = char_attr; | |
5720 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC)); | |
5721 } | |
5722 else if (draw_color_col && VCOL_HLC == *color_cols) | |
5723 { | |
5724 vcol_save_attr = char_attr; | |
5725 char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC)); | |
5726 } | |
5727 } | |
5728 #endif | |
5729 | |
5730 /* | |
5731 * Store character to be displayed. | |
5732 * Skip characters that are left of the screen for 'nowrap'. | |
5733 */ | |
5734 vcol_prev = vcol; | |
5735 if (draw_state < WL_LINE || n_skip <= 0) | |
5736 { | |
5737 /* | |
5738 * Store the character. | |
5739 */ | |
5740 #if defined(FEAT_RIGHTLEFT) | |
5741 if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1) | |
5742 { | |
5743 /* A double-wide character is: put first halve in left cell. */ | |
5744 --off; | |
5745 --col; | |
5746 } | |
5747 #endif | |
5748 ScreenLines[off] = c; | |
5749 if (enc_dbcs == DBCS_JPNU) | |
5750 { | |
5751 if ((mb_c & 0xff00) == 0x8e00) | |
5752 ScreenLines[off] = 0x8e; | |
5753 ScreenLines2[off] = mb_c & 0xff; | |
5754 } | |
5755 else if (enc_utf8) | |
5756 { | |
5757 if (mb_utf8) | |
5758 { | |
5759 int i; | |
5760 | |
5761 ScreenLinesUC[off] = mb_c; | |
5762 if ((c & 0xff) == 0) | |
5763 ScreenLines[off] = 0x80; /* avoid storing zero */ | |
5764 for (i = 0; i < Screen_mco; ++i) | |
5765 { | |
5766 ScreenLinesC[i][off] = u8cc[i]; | |
5767 if (u8cc[i] == 0) | |
5768 break; | |
5769 } | |
5770 } | |
5771 else | |
5772 ScreenLinesUC[off] = 0; | |
5773 } | |
5774 if (multi_attr) | |
5775 { | |
5776 ScreenAttrs[off] = multi_attr; | |
5777 multi_attr = 0; | |
5778 } | |
5779 else | |
5780 ScreenAttrs[off] = char_attr; | |
5781 | |
5782 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) | |
5783 { | |
5784 /* Need to fill two screen columns. */ | |
5785 ++off; | |
5786 ++col; | |
5787 if (enc_utf8) | |
5788 /* UTF-8: Put a 0 in the second screen char. */ | |
5789 ScreenLines[off] = 0; | |
5790 else | |
5791 /* DBCS: Put second byte in the second screen char. */ | |
5792 ScreenLines[off] = mb_c & 0xff; | |
5793 if (draw_state > WL_NR | |
5794 #ifdef FEAT_DIFF | |
5795 && filler_todo <= 0 | |
5796 #endif | |
5797 ) | |
5798 ++vcol; | |
5799 /* When "tocol" is halfway a character, set it to the end of | |
5800 * the character, otherwise highlighting won't stop. */ | |
5801 if (tocol == vcol) | |
5802 ++tocol; | |
5803 #ifdef FEAT_RIGHTLEFT | |
5804 if (wp->w_p_rl) | |
5805 { | |
5806 /* now it's time to backup one cell */ | |
5807 --off; | |
5808 --col; | |
5809 } | |
5810 #endif | |
5811 } | |
5812 #ifdef FEAT_RIGHTLEFT | |
5813 if (wp->w_p_rl) | |
5814 { | |
5815 --off; | |
5816 --col; | |
5817 } | |
5818 else | |
5819 #endif | |
5820 { | |
5821 ++off; | |
5822 ++col; | |
5823 } | |
5824 } | |
5825 #ifdef FEAT_CONCEAL | |
5826 else if (wp->w_p_cole > 0 && is_concealing) | |
5827 { | |
5828 --n_skip; | |
5829 ++vcol_off; | |
5830 if (n_extra > 0) | |
5831 vcol_off += n_extra; | |
5832 if (wp->w_p_wrap) | |
5833 { | |
5834 /* | |
5835 * Special voodoo required if 'wrap' is on. | |
5836 * | |
5837 * Advance the column indicator to force the line | |
5838 * drawing to wrap early. This will make the line | |
5839 * take up the same screen space when parts are concealed, | |
5840 * so that cursor line computations aren't messed up. | |
5841 * | |
5842 * To avoid the fictitious advance of 'col' causing | |
5843 * trailing junk to be written out of the screen line | |
5844 * we are building, 'boguscols' keeps track of the number | |
5845 * of bad columns we have advanced. | |
5846 */ | |
5847 if (n_extra > 0) | |
5848 { | |
5849 vcol += n_extra; | |
5850 # ifdef FEAT_RIGHTLEFT | |
5851 if (wp->w_p_rl) | |
5852 { | |
5853 col -= n_extra; | |
5854 boguscols -= n_extra; | |
5855 } | |
5856 else | |
5857 # endif | |
5858 { | |
5859 col += n_extra; | |
5860 boguscols += n_extra; | |
5861 } | |
5862 n_extra = 0; | |
5863 n_attr = 0; | |
5864 } | |
5865 | |
5866 | |
5867 if (has_mbyte && (*mb_char2cells)(mb_c) > 1) | |
5868 { | |
5869 /* Need to fill two screen columns. */ | |
5870 # ifdef FEAT_RIGHTLEFT | |
5871 if (wp->w_p_rl) | |
5872 { | |
5873 --boguscols; | |
5874 --col; | |
5875 } | |
5876 else | |
5877 # endif | |
5878 { | |
5879 ++boguscols; | |
5880 ++col; | |
5881 } | |
5882 } | |
5883 | |
5884 # ifdef FEAT_RIGHTLEFT | |
5885 if (wp->w_p_rl) | |
5886 { | |
5887 --boguscols; | |
5888 --col; | |
5889 } | |
5890 else | |
5891 # endif | |
5892 { | |
5893 ++boguscols; | |
5894 ++col; | |
5895 } | |
5896 } | |
5897 else | |
5898 { | |
5899 if (n_extra > 0) | |
5900 { | |
5901 vcol += n_extra; | |
5902 n_extra = 0; | |
5903 n_attr = 0; | |
5904 } | |
5905 } | |
5906 | |
5907 } | |
5908 #endif /* FEAT_CONCEAL */ | |
5909 else | |
5910 --n_skip; | |
5911 | |
5912 /* Only advance the "vcol" when after the 'number' or 'relativenumber' | |
5913 * column. */ | |
5914 if (draw_state > WL_NR | |
5915 #ifdef FEAT_DIFF | |
5916 && filler_todo <= 0 | |
5917 #endif | |
5918 ) | |
5919 ++vcol; | |
5920 | |
5921 #ifdef FEAT_SYN_HL | |
5922 if (vcol_save_attr >= 0) | |
5923 char_attr = vcol_save_attr; | |
5924 #endif | |
5925 | |
5926 /* restore attributes after "predeces" in 'listchars' */ | |
5927 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) | |
5928 char_attr = saved_attr3; | |
5929 | |
5930 /* restore attributes after last 'listchars' or 'number' char */ | |
5931 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0) | |
5932 char_attr = saved_attr2; | |
5933 | |
5934 /* | |
5935 * At end of screen line and there is more to come: Display the line | |
5936 * so far. If there is no more to display it is caught above. | |
5937 */ | |
5938 if (( | |
5939 #ifdef FEAT_RIGHTLEFT | |
5940 wp->w_p_rl ? (col < 0) : | |
5941 #endif | |
5942 (col >= wp->w_width)) | |
5943 && (*ptr != NUL | |
5944 #ifdef FEAT_DIFF | |
5945 || filler_todo > 0 | |
5946 #endif | |
5947 || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str) | |
5948 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL))) | |
5949 ) | |
5950 { | |
5951 #ifdef FEAT_CONCEAL | |
5952 screen_line(screen_row, wp->w_wincol, col - boguscols, | |
5953 (int)wp->w_width, screen_line_flags); | |
5954 boguscols = 0; | |
5955 #else | |
5956 screen_line(screen_row, wp->w_wincol, col, | |
5957 (int)wp->w_width, screen_line_flags); | |
5958 #endif | |
5959 ++row; | |
5960 ++screen_row; | |
5961 | |
5962 /* When not wrapping and finished diff lines, or when displayed | |
5963 * '$' and highlighting until last column, break here. */ | |
5964 if ((!wp->w_p_wrap | |
5965 #ifdef FEAT_DIFF | |
5966 && filler_todo <= 0 | |
5967 #endif | |
5968 ) || lcs_eol_one == -1) | |
5969 break; | |
5970 | |
5971 /* When the window is too narrow draw all "@" lines. */ | |
5972 if (draw_state != WL_LINE | |
5973 #ifdef FEAT_DIFF | |
5974 && filler_todo <= 0 | |
5975 #endif | |
5976 ) | |
5977 { | |
5978 win_draw_end(wp, '@', ' ', TRUE, row, wp->w_height, HLF_AT); | |
5979 draw_vsep_win(wp, row); | |
5980 row = endrow; | |
5981 } | |
5982 | |
5983 /* When line got too long for screen break here. */ | |
5984 if (row == endrow) | |
5985 { | |
5986 ++row; | |
5987 break; | |
5988 } | |
5989 | |
5990 if (screen_cur_row == screen_row - 1 | |
5991 #ifdef FEAT_DIFF | |
5992 && filler_todo <= 0 | |
5993 #endif | |
5994 && wp->w_width == Columns) | |
5995 { | |
5996 /* Remember that the line wraps, used for modeless copy. */ | |
5997 LineWraps[screen_row - 1] = TRUE; | |
5998 | |
5999 /* | |
6000 * Special trick to make copy/paste of wrapped lines work with | |
6001 * xterm/screen: write an extra character beyond the end of | |
6002 * the line. This will work with all terminal types | |
6003 * (regardless of the xn,am settings). | |
6004 * Only do this on a fast tty. | |
6005 * Only do this if the cursor is on the current line | |
6006 * (something has been written in it). | |
6007 * Don't do this for the GUI. | |
6008 * Don't do this for double-width characters. | |
6009 * Don't do this for a window not at the right screen border. | |
6010 */ | |
6011 if (p_tf | |
6012 #ifdef FEAT_GUI | |
6013 && !gui.in_use | |
6014 #endif | |
6015 && !(has_mbyte | |
6016 && ((*mb_off2cells)(LineOffset[screen_row], | |
6017 LineOffset[screen_row] + screen_Columns) | |
6018 == 2 | |
6019 || (*mb_off2cells)(LineOffset[screen_row - 1] | |
6020 + (int)Columns - 2, | |
6021 LineOffset[screen_row] + screen_Columns) | |
6022 == 2))) | |
6023 { | |
6024 /* First make sure we are at the end of the screen line, | |
6025 * then output the same character again to let the | |
6026 * terminal know about the wrap. If the terminal doesn't | |
6027 * auto-wrap, we overwrite the character. */ | |
6028 if (screen_cur_col != wp->w_width) | |
6029 screen_char(LineOffset[screen_row - 1] | |
6030 + (unsigned)Columns - 1, | |
6031 screen_row - 1, (int)(Columns - 1)); | |
6032 | |
6033 /* When there is a multi-byte character, just output a | |
6034 * space to keep it simple. */ | |
6035 if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[ | |
6036 screen_row - 1] + (Columns - 1)]) > 1) | |
6037 out_char(' '); | |
6038 else | |
6039 out_char(ScreenLines[LineOffset[screen_row - 1] | |
6040 + (Columns - 1)]); | |
6041 /* force a redraw of the first char on the next line */ | |
6042 ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1; | |
6043 screen_start(); /* don't know where cursor is now */ | |
6044 } | |
6045 } | |
6046 | |
6047 col = 0; | |
6048 off = (unsigned)(current_ScreenLine - ScreenLines); | |
6049 #ifdef FEAT_RIGHTLEFT | |
6050 if (wp->w_p_rl) | |
6051 { | |
6052 col = wp->w_width - 1; /* col is not used if breaking! */ | |
6053 off += col; | |
6054 } | |
6055 #endif | |
6056 | |
6057 /* reset the drawing state for the start of a wrapped line */ | |
6058 draw_state = WL_START; | |
6059 saved_n_extra = n_extra; | |
6060 saved_p_extra = p_extra; | |
6061 saved_c_extra = c_extra; | |
6062 saved_c_final = c_final; | |
6063 #ifdef FEAT_SYN_HL | |
6064 if (!(cul_screenline | |
6065 # ifdef FEAT_DIFF | |
6066 && diff_hlf == (hlf_T)0) | |
6067 # endif | |
6068 ) | |
6069 saved_char_attr = char_attr; | |
6070 else | |
6071 #endif | |
6072 saved_char_attr = 0; | |
6073 n_extra = 0; | |
6074 lcs_prec_todo = lcs_prec; | |
6075 #ifdef FEAT_LINEBREAK | |
6076 # ifdef FEAT_DIFF | |
6077 if (filler_todo <= 0) | |
6078 # endif | |
6079 need_showbreak = TRUE; | |
6080 #endif | |
6081 #ifdef FEAT_DIFF | |
6082 --filler_todo; | |
6083 /* When the filler lines are actually below the last line of the | |
6084 * file, don't draw the line itself, break here. */ | |
6085 if (filler_todo == 0 && wp->w_botfill) | |
6086 break; | |
6087 #endif | |
6088 } | |
6089 | |
6090 } /* for every character in the line */ | |
6091 | |
6092 #ifdef FEAT_SPELL | |
6093 /* After an empty line check first word for capital. */ | |
6094 if (*skipwhite(line) == NUL) | |
6095 { | |
6096 capcol_lnum = lnum + 1; | |
6097 cap_col = 0; | |
6098 } | |
6099 #endif | |
6100 #ifdef FEAT_TEXT_PROP | |
6101 vim_free(text_props); | |
6102 vim_free(text_prop_idxs); | |
6103 #endif | |
6104 | |
6105 vim_free(p_extra_free); | |
6106 return row; | |
6107 } | |
6108 | 290 |
6109 /* | 291 /* |
6110 * Return if the composing characters at "off_from" and "off_to" differ. | 292 * Return if the composing characters at "off_from" and "off_to" differ. |
6111 * Only to be used when ScreenLinesUC[off_from] != 0. | 293 * Only to be used when ScreenLinesUC[off_from] != 0. |
6112 */ | 294 */ |
6180 return FALSE; | 362 return FALSE; |
6181 off = row * screen_Columns + col; | 363 off = row * screen_Columns + col; |
6182 return popup_mask[off] > screen_zindex || popup_transparent[off]; | 364 return popup_mask[off] > screen_zindex || popup_transparent[off]; |
6183 } | 365 } |
6184 #endif | 366 #endif |
367 | |
368 /* | |
369 * Reset the highlighting. Used before clearing the screen. | |
370 */ | |
371 void | |
372 reset_screen_attr(void) | |
373 { | |
374 #ifdef FEAT_GUI | |
375 if (gui.in_use) | |
376 // Use a code that will reset gui.highlight_mask in | |
377 // gui_stop_highlight(). | |
378 screen_attr = HL_ALL + 1; | |
379 else | |
380 #endif | |
381 // Use attributes that is very unlikely to appear in text. | |
382 screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH; | |
383 } | |
6185 | 384 |
6186 /* | 385 /* |
6187 * Move one "cooked" screen line to the screen, but only the characters that | 386 * Move one "cooked" screen line to the screen, but only the characters that |
6188 * have actually changed. Handle insert/delete character. | 387 * have actually changed. Handle insert/delete character. |
6189 * "coloff" gives the first column on the screen for this line. | 388 * "coloff" gives the first column on the screen for this line. |
6594 } | 793 } |
6595 } | 794 } |
6596 #endif | 795 #endif |
6597 | 796 |
6598 /* | 797 /* |
6599 * mark all status lines for redraw; used after first :cd | 798 * Draw the verticap separator right of window "wp" starting with line "row". |
6600 */ | 799 */ |
6601 void | 800 void |
6602 status_redraw_all(void) | |
6603 { | |
6604 win_T *wp; | |
6605 | |
6606 FOR_ALL_WINDOWS(wp) | |
6607 if (wp->w_status_height) | |
6608 { | |
6609 wp->w_redr_status = TRUE; | |
6610 redraw_later(VALID); | |
6611 } | |
6612 } | |
6613 | |
6614 /* | |
6615 * mark all status lines of the current buffer for redraw | |
6616 */ | |
6617 void | |
6618 status_redraw_curbuf(void) | |
6619 { | |
6620 win_T *wp; | |
6621 | |
6622 FOR_ALL_WINDOWS(wp) | |
6623 if (wp->w_status_height != 0 && wp->w_buffer == curbuf) | |
6624 { | |
6625 wp->w_redr_status = TRUE; | |
6626 redraw_later(VALID); | |
6627 } | |
6628 } | |
6629 | |
6630 /* | |
6631 * Redraw all status lines that need to be redrawn. | |
6632 */ | |
6633 void | |
6634 redraw_statuslines(void) | |
6635 { | |
6636 win_T *wp; | |
6637 | |
6638 FOR_ALL_WINDOWS(wp) | |
6639 if (wp->w_redr_status) | |
6640 win_redr_status(wp, FALSE); | |
6641 if (redraw_tabline) | |
6642 draw_tabline(); | |
6643 } | |
6644 | |
6645 #if defined(FEAT_WILDMENU) || defined(PROTO) | |
6646 /* | |
6647 * Redraw all status lines at the bottom of frame "frp". | |
6648 */ | |
6649 void | |
6650 win_redraw_last_status(frame_T *frp) | |
6651 { | |
6652 if (frp->fr_layout == FR_LEAF) | |
6653 frp->fr_win->w_redr_status = TRUE; | |
6654 else if (frp->fr_layout == FR_ROW) | |
6655 { | |
6656 FOR_ALL_FRAMES(frp, frp->fr_child) | |
6657 win_redraw_last_status(frp); | |
6658 } | |
6659 else /* frp->fr_layout == FR_COL */ | |
6660 { | |
6661 frp = frp->fr_child; | |
6662 while (frp->fr_next != NULL) | |
6663 frp = frp->fr_next; | |
6664 win_redraw_last_status(frp); | |
6665 } | |
6666 } | |
6667 #endif | |
6668 | |
6669 /* | |
6670 * Draw the verticap separator right of window "wp" starting with line "row". | |
6671 */ | |
6672 static void | |
6673 draw_vsep_win(win_T *wp, int row) | 801 draw_vsep_win(win_T *wp, int row) |
6674 { | 802 { |
6675 int hl; | 803 int hl; |
6676 int c; | 804 int c; |
6677 | 805 |
6954 vim_free(buf); | 1082 vim_free(buf); |
6955 } | 1083 } |
6956 #endif | 1084 #endif |
6957 | 1085 |
6958 /* | 1086 /* |
6959 * Redraw the status line of window wp. | |
6960 * | |
6961 * If inversion is possible we use it. Else '=' characters are used. | |
6962 * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is | |
6963 * displayed. | |
6964 */ | |
6965 static void | |
6966 win_redr_status(win_T *wp, int ignore_pum UNUSED) | |
6967 { | |
6968 int row; | |
6969 char_u *p; | |
6970 int len; | |
6971 int fillchar; | |
6972 int attr; | |
6973 int this_ru_col; | |
6974 static int busy = FALSE; | |
6975 | |
6976 /* It's possible to get here recursively when 'statusline' (indirectly) | |
6977 * invokes ":redrawstatus". Simply ignore the call then. */ | |
6978 if (busy) | |
6979 return; | |
6980 busy = TRUE; | |
6981 | |
6982 wp->w_redr_status = FALSE; | |
6983 if (wp->w_status_height == 0) | |
6984 { | |
6985 /* no status line, can only be last window */ | |
6986 redraw_cmdline = TRUE; | |
6987 } | |
6988 else if (!redrawing() | |
6989 // don't update status line when popup menu is visible and may be | |
6990 // drawn over it, unless it will be redrawn later | |
6991 || (!ignore_pum && pum_visible())) | |
6992 { | |
6993 /* Don't redraw right now, do it later. */ | |
6994 wp->w_redr_status = TRUE; | |
6995 } | |
6996 #ifdef FEAT_STL_OPT | |
6997 else if (*p_stl != NUL || *wp->w_p_stl != NUL) | |
6998 { | |
6999 /* redraw custom status line */ | |
7000 redraw_custom_statusline(wp); | |
7001 } | |
7002 #endif | |
7003 else | |
7004 { | |
7005 fillchar = fillchar_status(&attr, wp); | |
7006 | |
7007 get_trans_bufname(wp->w_buffer); | |
7008 p = NameBuff; | |
7009 len = (int)STRLEN(p); | |
7010 | |
7011 if (bt_help(wp->w_buffer) | |
7012 #ifdef FEAT_QUICKFIX | |
7013 || wp->w_p_pvw | |
7014 #endif | |
7015 || bufIsChanged(wp->w_buffer) | |
7016 || wp->w_buffer->b_p_ro) | |
7017 *(p + len++) = ' '; | |
7018 if (bt_help(wp->w_buffer)) | |
7019 { | |
7020 STRCPY(p + len, _("[Help]")); | |
7021 len += (int)STRLEN(p + len); | |
7022 } | |
7023 #ifdef FEAT_QUICKFIX | |
7024 if (wp->w_p_pvw) | |
7025 { | |
7026 STRCPY(p + len, _("[Preview]")); | |
7027 len += (int)STRLEN(p + len); | |
7028 } | |
7029 #endif | |
7030 if (bufIsChanged(wp->w_buffer) | |
7031 #ifdef FEAT_TERMINAL | |
7032 && !bt_terminal(wp->w_buffer) | |
7033 #endif | |
7034 ) | |
7035 { | |
7036 STRCPY(p + len, "[+]"); | |
7037 len += 3; | |
7038 } | |
7039 if (wp->w_buffer->b_p_ro) | |
7040 { | |
7041 STRCPY(p + len, _("[RO]")); | |
7042 len += (int)STRLEN(p + len); | |
7043 } | |
7044 | |
7045 this_ru_col = ru_col - (Columns - wp->w_width); | |
7046 if (this_ru_col < (wp->w_width + 1) / 2) | |
7047 this_ru_col = (wp->w_width + 1) / 2; | |
7048 if (this_ru_col <= 1) | |
7049 { | |
7050 p = (char_u *)"<"; /* No room for file name! */ | |
7051 len = 1; | |
7052 } | |
7053 else if (has_mbyte) | |
7054 { | |
7055 int clen = 0, i; | |
7056 | |
7057 /* Count total number of display cells. */ | |
7058 clen = mb_string2cells(p, -1); | |
7059 | |
7060 /* Find first character that will fit. | |
7061 * Going from start to end is much faster for DBCS. */ | |
7062 for (i = 0; p[i] != NUL && clen >= this_ru_col - 1; | |
7063 i += (*mb_ptr2len)(p + i)) | |
7064 clen -= (*mb_ptr2cells)(p + i); | |
7065 len = clen; | |
7066 if (i > 0) | |
7067 { | |
7068 p = p + i - 1; | |
7069 *p = '<'; | |
7070 ++len; | |
7071 } | |
7072 | |
7073 } | |
7074 else if (len > this_ru_col - 1) | |
7075 { | |
7076 p += len - (this_ru_col - 1); | |
7077 *p = '<'; | |
7078 len = this_ru_col - 1; | |
7079 } | |
7080 | |
7081 row = W_WINROW(wp) + wp->w_height; | |
7082 screen_puts(p, row, wp->w_wincol, attr); | |
7083 screen_fill(row, row + 1, len + wp->w_wincol, | |
7084 this_ru_col + wp->w_wincol, fillchar, fillchar, attr); | |
7085 | |
7086 if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL) | |
7087 && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1)) | |
7088 screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff) | |
7089 - 1 + wp->w_wincol), attr); | |
7090 | |
7091 #ifdef FEAT_CMDL_INFO | |
7092 win_redr_ruler(wp, TRUE, ignore_pum); | |
7093 #endif | |
7094 } | |
7095 | |
7096 /* | |
7097 * May need to draw the character below the vertical separator. | |
7098 */ | |
7099 if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing()) | |
7100 { | |
7101 if (stl_connected(wp)) | |
7102 fillchar = fillchar_status(&attr, wp); | |
7103 else | |
7104 fillchar = fillchar_vsep(&attr); | |
7105 screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp), | |
7106 attr); | |
7107 } | |
7108 busy = FALSE; | |
7109 } | |
7110 | |
7111 #ifdef FEAT_STL_OPT | |
7112 /* | |
7113 * Redraw the status line according to 'statusline' and take care of any | |
7114 * errors encountered. | |
7115 */ | |
7116 static void | |
7117 redraw_custom_statusline(win_T *wp) | |
7118 { | |
7119 static int entered = FALSE; | |
7120 int saved_did_emsg = did_emsg; | |
7121 | |
7122 /* When called recursively return. This can happen when the statusline | |
7123 * contains an expression that triggers a redraw. */ | |
7124 if (entered) | |
7125 return; | |
7126 entered = TRUE; | |
7127 | |
7128 did_emsg = FALSE; | |
7129 win_redr_custom(wp, FALSE); | |
7130 if (did_emsg) | |
7131 { | |
7132 /* When there is an error disable the statusline, otherwise the | |
7133 * display is messed up with errors and a redraw triggers the problem | |
7134 * again and again. */ | |
7135 set_string_option_direct((char_u *)"statusline", -1, | |
7136 (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL | |
7137 ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR); | |
7138 } | |
7139 did_emsg |= saved_did_emsg; | |
7140 entered = FALSE; | |
7141 } | |
7142 #endif | |
7143 | |
7144 /* | |
7145 * Return TRUE if the status line of window "wp" is connected to the status | 1087 * Return TRUE if the status line of window "wp" is connected to the status |
7146 * line of the window right of it. If not, then it's a vertical separator. | 1088 * line of the window right of it. If not, then it's a vertical separator. |
7147 * Only call if (wp->w_vsep_width != 0). | 1089 * Only call if (wp->w_vsep_width != 0). |
7148 */ | 1090 */ |
7149 int | 1091 int |
7221 #if defined(FEAT_STL_OPT) || defined(PROTO) | 1163 #if defined(FEAT_STL_OPT) || defined(PROTO) |
7222 /* | 1164 /* |
7223 * Redraw the status line or ruler of window "wp". | 1165 * Redraw the status line or ruler of window "wp". |
7224 * When "wp" is NULL redraw the tab pages line from 'tabline'. | 1166 * When "wp" is NULL redraw the tab pages line from 'tabline'. |
7225 */ | 1167 */ |
7226 static void | 1168 void |
7227 win_redr_custom( | 1169 win_redr_custom( |
7228 win_T *wp, | 1170 win_T *wp, |
7229 int draw_ruler) /* TRUE or FALSE */ | 1171 int draw_ruler) // TRUE or FALSE |
7230 { | 1172 { |
7231 static int entered = FALSE; | 1173 static int entered = FALSE; |
7232 int attr; | 1174 int attr; |
7233 int curattr; | 1175 int curattr; |
7234 int row; | 1176 int row; |
7245 struct stl_hlrec tabtab[STL_MAX_ITEM]; | 1187 struct stl_hlrec tabtab[STL_MAX_ITEM]; |
7246 int use_sandbox = FALSE; | 1188 int use_sandbox = FALSE; |
7247 win_T *ewp; | 1189 win_T *ewp; |
7248 int p_crb_save; | 1190 int p_crb_save; |
7249 | 1191 |
7250 /* There is a tiny chance that this gets called recursively: When | 1192 // There is a tiny chance that this gets called recursively: When |
7251 * redrawing a status line triggers redrawing the ruler or tabline. | 1193 // redrawing a status line triggers redrawing the ruler or tabline. |
7252 * Avoid trouble by not allowing recursion. */ | 1194 // Avoid trouble by not allowing recursion. |
7253 if (entered) | 1195 if (entered) |
7254 return; | 1196 return; |
7255 entered = TRUE; | 1197 entered = TRUE; |
7256 | 1198 |
7257 /* setup environment for the task at hand */ | 1199 // setup environment for the task at hand |
7258 if (wp == NULL) | 1200 if (wp == NULL) |
7259 { | 1201 { |
7260 /* Use 'tabline'. Always at the first line of the screen. */ | 1202 // Use 'tabline'. Always at the first line of the screen. |
7261 stl = p_tal; | 1203 stl = p_tal; |
7262 row = 0; | 1204 row = 0; |
7263 fillchar = ' '; | 1205 fillchar = ' '; |
7264 attr = HL_ATTR(HLF_TPF); | 1206 attr = HL_ATTR(HLF_TPF); |
7265 maxwidth = Columns; | 1207 maxwidth = Columns; |
7274 maxwidth = wp->w_width; | 1216 maxwidth = wp->w_width; |
7275 | 1217 |
7276 if (draw_ruler) | 1218 if (draw_ruler) |
7277 { | 1219 { |
7278 stl = p_ruf; | 1220 stl = p_ruf; |
7279 /* advance past any leading group spec - implicit in ru_col */ | 1221 // advance past any leading group spec - implicit in ru_col |
7280 if (*stl == '%') | 1222 if (*stl == '%') |
7281 { | 1223 { |
7282 if (*++stl == '-') | 1224 if (*++stl == '-') |
7283 stl++; | 1225 stl++; |
7284 if (atoi((char *)stl)) | 1226 if (atoi((char *)stl)) |
7292 col = (wp->w_width + 1) / 2; | 1234 col = (wp->w_width + 1) / 2; |
7293 maxwidth = wp->w_width - col; | 1235 maxwidth = wp->w_width - col; |
7294 if (!wp->w_status_height) | 1236 if (!wp->w_status_height) |
7295 { | 1237 { |
7296 row = Rows - 1; | 1238 row = Rows - 1; |
7297 --maxwidth; /* writing in last column may cause scrolling */ | 1239 --maxwidth; // writing in last column may cause scrolling |
7298 fillchar = ' '; | 1240 fillchar = ' '; |
7299 attr = 0; | 1241 attr = 0; |
7300 } | 1242 } |
7301 | 1243 |
7302 # ifdef FEAT_EVAL | 1244 # ifdef FEAT_EVAL |
7319 } | 1261 } |
7320 | 1262 |
7321 if (maxwidth <= 0) | 1263 if (maxwidth <= 0) |
7322 goto theend; | 1264 goto theend; |
7323 | 1265 |
7324 /* Temporarily reset 'cursorbind', we don't want a side effect from moving | 1266 // Temporarily reset 'cursorbind', we don't want a side effect from moving |
7325 * the cursor away and back. */ | 1267 // the cursor away and back. |
7326 ewp = wp == NULL ? curwin : wp; | 1268 ewp = wp == NULL ? curwin : wp; |
7327 p_crb_save = ewp->w_p_crb; | 1269 p_crb_save = ewp->w_p_crb; |
7328 ewp->w_p_crb = FALSE; | 1270 ewp->w_p_crb = FALSE; |
7329 | 1271 |
7330 /* Make a copy, because the statusline may include a function call that | 1272 // Make a copy, because the statusline may include a function call that |
7331 * might change the option value and free the memory. */ | 1273 // might change the option value and free the memory. |
7332 stl = vim_strsave(stl); | 1274 stl = vim_strsave(stl); |
7333 width = build_stl_str_hl(ewp, buf, sizeof(buf), | 1275 width = build_stl_str_hl(ewp, buf, sizeof(buf), |
7334 stl, use_sandbox, | 1276 stl, use_sandbox, |
7335 fillchar, maxwidth, hltab, tabtab); | 1277 fillchar, maxwidth, hltab, tabtab); |
7336 vim_free(stl); | 1278 vim_free(stl); |
7337 ewp->w_p_crb = p_crb_save; | 1279 ewp->w_p_crb = p_crb_save; |
7338 | 1280 |
7339 /* Make all characters printable. */ | 1281 // Make all characters printable. |
7340 p = transstr(buf); | 1282 p = transstr(buf); |
7341 if (p != NULL) | 1283 if (p != NULL) |
7342 { | 1284 { |
7343 vim_strncpy(buf, p, sizeof(buf) - 1); | 1285 vim_strncpy(buf, p, sizeof(buf) - 1); |
7344 vim_free(p); | 1286 vim_free(p); |
7345 } | 1287 } |
7346 | 1288 |
7347 /* fill up with "fillchar" */ | 1289 // fill up with "fillchar" |
7348 len = (int)STRLEN(buf); | 1290 len = (int)STRLEN(buf); |
7349 while (width < maxwidth && len < (int)sizeof(buf) - 1) | 1291 while (width < maxwidth && len < (int)sizeof(buf) - 1) |
7350 { | 1292 { |
7351 len += (*mb_char2bytes)(fillchar, buf + len); | 1293 len += (*mb_char2bytes)(fillchar, buf + len); |
7352 ++width; | 1294 ++width; |
7384 } | 1326 } |
7385 screen_puts(p, row, col, curattr); | 1327 screen_puts(p, row, col, curattr); |
7386 | 1328 |
7387 if (wp == NULL) | 1329 if (wp == NULL) |
7388 { | 1330 { |
7389 /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */ | 1331 // Fill the TabPageIdxs[] array for clicking in the tab pagesline. |
7390 col = 0; | 1332 col = 0; |
7391 len = 0; | 1333 len = 0; |
7392 p = buf; | 1334 p = buf; |
7393 fillchar = 0; | 1335 fillchar = 0; |
7394 for (n = 0; tabtab[n].start != NULL; n++) | 1336 for (n = 0; tabtab[n].start != NULL; n++) |
7405 | 1347 |
7406 theend: | 1348 theend: |
7407 entered = FALSE; | 1349 entered = FALSE; |
7408 } | 1350 } |
7409 | 1351 |
7410 #endif /* FEAT_STL_OPT */ | 1352 #endif // FEAT_STL_OPT |
7411 | 1353 |
7412 /* | 1354 /* |
7413 * Output a single character directly to the screen and update ScreenLines. | 1355 * Output a single character directly to the screen and update ScreenLines. |
7414 */ | 1356 */ |
7415 void | 1357 void |
7434 void | 1376 void |
7435 screen_getbytes(int row, int col, char_u *bytes, int *attrp) | 1377 screen_getbytes(int row, int col, char_u *bytes, int *attrp) |
7436 { | 1378 { |
7437 unsigned off; | 1379 unsigned off; |
7438 | 1380 |
7439 /* safety check */ | 1381 // safety check |
7440 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns) | 1382 if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns) |
7441 { | 1383 { |
7442 off = LineOffset[row] + col; | 1384 off = LineOffset[row] + col; |
7443 *attrp = ScreenAttrs[off]; | 1385 *attrp = ScreenAttrs[off]; |
7444 bytes[0] = ScreenLines[off]; | 1386 bytes[0] = ScreenLines[off]; |
7517 int mbyte_cells = 1; | 1459 int mbyte_cells = 1; |
7518 int u8c = 0; | 1460 int u8c = 0; |
7519 int u8cc[MAX_MCO]; | 1461 int u8cc[MAX_MCO]; |
7520 int clear_next_cell = FALSE; | 1462 int clear_next_cell = FALSE; |
7521 #ifdef FEAT_ARABIC | 1463 #ifdef FEAT_ARABIC |
7522 int prev_c = 0; /* previous Arabic character */ | 1464 int prev_c = 0; // previous Arabic character |
7523 int pc, nc, nc1; | 1465 int pc, nc, nc1; |
7524 int pcc[MAX_MCO]; | 1466 int pcc[MAX_MCO]; |
7525 #endif | 1467 #endif |
7526 int force_redraw_this; | 1468 int force_redraw_this; |
7527 int force_redraw_next = FALSE; | 1469 int force_redraw_next = FALSE; |
7533 || row >= screen_Rows || row < 0 | 1475 || row >= screen_Rows || row < 0 |
7534 || col >= screen_Columns || col < 0) | 1476 || col >= screen_Columns || col < 0) |
7535 return; | 1477 return; |
7536 off = LineOffset[row] + col; | 1478 off = LineOffset[row] + col; |
7537 | 1479 |
7538 /* When drawing over the right halve of a double-wide char clear out the | 1480 // When drawing over the right halve of a double-wide char clear out the |
7539 * left halve. Only needed in a terminal. */ | 1481 // left halve. Only needed in a terminal. |
7540 if (has_mbyte && col > 0 && col < screen_Columns | 1482 if (has_mbyte && col > 0 && col < screen_Columns |
7541 #ifdef FEAT_GUI | 1483 #ifdef FEAT_GUI |
7542 && !gui.in_use | 1484 && !gui.in_use |
7543 #endif | 1485 #endif |
7544 && mb_fix_col(col, row) != col) | 1486 && mb_fix_col(col, row) != col) |
7548 if (enc_utf8) | 1490 if (enc_utf8) |
7549 { | 1491 { |
7550 ScreenLinesUC[off - 1] = 0; | 1492 ScreenLinesUC[off - 1] = 0; |
7551 ScreenLinesC[0][off - 1] = 0; | 1493 ScreenLinesC[0][off - 1] = 0; |
7552 } | 1494 } |
7553 /* redraw the previous cell, make it empty */ | 1495 // redraw the previous cell, make it empty |
7554 screen_char(off - 1, row, col - 1); | 1496 screen_char(off - 1, row, col - 1); |
7555 /* force the cell at "col" to be redrawn */ | 1497 // force the cell at "col" to be redrawn |
7556 force_redraw_next = TRUE; | 1498 force_redraw_next = TRUE; |
7557 } | 1499 } |
7558 | 1500 |
7559 max_off = LineOffset[row] + screen_Columns; | 1501 max_off = LineOffset[row] + screen_Columns; |
7560 while (col < screen_Columns | 1502 while (col < screen_Columns |
7754 else | 1696 else |
7755 screen_char(off, row, col); | 1697 screen_char(off, row, col); |
7756 } | 1698 } |
7757 } | 1699 } |
7758 | 1700 |
7759 #ifdef FEAT_SEARCH_EXTRA | 1701 #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) |
7760 /* | 1702 /* |
7761 * Prepare for 'hlsearch' highlighting. | 1703 * Prepare for 'hlsearch' highlighting. |
7762 */ | 1704 */ |
7763 static void | 1705 void |
7764 start_search_hl(void) | 1706 start_search_hl(void) |
7765 { | 1707 { |
7766 if (p_hls && !no_hlsearch) | 1708 if (p_hls && !no_hlsearch) |
7767 { | 1709 { |
7768 last_pat_prog(&search_hl.rm); | 1710 last_pat_prog(&screen_search_hl.rm); |
7769 search_hl.attr = HL_ATTR(HLF_L); | 1711 screen_search_hl.attr = HL_ATTR(HLF_L); |
7770 # ifdef FEAT_RELTIME | 1712 # ifdef FEAT_RELTIME |
7771 /* Set the time limit to 'redrawtime'. */ | 1713 /* Set the time limit to 'redrawtime'. */ |
7772 profile_setlimit(p_rdt, &search_hl.tm); | 1714 profile_setlimit(p_rdt, &screen_search_hl.tm); |
7773 # endif | 1715 # endif |
7774 } | 1716 } |
7775 } | 1717 } |
7776 | 1718 |
7777 /* | 1719 /* |
7778 * Clean up for 'hlsearch' highlighting. | 1720 * Clean up for 'hlsearch' highlighting. |
7779 */ | 1721 */ |
7780 static void | 1722 void |
7781 end_search_hl(void) | 1723 end_search_hl(void) |
7782 { | 1724 { |
7783 if (search_hl.rm.regprog != NULL) | 1725 if (screen_search_hl.rm.regprog != NULL) |
7784 { | 1726 { |
7785 vim_regfree(search_hl.rm.regprog); | 1727 vim_regfree(screen_search_hl.rm.regprog); |
7786 search_hl.rm.regprog = NULL; | 1728 screen_search_hl.rm.regprog = NULL; |
7787 } | 1729 } |
7788 } | 1730 } |
7789 #endif | 1731 #endif |
7790 | 1732 |
7791 static void | 1733 static void |
8062 | 2004 |
8063 /* | 2005 /* |
8064 * Put character ScreenLines["off"] on the screen at position "row" and "col", | 2006 * Put character ScreenLines["off"] on the screen at position "row" and "col", |
8065 * using the attributes from ScreenAttrs["off"]. | 2007 * using the attributes from ScreenAttrs["off"]. |
8066 */ | 2008 */ |
8067 static void | 2009 void |
8068 screen_char(unsigned off, int row, int col) | 2010 screen_char(unsigned off, int row, int col) |
8069 { | 2011 { |
8070 int attr; | 2012 int attr; |
8071 | 2013 |
8072 /* Check for illegal values, just in case (could happen just after | 2014 /* Check for illegal values, just in case (could happen just after |
8253 width = wp->w_width; | 2195 width = wp->w_width; |
8254 } | 2196 } |
8255 screen_draw_rectangle(row, col, end - row, width, FALSE); | 2197 screen_draw_rectangle(row, col, end - row, width, FALSE); |
8256 } | 2198 } |
8257 | 2199 |
8258 static void | 2200 void |
8259 space_to_screenline(int off, int attr) | 2201 space_to_screenline(int off, int attr) |
8260 { | 2202 { |
8261 ScreenLines[off] = ' '; | 2203 ScreenLines[off] = ' '; |
8262 ScreenAttrs[off] = attr; | 2204 ScreenAttrs[off] = attr; |
8263 if (enc_utf8) | 2205 if (enc_utf8) |
10501 } | 4443 } |
10502 | 4444 |
10503 /* | 4445 /* |
10504 * Get the character to use in a status line. Get its attributes in "*attr". | 4446 * Get the character to use in a status line. Get its attributes in "*attr". |
10505 */ | 4447 */ |
10506 static int | 4448 int |
10507 fillchar_status(int *attr, win_T *wp) | 4449 fillchar_status(int *attr, win_T *wp) |
10508 { | 4450 { |
10509 int fill; | 4451 int fill; |
10510 | 4452 |
10511 #ifdef FEAT_TERMINAL | 4453 #ifdef FEAT_TERMINAL |
10548 | 4490 |
10549 /* | 4491 /* |
10550 * Get the character to use in a separator between vertically split windows. | 4492 * Get the character to use in a separator between vertically split windows. |
10551 * Get its attributes in "*attr". | 4493 * Get its attributes in "*attr". |
10552 */ | 4494 */ |
10553 static int | 4495 int |
10554 fillchar_vsep(int *attr) | 4496 fillchar_vsep(int *attr) |
10555 { | 4497 { |
10556 *attr = HL_ATTR(HLF_C); | 4498 *attr = HL_ATTR(HLF_C); |
10557 if (*attr == 0 && fill_vert == ' ') | 4499 if (*attr == 0 && fill_vert == ' ') |
10558 return '|'; | 4500 return '|'; |
10584 int | 4526 int |
10585 messaging(void) | 4527 messaging(void) |
10586 { | 4528 { |
10587 return (!(p_lz && char_avail() && !KeyTyped)); | 4529 return (!(p_lz && char_avail() && !KeyTyped)); |
10588 } | 4530 } |
10589 | |
10590 #ifdef FEAT_MENU | |
10591 /* | |
10592 * Draw the window toolbar. | |
10593 */ | |
10594 static void | |
10595 redraw_win_toolbar(win_T *wp) | |
10596 { | |
10597 vimmenu_T *menu; | |
10598 int item_idx = 0; | |
10599 int item_count = 0; | |
10600 int col = 0; | |
10601 int next_col; | |
10602 int off = (int)(current_ScreenLine - ScreenLines); | |
10603 int fill_attr = syn_name2attr((char_u *)"ToolbarLine"); | |
10604 int button_attr = syn_name2attr((char_u *)"ToolbarButton"); | |
10605 | |
10606 vim_free(wp->w_winbar_items); | |
10607 for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next) | |
10608 ++item_count; | |
10609 wp->w_winbar_items = ALLOC_CLEAR_MULT(winbar_item_T, item_count + 1); | |
10610 | |
10611 /* TODO: use fewer spaces if there is not enough room */ | |
10612 for (menu = wp->w_winbar->children; | |
10613 menu != NULL && col < wp->w_width; menu = menu->next) | |
10614 { | |
10615 space_to_screenline(off + col, fill_attr); | |
10616 if (++col >= wp->w_width) | |
10617 break; | |
10618 if (col > 1) | |
10619 { | |
10620 space_to_screenline(off + col, fill_attr); | |
10621 if (++col >= wp->w_width) | |
10622 break; | |
10623 } | |
10624 | |
10625 wp->w_winbar_items[item_idx].wb_startcol = col; | |
10626 space_to_screenline(off + col, button_attr); | |
10627 if (++col >= wp->w_width) | |
10628 break; | |
10629 | |
10630 next_col = text_to_screenline(wp, menu->name, col); | |
10631 while (col < next_col) | |
10632 { | |
10633 ScreenAttrs[off + col] = button_attr; | |
10634 ++col; | |
10635 } | |
10636 wp->w_winbar_items[item_idx].wb_endcol = col; | |
10637 wp->w_winbar_items[item_idx].wb_menu = menu; | |
10638 ++item_idx; | |
10639 | |
10640 if (col >= wp->w_width) | |
10641 break; | |
10642 space_to_screenline(off + col, button_attr); | |
10643 ++col; | |
10644 } | |
10645 while (col < wp->w_width) | |
10646 { | |
10647 space_to_screenline(off + col, fill_attr); | |
10648 ++col; | |
10649 } | |
10650 wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */ | |
10651 | |
10652 screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width, | |
10653 (int)wp->w_width, 0); | |
10654 } | |
10655 #endif | |
10656 | |
10657 /* | |
10658 * Show current status info in ruler and various other places | |
10659 * If always is FALSE, only show ruler if position has changed. | |
10660 */ | |
10661 void | |
10662 showruler(int always) | |
10663 { | |
10664 if (!always && !redrawing()) | |
10665 return; | |
10666 if (pum_visible()) | |
10667 { | |
10668 /* Don't redraw right now, do it later. */ | |
10669 curwin->w_redr_status = TRUE; | |
10670 return; | |
10671 } | |
10672 #if defined(FEAT_STL_OPT) | |
10673 if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) | |
10674 redraw_custom_statusline(curwin); | |
10675 else | |
10676 #endif | |
10677 #ifdef FEAT_CMDL_INFO | |
10678 win_redr_ruler(curwin, always, FALSE); | |
10679 #endif | |
10680 | |
10681 #ifdef FEAT_TITLE | |
10682 if (need_maketitle | |
10683 # ifdef FEAT_STL_OPT | |
10684 || (p_icon && (stl_syntax & STL_IN_ICON)) | |
10685 || (p_title && (stl_syntax & STL_IN_TITLE)) | |
10686 # endif | |
10687 ) | |
10688 maketitle(); | |
10689 #endif | |
10690 /* Redraw the tab pages line if needed. */ | |
10691 if (redraw_tabline) | |
10692 draw_tabline(); | |
10693 } | |
10694 | |
10695 #ifdef FEAT_CMDL_INFO | |
10696 static void | |
10697 win_redr_ruler(win_T *wp, int always, int ignore_pum) | |
10698 { | |
10699 #define RULER_BUF_LEN 70 | |
10700 char_u buffer[RULER_BUF_LEN]; | |
10701 int row; | |
10702 int fillchar; | |
10703 int attr; | |
10704 int empty_line = FALSE; | |
10705 colnr_T virtcol; | |
10706 int i; | |
10707 size_t len; | |
10708 int o; | |
10709 int this_ru_col; | |
10710 int off = 0; | |
10711 int width; | |
10712 | |
10713 /* If 'ruler' off or redrawing disabled, don't do anything */ | |
10714 if (!p_ru) | |
10715 return; | |
10716 | |
10717 /* | |
10718 * Check if cursor.lnum is valid, since win_redr_ruler() may be called | |
10719 * after deleting lines, before cursor.lnum is corrected. | |
10720 */ | |
10721 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) | |
10722 return; | |
10723 | |
10724 // Don't draw the ruler while doing insert-completion, it might overwrite | |
10725 // the (long) mode message. | |
10726 if (wp == lastwin && lastwin->w_status_height == 0) | |
10727 if (edit_submode != NULL) | |
10728 return; | |
10729 // Don't draw the ruler when the popup menu is visible, it may overlap. | |
10730 // Except when the popup menu will be redrawn anyway. | |
10731 if (!ignore_pum && pum_visible()) | |
10732 return; | |
10733 | |
10734 #ifdef FEAT_STL_OPT | |
10735 if (*p_ruf) | |
10736 { | |
10737 int save_called_emsg = called_emsg; | |
10738 | |
10739 called_emsg = FALSE; | |
10740 win_redr_custom(wp, TRUE); | |
10741 if (called_emsg) | |
10742 set_string_option_direct((char_u *)"rulerformat", -1, | |
10743 (char_u *)"", OPT_FREE, SID_ERROR); | |
10744 called_emsg |= save_called_emsg; | |
10745 return; | |
10746 } | |
10747 #endif | |
10748 | |
10749 /* | |
10750 * Check if not in Insert mode and the line is empty (will show "0-1"). | |
10751 */ | |
10752 if (!(State & INSERT) | |
10753 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL) | |
10754 empty_line = TRUE; | |
10755 | |
10756 /* | |
10757 * Only draw the ruler when something changed. | |
10758 */ | |
10759 validate_virtcol_win(wp); | |
10760 if ( redraw_cmdline | |
10761 || always | |
10762 || wp->w_cursor.lnum != wp->w_ru_cursor.lnum | |
10763 || wp->w_cursor.col != wp->w_ru_cursor.col | |
10764 || wp->w_virtcol != wp->w_ru_virtcol | |
10765 || wp->w_cursor.coladd != wp->w_ru_cursor.coladd | |
10766 || wp->w_topline != wp->w_ru_topline | |
10767 || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count | |
10768 #ifdef FEAT_DIFF | |
10769 || wp->w_topfill != wp->w_ru_topfill | |
10770 #endif | |
10771 || empty_line != wp->w_ru_empty) | |
10772 { | |
10773 cursor_off(); | |
10774 if (wp->w_status_height) | |
10775 { | |
10776 row = W_WINROW(wp) + wp->w_height; | |
10777 fillchar = fillchar_status(&attr, wp); | |
10778 off = wp->w_wincol; | |
10779 width = wp->w_width; | |
10780 } | |
10781 else | |
10782 { | |
10783 row = Rows - 1; | |
10784 fillchar = ' '; | |
10785 attr = 0; | |
10786 width = Columns; | |
10787 off = 0; | |
10788 } | |
10789 | |
10790 /* In list mode virtcol needs to be recomputed */ | |
10791 virtcol = wp->w_virtcol; | |
10792 if (wp->w_p_list && lcs_tab1 == NUL) | |
10793 { | |
10794 wp->w_p_list = FALSE; | |
10795 getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); | |
10796 wp->w_p_list = TRUE; | |
10797 } | |
10798 | |
10799 /* | |
10800 * Some sprintfs return the length, some return a pointer. | |
10801 * To avoid portability problems we use strlen() here. | |
10802 */ | |
10803 vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,", | |
10804 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) | |
10805 ? 0L | |
10806 : (long)(wp->w_cursor.lnum)); | |
10807 len = STRLEN(buffer); | |
10808 col_print(buffer + len, RULER_BUF_LEN - len, | |
10809 empty_line ? 0 : (int)wp->w_cursor.col + 1, | |
10810 (int)virtcol + 1); | |
10811 | |
10812 /* | |
10813 * Add a "50%" if there is room for it. | |
10814 * On the last line, don't print in the last column (scrolls the | |
10815 * screen up on some terminals). | |
10816 */ | |
10817 i = (int)STRLEN(buffer); | |
10818 get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1); | |
10819 o = i + vim_strsize(buffer + i + 1); | |
10820 if (wp->w_status_height == 0) /* can't use last char of screen */ | |
10821 ++o; | |
10822 this_ru_col = ru_col - (Columns - width); | |
10823 if (this_ru_col < 0) | |
10824 this_ru_col = 0; | |
10825 /* Never use more than half the window/screen width, leave the other | |
10826 * half for the filename. */ | |
10827 if (this_ru_col < (width + 1) / 2) | |
10828 this_ru_col = (width + 1) / 2; | |
10829 if (this_ru_col + o < width) | |
10830 { | |
10831 /* need at least 3 chars left for get_rel_pos() + NUL */ | |
10832 while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) | |
10833 { | |
10834 if (has_mbyte) | |
10835 i += (*mb_char2bytes)(fillchar, buffer + i); | |
10836 else | |
10837 buffer[i++] = fillchar; | |
10838 ++o; | |
10839 } | |
10840 get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i); | |
10841 } | |
10842 /* Truncate at window boundary. */ | |
10843 if (has_mbyte) | |
10844 { | |
10845 o = 0; | |
10846 for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i)) | |
10847 { | |
10848 o += (*mb_ptr2cells)(buffer + i); | |
10849 if (this_ru_col + o > width) | |
10850 { | |
10851 buffer[i] = NUL; | |
10852 break; | |
10853 } | |
10854 } | |
10855 } | |
10856 else if (this_ru_col + (int)STRLEN(buffer) > width) | |
10857 buffer[width - this_ru_col] = NUL; | |
10858 | |
10859 screen_puts(buffer, row, this_ru_col + off, attr); | |
10860 i = redraw_cmdline; | |
10861 screen_fill(row, row + 1, | |
10862 this_ru_col + off + (int)STRLEN(buffer), | |
10863 (int)(off + width), | |
10864 fillchar, fillchar, attr); | |
10865 /* don't redraw the cmdline because of showing the ruler */ | |
10866 redraw_cmdline = i; | |
10867 wp->w_ru_cursor = wp->w_cursor; | |
10868 wp->w_ru_virtcol = wp->w_virtcol; | |
10869 wp->w_ru_empty = empty_line; | |
10870 wp->w_ru_topline = wp->w_topline; | |
10871 wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count; | |
10872 #ifdef FEAT_DIFF | |
10873 wp->w_ru_topfill = wp->w_topfill; | |
10874 #endif | |
10875 } | |
10876 } | |
10877 #endif | |
10878 | 4531 |
10879 /* | 4532 /* |
10880 * Compute columns for ruler and shown command. 'sc_col' is also used to | 4533 * Compute columns for ruler and shown command. 'sc_col' is also used to |
10881 * decide what the maximum length of a message on the status line can be. | 4534 * decide what the maximum length of a message on the status line can be. |
10882 * If there is a status line for the last window, 'sc_col' is independent | 4535 * If there is a status line for the last window, 'sc_col' is independent |
11123 } | 4776 } |
11124 | 4777 |
11125 return NULL; // no error | 4778 return NULL; // no error |
11126 } | 4779 } |
11127 | 4780 |
11128 #ifdef FEAT_SYN_HL | |
11129 /* | |
11130 * Used when 'cursorlineopt' contains "screenline": compute the margins between | |
11131 * which the highlighting is used. | |
11132 */ | |
11133 static void | |
11134 margin_columns_win(win_T *wp, int *left_col, int *right_col) | |
11135 { | |
11136 // cache previous calculations depending on w_virtcol | |
11137 static int saved_w_virtcol; | |
11138 static win_T *prev_wp; | |
11139 static int prev_left_col; | |
11140 static int prev_right_col; | |
11141 static int prev_col_off; | |
11142 | |
11143 int cur_col_off = win_col_off(wp); | |
11144 int width1; | |
11145 int width2; | |
11146 | |
11147 if (saved_w_virtcol == wp->w_virtcol | |
11148 && prev_wp == wp && prev_col_off == cur_col_off) | |
11149 { | |
11150 *right_col = prev_right_col; | |
11151 *left_col = prev_left_col; | |
11152 return; | |
11153 } | |
11154 | |
11155 width1 = wp->w_width - cur_col_off; | |
11156 width2 = width1 + win_col_off2(wp); | |
11157 | |
11158 *left_col = 0; | |
11159 *right_col = width1; | |
11160 | |
11161 if (wp->w_virtcol >= (colnr_T)width1) | |
11162 *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2; | |
11163 if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) | |
11164 *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1; | |
11165 | |
11166 // cache values | |
11167 prev_left_col = *left_col; | |
11168 prev_right_col = *right_col; | |
11169 prev_wp = wp; | |
11170 saved_w_virtcol = wp->w_virtcol; | |
11171 prev_col_off = cur_col_off; | |
11172 } | |
11173 #endif |