summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-06-14 20:04:42 +0200
committerChristian Brabandt <cb@256bit.org>2024-06-14 20:04:42 +0200
commit8e56747fd26b3b040b6fcbfb6be41b7d5922c6b5 (patch)
treedb8335d4996d96535286f9183d39f7fa68d181a0
parent440746158ce0fec2880ccacc03f39dbc954c5543 (diff)
patch 9.1.0484: Sorting of completeopt+=fuzzy is not stablev9.1.0484
Problem: Sorting of completeopt+=fuzzy is not stable. Solution: Compare original indexes when scores are the same. (zeertzjq) closes: #14988 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/insexpand.c13
-rw-r--r--src/structs.h3
-rw-r--r--src/testdir/test_ins_complete.vim20
-rw-r--r--src/version.c2
4 files changed, 34 insertions, 4 deletions
diff --git a/src/insexpand.c b/src/insexpand.c
index 74be94cf4b..fafa7a2f0d 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -1203,11 +1203,13 @@ trigger_complete_changed_event(int cur)
* pumitem qsort compare func
*/
static int
-ins_compl_fuzzy_sort(const void *a, const void *b)
+ins_compl_fuzzy_cmp(const void *a, const void *b)
{
const int sa = (*(pumitem_T *)a).pum_score;
const int sb = (*(pumitem_T *)b).pum_score;
- return sa == sb ? 0 : sa < sb ? 1 : -1;
+ const int ia = (*(pumitem_T *)a).pum_idx;
+ const int ib = (*(pumitem_T *)b).pum_idx;
+ return sa == sb ? (ia == ib ? 0 : (ia < ib ? -1 : 1)) : (sa < sb ? 1 : -1);
}
/*
@@ -1355,8 +1357,13 @@ ins_compl_build_pum(void)
} while (compl != NULL && !is_first_match(compl));
if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0)
+ {
+ for (i = 0; i < compl_match_arraysize; i++)
+ compl_match_array[i].pum_idx = i;
// sort by the largest score of fuzzy match
- qsort(compl_match_array, (size_t)compl_match_arraysize, sizeof(pumitem_T), ins_compl_fuzzy_sort);
+ qsort(compl_match_array, (size_t)compl_match_arraysize,
+ sizeof(pumitem_T), ins_compl_fuzzy_cmp);
+ }
if (!shown_match_ok) // no displayed match at all
cur = -1;
diff --git a/src/structs.h b/src/structs.h
index f1bbf1735d..7e21f0fc8b 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -4470,7 +4470,8 @@ typedef struct
char_u *pum_kind; // extra kind text (may be truncated)
char_u *pum_extra; // extra menu text (may be truncated)
char_u *pum_info; // extra info
- int pum_score; // fuzzy match score
+ int pum_score; // fuzzy match score
+ int pum_idx; // index of item before sorting by score
} pumitem_T;
/*
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index ad9f4978e7..c2cc484c8a 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -2578,4 +2578,24 @@ func Test_complete_fuzzy_match()
unlet g:word
endfunc
+" Check that tie breaking is stable for completeopt+=fuzzy (which should
+" behave the same on different platforms).
+func Test_complete_fuzzy_match_tie()
+ new
+ set completeopt+=fuzzy,noselect
+ call setline(1, ['aaabbccc', 'aaabbCCC', 'aaabbcccc', 'aaabbCCCC', ''])
+
+ call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-Y>", 'tx')
+ call assert_equal('aaabbccc', getline('.'))
+ call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('aaabbCCC', getline('.'))
+ call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-N>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('aaabbcccc', getline('.'))
+ call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-N>\<C-N>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('aaabbCCCC', getline('.'))
+
+ bwipe!
+ set completeopt&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
diff --git a/src/version.c b/src/version.c
index 2df2071085..36761aaed5 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 484,
+/**/
483,
/**/
482,