aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorglepnir <glephunter@gmail.com>2024-12-05 17:49:39 +0800
committerGitHub <noreply@github.com>2024-12-05 17:49:39 +0800
commit2f5e7cbac49ed2fde571c5bf85619afec624f8e8 (patch)
tree83a34f6938347bca119ec569e8d5602abd2a7711
parent540def7d2c1aa97d18b08bd7dc234442a7ab4757 (diff)
downloadrneovim-2f5e7cbac49ed2fde571c5bf85619afec624f8e8.tar.gz
rneovim-2f5e7cbac49ed2fde571c5bf85619afec624f8e8.tar.bz2
rneovim-2f5e7cbac49ed2fde571c5bf85619afec624f8e8.zip
vim-patch:9.1.0905: Missing information in CompleteDone event (#31455)
Problem: Missing information in CompleteDone event Solution: add complete_word and complete_type to v:event dict (glepnir) closes: vim/vim#16153 https://github.com/vim/vim/commit/1c5a120a701fcf558617c4e70b5a447778f0e51d
-rw-r--r--runtime/doc/autocmd.txt4
-rw-r--r--runtime/doc/vvars.txt2
-rw-r--r--runtime/lua/vim/_meta/vvars.lua2
-rw-r--r--src/nvim/insexpand.c17
-rw-r--r--src/nvim/vvars.lua2
-rw-r--r--test/old/testdir/test_ins_complete.vim85
6 files changed, 109 insertions, 3 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 998ef5e9f3..c094281154 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -463,6 +463,10 @@ CompleteDone After Insert mode completion is done. Either
|v:completed_item| gives the completed item.
Sets these |v:event| keys:
+ complete_word The word that was
+ selected, empty if
+ abandoned complete.
+ complete_type |complete_info_mode|
reason Reason for completion being
done. Can be one of:
- "accept": completion was
diff --git a/runtime/doc/vvars.txt b/runtime/doc/vvars.txt
index 0c349c4e57..32f3b96269 100644
--- a/runtime/doc/vvars.txt
+++ b/runtime/doc/vvars.txt
@@ -189,6 +189,8 @@ v:event
changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone|
+ complete_word The word that was selected, empty if abandoned complete.
+ complete_type See |complete_info_mode|
*v:exception* *exception-variable*
v:exception
diff --git a/runtime/lua/vim/_meta/vvars.lua b/runtime/lua/vim/_meta/vvars.lua
index 8784fdbac9..264907109f 100644
--- a/runtime/lua/vim/_meta/vvars.lua
+++ b/runtime/lua/vim/_meta/vvars.lua
@@ -197,6 +197,8 @@ vim.v.errors = ...
--- changing window (or tab) on `DirChanged`.
--- status Job status or exit code, -1 means "unknown". `TermClose`
--- reason Reason for completion being done. `CompleteDone`
+--- complete_word The word that was selected, empty if abandoned complete.
+--- complete_type See `complete_info_mode`
--- @type any
vim.v.event = ...
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index a1cebb407e..93d081153c 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -561,11 +561,19 @@ static bool is_first_match(const compl_T *const match)
return match == compl_first_match;
}
-static void do_autocmd_completedone(int c)
+static void do_autocmd_completedone(int c, int mode, char *word)
{
save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&save_v_event);
+ mode = mode & ~CTRL_X_WANT_IDENT;
+ char *mode_str = NULL;
+ if (ctrl_x_mode_names[mode]) {
+ mode_str = ctrl_x_mode_names[mode];
+ }
+ tv_dict_add_str(v_event, S_LEN("complete_word"), word != NULL ? word : "");
+ tv_dict_add_str(v_event, S_LEN("complete_type"), mode_str != NULL ? mode_str : "");
+
tv_dict_add_str(v_event, S_LEN("reason"), (c == Ctrl_Y ? "accept" : "cancel"));
tv_dict_set_keys_readonly(v_event);
@@ -2115,12 +2123,14 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
}
+ char *word = NULL;
// If the popup menu is displayed pressing CTRL-Y means accepting
// the selection without inserting anything. When
// compl_enter_selects is set the Enter key does the same.
if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible()) {
+ word = xstrdup(compl_shown_match->cp_str);
retval = true;
}
@@ -2178,7 +2188,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, prev_mode, word);
+ xfree(word);
return retval;
}
@@ -2267,7 +2278,7 @@ bool ins_compl_prep(int c)
} 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.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, ctrl_x_mode, NULL);
}
may_trigger_modechanged();
diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua
index 5fc014a50c..f1b8c22bdd 100644
--- a/src/nvim/vvars.lua
+++ b/src/nvim/vvars.lua
@@ -208,6 +208,8 @@ M.vars = {
changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone|
+ complete_word The word that was selected, empty if abandoned complete.
+ complete_type See |complete_info_mode|
]=],
},
exception = {
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index 6cc894c28c..bf7477f088 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -253,6 +253,91 @@ func Test_CompleteDoneNone()
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)