1
0
forked from aniani/vim

patch 8.2.4483: command completion makes two rounds to collect matches

Problem:    Command completion makes two rounds to collect matches.
Solution:   Use a growarray to collect matches. (Yegappan Lakshmanan,
            closes #9860)
This commit is contained in:
Yegappan Lakshmanan
2022-02-28 13:28:38 +00:00
committed by Bram Moolenaar
parent afd4ae35d6
commit 5de4c4372d
5 changed files with 256 additions and 221 deletions

View File

@@ -2814,12 +2814,15 @@ ExpandBufnames(
} }
} }
if (p != NULL) if (p == NULL)
{ continue;
if (round == 1) if (round == 1)
++count;
else
{ {
++count;
continue;
}
if (options & WILD_HOME_REPLACE) if (options & WILD_HOME_REPLACE)
p = home_replace_save(buf, p); p = home_replace_save(buf, p);
else else
@@ -2846,8 +2849,6 @@ ExpandBufnames(
count++; count++;
} }
} }
}
}
if (count == 0) // no match found, break here if (count == 0) // no match found, break here
break; break;
if (round == 1) if (round == 1)

View File

@@ -2633,22 +2633,22 @@ ExpandGeneric(
int escaped) int escaped)
{ {
int i; int i;
int count = 0; garray_T ga;
int round;
char_u *str; char_u *str;
fuzmatch_str_T *fuzmatch = NULL; fuzmatch_str_T *fuzmatch = NULL;
int score = 0; int score = 0;
int fuzzy; int fuzzy;
int funcsort = FALSE;
int match; int match;
fuzzy = cmdline_fuzzy_complete(pat); fuzzy = cmdline_fuzzy_complete(pat);
*matches = NULL;
*numMatches = 0;
if (!fuzzy)
ga_init2(&ga, sizeof(char *), 30);
else
ga_init2(&ga, sizeof(fuzmatch_str_T), 30);
// do this loop twice:
// round == 0: count the number of matching names
// round == 1: copy the matching names into allocated memory
for (round = 0; round <= 1; ++round)
{
for (i = 0; ; ++i) for (i = 0; ; ++i)
{ {
str = (*func)(xp, i); str = (*func)(xp, i);
@@ -2657,6 +2657,8 @@ ExpandGeneric(
if (*str == NUL) // skip empty strings if (*str == NUL) // skip empty strings
continue; continue;
if (xp->xp_pattern[0] != NUL)
{
if (!fuzzy) if (!fuzzy)
match = vim_regexec(regmatch, str, (colnr_T)0); match = vim_regexec(regmatch, str, (colnr_T)0);
else else
@@ -2664,36 +2666,52 @@ ExpandGeneric(
score = fuzzy_match_str(str, pat); score = fuzzy_match_str(str, pat);
match = (score != 0); match = (score != 0);
} }
}
else
match = TRUE;
if (!match) if (!match)
continue; continue;
if (round)
{
if (escaped) if (escaped)
str = vim_strsave_escaped(str, (char_u *)" \t\\."); str = vim_strsave_escaped(str, (char_u *)" \t\\.");
else else
str = vim_strsave(str); str = vim_strsave(str);
if (str == NULL) if (str == NULL)
{ {
if (fuzzy) if (!fuzzy)
fuzmatch_str_free(fuzmatch, count); {
else if (count > 0) ga_clear_strings(&ga);
FreeWild(count, *matches);
*numMatches = 0;
*matches = NULL;
return FAIL; return FAIL;
} }
for (i = 0; i < ga.ga_len; ++i)
{
fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[i];
vim_free(fuzmatch->str);
}
ga_clear(&ga);
return FAIL;
}
if (ga_grow(&ga, 1) == FAIL)
{
vim_free(str);
break;
}
if (fuzzy) if (fuzzy)
{ {
fuzmatch[count].idx = count; fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch[count].str = str; fuzmatch->idx = ga.ga_len;
fuzmatch[count].score = score; fuzmatch->str = str;
fuzmatch->score = score;
} }
else else
(*matches)[count] = str; ((char_u **)ga.ga_data)[ga.ga_len] = str;
# ifdef FEAT_MENU # ifdef FEAT_MENU
if (func == get_menu_names && str != NULL) if (func == get_menu_names)
{ {
// test for separator added by get_menu_names() // test for separator added by get_menu_names()
str += STRLEN(str) - 1; str += STRLEN(str) - 1;
@@ -2701,48 +2719,48 @@ ExpandGeneric(
*str = '.'; *str = '.';
} }
# endif # endif
}
++count; ++ga.ga_len;
}
if (round == 0)
{
if (count == 0)
return OK;
if (fuzzy)
fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
else
*matches = ALLOC_MULT(char_u *, count);
if ((!fuzzy && (*matches == NULL))
|| (fuzzy && (fuzmatch == NULL)))
{
*numMatches = 0;
*matches = NULL;
return FAIL;
}
*numMatches = count;
count = 0;
}
} }
if (ga.ga_len == 0)
return OK;
// Sort the results. Keep menu's in the specified order. // Sort the results. Keep menu's in the specified order.
if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) if (!fuzzy && xp->xp_context != EXPAND_MENUNAMES
&& xp->xp_context != EXPAND_MENUS)
{ {
if (xp->xp_context == EXPAND_EXPRESSION if (xp->xp_context == EXPAND_EXPRESSION
|| xp->xp_context == EXPAND_FUNCTIONS || xp->xp_context == EXPAND_FUNCTIONS
|| xp->xp_context == EXPAND_USER_FUNC || xp->xp_context == EXPAND_USER_FUNC
|| xp->xp_context == EXPAND_DISASSEMBLE) || xp->xp_context == EXPAND_DISASSEMBLE)
{
// <SNR> functions should be sorted to the end. // <SNR> functions should be sorted to the end.
funcsort = TRUE; qsort((void *)ga.ga_data, (size_t)ga.ga_len, sizeof(char_u *),
if (!fuzzy)
qsort((void *)*matches, (size_t)*numMatches, sizeof(char_u *),
sort_func_compare); sort_func_compare);
else
sort_strings((char_u **)ga.ga_data, ga.ga_len);
}
if (!fuzzy)
{
*matches = ga.ga_data;
*numMatches = ga.ga_len;
} }
else else
{ {
if (!fuzzy) int funcsort = FALSE;
sort_strings(*matches, *numMatches);
} if (xp->xp_context == EXPAND_EXPRESSION
|| xp->xp_context == EXPAND_FUNCTIONS
|| xp->xp_context == EXPAND_USER_FUNC
|| xp->xp_context == EXPAND_DISASSEMBLE)
// <SNR> functions should be sorted to the end.
funcsort = TRUE;
if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
funcsort) == FAIL)
return FAIL;
*numMatches = ga.ga_len;
} }
#if defined(FEAT_SYN_HL) #if defined(FEAT_SYN_HL)
@@ -2751,10 +2769,6 @@ ExpandGeneric(
reset_expand_highlight(); reset_expand_highlight();
#endif #endif
if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
funcsort) == FAIL)
return FAIL;
return OK; return OK;
} }
@@ -2990,12 +3004,11 @@ ExpandUserDefined(
int fuzzy; int fuzzy;
int match; int match;
int score; int score;
int count = 0;
fuzzy = cmdline_fuzzy_complete(pat); fuzzy = cmdline_fuzzy_complete(pat);
*matches = NULL; *matches = NULL;
*numMatches = 0; *numMatches = 0;
retstr = call_user_expand_func(call_func_retstr, xp); retstr = call_user_expand_func(call_func_retstr, xp);
if (retstr == NULL) if (retstr == NULL)
return FAIL; return FAIL;
@@ -3013,7 +3026,7 @@ ExpandUserDefined(
keep = *e; keep = *e;
*e = NUL; *e = NUL;
if (xp->xp_pattern[0] || fuzzy) if (xp->xp_pattern[0] != NUL)
{ {
if (!fuzzy) if (!fuzzy)
match = vim_regexec(regmatch, s, (colnr_T)0); match = vim_regexec(regmatch, s, (colnr_T)0);
@@ -3038,12 +3051,11 @@ ExpandUserDefined(
{ {
fuzmatch_str_T *fuzmatch = fuzmatch_str_T *fuzmatch =
&((fuzmatch_str_T *)ga.ga_data)[ga.ga_len]; &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch->idx = count; fuzmatch->idx = ga.ga_len;
fuzmatch->str = vim_strnsave(s, e - s); fuzmatch->str = vim_strnsave(s, e - s);
fuzmatch->score = score; fuzmatch->score = score;
} }
++ga.ga_len; ++ga.ga_len;
count++;
} }
if (*e != NUL) if (*e != NUL)
@@ -3051,6 +3063,9 @@ ExpandUserDefined(
} }
vim_free(retstr); vim_free(retstr);
if (ga.ga_len == 0)
return OK;
if (!fuzzy) if (!fuzzy)
{ {
*matches = ga.ga_data; *matches = ga.ga_data;
@@ -3058,10 +3073,10 @@ ExpandUserDefined(
} }
else else
{ {
if (fuzzymatches_to_strmatches(ga.ga_data, matches, count, if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
FALSE) == FAIL) FALSE) == FAIL)
return FAIL; return FAIL;
*numMatches = count; *numMatches = ga.ga_len;
} }
return OK; return OK;
} }

