Skip to content

Commit

Permalink
patch 8.2.4325: 'wildmenu' only shows few matches
Browse files Browse the repository at this point in the history
Problem:    'wildmenu' only shows few matches.
Solution:   Add the "pum" option: use a popup menu to show the matches.
            (Yegappan Lakshmanan et al., closes #9707)
  • Loading branch information
yegappan authored and brammool committed Feb 8, 2022
1 parent 3787f26 commit 3908ef5
Show file tree
Hide file tree
Showing 41 changed files with 673 additions and 17 deletions.
31 changes: 25 additions & 6 deletions runtime/doc/options.txt
Expand Up @@ -8974,18 +8974,21 @@ A jump table for the options with a short description can be found at |Q_op|.
mode. On pressing 'wildchar' (usually <Tab>) to invoke completion,
the possible matches are shown just above the command line, with the
first match highlighted (overwriting the status line, if there is
one). Keys that show the previous/next match, such as <Tab> or
one). This is the behavior without "pum" in 'wildoptions.
Keys that show the previous/next match, such as <Tab> or
CTRL-P/CTRL-N, cause the highlight to move to the appropriate match.
When 'wildmode' is used, "wildmenu" mode is used where "full" is
specified. "longest" and "list" do not start "wildmenu" mode.
You can check the current mode with |wildmenumode()|.
If there are more matches than can fit in the line, a ">" is shown on
the right and/or a "<" is shown on the left. The status line scrolls
as needed.
When 'wildoptions' contains "pum", then the completion matches are
shown in a popup menu.
The "wildmenu" mode is abandoned when a key is hit that is not used
for selecting a completion.
While the "wildmenu" is active the following keys have special
meanings:
While the "wildmenu" is active, not using the popup menu, the
following keys have special meanings:

<Left> <Right> - select previous/next match (like CTRL-P/CTRL-N)
<Down> - in filename/menu name completion: move into a
Expand All @@ -8995,6 +8998,21 @@ A jump table for the options with a short description can be found at |Q_op|.
<Up> - in filename/menu name completion: move up into
parent directory or parent menu.

When using the popup menu for command line completion, the following
keys have special meanings:
<Down> - select next match (like CTRL-N)
<Left> - in filename/menu name completion: move up into
parent directory or parent menu.
<Right> - in filename/menu name completion: move into a
subdirectory or submenu.
<Up> - select previous match (like CTRL-P)
CTRL-E - end completion, go back to what was there before
selecting a match.
CTRL-N - go to the next entry
CTRL-P - go to the previous entry
CTRL-Y - accept the currently selected match and stop
completion.

This makes the menus accessible from the console |console-menus|.

If you prefer the <Left> and <Right> keys to move the cursor instead
Expand Down Expand Up @@ -9057,14 +9075,15 @@ A jump table for the options with a short description can be found at |Q_op|.
global
{not available when compiled without the |+wildignore|
feature}
A list of words that change how command line completion is done.
Currently only one word is allowed:
A list of words that change how |cmdline-completion| is done.
The following values are supported:
pum Display the completion matches using the popupmenu
in the same style as the |ins-completion-menu|.
tagfile When using CTRL-D to list matching tags, the kind of
tag and the file of the tag is listed. Only one match
is displayed per line. Often used tag kinds are:
d #define
f function
Also see |cmdline-completion|.

*'winaltkeys'* *'wak'*
'winaltkeys' 'wak' string (default "menu")
Expand Down
109 changes: 106 additions & 3 deletions src/cmdexpand.c
Expand Up @@ -25,6 +25,16 @@ static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int f
#if defined(FEAT_EVAL)
static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file);
static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file);
#endif

#ifdef FEAT_WILDMENU
// "compl_match_array" points the currently displayed list of entries in the
// popup menu. It is NULL when there is no popup menu.
static pumitem_T *compl_match_array = NULL;
static int compl_match_arraysize;
// First column in cmdline of the matched item for completion.
static int compl_startcol;
static int compl_selected;
#endif

static int
Expand Down Expand Up @@ -245,6 +255,42 @@ nextwild(
return OK;
}

#if defined(FEAT_WILDMENU) || defined(PROTO)
/*
* Display the cmdline completion matches in a popup menu
*/
void cmdline_pum_display(void)
{
pum_display(compl_match_array, compl_match_arraysize, compl_selected);
}

int cmdline_pum_active(void)
{
return p_wmnu && pum_visible() && compl_match_array != NULL;
}

/*
* Remove the cmdline completion popup menu
*/
void cmdline_pum_remove(void)
{
pum_undisplay();
VIM_CLEAR(compl_match_array);
update_screen(0);
}

void cmdline_pum_cleanup(cmdline_info_T *cclp)
{
cmdline_pum_remove();
wildmenu_cleanup(cclp);
}

