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.
+channels, an empty string for a RAW or NL channel. You can use |ch_canread()|
+to check if there is something to read.
+
+Note that when there is no callback message are dropped. To avoid that add a
+close callback to the channel.
To read all output from a RAW channel that is available: >
let output = ch_readraw(channel)
of a pipe causes the read end to get EOF). To avoid this make the job sleep
for a short while before it exits.
+Note that if the job exits before you read the output, the output may be lost.
+This depends on the system (on Unix this happens because closing the write end
+of a pipe causes the read end to get EOF). To avoid this make the job sleep
+for a short while before it exits.
+
The handler defined for "out_cb" will not receive stderr. If you want to
handle that separately, add an "err_cb" handler: >
let job = job_start(command, {"out_cb": "MyHandler",
call({func}, {arglist} [, {dict}])
any call {func} with arguments {arglist}
ceil({expr}) Float round {expr} up
+ch_canread({handle}) Number check if there is something to read
ch_close({handle}) none close {handle}
ch_close_in({handle}) none close in part of {handle}
ch_evalexpr({handle}, {expr} [, {options}])
don't fit, a vertical layout is used anyway. For some systems
the horizontal layout is always used.
+ch_canread({handle}) *ch_canread()*
+ Return non-zero when there is something to read from {handle}.
+ {handle} can be a Channel or a Job that has a Channel.
+
+ This is useful to read from a channel at a convenient time,
+ e.g. from a timer.
+
+ Note that messages are dropped when the channel does not have
+ a callback. Add a close callback to avoid that.
+
+ {only available when compiled with the |+channel| feature}
+
ch_close({handle}) *ch_close()*
Close {handle}. See |channel-close|.
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
A close callback is not invoked.
{only available when compiled with the |+channel| feature}
ch_close_in({handle}) *ch_close_in()*
Close the "in" part of {handle}. See |channel-close-in|.
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
A close callback is not invoked.
{only available when compiled with the |+channel| feature}
Send {expr} over {handle}. The {expr} is encoded
according to the type of channel. The function cannot be used
with a raw channel. See |channel-use|.
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
*E917*
{options} must be a Dictionary. It must not have a "callback"
entry. It can have a "timeout" entry to specify the timeout
ch_evalraw({handle}, {string} [, {options}]) *ch_evalraw()*
Send {string} over {handle}.
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
Works like |ch_evalexpr()|, but does not encode the request or
decode the response. The caller is responsible for the
ch_getbufnr({handle}, {what}) *ch_getbufnr()*
Get the buffer number that {handle} is using for {what}.
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
{what} can be "err" for stderr, "out" for stdout or empty for
socket output.
Returns -1 when there is no buffer.
ch_read({handle} [, {options}]) *ch_read()*
Read from {handle} and return the received message.
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
See |channel-more|.
{only available when compiled with the |+channel| feature}
according to the type of channel. The function cannot be used
with a raw channel.
See |channel-use|. *E912*
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
{only available when compiled with the |+channel| feature}
"timeout" default read timeout in msec
"mode" mode for the whole channel
See |ch_open()| for more explanation.
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
Note that changing the mode may cause queued messages to be
lost.
"open" channel can be used
"buffered" channel can be read, not written to
"closed" channel can not be used
- {handle} can be Channel or a Job that has a Channel.
+ {handle} can be a Channel or a Job that has a Channel.
"buffered" is used when the channel was closed but there is
still data that can be obtained with |ch_read()|.
/*
* Return TRUE if "channel" has JSON or other typeahead.
*/
- static int
+ int
channel_has_readahead(channel_T *channel, ch_part_T part)
{
ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
static void f_ceil(typval_T *argvars, typval_T *rettv);
#endif
#ifdef FEAT_JOB_CHANNEL
+static void f_ch_canread(typval_T *argvars, typval_T *rettv);
static void f_ch_close(typval_T *argvars, typval_T *rettv);
static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
{"ceil", 1, 1, f_ceil},
#endif
#ifdef FEAT_JOB_CHANNEL
+ {"ch_canread", 1, 1, f_ch_canread},
{"ch_close", 1, 1, f_ch_close},
{"ch_close_in", 1, 1, f_ch_close_in},
{"ch_evalexpr", 2, 3, f_ch_evalexpr},
#endif
#ifdef FEAT_JOB_CHANNEL
+/*
+ * "ch_canread()" function
+ */
+ static void
+f_ch_canread(typval_T *argvars, typval_T *rettv)
+{
+ channel_T *channel = get_channel_arg(&argvars[0], TRUE, TRUE, 0);
+
+ rettv->vval.v_number = 0;
+ if (channel != NULL)
+ rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
+ || channel_has_readahead(channel, PART_OUT)
+ || channel_has_readahead(channel, PART_ERR);
+}
+
/*
* "ch_close()" function
*/
int channel_collapse(channel_T *channel, ch_part_T part, int want_nl);
int channel_can_write_to(channel_T *channel);
int channel_is_open(channel_T *channel);
+int channel_has_readahead(channel_T *channel, ch_part_T part);
char *channel_status(channel_T *channel, int req_part);
void channel_info(channel_T *channel, dict_T *dict);
void channel_close(channel_T *channel, int invoke_close_cb);
call call(function(a:testfunc), [port])
catch
- call assert_false(1, "Caught exception: " . v:exception)
+ call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint)
finally
call s:kill_server(a:cmd)
endtry
" string with ][ should work
call assert_equal('this][that', ch_evalexpr(handle, 'echo this][that'))
+ " nothing to read now
+ call assert_equal(0, ch_canread(handle))
+
" sending three messages quickly then reading should work
for i in range(3)
call ch_sendexpr(handle, 'echo hello ' . i)
endif
call ch_setoptions(handle, {'mode': 'raw'})
- " The message are sent raw, we do our own JSON strings here.
+ " The messages are sent raw, we do our own JSON strings here.
call ch_sendraw(handle, "[1, \"hello!\"]\n", {'callback': 'Ch_handleRaw1'})
call WaitFor('g:Ch_reply1 != ""')
call assert_equal("[1, \"got it\"]", g:Ch_reply1)
return
endif
call ch_log('Test_raw_pipe()')
- let job = job_start(s:python . " test_channel_pipe.py", {'mode': 'raw'})
+ " Add a dummy close callback to avoid that messages are dropped when calling
+ " ch_canread().
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'mode': 'raw', 'close_cb': {chan -> 0}})
call assert_equal(v:t_job, type(job))
call assert_equal("run", job_status(job))
call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
call ch_sendraw(job, "double this\n")
+ let g:handle = job_getchannel(job)
+ call WaitFor('ch_canread(g:handle)')
+ unlet g:handle
let msg = ch_readraw(job)
call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 105,
/**/
104,
/**/