# HG changeset patch # User Bram Moolenaar # Date 1559422806 -7200 # Node ID 5131023c57283a4ea7bb639997b0fc8fb2a5a8c4 # Parent b6d0ad5822b13eae1081099175fc7342eed6980d patch 8.1.1446: popup window callback not implemented yet commit https://github.com/vim/vim/commit/9eaac896501bcd6abdd430a90293eae8101df24a Author: Bram Moolenaar Date: Sat Jun 1 22:49:29 2019 +0200 patch 8.1.1446: popup window callback not implemented yet Problem: Popup window callback not implemented yet. Solution: Implement the callback. diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -90,6 +90,7 @@ Probably 2. is the best choice. IMPLEMENTATION: - Code is in popupwin.c +- Fix positioning with border and padding. - Why does 'nrformats' leak from the popup window buffer??? - Make redrawing more efficient and avoid flicker. Store popup info in a mask, use the mask in screen_line() @@ -133,10 +134,15 @@ popup_create({text}, {options}) *popu < In case of failure zero is returned. -popup_close({id}) *popup_close()* +popup_close({id} [, {result}]) *popup_close()* Close popup {id}. The window and the associated buffer will be deleted. + If the popup has a callback it will be called just before the + popup window is deleted. If the optional {result} is present + it will be passed as the second argument of the callback. + Otherwise zero is passed to the callback. + popup_dialog({text}, {options}) *popup_dialog()* {not implemented yet} @@ -145,6 +151,7 @@ popup_dialog({text}, {options}) *popu \ 'pos': 'center', \ 'zindex': 200, \ 'border': [], + \ 'padding': [], \}) < Use {options} to change the properties. @@ -166,6 +173,7 @@ popup_notification({text}, {options}) popup_atcursor({text}, {options}) *popup_atcursor()* + {not implemented yet: close when cursor moves} Show the {text} above the cursor, and close it when the cursor moves. This works like: > call popup_create({text}, { @@ -394,7 +402,6 @@ The second argument of |popup_create()| |popup-filter| callback a callback to be used when the popup closes, e.g. when using |popup_filter_menu()|, see |popup-callback|. - {not implemented yet} Depending on the "zindex" the popup goes under or above other popups. The completion menu (|popup-menu|) has zindex 100. For messages that occur for a @@ -477,11 +484,12 @@ Vim recognizes the Esc key. If you do u POPUP CALLBACK *popup-callback* -{not implemented yet} A callback that is invoked when the popup closes. Used by -|popup_filter_menu()|. Invoked with two arguments: the ID of the popup and -the result, which would usually be an index in the popup lines, or whatever -the filter wants to pass. +|popup_filter_menu()|. + +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()`. ============================================================================== 3. Examples *popup-examples* diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -810,7 +810,7 @@ static struct fst #endif #ifdef FEAT_TEXT_PROP {"popup_atcursor", 2, 2, f_popup_atcursor}, - {"popup_close", 1, 1, f_popup_close}, + {"popup_close", 1, 2, f_popup_close}, {"popup_create", 2, 2, f_popup_create}, {"popup_getoptions", 1, 1, f_popup_getoptions}, {"popup_getpos", 1, 1, f_popup_getpos}, diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -201,6 +201,15 @@ apply_options(win_T *wp, buf_T *buf UNUS wp->w_p_wrap = nr != 0; } + di = dict_find(dict, (char_u *)"callback", -1); + if (di != NULL) + { + callback_T callback = get_callback(&di->di_tv); + + if (callback.cb_name != NULL) + set_callback(&wp->w_close_cb, &callback); + } + di = dict_find(dict, (char_u *)"filter", -1); if (di != NULL) { @@ -632,14 +641,53 @@ popup_any_visible(void) } /* + * Invoke the close callback for window "wp" with value "result". + * Careful: The callback may make "wp" invalid! + */ + static void +invoke_popup_callback(win_T *wp, typval_T *result) +{ + typval_T rettv; + int dummy; + typval_T argv[3]; + + argv[0].v_type = VAR_NUMBER; + argv[0].vval.v_number = (varnumber_T)wp->w_id; + + if (result != NULL && result->v_type != VAR_UNKNOWN) + copy_tv(result, &argv[1]); + else + { + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = 0; + } + + argv[2].v_type = VAR_UNKNOWN; + + call_callback(&wp->w_close_cb, -1, + &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL); + if (result != NULL) + clear_tv(&argv[1]); + clear_tv(&rettv); +} + +/* * popup_close({id}) */ void f_popup_close(typval_T *argvars, typval_T *rettv UNUSED) { int id = (int)tv_get_number(argvars); + win_T *wp = find_popup_win(id); - popup_close(id); + if (wp != NULL) + { + if (wp->w_close_cb.cb_name != NULL) + // Careful: This may make "wp" invalid. + invoke_popup_callback(wp, &argvars[1]); + + popup_close(id); + } } /* @@ -688,6 +736,7 @@ popup_free(win_T *wp) /* * Close a popup window by Window-id. + * Does not invoke the callback. */ void popup_close(int id) diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -2894,6 +2894,7 @@ struct window_S int w_border_char[8]; // popup border characters varnumber_T w_popup_last_changedtick; // b:changedtick when position was // computed + callback_T w_close_cb; // popup close callback callback_T w_filter_cb; // popup filter callback # if defined(FEAT_TIMERS) timer_T *w_popup_timer; // timer for closing popup window diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -586,3 +586,13 @@ func Test_popup_filter() delfunc MyPopupFilter popupclear endfunc + +func Test_popup_close_callback() + func PopupDone(id, result) + let g:result = a:result + endfunc + let winid = popup_create('something', {'callback': 'PopupDone'}) + redraw + call popup_close(winid, 'done') + call assert_equal('done', g:result) +endfunc diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 1446, +/**/ 1445, /**/ 1444, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -4845,6 +4845,7 @@ win_free( remove_winbar(wp); #endif #ifdef FEAT_TEXT_PROP + free_callback(&wp->w_close_cb); free_callback(&wp->w_filter_cb); for (i = 0; i < 4; ++i) VIM_CLEAR(wp->w_border_highlight[i]);