]> granicus.if.org Git - vim/commitdiff
patch 8.2.4679: cannot have expandcmd() give an error message for mistakes v8.2.4679
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 3 Apr 2022 20:30:32 +0000 (21:30 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 3 Apr 2022 20:30:32 +0000 (21:30 +0100)
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)

runtime/doc/builtin.txt
src/evalfunc.c
src/filepath.c
src/testdir/test_expand.vim
src/testdir/test_vim9_builtin.vim
src/version.c

index f2e98298df26226b51a9d825c2e42f1190a2b057..08872d04e2a30f150ad801b94da57410a32564f0 100644 (file)
@@ -161,7 +161,8 @@ exists_compiled({expr})             Number  |TRUE| if {expr} exists at compile time
 exp({expr})                    Float   exponential of {expr}
 expand({expr} [, {nosuf} [, {list}]])
                                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}])
                                List/Dict insert items of {expr2} into {expr1}
 extendnew({expr1}, {expr2} [, {expr3}])
@@ -2293,18 +2294,27 @@ expand({string} [, {nosuf} [, {list}]])                         *expand()*
                Can also be used as a |method|: >
                        Getpattern()->expand()
 
-expandcmd({string})                                    *expandcmd()*
+expandcmd({string} [, {options}])                      *expandcmd()*
                Expand special items in String {string} like what is done for
                an Ex command such as `:edit`.  This expands special keywords,
                like with |expand()|, and environment variables, anywhere in
                {string}.  "~user" and "~/path" are only expanded at the
                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
                during expansion, the unmodified {string} is returned.
+
                Example: >
                        :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|: >
                        GetCommand()->expandcmd()
 <
index 5a0428ecff99ff2944374f3f69db0a53ce409d89..482967346495957fd2fe0110bab45f9ad53a747d 100644 (file)
@@ -1761,7 +1761,7 @@ static funcentry_T global_functions[] =
                        ret_float,          FLOAT_FUNC(f_exp)},
     {"expand",         1, 3, FEARG_1,      arg3_string_bool_bool,
                        ret_any,            f_expand},
-    {"expandcmd",      1, 1, FEARG_1,      arg1_string,
+    {"expandcmd",      1, 2, FEARG_1,      arg2_string_dict,
                        ret_string,         f_expandcmd},
     {"extend",         2, 3, FEARG_1,      arg23_extend,
                        ret_extend,         f_extend},
@@ -4152,10 +4152,18 @@ f_expandcmd(typval_T *argvars, typval_T *rettv)
     exarg_T    eap;
     char_u     *cmdstr;
     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;
 
+    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;
     cmdstr = vim_strsave(tv_get_string(&argvars[0]));
 
@@ -4167,9 +4175,13 @@ f_expandcmd(typval_T *argvars, typval_T *rettv)
     eap.nextcmd = NULL;
     eap.cmdidx = CMD_USER;
 
-    ++emsg_off;
-    expand_filename(&eap, &cmdstr, &errormsg);
-    --emsg_off;
+    if (emsgoff)
+       ++emsg_off;
+    if (expand_filename(&eap, &cmdstr, &errormsg) == FAIL)
+       if (!emsgoff && errormsg != NULL && *errormsg != NUL)
+           emsg(errormsg);
+    if (emsgoff)
+       --emsg_off;
 
     rettv->vval.v_string = cmdstr;
 }
index 5bf31ea8e82e0b5cd6e42776e518d664dacff2f2..3786ef63307aa2c9ba2f91cd70c6291d297a187f 100644 (file)
@@ -3999,7 +3999,7 @@ gen_expand_wildcards(
 
     // When returning FAIL the array must be freed here.
     if (retval == FAIL)
-       ga_clear(&ga);
+       ga_clear_strings(&ga);
 
     *num_file = ga.ga_len;
     *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data
index ce414e4b11bcfd1a1db50018cb692f3949cd8780..638f9c7c3466d6171265318974702d1df54ddb1e 100644 (file)
@@ -90,14 +90,26 @@ func Test_expandcmd()
   " Test for expression expansion `=
   let $FOO= "blue"
   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
   let $FOO= "foo bar baz"
   call assert_equal("e foo bar baz", expandcmd("e $FOO"))
 
-  if has('unix')
-    " test for using the shell to expand a command argument
-    call assert_equal('{1..4}', expandcmd('{1..4}'))
+  if has('unix') && executable('bash')
+    " test for using the shell to expand a command argument.
+    " 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
 
   unlet $FOO
index 01f29d9d2bcfd701dadeb0ec0c26596ef6909281..b20ff144ca087fbe7c4a56e1bafccc5f6f0dbf18 100644 (file)
@@ -1020,6 +1020,7 @@ def Test_expandcmd()
   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("abc", [])'], ['E1013: Argument 2: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 2'])
 enddef
 
 def Test_extend_arg_types()
index 22191c9976e282c4dbdade3e1589cc56ffa69c26..fda6f6abc2b355dfbd7285f1b6d22796f6ae072f 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4679,
 /**/
     4678,
 /**/