diff options
-rw-r--r-- | runtime/doc/options.txt | 4 | ||||
-rw-r--r-- | runtime/lua/vim/_meta/options.lua | 4 | ||||
-rw-r--r-- | src/nvim/insexpand.c | 19 | ||||
-rw-r--r-- | src/nvim/options.lua | 5 | ||||
-rw-r--r-- | test/old/testdir/test_ins_complete.vim | 22 |
5 files changed, 45 insertions, 9 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 8d171183d6..1f19db5eb9 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -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 diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 107b1ffdfb..f0f0d1a768 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -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 diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index a5f5a4eda3..8eb1a49e7d 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -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_filter = (cur_cot_flags & kOptCotFlagFuzzy) != 0; + bool fuzzy_sort = fuzzy_filter && !(cur_cot_flags & kOptCotFlagNosort); 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_sort && 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_sort && 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_sort && compl_leader.data != NULL && compl_leader.size > 0) { for (i = 0; i < compl_match_arraysize; i++) { compl_match_array[i].pum_idx = i; } diff --git a/src/nvim/options.lua b/src/nvim/options.lua index ee8034a871..c6f5221c8b 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -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', diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim index f1ff45ff90..1c63e8f4cc 100644 --- a/test/old/testdir/test_ins_complete.vim +++ b/test/old/testdir/test_ins_complete.vim @@ -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,26 @@ 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) + + " "nosort" shouldn't enable fuzzy filtering when "fuzzy" isn't present. + set cot=menuone,noinsert,nosort + call feedkeys("S\<C-x>\<C-o>fooB\<C-Y>", 'tx') + call assert_equal('fooBaz', getline('.')) + " clean up set omnifunc= bw! |