]> granicus.if.org Git - vim/commitdiff
patch 8.1.1522: poup_notification() not implemented yet v8.1.1522
authorBram Moolenaar <Bram@vim.org>
Wed, 12 Jun 2019 20:42:41 +0000 (22:42 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 12 Jun 2019 20:42:41 +0000 (22:42 +0200)
Problem:    Popup_notification() not implemented yet.
Solution:   Implement it.

runtime/doc/popup.txt
src/evalfunc.c
src/popupwin.c
src/proto/popupwin.pro
src/structs.h
src/testdir/dumps/Test_popupwin_notify_01.dump [new file with mode: 0644]
src/testdir/dumps/Test_popupwin_notify_02.dump [new file with mode: 0644]
src/testdir/test_popupwin.vim
src/version.c

index 0400880579341cdcc4798a504dfaa25bc08daf44..b80b8755951d5c39dca8e13a5c76889c0779418a 100644 (file)
@@ -1,4 +1,4 @@
-*popup.txt*  For Vim version 8.1.  Last change: 2019 Jun 10
+*popup.txt*  For Vim version 8.1.  Last change: 2019 Jun 12
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -36,7 +36,7 @@ The default color used is "Pmenu".  If you prefer something else use the
        hi MyPopupColor ctermbg=lightblue guibg=lightblue
        call setwinvar(winid, '&wincolor', 'MyPopupColor')
 
-'hlsearch' and match highlighting are not displayed in a popup window.
+'hlsearch' highlighting is not displayed in a popup window.
 
 A popup window has a window-ID like other windows, but behaves differently.
 The size can be up to the whole Vim window and it overlaps other windows.
@@ -63,7 +63,7 @@ property.
 
 The width of the window is normally equal to the longest line in the buffer.
 It can be limited with the "maxwidth" property.  You can use spaces to
-increase the width or the "minwidth" property.
+increase the width or use the "minwidth" property.
 
 By default the 'wrap' option is set, so that no text disappears.  Otherwise,
 if there is not enough space then the window is shifted left in order to
@@ -79,24 +79,32 @@ window it will be placed below the cursor position.
 When the screen scrolls up for output of an Ex command, popups move too, so
 that they will not cover the output.
 
+The current cursor position is displayed even when it is under a popup window.
+That way you can still see where it is, even though you cannot see the text
+that it is in.
 
 
 
 IMPLEMENTATION:
-- buffers remain after a popup was deleted.
 - Why does 'nrformats' leak from the popup window buffer???
+- Option to set first line to display (useful for a preview window)
+- Disable commands, feedkeys(), CTRL-W, etc. in a popup window.
+  Use NOT_IN_POPUP_WINDOW for more commands.
 - Add 'balloonpopup': instead of showing text, let the callback open a popup
   window and return the window ID.   The popup will then be closed when the
   mouse moves, except when it moves inside the popup.
 - For the "moved" property also include mouse movement?
+- When selecting text in the popup with modeless selection, do not select
+  outside of the popup and don't select the border or padding.
+- Allow the user to drag the popup window when the "dragging" property is set.
 - Make redrawing more efficient and avoid flicker:
     - put popup menu also put in popup_mask?
-- Disable commands, feedkeys(), CTRL-W, etc. in a popup window.
-  Use NOT_IN_POPUP_WINDOW for more commands.
 - Invoke filter with character before mapping?
 - Figure out the size and position better.
     if wrapping splits a double-wide character
     if wrapping inserts indent
+- 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?
 - Implement all the unimplemented options and features.
 
@@ -106,7 +114,34 @@ IMPLEMENTATION:
 
 THIS IS UNDER DESIGN - ANYTHING MAY STILL CHANGE
 
-[functions to be moved to eval.txt later, keep overview of functions here]
+Creating a popup window:
+       |popup_create()|        centered in the screen
+       |popup_atcursor()|      just above the cursor position, closes when
+                               the cursor moves away
+       |popup_notifiation()|   show a notification for three seconds
+       |popup_dialog()|        centered with padding and border
+       |popup_menu()|          prompt for selecting an item from a list
+
+Manipulating a popup window:
+       |popup_hide()|          hide a popup temporarily
+       |popup_show()|          show a previously hidden popup
+       |popup_move()|          change the position and size of a popup
+       |popup_setoptions()|    override options of a popup
+
+Closing popup windows:
+       |popup_close()|         close one popup
+       |popup_clear()|         close all popups
+
+Filter functions:
+       |popup_filter_menu()|   select from a list of items
+       |popup_filter_yesno()|  blocks until 'y' or 'n' is pressed
+
+Other:
+       |popup_getoptions()|    get current options for a popup
+       |popup_getpos()|        get actual position and size of a popup
+
+
+[functions to be moved to eval.txt later]
 
 popup_atcursor({text}, {options})                       *popup_atcursor()*
                Show the {text} above the cursor, and close it when the cursor
@@ -162,7 +197,8 @@ popup_dialog({text}, {options})                             *popup_dialog()*
                                \ 'border': [],
                                \ 'padding': [],
                                \})
