Skip to content

Commit d7f246c

Browse files
committed
patch 8.1.1138: plugins don't get notified when the popup menu changes
Problem: Plugins don't get notified when the popup menu changes. Solution: Add the CompleteChanged event. (Andy Massimino. closes #4176)
1 parent 62e1bb4 commit d7f246c

File tree

11 files changed

+164
-17
lines changed

11 files changed

+164
-17
lines changed

runtime/doc/autocmd.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ Name triggered by ~
367367
|SessionLoadPost| after loading a session file
368368

369369
|MenuPopup| just before showing the popup menu
370+
|CompleteChanged| after Insert mode completion menu changed
370371
|CompleteDone| after Insert mode completion is done
371372

372373
|User| to be used in combination with ":doautocmd"
@@ -579,7 +580,22 @@ ColorScheme After loading a color scheme. |:colorscheme|
579580
ColorSchemePre Before loading a color scheme. |:colorscheme|
580581
Useful to setup removing things added by a
581582
color scheme, before another one is loaded.
583+
CompleteChanged *CompleteChanged*
584+
After each time the Insert mode completion
585+
menu changed. Not fired on popup menu hide,
586+
use |CompleteDone| for that. Never triggered
587+
recursively.
588+
589+
Sets these |v:event| keys:
590+
completed_item
591+
height nr of items visible
592+
width screen cells
593+
row top screen row
594+
col leftmost screen column
595+
size total nr of items
596+
scrollbar TRUE if visible
582597

598+
It is not allowed to change the text |textlock|.
583599
*CompleteDone*
584600
CompleteDone After Insert mode completion is done. Either
585601
when something was completed or abandoning

src/autocmd.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ static struct event_name
112112
{"CmdUndefined", EVENT_CMDUNDEFINED},
113113
{"ColorScheme", EVENT_COLORSCHEME},
114114
{"ColorSchemePre", EVENT_COLORSCHEMEPRE},
115+
{"CompleteChanged", EVENT_COMPLETECHANGED},
115116
{"CompleteDone", EVENT_COMPLETEDONE},
116117
{"CursorHold", EVENT_CURSORHOLD},
117118
{"CursorHoldI", EVENT_CURSORHOLDI},
@@ -1794,6 +1795,17 @@ has_textyankpost(void)
17941795
}
17951796
#endif
17961797

