Patch 7.4.1376
Problem:    ch_setoptions() cannot set all options.
Solution:   Support more options.
Files:      src/channel.c, src/eval.c, src/structs.h, runtime/doc/channel.txt,
            src/testdir/test_channel.vim


*** ../vim-7.4.1375/src/channel.c       2016-02-20 21:38:58.770661562 +0100
--- src/channel.c       2016-02-20 23:19:00.719644632 +0100
***************
*** 737,763 ****
  }
  
  /*
!  * Set various properties from an "options" argument.
   */
      void
! channel_set_options(channel_T *channel, jobopt_T *options)
  {
!     int part;
  
!     if (options->jo_set & JO_MODE)
        for (part = PART_SOCK; part <= PART_IN; ++part)
!           channel->ch_part[part].ch_mode = options->jo_mode;
!     if (options->jo_set & JO_TIMEOUT)
        for (part = PART_SOCK; part <= PART_IN; ++part)
!           channel->ch_part[part].ch_timeout = options->jo_timeout;
  
!     if (options->jo_set & JO_CALLBACK)
      {
!       vim_free(channel->ch_callback);
!       if (options->jo_callback != NULL && *options->jo_callback != NUL)
!           channel->ch_callback = vim_strsave(options->jo_callback);
        else
!           channel->ch_callback = NULL;
      }
  }
  
--- 737,794 ----
  }
  
  /*
!  * Set various properties from an "opt" argument.
   */
      void
! channel_set_options(channel_T *channel, jobopt_T *opt)
  {
!     int    part;
!     char_u **cbp;
  
!     if (opt->jo_set & JO_MODE)
        for (part = PART_SOCK; part <= PART_IN; ++part)
!           channel->ch_part[part].ch_mode = opt->jo_mode;
!     if (opt->jo_set & JO_IN_MODE)
!       channel->ch_part[PART_IN].ch_mode = opt->jo_in_mode;
!     if (opt->jo_set & JO_OUT_MODE)
!       channel->ch_part[PART_OUT].ch_mode = opt->jo_out_mode;
!     if (opt->jo_set & JO_ERR_MODE)
!       channel->ch_part[PART_ERR].ch_mode = opt->jo_err_mode;
! 
!     if (opt->jo_set & JO_TIMEOUT)
        for (part = PART_SOCK; part <= PART_IN; ++part)
!           channel->ch_part[part].ch_timeout = opt->jo_timeout;
!     if (opt->jo_set & JO_OUT_TIMEOUT)
!       channel->ch_part[PART_OUT].ch_timeout = opt->jo_out_timeout;
!     if (opt->jo_set & JO_ERR_TIMEOUT)
!       channel->ch_part[PART_ERR].ch_timeout = opt->jo_err_timeout;
  
!     if (opt->jo_set & JO_CALLBACK)
!     {
!       cbp = &channel->ch_callback;
!       vim_free(*cbp);
!       if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
!           *cbp = vim_strsave(opt->jo_callback);
!       else
!           *cbp = NULL;
!     }
!     if (opt->jo_set & JO_OUT_CALLBACK)
!     {
!       cbp = &channel->ch_part[PART_OUT].ch_callback;
!       vim_free(*cbp);
!       if (opt->jo_out_cb != NULL && *opt->jo_out_cb != NUL)
!           *cbp = vim_strsave(opt->jo_out_cb);
!       else
!           *cbp = NULL;
!     }
!     if (opt->jo_set & JO_ERR_CALLBACK)
      {
!       cbp = &channel->ch_part[PART_ERR].ch_callback;
!       vim_free(*cbp);
!       if (opt->jo_err_cb != NULL && *opt->jo_err_cb != NUL)
!           *cbp = vim_strsave(opt->jo_err_cb);
        else
!           *cbp = NULL;
      }
  }
  
*** ../vim-7.4.1375/src/eval.c  2016-02-20 22:16:54.078901664 +0100
--- src/eval.c  2016-02-20 23:18:24.492027122 +0100
***************
*** 9873,9878 ****
--- 9873,9906 ----
      return NULL;
  }
  
