patch 9.1.1639: completion: popup may be misplaced Commit: https://github.com/vim/vim/commit/1e38198a413f7235c909ccd0d55b339a3e920615 Author: Girish Palya <giris...@gmail.com> 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 <giris...@gmail.com> Signed-off-by: Christian Brabandt <c...@256bit.org> 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 vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1unJn9-001AGM-Pi%40256bit.org.