patch 9.1.1471: completion: inconsistent ordering with CTRL-P

Problem:  completion: inconsistent ordering with CTRL-P
          (zeertzjq)
Solution: reset compl_curr_match when using CTRL-P (Girish Palya)

fixes: #17425
closes: #17434

Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Girish Palya
2025-06-18 19:15:45 +02:00
committed by Christian Brabandt
parent 1c00af2a24
commit 5fbe72edda
5 changed files with 84 additions and 13 deletions

View File

@ -693,7 +693,7 @@ edit(
&& stop_arrow() == OK) && stop_arrow() == OK)
{ {
ins_compl_delete(); ins_compl_delete();
ins_compl_insert(FALSE, FALSE); ins_compl_insert(FALSE);
} }
// Delete preinserted text when typing special chars // Delete preinserted text when typing special chars
else if (IS_WHITE_NL_OR_NUL(c) && ins_compl_preinsert_effect()) else if (IS_WHITE_NL_OR_NUL(c) && ins_compl_preinsert_effect())

View File

@ -2378,7 +2378,7 @@ ins_compl_new_leader(void)
if (compl_match_array == NULL) if (compl_match_array == NULL)
compl_enter_selects = FALSE; compl_enter_selects = FALSE;
else if (ins_compl_has_preinsert() && compl_leader.length > 0) 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; 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; cpt_sources_index = -1;
compl_started = TRUE; compl_started = TRUE;
@ -5404,12 +5410,11 @@ ins_compl_expand_multiple(char_u *str)
/* /*
* Insert the new text being completed. * 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 * "move_cursor" is used when 'completeopt' includes "preinsert" and when TRUE
* cursor needs to move back from the inserted text to the compl_leader. * cursor needs to move back from the inserted text to the compl_leader.
*/ */
void void
ins_compl_insert(int in_compl_func, int move_cursor) ins_compl_insert(int move_cursor)
{ {
int compl_len = get_compl_len(); int compl_len = get_compl_len();
int preinsert = ins_compl_has_preinsert(); 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); set_vim_var_dict(VV_COMPLETED_ITEM, dict);
} }
#endif #endif
if (!in_compl_func)
compl_curr_match = compl_shown_match;
} }
/* /*
@ -5638,8 +5641,7 @@ ins_compl_next(
int allow_get_expansion, int allow_get_expansion,
int count, // repeat completion this many times; should int count, // repeat completion this many times; should
// be at least 1 // be at least 1
int insert_match, // Insert the newly selected match int insert_match) // Insert the newly selected match
int in_compl_func) // called from complete_check()
{ {
int num_matches = -1; int num_matches = -1;
int todo = count; int todo = count;
@ -5700,7 +5702,7 @@ ins_compl_next(
else if (insert_match) else if (insert_match)
{ {
if (!compl_get_longest || compl_used_match) if (!compl_get_longest || compl_used_match)
ins_compl_insert(in_compl_func, TRUE); ins_compl_insert(TRUE);
else else
ins_compl_insert_bytes(compl_leader.string + get_compl_len(), -1); 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 c = safe_vgetc(); // Eat the character
compl_shows_dir = ins_compl_key2dir(c); compl_shows_dir = ins_compl_key2dir(c);
(void)ins_compl_next(FALSE, ins_compl_key2count(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 else
{ {
@ -5809,7 +5811,7 @@ ins_compl_check_keys(int frequency, int in_compl_func)
int todo = compl_pending > 0 ? compl_pending : -compl_pending; int todo = compl_pending > 0 ? compl_pending : -compl_pending;
compl_pending = 0; 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). // Find next match (and following matches).
save_w_wrow = curwin->w_wrow; save_w_wrow = curwin->w_wrow;
save_w_leftcol = curwin->w_leftcol; 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 // may undisplay the popup menu
ins_compl_upd_pum(); ins_compl_upd_pum();

View File

@ -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_check(typval_T *argvars, typval_T *rettv);
void f_complete_info(typval_T *argvars, typval_T *rettv); void f_complete_info(typval_T *argvars, typval_T *rettv);
void ins_compl_delete(void); 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); void ins_compl_check_keys(int frequency, int in_compl_func);
int ins_complete(int c, int enable_pum); int ins_complete(int c, int enable_pum);
void free_insexpand_stuff(void); void free_insexpand_stuff(void);

View File

@ -4754,6 +4754,73 @@ func Test_complete_unloaded_buf_refresh_always()
delfunc TestComplete delfunc TestComplete
endfunc 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 <buffer> <F2> <Cmd>let b:matches = complete_info(["matches"]).matches<CR>
call setline(1, ['xxx', 'yyy', 'zzz', ''])
call feedkeys("GS\<C-N>\<F2>\<Esc>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\<C-P>\<F2>\<Esc>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\<C-N>\<F2>\<Esc>0", 'tx!')
call assert_equal([
\ 'one', 'two', 'three',
\ 'four', 'five', 'six',
\ 'seven', 'eight', 'nine',
\ ], b:matches->mapnew('v:val.word'))
call feedkeys("GS\<C-P>\<F2>\<Esc>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() func Test_complete_fuzzy_omnifunc_backspace()
let g:do_complete = v:false let g:do_complete = v:false
func Omni_test(findstart, base) func Omni_test(findstart, base)

View File

@ -709,6 +709,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1471,
/**/ /**/
1470, 1470,
/**/ /**/