+     static int
+ handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo)
+ {
+     char_u    *val = get_tv_string(item);
+ 
+     opt->jo_set |= jo;
+     if (STRCMP(val, "nl") == 0)
+       *modep = MODE_NL;
+     else if (STRCMP(val, "raw") == 0)
+       *modep = MODE_RAW;
+     else if (STRCMP(val, "js") == 0)
+       *modep = MODE_JS;
+     else if (STRCMP(val, "json") == 0)
+       *modep = MODE_JSON;
+     else
+     {
+       EMSG2(_(e_invarg2), val);
+       return FAIL;
+     }
+     return OK;
+ }
+ 
+     static void
+ clear_job_options(jobopt_T *opt)
+ {
+     vim_memset(opt, 0, sizeof(jobopt_T));
+ }
+ 
  /*
   * Get the option entries from the dict in "tv", parse them and put the result
   * in "opt".
***************
*** 9910,9930 ****
            {
                if (!(supported & JO_MODE))
                    break;
!               opt->jo_set |= JO_MODE;
!               val = get_tv_string(item);
!               if (STRCMP(val, "nl") == 0)
!                   opt->jo_mode = MODE_NL;
!               else if (STRCMP(val, "raw") == 0)
!                   opt->jo_mode = MODE_RAW;
!               else if (STRCMP(val, "js") == 0)
!                   opt->jo_mode = MODE_JS;
!               else if (STRCMP(val, "json") == 0)
!                   opt->jo_mode = MODE_JSON;
!               else
!               {
!                   EMSG2(_(e_invarg2), val);
                    return FAIL;
-               }
            }
            else if (STRCMP(hi->hi_key, "callback") == 0)
            {
--- 9938,9969 ----
            {
                if (!(supported & JO_MODE))
                    break;
!               if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL)
!                   return FAIL;
!           }
!           else if (STRCMP(hi->hi_key, "in-mode") == 0)
!           {
!               if (!(supported & JO_IN_MODE))
!                   break;
!               if (handle_mode(item, opt, &opt->jo_in_mode, JO_IN_MODE)
!                                                                     == FAIL)
!                   return FAIL;
!           }
!           else if (STRCMP(hi->hi_key, "out-mode") == 0)
!           {
!               if (!(supported & JO_OUT_MODE))
!                   break;
!               if (handle_mode(item, opt, &opt->jo_out_mode, JO_OUT_MODE)
!                                                                     == FAIL)
!                   return FAIL;
!           }
!           else if (STRCMP(hi->hi_key, "err-mode") == 0)
!           {
!               if (!(supported & JO_ERR_MODE))
!                   break;
!               if (handle_mode(item, opt, &opt->jo_err_mode, JO_ERR_MODE)
!                                                                     == FAIL)
                    return FAIL;
            }
            else if (STRCMP(hi->hi_key, "callback") == 0)
            {
***************
*** 9938,9943 ****
--- 9977,10006 ----
                    return FAIL;
                }
            }
+           else if (STRCMP(hi->hi_key, "out-cb") == 0)
+           {
+               if (!(supported & JO_OUT_CALLBACK))
+                   break;
+               opt->jo_set |= JO_OUT_CALLBACK;
+               opt->jo_out_cb = get_callback(item);
+               if (opt->jo_out_cb == NULL)
+               {
+                   EMSG2(_(e_invarg2), "out-db");
+                   return FAIL;
+               }
+           }
+           else if (STRCMP(hi->hi_key, "err-cb") == 0)
+           {
+               if (!(supported & JO_ERR_CALLBACK))
+                   break;
+               opt->jo_set |= JO_ERR_CALLBACK;
+               opt->jo_err_cb = get_callback(item);
+               if (opt->jo_err_cb == NULL)
+               {
+                   EMSG2(_(e_invarg2), "err-cb");
+                   return FAIL;
+               }
+           }
            else if (STRCMP(hi->hi_key, "waittime") == 0)
            {
                if (!(supported & JO_WAITTIME))
***************
*** 9952,9957 ****
--- 10015,10034 ----
                opt->jo_set |= JO_TIMEOUT;
                opt->jo_timeout = get_tv_number(item);
            }
+           else if (STRCMP(hi->hi_key, "out-timeout") == 0)
+           {
+               if (!(supported & JO_OUT_TIMEOUT))
+                   break;
+               opt->jo_set |= JO_OUT_TIMEOUT;
+               opt->jo_out_timeout = get_tv_number(item);
+           }
+           else if (STRCMP(hi->hi_key, "err-timeout") == 0)
+           {
+               if (!(supported & JO_ERR_TIMEOUT))
+                   break;
+               opt->jo_set |= JO_ERR_TIMEOUT;
+               opt->jo_err_timeout = get_tv_number(item);
+           }
            else if (STRCMP(hi->hi_key, "part") == 0)
            {
                if (!(supported & JO_PART))
***************
*** 10107,10118 ****
      }
  
      /* parse options */
      opt.jo_mode = MODE_JSON;
-     opt.jo_callback = NULL;
-     opt.jo_waittime = 0;
      opt.jo_timeout = 2000;
      if (get_job_options(&argvars[1], &opt,
!               JO_MODE + JO_CALLBACK + JO_WAITTIME + JO_TIMEOUT) == FAIL)
        return;
      if (opt.jo_timeout < 0)
      {
--- 10184,10194 ----
      }
  
      /* parse options */
+     clear_job_options(&opt);
      opt.jo_mode = MODE_JSON;
      opt.jo_timeout = 2000;
      if (get_job_options(&argvars[1], &opt,
!             JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL) == FAIL)
        return;
      if (opt.jo_timeout < 0)
      {
***************
*** 10147,10153 ****
      rettv->v_type = VAR_STRING;
      rettv->vval.v_string = NULL;
  
!     opt.jo_set = 0;
      if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID)
                                                                      == FAIL)
        return;
--- 10223,10229 ----
      rettv->v_type = VAR_STRING;
      rettv->vval.v_string = NULL;
  
!     clear_job_options(&opt);
      if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID)
                                                                      == FAIL)
        return;
