Mercurial > vim
diff src/channel.c @ 7840:28f569c7dab9 v7.4.1217
commit https://github.com/vim/vim/commit/20fb9f346497daca4d19402fdfa5de7958642477
Author: Bram Moolenaar <Bram@vim.org>
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.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 30 Jan 2016 23:30:05 +0100 |
parents | 83861277e6a3 |
children | 6b0891de44a9 |
line wrap: on
line diff
--- 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 */