mirror of
https://github.com/vim/vim
synced 2025-07-16 01:01:58 +00:00
patch 9.1.1416: completion limits not respected for fuzzy completions
Problem: completion limits not respected when using fuzzy completion (Maxim Kim) Solution: trim completion array (Girish Palya) fixes: #17379 closes: #17386 Signed-off-by: Girish Palya <girishji@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
0bc8709a63
commit
19ef6b0b4b
@ -1438,6 +1438,71 @@ trigger_complete_changed_event(int cur)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Trim compl_match_array to enforce max_matches per completion source.
|
||||
*
|
||||
* Note: This special-case trimming is a workaround because compl_match_array
|
||||
* becomes inconsistent with compl_first_match (list) after former is sorted by
|
||||
* fuzzy score. The two structures end up in different orders.
|
||||
* Ideally, compl_first_match list should have been sorted instead.
|
||||
*/
|
||||
static void
|
||||
trim_compl_match_array(void)
|
||||
{
|
||||
int i, src_idx, limit, new_size = 0, *match_counts = NULL;
|
||||
pumitem_T *trimmed = NULL;
|
||||
int trimmed_idx = 0;
|
||||
|
||||
// Count current matches per source.
|
||||
match_counts = ALLOC_CLEAR_MULT(int, cpt_sources_count);
|
||||
if (match_counts == NULL)
|
||||
return;
|
||||
for (i = 0; i < compl_match_arraysize; i++)
|
||||
{
|
||||
src_idx = compl_match_array[i].pum_cpt_source_idx;
|
||||
if (src_idx != -1)
|
||||
match_counts[src_idx]++;
|
||||
}
|
||||
|
||||
// Calculate size of trimmed array, respecting max_matches per source.
|
||||
for (i = 0; i < cpt_sources_count; i++)
|
||||
{
|
||||
limit = cpt_sources_array[i].max_matches;
|
||||
new_size += (limit > 0 && match_counts[i] > limit)
|
||||
? limit : match_counts[i];
|
||||
}
|
||||
|
||||
if (new_size == compl_match_arraysize)
|
||||
goto theend;
|
||||
|
||||
// Create trimmed array while enforcing per-source limits
|
||||
trimmed = ALLOC_CLEAR_MULT(pumitem_T, new_size);
|
||||
if (trimmed == NULL)
|
||||
goto theend;
|
||||
vim_memset(match_counts, 0, sizeof(int) * cpt_sources_count);
|
||||
for (i = 0; i < compl_match_arraysize; i++)
|
||||
{
|
||||
src_idx = compl_match_array[i].pum_cpt_source_idx;
|
||||
if (src_idx != -1)
|
||||
{
|
||||
limit = cpt_sources_array[src_idx].max_matches;
|
||||
if (limit <= 0 || match_counts[src_idx] < limit)
|
||||
{
|
||||
trimmed[trimmed_idx++] = compl_match_array[i];
|
||||
match_counts[src_idx]++;
|
||||
}
|
||||
}
|
||||
else
|
||||
trimmed[trimmed_idx++] = compl_match_array[i];
|
||||
}
|
||||
vim_free(compl_match_array);
|
||||
compl_match_array = trimmed;
|
||||
compl_match_arraysize = new_size;
|
||||
|
||||
theend:
|
||||
vim_free(match_counts);
|
||||
}
|
||||
|
||||
/*
|
||||
* pumitem qsort compare func
|
||||
*/
|
||||
@ -1477,7 +1542,7 @@ ins_compl_build_pum(void)
|
||||
int match_count = 0;
|
||||
int cur_source = -1;
|
||||
int max_matches_found = FALSE;
|
||||
int is_forward = compl_shows_dir_forward() && !fuzzy_filter;
|
||||
int is_forward = compl_shows_dir_forward();
|
||||
|
||||
// Need to build the popup menu list.
|
||||
compl_match_arraysize = 0;
|
||||
@ -1506,7 +1571,7 @@ ins_compl_build_pum(void)
|
||||
if (fuzzy_filter && compl_leader.string != NULL && compl_leader.length > 0)
|
||||
compl->cp_score = fuzzy_match_str(compl->cp_str.string, compl_leader.string);
|
||||
|
||||
if (is_forward && compl->cp_cpt_source_idx != -1)
|
||||
if (is_forward && !fuzzy_sort && compl->cp_cpt_source_idx != -1)
|
||||
{
|
||||
if (cur_source != compl->cp_cpt_source_idx)
|
||||
{
|
||||
@ -1579,7 +1644,7 @@ ins_compl_build_pum(void)
|
||||
shown_match_ok = TRUE;
|
||||
}
|
||||
}
|
||||
if (is_forward && compl->cp_cpt_source_idx != -1)
|
||||
if (is_forward && !fuzzy_sort && compl->cp_cpt_source_idx != -1)
|
||||
match_count++;
|
||||
i++;
|
||||
}
|
||||
@ -1627,6 +1692,7 @@ ins_compl_build_pum(void)
|
||||
compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
|
||||
compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
|
||||
compl_match_array[i].pum_score = compl->cp_score;
|
||||
compl_match_array[i].pum_cpt_source_idx = compl->cp_cpt_source_idx;
|
||||
compl_match_array[i].pum_user_abbr_hlattr = compl->cp_user_abbr_hlattr;
|
||||
compl_match_array[i].pum_user_kind_hlattr = compl->cp_user_kind_hlattr;
|
||||
compl_match_array[i++].pum_extra = compl->cp_text[CPT_MENU] != NULL
|
||||
@ -1646,6 +1712,9 @@ ins_compl_build_pum(void)
|
||||
shown_match_ok = TRUE;
|
||||
}
|
||||
|
||||
if (is_forward && fuzzy_sort && cpt_sources_array != NULL)
|
||||
trim_compl_match_array(); // Truncate by max_matches in 'cpt'
|
||||
|
||||
if (!shown_match_ok) // no displayed match at all
|
||||
cur = -1;
|
||||
|
||||
|
@ -4566,6 +4566,7 @@ typedef struct
|
||||
char_u *pum_info; // extra info
|
||||
int pum_score; // fuzzy match score
|
||||
int pum_idx; // index of item before sorting by score
|
||||
int pum_cpt_source_idx; // index of completion source in 'cpt'
|
||||
int pum_user_abbr_hlattr; // highlight attribute for abbr
|
||||
int pum_user_kind_hlattr; // highlight attribute for kind
|
||||
} pumitem_T;
|
||||
|
@ -4078,7 +4078,7 @@ func Test_complete_multiline_marks()
|
||||
endfunc
|
||||
|
||||
func Test_complete_match_count()
|
||||
func PrintMenuWords()
|
||||
func! PrintMenuWords()
|
||||
let info = complete_info(["selected", "matches"])
|
||||
call map(info.matches, {_, v -> v.word})
|
||||
return info
|
||||
@ -4198,8 +4198,50 @@ func Test_complete_match_count()
|
||||
call assert_equal(3, g:CallCount)
|
||||
bw!
|
||||
|
||||
" Test 'fuzzy' with max_items
|
||||
" XXX: Cannot use complete_info() since it is broken for 'fuzzy'
|
||||
new
|
||||
set completeopt=menu,noselect,fuzzy
|
||||
set complete=.
|
||||
call setline(1, ["abcd", "abac", "abdc"])
|
||||
execute "normal Goa\<c-n>c\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>\<c-n>\<c-n>\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
set complete=.^1
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
set complete=.^2
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>\<c-n>\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
set complete=.^3
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>\<c-n>\<c-n>\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
set complete=.^4
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>\<c-n>\<c-n>\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
|
||||
func! ComplFunc(findstart, base)
|
||||
if a:findstart
|
||||
return col(".")
|
||||
endif
|
||||
return ["abcde", "abacr"]
|
||||
endfunc
|
||||
|
||||
set complete=.,FComplFunc^1
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>"
|
||||
call assert_equal('abacr', getline(4))
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>\<c-n>\<c-n>\<c-n>\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
set complete=.^1,FComplFunc^1
|
||||
execute "normal Sa\<c-n>c\<c-n>\<c-n>\<c-n>\<c-n>"
|
||||
call assert_equal('abac', getline(4))
|
||||
bw!
|
||||
|
||||
set completeopt& complete&
|
||||
delfunc PrintMenuWords
|
||||
delfunc ComplFunc
|
||||
delfunc CompleteItemsSelect
|
||||
endfunc
|
||||
|
||||
func Test_complete_append_selected_match_default()
|
||||
@ -4321,7 +4363,7 @@ endfunc
|
||||
" Test 'nearest' flag of 'completeopt'
|
||||
func Test_nearest_cpt_option()
|
||||
|
||||
func PrintMenuWords()
|
||||
func! PrintMenuWords()
|
||||
let info = complete_info(["selected", "matches"])
|
||||
call map(info.matches, {_, v -> v.word})
|
||||
return info
|
||||
|
@ -709,6 +709,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1416,
|
||||
/**/
|
||||
1415,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user