summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-01-30 23:20:33 +0100
committerBram Moolenaar <Bram@vim.org>2016-01-30 23:20:33 +0100
commit20fb9f346497daca4d19402fdfa5de7958642477 (patch)
treea5f484e21e755b04f4e2ab195c8aac3e8c299daa
parentba4ef2757cfc126f342b710f1ad9ea39e6b56cec (diff)
downloadvim-git-20fb9f346497daca4d19402fdfa5de7958642477.tar.gz
patch 7.4.1217v7.4.1217
Problem: Execution of command on channel doesn't work yet. Solution: Implement the "ex" and "normal" commands.
-rw-r--r--src/channel.c179
-rw-r--r--src/eval.c6
-rw-r--r--src/ex_docmd.c5
-rw-r--r--src/feature.h2
-rw-r--r--src/misc2.c4
-rw-r--r--src/proto/channel.pro4
-rw-r--r--src/proto/ex_docmd.pro1
-rw-r--r--src/version.c2
8 files changed, 135 insertions, 68 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 */
diff --git a/src/eval.c b/src/eval.c
index 90fa53a11..767925193 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -16889,8 +16889,6 @@ send_common(typval_T *argvars, char_u *text, char *fun)
* 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 *rettv)
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 *rettv)
{
/* 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
index 7dfd990a1..24df1d17b 100644
--- 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
index dd18394c5..f1a3a4a39 100644
--- 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
index 05f779f9b..78a7479cc 100644
--- 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
index 2d46a4963..bf3d93e5f 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -4,8 +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);
-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 *fds_in);
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
index 15e5fc5c0..0ba0fd711 100644
--- 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
index 62075750f..d57420b08 100644
--- 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,