Patch 8.2.1587
Problem:    Loop for handling keys for the command line is too long.
Solution:   Move wild menu handling to separate functions. (Yegappan
            Lakshmanan, closes #6856)
Files:      src/cmdexpand.c, src/proto/cmdexpand.pro, src/ex_getln.c


*** ../vim-8.2.1586/src/cmdexpand.c     2020-07-25 14:11:50.545128202 +0200
--- src/cmdexpand.c     2020-09-04 15:33:43.490037208 +0200
***************
*** 2614,2619 ****
--- 2614,2868 ----
      vim_free(buf);
  }
  
+ #ifdef FEAT_WILDMENU
+ 
+ /*
+  * Translate some keys pressed when 'wildmenu' is used.
+  */
+     int
+ wildmenu_translate_key(
+       cmdline_info_T  *cclp,
+       int             key,
+       expand_T        *xp,
+       int             did_wild_list)
+ {
+     int c = key;
+ 
+     if (did_wild_list && p_wmnu)
+     {
+       if (c == K_LEFT)
+           c = Ctrl_P;
+       else if (c == K_RIGHT)
+           c = Ctrl_N;
+     }
+     // Hitting CR after "emenu Name.": complete submenu
+     if (xp->xp_context == EXPAND_MENUNAMES && p_wmnu
+           && cclp->cmdpos > 1
+           && cclp->cmdbuff[cclp->cmdpos - 1] == '.'
+           && cclp->cmdbuff[cclp->cmdpos - 2] != '\\'
+           && (c == '\n' || c == '\r' || c == K_KENTER))
+       c = K_DOWN;
+ 
+     return c;
+ }
+ 
+ /*
+  * Delete characters on the command line, from "from" to the current
+  * position.
+  */
+     static void
+ cmdline_del(cmdline_info_T *cclp, int from)
+ {
+     mch_memmove(cclp->cmdbuff + from, cclp->cmdbuff + cclp->cmdpos,
+           (size_t)(cclp->cmdlen - cclp->cmdpos + 1));
+     cclp->cmdlen -= cclp->cmdpos - from;
+     cclp->cmdpos = from;
+ }
+ 
+ /*
+  * Handle a key pressed when wild menu is displayed
+  */
+     int
+ wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
+ {
+     int               c = key;
+     int               i;
+     int               j;
+ 
+     if (!p_wmnu)
+       return c;
+ 
+     // Special translations for 'wildmenu'
+     if (xp->xp_context == EXPAND_MENUNAMES)
+     {
+       // Hitting <Down> after "emenu Name.": complete submenu
+       if (c == K_DOWN && cclp->cmdpos > 0
+               && cclp->cmdbuff[cclp->cmdpos - 1] == '.')
+           c = p_wc;
+       else if (c == K_UP)
+       {
+           // Hitting <Up>: Remove one submenu name in front of the
+           // cursor
+           int found = FALSE;
+ 
+           j = (int)(xp->xp_pattern - cclp->cmdbuff);
+           i = 0;
+           while (--j > 0)
+           {
+               // check for start of menu name
+               if (cclp->cmdbuff[j] == ' '
+                       && cclp->cmdbuff[j - 1] != '\\')
+               {
+                   i = j + 1;
+                   break;
+               }
+               // check for start of submenu name
+               if (cclp->cmdbuff[j] == '.'
+                       && cclp->cmdbuff[j - 1] != '\\')
+               {
+                   if (found)
+                   {
+                       i = j + 1;
+                       break;
+                   }
+                   else
+                       found = TRUE;
+               }
+           }
+           if (i > 0)
+               cmdline_del(cclp, i);
+           c = p_wc;
+           xp->xp_context = EXPAND_NOTHING;
+       }
+     }
+     if ((xp->xp_context == EXPAND_FILES
+               || xp->xp_context == EXPAND_DIRECTORIES
+               || xp->xp_context == EXPAND_SHELLCMD))
+     {
+       char_u upseg[5];
+ 
+       upseg[0] = PATHSEP;
+       upseg[1] = '.';
+       upseg[2] = '.';
+       upseg[3] = PATHSEP;
+       upseg[4] = NUL;
+ 
+       if (c == K_DOWN
+               && cclp->cmdpos > 0
+               && cclp->cmdbuff[cclp->cmdpos - 1] == PATHSEP
+               && (cclp->cmdpos < 3
+                   || cclp->cmdbuff[cclp->cmdpos - 2] != '.'
+                   || cclp->cmdbuff[cclp->cmdpos - 3] != '.'))
+       {
+           // go down a directory
+           c = p_wc;
+       }
+       else if (STRNCMP(xp->xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN)
+       {
+           // If in a direct ancestor, strip off one ../ to go down
+           int found = FALSE;
+ 
+           j = cclp->cmdpos;
+           i = (int)(xp->xp_pattern - cclp->cmdbuff);
+           while (--j > i)
+           {
+               if (has_mbyte)
+                   j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j);
+               if (vim_ispathsep(cclp->cmdbuff[j]))
+               {
+                   found = TRUE;
+                   break;
+               }
+           }
+           if (found
+                   && cclp->cmdbuff[j - 1] == '.'
+                   && cclp->cmdbuff[j - 2] == '.'
+                   && (vim_ispathsep(cclp->cmdbuff[j - 3]) || j == i + 2))
+           {
+               cmdline_del(cclp, j - 2);
+               c = p_wc;
+           }
+       }
+       else if (c == K_UP)
+       {
+           // go up a directory
+           int found = FALSE;
+ 
+           j = cclp->cmdpos - 1;
+           i = (int)(xp->xp_pattern - cclp->cmdbuff);
+           while (--j > i)
+           {
+               if (has_mbyte)
+                   j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j);
+               if (vim_ispathsep(cclp->cmdbuff[j])
+ # ifdef BACKSLASH_IN_FILENAME
+                       && vim_strchr((char_u *)" *?[{`$%#",
+                           cclp->cmdbuff[j + 1]) == NULL
+ # endif
+                  )
+               {
+                   if (found)
+                   {
+                       i = j + 1;
+                       break;
+                   }
+                   else
+                       found = TRUE;
+               }
+           }
+ 
+           if (!found)
+               j = i;
+           else if (STRNCMP(cclp->cmdbuff + j, upseg, 4) == 0)
+               j += 4;
+           else if (STRNCMP(cclp->cmdbuff + j, upseg + 1, 3) == 0
+                   && j == i)
+               j += 3;
+           else
+               j = 0;
+           if (j > 0)
+           {
+               // TODO this is only for DOS/UNIX systems - need to put in
+               // machine-specific stuff here and in upseg init
+               cmdline_del(cclp, j);
+               put_on_cmdline(upseg + 1, 3, FALSE);
+           }
+           else if (cclp->cmdpos > i)
+               cmdline_del(cclp, i);
+ 
+           // Now complete in the new directory. Set KeyTyped in case the
+           // Up key came from a mapping.
+           c = p_wc;
+           KeyTyped = TRUE;
+       }
+     }
+ 
+     return c;
+ }
+ 
+ /*
+  * Free expanded names when finished walking through the matches
+  */
+     void
+ wildmenu_cleanup(cmdline_info_T *cclp)
+ {
+     int skt = KeyTyped;
+     int old_RedrawingDisabled = RedrawingDisabled;
+ 
+     if (!p_wmnu || wild_menu_showing == 0)
+       return;
+ 
+     if (cclp->input_fn)
+       RedrawingDisabled = 0;
+ 
+     if (wild_menu_showing == WM_SCROLLED)
+     {
+       // Entered command line, move it up
+       cmdline_row--;
+       redrawcmd();
+     }
+     else if (save_p_ls != -1)
+     {
+       // restore 'laststatus' and 'winminheight'
+       p_ls = save_p_ls;
+       p_wmh = save_p_wmh;
+       last_status(FALSE);
+       update_screen(VALID);   // redraw the screen NOW
+       redrawcmd();
+       save_p_ls = -1;
+     }
+     else
+     {
+       win_redraw_last_status(topframe);
+       redraw_statuslines();
+     }
+     KeyTyped = skt;
+     wild_menu_showing = 0;
+     if (cclp->input_fn)
+       RedrawingDisabled = old_RedrawingDisabled;
+ }
+ #endif
+ 
  #if defined(FEAT_EVAL) || defined(PROTO)
  /*
   * "getcompletion()" function
*** ../vim-8.2.1586/src/proto/cmdexpand.pro     2020-01-05 14:38:37.110600924 
+0100
--- src/proto/cmdexpand.pro     2020-09-04 15:33:31.810062466 +0200
***************
*** 9,13 ****
--- 9,16 ----
  void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int 
use_ccline);
  int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, 
char_u ***matches);
  void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options);
+ int wildmenu_translate_key(cmdline_info_T *cclp, int key, expand_T *xp, int 
did_wild_list);
+ int wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp);
+ void wildmenu_cleanup(cmdline_info_T *cclp);
  void f_getcompletion(typval_T *argvars, typval_T *rettv);
  /* vim: set ft=c : */
