Patch 7.4.1341
Problem:    It's difficult to add more arguments to ch_sendraw() and
            ch_sendexpr().
Solution:   Make the third option a dictionary.
Files:      src/eval.c, src/structs.h, src/channel.c, src/os_unix.c,
            src/os_win32.c, src/proto/channel.pro,
            src/testdir/test_channel.vim, runtime/doc/eval.txt


*** ../vim-7.4.1340/src/eval.c  2016-02-16 19:37:24.445233506 +0100
--- src/eval.c  2016-02-16 20:53:30.309425831 +0100
***************
*** 9930,9944 ****
  }
  
  /*
!  * Get the "mode" entry from "dict", if it exists, and parse the mode name.
!  * If the mode is invalide return FAIL.
   */
      static int
! get_mode_arg(dict_T *dict, jobopt_T *opt)
  {
      dictitem_T        *item;
      char_u    *mode;
  
      if ((item = dict_find(dict, (char_u *)"mode", -1)) != NULL)
      {
        mode = get_tv_string(&item->di_tv);
--- 9930,9947 ----
  }
  
  /*
!  * Get the option entries from "dict", and parse them.
!  * If an option value is invalid return FAIL.
   */
      static int
! get_job_options(dict_T *dict, jobopt_T *opt)
  {
      dictitem_T        *item;
      char_u    *mode;
  
+     if (dict == NULL)
+       return OK;
+ 
      if ((item = dict_find(dict, (char_u *)"mode", -1)) != NULL)
      {
        mode = get_tv_string(&item->di_tv);
***************
*** 9956,9961 ****
--- 9959,9975 ----
            return FAIL;
        }
      }
+ 
+     if ((item = dict_find(dict, (char_u *)"callback", -1)) != NULL)
+     {
+       opt->jo_callback = get_callback(&item->di_tv);
+       if (opt->jo_callback == NULL)
+       {
+           EMSG2(_(e_invarg2), "callback");
+           return FAIL;
+       }
+     }
+ 
      return OK;
  }
  
***************
*** 9966,9972 ****
  f_ch_open(typval_T *argvars, typval_T *rettv)
  {
      char_u    *address;
-     char_u    *callback = NULL;
      char_u    *p;
      char      *rest;
      int               port;
--- 9980,9985 ----
***************
*** 10004,10023 ****
      }
  
      options.jo_mode = MODE_JSON;
      if (argvars[1].v_type == VAR_DICT)
      {
        dict_T      *dict = argvars[1].vval.v_dict;
        dictitem_T  *item;
  
        /* parse argdict */
!       if (get_mode_arg(dict, &options) == FAIL)
            return;
        if ((item = dict_find(dict, (char_u *)"waittime", -1)) != NULL)
            waittime = get_tv_number(&item->di_tv);
        if ((item = dict_find(dict, (char_u *)"timeout", -1)) != NULL)
            timeout = get_tv_number(&item->di_tv);
-       if ((item = dict_find(dict, (char_u *)"callback", -1)) != NULL)
-           callback = get_callback(&item->di_tv);
      }
      if (waittime < 0 || timeout < 0)
      {
--- 10017,10035 ----
      }
  
      options.jo_mode = MODE_JSON;
+     options.jo_callback = NULL;
      if (argvars[1].v_type == VAR_DICT)
      {
        dict_T      *dict = argvars[1].vval.v_dict;
        dictitem_T  *item;
  
        /* parse argdict */
!       if (get_job_options(dict, &options) == FAIL)
            return;
        if ((item = dict_find(dict, (char_u *)"waittime", -1)) != NULL)
            waittime = get_tv_number(&item->di_tv);
        if ((item = dict_find(dict, (char_u *)"timeout", -1)) != NULL)
            timeout = get_tv_number(&item->di_tv);
      }
      if (waittime < 0 || timeout < 0)
      {
***************
*** 10029,10038 ****
      if (channel != NULL)
      {
        rettv->vval.v_channel = channel;
!       channel_set_mode(channel, options.jo_mode);
        channel_set_timeout(channel, timeout);
-       if (callback != NULL && *callback != NUL)
-           channel_set_callback(channel, callback);
      }
  }
  
--- 10041,10048 ----
      if (channel != NULL)
      {
        rettv->vval.v_channel = channel;
!       channel_set_options(channel, &options);
        channel_set_timeout(channel, timeout);
      }
  }
  
