mirror of
https://github.com/neovim/neovim.git
synced 2026-07-12 20:30:35 +00:00
Merge pull request #40525 from zeertzjq/vim-9.2.0739
vim-patch:9.2.{0739,0748,0749,0750,0755,0759}: 'autocompletedelay' fixes
This commit is contained in:
@@ -146,14 +146,19 @@ static linenr_T o_lnum = 0;
|
||||
|
||||
static kvec_t(char) replace_stack = KV_INITIAL_VALUE;
|
||||
|
||||
// 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 { \
|
||||
redraw_later(curwin, UPD_VALID); \
|
||||
update_screen(); /* Show char deletion immediately */ \
|
||||
ui_flush(); \
|
||||
ins_compl_enable_autocomplete(); \
|
||||
insert_do_complete(s); \
|
||||
break; \
|
||||
if (!ins_compl_arm_autocomplete_delay()) { \
|
||||
insert_do_complete(s); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MAY_TRIGGER_AUTOCOMPLETE(c) \
|
||||
@@ -367,6 +372,8 @@ static void insert_enter(InsertState *s)
|
||||
// and return false, causing `state_enter` to be called again.
|
||||
} while (!ins_esc(&s->count, s->cmdchar, s->nomove));
|
||||
|
||||
// Drop a pending autocomplete so it does not outlive Insert mode.
|
||||
ins_compl_clear_autocomplete_delay();
|
||||
// Always update o_lnum, so that a "CTRL-O ." that adds a line
|
||||
// still puts the cursor back after the inserted text.
|
||||
if (ins_at_eol) {
|
||||
@@ -519,8 +526,8 @@ static int insert_check(VimState *state)
|
||||
s->old_topline = curwin->w_topline;
|
||||
s->old_topfill = curwin->w_topfill;
|
||||
|
||||
if (s->c != K_EVENT) {
|
||||
s->lastc = s->c; // remember previous char for CTRL-D
|
||||
if (s->c != K_EVENT && s->c != K_COMPLETE_DELAY) {
|
||||
s->lastc = s->c; // remember the previous char for CTRL-D
|
||||
}
|
||||
|
||||
// After using CTRL-G U the next cursor key will not break undo.
|
||||
@@ -540,9 +547,13 @@ static int insert_check(VimState *state)
|
||||
if (vim_isprintc(s->c)) {
|
||||
ins_compl_enable_autocomplete();
|
||||
ins_compl_init_get_longest();
|
||||
insert_do_complete(s);
|
||||
insert_handle_key_post(s);
|
||||
return 1;
|
||||
// Defer until the delay expires (K_COMPLETE_DELAY), or
|
||||
// trigger now when no delay is in effect.
|
||||
if (!ins_compl_arm_autocomplete_delay()) {
|
||||
insert_do_complete(s);
|
||||
insert_handle_key_post(s);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,6 +584,10 @@ static int insert_execute(VimState *state, int key)
|
||||
if (key != K_EVENT) {
|
||||
did_cursorhold = true;
|
||||
}
|
||||
if (key != K_EVENT && key != K_COMPLETE_DELAY) {
|
||||
// Don't want delayed autocompletion from the previous key either.
|
||||
ins_compl_clear_autocomplete_delay();
|
||||
}
|
||||
|
||||
// Special handling of keys while the popup menu is visible or wanted
|
||||
// and the cursor is still in the completed word. Only when there is
|
||||
@@ -995,6 +1010,25 @@ static int insert_handle_key(InsertState *s)
|
||||
break;
|
||||
}
|
||||
|
||||
case K_COMPLETE_DELAY: // 'autocompletedelay' expired
|
||||
// If CTRL-G U was used apply it to the next typed key.
|
||||
if (dont_sync_undo == kTrue) {
|
||||
dont_sync_undo = kNone;
|
||||
}
|
||||
ins_compl_clear_autocomplete_delay();
|
||||
if (!ins_compl_has_autocomplete() || char_avail() || curwin->w_cursor.col == 0) {
|
||||
break;
|
||||
}
|
||||
s->c = char_before_cursor();
|
||||
if (!vim_isprintc(s->c)) {
|
||||
break;
|
||||
}
|
||||
// The completion may have been cleared while waiting, so re-enable
|
||||
// autocomplete to match a zero delay.
|
||||
ins_compl_enable_autocomplete();
|
||||
insert_do_complete(s);
|
||||
break;
|
||||
|
||||
case K_HOME: // <Home>
|
||||
case K_KHOME:
|
||||
case K_S_HOME:
|
||||
@@ -1271,6 +1305,7 @@ normalchar:
|
||||
|
||||
static void insert_do_complete(InsertState *s)
|
||||
{
|
||||
ins_compl_clear_autocomplete_delay();
|
||||
compl_busy = true;
|
||||
disable_fold_update++; // don't redraw folds here
|
||||
if (ins_complete(s->c, true) == FAIL) {
|
||||
@@ -1294,8 +1329,9 @@ static void insert_do_cindent(InsertState *s)
|
||||
|
||||
static void insert_handle_key_post(InsertState *s)
|
||||
{
|
||||
// If typed something may trigger CursorHoldI again.
|
||||
if (s->c != K_EVENT
|
||||
// If typed something may trigger CursorHoldI again; K_COMPLETE_DELAY is
|
||||
// injected, not typed.
|
||||
if (s->c != K_EVENT && s->c != K_COMPLETE_DELAY
|
||||
// but not in CTRL-X mode, a script can't restore the state
|
||||
&& ctrl_x_mode_normal()) {
|
||||
did_cursorhold = false;
|
||||
|
||||
@@ -1194,6 +1194,10 @@ static bool gotchars_add_byte(gotchars_state_T *state, uint8_t byte)
|
||||
goto ret_false;
|
||||
}
|
||||
c = TO_SPECIAL(state->prev_c, c);
|
||||
// Drop K_COMPLETE_DELAY, it's not useful in a recording.
|
||||
if (c == K_COMPLETE_DELAY) {
|
||||
state->buflen = 0;
|
||||
}
|
||||
}
|
||||
// When receiving a multibyte character, store it until we have all
|
||||
// the bytes, so that it won't be split between two buffer blocks,
|
||||
|
||||
@@ -294,6 +294,8 @@ static buf_T *compl_curr_buf = NULL; ///< buf where completion is active
|
||||
// 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 bool compl_autocomplete_pending = false;
|
||||
static uint64_t compl_autocomplete_start_tv; ///< when the delay was armed
|
||||
static uint64_t compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
|
||||
static bool compl_time_slice_expired = false; ///< time budget exceeded for current source
|
||||
static bool compl_from_nonkeyword = false; ///< completion started from non-keyword
|
||||
@@ -2336,13 +2338,6 @@ static void ins_compl_new_leader(void)
|
||||
ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
|
||||
compl_used_match = false;
|
||||
|
||||
if (p_acl > 0) {
|
||||
pum_undisplay(true);
|
||||
redraw_later(curwin, UPD_VALID);
|
||||
update_screen(); // Show char (deletion) immediately
|
||||
ui_flush();
|
||||
}
|
||||
|
||||
int save_w_wrow = curwin->w_wrow;
|
||||
int save_w_leftcol = curwin->w_leftcol;
|
||||
if (compl_started) {
|
||||
@@ -2371,7 +2366,9 @@ static void ins_compl_new_leader(void)
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -5418,7 +5415,6 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
||||
bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0
|
||||
|| (compl_autocomplete && !ins_compl_has_preinsert());
|
||||
bool compl_preinsert = ins_compl_has_preinsert();
|
||||
bool has_autocomplete_delay = (compl_autocomplete && p_acl > 0);
|
||||
|
||||
// When user complete function return -1 for findstart which is next
|
||||
// time of 'always', compl_shown_match become NULL.
|
||||
@@ -5465,9 +5461,6 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
||||
// Insert the text of the new completion, or the compl_leader.
|
||||
if (!started && ins_compl_preinsert_longest()) {
|
||||
ins_compl_insert(true, true);
|
||||
if (has_autocomplete_delay) {
|
||||
update_screen(); // Show the inserted text right away
|
||||
}
|
||||
} else if (compl_no_insert && !started && !compl_preinsert) {
|
||||
ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1);
|
||||
compl_used_match = false;
|
||||
@@ -5492,10 +5485,8 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
||||
// redraw to show the user what was inserted
|
||||
update_screen(); // TODO(bfredl): no!
|
||||
|
||||
if (!has_autocomplete_delay) {
|
||||
// display the updated popup menu
|
||||
ins_compl_show_pum();
|
||||
}
|
||||
// display the updated popup menu
|
||||
ins_compl_show_pum();
|
||||
|
||||
// Delete old text to be replaced, since we're still searching and
|
||||
// don't want to match ourselves!
|
||||
@@ -6269,10 +6260,6 @@ static void ins_compl_show_statusmsg(void)
|
||||
/// Returns OK if completion was done, FAIL if something failed.
|
||||
int ins_complete(int c, bool enable_pum)
|
||||
{
|
||||
const bool disable_ac_delay = compl_started && ctrl_x_mode_normal()
|
||||
&& (c == Ctrl_N || c == Ctrl_P || c == Ctrl_R
|
||||
|| ins_compl_pum_key(c));
|
||||
|
||||
compl_direction = ins_compl_key2dir(c);
|
||||
int insert_match = ins_compl_use_match(c);
|
||||
|
||||
@@ -6284,10 +6271,6 @@ int ins_complete(int c, bool enable_pum)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
uint64_t compl_start_tv = 0; ///< Time when match collection starts
|
||||
if (compl_autocomplete && p_acl > 0 && !disable_ac_delay) {
|
||||
compl_start_tv = os_hrtime();
|
||||
}
|
||||
compl_curr_win = curwin;
|
||||
compl_curr_buf = curwin->w_buffer;
|
||||
compl_shown_match = compl_curr_match;
|
||||
@@ -6343,26 +6326,6 @@ int ins_complete(int c, bool enable_pum)
|
||||
ins_compl_show_statusmsg();
|
||||
}
|
||||
|
||||
// Wait for the autocompletion delay to expire
|
||||
if (compl_autocomplete && p_acl > 0 && !disable_ac_delay && !no_matches_found
|
||||
&& (os_hrtime() - compl_start_tv) / 1000000 < (uint64_t)p_acl) {
|
||||
setcursor();
|
||||
ui_flush();
|
||||
do {
|
||||
if (char_avail()) {
|
||||
if (ins_compl_preinsert_effect() && ins_compl_win_active(curwin)) {
|
||||
ins_compl_delete(false); // Remove pre-inserted text
|
||||
compl_ins_end_col = compl_col;
|
||||
}
|
||||
ins_compl_restart();
|
||||
compl_interrupted = true;
|
||||
break;
|
||||
} else {
|
||||
os_delay(2L, true);
|
||||
}
|
||||
} while ((os_hrtime() - compl_start_tv) / 1000000 < (uint64_t)p_acl);
|
||||
}
|
||||
|
||||
// Show the popup menu, unless we got interrupted.
|
||||
if (enable_pum && !compl_interrupted) {
|
||||
show_pum(save_w_wrow, save_w_leftcol);
|
||||
@@ -6380,6 +6343,36 @@ void ins_compl_enable_autocomplete(void)
|
||||
compl_get_longest = false;
|
||||
}
|
||||
|
||||
/// 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)
|
||||
{
|
||||
if (p_acl > 0) {
|
||||
compl_autocomplete_start_tv = os_hrtime();
|
||||
compl_autocomplete_pending = true;
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/// Return the time in msec since the 'autocompletedelay' was armed.
|
||||
int64_t ins_compl_autocomplete_elapsed(void)
|
||||
{
|
||||
return (int64_t)((os_hrtime() - compl_autocomplete_start_tv) / 1000000);
|
||||
}
|
||||
|
||||
/// Remove (if needed) and show the popup menu
|
||||
static void show_pum(int prev_w_wrow, int prev_w_leftcol)
|
||||
{
|
||||
|
||||
@@ -224,6 +224,8 @@ enum key_extra {
|
||||
// KE_SID = 106,
|
||||
// KE_ESC = 107,
|
||||
KE_WILD = 108, // triggers wildmode completion
|
||||
// KE_OSC = 109,
|
||||
KE_COMPLETE_DELAY = 110, // 'autocompletedelay' expired
|
||||
};
|
||||
|
||||
// the three byte codes are replaced with the following int when using vgetc()
|
||||
@@ -451,6 +453,8 @@ enum key_extra {
|
||||
|
||||
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
|
||||
|
||||
#define K_COMPLETE_DELAY TERMCAP2KEY(KS_EXTRA, KE_COMPLETE_DELAY)
|
||||
|
||||
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
|
||||
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
|
||||
#define K_LUA TERMCAP2KEY(KS_EXTRA, KE_LUA)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "nvim/getchar.h"
|
||||
#include "nvim/gettext_defs.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/insexpand.h"
|
||||
#include "nvim/keycodes.h"
|
||||
#include "nvim/log.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
@@ -111,6 +112,7 @@ static void reset_cursorhold_wait(int tb_change_cnt)
|
||||
/// @return Bytes read into buf, or 0 if no input was read
|
||||
int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
|
||||
{
|
||||
assert((maxlen > 0 && buf != NULL) || maxlen == 0);
|
||||
// This check is needed so that feeding typeahead from RPC can prevent CursorHold.
|
||||
if (tb_change_cnt != cursorhold_tb_change_cnt) {
|
||||
reset_cursorhold_wait(tb_change_cnt);
|
||||
@@ -120,7 +122,6 @@ int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
|
||||
do { \
|
||||
if (maxlen && input_available()) { \
|
||||
reset_cursorhold_wait(tb_change_cnt); \
|
||||
assert(maxlen >= 0); \
|
||||
size_t to_read = MIN((size_t)maxlen, input_available()); \
|
||||
memcpy(buf, input_read_pos, to_read); \
|
||||
input_read_pos += to_read; \
|
||||
@@ -145,11 +146,45 @@ int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
|
||||
} else {
|
||||
uint64_t wait_start = os_hrtime();
|
||||
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
|
||||
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kFalse) {
|
||||
// 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.
|
||||
// Gate the injection like trigger_cursorhold() so the deferred key
|
||||
// cannot fire while outside Insert mode, but do still fire the key
|
||||
// when recording a register (gotchars_add_byte() will ignore it).
|
||||
bool delay_pending = ins_compl_autocomplete_pending() && p_acl > 0
|
||||
&& typebuf.tb_len == 0
|
||||
&& !ins_compl_active()
|
||||
&& (get_real_state() & MODE_INSERT) != 0;
|
||||
// Measure the delay from when it was armed (the keystroke), so a
|
||||
// CursorHold returning in between does not push the popup back.
|
||||
int64_t wait_time = p_ut - cursorhold_time;
|
||||
if (delay_pending) {
|
||||
int64_t delay_left = p_acl - ins_compl_autocomplete_elapsed();
|
||||
wait_time = MIN(MAX(delay_left, 0), wait_time);
|
||||
}
|
||||
if ((result = inbuf_poll((int)wait_time, events)) == kFalse) {
|
||||
if (read_stream.s.closed && silent_mode) {
|
||||
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
|
||||
read_error_exit();
|
||||
}
|
||||
// The 'autocompletedelay' expired: trigger the popup. When
|
||||
// 'updatetime' is shorter, fall through to CursorHold instead.
|
||||
if (delay_pending && ins_compl_autocomplete_elapsed() >= p_acl
|
||||
&& (buf == NULL || maxlen >= 3) && !typebuf_changed(tb_change_cnt)) {
|
||||
if (buf == NULL) {
|
||||
uint8_t ibuf[3];
|
||||
ibuf[0] = K_SPECIAL;
|
||||
ibuf[1] = KS_EXTRA;
|
||||
ibuf[2] = KE_COMPLETE_DELAY;
|
||||
input_enqueue_raw((char *)ibuf, 3);
|
||||
return 0;
|
||||
}
|
||||
buf[0] = K_SPECIAL;
|
||||
buf[1] = KS_EXTRA;
|
||||
buf[2] = KE_COMPLETE_DELAY;
|
||||
return 3;
|
||||
}
|
||||
reset_cursorhold_wait(tb_change_cnt);
|
||||
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
|
||||
create_cursorhold_event(events == main_loop.events);
|
||||
|
||||
@@ -1552,15 +1552,6 @@ describe('completion', function()
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
foo |
|
||||
foobar |
|
||||
foobarbaz |
|
||||
f^ |
|
||||
{1:~ }|*5
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
vim.uv.sleep(500)
|
||||
screen:expect([[
|
||||
foo |
|
||||
foobar |
|
||||
@@ -1572,6 +1563,8 @@ describe('completion', function()
|
||||
{1:~ }|*2
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
vim.uv.sleep(500)
|
||||
screen:expect_unchanged()
|
||||
|
||||
-- During delay wait, user can open menu using CTRL_N completion
|
||||
feed('<Esc>')
|
||||
@@ -1589,7 +1582,9 @@ describe('completion', function()
|
||||
{5:-- Keyword completion (^N^P) }{6:match 1 of 3} |
|
||||
]])
|
||||
|
||||
-- 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.
|
||||
feed('<Esc>')
|
||||
command('set completeopt=menu')
|
||||
feed('Sf')
|
||||
@@ -1601,7 +1596,7 @@ describe('completion', function()
|
||||
{1:~ }|*5
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
vim.uv.sleep(500)
|
||||
vim.uv.sleep(600)
|
||||
screen:expect([[
|
||||
foo |
|
||||
foobar |
|
||||
@@ -1670,6 +1665,35 @@ describe('completion', function()
|
||||
feed('<esc>')
|
||||
end)
|
||||
|
||||
local function run_test_autocompletedelay_ctrl_k(delay1, delay2)
|
||||
source([[
|
||||
new
|
||||
call setline(1, 'foo bar baz')
|
||||
set autocomplete autocompletedelay=200
|
||||
]])
|
||||
|
||||
feed('ob')
|
||||
vim.uv.sleep(delay1)
|
||||
feed('<C-K>')
|
||||
vim.uv.sleep(delay2)
|
||||
feed('.,<Esc>')
|
||||
poke_eventloop()
|
||||
expect('foo bar baz\nb…')
|
||||
|
||||
source([[
|
||||
set autocomplete& autocompletedelay&
|
||||
bwipe!
|
||||
]])
|
||||
end
|
||||
|
||||
-- oldtest: Test_autocompletedelay_ctrl_k()
|
||||
it("'autocompletedelay' doesn't interfere with i_CTRL-K", function()
|
||||
-- Ctrl-K typed after 'autocompletedelay' expires
|
||||
run_test_autocompletedelay_ctrl_k(250, 500)
|
||||
-- Ctrl-K typed before 'autocompletedelay' expires
|
||||
run_test_autocompletedelay_ctrl_k(150, 500)
|
||||
end)
|
||||
|
||||
-- oldtest: Test_fuzzy_select_item_when_acl()
|
||||
it([[first item isn't selected with "fuzzy" and 'acl']], function()
|
||||
screen:try_resize(60, 10)
|
||||
@@ -1734,7 +1758,7 @@ describe('completion', function()
|
||||
screen:expect([[
|
||||
autocomplete |
|
||||
autocomxxx |
|
||||
au{102:^tocom} |
|
||||
au^ |
|
||||
{1:~ }|*4
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
@@ -1742,7 +1766,7 @@ describe('completion', function()
|
||||
screen:expect([[
|
||||
autocomplete |
|
||||
autocomxxx |
|
||||
autoc{102:^om} |
|
||||
autoc^ |
|
||||
{1:~ }|*4
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
@@ -1762,7 +1786,7 @@ describe('completion', function()
|
||||
screen:expect([[
|
||||
autocomplete |
|
||||
autocomxxx |
|
||||
aut{102:^ocom} |
|
||||
aut^ |
|
||||
{1:~ }|*4
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
@@ -1770,7 +1794,7 @@ describe('completion', function()
|
||||
screen:expect([[
|
||||
autocomplete |
|
||||
autocomxxx |
|
||||
au{102:^tocom} |
|
||||
au^ |
|
||||
{1:~ }|*4
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
@@ -1787,13 +1811,11 @@ describe('completion', function()
|
||||
|
||||
-- Preinsert
|
||||
command('set completeopt& completeopt+=preinsert')
|
||||
|
||||
-- Show preinserted text right away but display popup later
|
||||
feed('<Esc>Sau')
|
||||
screen:expect([[
|
||||
autocomplete |
|
||||
autocomxxx |
|
||||
au{102:^tocomplete} |
|
||||
au^ |
|
||||
{1:~ }|*4
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
|
||||
@@ -6039,17 +6039,19 @@ func Test_autocompletedelay()
|
||||
call term_sendkeys(buf, "\<BS>")
|
||||
call VerifyScreenDump(buf, 'Test_autocompletedelay_5', {})
|
||||
sleep 500m
|
||||
call VerifyScreenDump(buf, 'Test_autocompletedelay_6', {})
|
||||
call VerifyScreenDump(buf, 'Test_autocompletedelay_5', {})
|
||||
|
||||
" During delay wait, user can open menu using CTRL_N completion
|
||||
call term_sendkeys(buf, "\<Esc>:set completeopt=menuone\<CR>")
|
||||
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>")
|
||||
@@ -6066,6 +6068,80 @@ func Test_autocompletedelay()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
func Run_test_autocompletedelay_ctrl_g_U(delay1, delay2)
|
||||
new
|
||||
call setline(1, 'foo bar baz')
|
||||
inoremap <buffer> ( ()<C-g>U
|
||||
set autocomplete autocompletedelay=200
|
||||
|
||||
call timer_start(a:delay1, { -> feedkeys('(', 't') })
|
||||
call timer_start(a:delay2, { -> feedkeys("\<Left>a\<Esc>", 't') })
|
||||
call feedkeys('ob', 'tx!')
|
||||
call assert_equal(['foo bar baz', 'b(a)'], getline(1, '$'))
|
||||
undo
|
||||
call assert_equal(['foo bar baz'], getline(1, '$'))
|
||||
|
||||
set autocomplete& autocompletedelay&
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_autocompletedelay_ctrl_g_U()
|
||||
" '(' typed after 'autocompletedelay' expires
|
||||
call Run_test_autocompletedelay_ctrl_g_U(250, 500)
|
||||
" '(' typed before 'autocompletedelay' expires
|
||||
call Run_test_autocompletedelay_ctrl_g_U(150, 500)
|
||||
endfunc
|
||||
|
||||
func Run_test_autocompletedelay_ctrl_k(delay1, delay2)
|
||||
new
|
||||
call setline(1, 'foo bar baz')
|
||||
set autocomplete autocompletedelay=200
|
||||
|
||||
call timer_start(a:delay1, { -> feedkeys("\<C-K>", 't') })
|
||||
call timer_start(a:delay2, { -> feedkeys(".,\<Esc>", 't') })
|
||||
call feedkeys('ob', 'tx!')
|
||||
call assert_equal(['foo bar baz', 'b…'], getline(1, '$'))
|
||||
|
||||
set autocomplete& autocompletedelay&
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_autocompletedelay_ctrl_k()
|
||||
throw 'Skipped: use test/functional/editor/completion_spec.lua'
|
||||
" Ctrl-K typed after 'autocompletedelay' expires
|
||||
call Run_test_autocompletedelay_ctrl_k(250, 500)
|
||||
" Ctrl-K typed before 'autocompletedelay' expires
|
||||
call Run_test_autocompletedelay_ctrl_k(150, 500)
|
||||
endfunc
|
||||
|
||||
func Test_autocompletedelay_no_record()
|
||||
" The K_COMPLETE_DELAY pseudo key must not be recorded into a register while
|
||||
" recording a macro, like K_CURSORHOLD.
|
||||
new
|
||||
call setline(1, 'foobar')
|
||||
set autocomplete autocompletedelay=100
|
||||
|
||||
let @a = ''
|
||||
" Type a char that arms the delay, idle past 'autocompletedelay' so a
|
||||
" K_COMPLETE_DELAY would be injected, then end Insert mode and stop recording.
|
||||
call timer_start(300, { -> feedkeys("\<Esc>q", 't') })
|
||||
call feedkeys("qaSf", 'tx!')
|
||||
call assert_equal("Sf\<Esc>", @a)
|
||||
|
||||
" Delayed autocompletion still works when recording.
|
||||
if !has('win32') || has('nvim')
|
||||
call setline(1, 'foobar foofoo')
|
||||
call timer_start(300, { -> feedkeys("\<Down>\<C-Y>\<Esc>q", 't') })
|
||||
call feedkeys("qaof", 'tx!')
|
||||
call assert_equal('foobar', getline('.'))
|
||||
" XXX: This doesn't produce the same result when replaying.
|
||||
call assert_equal("of\<Down>\<C-Y>\<Esc>", @a)
|
||||
endif
|
||||
|
||||
set autocomplete& autocompletedelay&
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" Preinsert longest prefix when autocomplete
|
||||
func Test_autocomplete_longest()
|
||||
func GetLine()
|
||||
@@ -6366,8 +6442,6 @@ func Test_autocompletedelay_longest_preinsert()
|
||||
|
||||
" Preinsert
|
||||
call term_sendkeys(buf, "\<Esc>:set completeopt& completeopt+=preinsert\<CR>")
|
||||
|
||||
" Show preinserted text right away but display popup later
|
||||
call term_sendkeys(buf, "\<Esc>Sau")
|
||||
sleep 100m
|
||||
call VerifyScreenDump(buf, 'Test_autocompletedelay_preinsert_1', {})
|
||||
|
||||
Reference in New Issue
Block a user