1
0
forked from aniani/vim

patch 8.1.1548: popup_dialog() is not implemented

Problem:    Popup_dialog() is not implemented.
Solution:   Implement popup_dialog() and popup_filter_yesno().
This commit is contained in:
Bram Moolenaar
2019-06-15 21:46:30 +02:00
parent 26910de8b0
commit a42d945efc
8 changed files with 177 additions and 46 deletions

View File

@@ -103,10 +103,10 @@ TODO:
- When drawing on top half a double-wide character, display ">" or "<" in the - When drawing on top half a double-wide character, display ">" or "<" in the
incomplete cell. incomplete cell.
- Can the buffer be re-used, to avoid using up lots of buffer numbers? - 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: - Implement:
popup_dialog({text}, {options})
popup_filter_menu({id}, {key}) popup_filter_menu({id}, {key})
popup_filter_yesno({id}, {key})
popup_menu({text}, {options}) popup_menu({text}, {options})
popup_setoptions({id}, {options}) popup_setoptions({id}, {options})
flip option flip option
@@ -196,16 +196,23 @@ popup_create({text}, {options}) *popup_create()*
popup_dialog({text}, {options}) *popup_dialog()* popup_dialog({text}, {options}) *popup_dialog()*
{not implemented yet}
Just like |popup_create()| but with these default options: > Just like |popup_create()| but with these default options: >
call popup_create({text}, { call popup_create({text}, {
\ 'pos': 'center', \ 'pos': 'center',
\ 'zindex': 200, \ 'zindex': 200,
\ 'drag': 1,
\ 'border': [], \ 'border': [],
\ 'padding': [], \ 'padding': [],
\}) \})
< Use {options} to change the properties. E.g. add a 'filter' < 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()* 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()* popup_filter_yesno({id}, {key}) *popup_filter_yesno()*
{not implemented yet}
Filter that can be used for a popup. It handles only the keys Filter that can be used for a popup. It handles only the keys
'y', 'Y' and 'n' or 'N'. Invokes the "callback" of the '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' 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 as the second argument. Pressing Esc and 'x' works like
pressing 'n'. Other keys are ignored. pressing 'n'. CTRL-C invokes the callback with -1. Other
keys are ignored.
popup_getoptions({id}) *popup_getoptions()* popup_getoptions({id}) *popup_getoptions()*
@@ -301,7 +308,7 @@ popup_notification({text}, {options}) *popup_notification()*
\ 'minwidth': 20, \ 'minwidth': 20,
\ 'time': 3000, \ 'time': 3000,
\ 'tabpage': -1, \ 'tabpage': -1,
\ 'zindex': 200, \ 'zindex': 300,
\ 'drag': 1, \ 'drag': 1,
\ 'highlight': 'WarningMsg', \ 'highlight': 'WarningMsg',
\ 'border': [], \ 'border': [],
@@ -521,7 +528,7 @@ filter is also called. The filter of the popup window with the highest zindex
is called first. is called first.
The filter function is called with two arguments: the ID of the popup and the 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) func MyFilter(winid, key)
if a:key == "\<F2>" if a:key == "\<F2>"
" do something " 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* POPUP CALLBACK *popup-callback*
A callback that is invoked when the popup closes. Used by A callback that is invoked when the popup closes.
|popup_filter_menu()|.
The callback is invoked with two arguments: the ID of the popup window and the 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 result, which could be an index in the popup lines, or whatever was passed as
the second argument of `popup_close()`. the second argument of `popup_close()`.
If the popup is closed because the cursor moved, the number -1 is passed to If the popup is force-closed, e.g. because the cursor moved or CTRL-C was
the callback. pressed, the number -1 is passed to the callback.
============================================================================== ==============================================================================
3. Examples *popup-examples* 3. Examples *popup-examples*

View File

@@ -815,6 +815,8 @@ static struct fst
{"popup_clear", 0, 0, f_popup_clear}, {"popup_clear", 0, 0, f_popup_clear},
{"popup_close", 1, 2, f_popup_close}, {"popup_close", 1, 2, f_popup_close},
{"popup_create", 2, 2, f_popup_create}, {"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_getoptions", 1, 1, f_popup_getoptions},
{"popup_getpos", 1, 1, f_popup_getpos}, {"popup_getpos", 1, 1, f_popup_getpos},
{"popup_hide", 1, 1, f_popup_hide}, {"popup_hide", 1, 1, f_popup_hide},

