From: glepnir Date: Wed, 4 Dec 2024 19:27:34 +0000 (+0100) Subject: patch 9.1.0905: Missing information in CompleteDone event X-Git-Tag: v9.1.0905^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1c5a120a701fcf558617c4e70b5a447778f0e51d;p=thirdparty%2Fvim.git 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 Signed-off-by: Christian Brabandt --- diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 6ca00a6e1e..8a653f2be7 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 @@ CompleteDone After Insert mode completion is done. Either 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 e73d2f1fe2..b1318cf9e1 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 @@ Insert mode completion/expansion: - 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 75403f1b3b..305511cd8c 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -2296,6 +2296,35 @@ set_ctrl_x_mode(int c) return retval; } +/* + * 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 */ @@ -2303,6 +2332,7 @@ set_ctrl_x_mode(int c) 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 @@ ins_compl_stop(int c, int prev_mode, int retval) 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 @@ ins_compl_stop(int c, int prev_mode, int retval) 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 @@ 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. - 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 7829f79fbb..ad2d421676 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -277,6 +277,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\\\", 'tx') + call assert_equal('', g:complete_word) + call assert_equal('omni', g:complete_type) + + call feedkeys("S\\\\", 'tx') + call assert_equal('foo', g:complete_word) + call assert_equal('omni', g:complete_type) + + call feedkeys("S\\\\\0", 'tx') + call assert_equal('bar', g:complete_word) + call assert_equal('omni', g:complete_type) + + call feedkeys("Shello vim visual v\\\", 'tx') + call assert_equal('', g:complete_word) + call assert_equal('keyword', g:complete_type) + + call feedkeys("Shello vim visual v\\\", 'tx') + call assert_equal('vim', g:complete_word) + call assert_equal('keyword', g:complete_type) + + call feedkeys("Shello vim visual v\\\", 'tx') + call assert_equal('vim', g:complete_word) + call assert_equal('keyword', g:complete_type) + + call feedkeys("Shello vim\completion test\\\\", 'tx') + call assert_equal('completion test', g:complete_word) + call assert_equal('whole_line', g:complete_type) + + call feedkeys("S\\\", 'tx') + call assert_equal('foo', g:complete_word) + call assert_equal('function', g:complete_type) + + inoremap call complete(1, ["red", "blue"]) + call feedkeys("S\\", 'tx') + call assert_equal('red', g:complete_word) + call assert_equal('eval', g:complete_type) + + call feedkeys("S\\\", 'tx') + call assert_equal('!', g:complete_word) + call assert_equal('cmdline', g:complete_type) + + call writefile([''], 'foo_test', 'D') + call feedkeys("Sfoo\\\\", '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\\\\", 'tx') + call assert_equal('hello', g:complete_word) + call assert_equal('dictionary', g:complete_type) + + set spell spelllang=en_us + call feedkeys("STheatre\s\\", '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 CompleteDone_CheckCompletedItemDict(1) au CompleteDone * :call CompleteDone_CheckCompletedItemDict(0) diff --git a/src/version.c b/src/version.c index 42d8e1182b..4cf68620cb 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 905, /**/ 904, /**/