patch 9.1.1576: cannot easily trigger wildcard expansion

Commit: 
https://github.com/vim/vim/commit/b486ed8266d3b8cd1ffab7d7f302fbd6d5a55c70
Author: Girish Palya <giris...@gmail.com>
Date:   Mon Jul 21 21:26:32 2025 +0200

    patch 9.1.1576: cannot easily trigger wildcard expansion
    
    Problem:  cannot easily trigger wildcard expansion
    Solution: Introduce wildtrigger() function
              (Girish Palya)
    
    This PR introduces a new `wildtrigger()` function.
    
    See `:h wildtrigger()`
    
    `wildtrigger()` behaves like pressing the `wildchar,` but provides a
    more refined and controlled completion experience:
    
    - Suppresses beeps when no matches are found.
    - Avoids displaying irrelevant completions (like full command lists)
      when the prefix is insufficient or doesn't match.
    - Skips completion if the typeahead buffer has pending input or if a
      wildmenu is already active.
    - Does not print "..." before completion.
    
    This is an improvement on the `feedkeys()` based autocompletion script
    given in #16759.
    
    closes: #17806
    
    Signed-off-by: Girish Palya <giris...@gmail.com>
    Co-authored-by: zeertzjq <zeert...@outlook.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index e1847b1d3..c7d3b401f 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1,4 +1,4 @@
-*builtin.txt*  For Vim version 9.1.  Last change: 2025 Jul 17
+*builtin.txt*  For Vim version 9.1.  Last change: 2025 Jul 21
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -757,6 +757,7 @@ virtcol2col({winid}, {lnum}, {col})
                                Number  byte index of a character on screen
 visualmode([{expr}])           String  last visual mode used
 wildmenumode()                 Number  whether 'wildmenu' mode is active
+wildtrigger()                  Number  start wildcard expansion
 win_execute({id}, {command} [, {silent}])
                                String  execute {command} in window {id}
 win_findbuf({bufnr})           List    find windows containing {bufnr}
@@ -12331,6 +12332,33 @@ wildmenumode()                                 
*wildmenumode()*
                Return type: |Number|
 
 
+wildtrigger()                                          *wildtrigger()*
+               Start wildcard expansion in the command-line, using the
+               behavior defined by the 'wildmode' and 'wildoptions' settings.
+               See |cmdline-completion|.
+
+               This function also enables completion in search patterns such
+               as |/|, |?|, |:s|, |:g|, |:v| and |:vimgrep|.
+
+               Unlike pressing 'wildchar' manually, this function does not
+               produce a beep when no matches are found and generally
+               operates more quietly.  This makes it suitable for triggering
+               completion automatically, such as from an |:autocmd|.
+                                                       *cmdline-autocompletion*
+               Example: To make the completion menu pop up automatically as
+               you type on the command line, use: >
+                       autocmd CmdlineChanged [:/?] call wildtrigger()
+                       set wildmode=noselect:lastused,full wildoptions=pum
+<
+               To retain normal history navigation (up/down keys): >
+                       cnoremap <Up>   <C-U><Up>
+                       cnoremap <Down> <C-U><Down>
+<
+               Return value is always 0.
+
+               Return type: |Number|
+
+
 win_execute({id}, {command} [, {silent}])              *win_execute()*
                Like `execute()` but in the context of window {id}.
                The window will temporarily be made the current window,
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index a15debe5e..edc0f0fc3 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -1,4 +1,4 @@
-*cmdline.txt*   For Vim version 9.1.  Last change: 2025 Jun 28
+*cmdline.txt*   For Vim version 9.1.  Last change: 2025 Jul 21
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -479,6 +479,8 @@ When repeating 'wildchar' or CTRL-N you cycle through the 
matches, eventually
 ending up back to what was typed.  If the first match is not what you wanted,
 you can use <S-Tab> or CTRL-P to go straight back to what you typed.
 
