From 461a7fcfce3cd6414f990037e6468af3b5ccf119 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 22 Dec 2018 13:28:07 +0100 Subject: [PATCH] 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. --- runtime/doc/eval.txt | 9 +++++---- src/eval.c | 31 ++++++++++++++++++++++++++++++- src/evalfunc.c | 3 +-- src/message.c | 5 ++++- src/proto/eval.pro | 1 + src/proto/evalfunc.pro | 1 + src/testdir/test_messages.vim | 30 +++++++++++++++++++++++++++++- src/version.c | 2 ++ 8 files changed, 73 insertions(+), 9 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index f76af3848..2bc27a629 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -9233,7 +9233,8 @@ test_ignore_error({expr}) *test_ignore_error()* 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 @@ This does NOT work: > 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 @@ This does NOT work: > 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 index 1d14e1b0e..b6463d2e7 100644 --- a/src/eval.c +++ b/src/eval.c @@ -7162,6 +7162,30 @@ tv_get_string_buf_chk(typval_T *varp, char_u *buf) return NULL; } +/* + * 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. @@ -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 index cbe2a4ebb..bd2acef7f 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -396,7 +396,6 @@ static void f_strftime(typval_T *argvars, typval_T *rettv); #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 *rettv) /* * "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 index f191c78a2..1c9fbe513 100644 --- 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 index bc6808c74..7d73f6c28 100644 --- 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 index c79b59c0d..09861628b 100644 --- a/src/proto/evalfunc.pro +++ b/src/proto/evalfunc.pro @@ -9,6 +9,7 @@ void execute_redir_str(char_u *value, int value_len); 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 index de14b81f9..0a7f3f59a 100644 --- 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 index 1612f9dd1..b1a28c1fa 100644 --- a/src/version.c +++ b/src/version.c @@ -799,6 +799,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 619, /**/ 618, /**/ -- 2.40.0