mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -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
|
|SessionLoadPost| after loading a session file
|
||||||
|
|
||||||
|MenuPopup| just before showing the popup menu
|
|MenuPopup| just before showing the popup menu
|
||||||
|
|CompleteChanged| after Insert mode completion menu changed
|
||||||
|CompleteDone| after Insert mode completion is done
|
|CompleteDone| after Insert mode completion is done
|
||||||
|
|
||||||
|User| to be used in combination with ":doautocmd"
|
|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|
|
ColorSchemePre Before loading a color scheme. |:colorscheme|
|
||||||
Useful to setup removing things added by a
|
Useful to setup removing things added by a
|
||||||
color scheme, before another one is loaded.
|
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*
|
||||||
CompleteDone After Insert mode completion is done. Either
|
CompleteDone After Insert mode completion is done. Either
|
||||||
when something was completed or abandoning
|
when something was completed or abandoning
|
||||||
|
@@ -112,6 +112,7 @@ static struct event_name
|
|||||||
{"CmdUndefined", EVENT_CMDUNDEFINED},
|
{"CmdUndefined", EVENT_CMDUNDEFINED},
|
||||||
{"ColorScheme", EVENT_COLORSCHEME},
|
{"ColorScheme", EVENT_COLORSCHEME},
|
||||||
{"ColorSchemePre", EVENT_COLORSCHEMEPRE},
|
{"ColorSchemePre", EVENT_COLORSCHEMEPRE},
|
||||||
|
{"CompleteChanged", EVENT_COMPLETECHANGED},
|
||||||
{"CompleteDone", EVENT_COMPLETEDONE},
|
{"CompleteDone", EVENT_COMPLETEDONE},
|
||||||
{"CursorHold", EVENT_CURSORHOLD},
|
{"CursorHold", EVENT_CURSORHOLD},
|
||||||
{"CursorHoldI", EVENT_CURSORHOLDI},
|
{"CursorHoldI", EVENT_CURSORHOLDI},
|
||||||
@@ -1794,6 +1795,17 @@ has_textyankpost(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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".
|
* Execute autocommands for "event" and file name "fname".
|
||||||
* Return TRUE if some commands were executed.
|
* 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.
|
* Returns FAIL when out of memory and when key already exists.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
dict_add_number(dict_T *d, char *key, varnumber_T nr)
|
dict_add_number_special(dict_T *d, char *key, varnumber_T nr, int special)
|
||||||
{
|
{
|
||||||
dictitem_T *item;
|
dictitem_T *item;
|
||||||
|
|
||||||
item = dictitem_alloc((char_u *)key);
|
item = dictitem_alloc((char_u *)key);
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
return FAIL;
|
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;
|
item->di_tv.vval.v_number = nr;
|
||||||
if (dict_add(d, item) == FAIL)
|
if (dict_add(d, item) == FAIL)
|
||||||
{
|
{
|
||||||
@@ -363,6 +363,26 @@ dict_add_number(dict_T *d, char *key, varnumber_T nr)
|
|||||||
return OK;
|
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".
|
* Add a string entry to dictionary "d".
|
||||||
* Returns FAIL when out of memory and when key already exists.
|
* 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_list(list_T *list);
|
||||||
static void ins_compl_add_dict(dict_T *dict);
|
static void ins_compl_add_dict(dict_T *dict);
|
||||||
# endif
|
# endif
|
||||||
|
static dict_T *ins_compl_dict_alloc(compl_T *match);
|
||||||
static int ins_compl_key2dir(int c);
|
static int ins_compl_key2dir(int c);
|
||||||
static int ins_compl_pum_key(int c);
|
static int ins_compl_pum_key(int c);
|
||||||
static int ins_compl_key2count(int c);
|
static int ins_compl_key2count(int c);
|
||||||
@@ -994,6 +995,37 @@ pum_enough_matches(void)
|
|||||||
return (i >= 2);
|
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.
|
* Show the popup menu for the list of matches.
|
||||||
* Also adjusts "compl_shown_match" to an entry that is actually displayed.
|
* 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;
|
curwin->w_cursor.col = compl_col;
|
||||||
pum_display(compl_match_array, compl_match_arraysize, cur);
|
pum_display(compl_match_array, compl_match_arraysize, cur);
|
||||||
curwin->w_cursor.col = col;
|
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;
|
compl_used_match = FALSE;
|
||||||
else
|
else
|
||||||
compl_used_match = TRUE;
|
compl_used_match = TRUE;
|
||||||
|
dict = ins_compl_dict_alloc(compl_shown_match);
|
||||||
// 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]);
|
|
||||||
}
|
|
||||||
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
||||||
if (!in_compl_func)
|
if (!in_compl_func)
|
||||||
compl_curr_match = compl_shown_match;
|
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.
|
* Fill in the next completion in the current direction.
|
||||||
* If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
|
* 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;
|
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)
|
# if defined(FEAT_BEVAL_TERM) || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
|
||||||
static void
|
static void
|
||||||
pum_position_at_mouse(int min_width)
|
pum_position_at_mouse(int min_width)
|
||||||
|
@@ -26,6 +26,7 @@ int has_insertcharpre(void);
|
|||||||
int has_cmdundefined(void);
|
int has_cmdundefined(void);
|
||||||
int has_funcundefined(void);
|
int has_funcundefined(void);
|
||||||
int has_textyankpost(void);
|
int has_textyankpost(void);
|
||||||
|
int has_completechanged(void);
|
||||||
void block_autocmds(void);
|
void block_autocmds(void);
|
||||||
void unblock_autocmds(void);
|
void unblock_autocmds(void);
|
||||||
int is_autocmd_blocked(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);
|
dict_T *dict_copy(dict_T *orig, int deep, int copyID);
|
||||||
int dict_add(dict_T *d, dictitem_T *item);
|
int dict_add(dict_T *d, dictitem_T *item);
|
||||||
int dict_add_number(dict_T *d, char *key, varnumber_T nr);
|
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(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_string_len(dict_T *d, char *key, char_u *str, int len);
|
||||||
int dict_add_list(dict_T *d, char *key, list_T *list);
|
int dict_add_list(dict_T *d, char *key, list_T *list);
|
||||||
|
@@ -8,6 +8,7 @@ void pum_clear(void);
|
|||||||
int pum_visible(void);
|
int pum_visible(void);
|
||||||
void pum_may_redraw(void);
|
void pum_may_redraw(void);
|
||||||
int pum_get_height(void);
|
int pum_get_height(void);
|
||||||
|
void pum_set_event_info(dict_T *dict);
|
||||||
int split_message(char_u *mesg, pumitem_T **array);
|
int split_message(char_u *mesg, pumitem_T **array);
|
||||||
void ui_remove_balloon(void);
|
void ui_remove_balloon(void);
|
||||||
void ui_post_balloon(char_u *mesg, list_T *list);
|
void ui_post_balloon(char_u *mesg, list_T *list);
|
||||||
|
@@ -1029,4 +1029,38 @@ func Test_popup_complete_info_02()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -771,6 +771,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1138,
|
||||||
/**/
|
/**/
|
||||||
1137,
|
1137,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -1270,6 +1270,7 @@ enum auto_event
|
|||||||
EVENT_CMDWINLEAVE, // before leaving the cmdline window
|
EVENT_CMDWINLEAVE, // before leaving the cmdline window
|
||||||
EVENT_COLORSCHEME, // after loading a colorscheme
|
EVENT_COLORSCHEME, // after loading a colorscheme
|
||||||
EVENT_COLORSCHEMEPRE, // before loading a colorscheme
|
EVENT_COLORSCHEMEPRE, // before loading a colorscheme
|
||||||
|
EVENT_COMPLETECHANGED, // after completion popup menu changed
|
||||||
EVENT_COMPLETEDONE, // after finishing insert complete
|
EVENT_COMPLETEDONE, // after finishing insert complete
|
||||||
EVENT_CURSORHOLD, // cursor in same position for a while
|
EVENT_CURSORHOLD, // cursor in same position for a while
|
||||||
EVENT_CURSORHOLDI, // idem, in Insert mode
|
EVENT_CURSORHOLDI, // idem, in Insert mode
|
||||||
|
Reference in New Issue
Block a user