0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 9.1.1049: insert-completed items are always sorted

Problem:  insert-completed items are always sorted, although the LSP
          spec[1] standard defines sortText in the returned
          completionitem list. This means that the server has sorted the
          results. When fuzzy is enabled, this will break the server's
          sorting results.
Solution: disable sorting of candidates when "nosort" is set in
          'completeopt'

[1]
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItem

closes: #16501

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
glepnir
2025-01-23 19:55:14 +01:00
committed by Christian Brabandt
parent df098fedbc
commit f400a0cc41
7 changed files with 46 additions and 21 deletions

View File

@@ -1,4 +1,4 @@
*options.txt* For Vim version 9.1. Last change: 2025 Jan 21 *options.txt* For Vim version 9.1. Last change: 2025 Jan 23
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2164,6 +2164,10 @@ A jump table for the options with a short description can be found at |Q_op|.
characters can be skipped and matches can be found even characters can be skipped and matches can be found even
if the exact sequence is not typed. if the exact sequence is not typed.
nosort Disable sorting of completion candidates based on fuzzy
scores when "fuzzy" is enabled. Candidates will appear
in their original order.
*'completepopup'* *'cpp'* *'completepopup'* *'cpp'*
'completepopup' 'cpp' string (default empty) 'completepopup' 'cpp' string (default empty)
global global

View File

@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2025 Jan 18 *version9.txt* For Vim version 9.1. Last change: 2025 Jan 23
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41560,15 +41560,17 @@ Support for Wayland UI.
Support for the XDG Desktop Specification |xdg-base-dir| Support for the XDG Desktop Specification |xdg-base-dir|
Support highlighting the matched text for insert-mode completion and
command-line completion in |ins-completion-menu|.
Support highlighting the completion kind in |ins-completion-menu|, see
|complete-items|.
Support for translating messages in Vim script plugins using the |gettext()| Support for translating messages in Vim script plugins using the |gettext()|
and |bindtextdomain()| functions. and |bindtextdomain()| functions.
Support highlighting the matched text and the completion kind for insert-mode
completion and command-line completion in |ins-completion-menu|, see
|complete-items|
Include the "linematch" algorithm for the 'diffopt' setting. This aligns
changes between buffers on similar lines improving the diff highlighting in
Vim
*changed-9.2* *changed-9.2*
Changed~ Changed~
------- -------
@@ -41623,9 +41625,7 @@ Changed~
the "matches" key the "matches" key
- |v:stacktrace| The stack trace of the exception most recently caught and - |v:stacktrace| The stack trace of the exception most recently caught and
not finished not finished
- include the linematch algorithm for the 'diffopt' setting. This aligns - New option value "nosort" for 'completeopt'
changes between buffers on similar lines improving the diff highlighting in
Vim
*added-9.2* *added-9.2*
Added ~ Added ~

View File