***************
*** 10219,10225 ****
      part_send = channel_part_send(channel);
      *part_read = channel_part_read(channel);
  
!     opt.jo_callback = NULL;
      if (get_job_options(&argvars[2], &opt, JO_CALLBACK) == FAIL)
        return NULL;
  
--- 10295,10301 ----
      part_send = channel_part_send(channel);
      *part_read = channel_part_read(channel);
  
!     clear_job_options(&opt);
      if (get_job_options(&argvars[2], &opt, JO_CALLBACK) == FAIL)
        return NULL;
  
***************
*** 10329,10335 ****
      channel = get_channel_arg(&argvars[0]);
      if (channel == NULL)
        return;
!     if (get_job_options(&argvars[1], &opt, JO_CALLBACK + JO_TIMEOUT) == FAIL)
        return;
      channel_set_options(channel, &opt);
  }
--- 10405,10413 ----
      channel = get_channel_arg(&argvars[0]);
      if (channel == NULL)
        return;
!     clear_job_options(&opt);
!     if (get_job_options(&argvars[1], &opt,
!               JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == FAIL)
        return;
      channel_set_options(channel, &opt);
  }
***************
*** 14684,14692 ****
      rettv->vval.v_job->jv_status = JOB_FAILED;
  
      /* Default mode is NL. */
      opt.jo_mode = MODE_NL;
!     opt.jo_callback = NULL;
!     if (get_job_options(&argvars[1], &opt, JO_MODE + JO_CALLBACK) == FAIL)
        return;
  
  #ifndef USE_ARGV
--- 14762,14771 ----
      rettv->vval.v_job->jv_status = JOB_FAILED;
  
      /* Default mode is NL. */
+     clear_job_options(&opt);
      opt.jo_mode = MODE_NL;
!     if (get_job_options(&argvars[1], &opt,
!                           JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL) == FAIL)
        return;
  
  #ifndef USE_ARGV
*** ../vim-7.4.1375/src/structs.h       2016-02-20 22:16:54.086901581 +0100
--- src/structs.h       2016-02-20 23:16:17.741365460 +0100
***************
*** 1373,1386 ****
      int               ch_refcount;    /* reference count */
  };
  
! #define JO_MODE               1       /* all modes */
! #define JO_CALLBACK   2       /* channel callback */
! #define JO_WAITTIME   4       /* only for ch_open() */
! #define JO_TIMEOUT    8       /* all timeouts */
! #define JO_PART               16      /* "part" */
! #define JO_ID         32      /* "id" */
  #define JO_ALL                0xffffff
  
  /*
   * Options for job and channel commands.
   */
--- 1373,1397 ----
      int               ch_refcount;    /* reference count */
  };
  
! #define JO_MODE               0x0001  /* channel mode */
! #define JO_IN_MODE    0x0002  /* stdin mode */
! #define JO_OUT_MODE   0x0004  /* stdout mode */
! #define JO_ERR_MODE   0x0008  /* stderr mode */
! #define JO_CALLBACK   0x0010  /* channel callback */
! #define JO_OUT_CALLBACK       0x0020  /* stdout callback */
! #define JO_ERR_CALLBACK       0x0040  /* stderr callback */
! #define JO_WAITTIME   0x0080  /* only for ch_open() */
! #define JO_TIMEOUT    0x0100  /* all timeouts */
! #define JO_OUT_TIMEOUT        0x0200  /* stdout timeouts */
! #define JO_ERR_TIMEOUT        0x0400  /* stderr timeouts */
! #define JO_PART               0x0800  /* "part" */
! #define JO_ID         0x1000  /* "id" */
  #define JO_ALL                0xffffff
  
+ #define JO_MODE_ALL   (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
+ #define JO_CB_ALL     (JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK)
+ #define JO_TIMEOUT_ALL        (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT)
+ 
  /*
   * Options for job and channel commands.
   */
***************
*** 1389,1397 ****
--- 1400,1415 ----
      int               jo_set;         /* JO_ bits for values that were set */
  
      ch_mode_T jo_mode;
+     ch_mode_T jo_in_mode;
+     ch_mode_T jo_out_mode;
+     ch_mode_T jo_err_mode;
      char_u    *jo_callback;   /* not allocated! */
+     char_u    *jo_out_cb;     /* not allocated! */
+     char_u    *jo_err_cb;     /* not allocated! */
      int               jo_waittime;
      int               jo_timeout;
+     int               jo_out_timeout;
+     int               jo_err_timeout;
      int               jo_part;
      int               jo_id;
  } jobopt_T;
*** ../vim-7.4.1375/runtime/doc/channel.txt     2016-02-07 19:16:24.242303692 
+0100
--- runtime/doc/channel.txt     2016-02-20 23:28:32.273611285 +0100
***************
*** 1,4 ****
! *channel.txt*      For Vim version 7.4.  Last change: 2016 Feb 07
  
  
                  VIM REFERENCE MANUAL    by Bram Moolenaar
--- 1,4 ----
! *channel.txt*      For Vim version 7.4.  Last change: 2016 Feb 20
  
  
                  VIM REFERENCE MANUAL    by Bram Moolenaar
