]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1471: completion: inconsistent ordering with CTRL-P v9.1.1471
authorGirish Palya <girishji@gmail.com>
Wed, 18 Jun 2025 17:15:45 +0000 (19:15 +0200)
committerChristian Brabandt <cb@256bit.org>
Wed, 18 Jun 2025 17:15:45 +0000 (19:15 +0200)
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>
src/edit.c
src/insexpand.c
src/proto/insexpand.pro
src/testdir/test_ins_complete.vim
src/version.c

index 9cc55ef3d756e4a1bc363e37c04ce55303670dd7..97e4224c0b24c408b266a43d0727b58b1a6dfd7e 100644 (file)
@@ -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())
index 2d398877b7bafd3b89ca8b64eb6d210271026348..94eb760d7e29c81d0b7d5cd3345fe2a7ab44f09d 100644 (file)
@@ -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();
index 8965aca4c715e6e3dfb94a72f54f3f5e2c219ac7..05640087cf280527c82227de6a7c00fc21513a30 100644 (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_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);
index 155c5b79643a12a1271a0a71149d8f4d45b76262..df59e1e2a009713f2684145597bb7a9f91439820 100644 (file)
@@ -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 <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()
   let g:do_complete = v:false
   func Omni_test(findstart, base)
index 05e85ad4d7cc305b21038a357a06dc981aec185e..52fdfc361a6642081e8138a417a798831352df80 100644 (file)
@@ -709,6 +709,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1471,
 /**/
     1470,
 /**/