# HG changeset patch # User Christian Brabandt # Date 1454193005 -3600 # Node ID 28f569c7dab9868cbde1a9703cc648369a6540cc # Parent daacc8ad538b54875c320c12990876c3cf31f34c commit https://github.com/vim/vim/commit/20fb9f346497daca4d19402fdfa5de7958642477 Author: Bram Moolenaar Date: Sat Jan 30 23:20:33 2016 +0100 patch 7.4.1217 Problem: Execution of command on channel doesn't work yet. Solution: Implement the "ex" and "normal" commands. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -99,7 +99,6 @@ typedef struct { char_u *ch_callback; /* function to call when a msg is not handled */ char_u *ch_req_callback; /* function to call for current request */ - int ch_will_block; /* do not use callback right now */ int ch_json_mode; } channel_T; @@ -419,21 +418,13 @@ channel_set_req_callback(int idx, char_u } /* - * Set the flag that the callback for channel "idx" should not be used now. - */ - void -channel_will_block(int idx) -{ - channels[idx].ch_will_block = TRUE; -} - -/* - * Decode JSON "msg", which must have the form "[nr, expr]". - * Put "expr" in "tv". + * Decode JSON "msg", which must have the form "[expr1, expr2]". + * Put "expr1" in "tv1". + * Put "expr2" in "tv2". * Return OK or FAIL. */ int -channel_decode_json(char_u *msg, typval_T *tv) +channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2) { js_read_T reader; typval_T listtv; @@ -442,14 +433,14 @@ channel_decode_json(char_u *msg, typval_ reader.js_eof = TRUE; reader.js_used = 0; json_decode(&reader, &listtv); - /* TODO: use the sequence number */ - if (listtv.v_type == VAR_LIST - && listtv.vval.v_list->lv_len == 2 - && listtv.vval.v_list->lv_first->li_tv.v_type == VAR_NUMBER) + + if (listtv.v_type == VAR_LIST && listtv.vval.v_list->lv_len == 2) { /* Move the item from the list and then change the type to avoid the * item being freed. */ - *tv = listtv.vval.v_list->lv_last->li_tv; + *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; @@ -464,17 +455,79 @@ channel_decode_json(char_u *msg, typval_ * Invoke the "callback" on channel "idx". */ static void -invoke_callback(int idx, char_u *callback) +invoke_callback(int idx, char_u *callback, typval_T *argv) { - typval_T argv[3]; typval_T rettv; int dummy; - char_u *msg; - int ret = OK; argv[0].v_type = VAR_NUMBER; argv[0].vval.v_number = idx; + call_func(callback, (int)STRLEN(callback), + &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL); + /* If an echo command was used the cursor needs to be put back where + * it belongs. */ + setcursor(); + cursor_on(); + out_flush(); +} + + static void +channel_exe_cmd(char_u *cmd, typval_T *arg) +{ + 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"); + } + else if (STRCMP(cmd, "normal") == 0) + { + if (arg->v_type == VAR_STRING) + { + exarg_T ea; + + ea.arg = arg->vval.v_string; + ea.addr_count = 0; + ea.forceit = TRUE; /* no mapping */ + ex_normal(&ea); + + update_screen(0); + showruler(FALSE); + setcursor(); + out_flush(); +#ifdef FEAT_GUI + if (gui.in_use) + { + gui_update_cursor(FALSE, FALSE); + gui_mch_flush(); + } +#endif + } + 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); +} + +/* + * Invoke a callback for channel "idx" if needed. + */ + static void +may_invoke_callback(int idx) +{ + char_u *msg; + typval_T typetv; + typval_T argv[3]; + char_u *cmd = NULL; + int seq_nr = -1; + int ret = OK; + + if (channel_peek(idx) == NULL) + return; + /* Concatenate everything into one buffer. * TODO: only read what the callback will use. * TODO: avoid multiple allocations. */ @@ -483,7 +536,16 @@ invoke_callback(int idx, char_u *callbac msg = channel_get(idx); if (channels[idx].ch_json_mode) - ret = channel_decode_json(msg, &argv[1]); + { + ret = channel_decode_json(msg, &typetv, &argv[1]); + if (ret == OK) + { + if (typetv.v_type == VAR_STRING) + cmd = typetv.vval.v_string; + else if (typetv.v_type == VAR_NUMBER) + seq_nr = typetv.vval.v_number; + } + } else { argv[1].v_type = VAR_STRING; @@ -492,39 +554,32 @@ invoke_callback(int idx, char_u *callbac if (ret == OK) { - call_func(callback, (int)STRLEN(callback), - &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL); - /* If an echo command was used the cursor needs to be put back where - * it belongs. */ - setcursor(); - cursor_on(); - out_flush(); - } - vim_free(msg); -} + if (cmd != NULL) + { + channel_exe_cmd(cmd, &argv[1]); + } + else if (channels[idx].ch_req_callback != NULL && seq_nr != 0) + { + /* TODO: check the sequence number */ + /* invoke the one-time callback */ + invoke_callback(idx, channels[idx].ch_req_callback, argv); + channels[idx].ch_req_callback = NULL; + } + else if (channels[idx].ch_callback != NULL) + { + /* invoke the channel callback */ + invoke_callback(idx, channels[idx].ch_callback, argv); + } + /* else: drop the message */ -/* - * Invoke a callback for channel "idx" if needed. - */ - static void -may_invoke_callback(int idx) -{ - if (channels[idx].ch_will_block) - return; - if (channel_peek(idx) == NULL) - return; - - if (channels[idx].ch_req_callback != NULL) - { - /* invoke the one-time callback */ - invoke_callback(idx, channels[idx].ch_req_callback); - channels[idx].ch_req_callback = NULL; - return; + if (channels[idx].ch_json_mode) + { + clear_tv(&typetv); + clear_tv(&argv[1]); + } } - if (channels[idx].ch_callback != NULL) - /* invoke the channel callback */ - invoke_callback(idx, channels[idx].ch_callback); + vim_free(msg); } /* @@ -823,8 +878,6 @@ channel_read(int idx) } } - may_invoke_callback(idx); - #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK) if (CH_HAS_GUI && gtk_main_level() > 0) gtk_main_quit(); @@ -845,10 +898,7 @@ channel_read_block(int idx) /* Wait for up to 2 seconds. * TODO: use timeout set on the channel. */ if (channel_wait(channels[idx].ch_fd, 2000) == FAIL) - { - channels[idx].ch_will_block = FALSE; return NULL; - } channel_read(idx); } @@ -857,7 +907,6 @@ channel_read_block(int idx) while (channel_collapse(idx) == OK) ; - channels[idx].ch_will_block = FALSE; return channel_get(idx); } @@ -1009,4 +1058,16 @@ channel_select_check(int ret_in, void *r } # endif /* !FEAT_GUI_W32 && HAVE_SELECT */ +/* + * Invoked from the main loop when it's save to execute received commands. + */ + void +channel_parse_messages(void) +{ + int i; + + for (i = 0; i < channel_count; ++i) + may_invoke_callback(i); +} + #endif /* FEAT_CHANNEL */ diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -16889,8 +16889,6 @@ send_common(typval_T *argvars, char_u *t * not reading the response. */ channel_set_req_callback(ch_idx, callback != NULL && *callback == NUL ? NULL : callback); - if (callback == NULL) - channel_will_block(ch_idx); if (channel_send(ch_idx, text, fun) == OK && callback == NULL) return ch_idx; @@ -16907,6 +16905,7 @@ f_sendexpr(typval_T *argvars, typval_T * char_u *resp; typval_T nrtv; typval_T listtv; + typval_T typetv; int ch_idx; /* return an empty string by default */ @@ -16932,10 +16931,11 @@ f_sendexpr(typval_T *argvars, typval_T * { /* TODO: read until the whole JSON message is received */ /* TODO: only use the message with the right message ID */ + /* TODO: check sequence number */ resp = channel_read_block(ch_idx); if (resp != NULL) { - channel_decode_json(resp, rettv); + channel_decode_json(resp, &typetv, rettv); vim_free(resp); } } diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -345,7 +345,6 @@ static char_u *uc_fun_cmd(void); static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl); #endif #ifdef FEAT_EX_EXTRA -static void ex_normal(exarg_T *eap); static void ex_startinsert(exarg_T *eap); static void ex_stopinsert(exarg_T *eap); #else @@ -9861,11 +9860,11 @@ update_topline_cursor(void) update_curswant(); } -#ifdef FEAT_EX_EXTRA +#if defined(FEAT_EX_EXTRA) || defined(PROTO) /* * ":normal[!] {commands}": Execute normal mode commands. */ - static void + void ex_normal(exarg_T *eap) { int save_msg_scroll = msg_scroll; diff --git a/src/feature.h b/src/feature.h --- a/src/feature.h +++ b/src/feature.h @@ -256,7 +256,7 @@ /* * +ex_extra ":retab", ":right", ":left", ":center", ":normal". */ -#ifdef FEAT_NORMAL +#if defined(FEAT_NORMAL) || defined(FEAT_CHANNEL) # define FEAT_EX_EXTRA #endif diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -6240,6 +6240,10 @@ parse_queued_messages(void) /* Process the queued netbeans messages. */ netbeans_parse_messages(); # endif +# ifdef FEAT_CHANNEL + /* Process the messages queued on channels. */ + channel_parse_messages(); +# endif # if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) /* Process the queued clientserver messages. */ server_parse_messages(); diff --git a/src/proto/channel.pro b/src/proto/channel.pro --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -4,8 +4,7 @@ int channel_open(char *hostname, int por 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); -void channel_will_block(int idx); -int channel_decode_json(char_u *msg, typval_T *tv); +int channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2); int channel_is_open(int idx); void channel_close(int idx); int channel_save(int idx, char_u *buf, int len); @@ -22,4 +21,5 @@ int channel_poll_setup(int nfd_in, void int channel_poll_check(int ret_in, void *fds_in); int channel_select_setup(int maxfd_in, void *rfds_in); int channel_select_check(int ret_in, void *rfds_in); +void channel_parse_messages(void); /* vim: set ft=c : */ diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -49,6 +49,7 @@ void ex_may_print(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); +void ex_normal(exarg_T *eap); void exec_normal_cmd(char_u *cmd, int remap, int silent); void exec_normal(int was_typed); int find_cmdline_var(char_u *src, int *usedlen); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1217, +/**/ 1216, /**/ 1215,