***************
*** 9,44 ****
  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT
  
  Vim uses channels to communicate with other processes.
! A channel uses a socket.                              *socket-interface*
  
  Vim current supports up to 10 simultaneous channels.
  The Netbeans interface also uses a channel. |netbeans|
  
! 1. Demo                                       |channel-demo|
! 2. Opening a channel                  |channel-open|
! 3. Using a JSON or JS channel         |channel-use|
! 4. Vim commands                               |channel-commands|
! 5. Using a raw channel                        |channel-use|
! 6. Job control                                |job-control|
  
  {Vi does not have any of these features}
! {only available when compiled with the |+channel| feature}
  
  ==============================================================================
! 1. Demo                                                       *channel-demo*
  
  This requires Python.  The demo program can be found in
  $VIMRUNTIME/tools/demoserver.py
  Run it in one terminal.  We will call this T1.
  
  Run Vim in another terminal.  Connect to the demo server with: >
!       let handle = ch_open('localhost:8765')
  
  In T1 you should see:
        === socket opened === ~
  
  You can now send a message to the server: >
!       echo ch_sendexpr(handle, 'hello!')
  
  The message is received in T1 and a response is sent back to Vim.
  You can see the raw messages in T1.  What Vim sends is:
--- 9,80 ----
  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT
  
  Vim uses channels to communicate with other processes.
! A channel uses a socket or pipes                      *socket-interface*
! Jobs can be used to start processes and communicate with them.
  
  Vim current supports up to 10 simultaneous channels.
  The Netbeans interface also uses a channel. |netbeans|
  
! 1. Overview                           |job-channel-overview|
! 2. Channel demo                               |channel-demo|
! 3. Opening a channel                  |channel-open|
! 4. Using a JSON or JS channel         |channel-use|
! 5. Channel commands                   |channel-commands|
! 6. Using a RAW or NL channel          |channel-raw|
! 7. More channel functions             |channel-more|
! 8. Starting a job with a channel      |job-start|
! 9. Starting a job without a channel   |job-start-nochannel|
! 10. Job options                               |job-options|
! 11. Controlling a job                 |job-control|
  
  {Vi does not have any of these features}
! {only when compiled with the |+channel| feature for channel stuff}
! {only when compiled with the |+job| feature for job stuff}
  
  ==============================================================================
! 1. Overview                                           *job-channel-overview*
! 
! There are four main types of jobs:
! 1. A deamon, serving several Vim instances.
!    Vim connects to it with a socket.
! 2. One job working with one Vim instance, asynchronously.
!    Uses a socket or pipes.
! 3. A job performing some work for a short time, asynchronously.
!    Uses a socket or pipes.
! 4. Running a filter, synchronously.
!    Uses pipes.
! 
! For when using sockets See |job-start|, |job-may-start| and |channel-open|.
! For 2 and 3, one or more jobs using pipes, see |job-start|.
! For 4 use the ":{range}!cmd" command, see |filter|.
! 
! Over the socket and pipes these protocols are available:
! RAW   nothing known, Vim cannot tell where a message ends
! NL    every message ends in a NL (newline) character
! JSON  JSON encoding |json_encode()|
! JS    JavaScript style JSON-like encoding |js_encode()|
! 
! Common combination are:
! - Using a job connected through pipes in NL mode.  E.g., to run a style
!   checker and receive errors and warnings.
! - Using a deamon, connecting over a socket in JSON mode.  E.g. to lookup
!   crosss-refrences in a database.
! 
! ==============================================================================
! 2. Channel demo                                               *channel-demo*
  
  This requires Python.  The demo program can be found in
  $VIMRUNTIME/tools/demoserver.py
  Run it in one terminal.  We will call this T1.
  
  Run Vim in another terminal.  Connect to the demo server with: >
!       let channel = ch_open('localhost:8765')
  
  In T1 you should see:
        === socket opened === ~
  
  You can now send a message to the server: >
!       echo ch_sendexpr(channel, 'hello!')
  
  The message is received in T1 and a response is sent back to Vim.
  You can see the raw messages in T1.  What Vim sends is:
***************
*** 54,100 ****
        ["normal","w"] ~
  
  To handle asynchronous communication a callback needs to be used: >
!       func MyHandler(handle, msg)
          echo "from the handler: " . a:msg
        endfunc
!       call ch_sendexpr(handle, 'hello!', "MyHandler")
  
  Instead of giving a callback with every send call, it can also be specified
  when opening the channel: >
!       call ch_close(handle)
!       let handle = ch_open('localhost:8765', {'callback': "MyHandler"})
!       call ch_sendexpr(handle, 'hello!', 0)
  
  ==============================================================================
! 2. Opening a channel                                  *channel-open*
  
  To open a channel: >
!     let handle = ch_open({address} [, {argdict}])
  
  {address} has the form "hostname:port".  E.g., "localhost:8765".
  
! {argdict} is a dictionary with optional entries:
  
  "mode" can be:                                                *channel-mode*
        "json" - Use JSON, see below; most convenient way. Default.