+See also |wildtrigger()|.
+
 The 'wildmenu' option can be set to show the matches just above the command
 line.
 
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index d4bdc8196..0a1d955fb 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt*  For Vim version 9.1.  Last change: 2025 Jul 20
+*options.txt*  For Vim version 9.1.  Last change: 2025 Jul 21
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -9797,7 +9797,7 @@ A jump table for the options with a short description can 
be found at |Q_op|.
 <      'wildchar' also enables completion in search pattern contexts such as
        |/|, |?|, |:s|, |:g|, |:v|, and |:vim|.  To insert a literal <Tab>
        instead of triggering completion, type <C-V><Tab> or "  ".
-       See also |'wildoptions'|.
+       See also 'wildoptions' and |wildtrigger()|.
        NOTE: This option is set to the Vi default value when 'compatible' is
        set and to the Vim default value when 'compatible' is reset.
 
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 8e2fb0e96..5535036b2 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -6620,6 +6620,7 @@ cmdarg-variable   eval.txt        /*cmdarg-variable*
 cmdbang-variable       eval.txt        /*cmdbang-variable*
 cmdcomplete_info()     builtin.txt     /*cmdcomplete_info()*
 cmdline-arguments      vi_diff.txt     /*cmdline-arguments*
+cmdline-autocompletion builtin.txt     /*cmdline-autocompletion*
 cmdline-changed        version5.txt    /*cmdline-changed*
 cmdline-completion     cmdline.txt     /*cmdline-completion*
 cmdline-editing        cmdline.txt     /*cmdline-editing*
@@ -11608,6 +11609,7 @@ whitespace      pattern.txt     /*whitespace*
 wildcard       editing.txt     /*wildcard*
 wildcards      editing.txt     /*wildcards*
 wildmenumode() builtin.txt     /*wildmenumode()*
+wildtrigger()  builtin.txt     /*wildtrigger()*
 win-scrolled-resized   windows.txt     /*win-scrolled-resized*
 win16  os_win32.txt    /*win16*
 win32  os_win32.txt    /*win32*
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 02d58f0d8..d263bed9e 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1,4 +1,4 @@
-*usr_41.txt*   For Vim version 9.1.  Last change: 2025 Jul 05
+*usr_41.txt*   For Vim version 9.1.  Last change: 2025 Jul 21
 
                     VIM USER MANUAL - by Bram Moolenaar
 
@@ -1233,6 +1233,7 @@ Mappings and Menus:                           
*mapping-functions*
        mapset()                restore a mapping
        menu_info()             get information about a menu item
        wildmenumode()          check if the wildmode is active
+       wildtrigger()           start wildcard expansion
 
 Testing:                                   *test-functions*
        assert_equal()          assert that two expressions values are equal
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index b49b86a2b..79aec13ad 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt*  For Vim version 9.1.  Last change: 2025 Jul 20
+*version9.txt*  For Vim version 9.1.  Last change: 2025 Jul 21
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -41601,6 +41601,7 @@ Completion~
        "nosort"        - do not sort completion results
        "preinsert"     - highlight to be inserted values
        "nearest"       - sort completion results by distance to cursor
+- new function |wildtrigger()| to trigger wildcard expansion
 
 Platform specific~
 -----------------
@@ -41765,6 +41766,7 @@ Functions: ~
 |str2blob()|           convert a List of strings into a blob
 |test_null_tuple()|    return a null tuple
 |tuple2list()|         turn a Tuple of items into a List
+|wildtrigger()|                trigger wildcard expansion
 
 
 Autocommands: ~
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index c6f3943d2..4e394d35a 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -2,7 +2,7 @@
 " Language:       Vim script
 " Maintainer:     Hirohito Higashi <h.east.727 ATMARK gmail.com>
 "         Doug Kearns <dougkea...@gmail.com>
-" Last Change:    2025 Jul 18
+" Last Change:    2025 Jul 21
 " Former Maintainer: Charles E. Campbell
 
 " DO NOT CHANGE DIRECTLY.
@@ -141,7 +141,7 @@ syn match   vimUserAutoEvent        contained       
"\<\h\w*\>"     skipwhite nextgroup=vimUserAuto
 
 " Highlight commonly used Groupnames {{{2
 " GEN_SYN_VIM: vimGroup, START_STR='syn keyword vimGroup contained', END_STR=''
-syn keyword vimGroup contained Added Boolean Changed Character Comment 
Conditional Constant Debug Define Delimiter Error Exception Float Function 
Identifier Ignore Include Keyword Label Macro Number Operator PreCondit PreProc 
Removed Repeat Special SpecialChar SpecialComment Statement StorageClass String 
Structure Tag Todo Type Typedef Underlined
+syn keyword vimGroup contained Added Bold BoldItalic Boolean Changed Character 
Comment Conditional Constant Debug Define Delimiter Error Exception Float 
Function Identifier Ignore Include Italic Keyword Label Macro Number Operator 
PreCondit PreProc Removed Repeat Special SpecialChar SpecialComment Statement 
StorageClass String Structure Tag Todo Type Typedef Underlined
 
 " Default highlighting groups {{{2
 " GEN_SYN_VIM: vimHLGroup, START_STR='syn keyword vimHLGroup contained', 
END_STR=''
@@ -159,8 +159,8 @@ syn keyword vimFuncName contained histadd histdel histget 
histnr hlID hlexists h
 syn keyword vimFuncName contained mzeval nextnonblank ngettext nr2char or 
pathshorten perleval popup_atcursor popup_beval popup_clear popup_close 
popup_create popup_dialog popup_filter_menu popup_filter_yesno popup_findecho 
popup_findinfo popup_findpreview popup_getoptions popup_getpos popup_hide 
popup_list popup_locate popup_menu popup_move popup_notification popup_setbuf 
popup_setoptions popup_settext popup_show pow prevnonblank printf 
prompt_getprompt prompt_setcallback prompt_setinterrupt prompt_setprompt 
prop_add prop_add_list prop_clear prop_find prop_list prop_remove prop_type_add 
prop_type_change prop_type_delete prop_type_get prop_type_list pum_getpos 
pumvisible py3eval pyeval pyxeval rand range readblob readdir readdirex 
readfile reduce reg_executing
 syn keyword vimFuncName contained reg_recording reltime reltimefloat 
reltimestr remote_expr remote_foreground remote_peek remote_read remote_send 
remote_startserver remove rename repeat resolve reverse round rubyeval 
screenattr screenchar screenchars screencol screenpos screenrow screenstring 
search searchcount searchdecl searchpair searchpairpos searchpos server2client 
serverlist setbufline setbufvar setcellwidths setcharpos setcharsearch 
setcmdline setcmdpos setcursorcharpos setenv setfperm setline setloclist 
setmatches setpos setqflist setreg settabvar settabwinvar settagstack setwinvar 
sha256 shellescape shiftwidth sign_define sign_getdefined sign_getplaced 
sign_jump sign_place sign_placelist sign_undefine sign_unplace sign_unplacelist 
simplify sin sinh slice
 syn keyword vimFuncName contained sort sound_clear sound_playevent 
sound_playfile sound_stop soundfold spellbadword spellsuggest split sqrt srand 
state str2blob str2float str2list str2nr strcharlen strcharpart strchars 
strdisplaywidth strftime strgetchar stridx string strlen strpart strptime 
strridx strtrans strutf16len strwidth submatch substitute swapfilelist swapinfo 
swapname synID synIDattr synIDtrans synconcealed synstack system systemlist 
tabpagebuflist tabpagenr tabpagewinnr tagfiles taglist tan tanh tempname 
term_dumpdiff term_dumpload term_dumpwrite term_getaltscreen term_getansicolors 
term_getattr term_getcursor term_getjob term_getline term_getscrolled 
term_getsize term_getstatus term_gettitle term_gettty term_list term_scrape 
term_sendkeys term_setansicolors
-syn keyword vimFuncName contained term_setapi term_setkill term_setrestore 
term_setsize term_start term_wait terminalprops test_alloc_fail test_autochdir 
test_feedinput test_garbagecollect_now test_garbagecollect_soon test_getvalue 
test_gui_event test_ignore_error test_mswin_event test_null_blob 
test_null_channel test_null_dict test_null_function test_null_job 
test_null_list test_null_partial test_null_string test_null_tuple 
test_option_not_set test_override test_refcount test_setmouse test_settime 
test_srand_seed test_unknown test_void timer_info timer_pause timer_start 
timer_stop timer_stopall tolower toupper tr trim trunc tuple2list type typename 
undofile undotree uniq utf16idx values virtcol virtcol2col visualmode 
wildmenumode win_execute win_findbuf win_getid
-syn keyword vimFuncName contained win_gettype win_gotoid win_id2tabwin 
win_id2win win_move_separator win_move_statusline win_screenpos win_splitmove 
winbufnr wincol windowsversion winheight winlayout winline winnr winrestcmd 
winrestview winsaveview winwidth wordcount writefile xor
+syn keyword vimFuncName contained term_setapi term_setkill term_setrestore 
term_setsize term_start term_wait terminalprops test_alloc_fail test_autochdir 
test_feedinput test_garbagecollect_now test_garbagecollect_soon test_getvalue 
test_gui_event test_ignore_error test_mswin_event test_null_blob 
test_null_channel test_null_dict test_null_function test_null_job 
test_null_list test_null_partial test_null_string test_null_tuple 
test_option_not_set test_override test_refcount test_setmouse test_settime 
test_srand_seed test_unknown test_void timer_info timer_pause timer_start 
timer_stop timer_stopall tolower toupper tr trim trunc tuple2list type typename 
undofile undotree uniq utf16idx values virtcol virtcol2col visualmode 
wildmenumode wildtrigger win_execute win_findbuf
+syn keyword vimFuncName contained win_getid win_gettype win_gotoid 
win_id2tabwin win_id2win win_move_separator win_move_statusline win_screenpos 
win_splitmove winbufnr wincol windowsversion winheight winlayout winline winnr 
winrestcmd winrestview winsaveview winwidth wordcount writefile xor
 " Predefined variable names {{{2
 " GEN_SYN_VIM: vimVarName, START_STR='syn keyword vimVimVarName contained', 
END_STR=''
 syn keyword vimVimVarName contained count count1 prevcount errmsg warningmsg 
statusmsg shell_error this_session version lnum termresponse fname lang lc_time 
ctype charconvert_from charconvert_to fname_in fname_out fname_new fname_diff 
cmdarg foldstart foldend folddashes foldlevel progname servername dying 
exception throwpoint register cmdbang insertmode val key profiling fcs_reason 
fcs_choice beval_bufnr beval_winnr beval_winid beval_lnum beval_col beval_text 
scrollstart swapname swapchoice swapcommand char mouse_win mouse_winid 
mouse_lnum mouse_col operator searchforward hlsearch oldfiles windowid progpath 
completed_item option_new option_old option_oldlocal option_oldglobal 
option_command option_type errors false true none null numbermax numbermin 
numbersize
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index a7a5acf95..bddfe8ca6 100644
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -238,6 +238,7 @@ nextwild(
     cmdline_info_T     *ccline = get_cmdline_info();
     int                i;
     char_u     *p;
+    int                from_wildtrigger_func = options & WILD_FUNC_TRIGGER;
 
     if (xp->xp_numfiles == -1)
     {
@@ -269,17 +270,22 @@ nextwild(
        return FAIL;
     }
 
+    i = (int)(xp->xp_pattern - ccline->cmdbuff);
+    xp->xp_pattern_len = ccline->cmdpos - i;
+
+    // Skip showing matches if prefix is invalid during wildtrigger()
+    if (from_wildtrigger_func && xp->xp_context == EXPAND_COMMANDS
+           && xp->xp_pattern_len == 0)
+       return FAIL;
+
     // If cmd_silent is set then don't show the dots, because redrawcmd() below
     // won't remove them.
-    if (!cmd_silent)
+    if (!cmd_silent && !from_wildtrigger_func)
     {
        msg_puts("...");            // show that we are busy
        out_flush();
     }
 
-    i = (int)(xp->xp_pattern - ccline->cmdbuff);
-    xp->xp_pattern_len = ccline->cmdpos - i;
-
     if (type == WILD_NEXT || type == WILD_PREV
            || type == WILD_PAGEUP || type == WILD_PAGEDOWN)
     {
diff --git a/src/evalfunc.c b/src/evalfunc.c
index ec21087e2..3c8339ee3 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -3126,6 +3126,8 @@ static funcentry_T global_functions[] =
                        ret_string,         f_visualmode},
     {"wildmenumode",   0, 0, 0,            NULL,
                        ret_number,         f_wildmenumode},
+    {"wildtrigger",    0, 0, 0,            NULL,
+                       ret_void,           f_wildtrigger},
     {"win_execute",    2, 3, FEARG_2,      arg23_win_execute,
                        ret_string,         f_win_execute},
     {"win_findbuf",    1, 1, FEARG_1,      arg1_number,
diff --git a/src/ex_getln.c b/src/ex_getln.c
index 5ee94d219..560324c6e 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -957,9 +957,11 @@ cmdline_wildchar_complete(
     }
     else                   // typed p_wc first time
     {
-       if (c == p_wc || c == p_wcm)
+       if (c == p_wc || c == p_wcm || c == K_WILD)
        {
            options |= WILD_MAY_EXPAND_PATTERN;
+           if (c == K_WILD)
+               options |= WILD_FUNC_TRIGGER;
            if (pre_incsearch_pos)
                xp->xp_pre_incsearch_pos = *pre_incsearch_pos;
            else
@@ -1395,7 +1397,7 @@ cmdline_browse_history(
     for (;;)
     {
        // one step backwards
-       if (c == K_UP|| c == K_S_UP || c == Ctrl_P
+       if (c == K_UP || c == K_S_UP || c == Ctrl_P
                || c == K_PAGEUP || c == K_KPAGEUP)
        {
            if (hiscnt == get_hislen()) // first time
@@ -1818,9 +1820,9 @@ getcmdline_int(
      */
     for (;;)
     {
-       int trigger_cmdlinechanged = TRUE;
-       int end_wildmenu;
-       int prev_cmdpos = ccline.cmdpos;
+       int     trigger_cmdlinechanged = TRUE;
+       int     end_wildmenu;
+       int     prev_cmdpos = ccline.cmdpos;
 
        VIM_CLEAR(prev_cmdbuff);
 
@@ -2058,9 +2060,11 @@ getcmdline_int(
            }
        }
 
