diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-05-25 19:51:39 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-05-25 19:51:39 +0200 |
commit | 4d784b21d14fc66e98a2b07f70343cdd4acd62aa (patch) | |
tree | c2e869a4f07eebdf7e0272c74b0fe7392807836c /src | |
parent | 8f46e4c4bde13fd5ad68a6670b79cc462b65fbec (diff) | |
download | vim-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.mak | 1 | ||||
-rw-r--r-- | src/Make_mvc.mak | 5 | ||||
-rw-r--r-- | src/Make_vms.mms | 10 | ||||
-rw-r--r-- | src/Makefile | 10 | ||||
-rw-r--r-- | src/autocmd.c | 18 | ||||
-rw-r--r-- | src/buffer.c | 14 | ||||
-rw-r--r-- | src/eval.c | 26 | ||||
-rw-r--r-- | src/evalfunc.c | 4 | ||||
-rw-r--r-- | src/ex_cmdidxs.h | 24 | ||||
-rw-r--r-- | src/ex_cmds.h | 3 | ||||
-rw-r--r-- | src/feature.h | 2 | ||||
-rw-r--r-- | src/globals.h | 12 | ||||
-rw-r--r-- | src/option.c | 11 | ||||
-rw-r--r-- | src/option.h | 1 | ||||
-rw-r--r-- | src/popupwin.c | 231 | ||||
-rw-r--r-- | src/proto.h | 1 | ||||
-rw-r--r-- | src/proto/buffer.pro | 1 | ||||
-rw-r--r-- | src/proto/popupwin.pro | 7 | ||||
-rw-r--r-- | src/proto/window.pro | 5 | ||||
-rw-r--r-- | src/screen.c | 171 | ||||
-rw-r--r-- | src/structs.h | 58 | ||||
-rw-r--r-- | src/terminal.c | 4 | ||||
-rw-r--r-- | src/testdir/Make_all.mak | 6 | ||||
-rw-r--r-- | src/testdir/dumps/Test_popupwin_01.dump | 10 | ||||
-rw-r--r-- | src/testdir/test_popupwin.vim | 26 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 17 | ||||
-rw-r--r-- | src/window.c | 176 |
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+0fd7ff255|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, @@ -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; } |