!       "js"   - Use JavaScript encoding, more efficient than JSON.
        "raw"  - Use raw messages
  
                                                        *channel-callback*
! "callback" is a function that is called when a message is received that is not
! handled otherwise.  It gets two arguments: the channel handle and the received
! message. Example: >
!       func Handle(handle, msg)
          echo 'Received: ' . a:msg
        endfunc
!       let handle = ch_open("localhost:8765", {"callback": "Handle"})
! 
! "waittime" is the time to wait for the connection to be made in milliseconds.
! The default is zero, don't wait, which is useful if the server is supposed to
! be running already.  A negative number waits forever.
! 
! "timeout" is the time to wait for a request when blocking, using
! ch_sendexpr().  Again in milliseconds.  The default is 2000 (2 seconds).
  
  When "mode" is "json" or "js" the "msg" argument is the body of the received
  message, converted to Vim types.
--- 90,169 ----
        ["normal","w"] ~
  
  To handle asynchronous communication a callback needs to be used: >
!       func MyHandler(channel, msg)
          echo "from the handler: " . a:msg
        endfunc
!       call ch_sendexpr(channel, 'hello!', "MyHandler")
! Vim will not wait for a response.  Now the server can send the response later
! and MyHandler will be invoked.
  
  Instead of giving a callback with every send call, it can also be specified
  when opening the channel: >
!       call ch_close(channel)
!       let channel = ch_open('localhost:8765', {'callback': "MyHandler"})
!       call ch_sendexpr(channel, 'hello!', 0)
  
  ==============================================================================
! 3. Opening a channel                                  *channel-open*
  
  To open a channel: >
!     let channel = ch_open({address} [, {options}])
! 
! Use |ch_status()| to see if the channel could be opened.
  
  {address} has the form "hostname:port".  E.g., "localhost:8765".
  
! {options} is a dictionary with optional entries:
  
  "mode" can be:                                                *channel-mode*
        "json" - Use JSON, see below; most convenient way. Default.
!       "js"   - Use JS (JavaScript) encoding, more efficient than JSON.
!       "nl"   - Use messages that end in a NL character
        "raw"  - Use raw messages
  
+ "in-mode"     mode specifically for stdin, only when using pipes
+ "out-mode"    mode specifically for stdout, only when using pipes
+ "err-mode"    mode specifically for stderr, only when using pipes
+               Note: when setting "mode" the part specific mode is
+               overwritten.  Therefore set "mode" first and the part specific
+               mode later.
+ 
                                                        *channel-callback*
! "callback"    A function that is called when a message is received that is
!               not handled otherwise.  It gets two arguments: the channel
!               handle and the received message. Example: >
!       func Handle(channel, msg)
          echo 'Received: ' . a:msg
        endfunc
!       let channel = ch_open("localhost:8765", {"callback": "Handle"})
! <
! "out-cb"      A function like "callback" but used for stdout.  Only for when
!               the channel uses pipes.  When "out-cb" wasn't set the channel
!               callback is used.
! 
! "err-cb"      A function like "callback" but used for stderr.  Only for when
!               the channel uses pipes.  When "err-cb" wasn't set the channel
!               callback is used.
! 
!               TODO:
! "close-cb"    A function that is called when the channel gets closed, other
!               than by calling ch_close().  It should be defined like this: >
!       func MyCloseHandler(channel)
! 
! "waittime"    The time to wait for the connection to be made in
!               milliseconds.  The default is zero, don't wait, which is
!               useful if the server is supposed to be running already.  A
!               negative number waits forever.
! 
! "timeout"     The time to wait for a request when blocking, E.g. when using
!               ch_sendexpr().  In milliseconds.  The default is 2000 (2
!               seconds).
! 
! "out-timeout" Timeout for stdout.  Only when using pipes.
! "err-timeout" Timeout for stderr.  Only when using pipes.
!               Note: when setting "timeout" the part specific mode is
!               overwritten.  Therefore set "timeout" first and the part
!               specific mode later.
  
  When "mode" is "json" or "js" the "msg" argument is the body of the received
  message, converted to Vim types.
***************
*** 103,144 ****
  When "mode" is "json" or "js" the "callback" is optional.  When omitted it is
  only possible to receive a message after sending one.
  
! The handler can be added or changed later: >
!     call ch_setcallback(handle, {callback})
  When "callback" is empty (zero or an empty string) the handler is removed.
- NOT IMPLEMENTED YET
  
! The timeout can be changed later: >
!     call ch_settimeout(handle, {msec})
! NOT IMPLEMENTED YET
                                                          *E906*
  Once done with the channel, disconnect it like this: >
