diff options
Diffstat (limited to 'src/channel.c')
-rw-r--r-- | src/channel.c | 179 |
1 files changed, 120 insertions, 59 deletions
diff --git a/src/channel.c b/src/channel.c index 2a75342f2..416b53815 100644 --- 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 *callback) } /* - * 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_T *tv) 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,43 +455,61 @@ channel_decode_json(char_u *msg, typval_T *tv) * 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; - /* Concatenate everything into one buffer. - * TODO: only read what the callback will use. - * TODO: avoid multiple allocations. */ - while (channel_collapse(idx) == OK) - ; - msg = channel_get(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(); +} - if (channels[idx].ch_json_mode) - ret = channel_decode_json(msg, &argv[1]); - else + static void +channel_exe_cmd(char_u *cmd, typval_T *arg) +{ + if (STRCMP(cmd, "ex") == 0) { - argv[1].v_type = VAR_STRING; - argv[1].vval.v_string = msg; + 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"); } - - if (ret == OK) + else if (STRCMP(cmd, "normal") == 0) { - 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(); + 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"); } - vim_free(msg); + else if (p_verbose > 2) + EMSG2("E999: received unknown command: %s", cmd); } /* @@ -509,22 +518,68 @@ invoke_callback(int idx, char_u *callback) static void may_invoke_callback(int idx) { - if (channels[idx].ch_will_block) - return; + 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; - if (channels[idx].ch_req_callback != NULL) + /* Concatenate everything into one buffer. + * TODO: only read what the callback will use. + * TODO: avoid multiple allocations. */ + while (channel_collapse(idx) == OK) + ; + msg = channel_get(idx); + + if (channels[idx].ch_json_mode) { - /* invoke the one-time callback */ - invoke_callback(idx, channels[idx].ch_req_callback); - channels[idx].ch_req_callback = NULL; - return; + 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; + argv[1].vval.v_string = msg; + } + + if (ret == OK) + { + 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 */ + + 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 *rfds_in) } # 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 */ |