*** ../vim-8.2.1586/src/ex_getln.c      2020-09-03 16:49:49.721754552 +0200
--- src/ex_getln.c      2020-09-04 15:33:28.642069304 +0200
***************
*** 44,52 ****
  static void   save_cmdline(cmdline_info_T *ccp);
  static void   restore_cmdline(cmdline_info_T *ccp);
  static int    cmdline_paste(int regname, int literally, int remcr);
- #ifdef FEAT_WILDMENU
- static void   cmdline_del(int from);
- #endif
  static void   redrawcmdprompt(void);
  static int    ccheck_abbr(int);
  
--- 44,49 ----
***************
*** 1064,1084 ****
            c = Ctrl_P;
  
  #ifdef FEAT_WILDMENU
!       // Special translations for 'wildmenu'
!       if (did_wild_list && p_wmnu)
!       {
!           if (c == K_LEFT)
!               c = Ctrl_P;
!           else if (c == K_RIGHT)
!               c = Ctrl_N;
!       }
!       // Hitting CR after "emenu Name.": complete submenu
!       if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu
!               && ccline.cmdpos > 1
!               && ccline.cmdbuff[ccline.cmdpos - 1] == '.'
!               && ccline.cmdbuff[ccline.cmdpos - 2] != '\\'
!               && (c == '\n' || c == '\r' || c == K_KENTER))
!           c = K_DOWN;
  #endif
  
        // free expanded names when finished walking through matches