int cmdline_compl_startcol(void)
{
return compl_startcol;
}
#endif

/*
* Do wildcard expansion on the string 'str'.
* Chars that should not be expanded must be preceded with a backslash.
Expand Down Expand Up @@ -327,7 +373,12 @@ ExpandOne(
findex = -1;
}
#ifdef FEAT_WILDMENU
if (p_wmnu)
if (compl_match_array)
{
compl_selected = findex;
cmdline_pum_display();
}
else if (p_wmnu)
win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files,
findex, cmd_showtail);
#endif
Expand All @@ -339,6 +390,12 @@ ExpandOne(
return NULL;
}

if (mode == WILD_CANCEL)
ss = vim_strsave(orig_save ? orig_save : (char_u *)"");
else if (mode == WILD_APPLY)
ss = vim_strsave(findex == -1 ? (orig_save ?
orig_save : (char_u *)"") : xp->xp_files[findex]);

// free old names
if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
{
Expand All @@ -351,7 +408,7 @@ ExpandOne(
if (mode == WILD_FREE) // only release file name
return NULL;

if (xp->xp_numfiles == -1)
if (xp->xp_numfiles == -1 && mode != WILD_APPLY && mode != WILD_CANCEL)
{
vim_free(orig_save);
orig_save = orig;
Expand Down Expand Up @@ -553,6 +610,35 @@ showmatches(expand_T *xp, int wildmenu UNUSED)
showtail = cmd_showtail;
}

#ifdef FEAT_WILDMENU
if (wildmenu && vim_strchr(p_wop, WOP_PUM) != NULL)
{
compl_match_arraysize = num_files;
compl_match_array = ALLOC_MULT(pumitem_T, compl_match_arraysize);
for (i = 0; i < num_files; i++)
{
compl_match_array[i].pum_text = L_SHOWFILE(i);
compl_match_array[i].pum_info = NULL;
compl_match_array[i].pum_extra = NULL;
compl_match_array[i].pum_kind = NULL;
}
compl_startcol = ccline->cmdpos + 1;
columns = vim_strsize(xp->xp_pattern);
if (showtail)
{
columns += vim_strsize(sm_gettail(files_found[0]));
columns -= vim_strsize(files_found[0]);
}
if (columns >= compl_startcol)
compl_startcol = 0;
else
compl_startcol -= columns;
compl_selected = -1;
cmdline_pum_display();
return EXPAND_OK;
}
#endif

#ifdef FEAT_WILDMENU
if (!wildmenu)
{
Expand Down Expand Up @@ -1500,7 +1586,7 @@ set_one_cmd_context(
case CMD_tjump:
case CMD_stjump:
case CMD_ptjump:
if (*p_wop != NUL)
if (vim_strchr(p_wop, WOP_TAGFILE) != NULL)
xp->xp_context = EXPAND_TAGS_LISTFILES;
else
xp->xp_context = EXPAND_TAGS;
Expand Down Expand Up @@ -2639,13 +2725,30 @@ wildmenu_translate_key(
{
int c = key;

#ifdef FEAT_WILDMENU
if (p_wmnu && cmdline_pum_active())
{
// When the popup menu is used, Up/Down keys go to the previous and
// next items in the menu and Left/Right keys go up/down a directory.
if (c == K_UP)
c = K_LEFT;
else if (c == K_DOWN)
c = K_RIGHT;
else if (c == K_LEFT)
c = K_UP;
else if (c == K_RIGHT)
c = K_DOWN;
}
#endif

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
Expand Down
4 changes: 4 additions & 0 deletions src/drawscreen.c
Expand Up @@ -3048,6 +3048,10 @@ redraw_after_callback(int call_update_screen, int do_message)
}
else if (State & CMDLINE)
{
#ifdef FEAT_WILDMENU
if (pum_visible())
cmdline_pum_display();
#endif
// Don't redraw when in prompt_for_number().
if (cmdline_row > 0)
{
Expand Down
2 changes: 1 addition & 1 deletion src/evalfunc.c
Expand Up @@ -10336,7 +10336,7 @@ f_visualmode(typval_T *argvars, typval_T *rettv)
f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
#ifdef FEAT_WILDMENU
if (wild_menu_showing)
if (wild_menu_showing || ((State & CMDLINE) && cmdline_pum_active()))
rettv->vval.v_number = 1;
#endif
}
Expand Down
55 changes: 50 additions & 5 deletions src/ex_getln.c
Expand Up @@ -924,9 +924,18 @@ cmdline_wildchar_complete(
// if 'wildmode' contains "list" may still need to list
if (xp->xp_numfiles > 1
&& !*did_wild_list
&& (wim_flags[wim_index] & WIM_LIST))
&& ((wim_flags[wim_index] & WIM_LIST)
#ifdef FEAT_WILDMENU
|| (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)
#endif
))
{
#ifdef FEAT_WILDMENU
(void)showmatches(xp,
p_wmnu && ((wim_flags[wim_index] & WIM_LIST) == 0));
#else
(void)showmatches(xp, FALSE);
#endif
redrawcmd();
*did_wild_list = TRUE;
}
Expand Down Expand Up @@ -1848,6 +1857,23 @@ getcmdline_int(

#ifdef FEAT_WILDMENU
c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list);

if (cmdline_pum_active())
{
if (c == Ctrl_E || c == Ctrl_Y)
{
int wild_type;

wild_type = (c == Ctrl_E) ? WILD_CANCEL : WILD_APPLY;

if (nextwild(&xpc, wild_type, WILD_NO_BEEP,
firstc != '@') == FAIL)
break;
cmdline_pum_cleanup(&ccline);
xpc.xp_context = EXPAND_NOTHING;
goto cmdline_changed;
}
}
#endif

// free expanded names when finished walking through matches
Expand All @@ -1856,6 +1882,9 @@ getcmdline_int(
&& c != Ctrl_N && c != Ctrl_P && c != Ctrl_A
&& c != Ctrl_L)
{
#ifdef FEAT_WILDMENU
cmdline_pum_remove();
#endif
(void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
did_wild_list = FALSE;
#ifdef FEAT_WILDMENU
Expand Down Expand Up @@ -1950,10 +1979,19 @@ getcmdline_int(
// <S-Tab> goes to last match, in a clumsy way
if (c == K_S_TAB && KeyTyped)
{
if (nextwild(&xpc, WILD_EXPAND_KEEP, 0, firstc != '@') == OK
&& nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK
&& nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK)
goto cmdline_changed;
if (nextwild(&xpc, WILD_EXPAND_KEEP, 0, firstc != '@') == OK)
{
#ifdef FEAT_WILDMENU
// Trigger the popup menu when wildoptions=pum
showmatches(&xpc,
p_wmnu && ((wim_flags[wim_index] & WIM_LIST) == 0));
#else
(void)showmatches(&xpc, FALSE);
#endif
if (nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK
&& nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK)
goto cmdline_changed;
}
}

if (c == NUL || c == K_ZERO) // NUL is stored as NL
Expand Down Expand Up @@ -2222,6 +2260,13 @@ getcmdline_int(
case Ctrl_A: // all matches
if (nextwild(&xpc, WILD_ALL, 0, firstc != '@') == FAIL)
break;
#ifdef FEAT_WILDMENU
if (cmdline_pum_active())
{
cmdline_pum_cleanup(&ccline);
xpc.xp_context = EXPAND_NOTHING;
}
#endif
goto cmdline_changed;

case Ctrl_L:
Expand Down
5 changes: 5 additions & 0 deletions src/option.h
Expand Up @@ -356,6 +356,11 @@ typedef enum {
#define WIM_LIST 0x04
#define WIM_BUFLASTUSED 0x08

// flags for the 'wildoptions' option
// each defined char should be unique over all values.
#define WOP_TAGFILE 't'
#define WOP_PUM 'p'

// arguments for can_bs()
// each defined char should be unique over all values
// except for BS_START, that intentionally also matches BS_NOSTOP
Expand Down
2 changes: 1 addition & 1 deletion src/optionstr.c
Expand Up @@ -57,7 +57,7 @@ static char *(p_tbis_values[]) = {"tiny", "small", "medium", "large", "huge", "g
static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", "jsbterm", "pterm", "urxvt", "sgr", NULL};
#endif
static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", "none", "NONE", NULL};
static char *(p_wop_values[]) = {"tagfile", NULL};
static char *(p_wop_values[]) = {"tagfile", "pum", NULL};
#ifdef FEAT_WAK
static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
#endif
Expand Down
10 changes: 9 additions & 1 deletion src/popupmenu.c
Expand Up @@ -116,7 +116,10 @@ pum_display(
// Remember the essential parts of the window position and size, so we
// can decide when to reposition the popup menu.
pum_window = curwin;
pum_win_row = curwin->w_wrow + W_WINROW(curwin);
if (State == CMDLINE)
pum_win_row = cmdline_row;
else
pum_win_row = curwin->w_wrow + W_WINROW(curwin);
pum_win_height = curwin->w_height;
pum_win_col = curwin->w_wincol;
pum_win_wcol = curwin->w_wcol;
Expand Down Expand Up @@ -215,6 +218,11 @@ pum_display(
max_width = pum_base_width;

// Calculate column
#ifdef FEAT_WILDMENU
if (State == CMDLINE)
cursor_col = cmdline_compl_startcol();
else
#endif
#ifdef FEAT_RIGHTLEFT
if (curwin->w_p_rl)
cursor_col = curwin->w_wincol + curwin->w_width
Expand Down

0 comments on commit 3908ef5

Please sign in to comment.