Patch 7.4.1229
Problem:    "eval" and "expr" channel commands don't work yet.
Solution:   Implement them.  Update the error numbers.  Also add "redraw".
Files:      src/channel.c, src/eval.c, src/json.c, src/ex_docmd.c,
            src/proto/channel.pro, src/proto/json.pro, src/proto/ex_docmd.pro,
            runtime/doc/channel.txt


*** ../vim-7.4.1228/src/channel.c       2016-01-30 23:20:28.523141073 +0100
--- src/channel.c       2016-01-31 20:15:26.863506973 +0100
***************
*** 293,306 ****
      if (idx < 0)
      {
        CHERROR("All channels are in use\n", "");
!       EMSG(_("E999: All channels are in use"));
        return -1;
      }
  
      if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
      {
        CHERROR("error in socket() in channel_open()\n", "");
!       PERROR("E999: socket() in channel_open()");
        return -1;
      }
  
--- 293,306 ----
      if (idx < 0)
      {
        CHERROR("All channels are in use\n", "");
!       EMSG(_("E897: All channels are in use"));
        return -1;
      }
  
      if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
      {
        CHERROR("error in socket() in channel_open()\n", "");
!       PERROR("E898: socket() in channel_open()");
        return -1;
      }
  
***************
*** 312,318 ****
      if ((host = gethostbyname(hostname)) == NULL)
      {
        CHERROR("error in gethostbyname() in channel_open()\n", "");
!       PERROR("E999: gethostbyname() in channel_open()");
        sock_close(sd);
        return -1;
      }
--- 312,318 ----
      if ((host = gethostbyname(hostname)) == NULL)
      {
        CHERROR("error in gethostbyname() in channel_open()\n", "");
!       PERROR("E901: gethostbyname() in channel_open()");
        sock_close(sd);
        return -1;
      }
***************
*** 330,336 ****
            {
                SOCK_ERRNO;
                CHERROR("socket() retry in channel_open()\n", "");
!               PERROR("E999: socket() retry in channel_open()");
                return -1;
            }
            if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
--- 330,336 ----
            {
                SOCK_ERRNO;
                CHERROR("socket() retry in channel_open()\n", "");
!               PERROR("E900: socket() retry in channel_open()");
                return -1;
            }
            if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
***************
*** 362,368 ****
                {
                    /* Get here when the server can't be found. */
                    CHERROR("Cannot connect to port after retry\n", "");
!                   PERROR(_("E999: Cannot connect to port after retry2"));
                    sock_close(sd);
                    return -1;
                }
--- 362,368 ----
                {
                    /* Get here when the server can't be found. */
                    CHERROR("Cannot connect to port after retry\n", "");
!                   PERROR(_("E899: Cannot connect to port after retry2"));
                    sock_close(sd);
                    return -1;
                }
***************
*** 371,377 ****
        else
        {
            CHERROR("Cannot connect to port\n", "");
!           PERROR(_("E999: Cannot connect to port"));
            sock_close(sd);
            return -1;
        }
--- 371,377 ----
        else
        {
            CHERROR("Cannot connect to port\n", "");
!           PERROR(_("E902: Cannot connect to port"));
            sock_close(sd);
            return -1;
        }
***************
*** 418,430 ****
  }
  
  /*
!  * 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 *tv1, typval_T *tv2)
  {
      js_read_T reader;
      typval_T  listtv;
--- 418,432 ----
  }
  
  /*
!  * Decode JSON "msg", which must have the form "[expr1, expr2, expr3]".
   * Put "expr1" in "tv1".
   * Put "expr2" in "tv2".
+  * Put "expr3" in "tv3". If "tv3" is NULL there is no "expr3".
+  *
   * Return OK or FAIL.
   */
      int
! channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T *tv3)
  {
      js_read_T reader;
      typval_T  listtv;
***************
*** 434,449 ****
      reader.js_used = 0;
      json_decode(&reader, &listtv);
  
!     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. */
!       *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;
      }
  
      /* give error message? */
--- 436,466 ----
      reader.js_used = 0;
      json_decode(&reader, &listtv);
  