***************
*** 10082,10087 ****
--- 10092,10098 ----
  {
      channel_T *channel;
      char_u    *callback = NULL;
+     jobopt_T  options;
  
      channel = get_channel_arg(&argvars[0]);
      if (channel == NULL)
***************
*** 10089,10097 ****
  
      if (argvars[2].v_type != VAR_UNKNOWN)
      {
!       callback = get_callback(&argvars[2]);
!       if (callback == NULL)
            return NULL;
      }
      /* Set the callback. An empty callback means no callback and not reading
       * the response. */
--- 10100,10114 ----
  
      if (argvars[2].v_type != VAR_UNKNOWN)
      {
!       if (argvars[2].v_type != VAR_DICT)
!       {
!           EMSG(_(e_invarg));
            return NULL;
+       }
+       options.jo_callback = NULL;
+       if (get_job_options(argvars[2].vval.v_dict, &options) == FAIL)
+           return NULL;
+       callback = options.jo_callback;
      }
      /* Set the callback. An empty callback means no callback and not reading
       * the response. */
***************
*** 14511,14527 ****
  
      /* Default mode is NL. */
      options.jo_mode = MODE_NL;
      if (argvars[1].v_type != VAR_UNKNOWN)
      {
-       dict_T      *dict;
- 
        if (argvars[1].v_type != VAR_DICT)
        {
            EMSG(_(e_invarg));
            return;
        }
!       dict = argvars[1].vval.v_dict;
!       if (get_mode_arg(dict, &options) == FAIL)
            return;
      }
  
--- 14528,14542 ----
  
      /* Default mode is NL. */
      options.jo_mode = MODE_NL;
+     options.jo_callback = NULL;
      if (argvars[1].v_type != VAR_UNKNOWN)
      {
        if (argvars[1].v_type != VAR_DICT)
        {
            EMSG(_(e_invarg));
            return;
        }
!       if (get_job_options(argvars[1].vval.v_dict, &options) == FAIL)
            return;
      }
  
*** ../vim-7.4.1340/src/structs.h       2016-02-16 19:25:07.580925715 +0100
--- src/structs.h       2016-02-16 20:34:24.021499966 +0100
***************
*** 1373,1383 ****
  };
  
  /*
!  * Options for job commands.
   */
  typedef struct
  {
!     ch_mode_T jo_mode;
  } jobopt_T;
  
  
--- 1373,1384 ----
  };
  
  /*
!  * Options for job and channel commands.
   */
  typedef struct
  {
!     ch_mode_T jo_mode;        /* "mode" */
!     char_u    *jo_callback;   /* "callback", not allocated! */
  } jobopt_T;
  
  
*** ../vim-7.4.1340/src/channel.c       2016-02-16 19:25:07.580925715 +0100
--- src/channel.c       2016-02-16 20:43:11.751946370 +0100
***************
*** 697,702 ****
--- 697,714 ----
  }
  
  /*
+  * Set various properties from an "options" argument.
+  */
+     void
+ channel_set_options(channel_T *channel, jobopt_T *options)
+ {
+     channel_set_mode(channel, options->jo_mode);
+ 
+     if (options->jo_callback != NULL && *options->jo_callback != NUL)
+       channel_set_callback(channel, options->jo_callback);
+ }
+ 
+ /*
   * Set the callback for channel "channel" for the response with "id".
   */
      void
*** ../vim-7.4.1340/src/os_unix.c       2016-02-16 19:44:14.732951080 +0100
--- src/os_unix.c       2016-02-16 20:44:19.763229009 +0100
***************
*** 5127,5133 ****
  # ifdef FEAT_CHANNEL
      channel_set_pipes(channel, fd_in[1], fd_out[0], fd_err[0]);
      channel_set_job(channel, job);
!     channel_set_mode(channel, options->jo_mode);
  #  ifdef FEAT_GUI
      channel_gui_register(channel);
  #  endif
--- 5127,5133 ----
  # ifdef FEAT_CHANNEL
      channel_set_pipes(channel, fd_in[1], fd_out[0], fd_err[0]);
      channel_set_job(channel, job);
!     channel_set_options(channel, options);
  #  ifdef FEAT_GUI
      channel_gui_register(channel);
  #  endif
*** ../vim-7.4.1340/src/os_win32.c      2016-02-16 20:31:27.223345909 +0100
--- src/os_win32.c      2016-02-16 20:45:31.702470333 +0100
***************
*** 5125,5131 ****
      job->jv_channel = channel;
      channel_set_pipes(channel, (sock_T)ifd[1], (sock_T)ofd[0], 
(sock_T)efd[0]);
      channel_set_job(channel, job);
!     channel_set_mode(channel, options->jo_mode);
  
  #   ifdef FEAT_GUI
       channel_gui_register(channel);
--- 5125,5131 ----
      job->jv_channel = channel;
      channel_set_pipes(channel, (sock_T)ifd[1], (sock_T)ofd[0], 
(sock_T)efd[0]);
      channel_set_job(channel, job);
