]> granicus.if.org Git - vim/commitdiff
patch 8.1.1446: popup window callback not implemented yet v8.1.1446
authorBram Moolenaar <Bram@vim.org>
Sat, 1 Jun 2019 20:49:29 +0000 (22:49 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 1 Jun 2019 20:49:29 +0000 (22:49 +0200)
Problem:    Popup window callback not implemented yet.
Solution:   Implement the callback.

runtime/doc/popup.txt
src/evalfunc.c
src/popupwin.c
src/structs.h
src/testdir/test_popupwin.vim
src/version.c
src/window.c

index ac16b221c4e9e493c4b80935be3dd4441444a5fc..c8cca5b9054246caa5b0966fd51fac5bec50a1f0 100644 (file)
@@ -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})                           *popup_create()*
 <              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})                             *popup_dialog()*
                                \ 'pos': 'center',
                                \ 'zindex': 200,
                                \ 'border': [],
+                               \ 'padding': [],
                                \})
 <              Use {options} to change the properties.
 
@@ -166,6 +173,7 @@ popup_notification({text}, {options})                        *popup_notification()*
 
 
 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()| is a dictionary with options:
                        |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 use Esc, it is reecommended to set the
 
 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*
index ccb8b3e89092e1d91ae3d305f499f6479d1d09d5..bc6056785954582264a24e4d050da9e859362abb 100644 (file)
@@ -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},
index 810987aace23ffb22ed73f6dea6c34be480fdff1..dc3b56468bd21e6c78b6665f18adf9272d3abe36 100644 (file)
@@ -201,6 +201,15 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict, int atcursor)
        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)
     {
@@ -631,6 +640,37 @@ popup_any_visible(void)
     return FALSE;
 }
 
+/*
+ * 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})
  */
@@ -638,8 +678,16 @@ popup_any_visible(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);
+
+    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);
+       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)
index f6db26465bde39c9473365bd6074abcd02fd1abf..2100135ac608ecc75b86be6d6059249daec8e520 100644 (file)
@@ -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
index 6a2ef24a472380765754a30826272bc3f85c0da7..6e059193bfb8fbf8008ed6c954aae14ba0fe1d3e 100644 (file)
@@ -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
index 3be4e657abdd7aced48648c32c2fcb836ece5bde..597fb90fe713a1235a4c1fed83e5b6f2e12b5b16 100644 (file)
@@ -767,6 +767,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1446,
 /**/
     1445,
 /**/
index e15b31191fa53e97ac50b4fb1f1a6a9bfea81c59..f4ef983c6ddff6875d5cc5da60371ef73a138369 100644 (file)
@@ -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]);