feat(complete): specify reason for CompleteDone

Problem: `CompleteDone` currently does not specify the reason for why completion was done, which is problematic for completion plugins as they cannot know whether the event was triggered due to the completion being canceled, accepted, or for some other reason.

Solution: Add a `reason` key to `v:event`, which is set by `CompleteDone` to indicate why completion ended.
This commit is contained in:
Famiu Haque 2024-05-24 15:57:46 +06:00 committed by GitHub
parent d123202ae6
commit a616272f56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 71 additions and 2 deletions

View File

@ -466,6 +466,16 @@ CompleteDone After Insert mode completion is done. Either
CompleteDonePre if you need it. CompleteDonePre if you need it.
|v:completed_item| gives the completed item. |v:completed_item| gives the completed item.
Sets these |v:event| keys:
reason Reason for completion being
done. Can be one of:
- "accept": completion was
accepted using |complete_CTRL-Y|.
- "cancel": completion was cancelled
using |complete_CTRL-E|, pressing
a non-keyword character, or
triggering a new completion.
*CursorHold* *CursorHold*
CursorHold When the user doesn't press a key for the time CursorHold When the user doesn't press a key for the time
specified with 'updatetime'. Not triggered specified with 'updatetime'. Not triggered

View File

@ -130,6 +130,9 @@ UI
• TODO • TODO
• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason
for completion being done.
============================================================================== ==============================================================================
CHANGED FEATURES *news-changed* CHANGED FEATURES *news-changed*

View File

@ -187,6 +187,7 @@ v:event
changed_window Is |v:true| if the event fired while changed_window Is |v:true| if the event fired while
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|
*v:exception* *exception-variable* *v:exception* *exception-variable*
v:exception v:exception

View File

@ -195,6 +195,7 @@ vim.v.errors = ...
--- changed_window Is `v:true` if the event fired while --- changed_window Is `v:true` if the event fired while
--- 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`
--- @type any --- @type any
vim.v.event = ... vim.v.event = ...

View File

@ -568,6 +568,18 @@ 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)
{
save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&save_v_event);
tv_dict_add_str(v_event, S_LEN("reason"), (c == Ctrl_Y ? "accept" : "cancel"));
tv_dict_set_keys_readonly(v_event);
ins_apply_autocmds(EVENT_COMPLETEDONE);
restore_v_event(v_event, &save_v_event);
}
/// Check that character "c" is part of the item currently being /// Check that character "c" is part of the item currently being
/// completed. Used to decide whether to abandon complete mode when the menu /// completed. Used to decide whether to abandon complete mode when the menu
/// is visible. /// is visible.
@ -2110,7 +2122,7 @@ 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.
ins_apply_autocmds(EVENT_COMPLETEDONE); do_autocmd_completedone(c);
return retval; return retval;
} }
@ -2199,7 +2211,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.
ins_apply_autocmds(EVENT_COMPLETEDONE); do_autocmd_completedone(c);
} }
may_trigger_modechanged(); may_trigger_modechanged();

View File

@ -215,6 +215,7 @@ M.vars = {
changed_window Is |v:true| if the event fired while changed_window Is |v:true| if the event fired while
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|
]=], ]=],
}, },
exception = { exception = {

View File

@ -0,0 +1,41 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local clear = n.clear
local command = n.command
local call = n.call
local feed = n.feed
local eval = n.eval
local eq = t.eq
describe('CompleteDone', function()
before_each(clear)
describe('sets v:event.reason', function()
before_each(function()
clear()
command('autocmd CompleteDone * let g:donereason = v:event.reason')
feed('i')
call('complete', call('col', '.'), { 'foo', 'bar' })
end)
it('accept', function()
feed('<C-y>')
eq('accept', eval('g:donereason'))
end)
describe('cancel', function()
it('on <C-e>', function()
feed('<C-e>')
eq('cancel', eval('g:donereason'))
end)
it('on non-keyword character', function()
feed('<Esc>')
eq('cancel', eval('g:donereason'))
end)
it('when overriden by another complete()', function()
call('complete', call('col', '.'), { 'bar', 'baz' })
eq('cancel', eval('g:donereason'))
end)
end)
end)
end)