View File

@@ -600,6 +600,7 @@ EXTERN int aucmd_win_used INIT(= FALSE); /* aucmd_win is being used */
#ifdef FEAT_TEXT_PROP #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 #endif
/* /*

View File

@@ -201,6 +201,10 @@ popup_start_drag(win_T *wp)
drag_start_wantcol = wp->w_wincol + 1; drag_start_wantcol = wp->w_wincol + 1;
else else
drag_start_wantcol = wp->w_wantcol; drag_start_wantcol = wp->w_wantcol;
// Stop centering the popup
if (wp->w_popup_pos == POPPOS_CENTER)
wp->w_popup_pos = POPPOS_TOPLEFT;
} }
/* /*
@@ -301,6 +305,8 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict)
wp->w_p_wrap = nr != 0; wp->w_p_wrap = nr != 0;
} }
di = dict_find(dict, (char_u *)"drag", -1);
if (di != NULL)
wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag"); wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag");
di = dict_find(dict, (char_u *)"callback", -1); di = dict_find(dict, (char_u *)"callback", -1);
@@ -692,13 +698,13 @@ typedef enum
{ {
TYPE_NORMAL, TYPE_NORMAL,
TYPE_ATCURSOR, TYPE_ATCURSOR,
TYPE_NOTIFICATION TYPE_NOTIFICATION,
TYPE_DIALOG
} create_type_T; } create_type_T;
/* /*
* popup_create({text}, {options}) * popup_create({text}, {options})
* popup_atcursor({text}, {options}) * popup_atcursor({text}, {options})
* When called from f_popup_atcursor() "type" is TYPE_ATCURSOR.
*/ */
static void static void
popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) 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); 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. // Deal with options.
apply_options(wp, buf, argvars[1].vval.v_dict); apply_options(wp, buf, argvars[1].vval.v_dict);
@@ -912,33 +932,6 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv)
popup_create(argvars, rettv, TYPE_ATCURSOR); popup_create(argvars, rettv, TYPE_ATCURSOR);
} }
/*
* 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". * Invoke the close callback for window "wp" with value "result".
* Careful: The callback may make "wp" invalid! * Careful: The callback may make "wp" invalid!
@@ -985,6 +978,90 @@ popup_close_and_callback(win_T *wp, typval_T *arg)
popup_close(id); popup_close(id);
} }
/*
* 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}) * popup_close({id})
*/ */
@@ -1299,6 +1376,15 @@ invoke_popup_filter(win_T *wp, int c)
typval_T argv[3]; typval_T argv[3];
char_u buf[NUMBUFLEN]; 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].v_type = VAR_NUMBER;
argv[0].vval.v_number = (varnumber_T)wp->w_id; 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; argv[2].v_type = VAR_UNKNOWN;
// NOTE: The callback might close the popup, thus make "wp" invalid.
call_callback(&wp->w_filter_cb, -1, call_callback(&wp->w_filter_cb, -1,
&rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL); &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
res = tv_get_number(&rettv); res = tv_get_number(&rettv);

View File

@@ -8,6 +8,8 @@ void popup_adjust_position(win_T *wp);
void f_popup_clear(typval_T *argvars, typval_T *rettv); void f_popup_clear(typval_T *argvars, typval_T *rettv);
void f_popup_create(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_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_notification(typval_T *argvars, typval_T *rettv);
void f_popup_close(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); void f_popup_hide(typval_T *argvars, typval_T *rettv);

View File

@@ -1998,7 +1998,8 @@ typedef enum {
# define POPUPWIN_DEFAULT_ZINDEX 50 # define POPUPWIN_DEFAULT_ZINDEX 50
# define POPUPMENU_ZINDEX 100 # define POPUPMENU_ZINDEX 100
# define POPUPWIN_NOTIFICATION_ZINDEX 200 # define POPUPWIN_DIALOG_ZINDEX 200
# define POPUPWIN_NOTIFICATION_ZINDEX 300
#endif #endif
/* /*

View File

@@ -870,6 +870,36 @@ func Test_popup_filter()
call popup_clear() call popup_clear()
endfunc 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 Test_popup_close_callback()
func PopupDone(id, result) func PopupDone(id, result)
let g:result = a:result let g:result = a:result

View File

@@ -777,6 +777,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1548,
/**/ /**/
1547, 1547,
/**/ /**/