static int dont_sync_undo = FALSE; // CTRL-G U prevents syncing undo for
// the next left/right cursor key
+// With 'autocompletedelay' set, arm the delay and let the main loop fire
+// Insert-mode autocommands; the popup is shown later on K_COMPLETE_DELAY.
+// Otherwise trigger completion right away.
#define TRIGGER_AUTOCOMPLETE() \
do { \
update_screen(UPD_VALID); /* Show char (deletion) immediately */ \
out_flush(); \
ins_compl_enable_autocomplete(); \
- goto docomplete; \
+ if (!ins_compl_arm_autocomplete_delay())\
+ goto docomplete; \
} while (0)
#define MAY_TRIGGER_AUTOCOMPLETE(c) \
/*
* Get a character for Insert mode. Ignore K_IGNORE and K_NOP.
*/
- if (c != K_CURSORHOLD)
+ if (c != K_CURSORHOLD && c != K_COMPLETE_DELAY)
lastc = c; // remember the previous char for CTRL-D
// After using CTRL-G U the next cursor key will not break undo.
if (p_hkmap)
c = hkmap(c); // Hebrew mode mapping
#endif
- goto docomplete;
+ // Defer until the delay expires (K_COMPLETE_DELAY), or
+ // trigger now when no delay is in effect.
+ if (!ins_compl_arm_autocomplete_delay())
+ goto docomplete;
}
}
}
dont_sync_undo = MAYBE;
break;
+ case K_COMPLETE_DELAY: // 'autocompletedelay' expired
+ ins_compl_clear_autocomplete_delay();
+ if (!ins_compl_has_autocomplete() || char_avail()
+ || curwin->w_cursor.col == 0)
+ break;
+ c = char_before_cursor();
+ if (!vim_isprintc(c))
+ break;
+ // The completion may have been cleared while waiting, so re-enable
+ // autocomplete to match a zero delay.
+ ins_compl_enable_autocomplete();
+ goto docomplete;
+
#ifdef FEAT_GUI_MSWIN
// On MS-Windows ignore <M-F4>, we get it when closing the window
// was cancelled.
goto normalchar;
docomplete:
+ ins_compl_clear_autocomplete_delay();
compl_busy = TRUE;
#ifdef FEAT_FOLDING
disable_fold_update++; // don't redraw folds here
else
#endif
if (p[0] == NUL || (p[0] == K_SPECIAL
- // timeout may generate K_CURSORHOLD
- && (i < 2 || p[1] != KS_EXTRA || p[2] != (int)KE_CURSORHOLD)
+ // timeout may generate K_CURSORHOLD,
+ // 'autocompletedelay' timeout K_COMPLETE_DELAY
+ && (i < 2 || p[1] != KS_EXTRA
+ || (p[2] != (int)KE_CURSORHOLD
+ && p[2] != (int)KE_COMPLETE_DELAY))
#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
// Win32 console passes modifiers
&& (
// 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 bool compl_autocomplete_pending = false;
static int compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
static int compl_time_slice_expired = FALSE; // time budget exceeded for current source
static int compl_from_nonkeyword = FALSE; // completion started from non-keyword
compl_enter_selects = !compl_used_match && compl_selected_item != -1;
- // Show the popup menu with a different set of matches.
+ // Show the popup menu with a different set of matches. With
+ // 'autocompletedelay' the menu is already visible here, so update it
+ // immediately rather than re-arming the delay, like a zero delay does.
if (!compl_interrupted)
show_pum(save_w_wrow, save_w_leftcol);
int save_w_leftcol;
int insert_match;
int no_matches_found;
-#ifdef ELAPSED_FUNC
- elapsed_T compl_start_tv = {0}; // Time when match collection starts
- int disable_ac_delay;
-
- disable_ac_delay = compl_started && ctrl_x_mode_normal()
- && (c == Ctrl_N || c == Ctrl_P || c == Ctrl_R || ins_compl_pum_key(c));
-#endif
compl_direction = ins_compl_key2dir(c);
insert_match = ins_compl_use_match(c);
else if (insert_match && stop_arrow() == FAIL)
return FAIL;
-#ifdef ELAPSED_FUNC
- if (compl_autocomplete && p_acl > 0 && !disable_ac_delay)
- ELAPSED_INIT(compl_start_tv);
-#endif
compl_curr_win = curwin;
compl_curr_buf = curwin->w_buffer;
compl_shown_match = compl_curr_match;
if (!shortmess(SHM_COMPLETIONMENU) && !compl_autocomplete)
ins_compl_show_statusmsg();
- // Wait for the autocompletion delay to expire
-#ifdef ELAPSED_FUNC
- if (compl_autocomplete && p_acl > 0 && !disable_ac_delay
- && !no_matches_found && ELAPSED_FUNC(compl_start_tv) < p_acl)
- {
- cursor_on();
- setcursor();
- out_flush_cursor(FALSE, FALSE);
- do
- {
- if (char_avail())
- {
- if (ins_compl_preinsert_effect()
- && ins_compl_win_active(curwin))
- {
- ins_compl_delete(); // Remove pre-inserted text
- compl_ins_end_col = compl_col;
- }
- ins_compl_restart();
- compl_interrupted = TRUE;
- break;
- }
- else
- ui_delay(2L, TRUE);
- } while (ELAPSED_FUNC(compl_start_tv) < p_acl);
- }
-#endif
-
// Show the popup menu, unless we got interrupted.
if (enable_pum && !compl_interrupted)
show_pum(save_w_wrow, save_w_leftcol);
#endif
}
+/*
+ * Arm the 'autocompletedelay' timer when the delay is in effect.
+ * Return true when the popup should be deferred, false to trigger it now.
+ */
+ bool
+ins_compl_arm_autocomplete_delay(void)
+{
+#ifdef ELAPSED_FUNC
+ if (p_acl > 0)
+ {
+ compl_autocomplete_pending = true;
+ return true;
+ }
+#endif
+ return false;
+}
+
+/*
+ * Clear the pending 'autocompletedelay' state.
+ */
+ void
+ins_compl_clear_autocomplete_delay(void)
+{
+ compl_autocomplete_pending = false;
+}
+
+/*
+ * Return true while waiting for 'autocompletedelay' to expire.
+ */
+ bool
+ins_compl_autocomplete_pending(void)
+{
+ return compl_autocomplete_pending;
+}
+
/*
* Remove (if needed) and show the popup menu
*/
, KE_ESC = 107 // used for K_ESC
, KE_WILD = 108 // triggers wildmode completion
, KE_OSC = 109 // finished OSC sequence
+ , KE_COMPLETE_DELAY = 110 // 'autocompletedelay' expired
};
/*
#define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
#define K_CURSORHOLD TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
+#define K_COMPLETE_DELAY TERMCAP2KEY(KS_EXTRA, KE_COMPLETE_DELAY)
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
#define K_SCRIPT_COMMAND TERMCAP2KEY(KS_EXTRA, KE_SCRIPT_COMMAND)
void ins_compl_check_keys(int frequency, int in_compl_func);
int ins_complete(int c, int enable_pum);
void ins_compl_enable_autocomplete(void);
+bool ins_compl_arm_autocomplete_delay(void);
+void ins_compl_clear_autocomplete_delay(void);
+bool ins_compl_autocomplete_pending(void);
void free_insexpand_stuff(void);
void f_preinserted(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
|~| @73
|~| @73
|~| @73
-|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|4|,|1| @10|A|l@1|
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|4|,|2| @10|A|l@1|
|~| @73
|~| @73
|~| @73
-|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|4|,|1| @10|A|l@1|
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|4|,|3| @10|A|l@1|
|f|o@1|b|a|r| @68
|f|o@1|b|a|r|b|a|z| @65
|f> @73
-|~+0#4040ff13&| @73
-|~| @73
-|~| @73
+|f+0#0000001#ffd7ff255|o@1|b|a|r|b|a|z| @5| +0#4040ff13#ffffff0@59
+|f+0#0000001#ffd7ff255|o@1|b|a|r| @8| +0#4040ff13#ffffff0@59
+|f+0#0000001#ffd7ff255|o@1| @11| +0#4040ff13#ffffff0@59
|~| @73
|~| @73
|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|4|,|2| @10|A|l@1|
|a+0&#ffffff0|u|t|o|c|o|m|p|l|e|t|e| @62
|a|u|t|o|c|o|m|x@2| @64
-|a|u|t|o|c>o+0#00e0003&|m| +0#0000000&@67
+|a|u|t|o|c> @69
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
-|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|3|,|1| @10|T|o|p|
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|3|,|6| @10|A|l@1|
|a+0&#ffffff0|u|t|o|c|o|m|p|l|e|t|e| @62
|a|u|t|o|c|o|m|x@2| @64
-|a|u>t+0#00e0003&|o|c|o|m| +0#0000000&@67
+|a|u> @72
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
-|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|3|,|1| @10|A|l@1|
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|3|,|3| @10|A|l@1|
|a+0&#ffffff0|u|t|o|c|o|m|p|l|e|t|e| @62
|a|u|t|o|c|o|m|x@2| @64
-|a|u>t+0#00e0003&|o|c|o|m|p|l|e|t|e| +0#0000000&@62
+|a|u> @72
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
-|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|3|,|1| @10|A|l@1|
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|3|,|3| @10|A|l@1|
call term_sendkeys(buf, "Sf\<C-N>")
call VerifyScreenDump(buf, 'Test_autocompletedelay_7', {})
- " After the menu is open, ^N/^P and Up/Down should not delay
+ " After the menu is open, ^N/^P and Up/Down should not delay.
+ " Wait a bit longer than 'autocompletedelay' so the popup is surely shown
+ " before sending CTRL-N, otherwise the keys race with the deferred popup.
call term_sendkeys(buf, "\<Esc>:set completeopt=menu noruler\<CR>")
call term_sendkeys(buf, "\<Esc>Sf")
- sleep 500ms
+ sleep 600ms
call term_sendkeys(buf, "\<C-N>")
call VerifyScreenDump(buf, 'Test_autocompletedelay_8', {})
call term_sendkeys(buf, "\<Down>")
return 0;
}
# endif
- if (wtime < 0 && did_start_blocking)
+ // When an autocomplete is pending, wake at the sooner of
+ // 'autocompletedelay' and 'updatetime' so the delay does not postpone
+ // CursorHold. Once CursorHold has fired, only the delay is left.
+ bool delay_pending = ins_compl_autocomplete_pending() && p_acl > 0;
+
+ if (wtime < 0 && did_start_blocking && !delay_pending)
// blocking and already waited for p_ut
wait_time = -1;
else
{
if (wtime >= 0)
wait_time = wtime;
+ else if (delay_pending)
+ wait_time = did_start_blocking ? p_acl : MIN(p_acl, p_ut);
else
// going to block after p_ut
wait_time = p_ut;
// no character available within "wtime"
return 0;
+ // The 'autocompletedelay' expired: trigger the popup. When
+ // 'updatetime' is shorter, fall through to CursorHold instead.
+ if (delay_pending && elapsed_time >= p_acl && maxlen >= 3
+ && !typebuf_changed(tb_change_cnt))
+ {
+ if (buf == NULL)
+ {
+ char_u ibuf[3];
+
+ ibuf[0] = CSI;
+ ibuf[1] = KS_EXTRA;
+ ibuf[2] = (int)KE_COMPLETE_DELAY;
+ add_to_input_buf(ibuf, 3);
+ }
+ else
+ {
+ buf[0] = K_SPECIAL;
+ buf[1] = KS_EXTRA;
+ buf[2] = (int)KE_COMPLETE_DELAY;
+ }
+ return 3;
+ }
+
// No character available within 'updatetime'.
did_start_blocking = TRUE;
if (trigger_cursorhold() && maxlen >= 3
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 739,
/**/
738,
/**/