patch 9.1.1639: completion: popup may be misplaced
Commit:
https://github.com/vim/vim/commit/1e38198a413f7235c909ccd0d55b339a3e920615
Author: Girish Palya <[email protected]>
Date: Sat Aug 16 18:13:46 2025 +0200
patch 9.1.1639: completion: popup may be misplaced
Problem: During commandline completiom, popup window placement can be
incorrect when 'noselect' is present in 'wildmode'
(Shane-XB-Qian)
Solution: Disable "showtail" feature when 'noselect' is present.
fixes: #17969
closes: #18001
Signed-off-by: Girish Palya <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index dc65ae8ee..416a7a7b3 100644
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -342,7 +342,7 @@ nextwild(
{
size_t plen = STRLEN(p);
int difflen;
- int v;
+ int v = OK;
difflen = (int)plen - xp->xp_pattern_len;
if (ccline->cmdlen + difflen + 4 > ccline->cmdbufflen)
@@ -350,8 +350,7 @@ nextwild(
v = realloc_cmdbuff(ccline->cmdlen + difflen + 4);
xp->xp_pattern = ccline->cmdbuff + i;
}
- else
- v = OK;
+
if (v == OK)
{
mch_memmove(&ccline->cmdbuff[ccline->cmdpos + difflen],
@@ -395,7 +394,7 @@ cmdline_pum_create(
int showtail)
{
int i;
- int columns;
+ int prefix_len;
// Add all the completion matches
compl_match_array = ALLOC_MULT(pumitem_T, numMatches);
@@ -415,13 +414,11 @@ cmdline_pum_create(
// Compute the popup menu starting column
compl_startcol = ccline == NULL ? 0 : vim_strsize(ccline->cmdbuff) + 1;
- columns = vim_strsize(xp->xp_pattern);
+ prefix_len = vim_strsize(xp->xp_pattern);
if (showtail)
- {
- columns += vim_strsize(showmatches_gettail(matches[0]));
- columns -= vim_strsize(matches[0]);
- }
- compl_startcol = MAX(0, compl_startcol - columns);
+ prefix_len += vim_strsize(showmatches_gettail(matches[0]))
+ - vim_strsize(matches[0]);
+ compl_startcol = MAX(0, compl_startcol - prefix_len);
// no default selection
compl_selected = -1;
@@ -1279,12 +1276,12 @@ showmatches_oneline(
* be inserted like a normal character.
*/
int
-showmatches(expand_T *xp, int wildmenu UNUSED)
+showmatches(expand_T *xp, int wildmenu, int noselect)
{
cmdline_info_T *ccline = get_cmdline_info();
int numMatches;
char_u **matches;
- int i, j;
+ int i;
int maxlen;
int lines;
int columns;
@@ -1300,12 +1297,13 @@ showmatches(expand_T *xp, int wildmenu UNUSED)
if (xp->xp_numfiles == -1)
{
+ int retval;
set_expand_context(xp);
- i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos,
- &numMatches, &matches);
+ retval = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos,
+ &numMatches, &matches);
+ if (retval != EXPAND_OK)
+ return retval;
showtail = expand_showtail(xp);
- if (i != EXPAND_OK)
- return i;
}
else
{
@@ -1316,7 +1314,8 @@ showmatches(expand_T *xp, int wildmenu UNUSED)
if (wildmenu && vim_strchr(p_wop, WOP_PUM) != NULL)
// cmdline completion popup menu (with wildoptions=pum)
- return cmdline_pum_create(ccline, xp, matches, numMatches, showtail);
+ return cmdline_pum_create(ccline, xp, matches, numMatches,
+ showtail && !noselect);
if (!wildmenu)
{
@@ -1339,17 +1338,18 @@ showmatches(expand_T *xp, int wildmenu UNUSED)
maxlen = 0;
for (i = 0; i < numMatches; ++i)
{
+ int len;
if (!showtail && (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_SHELLCMD
|| xp->xp_context == EXPAND_BUFFERS))
{
home_replace(NULL, matches[i], NameBuff, MAXPATHL, TRUE);
- j = vim_strsize(NameBuff);
+ len = vim_strsize(NameBuff);
}
else
- j = vim_strsize(SHOW_MATCH(i));
- if (j > maxlen)
- maxlen = j;
+ len = vim_strsize(SHOW_MATCH(i));
+ if (len > maxlen)
+ maxlen = len;
}
if (xp->xp_context == EXPAND_TAGS_LISTFILES)
diff --git a/src/ex_getln.c b/src/ex_getln.c
index a96ece70c..7dbb743ec 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -946,10 +946,11 @@ cmdline_wildchar_complete(
int res;
int j;
int options = WILD_NO_BEEP;
+ int noselect = (wim_flags[0] & WIM_NOSELECT) != 0;
if (wim_flags[wim_index] & WIM_BUFLASTUSED)
options |= WILD_BUFLASTUSED;
- if (wim_flags[0] & WIM_NOSELECT)
+ if (noselect)
options |= WILD_KEEP_SOLE_ITEM;
if (xp->xp_numfiles > 0) // typed p_wc at least twice
{
@@ -960,7 +961,8 @@ cmdline_wildchar_complete(
|| (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)))
{
(void)showmatches(xp,
- p_wmnu && ((wim_flags[wim_index] & WIM_LIST) == 0));
+ p_wmnu && ((wim_flags[wim_index] & WIM_LIST) == 0),
+ noselect);
redrawcmd();
*did_wild_list = TRUE;
}
@@ -1011,7 +1013,7 @@ cmdline_wildchar_complete(
// "list", or no change and 'wildmode' contains "longest,list",
// list all matches
if (res == OK
- && xp->xp_numfiles > ((wim_flags[wim_index] & WIM_NOSELECT) ? 0
: 1))
+ && xp->xp_numfiles > (noselect ? 0 : 1))
{
// a "longest" that didn't do anything is skipped (but not
// "list:longest")
@@ -1031,7 +1033,7 @@ cmdline_wildchar_complete(
p_wmnu = p_wmnu_save;
}
(void)showmatches(xp, p_wmnu
- && ((wim_flags[wim_index] & WIM_LIST) == 0));
+ && ((wim_flags[wim_index] & WIM_LIST) == 0), noselect);
redrawcmd();
*did_wild_list = TRUE;
if (wim_flags[wim_index] & WIM_LONGEST)
@@ -2013,7 +2015,8 @@ getcmdline_int(
{
if (cmdline_pum_active())
{
- skip_pum_redraw = skip_pum_redraw && (vim_isprintc(c)
+ skip_pum_redraw = skip_pum_redraw && !key_is_wc
+ && (vim_isprintc(c)
|| c == K_BS || c == Ctrl_H || c == K_DEL
|| c == K_KDEL || c == Ctrl_W || c == Ctrl_U);
cmdline_pum_remove(&ccline, skip_pum_redraw);
@@ -2124,7 +2127,8 @@ getcmdline_int(
{
// Trigger the popup menu when wildoptions=pum
showmatches(&xpc, p_wmnu
- && ((wim_flags[wim_index] & WIM_LIST) == 0));
+ && ((wim_flags[wim_index] & WIM_LIST) == 0),
+ wim_flags[0] & WIM_NOSELECT);
}
if (nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK
&& nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK)
@@ -2239,7 +2243,8 @@ getcmdline_int(
goto cmdline_not_changed;
case Ctrl_D:
- if (showmatches(&xpc, FALSE) == EXPAND_NOTHING)
+ if (showmatches(&xpc, FALSE, wim_flags[0] & WIM_NOSELECT)
+ == EXPAND_NOTHING)
break; // Use ^D as normal char instead
redrawcmd();
diff --git a/src/proto/cmdexpand.pro b/src/proto/cmdexpand.pro
index 388b80b13..501b5e642 100644
--- a/src/proto/cmdexpand.pro
+++ b/src/proto/cmdexpand.pro
@@ -12,7 +12,7 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig,
int options, int mode
void ExpandInit(expand_T *xp);
void ExpandCleanup(expand_T *xp);
void clear_cmdline_orig(void);
-int showmatches(expand_T *xp, int wildmenu);
+int showmatches(expand_T *xp, int wildmenu, int noselect);
char_u *addstar(char_u *fname, int len, int context);
void set_expand_context(expand_T *xp);
void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int
use_ccline);
diff --git a/src/testdir/dumps/Test_expand_env_var_1.dump
b/src/testdir/dumps/Test_expand_env_var_1.dump
new file mode 100644
index 000000000..64cad0d0a
--- /dev/null
+++ b/src/testdir/dumps/Test_expand_env_var_1.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| | +0#0000001#ffd7ff255|a|/|b|/|c|/| @8| +0#4040ff13#ffffff0@56
+|~| | +0#0000001#ffd7ff255|a|/|b|/|f|i|l|e|X|n|a|m|e|1| |
+0#4040ff13#ffffff0@56
+|~| | +0#0000001#ffd7ff255|a|/|b|/|f|i|l|e|X|n|a|m|e|2| |
+0#4040ff13#ffffff0@56
+|:+0#0000000&|e| |$|T|E|S|T|D|I|R|/> @62
diff --git a/src/testdir/dumps/Test_expand_env_var_2.dump
b/src/testdir/dumps/Test_expand_env_var_2.dump
new file mode 100644
index 000000000..95bcb450c
--- /dev/null
+++ b/src/testdir/dumps/Test_expand_env_var_2.dump
@@ -0,0 +1,8 @@
+| +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| | +0#0000001#e0e0e08|a|/|b|/|c|/| @8| +0#4040ff13#ffffff0@56
+|~| | +0#0000001#ffd7ff255|a|/|b|/|f|i|l|e|X|n|a|m|e|1| |
+0#4040ff13#ffffff0@56
+|~| | +0#0000001#ffd7ff255|a|/|b|/|f|i|l|e|X|n|a|m|e|2| |
+0#4040ff13#ffffff0@56
+|:+0#0000000&|e| |a|/|b|/|c|/> @65
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 523bde86b..d2c9c7898 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -4859,4 +4859,34 @@ func Test_wildtrigger_update_screen()
cnoremap <buffer> <F8> <C-R>=wildtrigger()[-1]<CR>
endfunc
+" Issue #17969: With 'noselect', the popup menu should appear next to the
+" environment variable being expanded. Disable 'showtail' when completing
+" file paths when 'noselect' is present.
+func Test_noselect_expand_env_var()
+ CheckScreendump
+
+ let lines =<< trim [SCRIPT]
+ set wildmenu wildoptions=pum wildmode=noselect,full
+ let $TESTDIR = 'a/b'
+ [SCRIPT]
+ call writefile(lines, 'XTest_wildmenu', 'D')
+ let buf = RunVimInTerminal('-S XTest_wildmenu', {'rows': 8})
+
+ call mkdir('a/b/c', 'pR')
+ call writefile(['asdf'], 'a/b/fileXname1')
+ call writefile(['foo'], 'a/b/fileXname2')
+
+ call term_sendkeys(buf, ":e $TESTDIR/\<Tab>")
+ call VerifyScreenDump(buf, 'Test_expand_env_var_1', {})
+
+ call term_sendkeys(buf, "\<C-N>")
+ call VerifyScreenDump(buf, 'Test_expand_env_var_2', {})
+
+ call term_sendkeys(buf, "\<C-P>")
+ call VerifyScreenDump(buf, 'Test_expand_env_var_1', {})
+ " clean up
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 5488cf8a1..cc08bffa8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -719,6 +719,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1639,
/**/
1638,
/**/
--
--
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 visit
https://groups.google.com/d/msgid/vim_dev/E1unJn9-001AGM-Pi%40256bit.org.