-       // Completion for 'wildchar' or 'wildcharm' key.
-       if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
+       // Completion for 'wildchar', 'wildcharm', and wildtrigger()
+       if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm || c == K_WILD)
        {
+           if (c == K_WILD)
+               ++emsg_silent;  // Silence the bell
            res = cmdline_wildchar_complete(c, firstc != '@', &did_wild_list,
                    &wim_index, &xpc, &gotesc,
 #ifdef FEAT_SEARCH_EXTRA
@@ -2069,8 +2073,12 @@ getcmdline_int(
                    NULL
 #endif
                    );
+           if (c == K_WILD)
+               --emsg_silent;
            if (res == CMDLINE_CHANGED)
                goto cmdline_changed;
+           if (c == K_WILD)
+               goto cmdline_not_changed;
        }
 
        gotesc = FALSE;
@@ -5109,3 +5117,30 @@ get_user_input(
     cmd_silent = cmd_silent_save;
 }
 #endif
+
+/*
+ * "wildtrigger()" function
+ */
+    void
+f_wildtrigger(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+    if (!(State & MODE_CMDLINE) || char_avail() || wild_menu_showing
+           || cmdline_pum_active())
+       return;
+
+    int cmd_type = get_cmdline_type();
+
+    if (cmd_type == ':' || cmd_type == '/' || cmd_type == '?')
+    {
+       // Add K_WILD as a single special key
+       char_u  key_string[4];
+
+       key_string[0] = K_SPECIAL;
+       key_string[1] = KS_EXTRA;
+       key_string[2] = KE_WILD;
+       key_string[3] = NUL;
+
+       // Insert it into the typeahead buffer
+       ins_typebuf(key_string, REMAP_NONE, 0, TRUE, FALSE);
+    }
+}
diff --git a/src/keymap.h b/src/keymap.h
index 29e2a055c..e993e0999 100644
--- a/src/keymap.h
+++ b/src/keymap.h
@@ -279,6 +279,7 @@ enum key_extra
     , KE_S_BS = 105            // shift + <BS>
     , KE_SID = 106             // <SID> special key, followed by {nr};
     , KE_ESC = 107             // used for K_ESC
+    , KE_WILD = 108            // triggers wildmode completion
 };
 
 /*
@@ -491,6 +492,8 @@ enum key_extra
 #define K_SCRIPT_COMMAND TERMCAP2KEY(KS_EXTRA, KE_SCRIPT_COMMAND)
 #define K_SID          TERMCAP2KEY(KS_EXTRA, KE_SID)
 
+#define K_WILD         TERMCAP2KEY(KS_EXTRA, KE_WILD)
+
 // Bits for modifier mask
 // 0x01 cannot be used, because the modifier must be 0x02 or higher
 #define MOD_MASK_SHIFT     0x02
diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro
index 6c93ac755..7270469a2 100644
--- a/src/proto/ex_getln.pro
+++ b/src/proto/ex_getln.pro
@@ -39,6 +39,7 @@ void f_getcmdscreenpos(typval_T *argvars, typval_T *rettv);
 void f_getcmdtype(typval_T *argvars, typval_T *rettv);
 void f_setcmdline(typval_T *argvars, typval_T *rettv);
 void f_setcmdpos(typval_T *argvars, typval_T *rettv);
+void f_wildtrigger(typval_T *argvars, typval_T *rettv);
 int get_cmdline_firstc(void);
 int get_list_range(char_u **str, int *num1, int *num2);
 char *did_set_cedit(optset_T *args);
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 697b01acd..4e4d34caa 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -4329,42 +4329,63 @@ func Test_cmdcomplete_info()
     autocmd CmdlineLeavePre * call expand('test_cmdline.*')
     autocmd CmdlineLeavePre * let g:cmdcomplete_info = 
string(cmdcomplete_info())
   augroup END
-  new
+
+  " Disable char_avail so that wildtrigger() does not bail out
+  call test_override("char_avail", 1)
+
+  cnoremap <F8> <C-R>=wildtrigger()[-1]<CR>
+
   call assert_equal({}, cmdcomplete_info())
-  call feedkeys(":h echom\<cr>", "tx") " No expansion
-  call assert_equal('{}', g:cmdcomplete_info)
-  call feedkeys(":h echoms\<tab>\<cr>", "tx")
-  call assert_equal('{''cmdline_orig'': '''', ''pum_visible'': 0, ''matches'': 
[], ''selected'': 0}', g:cmdcomplete_info)
-  call feedkeys(":h echom\<tab>\<cr>", "tx")
-  call assert_equal(
-        \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 0, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 0}',
-        \ g:cmdcomplete_info)
-  call feedkeys(":h echom\<tab>\<tab>\<cr>", "tx")
-  call assert_equal(
-        \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 0, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 1}',
-        \ g:cmdcomplete_info)
-  call feedkeys(":h echom\<tab>\<tab>\<tab>\<cr>", "tx")
-  call assert_equal(
-        \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 0, ''matches'': 
['':echom'', '':echomsg''], ''selected'': -1}',
-        \ g:cmdcomplete_info)
 
-  set wildoptions=pum
-  call feedkeys(":h echoms\<tab>\<cr>", "tx")
-  call assert_equal('{''cmdline_orig'': '''', ''pum_visible'': 0, ''matches'': 
[], ''selected'': 0}', g:cmdcomplete_info)
-  call feedkeys(":h echom\<tab>\<cr>", "tx")
-  call assert_equal(
-        \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 1, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 0}',
-        \ g:cmdcomplete_info)
-  call feedkeys(":h echom\<tab>\<tab>\<cr>", "tx")
-  call assert_equal(
-        \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 1, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 1}',
-        \ g:cmdcomplete_info)
-  call feedkeys(":h echom\<tab>\<tab>\<tab>\<cr>", "tx")
-  call assert_equal(
-        \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 1, ''matches'': 
['':echom'', '':echomsg''], ''selected'': -1}',
-        \ g:cmdcomplete_info)
-  bw!
-  set wildoptions&
+  for trig in ["\<Tab>", "\<F8>"]
+    new
+    call assert_equal({}, 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 feedkeys($":h echom{trig}\<cr>", "tx")
+    call assert_equal(
+          \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 0, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 0}',
+          \ g:cmdcomplete_info)
+    call feedkeys($":h echom{trig}\<tab>\<cr>", "tx")
+    call assert_equal(
+          \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 0, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 1}',
+          \ g:cmdcomplete_info)
+    call feedkeys($":h echom{trig}\<tab>\<tab>\<cr>", "tx")
+    call assert_equal(
+          \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 0, ''matches'': 
['':echom'', '':echomsg''], ''selected'': -1}',
+          \ g: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 feedkeys($":h echom{trig}\<cr>", "tx")
+    call assert_equal(
+          \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 1, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 0}',
+          \ g:cmdcomplete_info)
+    call feedkeys($":h echom{trig}\<tab>\<cr>", "tx")
+    call assert_equal(
+          \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 1, ''matches'': 
['':echom'', '':echomsg''], ''selected'': 1}',
+          \ g:cmdcomplete_info)
+    call feedkeys($":h echom{trig}\<tab>\<tab>\<cr>", "tx")
+    call assert_equal(
+          \ '{''cmdline_orig'': ''h echom'', ''pum_visible'': 1, ''matches'': 
['':echom'', '':echomsg''], ''selected'': -1}',
+          \ g:cmdcomplete_info)
+    bw!
+    set wildoptions&
+  endfor
+
+  " wildtrigger() should not show matches when prefix is invalid
+  for pat in ["", " ", "22"]
+    call feedkeys($":{pat}\<F8>\<cr>", "tx") " No expansion
+    call assert_equal('{}', g:cmdcomplete_info)
+  endfor
+
+  augroup test_CmdlineLeavePre | autocmd! | augroup END
+  call test_override("char_avail", 0)
+  unlet g:cmdcomplete_info
+  cunmap <F8>
 endfunc
 
 func Test_redrawtabpanel_error()
@@ -4387,6 +4408,7 @@ func Test_search_complete()
 
   new
   cnoremap <buffer><expr> <F9> GetComplInfo()
+  cnoremap <buffer> <F8> <C-R>=wildtrigger()[-1]<CR>
 
   " Pressing <Tab> inserts tab character
   set wildchar=0
@@ -4397,7 +4419,7 @@ func Test_search_complete()
 
   call setline(1, ['the', 'these', 'thethe', 'thethere', 'foobar'])
 
-  for trig in ["\<tab>", "\<c-z>"]
+  for trig in ["\<tab>", "\<c-z>", "\<F8>"]
     " Test menu first item and order
     call feedkeys($"gg2j/t{trig}\<f9>", 'tx')
     call assert_equal(['the', 'thethere', 'there', 'these', 'thethe'], 
g:compl_info.matches)
@@ -4610,10 +4632,11 @@ func Test_range_complete()
   endfunc
   new
   cnoremap <buffer><expr> <F9> GetComplInfo()
+  cnoremap <buffer> <F8> <C-R>=wildtrigger()[-1]<CR>
 
   call setline(1, ['ab', 'ba', 'ca', 'af'])
 
-  for trig in ["\<tab>", "\<c-z>"]
+  for trig in ["\<tab>", "\<c-z>", "\<F8>"]
     call feedkeys($":%s/a{trig}\<f9>", 'xt')
     call assert_equal(['ab', 'a', 'af'], g:compl_info.matches)
     call feedkeys($":vim9cmd :%s/a{trig}\<f9>", 'xt')
@@ -4699,25 +4722,35 @@ func Test_cmdline_changed()
     autocmd CmdlineChanged * if getcmdline() =~ g:cmdprefix | let 
g:cmdchg_count += 1 | endif
   augroup END
 
+  " Disable char_avail so that wildtrigger() does not bail out
+  call test_override("char_avail", 1)
+
   new
+  cnoremap <buffer> <F8> <C-R>=wildtrigger()[-1]<CR>
   set wildmenu
   set wildmode=full
 
   let g:cmdprefix = 'echomsg'
-  let g:cmdchg_count = 0
-  call feedkeys(":echomsg\<Tab>", "tx")
-  call assert_equal(1, g:cmdchg_count) " once only for 'g', not again for <Tab>
+  for trig in ["\<Tab>", "\<F8>"]
+    let g:cmdchg_count = 0
+    call feedkeys($":echomsg{trig}", "tx")
+    call assert_equal(1, g:cmdchg_count) " once only for 'g', not again for 
<Tab>
+  endfor
 
-  let g:cmdchg_count = 0
   let g:cmdprefix = 'echo'
-  call feedkeys(":ech\<Tab>", "tx")
-  call assert_equal(1, g:cmdchg_count) " (once for 'h' and) once for 'o'
+  for trig in ["\<Tab>", "\<F8>"]
+    let g:cmdchg_count = 0
+    call feedkeys($":ech{trig}", "tx")
+    call assert_equal(1, g:cmdchg_count) " (once for 'h' and) once for 'o'
+  endfor
 
   set wildmode=noselect,full
-  let g:cmdchg_count = 0
   let g:cmdprefix = 'ech'
-  call feedkeys(":ech\<Tab>", "tx")
-  call assert_equal(1, g:cmdchg_count) " once for 'h', not again for <tab>
+  for trig in ["\<Tab>", "\<F8>"]
+    let g:cmdchg_count = 0
+    call feedkeys($":ech{trig}", "tx")
+    call assert_equal(1, g:cmdchg_count) " once for 'h', not again for <tab>
+  endfor
 
   command! -nargs=+ -complete=custom,TestComplete Test echo
 
@@ -4726,10 +4759,12 @@ func Test_cmdline_changed()
   endfunc
 
   set wildoptions=fuzzy wildmode=full
-  let g:cmdchg_count = 0
   let g:cmdprefix = 'Test \(AbC\|abc\)'
-  call feedkeys(":Test abc\<Tab>", "tx")
-  call assert_equal(2, g:cmdchg_count) " once for 'c', again for 'AbC'
+  for trig in ["\<Tab>", "\<F8>"]
+    let g:cmdchg_count = 0
+    call feedkeys($":Test abc{trig}", "tx")
+    call assert_equal(2, g:cmdchg_count) " once for 'c', again for 'AbC'
+  endfor
 
   bw!
   set wildmode& wildmenu& wildoptions&
@@ -4738,6 +4773,7 @@ func Test_cmdline_changed()
   unlet g:cmdprefix
   delfunc TestComplete
   delcommand Test
+  call test_override("char_avail", 0)
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 8e4cfcc2b..11357b22e 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 */
+/**/
+    1576,
 /**/
     1575,
 /**/
diff --git a/src/vim.h b/src/vim.h
index 74a349dcc..94a10a322 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -897,6 +897,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 #define BUF_DIFF_FILTER                    0x2000
 #define WILD_KEEP_SOLE_ITEM        0x4000
 #define WILD_MAY_EXPAND_PATTERN            0x8000
+#define WILD_FUNC_TRIGGER          0x10000 // called from wildtrigger()
 
 // Flags for expand_wildcards()
 #define EW_DIR         0x01    // include directory names

-- 
-- 
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/E1udwRg-002B9t-99%40256bit.org.

Raspunde prin e-mail lui