changeset 22075:eb878f85967e v8.2.1587

patch 8.2.1587: loop for handling keys for the command line is too long Commit: https://github.com/vim/vim/commit/eadee486c70946ad0e1746d77898d6f4f4acc817 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Sep 4 15:37:31 2020 +0200 patch 8.2.1587: loop for handling keys for the command line is too long Problem: Loop for handling keys for the command line is too long. Solution: Move wild menu handling to separate functions. (Yegappan Lakshmanan, closes #6856)
author Bram Moolenaar <Bram@vim.org>
date Fri, 04 Sep 2020 15:45:03 +0200
parents 923f618adb59
children 1b8ace0b3487
files src/cmdexpand.c src/ex_getln.c src/proto/cmdexpand.pro src/version.c
diffstat 4 files changed, 258 insertions(+), 213 deletions(-) [+]
line wrap: on
line diff
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -2614,6 +2614,255 @@ globpath(
     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
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -44,9 +44,6 @@ static void	draw_cmdline(int start, int 
 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);
 
@@ -1064,21 +1061,7 @@ getcmdline_int(
 	    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;
+	c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list);
 #endif
 
 	// free expanded names when finished walking through matches
@@ -1095,190 +1078,13 @@ getcmdline_int(
 		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;
-	    }
+	    wildmenu_cleanup(&ccline);
 #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
+	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,21 +3466,6 @@ cmdline_paste_str(char_u *s, int literal
 	}
 }
 
-#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
--- a/src/proto/cmdexpand.pro
+++ b/src/proto/cmdexpand.pro
@@ -9,5 +9,8 @@ char_u *addstar(char_u *fname, int len, 
 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 : */
--- 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 */
 /**/
+    1587,
+/**/
     1586,
 /**/
     1585,