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:
@@ -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
|
||||
|
@@ -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.
|
||||
|
28
src/dict.c
28
src/dict.c
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -771,6 +771,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1138,
|
||||
/**/
|
||||
1137,
|
||||
/**/
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user