-<              Use {options} to change the properties.
+<              Use {options} to change the properties. E.g. add a 'filter'
+               option with value 'popup_filter_yesno'.
 
 
 popup_filter_menu({id}, {key})                         *popup_filter_menu()*
@@ -180,7 +216,7 @@ popup_filter_yesno({id}, {key})                             *popup_filter_yesno()*
                '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'.
+               pressing 'n'.  Other keys are ignored.
 
 
 popup_getoptions({id})                                 *popup_getoptions()*
@@ -250,7 +286,6 @@ popup_move({id}, {options})                                 *popup_move()*
 
 
 popup_notification({text}, {options})                   *popup_notification()*
-               {not implemented yet}
                Show the {text} for 3 seconds at the top of the Vim window.
                This works like: >
                        call popup_create({text}, {
@@ -261,8 +296,11 @@ popup_notification({text}, {options})                       *popup_notification()*
                                \ 'zindex': 200,
                                \ 'highlight': 'WarningMsg',
                                \ 'border': [],
+                               \ 'padding': [0,1,0,1],
                                \ })
-<              Use {options} to change the properties.
+<              The position will be adjusted to avoid overlap with other
+               notifications.
+               Use {options} to change the properties.
 
 
 popup_show({id})                                               *popup_show()*
index 134280f6de9ebf4a7398361d23ae92bfe895ed26..0ef76095f404bd2d7ab580e3dd7d8537e47962e9 100644 (file)
@@ -819,6 +819,7 @@ static struct fst
     {"popup_getpos",   1, 1, f_popup_getpos},
     {"popup_hide",     1, 1, f_popup_hide},
     {"popup_move",     2, 2, f_popup_move},
+    {"popup_notification", 2, 2, f_popup_notification},
     {"popup_show",     1, 1, f_popup_show},
 #endif
 #ifdef FEAT_FLOAT
index adfa462299a5ae0177a9711c2f49e9c77303e297..d0f106fe61bd37f1ed0f98c6ed2874b551dd61fe 100644 (file)
@@ -110,7 +110,6 @@ get_padding_border(dict_T *dict, int *array, char *name, int max_val)
 {
     dictitem_T *di;
 
-    vim_memset(array, 0, sizeof(int) * 4);
     di = dict_find(dict, (char_u *)name, -1);
     if (di != NULL)
     {
@@ -165,6 +164,26 @@ set_moved_columns(win_T *wp, int flags)
     }
 }
 
