patch 9.1.1441: completion: code can be improved

Commit: 
https://github.com/vim/vim/commit/b8ee1cf56e687a02756b15d8c530206827e3ef1e
Author: Girish Palya <giris...@gmail.com>
Date:   Sun Jun 8 16:20:06 2025 +0200

    patch 9.1.1441: completion: code can be improved
    
    Problem:  completion: code can be improved
    Solution: remove reposition_match() and use mergesort_list(),
              for fuzzy completion, sort by fuzzy score immediately after
              setting a new leader (Girish Palya)
    
    closes: #17460
    
    Co-authored-by: glepnir <glephun...@gmail.com>
    Signed-off-by: Girish Palya <giris...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/insexpand.c b/src/insexpand.c
index 33d00e0c6..ff8e87e4e 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -818,77 +818,6 @@ is_nearest_active(void)
     return (get_cot_flags() & (COT_NEAREST | COT_FUZZY)) == COT_NEAREST;
 }
 
-/*
- * Repositions a match in the completion list based on its proximity score.
- * If the match is at the head and has a higher score than the next node,
- * or if it's in the middle/tail and has a lower score than the previous node,
- * it is moved to the correct position while maintaining ascending order.
- */
-    static void
-reposition_match(compl_T *match)
-{
-    compl_T *insert_before = NULL;
-    compl_T *insert_after = NULL;
-
-    // Node is at head and score is too big
-    if (!match->cp_prev)
-    {
-       if (match->cp_next && match->cp_next->cp_score > 0 &&
-               match->cp_next->cp_score < match->cp_score)
-       {
-           // <c-p>: compl_first_match is at head and newly inserted node
-           compl_first_match = compl_curr_match = match->cp_next;
-           // Find the correct position in ascending order
-           insert_before = match->cp_next;
-           do
-           {
-               insert_after = insert_before;
-               insert_before = insert_before->cp_next;
-           } while (insert_before && insert_before->cp_score > 0 &&
-                   insert_before->cp_score < match->cp_score);
-       }
-       else
-           return;
-    }
-    // Node is at tail or in the middle but score is too small
-    else
-    {
-       if (match->cp_prev->cp_score > 0 && match->cp_prev->cp_score > 
match->cp_score)
-       {
-           // <c-n>: compl_curr_match (and newly inserted match) is at tail
-           if (!match->cp_next)
-               compl_curr_match = compl_curr_match->cp_prev;
-           // Find the correct position in ascending order
-           insert_after = match->cp_prev;
-           do
-           {
-               insert_before = insert_after;
-               insert_after = insert_after->cp_prev;
-           } while (insert_after && insert_after->cp_score > 0 &&
-                   insert_after->cp_score > match->cp_score);
-       }
-       else
-           return;
-    }
-
-    if (insert_after)
-    {
-       // Remove the match from its current position
-       if (match->cp_prev)
-           match->cp_prev->cp_next = match->cp_next;
-       else
-           compl_first_match = match->cp_next;
-       if (match->cp_next)
-           match->cp_next->cp_prev = match->cp_prev;
-
-       // Insert the match at the correct position
-       match->cp_next = insert_before;
-       match->cp_prev = insert_after;
-       insert_after->cp_next = match;
-       insert_before->cp_prev = match;
-    }
-}
-
 /*
  * Add a match to the list of matches. The arguments are:
  *     str       - text of the match to add
@@ -948,10 +877,7 @@ ins_compl_add(
                                                 || match->cp_str.string[len] 
== NUL))
            {
                if (is_nearest_active() && score > 0 && score < match->cp_score)
-               {
                    match->cp_score = score;
-                   reposition_match(match);
-               }
                return NOTDONE;
            }
            match = match->cp_next;
@@ -1063,9 +989,6 @@ ins_compl_add(
        compl_first_match = match;
     compl_curr_match = match;
 
-    if (is_nearest_active() && score > 0)
-       reposition_match(match);
-
     // Find the longest common string if still doing that.
     if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0 && 
!cfc_has_mode())
        ins_compl_longest_match(match);
@@ -1476,6 +1399,69 @@ cp_compare_fuzzy(const void* a, const void* b)
     return (score_b > score_a) ? 1 : (score_b < score_a) ? -1 : 0;
 }
 
+    static int
+cp_compare_nearest(const void* a, const void* b)
+{
+    int score_a = ((compl_T*)a)->cp_score;
+    int score_b = ((compl_T*)b)->cp_score;
+    if (score_a < 0 || score_b < 0)
+       return 0;
+    return (score_a > score_b) ? 1 : (score_a < score_b) ? -1 : 0;
+}
+
+/*
+ * Set fuzzy score.
+ */
+    static void
+set_fuzzy_score(void)
+{
+    compl_T     *compl = compl_first_match->cp_prev;
+
+    if (compl_leader.string != NULL && compl_leader.length > 0)
+    {
+       compl = compl_first_match;
+       do
+       {
+           compl->cp_score = fuzzy_match_str(compl->cp_str.string,
+                   compl_leader.string);
+           compl = compl->cp_next;
+       } while (compl != NULL && !is_first_match(compl));
+    }
+}
+
+/*
+ * Sort completion matches, excluding the node that contains the leader.
+ */
+    static void
+sort_compl_match_list(int (*compare)(const void *, const void *))
+{
+    compl_T     *compl = compl_first_match->cp_prev;
+
+    if (!compl_first_match || is_first_match(compl_first_match->cp_next))
+       return;
+
+    ins_compl_make_linear();
+    if (compl_shows_dir_forward())
+    {
+       compl_first_match->cp_next->cp_prev = NULL;
+       compl_first_match->cp_next = mergesort_list(compl_first_match->cp_next,
+               cp_get_next, cp_set_next, cp_get_prev, cp_set_prev, compare);
+       compl_first_match->cp_next->cp_prev = compl_first_match;
+    }
+    else
+    {
+       compl->cp_prev->cp_next = NULL;
+       compl_first_match = mergesort_list(compl_first_match, cp_get_next,
+               cp_set_next, cp_get_prev, cp_set_prev, compare);
+       compl_T *tail = compl_first_match;
+       while (tail->cp_next != NULL)
+           tail = tail->cp_next;
+       tail->cp_next = compl;
+       compl->cp_prev = tail;
+    }
+    (void)ins_compl_make_cyclic();
+}
+
 /*
  * Build a popup menu to show the completion matches.
  * Returns the popup menu entry that should be selected. Returns -1 if nothing
@@ -1493,7 +1479,6 @@ ins_compl_build_pum(void)
     unsigned int cur_cot_flags = get_cot_flags();
     int                compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
     int                fuzzy_filter = (cur_cot_flags & COT_FUZZY) != 0;
-    int                fuzzy_sort = fuzzy_filter && !(cur_cot_flags & 
COT_NOSORT);
     compl_T    *match_head = NULL;
     compl_T    *match_tail = NULL;
     compl_T    *match_next = NULL;
@@ -1515,45 +1500,6 @@ ins_compl_build_pum(void)
        compl_shown_match = compl_no_select ? compl_first_match
                                            : compl_first_match->cp_next;
 
-    // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
-    // set the cp_score for later comparisons.
-    if (fuzzy_filter && compl_leader.string != NULL && compl_leader.length > 0)
-    {
-       compl = compl_first_match;
-       do
-       {
-           compl->cp_score = fuzzy_match_str(compl->cp_str.string, 
compl_leader.string);
-           compl = compl->cp_next;
-       } while (compl != NULL && !is_first_match(compl));
-    }
-
-    // Sort the linked list based on fuzzy score
-    if (fuzzy_sort && compl_leader.string != NULL && compl_leader.length > 0
-           && !is_first_match(compl_first_match->cp_next))
-    {
-       compl = compl_first_match->cp_prev;
-       ins_compl_make_linear();
-       if (is_forward)
-       {
-           compl_first_match->cp_next->cp_prev = NULL;
-           compl_first_match->cp_next = 
mergesort_list(compl_first_match->cp_next, cp_get_next,
-                   cp_set_next, cp_get_prev, cp_set_prev, cp_compare_fuzzy);
-           compl_first_match->cp_next->cp_prev = compl_first_match;
-       }
-       else
-       {
-           compl->cp_prev->cp_next = NULL;
-           compl_first_match = mergesort_list(compl_first_match, cp_get_next,
-                   cp_set_next, cp_get_prev, cp_set_prev, cp_compare_fuzzy);
-           compl_T     *tail = compl_first_match;
-           while (tail->cp_next != NULL)
-               tail = tail->cp_next;
-           tail->cp_next = compl;
-           compl->cp_prev = tail;
-       }
-       (void)ins_compl_make_cyclic();
-    }
-
     if (is_cpt_completion)
     {
        match_count = ALLOC_CLEAR_MULT(int, cpt_sources_count);
@@ -2402,6 +2348,23 @@ ins_compl_new_leader(void)
        compl_restarting = FALSE;
     }
 
+    // When 'cot' contains "fuzzy" set the cp_score
+    if (get_cot_flags() & COT_FUZZY)
+       set_fuzzy_score();
+    // Sort the matches linked list based on fuzzy score
+    int        cur_cot_flags = get_cot_flags();
+    if ((cur_cot_flags & COT_FUZZY) && !(cur_cot_flags & COT_NOSORT))
+    {
+       sort_compl_match_list(cp_compare_fuzzy);
+       if ((cur_cot_flags & COT_NOINSERT) && !(cur_cot_flags & COT_NOSELECT)
+               && compl_first_match)
+       {
+           compl_shown_match = compl_first_match;
+           if (compl_shows_dir_forward())
+               compl_shown_match = compl_first_match->cp_next;
+       }
+    }
+
     compl_enter_selects = !compl_used_match && compl_selected_item != -1;
 
     // Show the popup menu with a different set of matches.
@@ -5296,6 +5259,9 @@ ins_compl_get_exp(pos_T *ini)
     }
     may_trigger_modechanged();
 
+    if (is_nearest_active())
+       sort_compl_match_list(cp_compare_nearest);
+
     return i;
 }
 
@@ -5518,7 +5484,7 @@ ins_compl_show_filename(void)
  * in 'compl_match_array'.
  */
     static compl_T *
