aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/cmdexpand.c233
-rw-r--r--src/nvim/cmdexpand.h1
-rw-r--r--src/nvim/ex_getln.c205
3 files changed, 233 insertions, 206 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 28806094d6..dd5251e761 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -10,6 +10,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/cmdhist.h"
+#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/userfunc.h"
@@ -40,6 +41,7 @@
#include "nvim/ui.h"
#include "nvim/usercmd.h"
#include "nvim/vim.h"
+#include "nvim/window.h"
/// Type used by ExpandGeneric()
typedef char *(*CompleteListItemGetter)(expand_T *, int);
@@ -53,15 +55,13 @@ typedef void *(*user_expand_func_T)(const char_u *, int, typval_T *);
static int cmd_showtail; ///< Only show path tail in lists ?
-// TODO(zeertzjq): make these four variables static in cmdexpand.c
-
/// "compl_match_array" points the currently displayed list of entries in the
/// popup menu. It is NULL when there is no popup menu.
-pumitem_T *compl_match_array = NULL;
-int compl_match_arraysize;
+pumitem_T *compl_match_array = NULL; // TODO(zeertzjq): make this static in cmdexpand.c
+static int compl_match_arraysize;
/// First column in cmdline of the matched item for completion.
-int compl_startcol;
-int compl_selected;
+static int compl_startcol;
+static int compl_selected;
static int sort_func_compare(const void *s1, const void *s2)
{
@@ -2509,6 +2509,227 @@ void globpath(char *path, char_u *file, garray_T *ga, int expand_options)
xfree(buf);
}
+/// Translate some keys pressed when 'wildmenu' is used.
+int wildmenu_translate_key(CmdlineInfo *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(CmdlineInfo *cclp, int from)
+{
+ assert(cclp->cmdpos <= cclp->cmdlen);
+ memmove(cclp->cmdbuff + from, cclp->cmdbuff + cclp->cmdpos,
+ (size_t)cclp->cmdlen - (size_t)cclp->cmdpos + 1);
+ cclp->cmdlen -= cclp->cmdpos - from;
+ cclp->cmdpos = from;
+}
+
+/// Handle a key pressed when wild menu is displayed
+int wildmenu_process_key(CmdlineInfo *cclp, int key, expand_T *xp)
+{
+ int c = key;
+
+ 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 = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ } else if (c == K_UP) {
+ // Hitting <Up>: Remove one submenu name in front of the
+ // cursor
+ int found = false;
+
+ int j = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff);
+ int 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 = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ 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 = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ } 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;
+
+ int j = cclp->cmdpos;
+ int i = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff);
+ while (--j > i) {
+ j -= utf_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 = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ }
+ } else if (c == K_UP) {
+ // go up a directory
+ int found = false;
+
+ int j = cclp->cmdpos - 1;
+ int i = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff);
+ while (--j > i) {
+ j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j);
+ if (vim_ispathsep(cclp->cmdbuff[j])
+#ifdef BACKSLASH_IN_FILENAME
+ && vim_strchr((const 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(tarruda): 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 = (int)p_wc;
+ KeyTyped = true;
+ }
+ }
+
+ return c;
+}
+
+/// Free expanded names when finished walking through the matches
+void wildmenu_cleanup(CmdlineInfo *cclp)
+{
+ if (!p_wmnu || wild_menu_showing == 0) {
+ return;
+ }
+
+ const bool skt = KeyTyped;
+ int old_RedrawingDisabled = RedrawingDisabled;
+
+ if (cclp->input_fn) {
+ RedrawingDisabled = 0;
+ }
+
+ if (wild_menu_showing == WM_SCROLLED) {
+ // Entered command line, move it up
+ cmdline_row--;
+ redrawcmd();
+ wild_menu_showing = 0;
+ } 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;
+ wild_menu_showing = 0;
+ // don't redraw statusline if WM_LIST is showing
+ } else if (wild_menu_showing != WM_LIST) {
+ win_redraw_last_status(topframe);
+ wild_menu_showing = 0; // must be before redraw_statuslines #8385
+ redraw_statuslines();
+ } else {
+ wild_menu_showing = 0;
+ }
+ KeyTyped = skt;
+ if (cclp->input_fn) {
+ RedrawingDisabled = old_RedrawingDisabled;
+ }
+}
+
/// "getcompletion()" function
void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
diff --git a/src/nvim/cmdexpand.h b/src/nvim/cmdexpand.h
index f534a2e0d3..93e91af169 100644
--- a/src/nvim/cmdexpand.h
+++ b/src/nvim/cmdexpand.h
@@ -2,6 +2,7 @@
#define NVIM_CMDEXPAND_H
#include "nvim/eval/typval.h"
+#include "nvim/ex_getln.h"
#include "nvim/garray.h"
#include "nvim/types.h"
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index c14eca6604..ec6c4af18a 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -170,12 +170,7 @@ static Array cmdline_block = ARRAY_DICT_INIT;
/// user interrupting highlight function to not interrupt command-line.
static bool getln_interrupted_highlight = false;
-// TODO(zeertzjq): make these four variables static in cmdexpand.c
-
-extern pumitem_T *compl_match_array;
-extern int compl_match_arraysize;
-extern int compl_startcol;
-extern int compl_selected;
+extern pumitem_T *compl_match_array; // TODO(zeertzjq): make this static in cmdexpand.c
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_getln.c.generated.h"
@@ -1028,14 +1023,8 @@ static int command_line_execute(VimState *state, int key)
s->c = Ctrl_P;
}
- // Special translations for 'wildmenu'
- if (s->did_wild_list && p_wmnu) {
- if (s->c == K_LEFT) {
- s->c = Ctrl_P;
- } else if (s->c == K_RIGHT) {
- s->c = Ctrl_N;
- }
- }
+ s->c = wildmenu_translate_key(&ccline, s->c, &s->xpc, s->did_wild_list);
+
if (compl_match_array || s->did_wild_list) {
if (s->c == Ctrl_E) {
s->res = nextwild(&s->xpc, WILD_CANCEL, WILD_NO_BEEP,
@@ -1047,15 +1036,6 @@ static int command_line_execute(VimState *state, int key)
}
}
- // Hitting CR after "emenu Name.": complete submenu
- if (s->xpc.xp_context == EXPAND_MENUNAMES && p_wmnu
- && ccline.cmdpos > 1
- && ccline.cmdbuff[ccline.cmdpos - 1] == '.'
- && ccline.cmdbuff[ccline.cmdpos - 2] != '\\'
- && (s->c == '\n' || s->c == '\r' || s->c == K_KENTER)) {
- s->c = K_DOWN;
- }
-
// free expanded names when finished walking through matches
if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z
&& s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A
@@ -1072,175 +1052,10 @@ static int command_line_execute(VimState *state, int key)
s->xpc.xp_context = EXPAND_NOTHING;
}
s->wim_index = 0;
- if (p_wmnu && wild_menu_showing != 0) {
- const bool 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();
- wild_menu_showing = 0;
- } 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;
- wild_menu_showing = 0;
- // don't redraw statusline if WM_LIST is showing
- } else if (wild_menu_showing != WM_LIST) {
- win_redraw_last_status(topframe);
- wild_menu_showing = 0; // must be before redraw_statuslines #8385
- redraw_statuslines();
- } else {
- wild_menu_showing = 0;
- }
- KeyTyped = skt;
- if (ccline.input_fn) {
- RedrawingDisabled = old_RedrawingDisabled;
- }
- }
- }
-
- // Special translations for 'wildmenu'
- if (s->xpc.xp_context == EXPAND_MENUNAMES && p_wmnu) {
- // Hitting <Down> after "emenu Name.": complete submenu
- if (s->c == K_DOWN && ccline.cmdpos > 0
- && ccline.cmdbuff[ccline.cmdpos - 1] == '.') {
- s->c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
- } else if (s->c == K_UP) {
- // Hitting <Up>: Remove one submenu name in front of the
- // cursor
- int found = false;
-
- int j = (int)((char_u *)s->xpc.xp_pattern - ccline.cmdbuff);
- int 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);
- }
- s->c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
- s->xpc.xp_context = EXPAND_NOTHING;
- }
+ wildmenu_cleanup(&ccline);
}
- if ((s->xpc.xp_context == EXPAND_FILES
- || s->xpc.xp_context == EXPAND_DIRECTORIES
- || s->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 (s->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
- s->c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
- } else if (STRNCMP(s->xpc.xp_pattern, upseg + 1, 3) == 0
- && s->c == K_DOWN) {
- // If in a direct ancestor, strip off one ../ to go down
- int found = false;
-
- int j = ccline.cmdpos;
- int i = (int)((char_u *)s->xpc.xp_pattern - ccline.cmdbuff);
- while (--j > i) {
- j -= utf_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);
- s->c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
- }
- } else if (s->c == K_UP) {
- // go up a directory
- int found = false;
-
- int j = ccline.cmdpos - 1;
- int i = (int)((char_u *)s->xpc.xp_pattern - ccline.cmdbuff);
- while (--j > i) {
- j -= utf_head_off(ccline.cmdbuff, ccline.cmdbuff + j);
- if (vim_ispathsep(ccline.cmdbuff[j])
-#ifdef BACKSLASH_IN_FILENAME
- && vim_strchr((const 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(tarruda): 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.
- s->c = (int)p_wc;
- KeyTyped = true;
- }
- }
+ s->c = wildmenu_process_key(&ccline, s->c, &s->xpc);
// CTRL-\ CTRL-N goes to Normal mode, CTRL-\ e prompts for an expression.
if (s->c == Ctrl_BSL) {
@@ -3749,16 +3564,6 @@ void cmdline_paste_str(char_u *s, int literally)
}
}
-/// Delete characters on the command line, from "from" to the current position.
-static void cmdline_del(int from)
-{
- assert(ccline.cmdpos <= ccline.cmdlen);
- memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos,
- (size_t)ccline.cmdlen - (size_t)ccline.cmdpos + 1);
- ccline.cmdlen -= ccline.cmdpos - from;
- ccline.cmdpos = from;
-}
-
// This function is called when the screen size changes and with incremental
// search and in other situations where the command line may have been
// overwritten.