--- 1061,1067 ----
            c = Ctrl_P;
  
  #ifdef FEAT_WILDMENU
!       c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list);
  #endif
  
        // free expanded names when finished walking through matches
***************
*** 1095,1284 ****
                xpc.xp_context = EXPAND_NOTHING;
            wim_index = 0;
  #ifdef FEAT_WILDMENU
!           if (p_wmnu && wild_menu_showing != 0)
!           {
!               int skt = KeyTyped;
!               int old_RedrawingDisabled = RedrawingDisabled;
! 
!               if (ccline.input_fn)
!                   RedrawingDisabled = 0;
! 
!               if (wild_menu_showing == WM_SCROLLED)
!               {
!                   // Entered command line, move it up
!                   cmdline_row--;
!                   redrawcmd();
!               }
!               else if (save_p_ls != -1)
!               {
!                   // restore 'laststatus' and 'winminheight'
!                   p_ls = save_p_ls;
!                   p_wmh = save_p_wmh;
!                   last_status(FALSE);
!                   update_screen(VALID);       // redraw the screen NOW
!                   redrawcmd();
!                   save_p_ls = -1;
!               }
!               else
!               {
!                   win_redraw_last_status(topframe);
!                   redraw_statuslines();
!               }
!               KeyTyped = skt;
!               wild_menu_showing = 0;
!               if (ccline.input_fn)
!                   RedrawingDisabled = old_RedrawingDisabled;
!           }
  #endif
        }
  
  #ifdef FEAT_WILDMENU
