From 99d688e6459c7963b00a95d544de7a3de951a70b Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Mon, 3 Mar 2025 17:51:42 +0100 Subject: vim-patch:9.1.1166: command-line auto-completion hard with wildmenu Problem: command-line auto-completion hard with wildmenu Solution: implement "noselect" wildoption value (Girish Palya) When `noselect` is present in `wildmode` and 'wildmenu' is enabled, the completion menu appears without pre-selecting the first item. This change makes it easier to implement command-line auto-completion, where the menu dynamically appears as characters are typed, and `` can be used to manually select an item. This can be achieved by leveraging the `CmdlineChanged` event to insert `wildchar(m)`, triggering completion menu. Without this change, auto-completion using the 'wildmenu' mechanism is not feasible, as it automatically inserts the first match, preventing dynamic selection. The following Vimscript snippet demonstrates how to configure auto-completion using `noselect`: ```vim vim9script set wim=noselect:lastused,full wop=pum wcm= wmnu autocmd CmdlineChanged : timer_start(0, function(CmdComplete, [getcmdline()])) def CmdComplete(cur_cmdline: string, timer: number) var [cmdline, curpos] = [getcmdline(), getcmdpos()] if cur_cmdline ==# cmdline # Avoid completing each character in keymaps and pasted text && !pumvisible() && curpos == cmdline->len() + 1 if cmdline[curpos - 2] =~ '[\w*/:]' # Reduce noise by completing only selected characters feedkeys("\", "ti") set eventignore+=CmdlineChanged # Suppress redundant completion attempts timer_start(0, (_) => { getcmdline()->substitute('\%x00$', '', '')->setcmdline() # Remove if no completion items exist set eventignore-=CmdlineChanged }) endif endif enddef ``` fixes: vim/vim#16551 closes: vim/vim#16759 https://github.com/vim/vim/commit/2bacc3e5fb3569e0fd98e129cb1e422ca18b80a6 Cherry-pick Wildmode_Tests() change from patch 9.0.0418. Co-authored-by: Girish Palya Signed-off-by: Tomas Slusny --- src/nvim/ex_getln.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/nvim/ex_getln.c') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index fc20748309..dbe3505e13 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1082,6 +1082,9 @@ static int command_line_wildchar_complete(CommandLineState *s) if (wim_flags[s->wim_index] & kOptWimFlagLastused) { options |= WILD_BUFLASTUSED; } + if (wim_flags[0] & kOptWimFlagNoselect) { + options |= WILD_KEEP_SOLE_ITEM; + } if (s->xpc.xp_numfiles > 0) { // typed p_wc at least twice // if 'wildmode' contains "list" may still need to list if (s->xpc.xp_numfiles > 1 @@ -1124,19 +1127,20 @@ static int command_line_wildchar_complete(CommandLineState *s) // when more than one match, and 'wildmode' first contains // "list", or no change and 'wildmode' contains "longest,list", // list all matches - if (res == OK && s->xpc.xp_numfiles > 1) { + if (res == OK + && s->xpc.xp_numfiles > ((wim_flags[s->wim_index] & kOptWimFlagNoselect) ? 0 : 1)) { // a "longest" that didn't do anything is skipped (but not // "list:longest") if (wim_flags[0] == kOptWimFlagLongest && ccline.cmdpos == j) { s->wim_index = 1; } if ((wim_flags[s->wim_index] & kOptWimFlagList) - || (p_wmnu && (wim_flags[s->wim_index] & kOptWimFlagFull) != 0)) { + || (p_wmnu && (wim_flags[s->wim_index] & (kOptWimFlagFull|kOptWimFlagNoselect)))) { if (!(wim_flags[0] & kOptWimFlagLongest)) { int p_wmnu_save = p_wmnu; p_wmnu = 0; // remove match - nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@'); + nextwild(&s->xpc, WILD_PREV, 0 | (options & ~kOptWimFlagNoselect), s->firstc != '@'); p_wmnu = p_wmnu_save; } @@ -1146,7 +1150,8 @@ static int command_line_wildchar_complete(CommandLineState *s) if (wim_flags[s->wim_index] & kOptWimFlagLongest) { nextwild(&s->xpc, WILD_LONGEST, options, s->firstc != '@'); - } else if (wim_flags[s->wim_index] & kOptWimFlagFull) { + } else if ((wim_flags[s->wim_index] & kOptWimFlagFull) + && !(wim_flags[s->wim_index] & kOptWimFlagNoselect)) { nextwild(&s->xpc, WILD_NEXT, options, s->firstc != '@'); } } else { @@ -2875,6 +2880,8 @@ int check_opt_wim(void) new_wim_flags[idx] |= kOptWimFlagList; } else if (i == 8 && strncmp(p, "lastused", 8) == 0) { new_wim_flags[idx] |= kOptWimFlagLastused; + } else if (i == 8 && strncmp(p, "noselect", 8) == 0) { + new_wim_flags[idx] |= kOptWimFlagNoselect; } else { return FAIL; } -- cgit From e56f7413505c76b7b57ced2552479ad02875bc74 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 4 Mar 2025 06:00:24 +0800 Subject: vim-patch:9.1.1168: wrong flags passed down to nextwild() Problem: wrong flags passed down to nextwild() (zeertzjq, after v9.1.1166) Solution: only pass options flags (Girish Palya) `options` needs to be passed into nextwild() since it may contain WILD_KEEP_SOLE_ITEM which prevents the menu items list from getting freed if there is only 1 item left (if `noselect` is set). closes: vim/vim#16778 https://github.com/vim/vim/commit/d2219d547d2e70ba7af498866b0d12d3b6517b16 Co-authored-by: Girish Palya --- src/nvim/ex_getln.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_getln.c') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index dbe3505e13..240bdae6cb 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1140,7 +1140,7 @@ static int command_line_wildchar_complete(CommandLineState *s) int p_wmnu_save = p_wmnu; p_wmnu = 0; // remove match - nextwild(&s->xpc, WILD_PREV, 0 | (options & ~kOptWimFlagNoselect), s->firstc != '@'); + nextwild(&s->xpc, WILD_PREV, options, s->firstc != '@'); p_wmnu = p_wmnu_save; } -- cgit