Problem: 'findexpr' completion doesn't set v:fname to cmdline argument.
Solution: Set v:fname to the cmdline argument as-is (zeertzjq).
closes: #15934
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
-*eval.txt* For Vim version 9.1. Last change: 2024 Oct 22
+*eval.txt* For Vim version 9.1. Last change: 2024 Oct 28
VIM REFERENCE MANUAL by Bram Moolenaar
was used the value is 1, otherwise it is 0. Note that this
can only be used in autocommands. For user commands |<bang>|
can be used.
+
+ *v:cmdcomplete* *cmdcomplete-variable*
+v:cmdcomplete When evaluating 'findexpr': if 'findexpr' is used for cmdline
+ completion the value is |v:true|, otherwise it is |v:false|.
+
*v:collate* *collate-variable*
v:collate The current locale setting for collation order of the runtime
environment. This allows Vim scripts to be aware of the
-*options.txt* For Vim version 9.1. Last change: 2024 Oct 22
+*options.txt* For Vim version 9.1. Last change: 2024 Oct 28
VIM REFERENCE MANUAL by Bram Moolenaar
The expression is evaluated only once per |:find| command invocation.
The expression can process all the directories specified in 'path'.
+ The expression may be evaluated for command-line completion as well,
+ in which case the |v:cmdcomplete| variable will be set to |v:true|,
+ otherwise it will be set to |v:false|.
+
If a match is found, the expression should return a |List| containing
one or more file names. If a match is not found, the expression
should return an empty List.
>
" Use glob()
func FindExprGlob()
- return glob(v:fname, v:false, v:true)
+ let pat = v:cmdcomplete ? $'{v:fname}*' : v:fname
+ return glob(pat, v:false, v:true)
endfunc
set findexpr=FindExprGlob()
closure eval.txt /*closure*
cmdarg-variable eval.txt /*cmdarg-variable*
cmdbang-variable eval.txt /*cmdbang-variable*
+cmdcomplete-variable eval.txt /*cmdcomplete-variable*
cmdline-arguments vi_diff.txt /*cmdline-arguments*
cmdline-changed version5.txt /*cmdline-changed*
cmdline-completion cmdline.txt /*cmdline-completion*
v:charconvert_to eval.txt /*v:charconvert_to*
v:cmdarg eval.txt /*v:cmdarg*
v:cmdbang eval.txt /*v:cmdbang*
+v:cmdcomplete eval.txt /*v:cmdcomplete*
v:collate eval.txt /*v:collate*
v:colornames eval.txt /*v:colornames*
v:completed_item eval.txt /*v:completed_item*
&& xp->xp_context != EXPAND_FILES
&& xp->xp_context != EXPAND_FILES_IN_PATH
&& xp->xp_context != EXPAND_FILETYPE
+ && xp->xp_context != EXPAND_FINDEXPR
&& xp->xp_context != EXPAND_HELP
&& xp->xp_context != EXPAND_KEYMAP
&& xp->xp_context != EXPAND_OLD_SETTING
// For help tags the translation is done in find_help_tags().
// For a tag pattern starting with "/" no translation is needed.
- if (context == EXPAND_HELP
+ if (context == EXPAND_FINDEXPR
+ || context == EXPAND_HELP
|| context == EXPAND_COLORS
|| context == EXPAND_COMPILER
|| context == EXPAND_OWNSYNTAX
case CMD_sfind:
case CMD_tabfind:
if (xp->xp_context == EXPAND_FILES)
- xp->xp_context = EXPAND_FILES_IN_PATH;
+ xp->xp_context = *get_findexpr() != NUL ? EXPAND_FINDEXPR
+ : EXPAND_FILES_IN_PATH;
break;
case CMD_cd:
case CMD_chdir:
}
}
- if (xp->xp_context == EXPAND_FILES_IN_PATH && *get_findexpr() != NUL)
+ if (xp->xp_context == EXPAND_FINDEXPR)
{
#ifdef FEAT_EVAL
ret = expand_findexpr(pat, matches, numMatches);
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
|| xp->xp_context == EXPAND_FILES_IN_PATH
+ || xp->xp_context == EXPAND_FINDEXPR
|| xp->xp_context == EXPAND_DIRS_IN_CDPATH)
return expand_files_and_dirs(xp, pat, matches, numMatches, flags,
options);
EXTERN char e_winfixbuf_cannot_go_to_buffer[]
INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
EXTERN char e_invalid_return_type_from_findexpr[]
- INIT(= N_("E1514: findexpr did not return a List type"));
+ INIT(= N_("E1514: 'findexpr' did not return a List type"));
{VV_NAME("t_typealias", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("t_enum", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO},
+ {VV_NAME("cmdcomplete", VAR_BOOL), NULL, VV_RO},
};
// shorthand
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
set_vim_var_nr(VV_HLSEARCH, 1L);
set_vim_var_nr(VV_EXITING, VVAL_NULL);
+ set_vim_var_nr(VV_CMDCOMPLETE, VVAL_FALSE);
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
set_vim_var_list(VV_ERRORS, list_alloc());
set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
* the expression, v:fname is set to the ":find" command argument.
*/
static list_T *
-eval_findexpr(char_u *ptr)
+eval_findexpr(char_u *pat, int cmdcomplete)
{
sctx_T saved_sctx = current_sctx;
char_u *findexpr;
findexpr = get_findexpr();
- set_vim_var_string(VV_FNAME, ptr, -1);
+ set_vim_var_string(VV_FNAME, pat, -1);
+ set_vim_var_nr(VV_CMDCOMPLETE, cmdcomplete ? VVAL_TRUE : VVAL_FALSE);
current_sctx = curbuf->b_p_script_ctx[BV_FEXPR];
arg = skipwhite(findexpr);
clear_evalarg(&EVALARG_EVALUATE, NULL);
set_vim_var_string(VV_FNAME, NULL, 0);
+ set_vim_var_nr(VV_CMDCOMPLETE, VVAL_FALSE);
current_sctx = saved_sctx;
return retlist;
{
list_T *l;
int len;
- char_u *regpat;
*numMatches = 0;
*files = NULL;
- // File name expansion uses wildchars. But the 'findexpr' expression
- // expects a regular expression argument. So convert wildchars in the
- // argument to regular expression patterns.
- regpat = file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
- if (regpat == NULL)
- return FAIL;
-
- l = eval_findexpr(regpat);
-
- vim_free(regpat);
+ l = eval_findexpr(pat, TRUE);
if (l == NULL)
return FAIL;
cc = findarg[findarg_len];
findarg[findarg_len] = NUL;
- fname_list = eval_findexpr(findarg);
+ fname_list = eval_findexpr(findarg, FALSE);
fname_count = list_len(fname_list);
if (fname_count == 0)
" Expression returning a string
set findexpr='abc'
- call assert_fails('find Xfindexpr1.c', 'E1514: findexpr did not return a List type')
+ call assert_fails('find Xfindexpr1.c', "E1514: 'findexpr' did not return a List type")
set findexpr&
delfunc! FindExpr1
" Test for expanding the argument to the :find command using 'findexpr'
func Test_findexpr_expand_arg()
- func FindExpr1()
- let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
- return fnames->copy()->filter('v:val =~? v:fname')
+ let s:fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
+
+ " 'findexpr' that accepts a regular expression
+ func FindExprRegexp()
+ return s:fnames->copy()->filter('v:val =~? v:fname')
endfunc
- set findexpr=FindExpr1()
- call feedkeys(":find \<Tab>\<C-B>\"\<CR>", "xt")
- call assert_equal('"find Xfindexpr1.c', @:)
+ " 'findexpr' that accepts a glob
+ func FindExprGlob()
+ let pat = glob2regpat(v:cmdcomplete ? $'*{v:fname}*' : v:fname)
+ return s:fnames->copy()->filter('v:val =~? pat')
+ endfunc
+
+ for regexp in [v:true, v:false]
+ let &findexpr = regexp ? 'FindExprRegexp()' : 'FindExprGlob()'
+
+ call feedkeys(":find \<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindexpr1.c', @:)
+
+ call feedkeys(":find Xfind\<Tab>\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindexpr2.c', @:)
- call feedkeys(":find Xfind\<Tab>\<Tab>\<C-B>\"\<CR>", "xt")
- call assert_equal('"find Xfindexpr2.c', @:)
+ call assert_equal(s:fnames, getcompletion('find ', 'cmdline'))
+ call assert_equal(s:fnames, getcompletion('find Xfind', 'cmdline'))
- call feedkeys(":find *3*\<Tab>\<C-B>\"\<CR>", "xt")
- call assert_equal('"find Xfindexpr3.c', @:)
+ let pat = regexp ? 'X.*1\.c' : 'X*1.c'
+ call feedkeys($":find {pat}\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindexpr1.c', @:)
+ call assert_equal(['Xfindexpr1.c'], getcompletion($'find {pat}', 'cmdline'))
- call feedkeys(":find Xfind\<C-A>\<C-B>\"\<CR>", "xt")
- call assert_equal('"find Xfindexpr1.c Xfindexpr2.c Xfindexpr3.c', @:)
+ call feedkeys(":find 3\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindexpr3.c', @:)
+ call assert_equal(['Xfindexpr3.c'], getcompletion($'find 3', 'cmdline'))
- call feedkeys(":find abc\<Tab>\<C-B>\"\<CR>", "xt")
- call assert_equal('"find abc', @:)
+ call feedkeys(":find Xfind\<C-A>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find Xfindexpr1.c Xfindexpr2.c Xfindexpr3.c', @:)
+
+ call feedkeys(":find abc\<Tab>\<C-B>\"\<CR>", "xt")
+ call assert_equal('"find abc', @:)
+ call assert_equal([], getcompletion('find abc', 'cmdline'))
+ endfor
set findexpr&
- delfunc! FindExpr1
+ delfunc! FindExprRegexp
+ delfunc! FindExprGlob
+ unlet s:fnames
endfunc
" vim: shiftwidth=2 sts=2 expandtab
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 821,
/**/
820,
/**/
#define EXPAND_KEYMAP 58
#define EXPAND_DIRS_IN_CDPATH 59
#define EXPAND_SHELLCMDLINE 60
+#define EXPAND_FINDEXPR 61
// Values for exmode_active (0 is no exmode)
#define VV_TYPE_TYPEALIAS 107
#define VV_TYPE_ENUM 108
#define VV_TYPE_ENUMVALUE 109
-#define VV_LEN 110 // number of v: vars
+#define VV_CMDCOMPLETE 110
+#define VV_LEN 111 // number of v: vars
// used for v_number in VAR_BOOL and VAR_SPECIAL
#define VVAL_FALSE 0L // VAR_BOOL