Skip to content

Commit a42d945

Browse files
committed
patch 8.1.1548: popup_dialog() is not implemented
Problem: Popup_dialog() is not implemented. Solution: Implement popup_dialog() and popup_filter_yesno().
1 parent 26910de commit a42d945

8 files changed

Lines changed: 177 additions & 46 deletions

File tree

runtime/doc/popup.txt

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,10 @@ TODO:
103103
- When drawing on top half a double-wide character, display ">" or "<" in the
104104
incomplete cell.
105105
- Can the buffer be re-used, to avoid using up lots of buffer numbers?
106+
- Use a popup window for the "info" item of completion instead of using a
107+
preview window.
106108
- Implement:
107-
popup_dialog({text}, {options})
108109
popup_filter_menu({id}, {key})
109-
popup_filter_yesno({id}, {key})
110110
popup_menu({text}, {options})
111111
popup_setoptions({id}, {options})
112112
flip option
@@ -196,16 +196,23 @@ popup_create({text}, {options}) *popup_create()*
196196

197197

198198
popup_dialog({text}, {options}) *popup_dialog()*
199-
{not implemented yet}
200199
Just like |popup_create()| but with these default options: >
201200
call popup_create({text}, {
202201
\ 'pos': 'center',
203202
\ 'zindex': 200,
203+
\ 'drag': 1,
204204
\ 'border': [],
205205
\ 'padding': [],
206206
\})
207207
< Use {options} to change the properties. E.g. add a 'filter'
208-
option with value 'popup_filter_yesno'.
208+
option with value 'popup_filter_yesno'. Example: >
209+
call popup_create('do you want to quit (Yes/no)?', {
210+
\ 'filter': 'popup_filter_yesno',
211+
\ 'callback': 'QuitCallback',
212+
\ })
213+
214+
< By default the dialog can be dragged, so that text below it
215+
can be read if needed.
209216

210217

211218
popup_filter_menu({id}, {key}) *popup_filter_menu()*
@@ -218,12 +225,12 @@ popup_filter_menu({id}, {key}) *popup_filter_menu()*
218225

219226

220227
popup_filter_yesno({id}, {key}) *popup_filter_yesno()*
221-
{not implemented yet}
222228
Filter that can be used for a popup. It handles only the keys
223229
'y', 'Y' and 'n' or 'N'. Invokes the "callback" of the
224230
popup menu with the 1 for 'y' or 'Y' and zero for 'n' or 'N'
225-
as the second argument. Pressing Esc and CTRL-C works like
226-
pressing 'n'. Other keys are ignored.
231+
as the second argument. Pressing Esc and 'x' works like
232+
pressing 'n'. CTRL-C invokes the callback with -1. Other
233+
keys are ignored.
227234

228235

229236
popup_getoptions({id}) *popup_getoptions()*
@@ -301,7 +308,7 @@ popup_notification({text}, {options}) *popup_notification()*
301308
\ 'minwidth': 20,
302309
\ 'time': 3000,
303310
\ 'tabpage': -1,
304-
\ 'zindex': 200,
311+
\ 'zindex': 300,
305312
\ 'drag': 1,
306313
\ 'highlight': 'WarningMsg',
307314
\ 'border': [],
@@ -521,7 +528,7 @@ filter is also called. The filter of the popup window with the highest zindex
521528
is called first.
522529

523530
The filter function is called with two arguments: the ID of the popup and the
524-
key, e.g.: >
531+
key as a string, e.g.: >
525532
func MyFilter(winid, key)
526533
if a:key == "\<F2>"
527534
" do something
@@ -556,15 +563,14 @@ Vim recognizes the Esc key. If you do use Esc, it is recommended to set the
556563

557564
POPUP CALLBACK *popup-callback*
558565

559-
A callback that is invoked when the popup closes. Used by
560-
|popup_filter_menu()|.
566+
A callback that is invoked when the popup closes.
561567

562568
The callback is invoked with two arguments: the ID of the popup window and the
563569
result, which could be an index in the popup lines, or whatever was passed as
564570
the second argument of `popup_close()`.
565571

