forked from aniani/vim
patch 7.4.1341
Problem: It's difficult to add more arguments to ch_sendraw() and ch_sendexpr(). Solution: Make the third option a dictionary.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
*channel.txt* For Vim version 7.4. Last change: 2016 Feb 15
|
||||
*channel.txt* For Vim version 7.4. Last change: 2016 Feb 16
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -117,7 +117,7 @@ Use |ch_status()| to see if the channel could be opened.
|
||||
|
||||
"mode" can be: *channel-mode*
|
||||
"json" - Use JSON, see below; most convenient way. Default.
|
||||
"js" - Use JavaScript encoding, more efficient than JSON.
|
||||
"js" - Use JS (JavaScript) encoding, more efficient than JSON.
|
||||
"nl" - Use messages that end in a NL character
|
||||
"raw" - Use raw messages
|
||||
|
||||
@@ -188,11 +188,11 @@ If there is an error reading or writing a channel it will be closed.
|
||||
==============================================================================
|
||||
4. Using a JSON or JS channel *channel-use*
|
||||
|
||||
If {mode} is "json" then a message can be sent synchronously like this: >
|
||||
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
|
||||
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: >
|
||||
@@ -242,7 +242,7 @@ 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
|
||||
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*
|
||||
@@ -316,14 +316,15 @@ Example:
|
||||
==============================================================================
|
||||
6. Using a RAW or NL channel *channel-raw*
|
||||
|
||||
If {mode} is "raw" then a message can be send like this: >
|
||||
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
|
||||
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.
|
||||
@@ -450,6 +451,7 @@ The {options} argument in job_start() is a dictionary. All entries are
|
||||
optional. The same options can be used with job_setoptions(job, {options}).
|
||||
|
||||
TODO: *job-out-cb*
|
||||
"callback": handler
|
||||
"out-cb": handler Callback for when there is something to read on
|
||||
stdout.
|
||||
TODO: *job-err-cb*
|
||||
@@ -484,7 +486,7 @@ TODO: *job-out-io*
|
||||
"out-buffer": "name" buffer to append to
|
||||
|
||||
TODO: *job-err-io*
|
||||
"err-io": "out" same as stdout (default)
|
||||
"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
|
||||
|
@@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Feb 13
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Feb 16
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -1821,9 +1821,9 @@ ch_close( {handle}) none close a channel
|
||||
ch_logfile( {fname} [, {mode}]) none start logging channel activity
|
||||
ch_open( {address} [, {argdict})] Number open a channel to {address}
|
||||
ch_readraw( {handle}) String read from channel {handle}
|
||||
ch_sendexpr( {handle}, {expr} [, {callback}])
|
||||
ch_sendexpr( {handle}, {expr} [, {options}])
|
||||
any send {expr} over JSON channel {handle}
|
||||
ch_sendraw( {handle}, {string} [, {callback}])
|
||||
ch_sendraw( {handle}, {string} [, {options}])
|
||||
any send {string} over raw channel {handle}
|
||||
ch_status( {handle}) String status of channel {handle}
|
||||
changenr() Number current change number
|
||||
@@ -2725,28 +2725,32 @@ ch_readraw({handle}) *ch_readraw()*
|
||||
within that time an empty string is returned.
|
||||
TODO: depends on channel mode.
|
||||
|
||||
ch_sendexpr({handle}, {expr} [, {callback}]) *ch_sendexpr()*
|
||||
ch_sendexpr({handle}, {expr} [, {options}]) *ch_sendexpr()*
|
||||
Send {expr} over channel {handle}. The {expr} is encoded
|
||||
according to the type of channel. The function cannot be used
|
||||
with a raw channel. See |channel-use|. *E912*
|
||||
|
||||
When {callback} is given returns immediately. Without
|
||||
{callback} waits for a response and returns the decoded
|
||||
expression. When there is an error or timeout returns an
|
||||
empty string.
|
||||
{options} must be a Dictionary.
|
||||
When "callback" is a Funcref or the name of a function,
|
||||
ch_sendexpr() returns immediately. The callback is invoked
|
||||
when the response is received. See |channel-callback|.
|
||||
|
||||
When {callback} is zero no response is expected.
|
||||
Otherwise {callback} must be a Funcref or the name of a
|
||||
function. It is called when the response is received. See
|
||||
|channel-callback|.
|
||||
Without "callback" ch_sendexpr() waits for a response and
|
||||
returns the decoded expression. When there is an error or
|
||||
timeout it returns an empty string.
|
||||
|
||||
When "callback" is zero no response is expected.
|
||||
|
||||
{only available when compiled with the |+channel| feature}
|
||||
|
||||
ch_sendraw({handle}, {string} [, {callback}]) *ch_sendraw()*
|
||||
ch_sendraw({handle}, {string} [, {options}]) *ch_sendraw()*
|
||||
Send {string} over channel {handle}.
|
||||
Works like |ch_sendexpr()|, but does not encode the request or
|
||||
decode the response. The caller is responsible for the
|
||||
correct contents. See |channel-use|.
|
||||
correct contents. Also does not add a newline for a channel
|
||||
in NL mode, the caller must do that. The NL in the response
|
||||
is removed.
|
||||
See |channel-use|.
|
||||
|
||||
{only available when compiled with the |+channel| feature}
|
||||
|
||||
@@ -7274,7 +7278,7 @@ listcmds Compiled with commands for the buffer list |:files|
|
||||
and the argument list |arglist|.
|
||||
localmap Compiled with local mappings and abbr. |:map-local|
|
||||
lua Compiled with Lua interface |Lua|.
|
||||
mac Macintosh version of Vim.
|
||||
mac Any Macintosh version of Vim.
|
||||
macunix Compiled for OS X, with darwin
|
||||
osx Compiled for OS X, with or without darwin
|
||||
menu Compiled with support for |:menu|.
|
||||
|
@@ -696,6 +696,18 @@ channel_set_callback(channel_T *channel, char_u *callback)
|
||||
channel->ch_callback = vim_strsave(callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set various properties from an "options" argument.
|
||||
*/
|
||||
void
|
||||
channel_set_options(channel_T *channel, jobopt_T *options)
|
||||
{
|
||||
channel_set_mode(channel, options->jo_mode);
|
||||
|
||||
if (options->jo_callback != NULL && *options->jo_callback != NUL)
|
||||
channel_set_callback(channel, options->jo_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the callback for channel "channel" for the response with "id".
|
||||
*/
|
||||
|
47
src/eval.c
47
src/eval.c
@@ -9930,15 +9930,18 @@ f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the "mode" entry from "dict", if it exists, and parse the mode name.
|
||||
* If the mode is invalide return FAIL.
|
||||
* Get the option entries from "dict", and parse them.
|
||||
* If an option value is invalid return FAIL.
|
||||
*/
|
||||
static int
|
||||
get_mode_arg(dict_T *dict, jobopt_T *opt)
|
||||
get_job_options(dict_T *dict, jobopt_T *opt)
|
||||
{
|
||||
dictitem_T *item;
|
||||
char_u *mode;
|
||||
|
||||
if (dict == NULL)
|
||||
return OK;
|
||||
|
||||
if ((item = dict_find(dict, (char_u *)"mode", -1)) != NULL)
|
||||
{
|
||||
mode = get_tv_string(&item->di_tv);
|
||||
@@ -9956,6 +9959,17 @@ get_mode_arg(dict_T *dict, jobopt_T *opt)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((item = dict_find(dict, (char_u *)"callback", -1)) != NULL)
|
||||
{
|
||||
opt->jo_callback = get_callback(&item->di_tv);
|
||||
if (opt->jo_callback == NULL)
|
||||
{
|
||||
EMSG2(_(e_invarg2), "callback");
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -9966,7 +9980,6 @@ get_mode_arg(dict_T *dict, jobopt_T *opt)
|
||||
f_ch_open(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *address;
|
||||
char_u *callback = NULL;
|
||||
char_u *p;
|
||||
char *rest;
|
||||
int port;
|
||||
@@ -10004,20 +10017,19 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
|
||||
options.jo_mode = MODE_JSON;
|
||||
options.jo_callback = NULL;
|
||||
if (argvars[1].v_type == VAR_DICT)
|
||||
{
|
||||
dict_T *dict = argvars[1].vval.v_dict;
|
||||
dictitem_T *item;
|
||||
|
||||
/* parse argdict */
|
||||
if (get_mode_arg(dict, &options) == FAIL)
|
||||
if (get_job_options(dict, &options) == FAIL)
|
||||
return;
|
||||
if ((item = dict_find(dict, (char_u *)"waittime", -1)) != NULL)
|
||||
waittime = get_tv_number(&item->di_tv);
|
||||
if ((item = dict_find(dict, (char_u *)"timeout", -1)) != NULL)
|
||||
timeout = get_tv_number(&item->di_tv);
|
||||
if ((item = dict_find(dict, (char_u *)"callback", -1)) != NULL)
|
||||
callback = get_callback(&item->di_tv);
|
||||
}
|
||||
if (waittime < 0 || timeout < 0)
|
||||
{
|
||||
@@ -10029,10 +10041,8 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
||||
if (channel != NULL)
|
||||
{
|
||||
rettv->vval.v_channel = channel;
|
||||
channel_set_mode(channel, options.jo_mode);
|
||||
channel_set_options(channel, &options);
|
||||
channel_set_timeout(channel, timeout);
|
||||
if (callback != NULL && *callback != NUL)
|
||||
channel_set_callback(channel, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10082,6 +10092,7 @@ send_common(typval_T *argvars, char_u *text, int id, char *fun)
|
||||
{
|
||||
channel_T *channel;
|
||||
char_u *callback = NULL;
|
||||
jobopt_T options;
|
||||
|
||||
channel = get_channel_arg(&argvars[0]);
|
||||
if (channel == NULL)
|
||||
@@ -10089,10 +10100,16 @@ send_common(typval_T *argvars, char_u *text, int id, char *fun)
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
callback = get_callback(&argvars[2]);
|
||||
if (callback == NULL)
|
||||
if (argvars[2].v_type != VAR_DICT)
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
return NULL;
|
||||
}
|
||||
options.jo_callback = NULL;
|
||||
if (get_job_options(argvars[2].vval.v_dict, &options) == FAIL)
|
||||
return NULL;
|
||||
callback = options.jo_callback;
|
||||
}
|
||||
/* Set the callback. An empty callback means no callback and not reading
|
||||
* the response. */
|
||||
if (callback != NULL && *callback != NUL)
|
||||
@@ -14511,17 +14528,15 @@ f_job_start(typval_T *argvars UNUSED, typval_T *rettv)
|
||||
|
||||
/* Default mode is NL. */
|
||||
options.jo_mode = MODE_NL;
|
||||
options.jo_callback = NULL;
|
||||
if (argvars[1].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
dict_T *dict;
|
||||
|
||||
if (argvars[1].v_type != VAR_DICT)
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
return;
|
||||
}
|
||||
dict = argvars[1].vval.v_dict;
|
||||
if (get_mode_arg(dict, &options) == FAIL)
|
||||
if (get_job_options(argvars[1].vval.v_dict, &options) == FAIL)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -5127,7 +5127,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
|
||||
# ifdef FEAT_CHANNEL
|
||||
channel_set_pipes(channel, fd_in[1], fd_out[0], fd_err[0]);
|
||||
channel_set_job(channel, job);
|
||||
channel_set_mode(channel, options->jo_mode);
|
||||
channel_set_options(channel, options);
|
||||
# ifdef FEAT_GUI
|
||||
channel_gui_register(channel);
|
||||
# endif
|
||||
|
@@ -5125,7 +5125,7 @@ mch_start_job(char *cmd, job_T *job, jobopt_T *options)
|
||||
job->jv_channel = channel;
|
||||
channel_set_pipes(channel, (sock_T)ifd[1], (sock_T)ofd[0], (sock_T)efd[0]);
|
||||
channel_set_job(channel, job);
|
||||
channel_set_mode(channel, options->jo_mode);
|
||||
channel_set_options(channel, options);
|
||||
|
||||
# ifdef FEAT_GUI
|
||||
channel_gui_register(channel);
|
||||
|
@@ -7,9 +7,10 @@ void channel_gui_register_all(void);
|
||||
channel_T *channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
|
||||
void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
|
||||
void channel_set_job(channel_T *channel, job_T *job);
|
||||
void channel_set_mode(channel_T *channel, ch_mode_T ch_mode);
|
||||
void channel_set_mode(channel_T *channel, ch_mode_T mode);
|
||||
void channel_set_timeout(channel_T *channel, int timeout);
|
||||
void channel_set_callback(channel_T *channel, char_u *callback);
|
||||
void channel_set_options(channel_T *channel, jobopt_T *options);
|
||||
void channel_set_req_callback(channel_T *channel, char_u *callback, int id);
|
||||
char_u *channel_get(channel_T *channel);
|
||||
int channel_collapse(channel_T *channel);
|
||||
|
@@ -1373,11 +1373,12 @@ struct channel_S {
|
||||
};
|
||||
|
||||
/*
|
||||
* Options for job commands.
|
||||
* Options for job and channel commands.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ch_mode_T jo_mode;
|
||||
ch_mode_T jo_mode; /* "mode" */
|
||||
char_u *jo_callback; /* "callback", not allocated! */
|
||||
} jobopt_T;
|
||||
|
||||
|
||||
|
@@ -117,7 +117,7 @@ func s:communicate(port)
|
||||
call assert_equal('added more', getline('$'))
|
||||
|
||||
" Send a request with a specific handler.
|
||||
call ch_sendexpr(handle, 'hello!', 's:RequestHandler')
|
||||
call ch_sendexpr(handle, 'hello!', {'callback': 's:RequestHandler'})
|
||||
sleep 10m
|
||||
if !exists('s:responseHandle')
|
||||
call assert_false(1, 's:responseHandle was not set')
|
||||
@@ -128,7 +128,7 @@ func s:communicate(port)
|
||||
|
||||
unlet s:responseHandle
|
||||
let s:responseMsg = ''
|
||||
call ch_sendexpr(handle, 'hello!', function('s:RequestHandler'))
|
||||
call ch_sendexpr(handle, 'hello!', {'callback': function('s:RequestHandler')})
|
||||
sleep 10m
|
||||
if !exists('s:responseHandle')
|
||||
call assert_false(1, 's:responseHandle was not set')
|
||||
@@ -171,7 +171,7 @@ func s:communicate(port)
|
||||
call assert_equal('ok', ch_sendexpr(handle, 'empty-request'))
|
||||
|
||||
" make the server quit, can't check if this works, should not hang.
|
||||
call ch_sendexpr(handle, '!quit!', 0)
|
||||
call ch_sendexpr(handle, '!quit!', {'callback': 0})
|
||||
endfunc
|
||||
|
||||
func Test_communicate()
|
||||
@@ -242,7 +242,7 @@ func s:channel_handler(port)
|
||||
call assert_equal('we called you', s:reply)
|
||||
|
||||
" Test that it works while not waiting on a numbered message.
|
||||
call ch_sendexpr(handle, 'call me again', 0)
|
||||
call ch_sendexpr(handle, 'call me again', {'callback': 0})
|
||||
sleep 10m
|
||||
call assert_equal('we did call you', s:reply)
|
||||
endfunc
|
||||
@@ -292,11 +292,11 @@ func Test_raw_pipe()
|
||||
call assert_equal("run", job_status(job))
|
||||
try
|
||||
let handle = job_getchannel(job)
|
||||
call ch_sendraw(handle, "echo something\n", 0)
|
||||
call ch_sendraw(handle, "echo something\n", {'callback': 0})
|
||||
let msg = ch_readraw(handle)
|
||||
call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
|
||||
|
||||
call ch_sendraw(handle, "double this\n", 0)
|
||||
call ch_sendraw(handle, "double this\n", {'callback': 0})
|
||||
let msg = ch_readraw(handle)
|
||||
call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
|
||||
|
||||
@@ -315,10 +315,10 @@ func Test_nl_pipe()
|
||||
call assert_equal("run", job_status(job))
|
||||
try
|
||||
let handle = job_getchannel(job)
|
||||
call ch_sendraw(handle, "echo something\n", 0)
|
||||
call ch_sendraw(handle, "echo something\n", {'callback': 0})
|
||||
call assert_equal("something", ch_readraw(handle))
|
||||
|
||||
call ch_sendraw(handle, "double this\n", 0)
|
||||
call ch_sendraw(handle, "double this\n", {'callback': 0})
|
||||
call assert_equal("this", ch_readraw(handle))
|
||||
call assert_equal("AND this", ch_readraw(handle))
|
||||
|
||||
@@ -340,7 +340,7 @@ endfunc
|
||||
" Test that "unlet handle" in a handler doesn't crash Vim.
|
||||
func s:unlet_handle(port)
|
||||
let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
|
||||
call ch_sendexpr(s:channelfd, "test", function('s:UnletHandler'))
|
||||
call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')})
|
||||
sleep 10m
|
||||
call assert_equal('what?', s:unletResponse)
|
||||
endfunc
|
||||
@@ -360,7 +360,7 @@ endfunc
|
||||
" Test that "unlet handle" in a handler doesn't crash Vim.
|
||||
func s:close_handle(port)
|
||||
let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
|
||||
call ch_sendexpr(s:channelfd, "test", function('s:CloseHandler'))
|
||||
call ch_sendexpr(s:channelfd, "test", {'callback': function('s:CloseHandler')})
|
||||
sleep 10m
|
||||
call assert_equal('what?', s:unletResponse)
|
||||
endfunc
|
||||
|
@@ -747,6 +747,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1341,
|
||||
/**/
|
||||
1340,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user