!     channel_set_options(channel, options);
  
  #   ifdef FEAT_GUI
       channel_gui_register(channel);
*** ../vim-7.4.1340/src/proto/channel.pro       2016-02-16 19:25:07.580925715 
+0100
--- src/proto/channel.pro       2016-02-16 20:43:52.371517915 +0100
***************
*** 7,15 ****
  channel_T *channel_open(char *hostname, int port_in, int waittime, void 
(*close_cb)(void));
  void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
  void channel_set_job(channel_T *channel, job_T *job);
! void channel_set_mode(channel_T *channel, ch_mode_T ch_mode);
  void channel_set_timeout(channel_T *channel, int timeout);
  void channel_set_callback(channel_T *channel, char_u *callback);
  void channel_set_req_callback(channel_T *channel, char_u *callback, int id);
  char_u *channel_get(channel_T *channel);
  int channel_collapse(channel_T *channel);
--- 7,16 ----
  channel_T *channel_open(char *hostname, int port_in, int waittime, void 
(*close_cb)(void));
  void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
  void channel_set_job(channel_T *channel, job_T *job);
! void channel_set_mode(channel_T *channel, ch_mode_T mode);
  void channel_set_timeout(channel_T *channel, int timeout);
  void channel_set_callback(channel_T *channel, char_u *callback);
+ void channel_set_options(channel_T *channel, jobopt_T *options);
  void channel_set_req_callback(channel_T *channel, char_u *callback, int id);
  char_u *channel_get(channel_T *channel);
  int channel_collapse(channel_T *channel);
*** ../vim-7.4.1340/src/testdir/test_channel.vim        2016-02-16 
19:25:07.584925674 +0100
--- src/testdir/test_channel.vim        2016-02-16 20:57:00.983206848 +0100
***************
*** 117,123 ****
    call assert_equal('added more', getline('$'))
  
    " Send a request with a specific handler.
!   call ch_sendexpr(handle, 'hello!', 's:RequestHandler')
    sleep 10m
    if !exists('s:responseHandle')
      call assert_false(1, 's:responseHandle was not set')
--- 117,123 ----
    call assert_equal('added more', getline('$'))
  
    " Send a request with a specific handler.
!   call ch_sendexpr(handle, 'hello!', {'callback': 's:RequestHandler'})
    sleep 10m
    if !exists('s:responseHandle')
      call assert_false(1, 's:responseHandle was not set')
***************
*** 128,134 ****
  
    unlet s:responseHandle
    let s:responseMsg = ''
!   call ch_sendexpr(handle, 'hello!', function('s:RequestHandler'))
    sleep 10m
    if !exists('s:responseHandle')
      call assert_false(1, 's:responseHandle was not set')
--- 128,134 ----
  
    unlet s:responseHandle
    let s:responseMsg = ''
!   call ch_sendexpr(handle, 'hello!', {'callback': 
function('s:RequestHandler')})
    sleep 10m
    if !exists('s:responseHandle')
      call assert_false(1, 's:responseHandle was not set')
***************
*** 171,177 ****
    call assert_equal('ok', ch_sendexpr(handle, 'empty-request'))
  
    " make the server quit, can't check if this works, should not hang.
!   call ch_sendexpr(handle, '!quit!', 0)
  endfunc
  
  func Test_communicate()
--- 171,177 ----
    call assert_equal('ok', ch_sendexpr(handle, 'empty-request'))
  
    " make the server quit, can't check if this works, should not hang.
!   call ch_sendexpr(handle, '!quit!', {'callback': 0})
  endfunc
  
  func Test_communicate()
***************
*** 242,248 ****
    call assert_equal('we called you', s:reply)
  
    " Test that it works while not waiting on a numbered message.
!   call ch_sendexpr(handle, 'call me again', 0)
    sleep 10m
    call assert_equal('we did call you', s:reply)
  endfunc
--- 242,248 ----
    call assert_equal('we called you', s:reply)
  
    " Test that it works while not waiting on a numbered message.
!   call ch_sendexpr(handle, 'call me again', {'callback': 0})
    sleep 10m
    call assert_equal('we did call you', s:reply)
  endfunc
***************
*** 292,302 ****
    call assert_equal("run", job_status(job))
    try
      let handle = job_getchannel(job)
!     call ch_sendraw(handle, "echo something\n", 0)
      let msg = ch_readraw(handle)
      call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
  
!     call ch_sendraw(handle, "double this\n", 0)
      let msg = ch_readraw(handle)
      call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
  
