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.