1798+
#if defined(FEAT_EVAL) || defined(PROTO)
1799+
/*
1800+
* Return TRUE when there is a CompleteChanged autocommand defined.
1801+
*/
1802+
int
1803+
has_completechanged(void)
1804+
{
1805+
return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1806+
}
1807+
#endif
1808+
17971809
/*
17981810
* Execute autocommands for "event" and file name "fname".
17991811
* Return TRUE if some commands were executed.

src/dict.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,18 +342,18 @@ dict_add(dict_T *d, dictitem_T *item)
342342
}
343343

344344
/*
345-
* Add a number entry to dictionary "d".
345+
* Add a number or special entry to dictionary "d".
346346
* Returns FAIL when out of memory and when key already exists.
347347
*/
348-
int
349-
dict_add_number(dict_T *d, char *key, varnumber_T nr)
348+
static int
349+
dict_add_number_special(dict_T *d, char *key, varnumber_T nr, int special)
350350
{
351351
dictitem_T *item;
352352

353353
item = dictitem_alloc((char_u *)key);
354354
if (item == NULL)
355355
return FAIL;
356-
item->di_tv.v_type = VAR_NUMBER;
356+
item->di_tv.v_type = special ? VAR_SPECIAL : VAR_NUMBER;
357357
item->di_tv.vval.v_number = nr;
358358
if (dict_add(d, item) == FAIL)
359359
{
@@ -363,6 +363,26 @@ dict_add_number(dict_T *d, char *key, varnumber_T nr)
363363
return OK;
364364
}
365365

366+
/*
367+
* Add a number entry to dictionary "d".
368+
* Returns FAIL when out of memory and when key already exists.
369+
*/
370+
int
371+
dict_add_number(dict_T *d, char *key, varnumber_T nr)
372+
{
373+
return dict_add_number_special(d, key, nr, FALSE);
374+
}
375+
376+
/*
377+
* Add a special entry to dictionary "d".
378+
* Returns FAIL when out of memory and when key already exists.
379+
*/
380+
int
381+
dict_add_special(dict_T *d, char *key, varnumber_T nr)
382+
{
383+
return dict_add_number_special(d, key, nr, TRUE);
384+
}
385+
366386
/*
367387
* Add a string entry to dictionary "d".
368388
* Returns FAIL when out of memory and when key already exists.

src/insexpand.c

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg);
203203
static void ins_compl_add_list(list_T *list);
204204
static void ins_compl_add_dict(dict_T *dict);
205205
# endif
206+
static dict_T *ins_compl_dict_alloc(compl_T *match);
206207
static int ins_compl_key2dir(int c);
207208
static int ins_compl_pum_key(int c);
208209
static int ins_compl_key2count(int c);
@@ -994,6 +995,37 @@ pum_enough_matches(void)
994995
return (i >= 2);
995996
}
996997

998+
static void
999+
trigger_complete_changed_event(int cur)
1000+
{
1001+
dict_T *v_event;
1002+
dict_T *item;
1003+
static int recursive = FALSE;
1004+
1005+
if (recursive)
1006+
return;
1007+
1008+
v_event = get_vim_var_dict(VV_EVENT);
1009+
if (cur < 0)
1010+
item = dict_alloc();
1011+
else
1012+
item = ins_compl_dict_alloc(compl_curr_match);
1013+
if (item == NULL)
1014+
return;
1015+
dict_add_dict(v_event, "completed_item", item);
1016+
pum_set_event_info(v_event);
1017+
dict_set_items_ro(v_event);
1018+
1019+
recursive = TRUE;
1020+
textlock++;
1021+
apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, FALSE, curbuf);
1022+
textlock--;
1023+
recursive = FALSE;
1024+
1025+
dict_free_contents(v_event);
1026+
hash_init(&v_event->dv_hashtab);
1027+
}
1028+
9971029
/*
9981030
* Show the popup menu for the list of matches.
9991031
* Also adjusts "compl_shown_match" to an entry that is actually displayed.
@@ -1136,6 +1168,9 @@ ins_compl_show_pum(void)
11361168
curwin->w_cursor.col = compl_col;
11371169
pum_display(compl_match_array, compl_match_arraysize, cur);
11381170
curwin->w_cursor.col = col;
1171+
1172+
if (has_completechanged())
1173+
trigger_complete_changed_event(cur);
11391174
}
11401175
}
11411176

@@ -2899,23 +2934,31 @@ ins_compl_insert(int in_compl_func)
28992934
compl_used_match = FALSE;
29002935
else
29012936
compl_used_match = TRUE;
2937+
dict = ins_compl_dict_alloc(compl_shown_match);
2938+
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
2939+
if (!in_compl_func)
2940+
compl_curr_match = compl_shown_match;
2941+
}
2942+
2943+
/*
2944+
* Allocate Dict for the completed item.
2945+
* { word, abbr, menu, kind, info }
2946+
*/
2947+
static dict_T *
2948+
ins_compl_dict_alloc(compl_T *match)
2949+
{
2950+
dict_T *dict = dict_alloc_lock(VAR_FIXED);
29022951

2903-
// Set completed item.
2904-
// { word, abbr, menu, kind, info }
2905-
dict = dict_alloc_lock(VAR_FIXED);
29062952
if (dict != NULL)
29072953
{
2908-
dict_add_string(dict, "word", compl_shown_match->cp_str);
2909-
dict_add_string(dict, "abbr", compl_shown_match->cp_text[CPT_ABBR]);
2910-
dict_add_string(dict, "menu", compl_shown_match->cp_text[CPT_MENU]);
2911-
dict_add_string(dict, "kind", compl_shown_match->cp_text[CPT_KIND]);
2912-
dict_add_string(dict, "info", compl_shown_match->cp_text[CPT_INFO]);
2913-
dict_add_string(dict, "user_data",
2914-
compl_shown_match->cp_text[CPT_USER_DATA]);
2954+
dict_add_string(dict, "word", match->cp_str);
2955+
dict_add_string(dict, "abbr", match->cp_text[CPT_ABBR]);
2956+
dict_add_string(dict, "menu", match->cp_text[CPT_MENU]);
2957+
dict_add_string(dict, "kind", match->cp_text[CPT_KIND]);
2958+
dict_add_string(dict, "info", match->cp_text[CPT_INFO]);
2959+
dict_add_string(dict, "user_data", match->cp_text[CPT_USER_DATA]);
29152960
}
2916-
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
2917-
if (!in_compl_func)
2918-
compl_curr_match = compl_shown_match;
2961+
return dict;
29192962
}
29202963

29212964
/*

src/popupmnu.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,22 @@ pum_get_height(void)
923923
return pum_height;
924924
}
925925

926+
/*
927+
* Add size information about the pum to "dict".
928+
*/
929+
void
930+
pum_set_event_info(dict_T *dict)
931+
{
932+
if (!pum_visible())
933+
return;
934+
dict_add_number(dict, "height", pum_height);
935+
dict_add_number(dict, "width", pum_width);
936+
dict_add_number(dict, "row", pum_row);
937+
dict_add_number(dict, "col", pum_col);
938+
dict_add_number(dict, "size", pum_size);
939+
dict_add_special(dict, "scrollbar", pum_scrollbar ? VVAL_TRUE : VVAL_FALSE);
940+
}
941+
926942
# if defined(FEAT_BEVAL_TERM) || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
927943
static void
928944
pum_position_at_mouse(int min_width)

src/proto/autocmd.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ int has_insertcharpre(void);
2626
int has_cmdundefined(void);
2727
int has_funcundefined(void);
2828
int has_textyankpost(void);
29+
int has_completechanged(void);
2930
void block_autocmds(void);
3031
void unblock_autocmds(void);
3132
int is_autocmd_blocked(void);

src/proto/dict.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void dictitem_free(dictitem_T *item);
1414
dict_T *dict_copy(dict_T *orig, int deep, int copyID);
1515
int dict_add(dict_T *d, dictitem_T *item);
1616
int dict_add_number(dict_T *d, char *key, varnumber_T nr);
17+
int dict_add_special(dict_T *d, char *key, varnumber_T nr);
1718
int dict_add_string(dict_T *d, char *key, char_u *str);
1819
int dict_add_string_len(dict_T *d, char *key, char_u *str, int len);
1920
int dict_add_list(dict_T *d, char *key, list_T *list);

src/proto/popupmnu.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ void pum_clear(void);
88
int pum_visible(void);
99
void pum_may_redraw(void);
1010
int pum_get_height(void);
11+
void pum_set_event_info(dict_T *dict);
1112
int split_message(char_u *mesg, pumitem_T **array);
1213
void ui_remove_balloon(void);
1314
void ui_post_balloon(char_u *mesg, list_T *list);

src/testdir/test_popup.vim

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,4 +1029,38 @@ func Test_popup_complete_info_02()
10291029
bwipe!
10301030
endfunc
10311031

1032+
func Test_CompleteChanged()
1033+
new
1034+
call setline(1, ['foo', 'bar', 'foobar', ''])
1035+
set complete=. completeopt=noinsert,noselect,menuone
1036+
function! OnPumChange()
1037+
let g:event = copy(v:event)
1038+
let g:item = get(v:event, 'completed_item', {})
1039+
let g:word = get(g:item, 'word', v:null)
1040+
endfunction
1041+
augroup AAAAA_Group
1042+
au!
1043+
autocmd CompleteChanged * :call OnPumChange()
1044+
augroup END
1045+
call cursor(4, 1)
1046+
1047+
call feedkeys("Sf\<C-N>", 'tx')
1048+
call assert_equal({'completed_item': {}, 'width': 15,
1049+
\ 'height': 2, 'size': 2,
1050+
\ 'col': 0, 'row': 4, 'scrollbar': v:false}, g:event)
1051+
call feedkeys("a\<C-N>\<C-N>\<C-E>", 'tx')
1052+
call assert_equal('foo', g:word)
1053+
call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1054+
call assert_equal('foobar', g:word)
1055+
call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1056+
call assert_equal(v:null, g:word)
1057+
call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-P>", 'tx')
1058+
call assert_equal('foobar', g:word)
1059+
1060+
autocmd! AAAAA_Group
1061+
set complete& completeopt&
1062+
delfunc! OnPumchange
1063+
bw!
1064+
endfunc
1065+
10321066
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

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

772772
static int included_patches[] =
773773
{ /* Add new patch number below this line */
774+
/**/
775+
1138,
774776
/**/
775777
1137,
776778
/**/

0 commit comments

Comments
 (0)