summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-05-25 19:51:39 +0200
committerBram Moolenaar <Bram@vim.org>2019-05-25 19:51:39 +0200
commit4d784b21d14fc66e98a2b07f70343cdd4acd62aa (patch)
treec2e869a4f07eebdf7e0272c74b0fe7392807836c /src
parent8f46e4c4bde13fd5ad68a6670b79cc462b65fbec (diff)
downloadvim-git-4d784b21d14fc66e98a2b07f70343cdd4acd62aa.tar.gz
patch 8.1.1391: no popup window supportv8.1.1391
Problem: No popup window support. Solution: Add initial code for popup windows. Add the 'wincolor' option.
Diffstat (limited to 'src')
-rw-r--r--src/Make_cyg_ming.mak1
-rw-r--r--src/Make_mvc.mak5
-rw-r--r--src/Make_vms.mms10
-rw-r--r--src/Makefile10
-rw-r--r--src/autocmd.c18
-rw-r--r--src/buffer.c14
-rw-r--r--src/eval.c26
-rw-r--r--src/evalfunc.c4
-rw-r--r--src/ex_cmdidxs.h24
-rw-r--r--src/ex_cmds.h3
-rw-r--r--src/feature.h2
-rw-r--r--src/globals.h12
-rw-r--r--src/option.c11
-rw-r--r--src/option.h1
-rw-r--r--src/popupwin.c231
-rw-r--r--src/proto.h1
-rw-r--r--src/proto/buffer.pro1
-rw-r--r--src/proto/popupwin.pro7
-rw-r--r--src/proto/window.pro5
-rw-r--r--src/screen.c171
-rw-r--r--src/structs.h58
-rw-r--r--src/terminal.c4
-rw-r--r--src/testdir/Make_all.mak6
-rw-r--r--src/testdir/dumps/Test_popupwin_01.dump10
-rw-r--r--src/testdir/test_popupwin.vim26
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h17
-rw-r--r--src/window.c176
28 files changed, 708 insertions, 148 deletions
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index 7844e004c..f47981216 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -740,6 +740,7 @@ OBJ = \
$(OUTDIR)/os_win32.o \
$(OUTDIR)/pathdef.o \
$(OUTDIR)/popupmnu.o \
+ $(OUTDIR)/popupwin.o \
$(OUTDIR)/quickfix.o \
$(OUTDIR)/regexp.o \
$(OUTDIR)/screen.o \
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index f8e406e43..c1cd0a460 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -743,6 +743,8 @@ OBJ = \
$(OUTDIR)\os_win32.obj \
$(OUTDIR)\pathdef.obj \
$(OUTDIR)\popupmnu.obj \
+ $(OUTDIR)\popupwin.obj \
+ $(OUTDIR)\popupwin.obj \
$(OUTDIR)\quickfix.obj \
$(OUTDIR)\regexp.obj \
$(OUTDIR)\screen.obj \
@@ -1575,6 +1577,8 @@ $(OUTDIR)/pathdef.obj: $(OUTDIR) $(PATHDEF_SRC) $(INCL)
$(OUTDIR)/popupmnu.obj: $(OUTDIR) popupmnu.c $(INCL)
+$(OUTDIR)/popupwin.obj: $(OUTDIR) popupwin.c $(INCL)
+
$(OUTDIR)/quickfix.obj: $(OUTDIR) quickfix.c $(INCL)
$(OUTDIR)/regexp.obj: $(OUTDIR) regexp.c regexp_nfa.c $(INCL)
@@ -1745,6 +1749,7 @@ proto.h: \
proto/winclip.pro \
proto/os_win32.pro \
proto/popupmnu.pro \
+ proto/popupwin.pro \
proto/quickfix.pro \
proto/regexp.pro \
proto/screen.pro \
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index 1a0537bc8..f01d325c0 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -2,7 +2,7 @@
# Makefile for Vim on OpenVMS
#
# Maintainer: Zoltan Arpadffy <arpadffy@polarhome.com>
-# Last change: 2019 May 11
+# Last change: 2019 May 24
#
# This has script been tested on VMS 6.2 to 8.2 on DEC Alpha, VAX and IA64
# with MMS and MMK
@@ -313,7 +313,7 @@ SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c change.c charset.c \
if_cscope.c if_xcmdsrv.c fileio.c findfile.c fold.c getchar.c \
hardcopy.c hashtab.c indent.c insexpand.c json.c list.c main.c mark.c \
menu.c mbyte.c memfile.c memline.c message.c misc1.c misc2.c move.c \
- normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c \
+ normal.c ops.c option.c popupmnu.c popupwin.c, quickfix.c regexp.c search.c \
sha256.c sign.c spell.c spellfile.c syntax.c tag.c term.c termlib.c \
textprop.c ui.c undo.c usercmd.c userfunc.c version.c screen.c \
window.c os_unix.c os_vms.c pathdef.c \
@@ -327,7 +327,7 @@ OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj change.
fileio.obj findfile.obj fold.obj getchar.obj hardcopy.obj hashtab.obj \
indent.obj insexpand.obj json.obj list.obj main.obj mark.obj \
menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
- move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj \
+ move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj popupwin.obj\
quickfix.obj regexp.obj search.obj sha256.obj sign.obj spell.obj \
spellfile.obj syntax.obj tag.obj term.obj termlib.obj textprop.obj \
ui.obj undo.obj usercmd.obj userfunc.obj screen.obj version.obj \
@@ -688,6 +688,10 @@ popupmnu.obj : popupmnu.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h \
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
globals.h
+popupwin.obj : popupwin.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h
quickfix.obj : quickfix.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h \
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
diff --git a/src/Makefile b/src/Makefile
index ff5ae1016..d74eac40a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1620,6 +1620,7 @@ BASIC_SRC = \
os_unix.c \
auto/pathdef.c \
popupmnu.c \
+ popupwin.c \
pty.c \
quickfix.c \
regexp.c \
@@ -1734,6 +1735,7 @@ OBJ_COMMON = \
objects/os_unix.o \
objects/pathdef.o \
objects/popupmnu.o \
+ objects/popupwin.o \
objects/pty.o \
objects/quickfix.o \
objects/regexp.o \
@@ -1873,6 +1875,7 @@ PRO_AUTO = \
os_mac_conv.pro \
os_unix.pro \
popupmnu.pro \
+ popupwin.pro \
pty.pro \
quickfix.pro \
regexp.pro \
@@ -3208,6 +3211,9 @@ objects/pathdef.o: auto/pathdef.c
objects/popupmnu.o: popupmnu.c
$(CCC) -o $@ popupmnu.c
+objects/popupwin.o: popupwin.c
+ $(CCC) -o $@ popupwin.c
+
objects/pty.o: pty.c
$(CCC) -o $@ pty.c
@@ -3612,6 +3618,10 @@ objects/popupmnu.o: popupmnu.c vim.h protodef.h auto/config.h feature.h os_unix.
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
proto.h globals.h
+objects/popupwin.o: popupwin.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h
objects/pty.o: pty.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
diff --git a/src/autocmd.c b/src/autocmd.c
index 614bc331f..152dabde7 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -1349,7 +1349,7 @@ ex_doautoall(exarg_T *eap)
*/
FOR_ALL_BUFFERS(buf)
{
- if (buf->b_ml.ml_mfp != NULL)
+ if (buf->b_ml.ml_mfp != NULL && !bt_popup(buf))
{
// find a window for this buffer and save some values
aucmd_prepbuf(&aco, buf);
@@ -1423,7 +1423,7 @@ aucmd_prepbuf(
// back to using the current window.
if (win == NULL && aucmd_win == NULL)
{
- win_alloc_aucmd_win();
+ aucmd_win = win_alloc_popup_win();
if (aucmd_win == NULL)
win = curwin;
}
@@ -1451,20 +1451,12 @@ aucmd_prepbuf(
// unexpected results.
aco->use_aucmd_win = TRUE;
aucmd_win_used = TRUE;
- aucmd_win->w_buffer = buf;
-#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
- aucmd_win->w_s = &buf->b_s;
-#endif
- ++buf->b_nwindows;
- win_init_empty(aucmd_win); // set cursor and topline to safe values
- // Make sure w_localdir and globaldir are NULL to avoid a chdir() in
- // win_enter_ext().
- VIM_CLEAR(aucmd_win->w_localdir);
+ win_init_popup_win(aucmd_win, buf);
+
aco->globaldir = globaldir;
globaldir = NULL;
-
// Split the current window, put the aucmd_win in the upper half.
// We don't want the BufEnter or WinEnter autocommands.
block_autocmds();
@@ -1620,6 +1612,8 @@ apply_autocmds(
int force, // when TRUE, ignore autocmd_busy
buf_T *buf) // buffer for <abuf>
{
+ if (bt_popup(buf))
+ return FALSE;
return apply_autocmds_group(event, fname, fname_io, force,
AUGROUP_ALL, buf, NULL);
}
diff --git a/src/buffer.c b/src/buffer.c
index f6210952d..6174d80ce 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -456,7 +456,7 @@ close_buffer(
win_T *win, /* if not NULL, set b_last_cursor */
buf_T *buf,
int action,
- int abort_if_last UNUSED)
+ int abort_if_last)
{
int is_curbuf;
int nwindows;
@@ -5678,7 +5678,17 @@ bt_help(buf_T *buf)
int
bt_prompt(buf_T *buf)
{
- return buf != NULL && buf->b_p_bt[0] == 'p';
+ return buf != NULL && buf->b_p_bt[0] == 'p' && buf->b_p_bt[1] == 'r';
+}
+
+/*
+ * Return TRUE if "buf" is a buffer for a popup window.
+ */
+ int
+bt_popup(buf_T *buf)
+{
+ return buf != NULL && buf->b_p_bt != NULL
+ && buf->b_p_bt[0] == 'p' && buf->b_p_bt[1] == 'o';
}
/*
diff --git a/src/eval.c b/src/eval.c
index 1d5d0f11a..fb417c8b4 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -5585,6 +5585,19 @@ garbage_collect(int testing)
if (aucmd_win != NULL)
abort = abort || set_ref_in_item(&aucmd_win->w_winvar.di_tv, copyID,
NULL, NULL);
+#ifdef FEAT_TEXT_PROP
+ for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+ abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
+ NULL, NULL);
+ for (wp = first_tab_popupwin; wp != NULL; wp = wp->w_next)
+ abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
+ NULL, NULL);
+ FOR_ALL_TABPAGES(tp)
+ if (tp != curtab)
+ for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
+ abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
+ NULL, NULL);
+#endif
/* tabpage-local variables */
FOR_ALL_TABPAGES(tp)
@@ -8801,7 +8814,20 @@ find_win_by_nr(
break;
}
if (nr >= LOWEST_WIN_ID)
+ {
+#ifdef FEAT_TEXT_PROP
+ // popup windows are in a separate list
+ for (wp = (tp == NULL || tp == curtab)
+ ? first_tab_popupwin : tp->tp_first_popupwin;
+ wp != NULL; wp = wp->w_next)
+ if (wp->w_id == nr)
+ return wp;
+ for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+ if (wp->w_id == nr)
+ return wp;
+#endif
return NULL;
+ }
return wp;
}
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 58ea7103f..914efb1c9 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -807,6 +807,10 @@ static struct fst
#ifdef FEAT_PERL
{"perleval", 1, 1, f_perleval},
#endif
+#ifdef FEAT_TEXT_PROP
+ {"popup_close", 1, 1, f_popup_close},
+ {"popup_create", 2, 2, f_popup_create},
+#endif
#ifdef FEAT_FLOAT
{"pow", 2, 2, f_pow},
#endif
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index 0103a1741..2aae4b63d 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -21,16 +21,16 @@ static const unsigned short cmdidxs1[26] =
/* n */ 285,
/* o */ 305,
/* p */ 317,
- /* q */ 356,
- /* r */ 359,
- /* s */ 379,
- /* t */ 447,
- /* u */ 492,
- /* v */ 503,
- /* w */ 521,
- /* x */ 535,
- /* y */ 545,
- /* z */ 546
+ /* q */ 357,
+ /* r */ 360,
+ /* s */ 380,
+ /* t */ 448,
+ /* u */ 493,
+ /* v */ 504,
+ /* w */ 522,
+ /* x */ 536,
+ /* y */ 546,
+ /* z */ 547
};
/*
@@ -56,7 +56,7 @@ static const unsigned char cmdidxs2[26][26] =
/* m */ { 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 },
/* n */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 10, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0 },
/* o */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 0, 9, 0, 11, 0, 0, 0 },
- /* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 16, 17, 26, 0, 27, 0, 28, 0 },
+ /* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 10, 0, 0, 17, 18, 27, 0, 28, 0, 29, 0 },
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 },
/* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 49, 0, 50, 0, 62, 63, 0, 64, 0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
-static const int command_count = 559;
+static const int command_count = 560;
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 5ec69be36..9c913a8f6 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1091,6 +1091,9 @@ EX(CMD_pop, "pop", ex_tag,
EX(CMD_popup, "popup", ex_popup,
NEEDARG|EXTRA|BANG|TRLBAR|NOTRLCOM|CMDWIN,
ADDR_NONE),
+EX(CMD_popupclear, "popupclear", ex_popupclear,
+ TRLBAR,
+ ADDR_NONE),
EX(CMD_ppop, "ppop", ex_ptag,
RANGE|BANG|COUNT|TRLBAR|ZEROR,
ADDR_OTHER),
diff --git a/src/feature.h b/src/feature.h
index bfbabe0af..c613c4bc9 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -477,7 +477,7 @@
#endif
/*
- * +textprop Text properties
+ * +textprop Text properties and popup windows
*/
#if defined(FEAT_EVAL) && defined(FEAT_SYN_HL)
# define FEAT_TEXT_PROP
diff --git a/src/globals.h b/src/globals.h
index 09ac6b5e8..7d250f443 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -550,9 +550,10 @@ EXTERN int clip_unnamed_saved INIT(= 0);
#endif
/*
- * All windows are linked in a list. firstwin points to the first entry,
- * lastwin to the last entry (can be the same as firstwin) and curwin to the
- * currently active window.
+ * All regular windows are linked in a list. "firstwin" points to the first
+ * entry, "lastwin" to the last entry (can be the same as firstwin) and
+ * "curwin" to the currently active window.
+ * When switching tabs these swapped with the pointers in "tabpage_T".
*/
EXTERN win_T *firstwin; /* first window */
EXTERN win_T *lastwin; /* last window */
@@ -580,6 +581,11 @@ EXTERN win_T *curwin; /* currently active window */
EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */
EXTERN int aucmd_win_used INIT(= FALSE); /* aucmd_win is being used */
+#ifdef FEAT_TEXT_PROP
+EXTERN win_T *first_tab_popupwin; // first popup window local to tab page
+EXTERN win_T *first_popupwin; // first global popup window
+#endif
+
/*
* The window layout is kept in a tree of frames. topframe points to the top
* of the tree.
diff --git a/src/option.c b/src/option.c
index 42a252e0f..9b23eed58 100644
--- a/src/option.c
+++ b/src/option.c
@@ -196,6 +196,7 @@
# define PV_BRI OPT_WIN(WV_BRI)
# define PV_BRIOPT OPT_WIN(WV_BRIOPT)
#endif
+# define PV_WCR OPT_WIN(WV_WCR)
#ifdef FEAT_DIFF
# define PV_DIFF OPT_WIN(WV_DIFF)
#endif
@@ -3033,6 +3034,10 @@ static struct vimoption options[] =
{(char_u *)NULL, (char_u *)0L}
#endif
SCTX_INIT},
+ {"wincolor", "wcr", P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN,
+ (char_u *)VAR_WIN, PV_WCR,
+ {(char_u *)"", (char_u *)NULL}
+ SCTX_INIT},
{"window", "wi", P_NUM|P_VI_DEF,
(char_u *)&p_window, PV_NONE,
{(char_u *)0L, (char_u *)0L} SCTX_INIT},
@@ -3211,7 +3216,7 @@ static char *(p_bsdir_values[]) = {"current", "last", "buffer", NULL};
static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL};
static char *(p_debug_values[]) = {"msg", "throw", "beep", NULL};
static char *(p_ead_values[]) = {"both", "ver", "hor", NULL};
-static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", "acwrite", "prompt", NULL};
+static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", "acwrite", "prompt", "popup", NULL};
static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
static char *(p_bs_values[]) = {"indent", "eol", "start", NULL};
#ifdef FEAT_FOLDING
@@ -10940,6 +10945,7 @@ get_varp(struct vimoption *p)
case PV_BRI: return (char_u *)&(curwin->w_p_bri);
case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt);
#endif
+ case PV_WCR: return (char_u *)&(curwin->w_p_wcr);
case PV_SCBIND: return (char_u *)&(curwin->w_p_scb);
case PV_CRBIND: return (char_u *)&(curwin->w_p_crb);
#ifdef FEAT_CONCEAL
@@ -11124,6 +11130,7 @@ copy_winopt(winopt_T *from, winopt_T *to)
to->wo_bri = from->wo_bri;
to->wo_briopt = vim_strsave(from->wo_briopt);
#endif
+ to->wo_wcr = vim_strsave(from->wo_wcr);
to->wo_scb = from->wo_scb;
to->wo_scb_save = from->wo_scb_save;
to->wo_crb = from->wo_crb;
@@ -11221,6 +11228,7 @@ check_winopt(winopt_T *wop UNUSED)
#ifdef FEAT_LINEBREAK
check_string_option(&wop->wo_briopt);
#endif
+ check_string_option(&wop->wo_wcr);
}
/*
@@ -11245,6 +11253,7 @@ clear_winopt(winopt_T *wop UNUSED)
#ifdef FEAT_LINEBREAK
clear_string_option(&wop->wo_briopt);
#endif
+ clear_string_option(&wop->wo_wcr);
#ifdef FEAT_RIGHTLEFT
clear_string_option(&wop->wo_rlc);
#endif
diff --git a/src/option.h b/src/option.h
index 082ff9b7c..7e657ddc3 100644
--- a/src/option.h
+++ b/src/option.h
@@ -1116,6 +1116,7 @@ enum
, WV_BRI
, WV_BRIOPT
#endif
+ , WV_WCR
#ifdef FEAT_DIFF
, WV_DIFF
#endif
diff --git a/src/popupwin.c b/src/popupwin.c
new file mode 100644
index 000000000..f7a8921df
--- /dev/null
+++ b/src/popupwin.c
@@ -0,0 +1,231 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read a list of people who contributed.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * Implementation of popup windows. See ":help popup".
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_TEXT_PROP
+
+/*
+ * Go through the options in "dict" and apply them to buffer "buf" displayed in
+ * popup window "wp".
+ */
+ static void
+apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict)
+{
+ wp->w_maxwidth = dict_get_number(dict, (char_u *)"maxwidth");
+ wp->w_maxheight = dict_get_number(dict, (char_u *)"maxheight");
+ wp->w_winrow = dict_get_number(dict, (char_u *)"line");
+ wp->w_wincol = dict_get_number(dict, (char_u *)"col");
+ wp->w_zindex = dict_get_number(dict, (char_u *)"zindex");
+}
+
+/*
+ * popup_create({text}, {options})
+ */
+ void
+f_popup_create(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp;
+ buf_T *buf;
+ dict_T *d;
+ int nr;
+
+ // Check arguments look OK.
+ if (!(argvars[0].v_type == VAR_STRING
+ && argvars[0].vval.v_string != NULL
+ && STRLEN(argvars[0].vval.v_string) > 0)
+ && !(argvars[0].v_type == VAR_LIST
+ && argvars[0].vval.v_list != NULL
+ && argvars[0].vval.v_list->lv_len > 0))
+ {
+ emsg(_(e_listreq));
+ return;
+ }
+ if (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ d = argvars[1].vval.v_dict;
+
+ // Create the window and buffer.
+ wp = win_alloc_popup_win();
+ if (wp == NULL)
+ return;
+ rettv->vval.v_number = wp->w_id;
+ wp->w_p_wrap = TRUE; // 'wrap' is default on
+
+ buf = buflist_new(NULL, NULL, (linenr_T)0, BLN_NEW|BLN_LISTED|BLN_DUMMY);
+ if (buf == NULL)
+ return;
+ ml_open(buf);
+ curbuf = buf;
+ set_string_option_direct((char_u *)"buftype", -1,
+ (char_u *)"popup", OPT_FREE|OPT_LOCAL, 0);
+ set_string_option_direct((char_u *)"bufhidden", -1,
+ (char_u *)"hide", OPT_FREE|OPT_LOCAL, 0);
+ curbuf = curwin->w_buffer;
+ buf->b_p_ul = -1; // no undo
+ buf->b_p_swf = FALSE; // no swap file
+ buf->b_p_bl = FALSE; // unlisted buffer
+
+ win_init_popup_win(wp, buf);
+
+ nr = (int)dict_get_number(d, (char_u *)"tab");
+ if (nr == 0)
+ {
+ // popup on current tab
+ wp->w_next = first_tab_popupwin;
+ first_tab_popupwin = wp;
+ }
+ else if (nr < 0)
+ {
+ // global popup
+ wp->w_next = first_popupwin;
+ first_popupwin = wp;
+ }
+ else
+ // TODO: find tab page "nr"
+ emsg("Not implemented yet");
+
+ // Add text to the buffer.
+ if (argvars[0].v_type == VAR_STRING)
+ // just a string
+ ml_append_buf(buf, 0, argvars[0].vval.v_string, (colnr_T)0, TRUE);
+ else if (argvars[0].vval.v_list->lv_first->li_tv.v_type == VAR_STRING)
+ {
+ listitem_T *li;
+ linenr_T lnum = 0;
+ char_u *p;
+
+ // list of strings
+ for (li = argvars[0].vval.v_list->lv_first; li != NULL;
+ li = li->li_next)
+ if (li->li_tv.v_type == VAR_STRING)
+ {
+ p = li->li_tv.vval.v_string;
+ ml_append_buf(buf, lnum++,
+ p == NULL ? (char_u *)"" : p, (colnr_T)0, TRUE);
+ }
+ }
+ else
+ // TODO: handle a list of dictionaries
+ emsg("Not implemented yet");
+
+ // Delete the line of the empty buffer.
+ curbuf = buf;
+ ml_delete(buf->b_ml.ml_line_count, FALSE);
+ curbuf = curwin->w_buffer;
+
+ // Deal with options.
+ apply_options(wp, buf, argvars[1].vval.v_dict);
+
+ // set default values
+ if (wp->w_zindex == 0)
+ wp->w_zindex = 50;
+
+ // TODO: Compute the size and position properly.
+
+ // Default position is in middle of the screen, assuming a small popup
+ if (wp->w_winrow == 0)
+ wp->w_winrow = Rows > 5 ? Rows / 2 - 2 : 0;
+ else
+ --wp->w_winrow; // option value is one-based
+ if (wp->w_wincol == 0)
+ wp->w_wincol = Columns > 20 ? Columns / 2 - 10 : 0;
+ else
+ --wp->w_wincol; // option value is one-based
+
+
+ // TODO: set width based on longest text line and the 'wrap' option
+ wp->w_width = wp->w_maxwidth == 0 ? 20 : wp->w_maxwidth;
+ if (wp->w_maxwidth > 0 && wp->w_width > wp->w_maxwidth)
+ wp->w_width = wp->w_maxwidth;
+ if (wp->w_width > Columns - wp->w_wincol)
+ wp->w_width = Columns - wp->w_wincol;
+
+ // TODO: adjust height for wrapped lines
+ wp->w_height = buf->b_ml.ml_line_count;
+ if (wp->w_maxheight > 0 && wp->w_height > wp->w_maxheight)
+ wp->w_height = wp->w_maxheight;
+ if (wp->w_height > Rows - wp->w_winrow)
+ wp->w_height = Rows - wp->w_winrow;
+
+ wp->w_vsep_width = 0;
+
+ redraw_all_later(NOT_VALID);
+}
+
+/*
+ * popup_close({id})
+ */
+ void
+f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ int nr = (int)tv_get_number(argvars);
+
+ popup_close(nr);
+}
+
+ void
+popup_close(int nr)
+{
+ win_T *wp;
+ win_T *prev = NULL;
+
+ for (wp = first_popupwin; wp != NULL; prev = wp, wp = wp->w_next)
+ if (wp->w_id == nr)
+ {
+ if (prev == NULL)
+ first_popupwin = wp->w_next;
+ else
+ prev->w_next = wp->w_next;
+ break;
+ }
+
+ if (wp == NULL)
+ {
+ prev = NULL;
+ for (wp = first_tab_popupwin; wp != NULL; prev = wp, wp = wp->w_next)
+ if (wp->w_id == nr)
+ {
+ if (prev == NULL)
+ first_tab_popupwin = wp->w_next;
+ else
+ prev->w_next = wp->w_next;
+ break;
+ }
+ }
+ if (wp != NULL)
+ {
+ win_free_popup(wp);
+ redraw_all_later(NOT_VALID);
+ }
+}
+
+ void
+close_all_popups(void)
+{
+ while (first_popupwin != NULL)
+ popup_close(first_popupwin->w_id);
+ while (first_tab_popupwin != NULL)
+ popup_close(first_tab_popupwin->w_id);
+}
+
+ void
+ex_popupclear(exarg_T *eap UNUSED)
+{
+ close_all_popups();
+}
+
+#endif // FEAT_TEXT_PROP
diff --git a/src/proto.h b/src/proto.h
index 4d2edede9..e606f08f5 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -195,6 +195,7 @@ void qsort(void *base, size_t elm_count, size_t elm_size, int (*cmp)(const void
# include "termlib.pro"
# endif
# ifdef FEAT_TEXT_PROP
+# include "popupwin.pro"
# include "textprop.pro"
# endif
# include "ui.pro"
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
index 5e1aa7a8d..1748fb51f 100644
--- a/src/proto/buffer.pro
+++ b/src/proto/buffer.pro
@@ -61,6 +61,7 @@ int bt_quickfix(buf_T *buf);
int bt_terminal(buf_T *buf);
int bt_help(buf_T *buf);
int bt_prompt(buf_T *buf);
+int bt_popup(buf_T *buf);
int bt_nofile(buf_T *buf);
int bt_dontwrite(buf_T *buf);
int bt_dontwrite_msg(buf_T *buf);
diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro
new file mode 100644
index 000000000..a3d78b8c6
--- /dev/null
+++ b/src/proto/popupwin.pro
@@ -0,0 +1,7 @@
+/* popupwin.c */
+void f_popup_create(typval_T *argvars, typval_T *rettv);
+void f_popup_close(typval_T *argvars, typval_T *rettv);
+void popup_close(int nr);
+void close_all_popups(void);
+void ex_popupclear(exarg_T *eap);
+/* vim: set ft=c : */
diff --git a/src/proto/window.pro b/src/proto/window.pro
index b4ad98afb..b5cbf6922 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -19,7 +19,8 @@ void close_others(int message, int forceit);
void curwin_init(void);
void win_init_empty(win_T *wp);
int win_alloc_first(void);
-void win_alloc_aucmd_win(void);
+win_T *win_alloc_popup_win(void);
+void win_init_popup_win(win_T *wp, buf_T *buf);
void win_init_size(void);
void free_tabpage(tabpage_T *tp);
int win_new_tabpage(int after);
@@ -42,6 +43,8 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, int left, long count);
void win_enter(win_T *wp, int undo_sync);
win_T *buf_jump_open_win(buf_T *buf);
win_T *buf_jump_open_tab(buf_T *buf);
+int win_unlisted(win_T *wp);
+void win_free_popup(win_T *win);
void win_append(win_T *after, win_T *wp);
void win_remove(win_T *wp, tabpage_T *tp);
int win_alloc_lines(win_T *wp);
diff --git a/src/screen.c b/src/screen.c
index 469177505..79baebe77 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -121,6 +121,9 @@ static int redrawing_for_callback = 0;
*/
static schar_T *current_ScreenLine;
+#ifdef FEAT_TEXT_PROP
+static void update_popups(void);
+#endif
static void win_update(win_T *wp);
static void win_redr_status(win_T *wp, int ignore_pum);
static void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl);
@@ -178,6 +181,10 @@ static int screen_char_attr = 0;
# define HAS_RIGHTLEFT(x) FALSE
#endif
+// flags for screen_line()
+#define SLF_RIGHTLEFT 1
+#define SLF_POPUP 2
+
/*
* Redraw the current window later, with update_screen(type).
* Set must_redraw only if not already set to a higher value.
@@ -406,7 +413,7 @@ redraw_asap(int type)
mch_memmove(ScreenLines2 + off,
screenline2 + r * cols,
(size_t)cols * sizeof(schar_T));
- screen_line(cmdline_row + r, 0, cols, cols, FALSE);
+ screen_line(cmdline_row + r, 0, cols, cols, 0);
}
ret = 4;
}
@@ -604,6 +611,11 @@ update_screen(int type_arg)
curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
return FAIL;
}
+#ifdef FEAT_TEXT_PROP
+ // TODO: avoid redrawing everything when there is a popup window.
+ if (first_popupwin != NULL || first_tab_popupwin != NULL)
+ type = NOT_VALID;
+#endif
updating_screen = TRUE;
#ifdef FEAT_SYN_HL
@@ -811,6 +823,11 @@ update_screen(int type_arg)
maybe_intro_message();
did_intro = TRUE;
+#ifdef FEAT_TEXT_PROP
+ // Display popup windows on top of the others.
+ update_popups();
+#endif
+
#ifdef FEAT_GUI
/* Redraw the cursor and update the scrollbars when all screen updating is
* done. */
@@ -975,6 +992,50 @@ update_debug_sign(buf_T *buf, linenr_T lnum)
}
#endif
+#ifdef FEAT_TEXT_PROP
+ static void
+update_popups(void)
+{
+ win_T *wp;
+ win_T *lowest_wp;
+ int lowest_zindex;
+
+ // Reset all the VALID_POPUP flags.
+ for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+ wp->w_valid &= ~VALID_POPUP;
+ for (wp = first_tab_popupwin; wp != NULL; wp = wp->w_next)
+ wp->w_valid &= ~VALID_POPUP;
+
+ // TODO: don't redraw every popup every time.
+ for (;;)
+ {
+ // Find the window with the lowest zindex that hasn't been updated yet,
+ // so that the window with a higher zindex is drawn later, thus goes on
+ // top.
+ lowest_zindex = INT_MAX;
+ lowest_wp = NULL;
+ for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+ if ((wp->w_valid & VALID_POPUP) == 0
+ && wp->w_zindex < lowest_zindex)
+ {
+ lowest_zindex = wp->w_zindex;
+ lowest_wp = wp;
+ }
+ for (wp = first_tab_popupwin; wp != NULL; wp = wp->w_next)
+ if ((wp->w_valid & VALID_POPUP) == 0
+ && wp->w_zindex < lowest_zindex)
+ {
+ lowest_zindex = wp->w_zindex;
+ lowest_wp = wp;
+ }
+
+ if (lowest_wp == NULL)
+ break;
+ win_update(lowest_wp);
+ lowest_wp->w_valid |= VALID_POPUP;
+ }
+}
+#endif
#if defined(FEAT_GUI) || defined(PROTO)
/*
@@ -2862,7 +2923,7 @@ fold_line(
#endif
screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
- (int)wp->w_width, FALSE);
+ (int)wp->w_width, 0);
/*
* Update w_cline_height and w_cline_folded if the cursor line was
@@ -3046,7 +3107,8 @@ win_line(
int attr_pri = FALSE; /* char_attr has priority */
int area_highlighting = FALSE; /* Visual or incsearch highlighting
in this line */
- int attr = 0; /* attributes for area highlighting */
+ int vi_attr = 0; /* attributes for Visual and incsearch
+ highlighting */
int area_attr = 0; /* attributes desired by highlighting */
int search_attr = 0; /* attributes desired by 'hlsearch' */
#ifdef FEAT_SYN_HL
@@ -3127,8 +3189,8 @@ win_line(
#endif
#ifdef FEAT_TERMINAL
int get_term_attr = FALSE;
- int term_attr = 0; /* background for terminal window */
#endif
+ int win_attr = 0; // background for whole window
/* draw_state: items that are drawn in sequence: */
#define WL_START 0 /* nothing done yet */
@@ -3164,6 +3226,7 @@ win_line(
int feedback_col = 0;
int feedback_old_attr = -1;
#endif
+ int screen_line_flags = 0;
#ifdef FEAT_CONCEAL
int syntax_flags = 0;
@@ -3244,7 +3307,7 @@ win_line(
{
extra_check = TRUE;
get_term_attr = TRUE;
- term_attr = term_get_attr(wp->w_buffer, lnum, -1);
+ win_attr = term_get_attr(wp->w_buffer, lnum, -1);
}
#endif
@@ -3362,13 +3425,13 @@ win_line(
if (fromcol >= 0)
{
area_highlighting = TRUE;
- attr = HL_ATTR(HLF_V);
+ vi_attr = HL_ATTR(HLF_V);
#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
if ((clip_star.available && !clip_star.owned
- && clip_isautosel_star())
+ && clip_isautosel_star())
|| (clip_plus.available && !clip_plus.owned
- && clip_isautosel_plus()))
- attr = HL_ATTR(HLF_VNC);
+ && clip_isautosel_plus()))
+ vi_attr = HL_ATTR(HLF_VNC);
#endif
}
}
@@ -3398,7 +3461,7 @@ win_line(
if (fromcol == tocol)
tocol = fromcol + 1;
area_highlighting = TRUE;
- attr = HL_ATTR(HLF_I);
+ vi_attr = HL_ATTR(HLF_I);
}
}
@@ -3497,6 +3560,30 @@ win_line(
}
}
+ if (*wp->w_p_wcr != NUL)
+ {
+ int attr = syn_name2attr(wp->w_p_wcr);
+
+ // 'wincolor' highlighting for the whole window
+ if (attr != 0)
+ {
+ win_attr = attr;
+ area_highlighting = TRUE;
+ }
+ }
+#ifdef FEAT_TEXT_PROP
+ if (bt_popup(wp->w_buffer))
+ {
+ screen_line_flags |= SLF_POPUP;
+
+ if (win_attr == 0)
+ {
+ win_attr = HL_ATTR(HLF_PNI);
+ area_highlighting = TRUE;
+ }
+ }
+#endif
+
/*
* 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
* first character to be displayed.
@@ -3630,10 +3717,12 @@ win_line(
/*
* Handle highlighting the last used search pattern and matches.
* Do this for both search_hl and the match list.
+ * Not in a popup window.
*/
cur = wp->w_match_head;
shl_flag = FALSE;
- while ((cur != NULL || shl_flag == FALSE) && !number_only)
+ while ((cur != NULL || shl_flag == FALSE) && !number_only
+ && !(screen_line_flags & SLF_POPUP))
{
if (shl_flag == FALSE)
{
@@ -3729,6 +3818,7 @@ win_line(
off = (unsigned)(current_ScreenLine - ScreenLines);
col = 0;
+
#ifdef FEAT_RIGHTLEFT
if (wp->w_p_rl)
{
@@ -3737,6 +3827,7 @@ win_line(
* rightmost column of the window. */
col = wp->w_width - 1;
off += col;
+ screen_line_flags |= SLF_RIGHTLEFT;
}
#endif
@@ -4048,7 +4139,7 @@ win_line(
char_attr = saved_char_attr;
}
else
- char_attr = 0;
+ char_attr = win_attr;
}
}
@@ -4064,7 +4155,7 @@ win_line(
|| (number_only && draw_state > WL_NR))
{
screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
- HAS_RIGHTLEFT(wp->w_p_rl));
+ screen_line_flags);
/* Pretend we have finished updating the window. Except when
* 'cursorcolumn' is set. */
#ifdef FEAT_SYN_HL
@@ -4089,7 +4180,7 @@ win_line(
|| ((int)vcol_prev == fromcol_prev
&& vcol_prev < vcol /* not at margin */
&& vcol < tocol))
- area_attr = attr; /* start highlighting */
+ area_attr = vi_attr; /* start highlighting */
else if (area_attr != 0
&& (vcol == tocol
|| (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
@@ -4344,6 +4435,8 @@ win_line(
char_attr = 0;
}
}
+ if (char_attr == 0)
+ char_attr = win_attr;
/*
* Get the next character to put on the screen.
@@ -4672,9 +4765,15 @@ win_line(
{
wp->w_s->b_syn_error = TRUE;
has_syntax = FALSE;
+ syntax_attr = 0;
}
else
did_emsg = save_did_emsg;
+
+ // combine syntax attribute with 'wincolor'
+ if (win_attr != 0)
+ syntax_attr = hl_combine_attr(win_attr, syntax_attr);
+
#ifdef SYN_TIME_LIMIT
if (wp->w_s->b_syn_slow)
has_syntax = FALSE;
@@ -5149,7 +5248,7 @@ win_line(
diff_hlf != (hlf_T)0 ||
# endif
# ifdef FEAT_TERMINAL
- term_attr != 0 ||
+ win_attr != 0 ||
# endif
line_attr != 0
) && (
@@ -5178,7 +5277,7 @@ win_line(
if (diff_hlf == HLF_TXD)
{
diff_hlf = HLF_CHD;
- if (attr == 0 || char_attr != attr)
+ if (vi_attr == 0 || char_attr != vi_attr)
{
char_attr = HL_ATTR(diff_hlf);
if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
@@ -5188,9 +5287,9 @@ win_line(
}
# endif
# ifdef FEAT_TERMINAL
- if (term_attr != 0)
+ if (win_attr != 0)
{
- char_attr = term_attr;
+ char_attr = win_attr;
if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
char_attr = hl_combine_attr(char_attr,
HL_ATTR(HLF_CUL));
@@ -5550,7 +5649,8 @@ win_line(
&& (int)wp->w_virtcol <
wp->w_width * (row - startrow + 1) + v
&& lnum != wp->w_cursor.lnum)
- || draw_color_col)
+ || draw_color_col
+ || win_attr != 0)
# ifdef FEAT_RIGHTLEFT
&& !wp->w_p_rl
# endif
@@ -5582,9 +5682,9 @@ win_line(
else if (draw_color_col && VCOL_HLC == *color_cols)
ScreenAttrs[off++] = HL_ATTR(HLF_MC);
else
- ScreenAttrs[off++] = 0;
+ ScreenAttrs[off++] = win_attr;
- if (VCOL_HLC >= rightmost_vcol)
+ if (VCOL_HLC >= rightmost_vcol && win_attr == 0)
break;
++vcol;
@@ -5593,7 +5693,7 @@ win_line(
#endif
screen_line(screen_row, wp->w_wincol, col,
- (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
+ (int)wp->w_width, screen_line_flags);
row++;
/*
@@ -5893,11 +5993,11 @@ win_line(
{
#ifdef FEAT_CONCEAL
screen_line(screen_row, wp->w_wincol, col - boguscols,
- (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
+ (int)wp->w_width, screen_line_flags);
boguscols = 0;
#else
screen_line(screen_row, wp->w_wincol, col,
- (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
+ (int)wp->w_width, screen_line_flags);
#endif
++row;
++screen_row;
@@ -6107,7 +6207,9 @@ screen_get_current_line_off()
* "endcol" gives the columns where valid characters are.
* "clear_width" is the width of the window. It's > 0 if the rest of the line
* needs to be cleared, negative otherwise.
- * "rlflag" is TRUE in a rightleft window:
+ * "flags" can have bits:
+ * SLF_POPUP popup window
+ * SLF_RIGHTLEFT rightleft window:
* When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
* When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
*/
@@ -6117,7 +6219,7 @@ screen_line(
int coloff,
int endcol,
int clear_width,
- int rlflag UNUSED)
+ int flags UNUSED)
{
unsigned off_from;
unsigned off_to;
@@ -6153,7 +6255,7 @@ screen_line(
max_off_to = LineOffset[row] + screen_Columns;
#ifdef FEAT_RIGHTLEFT
- if (rlflag)
+ if (flags & SLF_RIGHTLEFT)
{
/* Clear rest first, because it's left of the text. */
if (clear_width > 0)
@@ -6377,7 +6479,7 @@ screen_line(
if (clear_width > 0
#ifdef FEAT_RIGHTLEFT
- && !rlflag
+ && !(flags & SLF_RIGHTLEFT)
#endif
)
{
@@ -6444,10 +6546,15 @@ screen_line(
}
}
- if (clear_width > 0)
+ if (clear_width > 0
+#ifdef FEAT_TEXT_PROP
+ && !(flags & SLF_POPUP) // no separator for popup window
+#endif
+ )
{
- /* For a window that's left of another, draw the separator char. */
- if (col + coloff < Columns)
+ // For a window that has a right neighbor, draw the separator char
+ // right of the window contents.
+ if (coloff + col < Columns)
{
int c;
@@ -10784,7 +10891,7 @@ redraw_win_toolbar(win_T *wp)
wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */
screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
- (int)wp->w_width, FALSE);
+ (int)wp->w_width, 0);
}
#endif
diff --git a/src/structs.h b/src/structs.h
index afd3e0281..e424830f3 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -163,17 +163,19 @@ typedef struct
{
#ifdef FEAT_ARABIC
int wo_arab;
-# define w_p_arab w_onebuf_opt.wo_arab /* 'arabic' */
+# define w_p_arab w_onebuf_opt.wo_arab // 'arabic'
#endif
#ifdef FEAT_LINEBREAK
int wo_bri;
-# define w_p_bri w_onebuf_opt.wo_bri /* 'breakindent' */
+# define w_p_bri w_onebuf_opt.wo_bri // 'breakindent'
char_u *wo_briopt;
-# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */
+# define w_p_briopt w_onebuf_opt.wo_briopt // 'breakindentopt'
#endif
+ char_u *wo_wcr;
+# define w_p_wcr w_onebuf_opt.wo_wcr // 'wincolor'
#ifdef FEAT_DIFF
int wo_diff;
-# define w_p_diff w_onebuf_opt.wo_diff /* 'diff' */
+# define w_p_diff w_onebuf_opt.wo_diff // 'diff'
#endif
#ifdef FEAT_FOLDING
long wo_fdc;
@@ -2592,19 +2594,22 @@ struct diffblock_S
typedef struct tabpage_S tabpage_T;
struct tabpage_S
{
- tabpage_T *tp_next; /* next tabpage or NULL */
- frame_T *tp_topframe; /* topframe for the windows */
- win_T *tp_curwin; /* current window in this Tab page */
- win_T *tp_prevwin; /* previous window in this Tab page */
- win_T *tp_firstwin; /* first window in this Tab page */
- win_T *tp_lastwin; /* last window in this Tab page */
- long tp_old_Rows; /* Rows when Tab page was left */
- long tp_old_Columns; /* Columns when Tab page was left */
- long tp_ch_used; /* value of 'cmdheight' when frame size
- was set */
+ tabpage_T *tp_next; // next tabpage or NULL
+ frame_T *tp_topframe; // topframe for the windows
+ win_T *tp_curwin; // current window in this Tab page
+ win_T *tp_prevwin; // previous window in this Tab page
+ win_T *tp_firstwin; // first window in this Tab page
+ win_T *tp_lastwin; // last window in this Tab page
+#ifdef FEAT_TEXT_PROP
+ win_T *tp_first_popupwin; // first popup window in this Tab page
+#endif
+ long tp_old_Rows; // Rows when Tab page was left
+ long tp_old_Columns; // Columns when Tab page was left
+ long tp_ch_used; // value of 'cmdheight' when frame size
+ // was set
#ifdef FEAT_GUI
int tp_prev_which_scrollbars[3];
- /* previous value of which_scrollbars */
+ // previous value of which_scrollbars
#endif
char_u *tp_localdir; // absolute path of local directory or
@@ -2615,18 +2620,18 @@ struct tabpage_S
int tp_diff_invalid; // list of diffs is outdated
int tp_diff_update; // update diffs before redrawing
#endif
- frame_T *(tp_snapshot[SNAP_COUNT]); /* window layout snapshots */
+ frame_T *(tp_snapshot[SNAP_COUNT]); // window layout snapshots
#ifdef FEAT_EVAL
- dictitem_T tp_winvar; /* variable for "t:" Dictionary */
- dict_T *tp_vars; /* internal variables, local to tab page */
+ dictitem_T tp_winvar; // variable for "t:" Dictionary
+ dict_T *tp_vars; // internal variables, local to tab page
#endif
#ifdef FEAT_PYTHON
- void *tp_python_ref; /* The Python value for this tab page */
+ void *tp_python_ref; // The Python value for this tab page
#endif
#ifdef FEAT_PYTHON3
- void *tp_python3_ref; /* The Python value for this tab page */
+ void *tp_python3_ref; // The Python value for this tab page
#endif
};
@@ -2775,15 +2780,15 @@ struct window_S
{
int w_id; /* unique window ID */
- buf_T *w_buffer; /* buffer we are a window into (used
- often, keep it the first item!) */
+ buf_T *w_buffer; /* buffer we are a window into */
+
+ win_T *w_prev; /* link to previous window */
+ win_T *w_next; /* link to next window */
#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
synblock_T *w_s; /* for :ownsyntax */
#endif
- win_T *w_prev; /* link to previous window */
- win_T *w_next; /* link to next window */
int w_closing; /* window is being closed, don't let
autocommands close it too. */
@@ -2847,6 +2852,11 @@ struct window_S
int w_width; /* Width of window, excluding separation. */
int w_vsep_width; /* Number of separator columns (0 or 1). */
pos_save_T w_save_cursor; /* backup of cursor pos and topline */
+#ifdef FEAT_TEXT_PROP
+ int w_zindex;
+ int w_maxheight; // "maxheight" for popup window
+ int w_maxwidth; // "maxwidth" for popup window
+#endif
/*
diff --git a/src/terminal.c b/src/terminal.c
index 1ceac3ada..606a9dbe1 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -3257,7 +3257,7 @@ update_system_term(term_T *term)
else
pos.col = 0;
- screen_line(term->tl_toprow + pos.row, 0, pos.col, Columns, FALSE);
+ screen_line(term->tl_toprow + pos.row, 0, pos.col, Columns, 0);
}
term->tl_dirty_row_start = MAX_ROW;
@@ -3368,7 +3368,7 @@ term_update_window(win_T *wp)
#ifdef FEAT_MENU
+ winbar_height(wp)
#endif
- , wp->w_wincol, pos.col, wp->w_width, FALSE);
+ , wp->w_wincol, pos.col, wp->w_width, 0);
}
term->tl_dirty_row_start = MAX_ROW;
term->tl_dirty_row_end = 0;
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 6442236dc..9de5f1662 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -196,6 +196,7 @@ NEW_TESTS = \
test_perl \
test_plus_arg_edit \
test_popup \
+ test_popupwin \
test_preview \
test_profile \
test_prompt_buffer \
@@ -250,8 +251,8 @@ NEW_TESTS = \
test_tagjump \
test_taglist \
test_tcl \
- test_termencoding \
test_termcodes \
+ test_termencoding \
test_terminal \
test_terminal_fail \
test_textformat \
@@ -377,6 +378,7 @@ NEW_TESTS_RES = \
test_paste.res \
test_perl.res \
test_plus_arg_edit.res \
+ test_popupwin.res \
test_preview.res \
test_profile.res \
test_prompt_buffer.res \
@@ -409,8 +411,8 @@ NEW_TESTS_RES = \
test_system.res \
test_tab.res \
test_tcl.res \
- test_termencoding.res \
test_termcodes.res \
+ test_termencoding.res \
test_terminal.res \
test_terminal_fail.res \
test_textformat.res \
diff --git a/src/testdir/dumps/Test_popupwin_01.dump b/src/testdir/dumps/Test_popupwin_01.dump
new file mode 100644
index 000000000..b3818c10a
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_01.dump
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @73
+|3| @8|h+0&#5fd7ff255|e|l@1|o| |t|h|e|r|e| @8|r+0#0000001#ffd7ff255| |o|n|e| @8| +0#0000000#ffffff0@30
+|4| @22|a+0#0000001#ffd7ff255|n|o|t|h|e|r| |t|w|o| @8| +0#0000000#ffffff0@30
+|5| @22|a+0#0000001#ffd7ff255|n|o|t|h|e|r| |t|h|r|e@1| @6| +0#0000000#ffffff0@30
+|6| @73
+|7| @73
+|8| @73
+|9| @73
+@57|1|,|1| @10|T|o|p|
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
new file mode 100644
index 000000000..7bae0b5b8
--- /dev/null
+++ b/src/testdir/test_popupwin.vim
@@ -0,0 +1,26 @@
+" Tests for popup windows
+
+if !has('textprop')
+ finish
+endif
+
+source screendump.vim
+
+func Test_simple_popup()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ "call setline(1, range(1, 100))",
+ \ "let winid = popup_create('hello there', {'line': 3, 'col': 11})",
+ \ "hi PopupColor ctermbg=lightblue",
+ \ "call setwinvar(winid, '&wincolor', 'PopupColor')",
+ \ "let winid2 = popup_create(['another one', 'another two', 'another three'], {'line': 3, 'col': 25})",
+ \], 'XtestPopup')
+ let buf = RunVimInTerminal('-S XtestPopup', {'rows': 10})
+ call VerifyScreenDump(buf, 'Test_popupwin_01', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XtestPopup')
+endfunc
diff --git a/src/version.c b/src/version.c
index a97163376..5573f44e5 100644
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1391,
+/**/
1390,
/**/
1389,
diff --git a/src/vim.h b/src/vim.h
index 57fbe36af..3389ef5a1 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -604,14 +604,15 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
* off off w_botline not valid
* on off not possible
*/
-#define VALID_WROW 0x01 /* w_wrow (window row) is valid */
-#define VALID_WCOL 0x02 /* w_wcol (window col) is valid */
-#define VALID_VIRTCOL 0x04 /* w_virtcol (file col) is valid */
-#define VALID_CHEIGHT 0x08 /* w_cline_height and w_cline_folded valid */
-#define VALID_CROW 0x10 /* w_cline_row is valid */
-#define VALID_BOTLINE 0x20 /* w_botine and w_empty_rows are valid */
-#define VALID_BOTLINE_AP 0x40 /* w_botine is approximated */
-#define VALID_TOPLINE 0x80 /* w_topline is valid (for cursor position) */
+#define VALID_WROW 0x01 // w_wrow (window row) is valid
+#define VALID_WCOL 0x02 // w_wcol (window col) is valid
+#define VALID_VIRTCOL 0x04 // w_virtcol (file col) is valid
+#define VALID_CHEIGHT 0x08 // w_cline_height and w_cline_folded valid
+#define VALID_CROW 0x10 // w_cline_row is valid
+#define VALID_BOTLINE 0x20 // w_botine and w_empty_rows are valid
+#define VALID_BOTLINE_AP 0x40 // w_botine is approximated
+#define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position)
+#define VALID_POPUP 0x100 // popup has been redrawn
/*
* Terminal highlighting attribute bits.
diff --git a/src/window.c b/src/window.c
index 6e02caad6..bed3d3fb7 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1362,6 +1362,21 @@ win_init_some(win_T *newp, win_T *oldp)
win_copy_options(oldp, newp);
}
+ static int
+win_valid_popup(win_T *win)
+{
+#ifdef FEAT_TEXT_PROP
+ win_T *wp;
+
+ for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+ if (wp == win)
+ return TRUE;
+ for (wp = first_tab_popupwin; wp != NULL; wp = wp->w_next)
+ if (wp == win)
+ return TRUE;
+#endif
+ return FALSE;
+}
/*
* Check if "win" is a pointer to an existing window in the current tab page.
@@ -1376,7 +1391,7 @@ win_valid(win_T *win)
FOR_ALL_WINDOWS(wp)
if (wp == win)
return TRUE;
- return FALSE;
+ return win_valid_popup(win);
}
/*
@@ -1398,7 +1413,7 @@ win_valid_any_tab(win_T *win)
return TRUE;
}
}
- return FALSE;
+ return win_valid_popup(win);
}
/*
@@ -2293,6 +2308,44 @@ close_last_window_tabpage(
}
/*
+ * Close the buffer of "win" and unload it if "free_buf" is TRUE.
+ * "abort_if_last" is passed to close_buffer(): abort closing if all other
+ * windows are closed.
+ */
+ static void
+win_close_buffer(win_T *win, int free_buf, int abort_if_last)
+{
+#ifdef FEAT_SYN_HL
+ // Free independent synblock before the buffer is freed.
+ if (win->w_buffer != NULL)
+ reset_synblock(win);
+#endif
+
+#ifdef FEAT_QUICKFIX
+ // When the quickfix/location list window is closed, unlist the buffer.
+ if (win->w_buffer != NULL && bt_quickfix(win->w_buffer))
+ win->w_buffer->b_p_bl = FALSE;
+#endif
+
+ // Close the link to the buffer.
+ if (win->w_buffer != NULL)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, curbuf);
+ win->w_closing = TRUE;
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0,
+ abort_if_last);
+ if (win_valid_any_tab(win))
+ win->w_closing = FALSE;
+ // Make sure curbuf is valid. It can become invalid if 'bufhidden' is
+ // "wipe".
+ if (!bufref_valid(&bufref))
+ curbuf = firstbuf;
+ }
+}
+
+/*
* Close window "win". Only works for the current tab page.
* If "free_buf" is TRUE related buffer may be unloaded.
*
@@ -2319,9 +2372,9 @@ win_close(win_T *win, int free_buf)
if (win->w_closing || (win->w_buffer != NULL
&& win->w_buffer->b_locked > 0))
return FAIL; /* window is already being closed */
- if (win == aucmd_win)
+ if (win_unlisted(win))
{
- emsg(_("E813: Cannot close autocmd window"));
+ emsg(_("E813: Cannot close autocmd or popup window"));
return FAIL;
}
if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window())
@@ -2390,35 +2443,7 @@ win_close(win_T *win, int free_buf)
out_flush();
#endif
-#ifdef FEAT_SYN_HL
- // Free independent synblock before the buffer is freed.
- if (win->w_buffer != NULL)
- reset_synblock(win);
-#endif
-
-#ifdef FEAT_QUICKFIX
- // When the quickfix/location list window is closed, unlist the buffer.
- if (win->w_buffer != NULL && bt_quickfix(win->w_buffer))
- win->w_buffer->b_p_bl = FALSE;
-#endif
-
- /*
- * Close the link to the buffer.
- */
- if (win->w_buffer != NULL)
- {
- bufref_T bufref;
-
- set_bufref(&bufref, curbuf);
- win->w_closing = TRUE;
- close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
- if (win_valid_any_tab(win))
- win->w_closing = FALSE;
- /* Make sure curbuf is valid. It can become invalid if 'bufhidden' is
- * "wipe". */
- if (!bufref_valid(&bufref))
- curbuf = firstbuf;
- }
+ win_close_buffer(win, free_buf, TRUE);
if (only_one_window() && win_valid(win) && win->w_buffer == NULL
&& (last_window() || curtab != prev_curtab
@@ -2627,6 +2652,9 @@ win_free_all(void)
(void)win_free_mem(aucmd_win, &dummy, NULL);
aucmd_win = NULL;
}
+# ifdef FEAT_TEXT_PROP
+ close_all_popups();
+# endif
while (firstwin != NULL)
(void)win_free_mem(firstwin, &dummy, NULL);
@@ -3458,7 +3486,7 @@ win_init_empty(win_T *wp)
wp->w_topfill = 0;
#endif
wp->w_botline = 2;
-#ifdef FEAT_SYN_HL
+#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
wp->w_s = &wp->w_buffer->b_s;
#endif
}
@@ -3484,19 +3512,41 @@ win_alloc_first(void)
}
/*
- * Init "aucmd_win". This can only be done after the first
- * window is fully initialized, thus it can't be in win_alloc_first().
+ * Allocate and init a window that is not a regular window.
+ * This can only be done after the first window is fully initialized, thus it
+ * can't be in win_alloc_first().
*/
- void
-win_alloc_aucmd_win(void)
+ win_T *
+win_alloc_popup_win(void)
{
- aucmd_win = win_alloc(NULL, TRUE);
- if (aucmd_win != NULL)
+ win_T *wp;
+
+ wp = win_alloc(NULL, TRUE);
+ if (wp != NULL)
{
- win_init_some(aucmd_win, curwin);
- RESET_BINDING(aucmd_win);
- new_frame(aucmd_win);
+ // We need to initialize options with something, using the current
+ // window makes most sense.
+ win_init_some(wp, curwin);
+
+ RESET_BINDING(wp);
+ new_frame(wp);
}
+ return wp;
+}
+
+/*
+ * Initialize window "wp" to display buffer "buf".
+ */
+ void
+win_init_popup_win(win_T *wp, buf_T *buf)
+{
+ wp->w_buffer = buf;
+ ++buf->b_nwindows;
+ win_init_empty(wp); // set cursor and topline to safe values
+
+ // Make sure w_localdir and globaldir are NULL to avoid a chdir() in
+ // win_enter_ext().
+ VIM_CLEAR(wp->w_localdir);
}
/*
@@ -3619,6 +3669,10 @@ free_tabpage(tabpage_T *tp)
# ifdef FEAT_DIFF
diff_clear(tp);
# endif
+# ifdef FEAT_TEXT_PROP
+ while (tp->tp_first_popupwin != NULL)
+ popup_close(tp->tp_first_popupwin->w_id);
+#endif
for (idx = 0; idx < SNAP_COUNT; ++idx)
clear_snapshot(tp, idx);
#ifdef FEAT_EVAL
@@ -4782,7 +4836,7 @@ win_free(
vim_free(wp->w_p_cc_cols);
#endif
- if (wp != aucmd_win)
+ if (win_valid_any_tab(wp))
win_remove(wp, tp);
if (autocmd_busy)
{
@@ -4796,6 +4850,28 @@ win_free(
}
/*
+ * Return TRUE if "wp" is not in the list of windows: the autocmd window or a
+ * popup window.
+ */
+ int
+win_unlisted(win_T *wp)
+{
+ return wp == aucmd_win || bt_popup(wp->w_buffer);
+}
+
+/*
+ * Free a popup window. This does not take the window out of the window list
+ * and assumes there is only one toplevel frame, no split.
+ */
+ void
+win_free_popup(win_T *win)
+{
+ win_close_buffer(win, TRUE, FALSE);
+ vim_free(win->w_frame);
+ win_free(win, NULL);
+}
+
+/*
* Append window "wp" in the window list after window "after".
*/
void
@@ -6182,7 +6258,7 @@ min_rows(void)
/*
* Return TRUE if there is only one window (in the current tab page), not
* counting a help or preview window, unless it is the current window.
- * Does not count "aucmd_win".
+ * Does not count unlisted windows.
*/
int
only_one_window(void)
@@ -6974,6 +7050,16 @@ win_id2wp(int id)
FOR_ALL_TAB_WINDOWS(tp, wp)
if (wp->w_id == id)
return wp;
+#ifdef FEAT_TEXT_PROP
+ // popup windows are in a separate list
+ FOR_ALL_TABPAGES(tp)
+ for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
+ if (wp->w_id == id)
+ return wp;
+ for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+ if (wp->w_id == id)
+ return wp;
+#endif
return NULL;
}