diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2022-02-28 13:28:38 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-02-28 13:28:38 +0000 |
commit | 5de4c4372d4366bc85cb66efb3e373439b9471c5 (patch) | |
tree | 03a6aea2f9b80a06bc66775e4ea88168dd2d148d | |
parent | afd4ae35d66b2e7732eceb5ad9f6b4ece6b7c64c (diff) |
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)
-rw-r--r-- | src/buffer.c | 57 | ||||
-rw-r--r-- | src/cmdexpand.c | 193 | ||||
-rw-r--r-- | src/map.c | 201 | ||||
-rw-r--r-- | src/testdir/test_cmdline.vim | 18 | ||||
-rw-r--r-- | src/version.c | 2 |
5 files changed, 253 insertions, 218 deletions
diff --git a/src/buffer.c b/src/buffer.c index e580874906..8e68d94248 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 fee9f66099..f46045e6e1 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; } @@ -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 1e68f472e2..c354fa1023 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 9c9ddeb311..9ba8bb9bbb 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, |