diff options
-rw-r--r-- | src/channel.c | 19 | ||||
-rw-r--r-- | src/json.c | 21 | ||||
-rw-r--r-- | src/testdir/test_channel.py | 7 | ||||
-rw-r--r-- | src/testdir/test_channel.vim | 7 | ||||
-rw-r--r-- | src/testdir/test_json.vim | 3 | ||||
-rw-r--r-- | src/version.c | 2 |
6 files changed, 47 insertions, 12 deletions
diff --git a/src/channel.c b/src/channel.c index 811d87ae1..a6458c65e 100644 --- a/src/channel.c +++ b/src/channel.c @@ -853,24 +853,31 @@ channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3) { typval_T *tv; typval_T err_tv; - char_u *json; + char_u *json = NULL; /* Don't pollute the display with errors. */ ++emsg_skip; tv = eval_expr(arg, NULL); - --emsg_skip; if (is_eval) { - if (tv == NULL) + if (tv != NULL) + json = json_encode_nr_expr(arg3->vval.v_number, tv); + if (tv == NULL || (json != NULL && *json == NUL)) { + /* If evaluation failed or the result can't be encoded + * then return the string "ERROR". */ err_tv.v_type = VAR_STRING; err_tv.vval.v_string = (char_u *)"ERROR"; tv = &err_tv; + json = json_encode_nr_expr(arg3->vval.v_number, tv); + } + if (json != NULL) + { + channel_send(idx, json, "eval"); + vim_free(json); } - json = json_encode_nr_expr(arg3->vval.v_number, tv); - channel_send(idx, json, "eval"); - vim_free(json); } + --emsg_skip; if (tv != &err_tv) free_tv(tv); } diff --git a/src/json.c b/src/json.c index 6688437ae..17eed4fa1 100644 --- a/src/json.c +++ b/src/json.c @@ -21,6 +21,8 @@ static int json_decode_item(js_read_T *reader, typval_T *res); /* * Encode "val" into a JSON format string. + * The result is in allocated memory. + * The result is empty when encoding fails. */ char_u * json_encode(typval_T *val) @@ -29,12 +31,16 @@ json_encode(typval_T *val) /* Store bytes in the growarray. */ ga_init2(&ga, 1, 4000); - json_encode_item(&ga, val, get_copyID(), TRUE); + if (json_encode_item(&ga, val, get_copyID(), TRUE) == FAIL) + { + vim_free(ga.ga_data); + return vim_strsave((char_u *)""); + } return ga.ga_data; } /* - * Encode ["nr", "val"] into a JSON format string. + * Encode ["nr", "val"] into a JSON format string in allocated memory. * Returns NULL when out of memory. */ char_u * @@ -136,8 +142,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none) case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; case VVAL_NONE: if (!allow_none) + { /* TODO: better error */ EMSG(_(e_invarg)); + return FAIL; + } break; case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; } @@ -155,6 +164,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none) break; case VAR_FUNC: + case VAR_JOB: /* no JSON equivalent TODO: better error */ EMSG(_(e_invarg)); return FAIL; @@ -226,14 +236,15 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none) } break; -#ifdef FEAT_FLOAT case VAR_FLOAT: +#ifdef FEAT_FLOAT vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float); ga_concat(gap, numbuf); break; #endif - default: EMSG2(_(e_intern2), "json_encode_item()"); break; - return FAIL; + case VAR_UNKNOWN: + EMSG2(_(e_intern2), "json_encode_item()"); break; + return FAIL; } return OK; } diff --git a/src/testdir/test_channel.py b/src/testdir/test_channel.py index d8830c519..40a2043cc 100644 --- a/src/testdir/test_channel.py +++ b/src/testdir/test_channel.py @@ -93,6 +93,13 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): print("sending: {}".format(cmd)) self.request.sendall(cmd.encode('utf-8')) response = "ok" + elif decoded[1] == 'eval-error': + # Send an eval request that works but the result can't + # be encoded. + cmd = '["eval","function(\\"tr\\")", -3]' + print("sending: {}".format(cmd)) + self.request.sendall(cmd.encode('utf-8')) + response = "ok" elif decoded[1] == 'eval-bad': # Send an eval request missing the third argument. cmd = '["eval","xxx"]' diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 94ad81cca..2a56c0d28 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -118,10 +118,15 @@ func Test_communicate() sleep 10m call assert_equal([-2, 'ERROR'], ch_sendexpr(handle, 'eval-result')) + " Send an eval request that works but can't be encoded. + call assert_equal('ok', ch_sendexpr(handle, 'eval-error')) + sleep 10m + call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result')) + " Send a bad eval request. There will be no response. call assert_equal('ok', ch_sendexpr(handle, 'eval-bad')) sleep 10m - call assert_equal([-2, 'ERROR'], ch_sendexpr(handle, 'eval-result')) + call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result')) " Send an expr request call assert_equal('ok', ch_sendexpr(handle, 'an expr')) diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim index 05c394968..52cffc825 100644 --- a/src/testdir/test_json.vim +++ b/src/testdir/test_json.vim @@ -75,6 +75,9 @@ func Test_encode() call assert_fails('echo jsonencode(function("tr"))', 'E474:') call assert_fails('echo jsonencode([function("tr")])', 'E474:') call assert_fails('echo jsonencode({"key":v:none})', 'E474:') + + silent! let res = jsonencode(function("tr")) + call assert_equal("", res) endfunc func Test_decode() diff --git a/src/version.c b/src/version.c index f979949b5..00b7176f5 100644 --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1278, +/**/ 1277, /**/ 1276, |