summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-06-15 21:46:30 +0200
committerBram Moolenaar <Bram@vim.org>2019-06-15 21:46:30 +0200
commita42d945efc60e6130c15f72b5a5aa9fd2b63241a (patch)
tree241a17519918476c5d216d203fecad13d7ff4159
parent26910de8b0da6abab87bd5a397330f9cbe483309 (diff)
downloadvim-git-a42d945efc60e6130c15f72b5a5aa9fd2b63241a.tar.gz
patch 8.1.1548: popup_dialog() is not implementedv8.1.1548
Problem: Popup_dialog() is not implemented. Solution: Implement popup_dialog() and popup_filter_yesno().
-rw-r--r--runtime/doc/popup.txt32
-rw-r--r--src/evalfunc.c2
-rw-r--r--src/globals.h3
-rw-r--r--src/popupwin.c149
-rw-r--r--src/proto/popupwin.pro2
-rw-r--r--src/structs.h3
-rw-r--r--src/testdir/test_popupwin.vim30
-rw-r--r--src/version.c2
8 files changed, 177 insertions, 46 deletions
diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt
index 3ee92f269..a9f55be27 100644
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -103,10 +103,10 @@ TODO:
- When drawing on top half a double-wide character, display ">" or "<" in the
incomplete cell.
- Can the buffer be re-used, to avoid using up lots of buffer numbers?
+- Use a popup window for the "info" item of completion instead of using a
+ preview window.
- Implement:
- popup_dialog({text}, {options})
popup_filter_menu({id}, {key})
- popup_filter_yesno({id}, {key})
popup_menu({text}, {options})
popup_setoptions({id}, {options})
flip option
@@ -196,16 +196,23 @@ popup_create({text}, {options}) *popup_create()*
popup_dialog({text}, {options}) *popup_dialog()*
- {not implemented yet}
Just like |popup_create()| but with these default options: >
call popup_create({text}, {
\ 'pos': 'center',
\ 'zindex': 200,
+ \ 'drag': 1,
\ 'border': [],
\ 'padding': [],
\})
< Use {options} to change the properties. E.g. add a 'filter'
- option with value 'popup_filter_yesno'.
+ option with value 'popup_filter_yesno'. Example: >
+ call popup_create('do you want to quit (Yes/no)?', {
+ \ 'filter': 'popup_filter_yesno',
+ \ 'callback': 'QuitCallback',
+ \ })
+
+< By default the dialog can be dragged, so that text below it
+ can be read if needed.
popup_filter_menu({id}, {key}) *popup_filter_menu()*
@@ -218,12 +225,12 @@ popup_filter_menu({id}, {key}) *popup_filter_menu()*
popup_filter_yesno({id}, {key}) *popup_filter_yesno()*
- {not implemented yet}
Filter that can be used for a popup. It handles only the keys
'y', 'Y' and 'n' or 'N'. Invokes the "callback" of the
popup menu with the 1 for 'y' or 'Y' and zero for 'n' or 'N'
- as the second argument. Pressing Esc and CTRL-C works like
- pressing 'n'. Other keys are ignored.
+ as the second argument. Pressing Esc and 'x' works like
+ pressing 'n'. CTRL-C invokes the callback with -1. Other
+ keys are ignored.
popup_getoptions({id}) *popup_getoptions()*
@@ -301,7 +308,7 @@ popup_notification({text}, {options}) *popup_notification()*
\ 'minwidth': 20,
\ 'time': 3000,
\ 'tabpage': -1,
- \ 'zindex': 200,
+ \ 'zindex': 300,
\ 'drag': 1,
\ 'highlight': 'WarningMsg',
\ 'border': [],
@@ -521,7 +528,7 @@ filter is also called. The filter of the popup window with the highest zindex
is called first.
The filter function is called with two arguments: the ID of the popup and the
-key, e.g.: >
+key as a string, e.g.: >
func MyFilter(winid, key)
if a:key == "\<F2>"
" do something
@@ -556,15 +563,14 @@ Vim recognizes the Esc key. If you do use Esc, it is recommended to set the
POPUP CALLBACK *popup-callback*
-A callback that is invoked when the popup closes. Used by
-|popup_filter_menu()|.
+A callback that is invoked when the popup closes.
The callback is invoked with two arguments: the ID of the popup window and the
result, which could be an index in the popup lines, or whatever was passed as
the second argument of `popup_close()`.
-If the popup is closed because the cursor moved, the number -1 is passed to
-the callback.
+If the popup is force-closed, e.g. because the cursor moved or CTRL-C was
+pressed, the number -1 is passed to the callback.
==============================================================================
3. Examples *popup-examples*
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 544426fa6..d371c28b6 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -815,6 +815,8 @@ static struct fst
{"popup_clear", 0, 0, f_popup_clear},
{"popup_close", 1, 2, f_popup_close},
{"popup_create", 2, 2, f_popup_create},
+ {"popup_dialog", 2, 2, f_popup_dialog},
+ {"popup_filter_yesno", 2, 2, f_popup_filter_yesno},
{"popup_getoptions", 1, 1, f_popup_getoptions},
{"popup_getpos", 1, 1, f_popup_getpos},
{"popup_hide", 1, 1, f_popup_hide},
diff --git a/src/globals.h b/src/globals.h
index 992ce2a54..ec4298494 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -599,7 +599,8 @@ 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_popupwin; // first global popup window
+EXTERN win_T *first_popupwin; // first global popup window
+EXTERN win_T *popup_dragwin INIT(= NULL); // popup window being dragged
#endif
/*
diff --git a/src/popupwin.c b/src/popupwin.c
index aeed2e79b..adbc72914 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -201,6 +201,10 @@ popup_start_drag(win_T *wp)
drag_start_wantcol = wp->w_wincol + 1;
else
drag_start_wantcol = wp->w_wantcol;
+
+ // Stop centering the popup
+ if (wp->w_popup_pos == POPPOS_CENTER)
+ wp->w_popup_pos = POPPOS_TOPLEFT;
}
/*
@@ -301,7 +305,9 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict)
wp->w_p_wrap = nr != 0;
}
- wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag");
+ di = dict_find(dict, (char_u *)"drag", -1);
+ if (di != NULL)
+ wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag");
di = dict_find(dict, (char_u *)"callback", -1);
if (di != NULL)
@@ -692,13 +698,13 @@ typedef enum
{
TYPE_NORMAL,
TYPE_ATCURSOR,
- TYPE_NOTIFICATION
+ TYPE_NOTIFICATION,
+ TYPE_DIALOG
} create_type_T;
/*
* popup_create({text}, {options})
* popup_atcursor({text}, {options})
- * When called from f_popup_atcursor() "type" is TYPE_ATCURSOR.
*/
static void
popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
@@ -871,6 +877,20 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
OPT_FREE|OPT_LOCAL, 0);
}
+ if (type == TYPE_DIALOG)
+ {
+ int i;
+
+ wp->w_popup_pos = POPPOS_CENTER;
+ wp->w_zindex = POPUPWIN_DIALOG_ZINDEX;
+ wp->w_popup_drag = 1;
+ for (i = 0; i < 4; ++i)
+ {
+ wp->w_popup_border[i] = 1;
+ wp->w_popup_padding[i] = 1;
+ }
+ }
+
// Deal with options.
apply_options(wp, buf, argvars[1].vval.v_dict);
@@ -913,33 +933,6 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv)
}
/*
- * popup_notification({text}, {options})
- */
- void
-f_popup_notification(typval_T *argvars, typval_T *rettv)
-{
- popup_create(argvars, rettv, TYPE_NOTIFICATION);
-}
-
-/*
- * Find the popup window with window-ID "id".
- * If the popup window does not exist NULL is returned.
- * If the window is not a popup window, and error message is given.
- */
- static win_T *
-find_popup_win(int id)
-{
- win_T *wp = win_id2wp(id);
-
- if (wp != NULL && !bt_popup(wp->w_buffer))
- {
- semsg(_("E993: window %d is not a popup window"), id);
- return NULL;
- }
- return wp;
-}
-
-/*
* Invoke the close callback for window "wp" with value "result".
* Careful: The callback may make "wp" invalid!
*/
@@ -986,6 +979,90 @@ popup_close_and_callback(win_T *wp, typval_T *arg)
}
/*
+ * popup_filter_yesno({text}, {options})
+ */
+ void
+f_popup_filter_yesno(typval_T *argvars, typval_T *rettv)
+{
+ int id = tv_get_number(&argvars[0]);
+ win_T *wp = win_id2wp(id);
+ char_u *key = tv_get_string(&argvars[1]);
+ typval_T res;
+
+ // If the popup has been closed don't consume the key.
+ if (wp == NULL)
+ return;
+
+ // consume all keys until done
+ rettv->vval.v_number = 1;
+
+ if (STRCMP(key, "y") == 0 || STRCMP(key, "Y") == 0)
+ res.vval.v_number = 1;
+ else if (STRCMP(key, "n") == 0 || STRCMP(key, "N") == 0
+ || STRCMP(key, "x") == 0 || STRCMP(key, "X") == 0
+ || STRCMP(key, "\x1b") == 0)
+ res.vval.v_number = 0;
+ else
+ {
+ int c = *key;
+ int row = mouse_row;
+ int col = mouse_col;
+
+ if (c == K_SPECIAL && key[1] != NUL)
+ c = TO_SPECIAL(key[1], key[2]);
+ if (wp->w_popup_drag
+ && is_mouse_key(c)
+ && (wp == popup_dragwin
+ || wp == mouse_find_win(&row, &col, FIND_POPUP)))
+ // allow for dragging the popup
+ rettv->vval.v_number = 0;
+
+ // ignore this key
+ return;
+ }
+
+ // Invoke callback
+ res.v_type = VAR_NUMBER;
+ popup_close_and_callback(wp, &res);
+}
+
+/*
+ * popup_dialog({text}, {options})
+ */
+ void
+f_popup_dialog(typval_T *argvars, typval_T *rettv)
+{
+ popup_create(argvars, rettv, TYPE_DIALOG);
+}
+
+/*
+ * popup_notification({text}, {options})
+ */
+ void
+f_popup_notification(typval_T *argvars, typval_T *rettv)
+{
+ popup_create(argvars, rettv, TYPE_NOTIFICATION);
+}
+
+/*
+ * Find the popup window with window-ID "id".
+ * If the popup window does not exist NULL is returned.
+ * If the window is not a popup window, and error message is given.
+ */
+ static win_T *
+find_popup_win(int id)
+{
+ win_T *wp = win_id2wp(id);
+
+ if (wp != NULL && !bt_popup(wp->w_buffer))
+ {
+ semsg(_("E993: window %d is not a popup window"), id);
+ return NULL;
+ }
+ return wp;
+}
+
+/*
* popup_close({id})
*/
void
@@ -1299,6 +1376,15 @@ invoke_popup_filter(win_T *wp, int c)
typval_T argv[3];
char_u buf[NUMBUFLEN];
+ // Emergency exit: CTRL-C closes the popup.
+ if (c == Ctrl_C)
+ {
+ rettv.v_type = VAR_NUMBER;
+ rettv.vval.v_number = -1;
+ popup_close_and_callback(wp, &rettv);
+ return 1;
+ }
+
argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = (varnumber_T)wp->w_id;
@@ -1310,6 +1396,7 @@ invoke_popup_filter(win_T *wp, int c)
argv[2].v_type = VAR_UNKNOWN;
+ // NOTE: The callback might close the popup, thus make "wp" invalid.
call_callback(&wp->w_filter_cb, -1,
&rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
res = tv_get_number(&rettv);
@@ -1326,7 +1413,7 @@ invoke_popup_filter(win_T *wp, int c)
popup_do_filter(int c)
{
int res = FALSE;
- win_T *wp;
+ win_T *wp;
popup_reset_handled();
diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro
index cde0cae6e..6e93791e6 100644
--- a/src/proto/popupwin.pro
+++ b/src/proto/popupwin.pro
@@ -8,6 +8,8 @@ void popup_adjust_position(win_T *wp);
void f_popup_clear(typval_T *argvars, typval_T *rettv);
void f_popup_create(typval_T *argvars, typval_T *rettv);
void f_popup_atcursor(typval_T *argvars, typval_T *rettv);
+void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv);
+void f_popup_dialog(typval_T *argvars, typval_T *rettv);
void f_popup_notification(typval_T *argvars, typval_T *rettv);
void f_popup_close(typval_T *argvars, typval_T *rettv);
void f_popup_hide(typval_T *argvars, typval_T *rettv);
diff --git a/src/structs.h b/src/structs.h
index 59259274a..09158a0cc 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1998,7 +1998,8 @@ typedef enum {
# define POPUPWIN_DEFAULT_ZINDEX 50
# define POPUPMENU_ZINDEX 100
-# define POPUPWIN_NOTIFICATION_ZINDEX 200
+# define POPUPWIN_DIALOG_ZINDEX 200
+# define POPUPWIN_NOTIFICATION_ZINDEX 300
#endif
/*
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index a3f2046f4..f7a319c23 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -870,6 +870,36 @@ func Test_popup_filter()
call popup_clear()
endfunc
+func ShowDialog(key, result)
+ let s:cb_res = 999
+ let winid = popup_dialog('do you want to quit (Yes/no)?', {
+ \ 'filter': 'popup_filter_yesno',
+ \ 'callback': 'QuitCallback',
+ \ })
+ redraw
+ call feedkeys(a:key, "xt")
+ call assert_equal(winid, s:cb_winid)
+ call assert_equal(a:result, s:cb_res)
+endfunc
+
+func Test_popup_dialog()
+ func QuitCallback(id, res)
+ let s:cb_winid = a:id
+ let s:cb_res = a:res
+ endfunc
+
+ let winid = ShowDialog("y", 1)
+ let winid = ShowDialog("Y", 1)
+ let winid = ShowDialog("n", 0)
+ let winid = ShowDialog("N", 0)
+ let winid = ShowDialog("x", 0)
+ let winid = ShowDialog("X", 0)
+ let winid = ShowDialog("\<Esc>", 0)
+ let winid = ShowDialog("\<C-C>", -1)
+
+ delfunc QuitCallback
+endfunc
+
func Test_popup_close_callback()
func PopupDone(id, result)
let g:result = a:result
diff --git a/src/version.c b/src/version.c
index 113fb97ce..9d457038e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1548,
+/**/
1547,
/**/
1546,