patch 9.1.0905: Missing information in CompleteDone event
Problem: Missing information in CompleteDone event
Solution: add complete_word and complete_type to v:event dict
(glepnir)
closes: #16153
Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 6ca00a6..8a653f2 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -1,4 +1,4 @@
-*autocmd.txt* For Vim version 9.1. Last change: 2024 Oct 27
+*autocmd.txt* For Vim version 9.1. Last change: 2024 Dec 04
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -702,6 +702,12 @@
The |v:completed_item| variable contains
information about the completed item.
+ Sets these |v:event| keys:
+ complete_word The word that was
+ selected, empty if
+ abandoned complete.
+ complete_type |complete_info_mode|
+
*CursorHold*
CursorHold When the user doesn't press a key for the time
specified with 'updatetime'. Not triggered
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index e73d2f1..b1318cf 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt* For Vim version 9.1. Last change: 2024 Dec 02
+*todo.txt* For Vim version 9.1. Last change: 2024 Dec 04
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -4752,9 +4752,6 @@
- When complete() first argument is before where insert started and
'backspace' is Vi compatible, the completion fails.
(Hirohito Higashi, 2015 Feb 19)
-- The CompleteDone autocommand needs some info passed to it:
- - The word that was selected (empty if abandoned complete)
- - Type of completion: tag, omnifunc, user func.
- When a:base in 'completefunc' starts with a number it's passed as a
number, not a string. (Sean Ma) Need to add flag to call_func_retlist()
to force a string value.
diff --git a/src/insexpand.c b/src/insexpand.c
index 75403f1..305511c 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -2297,12 +2297,42 @@
}
/*
+ * Trigger CompleteDone event and adds relevant information to v:event
+ */
+ static void
+trigger_complete_done_event(int mode UNUSED, char_u *word UNUSED)
+{
+#if defined(FEAT_EVAL)
+ save_v_event_T save_v_event;
+ dict_T *v_event = get_v_event(&save_v_event);
+ char_u *mode_str = NULL;
+
+ mode = mode & ~CTRL_X_WANT_IDENT;
+ if (ctrl_x_mode_names[mode])
+ mode_str = (char_u *)ctrl_x_mode_names[mode];
+
+ (void)dict_add_string(v_event, "complete_word",
+ word == NULL ? (char_u *)"" : word);
+ (void)dict_add_string(v_event, "complete_type",
+ mode_str != NULL ? mode_str : (char_u *)"");
+
+ dict_set_items_ro(v_event);
+#endif
+ ins_apply_autocmds(EVENT_COMPLETEDONE);
+
+#if defined(FEAT_EVAL)
+ restore_v_event(v_event, &save_v_event);
+#endif
+}
+
+/*
* Stop insert completion mode
*/
static int
ins_compl_stop(int c, int prev_mode, int retval)
{
int want_cindent;
+ char_u *word = NULL;
// Get here when we have finished typing a sequence of ^N and
// ^P or other completion characters in CTRL-X mode. Free up
@@ -2358,7 +2388,10 @@
if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible())
+ {
+ word = vim_strsave(compl_shown_match->cp_str.string);
retval = TRUE;
+ }
// CTRL-E means completion is Ended, go back to the typed text.
// but only do this, if the Popup is still visible
@@ -2418,7 +2451,8 @@
do_c_expr_indent();
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
- ins_apply_autocmds(EVENT_COMPLETEDONE);
+ trigger_complete_done_event(prev_mode, word);
+ vim_free(word);
return retval;
}
@@ -2538,7 +2572,7 @@
else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
// Trigger the CompleteDone event to give scripts a chance to act
// upon the (possibly failed) completion.
- ins_apply_autocmds(EVENT_COMPLETEDONE);
+ trigger_complete_done_event(ctrl_x_mode, NULL);
may_trigger_modechanged();
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index 7829f79..ad2d421 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -277,6 +277,91 @@
au! CompleteDone
endfunc
+func Test_CompleteDone_vevent_keys()
+ func OnDone()
+ let g:complete_word = get(v:event, 'complete_word', v:null)
+ let g:complete_type = get(v:event, 'complete_type', v:null)
+ endfunction
+
+ autocmd CompleteDone * :call OnDone()
+
+ func CompleteFunc(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "foo"}, #{word: "bar"}]
+ endfunc
+ set omnifunc=CompleteFunc
+ set completefunc=CompleteFunc
+ set completeopt+=menuone
+
+ new
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-N>\<C-Y>\<Esc>0", 'tx')
+ call assert_equal('bar', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<ESC>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim\<CR>completion test\<CR>\<C-X>\<C-l>\<C-Y>", 'tx')
+ call assert_equal('completion test', g:complete_word)
+ call assert_equal('whole_line', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-U>\<C-Y>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('function', g:complete_type)
+
+ inoremap <buffer> <f3> <cmd>call complete(1, ["red", "blue"])<cr>
+ call feedkeys("S\<f3>\<C-Y>", 'tx')
+ call assert_equal('red', g:complete_word)
+ call assert_equal('eval', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-V>\<C-Y>", 'tx')
+ call assert_equal('!', g:complete_word)
+ call assert_equal('cmdline', g:complete_type)
+
+ call writefile([''], 'foo_test', 'D')
+ call feedkeys("Sfoo\<C-X>\<C-F>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo_test', g:complete_word)
+ call assert_equal('files', g:complete_type)
+
+ call writefile(['hello help'], 'test_case.txt', 'D')
+ set dictionary=test_case.txt
+ call feedkeys("ggdGSh\<C-X>\<C-K>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('hello', g:complete_word)
+ call assert_equal('dictionary', g:complete_type)
+
+ set spell spelllang=en_us
+ call feedkeys("STheatre\<C-X>s\<C-Y>\<Esc>", 'tx')
+ call assert_equal('Theater', g:complete_word)
+ call assert_equal('spell', g:complete_type)
+
+ bwipe!
+ set completeopt& omnifunc& completefunc& spell& spelllang& dictionary&
+ autocmd! CompleteDone
+ delfunc OnDone
+ delfunc CompleteFunc
+ unlet g:complete_word
+ unlet g:complete_type
+endfunc
+
func Test_CompleteDoneDict()
au CompleteDonePre * :call <SID>CompleteDone_CheckCompletedItemDict(1)
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict(0)
diff --git a/src/version.c b/src/version.c
index 42d8e11..4cf6862 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 905,
+/**/
904,
/**/
903,