mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	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:
		@@ -466,6 +466,16 @@ CompleteDone			After Insert mode completion is done.  Either
 | 
			
		||||
				CompleteDonePre if you need it.
 | 
			
		||||
				|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			When the user doesn't press a key for the time
 | 
			
		||||
				specified with 'updatetime'.  Not triggered
 | 
			
		||||
 
 | 
			
		||||
@@ -130,6 +130,9 @@ UI
 | 
			
		||||
• TODO
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason
 | 
			
		||||
  for completion being done.
 | 
			
		||||
 | 
			
		||||
==============================================================================
 | 
			
		||||
CHANGED FEATURES                                                 *news-changed*
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -187,6 +187,7 @@ v:event
 | 
			
		||||
		  changed_window   Is |v:true| if the event fired while
 | 
			
		||||
		                   changing window  (or tab) on |DirChanged|.
 | 
			
		||||
		  status           Job status or exit code, -1 means "unknown". |TermClose|
 | 
			
		||||
		  reason           Reason for completion being done. |CompleteDone|
 | 
			
		||||
 | 
			
		||||
				*v:exception* *exception-variable*
 | 
			
		||||
v:exception
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								runtime/lua/vim/_meta/vvars.lua
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								runtime/lua/vim/_meta/vvars.lua
									
									
									
										generated
									
									
									
								
							@@ -195,6 +195,7 @@ vim.v.errors = ...
 | 
			
		||||
---   changed_window   Is `v:true` if the event fired while
 | 
			
		||||
---                    changing window  (or tab) on `DirChanged`.
 | 
			
		||||
---   status           Job status or exit code, -1 means "unknown". `TermClose`
 | 
			
		||||
---   reason           Reason for completion being done. `CompleteDone`
 | 
			
		||||
--- @type any
 | 
			
		||||
vim.v.event = ...
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -568,6 +568,18 @@ static bool is_first_match(const compl_T *const 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
 | 
			
		||||
/// completed.  Used to decide whether to abandon complete mode when the menu
 | 
			
		||||
/// 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
 | 
			
		||||
  // upon the end of completion.
 | 
			
		||||
  ins_apply_autocmds(EVENT_COMPLETEDONE);
 | 
			
		||||
  do_autocmd_completedone(c);
 | 
			
		||||
 | 
			
		||||
  return retval;
 | 
			
		||||
}
 | 
			
		||||
@@ -2199,7 +2211,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.
 | 
			
		||||
    ins_apply_autocmds(EVENT_COMPLETEDONE);
 | 
			
		||||
    do_autocmd_completedone(c);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  may_trigger_modechanged();
 | 
			
		||||
 
 | 
			
		||||
@@ -215,6 +215,7 @@ M.vars = {
 | 
			
		||||
        changed_window   Is |v:true| if the event fired while
 | 
			
		||||
                         changing window  (or tab) on |DirChanged|.
 | 
			
		||||
        status           Job status or exit code, -1 means "unknown". |TermClose|
 | 
			
		||||
        reason           Reason for completion being done. |CompleteDone|
 | 
			
		||||
    ]=],
 | 
			
		||||
  },
 | 
			
		||||
  exception = {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								test/functional/autocmd/completedone_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								test/functional/autocmd/completedone_spec.lua
									
									
									
									
									
										Normal 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)
 | 
			
		||||
		Reference in New Issue
	
	Block a user