--- 292,302 ----
    call assert_equal("run", job_status(job))
    try
      let handle = job_getchannel(job)
!     call ch_sendraw(handle, "echo something\n", {'callback': 0})
      let msg = ch_readraw(handle)
      call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
  
!     call ch_sendraw(handle, "double this\n", {'callback': 0})
      let msg = ch_readraw(handle)
      call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
  
***************
*** 315,324 ****
    call assert_equal("run", job_status(job))
    try
      let handle = job_getchannel(job)
!     call ch_sendraw(handle, "echo something\n", 0)
      call assert_equal("something", ch_readraw(handle))
  
!     call ch_sendraw(handle, "double this\n", 0)
      call assert_equal("this", ch_readraw(handle))
      call assert_equal("AND this", ch_readraw(handle))
  
--- 315,324 ----
    call assert_equal("run", job_status(job))
    try
      let handle = job_getchannel(job)
!     call ch_sendraw(handle, "echo something\n", {'callback': 0})
      call assert_equal("something", ch_readraw(handle))
  
!     call ch_sendraw(handle, "double this\n", {'callback': 0})
      call assert_equal("this", ch_readraw(handle))
      call assert_equal("AND this", ch_readraw(handle))
  
***************
*** 340,346 ****
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func s:unlet_handle(port)
    let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
!   call ch_sendexpr(s:channelfd, "test", function('s:UnletHandler'))
    sleep 10m
    call assert_equal('what?', s:unletResponse)
  endfunc
--- 340,346 ----
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func s:unlet_handle(port)
    let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
!   call ch_sendexpr(s:channelfd, "test", {'callback': 
function('s:UnletHandler')})
    sleep 10m
    call assert_equal('what?', s:unletResponse)
  endfunc
***************
*** 360,366 ****
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func s:close_handle(port)
    let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
!   call ch_sendexpr(s:channelfd, "test", function('s:CloseHandler'))
    sleep 10m
    call assert_equal('what?', s:unletResponse)
  endfunc
--- 360,366 ----
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func s:close_handle(port)
    let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
!   call ch_sendexpr(s:channelfd, "test", {'callback': 
function('s:CloseHandler')})
    sleep 10m
    call assert_equal('what?', s:unletResponse)
  endfunc
*** ../vim-7.4.1340/runtime/doc/eval.txt        2016-02-16 14:07:36.186482678 
+0100
--- runtime/doc/eval.txt        2016-02-16 20:48:54.952327482 +0100
***************
*** 1809,1818 ****
  ch_logfile( {fname} [, {mode}])       none    start logging channel activity
  ch_open( {address} [, {argdict})] Number open a channel to {address}
  ch_readraw( {handle})         String  read from channel {handle}
! ch_sendexpr( {handle}, {expr} [, {callback}])
                                any     send {expr} over JSON channel {handle}
! ch_sendraw( {handle}, {string} [, {callback}])
                                any     send {string} over raw channel {handle}
  changenr()                    Number  current change number
  char2nr( {expr}[, {utf8}])    Number  ASCII/UTF8 value of first char in {expr}
  cindent( {lnum})              Number  C indent for line {lnum}
--- 1821,1831 ----
  ch_logfile( {fname} [, {mode}])       none    start logging channel activity
  ch_open( {address} [, {argdict})] Number open a channel to {address}
  ch_readraw( {handle})         String  read from channel {handle}
! ch_sendexpr( {handle}, {expr} [, {options}])
                                any     send {expr} over JSON channel {handle}
! ch_sendraw( {handle}, {string} [, {options}])
                                any     send {string} over raw channel {handle}
+ ch_status( {handle})          String  status of channel {handle}
  changenr()                    Number  current change number
  char2nr( {expr}[, {utf8}])    Number  ASCII/UTF8 value of first char in {expr}
  cindent( {lnum})              Number  C indent for line {lnum}
***************
*** 1945,1950 ****
--- 1958,1964 ----
  isdirectory( {directory})     Number  TRUE if {directory} is a directory
  islocked( {expr})             Number  TRUE if {expr} is locked
  items( {dict})                        List    key-value pairs in {dict}
+ job_getchannel( {job})                Number  get the channel handle for {job}
  job_start( {command} [, {options}]) Job       start a job     
  job_status( {job})            String  get the status of a job
  job_stop( {job} [, {how}])    Number  stop a job
***************
*** 2671,2679 ****
  
  ch_logfile( {fname} [, {mode}])                                       
*ch_logfile()*
                Start logging channel activity to {fname}.
                When {mode} is omitted or "a" append to the file.
                When {mode} is "w" start with an empty file.
