vim-patch:9.1.1672: completion: cannot add timeouts for 'cpt' sources (#35447)

Problem:  completion: cannot add timeouts for 'cpt' sources
          (Evgeni Chasnovski)
Solution: Add the 'autocompletetimeout' and 'completetimeout' options
          (Girish Palya)

fixes: vim/vim#17908
closes: vim/vim#17967

69a337edc1

Co-authored-by: Girish Palya <girishji@gmail.com>
This commit is contained in:
zeertzjq
2025-08-24 13:16:55 +08:00
committed by GitHub
parent c1fa3c7c37
commit 810a234978
9 changed files with 190 additions and 23 deletions

View File

@@ -289,6 +289,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 bool compl_autocomplete = false; ///< whether autocompletion is active
static uint64_t compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
static bool compl_time_slice_expired = false; ///< time budget exceeded for current source
@@ -303,6 +306,10 @@ static bool compl_from_nonkeyword = false; ///< completion started from non-
} \
} 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
@@ -4640,7 +4647,7 @@ static void prepare_cpt_compl_funcs(void)
/// Start the timer for the current completion source.
static void compl_source_start_timer(int source_idx)
{
if (compl_autocomplete && cpt_sources_array != NULL) {
if (compl_autocomplete || p_cto > 0) {
cpt_sources_array[source_idx].compl_start_tv = os_hrtime();
compl_time_slice_expired = false;
}
@@ -4657,8 +4664,6 @@ static int 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
/// compl_direction.
@@ -4708,12 +4713,17 @@ static int ins_compl_get_exp(pos_T *ini)
compl_old_match = compl_curr_match; // remember the last current match
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)) {
bool 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
? (uint64_t)MAX(COMPL_INITIAL_TIMEOUT_MS, p_act)
: (uint64_t)p_cto;
}
}
@@ -4743,12 +4753,15 @@ static int ins_compl_get_exp(pos_T *ini)
}
}
if (compl_autocomplete && type == CTRL_X_FUNCTION) {
uint64_t compl_timeout_save = 0;
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;
}
@@ -4796,9 +4809,10 @@ static int 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
@@ -5295,10 +5309,6 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
/// collecting, and halve the timeout.
static void check_elapsed_time(void)
{
if (cpt_sources_array == NULL || cpt_sources_index < 0) {
return;
}
uint64_t start_tv = cpt_sources_array[cpt_sources_index].compl_start_tv;
uint64_t elapsed_ms = (os_hrtime() - start_tv) / 1000000;
@@ -5355,8 +5365,13 @@ void ins_compl_check_keys(int frequency, bool in_compl_func)
vungetc(c);
}
}
} else if (compl_autocomplete) {
check_elapsed_time();
} else {
bool 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 & kOptCotFlagNoinsert)

View File

@@ -292,6 +292,7 @@ EXTERN OptInt p_cwh; ///< 'cmdwinheight'
EXTERN OptInt p_ch; ///< 'cmdheight'
EXTERN char *p_cms; ///< 'commentstring'
EXTERN char *p_cpt; ///< 'complete'
EXTERN OptInt p_cto; ///< 'completetimeout'
EXTERN OptInt p_columns; ///< 'columns'
EXTERN int p_confirm; ///< 'confirm'
EXTERN char *p_cfc; ///< 'completefuzzycollect'
@@ -301,6 +302,7 @@ EXTERN unsigned cia_flags; ///< order flags of 'completeitemalign'
EXTERN char *p_cot; ///< 'completeopt'
EXTERN unsigned cot_flags; ///< flags from 'completeopt'
EXTERN int p_ac; ///< 'autocomplete'
EXTERN OptInt p_act; ///< 'autocompletetimeout'
EXTERN OptInt p_acl; ///< 'autocompletedelay'
#ifdef BACKSLASH_IN_FILENAME
EXTERN char *p_csl; ///< 'completeslash'

View File

@@ -255,6 +255,27 @@ local options = {
type = 'number',
varname = 'p_acl',
},
{
abbreviation = 'act',
defaults = 80,
desc = [=[
Initial timeout (in milliseconds) for the decaying time-sliced
completion algorithm. Starts at this value, halves for each slower
source until a minimum is reached. All sources run, but slower ones
are quickly de-prioritized. The default is tuned so the popup menu
opens within ~200ms even with multiple slow sources on a slow system.
Changing this value is rarely needed. Only 80 or higher is valid.
Special case: when 'complete' contains "F" or "o" (function sources),
a longer timeout is used, allowing up to ~1s for sources such as LSP
servers that may sometimes take longer (e.g., while loading modules).
See |ins-autocompletion|.
]=],
full_name = 'autocompletetimeout',
scope = { 'global' },
short_desc = N_('initial decay timeout for autocompletion algorithm'),
type = 'number',
varname = 'p_act',
},
{
abbreviation = 'ai',
defaults = true,
@@ -1722,6 +1743,19 @@ local options = {
type = 'string',
varname = 'p_csl',
},
{
abbreviation = 'cto',
defaults = 0,
desc = [=[
Like 'autocompletetimeout', but applies to |i_CTRL-N| and |i_CTRL-P|
completion. Value of 0 disables the timeout; positive values allowed.
]=],
full_name = 'completetimeout',
scope = { 'global' },
short_desc = N_('initial decay timeout for CTRL-N and CTRL-P'),
type = 'number',
varname = 'p_cto',
},
{
abbreviation = 'cocu',
cb = 'did_set_concealcursor',