!     if (listtv.v_type == VAR_LIST)
      {
!       list_T *list = listtv.vval.v_list;
! 
!       if (list->lv_len == 2 || (tv3 != NULL && list->lv_len == 3))
!       {
!           /* Move the item from the list and then change the type to avoid the
!            * item being freed. */
!           *tv1 = list->lv_first->li_tv;
!           list->lv_first->li_tv.v_type = VAR_NUMBER;
!           *tv2 = list->lv_first->li_next->li_tv;
!           list->lv_first->li_next->li_tv.v_type = VAR_NUMBER;
!           if (tv3 != NULL)
!           {
!               if (list->lv_len == 3)
!               {
!                   *tv3 = list->lv_last->li_tv;
!                   list->lv_last->li_tv.v_type = VAR_NUMBER;
!               }
!               else
!                   tv3->v_type = VAR_UNKNOWN;
!           }
!           list_unref(list);
!           return OK;
!       }
      }
  
      /* give error message? */
***************
*** 472,515 ****
      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);
  }
  
  /*
--- 489,574 ----
      out_flush();
  }
  
+ /*
+  * Execute a command received over channel "idx".
+  * "cmd" is the command string, "arg2" the second argument.
+  * "arg3" is the third argument, NULL if missing.
+  */
      static void
! channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3)
  {
+     char_u *arg;
+ 
+     if (arg2->v_type != VAR_STRING)
+     {
+       if (p_verbose > 2)
+           EMSG("E903: received ex command with non-string argument");
+       return;
+     }
+     arg = arg2->vval.v_string;
+ 
      if (STRCMP(cmd, "ex") == 0)
      {
!       do_cmdline_cmd(arg);
      }
      else if (STRCMP(cmd, "normal") == 0)
      {
!       exarg_T ea;
  
!       ea.arg = arg;
!       ea.addr_count = 0;
!       ea.forceit = TRUE; /* no mapping */
!       ex_normal(&ea);
!     }
!     else if (STRCMP(cmd, "redraw") == 0)
!     {
!       exarg_T ea;
! 
!       ea.forceit = *arg != NUL;
!       ex_redraw(&ea);
!       showruler(FALSE);
!       setcursor();
!       out_flush();
  #ifdef FEAT_GUI
!       if (gui.in_use)
!       {
!           gui_update_cursor(FALSE, FALSE);
!           gui_mch_flush();
!       }
! #endif
!     }
!     else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "eval") == 0)
!     {
!       int is_eval = cmd[1] == 'v';
! 
!       if (is_eval && arg3->v_type != VAR_NUMBER)
!       {
!           if (p_verbose > 2)
!               EMSG("E904: third argument for eval must be a number");
!       }
!       else
!       {
!           typval_T    *tv = eval_expr(arg, NULL);
!           typval_T    err_tv;
!           char_u      *json;
! 
!           if (is_eval)
            {
!               if (tv == NULL)
!               {
!                   err_tv.v_type = VAR_STRING;
!                   err_tv.vval.v_string = (char_u *)"ERROR";
!                   tv = &err_tv;
!               }
!               json = json_encode_nr_expr(arg3->vval.v_number, tv);
!               channel_send(idx, json, "eval");
!               vim_free(json);
            }
!           free_tv(tv);
        }
      }
      else if (p_verbose > 2)
!       EMSG2("E905: received unknown command: %s", cmd);
  }
  
  /*
***************
*** 521,526 ****
--- 580,586 ----
      char_u    *msg;
      typval_T  typetv;
      typval_T  argv[3];
+     typval_T  arg3;
      char_u    *cmd = NULL;
      int               seq_nr = -1;
      int               ret = OK;
***************
*** 537,545 ****
  
      if (channels[idx].ch_json_mode)
      {
!       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)
--- 597,606 ----
  
      if (channels[idx].ch_json_mode)
      {
!       ret = channel_decode_json(msg, &typetv, &argv[1], &arg3);
        if (ret == OK)
        {
+           /* TODO: error if arg3 is set when it shouldn't? */
            if (typetv.v_type == VAR_STRING)
                cmd = typetv.vval.v_string;
            else if (typetv.v_type == VAR_NUMBER)
