]> granicus.if.org Git - vim/commitdiff
patch 8.1.1138: plugins don't get notified when the popup menu changes v8.1.1138
authorBram Moolenaar <Bram@vim.org>
Mon, 8 Apr 2019 16:15:41 +0000 (18:15 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 8 Apr 2019 16:15:41 +0000 (18:15 +0200)
Problem:    Plugins don't get notified when the popup menu changes.
Solution:   Add the CompleteChanged event. (Andy Massimino. closes #4176)

runtime/doc/autocmd.txt
src/autocmd.c
src/dict.c
src/insexpand.c
src/popupmnu.c
src/proto/autocmd.pro
src/proto/dict.pro
src/proto/popupmnu.pro
src/testdir/test_popup.vim
src/version.c
src/vim.h

index 5eb1936c48005b6feaf35d7f06a9102008a3ee1b..c4bc004d27d35b347519e45fdd598c0eb0817bb2 100644 (file)
@@ -367,6 +367,7 @@ Name                        triggered by ~
 |SessionLoadPost|      after loading a session file
 
 |MenuPopup|            just before showing the popup menu
+|CompleteChanged|      after Insert mode completion menu changed
 |CompleteDone|         after Insert mode completion is done
 
 |User|                 to be used in combination with ":doautocmd"
@@ -579,7 +580,22 @@ ColorScheme                        After loading a color scheme. |:colorscheme|
 ColorSchemePre                 Before loading a color scheme. |:colorscheme|
                                Useful to setup removing things added by a
                                color scheme, before another one is loaded.
+CompleteChanged                                        *CompleteChanged*
+                               After each time the Insert mode completion
+                               menu changed.  Not fired on popup menu hide,
+                               use |CompleteDone| for that.  Never triggered
+                               recursively.
+
+                               Sets these |v:event| keys:
+                                   completed_item
+                                   height              nr of items visible
+                                   width               screen cells
+                                   row                 top screen row
+                                   col                 leftmost screen column
+                                   size                total nr of items
+                                   scrollbar           TRUE if visible
 
+                               It is not allowed to change the text |textlock|.
                                                        *CompleteDone*
 CompleteDone                   After Insert mode completion is done.  Either
                                when something was completed or abandoning
index aa1114333793c50df5c3253bbf01b271af9b1108..2ea23ccc4ff99e78e6cfb380ef203db9df9b378c 100644 (file)
@@ -112,6 +112,7 @@ static struct event_name
     {"CmdUndefined",   EVENT_CMDUNDEFINED},
     {"ColorScheme",    EVENT_COLORSCHEME},
     {"ColorSchemePre", EVENT_COLORSCHEMEPRE},
+    {"CompleteChanged",        EVENT_COMPLETECHANGED},
     {"CompleteDone",   EVENT_COMPLETEDONE},
     {"CursorHold",     EVENT_CURSORHOLD},
     {"CursorHoldI",    EVENT_CURSORHOLDI},
@@ -1794,6 +1795,17 @@ has_textyankpost(void)
 }
 #endif
 
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE when there is a CompleteChanged autocommand defined.
+ */
+    int
+has_completechanged(void)
+{
+    return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
+}
+#endif
+
 /*
  * Execute autocommands for "event" and file name "fname".
  * Return TRUE if some commands were executed.
index 0bb9dfa875edcb6e5a362fc90bbd5d7a7a335323..7d49599efa5ffb5a579f67e22b0bce25e0c719b0 100644 (file)
@@ -342,18 +342,18 @@ dict_add(dict_T *d, dictitem_T *item)
 }
 
 /*
- * Add a number entry to dictionary "d".
+ * Add a number or special entry to dictionary "d".
  * Returns FAIL when out of memory and when key already exists.
  */
-    int
-dict_add_number(dict_T *d, char *key, varnumber_T nr)
+    static int
+dict_add_number_special(dict_T *d, char *key, varnumber_T nr, int special)
 {
     dictitem_T *item;
 
     item = dictitem_alloc((char_u *)key);
     if (item == NULL)
        return FAIL;
-    item->di_tv.v_type = VAR_NUMBER;
+    item->di_tv.v_type = special ? VAR_SPECIAL : VAR_NUMBER;
     item->di_tv.vval.v_number = nr;
     if (dict_add(d, item) == FAIL)
     {
@@ -363,6 +363,26 @@ dict_add_number(dict_T *d, char *key, varnumber_T nr)
     return OK;
 }
 
+/*
+ * Add a number entry to dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+    int
+dict_add_number(dict_T *d, char *key, varnumber_T nr)
+{
+    return dict_add_number_special(d, key, nr, FALSE);
+}
+
+/*
+ * Add a special entry to dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+    int
+dict_add_special(dict_T *d, char *key, varnumber_T nr)
+{
+    return dict_add_number_special(d, key, nr, TRUE);
+}
+
 /*
  * Add a string entry to dictionary "d".
  * Returns FAIL when out of memory and when key already exists.
index ac7f5322fa9f988cc9965b41a8e2964d38056534..ad95acc2e24257b6d8759e3059b8d91a2ef95bc9 100644 (file)
@@ -203,6 +203,7 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg);
 static void ins_compl_add_list(list_T *list);
 static void ins_compl_add_dict(dict_T *dict);
 # endif
+static dict_T *ins_compl_dict_alloc(compl_T *match);
 static int  ins_compl_key2dir(int c);
 static int  ins_compl_pum_key(int c);
 static int  ins_compl_key2count(int c);
@@ -994,6 +995,37 @@ pum_enough_matches(void)
     return (i >= 2);
 }
 
+    static void
+trigger_complete_changed_event(int cur)
+{
+    dict_T         *v_event;
+    dict_T         *item;
+    static int     recursive = FALSE;
+
+    if (recursive)
+       return;
+
+    v_event = get_vim_var_dict(VV_EVENT);
+    if (cur < 0)
+       item = dict_alloc();
+    else
+       item = ins_compl_dict_alloc(compl_curr_match);
+    if (item == NULL)
+       return;
+    dict_add_dict(v_event, "completed_item", item);
+    pum_set_event_info(v_event);
+    dict_set_items_ro(v_event);
+
+    recursive = TRUE;
+    textlock++;
+    apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, FALSE, curbuf);
+    textlock--;
+    recursive = FALSE;
+
+    dict_free_contents(v_event);
+    hash_init(&v_event->dv_hashtab);
+}
+
 /*
  * Show the popup menu for the list of matches.
  * Also adjusts "compl_shown_match" to an entry that is actually displayed.
@@ -1136,6 +1168,9 @@ ins_compl_show_pum(void)
        curwin->w_cursor.col = compl_col;
        pum_display(compl_match_array, compl_match_arraysize, cur);
        curwin->w_cursor.col = col;
+
+       if (has_completechanged())
+           trigger_complete_changed_event(cur);
     }
 }
 
@@ -2899,23 +2934,31 @@ ins_compl_insert(int in_compl_func)
        compl_used_match = FALSE;
     else
        compl_used_match = TRUE;
+    dict = ins_compl_dict_alloc(compl_shown_match);
+    set_vim_var_dict(VV_COMPLETED_ITEM, dict);
+    if (!in_compl_func)
+       compl_curr_match = compl_shown_match;
+}
+
+/*
+ * Allocate Dict for the completed item.
+ * { word, abbr, menu, kind, info }
+ */
+    static dict_T *
+ins_compl_dict_alloc(compl_T *match)
+{
+    dict_T *dict = dict_alloc_lock(VAR_FIXED);
 
-    // Set completed item.
-    // { word, abbr, menu, kind, info }
-    dict = dict_alloc_lock(VAR_FIXED);
     if (dict != NULL)
     {
-       dict_add_string(dict, "word", compl_shown_match->cp_str);
-       dict_add_string(dict, "abbr", compl_shown_match->cp_text[CPT_ABBR]);
-       dict_add_string(dict, "menu", compl_shown_match->cp_text[CPT_MENU]);
-       dict_add_string(dict, "kind", compl_shown_match->cp_text[CPT_KIND]);
-       dict_add_string(dict, "info", compl_shown_match->cp_text[CPT_INFO]);
-       dict_add_string(dict, "user_data",
-                                compl_shown_match->cp_text[CPT_USER_DATA]);
+       dict_add_string(dict, "word", match->cp_str);
+       dict_add_string(dict, "abbr", match->cp_text[CPT_ABBR]);
+       dict_add_string(dict, "menu", match->cp_text[CPT_MENU]);
+       dict_add_string(dict, "kind", match->cp_text[CPT_KIND]);
+       dict_add_string(dict, "info", match->cp_text[CPT_INFO]);
+       dict_add_string(dict, "user_data", match->cp_text[CPT_USER_DATA]);
     }
-    set_vim_var_dict(VV_COMPLETED_ITEM, dict);
-    if (!in_compl_func)
-       compl_curr_match = compl_shown_match;
+    return dict;
 }
 
 /*
index 7be8a9be4181874582a6f794a4f2bfd0bd1b359e..ba9c7adc75ffba848c708af5b992ac86eb0c55a6 100644 (file)
@@ -923,6 +923,22 @@ pum_get_height(void)
     return pum_height;
 }
 
+/*
+ * Add size information about the pum to "dict".
+ */
+    void
+pum_set_event_info(dict_T *dict)
+{
+    if (!pum_visible())
+       return;
+    dict_add_number(dict, "height", pum_height);
+    dict_add_number(dict, "width", pum_width);
+    dict_add_number(dict, "row", pum_row);
+    dict_add_number(dict, "col", pum_col);
+    dict_add_number(dict, "size", pum_size);
+    dict_add_special(dict, "scrollbar", pum_scrollbar ? VVAL_TRUE : VVAL_FALSE);
+}
+
 # if defined(FEAT_BEVAL_TERM) || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
     static void
 pum_position_at_mouse(int min_width)
index 8c6d18f75430b69bfe09a02e79bfec1bc8c6a650..a448dad0416a79cd01473ace7e1d9b79be4479b7 100644 (file)
@@ -26,6 +26,7 @@ int has_insertcharpre(void);
 int has_cmdundefined(void);
 int has_funcundefined(void);
 int has_textyankpost(void);
+int has_completechanged(void);
 void block_autocmds(void);
 void unblock_autocmds(void);
 int is_autocmd_blocked(void);
index b09a647bd4e05fa7b9a66c0f6b369022484e2de2..6d9ae194a651852d040e5fa23fb2a84ffaf78e46 100644 (file)
@@ -14,6 +14,7 @@ void dictitem_free(dictitem_T *item);
 dict_T *dict_copy(dict_T *orig, int deep, int copyID);
 int dict_add(dict_T *d, dictitem_T *item);
 int dict_add_number(dict_T *d, char *key, varnumber_T nr);
+int dict_add_special(dict_T *d, char *key, varnumber_T nr);
 int dict_add_string(dict_T *d, char *key, char_u *str);
 int dict_add_string_len(dict_T *d, char *key, char_u *str, int len);
 int dict_add_list(dict_T *d, char *key, list_T *list);
index e2ae92ae8f2118413abc7c04fadee00906b2b72f..c01966396c36a644a327680fe6d4766334c43718 100644 (file)
@@ -8,6 +8,7 @@ void pum_clear(void);
 int pum_visible(void);
 void pum_may_redraw(void);
 int pum_get_height(void);
+void pum_set_event_info(dict_T *dict);
 int split_message(char_u *mesg, pumitem_T **array);
 void ui_remove_balloon(void);
 void ui_post_balloon(char_u *mesg, list_T *list);
index a8416788ab120068ff6f261ace27fddcba47da97..538dd220ca3f230ce6b6543db52dbe6ab2d10896 100644 (file)
@@ -1029,4 +1029,38 @@ func Test_popup_complete_info_02()
   bwipe!
 endfunc
 
+func Test_CompleteChanged()
+  new
+  call setline(1, ['foo', 'bar', 'foobar', ''])
+  set complete=. completeopt=noinsert,noselect,menuone
+  function! OnPumChange()
+    let g:event = copy(v:event)
+    let g:item = get(v:event, 'completed_item', {})
+    let g:word = get(g:item, 'word', v:null)
+  endfunction
+  augroup AAAAA_Group
+    au!
+    autocmd CompleteChanged * :call OnPumChange()
+  augroup END
+  call cursor(4, 1)
+
+  call feedkeys("Sf\<C-N>", 'tx')
+  call assert_equal({'completed_item': {}, 'width': 15,
+        \ 'height': 2, 'size': 2,
+        \ 'col': 0, 'row': 4, 'scrollbar': v:false}, g:event)
+  call feedkeys("a\<C-N>\<C-N>\<C-E>", 'tx')
+  call assert_equal('foo', g:word)
+  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
+  call assert_equal('foobar', g:word)
+  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
+  call assert_equal(v:null, g:word)
+  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-P>", 'tx')
+  call assert_equal('foobar', g:word)
+
+  autocmd! AAAAA_Group
+  set complete& completeopt&
+  delfunc! OnPumchange
+  bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index d2da9fcca02e29bcaf4d6d14989efee6dc3136a2..dadb0172031bd0fa17ca439c42b18bdd32b60131 100644 (file)
@@ -771,6 +771,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1138,
 /**/
     1137,
 /**/
index 01123e0c75e0f01ff5a35eb9fc6ac2e5cc7848cb..af779f3610e752ecf52c7c950cb2bb67e0b1500c 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -1270,6 +1270,7 @@ enum auto_event
     EVENT_CMDWINLEAVE,         // before leaving the cmdline window
     EVENT_COLORSCHEME,         // after loading a colorscheme
     EVENT_COLORSCHEMEPRE,      // before loading a colorscheme
+    EVENT_COMPLETECHANGED,     // after completion popup menu changed
     EVENT_COMPLETEDONE,                // after finishing insert complete
     EVENT_CURSORHOLD,          // cursor in same position for a while
     EVENT_CURSORHOLDI,         // idem, in Insert mode