-find_comp_when_cpt_sources(void)
+find_next_match_in_menu(void)
 {
     int            is_forward = compl_shows_dir_forward();
     compl_T *match = compl_shown_match;
@@ -5555,14 +5521,13 @@ find_next_completion_match(
     unsigned int cur_cot_flags = get_cot_flags();
     int            compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
     int            compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
-    int            cpt_sources_active = compl_match_array && cpt_sources_array;
 
     while (--todo >= 0)
     {
        if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL)
        {
-           if (cpt_sources_active)
-               compl_shown_match = find_comp_when_cpt_sources();
+           if (compl_match_array != NULL)
+               compl_shown_match = find_next_match_in_menu();
            else
                compl_shown_match = compl_shown_match->cp_next;
            found_end = (compl_first_match != NULL
@@ -5573,8 +5538,8 @@ find_next_completion_match(
                && compl_shown_match->cp_prev != NULL)
        {
            found_end = is_first_match(compl_shown_match);
-           if (cpt_sources_active)
-               compl_shown_match = find_comp_when_cpt_sources();
+           if (compl_match_array != NULL)
+               compl_shown_match = find_next_match_in_menu();
            else
                compl_shown_match = compl_shown_match->cp_prev;
            found_end |= is_first_match(compl_shown_match);
diff --git a/src/testdir/test_ins_complete.vim 
b/src/testdir/test_ins_complete.vim
index fcd2e6c6b..33c87cb2c 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -3394,8 +3394,11 @@ func Test_complete_opt_fuzzy()
     endif
     if g:change == 0
       return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: 
"foobala"}, #{word: "你好吗"}, #{word: "我好"}]
+    elseif g:change == 1
+      return [#{word: "cp_match_array"}, #{word: "cp_str"}, #{word: 
"cp_score"}]
+    else
+      return [#{word: "for i = .."}, #{word: "bar"}, #{word: "foo"}, #{word: 
"for .. ipairs"}, #{word: "for .. pairs"}]
     endif
-    return [#{word: "for i = .."}, #{word: "bar"}, #{word: "foo"}, #{word: 
"for .. ipairs"}, #{word: "for .. pairs"}]
   endfunc
 
   new
@@ -3493,7 +3496,7 @@ func Test_complete_opt_fuzzy()
   call assert_equal('alpha bravio charlie', getline('.'))
 
   set cot=fuzzy,menu,noinsert
-  call feedkeys(":let g:change=1\<CR>")
+  call feedkeys(":let g:change=2\<CR>")
   call feedkeys("S\<C-X>\<C-O>for\<C-N>\<C-N>\<C-N>", 'tx')
   call assert_equal('for', getline('.'))
   call feedkeys("S\<C-X>\<C-O>for\<C-P>", 'tx')
@@ -3501,6 +3504,10 @@ func Test_complete_opt_fuzzy()
   call feedkeys("S\<C-X>\<C-O>for\<C-P>\<C-P>", 'tx')
   call assert_equal('for .. ipairs', getline('.'))
 
+  call feedkeys(":let g:change=1\<CR>")
+  call feedkeys("S\<C-X>\<C-O>c\<C-Y>", 'tx')
+  call assert_equal('cp_str', getline('.'))
+
   " clean up
   set omnifunc=
   bw!
diff --git a/src/version.c b/src/version.c
index 6dc4bf818..7964c14ad 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 */
+/**/
+    1441,
 /**/
     1440,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1uOH2C-007Wea-E4%40256bit.org.

Raspunde prin e-mail lui