patch 9.1.1676: completion: long line shown twice

Commit: 
https://github.com/vim/vim/commit/57379302aa2a82ee0c9aca49ddd681308cf1483c
Author: Girish Palya <giris...@gmail.com>
Date:   Sat Aug 23 17:11:18 2025 +0200

    patch 9.1.1676: completion: long line shown twice
    
    Problem:  completion: long line shown twice
              (Maxim Kim)
    Solution: Fix the issue, disable an incorrect test.
              (Girish Palya)
    
    fixes: #18035
    closes: #18088
    
    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 4bde81c62..f4feec94b 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 7dbb743ec..3f5f852a4 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 000000000..a63ef65a5
--- /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 000000000..5bd4ea179
--- /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 000000000..d79a28453
--- /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 d2c9c7898..2ae27da7f 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*      \<C-B>\"\<CR>", '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*    \<C-B>\"\<CR>", 'xt')
+  " call assert_equal('"help a', @:)
   " non existing file
   call feedkeys(":e a1b2y3z4   \<C-B>\"\<CR>", 'xt')
   call assert_equal('"e a1b2y3z4', @:)
@@ -4351,7 +4354,7 @@ func Test_cmdcomplete_info()
     call feedkeys(":h echom\<cr>", "tx") " No expansion
     call assert_equal('{}', g:cmdcomplete_info)
     call feedkeys($":h echoms{trig}\<cr>", "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}\<cr>", "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}\<cr>", "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}\<cr>", "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 \<Tab>")
+  call VerifyScreenDump(buf, 'Test_long_line_noselect_1', {})
+
+  call term_sendkeys(buf, "\<Esc>:DoubleEntry \<Tab>\<C-N>")
+  call VerifyScreenDump(buf, 'Test_long_line_noselect_2', {})
+
+  call term_sendkeys(buf, "\<Esc>:DoubleEntry \<Tab>\<C-N>\<C-N>")
+  call VerifyScreenDump(buf, 'Test_long_line_noselect_3', {})
+  " 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 2262124dd..a1a48ad92 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 4a4a9b255..9845cbe78 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()
 

-- 
-- 
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/E1uppxS-00F5CD-Pf%40256bit.org.

Raspunde prin e-mail lui