changeset 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 daacc8ad538b
children c39d982a69aa
files src/channel.c src/eval.c src/ex_docmd.c src/feature.h src/misc2.c src/proto/channel.pro src/proto/ex_docmd.pro src/version.c
diffstat 8 files changed, 135 insertions(+), 68 deletions(-) [+]
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 */
--- 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);
 	}
     }
--- 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;
--- 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
 
--- 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();
--- 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 : */
--- 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);
--- 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,