mirror of
https://github.com/vim/vim.git
synced 2025-10-28 09:27:14 -04:00
patch 9.1.1672: completion: cannot add timeouts for 'cpt' sources
Problem: completion: cannot add timeouts for 'cpt' sources
(Evgeni Chasnovski)
Solution: Add the 'autocompletetimeout' and 'completetimeout' options
(Girish Palya)
fixes: #17908
closes: #17967
Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
f66674cf42
commit
69a337edc1
@@ -203,6 +203,9 @@ static buf_T *compl_curr_buf = NULL; // buf where completion is active
|
||||
// if the current source exceeds its timeout, it is interrupted and the next
|
||||
// begins with half the time. A small minimum timeout ensures every source
|
||||
// gets at least a brief chance.
|
||||
// Special case: when 'complete' contains "F" or "o" (function sources), a
|
||||
// longer fixed timeout is used (COMPL_FUNC_TIMEOUT_MS or
|
||||
// COMPL_FUNC_TIMEOUT_NON_KW_MS). - girish
|
||||
static int compl_autocomplete = FALSE; // whether autocompletion is active
|
||||
static int compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
|
||||
static int compl_time_slice_expired = FALSE; // time budget exceeded for current source
|
||||
@@ -216,6 +219,10 @@ static int compl_from_nonkeyword = FALSE; // completion started from non-ke
|
||||
compl_timeout_ms /= 2; \
|
||||
} while (0)
|
||||
|
||||
// Timeout values for F{func}, F and o values in 'complete'
|
||||
#define COMPL_FUNC_TIMEOUT_MS 300
|
||||
#define COMPL_FUNC_TIMEOUT_NON_KW_MS 1000
|
||||
|
||||
// List of flags for method of completion.
|
||||
static int compl_cont_status = 0;
|
||||
# define CONT_ADDING 1 // "normal" or "adding" expansion
|
||||
@@ -5393,7 +5400,7 @@ prepare_cpt_compl_funcs(void)
|
||||
compl_source_start_timer(int source_idx UNUSED)
|
||||
{
|
||||
#ifdef ELAPSED_FUNC
|
||||
if (compl_autocomplete && cpt_sources_array != NULL)
|
||||
if (compl_autocomplete || p_cto > 0)
|
||||
{
|
||||
ELAPSED_INIT(cpt_sources_array[source_idx].compl_start_tv);
|
||||
compl_time_slice_expired = FALSE;
|
||||
@@ -5418,8 +5425,6 @@ advance_cpt_sources_index_safe(void)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
#define COMPL_FUNC_TIMEOUT_MS 300
|
||||
#define COMPL_FUNC_TIMEOUT_NON_KW_MS 1000
|
||||
/*
|
||||
* Get the next expansion(s), using "compl_pattern".
|
||||
* The search starts at position "ini" in curbuf and in the direction
|
||||
@@ -5439,6 +5444,8 @@ ins_compl_get_exp(pos_T *ini)
|
||||
int type = ctrl_x_mode;
|
||||
int may_advance_cpt_idx = FALSE;
|
||||
pos_T start_pos = *ini;
|
||||
int normal_mode_strict = FALSE;
|
||||
long compl_timeout_save = 0;
|
||||
|
||||
if (!compl_started)
|
||||
{
|
||||
@@ -5476,15 +5483,18 @@ ins_compl_get_exp(pos_T *ini)
|
||||
st.cur_match_pos = (compl_dir_forward())
|
||||
? &st.last_match_pos : &st.first_match_pos;
|
||||
|
||||
if (cpt_sources_array != NULL && ctrl_x_mode_normal()
|
||||
&& !ctrl_x_mode_line_or_eval()
|
||||
&& !(compl_cont_status & CONT_LOCAL))
|
||||
normal_mode_strict = ctrl_x_mode_normal() && !ctrl_x_mode_line_or_eval()
|
||||
&& !(compl_cont_status & CONT_LOCAL) && cpt_sources_array != NULL;
|
||||
if (normal_mode_strict)
|
||||
{
|
||||
cpt_sources_index = 0;
|
||||
if (compl_autocomplete)
|
||||
if (compl_autocomplete || p_cto > 0)
|
||||
{
|
||||
compl_source_start_timer(0);
|
||||
compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
|
||||
compl_time_slice_expired = FALSE;
|
||||
compl_timeout_ms = compl_autocomplete
|
||||
? MAX(COMPL_INITIAL_TIMEOUT_MS, p_act)
|
||||
: p_cto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5517,14 +5527,18 @@ ins_compl_get_exp(pos_T *ini)
|
||||
}
|
||||
}
|
||||
|
||||
if (compl_autocomplete && type == CTRL_X_FUNCTION)
|
||||
if (normal_mode_strict && type == CTRL_X_FUNCTION
|
||||
&& (compl_autocomplete || p_cto > 0))
|
||||
{
|
||||
// LSP servers may sporadically take >1s to respond (e.g., while
|
||||
// loading modules), but other sources might already have matches.
|
||||
// To show results quickly use a short timeout for keyword
|
||||
// completion. Allow longer timeout for non-keyword completion
|
||||
// where only function based sources (e.g. LSP) are active.
|
||||
compl_timeout_save = compl_timeout_ms;
|
||||
compl_timeout_ms = compl_from_nonkeyword
|
||||
? COMPL_FUNC_TIMEOUT_NON_KW_MS : COMPL_FUNC_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
// get the next set of completion matches
|
||||
found_new_match = get_next_completion_match(type, &st, &start_pos);
|
||||
@@ -5567,9 +5581,10 @@ ins_compl_get_exp(pos_T *ini)
|
||||
compl_started = FALSE;
|
||||
}
|
||||
|
||||
// Reset the timeout after collecting matches from function source
|
||||
if (compl_autocomplete && type == CTRL_X_FUNCTION)
|
||||
compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
|
||||
// Restore the timeout after collecting matches from function source
|
||||
if (normal_mode_strict && type == CTRL_X_FUNCTION
|
||||
&& (compl_autocomplete || p_cto > 0))
|
||||
compl_timeout_ms = compl_timeout_save;
|
||||
|
||||
// For `^P` completion, reset `compl_curr_match` to the head to avoid
|
||||
// mixing matches from different sources.
|
||||
@@ -6136,9 +6151,6 @@ ins_compl_next(
|
||||
check_elapsed_time(void)
|
||||
{
|
||||
#ifdef ELAPSED_FUNC
|
||||
if (cpt_sources_array == NULL || cpt_sources_index < 0)
|
||||
return;
|
||||
|
||||
elapsed_T *start_tv
|
||||
= &cpt_sources_array[cpt_sources_index].compl_start_tv;
|
||||
long elapsed_ms = ELAPSED_FUNC(*start_tv);
|
||||
@@ -6211,8 +6223,14 @@ ins_compl_check_keys(int frequency, int in_compl_func)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (compl_autocomplete)
|
||||
check_elapsed_time();
|
||||
else
|
||||
{
|
||||
int normal_mode_strict = ctrl_x_mode_normal()
|
||||
&& !ctrl_x_mode_line_or_eval() && !(compl_cont_status & CONT_LOCAL)
|
||||
&& cpt_sources_array != NULL && cpt_sources_index >= 0;
|
||||
if (normal_mode_strict && (compl_autocomplete || p_cto > 0))
|
||||
check_elapsed_time();
|
||||
}
|
||||
|
||||
if (compl_pending != 0 && !got_int && !(cot_flags & COT_NOINSERT)
|
||||
&& !compl_autocomplete)
|
||||
|
||||
@@ -513,6 +513,7 @@ EXTERN long p_ch; // 'cmdheight'
|
||||
EXTERN char_u *p_cms; // 'commentstring'
|
||||
#endif
|
||||
EXTERN char_u *p_cpt; // 'complete'
|
||||
EXTERN long p_cto; // 'completetimeout'
|
||||
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
|
||||
EXTERN int p_confirm; // 'confirm'
|
||||
#endif
|
||||
@@ -524,6 +525,7 @@ EXTERN unsigned cia_flags; // order flags of 'completeitemalign'
|
||||
EXTERN char_u *p_cot; // 'completeopt'
|
||||
EXTERN unsigned cot_flags; // flags from 'completeopt'
|
||||
EXTERN int p_ac; // 'autocomplete'
|
||||
EXTERN long p_act; // 'autocompletetimeout'
|
||||
EXTERN long p_acl; // 'autocompletedelay'
|
||||
// Keep in sync with p_cot_values in optionstr.c
|
||||
#define COT_MENU 0x001
|
||||
|
||||
@@ -395,6 +395,9 @@ static struct vimoption options[] =
|
||||
{"autocompletedelay", "acl", P_NUM|P_VI_DEF,
|
||||
(char_u *)&p_acl, PV_NONE, NULL, NULL,
|
||||
{(char_u *)0L, (char_u *)0L} SCTX_INIT},
|
||||
{"autocompletetimeout", "act", P_NUM|P_VI_DEF,
|
||||
(char_u *)&p_act, PV_NONE, NULL, NULL,
|
||||
{(char_u *)80L, (char_u *)0L} SCTX_INIT},
|
||||
#endif
|
||||
{"autoindent", "ai", P_BOOL|P_VI_DEF,
|
||||
(char_u *)&p_ai, PV_AI, NULL, NULL,
|
||||
@@ -723,6 +726,9 @@ static struct vimoption options[] =
|
||||
{(char_u *)0L, (char_u *)0L}
|
||||
#endif
|
||||
SCTX_INIT},
|
||||
{"completetimeout", "cto", P_NUM|P_VI_DEF,
|
||||
(char_u *)&p_cto, PV_NONE, NULL, NULL,
|
||||
{(char_u *)0L, (char_u *)0L} SCTX_INIT},
|
||||
{"concealcursor","cocu", P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF|P_FLAGLIST,
|
||||
#ifdef FEAT_CONCEAL
|
||||
(char_u *)VAR_WIN, PV_COCU, did_set_concealcursor, expand_set_concealcursor,
|
||||
|
||||
8
src/po/vim.pot
generated
8
src/po/vim.pot
generated
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Vim\n"
|
||||
"Report-Msgid-Bugs-To: vim-dev@vim.org\n"
|
||||
"POT-Creation-Date: 2025-08-18 21:30+0200\n"
|
||||
"POT-Creation-Date: 2025-08-23 16:16+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -9952,6 +9952,12 @@ msgstr ""
|
||||
msgid "automatic completion in insert mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "initial decay timeout for 'autocomplete' algorithm"
|
||||
msgstr ""
|
||||
|
||||
msgid "initial decay timeout for CTRL-N and CTRL-P completion"
|
||||
msgstr ""
|
||||
|
||||
msgid "delay in msec before menu appears after typing"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -22,8 +22,10 @@ int diffopt_horizontal(void);
|
||||
int diffopt_hiddenoff(void);
|
||||
int diffopt_closeoff(void);
|
||||
void diff_update_line(linenr_T lnum);
|
||||
#ifdef FEAT_DIFF
|
||||
int diff_change_parse(diffline_T *diffline, diffline_change_T *change, int *change_start, int *change_end);
|
||||
int diff_find_change(win_T *wp, linenr_T lnum, diffline_T *diffline);
|
||||
#endif
|
||||
int diff_infold(win_T *wp, linenr_T lnum);
|
||||
void nv_diffgetput(int put, long count);
|
||||
void ex_diffgetput(exarg_T *eap);
|
||||
|
||||
@@ -5460,6 +5460,68 @@ func Test_omni_start_invalid_col()
|
||||
set omnifunc& complete&
|
||||
endfunc
|
||||
|
||||
func Test_completetimeout_autocompletetimeout()
|
||||
func OmniFunc(findstart, base)
|
||||
if a:findstart
|
||||
return 1
|
||||
else
|
||||
return ['fooOmni']
|
||||
endif
|
||||
endfunc
|
||||
|
||||
set omnifunc=OmniFunc
|
||||
call test_override("char_avail", 1)
|
||||
inoremap <F2> <Cmd>let b:matches = complete_info(["matches"]).matches<CR>
|
||||
|
||||
call setline(1, ['foobar', 'foobarbaz'])
|
||||
new
|
||||
call setline(1, ['foo', 'foobaz', ''])
|
||||
set complete=.,o,w
|
||||
call feedkeys("G", 'xt!')
|
||||
|
||||
set autocomplete
|
||||
for tt in [1, 80, 1000, -1, 0]
|
||||
exec $'set autocompletetimeout={tt}'
|
||||
call feedkeys("\<Esc>Sf\<F2>\<Esc>0", 'xt!')
|
||||
call assert_equal(['foobaz', 'foo', 'fooOmni', 'foobar', 'foobarbaz'], b:matches->mapnew('v:val.word'))
|
||||
endfor
|
||||
set autocomplete&
|
||||
|
||||
for tt in [80, 1000, -1, 0]
|
||||
exec $'set completetimeout={tt}'
|
||||
call feedkeys("\<Esc>Sf\<C-N>\<F2>\<Esc>0", 'xt!')
|
||||
call assert_equal(['foo', 'foobaz', 'fooOmni', 'foobar', 'foobarbaz'], b:matches->mapnew('v:val.word'))
|
||||
endfor
|
||||
|
||||
" Clock does not have fine granularity, so checking 'elapsed time' is only
|
||||
" approximate. We can only test that some type of timeout is enforced.
|
||||
call feedkeys("\<Esc>", 'xt!')
|
||||
call setline(1, map(range(60000), '"foo" . v:val'))
|
||||
set completetimeout=1
|
||||
call feedkeys("Gof\<C-N>\<F2>\<Esc>0", 'xt!')
|
||||
let match_count = len(b:matches->mapnew('v:val.word'))
|
||||
call assert_true(match_count < 2000)
|
||||
|
||||
set completetimeout=1000
|
||||
call feedkeys("\<Esc>Sf\<C-N>\<F2>\<Esc>0", 'xt!')
|
||||
let match_count = len(b:matches->mapnew('v:val.word'))
|
||||
call assert_true(match_count > 2000)
|
||||
|
||||
set autocomplete
|
||||
set autocompletetimeout=81
|
||||
call feedkeys("\<Esc>Sf\<F2>\<Esc>0", 'xt!')
|
||||
let match_count = len(b:matches->mapnew('v:val.word'))
|
||||
call assert_true(match_count < 50000)
|
||||
|
||||
call feedkeys("\<Esc>", 'xt!')
|
||||
set complete& omnifunc& autocomplete& autocompletetimeout& completetimeout&
|
||||
bwipe!
|
||||
%d
|
||||
call test_override("char_avail", 0)
|
||||
iunmap <F2>
|
||||
delfunc OmniFunc
|
||||
endfunc
|
||||
|
||||
func Test_autocompletedelay()
|
||||
CheckScreendump
|
||||
|
||||
|
||||
@@ -724,6 +724,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1672,
|
||||
/**/
|
||||
1671,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user