@@ -1264,7 +1264,8 @@ ins_compl_build_pum(void)
int max_fuzzy_score = 0; int max_fuzzy_score = 0;
unsigned int cur_cot_flags = get_cot_flags(); unsigned int cur_cot_flags = get_cot_flags();
int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
int compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; int fuzzy_nosort = (cur_cot_flags & COT_NOSORT) != 0;
int fuzzy_filter = fuzzy_nosort || (cur_cot_flags & COT_FUZZY) != 0;
compl_T *match_head = NULL; compl_T *match_head = NULL;
compl_T *match_tail = NULL; compl_T *match_tail = NULL;
compl_T *match_next = NULL; compl_T *match_next = NULL;
@@ -1289,13 +1290,13 @@ ins_compl_build_pum(void)
compl->cp_in_match_array = FALSE; compl->cp_in_match_array = FALSE;
// When 'completeopt' contains "fuzzy" and leader is not NULL or empty, // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
// set the cp_score for later comparisons. // set the cp_score for later comparisons.
if (compl_fuzzy_match && compl_leader.string != NULL && compl_leader.length > 0) if (fuzzy_filter && compl_leader.string != NULL && compl_leader.length > 0)
compl->cp_score = fuzzy_match_str(compl->cp_str.string, compl_leader.string); compl->cp_score = fuzzy_match_str(compl->cp_str.string, compl_leader.string);
if (!match_at_original_text(compl) if (!match_at_original_text(compl)
&& (compl_leader.string == NULL && (compl_leader.string == NULL
|| ins_compl_equal(compl, compl_leader.string, (int)compl_leader.length) || ins_compl_equal(compl, compl_leader.string, (int)compl_leader.length)
|| (compl_fuzzy_match && compl->cp_score > 0))) || (fuzzy_filter && compl->cp_score > 0)))
{ {
++compl_match_arraysize; ++compl_match_arraysize;
compl->cp_in_match_array = TRUE; compl->cp_in_match_array = TRUE;
@@ -1305,7 +1306,7 @@ ins_compl_build_pum(void)
match_tail->cp_match_next = compl; match_tail->cp_match_next = compl;
match_tail = compl; match_tail = compl;
if (!shown_match_ok && !compl_fuzzy_match) if (!shown_match_ok && !fuzzy_filter)
{ {
if (compl == compl_shown_match || did_find_shown_match) if (compl == compl_shown_match || did_find_shown_match)
{ {
@@ -1321,19 +1322,21 @@ ins_compl_build_pum(void)
shown_compl = compl; shown_compl = compl;
cur = i; cur = i;
} }
else if (compl_fuzzy_match) else if (fuzzy_filter)
{ {
if (i == 0) if (i == 0)
shown_compl = compl; shown_compl = compl;
// Update the maximum fuzzy score and the shown match // Update the maximum fuzzy score and the shown match
// if the current item's score is higher // if the current item's score is higher
if (compl->cp_score > max_fuzzy_score) if (!fuzzy_nosort && compl->cp_score > max_fuzzy_score)
{ {
did_find_shown_match = TRUE; did_find_shown_match = TRUE;
max_fuzzy_score = compl->cp_score; max_fuzzy_score = compl->cp_score;
if (!compl_no_select) if (!compl_no_select)
compl_shown_match = compl; compl_shown_match = compl;
} }
else if (fuzzy_nosort && i == 0 && !compl_no_select)
compl_shown_match = shown_compl;
if (!shown_match_ok && compl == compl_shown_match && !compl_no_select) if (!shown_match_ok && compl == compl_shown_match && !compl_no_select)
{ {
@@ -1344,7 +1347,7 @@ ins_compl_build_pum(void)
i++; i++;
} }
if (compl == compl_shown_match && !compl_fuzzy_match) if (compl == compl_shown_match && !fuzzy_filter)
{ {
did_find_shown_match = TRUE; did_find_shown_match = TRUE;
@@ -1389,7 +1392,7 @@ ins_compl_build_pum(void)
compl = match_next; compl = match_next;
} }
if (compl_fuzzy_match && compl_leader.string != NULL && compl_leader.length > 0) if (fuzzy_filter && !fuzzy_nosort && compl_leader.string != NULL && compl_leader.length > 0)
{ {
for (i = 0; i < compl_match_arraysize; i++) for (i = 0; i < compl_match_arraysize; i++)
compl_match_array[i].pum_idx = i; compl_match_array[i].pum_idx = i;

View File

@@ -530,6 +530,7 @@ EXTERN unsigned cot_flags; // flags from 'completeopt'
#define COT_NOINSERT 0x040 // FALSE: select & insert, TRUE: noinsert #define COT_NOINSERT 0x040 // FALSE: select & insert, TRUE: noinsert
#define COT_NOSELECT 0x080 // FALSE: select & insert, TRUE: noselect #define COT_NOSELECT 0x080 // FALSE: select & insert, TRUE: noselect
#define COT_FUZZY 0x100 // TRUE: fuzzy match enabled #define COT_FUZZY 0x100 // TRUE: fuzzy match enabled
#define COT_NOSORT 0x200 // TRUE: fuzzy match without qsort score
#ifdef BACKSLASH_IN_FILENAME #ifdef BACKSLASH_IN_FILENAME
EXTERN char_u *p_csl; // 'completeslash' EXTERN char_u *p_csl; // 'completeslash'
#endif #endif

View File

@@ -120,7 +120,7 @@ static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
NULL}; NULL};
static char *(p_fcl_values[]) = {"all", NULL}; static char *(p_fcl_values[]) = {"all", NULL};
#endif #endif
static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", "popup", "popuphidden", "noinsert", "noselect", "fuzzy", NULL}; static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", "popup", "popuphidden", "noinsert", "noselect", "fuzzy", "nosort", NULL};
#ifdef BACKSLASH_IN_FILENAME #ifdef BACKSLASH_IN_FILENAME
static char *(p_csl_values[]) = {"slash", "backslash", NULL}; static char *(p_csl_values[]) = {"slash", "backslash", NULL};
#endif #endif

View File

@@ -2700,7 +2700,7 @@ func Test_complete_fuzzy_match()
if a:findstart if a:findstart
return col(".") return col(".")
endif endif
return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}] return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}, #{word: "你好吗"}, #{word: "我好"}]
endfunc endfunc
new new
@@ -2855,6 +2855,21 @@ func Test_complete_fuzzy_match()
call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!') call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!')
call assert_equal('Tex', getline('.')) call assert_equal('Tex', getline('.'))
" test case for nosort option
set cot=menuone,menu,noinsert,fuzzy,nosort
" fooBaz" should have a higher score when the leader is "fb".
" With `nosort`, "foobar" should still be shown first in the popup menu.
call feedkeys("S\<C-x>\<C-o>fb", 'tx')
call assert_equal('foobar', g:word)
call feedkeys("S\<C-x>\<C-o>好", 'tx')
call assert_equal("你好吗", g:word)
set cot+=noselect
call feedkeys("S\<C-x>\<C-o>好", 'tx')
call assert_equal(v:null, g:word)
call feedkeys("S\<C-x>\<C-o>好\<C-N>", 'tx')
call assert_equal('你好吗', g:word)
" clean up " clean up
set omnifunc= set omnifunc=
bw! bw!

View File

@@ -704,6 +704,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 */
/**/
1049,
/**/ /**/
1048, 1048,
/**/ /**/