566-
If the popup is closed because the cursor moved, the number -1 is passed to
567-
the callback.
572+
If the popup is force-closed, e.g. because the cursor moved or CTRL-C was
573+
pressed, the number -1 is passed to the callback.
568574

569575
==============================================================================
570576
3. Examples *popup-examples*

src/evalfunc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,8 @@ static struct fst
815815
{"popup_clear", 0, 0, f_popup_clear},
816816
{"popup_close", 1, 2, f_popup_close},
817817
{"popup_create", 2, 2, f_popup_create},
818+
{"popup_dialog", 2, 2, f_popup_dialog},
819+
{"popup_filter_yesno", 2, 2, f_popup_filter_yesno},
818820
{"popup_getoptions", 1, 1, f_popup_getoptions},
819821
{"popup_getpos", 1, 1, f_popup_getpos},
820822
{"popup_hide", 1, 1, f_popup_hide},

src/globals.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,8 @@ EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */
599599
EXTERN int aucmd_win_used INIT(= FALSE); /* aucmd_win is being used */
600600

601601
#ifdef FEAT_TEXT_PROP
602-
EXTERN win_T *first_popupwin; // first global popup window
602+
EXTERN win_T *first_popupwin; // first global popup window
603+
EXTERN win_T *popup_dragwin INIT(= NULL); // popup window being dragged
603604
#endif
604605

605606
/*

src/popupwin.c

Lines changed: 118 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ popup_start_drag(win_T *wp)
201201
drag_start_wantcol = wp->w_wincol + 1;
202202
else
203203
drag_start_wantcol = wp->w_wantcol;
204+
205+
// Stop centering the popup
206+
if (wp->w_popup_pos == POPPOS_CENTER)
207+
wp->w_popup_pos = POPPOS_TOPLEFT;
204208
}
205209

206210
/*
@@ -301,7 +305,9 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict)
301305
wp->w_p_wrap = nr != 0;
302306
}
303307

304-
wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag");
308+
di = dict_find(dict, (char_u *)"drag", -1);
309+
if (di != NULL)
310+
wp->w_popup_drag = dict_get_number(dict, (char_u *)"drag");
305311

306312
di = dict_find(dict, (char_u *)"callback", -1);
307313
if (di != NULL)
@@ -692,13 +698,13 @@ typedef enum
692698
{
693699
TYPE_NORMAL,
694700
TYPE_ATCURSOR,
695-
TYPE_NOTIFICATION
701+
TYPE_NOTIFICATION,
702+
TYPE_DIALOG
696703
} create_type_T;
697704

698705
/*
699706
* popup_create({text}, {options})
700707
* popup_atcursor({text}, {options})
701-
* When called from f_popup_atcursor() "type" is TYPE_ATCURSOR.
702708
*/
703709
static void
704710
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)
871877
OPT_FREE|OPT_LOCAL, 0);
872878
}
873879

880+
if (type == TYPE_DIALOG)
881+
{
882+
int i;
883+
884+
wp->w_popup_pos = POPPOS_CENTER;
885+
wp->w_zindex = POPUPWIN_DIALOG_ZINDEX;
886+
wp->w_popup_drag = 1;
887+
for (i = 0; i < 4; ++i)
888+
{
889+
wp->w_popup_border[i] = 1;
890+
wp->w_popup_padding[i] = 1;
891+
}
892+
}
893+
874894
// Deal with options.
875895
apply_options(wp, buf, argvars[1].vval.v_dict);
876896

@@ -912,33 +932,6 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv)
912932
popup_create(argvars, rettv, TYPE_ATCURSOR);
913933
}
914934