!               When {fname} is an empty string: stop logging.
  
  ch_open({address} [, {argdict}])                              *ch_open()*
                Open a channel to {address}.  See |channel|.
--- 2688,2700 ----
  
  ch_logfile( {fname} [, {mode}])                                       
*ch_logfile()*
                Start logging channel activity to {fname}.
+               When {fname} is an empty string: stop logging.
+ 
                When {mode} is omitted or "a" append to the file.
                When {mode} is "w" start with an empty file.
! 
!               The file is flushed after every message, on Unix you can use
!               "tail -f" to see what is going on in real time.
  
  ch_open({address} [, {argdict}])                              *ch_open()*
                Open a channel to {address}.  See |channel|.
***************
*** 2704,2734 ****
                within that time an empty string is returned.
                TODO: depends on channel mode.
  
! ch_sendexpr({handle}, {expr} [, {callback}])                  *ch_sendexpr()*
                Send {expr} over channel {handle}.  The {expr} is encoded
                according to the type of channel.  The function cannot be used
                with a raw channel.  See |channel-use|.  *E912*
  
!               When {callback} is given returns immediately.  Without
!               {callback} waits for a response and returns the decoded
!               expression.  When there is an error or timeout returns an
!               empty string.
  
!               When {callback} is zero no response is expected.
!               Otherwise {callback} must be a Funcref or the name of a
!               function.  It is called when the response is received.  See
!               |channel-callback|.
  
                {only available when compiled with the |+channel| feature}
  
! ch_sendraw({handle}, {string} [, {callback}])         *ch_sendraw()*
                Send {string} over channel {handle}.
                Works like |ch_sendexpr()|, but does not encode the request or
                decode the response.  The caller is responsible for the
!               correct contents.  See |channel-use|.
  
                {only available when compiled with the |+channel| feature}
  
                                                        *copy()*
  copy({expr})  Make a copy of {expr}.  For Numbers and Strings this isn't
                different from using {expr} directly.
--- 2725,2765 ----
                within that time an empty string is returned.
                TODO: depends on channel mode.
  
! ch_sendexpr({handle}, {expr} [, {options}])                   *ch_sendexpr()*
                Send {expr} over channel {handle}.  The {expr} is encoded
                according to the type of channel.  The function cannot be used
                with a raw channel.  See |channel-use|.  *E912*
  
!               {options} must be a Dictionary.
!               When "callback" is a Funcref or the name of a function,
!               ch_sendexpr() returns immediately.  The callback is invoked
!               when the response is received.  See |channel-callback|.
! 
!               Without "callback" ch_sendexpr() waits for a response and
!               returns the decoded expression.  When there is an error or
!               timeout it returns an empty string.
  
!               When "callback" is zero no response is expected.
  
                {only available when compiled with the |+channel| feature}
  
! ch_sendraw({handle}, {string} [, {options}])          *ch_sendraw()*
                Send {string} over channel {handle}.
                Works like |ch_sendexpr()|, but does not encode the request or
                decode the response.  The caller is responsible for the
!               correct contents.  Also does not add a newline for a channel
!               in NL mode, the caller must do that.  The NL in the response
!               is removed.
!               See |channel-use|.
  
                {only available when compiled with the |+channel| feature}
  
+ ch_status({handle})                                           *ch_status()*
+               Return the status of channel {handle}:
+                       "fail"          failed to open the channel
+                       "open"          channel can be used
+                       "closed"        channel can not be used
+ 
                                                        *copy()*
  copy({expr})  Make a copy of {expr}.  For Numbers and Strings this isn't
                different from using {expr} directly.
***************
*** 4263,4269 ****
                order.
  
  
! job_start({command} [, {options}])                            *job_start()*
                Start a job and return a Job object.  Unlike |system()| and
                |:!cmd| this does not wait for the job to finish.
  
--- 4353,4363 ----
                order.
  
  
! job_getchannel({job})                                  *job_getchannel()*
!               Get the channel handle that {job} is using.
!               {only available when compiled with the |+job| feature}
! 
! job_start({command} [, {options}])                    *job_start()*
                Start a job and return a Job object.  Unlike |system()| and
                |:!cmd| this does not wait for the job to finish.
  
*** ../vim-7.4.1340/src/version.c       2016-02-16 20:31:27.223345909 +0100
--- src/version.c       2016-02-16 20:57:36.194836056 +0100
***************
*** 749,750 ****
--- 749,752 ----
  {   /* Add new patch number below this line */
+ /**/
+     1341,
  /**/

-- 
Facepalm statement #5: "Petrol getting more expensive?  Not for me, I'm always
tanking for 20 dollars"

 /// Bram Moolenaar -- [email protected] -- 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui