From 5de4c4372d4366bc85cb66efb3e373439b9471c5 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Mon, 28 Feb 2022 13:28:38 +0000 Subject: 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) --- src/cmdexpand.c | 193 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 104 insertions(+), 89 deletions(-) (limited to 'src/cmdexpand.c') 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) - { // 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) + // 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; } -- cgit v1.2.3