• R/O
  • SSH

vim: Commit

Mirror of the Vim source from https://github.com/vim/vim


Commit MetaInfo

Revision2a806e3c39f6c1a801423644a72fb2c4216041b4 (tree)
Zeit2019-09-20 06:15:05
AutorBram Moolenaar <Bram@vim....>
CommiterBram Moolenaar

Log Message

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)

Ändern Zusammenfassung

Diff

diff -r ceb4be0b23c7 -r 2a806e3c39f6 Filelist
--- a/Filelist Wed Sep 18 22:15:04 2019 +0200
+++ b/Filelist Thu Sep 19 23:15:05 2019 +0200
@@ -32,6 +32,8 @@
3232 src/dict.c \
3333 src/diff.c \
3434 src/digraph.c \
35+ src/drawline.c \
36+ src/drawscreen.c \
3537 src/edit.c \
3638 src/eval.c \
3739 src/evalbuffer.c \
@@ -192,6 +194,8 @@
192194 src/proto/dict.pro \
193195 src/proto/diff.pro \
194196 src/proto/digraph.pro \
197+ src/proto/drawline.pro \
198+ src/proto/drawscreen.pro \
195199 src/proto/edit.pro \
196200 src/proto/eval.pro \
197201 src/proto/evalbuffer.pro \
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/Make_cyg_ming.mak
--- a/src/Make_cyg_ming.mak Wed Sep 18 22:15:04 2019 +0200
+++ b/src/Make_cyg_ming.mak Thu Sep 19 23:15:05 2019 +0200
@@ -719,6 +719,8 @@
719719 $(OUTDIR)/dict.o \
720720 $(OUTDIR)/diff.o \
721721 $(OUTDIR)/digraph.o \
722+ $(OUTDIR)/drawline.o \
723+ $(OUTDIR)/drawscreen.o \
722724 $(OUTDIR)/edit.o \
723725 $(OUTDIR)/eval.o \
724726 $(OUTDIR)/evalbuffer.o \
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/Make_morph.mak
--- a/src/Make_morph.mak Wed Sep 18 22:15:04 2019 +0200
+++ b/src/Make_morph.mak Thu Sep 19 23:15:05 2019 +0200
@@ -39,6 +39,8 @@
3939 dict.c \
4040 diff.c \
4141 digraph.c \
42+ drawline.c \
43+ drawscreen.c \
4244 edit.c \
4345 eval.c \
4446 evalbuffer.c \
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/Make_mvc.mak
--- a/src/Make_mvc.mak Wed Sep 18 22:15:04 2019 +0200
+++ b/src/Make_mvc.mak Thu Sep 19 23:15:05 2019 +0200
@@ -726,6 +726,8 @@
726726 $(OUTDIR)\dict.obj \
727727 $(OUTDIR)\diff.obj \
728728 $(OUTDIR)\digraph.obj \
729+ $(OUTDIR)\drawline.obj \
730+ $(OUTDIR)\drawscreen.obj \
729731 $(OUTDIR)\edit.obj \
730732 $(OUTDIR)\eval.obj \
731733 $(OUTDIR)\evalbuffer.obj \
@@ -1484,6 +1486,10 @@
14841486
14851487 $(OUTDIR)/digraph.obj: $(OUTDIR) digraph.c $(INCL)
14861488
1489+$(OUTDIR)/drawline.obj: $(OUTDIR) drawline.c $(INCL)
1490+
1491+$(OUTDIR)/drawscreen.obj: $(OUTDIR) drawscreen.c $(INCL)
1492+
14871493 $(OUTDIR)/edit.obj: $(OUTDIR) edit.c $(INCL)
14881494
14891495 $(OUTDIR)/eval.obj: $(OUTDIR) eval.c $(INCL)
@@ -1783,6 +1789,8 @@
17831789 proto/dict.pro \
17841790 proto/diff.pro \
17851791 proto/digraph.pro \
1792+ proto/drawline.pro \
1793+ proto/drawscreen.pro \
17861794 proto/edit.pro \
17871795 proto/eval.pro \
17881796 proto/evalbuffer.pro \
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/Make_vms.mms
--- a/src/Make_vms.mms Wed Sep 18 22:15:04 2019 +0200
+++ b/src/Make_vms.mms Thu Sep 19 23:15:05 2019 +0200
@@ -309,8 +309,8 @@
309309
310310 SRC = arabic.c arglist.c autocmd.c beval.c blob.c blowfish.c buffer.c \
311311 change.c charset.c cmdexpand.c cmdhist.c crypt.c crypt_zip.c \
312- debugger.c dict.c diff.c digraph.c edit.c eval.c evalbuffer.c \
313- evalfunc.c \
312+ debugger.c dict.c diff.c digraph.c drawline.c drawscreen.c edit.c \
313+ eval.c evalbuffer.c evalfunc.c \
314314 evalvars.c evalwindow.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c \
315315 ex_getln.c \
316316 if_cscope.c if_xcmdsrv.c fileio.c filepath.c, findfile.c fold.c \
@@ -329,8 +329,8 @@
329329 OBJ = arabic.obj arglist.obj autocmd.obj beval.obj blob.obj blowfish.obj \
330330 buffer.obj change.obj charset.obj cmdexpand.obj cmdhist.obj \
331331 crypt.obj crypt_zip.obj debugger.obj dict.obj diff.obj digraph.obj \
332- edit.obj eval.obj evalbuffer.obj evalfunc.obj evalvars.obj \
333- evalwindow.obj ex_cmds.obj ex_cmds2.obj \
332+ drawline.obj drawscreen.obj edit.obj eval.obj evalbuffer.obj \
333+ evalfunc.obj evalvars.obj evalwindow.obj ex_cmds.obj ex_cmds2.obj \
334334 ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj if_xcmdsrv.obj \
335335 fileio.obj filepath.obj \
336336 findfile.obj fold.obj getchar.obj hardcopy.obj hashtab.obj \
@@ -556,16 +556,22 @@
556556 globals.h
557557 diff.obj : diff.c vim.h [.auto]config.h feature.h os_unix.h \
558558 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
559- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
560-
559+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
561560 digraph.obj : digraph.c vim.h [.auto]config.h feature.h os_unix.h \
562561 ascii.h keymap.h term.h macros.h structs.h regexp.h \
563562 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
564563 globals.h
564+drawline.obj : drawline.c vim.h [.auto]config.h feature.h os_unix.h \
565+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
566+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
567+ globals.h
568+drawscreen.obj : drawscreen.c vim.h [.auto]config.h feature.h os_unix.h \
569+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
570+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
571+ globals.h
565572 edit.obj : edit.c vim.h [.auto]config.h feature.h os_unix.h \
566573 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
567- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
568-
574+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
569575 eval.obj : eval.c vim.h [.auto]config.h feature.h os_unix.h \
570576 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
571577 [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
@@ -620,8 +626,7 @@
620626 globals.h
621627 fold.obj : fold.c vim.h [.auto]config.h feature.h os_unix.h \
622628 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
623- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
624-
629+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
625630 getchar.obj : getchar.c vim.h [.auto]config.h feature.h os_unix.h \
626631 ascii.h keymap.h term.h macros.h structs.h regexp.h \
627632 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
@@ -669,8 +674,7 @@
669674 [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
670675 mark.obj : mark.c vim.h [.auto]config.h feature.h os_unix.h \
671676 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
672- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
673-
677+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
674678 memfile.obj : memfile.c vim.h [.auto]config.h feature.h os_unix.h \
675679 ascii.h keymap.h term.h macros.h structs.h regexp.h \
676680 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
@@ -681,8 +685,7 @@
681685 globals.h
682686 menu.obj : menu.c vim.h [.auto]config.h feature.h os_unix.h \
683687 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
684- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
685-
688+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
686689 message.obj : message.c vim.h [.auto]config.h feature.h os_unix.h \
687690 ascii.h keymap.h term.h macros.h structs.h regexp.h \
688691 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
@@ -693,24 +696,20 @@
693696 version.h
694697 misc2.obj : misc2.c vim.h [.auto]config.h feature.h os_unix.h \
695698 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
696- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
697-
699+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
698700 move.obj : move.c vim.h [.auto]config.h feature.h os_unix.h \
699701 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
700- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
701-
702+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
702703 mbyte.obj : mbyte.c vim.h [.auto]config.h feature.h os_unix.h \
703704 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
704- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
705-
705+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
706706 normal.obj : normal.c vim.h [.auto]config.h feature.h os_unix.h \
707707 ascii.h keymap.h term.h macros.h structs.h regexp.h \
708708 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
709709 globals.h
710710 ops.obj : ops.c vim.h [.auto]config.h feature.h os_unix.h \
711711 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
712- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
713-
712+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
714713 option.obj : option.c vim.h [.auto]config.h feature.h os_unix.h \
715714 ascii.h keymap.h term.h macros.h structs.h regexp.h \
716715 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
@@ -789,42 +788,33 @@
789788 globals.h
790789 tag.obj : tag.c vim.h [.auto]config.h feature.h os_unix.h \
791790 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
792- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
793-
791+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
794792 term.obj : term.c vim.h [.auto]config.h feature.h os_unix.h \
795793 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
796- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
797-
794+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
798795 termlib.obj : termlib.c vim.h [.auto]config.h feature.h os_unix.h \
799796 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
800- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
801-
797+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
802798 testing.obj : testing.c vim.h [.auto]config.h feature.h os_unix.h \
803799 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
804- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
805-
800+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
806801 textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \
807802 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
808- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
809-
803+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
810804 ui.obj : ui.c vim.h [.auto]config.h feature.h os_unix.h \
811805 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
812- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
813-
806+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
814807 undo.obj : undo.c vim.h [.auto]config.h feature.h os_unix.h \
815808 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
816- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
817-
809+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
818810 usercmd.obj : usercmd.c vim.h [.auto]config.h feature.h os_unix.h \
819811 ascii.h keymap.h term.h macros.h option.h structs.h \
820812 regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
821813 proto.h globals.h
822-
823814 userfunc.obj : userfunc.c vim.h [.auto]config.h feature.h os_unix.h \
824815 ascii.h keymap.h term.h macros.h option.h structs.h \
825816 regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
826817 proto.h globals.h
827-
828818 version.obj : version.c vim.h [.auto]config.h feature.h os_unix.h \
829819 ascii.h keymap.h term.h macros.h structs.h regexp.h \
830820 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
@@ -839,8 +829,7 @@
839829 globals.h
840830 gui.obj : gui.c vim.h [.auto]config.h feature.h os_unix.h \
841831 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
842- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
843-
832+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
844833 gui_gtk.obj : gui_gtk.c gui_gtk_f.h vim.h [.auto]config.h feature.h \
845834 os_unix.h ascii.h keymap.h term.h macros.h structs.h \
846835 regexp.h gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h \
@@ -893,8 +882,7 @@
893882 globals.h gui_at_sb.h
894883 pty.obj : pty.c vim.h [.auto]config.h feature.h os_unix.h \
895884 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
896- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
897-
885+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
898886 hangulin.obj : hangulin.c vim.h [.auto]config.h feature.h os_unix.h \
899887 ascii.h keymap.h term.h macros.h structs.h regexp.h \
900888 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/Makefile
--- a/src/Makefile Wed Sep 18 22:15:04 2019 +0200
+++ b/src/Makefile Thu Sep 19 23:15:05 2019 +0200
@@ -1593,6 +1593,8 @@
15931593 dict.c \
15941594 diff.c \
15951595 digraph.c \
1596+ drawline.c \
1597+ drawscreen.c \
15961598 edit.c \
15971599 eval.c \
15981600 evalbuffer.c \
@@ -1727,6 +1729,8 @@
17271729 objects/dict.o \
17281730 objects/diff.o \
17291731 objects/digraph.o \
1732+ objects/drawline.o \
1733+ objects/drawscreen.o \
17301734 objects/edit.o \
17311735 objects/eval.o \
17321736 objects/evalbuffer.o \
@@ -1874,6 +1878,8 @@
18741878 dict.pro \
18751879 diff.pro \
18761880 digraph.pro \
1881+ drawline.pro \
1882+ drawscreen.pro \
18771883 edit.pro \
18781884 eval.pro \
18791885 evalbuffer.pro \
@@ -3083,6 +3089,12 @@
30833089 objects/digraph.o: digraph.c
30843090 $(CCC) -o $@ digraph.c
30853091
3092+objects/drawline.o: drawline.c
3093+ $(CCC) -o $@ drawline.c
3094+
3095+objects/drawscreen.o: drawscreen.c
3096+ $(CCC) -o $@ drawscreen.c
3097+
30863098 objects/edit.o: edit.c
30873099 $(CCC) -o $@ edit.c
30883100
@@ -3613,6 +3625,14 @@
36133625 auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
36143626 proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
36153627 proto.h globals.h
3628+objects/drawline.o: drawline.c vim.h protodef.h auto/config.h feature.h os_unix.h \
3629+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
3630+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
3631+ proto.h globals.h
3632+objects/drawscreen.o: drawscreen.c vim.h protodef.h auto/config.h feature.h os_unix.h \
3633+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
3634+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
3635+ proto.h globals.h
36163636 objects/edit.o: edit.c vim.h protodef.h auto/config.h feature.h os_unix.h \
36173637 auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
36183638 proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/README.md
--- a/src/README.md Wed Sep 18 22:15:04 2019 +0200
+++ b/src/README.md Thu Sep 19 23:15:05 2019 +0200
@@ -32,6 +32,8 @@
3232 cmdhist.c | command-line history
3333 debugger.c | vim script debugger
3434 diff.c | diff mode (vimdiff)
35+drawline.c | drawing a window line
36+drawscreen.c | drawing the windows
3537 eval.c | expression evaluation
3638 evalbuffer.c | buffer related built-in functions
3739 evalfunc.c | built-in functions
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/drawline.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/drawline.c Thu Sep 19 23:15:05 2019 +0200
@@ -0,0 +1,3131 @@
1+/* vi:set ts=8 sts=4 sw=4 noet:
2+ *
3+ * VIM - Vi IMproved by Bram Moolenaar
4+ *
5+ * Do ":help uganda" in Vim to read copying and usage conditions.
6+ * Do ":help credits" in Vim to see a list of people who contributed.
7+ * See README.txt for an overview of the Vim source code.
8+ */
9+
10+/*
11+ * drawline.c: Functions for drawing window lines on the screen.
12+ * This is the middle level, drawscreen. is the higher level and screen.c the
13+ * lower level.
14+ */
15+
16+#include "vim.h"
17+
18+#ifdef FEAT_SYN_HL
19+/*
20+ * Advance **color_cols and return TRUE when there are columns to draw.
21+ */
22+ static int
23+advance_color_col(int vcol, int **color_cols)
24+{
25+ while (**color_cols >= 0 && vcol > **color_cols)
26+ ++*color_cols;
27+ return (**color_cols >= 0);
28+}
29+#endif
30+
31+#ifdef FEAT_SYN_HL
32+/*
33+ * Used when 'cursorlineopt' contains "screenline": compute the margins between
34+ * which the highlighting is used.
35+ */
36+ static void
37+margin_columns_win(win_T *wp, int *left_col, int *right_col)
38+{
39+ // cache previous calculations depending on w_virtcol
40+ static int saved_w_virtcol;
41+ static win_T *prev_wp;
42+ static int prev_left_col;
43+ static int prev_right_col;
44+ static int prev_col_off;
45+
46+ int cur_col_off = win_col_off(wp);
47+ int width1;
48+ int width2;
49+
50+ if (saved_w_virtcol == wp->w_virtcol
51+ && prev_wp == wp && prev_col_off == cur_col_off)
52+ {
53+ *right_col = prev_right_col;
54+ *left_col = prev_left_col;
55+ return;
56+ }
57+
58+ width1 = wp->w_width - cur_col_off;
59+ width2 = width1 + win_col_off2(wp);
60+
61+ *left_col = 0;
62+ *right_col = width1;
63+
64+ if (wp->w_virtcol >= (colnr_T)width1)
65+ *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2;
66+ if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0)
67+ *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1;
68+
69+ // cache values
70+ prev_left_col = *left_col;
71+ prev_right_col = *right_col;
72+ prev_wp = wp;
73+ saved_w_virtcol = wp->w_virtcol;
74+ prev_col_off = cur_col_off;
75+}
76+#endif
77+
78+#ifdef FEAT_SIGNS
79+/*
80+ * Get information needed to display the sign in line 'lnum' in window 'wp'.
81+ * If 'nrcol' is TRUE, the sign is going to be displayed in the number column.
82+ * Otherwise the sign is going to be displayed in the sign column.
83+ */
84+ static void
85+get_sign_display_info(
86+ int nrcol,
87+ win_T *wp,
88+ linenr_T lnum UNUSED,
89+ sign_attrs_T *sattr,
90+ int wcr_attr,
91+ int row,
92+ int startrow,
93+ int filler_lines UNUSED,
94+ int filler_todo UNUSED,
95+ int *c_extrap,
96+ int *c_finalp,
97+ char_u *extra,
98+ char_u **pp_extra,
99+ int *n_extrap,
100+ int *char_attrp)
101+{
102+ int text_sign;
103+# ifdef FEAT_SIGN_ICONS
104+ int icon_sign;
105+# endif
106+
107+ // Draw two cells with the sign value or blank.
108+ *c_extrap = ' ';
109+ *c_finalp = NUL;
110+ if (nrcol)
111+ *n_extrap = number_width(wp) + 1;
112+ else
113+ {
114+ *char_attrp = hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC));
115+ *n_extrap = 2;
116+ }
117+
118+ if (row == startrow
119+#ifdef FEAT_DIFF
120+ + filler_lines && filler_todo <= 0
121+#endif
122+ )
123+ {
124+ text_sign = (sattr->text != NULL) ? sattr->typenr : 0;
125+# ifdef FEAT_SIGN_ICONS
126+ icon_sign = (sattr->icon != NULL) ? sattr->typenr : 0;
127+ if (gui.in_use && icon_sign != 0)
128+ {
129+ // Use the image in this position.
130+ if (nrcol)
131+ {
132+ *c_extrap = NUL;
133+ sprintf((char *)extra, "%-*c ", number_width(wp), SIGN_BYTE);
134+ *pp_extra = extra;
135+ *n_extrap = (int)STRLEN(*pp_extra);
136+ }
137+ else
138+ *c_extrap = SIGN_BYTE;
139+# ifdef FEAT_NETBEANS_INTG
140+ if (netbeans_active() && (buf_signcount(wp->w_buffer, lnum) > 1))
141+ {
142+ if (nrcol)
143+ {
144+ *c_extrap = NUL;
145+ sprintf((char *)extra, "%-*c ", number_width(wp),
146+ MULTISIGN_BYTE);
147+ *pp_extra = extra;
148+ *n_extrap = (int)STRLEN(*pp_extra);
149+ }
150+ else
151+ *c_extrap = MULTISIGN_BYTE;
152+ }
153+# endif
154+ *c_finalp = NUL;
155+ *char_attrp = icon_sign;
156+ }
157+ else
158+# endif
159+ if (text_sign != 0)
160+ {
161+ *pp_extra = sattr->text;
162+ if (*pp_extra != NULL)
163+ {
164+ if (nrcol)
165+ {
166+ int n, width = number_width(wp) - 2;
167+
168+ for (n = 0; n < width; n++)
169+ extra[n] = ' ';
170+ extra[n] = 0;
171+ STRCAT(extra, *pp_extra);
172+ STRCAT(extra, " ");
173+ *pp_extra = extra;
174+ }
175+ *c_extrap = NUL;
176+ *c_finalp = NUL;
177+ *n_extrap = (int)STRLEN(*pp_extra);
178+ }
179+ *char_attrp = sattr->texthl;
180+ }
181+ }
182+}
183+#endif
184+
185+#ifdef FEAT_TEXT_PROP
186+static textprop_T *current_text_props = NULL;
187+static buf_T *current_buf = NULL;
188+
189+ static int
190+text_prop_compare(const void *s1, const void *s2)
191+{
192+ int idx1, idx2;
193+ proptype_T *pt1, *pt2;
194+ colnr_T col1, col2;
195+
196+ idx1 = *(int *)s1;
197+ idx2 = *(int *)s2;
198+ pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type);
199+ pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type);
200+ if (pt1 == pt2)
201+ return 0;
202+ if (pt1 == NULL)
203+ return -1;
204+ if (pt2 == NULL)
205+ return 1;
206+ if (pt1->pt_priority != pt2->pt_priority)
207+ return pt1->pt_priority > pt2->pt_priority ? 1 : -1;
208+ col1 = current_text_props[idx1].tp_col;
209+ col2 = current_text_props[idx2].tp_col;
210+ return col1 == col2 ? 0 : col1 > col2 ? 1 : -1;
211+}
212+#endif
213+
214+/*
215+ * Display line "lnum" of window 'wp' on the screen.
216+ * Start at row "startrow", stop when "endrow" is reached.
217+ * wp->w_virtcol needs to be valid.
218+ *
219+ * Return the number of last row the line occupies.
220+ */
221+ int
222+win_line(
223+ win_T *wp,
224+ linenr_T lnum,
225+ int startrow,
226+ int endrow,
227+ int nochange UNUSED, // not updating for changed text
228+ int number_only) // only update the number column
229+{
230+ int col = 0; // visual column on screen
231+ unsigned off; // offset in ScreenLines/ScreenAttrs
232+ int c = 0; // init for GCC
233+ long vcol = 0; // virtual column (for tabs)
234+#ifdef FEAT_LINEBREAK
235+ long vcol_sbr = -1; // virtual column after showbreak
236+#endif
237+ long vcol_prev = -1; // "vcol" of previous character
238+ char_u *line; // current line
239+ char_u *ptr; // current position in "line"
240+ int row; // row in the window, excl w_winrow
241+ int screen_row; // row on the screen, incl w_winrow
242+
243+ char_u extra[21]; // "%ld " and 'fdc' must fit in here
244+ int n_extra = 0; // number of extra chars
245+ char_u *p_extra = NULL; // string of extra chars, plus NUL
246+ char_u *p_extra_free = NULL; // p_extra needs to be freed
247+ int c_extra = NUL; // extra chars, all the same
248+ int c_final = NUL; // final char, mandatory if set
249+ int extra_attr = 0; // attributes when n_extra != 0
250+ static char_u *at_end_str = (char_u *)""; // used for p_extra when
251+ // displaying lcs_eol at end-of-line
252+ int lcs_eol_one = lcs_eol; // lcs_eol until it's been used
253+ int lcs_prec_todo = lcs_prec; // lcs_prec until it's been used
254+
255+ // saved "extra" items for when draw_state becomes WL_LINE (again)
256+ int saved_n_extra = 0;
257+ char_u *saved_p_extra = NULL;
258+ int saved_c_extra = 0;
259+ int saved_c_final = 0;
260+ int saved_char_attr = 0;
261+
262+ int n_attr = 0; // chars with special attr
263+ int saved_attr2 = 0; // char_attr saved for n_attr
264+ int n_attr3 = 0; // chars with overruling special attr
265+ int saved_attr3 = 0; // char_attr saved for n_attr3
266+
267+ int n_skip = 0; // nr of chars to skip for 'nowrap'
268+
269+ int fromcol = -10; // start of inverting
270+ int tocol = MAXCOL; // end of inverting
271+ int fromcol_prev = -2; // start of inverting after cursor
272+ int noinvcur = FALSE; // don't invert the cursor
273+ pos_T *top, *bot;
274+ int lnum_in_visual_area = FALSE;
275+ pos_T pos;
276+ long v;
277+
278+ int char_attr = 0; // attributes for next character
279+ int attr_pri = FALSE; // char_attr has priority
280+ int area_highlighting = FALSE; // Visual or incsearch highlighting
281+ // in this line
282+ int vi_attr = 0; // attributes for Visual and incsearch
283+ // highlighting
284+ int wcr_attr = 0; // attributes from 'wincolor'
285+ int win_attr = 0; // background for whole window, except
286+ // margins and "~" lines.
287+ int area_attr = 0; // attributes desired by highlighting
288+ int search_attr = 0; // attributes desired by 'hlsearch'
289+#ifdef FEAT_SYN_HL
290+ int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
291+ int syntax_attr = 0; // attributes desired by syntax
292+ int has_syntax = FALSE; // this buffer has syntax highl.
293+ int save_did_emsg;
294+ int draw_color_col = FALSE; // highlight colorcolumn
295+ int *color_cols = NULL; // pointer to according columns array
296+#endif
297+ int eol_hl_off = 0; // 1 if highlighted char after EOL
298+#ifdef FEAT_TEXT_PROP
299+ int text_prop_count;
300+ int text_prop_next = 0; // next text property to use
301+ textprop_T *text_props = NULL;
302+ int *text_prop_idxs = NULL;
303+ int text_props_active = 0;
304+ proptype_T *text_prop_type = NULL;
305+ int text_prop_attr = 0;
306+ int text_prop_combine = FALSE;
307+#endif
308+#ifdef FEAT_SPELL
309+ int has_spell = FALSE; // this buffer has spell checking
310+# define SPWORDLEN 150
311+ char_u nextline[SPWORDLEN * 2];// text with start of the next line
312+ int nextlinecol = 0; // column where nextline[] starts
313+ int nextline_idx = 0; // index in nextline[] where next line
314+ // starts
315+ int spell_attr = 0; // attributes desired by spelling
316+ int word_end = 0; // last byte with same spell_attr
317+ static linenr_T checked_lnum = 0; // line number for "checked_col"
318+ static int checked_col = 0; // column in "checked_lnum" up to which
319+ // there are no spell errors
320+ static int cap_col = -1; // column to check for Cap word
321+ static linenr_T capcol_lnum = 0; // line number where "cap_col" used
322+ int cur_checked_col = 0; // checked column for current line
323+#endif
324+ int extra_check = 0; // has extra highlighting
325+ int multi_attr = 0; // attributes desired by multibyte
326+ int mb_l = 1; // multi-byte byte length
327+ int mb_c = 0; // decoded multi-byte character
328+ int mb_utf8 = FALSE; // screen char is UTF-8 char
329+ int u8cc[MAX_MCO]; // composing UTF-8 chars
330+#if defined(FEAT_DIFF) || defined(FEAT_SIGNS)
331+ int filler_lines = 0; // nr of filler lines to be drawn
332+ int filler_todo = 0; // nr of filler lines still to do + 1
333+#endif
334+#ifdef FEAT_DIFF
335+ hlf_T diff_hlf = (hlf_T)0; // type of diff highlighting
336+ int change_start = MAXCOL; // first col of changed area
337+ int change_end = -1; // last col of changed area
338+#endif
339+ colnr_T trailcol = MAXCOL; // start of trailing spaces
340+#ifdef FEAT_LINEBREAK
341+ int need_showbreak = FALSE; // overlong line, skipping first x
342+ // chars
343+#endif
344+#if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \
345+ || defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
346+# define LINE_ATTR
347+ int line_attr = 0; // attribute for the whole line
348+ int line_attr_save;
349+#endif
350+#ifdef FEAT_SIGNS
351+ int sign_present = FALSE;
352+ sign_attrs_T sattr;
353+#endif
354+#ifdef FEAT_ARABIC
355+ int prev_c = 0; // previous Arabic character
356+ int prev_c1 = 0; // first composing char for prev_c
357+#endif
358+#if defined(LINE_ATTR)
359+ int did_line_attr = 0;
360+#endif
361+#ifdef FEAT_TERMINAL
362+ int get_term_attr = FALSE;
363+#endif
364+#ifdef FEAT_SYN_HL
365+ int cul_attr = 0; // set when 'cursorline' active
366+
367+ // 'cursorlineopt' has "screenline" and cursor is in this line
368+ int cul_screenline = FALSE;
369+
370+ // margin columns for the screen line, needed for when 'cursorlineopt'
371+ // contains "screenline"
372+ int left_curline_col = 0;
373+ int right_curline_col = 0;
374+#endif
375+
376+ // draw_state: items that are drawn in sequence:
377+#define WL_START 0 // nothing done yet
378+#ifdef FEAT_CMDWIN
379+# define WL_CMDLINE WL_START + 1 // cmdline window column
380+#else
381+# define WL_CMDLINE WL_START
382+#endif
383+#ifdef FEAT_FOLDING
384+# define WL_FOLD WL_CMDLINE + 1 // 'foldcolumn'
385+#else
386+# define WL_FOLD WL_CMDLINE
387+#endif
388+#ifdef FEAT_SIGNS
389+# define WL_SIGN WL_FOLD + 1 // column for signs
390+#else
391+# define WL_SIGN WL_FOLD // column for signs
392+#endif
393+#define WL_NR WL_SIGN + 1 // line number
394+#ifdef FEAT_LINEBREAK
395+# define WL_BRI WL_NR + 1 // 'breakindent'
396+#else
397+# define WL_BRI WL_NR
398+#endif
399+#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
400+# define WL_SBR WL_BRI + 1 // 'showbreak' or 'diff'
401+#else
402+# define WL_SBR WL_BRI
403+#endif
404+#define WL_LINE WL_SBR + 1 // text in the line
405+ int draw_state = WL_START; // what to draw next
406+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
407+ int feedback_col = 0;
408+ int feedback_old_attr = -1;
409+#endif
410+ int screen_line_flags = 0;
411+
412+#if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA)
413+ int match_conc = 0; // cchar for match functions
414+#endif
415+#ifdef FEAT_CONCEAL
416+ int syntax_flags = 0;
417+ int syntax_seqnr = 0;
418+ int prev_syntax_id = 0;
419+ int conceal_attr = HL_ATTR(HLF_CONCEAL);
420+ int is_concealing = FALSE;
421+ int boguscols = 0; // nonexistent columns added to force
422+ // wrapping
423+ int vcol_off = 0; // offset for concealed characters
424+ int did_wcol = FALSE;
425+ int old_boguscols = 0;
426+# define VCOL_HLC (vcol - vcol_off)
427+# define FIX_FOR_BOGUSCOLS \
428+ { \
429+ n_extra += vcol_off; \
430+ vcol -= vcol_off; \
431+ vcol_off = 0; \
432+ col -= boguscols; \
433+ old_boguscols = boguscols; \
434+ boguscols = 0; \
435+ }
436+#else
437+# define VCOL_HLC (vcol)
438+#endif
439+
440+ if (startrow > endrow) // past the end already!
441+ return startrow;
442+
443+ row = startrow;
444+ screen_row = row + W_WINROW(wp);
445+
446+ if (!number_only)
447+ {
448+ // To speed up the loop below, set extra_check when there is linebreak,
449+ // trailing white space and/or syntax processing to be done.
450+#ifdef FEAT_LINEBREAK
451+ extra_check = wp->w_p_lbr;
452+#endif
453+#ifdef FEAT_SYN_HL
454+ if (syntax_present(wp) && !wp->w_s->b_syn_error
455+# ifdef SYN_TIME_LIMIT
456+ && !wp->w_s->b_syn_slow
457+# endif
458+ )
459+ {
460+ // Prepare for syntax highlighting in this line. When there is an
461+ // error, stop syntax highlighting.
462+ save_did_emsg = did_emsg;
463+ did_emsg = FALSE;
464+ syntax_start(wp, lnum);
465+ if (did_emsg)
466+ wp->w_s->b_syn_error = TRUE;
467+ else
468+ {
469+ did_emsg = save_did_emsg;
470+#ifdef SYN_TIME_LIMIT
471+ if (!wp->w_s->b_syn_slow)
472+#endif
473+ {
474+ has_syntax = TRUE;
475+ extra_check = TRUE;
476+ }
477+ }
478+ }
479+
480+ // Check for columns to display for 'colorcolumn'.
481+ color_cols = wp->w_p_cc_cols;
482+ if (color_cols != NULL)
483+ draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
484+#endif
485+
486+#ifdef FEAT_TERMINAL
487+ if (term_show_buffer(wp->w_buffer))
488+ {
489+ extra_check = TRUE;
490+ get_term_attr = TRUE;
491+ win_attr = term_get_attr(wp->w_buffer, lnum, -1);
492+ }
493+#endif
494+
495+#ifdef FEAT_SPELL
496+ if (wp->w_p_spell
497+ && *wp->w_s->b_p_spl != NUL
498+ && wp->w_s->b_langp.ga_len > 0
499+ && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
500+ {
501+ // Prepare for spell checking.
502+ has_spell = TRUE;
503+ extra_check = TRUE;
504+
505+ // Get the start of the next line, so that words that wrap to the
506+ // next line are found too: "et<line-break>al.".
507+ // Trick: skip a few chars for C/shell/Vim comments
508+ nextline[SPWORDLEN] = NUL;
509+ if (lnum < wp->w_buffer->b_ml.ml_line_count)
510+ {
511+ line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
512+ spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
513+ }
514+
515+ // When a word wrapped from the previous line the start of the
516+ // current line is valid.
517+ if (lnum == checked_lnum)
518+ cur_checked_col = checked_col;
519+ checked_lnum = 0;
520+
521+ // When there was a sentence end in the previous line may require a
522+ // word starting with capital in this line. In line 1 always check
523+ // the first word.
524+ if (lnum != capcol_lnum)
525+ cap_col = -1;
526+ if (lnum == 1)
527+ cap_col = 0;
528+ capcol_lnum = 0;
529+ }
530+#endif
531+
532+ // handle Visual active in this window
533+ if (VIsual_active && wp->w_buffer == curwin->w_buffer)
534+ {
535+ if (LTOREQ_POS(curwin->w_cursor, VIsual))
536+ {
537+ // Visual is after curwin->w_cursor
538+ top = &curwin->w_cursor;
539+ bot = &VIsual;
540+ }
541+ else
542+ {
543+ // Visual is before curwin->w_cursor
544+ top = &VIsual;
545+ bot = &curwin->w_cursor;
546+ }
547+ lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
548+ if (VIsual_mode == Ctrl_V)
549+ {
550+ // block mode
551+ if (lnum_in_visual_area)
552+ {
553+ fromcol = wp->w_old_cursor_fcol;
554+ tocol = wp->w_old_cursor_lcol;
555+ }
556+ }
557+ else
558+ {
559+ // non-block mode
560+ if (lnum > top->lnum && lnum <= bot->lnum)
561+ fromcol = 0;
562+ else if (lnum == top->lnum)
563+ {
564+ if (VIsual_mode == 'V') // linewise
565+ fromcol = 0;
566+ else
567+ {
568+ getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
569+ if (gchar_pos(top) == NUL)
570+ tocol = fromcol + 1;
571+ }
572+ }
573+ if (VIsual_mode != 'V' && lnum == bot->lnum)
574+ {
575+ if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0)
576+ {
577+ fromcol = -10;
578+ tocol = MAXCOL;
579+ }
580+ else if (bot->col == MAXCOL)
581+ tocol = MAXCOL;
582+ else
583+ {
584+ pos = *bot;
585+ if (*p_sel == 'e')
586+ getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
587+ else
588+ {
589+ getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
590+ ++tocol;
591+ }
592+ }
593+ }
594+ }
595+
596+ // Check if the character under the cursor should not be inverted
597+ if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
598+#ifdef FEAT_GUI
599+ && !gui.in_use
600+#endif
601+ )
602+ noinvcur = TRUE;
603+
604+ // if inverting in this line set area_highlighting
605+ if (fromcol >= 0)
606+ {
607+ area_highlighting = TRUE;
608+ vi_attr = HL_ATTR(HLF_V);
609+#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
610+ if ((clip_star.available && !clip_star.owned
611+ && clip_isautosel_star())
612+ || (clip_plus.available && !clip_plus.owned
613+ && clip_isautosel_plus()))
614+ vi_attr = HL_ATTR(HLF_VNC);
615+#endif
616+ }
617+ }
618+
619+ // handle 'incsearch' and ":s///c" highlighting
620+ else if (highlight_match
621+ && wp == curwin
622+ && lnum >= curwin->w_cursor.lnum
623+ && lnum <= curwin->w_cursor.lnum + search_match_lines)
624+ {
625+ if (lnum == curwin->w_cursor.lnum)
626+ getvcol(curwin, &(curwin->w_cursor),
627+ (colnr_T *)&fromcol, NULL, NULL);
628+ else
629+ fromcol = 0;
630+ if (lnum == curwin->w_cursor.lnum + search_match_lines)
631+ {
632+ pos.lnum = lnum;
633+ pos.col = search_match_endcol;
634+ getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
635+ }
636+ else
637+ tocol = MAXCOL;
638+ // do at least one character; happens when past end of line
639+ if (fromcol == tocol)
640+ tocol = fromcol + 1;
641+ area_highlighting = TRUE;
642+ vi_attr = HL_ATTR(HLF_I);
643+ }
644+ }
645+
646+#ifdef FEAT_DIFF
647+ filler_lines = diff_check(wp, lnum);
648+ if (filler_lines < 0)
649+ {
650+ if (filler_lines == -1)
651+ {
652+ if (diff_find_change(wp, lnum, &change_start, &change_end))
653+ diff_hlf = HLF_ADD; // added line
654+ else if (change_start == 0)
655+ diff_hlf = HLF_TXD; // changed text
656+ else
657+ diff_hlf = HLF_CHD; // changed line
658+ }
659+ else
660+ diff_hlf = HLF_ADD; // added line
661+ filler_lines = 0;
662+ area_highlighting = TRUE;
663+ }
664+ if (lnum == wp->w_topline)
665+ filler_lines = wp->w_topfill;
666+ filler_todo = filler_lines;
667+#endif
668+
669+#ifdef FEAT_SIGNS
670+ sign_present = buf_get_signattrs(wp->w_buffer, lnum, &sattr);
671+#endif
672+
673+#ifdef LINE_ATTR
674+# ifdef FEAT_SIGNS
675+ // If this line has a sign with line highlighting set line_attr.
676+ if (sign_present)
677+ line_attr = sattr.linehl;
678+# endif
679+# if defined(FEAT_QUICKFIX)
680+ // Highlight the current line in the quickfix window.
681+ if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
682+ line_attr = HL_ATTR(HLF_QFL);
683+# endif
684+ if (line_attr != 0)
685+ area_highlighting = TRUE;
686+#endif
687+
688+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
689+ ptr = line;
690+
691+#ifdef FEAT_SPELL
692+ if (has_spell && !number_only)
693+ {
694+ // For checking first word with a capital skip white space.
695+ if (cap_col == 0)
696+ cap_col = getwhitecols(line);
697+
698+ // To be able to spell-check over line boundaries copy the end of the
699+ // current line into nextline[]. Above the start of the next line was
700+ // copied to nextline[SPWORDLEN].
701+ if (nextline[SPWORDLEN] == NUL)
702+ {
703+ // No next line or it is empty.
704+ nextlinecol = MAXCOL;
705+ nextline_idx = 0;
706+ }
707+ else
708+ {
709+ v = (long)STRLEN(line);
710+ if (v < SPWORDLEN)
711+ {
712+ // Short line, use it completely and append the start of the
713+ // next line.
714+ nextlinecol = 0;
715+ mch_memmove(nextline, line, (size_t)v);
716+ STRMOVE(nextline + v, nextline + SPWORDLEN);
717+ nextline_idx = v + 1;
718+ }
719+ else
720+ {
721+ // Long line, use only the last SPWORDLEN bytes.
722+ nextlinecol = v - SPWORDLEN;
723+ mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
724+ nextline_idx = SPWORDLEN + 1;
725+ }
726+ }
727+ }
728+#endif
729+
730+ if (wp->w_p_list)
731+ {
732+ if (lcs_space || lcs_trail || lcs_nbsp)
733+ extra_check = TRUE;
734+ // find start of trailing whitespace
735+ if (lcs_trail)
736+ {
737+ trailcol = (colnr_T)STRLEN(ptr);
738+ while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
739+ --trailcol;
740+ trailcol += (colnr_T) (ptr - line);
741+ }
742+ }
743+
744+ wcr_attr = get_wcr_attr(wp);
745+ if (wcr_attr != 0)
746+ {
747+ win_attr = wcr_attr;
748+ area_highlighting = TRUE;
749+ }
750+#ifdef FEAT_TEXT_PROP
751+ if (WIN_IS_POPUP(wp))
752+ screen_line_flags |= SLF_POPUP;
753+#endif
754+
755+ // 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
756+ // first character to be displayed.
757+ if (wp->w_p_wrap)
758+ v = wp->w_skipcol;
759+ else
760+ v = wp->w_leftcol;
761+ if (v > 0 && !number_only)
762+ {
763+ char_u *prev_ptr = ptr;
764+
765+ while (vcol < v && *ptr != NUL)
766+ {
767+ c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
768+ vcol += c;
769+ prev_ptr = ptr;
770+ MB_PTR_ADV(ptr);
771+ }
772+
773+ // When:
774+ // - 'cuc' is set, or
775+ // - 'colorcolumn' is set, or
776+ // - 'virtualedit' is set, or
777+ // - the visual mode is active,
778+ // the end of the line may be before the start of the displayed part.
779+ if (vcol < v && (
780+#ifdef FEAT_SYN_HL
781+ wp->w_p_cuc || draw_color_col ||
782+#endif
783+ virtual_active() ||
784+ (VIsual_active && wp->w_buffer == curwin->w_buffer)))
785+ vcol = v;
786+
787+ // Handle a character that's not completely on the screen: Put ptr at
788+ // that character but skip the first few screen characters.
789+ if (vcol > v)
790+ {
791+ vcol -= c;
792+ ptr = prev_ptr;
793+ // If the character fits on the screen, don't need to skip it.
794+ // Except for a TAB.
795+ if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0)
796+ n_skip = v - vcol;
797+ }
798+
799+ // Adjust for when the inverted text is before the screen,
800+ // and when the start of the inverted text is before the screen.
801+ if (tocol <= vcol)
802+ fromcol = 0;
803+ else if (fromcol >= 0 && fromcol < vcol)
804+ fromcol = vcol;
805+
806+#ifdef FEAT_LINEBREAK
807+ // When w_skipcol is non-zero, first line needs 'showbreak'
808+ if (wp->w_p_wrap)
809+ need_showbreak = TRUE;
810+#endif
811+#ifdef FEAT_SPELL
812+ // When spell checking a word we need to figure out the start of the
813+ // word and if it's badly spelled or not.
814+ if (has_spell)
815+ {
816+ int len;
817+ colnr_T linecol = (colnr_T)(ptr - line);
818+ hlf_T spell_hlf = HLF_COUNT;
819+
820+ pos = wp->w_cursor;
821+ wp->w_cursor.lnum = lnum;
822+ wp->w_cursor.col = linecol;
823+ len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
824+
825+ // spell_move_to() may call ml_get() and make "line" invalid
826+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
827+ ptr = line + linecol;
828+
829+ if (len == 0 || (int)wp->w_cursor.col > ptr - line)
830+ {
831+ // no bad word found at line start, don't check until end of a
832+ // word
833+ spell_hlf = HLF_COUNT;
834+ word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
835+ }
836+ else
837+ {
838+ // bad word found, use attributes until end of word
839+ word_end = wp->w_cursor.col + len + 1;
840+
841+ // Turn index into actual attributes.
842+ if (spell_hlf != HLF_COUNT)
843+ spell_attr = highlight_attr[spell_hlf];
844+ }
845+ wp->w_cursor = pos;
846+
847+# ifdef FEAT_SYN_HL
848+ // Need to restart syntax highlighting for this line.
849+ if (has_syntax)
850+ syntax_start(wp, lnum);
851+# endif
852+ }
853+#endif
854+ }
855+
856+ // Correct highlighting for cursor that can't be disabled.
857+ // Avoids having to check this for each character.
858+ if (fromcol >= 0)
859+ {
860+ if (noinvcur)
861+ {
862+ if ((colnr_T)fromcol == wp->w_virtcol)
863+ {
864+ // highlighting starts at cursor, let it start just after the
865+ // cursor
866+ fromcol_prev = fromcol;
867+ fromcol = -1;
868+ }
869+ else if ((colnr_T)fromcol < wp->w_virtcol)
870+ // restart highlighting after the cursor
871+ fromcol_prev = wp->w_virtcol;
872+ }
873+ if (fromcol >= tocol)
874+ fromcol = -1;
875+ }
876+
877+#ifdef FEAT_SEARCH_EXTRA
878+ if (!number_only)
879+ {
880+ v = (long)(ptr - line);
881+ area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
882+ &line, &screen_search_hl,
883+ &search_attr);
884+ ptr = line + v; // "line" may have been updated
885+ }
886+#endif
887+
888+#ifdef FEAT_SYN_HL
889+ // Cursor line highlighting for 'cursorline' in the current window.
890+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
891+ {
892+ // Do not show the cursor line in the text when Visual mode is active,
893+ // because it's not clear what is selected then. Do update
894+ // w_last_cursorline.
895+ if (!(wp == curwin && VIsual_active)
896+ && wp->w_p_culopt_flags != CULOPT_NBR)
897+ {
898+ cul_screenline = (wp->w_p_wrap
899+ && (wp->w_p_culopt_flags & CULOPT_SCRLINE));
900+
901+ // Only set line_attr here when "screenline" is not present in
902+ // 'cursorlineopt'. Otherwise it's done later.
903+ if (!cul_screenline)
904+ {
905+ cul_attr = HL_ATTR(HLF_CUL);
906+ line_attr = cul_attr;
907+ wp->w_last_cursorline = wp->w_cursor.lnum;
908+ }
909+ else
910+ {
911+ line_attr_save = line_attr;
912+ wp->w_last_cursorline = 0;
913+ margin_columns_win(wp, &left_curline_col, &right_curline_col);
914+ }
915+ area_highlighting = TRUE;
916+ }
917+ else
918+ wp->w_last_cursorline = wp->w_cursor.lnum;
919+ }
920+#endif
921+
922+#ifdef FEAT_TEXT_PROP
923+ {
924+ char_u *prop_start;
925+
926+ text_prop_count = get_text_props(wp->w_buffer, lnum,
927+ &prop_start, FALSE);
928+ if (text_prop_count > 0)
929+ {
930+ // Make a copy of the properties, so that they are properly
931+ // aligned.
932+ text_props = ALLOC_MULT(textprop_T, text_prop_count);
933+ if (text_props != NULL)
934+ mch_memmove(text_props, prop_start,
935+ text_prop_count * sizeof(textprop_T));
936+
937+ // Allocate an array for the indexes.
938+ text_prop_idxs = ALLOC_MULT(int, text_prop_count);
939+ area_highlighting = TRUE;
940+ extra_check = TRUE;
941+ }
942+ }
943+#endif
944+
945+ off = (unsigned)(current_ScreenLine - ScreenLines);
946+ col = 0;
947+
948+#ifdef FEAT_RIGHTLEFT
949+ if (wp->w_p_rl)
950+ {
951+ // Rightleft window: process the text in the normal direction, but put
952+ // it in current_ScreenLine[] from right to left. Start at the
953+ // rightmost column of the window.
954+ col = wp->w_width - 1;
955+ off += col;
956+ screen_line_flags |= SLF_RIGHTLEFT;
957+ }
958+#endif
959+
960+ // Repeat for the whole displayed line.
961+ for (;;)
962+ {
963+#if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA)
964+ int has_match_conc = 0; // match wants to conceal
965+#endif
966+#ifdef FEAT_CONCEAL
967+ int did_decrement_ptr = FALSE;
968+#endif
969+ // Skip this quickly when working on the text.
970+ if (draw_state != WL_LINE)
971+ {
972+#ifdef FEAT_CMDWIN
973+ if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
974+ {
975+ draw_state = WL_CMDLINE;
976+ if (cmdwin_type != 0 && wp == curwin)
977+ {
978+ // Draw the cmdline character.
979+ n_extra = 1;
980+ c_extra = cmdwin_type;
981+ c_final = NUL;
982+ char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_AT));
983+ }
984+ }
985+#endif
986+
987+#ifdef FEAT_FOLDING
988+ if (draw_state == WL_FOLD - 1 && n_extra == 0)
989+ {
990+ int fdc = compute_foldcolumn(wp, 0);
991+
992+ draw_state = WL_FOLD;
993+ if (fdc > 0)
994+ {
995+ // Draw the 'foldcolumn'. Allocate a buffer, "extra" may
996+ // already be in use.
997+ vim_free(p_extra_free);
998+ p_extra_free = alloc(12 + 1);
999+
1000+ if (p_extra_free != NULL)
1001+ {
1002+ fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
1003+ n_extra = fdc;
1004+ p_extra_free[n_extra] = NUL;
1005+ p_extra = p_extra_free;
1006+ c_extra = NUL;
1007+ c_final = NUL;
1008+ char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC));
1009+ }
1010+ }
1011+ }
1012+#endif
1013+
1014+#ifdef FEAT_SIGNS
1015+ if (draw_state == WL_SIGN - 1 && n_extra == 0)
1016+ {
1017+ draw_state = WL_SIGN;
1018+ // Show the sign column when there are any signs in this
1019+ // buffer or when using Netbeans.
1020+ if (signcolumn_on(wp))
1021+ get_sign_display_info(FALSE, wp, lnum, &sattr, wcr_attr,
1022+ row, startrow, filler_lines, filler_todo, &c_extra,
1023+ &c_final, extra, &p_extra, &n_extra, &char_attr);
1024+ }
1025+#endif
1026+
1027+ if (draw_state == WL_NR - 1 && n_extra == 0)
1028+ {
1029+ draw_state = WL_NR;
1030+ // Display the absolute or relative line number. After the
1031+ // first fill with blanks when the 'n' flag isn't in 'cpo'
1032+ if ((wp->w_p_nu || wp->w_p_rnu)
1033+ && (row == startrow
1034+#ifdef FEAT_DIFF
1035+ + filler_lines
1036+#endif
1037+ || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
1038+ {
1039+#ifdef FEAT_SIGNS
1040+ // If 'signcolumn' is set to 'number' and a sign is present
1041+ // in 'lnum', then display the sign instead of the line
1042+ // number.
1043+ if ((*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')
1044+ && sign_present)
1045+ get_sign_display_info(TRUE, wp, lnum, &sattr, wcr_attr,
1046+ row, startrow, filler_lines, filler_todo,
1047+ &c_extra, &c_final, extra, &p_extra, &n_extra,
1048+ &char_attr);
1049+ else
1050+#endif
1051+ {
1052+ // Draw the line number (empty space after wrapping).
1053+ if (row == startrow
1054+#ifdef FEAT_DIFF
1055+ + filler_lines
1056+#endif
1057+ )
1058+ {
1059+ long num;
1060+ char *fmt = "%*ld ";
1061+
1062+ if (wp->w_p_nu && !wp->w_p_rnu)
1063+ // 'number' + 'norelativenumber'
1064+ num = (long)lnum;
1065+ else
1066+ {
1067+ // 'relativenumber', don't use negative numbers
1068+ num = labs((long)get_cursor_rel_lnum(wp, lnum));
1069+ if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
1070+ {
1071+ // 'number' + 'relativenumber'
1072+ num = lnum;
1073+ fmt = "%-*ld ";
1074+ }
1075+ }
1076+
1077+ sprintf((char *)extra, fmt,
1078+ number_width(wp), num);
1079+ if (wp->w_skipcol > 0)
1080+ for (p_extra = extra; *p_extra == ' '; ++p_extra)
1081+ *p_extra = '-';
1082+#ifdef FEAT_RIGHTLEFT
1083+ if (wp->w_p_rl) // reverse line numbers
1084+ {
1085+ char_u *p1, *p2;
1086+ int t;
1087+
1088+ // like rl_mirror(), but keep the space at the end
1089+ p2 = skiptowhite(extra) - 1;
1090+ for (p1 = extra; p1 < p2; ++p1, --p2)
1091+ {
1092+ t = *p1;
1093+ *p1 = *p2;
1094+ *p2 = t;
1095+ }
1096+ }
1097+#endif
1098+ p_extra = extra;
1099+ c_extra = NUL;
1100+ c_final = NUL;
1101+ }
1102+ else
1103+ {
1104+ c_extra = ' ';
1105+ c_final = NUL;
1106+ }
1107+ n_extra = number_width(wp) + 1;
1108+ char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_N));
1109+#ifdef FEAT_SYN_HL
1110+ // When 'cursorline' is set highlight the line number of
1111+ // the current line differently.
1112+ // When 'cursorlineopt' has "screenline" only highlight
1113+ // the line number itself.
1114+ // TODO: Can we use CursorLine instead of CursorLineNr
1115+ // when CursorLineNr isn't set?
1116+ if ((wp->w_p_cul || wp->w_p_rnu)
1117+ && (wp->w_p_culopt_flags & CULOPT_NBR)
1118+ && (row == startrow
1119+ || wp->w_p_culopt_flags & CULOPT_LINE)
1120+ && lnum == wp->w_cursor.lnum)
1121+ char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_CLN));
1122+#endif
1123+ }
1124+ }
1125+ }
1126+
1127+#ifdef FEAT_LINEBREAK
1128+ if (wp->w_p_brisbr && draw_state == WL_BRI - 1
1129+ && n_extra == 0 && *p_sbr != NUL)
1130+ // draw indent after showbreak value
1131+ draw_state = WL_BRI;
1132+ else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0)
1133+ // After the showbreak, draw the breakindent
1134+ draw_state = WL_BRI - 1;
1135+
1136+ // draw 'breakindent': indent wrapped text accordingly
1137+ if (draw_state == WL_BRI - 1 && n_extra == 0)
1138+ {
1139+ draw_state = WL_BRI;
1140+ // if need_showbreak is set, breakindent also applies
1141+ if (wp->w_p_bri && n_extra == 0
1142+ && (row != startrow || need_showbreak)
1143+# ifdef FEAT_DIFF
1144+ && filler_lines == 0
1145+# endif
1146+ )
1147+ {
1148+ char_attr = 0;
1149+# ifdef FEAT_DIFF
1150+ if (diff_hlf != (hlf_T)0)
1151+ {
1152+ char_attr = HL_ATTR(diff_hlf);
1153+# ifdef FEAT_SYN_HL
1154+ if (cul_attr != 0)
1155+ char_attr = hl_combine_attr(char_attr, cul_attr);
1156+# endif
1157+ }
1158+# endif
1159+ p_extra = NULL;
1160+ c_extra = ' ';
1161+ n_extra = get_breakindent_win(wp,
1162+ ml_get_buf(wp->w_buffer, lnum, FALSE));
1163+ // Correct end of highlighted area for 'breakindent',
1164+ // required when 'linebreak' is also set.
1165+ if (tocol == vcol)
1166+ tocol += n_extra;
1167+ }
1168+ }
1169+#endif
1170+
1171+#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
1172+ if (draw_state == WL_SBR - 1 && n_extra == 0)
1173+ {
1174+ draw_state = WL_SBR;
1175+# ifdef FEAT_DIFF
1176+ if (filler_todo > 0)
1177+ {
1178+ // Draw "deleted" diff line(s).
1179+ if (char2cells(fill_diff) > 1)
1180+ {
1181+ c_extra = '-';
1182+ c_final = NUL;
1183+ }
1184+ else
1185+ {
1186+ c_extra = fill_diff;
1187+ c_final = NUL;
1188+ }
1189+# ifdef FEAT_RIGHTLEFT
1190+ if (wp->w_p_rl)
1191+ n_extra = col + 1;
1192+ else
1193+# endif
1194+ n_extra = wp->w_width - col;
1195+ char_attr = HL_ATTR(HLF_DED);
1196+ }
1197+# endif
1198+# ifdef FEAT_LINEBREAK
1199+ if (*p_sbr != NUL && need_showbreak)
1200+ {
1201+ // Draw 'showbreak' at the start of each broken line.
1202+ p_extra = p_sbr;
1203+ c_extra = NUL;
1204+ c_final = NUL;
1205+ n_extra = (int)STRLEN(p_sbr);
1206+ char_attr = HL_ATTR(HLF_AT);
1207+ need_showbreak = FALSE;
1208+ vcol_sbr = vcol + MB_CHARLEN(p_sbr);
1209+ // Correct end of highlighted area for 'showbreak',
1210+ // required when 'linebreak' is also set.
1211+ if (tocol == vcol)
1212+ tocol += n_extra;
1213+ // combine 'showbreak' with 'wincolor'
1214+ if (win_attr != 0)
1215+ char_attr = hl_combine_attr(win_attr, char_attr);
1216+# ifdef FEAT_SYN_HL
1217+ // combine 'showbreak' with 'cursorline'
1218+ if (cul_attr != 0)
1219+ char_attr = hl_combine_attr(char_attr, cul_attr);
1220+# endif
1221+ }
1222+# endif
1223+ }
1224+#endif
1225+
1226+ if (draw_state == WL_LINE - 1 && n_extra == 0)
1227+ {
1228+ draw_state = WL_LINE;
1229+ if (saved_n_extra)
1230+ {
1231+ // Continue item from end of wrapped line.
1232+ n_extra = saved_n_extra;
1233+ c_extra = saved_c_extra;
1234+ c_final = saved_c_final;
1235+ p_extra = saved_p_extra;
1236+ char_attr = saved_char_attr;
1237+ }
1238+ else
1239+ char_attr = win_attr;
1240+ }
1241+ }
1242+#ifdef FEAT_SYN_HL
1243+ if (cul_screenline)
1244+ {
1245+ if (draw_state == WL_LINE
1246+ && vcol >= left_curline_col
1247+ && vcol < right_curline_col)
1248+ {
1249+ cul_attr = HL_ATTR(HLF_CUL);
1250+ line_attr = cul_attr;
1251+ }
1252+ else
1253+ {
1254+ cul_attr = 0;
1255+ line_attr = line_attr_save;
1256+ }
1257+ }
1258+#endif
1259+
1260+ // When still displaying '$' of change command, stop at cursor.
1261+ // When only displaying the (relative) line number and that's done,
1262+ // stop here.
1263+ if ((dollar_vcol >= 0 && wp == curwin
1264+ && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
1265+#ifdef FEAT_DIFF
1266+ && filler_todo <= 0
1267+#endif
1268+ )
1269+ || (number_only && draw_state > WL_NR))
1270+ {
1271+ screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
1272+ screen_line_flags);
1273+ // Pretend we have finished updating the window. Except when
1274+ // 'cursorcolumn' is set.
1275+#ifdef FEAT_SYN_HL
1276+ if (wp->w_p_cuc)
1277+ row = wp->w_cline_row + wp->w_cline_height;
1278+ else
1279+#endif
1280+ row = wp->w_height;
1281+ break;
1282+ }
1283+
1284+ if (draw_state == WL_LINE && (area_highlighting
1285+#ifdef FEAT_SPELL
1286+ || has_spell
1287+#endif
1288+ ))
1289+ {
1290+ // handle Visual or match highlighting in this line
1291+ if (vcol == fromcol
1292+ || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
1293+ && (*mb_ptr2cells)(ptr) > 1)
1294+ || ((int)vcol_prev == fromcol_prev
1295+ && vcol_prev < vcol // not at margin
1296+ && vcol < tocol))
1297+ area_attr = vi_attr; // start highlighting
1298+ else if (area_attr != 0
1299+ && (vcol == tocol
1300+ || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
1301+ area_attr = 0; // stop highlighting
1302+
1303+#ifdef FEAT_SEARCH_EXTRA
1304+ if (!n_extra)
1305+ {
1306+ // Check for start/end of 'hlsearch' and other matches.
1307+ // After end, check for start/end of next match.
1308+ // When another match, have to check for start again.
1309+ v = (long)(ptr - line);
1310+ search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line,
1311+ &screen_search_hl, &has_match_conc,
1312+ &match_conc, did_line_attr, lcs_eol_one);
1313+ ptr = line + v; // "line" may have been changed
1314+ }
1315+#endif
1316+
1317+#ifdef FEAT_DIFF
1318+ if (diff_hlf != (hlf_T)0)
1319+ {
1320+ if (diff_hlf == HLF_CHD && ptr - line >= change_start
1321+ && n_extra == 0)
1322+ diff_hlf = HLF_TXD; // changed text
1323+ if (diff_hlf == HLF_TXD && ptr - line > change_end
1324+ && n_extra == 0)
1325+ diff_hlf = HLF_CHD; // changed line
1326+ line_attr = HL_ATTR(diff_hlf);
1327+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum
1328+ && wp->w_p_culopt_flags != CULOPT_NBR
1329+ && (!cul_screenline || (vcol >= left_curline_col
1330+ && vcol <= right_curline_col)))
1331+ line_attr = hl_combine_attr(
1332+ line_attr, HL_ATTR(HLF_CUL));
1333+ }
1334+#endif
1335+
1336+#ifdef FEAT_TEXT_PROP
1337+ if (text_props != NULL)
1338+ {
1339+ int pi;
1340+ int bcol = (int)(ptr - line);
1341+
1342+ if (n_extra > 0)
1343+ --bcol; // still working on the previous char, e.g. Tab
1344+
1345+ // Check if any active property ends.
1346+ for (pi = 0; pi < text_props_active; ++pi)
1347+ {
1348+ int tpi = text_prop_idxs[pi];
1349+
1350+ if (bcol >= text_props[tpi].tp_col - 1
1351+ + text_props[tpi].tp_len)
1352+ {
1353+ if (pi + 1 < text_props_active)
1354+ mch_memmove(text_prop_idxs + pi,
1355+ text_prop_idxs + pi + 1,
1356+ sizeof(int)
1357+ * (text_props_active - (pi + 1)));
1358+ --text_props_active;
1359+ --pi;
1360+ }
1361+ }
1362+
1363+ // Add any text property that starts in this column.
1364+ while (text_prop_next < text_prop_count
1365+ && bcol >= text_props[text_prop_next].tp_col - 1)
1366+ text_prop_idxs[text_props_active++] = text_prop_next++;
1367+
1368+ text_prop_attr = 0;
1369+ text_prop_combine = FALSE;
1370+ if (text_props_active > 0)
1371+ {
1372+ // Sort the properties on priority and/or starting last.
1373+ // Then combine the attributes, highest priority last.
1374+ current_text_props = text_props;
1375+ current_buf = wp->w_buffer;
1376+ qsort((void *)text_prop_idxs, (size_t)text_props_active,
1377+ sizeof(int), text_prop_compare);
1378+
1379+ for (pi = 0; pi < text_props_active; ++pi)
1380+ {
1381+ int tpi = text_prop_idxs[pi];
1382+ proptype_T *pt = text_prop_type_by_id(
1383+ wp->w_buffer, text_props[tpi].tp_type);
1384+
1385+ if (pt != NULL && pt->pt_hl_id > 0)
1386+ {
1387+ int pt_attr = syn_id2attr(pt->pt_hl_id);
1388+
1389+ text_prop_type = pt;
1390+ text_prop_attr =
1391+ hl_combine_attr(text_prop_attr, pt_attr);
1392+ text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE;
1393+ }
1394+ }
1395+ }
1396+ }
1397+#endif
1398+
1399+ // Decide which of the highlight attributes to use.
1400+ attr_pri = TRUE;
1401+#ifdef LINE_ATTR
1402+ if (area_attr != 0)
1403+ char_attr = hl_combine_attr(line_attr, area_attr);
1404+ else if (search_attr != 0)
1405+ char_attr = hl_combine_attr(line_attr, search_attr);
1406+# ifdef FEAT_TEXT_PROP
1407+ else if (text_prop_type != NULL)
1408+ {
1409+ char_attr = hl_combine_attr(
1410+ line_attr != 0 ? line_attr : win_attr, text_prop_attr);
1411+ }
1412+# endif
1413+ else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
1414+ || vcol < fromcol || vcol_prev < fromcol_prev
1415+ || vcol >= tocol))
1416+ {
1417+ // Use line_attr when not in the Visual or 'incsearch' area
1418+ // (area_attr may be 0 when "noinvcur" is set).
1419+ char_attr = line_attr;
1420+ attr_pri = FALSE;
1421+ }
1422+#else
1423+ if (area_attr != 0)
1424+ char_attr = area_attr;
1425+ else if (search_attr != 0)
1426+ char_attr = search_attr;
1427+#endif
1428+ else
1429+ {
1430+ attr_pri = FALSE;
1431+#ifdef FEAT_TEXT_PROP
1432+ if (text_prop_type != NULL)
1433+ {
1434+ if (text_prop_combine)
1435+ char_attr = hl_combine_attr(
1436+ syntax_attr, text_prop_attr);
1437+ else
1438+ char_attr = hl_combine_attr(
1439+ win_attr, text_prop_attr);
1440+ }
1441+ else
1442+#endif
1443+#ifdef FEAT_SYN_HL
1444+ if (has_syntax)
1445+ char_attr = syntax_attr;
1446+ else
1447+#endif
1448+ char_attr = 0;
1449+ }
1450+ }
1451+ if (char_attr == 0)
1452+ char_attr = win_attr;
1453+
1454+ // Get the next character to put on the screen.
1455+
1456+ // The "p_extra" points to the extra stuff that is inserted to
1457+ // represent special characters (non-printable stuff) and other
1458+ // things. When all characters are the same, c_extra is used.
1459+ // If c_final is set, it will compulsorily be used at the end.
1460+ // "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
1461+ // "p_extra[n_extra]".
1462+ // For the '$' of the 'list' option, n_extra == 1, p_extra == "".
1463+ if (n_extra > 0)
1464+ {
1465+ if (c_extra != NUL || (n_extra == 1 && c_final != NUL))
1466+ {
1467+ c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra;
1468+ mb_c = c; // doesn't handle non-utf-8 multi-byte!
1469+ if (enc_utf8 && utf_char2len(c) > 1)
1470+ {
1471+ mb_utf8 = TRUE;
1472+ u8cc[0] = 0;
1473+ c = 0xc0;
1474+ }
1475+ else
1476+ mb_utf8 = FALSE;
1477+ }
1478+ else
1479+ {
1480+ c = *p_extra;
1481+ if (has_mbyte)
1482+ {
1483+ mb_c = c;
1484+ if (enc_utf8)
1485+ {
1486+ // If the UTF-8 character is more than one byte:
1487+ // Decode it into "mb_c".
1488+ mb_l = utfc_ptr2len(p_extra);
1489+ mb_utf8 = FALSE;
1490+ if (mb_l > n_extra)
1491+ mb_l = 1;
1492+ else if (mb_l > 1)
1493+ {
1494+ mb_c = utfc_ptr2char(p_extra, u8cc);
1495+ mb_utf8 = TRUE;
1496+ c = 0xc0;
1497+ }
1498+ }
1499+ else
1500+ {
1501+ // if this is a DBCS character, put it in "mb_c"
1502+ mb_l = MB_BYTE2LEN(c);
1503+ if (mb_l >= n_extra)
1504+ mb_l = 1;
1505+ else if (mb_l > 1)
1506+ mb_c = (c << 8) + p_extra[1];
1507+ }
1508+ if (mb_l == 0) // at the NUL at end-of-line
1509+ mb_l = 1;
1510+
1511+ // If a double-width char doesn't fit display a '>' in the
1512+ // last column.
1513+ if ((
1514+# ifdef FEAT_RIGHTLEFT
1515+ wp->w_p_rl ? (col <= 0) :
1516+# endif
1517+ (col >= wp->w_width - 1))
1518+ && (*mb_char2cells)(mb_c) == 2)
1519+ {
1520+ c = '>';
1521+ mb_c = c;
1522+ mb_l = 1;
1523+ mb_utf8 = FALSE;
1524+ multi_attr = HL_ATTR(HLF_AT);
1525+#ifdef FEAT_SYN_HL
1526+ if (cul_attr)
1527+ multi_attr = hl_combine_attr(multi_attr, cul_attr);
1528+#endif
1529+ // put the pointer back to output the double-width
1530+ // character at the start of the next line.
1531+ ++n_extra;
1532+ --p_extra;
1533+ }
1534+ else
1535+ {
1536+ n_extra -= mb_l - 1;
1537+ p_extra += mb_l - 1;
1538+ }
1539+ }
1540+ ++p_extra;
1541+ }
1542+ --n_extra;
1543+ }
1544+ else
1545+ {
1546+#ifdef FEAT_LINEBREAK
1547+ int c0;
1548+#endif
1549+
1550+ if (p_extra_free != NULL)
1551+ VIM_CLEAR(p_extra_free);
1552+ // Get a character from the line itself.
1553+ c = *ptr;
1554+#ifdef FEAT_LINEBREAK
1555+ c0 = *ptr;
1556+#endif
1557+ if (has_mbyte)
1558+ {
1559+ mb_c = c;
1560+ if (enc_utf8)
1561+ {
1562+ // If the UTF-8 character is more than one byte: Decode it
1563+ // into "mb_c".
1564+ mb_l = utfc_ptr2len(ptr);
1565+ mb_utf8 = FALSE;
1566+ if (mb_l > 1)
1567+ {
1568+ mb_c = utfc_ptr2char(ptr, u8cc);
1569+ // Overlong encoded ASCII or ASCII with composing char
1570+ // is displayed normally, except a NUL.
1571+ if (mb_c < 0x80)
1572+ {
1573+ c = mb_c;
1574+#ifdef FEAT_LINEBREAK
1575+ c0 = mb_c;
1576+#endif
1577+ }
1578+ mb_utf8 = TRUE;
1579+
1580+ // At start of the line we can have a composing char.
1581+ // Draw it as a space with a composing char.
1582+ if (utf_iscomposing(mb_c))
1583+ {
1584+ int i;
1585+
1586+ for (i = Screen_mco - 1; i > 0; --i)
1587+ u8cc[i] = u8cc[i - 1];
1588+ u8cc[0] = mb_c;
1589+ mb_c = ' ';
1590+ }
1591+ }
1592+
1593+ if ((mb_l == 1 && c >= 0x80)
1594+ || (mb_l >= 1 && mb_c == 0)
1595+ || (mb_l > 1 && (!vim_isprintc(mb_c))))
1596+ {
1597+ // Illegal UTF-8 byte: display as <xx>.
1598+ // Non-BMP character : display as ? or fullwidth ?.
1599+ transchar_hex(extra, mb_c);
1600+# ifdef FEAT_RIGHTLEFT
1601+ if (wp->w_p_rl) // reverse
1602+ rl_mirror(extra);
1603+# endif
1604+ p_extra = extra;
1605+ c = *p_extra;
1606+ mb_c = mb_ptr2char_adv(&p_extra);
1607+ mb_utf8 = (c >= 0x80);
1608+ n_extra = (int)STRLEN(p_extra);
1609+ c_extra = NUL;
1610+ c_final = NUL;
1611+ if (area_attr == 0 && search_attr == 0)
1612+ {
1613+ n_attr = n_extra + 1;
1614+ extra_attr = HL_ATTR(HLF_8);
1615+ saved_attr2 = char_attr; // save current attr
1616+ }
1617+ }
1618+ else if (mb_l == 0) // at the NUL at end-of-line
1619+ mb_l = 1;
1620+#ifdef FEAT_ARABIC
1621+ else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
1622+ {
1623+ // Do Arabic shaping.
1624+ int pc, pc1, nc;
1625+ int pcc[MAX_MCO];
1626+
1627+ // The idea of what is the previous and next
1628+ // character depends on 'rightleft'.
1629+ if (wp->w_p_rl)
1630+ {
1631+ pc = prev_c;
1632+ pc1 = prev_c1;
1633+ nc = utf_ptr2char(ptr + mb_l);
1634+ prev_c1 = u8cc[0];
1635+ }
1636+ else
1637+ {
1638+ pc = utfc_ptr2char(ptr + mb_l, pcc);
1639+ nc = prev_c;
1640+ pc1 = pcc[0];
1641+ }
1642+ prev_c = mb_c;
1643+
1644+ mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
1645+ }
1646+ else
1647+ prev_c = mb_c;
1648+#endif
1649+ }
1650+ else // enc_dbcs
1651+ {
1652+ mb_l = MB_BYTE2LEN(c);
1653+ if (mb_l == 0) // at the NUL at end-of-line
1654+ mb_l = 1;
1655+ else if (mb_l > 1)
1656+ {
1657+ // We assume a second byte below 32 is illegal.
1658+ // Hopefully this is OK for all double-byte encodings!
1659+ if (ptr[1] >= 32)
1660+ mb_c = (c << 8) + ptr[1];
1661+ else
1662+ {
1663+ if (ptr[1] == NUL)
1664+ {
1665+ // head byte at end of line
1666+ mb_l = 1;
1667+ transchar_nonprint(extra, c);
1668+ }
1669+ else
1670+ {
1671+ // illegal tail byte
1672+ mb_l = 2;
1673+ STRCPY(extra, "XX");
1674+ }
1675+ p_extra = extra;
1676+ n_extra = (int)STRLEN(extra) - 1;
1677+ c_extra = NUL;
1678+ c_final = NUL;
1679+ c = *p_extra++;
1680+ if (area_attr == 0 && search_attr == 0)
1681+ {
1682+ n_attr = n_extra + 1;
1683+ extra_attr = HL_ATTR(HLF_8);
1684+ saved_attr2 = char_attr; // save current attr
1685+ }
1686+ mb_c = c;
1687+ }
1688+ }
1689+ }
1690+ // If a double-width char doesn't fit display a '>' in the
1691+ // last column; the character is displayed at the start of the
1692+ // next line.
1693+ if ((
1694+# ifdef FEAT_RIGHTLEFT
1695+ wp->w_p_rl ? (col <= 0) :
1696+# endif
1697+ (col >= wp->w_width - 1))
1698+ && (*mb_char2cells)(mb_c) == 2)
1699+ {
1700+ c = '>';
1701+ mb_c = c;
1702+ mb_utf8 = FALSE;
1703+ mb_l = 1;
1704+ multi_attr = HL_ATTR(HLF_AT);
1705+ // Put pointer back so that the character will be
1706+ // displayed at the start of the next line.
1707+ --ptr;
1708+#ifdef FEAT_CONCEAL
1709+ did_decrement_ptr = TRUE;
1710+#endif
1711+ }
1712+ else if (*ptr != NUL)
1713+ ptr += mb_l - 1;
1714+
1715+ // If a double-width char doesn't fit at the left side display
1716+ // a '<' in the first column. Don't do this for unprintable
1717+ // characters.
1718+ if (n_skip > 0 && mb_l > 1 && n_extra == 0)
1719+ {
1720+ n_extra = 1;
1721+ c_extra = MB_FILLER_CHAR;
1722+ c_final = NUL;
1723+ c = ' ';
1724+ if (area_attr == 0 && search_attr == 0)
1725+ {
1726+ n_attr = n_extra + 1;
1727+ extra_attr = HL_ATTR(HLF_AT);
1728+ saved_attr2 = char_attr; // save current attr
1729+ }
1730+ mb_c = c;
1731+ mb_utf8 = FALSE;
1732+ mb_l = 1;
1733+ }
1734+
1735+ }
1736+ ++ptr;
1737+
1738+ if (extra_check)
1739+ {
1740+#ifdef FEAT_SPELL
1741+ int can_spell = TRUE;
1742+#endif
1743+
1744+#ifdef FEAT_TERMINAL
1745+ if (get_term_attr)
1746+ {
1747+ syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol);
1748+
1749+ if (!attr_pri)
1750+ char_attr = syntax_attr;
1751+ else
1752+ char_attr = hl_combine_attr(syntax_attr, char_attr);
1753+ }
1754+#endif
1755+
1756+#ifdef FEAT_SYN_HL
1757+ // Get syntax attribute, unless still at the start of the line
1758+ // (double-wide char that doesn't fit).
1759+ v = (long)(ptr - line);
1760+ if (has_syntax && v > 0)
1761+ {
1762+ // Get the syntax attribute for the character. If there
1763+ // is an error, disable syntax highlighting.
1764+ save_did_emsg = did_emsg;
1765+ did_emsg = FALSE;
1766+
1767+ syntax_attr = get_syntax_attr((colnr_T)v - 1,
1768+# ifdef FEAT_SPELL
1769+ has_spell ? &can_spell :
1770+# endif
1771+ NULL, FALSE);
1772+
1773+ if (did_emsg)
1774+ {
1775+ wp->w_s->b_syn_error = TRUE;
1776+ has_syntax = FALSE;
1777+ syntax_attr = 0;
1778+ }
1779+ else
1780+ did_emsg = save_did_emsg;
1781+
1782+ // combine syntax attribute with 'wincolor'
1783+ if (win_attr != 0)
1784+ syntax_attr = hl_combine_attr(win_attr, syntax_attr);
1785+
1786+# ifdef SYN_TIME_LIMIT
1787+ if (wp->w_s->b_syn_slow)
1788+ has_syntax = FALSE;
1789+# endif
1790+
1791+ // Need to get the line again, a multi-line regexp may
1792+ // have made it invalid.
1793+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
1794+ ptr = line + v;
1795+
1796+# ifdef FEAT_TEXT_PROP
1797+ // Text properties overrule syntax highlighting or combine.
1798+ if (text_prop_attr == 0 || text_prop_combine)
1799+# endif
1800+ {
1801+ int comb_attr = syntax_attr;
1802+# ifdef FEAT_TEXT_PROP
1803+ comb_attr = hl_combine_attr(text_prop_attr, comb_attr);
1804+# endif
1805+ if (!attr_pri)
1806+ {
1807+#ifdef FEAT_SYN_HL
1808+ if (cul_attr)
1809+ char_attr = hl_combine_attr(
1810+ comb_attr, cul_attr);
1811+ else
1812+#endif
1813+ if (line_attr)
1814+ char_attr = hl_combine_attr(
1815+ comb_attr, line_attr);
1816+ else
1817+ char_attr = comb_attr;
1818+ }
1819+ else
1820+ char_attr = hl_combine_attr(comb_attr, char_attr);
1821+ }
1822+# ifdef FEAT_CONCEAL
1823+ // no concealing past the end of the line, it interferes
1824+ // with line highlighting
1825+ if (c == NUL)
1826+ syntax_flags = 0;
1827+ else
1828+ syntax_flags = get_syntax_info(&syntax_seqnr);
1829+# endif
1830+ }
1831+#endif
1832+
1833+#ifdef FEAT_SPELL
1834+ // Check spelling (unless at the end of the line).
1835+ // Only do this when there is no syntax highlighting, the
1836+ // @Spell cluster is not used or the current syntax item
1837+ // contains the @Spell cluster.
1838+ if (has_spell && v >= word_end && v > cur_checked_col)
1839+ {
1840+ spell_attr = 0;
1841+ if (c != 0 && (
1842+# ifdef FEAT_SYN_HL
1843+ !has_syntax ||
1844+# endif
1845+ can_spell))
1846+ {
1847+ char_u *prev_ptr, *p;
1848+ int len;
1849+ hlf_T spell_hlf = HLF_COUNT;
1850+ if (has_mbyte)
1851+ {
1852+ prev_ptr = ptr - mb_l;
1853+ v -= mb_l - 1;
1854+ }
1855+ else
1856+ prev_ptr = ptr - 1;
1857+
1858+ // Use nextline[] if possible, it has the start of the
1859+ // next line concatenated.
1860+ if ((prev_ptr - line) - nextlinecol >= 0)
1861+ p = nextline + (prev_ptr - line) - nextlinecol;
1862+ else
1863+ p = prev_ptr;
1864+ cap_col -= (int)(prev_ptr - line);
1865+ len = spell_check(wp, p, &spell_hlf, &cap_col,
1866+ nochange);
1867+ word_end = v + len;
1868+
1869+ // In Insert mode only highlight a word that
1870+ // doesn't touch the cursor.
1871+ if (spell_hlf != HLF_COUNT
1872+ && (State & INSERT) != 0
1873+ && wp->w_cursor.lnum == lnum
1874+ && wp->w_cursor.col >=
1875+ (colnr_T)(prev_ptr - line)
1876+ && wp->w_cursor.col < (colnr_T)word_end)
1877+ {
1878+ spell_hlf = HLF_COUNT;
1879+ spell_redraw_lnum = lnum;
1880+ }
1881+
1882+ if (spell_hlf == HLF_COUNT && p != prev_ptr
1883+ && (p - nextline) + len > nextline_idx)
1884+ {
1885+ // Remember that the good word continues at the
1886+ // start of the next line.
1887+ checked_lnum = lnum + 1;
1888+ checked_col = (int)((p - nextline) + len - nextline_idx);
1889+ }
1890+
1891+ // Turn index into actual attributes.
1892+ if (spell_hlf != HLF_COUNT)
1893+ spell_attr = highlight_attr[spell_hlf];
1894+
1895+ if (cap_col > 0)
1896+ {
1897+ if (p != prev_ptr
1898+ && (p - nextline) + cap_col >= nextline_idx)
1899+ {
1900+ // Remember that the word in the next line
1901+ // must start with a capital.
1902+ capcol_lnum = lnum + 1;
1903+ cap_col = (int)((p - nextline) + cap_col
1904+ - nextline_idx);
1905+ }
1906+ else
1907+ // Compute the actual column.
1908+ cap_col += (int)(prev_ptr - line);
1909+ }
1910+ }
1911+ }
1912+ if (spell_attr != 0)
1913+ {
1914+ if (!attr_pri)
1915+ char_attr = hl_combine_attr(char_attr, spell_attr);
1916+ else
1917+ char_attr = hl_combine_attr(spell_attr, char_attr);
1918+ }
1919+#endif
1920+#ifdef FEAT_LINEBREAK
1921+ // Found last space before word: check for line break.
1922+ if (wp->w_p_lbr && c0 == c
1923+ && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr))
1924+ {
1925+ int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0;
1926+ char_u *p = ptr - (mb_off + 1);
1927+
1928+ // TODO: is passing p for start of the line OK?
1929+ n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
1930+ NULL) - 1;
1931+ if (c == TAB && n_extra + col > wp->w_width)
1932+# ifdef FEAT_VARTABS
1933+ n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
1934+ wp->w_buffer->b_p_vts_array) - 1;
1935+# else
1936+ n_extra = (int)wp->w_buffer->b_p_ts
1937+ - vcol % (int)wp->w_buffer->b_p_ts - 1;
1938+# endif
1939+
1940+ c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
1941+ c_final = NUL;
1942+ if (VIM_ISWHITE(c))
1943+ {
1944+#ifdef FEAT_CONCEAL
1945+ if (c == TAB)
1946+ // See "Tab alignment" below.
1947+ FIX_FOR_BOGUSCOLS;
1948+#endif
1949+ if (!wp->w_p_list)
1950+ c = ' ';
1951+ }
1952+ }
1953+#endif
1954+
1955+ // 'list': Change char 160 to lcs_nbsp and space to lcs_space.
1956+ // But not when the character is followed by a composing
1957+ // character (use mb_l to check that).
1958+ if (wp->w_p_list
1959+ && ((((c == 160 && mb_l == 1)
1960+ || (mb_utf8
1961+ && ((mb_c == 160 && mb_l == 2)
1962+ || (mb_c == 0x202f && mb_l == 3))))
1963+ && lcs_nbsp)
1964+ || (c == ' '
1965+ && mb_l == 1
1966+ && lcs_space
1967+ && ptr - line <= trailcol)))
1968+ {
1969+ c = (c == ' ') ? lcs_space : lcs_nbsp;
1970+ if (area_attr == 0 && search_attr == 0)
1971+ {
1972+ n_attr = 1;
1973+ extra_attr = HL_ATTR(HLF_8);
1974+ saved_attr2 = char_attr; // save current attr
1975+ }
1976+ mb_c = c;
1977+ if (enc_utf8 && utf_char2len(c) > 1)
1978+ {
1979+ mb_utf8 = TRUE;
1980+ u8cc[0] = 0;
1981+ c = 0xc0;
1982+ }
1983+ else
1984+ mb_utf8 = FALSE;
1985+ }
1986+
1987+ if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
1988+ {
1989+ c = lcs_trail;
1990+ if (!attr_pri)
1991+ {
1992+ n_attr = 1;
1993+ extra_attr = HL_ATTR(HLF_8);
1994+ saved_attr2 = char_attr; // save current attr
1995+ }
1996+ mb_c = c;
1997+ if (enc_utf8 && utf_char2len(c) > 1)
1998+ {
1999+ mb_utf8 = TRUE;
2000+ u8cc[0] = 0;
2001+ c = 0xc0;
2002+ }
2003+ else
2004+ mb_utf8 = FALSE;
2005+ }
2006+ }
2007+
2008+ // Handling of non-printable characters.
2009+ if (!vim_isprintc(c))
2010+ {
2011+ // when getting a character from the file, we may have to
2012+ // turn it into something else on the way to putting it
2013+ // into "ScreenLines".
2014+ if (c == TAB && (!wp->w_p_list || lcs_tab1))
2015+ {
2016+ int tab_len = 0;
2017+ long vcol_adjusted = vcol; // removed showbreak length
2018+#ifdef FEAT_LINEBREAK
2019+ // only adjust the tab_len, when at the first column
2020+ // after the showbreak value was drawn
2021+ if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap)
2022+ vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
2023+#endif
2024+ // tab amount depends on current column
2025+#ifdef FEAT_VARTABS
2026+ tab_len = tabstop_padding(vcol_adjusted,
2027+ wp->w_buffer->b_p_ts,
2028+ wp->w_buffer->b_p_vts_array) - 1;
2029+#else
2030+ tab_len = (int)wp->w_buffer->b_p_ts
2031+ - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
2032+#endif
2033+
2034+#ifdef FEAT_LINEBREAK
2035+ if (!wp->w_p_lbr || !wp->w_p_list)
2036+#endif
2037+ // tab amount depends on current column
2038+ n_extra = tab_len;
2039+#ifdef FEAT_LINEBREAK
2040+ else
2041+ {
2042+ char_u *p;
2043+ int len;
2044+ int i;
2045+ int saved_nextra = n_extra;
2046+
2047+#ifdef FEAT_CONCEAL
2048+ if (vcol_off > 0)
2049+ // there are characters to conceal
2050+ tab_len += vcol_off;
2051+ // boguscols before FIX_FOR_BOGUSCOLS macro from above
2052+ if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
2053+ && n_extra > tab_len)
2054+ tab_len += n_extra - tab_len;
2055+#endif
2056+
2057+ // if n_extra > 0, it gives the number of chars, to
2058+ // use for a tab, else we need to calculate the width
2059+ // for a tab
2060+ len = (tab_len * mb_char2len(lcs_tab2));
2061+ if (n_extra > 0)
2062+ len += n_extra - tab_len;
2063+ c = lcs_tab1;
2064+ p = alloc(len + 1);
2065+ vim_memset(p, ' ', len);
2066+ p[len] = NUL;
2067+ vim_free(p_extra_free);
2068+ p_extra_free = p;
2069+ for (i = 0; i < tab_len; i++)
2070+ {
2071+ int lcs = lcs_tab2;
2072+
2073+ if (*p == NUL)
2074+ {
2075+ tab_len = i;
2076+ break;
2077+ }
2078+
2079+ // if lcs_tab3 is given, need to change the char
2080+ // for tab
2081+ if (lcs_tab3 && i == tab_len - 1)
2082+ lcs = lcs_tab3;
2083+ mb_char2bytes(lcs, p);
2084+ p += mb_char2len(lcs);
2085+ n_extra += mb_char2len(lcs)
2086+ - (saved_nextra > 0 ? 1 : 0);
2087+ }
2088+ p_extra = p_extra_free;
2089+#ifdef FEAT_CONCEAL
2090+ // n_extra will be increased by FIX_FOX_BOGUSCOLS
2091+ // macro below, so need to adjust for that here
2092+ if (vcol_off > 0)
2093+ n_extra -= vcol_off;
2094+#endif
2095+ }
2096+#endif
2097+#ifdef FEAT_CONCEAL
2098+ {
2099+ int vc_saved = vcol_off;
2100+
2101+ // Tab alignment should be identical regardless of
2102+ // 'conceallevel' value. So tab compensates of all
2103+ // previous concealed characters, and thus resets
2104+ // vcol_off and boguscols accumulated so far in the
2105+ // line. Note that the tab can be longer than
2106+ // 'tabstop' when there are concealed characters.
2107+ FIX_FOR_BOGUSCOLS;
2108+
2109+ // Make sure, the highlighting for the tab char will be
2110+ // correctly set further below (effectively reverts the
2111+ // FIX_FOR_BOGSUCOLS macro
2112+ if (n_extra == tab_len + vc_saved && wp->w_p_list
2113+ && lcs_tab1)
2114+ tab_len += vc_saved;
2115+ }
2116+#endif
2117+ mb_utf8 = FALSE; // don't draw as UTF-8
2118+ if (wp->w_p_list)
2119+ {
2120+ c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
2121+#ifdef FEAT_LINEBREAK
2122+ if (wp->w_p_lbr)
2123+ c_extra = NUL; // using p_extra from above
2124+ else
2125+#endif
2126+ c_extra = lcs_tab2;
2127+ c_final = lcs_tab3;
2128+ n_attr = tab_len + 1;
2129+ extra_attr = HL_ATTR(HLF_8);
2130+ saved_attr2 = char_attr; // save current attr
2131+ mb_c = c;
2132+ if (enc_utf8 && utf_char2len(c) > 1)
2133+ {
2134+ mb_utf8 = TRUE;
2135+ u8cc[0] = 0;
2136+ c = 0xc0;
2137+ }
2138+ }
2139+ else
2140+ {
2141+ c_final = NUL;
2142+ c_extra = ' ';
2143+ c = ' ';
2144+ }
2145+ }
2146+ else if (c == NUL
2147+ && (wp->w_p_list
2148+ || ((fromcol >= 0 || fromcol_prev >= 0)
2149+ && tocol > vcol
2150+ && VIsual_mode != Ctrl_V
2151+ && (
2152+# ifdef FEAT_RIGHTLEFT
2153+ wp->w_p_rl ? (col >= 0) :
2154+# endif
2155+ (col < wp->w_width))
2156+ && !(noinvcur
2157+ && lnum == wp->w_cursor.lnum
2158+ && (colnr_T)vcol == wp->w_virtcol)))
2159+ && lcs_eol_one > 0)
2160+ {
2161+ // Display a '$' after the line or highlight an extra
2162+ // character if the line break is included.
2163+#if defined(FEAT_DIFF) || defined(LINE_ATTR)
2164+ // For a diff line the highlighting continues after the
2165+ // "$".
2166+ if (
2167+# ifdef FEAT_DIFF
2168+ diff_hlf == (hlf_T)0
2169+# ifdef LINE_ATTR
2170+ &&
2171+# endif
2172+# endif
2173+# ifdef LINE_ATTR
2174+ line_attr == 0
2175+# endif
2176+ )
2177+#endif
2178+ {
2179+ // In virtualedit, visual selections may extend
2180+ // beyond end of line.
2181+ if (area_highlighting && virtual_active()
2182+ && tocol != MAXCOL && vcol < tocol)
2183+ n_extra = 0;
2184+ else
2185+ {
2186+ p_extra = at_end_str;
2187+ n_extra = 1;
2188+ c_extra = NUL;
2189+ c_final = NUL;
2190+ }
2191+ }
2192+ if (wp->w_p_list && lcs_eol > 0)
2193+ c = lcs_eol;
2194+ else
2195+ c = ' ';
2196+ lcs_eol_one = -1;
2197+ --ptr; // put it back at the NUL
2198+ if (!attr_pri)
2199+ {
2200+ extra_attr = HL_ATTR(HLF_AT);
2201+ n_attr = 1;
2202+ }
2203+ mb_c = c;
2204+ if (enc_utf8 && utf_char2len(c) > 1)
2205+ {
2206+ mb_utf8 = TRUE;
2207+ u8cc[0] = 0;
2208+ c = 0xc0;
2209+ }
2210+ else
2211+ mb_utf8 = FALSE; // don't draw as UTF-8
2212+ }
2213+ else if (c != NUL)
2214+ {
2215+ p_extra = transchar(c);
2216+ if (n_extra == 0)
2217+ n_extra = byte2cells(c) - 1;
2218+#ifdef FEAT_RIGHTLEFT
2219+ if ((dy_flags & DY_UHEX) && wp->w_p_rl)
2220+ rl_mirror(p_extra); // reverse "<12>"
2221+#endif
2222+ c_extra = NUL;
2223+ c_final = NUL;
2224+#ifdef FEAT_LINEBREAK
2225+ if (wp->w_p_lbr)
2226+ {
2227+ char_u *p;
2228+
2229+ c = *p_extra;
2230+ p = alloc(n_extra + 1);
2231+ vim_memset(p, ' ', n_extra);
2232+ STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
2233+ p[n_extra] = NUL;
2234+ vim_free(p_extra_free);
2235+ p_extra_free = p_extra = p;
2236+ }
2237+ else
2238+#endif
2239+ {
2240+ n_extra = byte2cells(c) - 1;
2241+ c = *p_extra++;
2242+ }
2243+ if (!attr_pri)
2244+ {
2245+ n_attr = n_extra + 1;
2246+ extra_attr = HL_ATTR(HLF_8);
2247+ saved_attr2 = char_attr; // save current attr
2248+ }
2249+ mb_utf8 = FALSE; // don't draw as UTF-8
2250+ }
2251+ else if (VIsual_active
2252+ && (VIsual_mode == Ctrl_V
2253+ || VIsual_mode == 'v')
2254+ && virtual_active()
2255+ && tocol != MAXCOL
2256+ && vcol < tocol
2257+ && (
2258+#ifdef FEAT_RIGHTLEFT
2259+ wp->w_p_rl ? (col >= 0) :
2260+#endif
2261+ (col < wp->w_width)))
2262+ {
2263+ c = ' ';
2264+ --ptr; // put it back at the NUL
2265+ }
2266+#if defined(LINE_ATTR)
2267+ else if ((
2268+# ifdef FEAT_DIFF
2269+ diff_hlf != (hlf_T)0 ||
2270+# endif
2271+# ifdef FEAT_TERMINAL
2272+ win_attr != 0 ||
2273+# endif
2274+ line_attr != 0
2275+ ) && (
2276+# ifdef FEAT_RIGHTLEFT
2277+ wp->w_p_rl ? (col >= 0) :
2278+# endif
2279+ (col
2280+# ifdef FEAT_CONCEAL
2281+ - boguscols
2282+# endif
2283+ < wp->w_width)))
2284+ {
2285+ // Highlight until the right side of the window
2286+ c = ' ';
2287+ --ptr; // put it back at the NUL
2288+
2289+ // Remember we do the char for line highlighting.
2290+ ++did_line_attr;
2291+
2292+ // don't do search HL for the rest of the line
2293+ if (line_attr != 0 && char_attr == search_attr
2294+ && (did_line_attr > 1
2295+ || (wp->w_p_list && lcs_eol > 0)))
2296+ char_attr = line_attr;
2297+# ifdef FEAT_DIFF
2298+ if (diff_hlf == HLF_TXD)
2299+ {
2300+ diff_hlf = HLF_CHD;
2301+ if (vi_attr == 0 || char_attr != vi_attr)
2302+ {
2303+ char_attr = HL_ATTR(diff_hlf);
2304+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum
2305+ && wp->w_p_culopt_flags != CULOPT_NBR
2306+ && (!cul_screenline
2307+ || (vcol >= left_curline_col
2308+ && vcol <= right_curline_col)))
2309+ char_attr = hl_combine_attr(
2310+ char_attr, HL_ATTR(HLF_CUL));
2311+ }
2312+ }
2313+# endif
2314+# ifdef FEAT_TERMINAL
2315+ if (win_attr != 0)
2316+ {
2317+ char_attr = win_attr;
2318+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
2319+ {
2320+ if (!cul_screenline || (vcol >= left_curline_col
2321+ && vcol <= right_curline_col))
2322+ char_attr = hl_combine_attr(
2323+ char_attr, HL_ATTR(HLF_CUL));
2324+ }
2325+ else if (line_attr)
2326+ char_attr = hl_combine_attr(char_attr, line_attr);
2327+ }
2328+# endif
2329+ }
2330+#endif
2331+ }
2332+
2333+#ifdef FEAT_CONCEAL
2334+ if ( wp->w_p_cole > 0
2335+ && (wp != curwin || lnum != wp->w_cursor.lnum ||
2336+ conceal_cursor_line(wp))
2337+ && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
2338+ && !(lnum_in_visual_area
2339+ && vim_strchr(wp->w_p_cocu, 'v') == NULL))
2340+ {
2341+ char_attr = conceal_attr;
2342+ if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
2343+ && (syn_get_sub_char() != NUL || match_conc
2344+ || wp->w_p_cole == 1)
2345+ && wp->w_p_cole != 3)
2346+ {
2347+ // First time at this concealed item: display one
2348+ // character.
2349+ if (match_conc)
2350+ c = match_conc;
2351+ else if (syn_get_sub_char() != NUL)
2352+ c = syn_get_sub_char();
2353+ else if (lcs_conceal != NUL)
2354+ c = lcs_conceal;
2355+ else
2356+ c = ' ';
2357+
2358+ prev_syntax_id = syntax_seqnr;
2359+
2360+ if (n_extra > 0)
2361+ vcol_off += n_extra;
2362+ vcol += n_extra;
2363+ if (wp->w_p_wrap && n_extra > 0)
2364+ {
2365+# ifdef FEAT_RIGHTLEFT
2366+ if (wp->w_p_rl)
2367+ {
2368+ col -= n_extra;
2369+ boguscols -= n_extra;
2370+ }
2371+ else
2372+# endif
2373+ {
2374+ boguscols += n_extra;
2375+ col += n_extra;
2376+ }
2377+ }
2378+ n_extra = 0;
2379+ n_attr = 0;
2380+ }
2381+ else if (n_skip == 0)
2382+ {
2383+ is_concealing = TRUE;
2384+ n_skip = 1;
2385+ }
2386+ mb_c = c;
2387+ if (enc_utf8 && utf_char2len(c) > 1)
2388+ {
2389+ mb_utf8 = TRUE;
2390+ u8cc[0] = 0;
2391+ c = 0xc0;
2392+ }
2393+ else
2394+ mb_utf8 = FALSE; // don't draw as UTF-8
2395+ }
2396+ else
2397+ {
2398+ prev_syntax_id = 0;
2399+ is_concealing = FALSE;
2400+ }
2401+
2402+ if (n_skip > 0 && did_decrement_ptr)
2403+ // not showing the '>', put pointer back to avoid getting stuck
2404+ ++ptr;
2405+
2406+#endif // FEAT_CONCEAL
2407+ }
2408+
2409+#ifdef FEAT_CONCEAL
2410+ // In the cursor line and we may be concealing characters: correct
2411+ // the cursor column when we reach its position.
2412+ if (!did_wcol && draw_state == WL_LINE
2413+ && wp == curwin && lnum == wp->w_cursor.lnum
2414+ && conceal_cursor_line(wp)
2415+ && (int)wp->w_virtcol <= vcol + n_skip)
2416+ {
2417+# ifdef FEAT_RIGHTLEFT
2418+ if (wp->w_p_rl)
2419+ wp->w_wcol = wp->w_width - col + boguscols - 1;
2420+ else
2421+# endif
2422+ wp->w_wcol = col - boguscols;
2423+ wp->w_wrow = row;
2424+ did_wcol = TRUE;
2425+ curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
2426+ }
2427+#endif
2428+
2429+ // Don't override visual selection highlighting.
2430+ if (n_attr > 0
2431+ && draw_state == WL_LINE
2432+ && !attr_pri)
2433+ {
2434+#ifdef LINE_ATTR
2435+ if (line_attr)
2436+ char_attr = hl_combine_attr(extra_attr, line_attr);
2437+ else
2438+#endif
2439+ char_attr = extra_attr;
2440+ }
2441+
2442+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
2443+ // XIM don't send preedit_start and preedit_end, but they send
2444+ // preedit_changed and commit. Thus Vim can't set "im_is_active", use
2445+ // im_is_preediting() here.
2446+ if (p_imst == IM_ON_THE_SPOT
2447+ && xic != NULL
2448+ && lnum == wp->w_cursor.lnum
2449+ && (State & INSERT)
2450+ && !p_imdisable
2451+ && im_is_preediting()
2452+ && draw_state == WL_LINE)
2453+ {
2454+ colnr_T tcol;
2455+
2456+ if (preedit_end_col == MAXCOL)
2457+ getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
2458+ else
2459+ tcol = preedit_end_col;
2460+ if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
2461+ {
2462+ if (feedback_old_attr < 0)
2463+ {
2464+ feedback_col = 0;
2465+ feedback_old_attr = char_attr;
2466+ }
2467+ char_attr = im_get_feedback_attr(feedback_col);
2468+ if (char_attr < 0)
2469+ char_attr = feedback_old_attr;
2470+ feedback_col++;
2471+ }
2472+ else if (feedback_old_attr >= 0)
2473+ {
2474+ char_attr = feedback_old_attr;
2475+ feedback_old_attr = -1;
2476+ feedback_col = 0;
2477+ }
2478+ }
2479+#endif
2480+ // Handle the case where we are in column 0 but not on the first
2481+ // character of the line and the user wants us to show us a
2482+ // special character (via 'listchars' option "precedes:<char>".
2483+ if (lcs_prec_todo != NUL
2484+ && wp->w_p_list
2485+ && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
2486+#ifdef FEAT_DIFF
2487+ && filler_todo <= 0
2488+#endif
2489+ && draw_state > WL_NR
2490+ && c != NUL)
2491+ {
2492+ c = lcs_prec;
2493+ lcs_prec_todo = NUL;
2494+ if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
2495+ {
2496+ // Double-width character being overwritten by the "precedes"
2497+ // character, need to fill up half the character.
2498+ c_extra = MB_FILLER_CHAR;
2499+ c_final = NUL;
2500+ n_extra = 1;
2501+ n_attr = 2;
2502+ extra_attr = HL_ATTR(HLF_AT);
2503+ }
2504+ mb_c = c;
2505+ if (enc_utf8 && utf_char2len(c) > 1)
2506+ {
2507+ mb_utf8 = TRUE;
2508+ u8cc[0] = 0;
2509+ c = 0xc0;
2510+ }
2511+ else
2512+ mb_utf8 = FALSE; // don't draw as UTF-8
2513+ if (!attr_pri)
2514+ {
2515+ saved_attr3 = char_attr; // save current attr
2516+ char_attr = HL_ATTR(HLF_AT); // later copied to char_attr
2517+ n_attr3 = 1;
2518+ }
2519+ }
2520+
2521+ // At end of the text line or just after the last character.
2522+ if ((c == NUL
2523+#if defined(LINE_ATTR)
2524+ || did_line_attr == 1
2525+#endif
2526+ ) && eol_hl_off == 0)
2527+ {
2528+#ifdef FEAT_SEARCH_EXTRA
2529+ // flag to indicate whether prevcol equals startcol of search_hl or
2530+ // one of the matches
2531+ int prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl,
2532+ (long)(ptr - line) - (c == NUL));
2533+#endif
2534+ // Invert at least one char, used for Visual and empty line or
2535+ // highlight match at end of line. If it's beyond the last
2536+ // char on the screen, just overwrite that one (tricky!) Not
2537+ // needed when a '$' was displayed for 'list'.
2538+ if (lcs_eol == lcs_eol_one
2539+ && ((area_attr != 0 && vcol == fromcol
2540+ && (VIsual_mode != Ctrl_V
2541+ || lnum == VIsual.lnum
2542+ || lnum == curwin->w_cursor.lnum)
2543+ && c == NUL)
2544+#ifdef FEAT_SEARCH_EXTRA
2545+ // highlight 'hlsearch' match at end of line
2546+ || (prevcol_hl_flag
2547+# ifdef FEAT_SYN_HL
2548+ && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
2549+ && !(wp == curwin && VIsual_active))
2550+# endif
2551+# ifdef FEAT_DIFF
2552+ && diff_hlf == (hlf_T)0
2553+# endif
2554+# if defined(LINE_ATTR)
2555+ && did_line_attr <= 1
2556+# endif
2557+ )
2558+#endif
2559+ ))
2560+ {
2561+ int n = 0;
2562+
2563+#ifdef FEAT_RIGHTLEFT
2564+ if (wp->w_p_rl)
2565+ {
2566+ if (col < 0)
2567+ n = 1;
2568+ }
2569+ else
2570+#endif
2571+ {
2572+ if (col >= wp->w_width)
2573+ n = -1;
2574+ }
2575+ if (n != 0)
2576+ {
2577+ // At the window boundary, highlight the last character
2578+ // instead (better than nothing).
2579+ off += n;
2580+ col += n;
2581+ }
2582+ else
2583+ {
2584+ // Add a blank character to highlight.
2585+ ScreenLines[off] = ' ';
2586+ if (enc_utf8)
2587+ ScreenLinesUC[off] = 0;
2588+ }
2589+#ifdef FEAT_SEARCH_EXTRA
2590+ if (area_attr == 0)
2591+ {
2592+ // Use attributes from match with highest priority among
2593+ // 'search_hl' and the match list.
2594+ get_search_match_hl(wp, &screen_search_hl,
2595+ (long)(ptr - line), &char_attr);
2596+ }
2597+#endif
2598+ ScreenAttrs[off] = char_attr;
2599+#ifdef FEAT_RIGHTLEFT
2600+ if (wp->w_p_rl)
2601+ {
2602+ --col;
2603+ --off;
2604+ }
2605+ else
2606+#endif
2607+ {
2608+ ++col;
2609+ ++off;
2610+ }
2611+ ++vcol;
2612+ eol_hl_off = 1;
2613+ }
2614+ }
2615+
2616+ // At end of the text line.
2617+ if (c == NUL)
2618+ {
2619+#ifdef FEAT_SYN_HL
2620+ // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line.
2621+ if (wp->w_p_wrap)
2622+ v = wp->w_skipcol;
2623+ else
2624+ v = wp->w_leftcol;
2625+
2626+ // check if line ends before left margin
2627+ if (vcol < v + col - win_col_off(wp))
2628+ vcol = v + col - win_col_off(wp);
2629+#ifdef FEAT_CONCEAL
2630+ // Get rid of the boguscols now, we want to draw until the right
2631+ // edge for 'cursorcolumn'.
2632+ col -= boguscols;
2633+ boguscols = 0;
2634+#endif
2635+
2636+ if (draw_color_col)
2637+ draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
2638+
2639+ if (((wp->w_p_cuc
2640+ && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
2641+ && (int)wp->w_virtcol <
2642+ wp->w_width * (row - startrow + 1) + v
2643+ && lnum != wp->w_cursor.lnum)
2644+ || draw_color_col
2645+ || win_attr != 0)
2646+# ifdef FEAT_RIGHTLEFT
2647+ && !wp->w_p_rl
2648+# endif
2649+ )
2650+ {
2651+ int rightmost_vcol = 0;
2652+ int i;
2653+
2654+ if (wp->w_p_cuc)
2655+ rightmost_vcol = wp->w_virtcol;
2656+ if (draw_color_col)
2657+ // determine rightmost colorcolumn to possibly draw
2658+ for (i = 0; color_cols[i] >= 0; ++i)
2659+ if (rightmost_vcol < color_cols[i])
2660+ rightmost_vcol = color_cols[i];
2661+
2662+ while (col < wp->w_width)
2663+ {
2664+ ScreenLines[off] = ' ';
2665+ if (enc_utf8)
2666+ ScreenLinesUC[off] = 0;
2667+ ++col;
2668+ if (draw_color_col)
2669+ draw_color_col = advance_color_col(VCOL_HLC,
2670+ &color_cols);
2671+
2672+ if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol)
2673+ ScreenAttrs[off++] = HL_ATTR(HLF_CUC);
2674+ else if (draw_color_col && VCOL_HLC == *color_cols)
2675+ ScreenAttrs[off++] = HL_ATTR(HLF_MC);
2676+ else
2677+ ScreenAttrs[off++] = win_attr;
2678+
2679+ if (VCOL_HLC >= rightmost_vcol && win_attr == 0)
2680+ break;
2681+
2682+ ++vcol;
2683+ }
2684+ }
2685+#endif
2686+
2687+ screen_line(screen_row, wp->w_wincol, col,
2688+ (int)wp->w_width, screen_line_flags);
2689+ row++;
2690+
2691+ // Update w_cline_height and w_cline_folded if the cursor line was
2692+ // updated (saves a call to plines() later).
2693+ if (wp == curwin && lnum == curwin->w_cursor.lnum)
2694+ {
2695+ curwin->w_cline_row = startrow;
2696+ curwin->w_cline_height = row - startrow;
2697+#ifdef FEAT_FOLDING
2698+ curwin->w_cline_folded = FALSE;
2699+#endif
2700+ curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
2701+ }
2702+
2703+ break;
2704+ }
2705+
2706+ // Show "extends" character from 'listchars' if beyond the line end and
2707+ // 'list' is set.
2708+ if (lcs_ext != NUL
2709+ && wp->w_p_list
2710+ && !wp->w_p_wrap
2711+#ifdef FEAT_DIFF
2712+ && filler_todo <= 0
2713+#endif
2714+ && (
2715+#ifdef FEAT_RIGHTLEFT
2716+ wp->w_p_rl ? col == 0 :
2717+#endif
2718+ col == wp->w_width - 1)
2719+ && (*ptr != NUL
2720+ || (wp->w_p_list && lcs_eol_one > 0)
2721+ || (n_extra && (c_extra != NUL || *p_extra != NUL))))
2722+ {
2723+ c = lcs_ext;
2724+ char_attr = HL_ATTR(HLF_AT);
2725+ mb_c = c;
2726+ if (enc_utf8 && utf_char2len(c) > 1)
2727+ {
2728+ mb_utf8 = TRUE;
2729+ u8cc[0] = 0;
2730+ c = 0xc0;
2731+ }
2732+ else
2733+ mb_utf8 = FALSE;
2734+ }
2735+
2736+#ifdef FEAT_SYN_HL
2737+ // advance to the next 'colorcolumn'
2738+ if (draw_color_col)
2739+ draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
2740+
2741+ // Highlight the cursor column if 'cursorcolumn' is set. But don't
2742+ // highlight the cursor position itself.
2743+ // Also highlight the 'colorcolumn' if it is different than
2744+ // 'cursorcolumn'
2745+ vcol_save_attr = -1;
2746+ if (draw_state == WL_LINE && !lnum_in_visual_area
2747+ && search_attr == 0 && area_attr == 0)
2748+ {
2749+ if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
2750+ && lnum != wp->w_cursor.lnum)
2751+ {
2752+ vcol_save_attr = char_attr;
2753+ char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC));
2754+ }
2755+ else if (draw_color_col && VCOL_HLC == *color_cols)
2756+ {
2757+ vcol_save_attr = char_attr;
2758+ char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC));
2759+ }
2760+ }
2761+#endif
2762+
2763+ // Store character to be displayed.
2764+ // Skip characters that are left of the screen for 'nowrap'.
2765+ vcol_prev = vcol;
2766+ if (draw_state < WL_LINE || n_skip <= 0)
2767+ {
2768+ // Store the character.
2769+#if defined(FEAT_RIGHTLEFT)
2770+ if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
2771+ {
2772+ // A double-wide character is: put first halve in left cell.
2773+ --off;
2774+ --col;
2775+ }
2776+#endif
2777+ ScreenLines[off] = c;
2778+ if (enc_dbcs == DBCS_JPNU)
2779+ {
2780+ if ((mb_c & 0xff00) == 0x8e00)
2781+ ScreenLines[off] = 0x8e;
2782+ ScreenLines2[off] = mb_c & 0xff;
2783+ }
2784+ else if (enc_utf8)
2785+ {
2786+ if (mb_utf8)
2787+ {
2788+ int i;
2789+
2790+ ScreenLinesUC[off] = mb_c;
2791+ if ((c & 0xff) == 0)
2792+ ScreenLines[off] = 0x80; // avoid storing zero
2793+ for (i = 0; i < Screen_mco; ++i)
2794+ {
2795+ ScreenLinesC[i][off] = u8cc[i];
2796+ if (u8cc[i] == 0)
2797+ break;
2798+ }
2799+ }
2800+ else
2801+ ScreenLinesUC[off] = 0;
2802+ }
2803+ if (multi_attr)
2804+ {
2805+ ScreenAttrs[off] = multi_attr;
2806+ multi_attr = 0;
2807+ }
2808+ else
2809+ ScreenAttrs[off] = char_attr;
2810+
2811+ if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
2812+ {
2813+ // Need to fill two screen columns.
2814+ ++off;
2815+ ++col;
2816+ if (enc_utf8)
2817+ // UTF-8: Put a 0 in the second screen char.
2818+ ScreenLines[off] = 0;
2819+ else
2820+ // DBCS: Put second byte in the second screen char.
2821+ ScreenLines[off] = mb_c & 0xff;
2822+ if (draw_state > WL_NR
2823+#ifdef FEAT_DIFF
2824+ && filler_todo <= 0
2825+#endif
2826+ )
2827+ ++vcol;
2828+ // When "tocol" is halfway a character, set it to the end of
2829+ // the character, otherwise highlighting won't stop.
2830+ if (tocol == vcol)
2831+ ++tocol;
2832+#ifdef FEAT_RIGHTLEFT
2833+ if (wp->w_p_rl)
2834+ {
2835+ // now it's time to backup one cell
2836+ --off;
2837+ --col;
2838+ }
2839+#endif
2840+ }
2841+#ifdef FEAT_RIGHTLEFT
2842+ if (wp->w_p_rl)
2843+ {
2844+ --off;
2845+ --col;
2846+ }
2847+ else
2848+#endif
2849+ {
2850+ ++off;
2851+ ++col;
2852+ }
2853+ }
2854+#ifdef FEAT_CONCEAL
2855+ else if (wp->w_p_cole > 0 && is_concealing)
2856+ {
2857+ --n_skip;
2858+ ++vcol_off;
2859+ if (n_extra > 0)
2860+ vcol_off += n_extra;
2861+ if (wp->w_p_wrap)
2862+ {
2863+ // Special voodoo required if 'wrap' is on.
2864+ //
2865+ // Advance the column indicator to force the line
2866+ // drawing to wrap early. This will make the line
2867+ // take up the same screen space when parts are concealed,
2868+ // so that cursor line computations aren't messed up.
2869+ //
2870+ // To avoid the fictitious advance of 'col' causing
2871+ // trailing junk to be written out of the screen line
2872+ // we are building, 'boguscols' keeps track of the number
2873+ // of bad columns we have advanced.
2874+ if (n_extra > 0)
2875+ {
2876+ vcol += n_extra;
2877+# ifdef FEAT_RIGHTLEFT
2878+ if (wp->w_p_rl)
2879+ {
2880+ col -= n_extra;
2881+ boguscols -= n_extra;
2882+ }
2883+ else
2884+# endif
2885+ {
2886+ col += n_extra;
2887+ boguscols += n_extra;
2888+ }
2889+ n_extra = 0;
2890+ n_attr = 0;
2891+ }
2892+
2893+
2894+ if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
2895+ {
2896+ // Need to fill two screen columns.
2897+# ifdef FEAT_RIGHTLEFT
2898+ if (wp->w_p_rl)
2899+ {
2900+ --boguscols;
2901+ --col;
2902+ }
2903+ else
2904+# endif
2905+ {
2906+ ++boguscols;
2907+ ++col;
2908+ }
2909+ }
2910+
2911+# ifdef FEAT_RIGHTLEFT
2912+ if (wp->w_p_rl)
2913+ {
2914+ --boguscols;
2915+ --col;
2916+ }
2917+ else
2918+# endif
2919+ {
2920+ ++boguscols;
2921+ ++col;
2922+ }
2923+ }
2924+ else
2925+ {
2926+ if (n_extra > 0)
2927+ {
2928+ vcol += n_extra;
2929+ n_extra = 0;
2930+ n_attr = 0;
2931+ }
2932+ }
2933+
2934+ }
2935+#endif // FEAT_CONCEAL
2936+ else
2937+ --n_skip;
2938+
2939+ // Only advance the "vcol" when after the 'number' or 'relativenumber'
2940+ // column.
2941+ if (draw_state > WL_NR
2942+#ifdef FEAT_DIFF
2943+ && filler_todo <= 0
2944+#endif
2945+ )
2946+ ++vcol;
2947+
2948+#ifdef FEAT_SYN_HL
2949+ if (vcol_save_attr >= 0)
2950+ char_attr = vcol_save_attr;
2951+#endif
2952+
2953+ // restore attributes after "predeces" in 'listchars'
2954+ if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
2955+ char_attr = saved_attr3;
2956+
2957+ // restore attributes after last 'listchars' or 'number' char
2958+ if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
2959+ char_attr = saved_attr2;
2960+
2961+ // At end of screen line and there is more to come: Display the line
2962+ // so far. If there is no more to display it is caught above.
2963+ if ((
2964+#ifdef FEAT_RIGHTLEFT
2965+ wp->w_p_rl ? (col < 0) :
2966+#endif
2967+ (col >= wp->w_width))
2968+ && (*ptr != NUL
2969+#ifdef FEAT_DIFF
2970+ || filler_todo > 0
2971+#endif
2972+ || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
2973+ || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
2974+ )
2975+ {
2976+#ifdef FEAT_CONCEAL
2977+ screen_line(screen_row, wp->w_wincol, col - boguscols,
2978+ (int)wp->w_width, screen_line_flags);
2979+ boguscols = 0;
2980+#else
2981+ screen_line(screen_row, wp->w_wincol, col,
2982+ (int)wp->w_width, screen_line_flags);
2983+#endif
2984+ ++row;
2985+ ++screen_row;
2986+
2987+ // When not wrapping and finished diff lines, or when displayed
2988+ // '$' and highlighting until last column, break here.
2989+ if ((!wp->w_p_wrap
2990+#ifdef FEAT_DIFF
2991+ && filler_todo <= 0
2992+#endif
2993+ ) || lcs_eol_one == -1)
2994+ break;
2995+
2996+ // When the window is too narrow draw all "@" lines.
2997+ if (draw_state != WL_LINE
2998+#ifdef FEAT_DIFF
2999+ && filler_todo <= 0
3000+#endif
3001+ )
3002+ {
3003+ win_draw_end(wp, '@', ' ', TRUE, row, wp->w_height, HLF_AT);
3004+ draw_vsep_win(wp, row);
3005+ row = endrow;
3006+ }
3007+
3008+ // When line got too long for screen break here.
3009+ if (row == endrow)
3010+ {
3011+ ++row;
3012+ break;
3013+ }
3014+
3015+ if (screen_cur_row == screen_row - 1
3016+#ifdef FEAT_DIFF
3017+ && filler_todo <= 0
3018+#endif
3019+ && wp->w_width == Columns)
3020+ {
3021+ // Remember that the line wraps, used for modeless copy.
3022+ LineWraps[screen_row - 1] = TRUE;
3023+
3024+ // Special trick to make copy/paste of wrapped lines work with
3025+ // xterm/screen: write an extra character beyond the end of
3026+ // the line. This will work with all terminal types
3027+ // (regardless of the xn,am settings).
3028+ // Only do this on a fast tty.
3029+ // Only do this if the cursor is on the current line
3030+ // (something has been written in it).
3031+ // Don't do this for the GUI.
3032+ // Don't do this for double-width characters.
3033+ // Don't do this for a window not at the right screen border.
3034+ if (p_tf
3035+#ifdef FEAT_GUI
3036+ && !gui.in_use
3037+#endif
3038+ && !(has_mbyte
3039+ && ((*mb_off2cells)(LineOffset[screen_row],
3040+ LineOffset[screen_row] + screen_Columns)
3041+ == 2
3042+ || (*mb_off2cells)(LineOffset[screen_row - 1]
3043+ + (int)Columns - 2,
3044+ LineOffset[screen_row] + screen_Columns)
3045+ == 2)))
3046+ {
3047+ // First make sure we are at the end of the screen line,
3048+ // then output the same character again to let the
3049+ // terminal know about the wrap. If the terminal doesn't
3050+ // auto-wrap, we overwrite the character.
3051+ if (screen_cur_col != wp->w_width)
3052+ screen_char(LineOffset[screen_row - 1]
3053+ + (unsigned)Columns - 1,
3054+ screen_row - 1, (int)(Columns - 1));
3055+
3056+ // When there is a multi-byte character, just output a
3057+ // space to keep it simple.
3058+ if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
3059+ screen_row - 1] + (Columns - 1)]) > 1)
3060+ out_char(' ');
3061+ else
3062+ out_char(ScreenLines[LineOffset[screen_row - 1]
3063+ + (Columns - 1)]);
3064+ // force a redraw of the first char on the next line
3065+ ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
3066+ screen_start(); // don't know where cursor is now
3067+ }
3068+ }
3069+
3070+ col = 0;
3071+ off = (unsigned)(current_ScreenLine - ScreenLines);
3072+#ifdef FEAT_RIGHTLEFT
3073+ if (wp->w_p_rl)
3074+ {
3075+ col = wp->w_width - 1; // col is not used if breaking!
3076+ off += col;
3077+ }
3078+#endif
3079+
3080+ // reset the drawing state for the start of a wrapped line
3081+ draw_state = WL_START;
3082+ saved_n_extra = n_extra;
3083+ saved_p_extra = p_extra;
3084+ saved_c_extra = c_extra;
3085+ saved_c_final = c_final;
3086+#ifdef FEAT_SYN_HL
3087+ if (!(cul_screenline
3088+# ifdef FEAT_DIFF
3089+ && diff_hlf == (hlf_T)0)
3090+# endif
3091+ )
3092+ saved_char_attr = char_attr;
3093+ else
3094+#endif
3095+ saved_char_attr = 0;
3096+ n_extra = 0;
3097+ lcs_prec_todo = lcs_prec;
3098+#ifdef FEAT_LINEBREAK
3099+# ifdef FEAT_DIFF
3100+ if (filler_todo <= 0)
3101+# endif
3102+ need_showbreak = TRUE;
3103+#endif
3104+#ifdef FEAT_DIFF
3105+ --filler_todo;
3106+ // When the filler lines are actually below the last line of the
3107+ // file, don't draw the line itself, break here.
3108+ if (filler_todo == 0 && wp->w_botfill)
3109+ break;
3110+#endif
3111+ }
3112+
3113+ } // for every character in the line
3114+
3115+#ifdef FEAT_SPELL
3116+ // After an empty line check first word for capital.
3117+ if (*skipwhite(line) == NUL)
3118+ {
3119+ capcol_lnum = lnum + 1;
3120+ cap_col = 0;
3121+ }
3122+#endif
3123+#ifdef FEAT_TEXT_PROP
3124+ vim_free(text_props);
3125+ vim_free(text_prop_idxs);
3126+#endif
3127+
3128+ vim_free(p_extra_free);
3129+ return row;
3130+}
3131+
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/drawscreen.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/drawscreen.c Thu Sep 19 23:15:05 2019 +0200
@@ -0,0 +1,3112 @@
1+/* vi:set ts=8 sts=4 sw=4 noet:
2+ *
3+ * VIM - Vi IMproved by Bram Moolenaar
4+ *
5+ * Do ":help uganda" in Vim to read copying and usage conditions.
6+ * Do ":help credits" in Vim to see a list of people who contributed.
7+ * See README.txt for an overview of the Vim source code.
8+ */
9+
10+/*
11+ * drawscreen.c: Code for updating all the windows on the screen.
12+ * This is the top level, drawline.c is the middle and screen.c the lower
13+ * level.
14+ *
15+ * update_screen() is the function that updates all windows and status lines.
16+ * It is called form the main loop when must_redraw is non-zero. It may be
17+ * called from other places when an immediate screen update is needed.
18+ *
19+ * The part of the buffer that is displayed in a window is set with:
20+ * - w_topline (first buffer line in window)
21+ * - w_topfill (filler lines above the first line)
22+ * - w_leftcol (leftmost window cell in window),
23+ * - w_skipcol (skipped window cells of first line)
24+ *
25+ * Commands that only move the cursor around in a window, do not need to take
26+ * action to update the display. The main loop will check if w_topline is
27+ * valid and update it (scroll the window) when needed.
28+ *
29+ * Commands that scroll a window change w_topline and must call
30+ * check_cursor() to move the cursor into the visible part of the window, and
31+ * call redraw_later(VALID) to have the window displayed by update_screen()
32+ * later.
33+ *
34+ * Commands that change text in the buffer must call changed_bytes() or
35+ * changed_lines() to mark the area that changed and will require updating
36+ * later. The main loop will call update_screen(), which will update each
37+ * window that shows the changed buffer. This assumes text above the change
38+ * can remain displayed as it is. Text after the change may need updating for
39+ * scrolling, folding and syntax highlighting.
40+ *
41+ * Commands that change how a window is displayed (e.g., setting 'list') or
42+ * invalidate the contents of a window in another way (e.g., change fold
43+ * settings), must call redraw_later(NOT_VALID) to have the whole window
44+ * redisplayed by update_screen() later.
45+ *
46+ * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
47+ * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
48+ * buffer redisplayed by update_screen() later.
49+ *
50+ * Commands that change highlighting and possibly cause a scroll too must call
51+ * redraw_later(SOME_VALID) to update the whole window but still use scrolling
52+ * to avoid redrawing everything. But the length of displayed lines must not
53+ * change, use NOT_VALID then.
54+ *
55+ * Commands that move the window position must call redraw_later(NOT_VALID).
56+ * TODO: should minimize redrawing by scrolling when possible.
57+ *
58+ * Commands that change everything (e.g., resizing the screen) must call
59+ * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
60+ *
61+ * Things that are handled indirectly:
62+ * - When messages scroll the screen up, msg_scrolled will be set and
63+ * update_screen() called to redraw.
64+ */
65+
66+#include "vim.h"
67+
68+static void win_update(win_T *wp);
69+#ifdef FEAT_STL_OPT
70+static void redraw_custom_statusline(win_T *wp);
71+#endif
72+
73+/*
74+ * Based on the current value of curwin->w_topline, transfer a screenfull
75+ * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
76+ * Return OK when the screen was updated, FAIL if it was not done.
77+ */
78+ int
79+update_screen(int type_arg)
80+{
81+ int type = type_arg;
82+ win_T *wp;
83+ static int did_intro = FALSE;
84+#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
85+ int did_one;
86+#endif
87+#ifdef FEAT_GUI
88+ int did_undraw = FALSE;
89+ int gui_cursor_col = 0;
90+ int gui_cursor_row = 0;
91+#endif
92+ int no_update = FALSE;
93+
94+ // Don't do anything if the screen structures are (not yet) valid.
95+ if (!screen_valid(TRUE))
96+ return FAIL;
97+
98+ if (type == VALID_NO_UPDATE)
99+ {
100+ no_update = TRUE;
101+ type = 0;
102+ }
103+
104+#ifdef FEAT_EVAL
105+ {
106+ buf_T *buf;
107+
108+ // Before updating the screen, notify any listeners of changed text.
109+ FOR_ALL_BUFFERS(buf)
110+ invoke_listeners(buf);
111+ }
112+#endif
113+
114+#ifdef FEAT_DIFF
115+ // May have postponed updating diffs.
116+ if (need_diff_redraw)
117+ diff_redraw(TRUE);
118+#endif
119+
120+ if (must_redraw)
121+ {
122+ if (type < must_redraw) // use maximal type
123+ type = must_redraw;
124+
125+ // must_redraw is reset here, so that when we run into some weird
126+ // reason to redraw while busy redrawing (e.g., asynchronous
127+ // scrolling), or update_topline() in win_update() will cause a
128+ // scroll, the screen will be redrawn later or in win_update().
129+ must_redraw = 0;
130+ }
131+
132+ // May need to update w_lines[].
133+ if (curwin->w_lines_valid == 0 && type < NOT_VALID
134+#ifdef FEAT_TERMINAL
135+ && !term_do_update_window(curwin)
136+#endif
137+ )
138+ type = NOT_VALID;
139+
140+ // Postpone the redrawing when it's not needed and when being called
141+ // recursively.
142+ if (!redrawing() || updating_screen)
143+ {
144+ redraw_later(type); // remember type for next time
145+ must_redraw = type;
146+ if (type > INVERTED_ALL)
147+ curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now
148+ return FAIL;
149+ }
150+ updating_screen = TRUE;
151+
152+#ifdef FEAT_TEXT_PROP
153+ // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot
154+ // in some windows.
155+ may_update_popup_mask(type);
156+#endif
157+
158+#ifdef FEAT_SYN_HL
159+ ++display_tick; // let syntax code know we're in a next round of
160+ // display updating
161+#endif
162+ if (no_update)
163+ ++no_win_do_lines_ins;
164+
165+ // if the screen was scrolled up when displaying a message, scroll it down
166+ if (msg_scrolled)
167+ {
168+ clear_cmdline = TRUE;
169+ if (msg_scrolled > Rows - 5) // clearing is faster
170+ type = CLEAR;
171+ else if (type != CLEAR)
172+ {
173+ check_for_delay(FALSE);
174+ if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
175+ == FAIL)
176+ type = CLEAR;
177+ FOR_ALL_WINDOWS(wp)
178+ {
179+ if (wp->w_winrow < msg_scrolled)
180+ {
181+ if (W_WINROW(wp) + wp->w_height > msg_scrolled
182+ && wp->w_redr_type < REDRAW_TOP
183+ && wp->w_lines_valid > 0
184+ && wp->w_topline == wp->w_lines[0].wl_lnum)
185+ {
186+ wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
187+ wp->w_redr_type = REDRAW_TOP;
188+ }
189+ else
190+ {
191+ wp->w_redr_type = NOT_VALID;
192+ if (W_WINROW(wp) + wp->w_height + wp->w_status_height
193+ <= msg_scrolled)
194+ wp->w_redr_status = TRUE;
195+ }
196+ }
197+ }
198+ if (!no_update)
199+ redraw_cmdline = TRUE;
200+ redraw_tabline = TRUE;
201+ }
202+ msg_scrolled = 0;
203+ need_wait_return = FALSE;
204+ }
205+
206+ // reset cmdline_row now (may have been changed temporarily)
207+ compute_cmdrow();
208+
209+ // Check for changed highlighting
210+ if (need_highlight_changed)
211+ highlight_changed();
212+
213+ if (type == CLEAR) // first clear screen
214+ {
215+ screenclear(); // will reset clear_cmdline
216+ type = NOT_VALID;
217+ // must_redraw may be set indirectly, avoid another redraw later
218+ must_redraw = 0;
219+ }
220+
221+ if (clear_cmdline) // going to clear cmdline (done below)
222+ check_for_delay(FALSE);
223+
224+#ifdef FEAT_LINEBREAK
225+ // Force redraw when width of 'number' or 'relativenumber' column
226+ // changes.
227+ if (curwin->w_redr_type < NOT_VALID
228+ && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
229+ ? number_width(curwin) : 0))
230+ curwin->w_redr_type = NOT_VALID;
231+#endif
232+
233+ // Only start redrawing if there is really something to do.
234+ if (type == INVERTED)
235+ update_curswant();
236+ if (curwin->w_redr_type < type
237+ && !((type == VALID
238+ && curwin->w_lines[0].wl_valid
239+#ifdef FEAT_DIFF
240+ && curwin->w_topfill == curwin->w_old_topfill
241+ && curwin->w_botfill == curwin->w_old_botfill
242+#endif
243+ && curwin->w_topline == curwin->w_lines[0].wl_lnum)
244+ || (type == INVERTED
245+ && VIsual_active
246+ && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
247+ && curwin->w_old_visual_mode == VIsual_mode
248+ && (curwin->w_valid & VALID_VIRTCOL)
249+ && curwin->w_old_curswant == curwin->w_curswant)
250+ ))
251+ curwin->w_redr_type = type;
252+
253+ // Redraw the tab pages line if needed.
254+ if (redraw_tabline || type >= NOT_VALID)
255+ draw_tabline();
256+
257+#ifdef FEAT_SYN_HL
258+ // Correct stored syntax highlighting info for changes in each displayed
259+ // buffer. Each buffer must only be done once.
260+ FOR_ALL_WINDOWS(wp)
261+ {
262+ if (wp->w_buffer->b_mod_set)
263+ {
264+ win_T *wwp;
265+
266+ // Check if we already did this buffer.
267+ for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
268+ if (wwp->w_buffer == wp->w_buffer)
269+ break;
270+ if (wwp == wp && syntax_present(wp))
271+ syn_stack_apply_changes(wp->w_buffer);
272+ }
273+ }
274+#endif
275+
276+ // Go from top to bottom through the windows, redrawing the ones that need
277+ // it.
278+#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
279+ did_one = FALSE;
280+#endif
281+#ifdef FEAT_SEARCH_EXTRA
282+ screen_search_hl.rm.regprog = NULL;
283+#endif
284+ FOR_ALL_WINDOWS(wp)
285+ {
286+ if (wp->w_redr_type != 0)
287+ {
288+ cursor_off();
289+#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
290+ if (!did_one)
291+ {
292+ did_one = TRUE;
293+# ifdef FEAT_SEARCH_EXTRA
294+ start_search_hl();
295+# endif
296+# ifdef FEAT_CLIPBOARD
297+ // When Visual area changed, may have to update selection.
298+ if (clip_star.available && clip_isautosel_star())
299+ clip_update_selection(&clip_star);
300+ if (clip_plus.available && clip_isautosel_plus())
301+ clip_update_selection(&clip_plus);
302+# endif
303+#ifdef FEAT_GUI
304+ // Remove the cursor before starting to do anything, because
305+ // scrolling may make it difficult to redraw the text under
306+ // it.
307+ if (gui.in_use && wp == curwin)
308+ {
309+ gui_cursor_col = gui.cursor_col;
310+ gui_cursor_row = gui.cursor_row;
311+ gui_undraw_cursor();
312+ did_undraw = TRUE;
313+ }
314+#endif
315+ }
316+#endif
317+ win_update(wp);
318+ }
319+
320+ // redraw status line after the window to minimize cursor movement
321+ if (wp->w_redr_status)
322+ {
323+ cursor_off();
324+ win_redr_status(wp, TRUE); // any popup menu will be redrawn below
325+ }
326+ }
327+#if defined(FEAT_SEARCH_EXTRA)
328+ end_search_hl();
329+#endif
330+ // May need to redraw the popup menu.
331+ pum_may_redraw();
332+
333+ // Reset b_mod_set flags. Going through all windows is probably faster
334+ // than going through all buffers (there could be many buffers).
335+ FOR_ALL_WINDOWS(wp)
336+ wp->w_buffer->b_mod_set = FALSE;
337+
338+#ifdef FEAT_TEXT_PROP
339+ // Display popup windows on top of the windows and command line.
340+ update_popups(win_update);
341+#endif
342+
343+ after_updating_screen(TRUE);
344+
345+ // Clear or redraw the command line. Done last, because scrolling may
346+ // mess up the command line.
347+ if (clear_cmdline || redraw_cmdline || redraw_mode)
348+ showmode();
349+
350+ if (no_update)
351+ --no_win_do_lines_ins;
352+
353+ // May put up an introductory message when not editing a file
354+ if (!did_intro)
355+ maybe_intro_message();
356+ did_intro = TRUE;
357+
358+#ifdef FEAT_GUI
359+ // Redraw the cursor and update the scrollbars when all screen updating is
360+ // done.
361+ if (gui.in_use)
362+ {
363+ if (did_undraw && !gui_mch_is_blink_off())
364+ {
365+ mch_disable_flush();
366+ out_flush(); // required before updating the cursor
367+ mch_enable_flush();
368+
369+ // Put the GUI position where the cursor was, gui_update_cursor()
370+ // uses that.
371+ gui.col = gui_cursor_col;
372+ gui.row = gui_cursor_row;
373+ gui.col = mb_fix_col(gui.col, gui.row);
374+ gui_update_cursor(FALSE, FALSE);
375+ gui_may_flush();
376+ screen_cur_col = gui.col;
377+ screen_cur_row = gui.row;
378+ }
379+ else
380+ out_flush();
381+ gui_update_scrollbars(FALSE);
382+ }
383+#endif
384+ return OK;
385+}
386+
387+/*
388+ * Redraw the status line of window wp.
389+ *
390+ * If inversion is possible we use it. Else '=' characters are used.
391+ * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is
392+ * displayed.
393+ */
394+ void
395+win_redr_status(win_T *wp, int ignore_pum UNUSED)
396+{
397+ int row;
398+ char_u *p;
399+ int len;
400+ int fillchar;
401+ int attr;
402+ int this_ru_col;
403+ static int busy = FALSE;
404+
405+ // It's possible to get here recursively when 'statusline' (indirectly)
406+ // invokes ":redrawstatus". Simply ignore the call then.
407+ if (busy)
408+ return;
409+ busy = TRUE;
410+
411+ wp->w_redr_status = FALSE;
412+ if (wp->w_status_height == 0)
413+ {
414+ // no status line, can only be last window
415+ redraw_cmdline = TRUE;
416+ }
417+ else if (!redrawing()
418+ // don't update status line when popup menu is visible and may be
419+ // drawn over it, unless it will be redrawn later
420+ || (!ignore_pum && pum_visible()))
421+ {
422+ // Don't redraw right now, do it later.
423+ wp->w_redr_status = TRUE;
424+ }
425+#ifdef FEAT_STL_OPT
426+ else if (*p_stl != NUL || *wp->w_p_stl != NUL)
427+ {
428+ // redraw custom status line
429+ redraw_custom_statusline(wp);
430+ }
431+#endif
432+ else
433+ {
434+ fillchar = fillchar_status(&attr, wp);
435+
436+ get_trans_bufname(wp->w_buffer);
437+ p = NameBuff;
438+ len = (int)STRLEN(p);
439+
440+ if (bt_help(wp->w_buffer)
441+#ifdef FEAT_QUICKFIX
442+ || wp->w_p_pvw
443+#endif
444+ || bufIsChanged(wp->w_buffer)
445+ || wp->w_buffer->b_p_ro)
446+ *(p + len++) = ' ';
447+ if (bt_help(wp->w_buffer))
448+ {
449+ STRCPY(p + len, _("[Help]"));
450+ len += (int)STRLEN(p + len);
451+ }
452+#ifdef FEAT_QUICKFIX
453+ if (wp->w_p_pvw)
454+ {
455+ STRCPY(p + len, _("[Preview]"));
456+ len += (int)STRLEN(p + len);
457+ }
458+#endif
459+ if (bufIsChanged(wp->w_buffer)
460+#ifdef FEAT_TERMINAL
461+ && !bt_terminal(wp->w_buffer)
462+#endif
463+ )
464+ {
465+ STRCPY(p + len, "[+]");
466+ len += 3;
467+ }
468+ if (wp->w_buffer->b_p_ro)
469+ {
470+ STRCPY(p + len, _("[RO]"));
471+ len += (int)STRLEN(p + len);
472+ }
473+
474+ this_ru_col = ru_col - (Columns - wp->w_width);
475+ if (this_ru_col < (wp->w_width + 1) / 2)
476+ this_ru_col = (wp->w_width + 1) / 2;
477+ if (this_ru_col <= 1)
478+ {
479+ p = (char_u *)"<"; // No room for file name!
480+ len = 1;
481+ }
482+ else if (has_mbyte)
483+ {
484+ int clen = 0, i;
485+
486+ // Count total number of display cells.
487+ clen = mb_string2cells(p, -1);
488+
489+ // Find first character that will fit.
490+ // Going from start to end is much faster for DBCS.
491+ for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
492+ i += (*mb_ptr2len)(p + i))
493+ clen -= (*mb_ptr2cells)(p + i);
494+ len = clen;
495+ if (i > 0)
496+ {
497+ p = p + i - 1;
498+ *p = '<';
499+ ++len;
500+ }
501+
502+ }
503+ else if (len > this_ru_col - 1)
504+ {
505+ p += len - (this_ru_col - 1);
506+ *p = '<';
507+ len = this_ru_col - 1;
508+ }
509+
510+ row = W_WINROW(wp) + wp->w_height;
511+ screen_puts(p, row, wp->w_wincol, attr);
512+ screen_fill(row, row + 1, len + wp->w_wincol,
513+ this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
514+
515+ if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
516+ && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
517+ screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
518+ - 1 + wp->w_wincol), attr);
519+
520+#ifdef FEAT_CMDL_INFO
521+ win_redr_ruler(wp, TRUE, ignore_pum);
522+#endif
523+ }
524+
525+ /*
526+ * May need to draw the character below the vertical separator.
527+ */
528+ if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
529+ {
530+ if (stl_connected(wp))
531+ fillchar = fillchar_status(&attr, wp);
532+ else
533+ fillchar = fillchar_vsep(&attr);
534+ screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
535+ attr);
536+ }
537+ busy = FALSE;
538+}
539+
540+#ifdef FEAT_STL_OPT
541+/*
542+ * Redraw the status line according to 'statusline' and take care of any
543+ * errors encountered.
544+ */
545+ static void
546+redraw_custom_statusline(win_T *wp)
547+{
548+ static int entered = FALSE;
549+ int saved_did_emsg = did_emsg;
550+
551+ // When called recursively return. This can happen when the statusline
552+ // contains an expression that triggers a redraw.
553+ if (entered)
554+ return;
555+ entered = TRUE;
556+
557+ did_emsg = FALSE;
558+ win_redr_custom(wp, FALSE);
559+ if (did_emsg)
560+ {
561+ // When there is an error disable the statusline, otherwise the
562+ // display is messed up with errors and a redraw triggers the problem
563+ // again and again.
564+ set_string_option_direct((char_u *)"statusline", -1,
565+ (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
566+ ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
567+ }
568+ did_emsg |= saved_did_emsg;
569+ entered = FALSE;
570+}
571+#endif
572+
573+/*
574+ * Show current status info in ruler and various other places
575+ * If always is FALSE, only show ruler if position has changed.
576+ */
577+ void
578+showruler(int always)
579+{
580+ if (!always && !redrawing())
581+ return;
582+ if (pum_visible())
583+ {
584+ // Don't redraw right now, do it later.
585+ curwin->w_redr_status = TRUE;
586+ return;
587+ }
588+#if defined(FEAT_STL_OPT)
589+ if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
590+ redraw_custom_statusline(curwin);
591+ else
592+#endif
593+#ifdef FEAT_CMDL_INFO
594+ win_redr_ruler(curwin, always, FALSE);
595+#endif
596+
597+#ifdef FEAT_TITLE
598+ if (need_maketitle
599+# ifdef FEAT_STL_OPT
600+ || (p_icon && (stl_syntax & STL_IN_ICON))
601+ || (p_title && (stl_syntax & STL_IN_TITLE))
602+# endif
603+ )
604+ maketitle();
605+#endif
606+ // Redraw the tab pages line if needed.
607+ if (redraw_tabline)
608+ draw_tabline();
609+}
610+
611+#if defined(FEAT_CMDL_INFO) || defined(PROTO)
612+ void
613+win_redr_ruler(win_T *wp, int always, int ignore_pum)
614+{
615+#define RULER_BUF_LEN 70
616+ char_u buffer[RULER_BUF_LEN];
617+ int row;
618+ int fillchar;
619+ int attr;
620+ int empty_line = FALSE;
621+ colnr_T virtcol;
622+ int i;
623+ size_t len;
624+ int o;
625+ int this_ru_col;
626+ int off = 0;
627+ int width;
628+
629+ // If 'ruler' off or redrawing disabled, don't do anything
630+ if (!p_ru)
631+ return;
632+
633+ /*
634+ * Check if cursor.lnum is valid, since win_redr_ruler() may be called
635+ * after deleting lines, before cursor.lnum is corrected.
636+ */
637+ if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
638+ return;
639+
640+ // Don't draw the ruler while doing insert-completion, it might overwrite
641+ // the (long) mode message.
642+ if (wp == lastwin && lastwin->w_status_height == 0)
643+ if (edit_submode != NULL)
644+ return;
645+ // Don't draw the ruler when the popup menu is visible, it may overlap.
646+ // Except when the popup menu will be redrawn anyway.
647+ if (!ignore_pum && pum_visible())
648+ return;
649+
650+#ifdef FEAT_STL_OPT
651+ if (*p_ruf)
652+ {
653+ int save_called_emsg = called_emsg;
654+
655+ called_emsg = FALSE;
656+ win_redr_custom(wp, TRUE);
657+ if (called_emsg)
658+ set_string_option_direct((char_u *)"rulerformat", -1,
659+ (char_u *)"", OPT_FREE, SID_ERROR);
660+ called_emsg |= save_called_emsg;
661+ return;
662+ }
663+#endif
664+
665+ /*
666+ * Check if not in Insert mode and the line is empty (will show "0-1").
667+ */
668+ if (!(State & INSERT)
669+ && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
670+ empty_line = TRUE;
671+
672+ /*
673+ * Only draw the ruler when something changed.
674+ */
675+ validate_virtcol_win(wp);
676+ if ( redraw_cmdline
677+ || always
678+ || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
679+ || wp->w_cursor.col != wp->w_ru_cursor.col
680+ || wp->w_virtcol != wp->w_ru_virtcol
681+ || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
682+ || wp->w_topline != wp->w_ru_topline
683+ || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
684+#ifdef FEAT_DIFF
685+ || wp->w_topfill != wp->w_ru_topfill
686+#endif
687+ || empty_line != wp->w_ru_empty)
688+ {
689+ cursor_off();
690+ if (wp->w_status_height)
691+ {
692+ row = W_WINROW(wp) + wp->w_height;
693+ fillchar = fillchar_status(&attr, wp);
694+ off = wp->w_wincol;
695+ width = wp->w_width;
696+ }
697+ else
698+ {
699+ row = Rows - 1;
700+ fillchar = ' ';
701+ attr = 0;
702+ width = Columns;
703+ off = 0;
704+ }
705+
706+ // In list mode virtcol needs to be recomputed
707+ virtcol = wp->w_virtcol;
708+ if (wp->w_p_list && lcs_tab1 == NUL)
709+ {
710+ wp->w_p_list = FALSE;
711+ getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
712+ wp->w_p_list = TRUE;
713+ }
714+
715+ /*
716+ * Some sprintfs return the length, some return a pointer.
717+ * To avoid portability problems we use strlen() here.
718+ */
719+ vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
720+ (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
721+ ? 0L
722+ : (long)(wp->w_cursor.lnum));
723+ len = STRLEN(buffer);
724+ col_print(buffer + len, RULER_BUF_LEN - len,
725+ empty_line ? 0 : (int)wp->w_cursor.col + 1,
726+ (int)virtcol + 1);
727+
728+ /*
729+ * Add a "50%" if there is room for it.
730+ * On the last line, don't print in the last column (scrolls the
731+ * screen up on some terminals).
732+ */
733+ i = (int)STRLEN(buffer);
734+ get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
735+ o = i + vim_strsize(buffer + i + 1);
736+ if (wp->w_status_height == 0) // can't use last char of screen
737+ ++o;
738+ this_ru_col = ru_col - (Columns - width);
739+ if (this_ru_col < 0)
740+ this_ru_col = 0;
741+ // Never use more than half the window/screen width, leave the other
742+ // half for the filename.
743+ if (this_ru_col < (width + 1) / 2)
744+ this_ru_col = (width + 1) / 2;
745+ if (this_ru_col + o < width)
746+ {
747+ // need at least 3 chars left for get_rel_pos() + NUL
748+ while (this_ru_col + o < width && RULER_BUF_LEN > i + 4)
749+ {
750+ if (has_mbyte)
751+ i += (*mb_char2bytes)(fillchar, buffer + i);
752+ else
753+ buffer[i++] = fillchar;
754+ ++o;
755+ }
756+ get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
757+ }
758+ // Truncate at window boundary.
759+ if (has_mbyte)
760+ {
761+ o = 0;
762+ for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
763+ {
764+ o += (*mb_ptr2cells)(buffer + i);
765+ if (this_ru_col + o > width)
766+ {
767+ buffer[i] = NUL;
768+ break;
769+ }
770+ }
771+ }
772+ else if (this_ru_col + (int)STRLEN(buffer) > width)
773+ buffer[width - this_ru_col] = NUL;
774+
775+ screen_puts(buffer, row, this_ru_col + off, attr);
776+ i = redraw_cmdline;
777+ screen_fill(row, row + 1,
778+ this_ru_col + off + (int)STRLEN(buffer),
779+ (int)(off + width),
780+ fillchar, fillchar, attr);
781+ // don't redraw the cmdline because of showing the ruler
782+ redraw_cmdline = i;
783+ wp->w_ru_cursor = wp->w_cursor;
784+ wp->w_ru_virtcol = wp->w_virtcol;
785+ wp->w_ru_empty = empty_line;
786+ wp->w_ru_topline = wp->w_topline;
787+ wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
788+#ifdef FEAT_DIFF
789+ wp->w_ru_topfill = wp->w_topfill;
790+#endif
791+ }
792+}
793+#endif
794+
795+/*
796+ * To be called when "updating_screen" was set before and now the postponed
797+ * side effects may take place.
798+ */
799+ void
800+after_updating_screen(int may_resize_shell UNUSED)
801+{
802+ updating_screen = FALSE;
803+#ifdef FEAT_GUI
804+ if (may_resize_shell)
805+ gui_may_resize_shell();
806+#endif
807+#ifdef FEAT_TERMINAL
808+ term_check_channel_closed_recently();
809+#endif
810+
811+#ifdef HAVE_DROP_FILE
812+ // If handle_drop() was called while updating_screen was TRUE need to
813+ // handle the drop now.
814+ handle_any_postponed_drop();
815+#endif
816+}
817+
818+/*
819+ * Update all windows that are editing the current buffer.
820+ */
821+ void
822+update_curbuf(int type)
823+{
824+ redraw_curbuf_later(type);
825+ update_screen(type);
826+}
827+
828+#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
829+/*
830+ * Copy "text" to ScreenLines using "attr".
831+ * Returns the next screen column.
832+ */
833+ static int
834+text_to_screenline(win_T *wp, char_u *text, int col)
835+{
836+ int off = (int)(current_ScreenLine - ScreenLines);
837+
838+ if (has_mbyte)
839+ {
840+ int cells;
841+ int u8c, u8cc[MAX_MCO];
842+ int i;
843+ int idx;
844+ int c_len;
845+ char_u *p;
846+# ifdef FEAT_ARABIC
847+ int prev_c = 0; // previous Arabic character
848+ int prev_c1 = 0; // first composing char for prev_c
849+# endif
850+
851+# ifdef FEAT_RIGHTLEFT
852+ if (wp->w_p_rl)
853+ idx = off;
854+ else
855+# endif
856+ idx = off + col;
857+
858+ // Store multibyte characters in ScreenLines[] et al. correctly.
859+ for (p = text; *p != NUL; )
860+ {
861+ cells = (*mb_ptr2cells)(p);
862+ c_len = (*mb_ptr2len)(p);
863+ if (col + cells > wp->w_width
864+# ifdef FEAT_RIGHTLEFT
865+ - (wp->w_p_rl ? col : 0)
866+# endif
867+ )
868+ break;
869+ ScreenLines[idx] = *p;
870+ if (enc_utf8)
871+ {
872+ u8c = utfc_ptr2char(p, u8cc);
873+ if (*p < 0x80 && u8cc[0] == 0)
874+ {
875+ ScreenLinesUC[idx] = 0;
876+#ifdef FEAT_ARABIC
877+ prev_c = u8c;
878+#endif
879+ }
880+ else
881+ {
882+#ifdef FEAT_ARABIC
883+ if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
884+ {
885+ // Do Arabic shaping.
886+ int pc, pc1, nc;
887+ int pcc[MAX_MCO];
888+ int firstbyte = *p;
889+
890+ // The idea of what is the previous and next
891+ // character depends on 'rightleft'.
892+ if (wp->w_p_rl)
893+ {
894+ pc = prev_c;
895+ pc1 = prev_c1;
896+ nc = utf_ptr2char(p + c_len);
897+ prev_c1 = u8cc[0];
898+ }
899+ else
900+ {
901+ pc = utfc_ptr2char(p + c_len, pcc);
902+ nc = prev_c;
903+ pc1 = pcc[0];
904+ }
905+ prev_c = u8c;
906+
907+ u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
908+ pc, pc1, nc);
909+ ScreenLines[idx] = firstbyte;
910+ }
911+ else
912+ prev_c = u8c;
913+#endif
914+ // Non-BMP character: display as ? or fullwidth ?.
915+ ScreenLinesUC[idx] = u8c;
916+ for (i = 0; i < Screen_mco; ++i)
917+ {
918+ ScreenLinesC[i][idx] = u8cc[i];
919+ if (u8cc[i] == 0)
920+ break;
921+ }
922+ }
923+ if (cells > 1)
924+ ScreenLines[idx + 1] = 0;
925+ }
926+ else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
927+ // double-byte single width character
928+ ScreenLines2[idx] = p[1];
929+ else if (cells > 1)
930+ // double-width character
931+ ScreenLines[idx + 1] = p[1];
932+ col += cells;
933+ idx += cells;
934+ p += c_len;
935+ }
936+ }
937+ else
938+ {
939+ int len = (int)STRLEN(text);
940+
941+ if (len > wp->w_width - col)
942+ len = wp->w_width - col;
943+ if (len > 0)
944+ {
945+#ifdef FEAT_RIGHTLEFT
946+ if (wp->w_p_rl)
947+ mch_memmove(current_ScreenLine, text, len);
948+ else
949+#endif
950+ mch_memmove(current_ScreenLine + col, text, len);
951+ col += len;
952+ }
953+ }
954+ return col;
955+}
956+#endif
957+
958+#ifdef FEAT_MENU
959+/*
960+ * Draw the window toolbar.
961+ */
962+ static void
963+redraw_win_toolbar(win_T *wp)
964+{
965+ vimmenu_T *menu;
966+ int item_idx = 0;
967+ int item_count = 0;
968+ int col = 0;
969+ int next_col;
970+ int off = (int)(current_ScreenLine - ScreenLines);
971+ int fill_attr = syn_name2attr((char_u *)"ToolbarLine");
972+ int button_attr = syn_name2attr((char_u *)"ToolbarButton");
973+
974+ vim_free(wp->w_winbar_items);
975+ for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next)
976+ ++item_count;
977+ wp->w_winbar_items = ALLOC_CLEAR_MULT(winbar_item_T, item_count + 1);
978+
979+ // TODO: use fewer spaces if there is not enough room
980+ for (menu = wp->w_winbar->children;
981+ menu != NULL && col < wp->w_width; menu = menu->next)
982+ {
983+ space_to_screenline(off + col, fill_attr);
984+ if (++col >= wp->w_width)
985+ break;
986+ if (col > 1)
987+ {
988+ space_to_screenline(off + col, fill_attr);
989+ if (++col >= wp->w_width)
990+ break;
991+ }
992+
993+ wp->w_winbar_items[item_idx].wb_startcol = col;
994+ space_to_screenline(off + col, button_attr);
995+ if (++col >= wp->w_width)
996+ break;
997+
998+ next_col = text_to_screenline(wp, menu->name, col);
999+ while (col < next_col)
1000+ {
1001+ ScreenAttrs[off + col] = button_attr;
1002+ ++col;
1003+ }
1004+ wp->w_winbar_items[item_idx].wb_endcol = col;
1005+ wp->w_winbar_items[item_idx].wb_menu = menu;
1006+ ++item_idx;
1007+
1008+ if (col >= wp->w_width)
1009+ break;
1010+ space_to_screenline(off + col, button_attr);
1011+ ++col;
1012+ }
1013+ while (col < wp->w_width)
1014+ {
1015+ space_to_screenline(off + col, fill_attr);
1016+ ++col;
1017+ }
1018+ wp->w_winbar_items[item_idx].wb_menu = NULL; // end marker
1019+
1020+ screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
1021+ (int)wp->w_width, 0);
1022+}
1023+#endif
1024+
1025+#if defined(FEAT_FOLDING) || defined(PROTO)
1026+/*
1027+ * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
1028+ */
1029+ static void
1030+copy_text_attr(
1031+ int off,
1032+ char_u *buf,
1033+ int len,
1034+ int attr)
1035+{
1036+ int i;
1037+
1038+ mch_memmove(ScreenLines + off, buf, (size_t)len);
1039+ if (enc_utf8)
1040+ vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
1041+ for (i = 0; i < len; ++i)
1042+ ScreenAttrs[off + i] = attr;
1043+}
1044+
1045+/*
1046+ * Display one folded line.
1047+ */
1048+ static void
1049+fold_line(
1050+ win_T *wp,
1051+ long fold_count,
1052+ foldinfo_T *foldinfo,
1053+ linenr_T lnum,
1054+ int row)
1055+{
1056+ char_u buf[FOLD_TEXT_LEN];
1057+ pos_T *top, *bot;
1058+ linenr_T lnume = lnum + fold_count - 1;
1059+ int len;
1060+ char_u *text;
1061+ int fdc;
1062+ int col;
1063+ int txtcol;
1064+ int off = (int)(current_ScreenLine - ScreenLines);
1065+ int ri;
1066+
1067+ // Build the fold line:
1068+ // 1. Add the cmdwin_type for the command-line window
1069+ // 2. Add the 'foldcolumn'
1070+ // 3. Add the 'number' or 'relativenumber' column
1071+ // 4. Compose the text
1072+ // 5. Add the text
1073+ // 6. set highlighting for the Visual area an other text
1074+ col = 0;
1075+
1076+ // 1. Add the cmdwin_type for the command-line window
1077+ // Ignores 'rightleft', this window is never right-left.
1078+#ifdef FEAT_CMDWIN
1079+ if (cmdwin_type != 0 && wp == curwin)
1080+ {
1081+ ScreenLines[off] = cmdwin_type;
1082+ ScreenAttrs[off] = HL_ATTR(HLF_AT);
1083+ if (enc_utf8)
1084+ ScreenLinesUC[off] = 0;
1085+ ++col;
1086+ }
1087+#endif
1088+
1089+ // 2. Add the 'foldcolumn'
1090+ // Reduce the width when there is not enough space.
1091+ fdc = compute_foldcolumn(wp, col);
1092+ if (fdc > 0)
1093+ {
1094+ fill_foldcolumn(buf, wp, TRUE, lnum);
1095+#ifdef FEAT_RIGHTLEFT
1096+ if (wp->w_p_rl)
1097+ {
1098+ int i;
1099+
1100+ copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
1101+ HL_ATTR(HLF_FC));
1102+ // reverse the fold column
1103+ for (i = 0; i < fdc; ++i)
1104+ ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
1105+ }
1106+ else
1107+#endif
1108+ copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
1109+ col += fdc;
1110+ }
1111+
1112+#ifdef FEAT_RIGHTLEFT
1113+# define RL_MEMSET(p, v, l) \
1114+ do { \
1115+ if (wp->w_p_rl) \
1116+ for (ri = 0; ri < l; ++ri) \
1117+ ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \
1118+ else \
1119+ for (ri = 0; ri < l; ++ri) \
1120+ ScreenAttrs[off + (p) + ri] = v; \
1121+ } while (0)
1122+#else
1123+# define RL_MEMSET(p, v, l) \
1124+ do { \
1125+ for (ri = 0; ri < l; ++ri) \
1126+ ScreenAttrs[off + (p) + ri] = v; \
1127+ } while (0)
1128+#endif
1129+
1130+ // Set all attributes of the 'number' or 'relativenumber' column and the
1131+ // text
1132+ RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
1133+
1134+#ifdef FEAT_SIGNS
1135+ // If signs are being displayed, add two spaces.
1136+ if (signcolumn_on(wp))
1137+ {
1138+ len = wp->w_width - col;
1139+ if (len > 0)
1140+ {
1141+ if (len > 2)
1142+ len = 2;
1143+# ifdef FEAT_RIGHTLEFT
1144+ if (wp->w_p_rl)
1145+ // the line number isn't reversed
1146+ copy_text_attr(off + wp->w_width - len - col,
1147+ (char_u *)" ", len, HL_ATTR(HLF_FL));
1148+ else
1149+# endif
1150+ copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL));
1151+ col += len;
1152+ }
1153+ }
1154+#endif
1155+
1156+ // 3. Add the 'number' or 'relativenumber' column
1157+ if (wp->w_p_nu || wp->w_p_rnu)
1158+ {
1159+ len = wp->w_width - col;
1160+ if (len > 0)
1161+ {
1162+ int w = number_width(wp);
1163+ long num;
1164+ char *fmt = "%*ld ";
1165+
1166+ if (len > w + 1)
1167+ len = w + 1;
1168+
1169+ if (wp->w_p_nu && !wp->w_p_rnu)
1170+ // 'number' + 'norelativenumber'
1171+ num = (long)lnum;
1172+ else
1173+ {
1174+ // 'relativenumber', don't use negative numbers
1175+ num = labs((long)get_cursor_rel_lnum(wp, lnum));
1176+ if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
1177+ {
1178+ // 'number' + 'relativenumber': cursor line shows absolute
1179+ // line number
1180+ num = lnum;
1181+ fmt = "%-*ld ";
1182+ }
1183+ }
1184+
1185+ sprintf((char *)buf, fmt, w, num);
1186+#ifdef FEAT_RIGHTLEFT
1187+ if (wp->w_p_rl)
1188+ // the line number isn't reversed
1189+ copy_text_attr(off + wp->w_width - len - col, buf, len,
1190+ HL_ATTR(HLF_FL));
1191+ else
1192+#endif
1193+ copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL));
1194+ col += len;
1195+ }
1196+ }
1197+
1198+ // 4. Compose the folded-line string with 'foldtext', if set.
1199+ text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
1200+
1201+ txtcol = col; // remember where text starts
1202+
1203+ // 5. move the text to current_ScreenLine. Fill up with "fill_fold".
1204+ // Right-left text is put in columns 0 - number-col, normal text is put
1205+ // in columns number-col - window-width.
1206+ col = text_to_screenline(wp, text, col);
1207+
1208+ // Fill the rest of the line with the fold filler
1209+#ifdef FEAT_RIGHTLEFT
1210+ if (wp->w_p_rl)
1211+ col -= txtcol;
1212+#endif
1213+ while (col < wp->w_width
1214+#ifdef FEAT_RIGHTLEFT
1215+ - (wp->w_p_rl ? txtcol : 0)
1216+#endif
1217+ )
1218+ {
1219+ if (enc_utf8)
1220+ {
1221+ if (fill_fold >= 0x80)
1222+ {
1223+ ScreenLinesUC[off + col] = fill_fold;
1224+ ScreenLinesC[0][off + col] = 0;
1225+ ScreenLines[off + col] = 0x80; // avoid storing zero
1226+ }
1227+ else
1228+ {
1229+ ScreenLinesUC[off + col] = 0;
1230+ ScreenLines[off + col] = fill_fold;
1231+ }
1232+ col++;
1233+ }
1234+ else
1235+ ScreenLines[off + col++] = fill_fold;
1236+ }
1237+
1238+ if (text != buf)
1239+ vim_free(text);
1240+
1241+ // 6. set highlighting for the Visual area an other text.
1242+ // If all folded lines are in the Visual area, highlight the line.
1243+ if (VIsual_active && wp->w_buffer == curwin->w_buffer)
1244+ {
1245+ if (LTOREQ_POS(curwin->w_cursor, VIsual))
1246+ {
1247+ // Visual is after curwin->w_cursor
1248+ top = &curwin->w_cursor;
1249+ bot = &VIsual;
1250+ }
1251+ else
1252+ {
1253+ // Visual is before curwin->w_cursor
1254+ top = &VIsual;
1255+ bot = &curwin->w_cursor;
1256+ }
1257+ if (lnum >= top->lnum
1258+ && lnume <= bot->lnum
1259+ && (VIsual_mode != 'v'
1260+ || ((lnum > top->lnum
1261+ || (lnum == top->lnum
1262+ && top->col == 0))
1263+ && (lnume < bot->lnum
1264+ || (lnume == bot->lnum
1265+ && (bot->col - (*p_sel == 'e'))
1266+ >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
1267+ {
1268+ if (VIsual_mode == Ctrl_V)
1269+ {
1270+ // Visual block mode: highlight the chars part of the block
1271+ if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width)
1272+ {
1273+ if (wp->w_old_cursor_lcol != MAXCOL
1274+ && wp->w_old_cursor_lcol + txtcol
1275+ < (colnr_T)wp->w_width)
1276+ len = wp->w_old_cursor_lcol;
1277+ else
1278+ len = wp->w_width - txtcol;
1279+ RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V),
1280+ len - (int)wp->w_old_cursor_fcol);
1281+ }
1282+ }
1283+ else
1284+ {
1285+ // Set all attributes of the text
1286+ RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol);
1287+ }
1288+ }
1289+ }
1290+
1291+#ifdef FEAT_SYN_HL
1292+ // Show colorcolumn in the fold line, but let cursorcolumn override it.
1293+ if (wp->w_p_cc_cols)
1294+ {
1295+ int i = 0;
1296+ int j = wp->w_p_cc_cols[i];
1297+ int old_txtcol = txtcol;
1298+
1299+ while (j > -1)
1300+ {
1301+ txtcol += j;
1302+ if (wp->w_p_wrap)
1303+ txtcol -= wp->w_skipcol;
1304+ else
1305+ txtcol -= wp->w_leftcol;
1306+ if (txtcol >= 0 && txtcol < wp->w_width)
1307+ ScreenAttrs[off + txtcol] = hl_combine_attr(
1308+ ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC));
1309+ txtcol = old_txtcol;
1310+ j = wp->w_p_cc_cols[++i];
1311+ }
1312+ }
1313+
1314+ // Show 'cursorcolumn' in the fold line.
1315+ if (wp->w_p_cuc)
1316+ {
1317+ txtcol += wp->w_virtcol;
1318+ if (wp->w_p_wrap)
1319+ txtcol -= wp->w_skipcol;
1320+ else
1321+ txtcol -= wp->w_leftcol;
1322+ if (txtcol >= 0 && txtcol < wp->w_width)
1323+ ScreenAttrs[off + txtcol] = hl_combine_attr(
1324+ ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC));
1325+ }
1326+#endif
1327+
1328+ screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
1329+ (int)wp->w_width, 0);
1330+
1331+ // Update w_cline_height and w_cline_folded if the cursor line was
1332+ // updated (saves a call to plines() later).
1333+ if (wp == curwin
1334+ && lnum <= curwin->w_cursor.lnum
1335+ && lnume >= curwin->w_cursor.lnum)
1336+ {
1337+ curwin->w_cline_row = row;
1338+ curwin->w_cline_height = 1;
1339+ curwin->w_cline_folded = TRUE;
1340+ curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
1341+ }
1342+}
1343+#endif
1344+
1345+/*
1346+ * Update a single window.
1347+ *
1348+ * This may cause the windows below it also to be redrawn (when clearing the
1349+ * screen or scrolling lines).
1350+ *
1351+ * How the window is redrawn depends on wp->w_redr_type. Each type also
1352+ * implies the one below it.
1353+ * NOT_VALID redraw the whole window
1354+ * SOME_VALID redraw the whole window but do scroll when possible
1355+ * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
1356+ * INVERTED redraw the changed part of the Visual area
1357+ * INVERTED_ALL redraw the whole Visual area
1358+ * VALID 1. scroll up/down to adjust for a changed w_topline
1359+ * 2. update lines at the top when scrolled down
1360+ * 3. redraw changed text:
1361+ * - if wp->w_buffer->b_mod_set set, update lines between
1362+ * b_mod_top and b_mod_bot.
1363+ * - if wp->w_redraw_top non-zero, redraw lines between
1364+ * wp->w_redraw_top and wp->w_redr_bot.
1365+ * - continue redrawing when syntax status is invalid.
1366+ * 4. if scrolled up, update lines at the bottom.
1367+ * This results in three areas that may need updating:
1368+ * top: from first row to top_end (when scrolled down)
1369+ * mid: from mid_start to mid_end (update inversion or changed text)
1370+ * bot: from bot_start to last row (when scrolled up)
1371+ */
1372+ static void
1373+win_update(win_T *wp)
1374+{
1375+ buf_T *buf = wp->w_buffer;
1376+ int type;
1377+ int top_end = 0; // Below last row of the top area that needs
1378+ // updating. 0 when no top area updating.
1379+ int mid_start = 999;// first row of the mid area that needs
1380+ // updating. 999 when no mid area updating.
1381+ int mid_end = 0; // Below last row of the mid area that needs
1382+ // updating. 0 when no mid area updating.
1383+ int bot_start = 999;// first row of the bot area that needs
1384+ // updating. 999 when no bot area updating
1385+ int scrolled_down = FALSE; // TRUE when scrolled down when
1386+ // w_topline got smaller a bit
1387+#ifdef FEAT_SEARCH_EXTRA
1388+ int top_to_mod = FALSE; // redraw above mod_top
1389+#endif
1390+
1391+ int row; // current window row to display
1392+ linenr_T lnum; // current buffer lnum to display
1393+ int idx; // current index in w_lines[]
1394+ int srow; // starting row of the current line
1395+
1396+ int eof = FALSE; // if TRUE, we hit the end of the file
1397+ int didline = FALSE; // if TRUE, we finished the last line
1398+ int i;
1399+ long j;
1400+ static int recursive = FALSE; // being called recursively
1401+ int old_botline = wp->w_botline;
1402+#ifdef FEAT_FOLDING
1403+ long fold_count;
1404+#endif
1405+#ifdef FEAT_SYN_HL
1406+ // remember what happened to the previous line, to know if
1407+ // check_visual_highlight() can be used
1408+#define DID_NONE 1 // didn't update a line
1409+#define DID_LINE 2 // updated a normal line
1410+#define DID_FOLD 3 // updated a folded line
1411+ int did_update = DID_NONE;
1412+ linenr_T syntax_last_parsed = 0; // last parsed text line
1413+#endif
1414+ linenr_T mod_top = 0;
1415+ linenr_T mod_bot = 0;
1416+#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1417+ int save_got_int;
1418+#endif
1419+#ifdef SYN_TIME_LIMIT
1420+ proftime_T syntax_tm;
1421+#endif
1422+
1423+ type = wp->w_redr_type;
1424+
1425+ if (type == NOT_VALID)
1426+ {
1427+ wp->w_redr_status = TRUE;
1428+ wp->w_lines_valid = 0;
1429+ }
1430+
1431+ // Window is zero-height: nothing to draw.
1432+ if (wp->w_height + WINBAR_HEIGHT(wp) == 0)
1433+ {
1434+ wp->w_redr_type = 0;
1435+ return;
1436+ }
1437+
1438+ // Window is zero-width: Only need to draw the separator.
1439+ if (wp->w_width == 0)
1440+ {
1441+ // draw the vertical separator right of this window
1442+ draw_vsep_win(wp, 0);
1443+ wp->w_redr_type = 0;
1444+ return;
1445+ }
1446+
1447+#ifdef FEAT_TERMINAL
1448+ // If this window contains a terminal, redraw works completely differently.
1449+ if (term_do_update_window(wp))
1450+ {
1451+ term_update_window(wp);
1452+# ifdef FEAT_MENU
1453+ // Draw the window toolbar, if there is one.
1454+ if (winbar_height(wp) > 0)
1455+ redraw_win_toolbar(wp);
1456+# endif
1457+ wp->w_redr_type = 0;
1458+ return;
1459+ }
1460+#endif
1461+
1462+#ifdef FEAT_SEARCH_EXTRA
1463+ init_search_hl(wp, &screen_search_hl);
1464+#endif
1465+
1466+#ifdef FEAT_LINEBREAK
1467+ // Force redraw when width of 'number' or 'relativenumber' column
1468+ // changes.
1469+ i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
1470+ if (wp->w_nrwidth != i)
1471+ {
1472+ type = NOT_VALID;
1473+ wp->w_nrwidth = i;
1474+ }
1475+ else
1476+#endif
1477+
1478+ if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
1479+ {
1480+ // When there are both inserted/deleted lines and specific lines to be
1481+ // redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
1482+ // everything (only happens when redrawing is off for while).
1483+ type = NOT_VALID;
1484+ }
1485+ else
1486+ {
1487+ // Set mod_top to the first line that needs displaying because of
1488+ // changes. Set mod_bot to the first line after the changes.
1489+ mod_top = wp->w_redraw_top;
1490+ if (wp->w_redraw_bot != 0)
1491+ mod_bot = wp->w_redraw_bot + 1;
1492+ else
1493+ mod_bot = 0;
1494+ if (buf->b_mod_set)
1495+ {
1496+ if (mod_top == 0 || mod_top > buf->b_mod_top)
1497+ {
1498+ mod_top = buf->b_mod_top;
1499+#ifdef FEAT_SYN_HL
1500+ // Need to redraw lines above the change that may be included
1501+ // in a pattern match.
1502+ if (syntax_present(wp))
1503+ {
1504+ mod_top -= buf->b_s.b_syn_sync_linebreaks;
1505+ if (mod_top < 1)
1506+ mod_top = 1;
1507+ }
1508+#endif
1509+ }
1510+ if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
1511+ mod_bot = buf->b_mod_bot;
1512+
1513+#ifdef FEAT_SEARCH_EXTRA
1514+ // When 'hlsearch' is on and using a multi-line search pattern, a
1515+ // change in one line may make the Search highlighting in a
1516+ // previous line invalid. Simple solution: redraw all visible
1517+ // lines above the change.
1518+ // Same for a match pattern.
1519+ if (screen_search_hl.rm.regprog != NULL
1520+ && re_multiline(screen_search_hl.rm.regprog))
1521+ top_to_mod = TRUE;
1522+ else
1523+ {
1524+ matchitem_T *cur = wp->w_match_head;
1525+
1526+ while (cur != NULL)
1527+ {
1528+ if (cur->match.regprog != NULL
1529+ && re_multiline(cur->match.regprog))
1530+ {
1531+ top_to_mod = TRUE;
1532+ break;
1533+ }
1534+ cur = cur->next;
1535+ }
1536+ }
1537+#endif
1538+ }
1539+#ifdef FEAT_FOLDING
1540+ if (mod_top != 0 && hasAnyFolding(wp))
1541+ {
1542+ linenr_T lnumt, lnumb;
1543+
1544+ // A change in a line can cause lines above it to become folded or
1545+ // unfolded. Find the top most buffer line that may be affected.
1546+ // If the line was previously folded and displayed, get the first
1547+ // line of that fold. If the line is folded now, get the first
1548+ // folded line. Use the minimum of these two.
1549+
1550+ // Find last valid w_lines[] entry above mod_top. Set lnumt to
1551+ // the line below it. If there is no valid entry, use w_topline.
1552+ // Find the first valid w_lines[] entry below mod_bot. Set lnumb
1553+ // to this line. If there is no valid entry, use MAXLNUM.
1554+ lnumt = wp->w_topline;
1555+ lnumb = MAXLNUM;
1556+ for (i = 0; i < wp->w_lines_valid; ++i)
1557+ if (wp->w_lines[i].wl_valid)
1558+ {
1559+ if (wp->w_lines[i].wl_lastlnum < mod_top)
1560+ lnumt = wp->w_lines[i].wl_lastlnum + 1;
1561+ if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1562+ {
1563+ lnumb = wp->w_lines[i].wl_lnum;
1564+ // When there is a fold column it might need updating
1565+ // in the next line ("J" just above an open fold).
1566+ if (compute_foldcolumn(wp, 0) > 0)
1567+ ++lnumb;
1568+ }
1569+ }
1570+
1571+ (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1572+ if (mod_top > lnumt)
1573+ mod_top = lnumt;
1574+
1575+ // Now do the same for the bottom line (one above mod_bot).
1576+ --mod_bot;
1577+ (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1578+ ++mod_bot;
1579+ if (mod_bot < lnumb)
1580+ mod_bot = lnumb;
1581+ }
1582+#endif
1583+
1584+ // When a change starts above w_topline and the end is below
1585+ // w_topline, start redrawing at w_topline.
1586+ // If the end of the change is above w_topline: do like no change was
1587+ // made, but redraw the first line to find changes in syntax.
1588+ if (mod_top != 0 && mod_top < wp->w_topline)
1589+ {
1590+ if (mod_bot > wp->w_topline)
1591+ mod_top = wp->w_topline;
1592+#ifdef FEAT_SYN_HL
1593+ else if (syntax_present(wp))
1594+ top_end = 1;
1595+#endif
1596+ }
1597+
1598+ // When line numbers are displayed need to redraw all lines below
1599+ // inserted/deleted lines.
1600+ if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1601+ mod_bot = MAXLNUM;
1602+ }
1603+ wp->w_redraw_top = 0; // reset for next time
1604+ wp->w_redraw_bot = 0;
1605+
1606+ // When only displaying the lines at the top, set top_end. Used when
1607+ // window has scrolled down for msg_scrolled.
1608+ if (type == REDRAW_TOP)
1609+ {
1610+ j = 0;
1611+ for (i = 0; i < wp->w_lines_valid; ++i)
1612+ {
1613+ j += wp->w_lines[i].wl_size;
1614+ if (j >= wp->w_upd_rows)
1615+ {
1616+ top_end = j;
1617+ break;
1618+ }
1619+ }
1620+ if (top_end == 0)
1621+ // not found (cannot happen?): redraw everything
1622+ type = NOT_VALID;
1623+ else
1624+ // top area defined, the rest is VALID
1625+ type = VALID;
1626+ }
1627+
1628+ // Trick: we want to avoid clearing the screen twice. screenclear() will
1629+ // set "screen_cleared" to TRUE. The special value MAYBE (which is still
1630+ // non-zero and thus not FALSE) will indicate that screenclear() was not
1631+ // called.
1632+ if (screen_cleared)
1633+ screen_cleared = MAYBE;
1634+
1635+ // If there are no changes on the screen that require a complete redraw,
1636+ // handle three cases:
1637+ // 1: we are off the top of the screen by a few lines: scroll down
1638+ // 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1639+ // 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1640+ // w_lines[] that needs updating.
1641+ if ((type == VALID || type == SOME_VALID
1642+ || type == INVERTED || type == INVERTED_ALL)
1643+#ifdef FEAT_DIFF
1644+ && !wp->w_botfill && !wp->w_old_botfill
1645+#endif
1646+ )
1647+ {
1648+ if (mod_top != 0 && wp->w_topline == mod_top)
1649+ {
1650+ // w_topline is the first changed line, the scrolling will be done
1651+ // further down.
1652+ }
1653+ else if (wp->w_lines[0].wl_valid
1654+ && (wp->w_topline < wp->w_lines[0].wl_lnum
1655+#ifdef FEAT_DIFF
1656+ || (wp->w_topline == wp->w_lines[0].wl_lnum
1657+ && wp->w_topfill > wp->w_old_topfill)
1658+#endif
1659+ ))
1660+ {
1661+ // New topline is above old topline: May scroll down.
1662+#ifdef FEAT_FOLDING
1663+ if (hasAnyFolding(wp))
1664+ {
1665+ linenr_T ln;
1666+
1667+ // count the number of lines we are off, counting a sequence
1668+ // of folded lines as one
1669+ j = 0;
1670+ for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1671+ {
1672+ ++j;
1673+ if (j >= wp->w_height - 2)
1674+ break;
1675+ (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1676+ }
1677+ }
1678+ else
1679+#endif
1680+ j = wp->w_lines[0].wl_lnum - wp->w_topline;
1681+ if (j < wp->w_height - 2) // not too far off
1682+ {
1683+ i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1684+#ifdef FEAT_DIFF
1685+ // insert extra lines for previously invisible filler lines
1686+ if (wp->w_lines[0].wl_lnum != wp->w_topline)
1687+ i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1688+ - wp->w_old_topfill;
1689+#endif
1690+ if (i < wp->w_height - 2) // less than a screen off
1691+ {
1692+ // Try to insert the correct number of lines.
1693+ // If not the last window, delete the lines at the bottom.
1694+ // win_ins_lines may fail when the terminal can't do it.
1695+ if (i > 0)
1696+ check_for_delay(FALSE);
1697+ if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1698+ {
1699+ if (wp->w_lines_valid != 0)
1700+ {
1701+ // Need to update rows that are new, stop at the
1702+ // first one that scrolled down.
1703+ top_end = i;
1704+ scrolled_down = TRUE;
1705+
1706+ // Move the entries that were scrolled, disable
1707+ // the entries for the lines to be redrawn.
1708+ if ((wp->w_lines_valid += j) > wp->w_height)
1709+ wp->w_lines_valid = wp->w_height;
1710+ for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1711+ wp->w_lines[idx] = wp->w_lines[idx - j];
1712+ while (idx >= 0)
1713+ wp->w_lines[idx--].wl_valid = FALSE;
1714+ }
1715+ }
1716+ else
1717+ mid_start = 0; // redraw all lines
1718+ }
1719+ else
1720+ mid_start = 0; // redraw all lines
1721+ }
1722+ else
1723+ mid_start = 0; // redraw all lines
1724+ }
1725+ else
1726+ {
1727+ // New topline is at or below old topline: May scroll up.
1728+ // When topline didn't change, find first entry in w_lines[] that
1729+ // needs updating.
1730+
1731+ // try to find wp->w_topline in wp->w_lines[].wl_lnum
1732+ j = -1;
1733+ row = 0;
1734+ for (i = 0; i < wp->w_lines_valid; i++)
1735+ {
1736+ if (wp->w_lines[i].wl_valid
1737+ && wp->w_lines[i].wl_lnum == wp->w_topline)
1738+ {
1739+ j = i;
1740+ break;
1741+ }
1742+ row += wp->w_lines[i].wl_size;
1743+ }
1744+ if (j == -1)
1745+ {
1746+ // if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1747+ // lines
1748+ mid_start = 0;
1749+ }
1750+ else
1751+ {
1752+ // Try to delete the correct number of lines.
1753+ // wp->w_topline is at wp->w_lines[i].wl_lnum.
1754+#ifdef FEAT_DIFF
1755+ // If the topline didn't change, delete old filler lines,
1756+ // otherwise delete filler lines of the new topline...
1757+ if (wp->w_lines[0].wl_lnum == wp->w_topline)
1758+ row += wp->w_old_topfill;
1759+ else
1760+ row += diff_check_fill(wp, wp->w_topline);
1761+ // ... but don't delete new filler lines.
1762+ row -= wp->w_topfill;
1763+#endif
1764+ if (row > 0)
1765+ {
1766+ check_for_delay(FALSE);
1767+ if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
1768+ == OK)
1769+ bot_start = wp->w_height - row;
1770+ else
1771+ mid_start = 0; // redraw all lines
1772+ }
1773+ if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1774+ {
1775+ // Skip the lines (below the deleted lines) that are still
1776+ // valid and don't need redrawing. Copy their info
1777+ // upwards, to compensate for the deleted lines. Set
1778+ // bot_start to the first row that needs redrawing.
1779+ bot_start = 0;
1780+ idx = 0;
1781+ for (;;)
1782+ {
1783+ wp->w_lines[idx] = wp->w_lines[j];
1784+ // stop at line that didn't fit, unless it is still
1785+ // valid (no lines deleted)
1786+ if (row > 0 && bot_start + row
1787+ + (int)wp->w_lines[j].wl_size > wp->w_height)
1788+ {
1789+ wp->w_lines_valid = idx + 1;
1790+ break;
1791+ }
1792+ bot_start += wp->w_lines[idx++].wl_size;
1793+
1794+ // stop at the last valid entry in w_lines[].wl_size
1795+ if (++j >= wp->w_lines_valid)
1796+ {
1797+ wp->w_lines_valid = idx;
1798+ break;
1799+ }
1800+ }
1801+#ifdef FEAT_DIFF
1802+ // Correct the first entry for filler lines at the top
1803+ // when it won't get updated below.
1804+ if (wp->w_p_diff && bot_start > 0)
1805+ wp->w_lines[0].wl_size =
1806+ plines_win_nofill(wp, wp->w_topline, TRUE)
1807+ + wp->w_topfill;
1808+#endif
1809+ }
1810+ }
1811+ }
1812+
1813+ // When starting redraw in the first line, redraw all lines. When
1814+ // there is only one window it's probably faster to clear the screen
1815+ // first.
1816+ if (mid_start == 0)
1817+ {
1818+ mid_end = wp->w_height;
1819+ if (ONE_WINDOW && !WIN_IS_POPUP(wp))
1820+ {
1821+ // Clear the screen when it was not done by win_del_lines() or
1822+ // win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1823+ // then.
1824+ if (screen_cleared != TRUE)
1825+ screenclear();
1826+ // The screen was cleared, redraw the tab pages line.
1827+ if (redraw_tabline)
1828+ draw_tabline();
1829+ }
1830+ }
1831+
1832+ // When win_del_lines() or win_ins_lines() caused the screen to be
1833+ // cleared (only happens for the first window) or when screenclear()
1834+ // was called directly above, "must_redraw" will have been set to
1835+ // NOT_VALID, need to reset it here to avoid redrawing twice.
1836+ if (screen_cleared == TRUE)
1837+ must_redraw = 0;
1838+ }
1839+ else
1840+ {
1841+ // Not VALID or INVERTED: redraw all lines.
1842+ mid_start = 0;
1843+ mid_end = wp->w_height;
1844+ }
1845+
1846+ if (type == SOME_VALID)
1847+ {
1848+ // SOME_VALID: redraw all lines.
1849+ mid_start = 0;
1850+ mid_end = wp->w_height;
1851+ type = NOT_VALID;
1852+ }
1853+
1854+ // check if we are updating or removing the inverted part
1855+ if ((VIsual_active && buf == curwin->w_buffer)
1856+ || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1857+ {
1858+ linenr_T from, to;
1859+
1860+ if (VIsual_active)
1861+ {
1862+ if (VIsual_active
1863+ && (VIsual_mode != wp->w_old_visual_mode
1864+ || type == INVERTED_ALL))
1865+ {
1866+ // If the type of Visual selection changed, redraw the whole
1867+ // selection. Also when the ownership of the X selection is
1868+ // gained or lost.
1869+ if (curwin->w_cursor.lnum < VIsual.lnum)
1870+ {
1871+ from = curwin->w_cursor.lnum;
1872+ to = VIsual.lnum;
1873+ }
1874+ else
1875+ {
1876+ from = VIsual.lnum;
1877+ to = curwin->w_cursor.lnum;
1878+ }
1879+ // redraw more when the cursor moved as well
1880+ if (wp->w_old_cursor_lnum < from)
1881+ from = wp->w_old_cursor_lnum;
1882+ if (wp->w_old_cursor_lnum > to)
1883+ to = wp->w_old_cursor_lnum;
1884+ if (wp->w_old_visual_lnum < from)
1885+ from = wp->w_old_visual_lnum;
1886+ if (wp->w_old_visual_lnum > to)
1887+ to = wp->w_old_visual_lnum;
1888+ }
1889+ else
1890+ {
1891+ // Find the line numbers that need to be updated: The lines
1892+ // between the old cursor position and the current cursor
1893+ // position. Also check if the Visual position changed.
1894+ if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1895+ {
1896+ from = curwin->w_cursor.lnum;
1897+ to = wp->w_old_cursor_lnum;
1898+ }
1899+ else
1900+ {
1901+ from = wp->w_old_cursor_lnum;
1902+ to = curwin->w_cursor.lnum;
1903+ if (from == 0) // Visual mode just started
1904+ from = to;
1905+ }
1906+
1907+ if (VIsual.lnum != wp->w_old_visual_lnum
1908+ || VIsual.col != wp->w_old_visual_col)
1909+ {
1910+ if (wp->w_old_visual_lnum < from
1911+ && wp->w_old_visual_lnum != 0)
1912+ from = wp->w_old_visual_lnum;
1913+ if (wp->w_old_visual_lnum > to)
1914+ to = wp->w_old_visual_lnum;
1915+ if (VIsual.lnum < from)
1916+ from = VIsual.lnum;
1917+ if (VIsual.lnum > to)
1918+ to = VIsual.lnum;
1919+ }
1920+ }
1921+
1922+ // If in block mode and changed column or curwin->w_curswant:
1923+ // update all lines.
1924+ // First compute the actual start and end column.
1925+ if (VIsual_mode == Ctrl_V)
1926+ {
1927+ colnr_T fromc, toc;
1928+#if defined(FEAT_LINEBREAK)
1929+ int save_ve_flags = ve_flags;
1930+
1931+ if (curwin->w_p_lbr)
1932+ ve_flags = VE_ALL;
1933+#endif
1934+ getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
1935+#if defined(FEAT_LINEBREAK)
1936+ ve_flags = save_ve_flags;
1937+#endif
1938+ ++toc;
1939+ if (curwin->w_curswant == MAXCOL)
1940+ toc = MAXCOL;
1941+
1942+ if (fromc != wp->w_old_cursor_fcol
1943+ || toc != wp->w_old_cursor_lcol)
1944+ {
1945+ if (from > VIsual.lnum)
1946+ from = VIsual.lnum;
1947+ if (to < VIsual.lnum)
1948+ to = VIsual.lnum;
1949+ }
1950+ wp->w_old_cursor_fcol = fromc;
1951+ wp->w_old_cursor_lcol = toc;
1952+ }
1953+ }
1954+ else
1955+ {
1956+ // Use the line numbers of the old Visual area.
1957+ if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
1958+ {
1959+ from = wp->w_old_cursor_lnum;
1960+ to = wp->w_old_visual_lnum;
1961+ }
1962+ else
1963+ {
1964+ from = wp->w_old_visual_lnum;
1965+ to = wp->w_old_cursor_lnum;
1966+ }
1967+ }
1968+
1969+ // There is no need to update lines above the top of the window.
1970+ if (from < wp->w_topline)
1971+ from = wp->w_topline;
1972+
1973+ // If we know the value of w_botline, use it to restrict the update to
1974+ // the lines that are visible in the window.
1975+ if (wp->w_valid & VALID_BOTLINE)
1976+ {
1977+ if (from >= wp->w_botline)
1978+ from = wp->w_botline - 1;
1979+ if (to >= wp->w_botline)
1980+ to = wp->w_botline - 1;
1981+ }
1982+
1983+ // Find the minimal part to be updated.
1984+ // Watch out for scrolling that made entries in w_lines[] invalid.
1985+ // E.g., CTRL-U makes the first half of w_lines[] invalid and sets
1986+ // top_end; need to redraw from top_end to the "to" line.
1987+ // A middle mouse click with a Visual selection may change the text
1988+ // above the Visual area and reset wl_valid, do count these for
1989+ // mid_end (in srow).
1990+ if (mid_start > 0)
1991+ {
1992+ lnum = wp->w_topline;
1993+ idx = 0;
1994+ srow = 0;
1995+ if (scrolled_down)
1996+ mid_start = top_end;
1997+ else
1998+ mid_start = 0;
1999+ while (lnum < from && idx < wp->w_lines_valid) // find start
2000+ {
2001+ if (wp->w_lines[idx].wl_valid)
2002+ mid_start += wp->w_lines[idx].wl_size;
2003+ else if (!scrolled_down)
2004+ srow += wp->w_lines[idx].wl_size;
2005+ ++idx;
2006+# ifdef FEAT_FOLDING
2007+ if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
2008+ lnum = wp->w_lines[idx].wl_lnum;
2009+ else
2010+# endif
2011+ ++lnum;
2012+ }
2013+ srow += mid_start;
2014+ mid_end = wp->w_height;
2015+ for ( ; idx < wp->w_lines_valid; ++idx) // find end
2016+ {
2017+ if (wp->w_lines[idx].wl_valid
2018+ && wp->w_lines[idx].wl_lnum >= to + 1)
2019+ {
2020+ // Only update until first row of this line
2021+ mid_end = srow;
2022+ break;
2023+ }
2024+ srow += wp->w_lines[idx].wl_size;
2025+ }
2026+ }
2027+ }
2028+
2029+ if (VIsual_active && buf == curwin->w_buffer)
2030+ {
2031+ wp->w_old_visual_mode = VIsual_mode;
2032+ wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
2033+ wp->w_old_visual_lnum = VIsual.lnum;
2034+ wp->w_old_visual_col = VIsual.col;
2035+ wp->w_old_curswant = curwin->w_curswant;
2036+ }
2037+ else
2038+ {
2039+ wp->w_old_visual_mode = 0;
2040+ wp->w_old_cursor_lnum = 0;
2041+ wp->w_old_visual_lnum = 0;
2042+ wp->w_old_visual_col = 0;
2043+ }
2044+
2045+#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2046+ // reset got_int, otherwise regexp won't work
2047+ save_got_int = got_int;
2048+ got_int = 0;
2049+#endif
2050+#ifdef SYN_TIME_LIMIT
2051+ // Set the time limit to 'redrawtime'.
2052+ profile_setlimit(p_rdt, &syntax_tm);
2053+ syn_set_timeout(&syntax_tm);
2054+#endif
2055+#ifdef FEAT_FOLDING
2056+ win_foldinfo.fi_level = 0;
2057+#endif
2058+
2059+#ifdef FEAT_MENU
2060+ // Draw the window toolbar, if there is one.
2061+ // TODO: only when needed.
2062+ if (winbar_height(wp) > 0)
2063+ redraw_win_toolbar(wp);
2064+#endif
2065+
2066+ // Update all the window rows.
2067+ idx = 0; // first entry in w_lines[].wl_size
2068+ row = 0;
2069+ srow = 0;
2070+ lnum = wp->w_topline; // first line shown in window
2071+ for (;;)
2072+ {
2073+ // stop updating when reached the end of the window (check for _past_
2074+ // the end of the window is at the end of the loop)
2075+ if (row == wp->w_height)
2076+ {
2077+ didline = TRUE;
2078+ break;
2079+ }
2080+
2081+ // stop updating when hit the end of the file
2082+ if (lnum > buf->b_ml.ml_line_count)
2083+ {
2084+ eof = TRUE;
2085+ break;
2086+ }
2087+
2088+ // Remember the starting row of the line that is going to be dealt
2089+ // with. It is used further down when the line doesn't fit.
2090+ srow = row;
2091+
2092+ // Update a line when it is in an area that needs updating, when it
2093+ // has changes or w_lines[idx] is invalid.
2094+ // "bot_start" may be halfway a wrapped line after using
2095+ // win_del_lines(), check if the current line includes it.
2096+ // When syntax folding is being used, the saved syntax states will
2097+ // already have been updated, we can't see where the syntax state is
2098+ // the same again, just update until the end of the window.
2099+ if (row < top_end
2100+ || (row >= mid_start && row < mid_end)
2101+#ifdef FEAT_SEARCH_EXTRA
2102+ || top_to_mod
2103+#endif
2104+ || idx >= wp->w_lines_valid
2105+ || (row + wp->w_lines[idx].wl_size > bot_start)
2106+ || (mod_top != 0
2107+ && (lnum == mod_top
2108+ || (lnum >= mod_top
2109+ && (lnum < mod_bot
2110+#ifdef FEAT_SYN_HL
2111+ || did_update == DID_FOLD
2112+ || (did_update == DID_LINE
2113+ && syntax_present(wp)
2114+ && (
2115+# ifdef FEAT_FOLDING
2116+ (foldmethodIsSyntax(wp)
2117+ && hasAnyFolding(wp)) ||
2118+# endif
2119+ syntax_check_changed(lnum)))
2120+#endif
2121+#ifdef FEAT_SEARCH_EXTRA
2122+ // match in fixed position might need redraw
2123+ // if lines were inserted or deleted
2124+ || (wp->w_match_head != NULL
2125+ && buf->b_mod_xlines != 0)
2126+#endif
2127+ )))))
2128+ {
2129+#ifdef FEAT_SEARCH_EXTRA
2130+ if (lnum == mod_top)
2131+ top_to_mod = FALSE;
2132+#endif
2133+
2134+ // When at start of changed lines: May scroll following lines
2135+ // up or down to minimize redrawing.
2136+ // Don't do this when the change continues until the end.
2137+ // Don't scroll when dollar_vcol >= 0, keep the "$".
2138+ if (lnum == mod_top
2139+ && mod_bot != MAXLNUM
2140+ && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
2141+ {
2142+ int old_rows = 0;
2143+ int new_rows = 0;
2144+ int xtra_rows;
2145+ linenr_T l;
2146+
2147+ // Count the old number of window rows, using w_lines[], which
2148+ // should still contain the sizes for the lines as they are
2149+ // currently displayed.
2150+ for (i = idx; i < wp->w_lines_valid; ++i)
2151+ {
2152+ // Only valid lines have a meaningful wl_lnum. Invalid
2153+ // lines are part of the changed area.
2154+ if (wp->w_lines[i].wl_valid
2155+ && wp->w_lines[i].wl_lnum == mod_bot)
2156+ break;
2157+ old_rows += wp->w_lines[i].wl_size;
2158+#ifdef FEAT_FOLDING
2159+ if (wp->w_lines[i].wl_valid
2160+ && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
2161+ {
2162+ // Must have found the last valid entry above mod_bot.
2163+ // Add following invalid entries.
2164+ ++i;
2165+ while (i < wp->w_lines_valid
2166+ && !wp->w_lines[i].wl_valid)
2167+ old_rows += wp->w_lines[i++].wl_size;
2168+ break;
2169+ }
2170+#endif
2171+ }
2172+
2173+ if (i >= wp->w_lines_valid)
2174+ {
2175+ // We can't find a valid line below the changed lines,
2176+ // need to redraw until the end of the window.
2177+ // Inserting/deleting lines has no use.
2178+ bot_start = 0;
2179+ }
2180+ else
2181+ {
2182+ // Able to count old number of rows: Count new window
2183+ // rows, and may insert/delete lines
2184+ j = idx;
2185+ for (l = lnum; l < mod_bot; ++l)
2186+ {
2187+#ifdef FEAT_FOLDING
2188+ if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
2189+ ++new_rows;
2190+ else
2191+#endif
2192+#ifdef FEAT_DIFF
2193+ if (l == wp->w_topline)
2194+ new_rows += plines_win_nofill(wp, l, TRUE)
2195+ + wp->w_topfill;
2196+ else
2197+#endif
2198+ new_rows += plines_win(wp, l, TRUE);
2199+ ++j;
2200+ if (new_rows > wp->w_height - row - 2)
2201+ {
2202+ // it's getting too much, must redraw the rest
2203+ new_rows = 9999;
2204+ break;
2205+ }
2206+ }
2207+ xtra_rows = new_rows - old_rows;
2208+ if (xtra_rows < 0)
2209+ {
2210+ // May scroll text up. If there is not enough
2211+ // remaining text or scrolling fails, must redraw the
2212+ // rest. If scrolling works, must redraw the text
2213+ // below the scrolled text.
2214+ if (row - xtra_rows >= wp->w_height - 2)
2215+ mod_bot = MAXLNUM;
2216+ else
2217+ {
2218+ check_for_delay(FALSE);
2219+ if (win_del_lines(wp, row,
2220+ -xtra_rows, FALSE, FALSE, 0) == FAIL)
2221+ mod_bot = MAXLNUM;
2222+ else
2223+ bot_start = wp->w_height + xtra_rows;
2224+ }
2225+ }
2226+ else if (xtra_rows > 0)
2227+ {
2228+ // May scroll text down. If there is not enough
2229+ // remaining text of scrolling fails, must redraw the
2230+ // rest.
2231+ if (row + xtra_rows >= wp->w_height - 2)
2232+ mod_bot = MAXLNUM;
2233+ else
2234+ {
2235+ check_for_delay(FALSE);
2236+ if (win_ins_lines(wp, row + old_rows,
2237+ xtra_rows, FALSE, FALSE) == FAIL)
2238+ mod_bot = MAXLNUM;
2239+ else if (top_end > row + old_rows)
2240+ // Scrolled the part at the top that requires
2241+ // updating down.
2242+ top_end += xtra_rows;
2243+ }
2244+ }
2245+
2246+ // When not updating the rest, may need to move w_lines[]
2247+ // entries.
2248+ if (mod_bot != MAXLNUM && i != j)
2249+ {
2250+ if (j < i)
2251+ {
2252+ int x = row + new_rows;
2253+
2254+ // move entries in w_lines[] upwards
2255+ for (;;)
2256+ {
2257+ // stop at last valid entry in w_lines[]
2258+ if (i >= wp->w_lines_valid)
2259+ {
2260+ wp->w_lines_valid = j;
2261+ break;
2262+ }
2263+ wp->w_lines[j] = wp->w_lines[i];
2264+ // stop at a line that won't fit
2265+ if (x + (int)wp->w_lines[j].wl_size
2266+ > wp->w_height)
2267+ {
2268+ wp->w_lines_valid = j + 1;
2269+ break;
2270+ }
2271+ x += wp->w_lines[j++].wl_size;
2272+ ++i;
2273+ }
2274+ if (bot_start > x)
2275+ bot_start = x;
2276+ }
2277+ else // j > i
2278+ {
2279+ // move entries in w_lines[] downwards
2280+ j -= i;
2281+ wp->w_lines_valid += j;
2282+ if (wp->w_lines_valid > wp->w_height)
2283+ wp->w_lines_valid = wp->w_height;
2284+ for (i = wp->w_lines_valid; i - j >= idx; --i)
2285+ wp->w_lines[i] = wp->w_lines[i - j];
2286+
2287+ // The w_lines[] entries for inserted lines are
2288+ // now invalid, but wl_size may be used above.
2289+ // Reset to zero.
2290+ while (i >= idx)
2291+ {
2292+ wp->w_lines[i].wl_size = 0;
2293+ wp->w_lines[i--].wl_valid = FALSE;
2294+ }
2295+ }
2296+ }
2297+ }
2298+ }
2299+
2300+#ifdef FEAT_FOLDING
2301+ // When lines are folded, display one line for all of them.
2302+ // Otherwise, display normally (can be several display lines when
2303+ // 'wrap' is on).
2304+ fold_count = foldedCount(wp, lnum, &win_foldinfo);
2305+ if (fold_count != 0)
2306+ {
2307+ fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2308+ ++row;
2309+ --fold_count;
2310+ wp->w_lines[idx].wl_folded = TRUE;
2311+ wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
2312+# ifdef FEAT_SYN_HL
2313+ did_update = DID_FOLD;
2314+# endif
2315+ }
2316+ else
2317+#endif
2318+ if (idx < wp->w_lines_valid
2319+ && wp->w_lines[idx].wl_valid
2320+ && wp->w_lines[idx].wl_lnum == lnum
2321+ && lnum > wp->w_topline
2322+ && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
2323+ && !WIN_IS_POPUP(wp)
2324+ && srow + wp->w_lines[idx].wl_size > wp->w_height
2325+#ifdef FEAT_DIFF
2326+ && diff_check_fill(wp, lnum) == 0
2327+#endif
2328+ )
2329+ {
2330+ // This line is not going to fit. Don't draw anything here,
2331+ // will draw "@ " lines below.
2332+ row = wp->w_height + 1;
2333+ }
2334+ else
2335+ {
2336+#ifdef FEAT_SEARCH_EXTRA
2337+ prepare_search_hl(wp, &screen_search_hl, lnum);
2338+#endif
2339+#ifdef FEAT_SYN_HL
2340+ // Let the syntax stuff know we skipped a few lines.
2341+ if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
2342+ && syntax_present(wp))
2343+ syntax_end_parsing(syntax_last_parsed + 1);
2344+#endif
2345+
2346+ // Display one line.
2347+ row = win_line(wp, lnum, srow, wp->w_height,
2348+ mod_top == 0, FALSE);
2349+
2350+#ifdef FEAT_FOLDING
2351+ wp->w_lines[idx].wl_folded = FALSE;
2352+ wp->w_lines[idx].wl_lastlnum = lnum;
2353+#endif
2354+#ifdef FEAT_SYN_HL
2355+ did_update = DID_LINE;
2356+ syntax_last_parsed = lnum;
2357+#endif
2358+ }
2359+
2360+ wp->w_lines[idx].wl_lnum = lnum;
2361+ wp->w_lines[idx].wl_valid = TRUE;
2362+
2363+ // Past end of the window or end of the screen. Note that after
2364+ // resizing wp->w_height may be end up too big. That's a problem
2365+ // elsewhere, but prevent a crash here.
2366+ if (row > wp->w_height || row + wp->w_winrow >= Rows)
2367+ {
2368+ // we may need the size of that too long line later on
2369+ if (dollar_vcol == -1)
2370+ wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
2371+ ++idx;
2372+ break;
2373+ }
2374+ if (dollar_vcol == -1)
2375+ wp->w_lines[idx].wl_size = row - srow;
2376+ ++idx;
2377+#ifdef FEAT_FOLDING
2378+ lnum += fold_count + 1;
2379+#else
2380+ ++lnum;
2381+#endif
2382+ }
2383+ else
2384+ {
2385+ if (wp->w_p_rnu)
2386+ {
2387+#ifdef FEAT_FOLDING
2388+ // 'relativenumber' set: The text doesn't need to be drawn, but
2389+ // the number column nearly always does.
2390+ fold_count = foldedCount(wp, lnum, &win_foldinfo);
2391+ if (fold_count != 0)
2392+ fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2393+ else
2394+#endif
2395+ (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE);
2396+ }
2397+
2398+ // This line does not need to be drawn, advance to the next one.
2399+ row += wp->w_lines[idx++].wl_size;
2400+ if (row > wp->w_height) // past end of screen
2401+ break;
2402+#ifdef FEAT_FOLDING
2403+ lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
2404+#else
2405+ ++lnum;
2406+#endif
2407+#ifdef FEAT_SYN_HL
2408+ did_update = DID_NONE;
2409+#endif
2410+ }
2411+
2412+ if (lnum > buf->b_ml.ml_line_count)
2413+ {
2414+ eof = TRUE;
2415+ break;
2416+ }
2417+ }
2418+
2419+ // End of loop over all window lines.
2420+
2421+#ifdef FEAT_VTP
2422+ // Rewrite the character at the end of the screen line.
2423+ if (use_vtp())
2424+ {
2425+ int i;
2426+
2427+ for (i = 0; i < Rows; ++i)
2428+ if (enc_utf8)
2429+ if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
2430+ LineOffset[i] + screen_Columns) > 1)
2431+ screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
2432+ else
2433+ screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
2434+ else
2435+ screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
2436+ }
2437+#endif
2438+
2439+ if (idx > wp->w_lines_valid)
2440+ wp->w_lines_valid = idx;
2441+
2442+#ifdef FEAT_SYN_HL
2443+ // Let the syntax stuff know we stop parsing here.
2444+ if (syntax_last_parsed != 0 && syntax_present(wp))
2445+ syntax_end_parsing(syntax_last_parsed + 1);
2446+#endif
2447+
2448+ // If we didn't hit the end of the file, and we didn't finish the last
2449+ // line we were working on, then the line didn't fit.
2450+ wp->w_empty_rows = 0;
2451+#ifdef FEAT_DIFF
2452+ wp->w_filler_rows = 0;
2453+#endif
2454+ if (!eof && !didline)
2455+ {
2456+ if (lnum == wp->w_topline)
2457+ {
2458+ // Single line that does not fit!
2459+ // Don't overwrite it, it can be edited.
2460+ wp->w_botline = lnum + 1;
2461+ }
2462+#ifdef FEAT_DIFF
2463+ else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
2464+ {
2465+ // Window ends in filler lines.
2466+ wp->w_botline = lnum;
2467+ wp->w_filler_rows = wp->w_height - srow;
2468+ }
2469+#endif
2470+#ifdef FEAT_TEXT_PROP
2471+ else if (WIN_IS_POPUP(wp))
2472+ {
2473+ // popup line that doesn't fit is left as-is
2474+ wp->w_botline = lnum;
2475+ }
2476+#endif
2477+ else if (dy_flags & DY_TRUNCATE) // 'display' has "truncate"
2478+ {
2479+ int scr_row = W_WINROW(wp) + wp->w_height - 1;
2480+
2481+ // Last line isn't finished: Display "@@@" in the last screen line.
2482+ screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
2483+ HL_ATTR(HLF_AT));
2484+ screen_fill(scr_row, scr_row + 1,
2485+ (int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
2486+ '@', ' ', HL_ATTR(HLF_AT));
2487+ set_empty_rows(wp, srow);
2488+ wp->w_botline = lnum;
2489+ }
2490+ else if (dy_flags & DY_LASTLINE) // 'display' has "lastline"
2491+ {
2492+ // Last line isn't finished: Display "@@@" at the end.
2493+ screen_fill(W_WINROW(wp) + wp->w_height - 1,
2494+ W_WINROW(wp) + wp->w_height,
2495+ (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
2496+ '@', '@', HL_ATTR(HLF_AT));
2497+ set_empty_rows(wp, srow);
2498+ wp->w_botline = lnum;
2499+ }
2500+ else
2501+ {
2502+ win_draw_end(wp, '@', ' ', TRUE, srow, wp->w_height, HLF_AT);
2503+ wp->w_botline = lnum;
2504+ }
2505+ }
2506+ else
2507+ {
2508+ draw_vsep_win(wp, row);
2509+ if (eof) // we hit the end of the file
2510+ {
2511+ wp->w_botline = buf->b_ml.ml_line_count + 1;
2512+#ifdef FEAT_DIFF
2513+ j = diff_check_fill(wp, wp->w_botline);
2514+ if (j > 0 && !wp->w_botfill)
2515+ {
2516+ // Display filler lines at the end of the file.
2517+ if (char2cells(fill_diff) > 1)
2518+ i = '-';
2519+ else
2520+ i = fill_diff;
2521+ if (row + j > wp->w_height)
2522+ j = wp->w_height - row;
2523+ win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED);
2524+ row += j;
2525+ }
2526+#endif
2527+ }
2528+ else if (dollar_vcol == -1)
2529+ wp->w_botline = lnum;
2530+
2531+ // Make sure the rest of the screen is blank
2532+ // put '~'s on rows that aren't part of the file.
2533+ win_draw_end(wp, WIN_IS_POPUP(wp) ? ' ' : '~',
2534+ ' ', FALSE, row, wp->w_height, HLF_EOB);
2535+ }
2536+
2537+#ifdef SYN_TIME_LIMIT
2538+ syn_set_timeout(NULL);
2539+#endif
2540+
2541+ // Reset the type of redrawing required, the window has been updated.
2542+ wp->w_redr_type = 0;
2543+#ifdef FEAT_DIFF
2544+ wp->w_old_topfill = wp->w_topfill;
2545+ wp->w_old_botfill = wp->w_botfill;
2546+#endif
2547+
2548+ if (dollar_vcol == -1)
2549+ {
2550+ // There is a trick with w_botline. If we invalidate it on each
2551+ // change that might modify it, this will cause a lot of expensive
2552+ // calls to plines() in update_topline() each time. Therefore the
2553+ // value of w_botline is often approximated, and this value is used to
2554+ // compute the value of w_topline. If the value of w_botline was
2555+ // wrong, check that the value of w_topline is correct (cursor is on
2556+ // the visible part of the text). If it's not, we need to redraw
2557+ // again. Mostly this just means scrolling up a few lines, so it
2558+ // doesn't look too bad. Only do this for the current window (where
2559+ // changes are relevant).
2560+ wp->w_valid |= VALID_BOTLINE;
2561+ if (wp == curwin && wp->w_botline != old_botline && !recursive)
2562+ {
2563+ recursive = TRUE;
2564+ curwin->w_valid &= ~VALID_TOPLINE;
2565+ update_topline(); // may invalidate w_botline again
2566+ if (must_redraw != 0)
2567+ {
2568+ // Don't update for changes in buffer again.
2569+ i = curbuf->b_mod_set;
2570+ curbuf->b_mod_set = FALSE;
2571+ win_update(curwin);
2572+ must_redraw = 0;
2573+ curbuf->b_mod_set = i;
2574+ }
2575+ recursive = FALSE;
2576+ }
2577+ }
2578+
2579+#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2580+ // restore got_int, unless CTRL-C was hit while redrawing
2581+ if (!got_int)
2582+ got_int = save_got_int;
2583+#endif
2584+}
2585+
2586+#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI)
2587+/*
2588+ * Prepare for updating one or more windows.
2589+ * Caller must check for "updating_screen" already set to avoid recursiveness.
2590+ */
2591+ static void
2592+update_prepare(void)
2593+{
2594+ cursor_off();
2595+ updating_screen = TRUE;
2596+#ifdef FEAT_GUI
2597+ // Remove the cursor before starting to do anything, because scrolling may
2598+ // make it difficult to redraw the text under it.
2599+ if (gui.in_use)
2600+ gui_undraw_cursor();
2601+#endif
2602+#ifdef FEAT_SEARCH_EXTRA
2603+ start_search_hl();
2604+#endif
2605+#ifdef FEAT_TEXT_PROP
2606+ // Update popup_mask if needed.
2607+ may_update_popup_mask(must_redraw);
2608+#endif
2609+}
2610+
2611+/*
2612+ * Finish updating one or more windows.
2613+ */
2614+ static void
2615+update_finish(void)
2616+{
2617+ if (redraw_cmdline || redraw_mode)
2618+ showmode();
2619+
2620+# ifdef FEAT_SEARCH_EXTRA
2621+ end_search_hl();
2622+# endif
2623+
2624+ after_updating_screen(TRUE);
2625+
2626+# ifdef FEAT_GUI
2627+ // Redraw the cursor and update the scrollbars when all screen updating is
2628+ // done.
2629+ if (gui.in_use)
2630+ {
2631+ out_flush_cursor(FALSE, FALSE);
2632+ gui_update_scrollbars(FALSE);
2633+ }
2634+# endif
2635+}
2636+#endif
2637+
2638+#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
2639+ void
2640+update_debug_sign(buf_T *buf, linenr_T lnum)
2641+{
2642+ win_T *wp;
2643+ int doit = FALSE;
2644+
2645+# ifdef FEAT_FOLDING
2646+ win_foldinfo.fi_level = 0;
2647+# endif
2648+
2649+ // update/delete a specific sign
2650+ redraw_buf_line_later(buf, lnum);
2651+
2652+ // check if it resulted in the need to redraw a window
2653+ FOR_ALL_WINDOWS(wp)
2654+ if (wp->w_redr_type != 0)
2655+ doit = TRUE;
2656+
2657+ // Return when there is nothing to do, screen updating is already
2658+ // happening (recursive call), messages on the screen or still starting up.
2659+ if (!doit || updating_screen
2660+ || State == ASKMORE || State == HITRETURN
2661+ || msg_scrolled
2662+#ifdef FEAT_GUI
2663+ || gui.starting
2664+#endif
2665+ || starting)
2666+ return;
2667+
2668+ // update all windows that need updating
2669+ update_prepare();
2670+
2671+ FOR_ALL_WINDOWS(wp)
2672+ {
2673+ if (wp->w_redr_type != 0)
2674+ win_update(wp);
2675+ if (wp->w_redr_status)
2676+ win_redr_status(wp, FALSE);
2677+ }
2678+
2679+ update_finish();
2680+}
2681+#endif
2682+
2683+#if defined(FEAT_GUI) || defined(PROTO)
2684+/*
2685+ * Update a single window, its status line and maybe the command line msg.
2686+ * Used for the GUI scrollbar.
2687+ */
2688+ void
2689+updateWindow(win_T *wp)
2690+{
2691+ // return if already busy updating
2692+ if (updating_screen)
2693+ return;
2694+
2695+ update_prepare();
2696+
2697+#ifdef FEAT_CLIPBOARD
2698+ // When Visual area changed, may have to update selection.
2699+ if (clip_star.available && clip_isautosel_star())
2700+ clip_update_selection(&clip_star);
2701+ if (clip_plus.available && clip_isautosel_plus())
2702+ clip_update_selection(&clip_plus);
2703+#endif
2704+
2705+ win_update(wp);
2706+
2707+ // When the screen was cleared redraw the tab pages line.
2708+ if (redraw_tabline)
2709+ draw_tabline();
2710+
2711+ if (wp->w_redr_status
2712+# ifdef FEAT_CMDL_INFO
2713+ || p_ru
2714+# endif
2715+# ifdef FEAT_STL_OPT
2716+ || *p_stl != NUL || *wp->w_p_stl != NUL
2717+# endif
2718+ )
2719+ win_redr_status(wp, FALSE);
2720+
2721+#ifdef FEAT_TEXT_PROP
2722+ // Display popup windows on top of everything.
2723+ update_popups(win_update);
2724+#endif
2725+
2726+ update_finish();
2727+}
2728+#endif
2729+
2730+#if defined(FEAT_TERMRESPONSE) || defined(PROTO)
2731+/*
2732+ * Redraw as soon as possible. When the command line is not scrolled redraw
2733+ * right away and restore what was on the command line.
2734+ * Return a code indicating what happened.
2735+ */
2736+ int
2737+redraw_asap(int type)
2738+{
2739+ int rows;
2740+ int cols = screen_Columns;
2741+ int r;
2742+ int ret = 0;
2743+ schar_T *screenline; // copy from ScreenLines[]
2744+ sattr_T *screenattr; // copy from ScreenAttrs[]
2745+ int i;
2746+ u8char_T *screenlineUC = NULL; // copy from ScreenLinesUC[]
2747+ u8char_T *screenlineC[MAX_MCO]; // copy from ScreenLinesC[][]
2748+ schar_T *screenline2 = NULL; // copy from ScreenLines2[]
2749+
2750+ redraw_later(type);
2751+ if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
2752+ return ret;
2753+
2754+ // Allocate space to save the text displayed in the command line area.
2755+ rows = screen_Rows - cmdline_row;
2756+ screenline = LALLOC_MULT(schar_T, rows * cols);
2757+ screenattr = LALLOC_MULT(sattr_T, rows * cols);
2758+ if (screenline == NULL || screenattr == NULL)
2759+ ret = 2;
2760+ if (enc_utf8)
2761+ {
2762+ screenlineUC = LALLOC_MULT(u8char_T, rows * cols);
2763+ if (screenlineUC == NULL)
2764+ ret = 2;
2765+ for (i = 0; i < p_mco; ++i)
2766+ {
2767+ screenlineC[i] = LALLOC_MULT(u8char_T, rows * cols);
2768+ if (screenlineC[i] == NULL)
2769+ ret = 2;
2770+ }
2771+ }
2772+ if (enc_dbcs == DBCS_JPNU)
2773+ {
2774+ screenline2 = LALLOC_MULT(schar_T, rows * cols);
2775+ if (screenline2 == NULL)
2776+ ret = 2;
2777+ }
2778+
2779+ if (ret != 2)
2780+ {
2781+ // Save the text displayed in the command line area.
2782+ for (r = 0; r < rows; ++r)
2783+ {
2784+ mch_memmove(screenline + r * cols,
2785+ ScreenLines + LineOffset[cmdline_row + r],
2786+ (size_t)cols * sizeof(schar_T));
2787+ mch_memmove(screenattr + r * cols,
2788+ ScreenAttrs + LineOffset[cmdline_row + r],
2789+ (size_t)cols * sizeof(sattr_T));
2790+ if (enc_utf8)
2791+ {
2792+ mch_memmove(screenlineUC + r * cols,
2793+ ScreenLinesUC + LineOffset[cmdline_row + r],
2794+ (size_t)cols * sizeof(u8char_T));
2795+ for (i = 0; i < p_mco; ++i)
2796+ mch_memmove(screenlineC[i] + r * cols,
2797+ ScreenLinesC[i] + LineOffset[cmdline_row + r],
2798+ (size_t)cols * sizeof(u8char_T));
2799+ }
2800+ if (enc_dbcs == DBCS_JPNU)
2801+ mch_memmove(screenline2 + r * cols,
2802+ ScreenLines2 + LineOffset[cmdline_row + r],
2803+ (size_t)cols * sizeof(schar_T));
2804+ }
2805+
2806+ update_screen(0);
2807+ ret = 3;
2808+
2809+ if (must_redraw == 0)
2810+ {
2811+ int off = (int)(current_ScreenLine - ScreenLines);
2812+
2813+ // Restore the text displayed in the command line area.
2814+ for (r = 0; r < rows; ++r)
2815+ {
2816+ mch_memmove(current_ScreenLine,
2817+ screenline + r * cols,
2818+ (size_t)cols * sizeof(schar_T));
2819+ mch_memmove(ScreenAttrs + off,
2820+ screenattr + r * cols,
2821+ (size_t)cols * sizeof(sattr_T));
2822+ if (enc_utf8)
2823+ {
2824+ mch_memmove(ScreenLinesUC + off,
2825+ screenlineUC + r * cols,
2826+ (size_t)cols * sizeof(u8char_T));
2827+ for (i = 0; i < p_mco; ++i)
2828+ mch_memmove(ScreenLinesC[i] + off,
2829+ screenlineC[i] + r * cols,
2830+ (size_t)cols * sizeof(u8char_T));
2831+ }
2832+ if (enc_dbcs == DBCS_JPNU)
2833+ mch_memmove(ScreenLines2 + off,
2834+ screenline2 + r * cols,
2835+ (size_t)cols * sizeof(schar_T));
2836+ screen_line(cmdline_row + r, 0, cols, cols, 0);
2837+ }
2838+ ret = 4;
2839+ }
2840+ }
2841+
2842+ vim_free(screenline);
2843+ vim_free(screenattr);
2844+ if (enc_utf8)
2845+ {
2846+ vim_free(screenlineUC);
2847+ for (i = 0; i < p_mco; ++i)
2848+ vim_free(screenlineC[i]);
2849+ }
2850+ if (enc_dbcs == DBCS_JPNU)
2851+ vim_free(screenline2);
2852+
2853+ // Show the intro message when appropriate.
2854+ maybe_intro_message();
2855+
2856+ setcursor();
2857+
2858+ return ret;
2859+}
2860+#endif
2861+
2862+/*
2863+ * Invoked after an asynchronous callback is called.
2864+ * If an echo command was used the cursor needs to be put back where
2865+ * it belongs. If highlighting was changed a redraw is needed.
2866+ * If "call_update_screen" is FALSE don't call update_screen() when at the
2867+ * command line.
2868+ */
2869+ void
2870+redraw_after_callback(int call_update_screen)
2871+{
2872+ ++redrawing_for_callback;
2873+
2874+ if (State == HITRETURN || State == ASKMORE)
2875+ ; // do nothing
2876+ else if (State & CMDLINE)
2877+ {
2878+ // Don't redraw when in prompt_for_number().
2879+ if (cmdline_row > 0)
2880+ {
2881+ // Redrawing only works when the screen didn't scroll. Don't clear
2882+ // wildmenu entries.
2883+ if (msg_scrolled == 0
2884+#ifdef FEAT_WILDMENU
2885+ && wild_menu_showing == 0
2886+#endif
2887+ && call_update_screen)
2888+ update_screen(0);
2889+
2890+ // Redraw in the same position, so that the user can continue
2891+ // editing the command.
2892+ redrawcmdline_ex(FALSE);
2893+ }
2894+ }
2895+ else if (State & (NORMAL | INSERT | TERMINAL))
2896+ {
2897+ // keep the command line if possible
2898+ update_screen(VALID_NO_UPDATE);
2899+ setcursor();
2900+ }
2901+ cursor_on();
2902+#ifdef FEAT_GUI
2903+ if (gui.in_use && !gui_mch_is_blink_off())
2904+ // Don't update the cursor when it is blinking and off to avoid
2905+ // flicker.
2906+ out_flush_cursor(FALSE, FALSE);
2907+ else
2908+#endif
2909+ out_flush();
2910+
2911+ --redrawing_for_callback;
2912+}
2913+
2914+/*
2915+ * Redraw the current window later, with update_screen(type).
2916+ * Set must_redraw only if not already set to a higher value.
2917+ * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
2918+ */
2919+ void
2920+redraw_later(int type)
2921+{
2922+ redraw_win_later(curwin, type);
2923+}
2924+
2925+ void
2926+redraw_win_later(
2927+ win_T *wp,
2928+ int type)
2929+{
2930+ if (!exiting && wp->w_redr_type < type)
2931+ {
2932+ wp->w_redr_type = type;
2933+ if (type >= NOT_VALID)
2934+ wp->w_lines_valid = 0;
2935+ if (must_redraw < type) // must_redraw is the maximum of all windows
2936+ must_redraw = type;
2937+ }
2938+}
2939+
2940+/*
2941+ * Force a complete redraw later. Also resets the highlighting. To be used
2942+ * after executing a shell command that messes up the screen.
2943+ */
2944+ void
2945+redraw_later_clear(void)
2946+{
2947+ redraw_all_later(CLEAR);
2948+ reset_screen_attr();
2949+}
2950+
2951+/*
2952+ * Mark all windows to be redrawn later.
2953+ */
2954+ void
2955+redraw_all_later(int type)
2956+{
2957+ win_T *wp;
2958+
2959+ FOR_ALL_WINDOWS(wp)
2960+ redraw_win_later(wp, type);
2961+ // This may be needed when switching tabs.
2962+ if (must_redraw < type)
2963+ must_redraw = type;
2964+}
2965+
2966+/*
2967+ * Mark all windows that are editing the current buffer to be updated later.
2968+ */
2969+ void
2970+redraw_curbuf_later(int type)
2971+{
2972+ redraw_buf_later(curbuf, type);
2973+}
2974+
2975+ void
2976+redraw_buf_later(buf_T *buf, int type)
2977+{
2978+ win_T *wp;
2979+
2980+ FOR_ALL_WINDOWS(wp)
2981+ {
2982+ if (wp->w_buffer == buf)
2983+ redraw_win_later(wp, type);
2984+ }
2985+}
2986+
2987+#if defined(FEAT_SIGNS) || defined(PROTO)
2988+ void
2989+redraw_buf_line_later(buf_T *buf, linenr_T lnum)
2990+{
2991+ win_T *wp;
2992+
2993+ FOR_ALL_WINDOWS(wp)
2994+ if (wp->w_buffer == buf && lnum >= wp->w_topline
2995+ && lnum < wp->w_botline)
2996+ redrawWinline(wp, lnum);
2997+}
2998+#endif
2999+
3000+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
3001+ void
3002+redraw_buf_and_status_later(buf_T *buf, int type)
3003+{
3004+ win_T *wp;
3005+
3006+#ifdef FEAT_WILDMENU
3007+ if (wild_menu_showing != 0)
3008+ // Don't redraw while the command line completion is displayed, it
3009+ // would disappear.
3010+ return;
3011+#endif
3012+ FOR_ALL_WINDOWS(wp)
3013+ {
3014+ if (wp->w_buffer == buf)
3015+ {
3016+ redraw_win_later(wp, type);
3017+ wp->w_redr_status = TRUE;
3018+ }
3019+ }
3020+}
3021+#endif
3022+
3023+/*
3024+ * mark all status lines for redraw; used after first :cd
3025+ */
3026+ void
3027+status_redraw_all(void)
3028+{
3029+ win_T *wp;
3030+
3031+ FOR_ALL_WINDOWS(wp)
3032+ if (wp->w_status_height)
3033+ {
3034+ wp->w_redr_status = TRUE;
3035+ redraw_later(VALID);
3036+ }
3037+}
3038+
3039+/*
3040+ * mark all status lines of the current buffer for redraw
3041+ */
3042+ void
3043+status_redraw_curbuf(void)
3044+{
3045+ win_T *wp;
3046+
3047+ FOR_ALL_WINDOWS(wp)
3048+ if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
3049+ {
3050+ wp->w_redr_status = TRUE;
3051+ redraw_later(VALID);
3052+ }
3053+}
3054+
3055+/*
3056+ * Redraw all status lines that need to be redrawn.
3057+ */
3058+ void
3059+redraw_statuslines(void)
3060+{
3061+ win_T *wp;
3062+
3063+ FOR_ALL_WINDOWS(wp)
3064+ if (wp->w_redr_status)
3065+ win_redr_status(wp, FALSE);
3066+ if (redraw_tabline)
3067+ draw_tabline();
3068+}
3069+
3070+#if defined(FEAT_WILDMENU) || defined(PROTO)
3071+/*
3072+ * Redraw all status lines at the bottom of frame "frp".
3073+ */
3074+ void
3075+win_redraw_last_status(frame_T *frp)
3076+{
3077+ if (frp->fr_layout == FR_LEAF)
3078+ frp->fr_win->w_redr_status = TRUE;
3079+ else if (frp->fr_layout == FR_ROW)
3080+ {
3081+ FOR_ALL_FRAMES(frp, frp->fr_child)
3082+ win_redraw_last_status(frp);
3083+ }
3084+ else // frp->fr_layout == FR_COL
3085+ {
3086+ frp = frp->fr_child;
3087+ while (frp->fr_next != NULL)
3088+ frp = frp->fr_next;
3089+ win_redraw_last_status(frp);
3090+ }
3091+}
3092+#endif
3093+
3094+/*
3095+ * Changed something in the current window, at buffer line "lnum", that
3096+ * requires that line and possibly other lines to be redrawn.
3097+ * Used when entering/leaving Insert mode with the cursor on a folded line.
3098+ * Used to remove the "$" from a change command.
3099+ * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
3100+ * may become invalid and the whole window will have to be redrawn.
3101+ */
3102+ void
3103+redrawWinline(
3104+ win_T *wp,
3105+ linenr_T lnum)
3106+{
3107+ if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
3108+ wp->w_redraw_top = lnum;
3109+ if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
3110+ wp->w_redraw_bot = lnum;
3111+ redraw_win_later(wp, VALID);
3112+}
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/globals.h
--- a/src/globals.h Wed Sep 18 22:15:04 2019 +0200
+++ b/src/globals.h Thu Sep 19 23:15:05 2019 +0200
@@ -62,6 +62,31 @@
6262 EXTERN schar_T *ScreenLines2 INIT(= NULL);
6363
6464 /*
65+ * Buffer for one screen line (characters and attributes).
66+ */
67+EXTERN schar_T *current_ScreenLine INIT(= NULL);
68+
69+/*
70+ * Last known cursor position.
71+ * Positioning the cursor is reduced by remembering the last position.
72+ * Mostly used by windgoto() and screen_char().
73+ */
74+EXTERN int screen_cur_row INIT(= 0);
75+EXTERN int screen_cur_col INIT(= 0);
76+
77+#ifdef FEAT_SEARCH_EXTRA
78+EXTERN match_T screen_search_hl; // used for 'hlsearch' highlight matching
79+#endif
80+
81+#ifdef FEAT_FOLDING
82+EXTERN foldinfo_T win_foldinfo; // info for 'foldcolumn'
83+#endif
84+
85+// Flag that is set when drawing for a callback, not from the main command
86+// loop.
87+EXTERN int redrawing_for_callback INIT(= 0);
88+
89+/*
6590 * Indexes for tab page line:
6691 * N > 0 for label of tab page N
6792 * N == 0 for no label
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/proto.h
--- a/src/proto.h Wed Sep 18 22:15:04 2019 +0200
+++ b/src/proto.h Thu Sep 19 23:15:05 2019 +0200
@@ -73,6 +73,8 @@
7373 # include "dict.pro"
7474 # include "diff.pro"
7575 # include "digraph.pro"
76+# include "drawline.pro"
77+# include "drawscreen.pro"
7678 # include "edit.pro"
7779 # include "eval.pro"
7880 # include "evalbuffer.pro"
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/proto/drawline.pro
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto/drawline.pro Thu Sep 19 23:15:05 2019 +0200
@@ -0,0 +1,3 @@
1+/* drawline.c */
2+int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int nochange, int number_only);
3+/* vim: set ft=c : */
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/proto/drawscreen.pro
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto/drawscreen.pro Thu Sep 19 23:15:05 2019 +0200
@@ -0,0 +1,25 @@
1+/* drawscreen.c */
2+int update_screen(int type_arg);
3+void win_redr_status(win_T *wp, int ignore_pum);
4+void showruler(int always);
5+void win_redr_ruler(win_T *wp, int always, int ignore_pum);
6+void after_updating_screen(int may_resize_shell);
7+void update_curbuf(int type);
8+void update_debug_sign(buf_T *buf, linenr_T lnum);
9+void updateWindow(win_T *wp);
10+int redraw_asap(int type);
11+void redraw_after_callback(int call_update_screen);
12+void redraw_later(int type);
13+void redraw_win_later(win_T *wp, int type);
14+void redraw_later_clear(void);
15+void redraw_all_later(int type);
16+void redraw_curbuf_later(int type);
17+void redraw_buf_later(buf_T *buf, int type);
18+void redraw_buf_line_later(buf_T *buf, linenr_T lnum);
19+void redraw_buf_and_status_later(buf_T *buf, int type);
20+void status_redraw_all(void);
21+void status_redraw_curbuf(void);
22+void redraw_statuslines(void);
23+void win_redraw_last_status(frame_T *frp);
24+void redrawWinline(win_T *wp, linenr_T lnum);
25+/* vim: set ft=c : */
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/proto/screen.pro
--- a/src/proto/screen.pro Wed Sep 18 22:15:04 2019 +0200
+++ b/src/proto/screen.pro Thu Sep 19 23:15:05 2019 +0200
@@ -1,40 +1,30 @@
11 /* screen.c */
2-void redraw_later(int type);
3-void redraw_win_later(win_T *wp, int type);
4-void redraw_later_clear(void);
5-void redraw_all_later(int type);
6-void redraw_curbuf_later(int type);
7-void redraw_buf_later(buf_T *buf, int type);
8-void redraw_buf_line_later(buf_T *buf, linenr_T lnum);
9-void redraw_buf_and_status_later(buf_T *buf, int type);
10-int redraw_asap(int type);
11-void redraw_after_callback(int call_update_screen);
12-void redrawWinline(win_T *wp, linenr_T lnum);
13-void after_updating_screen(int may_resize_shell);
14-void update_curbuf(int type);
15-int update_screen(int type_arg);
162 int conceal_cursor_line(win_T *wp);
173 void conceal_check_cursor_line(void);
18-void update_debug_sign(buf_T *buf, linenr_T lnum);
194 int get_wcr_attr(win_T *wp);
20-void updateWindow(win_T *wp);
5+void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl);
6+int compute_foldcolumn(win_T *wp, int col);
7+void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
218 int screen_get_current_line_off(void);
9+void reset_screen_attr(void);
2210 void screen_line(int row, int coloff, int endcol, int clear_width, int flags);
2311 void rl_mirror(char_u *str);
24-void status_redraw_all(void);
25-void status_redraw_curbuf(void);
26-void redraw_statuslines(void);
27-void win_redraw_last_status(frame_T *frp);
12+void draw_vsep_win(win_T *wp, int row);
2813 void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, int match, int showtail);
2914 int stl_connected(win_T *wp);
3015 int get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len);
16+void win_redr_custom(win_T *wp, int draw_ruler);
3117 void screen_putchar(int c, int row, int col, int attr);
3218 void screen_getbytes(int row, int col, char_u *bytes, int *attrp);
3319 void screen_puts(char_u *text, int row, int col, int attr);
3420 void screen_puts_len(char_u *text, int textlen, int row, int col, int attr);
21+void start_search_hl(void);
22+void end_search_hl(void);
3523 void screen_stop_highlight(void);
3624 void reset_cterm_colors(void);
25+void screen_char(unsigned off, int row, int col);
3726 void screen_draw_rectangle(int row, int col, int height, int width, int invert);
27+void space_to_screenline(int off, int attr);
3828 void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1, int c2, int attr);
3929 void check_for_delay(int check_msg_scroll);
4030 int screen_valid(int doclear);
@@ -56,9 +46,10 @@
5646 void clearmode(void);
5747 void draw_tabline(void);
5848 void get_trans_bufname(buf_T *buf);
49+int fillchar_status(int *attr, win_T *wp);
50+int fillchar_vsep(int *attr);
5951 int redrawing(void);
6052 int messaging(void);
61-void showruler(int always);
6253 void comp_col(void);
6354 int number_width(win_T *wp);
6455 int screen_screencol(void);
diff -r ceb4be0b23c7 -r 2a806e3c39f6 src/screen.c
--- a/src/screen.c Wed Sep 18 22:15:04 2019 +0200
+++ b/src/screen.c Thu Sep 19 23:15:05 2019 +0200
@@ -8,7 +8,7 @@
88 */
99
1010 /*
11- * screen.c: code for displaying on the screen
11+ * screen.c: Lower level code for displaying on the screen.
1212 *
1313 * Output to the screen (console, terminal emulator or GUI window) is minimized
1414 * by remembering what is already on the screen, and only updating the parts
@@ -35,110 +35,15 @@
3535 *
3636 * The screen_*() functions write to the screen and handle updating
3737 * 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.
8838 */
8939
9040 #include "vim.h"
9141
92-#define MB_FILLER_CHAR '<' /* character used when a double-width character
93- * doesn't fit. */
94-
9542 /*
9643 * The attributes that are actually active for writing to the screen.
9744 */
9845 static int screen_attr = 0;
9946
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);
14247 static void screen_char_2(unsigned off, int row, int col);
14348 static void screenclear2(void);
14449 static void lineclear(unsigned off, int width, int attr);
@@ -147,762 +52,10 @@
14752 static void win_rest_invalid(win_T *wp);
14853 static void msg_pos_mode(void);
14954 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
16455
16556 /* Ugly global: overrule attribute used by screen_char() */
16657 static int screen_char_attr = 0;
16758
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-
90659 #if defined(FEAT_CONCEAL) || defined(PROTO)
90760 /*
90861 * Return TRUE if the cursor line in window "wp" may be concealed, according
@@ -944,52 +97,6 @@
94497 }
94598 #endif
94699
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-
993100 /*
994101 * Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
995102 * window then get the "Pmenu" highlight attribute.
@@ -1013,1353 +120,6 @@
1013120 return wcr_attr;
1014121 }
1015122
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