]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 7.4.1217 v7.4.1217
authorBram Moolenaar <Bram@vim.org>
Sat, 30 Jan 2016 22:20:33 +0000 (23:20 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 30 Jan 2016 22:20:33 +0000 (23:20 +0100)
Problem:    Execution of command on channel doesn't work yet.
Solution:   Implement the "ex" and "normal" commands.

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

index 2a75342f2dd539a2f0459cbb42c548672c3ca438..416b5381556482c32ef4ae673f0df2f3dacedc2b 100644 (file)
@@ -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 */
index 90fa53a1149329cc66ad0b3745b5303c43e56fd7..767925193a8638a946c1313093f7c66dfb7b6082 100644 (file)
@@ -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);
        }
     }
index 7dfd990a11fadd139e018ec6218471310d340ca9..24df1d17bf3c09f6ed5a0d18aec8e5c79e4a9acf 100644 (file)
@@ -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;
index dd18394c5376c67f5fdbbc27a3f99e30a41e3fc4..f1a3a4a39b3e7bcd1f44e468aa478c488a10e8dd 100644 (file)
 /*
  * +ex_extra           ":retab", ":right", ":left", ":center", ":normal".
  */
-#ifdef FEAT_NORMAL
+#if defined(FEAT_NORMAL) || defined(FEAT_CHANNEL)
 # define FEAT_EX_EXTRA
 #endif
 
index 05f779f9ba4e0cc0a6a31159fbda16250ec32064..78a7479ccfa0c5b247e0d64ab9701e9e94079860 100644 (file)
@@ -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();
index 2d46a4963fa90924126619677f9219b6cac83c28..bf3d93e5fe55d39ec515186f6dd04ea92f5ca86c 100644 (file)
@@ -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 : */
index 15e5fc5c04dc8b5f398b6f826429a344e286eb39..0ba0fd711ec3b523771b672f2c5f9e72c1b5ac35 100644 (file)
@@ -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);
index 62075750f1e090afde4e9967a490c77eed3364c0..d57420b08ef51a78ad5124bf73baf12efc822550 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1217,
 /**/
     1216,
 /**/