0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 8.2.4679: cannot have expandcmd() give an error message for mistakes

Problem:    Cannot have expandcmd() give an error message for mistakes.
Solution:   Add an optional argument to give errors. Fix memory leak when
            expanding files fails. (Yegappan Lakshmanan, closes #10071)
This commit is contained in:
Yegappan Lakshmanan
2022-04-03 21:30:32 +01:00
committed by Bram Moolenaar
parent 1061195057
commit 2b74b6805b
6 changed files with 50 additions and 13 deletions

View File

@@ -161,7 +161,8 @@ exists_compiled({expr}) Number |TRUE| if {expr} exists at compile time
exp({expr}) Float exponential of {expr} exp({expr}) Float exponential of {expr}
expand({expr} [, {nosuf} [, {list}]]) expand({expr} [, {nosuf} [, {list}]])
any expand special keywords in {expr} any expand special keywords in {expr}
expandcmd({expr}) String expand {expr} like with `:edit` expandcmd({string} [, {options}])
String expand {string} like with `:edit`
extend({expr1}, {expr2} [, {expr3}]) extend({expr1}, {expr2} [, {expr3}])
List/Dict insert items of {expr2} into {expr1} List/Dict insert items of {expr2} into {expr1}
extendnew({expr1}, {expr2} [, {expr3}]) extendnew({expr1}, {expr2} [, {expr3}])
@@ -2293,18 +2294,27 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
Can also be used as a |method|: > Can also be used as a |method|: >
Getpattern()->expand() Getpattern()->expand()
expandcmd({string}) *expandcmd()* expandcmd({string} [, {options}]) *expandcmd()*
Expand special items in String {string} like what is done for Expand special items in String {string} like what is done for
an Ex command such as `:edit`. This expands special keywords, an Ex command such as `:edit`. This expands special keywords,
like with |expand()|, and environment variables, anywhere in like with |expand()|, and environment variables, anywhere in
{string}. "~user" and "~/path" are only expanded at the {string}. "~user" and "~/path" are only expanded at the
start. start.
The following items are supported in the {options} Dict
argument:
errmsg If set to TRUE, error messages are displayed
if an error is encountered during expansion.
By default, error messages are not displayed.
Returns the expanded string. If an error is encountered Returns the expanded string. If an error is encountered
during expansion, the unmodified {string} is returned. during expansion, the unmodified {string} is returned.
Example: > Example: >
:echo expandcmd('make %<.o') :echo expandcmd('make %<.o')
< make /path/runtime/doc/builtin.o ~ make /path/runtime/doc/builtin.o
:echo expandcmd('make %<.o', {'errmsg': v:true})
<
Can also be used as a |method|: > Can also be used as a |method|: >
GetCommand()->expandcmd() GetCommand()->expandcmd()
< <

View File

@@ -1761,7 +1761,7 @@ static funcentry_T global_functions[] =
ret_float, FLOAT_FUNC(f_exp)}, ret_float, FLOAT_FUNC(f_exp)},
{"expand", 1, 3, FEARG_1, arg3_string_bool_bool, {"expand", 1, 3, FEARG_1, arg3_string_bool_bool,
ret_any, f_expand}, ret_any, f_expand},
{"expandcmd", 1, 1, FEARG_1, arg1_string, {"expandcmd", 1, 2, FEARG_1, arg2_string_dict,
ret_string, f_expandcmd}, ret_string, f_expandcmd},
{"extend", 2, 3, FEARG_1, arg23_extend, {"extend", 2, 3, FEARG_1, arg23_extend,
ret_extend, f_extend}, ret_extend, f_extend},
@@ -4152,10 +4152,18 @@ f_expandcmd(typval_T *argvars, typval_T *rettv)
exarg_T eap; exarg_T eap;
char_u *cmdstr; char_u *cmdstr;
char *errormsg = NULL; char *errormsg = NULL;
int emsgoff = TRUE;
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) if (in_vim9script()
&& (check_for_string_arg(argvars, 0) == FAIL
|| check_for_opt_dict_arg(argvars, 1) == FAIL))
return; return;
if (argvars[1].v_type == VAR_DICT
&& dict_get_bool(argvars[1].vval.v_dict, (char_u *)"errmsg",
VVAL_FALSE))
emsgoff = FALSE;
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
cmdstr = vim_strsave(tv_get_string(&argvars[0])); cmdstr = vim_strsave(tv_get_string(&argvars[0]));
@@ -4167,8 +4175,12 @@ f_expandcmd(typval_T *argvars, typval_T *rettv)
eap.nextcmd = NULL; eap.nextcmd = NULL;
eap.cmdidx = CMD_USER; eap.cmdidx = CMD_USER;
if (emsgoff)
++emsg_off; ++emsg_off;
expand_filename(&eap, &cmdstr, &errormsg); if (expand_filename(&eap, &cmdstr, &errormsg) == FAIL)
if (!emsgoff && errormsg != NULL && *errormsg != NUL)
emsg(errormsg);
if (emsgoff)
--emsg_off; --emsg_off;
rettv->vval.v_string = cmdstr; rettv->vval.v_string = cmdstr;

View File

@@ -3999,7 +3999,7 @@ gen_expand_wildcards(
// When returning FAIL the array must be freed here. // When returning FAIL the array must be freed here.
if (retval == FAIL) if (retval == FAIL)
ga_clear(&ga); ga_clear_strings(&ga);
*num_file = ga.ga_len; *num_file = ga.ga_len;
*file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data

View File

@@ -90,14 +90,26 @@ func Test_expandcmd()
" Test for expression expansion `= " Test for expression expansion `=
let $FOO= "blue" let $FOO= "blue"
call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`")) call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`"))
let x = expandcmd("`=axbycz`")
call assert_equal('`=axbycz`', x)
call assert_fails('let x = expandcmd("`=axbycz`", #{errmsg: 1})', 'E121:')
let x = expandcmd("`=axbycz`", #{abc: []})
call assert_equal('`=axbycz`', x)
" Test for env variable with spaces " Test for env variable with spaces
let $FOO= "foo bar baz" let $FOO= "foo bar baz"
call assert_equal("e foo bar baz", expandcmd("e $FOO")) call assert_equal("e foo bar baz", expandcmd("e $FOO"))
if has('unix') if has('unix') && executable('bash')
" test for using the shell to expand a command argument " test for using the shell to expand a command argument.
call assert_equal('{1..4}', expandcmd('{1..4}')) " only bash supports the {..} syntax
set shell=bash
let x = expandcmd('{1..4}')
call assert_equal('{1..4}', x)
call assert_fails("let x = expandcmd('{1..4}', #{errmsg: v:true})", 'E77:')
let x = expandcmd('{1..4}', #{error: v:true})
call assert_equal('{1..4}', x)
set shell&
endif endif
unlet $FOO unlet $FOO

View File

@@ -1020,6 +1020,7 @@ def Test_expandcmd()
expandcmd('')->assert_equal('') expandcmd('')->assert_equal('')
v9.CheckDefAndScriptFailure(['expandcmd([1])'], ['E1013: Argument 1: type mismatch, expected string but got list<number>', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['expandcmd([1])'], ['E1013: Argument 1: type mismatch, expected string but got list<number>', 'E1174: String required for argument 1'])
v9.CheckDefAndScriptFailure(['expandcmd("abc", [])'], ['E1013: Argument 2: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 2'])
enddef enddef
def Test_extend_arg_types() def Test_extend_arg_types()

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4679,
/**/ /**/
4678, 4678,
/**/ /**/