vim-patch:9.1.1714: completion: wildmode=longest:full selects wrong item

Problem:  completion: wildmode=longest:full selects wrong item
          (zeertzjq)
Solution: Fix issue, refactor ex_getln.c slightly
          (Girish Palya)

fixes: vim/vim#18102
closes: vim/vim#18125

2eccb4d0be

Co-authored-by: Girish Palya <girishji@gmail.com>
This commit is contained in:
zeertzjq
2025-09-01 08:09:05 +08:00
parent 3b5337ab6c
commit 1359578abb
4 changed files with 107 additions and 74 deletions

View File

@@ -1120,32 +1120,34 @@ static int command_line_wildchar_complete(CommandLineState *s)
{
int res;
int options = WILD_NO_BEEP;
bool noselect = p_wmnu && (wim_flags[0] & kOptWimFlagNoselect) != 0;
bool escape = s->firstc != '@';
bool wim_noselect = p_wmnu && (wim_flags[0] & kOptWimFlagNoselect) != 0;
if (wim_flags[s->wim_index] & kOptWimFlagLastused) {
options |= WILD_BUFLASTUSED;
}
if (s->xpc.xp_numfiles > 0) { // typed p_wc at least twice
// if 'wildmode' contains "list" may still need to list
// If "list" is present, list matches unless already listed
if (s->xpc.xp_numfiles > 1
&& !s->did_wild_list
&& ((wim_flags[s->wim_index] & kOptWimFlagList)
|| (p_wmnu && (wim_flags[s->wim_index] & kOptWimFlagFull) != 0))) {
showmatches(&s->xpc,
p_wmnu && ((wim_flags[s->wim_index] & kOptWimFlagList) == 0),
noselect);
&& (wim_flags[s->wim_index] & kOptWimFlagList)) {
showmatches(&s->xpc, false, true, wim_noselect);
redrawcmd();
s->did_wild_list = true;
}
if (wim_flags[s->wim_index] & kOptWimFlagLongest) {
res = nextwild(&s->xpc, WILD_LONGEST, options, s->firstc != '@');
res = nextwild(&s->xpc, WILD_LONGEST, options, escape);
} else if (wim_flags[s->wim_index] & kOptWimFlagFull) {
res = nextwild(&s->xpc, WILD_NEXT, options, s->firstc != '@');
res = nextwild(&s->xpc, WILD_NEXT, options, escape);
} else {
res = OK; // don't insert 'wildchar' now
}
} else { // typed p_wc first time
bool wim_longest = (wim_flags[0] & kOptWimFlagLongest);
bool wim_list = (wim_flags[0] & kOptWimFlagList);
bool wim_full = (wim_flags[0] & kOptWimFlagFull);
s->wim_index = 0;
if (s->c == p_wc || s->c == p_wcm || s->c == K_WILD || s->c == Ctrl_Z) {
options |= WILD_MAY_EXPAND_PATTERN;
if (s->c == K_WILD) {
@@ -1153,18 +1155,17 @@ static int command_line_wildchar_complete(CommandLineState *s)
}
s->xpc.xp_pre_incsearch_pos = s->is_state.search_start;
}
s->wim_index = 0;
int j = ccline.cmdpos;
int cmdpos_before = ccline.cmdpos;
// if 'wildmode' first contains "longest", get longest
// common part
if (wim_flags[0] & kOptWimFlagLongest) {
res = nextwild(&s->xpc, WILD_LONGEST, options, s->firstc != '@');
if (wim_longest) {
res = nextwild(&s->xpc, WILD_LONGEST, options, escape);
} else {
if (noselect || (wim_flags[s->wim_index] & kOptWimFlagList)) {
if (wim_noselect || wim_list) {
options |= WILD_NOSELECT;
}
res = nextwild(&s->xpc, WILD_EXPAND_KEEP, options, s->firstc != '@');
res = nextwild(&s->xpc, WILD_EXPAND_KEEP, options, escape);
}
// if interrupted while completing, behave like it failed
@@ -1176,29 +1177,28 @@ static int command_line_wildchar_complete(CommandLineState *s)
return CMDLINE_CHANGED;
}
// when more than one match, and 'wildmode' first contains
// "list", or no change and 'wildmode' contains "longest,list",
// list all matches
if (res == OK
&& s->xpc.xp_numfiles > (noselect ? 0 : 1)) {
// a "longest" that didn't do anything is skipped (but not
// "list:longest")
if (wim_flags[0] == kOptWimFlagLongest && ccline.cmdpos == j) {
s->wim_index = 1;
}
if ((wim_flags[s->wim_index] & kOptWimFlagList)
|| (p_wmnu && (wim_flags[s->wim_index] & (kOptWimFlagFull|kOptWimFlagNoselect)))) {
showmatches(&s->xpc,
p_wmnu && ((wim_flags[s->wim_index] & kOptWimFlagList) == 0),
noselect);
redrawcmd();
s->did_wild_list = true;
if (wim_flags[s->wim_index] & kOptWimFlagLongest) {
nextwild(&s->xpc, WILD_LONGEST, options, s->firstc != '@');
// Display matches
if (res == OK && s->xpc.xp_numfiles > (wim_noselect ? 0 : 1)) {
// If "longest" fails to identify the longest item, try other
// 'wim' values if available
if (wim_longest && ccline.cmdpos == cmdpos_before) {
if (wim_full) {
nextwild(&s->xpc, WILD_NEXT, options, escape);
}
} else {
vim_beep(kOptBoFlagWildmode);
if (wim_list || (p_wmnu && wim_full)) {
showmatches(&s->xpc, p_wmnu, wim_list, false);
}
} else if (!wim_longest) {
if (wim_list || (p_wmnu && (wim_full || wim_noselect))) {
showmatches(&s->xpc, p_wmnu, wim_list, wim_noselect);
} else {
vim_beep(kOptBoFlagWildmode);
}
}
redrawcmd();
if (wim_list) {
s->did_wild_list = true;
}
} else if (s->xpc.xp_numfiles == -1) {
s->xpc.xp_context = EXPAND_NOTHING;
@@ -1339,7 +1339,7 @@ static int command_line_execute(VimState *state, int key)
int wild_type = 0;
const bool key_is_wc = (s->c == p_wc && KeyTyped) || s->c == p_wcm;
if ((cmdline_pum_active() || s->did_wild_list) && !key_is_wc) {
if ((cmdline_pum_active() || wild_menu_showing || s->did_wild_list) && !key_is_wc) {
// Ctrl-Y: Accept the current selection and close the popup menu.
// Ctrl-E: cancel the cmdline popup menu and return the original text.
if (s->c == Ctrl_E || s->c == Ctrl_Y) {
@@ -1464,8 +1464,7 @@ static int command_line_execute(VimState *state, int key)
if (s->xpc.xp_numfiles > 1
&& ((!s->did_wild_list && (wim_flags[s->wim_index] & kOptWimFlagList)) || p_wmnu)) {
// Trigger the popup menu when wildoptions=pum
showmatches(&s->xpc,
p_wmnu && ((wim_flags[s->wim_index] & kOptWimFlagList) == 0),
showmatches(&s->xpc, p_wmnu, wim_flags[s->wim_index] & kOptWimFlagList,
wim_flags[0] & kOptWimFlagNoselect);
}
nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@');
@@ -2033,7 +2032,7 @@ static int command_line_handle_key(CommandLineState *s)
}
case Ctrl_D:
if (showmatches(&s->xpc, false, wim_flags[0] & kOptWimFlagNoselect)
if (showmatches(&s->xpc, false, true, wim_flags[0] & kOptWimFlagNoselect)
== EXPAND_NOTHING) {
break; // Use ^D as normal char instead
}