# HG changeset patch # User Bram Moolenaar # Date 1545481808 -3600 # Node ID dada0b389d4f0ff4a4de7f62095a7a82235d244a # Parent d8a6097d1f52562f09108d8f37f76120a88ebafe patch 8.1.0619: :echomsg and :echoerr do not handle List and Dict commit https://github.com/vim/vim/commit/461a7fcfce3cd6414f990037e6468af3b5ccf119 Author: Bram Moolenaar Date: Sat Dec 22 13:28:07 2018 +0100 patch 8.1.0619: :echomsg and :echoerr do not handle List and Dict Problem: :echomsg and :echoerr do not handle List and Dict like :echo does. (Daniel Hahler) Solution: Be more tolerant about the expression result type. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -9233,7 +9233,8 @@ test_ignore_error({expr}) *test_ignor error with try/catch cannot be used (because it skips over following code). {expr} is used literally, not as a pattern. - There is currently no way to revert this. + When the {expr} is the string "RESET" then the list of ignored + errors is made empty. test_null_channel() *test_null_channel()* Return a Channel that is null. Only useful for testing. @@ -10999,8 +11000,8 @@ 7. Commands *expression-commands* The parsing works slightly different from |:echo|, more like |:execute|. All the expressions are first evaluated and concatenated before echoing anything. - The expressions must evaluate to a Number or String, a - Dictionary or List causes an error. + If expressions does not evaluate to a Number or + String, string() is used to turn it into a string. Uses the highlighting set by the |:echohl| command. Example: > :echomsg "It's a Zizzer Zazzer Zuzz, as you can plainly see." @@ -11011,7 +11012,7 @@ 7. Commands *expression-commands* message in the |message-history|. When used in a script or function the line number will be added. Spaces are placed between the arguments as with the - :echo command. When used inside a try conditional, + |:echomsg| command. When used inside a try conditional, the message is raised as an error exception instead (see |try-echoerr|). Example: > diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -7163,6 +7163,30 @@ tv_get_string_buf_chk(typval_T *varp, ch } /* + * Turn a typeval into a string. Similar to tv_get_string_buf() but uses + * string() on Dict, List, etc. + */ + char_u * +tv_stringify(typval_T *varp, char_u *buf) +{ + if (varp->v_type == VAR_LIST + || varp->v_type == VAR_DICT + || varp->v_type == VAR_FUNC + || varp->v_type == VAR_PARTIAL + || varp->v_type == VAR_FLOAT) + { + typval_T tmp; + + f_string(varp, &tmp); + tv_get_string_buf(&tmp, buf); + clear_tv(varp); + *varp = tmp; + return tmp.vval.v_string; + } + return tv_get_string_buf(varp, buf); +} + +/* * Find variable "name" in the list of variables. * Return a pointer to it if found, NULL if not found. * Careful: "a:0" variables don't have a name. @@ -8142,7 +8166,12 @@ ex_execute(exarg_T *eap) if (!eap->skip) { - p = tv_get_string(&rettv); + char_u buf[NUMBUFLEN]; + + if (eap->cmdidx == CMD_execute) + p = tv_get_string_buf(&rettv, buf); + else + p = tv_stringify(&rettv, buf); len = (int)STRLEN(p); if (ga_grow(&ga, len + 2) == FAIL) { diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -396,7 +396,6 @@ static void f_strftime(typval_T *argvars #endif static void f_strgetchar(typval_T *argvars, typval_T *rettv); static void f_stridx(typval_T *argvars, typval_T *rettv); -static void f_string(typval_T *argvars, typval_T *rettv); static void f_strlen(typval_T *argvars, typval_T *rettv); static void f_strcharpart(typval_T *argvars, typval_T *rettv); static void f_strpart(typval_T *argvars, typval_T *rettv); @@ -12475,7 +12474,7 @@ f_stridx(typval_T *argvars, typval_T *re /* * "string()" function */ - static void + void f_string(typval_T *argvars, typval_T *rettv) { char_u *tofree; diff --git a/src/message.c b/src/message.c --- a/src/message.c +++ b/src/message.c @@ -553,7 +553,10 @@ ignore_error_for_testing(char_u *error) if (ignore_error_list.ga_itemsize == 0) ga_init2(&ignore_error_list, sizeof(char_u *), 1); - ga_add_string(&ignore_error_list, error); + if (STRCMP("RESET", error) == 0) + ga_clear_strings(&ignore_error_list); + else + ga_add_string(&ignore_error_list, error); } static int diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -89,6 +89,7 @@ char_u *tv_get_string(typval_T *varp); char_u *tv_get_string_buf(typval_T *varp, char_u *buf); char_u *tv_get_string_chk(typval_T *varp); char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf); +char_u *tv_stringify(typval_T *varp, char_u *buf); dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload); dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload); hashtab_T *find_var_ht(char_u *name, char_u **varname); diff --git a/src/proto/evalfunc.pro b/src/proto/evalfunc.pro --- a/src/proto/evalfunc.pro +++ b/src/proto/evalfunc.pro @@ -9,6 +9,7 @@ void execute_redir_str(char_u *value, in void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv); float_T vim_round(float_T f); long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit); +void f_string(typval_T *argvars, typval_T *rettv); char_u *get_callback(typval_T *arg, partial_T **pp); void free_callback(char_u *callback, partial_T *partial); /* vim: set ft=c : */ diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -1,4 +1,4 @@ -" Tests for :messages +" Tests for :messages, :echomsg, :echoerr function Test_messages() let oldmore = &more @@ -64,3 +64,31 @@ func Test_message_completion() call feedkeys(":message \\\"\", 'tx') call assert_equal('"message clear', @:) endfunc + +func Test_echomsg() + call assert_equal("\nhello", execute(':echomsg "hello"')) + call assert_equal("\n", execute(':echomsg ""')) + call assert_equal("\n12345", execute(':echomsg 12345')) + call assert_equal("\n[]", execute(':echomsg []')) + call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]')) + call assert_equal("\n{}", execute(':echomsg {}')) + call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}')) + if has('float') + call assert_equal("\n1.23", execute(':echomsg 1.23')) + endif + call assert_match("function('\\d*')", execute(':echomsg {-> 1234}')) +endfunc + +func Test_echoerr() + call test_ignore_error('IgNoRe') + call assert_equal("\nIgNoRe hello", execute(':echoerr "IgNoRe hello"')) + call assert_equal("\n12345 IgNoRe", execute(':echoerr 12345 "IgNoRe"')) + call assert_equal("\n[1, 2, 'IgNoRe']", execute(':echoerr [1, 2, "IgNoRe"]')) + call assert_equal("\n{'IgNoRe': 2, 'a': 1}", execute(':echoerr {"a": 1, "IgNoRe": 2}')) + if has('float') + call assert_equal("\n1.23 IgNoRe", execute(':echoerr 1.23 "IgNoRe"')) + endif + call test_ignore_error('') + call assert_match("function('\\d*')", execute(':echoerr {-> 1234}')) + call test_ignore_error('RESET') +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -800,6 +800,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 619, +/**/ 618, /**/ 617,