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

1c5a120a70
This commit is contained in:
glepnir 2024-12-05 17:49:39 +08:00 committed by GitHub
parent 540def7d2c
commit 2f5e7cbac4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 109 additions and 3 deletions

View File

@ -463,6 +463,10 @@ CompleteDone After Insert mode completion is done. Either
|v:completed_item| gives the completed item. |v:completed_item| gives the completed item.
Sets these |v:event| keys: 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 reason Reason for completion being
done. Can be one of: done. Can be one of:
- "accept": completion was - "accept": completion was

View File

@ -189,6 +189,8 @@ v:event
changing window (or tab) on |DirChanged|. changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose| status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone| 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* *exception-variable*
v:exception v:exception

View File

@ -197,6 +197,8 @@ vim.v.errors = ...
--- changing window (or tab) on `DirChanged`. --- changing window (or tab) on `DirChanged`.
--- status Job status or exit code, -1 means "unknown". `TermClose` --- status Job status or exit code, -1 means "unknown". `TermClose`
--- reason Reason for completion being done. `CompleteDone` --- 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 --- @type any
vim.v.event = ... vim.v.event = ...

View File

@ -561,11 +561,19 @@ static bool is_first_match(const compl_T *const match)
return match == compl_first_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; save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&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_add_str(v_event, S_LEN("reason"), (c == Ctrl_Y ? "accept" : "cancel"));
tv_dict_set_keys_readonly(v_event); 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 // If the popup menu is displayed pressing CTRL-Y means accepting
// the selection without inserting anything. When // the selection without inserting anything. When
// compl_enter_selects is set the Enter key does the same. // compl_enter_selects is set the Enter key does the same.
if ((c == Ctrl_Y || (compl_enter_selects if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL))) && (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible()) { && pum_visible()) {
word = xstrdup(compl_shown_match->cp_str);
retval = true; 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 // Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion. // upon the end of completion.
do_autocmd_completedone(c); do_autocmd_completedone(c, prev_mode, word);
xfree(word);
return retval; return retval;
} }
@ -2267,7 +2278,7 @@ bool ins_compl_prep(int c)
} else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) { } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
// Trigger the CompleteDone event to give scripts a chance to act // Trigger the CompleteDone event to give scripts a chance to act
// upon the (possibly failed) completion. // upon the (possibly failed) completion.
do_autocmd_completedone(c); do_autocmd_completedone(c, ctrl_x_mode, NULL);
} }
may_trigger_modechanged(); may_trigger_modechanged();

View File

@ -208,6 +208,8 @@ M.vars = {
changing window (or tab) on |DirChanged|. changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose| status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone| 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 = { exception = {

View File

@ -253,6 +253,91 @@ func Test_CompleteDoneNone()
au! CompleteDone au! CompleteDone
endfunc 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() func Test_CompleteDoneDict()
au CompleteDonePre * :call <SID>CompleteDone_CheckCompletedItemDict(1) au CompleteDonePre * :call <SID>CompleteDone_CheckCompletedItemDict(1)
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict(0) au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict(0)