mirror of
https://github.com/vim/vim.git
synced 2025-09-27 04:14:06 -04:00
patch 8.0.0105
Problem: When using ch_read() with zero timeout, can't tell the difference between reading an empty line and nothing available. Solution: Add ch_canread().
This commit is contained in:
@@ -418,7 +418,11 @@ This uses the channel timeout. To read without a timeout, just get any
|
|||||||
message that is available: >
|
message that is available: >
|
||||||
let output = ch_read(channel, {'timeout': 0})
|
let output = ch_read(channel, {'timeout': 0})
|
||||||
When no message was available then the result is v:none for a JSON or JS mode
|
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: >
|
To read all output from a RAW channel that is available: >
|
||||||
let output = ch_readraw(channel)
|
let output = ch_readraw(channel)
|
||||||
@@ -470,6 +474,11 @@ 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
|
of a pipe causes the read end to get EOF). To avoid this make the job sleep
|
||||||
for a short while before it exits.
|
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
|
The handler defined for "out_cb" will not receive stderr. If you want to
|
||||||
handle that separately, add an "err_cb" handler: >
|
handle that separately, add an "err_cb" handler: >
|
||||||
let job = job_start(command, {"out_cb": "MyHandler",
|
let job = job_start(command, {"out_cb": "MyHandler",
|
||||||
|
@@ -2009,6 +2009,7 @@ byteidxcomp({expr}, {nr}) Number byte index of {nr}'th char in {expr}
|
|||||||
call({func}, {arglist} [, {dict}])
|
call({func}, {arglist} [, {dict}])
|
||||||
any call {func} with arguments {arglist}
|
any call {func} with arguments {arglist}
|
||||||
ceil({expr}) Float round {expr} up
|
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({handle}) none close {handle}
|
||||||
ch_close_in({handle}) none close in part of {handle}
|
ch_close_in({handle}) none close in part of {handle}
|
||||||
ch_evalexpr({handle}, {expr} [, {options}])
|
ch_evalexpr({handle}, {expr} [, {options}])
|
||||||
@@ -2980,16 +2981,28 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
|
|||||||
don't fit, a vertical layout is used anyway. For some systems
|
don't fit, a vertical layout is used anyway. For some systems
|
||||||
the horizontal layout is always used.
|
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()*
|
ch_close({handle}) *ch_close()*
|
||||||
Close {handle}. See |channel-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.
|
A close callback is not invoked.
|
||||||
|
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+channel| feature}
|
||||||
|
|
||||||
ch_close_in({handle}) *ch_close_in()*
|
ch_close_in({handle}) *ch_close_in()*
|
||||||
Close the "in" part of {handle}. See |channel-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.
|
A close callback is not invoked.
|
||||||
|
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+channel| feature}
|
||||||
@@ -2998,7 +3011,7 @@ ch_evalexpr({handle}, {expr} [, {options}]) *ch_evalexpr()*
|
|||||||
Send {expr} over {handle}. The {expr} is encoded
|
Send {expr} over {handle}. The {expr} is encoded
|
||||||
according to the type of channel. The function cannot be used
|
according to the type of channel. The function cannot be used
|
||||||
with a raw channel. See |channel-use|.
|
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*
|
*E917*
|
||||||
{options} must be a Dictionary. It must not have a "callback"
|
{options} must be a Dictionary. It must not have a "callback"
|
||||||
entry. It can have a "timeout" entry to specify the timeout
|
entry. It can have a "timeout" entry to specify the timeout
|
||||||
@@ -3012,7 +3025,7 @@ ch_evalexpr({handle}, {expr} [, {options}]) *ch_evalexpr()*
|
|||||||
|
|
||||||
ch_evalraw({handle}, {string} [, {options}]) *ch_evalraw()*
|
ch_evalraw({handle}, {string} [, {options}]) *ch_evalraw()*
|
||||||
Send {string} over {handle}.
|
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
|
Works like |ch_evalexpr()|, but does not encode the request or
|
||||||
decode the response. The caller is responsible for the
|
decode the response. The caller is responsible for the
|
||||||
@@ -3025,7 +3038,7 @@ ch_evalraw({handle}, {string} [, {options}]) *ch_evalraw()*
|
|||||||
|
|
||||||
ch_getbufnr({handle}, {what}) *ch_getbufnr()*
|
ch_getbufnr({handle}, {what}) *ch_getbufnr()*
|
||||||
Get the buffer number that {handle} is using for {what}.
|
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
|
{what} can be "err" for stderr, "out" for stdout or empty for
|
||||||
socket output.
|
socket output.
|
||||||
Returns -1 when there is no buffer.
|
Returns -1 when there is no buffer.
|
||||||
@@ -3099,7 +3112,7 @@ ch_open({address} [, {options}]) *ch_open()*
|
|||||||
|
|
||||||
ch_read({handle} [, {options}]) *ch_read()*
|
ch_read({handle} [, {options}]) *ch_read()*
|
||||||
Read from {handle} and return the received message.
|
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|.
|
See |channel-more|.
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+channel| feature}
|
||||||
|
|
||||||
@@ -3113,7 +3126,7 @@ ch_sendexpr({handle}, {expr} [, {options}]) *ch_sendexpr()*
|
|||||||
according to the type of channel. The function cannot be used
|
according to the type of channel. The function cannot be used
|
||||||
with a raw channel.
|
with a raw channel.
|
||||||
See |channel-use|. *E912*
|
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}
|
{only available when compiled with the |+channel| feature}
|
||||||
|
|
||||||
@@ -3134,7 +3147,7 @@ ch_setoptions({handle}, {options}) *ch_setoptions()*
|
|||||||
"timeout" default read timeout in msec
|
"timeout" default read timeout in msec
|
||||||
"mode" mode for the whole channel
|
"mode" mode for the whole channel
|
||||||
See |ch_open()| for more explanation.
|
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
|
Note that changing the mode may cause queued messages to be
|
||||||
lost.
|
lost.
|
||||||
@@ -3148,7 +3161,7 @@ ch_status({handle} [, {options}]) *ch_status()*
|
|||||||
"open" channel can be used
|
"open" channel can be used
|
||||||
"buffered" channel can be read, not written to
|
"buffered" channel can be read, not written to
|
||||||
"closed" channel can not be used
|
"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
|
"buffered" is used when the channel was closed but there is
|
||||||
still data that can be obtained with |ch_read()|.
|
still data that can be obtained with |ch_read()|.
|
||||||
|
|
||||||
|
@@ -2603,7 +2603,7 @@ channel_is_open(channel_T *channel)
|
|||||||
/*
|
/*
|
||||||
* Return TRUE if "channel" has JSON or other typeahead.
|
* Return TRUE if "channel" has JSON or other typeahead.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
channel_has_readahead(channel_T *channel, ch_part_T part)
|
channel_has_readahead(channel_T *channel, ch_part_T part)
|
||||||
{
|
{
|
||||||
ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
|
ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
|
||||||
|
@@ -76,6 +76,7 @@ static void f_call(typval_T *argvars, typval_T *rettv);
|
|||||||
static void f_ceil(typval_T *argvars, typval_T *rettv);
|
static void f_ceil(typval_T *argvars, typval_T *rettv);
|
||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#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(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_close_in(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);
|
static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
|
||||||
@@ -499,6 +500,7 @@ static struct fst
|
|||||||
{"ceil", 1, 1, f_ceil},
|
{"ceil", 1, 1, f_ceil},
|
||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#ifdef FEAT_JOB_CHANNEL
|
||||||
|
{"ch_canread", 1, 1, f_ch_canread},
|
||||||
{"ch_close", 1, 1, f_ch_close},
|
{"ch_close", 1, 1, f_ch_close},
|
||||||
{"ch_close_in", 1, 1, f_ch_close_in},
|
{"ch_close_in", 1, 1, f_ch_close_in},
|
||||||
{"ch_evalexpr", 2, 3, f_ch_evalexpr},
|
{"ch_evalexpr", 2, 3, f_ch_evalexpr},
|
||||||
@@ -1778,6 +1780,21 @@ f_ceil(typval_T *argvars, typval_T *rettv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#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
|
* "ch_close()" function
|
||||||
*/
|
*/
|
||||||
|
@@ -25,6 +25,7 @@ void channel_consume(channel_T *channel, ch_part_T part, int len);
|
|||||||
int channel_collapse(channel_T *channel, ch_part_T part, int want_nl);
|
int channel_collapse(channel_T *channel, ch_part_T part, int want_nl);
|
||||||
int channel_can_write_to(channel_T *channel);
|
int channel_can_write_to(channel_T *channel);
|
||||||
int channel_is_open(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);
|
char *channel_status(channel_T *channel, int req_part);
|
||||||
void channel_info(channel_T *channel, dict_T *dict);
|
void channel_info(channel_T *channel, dict_T *dict);
|
||||||
void channel_close(channel_T *channel, int invoke_close_cb);
|
void channel_close(channel_T *channel, int invoke_close_cb);
|
||||||
|
@@ -88,7 +88,7 @@ func RunServer(cmd, testfunc, args)
|
|||||||
|
|
||||||
call call(function(a:testfunc), [port])
|
call call(function(a:testfunc), [port])
|
||||||
catch
|
catch
|
||||||
call assert_false(1, "Caught exception: " . v:exception)
|
call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint)
|
||||||
finally
|
finally
|
||||||
call s:kill_server(a:cmd)
|
call s:kill_server(a:cmd)
|
||||||
endtry
|
endtry
|
||||||
|
@@ -58,6 +58,9 @@ func Ch_communicate(port)
|
|||||||
" string with ][ should work
|
" string with ][ should work
|
||||||
call assert_equal('this][that', ch_evalexpr(handle, 'echo this][that'))
|
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
|
" sending three messages quickly then reading should work
|
||||||
for i in range(3)
|
for i in range(3)
|
||||||
call ch_sendexpr(handle, 'echo hello ' . i)
|
call ch_sendexpr(handle, 'echo hello ' . i)
|
||||||
@@ -368,7 +371,7 @@ func Ch_raw_one_time_callback(port)
|
|||||||
endif
|
endif
|
||||||
call ch_setoptions(handle, {'mode': 'raw'})
|
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 ch_sendraw(handle, "[1, \"hello!\"]\n", {'callback': 'Ch_handleRaw1'})
|
||||||
call WaitFor('g:Ch_reply1 != ""')
|
call WaitFor('g:Ch_reply1 != ""')
|
||||||
call assert_equal("[1, \"got it\"]", g:Ch_reply1)
|
call assert_equal("[1, \"got it\"]", g:Ch_reply1)
|
||||||
@@ -431,7 +434,10 @@ func Test_raw_pipe()
|
|||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
call ch_log('Test_raw_pipe()')
|
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(v:t_job, type(job))
|
||||||
call assert_equal("run", job_status(job))
|
call assert_equal("run", job_status(job))
|
||||||
|
|
||||||
@@ -458,6 +464,9 @@ func Test_raw_pipe()
|
|||||||
call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
|
call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
|
||||||
|
|
||||||
call ch_sendraw(job, "double this\n")
|
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)
|
let msg = ch_readraw(job)
|
||||||
call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
|
call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
|
||||||
|
|
||||||
|
@@ -764,6 +764,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
105,
|
||||||
/**/
|
/**/
|
||||||
104,
|
104,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user