***************
*** 556,562 ****
      {
        if (cmd != NULL)
        {
!           channel_exe_cmd(cmd, &argv[1]);
        }
        else if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
        {
--- 617,623 ----
      {
        if (cmd != NULL)
        {
!           channel_exe_cmd(idx, cmd, &argv[1], &arg3);
        }
        else if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
        {
***************
*** 576,581 ****
--- 637,643 ----
        {
            clear_tv(&typetv);
            clear_tv(&argv[1]);
+           clear_tv(&arg3);
        }
      }
  
***************
*** 874,880 ****
        {
            /* Todo: which channel? */
            CHERROR("%s(): cannot from channel\n", "channel_read");
!           PERROR(_("E999: read from channel"));
        }
      }
  
--- 936,942 ----
        {
            /* Todo: which channel? */
            CHERROR("%s(): cannot from channel\n", "channel_read");
!           PERROR(_("E896: read from channel"));
        }
      }
  
*** ../vim-7.4.1228/src/eval.c  2016-01-31 18:45:20.996084796 +0100
--- src/eval.c  2016-01-31 19:36:10.932096638 +0100
***************
*** 16897,16904 ****
  {
      char_u    *text;
      char_u    *resp;
-     typval_T  nrtv;
-     typval_T  listtv;
      typval_T  typetv;
      int               ch_idx;
  
--- 16897,16902 ----
***************
*** 16906,16924 ****
      rettv->v_type = VAR_STRING;
      rettv->vval.v_string = NULL;
  
!     nrtv.v_type = VAR_NUMBER;
!     nrtv.vval.v_number = channel_get_id();
!     if (rettv_list_alloc(&listtv) == FAIL)
        return;
-     if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
-           || list_append_tv(listtv.vval.v_list, &argvars[1]) == FAIL)
-     {
-       list_unref(listtv.vval.v_list);
-       return;
-     }
- 
-     text = json_encode(&listtv);
-     list_unref(listtv.vval.v_list);
  
      ch_idx = send_common(argvars, text, "sendexpr");
      if (ch_idx >= 0)
--- 16904,16912 ----
      rettv->v_type = VAR_STRING;
      rettv->vval.v_string = NULL;
  
!     text = json_encode_nr_expr(channel_get_id(), &argvars[1]);
!     if (text == NULL)
        return;
  
      ch_idx = send_common(argvars, text, "sendexpr");
      if (ch_idx >= 0)
***************
*** 16929,16935 ****
        resp = channel_read_block(ch_idx);
        if (resp != NULL)
        {
!           channel_decode_json(resp, &typetv, rettv);
            vim_free(resp);
        }
      }
--- 16917,16923 ----
        resp = channel_read_block(ch_idx);
        if (resp != NULL)
        {
!           channel_decode_json(resp, &typetv, rettv, NULL);
            vim_free(resp);
        }
      }
*** ../vim-7.4.1228/src/json.c  2016-01-28 22:46:52.017343116 +0100
--- src/json.c  2016-01-31 19:32:13.738584392 +0100
***************
*** 33,38 ****
--- 33,65 ----
      return ga.ga_data;
  }
  
+ /*
+  * Encode ["nr", "val"] into a JSON format string.
+  * Returns NULL when out of memory.
+  */
+     char_u *
+ json_encode_nr_expr(int nr, typval_T *val)
+ {
+     typval_T  listtv;
+     typval_T  nrtv;
+     char_u    *text;
+ 
+     nrtv.v_type = VAR_NUMBER;
+     nrtv.vval.v_number = nr;
+     if (rettv_list_alloc(&listtv) == FAIL)
+       return NULL;
+     if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
+           || list_append_tv(listtv.vval.v_list, val) == FAIL)
+     {
+       list_unref(listtv.vval.v_list);
+       return NULL;
+     }
+ 
+     text = json_encode(&listtv);
+     list_unref(listtv.vval.v_list);
+     return text;
+ }
+ 
      static void
  write_string(garray_T *gap, char_u *str)
  {
*** ../vim-7.4.1228/src/ex_docmd.c      2016-01-31 14:55:35.227538473 +0100
--- src/ex_docmd.c      2016-01-31 20:15:14.095639725 +0100
***************
*** 335,341 ****
  static void   ex_redo(exarg_T *eap);
  static void   ex_later(exarg_T *eap);
  static void   ex_redir(exarg_T *eap);
- static void   ex_redraw(exarg_T *eap);
  static void   ex_redrawstatus(exarg_T *eap);
  static void   close_redir(void);
  static void   ex_mkrc(exarg_T *eap);
--- 335,340 ----
***************
*** 9466,9472 ****
  /*
   * ":redraw": force redraw
   */
!     static void
  ex_redraw(exarg_T *eap)
  {
      int               r = RedrawingDisabled;
--- 9465,9471 ----
  /*
   * ":redraw": force redraw
   */
!     void
  ex_redraw(exarg_T *eap)
  {
      int               r = RedrawingDisabled;
*** ../vim-7.4.1228/src/proto/channel.pro       2016-01-30 23:20:28.523141073 
+0100
--- src/proto/channel.pro       2016-01-31 19:36:46.331725396 +0100
***************
*** 4,10 ****
  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);
! 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);
--- 4,10 ----
  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);