!     call ch_close(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 or JS channel                                 *channel-use*
  
! If {mode} is "json" then a message can be sent synchronously like this: >
!     let response = ch_sendexpr(handle, {expr})
  This awaits a response from the other side.
  
! When {mode} is "js" this works the same, except that the messages use
! JavaScript encoding.  See |jsencode()| for the difference.
  
  To send a message, without handling a response: >
!     call ch_sendexpr(handle, {expr}, 0)
  
  To send a message and letting the response handled by a specific function,
  asynchronously: >
!     call ch_sendexpr(handle, {expr}, {callback})
  
  The {expr} is converted to JSON and wrapped in an array.  An example of the
  message that the receiver will get when {expr} is the string "hello":
--- 172,227 ----
  When "mode" is "json" or "js" the "callback" is optional.  When omitted it is
  only possible to receive a message after sending one.
  
! To change the channel options after opening it use ch_setoptions().  The
! arguments are similar to what is passed to ch_open(), but "waittime" cannot be
! given, since that only applies to opening the channel.
! 
! The handler can be added or changed: >
!     call ch_setoptions(channel, {'callback': callback})
  When "callback" is empty (zero or an empty string) the handler is removed.
  
! The timeout can be changed: >
!     call ch_setoptions(channel, {'timeout': msec})
! <
                                                          *E906*
  Once done with the channel, disconnect it like this: >
!     call ch_close(channel)
! When a socket is used this will close the socket for both directions.  When
! pipes are used (stdin/stdout/stderr) they are all closed.  This might not be
! what you want!  Stopping the job with job_stop() might be better.
  
+ TODO:
  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.  There is a
! difference between MS-Windows and Unix: On Unix when the port doesn't exist
! ch_open() fails quickly.  On MS-Windows "waittime" applies.
  *E898* *E899* *E900* *E901* *E902*
  
  If there is an error reading or writing a channel it will be closed.
  *E896* *E630* *E631* 
  
  ==============================================================================
! 4. Using a JSON or JS channel                                 *channel-use*
  
! If mode is JSON then a message can be sent synchronously like this: >
!     let response = ch_sendexpr(channel, {expr})
  This awaits a response from the other side.
  
! When mode is JS this works the same, except that the messages use
! JavaScript encoding.  See |js_encode()| for the difference.
  
  To send a message, without handling a response: >
!     call ch_sendexpr(channel, {expr}, 0)
  
  To send a message and letting the response handled by a specific function,
  asynchronously: >
!     call ch_sendexpr(channel, {expr}, {callback})
! 
! Vim will match the response with the request using the message ID.  Once the
! response is received the callback will be invoked.  Further responses with the
! same ID will be ignored.  If your server sends back multiple responses you
! need to send them with ID zero, they will be passed to the channel callback.
  
  The {expr} is converted to JSON and wrapped in an array.  An example of the
  message that the receiver will get when {expr} is the string "hello":
***************
*** 166,188 ****
  Then channel handler will then get {response} converted to Vim types.  If the
  channel does not have a handler the message is dropped.
  
! On read error or ch_close() the string "DETACH" is sent, if still possible.
! The channel will then be inactive.
  
! ==============================================================================
! 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
--- 249,274 ----
  Then channel handler will then get {response} converted to Vim types.  If the
  channel does not have a handler the message is dropped.
  
! On read error or ch_close(), when using a socket, the string "DETACH" is sent,
! if still possible.  The channel will then be inactive.
  
! It is also possible to use ch_sendraw() on a JSON or JS channel.  The caller
! is then completely responsible for correct encoding and decoding.
  
! ==============================================================================
! 5. Channel commands                                   *channel-commands*
  
! 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}]
!     ["expr",   {expression}, {number}]
      ["expr",   {expression}]
+     ["call",   {func name}, {argument list}, {number}]
+     ["call",   {func name}, {argument list}]
  
  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
