diff --git a/src/edit.c b/src/edit.c index 9cc55ef3d7..97e4224c0b 100644 --- a/src/edit.c +++ b/src/edit.c @@ -693,7 +693,7 @@ edit( && stop_arrow() == OK) { ins_compl_delete(); - ins_compl_insert(FALSE, FALSE); + ins_compl_insert(FALSE); } // Delete preinserted text when typing special chars else if (IS_WHITE_NL_OR_NUL(c) && ins_compl_preinsert_effect()) diff --git a/src/insexpand.c b/src/insexpand.c index 2d398877b7..94eb760d7e 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -2378,7 +2378,7 @@ ins_compl_new_leader(void) if (compl_match_array == NULL) compl_enter_selects = FALSE; else if (ins_compl_has_preinsert() && compl_leader.length > 0) - ins_compl_insert(FALSE, TRUE); + ins_compl_insert(TRUE); } /* @@ -5235,6 +5235,12 @@ ins_compl_get_exp(pos_T *ini) compl_started = FALSE; } + + // For `^P` completion, reset `compl_curr_match` to the head to avoid + // mixing matches from different sources. + if (!compl_dir_forward()) + while (compl_curr_match->cp_prev) + compl_curr_match = compl_curr_match->cp_prev; } cpt_sources_index = -1; compl_started = TRUE; @@ -5404,12 +5410,11 @@ ins_compl_expand_multiple(char_u *str) /* * Insert the new text being completed. - * "in_compl_func" is TRUE when called from complete_check(). * "move_cursor" is used when 'completeopt' includes "preinsert" and when TRUE * cursor needs to move back from the inserted text to the compl_leader. */ void -ins_compl_insert(int in_compl_func, int move_cursor) +ins_compl_insert(int move_cursor) { int compl_len = get_compl_len(); int preinsert = ins_compl_has_preinsert(); @@ -5442,8 +5447,6 @@ ins_compl_insert(int in_compl_func, int move_cursor) set_vim_var_dict(VV_COMPLETED_ITEM, dict); } #endif - if (!in_compl_func) - compl_curr_match = compl_shown_match; } /* @@ -5638,8 +5641,7 @@ ins_compl_next( int allow_get_expansion, int count, // repeat completion this many times; should // be at least 1 - int insert_match, // Insert the newly selected match - int in_compl_func) // called from complete_check() + int insert_match) // Insert the newly selected match { int num_matches = -1; int todo = count; @@ -5700,7 +5702,7 @@ ins_compl_next( else if (insert_match) { if (!compl_get_longest || compl_used_match) - ins_compl_insert(in_compl_func, TRUE); + ins_compl_insert(TRUE); else ins_compl_insert_bytes(compl_leader.string + get_compl_len(), -1); } @@ -5786,7 +5788,7 @@ ins_compl_check_keys(int frequency, int in_compl_func) c = safe_vgetc(); // Eat the character compl_shows_dir = ins_compl_key2dir(c); (void)ins_compl_next(FALSE, ins_compl_key2count(c), - c != K_UP && c != K_DOWN, in_compl_func); + c != K_UP && c != K_DOWN); } else { @@ -5809,7 +5811,7 @@ ins_compl_check_keys(int frequency, int in_compl_func) int todo = compl_pending > 0 ? compl_pending : -compl_pending; compl_pending = 0; - (void)ins_compl_next(FALSE, todo, TRUE, in_compl_func); + (void)ins_compl_next(FALSE, todo, TRUE); } } @@ -6656,7 +6658,7 @@ ins_complete(int c, int enable_pum) // Find next match (and following matches). save_w_wrow = curwin->w_wrow; save_w_leftcol = curwin->w_leftcol; - n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match, FALSE); + n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match); // may undisplay the popup menu ins_compl_upd_pum(); diff --git a/src/proto/insexpand.pro b/src/proto/insexpand.pro index 8965aca4c7..05640087cf 100644 --- a/src/proto/insexpand.pro +++ b/src/proto/insexpand.pro @@ -63,7 +63,7 @@ void f_complete_add(typval_T *argvars, typval_T *rettv); void f_complete_check(typval_T *argvars, typval_T *rettv); void f_complete_info(typval_T *argvars, typval_T *rettv); void ins_compl_delete(void); -void ins_compl_insert(int in_compl_func, int move_cursor); +void ins_compl_insert(int move_cursor); void ins_compl_check_keys(int frequency, int in_compl_func); int ins_complete(int c, int enable_pum); void free_insexpand_stuff(void); diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 155c5b7964..df59e1e2a0 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -4754,6 +4754,73 @@ func Test_complete_unloaded_buf_refresh_always() delfunc TestComplete endfunc +" Verify that the order of matches from each source is consistent +" during both ^N and ^P completions (Issue #17425). +func Test_complete_with_multiple_function_sources() + func F1(findstart, base) + if a:findstart + return col('.') - 1 + endif + return ['one', 'two', 'three'] + endfunc + + func F2(findstart, base) + if a:findstart + return col('.') - 1 + endif + return ['four', 'five', 'six'] + endfunc + + func F3(findstart, base) + if a:findstart + return col('.') - 1 + endif + return ['seven', 'eight', 'nine'] + endfunc + + new + setlocal complete=.,FF1,FF2,FF3 + inoremap let b:matches = complete_info(["matches"]).matches + call setline(1, ['xxx', 'yyy', 'zzz', '']) + + call feedkeys("GS\\\0", 'tx!') + call assert_equal([ + \ 'xxx', 'yyy', 'zzz', + \ 'one', 'two', 'three', + \ 'four', 'five', 'six', + \ 'seven', 'eight', 'nine', + \ ], b:matches->mapnew('v:val.word')) + + call feedkeys("GS\\\0", 'tx!') + call assert_equal([ + \ 'seven', 'eight', 'nine', + \ 'four', 'five', 'six', + \ 'one', 'two', 'three', + \ 'xxx', 'yyy', 'zzz', + \ ], b:matches->mapnew('v:val.word')) + + %delete + + call feedkeys("GS\\\0", 'tx!') + call assert_equal([ + \ 'one', 'two', 'three', + \ 'four', 'five', 'six', + \ 'seven', 'eight', 'nine', + \ ], b:matches->mapnew('v:val.word')) + + call feedkeys("GS\\\0", 'tx!') + call assert_equal([ + \ 'seven', 'eight', 'nine', + \ 'four', 'five', 'six', + \ 'one', 'two', 'three', + \ ], b:matches->mapnew('v:val.word')) + + bwipe! + delfunc F1 + delfunc F2 + delfunc F3 +endfunc + func Test_complete_fuzzy_omnifunc_backspace() let g:do_complete = v:false func Omni_test(findstart, base) diff --git a/src/version.c b/src/version.c index 05e85ad4d7..52fdfc361a 100644 --- a/src/version.c +++ b/src/version.c @@ -709,6 +709,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1471, /**/ 1470, /**/