View File

@@ -1263,15 +1263,15 @@ ExpandMappings(
char_u ***matches) char_u ***matches)
{ {
mapblock_T *mp; mapblock_T *mp;
garray_T ga;
int hash; int hash;
int count; int count;
int round;
char_u *p; char_u *p;
int i; int i;
int fuzzy; int fuzzy;
int match; int match;
int score; int score;
fuzmatch_str_T *fuzmatch = NULL; fuzmatch_str_T *fuzmatch;
fuzzy = cmdline_fuzzy_complete(pat); fuzzy = cmdline_fuzzy_complete(pat);
@@ -1280,11 +1280,10 @@ ExpandMappings(
*numMatches = 0; // return values in case of FAIL *numMatches = 0; // return values in case of FAIL
*matches = NULL; *matches = NULL;
// round == 1: Count the matches. if (!fuzzy)
// round == 2: Build the array to keep the matches. ga_init2(&ga, sizeof(char *), 3);
for (round = 1; round <= 2; ++round) else
{ ga_init2(&ga, sizeof(fuzmatch_str_T), 3);
count = 0;
// First search in map modifier arguments // First search in map modifier arguments
for (i = 0; i < 7; ++i) for (i = 0; i < 7; ++i)
@@ -1319,18 +1318,19 @@ ExpandMappings(
if (!match) if (!match)
continue; continue;
if (round == 2) if (ga_grow(&ga, 1) == FAIL)
{ break;
if (fuzzy) if (fuzzy)
{ {
fuzmatch[count].idx = count; fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch[count].str = vim_strsave(p); fuzmatch->idx = ga.ga_len;
fuzmatch[count].score = score; fuzmatch->str = vim_strsave(p);
fuzmatch->score = score;
} }
else else
(*matches)[count] = vim_strsave(p); ((char_u **)ga.ga_data)[ga.ga_len] = vim_strsave(p);
} ++ga.ga_len;
++count;
} }
for (hash = 0; hash < 256; ++hash) for (hash = 0; hash < 256; ++hash)
@@ -1347,11 +1347,13 @@ ExpandMappings(
mp = maphash[hash]; mp = maphash[hash];
for (; mp; mp = mp->m_next) for (; mp; mp = mp->m_next)
{ {
if (mp->m_mode & expand_mapmodes) if (!(mp->m_mode & expand_mapmodes))
{ continue;
p = translate_mapping(mp->m_keys); p = translate_mapping(mp->m_keys);
if (p != NULL) if (p == NULL)
{ continue;
if (!fuzzy) if (!fuzzy)
match = vim_regexec(regmatch, p, (colnr_T)0); match = vim_regexec(regmatch, p, (colnr_T)0);
else else
@@ -1360,52 +1362,49 @@ ExpandMappings(
match = (score != 0); match = (score != 0);
} }
if (match) if (!match)
{ {
if (round == 2) vim_free(p);
continue;
}
if (ga_grow(&ga, 1) == FAIL)
{ {
vim_free(p);
break;
}
if (fuzzy) if (fuzzy)
{ {
fuzmatch[count].idx = count; fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch[count].str = p; fuzmatch->idx = ga.ga_len;
fuzmatch[count].score = score; fuzmatch->str = p;
fuzmatch->score = score;
} }
else else
(*matches)[count] = p; ((char_u **)ga.ga_data)[ga.ga_len] = p;
p = NULL;
} ++ga.ga_len;
++count;
}
}
vim_free(p);
}
} // for (mp) } // for (mp)
} // for (hash) } // for (hash)
if (count == 0) // no match found if (ga.ga_len == 0)
break; // for (round)
if (round == 1)
{
if (fuzzy)
{
fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
if (fuzmatch == NULL)
return FAIL; return FAIL;
if (!fuzzy)
{
*matches = ga.ga_data;
*numMatches = ga.ga_len;
} }
else else
{ {
*matches = ALLOC_MULT(char_u *, count); if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
if (*matches == NULL)
return FAIL;
}
}
} // for (round)
if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
FALSE) == FAIL) FALSE) == FAIL)
return FAIL; return FAIL;
*numMatches = ga.ga_len;
}
count = *numMatches;
if (count > 1) if (count > 1)
{ {
char_u **ptr1; char_u **ptr1;

View File

@@ -2661,6 +2661,24 @@ func Test_fuzzy_completion_userdefined_func()
set wildoptions& set wildoptions&
endfunc endfunc
" <SNR> functions should be sorted to the end
func Test_fuzzy_completion_userdefined_snr_func()
func s:Sendmail()
endfunc
func SendSomemail()
endfunc
func S1e2n3dmail()
endfunc
set wildoptions=fuzzy
call feedkeys(":call sendmail\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call SendSomemail() S1e2n3dmail() '
\ .. expand("<SID>") .. 'Sendmail()', @:)
set wildoptions&
delfunc s:Sendmail
delfunc SendSomemail
delfunc S1e2n3dmail
endfunc
" user defined command name completion " user defined command name completion
func Test_fuzzy_completion_userdefined_cmd() func Test_fuzzy_completion_userdefined_cmd()
set wildoptions& set wildoptions&

View File

@@ -754,6 +754,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 */
/**/
4483,
/**/ /**/
4482, 4482,
/**/ /**/