diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-01-31 20:24:32 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-01-31 20:24:32 +0100 |
commit | fb1f62691eae7c79a28b3b17a60e72ce198c71a2 (patch) | |
tree | 92456937dc3d372bf30b97df3c5b5148ea2a8243 /src | |
parent | 155500077c80cdb5d9c63996000c011b66a676bf (diff) | |
download | vim-git-fb1f62691eae7c79a28b3b17a60e72ce198c71a2.tar.gz |
patch 7.4.1229v7.4.1229
Problem: "eval" and "expr" channel commands don't work yet.
Solution: Implement them. Update the error numbers. Also add "redraw".
Diffstat (limited to 'src')
-rw-r--r-- | src/channel.c | 148 | ||||
-rw-r--r-- | src/eval.c | 18 | ||||
-rw-r--r-- | src/ex_docmd.c | 3 | ||||
-rw-r--r-- | src/json.c | 27 | ||||
-rw-r--r-- | src/proto/channel.pro | 2 | ||||
-rw-r--r-- | src/proto/ex_docmd.pro | 1 | ||||
-rw-r--r-- | src/proto/json.pro | 1 | ||||
-rw-r--r-- | src/version.c | 2 |
8 files changed, 141 insertions, 61 deletions
diff --git a/src/channel.c b/src/channel.c index 416b53815..14841e7bb 100644 --- a/src/channel.c +++ b/src/channel.c @@ -293,14 +293,14 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void)) if (idx < 0) { CHERROR("All channels are in use\n", ""); - EMSG(_("E999: All channels are in use")); + EMSG(_("E897: All channels are in use")); return -1; } if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1) { CHERROR("error in socket() in channel_open()\n", ""); - PERROR("E999: socket() in channel_open()"); + PERROR("E898: socket() in channel_open()"); return -1; } @@ -312,7 +312,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void)) if ((host = gethostbyname(hostname)) == NULL) { CHERROR("error in gethostbyname() in channel_open()\n", ""); - PERROR("E999: gethostbyname() in channel_open()"); + PERROR("E901: gethostbyname() in channel_open()"); sock_close(sd); return -1; } @@ -330,7 +330,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void)) { SOCK_ERRNO; CHERROR("socket() retry in channel_open()\n", ""); - PERROR("E999: socket() retry in channel_open()"); + PERROR("E900: socket() retry in channel_open()"); return -1; } if (connect(sd, (struct sockaddr *)&server, sizeof(server))) @@ -362,7 +362,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void)) { /* Get here when the server can't be found. */ CHERROR("Cannot connect to port after retry\n", ""); - PERROR(_("E999: Cannot connect to port after retry2")); + PERROR(_("E899: Cannot connect to port after retry2")); sock_close(sd); return -1; } @@ -371,7 +371,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void)) else { CHERROR("Cannot connect to port\n", ""); - PERROR(_("E999: Cannot connect to port")); + PERROR(_("E902: Cannot connect to port")); sock_close(sd); return -1; } @@ -418,13 +418,15 @@ channel_set_req_callback(int idx, char_u *callback) } /* - * Decode JSON "msg", which must have the form "[expr1, expr2]". + * Decode JSON "msg", which must have the form "[expr1, expr2, expr3]". * Put "expr1" in "tv1". * Put "expr2" in "tv2". + * Put "expr3" in "tv3". If "tv3" is NULL there is no "expr3". + * * Return OK or FAIL. */ int -channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2) +channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T *tv3) { js_read_T reader; typval_T listtv; @@ -434,16 +436,31 @@ channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2) reader.js_used = 0; json_decode(&reader, &listtv); - if (listtv.v_type == VAR_LIST && listtv.vval.v_list->lv_len == 2) + if (listtv.v_type == VAR_LIST) { - /* Move the item from the list and then change the type to avoid the - * item being freed. */ - *tv1 = listtv.vval.v_list->lv_first->li_tv; - listtv.vval.v_list->lv_first->li_tv.v_type = VAR_NUMBER; - *tv2 = listtv.vval.v_list->lv_last->li_tv; - listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER; - list_unref(listtv.vval.v_list); - return OK; + list_T *list = listtv.vval.v_list; + + if (list->lv_len == 2 || (tv3 != NULL && list->lv_len == 3)) + { + /* Move the item from the list and then change the type to avoid the + * item being freed. */ + *tv1 = list->lv_first->li_tv; + list->lv_first->li_tv.v_type = VAR_NUMBER; + *tv2 = list->lv_first->li_next->li_tv; + list->lv_first->li_next->li_tv.v_type = VAR_NUMBER; + if (tv3 != NULL) + { + if (list->lv_len == 3) + { + *tv3 = list->lv_last->li_tv; + list->lv_last->li_tv.v_type = VAR_NUMBER; + } + else + tv3->v_type = VAR_UNKNOWN; + } + list_unref(list); + return OK; + } } /* give error message? */ @@ -472,44 +489,86 @@ invoke_callback(int idx, char_u *callback, typval_T *argv) out_flush(); } +/* + * Execute a command received over channel "idx". + * "cmd" is the command string, "arg2" the second argument. + * "arg3" is the third argument, NULL if missing. + */ static void -channel_exe_cmd(char_u *cmd, typval_T *arg) +channel_exe_cmd(int idx, 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 (STRCMP(cmd, "ex") == 0) { - if (arg->v_type == VAR_STRING) - do_cmdline_cmd(arg->vval.v_string); - else if (p_verbose > 2) - EMSG("E999: received ex command with non-string argument"); + do_cmdline_cmd(arg); } else if (STRCMP(cmd, "normal") == 0) { - if (arg->v_type == VAR_STRING) - { - exarg_T ea; + exarg_T ea; - ea.arg = arg->vval.v_string; - ea.addr_count = 0; - ea.forceit = TRUE; /* no mapping */ - ex_normal(&ea); + ea.arg = arg; + ea.addr_count = 0; + ea.forceit = TRUE; /* no mapping */ + ex_normal(&ea); + } + else if (STRCMP(cmd, "redraw") == 0) + { + exarg_T ea; - update_screen(0); - showruler(FALSE); - setcursor(); - out_flush(); + ea.forceit = *arg != NUL; + ex_redraw(&ea); + showruler(FALSE); + setcursor(); + out_flush(); #ifdef FEAT_GUI - if (gui.in_use) + if (gui.in_use) + { + gui_update_cursor(FALSE, FALSE); + gui_mch_flush(); + } +#endif + } + else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "eval") == 0) + { + int is_eval = cmd[1] == 'v'; + + if (is_eval && arg3->v_type != VAR_NUMBER) + { + if (p_verbose > 2) + EMSG("E904: third argument for eval must be a number"); + } + else + { + typval_T *tv = eval_expr(arg, NULL); + typval_T err_tv; + char_u *json; + + if (is_eval) { - gui_update_cursor(FALSE, FALSE); - gui_mch_flush(); + if (tv == NULL) + { + 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); + channel_send(idx, json, "eval"); + vim_free(json); } -#endif + free_tv(tv); } - else if (p_verbose > 2) - EMSG("E999: received normal command with non-string argument"); } else if (p_verbose > 2) - EMSG2("E999: received unknown command: %s", cmd); + EMSG2("E905: received unknown command: %s", cmd); } /* @@ -521,6 +580,7 @@ may_invoke_callback(int idx) char_u *msg; typval_T typetv; typval_T argv[3]; + typval_T arg3; char_u *cmd = NULL; int seq_nr = -1; int ret = OK; @@ -537,9 +597,10 @@ may_invoke_callback(int idx) if (channels[idx].ch_json_mode) { - ret = channel_decode_json(msg, &typetv, &argv[1]); + ret = channel_decode_json(msg, &typetv, &argv[1], &arg3); if (ret == OK) { + /* TODO: error if arg3 is set when it shouldn't? */ if (typetv.v_type == VAR_STRING) cmd = typetv.vval.v_string; else if (typetv.v_type == VAR_NUMBER) @@ -556,7 +617,7 @@ may_invoke_callback(int idx) { if (cmd != NULL) { - channel_exe_cmd(cmd, &argv[1]); + channel_exe_cmd(idx, cmd, &argv[1], &arg3); } else if (channels[idx].ch_req_callback != NULL && seq_nr != 0) { @@ -576,6 +637,7 @@ may_invoke_callback(int idx) { clear_tv(&typetv); clear_tv(&argv[1]); + clear_tv(&arg3); } } @@ -874,7 +936,7 @@ channel_read(int idx) { /* Todo: which channel? */ CHERROR("%s(): cannot from channel\n", "channel_read"); - PERROR(_("E999: read from channel")); + PERROR(_("E896: read from channel")); } } diff --git a/src/eval.c b/src/eval.c index 4c530a0bf..503512667 100644 --- a/src/eval.c +++ b/src/eval.c @@ -16897,8 +16897,6 @@ f_sendexpr(typval_T *argvars, typval_T *rettv) { char_u *text; char_u *resp; - typval_T nrtv; - typval_T listtv; typval_T typetv; int ch_idx; @@ -16906,19 +16904,9 @@ f_sendexpr(typval_T *argvars, typval_T *rettv) rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - nrtv.v_type = VAR_NUMBER; - nrtv.vval.v_number = channel_get_id(); - if (rettv_list_alloc(&listtv) == FAIL) + text = json_encode_nr_expr(channel_get_id(), &argvars[1]); + if (text == NULL) return; - if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL - || list_append_tv(listtv.vval.v_list, &argvars[1]) == FAIL) - { - list_unref(listtv.vval.v_list); - return; - } - - text = json_encode(&listtv); - list_unref(listtv.vval.v_list); ch_idx = send_common(argvars, text, "sendexpr"); if (ch_idx >= 0) @@ -16929,7 +16917,7 @@ f_sendexpr(typval_T *argvars, typval_T *rettv) resp = channel_read_block(ch_idx); if (resp != NULL) { - channel_decode_json(resp, &typetv, rettv); + channel_decode_json(resp, &typetv, rettv, NULL); vim_free(resp); } } diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 028af35c6..1321b7fd6 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -335,7 +335,6 @@ static void ex_rundo(exarg_T *eap); static void ex_redo(exarg_T *eap); static void ex_later(exarg_T *eap); static void ex_redir(exarg_T *eap); -static void ex_redraw(exarg_T *eap); static void ex_redrawstatus(exarg_T *eap); static void close_redir(void); static void ex_mkrc(exarg_T *eap); @@ -9466,7 +9465,7 @@ ex_redir(exarg_T *eap) /* * ":redraw": force redraw */ - static void + void ex_redraw(exarg_T *eap) { int r = RedrawingDisabled; diff --git a/src/json.c b/src/json.c index 7256a8ced..a56104217 100644 --- a/src/json.c +++ b/src/json.c @@ -33,6 +33,33 @@ json_encode(typval_T *val) return ga.ga_data; } +/* + * Encode ["nr", "val"] into a JSON format string. + * Returns NULL when out of memory. + */ + char_u * +json_encode_nr_expr(int nr, typval_T *val) +{ + typval_T listtv; + typval_T nrtv; + char_u *text; + + nrtv.v_type = VAR_NUMBER; + nrtv.vval.v_number = nr; + if (rettv_list_alloc(&listtv) == FAIL) + return NULL; + if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL + || list_append_tv(listtv.vval.v_list, val) == FAIL) + { + list_unref(listtv.vval.v_list); + return NULL; + } + + text = json_encode(&listtv); + list_unref(listtv.vval.v_list); + return text; +} + static void write_string(garray_T *gap, char_u *str) { diff --git a/src/proto/channel.pro b/src/proto/channel.pro index bf3d93e5f..e0fbda891 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -4,7 +4,7 @@ int channel_open(char *hostname, int port_in, void (*close_cb)(void)); void channel_set_json_mode(int idx, int json_mode); void channel_set_callback(int idx, char_u *callback); void channel_set_req_callback(int idx, char_u *callback); -int channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2); +int channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T *tv3); int channel_is_open(int idx); void channel_close(int idx); int channel_save(int idx, char_u *buf, int len); diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 0ba0fd711..6ff1588e9 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -46,6 +46,7 @@ void post_chdir(int local); void ex_cd(exarg_T *eap); void do_sleep(long msec); void ex_may_print(exarg_T *eap); +void ex_redraw(exarg_T *eap); int vim_mkdir_emsg(char_u *name, int prot); FILE *open_exfile(char_u *fname, int forceit, char *mode); void update_topline_cursor(void); diff --git a/src/proto/json.pro b/src/proto/json.pro index 06635456b..48ce9ade9 100644 --- a/src/proto/json.pro +++ b/src/proto/json.pro @@ -1,4 +1,5 @@ /* json.c */ char_u *json_encode(typval_T *val); +char_u *json_encode_nr_expr(int nr, typval_T *val); void json_decode(js_read_T *reader, typval_T *res); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c index 6eb8b240d..1c9cbf51b 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1229, +/**/ 1228, /**/ 1227, |