aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/autocmd.txt17
-rw-r--r--runtime/doc/eval.txt13
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/edit.c45
-rw-r--r--src/nvim/popupmnu.c15
-rw-r--r--src/nvim/popupmnu.h1
-rw-r--r--test/functional/viml/completion_spec.lua79
7 files changed, 160 insertions, 11 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 6423939b83..89d9e45e0d 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -350,6 +350,7 @@ Name triggered by ~
|SessionLoadPost| after loading a session file
|MenuPopup| just before showing the popup menu
+|MenuPopupChanged| after popup menu changed, not fired on popup menu hide
|CompleteDone| after Insert mode completion is done
|User| to be used in combination with ":doautocmd"
@@ -843,6 +844,22 @@ MenuPopup Just before showing the popup menu (under the
o Operator-pending
i Insert
c Command line
+MenuPopupChanged *MenuPopupChanged*
+ After each time popup menu changed, not fired
+ on popup menu hide, use |CompleteDone| for popup
+ menu hide.
+
+ Sets these |v:event| keys:
+ completed_item
+ height
+ width
+ row
+ col
+ size
+ scrollbar
+
+ It is not allowed to change the text |textlock|.
+
*OptionSet*
OptionSet After setting an option. The pattern is
matched against the long option name.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 3efe651dfe..2610b2683e 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1552,6 +1552,19 @@ v:event Dictionary of event data for the current |autocommand|. Valid
operation.
regtype Type of register as returned by
|getregtype()|.
+ completed_item Current selected complete item on
+ |MenuPopupChanged|, Is `{}` when no complete
+ item selected.
+ height Height of popup menu on |MenuPopupChanged|
+ width width of popup menu on |MenuPopupChanged|
+ row Row count of popup menu on |MenuPopupChanged|,
+ relative to screen.
+ col Col count of popup menu on |MenuPopupChanged|,
+ relative to screen.
+ size Total number of completion items on
+ |MenuPopupChanged|.
+ scrollbar Is |v:true| if popup menu have scrollbar, or
+ |v:false| if not.
*v:exception* *exception-variable*
v:exception The value of the exception most recently caught and not
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index cc0ed0f587..345bf67c0e 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -66,6 +66,7 @@ return {
'InsertLeave', -- when leaving Insert mode
'JobActivity', -- when job sent some data
'MenuPopup', -- just before popup menu is displayed
+ 'MenuPopupChanged', -- after popup menu changed
'OptionSet', -- after setting any option
'QuickFixCmdPost', -- after :make, :grep etc.
'QuickFixCmdPre', -- before :make, :grep etc.
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 6b31406b0c..6f0468dbea 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -2658,6 +2658,23 @@ void ins_compl_show_pum(void)
pum_selected_item = cur;
pum_display(compl_match_array, compl_match_arraysize, cur, array_changed);
curwin->w_cursor.col = col;
+
+ if (!has_event(EVENT_MENUPOPUPCHANGED)) {
+ return;
+ }
+ dict_T *dict = get_vim_var_dict(VV_EVENT);
+ if (cur < 0) {
+ tv_dict_add_dict(dict, S_LEN("completed_item"), tv_dict_alloc());
+ } else {
+ dict_T *item = ins_compl_dict_alloc(compl_curr_match);
+ tv_dict_add_dict(dict, S_LEN("completed_item"), item);
+ }
+ pum_set_boundings(dict);
+ tv_dict_set_keys_readonly(dict);
+ textlock++;
+ apply_autocmds(EVENT_MENUPOPUPCHANGED, NULL, NULL, false, curbuf);
+ textlock--;
+ tv_dict_clear(dict);
}
#define DICT_FIRST (1) /* use just first element in "dict" */
@@ -4096,31 +4113,37 @@ static void ins_compl_insert(int in_compl_func)
else
compl_used_match = TRUE;
- // Set completed item.
+ dict_T *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;
+ }
+}
+
+// Convert to complete item dict
+static dict_T *ins_compl_dict_alloc(compl_T *match)
+{
// { word, abbr, menu, kind, info }
dict_T *dict = tv_dict_alloc();
tv_dict_add_str(
dict, S_LEN("word"),
- (const char *)EMPTY_IF_NULL(compl_shown_match->cp_str));
+ (const char *)EMPTY_IF_NULL(match->cp_str));
tv_dict_add_str(
dict, S_LEN("abbr"),
- (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
tv_dict_add_str(
dict, S_LEN("menu"),
- (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_MENU]));
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
tv_dict_add_str(
dict, S_LEN("kind"),
- (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_KIND]));
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
tv_dict_add_str(
dict, S_LEN("info"),
- (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
tv_dict_add_str(
dict, S_LEN("user_data"),
- (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_USER_DATA]));
- set_vim_var_dict(VV_COMPLETED_ITEM, dict);
- if (!in_compl_func) {
- compl_curr_match = compl_shown_match;
- }
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_USER_DATA]));
+ return dict;
}
/*
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 499ee11cad..e9b3f04454 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -12,6 +12,7 @@
#include "nvim/vim.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
+#include "nvim/eval/typval.h"
#include "nvim/popupmnu.h"
#include "nvim/charset.h"
#include "nvim/ex_cmds.h"
@@ -841,3 +842,17 @@ int pum_get_height(void)
{
return pum_height;
}
+
+void pum_set_boundings(dict_T *dict)
+{
+ if (!pum_visible()) {
+ return;
+ }
+ tv_dict_add_nr(dict, S_LEN("height"), pum_height);
+ tv_dict_add_nr(dict, S_LEN("width"), pum_width);
+ tv_dict_add_nr(dict, S_LEN("row"), pum_row);
+ tv_dict_add_nr(dict, S_LEN("col"), pum_col);
+ tv_dict_add_nr(dict, S_LEN("size"), pum_size);
+ tv_dict_add_special(dict, S_LEN("scrollbar"),
+ pum_scrollbar ? kSpecialVarTrue : kSpecialVarFalse);
+}
diff --git a/src/nvim/popupmnu.h b/src/nvim/popupmnu.h
index 42e6ef5653..7956e50a93 100644
--- a/src/nvim/popupmnu.h
+++ b/src/nvim/popupmnu.h
@@ -1,6 +1,7 @@
#ifndef NVIM_POPUPMNU_H
#define NVIM_POPUPMNU_H
+#include "nvim/vim.h"
#include "nvim/macros.h"
#include "nvim/grid_defs.h"
#include "nvim/types.h"
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index cd1b312265..c84b2c1087 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -1072,4 +1072,83 @@ describe('completion', function()
set complete&vim completeopt&vim
]])
end)
+
+ it('MenuPopupChanged autocommand', function()
+ curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar', ''})
+ source([[
+ 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
+ autocmd! MenuPopupChanged * :call OnPumChange()
+ call cursor(4, 1)
+ ]])
+
+ feed('Sf<C-N>')
+ screen:expect([[
+ foo |
+ bar |
+ foobar |
+ f^ |
+ {1:foo }{0: }|
+ {1:foobar }{0: }|
+ {0:~ }|
+ {3:-- Keyword completion (^N^P) }{5:Back at original} |
+ ]])
+ eq({completed_item = {}, width = 15,
+ height = 2, size = 2,
+ col = 0, row = 4, scrollbar = false},
+ eval('g:event'))
+ feed('<C-N>')
+ screen:expect([[
+ foo |
+ bar |
+ foobar |
+ foo^ |
+ {2:foo }{0: }|
+ {1:foobar }{0: }|
+ {0:~ }|
+ {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ ]])
+ eq('foo', eval('g:word'))
+ feed('<C-N>')
+ screen:expect([[
+ foo |
+ bar |
+ foobar |
+ foobar^ |
+ {1:foo }{0: }|
+ {2:foobar }{0: }|
+ {0:~ }|
+ {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
+ ]])
+ eq('foobar', eval('g:word'))
+ feed('<up>')
+ screen:expect([[
+ foo |
+ bar |
+ foobar |
+ foobar^ |
+ {2:foo }{0: }|
+ {1:foobar }{0: }|
+ {0:~ }|
+ {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ ]])
+ eq('foo', eval('g:word'))
+ feed('<down>')
+ screen:expect([[
+ foo |
+ bar |
+ foobar |
+ foobar^ |
+ {1:foo }{0: }|
+ {2:foobar }{0: }|
+ {0:~ }|
+ {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
+ ]])
+ eq('foobar', eval('g:word'))
+ feed('<esc>')
+ end)
end)