summaryrefslogtreecommitdiffstats
path: root/src/cmdexpand.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-09-04 15:37:31 +0200
committerBram Moolenaar <Bram@vim.org>2020-09-04 15:37:31 +0200
commiteadee486c70946ad0e1746d77898d6f4f4acc817 (patch)
treed36a72738e256191c2201dd015940cbcc2f13321 /src/cmdexpand.c
parentfe6dce873954a216eedb686bd5006710ffff4b89 (diff)
patch 8.2.1587: loop for handling keys for the command line is too longv8.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)
Diffstat (limited to 'src/cmdexpand.c')
-rw-r--r--src/cmdexpand.c249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index fe82ab7d4a..79fb006b24 100644
--- 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