Patch 8.2.4483
Problem:    Command completion makes two rounds to collect matches.
Solution:   Use a growarray to collect matches. (Yegappan Lakshmanan,
            closes #9860)
Files:      src/buffer.c, src/cmdexpand.c, src/map.c,
            src/testdir/test_cmdline.vim


*** ../vim-8.2.4482/src/buffer.c        2022-02-24 13:28:36.570222354 +0000
--- src/buffer.c        2022-02-28 13:20:51.285350690 +0000
***************
*** 2814,2851 ****
                    }
                }
  
!               if (p != NULL)
                {
!                   if (round == 1)
!                       ++count;
!                   else
!                   {
!                       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 (count == 0)     // no match found, break here
--- 2814,2852 ----
                    }
                }
  
!               if (p == NULL)
!                   continue;
! 
!               if (round == 1)
                {
!                   ++count;
!                   continue;
!               }
! 
!               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 (count == 0)     // no match found, break here
*** ../vim-8.2.4482/src/cmdexpand.c     2022-02-27 21:03:17.937471865 +0000
--- src/cmdexpand.c     2022-02-28 13:25:48.676936485 +0000
***************
*** 2633,2748 ****
      int               escaped)
  {
      int               i;
!     int               count = 0;
!     int               round;
      char_u    *str;
      fuzmatch_str_T    *fuzmatch = NULL;
!     int                       score = 0;
      int               fuzzy;
-     int               funcsort = FALSE;
      int               match;
  
      fuzzy = cmdline_fuzzy_complete(pat);
  
!     // 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)
!       {
!           str = (*func)(xp, i);
!           if (str == NULL)        // end of list
!               break;
!           if (*str == NUL)        // skip empty strings
!               continue;
  
            if (!fuzzy)
!              match = vim_regexec(regmatch, str, (colnr_T)0);
            else
            {
                score = fuzzy_match_str(str, pat);
                match = (score != 0);
            }
  
!           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 (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;
        }
      }
  
      // Sort the results.  Keep menu's in the specified order.
!     if (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 *),
                                                           sort_func_compare);
-       }
        else
!       {
!           if (!fuzzy)
!               sort_strings(*matches, *numMatches);
!       }
      }
  
  #if defined(FEAT_SYN_HL)
--- 2633,2766 ----
      int               escaped)
  {
      int               i;
!     garray_T  ga;
      char_u    *str;
      fuzmatch_str_T    *fuzmatch = NULL;
!     int               score = 0;
      int               fuzzy;
      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);
  
!     for (i = 0; ; ++i)
      {
!       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);
            else
            {
                score = fuzzy_match_str(str, pat);
                match = (score != 0);
            }
+       }
+       else
+           match = TRUE;
  
!       if (!match)
!           continue;
  
!       if (escaped)
!           str = vim_strsave_escaped(str, (char_u *)" \t\\.");
!       else
!           str = vim_strsave(str);
!       if (str == NULL)
        {
!           if (!fuzzy)
            {
!               ga_clear_strings(&ga);
                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)
+       {
+           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 (!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.
!           qsort((void *)ga.ga_data, (size_t)ga.ga_len, sizeof(char_u *),
                                                           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
!     {
!       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,2760 ****
      reset_expand_highlight();
  #endif
  
-     if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
-                                                       funcsort) == FAIL)
-       return FAIL;
- 
      return OK;
  }
  
--- 2769,2774 ----
***************
*** 2990,3001 ****
      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;
--- 3004,3014 ----
      int               fuzzy;
      int               match;
      int               score;
  
      fuzzy = cmdline_fuzzy_complete(pat);
      *matches = NULL;
      *numMatches = 0;
+ 
      retstr = call_user_expand_func(call_func_retstr, xp);
      if (retstr == NULL)
        return FAIL;
***************
*** 3013,3019 ****
        keep = *e;
        *e = NUL;
  
!       if (xp->xp_pattern[0] || fuzzy)
        {
            if (!fuzzy)
                match = vim_regexec(regmatch, s, (colnr_T)0);
--- 3026,3032 ----
        keep = *e;
        *e = NUL;
  
!       if (xp->xp_pattern[0] != NUL)
        {
            if (!fuzzy)
                match = vim_regexec(regmatch, s, (colnr_T)0);
***************
*** 3038,3049 ****
            {
                fuzmatch_str_T  *fuzmatch =
                                &((fuzmatch_str_T  *)ga.ga_data)[ga.ga_len];
!               fuzmatch->idx = count;
                fuzmatch->str = vim_strnsave(s, e - s);
                fuzmatch->score = score;
            }
            ++ga.ga_len;
-           count++;
        }
  
        if (*e != NUL)
--- 3051,3061 ----
            {
                fuzmatch_str_T  *fuzmatch =
                                &((fuzmatch_str_T  *)ga.ga_data)[ga.ga_len];
!               fuzmatch->idx = ga.ga_len;
                fuzmatch->str = vim_strnsave(s, e - s);
                fuzmatch->score = score;
            }
            ++ga.ga_len;
        }
  
        if (*e != NUL)
***************
*** 3051,3056 ****
--- 3063,3071 ----
      }
      vim_free(retstr);
  
+     if (ga.ga_len == 0)
+       return OK;
+ 
      if (!fuzzy)
      {
        *matches = ga.ga_data;
***************
*** 3058,3067 ****
      }
      else
      {
!       if (fuzzymatches_to_strmatches(ga.ga_data, matches, count,
!                                                       FALSE) == FAIL)
            return FAIL;
!       *numMatches = count;
      }
      return OK;
  }
