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.