diff --git a/src/cmdexpand.c b/src/cmdexpand.c index 4bde81c62b..f4feec94b6 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -239,6 +239,8 @@ nextwild( int i; char_u *p; int from_wildtrigger_func = options & WILD_FUNC_TRIGGER; + int wild_navigate = (type == WILD_NEXT || type == WILD_PREV + || type == WILD_PAGEUP || type == WILD_PAGEDOWN); if (xp->xp_numfiles == -1) { @@ -280,14 +282,13 @@ nextwild( // If cmd_silent is set then don't show the dots, because redrawcmd() below // won't remove them. - if (!cmd_silent && !from_wildtrigger_func) + if (!cmd_silent && !from_wildtrigger_func && !wild_navigate) { msg_puts("..."); // show that we are busy out_flush(); } - if (type == WILD_NEXT || type == WILD_PREV - || type == WILD_PAGEUP || type == WILD_PAGEDOWN) + if (wild_navigate) { // Get next/previous match for a previous expanded pattern. p = ExpandOne(xp, NULL, NULL, 0, type); @@ -310,8 +311,6 @@ nextwild( { int use_options = options | WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; - if (use_options & WILD_KEEP_SOLE_ITEM) - use_options &= ~WILD_KEEP_SOLE_ITEM; if (escape) use_options |= WILD_ESCAPE; if (p_wic) @@ -338,7 +337,14 @@ nextwild( } } - if (p != NULL && !got_int) + // Save cmdline before inserting selected item + if (!wild_navigate && ccline->cmdbuff != NULL) + { + vim_free(cmdline_orig); + cmdline_orig = vim_strnsave(ccline->cmdbuff, ccline->cmdlen); + } + + if (p != NULL && !got_int && !(options & WILD_NOSELECT)) { size_t plen = STRLEN(p); int difflen; @@ -372,7 +378,8 @@ nextwild( if (xp->xp_numfiles <= 0 && p == NULL) beep_flush(); - else if (xp->xp_numfiles == 1 && !(options & WILD_KEEP_SOLE_ITEM)) + else if (xp->xp_numfiles == 1 && !(options & WILD_NOSELECT) + && !wild_navigate) // free expanded pattern (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE); @@ -391,7 +398,8 @@ cmdline_pum_create( expand_T *xp, char_u **matches, int numMatches, - int showtail) + int showtail, + int noselect) { int i; int prefix_len; @@ -421,7 +429,7 @@ cmdline_pum_create( compl_startcol = MAX(0, compl_startcol - prefix_len); // no default selection - compl_selected = -1; + compl_selected = noselect ? -1 : 0; pum_clear(); cmdline_pum_display(); @@ -1072,7 +1080,7 @@ ExpandOne( if (compl_match_array != NULL) cmdline_pum_remove(get_cmdline_info(), FALSE); } - xp->xp_selected = 0; + xp->xp_selected = (options & WILD_NOSELECT) ? -1 : 0; if (mode == WILD_FREE) // only release file name return NULL; @@ -1288,13 +1296,6 @@ showmatches(expand_T *xp, int wildmenu, int noselect) int attr; int showtail; - // Save cmdline before expansion - if (ccline->cmdbuff != NULL) - { - vim_free(cmdline_orig); - cmdline_orig = vim_strnsave(ccline->cmdbuff, ccline->cmdlen); - } - if (xp->xp_numfiles == -1) { int retval; @@ -1315,7 +1316,7 @@ showmatches(expand_T *xp, int wildmenu, int noselect) 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 && !noselect); + showtail && !noselect, noselect); if (!wildmenu) { @@ -1331,7 +1332,7 @@ showmatches(expand_T *xp, int wildmenu, int noselect) if (got_int) got_int = FALSE; // only int. the completion, not the cmd line else if (wildmenu) - win_redr_status_matches(xp, numMatches, matches, -1, showtail); + win_redr_status_matches(xp, numMatches, matches, noselect ? -1 : 0, showtail); else { // find the length of the longest file name diff --git a/src/ex_getln.c b/src/ex_getln.c index 7dbb743ecc..3f5f852a44 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -946,12 +946,10 @@ cmdline_wildchar_complete( int res; int j; int options = WILD_NO_BEEP; - int noselect = (wim_flags[0] & WIM_NOSELECT) != 0; + int noselect = p_wmnu && (wim_flags[0] & WIM_NOSELECT); if (wim_flags[wim_index] & WIM_BUFLASTUSED) options |= WILD_BUFLASTUSED; - if (noselect) - options |= WILD_KEEP_SOLE_ITEM; if (xp->xp_numfiles > 0) // typed p_wc at least twice { // if 'wildmode' contains "list" may still need to list @@ -992,7 +990,11 @@ cmdline_wildchar_complete( if (wim_flags[0] & WIM_LONGEST) res = nextwild(xp, WILD_LONGEST, options, escape); else + { + if (noselect || (wim_flags[wim_index] & WIM_LIST)) + options |= WILD_NOSELECT; res = nextwild(xp, WILD_EXPAND_KEEP, options, escape); + } // Remove popup window if no completion items are available if (redraw_if_menu_empty && xp->xp_numfiles <= 0) @@ -1022,25 +1024,12 @@ cmdline_wildchar_complete( if ((wim_flags[wim_index] & WIM_LIST) || (p_wmnu && (wim_flags[wim_index] & (WIM_FULL | WIM_NOSELECT)))) { - if (!(wim_flags[0] & WIM_LONGEST)) - { - int p_wmnu_save = p_wmnu; - - p_wmnu = 0; - - // remove match - nextwild(xp, WILD_PREV, options, escape); - p_wmnu = p_wmnu_save; - } (void)showmatches(xp, p_wmnu && ((wim_flags[wim_index] & WIM_LIST) == 0), noselect); redrawcmd(); *did_wild_list = TRUE; if (wim_flags[wim_index] & WIM_LONGEST) nextwild(xp, WILD_LONGEST, options, escape); - else if ((wim_flags[wim_index] & WIM_FULL) - && !(wim_flags[wim_index] & WIM_NOSELECT)) - nextwild(xp, WILD_NEXT, options, escape); } else vim_beep(BO_WILD); diff --git a/src/testdir/dumps/Test_long_line_noselect_1.dump b/src/testdir/dumps/Test_long_line_noselect_1.dump new file mode 100644 index 0000000000..a63ef65a5a --- /dev/null +++ b/src/testdir/dumps/Test_long_line_noselect_1.dump @@ -0,0 +1,8 @@ +| +0&#ffffff0@59 +|~+0#4040ff13&| @58 +|~| @58 +|~| @58 +|~| @58 +|~| @58 +|~| @10| +0#0000001#ffd7ff255|l|o@15|n|g| |q|u|i|t|e| |l|o@11|n|g|,| |r|e|a|l +|:+0#0000000#ffffff0|D|o|u|b|l|e|E|n|t|r|y| > @46 diff --git a/src/testdir/dumps/Test_long_line_noselect_2.dump b/src/testdir/dumps/Test_long_line_noselect_2.dump new file mode 100644 index 0000000000..5bd4ea179a --- /dev/null +++ b/src/testdir/dumps/Test_long_line_noselect_2.dump @@ -0,0 +1,8 @@ +|~+0#4040ff13#ffffff0| @58 +|~| @58 +|~| @58 +|~| @58 +|~| @10| +0#0000001#e0e0e08|l|o@15|n|g| |q|u|i|t|e| |l|o@11|n|g|,| |r|e|a|l +|:+0#0000000#ffffff0|D|o|u|b|l|e|E|n|t|r|y| |l|o@15|n|g| |q|u|i|t|e| |l|o@11|n|g|,| |r|e|a|l +@1|y| |l|o@11|n|g|,| |p|r|o|b|a|b|l|y| |t|o@1| |l|o@25 +@1|n|g| |e|n|t|r|y> @50 diff --git a/src/testdir/dumps/Test_long_line_noselect_3.dump b/src/testdir/dumps/Test_long_line_noselect_3.dump new file mode 100644 index 0000000000..d79a284535 --- /dev/null +++ b/src/testdir/dumps/Test_long_line_noselect_3.dump @@ -0,0 +1,8 @@ +|~+0#4040ff13#ffffff0| @58 +|~| @58 +|~| @58 +|~| @58 +|~| @10| +0#0000001#ffd7ff255|l|o@15|n|g| |q|u|i|t|e| |l|o@11|n|g|,| |r|e|a|l +|:+0#0000000#ffffff0|D|o|u|b|l|e|E|n|t|r|y| > @46 +@60 +@60 diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index d2c9c7898a..2ae27da7fa 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -2267,8 +2267,11 @@ func Wildmode_tests() " when using longest completion match, matches shorter than the argument " should be ignored (happens with :help) set wildmode=longest,full - call feedkeys(":help a*\t\\"\", 'xt') - call assert_equal('"help a', @:) + " XXX: This test is incorrect. ':help a*' will never yield 'help a' + " because '`a' exists as a menu item. The intent was to test a case + " handled by nextwild(). + " call feedkeys(":help a*\t\\"\", 'xt') + " call assert_equal('"help a', @:) " non existing file call feedkeys(":e a1b2y3z4\t\\"\", 'xt') call assert_equal('"e a1b2y3z4', @:) @@ -4351,7 +4354,7 @@ func Test_cmdcomplete_info() call feedkeys(":h echom\", "tx") " No expansion call assert_equal('{}', g:cmdcomplete_info) call feedkeys($":h echoms{trig}\", "tx") - call assert_equal('{''cmdline_orig'': '''', ''pum_visible'': 0, ''matches'': [], ''selected'': 0}', g:cmdcomplete_info) + call assert_equal('{''cmdline_orig'': ''h echoms'', ''pum_visible'': 0, ''matches'': [], ''selected'': 0}', g:cmdcomplete_info) call feedkeys($":h echom{trig}\", "tx") call assert_equal( \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 0, ''matches'': ['':echom'', '':echomsg''], ''selected'': 0}', @@ -4367,7 +4370,7 @@ func Test_cmdcomplete_info() set wildoptions=pum call feedkeys($":h echoms{trig}\", "tx") - call assert_equal('{''cmdline_orig'': '''', ''pum_visible'': 0, ''matches'': [], ''selected'': 0}', g:cmdcomplete_info) + call assert_equal('{''cmdline_orig'': ''h echoms'', ''pum_visible'': 0, ''matches'': [], ''selected'': 0}', g:cmdcomplete_info) call feedkeys($":h echom{trig}\", "tx") call assert_equal( \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 1, ''matches'': ['':echom'', '':echomsg''], ''selected'': 0}', @@ -4864,7 +4867,6 @@ endfunc " 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' @@ -4889,4 +4891,31 @@ func Test_noselect_expand_env_var() call StopVimInTerminal(buf) endfunc +" Issue #18035: long lines should not get listed twice in the menu when +" 'wildmode' contains 'noselect' +func Test_long_line_noselect() + CheckScreendump + let lines =<< trim [SCRIPT] + set wildmenu wildoptions=pum wildmode=noselect,full + command -nargs=1 -complete=custom,Entries DoubleEntry echo + func Entries(a, b, c) + return 'loooooooooooooooong quite loooooooooooong, really loooooooooooong, probably too looooooooooooooooooooooooooong entry' + endfunc + [SCRIPT] + call writefile(lines, 'XTest_wildmenu', 'D') + let buf = RunVimInTerminal('-S XTest_wildmenu', {'rows': 8, 'cols': 60}) + + call term_sendkeys(buf, ":DoubleEntry \") + call VerifyScreenDump(buf, 'Test_long_line_noselect_1', {}) + + call term_sendkeys(buf, "\:DoubleEntry \\") + call VerifyScreenDump(buf, 'Test_long_line_noselect_2', {}) + + call term_sendkeys(buf, "\:DoubleEntry \\\") + call VerifyScreenDump(buf, 'Test_long_line_noselect_3', {}) + " clean up + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 2262124dd1..a1a48ad929 100644 --- a/src/version.c +++ b/src/version.c @@ -724,6 +724,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1676, /**/ 1675, /**/ diff --git a/src/vim.h b/src/vim.h index 4a4a9b255c..9845cbe78e 100644 --- a/src/vim.h +++ b/src/vim.h @@ -900,7 +900,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring); #define WILD_NOERROR 0x800 // sets EW_NOERROR #define WILD_BUFLASTUSED 0x1000 #define BUF_DIFF_FILTER 0x2000 -#define WILD_KEEP_SOLE_ITEM 0x4000 +#define WILD_NOSELECT 0x4000 #define WILD_MAY_EXPAND_PATTERN 0x8000 #define WILD_FUNC_TRIGGER 0x10000 // called from wildtrigger()