!       // Special translations for 'wildmenu'
!       if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu)
!       {
!           // Hitting <Down> after "emenu Name.": complete submenu
!           if (c == K_DOWN && ccline.cmdpos > 0
!                                 && ccline.cmdbuff[ccline.cmdpos - 1] == '.')
!               c = p_wc;
!           else if (c == K_UP)
!           {
!               // Hitting <Up>: Remove one submenu name in front of the
!               // cursor
!               int found = FALSE;
! 
!               j = (int)(xpc.xp_pattern - ccline.cmdbuff);
!               i = 0;
!               while (--j > 0)
!               {
!                   // check for start of menu name
!                   if (ccline.cmdbuff[j] == ' '
!                           && ccline.cmdbuff[j - 1] != '\\')
!                   {
!                       i = j + 1;
!                       break;
!                   }
!                   // check for start of submenu name
!                   if (ccline.cmdbuff[j] == '.'
!                           && ccline.cmdbuff[j - 1] != '\\')
!                   {
!                       if (found)
!                       {
!                           i = j + 1;
!                           break;
!                       }
!                       else
!                           found = TRUE;
!                   }
!               }
!               if (i > 0)
!                   cmdline_del(i);
!               c = p_wc;
!               xpc.xp_context = EXPAND_NOTHING;
!           }
!       }
!       if ((xpc.xp_context == EXPAND_FILES
!                             || xpc.xp_context == EXPAND_DIRECTORIES
!                             || xpc.xp_context == EXPAND_SHELLCMD) && p_wmnu)
!       {
!           char_u upseg[5];
! 
!           upseg[0] = PATHSEP;
!           upseg[1] = '.';
!           upseg[2] = '.';
!           upseg[3] = PATHSEP;
!           upseg[4] = NUL;
! 
!           if (c == K_DOWN
!                   && ccline.cmdpos > 0
!                   && ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP
!                   && (ccline.cmdpos < 3
!                       || ccline.cmdbuff[ccline.cmdpos - 2] != '.'
!                       || ccline.cmdbuff[ccline.cmdpos - 3] != '.'))
!           {
!               // go down a directory
!               c = p_wc;
!           }
!           else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN)
!           {
!               // If in a direct ancestor, strip off one ../ to go down
!               int found = FALSE;
! 
!               j = ccline.cmdpos;
!               i = (int)(xpc.xp_pattern - ccline.cmdbuff);
!               while (--j > i)
!               {
!                   if (has_mbyte)
!                       j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j);
!                   if (vim_ispathsep(ccline.cmdbuff[j]))
!                   {
!                       found = TRUE;
!                       break;
!                   }
!               }
!               if (found
!                       && ccline.cmdbuff[j - 1] == '.'
!                       && ccline.cmdbuff[j - 2] == '.'
!                       && (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2))
!               {
!                   cmdline_del(j - 2);
!                   c = p_wc;
!               }
!           }
!           else if (c == K_UP)
!           {
!               // go up a directory
!               int found = FALSE;
! 
!               j = ccline.cmdpos - 1;
!               i = (int)(xpc.xp_pattern - ccline.cmdbuff);
!               while (--j > i)
!               {
!                   if (has_mbyte)
!                       j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j);
!                   if (vim_ispathsep(ccline.cmdbuff[j])
! # ifdef BACKSLASH_IN_FILENAME
!                           && vim_strchr((char_u *)" *?[{`$%#",
!                               ccline.cmdbuff[j + 1]) == NULL
! # endif
!                      )
!                   {
!                       if (found)
!                       {
!                           i = j + 1;
!                           break;
!                       }
!                       else
!                           found = TRUE;
!                   }
!               }
! 
!               if (!found)
!                   j = i;
!               else if (STRNCMP(ccline.cmdbuff + j, upseg, 4) == 0)
!                   j += 4;
!               else if (STRNCMP(ccline.cmdbuff + j, upseg + 1, 3) == 0
!                            && j == i)
!                   j += 3;
!               else
!                   j = 0;
!               if (j > 0)
!               {
!                   // TODO this is only for DOS/UNIX systems - need to put in
!                   // machine-specific stuff here and in upseg init
!                   cmdline_del(j);
!                   put_on_cmdline(upseg + 1, 3, FALSE);
!               }
!               else if (ccline.cmdpos > i)
!                   cmdline_del(i);
! 
!               // Now complete in the new directory. Set KeyTyped in case the
!               // Up key came from a mapping.
!               c = p_wc;
!               KeyTyped = TRUE;
!           }
!       }
! 
! #endif        // FEAT_WILDMENU
  
        // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
        // mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
--- 1078,1090 ----
                xpc.xp_context = EXPAND_NOTHING;
            wim_index = 0;
  #ifdef FEAT_WILDMENU
!           wildmenu_cleanup(&ccline);
  #endif
        }
  
  #ifdef FEAT_WILDMENU
!       c = wildmenu_process_key(&ccline, c, &xpc);
! #endif
  
        // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
        // mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
***************
*** 3660,3680 ****
        }
  }
  
- #ifdef FEAT_WILDMENU
- /*
-  * Delete characters on the command line, from "from" to the current
-  * position.
-  */
-     static void
- cmdline_del(int from)
- {
-     mch_memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos,
-           (size_t)(ccline.cmdlen - ccline.cmdpos + 1));
-     ccline.cmdlen -= ccline.cmdpos - from;
-     ccline.cmdpos = from;
- }
- #endif
- 
  /*
   * This function is called when the screen size changes and with incremental
   * search and in other situations where the command line may have been
--- 3466,3471 ----
*** ../vim-8.2.1586/src/version.c       2020-09-04 14:41:17.621141198 +0200
--- src/version.c       2020-09-04 15:29:00.810636909 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1587,
  /**/

-- 
There are 2 kinds of people in my world: those who know Unix, Perl, Vim, GNU,
Linux, etc, and those who know COBOL.  It gets very difficult for me at
parties, not knowing which group to socialise with :-)
                                                Sitaram Chamarty

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202009041338.084Dc1w7335542%40masaka.moolenaar.net.

Raspunde prin e-mail lui