915-
/*
916-
* popup_notification({text}, {options})
917-
*/
918-
void
919-
f_popup_notification(typval_T *argvars, typval_T *rettv)
920-
{
921-
popup_create(argvars, rettv, TYPE_NOTIFICATION);
922-
}
923-
924-
/*
925-
* Find the popup window with window-ID "id".
926-
* If the popup window does not exist NULL is returned.
927-
* If the window is not a popup window, and error message is given.
928-
*/
929-
static win_T *
930-
find_popup_win(int id)
931-
{
932-
win_T *wp = win_id2wp(id);
933-
934-
if (wp != NULL && !bt_popup(wp->w_buffer))
935-
{
936-
semsg(_("E993: window %d is not a popup window"), id);
937-
return NULL;
938-
}
939-
return wp;
940-
}
941-
942935
/*
943936
* Invoke the close callback for window "wp" with value "result".
944937
* Careful: The callback may make "wp" invalid!
@@ -985,6 +978,90 @@ popup_close_and_callback(win_T *wp, typval_T *arg)
985978
popup_close(id);
986979
}
987980

981+
/*
982+
* popup_filter_yesno({text}, {options})
983+
*/
984+
void
985+
f_popup_filter_yesno(typval_T *argvars, typval_T *rettv)
986+
{
987+
int id = tv_get_number(&argvars[0]);
988+
win_T *wp = win_id2wp(id);
989+
char_u *key = tv_get_string(&argvars[1]);
990+
typval_T res;
991+
992+
// If the popup has been closed don't consume the key.
993+
if (wp == NULL)
994+
return;
995+
996+
// consume all keys until done
997+
rettv->vval.v_number = 1;
998+
999+
if (STRCMP(key, "y") == 0 || STRCMP(key, "Y") == 0)
1000+
res.vval.v_number = 1;
1001+
else if (STRCMP(key, "n") == 0 || STRCMP(key, "N") == 0
1002+
|| STRCMP(key, "x") == 0 || STRCMP(key, "X") == 0
1003+
|| STRCMP(key, "\x1b") == 0)
1004+
res.vval.v_number = 0;
1005+
else
1006+
{
1007+
int c = *key;
1008+
int row = mouse_row;
1009+
int col = mouse_col;
1010+
1011+
if (c == K_SPECIAL && key[1] != NUL)
1012+
c = TO_SPECIAL(key[1], key[2]);
1013+
if (wp->w_popup_drag
1014+
&& is_mouse_key(c)
1015+
&& (wp == popup_dragwin
1016+
|| wp == mouse_find_win(&row, &col, FIND_POPUP)))
1017+
// allow for dragging the popup
1018+
rettv->vval.v_number = 0;
1019+
1020+
// ignore this key
1021+
return;
1022+
}
1023+
1024+
// Invoke callback
1025+
res.v_type = VAR_NUMBER;
1026+
popup_close_and_callback(wp, &res);
1027+
}
1028+
1029+
/*
1030+
* popup_dialog({text}, {options})
1031+
*/
1032+
void
1033+
f_popup_dialog(typval_T *argvars, typval_T *rettv)
1034+
{
1035+
popup_create(argvars, rettv, TYPE_DIALOG);
1036+
}
1037+
1038+
/*
1039+
* popup_notification({text}, {options})
1040+
*/
1041+
void
1042+
f_popup_notification(typval_T *argvars, typval_T *rettv)
1043+
{
1044+
popup_create(argvars, rettv, TYPE_NOTIFICATION);
1045+
}
1046+
1047+
/*
1048+
* Find the popup window with window-ID "id".
1049+
* If the popup window does not exist NULL is returned.
1050+
* If the window is not a popup window, and error message is given.
1051+
*/
1052+
static win_T *
1053+
find_popup_win(int id)
1054+
{
1055+
win_T *wp = win_id2wp(id);
1056+
1057+
if (wp != NULL && !bt_popup(wp->w_buffer))
1058+
{
1059+
semsg(_("E993: window %d is not a popup window"), id);
1060+
return NULL;
1061+
}
1062+
return wp;
1063+
}
1064+
9881065
/*
9891066
* popup_close({id})
9901067
*/
@@ -1299,6 +1376,15 @@ invoke_popup_filter(win_T *wp, int c)
12991376
typval_T argv[3];
13001377
char_u buf[NUMBUFLEN];
13011378