--- 3073,3082 ----
      }
      else
      {
!       if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
!                                                               FALSE) == FAIL)
            return FAIL;
!       *numMatches = ga.ga_len;
      }
      return OK;
  }
*** ../vim-8.2.4482/src/map.c   2022-02-27 12:07:26.666960401 +0000
--- src/map.c   2022-02-28 13:20:51.289350682 +0000
***************
*** 1263,1277 ****
      char_u    ***matches)
  {
      mapblock_T        *mp;
      int               hash;
      int               count;
-     int               round;
      char_u    *p;
      int               i;
      int               fuzzy;
      int               match;
      int               score;
!     fuzmatch_str_T  *fuzmatch = NULL;
  
      fuzzy = cmdline_fuzzy_complete(pat);
  
--- 1263,1277 ----
      char_u    ***matches)
  {
      mapblock_T        *mp;
+     garray_T  ga;
      int               hash;
      int               count;
      char_u    *p;
      int               i;
      int               fuzzy;
      int               match;
      int               score;
!     fuzmatch_str_T  *fuzmatch;
  
      fuzzy = cmdline_fuzzy_complete(pat);
  
***************
*** 1280,1311 ****
      *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;
  
!       // 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>";
  #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
                continue;
  
            if (!fuzzy)
--- 1280,1357 ----
      *numMatches = 0;              // return values in case of FAIL
      *matches = NULL;
  
!     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>";
  #ifdef FEAT_EVAL
!       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
!           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,1411 ****
            }
  
            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);
            }
-           ++count;
-       }
  
!       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)
-               {
-                   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;
            }
            else
!           {
!               *matches = ALLOC_MULT(char_u *, count);
!               if (*matches == NULL)
!                   return FAIL;
!           }
!       }
!     } // for (round)
  
!     if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
!                                                       FALSE) == FAIL)
        return FAIL;
  
      if (count > 1)
      {
        char_u  **ptr1;
--- 1363,1410 ----
            }
  
            if (!match)
            {
!               vim_free(p);
!               continue;
            }
  
!           if (ga_grow(&ga, 1) == FAIL)
            {
!               vim_free(p);
!               break;
            }
  
            if (fuzzy)
            {
!               fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
!               fuzmatch->idx = ga.ga_len;
!               fuzmatch->str = p;
!               fuzmatch->score = score;
            }
            else
!               ((char_u **)ga.ga_data)[ga.ga_len] = p;
  
!           ++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;
*** ../vim-8.2.4482/src/testdir/test_cmdline.vim        2022-02-27 
21:03:17.937471865 +0000
--- src/testdir/test_cmdline.vim        2022-02-28 13:20:51.289350682 +0000
***************
*** 2661,2666 ****
--- 2661,2684 ----
    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&
*** ../vim-8.2.4482/src/version.c       2022-02-27 21:03:17.937471865 +0000
--- src/version.c       2022-02-28 13:22:51.085181069 +0000
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     4483,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
122. You ask if the Netaholics Anonymous t-shirt you ordered can be
     sent to you via e-mail.

 /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220228133052.1AD291C14BE%40moolenaar.net.

Reply via email to