summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2022-02-28 13:28:38 +0000
committerBram Moolenaar <Bram@vim.org>2022-02-28 13:28:38 +0000
commit5de4c4372d4366bc85cb66efb3e373439b9471c5 (patch)
tree03a6aea2f9b80a06bc66775e4ea88168dd2d148d /src
parentafd4ae35d66b2e7732eceb5ad9f6b4ece6b7c64c (diff)
downloadvim-git-5de4c4372d4366bc85cb66efb3e373439b9471c5.tar.gz
patch 8.2.4483: command completion makes two rounds to collect matchesv8.2.4483
Problem: Command completion makes two rounds to collect matches. Solution: Use a growarray to collect matches. (Yegappan Lakshmanan, closes #9860)
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c57
-rw-r--r--src/cmdexpand.c193
-rw-r--r--src/map.c201
-rw-r--r--src/testdir/test_cmdline.vim18
-rw-r--r--src/version.c2
5 files changed, 253 insertions, 218 deletions
diff --git a/src/buffer.c b/src/buffer.c
index e58087490..8e68d9424 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2814,38 +2814,39 @@ ExpandBufnames(
}
}
- if (p != NULL)
+ if (p == NULL)
+ continue;
+
+ if (round == 1)
{
- if (round == 1)
- ++count;
- else
- {
- if (options & WILD_HOME_REPLACE)
- p = home_replace_save(buf, p);
- else
- p = vim_strsave(p);
+ ++count;
+ continue;
+ }
- if (!fuzzy)
- {
+ if (options & WILD_HOME_REPLACE)
+ p = home_replace_save(buf, p);
+ else
+ p = vim_strsave(p);
+
+ if (!fuzzy)
+ {
#ifdef FEAT_VIMINFO
- if (matches != NULL)
- {
- matches[count].buf = buf;
- matches[count].match = p;
- count++;
- }
- else
-#endif
- (*file)[count++] = p;
- }
- else
- {
- fuzmatch[count].idx = count;
- fuzmatch[count].str = p;
- fuzmatch[count].score = score;
- count++;
- }
+ if (matches != NULL)
+ {
+ matches[count].buf = buf;
+ matches[count].match = p;
+ count++;
}
+ else
+#endif
+ (*file)[count++] = p;
+ }
+ else
+ {
+ fuzmatch[count].idx = count;
+ fuzmatch[count].str = p;
+ fuzmatch[count].score = score;
+ count++;
}
}
if (count == 0) // no match found, break here
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index fee9f6609..f46045e6e 100644
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -2633,116 +2633,134 @@ ExpandGeneric(
int escaped)
{
int i;
- int count = 0;
- int round;
+ garray_T ga;
char_u *str;
fuzmatch_str_T *fuzmatch = NULL;
- int score = 0;
+ int score = 0;
int fuzzy;
- int funcsort = FALSE;
int match;
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);
- if (str == NULL) // end of list
- break;
- if (*str == NUL) // skip empty strings
- continue;
+ str = (*func)(xp, i);
+ if (str == NULL) // end of list
+ break;
+ if (*str == NUL) // skip empty strings
+ continue;
+ if (xp->xp_pattern[0] != NUL)
+ {
if (!fuzzy)
- match = vim_regexec(regmatch, str, (colnr_T)0);
+ match = vim_regexec(regmatch, str, (colnr_T)0);
else
{
score = fuzzy_match_str(str, pat);
match = (score != 0);
}
+ }
+ else
+ match = TRUE;
- if (!match)
- continue;
+ if (!match)
+ continue;
- if (round)
- {
- if (escaped)
- str = vim_strsave_escaped(str, (char_u *)" \t\\.");
- else
- str = vim_strsave(str);
- if (str == NULL)
- {
- if (fuzzy)
- fuzmatch_str_free(fuzmatch, count);
- else if (count > 0)
- FreeWild(count, *matches);
- *numMatches = 0;
- *matches = NULL;
- return FAIL;
- }
- if (fuzzy)
- {
- fuzmatch[count].idx = count;
- fuzmatch[count].str = str;
- fuzmatch[count].score = score;
- }
- else
- (*matches)[count] = str;
-# ifdef FEAT_MENU
- if (func == get_menu_names && str != NULL)
- {
- // test for separator added by get_menu_names()
- str += STRLEN(str) - 1;
- if (*str == '\001')
- *str = '.';
- }
-# endif
- }
- ++count;
- }
- if (round == 0)
+ if (escaped)
+ str = vim_strsave_escaped(str, (char_u *)" \t\\.");
+ else
+ str = vim_strsave(str);
+ if (str == NULL)
{
- 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)))
+ if (!fuzzy)
{
- *numMatches = 0;
- *matches = NULL;
+ ga_clear_strings(&ga);
return FAIL;
}
- *numMatches = count;
- count = 0;
+
+ 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)
+ {
+ fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
+ fuzmatch->idx = ga.ga_len;
+ fuzmatch->str = str;
+ fuzmatch->score = score;
+ }
+ else
+ ((char_u **)ga.ga_data)[ga.ga_len] = str;
+
+# ifdef FEAT_MENU
+ if (func == get_menu_names)
+ {
+ // test for separator added by get_menu_names()
+ str += STRLEN(str) - 1;
+ if (*str == '\001')
+ *str = '.';
+ }
+# endif
+
+ ++ga.ga_len;
}
+ if (ga.ga_len == 0)
+ return OK;
+
// 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
|| 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 (!fuzzy)
- qsort((void *)*matches, (size_t)*numMatches, sizeof(char_u *),
+ qsort((void *)ga.ga_data, (size_t)ga.ga_len, sizeof(char_u *),
sort_func_compare);
- }
else
- {
- if (!fuzzy)
- sort_strings(*matches, *numMatches);
- }
+ sort_strings((char_u **)ga.ga_data, ga.ga_len);
+ }
+
+ if (!fuzzy)
+ {
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
+ }
+ else
+ {
+ int funcsort = FALSE;
+
+ 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)
@@ -2751,10 +2769,6 @@ ExpandGeneric(
reset_expand_highlight();
#endif
- if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
- funcsort) == FAIL)
- return FAIL;
-
return OK;
}
@@ -2990,12 +3004,11 @@ ExpandUserDefined(
int fuzzy;
int match;
int score;
- int count = 0;
fuzzy = cmdline_fuzzy_complete(pat);
-
*matches = NULL;
*numMatches = 0;
+
retstr = call_user_expand_func(call_func_retstr, xp);
if (retstr == NULL)
return FAIL;
@@ -3013,7 +3026,7 @@ ExpandUserDefined(
keep = *e;
*e = NUL;
- if (xp->xp_pattern[0] || fuzzy)
+ if (xp->xp_pattern[0] != NUL)
{
if (!fuzzy)
match = vim_regexec(regmatch, s, (colnr_T)0);
@@ -3038,12 +3051,11 @@ ExpandUserDefined(
{
fuzmatch_str_T *fuzmatch =
&((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->score = score;
}
++ga.ga_len;
- count++;
}
if (*e != NUL)
@@ -3051,6 +3063,9 @@ ExpandUserDefined(
}
vim_free(retstr);
+ if (ga.ga_len == 0)
+ return OK;
+
if (!fuzzy)
{
*matches = ga.ga_data;
@@ -3058,10 +3073,10 @@ ExpandUserDefined(
}
else
{
- if (fuzzymatches_to_strmatches(ga.ga_data, matches, count,
- FALSE) == FAIL)
+ if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
+ FALSE) == FAIL)
return FAIL;
- *numMatches = count;
+ *numMatches = ga.ga_len;
}
return OK;
}
diff --git a/src/map.c b/src/map.c
index 594c934d2..d99a84fc3 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1263,15 +1263,15 @@ ExpandMappings(
char_u ***matches)
{
mapblock_T *mp;
+ garray_T ga;
int hash;
int count;
- int round;
char_u *p;
int i;
int fuzzy;
int match;
int score;
- fuzmatch_str_T *fuzmatch = NULL;
+ fuzmatch_str_T *fuzmatch;
fuzzy = cmdline_fuzzy_complete(pat);
@@ -1280,32 +1280,78 @@ ExpandMappings(
*numMatches = 0; // return values in case of FAIL
*matches = NULL;
- // round == 1: Count the matches.
- // round == 2: Build the array to keep the matches.
- for (round = 1; round <= 2; ++round)
- {
- count = 0;
+ if (!fuzzy)
+ ga_init2(&ga, sizeof(char *), 3);
+ else
+ ga_init2(&ga, sizeof(fuzmatch_str_T), 3);
- // First search in map modifier arguments
- for (i = 0; i < 7; ++i)
- {
- if (i == 0)
- p = (char_u *)"<silent>";
- else if (i == 1)
- p = (char_u *)"<unique>";
+ // First search in map modifier arguments
+ for (i = 0; i < 7; ++i)
+ {
+ if (i == 0)
+ p = (char_u *)"<silent>";
+ else if (i == 1)
+ p = (char_u *)"<unique>";
#ifdef FEAT_EVAL
- else if (i == 2)
- p = (char_u *)"<script>";
- else if (i == 3)
- p = (char_u *)"<expr>";
+ else if (i == 2)
+ p = (char_u *)"<script>";
+ else if (i == 3)
+ p = (char_u *)"<expr>";
#endif
- else if (i == 4 && !expand_buffer)
- p = (char_u *)"<buffer>";
- else if (i == 5)
- p = (char_u *)"<nowait>";
- else if (i == 6)
- p = (char_u *)"<special>";
- else
+ else if (i == 4 && !expand_buffer)
+ p = (char_u *)"<buffer>";
+ else if (i == 5)
+ p = (char_u *)"<nowait>";
+ else if (i == 6)
+ p = (char_u *)"<special>";
+ else
+ continue;
+
+ if (!fuzzy)
+ match = vim_regexec(regmatch, p, (colnr_T)0);
+ else
+ {
+ score = fuzzy_match_str(p, pat);
+ match = (score != 0);
+ }
+
+ if (!match)
+ continue;
+
+ if (ga_grow(&ga, 1) == FAIL)
+ break;
+
+ if (fuzzy)
+ {
+ fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
+ fuzmatch->idx = ga.ga_len;
+ fuzmatch->str = vim_strsave(p);
+ fuzmatch->score = score;
+ }
+ else
+ ((char_u **)ga.ga_data)[ga.ga_len] = vim_strsave(p);
+ ++ga.ga_len;
+ }
+
+ for (hash = 0; hash < 256; ++hash)
+ {
+ if (expand_isabbrev)
+ {
+ if (hash > 0) // only one abbrev list
+ break; // for (hash)
+ mp = first_abbr;
+ }
+ else if (expand_buffer)
+ mp = curbuf->b_maphash[hash];
+ else
+ mp = maphash[hash];
+ for (; mp; mp = mp->m_next)
+ {
+ if (!(mp->m_mode & expand_mapmodes))
+ continue;
+
+ p = translate_mapping(mp->m_keys);
+ if (p == NULL)
continue;
if (!fuzzy)
@@ -1317,95 +1363,48 @@ ExpandMappings(
}
if (!match)
- continue;
-
- if (round == 2)
{
- if (fuzzy)
- {
- fuzmatch[count].idx = count;
- fuzmatch[count].str = vim_strsave(p);
- fuzmatch[count].score = score;
- }
- else
- (*matches)[count] = vim_strsave(p);
+ vim_free(p);
+ continue;
}
- ++count;
- }
- for (hash = 0; hash < 256; ++hash)
- {
- if (expand_isabbrev)
+ if (ga_grow(&ga, 1) == FAIL)
{
- if (hash > 0) // only one abbrev list
- break; // for (hash)
- mp = first_abbr;
+ vim_free(p);
+ break;
}
- else if (expand_buffer)
- mp = curbuf->b_maphash[hash];
- else
- mp = maphash[hash];
- for (; mp; mp = mp->m_next)
- {
- if (mp->m_mode & expand_mapmodes)
- {
- p = translate_mapping(mp->m_keys);
- if (p != NULL)
- {
- if (!fuzzy)
- match = vim_regexec(regmatch, p, (colnr_T)0);
- else
- {
- score = fuzzy_match_str(p, pat);
- match = (score != 0);
- }
- if (match)
- {
- if (round == 2)
- {
- if (fuzzy)
- {
- fuzmatch[count].idx = count;
- fuzmatch[count].str = p;
- fuzmatch[count].score = score;
- }
- else
- (*matches)[count] = p;
- p = NULL;
- }
- ++count;
- }
- }
- vim_free(p);
- }
- } // for (mp)
- } // for (hash)
-
- if (count == 0) // no match found
- break; // for (round)
-
- if (round == 1)
- {
if (fuzzy)
{
- fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
- if (fuzmatch == NULL)
- return FAIL;
+ fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
+ fuzmatch->idx = ga.ga_len;
+ fuzmatch->str = p;
+ fuzmatch->score = score;
}
else
- {
- *matches = ALLOC_MULT(char_u *, count);
- if (*matches == NULL)
- return FAIL;
- }
- }
- } // for (round)
+ ((char_u **)ga.ga_data)[ga.ga_len] = p;
- if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
- FALSE) == FAIL)
+ ++ga.ga_len;
+ } // for (mp)
+ } // for (hash)
+
+ if (ga.ga_len == 0)
return FAIL;
+ if (!fuzzy)
+ {
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
+ }
+ else
+ {
+ if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
+ FALSE) == FAIL)
+ return FAIL;
+ *numMatches = ga.ga_len;
+ }
+
+ count = *numMatches;
if (count > 1)
{
char_u **ptr1;
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 1e68f472e..c354fa102 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -2661,6 +2661,24 @@ func Test_fuzzy_completion_userdefined_func()
set wildoptions&
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
func Test_fuzzy_completion_userdefined_cmd()
set wildoptions&
diff --git a/src/version.c b/src/version.c
index 9c9ddeb31..9ba8bb9bb 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 4483,
+/**/
4482,
/**/
4481,