***************
*** 223,286 ****
        ["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 or the result can't be encoded in JSON 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*
  
- If {mode} is "raw" then a message can be send like this: >
-     let response = ch_sendraw(handle, {string})
  The {string} is sent as-is.  The response will be what can be read from the
  channel right away.  Since Vim doesn't know how to recognize the end of the
! message you need to take care of it yourself.
  
  To send a message, without expecting a response: >
!     call ch_sendraw(handle, {string}, 0)
  The process can send back a response, the channel handler will be called with
  it.
  
  To send a message and letting the response handled by a specific function,
  asynchronously: >
!     call ch_sendraw(handle, {string}, {callback})
  
! This {string} can also be JSON, use |jsonencode()| to create it and
! |jsondecode()| to handle a received JSON message.
  
  ==============================================================================
! 6. Job control                                                *job-control*
  
! NOT IMPLEMENTED YET
  
! To start another process: >
!     call startjob({command})
  
! This does not wait for {command} to exit.
  
  TODO:
  
!     let handle = startjob({command}, 's')            # uses stdin/stdout
!     let handle = startjob({command}, '', {address})  # uses socket
!     let handle = startjob({command}, 'd', {address}) # start if connect fails
  
  
   vim:tw=78:ts=8:ft=help:norl:
--- 309,552 ----
        ["normal" "zO"]
  
  
! Command "expr"  with response ~
  
! The "expr" command can be used to get the result of an expression.  For
  example, to get the number of lines in the current buffer:
!       ["expr","line('$')", -2] ~
  
! It will send back the result of the expression:
!       [-2, "last line"] ~
! The format is:
        [{number}, {result}]
+                                                       *E915*
  Here {number} is the same as what was in the request.  Use a negative number
! to avoid confusion with message that Vim sends.  Use a different number on
! every request to be able to match the request with the response.
  
  {result} is the result of the evaluation and is JSON encoded.  If the
  evaluation fails or the result can't be encoded in JSON it is the string
  "ERROR".
  
  
! Command "expr" without a response ~
  
! This command is similar to "expr" above, but does not send back any response.
  Example:
        ["expr","setline('$', ['one', 'two', 'three'])"] ~
+ There is no third argument in the request.
+ 
+ 
+ Command "call" ~
+ 
+ This is similar to "expr", but instead of passing the whole expression as a
+ string this passes the name of a function and a list of arguments.  This
+ avoids the conversion of the arguments to a string and escaping and
+ concatenating them.  Example:
+       ["call", "line", ["$"], -2] ~
+ 
+ Leave out the fourth argument if no response is to be sent:
+       ["call", "setline", ["$", ["one", "two", "three"]]] ~
  
  ==============================================================================
! 6. Using a RAW or NL channel                          *channel-raw*
! 
! If mode is RAW or NL then a message can be send like this: >
!     let response = ch_sendraw(channel, {string})
  
  The {string} is sent as-is.  The response will be what can be read from the
  channel right away.  Since Vim doesn't know how to recognize the end of the
! message you need to take care of it yourself.  The timeout applies for reading
! the first byte, after that it will not wait for anything more.
! 
! If mode is "nl" you can send a message in a similar way.  You are expected
! to put in the NL after each message.  Thus you can also send several messages
! ending in a NL at once.  The response will be the text up to and including the
! first NL.  This can also be just the NL for an empty response.
! If no NL was read before the channel timeout an empty string is returned.
  
  To send a message, without expecting a response: >
!     call ch_sendraw(channel, {string}, 0)
  The process can send back a response, the channel handler will be called with
  it.
  
  To send a message and letting the response handled by a specific function,
  asynchronously: >
!     call ch_sendraw(channel, {string}, {callback})
! 
! This {string} can also be JSON, use |json_encode()| to create it and
! |json_decode()| to handle a received JSON message.
! 
! It is not possible to use |ch_sendexpr()| on a raw channel.
! 
! ==============================================================================
! 7. More channel functions                             *channel-more*
! 
! To obtain the status of a channel: ch_status(channel).  The possible results
! are:
!       "fail"          Failed to open the channel.
!       "open"          The channel can be used.
!       "closed"        The channel was closed.
! 
! TODO:
! To objain the job associated with a channel: ch_getjob(channel)
  
! To read one message from a channel: >
!       let output = ch_read(channel)
! This uses the channel timeout.  To read without a timeout, just get any
! message that is available: >
!       let output = ch_read(channel, {'timeout': 0})
! When no message was available then the result is v:none for a JSON or JS mode
! channels, an empty string for a RAW or NL channel.
! 
! To read all output from a RAW channel that is available: >
!       let output = ch_readraw(channel)
! To read the error output: >
!       let output = ch_readraw(channel, {"part": "err"})
  
  ==============================================================================
! 8. Starting a job with a channel                      *job-start* *job*
  
! To start a job and open a channel for stdin/stdout/stderr: >
!     let job = job_start(command, {options})
  
! You can get the channel with: >
!     let channel = job_getchannel(job)
  
! The channel will use NL mode.  If you want another mode it's best to specify
! this in {options}.  When changing the mode later some text may have already
! been received and not parsed correctly.
! 
! If the command produces a line of output that you want to deal with, specify
! a handler for stdout: >
!     let job = job_start(command, {"out-cb": "MyHandler"})
! The function will be called with the channel and a message. You would define
! it like this: >
!     func MyHandler(channel, msg)
! 
! Without the handler you need to read the output with ch_read().
! 
! The handler defined for "out-cb" will also receive stderr.  If you want to
! handle that separately, add an "err-cb" handler: >
!     let job = job_start(command, {"out-cb": "MyHandler",
!           \                     "err-cb": "ErrHandler"})
! 
! You can send a message to the command with ch_sendraw().  If the channel is in
! JSON or JS mode you can use ch_sendexpr().
! 
! There are several options you can use, see |job-options|.
! 
! TODO:
! To run a job and read its output once it is done: >
! 
!       let job = job_start({command}, {'exit-cb': 'MyHandler'})
!       func MyHandler(job, status)
!         let channel = job_getchannel()
!         let output = ch_readall(channel)
!         " parse output
!       endfunc
! 
! ==============================================================================
! 9. Starting a job without a channel                   *job-start-nochannel*
! 
! To start another process without creating a channel: >
!     let job = job_start(command, {"in-io": "null", "out-io": "null"})
! 
! This starts {command} in the background, Vim does not wait for it to finish.
  
  TODO:
+ When Vim sees that neither stdin, stdout or stderr are connected, no channel
+ will be created.  Often you will want to include redirection in the command to
+ avoid it getting stuck.
+ 
+ There are several options you can use, see |job-options|.
+ 
+ TODO:                                                 *job-may-start*
+ To start a job only when connecting to an address does not work use
+ job_maystart('command', {address}, {options}), For Example: >
+       let job = job_maystart(command, address, {"waittime": 1000})
+       let channel = job_gethandle(job)
+ 
+ This comes down to: >
+       let channel = ch_open(address, {"waittime": 0})
+       if ch_status(channel) == "fail"
+         let job = job_start(command)
+         let channel = ch_open(address, {"waittime": 1000})
+         call job_sethandle(channel)
+       endif
+ Note that the specified waittime applies to when the job has been started.
+ This gives the job some time to make the port available.
+ 
+ ==============================================================================
+ 10. Job options                                               *job-options*
+ 
+ The {options} argument in job_start() is a dictionary.  All entries are
+ optional.  The same options can be used with job_setoptions(job, {options}).
+ 
+                                               *job-callback*
+ "callback": handler   Callback for something to read on any part of the
+                       channel.
+                                               *job-out-cb*
+ "out-cb": handler     Callback for when there is something to read on
+                       stdout.
+                                               *job-err-cb*
+ "err-cb": handler     Callback for when there is something to read on
+                       stderr.
+ TODO:                                         *job-close-cb*
+ "close-cb": handler   Callback for when the channel is closed.  Same as
+                       "close-cb" on ch_open().
+ TODO:                                         *job-exit-cb*
+ "exit-cb": handler    Callback for when the job ends.  The arguments are the
+                       job and the exit status.
+ TODO:                                         *job-killonexit*
+ "killonexit": 1               Stop the job when Vim exits.
+ "killonexit": 0               Do not stop the job when Vim exits.
+                       The default is 1.
+ TODO:                                         *job-term*
+ "term": "open"                Start a terminal and connect the job
+                       stdin/stdout/stderr to it.
+ 
+ TODO:                                         *job-in-io*
+ "in-io": "null"               disconnect stdin
+ "in-io": "pipe"               stdin is connected to the channel (default)
+ "in-io": "file"               stdin reads from a file
+ "in-file": "/path/file"       the file to read from
+ 
+ TODO:                                         *job-out-io*
+ "out-io": "null"      disconnect stdout
+ "out-io": "pipe"      stdout is connected to the channel (default)
+ "out-io": "file"      stdout writes to a file
+ "out-file": "/path/file" the file to write to
+ "out-io": "buffer"    stdout appends to a buffer
+ "out-buffer": "name"  buffer to append to
+ 
+ TODO:                                         *job-err-io*
+ "err-io": "out"               same type as stdout (default)
+ "err-io": "null"      disconnect stderr
+ "err-io": "pipe"      stderr is connected to the channel
+ "err-io": "file"      stderr writes to a file
+ "err-file": "/path/file" the file to write to
+ "err-io": "buffer"    stderr appends to a buffer
+ "err-buffer": "name"  buffer to append to
+ 
+ TODO: more options
+ 
+ 
+ ==============================================================================
+ 11. Controlling a job                                 *job-control*
+ 
+ To get the status of a job: >
+       echo job_status(job)
+ 
+ To make a job stop running: >
+       job_stop(job)
+ 
+ This is the normal way to end a job. On Unix it sends a SIGTERM to the job.
+ It is possible to use other ways to stop the job, or even send arbitrary
+ signals.  E.g. to force a job to stop, "kill it": >
+       job_stop(job, "kill")
  
! For more options see |job_stop()|.
  
  
   vim:tw=78:ts=8:ft=help:norl:
*** ../vim-7.4.1375/src/testdir/test_channel.vim        2016-02-20 
21:48:21.092789354 +0100
--- src/testdir/test_channel.vim        2016-02-20 23:23:59.700488487 +0100
***************
*** 147,154 ****
    " check setting options (without testing the effect)
    call ch_setoptions(handle, {'callback': 's:NotUsed'})
    call ch_setoptions(handle, {'timeout': 1111})
    call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475")
-   call assert_fails("call ch_setoptions(handle, {'mode': 'json'})", "E475")
    call ch_setoptions(handle, {'callback': ''})
  
    " Send an eval request that works.
--- 147,154 ----
    " check setting options (without testing the effect)
    call ch_setoptions(handle, {'callback': 's:NotUsed'})
    call ch_setoptions(handle, {'timeout': 1111})
+   call ch_setoptions(handle, {'mode': 'json'})
    call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475")
    call ch_setoptions(handle, {'callback': ''})
  
    " Send an eval request that works.
*** ../vim-7.4.1375/src/version.c       2016-02-20 22:16:54.086901581 +0100
--- src/version.c       2016-02-20 23:20:52.038469410 +0100
***************
*** 749,750 ****
--- 749,752 ----
  {   /* Add new patch number below this line */
+ /**/
+     1376,
  /**/

-- 
MORTICIAN:    Bring out your dead!
              [clang]
              Bring out your dead!
              [clang]
              Bring out your dead!
CUSTOMER:     Here's one -- nine pence.
DEAD PERSON:  I'm not dead!
                                  The Quest for the Holy Grail (Monty Python)

 /// 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