+
+#if defined(FEAT_TIMERS)
+    static void
+popup_add_timeout(win_T *wp, int time)
+{
+    char_u         cbbuf[50];
+    char_u         *ptr = cbbuf;
+    typval_T       tv;
+
+    vim_snprintf((char *)cbbuf, sizeof(cbbuf),
+                                      "{_ -> popup_close(%d)}", wp->w_id);
+    if (get_lambda_tv(&ptr, &tv, TRUE) == OK)
+    {
+       wp->w_popup_timer = create_timer(time, 0);
+       wp->w_popup_timer->tr_callback = get_callback(&tv);
+       clear_tv(&tv);
+    }
+}
+#endif
+
 /*
  * Go through the options in "dict" and apply them to buffer "buf" displayed in
  * popup window "wp".
@@ -184,31 +203,22 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict)
 
     get_pos_options(wp, dict);
 
-    wp->w_zindex = dict_get_number(dict, (char_u *)"zindex");
-    if (wp->w_zindex < 1)
-       wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
-    if (wp->w_zindex > 32000)
-       wp->w_zindex = 32000;
+    di = dict_find(dict, (char_u *)"zindex", -1);
+    if (di != NULL)
+    {
+       wp->w_zindex = dict_get_number(dict, (char_u *)"zindex");
+       if (wp->w_zindex < 1)
+           wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
+       if (wp->w_zindex > 32000)
+           wp->w_zindex = 32000;
+    }
 
-# if defined(FEAT_TIMERS)
+#if defined(FEAT_TIMERS)
     // Add timer to close the popup after some time.
     nr = dict_get_number(dict, (char_u *)"time");
     if (nr > 0)
-    {
-       char_u      cbbuf[50];
-       char_u      *ptr = cbbuf;
-       typval_T    tv;
-
-       vim_snprintf((char *)cbbuf, sizeof(cbbuf),
-                                          "{_ -> popup_close(%d)}", wp->w_id);
-       if (get_lambda_tv(&ptr, &tv, TRUE) == OK)
-       {
-           wp->w_popup_timer = create_timer(nr, 0);
-           wp->w_popup_timer->tr_callback = get_callback(&tv);
-           clear_tv(&tv);
-       }
-    }
-# endif
+       popup_add_timeout(wp, nr);
+#endif
 
     // Option values resulting in setting an option.
     str = dict_get_string(dict, (char_u *)"highlight", FALSE);
@@ -601,7 +611,8 @@ popup_adjust_position(win_T *wp)
 typedef enum
 {
     TYPE_NORMAL,
-    TYPE_ATCURSOR
+    TYPE_ATCURSOR,
+    TYPE_NOTIFICATION
 } create_type_T;
 
 /*
@@ -659,7 +670,13 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
     // Avoid that 'buftype' is reset when this buffer is entered.
     buf->b_p_initialized = TRUE;
 
-    nr = (int)dict_get_number(d, (char_u *)"tab");
+    if (dict_find(d, (char_u *)"tab", -1) != NULL)
+       nr = (int)dict_get_number(d, (char_u *)"tab");
+    else if (type == TYPE_NOTIFICATION)
+       nr = -1;  // notifications are global by default
+    else
+       nr = 0;
+
     if (nr == 0)
     {
        // popup on current tab
@@ -668,9 +685,18 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
     }
     else if (nr < 0)
     {
-       // global popup
-       wp->w_next = first_popupwin;
-       first_popupwin = wp;
+       win_T *prev = first_popupwin;
+
+       // Global popup: add at the end, so that it gets displayed on top of
+       // older ones with the same zindex. Matters for notifications.
+       if (first_popupwin == NULL)
+           first_popupwin = wp;
+       else
+       {
+           while (prev->w_next != NULL)
+               prev = prev->w_next;
+           prev->w_next = wp;
+       }
     }
     else
        // TODO: find tab page "nr"
@@ -720,9 +746,52 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
     // set default values
     wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
 
+    if (type == TYPE_NOTIFICATION)
+    {
+       win_T  *twp, *nextwin;
+       int     height = buf->b_ml.ml_line_count + 3;
+       int     i;
+
+       // Try to not overlap with another global popup.  Guess we need 3
+       // more screen lines than buffer lines.
+       wp->w_wantline = 1;
+       for (twp = first_popupwin; twp != NULL; twp = nextwin)
+       {
+           nextwin = twp->w_next;
+           if (twp != wp
+                   && twp->w_zindex == POPUPWIN_NOTIFICATION_ZINDEX
+                   && twp->w_winrow <= wp->w_wantline - 1 + height
+                   && twp->w_winrow + popup_height(twp) > wp->w_wantline - 1)
+           {
+               // move to below this popup and restart the loop to check for
+               // overlap with other popups
+               wp->w_wantline = twp->w_winrow + popup_height(twp) + 1;
+               nextwin = first_popupwin;
+           }
+       }
+       if (wp->w_wantline + height > Rows)
+       {
+           // can't avoid overlap, put on top in the hope that message goes
+           // away soon.
+           wp->w_wantline = 1;
+       }
+
+       wp->w_wantcol = 10;
+       wp->w_zindex = POPUPWIN_NOTIFICATION_ZINDEX;
+       for (i = 0; i < 4; ++i)
+           wp->w_popup_border[i] = 1;
+       wp->w_popup_padding[1] = 1;
+       wp->w_popup_padding[3] = 1;
+       set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
+                               (char_u *)"WarningMsg", OPT_FREE|OPT_LOCAL, 0);
+    }
+
     // Deal with options.
     apply_options(wp, buf, argvars[1].vval.v_dict);
 
+    if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL)
+       popup_add_timeout(wp, 3000);
+
     popup_adjust_position(wp);
 
     wp->w_vsep_width = 0;
@@ -758,6 +827,15 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv)
     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.
@@ -1017,8 +1095,10 @@ f_popup_getpos(typval_T *argvars, typval_T *rettv)
 
        dict_add_number(dict, "line", wp->w_winrow + 1);
        dict_add_number(dict, "col", wp->w_wincol + 1);
-       dict_add_number(dict, "width", wp->w_width + left_extra + wp->w_popup_border[1] + wp->w_popup_padding[1]);
-       dict_add_number(dict, "height", wp->w_height + top_extra + wp->w_popup_border[2] + wp->w_popup_padding[2]);
+       dict_add_number(dict, "width", wp->w_width + left_extra
+                            + wp->w_popup_border[1] + wp->w_popup_padding[1]);
+       dict_add_number(dict, "height", wp->w_height + top_extra
+                            + wp->w_popup_border[2] + wp->w_popup_padding[2]);
 
        dict_add_number(dict, "core_line", wp->w_winrow + 1 + top_extra);
        dict_add_number(dict, "core_col", wp->w_wincol + 1 + left_extra);
index a27444679ee28135d5d0d4778df26a504fc83dd7..03d3729ed04e087c4957f11f7c4ae8e84cab3a97 100644 (file)
@@ -5,6 +5,7 @@ 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_notification(typval_T *argvars, typval_T *rettv);
 int popup_any_visible(void);
 void f_popup_close(typval_T *argvars, typval_T *rettv);
 void f_popup_hide(typval_T *argvars, typval_T *rettv);
index 8e6d93f30e22738a3f6f9a44a60456c7fca295af..1fd430965dbb846247b264f1ca2340e8317a4bbb 100644 (file)
@@ -1992,8 +1992,9 @@ typedef enum {
     POPPOS_CENTER
 } poppos_T;
 
-# define POPUPWIN_DEFAULT_ZINDEX    50
-# define POPUPMENU_ZINDEX          100
+# define POPUPWIN_DEFAULT_ZINDEX        50
+# define POPUPMENU_ZINDEX              100
+# define POPUPWIN_NOTIFICATION_ZINDEX   200
 #endif
 
 /*
diff --git a/src/testdir/dumps/Test_popupwin_notify_01.dump b/src/testdir/dumps/Test_popupwin_notify_01.dump
new file mode 100644 (file)
index 0000000..2ecd5ee
--- /dev/null
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @7|╔+0#e000002&|═@19|╗| +0#0000000&@43
+|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0#0000000&@43
+|3| @7|╚+0#e000002&|═@19|╝| +0#0000000&@43
+|4| @73
+|5| @73
+|6| @73
+|7| @73
+|8| @73
+|9| @73
+@57|1|,|1| @10|T|o|p| 
diff --git a/src/testdir/dumps/Test_popupwin_notify_02.dump b/src/testdir/dumps/Test_popupwin_notify_02.dump
new file mode 100644 (file)
index 0000000..1017061
--- /dev/null
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @7|╔+0#e000002&|═@19|╗| +0#0000000&@43
+|2| @7|║+0#e000002&| |f|i|r|s|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0#0000000&@43
+|3| @7|╚+0#e000002&|═@19|╝| +0#0000000&@43
+|4| @7|╔+0&#5fd7ff255|═@31|╗| +0&#ffffff0@31
+|5| @7|║+0&#5fd7ff255| |a|n|o|t|h|e|r| |i|m|p|o|r|t|a|n|t| |n|o|t|i|f|i|c|a|t|i|o|n| |║| +0&#ffffff0@31
+|6| @7|╚+0&#5fd7ff255|═@31|╝| +0&#ffffff0@31
+|7| @73
+|8| @73
+|9| @73
+@57|1|,|1| @10|T|o|p| 
index d100dc99388cf1ae61a12695bda48337b2663705..9afd84033d22510617462694a65253ae71d208e9 100644 (file)
@@ -428,7 +428,7 @@ endfunc
 
 func Test_popup_time()
   if !has('timers')
-    return
+    throw 'Skipped, timer feature not supported'
   endif
   topleft vnew
   call setline(1, 'hello')
@@ -1086,3 +1086,29 @@ func Test_popup_moved()
   bwipe!
   call test_override('ALL', 0)
 endfunc
+
+func Test_notifications()
+  if !has('timers')
+    throw 'Skipped, timer feature not supported'
+  endif
+  if !CanRunVimInTerminal()
+    throw 'Skipped: cannot make screendumps'
+  endif
+
+  call writefile([
+       \ "call setline(1, range(1, 20))",
+       \ "hi Notification ctermbg=lightblue",
+       \ "call popup_notification('first notification', {})",
+       \], 'XtestNotifications')
+  let buf = RunVimInTerminal('-S XtestNotifications', {'rows': 10})
+  call VerifyScreenDump(buf, 'Test_popupwin_notify_01', {})
+
+  " second one goes below the first one
+  call term_sendkeys(buf, ":call popup_notification('another important notification', {'highlight': 'Notification'})\<CR>")
+  call VerifyScreenDump(buf, 'Test_popupwin_notify_02', {})
+
+
+  " clean up
+  call StopVimInTerminal(buf)
+  call delete('XtestNotifications')
+endfunc
index 28877cb560d28f47733b7afcc2bc7f09ff3431e7..9c4d0688aed43cbcec336fabf94a886c763e0e78 100644 (file)
@@ -777,6 +777,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1522,
 /**/
     1521,
 /**/