1379+
// Emergency exit: CTRL-C closes the popup.
1380+
if (c == Ctrl_C)
1381+
{
1382+
rettv.v_type = VAR_NUMBER;
1383+
rettv.vval.v_number = -1;
1384+
popup_close_and_callback(wp, &rettv);
1385+
return 1;
1386+
}
1387+
13021388
argv[0].v_type = VAR_NUMBER;
13031389
argv[0].vval.v_number = (varnumber_T)wp->w_id;
13041390

@@ -1310,6 +1396,7 @@ invoke_popup_filter(win_T *wp, int c)
13101396

13111397
argv[2].v_type = VAR_UNKNOWN;
13121398

1399+
// NOTE: The callback might close the popup, thus make "wp" invalid.
13131400
call_callback(&wp->w_filter_cb, -1,
13141401
&rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
13151402
res = tv_get_number(&rettv);
@@ -1326,7 +1413,7 @@ invoke_popup_filter(win_T *wp, int c)
13261413
popup_do_filter(int c)
13271414
{
13281415
int res = FALSE;
1329-
win_T *wp;
1416+
win_T *wp;
13301417

13311418
popup_reset_handled();
13321419

src/proto/popupwin.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ void popup_adjust_position(win_T *wp);
88
void f_popup_clear(typval_T *argvars, typval_T *rettv);
99
void f_popup_create(typval_T *argvars, typval_T *rettv);
1010
void f_popup_atcursor(typval_T *argvars, typval_T *rettv);
11+
void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv);
12+
void f_popup_dialog(typval_T *argvars, typval_T *rettv);
1113
void f_popup_notification(typval_T *argvars, typval_T *rettv);
1214
void f_popup_close(typval_T *argvars, typval_T *rettv);
1315
void f_popup_hide(typval_T *argvars, typval_T *rettv);

src/structs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1998,7 +1998,8 @@ typedef enum {
19981998

19991999
# define POPUPWIN_DEFAULT_ZINDEX 50
20002000
# define POPUPMENU_ZINDEX 100
2001-
# define POPUPWIN_NOTIFICATION_ZINDEX 200
2001+
# define POPUPWIN_DIALOG_ZINDEX 200
2002+
# define POPUPWIN_NOTIFICATION_ZINDEX 300
20022003
#endif
20032004

20042005
/*

src/testdir/test_popupwin.vim

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,36 @@ func Test_popup_filter()
870870
call popup_clear()
871871
endfunc
872872

873+
func ShowDialog(key, result)
874+
let s:cb_res = 999
875+
let winid = popup_dialog('do you want to quit (Yes/no)?', {
876+
\ 'filter': 'popup_filter_yesno',
877+
\ 'callback': 'QuitCallback',
878+
\ })
879+
redraw
880+
call feedkeys(a:key, "xt")
881+
call assert_equal(winid, s:cb_winid)
882+
call assert_equal(a:result, s:cb_res)
883+
endfunc
884+
885+
func Test_popup_dialog()
886+
func QuitCallback(id, res)
887+
let s:cb_winid = a:id
888+
let s:cb_res = a:res
889+
endfunc
890+
891+
let winid = ShowDialog("y", 1)
892+
let winid = ShowDialog("Y", 1)
893+
let winid = ShowDialog("n", 0)
894+
let winid = ShowDialog("N", 0)
895+
let winid = ShowDialog("x", 0)
896+
let winid = ShowDialog("X", 0)
897+
let winid = ShowDialog("\<Esc>", 0)
898+
let winid = ShowDialog("\<C-C>", -1)
899+
900+
delfunc QuitCallback
901+
endfunc
902+
873903
func Test_popup_close_callback()
874904
func PopupDone(id, result)
875905
let g:result = a:result

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,8 @@ static char *(features[]) =
777777

778778
static int included_patches[] =
779779
{ /* Add new patch number below this line */
780+
/**/
781+
1548,
780782
/**/
781783
1547,
782784
/**/

0 commit comments

Comments
 (0)