After this patch, sending an eval channel command never gets a return message. I don't get an error either. Has the syntax changed? The documentation isn't updated.
On Sat, Feb 20, 2016 at 1:39 PM, Bram Moolenaar <[email protected]> wrote: > > Patch 7.4.1373 > Problem: Calling a Vim function over a channel requires turning the > arguments into a string. > Solution: Add the "call" command. (Damien) Also merge "expr" and "eval" > into one. > Files: src/channel.c, src/testdir/test_channel.py, > src/testdir/test_channel.vim > > > *** ../vim-7.4.1372/src/channel.c 2016-02-20 19:56:08.999279558 +0100 > --- src/channel.c 2016-02-20 21:32:38.814632787 +0100 > *************** > *** 1080,1107 **** > return FAIL; > } > > /* > * Execute a command received over "channel"/"part" > ! * "cmd" is the command string, "arg2" the second argument. > ! * "arg3" is the third argument, NULL if missing. > */ > static void > ! channel_exe_cmd( > ! channel_T *channel, > ! int part, > ! char_u *cmd, > ! typval_T *arg2, > ! typval_T *arg3) > { > ! char_u *arg; > > ! if (arg2->v_type != VAR_STRING) > { > if (p_verbose > 2) > ! EMSG("E903: received ex command with non-string argument"); > return; > } > ! arg = arg2->vval.v_string; > if (arg == NULL) > arg = (char_u *)""; > > --- 1080,1107 ---- > return FAIL; > } > > + #define CH_JSON_MAX_ARGS 4 > + > /* > * Execute a command received over "channel"/"part" > ! * "argv[0]" is the command string. > ! * "argv[1]" etc. have further arguments, type is VAR_UNKNOWN if missing. > */ > static void > ! channel_exe_cmd(channel_T *channel, int part, typval_T *argv) > { > ! char_u *cmd = argv[0].vval.v_string; > ! char_u *arg; > ! int options = channel->ch_part[part].ch_mode == MODE_JS ? > JSON_JS : 0; > > ! if (argv[1].v_type != VAR_STRING) > { > + ch_error(channel, "received command with non-string argument"); > if (p_verbose > 2) > ! EMSG("E903: received command with non-string argument"); > return; > } > ! arg = argv[1].vval.v_string; > if (arg == NULL) > arg = (char_u *)""; > > *************** > *** 1135,1165 **** > } > #endif > } > ! else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "eval") == 0) > { > ! int is_eval = cmd[1] == 'v'; > > ! if (is_eval && (arg3 == NULL || arg3->v_type != VAR_NUMBER)) > { > if (p_verbose > 2) > ! EMSG("E904: third argument for eval must be a number"); > } > else > { > typval_T *tv; > typval_T err_tv; > char_u *json = NULL; > - int options = channel->ch_part[part].ch_mode == MODE_JS > - ? JSON_JS > : 0; > > /* Don't pollute the display with errors. */ > ++emsg_skip; > ! tv = eval_expr(arg, NULL); > ! if (is_eval) > { > if (tv != NULL) > ! json = json_encode_nr_expr(arg3->vval.v_number, tv, > ! > options); > if (tv == NULL || (json != NULL && *json == NUL)) > { > /* If evaluation failed or the result can't be encoded > --- 1135,1180 ---- > } > #endif > } > ! else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "call") == 0) > { > ! int is_call = cmd[0] == 'c'; > ! int id_idx = is_call ? 3 : 2; > > ! if (argv[id_idx].v_type != VAR_UNKNOWN > ! && argv[id_idx].v_type != > VAR_NUMBER) > ! { > ! ch_error(channel, "last argument for expr/call must be a > number"); > ! if (p_verbose > 2) > ! EMSG("E904: last argument for expr/call must be a number"); > ! } > ! else if (is_call && argv[2].v_type != VAR_LIST) > { > + ch_error(channel, "third argument for call must be a list"); > if (p_verbose > 2) > ! EMSG("E904: third argument for call must be a list"); > } > else > { > typval_T *tv; > + typval_T res_tv; > typval_T err_tv; > char_u *json = NULL; > > /* Don't pollute the display with errors. */ > ++emsg_skip; > ! if (!is_call) > ! tv = eval_expr(arg, NULL); > ! else if (func_call(arg, &argv[2], NULL, &res_tv) == OK) > ! tv = &res_tv; > ! else > ! tv = NULL; > ! > ! if (argv[id_idx].v_type == VAR_NUMBER) > { > + int id = argv[id_idx].vval.v_number; > + > if (tv != NULL) > ! json = json_encode_nr_expr(id, tv, options); > if (tv == NULL || (json != NULL && *json == NUL)) > { > /* If evaluation failed or the result can't be encoded > *************** > *** 1169,1190 **** > 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, > ! > options); > } > if (json != NULL) > { > ! channel_send(channel, part, json, "eval"); > vim_free(json); > } > } > --emsg_skip; > ! if (tv != &err_tv) > free_tv(tv); > } > } > else if (p_verbose > 2) > EMSG2("E905: received unknown command: %s", cmd); > } > > /* > --- 1184,1211 ---- > err_tv.v_type = VAR_STRING; > err_tv.vval.v_string = (char_u *)"ERROR"; > tv = &err_tv; > ! json = json_encode_nr_expr(id, tv, options); > } > if (json != NULL) > { > ! channel_send(channel, > ! part == PART_SOCK ? PART_SOCK : PART_IN, > ! json, (char *)cmd); > vim_free(json); > } > } > --emsg_skip; > ! if (tv == &res_tv) > ! clear_tv(tv); > ! else if (tv != &err_tv) > free_tv(tv); > } > } > else if (p_verbose > 2) > + { > + ch_errors(channel, "Receved unknown command: %s", (char *)cmd); > EMSG2("E905: received unknown command: %s", cmd); > + } > } > > /* > *************** > *** 1196,1204 **** > { > char_u *msg = NULL; > typval_T *listtv = NULL; > ! list_T *list; > ! typval_T *typetv; > ! typval_T argv[3]; > int seq_nr = -1; > ch_mode_T ch_mode = channel->ch_part[part].ch_mode; > char_u *callback = NULL; > --- 1217,1223 ---- > { > char_u *msg = NULL; > typval_T *listtv = NULL; > ! typval_T argv[CH_JSON_MAX_ARGS]; > int seq_nr = -1; > ch_mode_T ch_mode = channel->ch_part[part].ch_mode; > char_u *callback = NULL; > *************** > *** 1214,1219 **** > --- 1233,1241 ---- > > if (ch_mode == MODE_JSON || ch_mode == MODE_JS) > { > + listitem_T *item; > + int argc = 0; > + > /* Get any json message in the queue. */ > if (channel_get_json(channel, part, -1, &listtv) == FAIL) > { > *************** > *** 1223,1253 **** > return FALSE; > } > > ! list = listtv->vval.v_list; > ! argv[1] = list->lv_first->li_next->li_tv; > ! typetv = &list->lv_first->li_tv; > ! if (typetv->v_type == VAR_STRING) > ! { > ! typval_T *arg3 = NULL; > ! char_u *cmd = typetv->vval.v_string; > ! > ! /* ["cmd", arg] or ["cmd", arg, arg] */ > ! if (list->lv_len == 3) > ! arg3 = &list->lv_last->li_tv; > ch_logs(channel, "Executing %s command", (char *)cmd); > ! channel_exe_cmd(channel, part, cmd, &argv[1], arg3); > free_tv(listtv); > return TRUE; > } > > ! if (typetv->v_type != VAR_NUMBER) > { > ch_error(channel, > "Dropping message with invalid sequence number > type"); > free_tv(listtv); > return FALSE; > } > ! seq_nr = typetv->vval.v_number; > } > else if (channel_peek(channel, part) == NULL) > { > --- 1245,1276 ---- > return FALSE; > } > > ! for (item = listtv->vval.v_list->lv_first; > ! item != NULL && argc < CH_JSON_MAX_ARGS; > ! item = item->li_next) > ! argv[argc++] = item->li_tv; > ! while (argc < CH_JSON_MAX_ARGS) > ! argv[argc++].v_type = VAR_UNKNOWN; > ! > ! if (argv[0].v_type == VAR_STRING) > ! { > ! char_u *cmd = argv[0].vval.v_string; > ! > ! /* ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg] > */ > ch_logs(channel, "Executing %s command", (char *)cmd); > ! channel_exe_cmd(channel, part, argv); > free_tv(listtv); > return TRUE; > } > > ! if (argv[0].v_type != VAR_NUMBER) > { > ch_error(channel, > "Dropping message with invalid sequence number > type"); > free_tv(listtv); > return FALSE; > } > ! seq_nr = argv[0].vval.v_number; > } > else if (channel_peek(channel, part) == NULL) > { > *** ../vim-7.4.1372/src/testdir/test_channel.py 2016-02-20 > 18:26:43.664053539 +0100 > --- src/testdir/test_channel.py 2016-02-20 20:32:47.068182113 +0100 > *************** > *** 78,103 **** > response = "ok" > elif decoded[1] == 'eval-works': > # Send an eval request. We ignore the response. > ! cmd = '["eval","\\"foo\\" . 123", -1]' > print("sending: {}".format(cmd)) > self.request.sendall(cmd.encode('utf-8')) > response = "ok" > elif decoded[1] == 'eval-fails': > # Send an eval request that will fail. > ! cmd = '["eval","xxx", -2]' > 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"]' > print("sending: {}".format(cmd)) > self.request.sendall(cmd.encode('utf-8')) > response = "ok" > --- 78,103 ---- > response = "ok" > elif decoded[1] == 'eval-works': > # Send an eval request. We ignore the response. > ! cmd = '["expr","\\"foo\\" . 123", -1]' > print("sending: {}".format(cmd)) > self.request.sendall(cmd.encode('utf-8')) > response = "ok" > elif decoded[1] == 'eval-fails': > # Send an eval request that will fail. > ! cmd = '["expr","xxx", -2]' > 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 = '["expr","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 = '["expr","xxx"]' > print("sending: {}".format(cmd)) > self.request.sendall(cmd.encode('utf-8')) > response = "ok" > *************** > *** 107,112 **** > --- 107,117 ---- > print("sending: {}".format(cmd)) > self.request.sendall(cmd.encode('utf-8')) > response = "ok" > + elif decoded[1] == 'call-func': > + cmd = '["call","MyFunction",[1,2,3], 0]' > + print("sending: {}".format(cmd)) > + self.request.sendall(cmd.encode('utf-8')) > + response = "ok" > elif decoded[1] == 'redraw': > cmd = '["redraw",""]' > print("sending: {}".format(cmd)) > *************** > *** 135,140 **** > --- 140,148 ---- > print("sending: {}".format(cmd)) > self.request.sendall(cmd.encode('utf-8')) > response = "" > + elif decoded[1] == 'wait a bit': > + time.sleep(0.2) > + response = "waited" > elif decoded[1] == '!quit!': > # we're done > self.server.shutdown() > *** ../vim-7.4.1372/src/testdir/test_channel.vim 2016-02-20 > 19:56:09.011279432 +0100 > --- src/testdir/test_channel.vim 2016-02-20 20:34:14.363266356 +0100 > *************** > *** 431,433 **** > --- 431,456 ---- > " The server will wait half a second before creating the port. > call s:run_server('s:open_delay', 'delay') > endfunc > + > + """"""""" > + > + function MyFunction(a,b,c) > + let s:call_ret = [a:a, a:b, a:c] > + endfunc > + > + function s:test_call(port) > + let handle = ch_open('localhost:' . a:port, s:chopt) > + if ch_status(handle) == "fail" > + call assert_false(1, "Can't open channel") > + return > + endif > + > + call assert_equal('ok', ch_sendexpr(handle, 'call-func')) > + sleep 20m > + call assert_equal([1, 2, 3], s:call_ret) > + endfunc > + > + func Test_call() > + call ch_log('Test_call()') > + call s:run_server('s:test_call') > + endfunc > *** ../vim-7.4.1372/src/version.c 2016-02-20 19:56:09.011279432 +0100 > --- src/version.c 2016-02-20 21:37:36.503521505 +0100 > *************** > *** 749,750 **** > --- 749,752 ---- > { /* Add new patch number below this line */ > + /**/ > + 1373, > /**/ > > -- > Computers are not intelligent. They only think they are. > > /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net > \\\ > /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ > \\\ > \\\ an exciting new programming language -- http://www.Zimbu.org > /// > \\\ help me help AIDS victims -- http://ICCF-Holland.org > /// > > -- > -- > You received this message from the "vim_dev" maillist. > Do not top-post! Type your reply below the text you are replying to. > For more information, visit http://www.vim.org/maillist.php > > --- > You received this message because you are subscribed to the Google Groups > "vim_dev" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- Christian J. Robinson <[email protected]> -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
