0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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)
This commit is contained in:
Bram Moolenaar
2019-04-08 18:15:41 +02:00
parent 62e1bb4a11
commit d7f246c68c
11 changed files with 165 additions and 18 deletions

View 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

View 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.

View 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.

View 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,25 +2934,33 @@ ins_compl_insert(int in_compl_func)
compl_used_match = FALSE;
else
compl_used_match = TRUE;
// 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 = 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);
if (dict != NULL)
{
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]);
}
return dict;
}
/*
* Fill in the next completion in the current direction.
* If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to

View 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)

View 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);

View 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);

View 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);

View 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

View File

@@ -771,6 +771,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1138,
/**/
1137,
/**/

View File

@@ -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