forked from aniani/vim
patch 7.4.1372
Problem: channel read implementation is incomplete. Solution: Add ch_read() and options for ch_readraw().
This commit is contained in:
@@ -1696,12 +1696,11 @@ channel_read(channel_T *channel, int part, char *func)
|
|||||||
* Returns NULL in case of error or timeout.
|
* Returns NULL in case of error or timeout.
|
||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
channel_read_block(channel_T *channel, int part)
|
channel_read_block(channel_T *channel, int part, int timeout)
|
||||||
{
|
{
|
||||||
char_u *buf;
|
char_u *buf;
|
||||||
char_u *msg;
|
char_u *msg;
|
||||||
ch_mode_T mode = channel->ch_part[part].ch_mode;
|
ch_mode_T mode = channel->ch_part[part].ch_mode;
|
||||||
int timeout = channel->ch_part[part].ch_timeout;
|
|
||||||
sock_T fd = channel->ch_part[part].ch_fd;
|
sock_T fd = channel->ch_part[part].ch_fd;
|
||||||
char_u *nl;
|
char_u *nl;
|
||||||
|
|
||||||
@@ -1753,16 +1752,23 @@ channel_read_block(channel_T *channel, int part)
|
|||||||
/*
|
/*
|
||||||
* Read one JSON message with ID "id" from "channel"/"part" and store the
|
* Read one JSON message with ID "id" from "channel"/"part" and store the
|
||||||
* result in "rettv".
|
* result in "rettv".
|
||||||
|
* When "id" is -1 accept any message;
|
||||||
* Blocks until the message is received or the timeout is reached.
|
* Blocks until the message is received or the timeout is reached.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
channel_read_json_block(channel_T *channel, int part, int id, typval_T **rettv)
|
channel_read_json_block(
|
||||||
|
channel_T *channel,
|
||||||
|
int part,
|
||||||
|
int timeout,
|
||||||
|
int id,
|
||||||
|
typval_T **rettv)
|
||||||
{
|
{
|
||||||
int more;
|
int more;
|
||||||
sock_T fd;
|
sock_T fd;
|
||||||
|
|
||||||
ch_log(channel, "Reading JSON");
|
ch_log(channel, "Reading JSON");
|
||||||
channel->ch_part[part].ch_block_id = id;
|
if (id != -1)
|
||||||
|
channel->ch_part[part].ch_block_id = id;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
more = channel_parse_json(channel, part);
|
more = channel_parse_json(channel, part);
|
||||||
@@ -1781,10 +1787,9 @@ channel_read_json_block(channel_T *channel, int part, int id, typval_T **rettv)
|
|||||||
if (channel_parse_messages())
|
if (channel_parse_messages())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Wait for up to the channel timeout. */
|
/* Wait for up to the timeout. */
|
||||||
fd = channel->ch_part[part].ch_fd;
|
fd = channel->ch_part[part].ch_fd;
|
||||||
if (fd == INVALID_FD || channel_wait(channel, fd,
|
if (fd == INVALID_FD || channel_wait(channel, fd, timeout) == FAIL)
|
||||||
channel->ch_part[part].ch_timeout) == FAIL)
|
|
||||||
break;
|
break;
|
||||||
channel_read(channel, part, "channel_read_json_block");
|
channel_read(channel, part, "channel_read_json_block");
|
||||||
}
|
}
|
||||||
@@ -2161,4 +2166,13 @@ channel_get_mode(channel_T *channel, int part)
|
|||||||
return channel->ch_part[part].ch_mode;
|
return channel->ch_part[part].ch_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the timeout of "channel"/"part"
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
channel_get_timeout(channel_T *channel, int part)
|
||||||
|
{
|
||||||
|
return channel->ch_part[part].ch_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FEAT_CHANNEL */
|
#endif /* FEAT_CHANNEL */
|
||||||
|
109
src/eval.c
109
src/eval.c
@@ -507,6 +507,7 @@ static void f_ch_close(typval_T *argvars, typval_T *rettv);
|
|||||||
static void f_ch_log(typval_T *argvars, typval_T *rettv);
|
static void f_ch_log(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
|
static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_open(typval_T *argvars, typval_T *rettv);
|
static void f_ch_open(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_ch_read(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
|
static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
|
static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
|
static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
|
||||||
@@ -8129,6 +8130,7 @@ static struct fst
|
|||||||
{"ch_log", 1, 2, f_ch_log},
|
{"ch_log", 1, 2, f_ch_log},
|
||||||
{"ch_logfile", 1, 2, f_ch_logfile},
|
{"ch_logfile", 1, 2, f_ch_logfile},
|
||||||
{"ch_open", 1, 2, f_ch_open},
|
{"ch_open", 1, 2, f_ch_open},
|
||||||
|
{"ch_read", 1, 2, f_ch_read},
|
||||||
{"ch_readraw", 1, 2, f_ch_readraw},
|
{"ch_readraw", 1, 2, f_ch_readraw},
|
||||||
{"ch_sendexpr", 2, 3, f_ch_sendexpr},
|
{"ch_sendexpr", 2, 3, f_ch_sendexpr},
|
||||||
{"ch_sendraw", 2, 3, f_ch_sendraw},
|
{"ch_sendraw", 2, 3, f_ch_sendraw},
|
||||||
@@ -9881,7 +9883,7 @@ get_callback(typval_T *arg)
|
|||||||
get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
||||||
{
|
{
|
||||||
typval_T *item;
|
typval_T *item;
|
||||||
char_u *mode;
|
char_u *val;
|
||||||
dict_T *dict;
|
dict_T *dict;
|
||||||
int todo;
|
int todo;
|
||||||
hashitem_T *hi;
|
hashitem_T *hi;
|
||||||
@@ -9909,18 +9911,18 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
if (!(supported & JO_MODE))
|
if (!(supported & JO_MODE))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO_MODE;
|
opt->jo_set |= JO_MODE;
|
||||||
mode = get_tv_string(item);
|
val = get_tv_string(item);
|
||||||
if (STRCMP(mode, "nl") == 0)
|
if (STRCMP(val, "nl") == 0)
|
||||||
opt->jo_mode = MODE_NL;
|
opt->jo_mode = MODE_NL;
|
||||||
else if (STRCMP(mode, "raw") == 0)
|
else if (STRCMP(val, "raw") == 0)
|
||||||
opt->jo_mode = MODE_RAW;
|
opt->jo_mode = MODE_RAW;
|
||||||
else if (STRCMP(mode, "js") == 0)
|
else if (STRCMP(val, "js") == 0)
|
||||||
opt->jo_mode = MODE_JS;
|
opt->jo_mode = MODE_JS;
|
||||||
else if (STRCMP(mode, "json") == 0)
|
else if (STRCMP(val, "json") == 0)
|
||||||
opt->jo_mode = MODE_JSON;
|
opt->jo_mode = MODE_JSON;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EMSG2(_(e_invarg2), mode);
|
EMSG2(_(e_invarg2), val);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9950,6 +9952,27 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
opt->jo_set |= JO_TIMEOUT;
|
opt->jo_set |= JO_TIMEOUT;
|
||||||
opt->jo_timeout = get_tv_number(item);
|
opt->jo_timeout = get_tv_number(item);
|
||||||
}
|
}
|
||||||
|
else if (STRCMP(hi->hi_key, "part") == 0)
|
||||||
|
{
|
||||||
|
if (!(supported & JO_PART))
|
||||||
|
break;
|
||||||
|
opt->jo_set |= JO_PART;
|
||||||
|
val = get_tv_string(item);
|
||||||
|
if (STRCMP(val, "err") == 0)
|
||||||
|
opt->jo_part = PART_ERR;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EMSG2(_(e_invarg2), val);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (STRCMP(hi->hi_key, "id") == 0)
|
||||||
|
{
|
||||||
|
if (!(supported & JO_ID))
|
||||||
|
break;
|
||||||
|
opt->jo_set |= JO_ID;
|
||||||
|
opt->jo_id = get_tv_number(item);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
--todo;
|
--todo;
|
||||||
@@ -10107,29 +10130,76 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "ch_readraw()" function
|
* Common for ch_read() and ch_readraw().
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
f_ch_readraw(typval_T *argvars, typval_T *rettv)
|
common_channel_read(typval_T *argvars, typval_T *rettv, int raw)
|
||||||
{
|
{
|
||||||
channel_T *channel;
|
channel_T *channel;
|
||||||
int part;
|
int part;
|
||||||
|
jobopt_T opt;
|
||||||
|
int mode;
|
||||||
|
int timeout;
|
||||||
|
int id = -1;
|
||||||
|
typval_T *listtv = NULL;
|
||||||
|
|
||||||
/* return an empty string by default */
|
/* return an empty string by default */
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
rettv->vval.v_string = NULL;
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
/* TODO: use timeout from the options */
|
opt.jo_set = 0;
|
||||||
/* TODO: read from stderr */
|
if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID)
|
||||||
|
== FAIL)
|
||||||
|
return;
|
||||||
|
|
||||||
channel = get_channel_arg(&argvars[0]);
|
channel = get_channel_arg(&argvars[0]);
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
{
|
{
|
||||||
part = channel_part_read(channel);
|
if (opt.jo_set & JO_PART)
|
||||||
rettv->vval.v_string = channel_read_block(channel, part);
|
part = opt.jo_part;
|
||||||
|
else
|
||||||
|
part = channel_part_read(channel);
|
||||||
|
mode = channel_get_mode(channel, part);
|
||||||
|
timeout = channel_get_timeout(channel, part);
|
||||||
|
if (opt.jo_set & JO_TIMEOUT)
|
||||||
|
timeout = opt.jo_timeout;
|
||||||
|
|
||||||
|
if (raw || mode == MODE_RAW || mode == MODE_NL)
|
||||||
|
rettv->vval.v_string = channel_read_block(channel, part, timeout);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (opt.jo_set & JO_ID)
|
||||||
|
id = opt.jo_id;
|
||||||
|
channel_read_json_block(channel, part, timeout, id, &listtv);
|
||||||
|
if (listtv != NULL)
|
||||||
|
*rettv = *listtv;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rettv->v_type = VAR_SPECIAL;
|
||||||
|
rettv->vval.v_number = VVAL_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "ch_read()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_ch_read(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
common_channel_read(argvars, rettv, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "ch_readraw()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_ch_readraw(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
common_channel_read(argvars, rettv, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* common for "sendexpr()" and "sendraw()"
|
* common for "sendexpr()" and "sendraw()"
|
||||||
* Returns the channel if the caller should read the response.
|
* Returns the channel if the caller should read the response.
|
||||||
@@ -10177,6 +10247,7 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
|||||||
ch_mode_T ch_mode;
|
ch_mode_T ch_mode;
|
||||||
int part_send;
|
int part_send;
|
||||||
int part_read;
|
int part_read;
|
||||||
|
int timeout;
|
||||||
|
|
||||||
/* return an empty string by default */
|
/* return an empty string by default */
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
@@ -10204,7 +10275,10 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
|||||||
vim_free(text);
|
vim_free(text);
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
{
|
{
|
||||||
if (channel_read_json_block(channel, part_read, id, &listtv) == OK)
|
/* TODO: timeout from options */
|
||||||
|
timeout = channel_get_timeout(channel, part_read);
|
||||||
|
if (channel_read_json_block(channel, part_read, timeout, id, &listtv)
|
||||||
|
== OK)
|
||||||
{
|
{
|
||||||
list_T *list = listtv->vval.v_list;
|
list_T *list = listtv->vval.v_list;
|
||||||
|
|
||||||
@@ -10227,6 +10301,7 @@ f_ch_sendraw(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *text;
|
char_u *text;
|
||||||
channel_T *channel;
|
channel_T *channel;
|
||||||
int part_read;
|
int part_read;
|
||||||
|
int timeout;
|
||||||
|
|
||||||
/* return an empty string by default */
|
/* return an empty string by default */
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
@@ -10235,7 +10310,11 @@ f_ch_sendraw(typval_T *argvars, typval_T *rettv)
|
|||||||
text = get_tv_string_buf(&argvars[1], buf);
|
text = get_tv_string_buf(&argvars[1], buf);
|
||||||
channel = send_common(argvars, text, 0, "sendraw", &part_read);
|
channel = send_common(argvars, text, 0, "sendraw", &part_read);
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
rettv->vval.v_string = channel_read_block(channel, part_read);
|
{
|
||||||
|
/* TODO: timeout from options */
|
||||||
|
timeout = channel_get_timeout(channel, part_read);
|
||||||
|
rettv->vval.v_string = channel_read_block(channel, part_read, timeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -23,9 +23,9 @@ void channel_clear(channel_T *channel);
|
|||||||
void channel_free_all(void);
|
void channel_free_all(void);
|
||||||
int channel_get_id(void);
|
int channel_get_id(void);
|
||||||
void channel_read(channel_T *channel, int part, char *func);
|
void channel_read(channel_T *channel, int part, char *func);
|
||||||
char_u *channel_read_block(channel_T *channel, int part);
|
char_u *channel_read_block(channel_T *channel, int part, int timeout);
|
||||||
int channel_read_json_block(channel_T *channel, int part, int id, typval_T **rettv);
|
int channel_read_json_block(channel_T *channel, int part, int timeout, int id, typval_T **rettv);
|
||||||
channel_T *channel_fd2channel(sock_T fd, int *part);
|
channel_T *channel_fd2channel(sock_T fd, int *partp);
|
||||||
void channel_handle_events(void);
|
void channel_handle_events(void);
|
||||||
int channel_send(channel_T *channel, int part, char_u *buf, char *fun);
|
int channel_send(channel_T *channel, int part, char_u *buf, char *fun);
|
||||||
int channel_poll_setup(int nfd_in, void *fds_in);
|
int channel_poll_setup(int nfd_in, void *fds_in);
|
||||||
@@ -37,4 +37,5 @@ int set_ref_in_channel(int copyID);
|
|||||||
int channel_part_send(channel_T *channel);
|
int channel_part_send(channel_T *channel);
|
||||||
int channel_part_read(channel_T *channel);
|
int channel_part_read(channel_T *channel);
|
||||||
ch_mode_T channel_get_mode(channel_T *channel, int part);
|
ch_mode_T channel_get_mode(channel_T *channel, int part);
|
||||||
|
int channel_get_timeout(channel_T *channel, int part);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@@ -1377,6 +1377,8 @@ struct channel_S {
|
|||||||
#define JO_CALLBACK 2 /* channel callback */
|
#define JO_CALLBACK 2 /* channel callback */
|
||||||
#define JO_WAITTIME 4 /* only for ch_open() */
|
#define JO_WAITTIME 4 /* only for ch_open() */
|
||||||
#define JO_TIMEOUT 8 /* all timeouts */
|
#define JO_TIMEOUT 8 /* all timeouts */
|
||||||
|
#define JO_PART 16 /* "part" */
|
||||||
|
#define JO_ID 32 /* "id" */
|
||||||
#define JO_ALL 0xffffff
|
#define JO_ALL 0xffffff
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1390,6 +1392,8 @@ typedef struct
|
|||||||
char_u *jo_callback; /* not allocated! */
|
char_u *jo_callback; /* not allocated! */
|
||||||
int jo_waittime;
|
int jo_waittime;
|
||||||
int jo_timeout;
|
int jo_timeout;
|
||||||
|
int jo_part;
|
||||||
|
int jo_id;
|
||||||
} jobopt_T;
|
} jobopt_T;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -184,6 +184,21 @@ func s:communicate(port)
|
|||||||
|
|
||||||
call assert_equal('ok', ch_sendexpr(handle, 'empty-request'))
|
call assert_equal('ok', ch_sendexpr(handle, 'empty-request'))
|
||||||
|
|
||||||
|
" Reading while there is nothing available.
|
||||||
|
call assert_equal(v:none, ch_read(handle, {'timeout': 0}))
|
||||||
|
let start = reltime()
|
||||||
|
call assert_equal(v:none, ch_read(handle, {'timeout': 333}))
|
||||||
|
let elapsed = reltime(start)
|
||||||
|
call assert_true(reltimefloat(elapsed) > 0.3)
|
||||||
|
call assert_true(reltimefloat(elapsed) < 0.6)
|
||||||
|
|
||||||
|
" Send without waiting for a response, then wait for a response.
|
||||||
|
call ch_sendexpr(handle, 'wait a bit', {'callback': 0})
|
||||||
|
let resp = ch_read(handle)
|
||||||
|
call assert_equal(type([]), type(resp))
|
||||||
|
call assert_equal(type(11), type(resp[0]))
|
||||||
|
call assert_equal('waited', resp[1])
|
||||||
|
|
||||||
" make the server quit, can't check if this works, should not hang.
|
" make the server quit, can't check if this works, should not hang.
|
||||||
call ch_sendexpr(handle, '!quit!', {'callback': 0})
|
call ch_sendexpr(handle, '!quit!', {'callback': 0})
|
||||||
endfunc
|
endfunc
|
||||||
@@ -292,8 +307,7 @@ func Test_connect_waittime()
|
|||||||
" Oops, port does exists.
|
" Oops, port does exists.
|
||||||
call ch_close(handle)
|
call ch_close(handle)
|
||||||
else
|
else
|
||||||
" Failed connection doesn't wait the full time on Unix.
|
" Failed connection should wait about 500 msec.
|
||||||
" TODO: why is MS-Windows different?
|
|
||||||
let elapsed = reltime(start)
|
let elapsed = reltime(start)
|
||||||
call assert_true(reltimefloat(elapsed) < 1.0)
|
call assert_true(reltimefloat(elapsed) < 1.0)
|
||||||
endif
|
endif
|
||||||
|
@@ -747,6 +747,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 */
|
||||||
|
/**/
|
||||||
|
1372,
|
||||||
/**/
|
/**/
|
||||||
1371,
|
1371,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user