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 <glephunter@gmail.com>
Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/insexpand.c b/src/insexpand.c
index 33d00e0..ff8e87e 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -819,77 +819,6 @@
}
/*
- * 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
* len - length of "str". If -1, then the length of "str" is
@@ -948,10 +877,7 @@
|| 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
may_trigger_modechanged();
+ if (is_nearest_active())
+ sort_compl_match_list(cp_compare_nearest);
+
return i;
}
@@ -5518,7 +5484,7 @@
* 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 @@
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 @@
&& 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);