! int channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T 
*tv3);
  int channel_is_open(int idx);
  void channel_close(int idx);
  int channel_save(int idx, char_u *buf, int len);
*** ../vim-7.4.1228/src/proto/json.pro  2016-01-24 16:49:06.227712998 +0100
--- src/proto/json.pro  2016-01-31 19:35:59.988211410 +0100
***************
*** 1,4 ****
--- 1,5 ----
  /* json.c */
  char_u *json_encode(typval_T *val);
+ char_u *json_encode_nr_expr(int nr, typval_T *val);
  void json_decode(js_read_T *reader, typval_T *res);
  /* vim: set ft=c : */
*** ../vim-7.4.1228/src/proto/ex_docmd.pro      2016-01-30 23:20:28.531140989 
+0100
--- src/proto/ex_docmd.pro      2016-01-31 20:15:18.503593894 +0100
***************
*** 46,51 ****
--- 46,52 ----
  void ex_cd(exarg_T *eap);
  void do_sleep(long msec);
  void ex_may_print(exarg_T *eap);
+ void ex_redraw(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);
*** ../vim-7.4.1228/runtime/doc/channel.txt     2016-01-28 22:36:15.056065002 
+0100
--- runtime/doc/channel.txt     2016-01-31 20:07:19.752587340 +0100
***************
*** 1,4 ****
! *channel.txt*      For Vim version 7.4.  Last change: 2016 Jan 28
  
  
                  VIM REFERENCE MANUAL    by Bram Moolenaar
--- 1,4 ----
! *channel.txt*      For Vim version 7.4.  Last change: 2016 Jan 31
  
  
                  VIM REFERENCE MANUAL    by Bram Moolenaar
***************
*** 48,57 ****
  The number will increase every time you send a message.
  
  The server can send a command to Vim.  Type this on T1 (literally, including
! the quotes): >
!       NOT IMPLEMENTED YET
!       ["ex","echo 'hi there'"]
! And you should see the message in Vim.
  
  To handle asynchronous communication a callback needs to be used: >
        func MyHandler(handle, msg)
--- 48,57 ----
  The number will increase every time you send a message.
  
  The server can send a command to Vim.  Type this on T1 (literally, including
! the quotes):
!       ["ex","echo 'hi there'"] ~
! And you should see the message in Vim. You can move the cursor a word forward:
!       ["normal","w"] ~
  
  To handle asynchronous communication a callback needs to be used: >
        func MyHandler(handle, msg)
***************
*** 100,105 ****
--- 100,113 ----
  Once done with the channel, disconnect it like this: >
      call disconnect(handle)
  
+ Currently up to 10 channels can be in use at the same time. *E897*
+ 
+ When the channel can't be opened you will get an error message.
+ *E898* *E899* *E900* *E901* *E902*
+ 
+ If there is an error reading or writing a channel it will be closed.
+ *E896* *E630* *E631* 
+ 
  ==============================================================================
  3. Using a JSON channel                                       *channel-use*
  
***************
*** 146,181 ****
  ==============================================================================
  4. Vim commands                                               
*channel-commands*
  
