mirror of
https://github.com/neovim/neovim
synced 2025-07-16 01:01:49 +00:00
vim-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: vim/vim#16501
f400a0cc41
Co-authored-by: glepnir <glephunter@gmail.com>
This commit is contained in:
@ -1571,6 +1571,10 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
list of alternatives, but not how the candidates are
|
||||
collected (using different completion types).
|
||||
|
||||
nosort Disable sorting of completion candidates based on fuzzy
|
||||
scores when "fuzzy" is enabled. Candidates will appear
|
||||
in their original order.
|
||||
|
||||
*'completeslash'* *'csl'*
|
||||
'completeslash' 'csl' string (default "")
|
||||
local to buffer
|
||||
|
4
runtime/lua/vim/_meta/options.lua
generated
4
runtime/lua/vim/_meta/options.lua
generated
@ -1098,6 +1098,10 @@ vim.go.cia = vim.go.completeitemalign
|
||||
--- list of alternatives, but not how the candidates are
|
||||
--- collected (using different completion types).
|
||||
---
|
||||
--- nosort Disable sorting of completion candidates based on fuzzy
|
||||
--- scores when "fuzzy" is enabled. Candidates will appear
|
||||
--- in their original order.
|
||||
---
|
||||
--- @type string
|
||||
vim.o.completeopt = "menu,preview"
|
||||
vim.o.cot = vim.o.completeopt
|
||||
|
@ -1212,7 +1212,8 @@ static int ins_compl_build_pum(void)
|
||||
int max_fuzzy_score = 0;
|
||||
unsigned cur_cot_flags = get_cot_flags();
|
||||
bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0;
|
||||
bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
||||
bool fuzzy_nosort = (cur_cot_flags & kOptCotFlagNosort) != 0;
|
||||
bool fuzzy_filter = fuzzy_nosort || (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
||||
compl_T *match_head = NULL, *match_tail = NULL;
|
||||
|
||||
// If the current match is the original text don't find the first
|
||||
@ -1232,14 +1233,14 @@ static int ins_compl_build_pum(void)
|
||||
comp->cp_in_match_array = false;
|
||||
// When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
|
||||
// set the cp_score for later comparisons.
|
||||
if (compl_fuzzy_match && compl_leader.data != NULL && compl_leader.size > 0) {
|
||||
if (fuzzy_filter && compl_leader.data != NULL && compl_leader.size > 0) {
|
||||
comp->cp_score = fuzzy_match_str(comp->cp_str.data, compl_leader.data);
|
||||
}
|
||||
|
||||
if (!match_at_original_text(comp)
|
||||
&& (compl_leader.data == NULL
|
||||
|| ins_compl_equal(comp, compl_leader.data, compl_leader.size)
|
||||
|| (compl_fuzzy_match && comp->cp_score > 0))) {
|
||||
|| (fuzzy_filter && comp->cp_score > 0))) {
|
||||
compl_match_arraysize++;
|
||||
comp->cp_in_match_array = true;
|
||||
if (match_head == NULL) {
|
||||
@ -1248,7 +1249,7 @@ static int ins_compl_build_pum(void)
|
||||
match_tail->cp_match_next = comp;
|
||||
}
|
||||
match_tail = comp;
|
||||
if (!shown_match_ok && !compl_fuzzy_match) {
|
||||
if (!shown_match_ok && !fuzzy_filter) {
|
||||
if (comp == compl_shown_match || did_find_shown_match) {
|
||||
// This item is the shown match or this is the
|
||||
// first displayed item after the shown match.
|
||||
@ -1261,18 +1262,20 @@ static int ins_compl_build_pum(void)
|
||||
shown_compl = comp;
|
||||
}
|
||||
cur = i;
|
||||
} else if (compl_fuzzy_match) {
|
||||
} else if (fuzzy_filter) {
|
||||
if (i == 0) {
|
||||
shown_compl = comp;
|
||||
}
|
||||
// Update the maximum fuzzy score and the shown match
|
||||
// if the current item's score is higher
|
||||
if (comp->cp_score > max_fuzzy_score) {
|
||||
if (!fuzzy_nosort && comp->cp_score > max_fuzzy_score) {
|
||||
did_find_shown_match = true;
|
||||
max_fuzzy_score = comp->cp_score;
|
||||
if (!compl_no_select) {
|
||||
compl_shown_match = comp;
|
||||
}
|
||||
} else if (fuzzy_nosort && i == 0 && !compl_no_select) {
|
||||
compl_shown_match = shown_compl;
|
||||
}
|
||||
if (!shown_match_ok && comp == compl_shown_match && !compl_no_select) {
|
||||
cur = i;
|
||||
@ -1282,7 +1285,7 @@ static int ins_compl_build_pum(void)
|
||||
i++;
|
||||
}
|
||||
|
||||
if (comp == compl_shown_match && !compl_fuzzy_match) {
|
||||
if (comp == compl_shown_match && !fuzzy_filter) {
|
||||
did_find_shown_match = true;
|
||||
// When the original text is the shown match don't set
|
||||
// compl_shown_match.
|
||||
@ -1323,7 +1326,7 @@ static int ins_compl_build_pum(void)
|
||||
comp = match_next;
|
||||
}
|
||||
|
||||
if (compl_fuzzy_match && compl_leader.data != NULL && compl_leader.size > 0) {
|
||||
if (fuzzy_filter && !fuzzy_nosort && compl_leader.data != NULL && compl_leader.size > 0) {
|
||||
for (i = 0; i < compl_match_arraysize; i++) {
|
||||
compl_match_array[i].pum_idx = i;
|
||||
}
|
||||
|
@ -1493,6 +1493,7 @@ local options = {
|
||||
'noinsert',
|
||||
'noselect',
|
||||
'fuzzy',
|
||||
'nosort',
|
||||
},
|
||||
flags = true,
|
||||
deny_duplicates = true,
|
||||
@ -1537,6 +1538,10 @@ local options = {
|
||||
difference how completion candidates are reduced from the
|
||||
list of alternatives, but not how the candidates are
|
||||
collected (using different completion types).
|
||||
|
||||
nosort Disable sorting of completion candidates based on fuzzy
|
||||
scores when "fuzzy" is enabled. Candidates will appear
|
||||
in their original order.
|
||||
]=],
|
||||
full_name = 'completeopt',
|
||||
list = 'onecomma',
|
||||
|
@ -2778,7 +2778,7 @@ func Test_complete_fuzzy_match()
|
||||
if a:findstart
|
||||
return col(".")
|
||||
endif
|
||||
return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}]
|
||||
return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}, #{word: "你好吗"}, #{word: "我好"}]
|
||||
endfunc
|
||||
|
||||
new
|
||||
@ -2837,6 +2837,21 @@ func Test_complete_fuzzy_match()
|
||||
call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!')
|
||||
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
|
||||
set omnifunc=
|
||||
bw!
|
||||
|
Reference in New Issue
Block a user