]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1576: cannot easily trigger wildcard expansion v9.1.1576
authorGirish Palya <girishji@gmail.com>
Mon, 21 Jul 2025 19:26:32 +0000 (21:26 +0200)
committerChristian Brabandt <cb@256bit.org>
Mon, 21 Jul 2025 19:26:32 +0000 (21:26 +0200)
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 <girishji@gmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
15 files changed:
runtime/doc/builtin.txt
runtime/doc/cmdline.txt
runtime/doc/options.txt
runtime/doc/tags
runtime/doc/usr_41.txt
runtime/doc/version9.txt
runtime/syntax/vim.vim
src/cmdexpand.c
src/evalfunc.c
src/ex_getln.c
src/keymap.h
src/proto/ex_getln.pro
src/testdir/test_cmdline.vim
src/version.c
src/vim.h

index e1847b1d3b5874d7065bcf6eddff854c825a431b..c7d3b401ff3e101acf1c91dd9b5e15e8dba4d9fc 100644 (file)
@@ -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,
index a15debe5e8ff70a9f93719c0d33c7c457aa3b170..edc0f0fc36a08e0685eede668988db7fed2dcda6 100644 (file)
@@ -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.
 
index d4bdc8196c23e0d761cefe1705b5bff706b3c901..0a1d955fb3857fbd8ae9f29d9f847613cdebe091 100644 (file)
@@ -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 "\t".
-       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.
 
index 8e2fb0e968fcf20802f17a5b9800af6a11fd3218..5535036b2e22b8dfbffddc25f59ff37992da2974 100644 (file)
@@ -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*
index 02d58f0d8e7467b27484d41137bb21ec3fadf318..d263bed9ed77711d7b1cc05a0097dd1cb3098ab3 100644 (file)
@@ -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
index b49b86a2bd149f9ddf338b460f07990bbfd07279..79aec13adc0797261a98e2bd046fbafec4325d22 100644 (file)
@@ -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: ~
index c6f3943d2b9655b6e0c6e63d69d5ce5b70d4b15c..4e394d35ab6ddf7c289f8c42191b070750ba7c26 100644 (file)
@@ -2,7 +2,7 @@
 " Language:       Vim script
 " Maintainer:     Hirohito Higashi <h.east.727 ATMARK gmail.com>
 "         Doug Kearns <dougkearns@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
index a7a5acf95ff131d3c660f5e81ee691d812fbd8d7..bddfe8ca6a56e6c097fac99982acf232967e7ec3 100644 (file)
@@ -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)
     {
index ec21087e252c79f3ac673148ff97427a4a1d8c84..3c8339ee37e5307e2755cabb1854d165d2b780c9 100644 (file)
@@ -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,
index 5ee94d2197dfee1abb914a7e0f70d7150741aba0..560324c6e8fae26f8818b994ecf6ea3e5ef3a0c6 100644 (file)
@@ -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);
+    }
+}
index 29e2a055ca671850fcd65e5edb37424db4131987..e993e0999a437300d71d11706a95db6eae3d5042 100644 (file)
@@ -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
index 6c93ac755a24ca017f1cc6963710b07182f13d45..7270469a26c10c4d49f4047e57adb4cab2f84039 100644 (file)
@@ -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);
index 697b01acd1af07b05a3ecfd6ee62aa6d1c39200c..4e4d34caa6378496c299c2a0e42346184c8550c9 100644 (file)
@@ -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
index 8e4cfcc2b4707fdb741bc808ffe1dce0c9f80ffe..11357b22e0477d8acfade999dc30e92408824ae9 100644 (file)
@@ -719,6 +719,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1576,
 /**/
     1575,
 /**/
index 74a349dccc483afe8cb634ac5de294d96b75881b..94a10a32292ba3c5267fe09f4e5e0f0ea4bcd02e 100644 (file)
--- 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