! NOT IMPLEMENTED YET
  
  With a "json" channel the process can send commands to Vim that will be
  handled by Vim internally, it does not require a handler for the channel.
  
! Possible commands are:
      ["ex",     {Ex command}]
      ["normal", {Normal mode command}]
!     ["eval",   {number}, {expression}]
      ["expr",   {expression}]
  
  With all of these: Be careful what these commands do!  You can easily
  interfere with what the user is doing.  To avoid trouble use |mode()| to check
  that the editor is in the expected state.  E.g., to send keys that must be
! inserted as text, not executed as a command: >
!     ["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"]
  
  The "ex" command is executed as any Ex command.  There is no response for
! completion or error.  You could use functions in an |autoload| script.
! You can also invoke |feedkeys()| to insert anything.
  
! The "normal" command is executed like with |:normal|.
  
! The "eval" command will result in sending back the result of the expression:
        [{number}, {result}]
! Here {number} is the same as what was in the request.
  
! The "expr" command is similar, but does not send back any response.
  Example:
!       ["expr","setline('$', ['one', 'two', 'three'])"]
  
  ==============================================================================
  5. Using a raw channel                                        *channel-raw*
--- 154,230 ----
  ==============================================================================
  4. Vim commands                                               
*channel-commands*
  
! PARTLY IMPLEMENTED: only "ex" and "normal" work
  
  With a "json" channel the process can send commands to Vim that will be
  handled by Vim internally, it does not require a handler for the channel.
  
! Possible commands are:                                *E903* *E904* *E905*
!     ["redraw"  {forced}]
      ["ex",     {Ex command}]
      ["normal", {Normal mode command}]
!     ["eval",   {expression}, {number}]
      ["expr",   {expression}]
  
  With all of these: Be careful what these commands do!  You can easily
  interfere with what the user is doing.  To avoid trouble use |mode()| to check
  that the editor is in the expected state.  E.g., to send keys that must be
! inserted as text, not executed as a command:
!     ["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"] ~
! 
! Errors in these commands are normally not reported to avoid them messing up
! the display.  If you do want to see them, set the 'verbose' option to 3 or
! higher.
! 
! 
! Command "redraw" ~
! 
! The other commands do not update the screen, so that you can send a sequence
! of commands without the cursor moving around.  You must end with the "redraw"
! command to show any changed text and show the cursor where it belongs.
! 
! The argument is normally an empty string:
!       ["redraw", ""] ~
! To first clear the screen pass "force":
!       ["redraw", "force"] ~
! 
! 
! Command "ex" ~
  
  The "ex" command is executed as any Ex command.  There is no response for
! completion or error.  You could use functions in an |autoload| script:
!       ["ex","call myscript#MyFunc(arg)"]
  
! You can also use "call |feedkeys()|" to insert any key sequence.
  
! 
! Command "normal" ~
! 
! The "normal" command is executed like with |:normal!|, commands are not
! mapped.  Example to open the folds under the cursor:
!       ["normal" "zO"]
! 
! 
! Command "eval" ~
! 
! The "eval" command an be used to get the result of an expression.  For
! example, to get the number of lines in the current buffer:
!       ["eval","line('$')"] ~
! 
! it will send back the result of the expression:
        [{number}, {result}]
! Here {number} is the same as what was in the request.  Use a negative number
! to avoid confusion with message that Vim sends.
! 
! {result} is the result of the evaluation and is JSON encoded.  If the
! evaluation fails it is the string "ERROR".
! 
! 
! Command "expr" ~
  
! The "expr" command is similar to "eval", but does not send back any response.
  Example:
!       ["expr","setline('$', ['one', 'two', 'three'])"] ~
  
  ==============================================================================
  5. Using a raw channel                                        *channel-raw*
*** ../vim-7.4.1228/src/version.c       2016-01-31 18:45:20.996084796 +0100
--- src/version.c       2016-01-31 20:13:31.280708829 +0100
***************
*** 744,745 ****
--- 744,747 ----
  {   /* Add new patch number below this line */
+ /**/
+     1229,
  /**/

-- 
I AM THANKFUL...
...for the mess to clean after a party because it means I have
been surrounded by friends.

 /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui