-*channel.txt* For Vim version 7.4. Last change: 2016 Feb 23
+*channel.txt* For Vim version 7.4. Last change: 2016 Feb 27
VIM REFERENCE MANUAL by Bram Moolenaar
=== socket opened === ~
You can now send a message to the server: >
- echo ch_sendexpr(channel, 'hello!')
+ echo ch_evalexpr(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:
when opening the channel: >
call ch_close(channel)
let channel = ch_open('localhost:8765', {'callback': "MyHandler"})
- call ch_sendexpr(channel, 'hello!', {'callback': 0})
+ call ch_sendexpr(channel, 'hello!')
==============================================================================
3. Opening a channel *channel-open*
msec at least.
"timeout" The time to wait for a request when blocking, E.g. when using
- ch_sendexpr(). In milliseconds. The default is 2000 (2
+ ch_evalexpr(). In milliseconds. The default is 2000 (2
seconds).
*out-timeout* *err-timeout*
"out-timeout" Timeout for stdout. Only when using pipes.
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})
+ let response = ch_evalexpr(channel, {expr})
This awaits a response from the other side.
When mode is JS this works the same, except that the messages use
To send a message, without handling a response or letting the channel callback
handle the response: >
- call ch_sendexpr(channel, {expr}, {'callback': 0})
+ call ch_sendexpr(channel, {expr})
To send a message and letting the response handled by a specific function,
asynchronously: >
if still possible. The channel will then be inactive. For a JSON and JS mode
channel quotes are used around DETACH, otherwise there are no quotes.
-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.
+It is also possible to use ch_sendraw() and ch_evalraw() on a JSON or JS
+channel. The caller is then completely responsible for correct encoding and
+decoding.
==============================================================================
5. Channel commands *channel-commands*
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})
+ let response = ch_evalraw(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
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)
+ call ch_sendraw(channel, {string})
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})
+ call ch_sendraw(channel, {string}, {'callback': 'MyHandler'})
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.
+It is not possible to use |ch_evalexpr()| or |ch_sendexpr()| on a raw channel.
==============================================================================
7. More channel functions *channel-more*
"callback" option: >
let job = job_start(command, {"callback": "MyHandler"})
-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().
+You can send a message to the command with ch_evalraw(). If the channel is in
+JSON or JS mode you can use ch_evalexpr().
There are several options you can use, see |job-options|.
For example, to start a job and write its output in buffer "dummy": >
any call {func} with arguments {arglist}
ceil( {expr}) Float round {expr} up
ch_close( {channel}) none close {channel}
+ch_evalexpr( {channel}, {expr} [, {options}])
+ any evaluate {expr} on JSON {channel}
+ch_evalraw( {channel}, {string} [, {options}])
+ any evaluate {string} on raw {channel}
ch_getjob( {channel}) Job get the Job of {channel}
ch_log( {msg} [, {channel}]) none write {msg} in the channel log file
ch_logfile( {fname} [, {mode}]) none start logging channel activity
Close {channel}. See |channel-close|.
{only available when compiled with the |+channel| feature}
+ch_evalexpr({channel}, {expr} [, {options}]) *ch_evalexpr()*
+ Send {expr} over {channel}. The {expr} is encoded
+ according to the type of channel. The function cannot be used
+ with a raw channel. See |channel-use|. *E912*
+ *E917*
+ {options} must be a Dictionary. It must not have a "callback"
+ entry.
+
+ ch_evalexpr() waits for a response and returns the decoded
+ expression. When there is an error or timeout it returns an
+ empty string.
+
+ {only available when compiled with the |+channel| feature}
+
+ch_evalraw({channel}, {string} [, {options}]) *ch_evalraw()*
+ Send {string} over {channel}.
+ Works like |ch_evalexpr()|, but does not encode the request or
+ decode the response. The caller is responsible for the
+ 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}
+
ch_getjob({channel}) *ch_getjob()*
Get the Job associated with {channel}.
If there is no job calling |job_status()| on the returned Job
according to the type of channel. The function cannot be used
with a raw channel. See |channel-use|. *E912*
- {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|.
-
- 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.
+ {options} must be a Dictionary. The "callback" item is a
+ Funcref or the name of a function it is invoked when the
+ response is received. See |channel-callback|.
+ Without "callback" the channel handler is invoked, otherwise
+ any received message is dropped.
{only available when compiled with the |+channel| feature}
showcmd Compiled with 'showcmd' support.
signs Compiled with |:sign| support.
smartindent Compiled with 'smartindent' support.
-sniff Compiled with SNiFF interface support.
spell Compiled with spell checking support |spell|.
startuptime Compiled with |--startuptime| support.
statusline Compiled with support for 'statusline', 'rulerformat'
#endif
#ifdef FEAT_CHANNEL
static void f_ch_close(typval_T *argvars, typval_T *rettv);
+static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
+static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
# ifdef FEAT_JOB
static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
# endif
#endif
#ifdef FEAT_CHANNEL
{"ch_close", 1, 1, f_ch_close},
+ {"ch_evalexpr", 2, 3, f_ch_evalexpr},
+ {"ch_evalraw", 2, 3, f_ch_evalraw},
# ifdef FEAT_JOB
{"ch_getjob", 1, 1, f_ch_getjob},
# endif
* Otherwise returns NULL.
*/
static channel_T *
-send_common(typval_T *argvars, char_u *text, int id, char *fun, int *part_read)
+send_common(
+ typval_T *argvars,
+ char_u *text,
+ int id,
+ int eval,
+ char *fun,
+ int *part_read)
{
channel_T *channel;
jobopt_T opt;
return NULL;
/* Set the callback. An empty callback means no callback and not reading
- * the response. */
+ * the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
+ * allowed. */
if (opt.jo_callback != NULL && *opt.jo_callback != NUL)
+ {
+ if (eval)
+ {
+ EMSG2(_("E917: Cannot use a callback with %s()"), fun);
+ return NULL;
+ }
channel_set_req_callback(channel, part_send, opt.jo_callback, id);
+ }
if (channel_send(channel, part_send, text, fun) == OK
&& opt.jo_callback == NULL)
}
/*
- * "ch_sendexpr()" function
+ * common for "ch_evalexpr()" and "ch_sendexpr()"
*/
static void
-f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
+ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
{
char_u *text;
typval_T *listtv;
ch_mode = channel_get_mode(channel, part_send);
if (ch_mode == MODE_RAW || ch_mode == MODE_NL)
{
- EMSG(_("E912: cannot use ch_sendexpr() with a raw or nl channel"));
+ EMSG(_("E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"));
return;
}
if (text == NULL)
return;
- channel = send_common(argvars, text, id, "sendexpr", &part_read);
+ channel = send_common(argvars, text, id, eval,
+ eval ? "ch_evalexpr" : "ch_sendexpr", &part_read);
vim_free(text);
- if (channel != NULL)
+ if (channel != NULL && eval)
{
/* TODO: timeout from options */
timeout = channel_get_timeout(channel, part_read);
}
/*
- * "ch_sendraw()" function
+ * "ch_evalexpr()" function
*/
static void
-f_ch_sendraw(typval_T *argvars, typval_T *rettv)
+f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
+{
+ ch_expr_common(argvars, rettv, TRUE);
+}
+
+/*
+ * "ch_sendexpr()" function
+ */
+ static void
+f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
+{
+ ch_expr_common(argvars, rettv, FALSE);
+}
+
+/*
+ * common for "ch_evalraw()" and "ch_sendraw()"
+ */
+ static void
+ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
{
char_u buf[NUMBUFLEN];
char_u *text;
rettv->vval.v_string = NULL;
text = get_tv_string_buf(&argvars[1], buf);
- channel = send_common(argvars, text, 0, "sendraw", &part_read);
- if (channel != NULL)
+ channel = send_common(argvars, text, 0, eval,
+ eval ? "ch_evalraw" : "ch_sendraw", &part_read);
+ if (channel != NULL && eval)
{
/* TODO: timeout from options */
timeout = channel_get_timeout(channel, part_read);
}
}
+/*
+ * "ch_evalraw()" function
+ */
+ static void
+f_ch_evalraw(typval_T *argvars, typval_T *rettv)
+{
+ ch_raw_common(argvars, rettv, TRUE);
+}
+
+/*
+ * "ch_sendraw()" function
+ */
+ static void
+f_ch_sendraw(typval_T *argvars, typval_T *rettv)
+{
+ ch_raw_common(argvars, rettv, FALSE);
+}
+
/*
* "ch_setoptions()" function
*/
endif
" Simple string request and reply.
- call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
+ call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
" Request that triggers sending two ex commands. These will usually be
" handled before getting the response, but it's not guaranteed, thus wait a
" tiny bit for the commands to get executed.
- call assert_equal('ok', ch_sendexpr(handle, 'make change'))
+ call assert_equal('ok', ch_evalexpr(handle, 'make change'))
sleep 10m
call assert_equal('added1', getline(line('$') - 1))
call assert_equal('added2', getline('$'))
- call assert_equal('ok', ch_sendexpr(handle, 'do normal'))
+ call assert_equal('ok', ch_evalexpr(handle, 'do normal'))
sleep 10m
call assert_equal('added more', getline('$'))
call ch_setoptions(handle, {'callback': ''})
" Send an eval request that works.
- call assert_equal('ok', ch_sendexpr(handle, 'eval-works'))
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-works'))
sleep 10m
- call assert_equal([-1, 'foo123'], ch_sendexpr(handle, 'eval-result'))
+ call assert_equal([-1, 'foo123'], ch_evalexpr(handle, 'eval-result'))
" Send an eval request that fails.
- call assert_equal('ok', ch_sendexpr(handle, 'eval-fails'))
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-fails'))
sleep 10m
- call assert_equal([-2, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
+ call assert_equal([-2, 'ERROR'], ch_evalexpr(handle, 'eval-result'))
" Send an eval request that works but can't be encoded.
- call assert_equal('ok', ch_sendexpr(handle, 'eval-error'))
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-error'))
sleep 10m
- call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
+ call assert_equal([-3, 'ERROR'], ch_evalexpr(handle, 'eval-result'))
" Send a bad eval request. There will be no response.
- call assert_equal('ok', ch_sendexpr(handle, 'eval-bad'))
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-bad'))
sleep 10m
- call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
+ call assert_equal([-3, 'ERROR'], ch_evalexpr(handle, 'eval-result'))
" Send an expr request
- call assert_equal('ok', ch_sendexpr(handle, 'an expr'))
+ call assert_equal('ok', ch_evalexpr(handle, 'an expr'))
sleep 10m
call assert_equal('one', getline(line('$') - 2))
call assert_equal('two', getline(line('$') - 1))
call assert_equal('three', getline('$'))
" Request a redraw, we don't check for the effect.
- call assert_equal('ok', ch_sendexpr(handle, 'redraw'))
- call assert_equal('ok', ch_sendexpr(handle, 'redraw!'))
+ call assert_equal('ok', ch_evalexpr(handle, 'redraw'))
+ call assert_equal('ok', ch_evalexpr(handle, 'redraw!'))
- call assert_equal('ok', ch_sendexpr(handle, 'empty-request'))
+ call assert_equal('ok', ch_evalexpr(handle, 'empty-request'))
" Reading while there is nothing available.
call assert_equal(v:none, ch_read(handle, {'timeout': 0}))
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})
+ call ch_sendexpr(handle, 'wait a bit')
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.
- call ch_sendexpr(handle, '!quit!', {'callback': 0})
+ call ch_sendexpr(handle, '!quit!')
endfunc
func Test_communicate()
return
endif
- call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
+ call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
let newhandle = ch_open('localhost:' . a:port, s:chopt)
if ch_status(newhandle) == "fail"
call assert_false(1, "Can't open second channel")
return
endif
- call assert_equal('got it', ch_sendexpr(newhandle, 'hello!'))
- call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
+ call assert_equal('got it', ch_evalexpr(newhandle, 'hello!'))
+ call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
call ch_close(handle)
- call assert_equal('got it', ch_sendexpr(newhandle, 'hello!'))
+ call assert_equal('got it', ch_evalexpr(newhandle, 'hello!'))
call ch_close(newhandle)
endfunc
return
endif
- call ch_sendexpr(handle, '!crash!')
+ call ch_evalexpr(handle, '!crash!')
sleep 10m
endfunc
endif
" Test that it works while waiting on a numbered message.
- call assert_equal('ok', ch_sendexpr(handle, 'call me'))
+ call assert_equal('ok', ch_evalexpr(handle, 'call me'))
sleep 10m
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', {'callback': 0})
+ call ch_sendexpr(handle, 'call me again')
sleep 10m
call assert_equal('we did call you', s:reply)
endfunc
call assert_equal("run", job_status(job))
try
let handle = job_getchannel(job)
- call ch_sendraw(handle, "echo something\n", {'callback': 0})
+ call ch_sendraw(handle, "echo something\n")
let msg = ch_readraw(handle)
call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
- call ch_sendraw(handle, "double this\n", {'callback': 0})
+ call ch_sendraw(handle, "double this\n")
let msg = ch_readraw(handle)
call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
- let reply = ch_sendraw(handle, "quit\n")
+ let reply = ch_evalraw(handle, "quit\n")
call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g'))
finally
call job_stop(job)
call assert_equal("run", job_status(job))
try
let handle = job_getchannel(job)
- call ch_sendraw(handle, "echo something\n", {'callback': 0})
+ call ch_sendraw(handle, "echo something\n")
call assert_equal("something", ch_readraw(handle))
- call ch_sendraw(handle, "double this\n", {'callback': 0})
+ call ch_sendraw(handle, "double this\n")
call assert_equal("this", ch_readraw(handle))
call assert_equal("AND this", ch_readraw(handle))
- let reply = ch_sendraw(handle, "quit\n")
+ let reply = ch_evalraw(handle, "quit\n")
call assert_equal("Goodbye!", reply)
finally
call job_stop(job)
endtry
endfunc
+func Test_pipe_to_buffer()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_to_buffer()')
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out-io': 'buffer', 'out-name': 'pipe-output'})
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo line one\n")
+ call ch_sendraw(handle, "echo line two\n")
+ call ch_sendraw(handle, "double this\n")
+ call ch_sendraw(handle, "quit\n")
+ sp pipe-output
+ for i in range(100)
+ sleep 10m
+ if line('$') >= 6
+ break
+ endif
+ endfor
+ call assert_equal(['Reading from channel output...', 'line one', 'line two', 'this', 'AND this', 'Goodbye!'], getline(1, '$'))
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
""""""""""
let s:unletResponse = ''
call assert_false(1, "Can't open channel")
return
endif
- call assert_equal('got it', ch_sendexpr(channel, 'hello!'))
+ call assert_equal('got it', ch_evalexpr(channel, 'hello!'))
call ch_close(channel)
endfunc
return
endif
- call assert_equal('ok', ch_sendexpr(handle, 'call-func'))
+ call assert_equal('ok', ch_evalexpr(handle, 'call-func'))
sleep 20m
call assert_equal([1, 2, 3], s:call_ret)
endfunc
endif
call ch_setoptions(handle, {'close-cb': 'MyCloseCb'})
- call assert_equal('', ch_sendexpr(handle, 'close me'))
+ call assert_equal('', ch_evalexpr(handle, 'close me'))
sleep 20m
call assert_equal('closed', s:ch_close_ret)
endfunc
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1435,
/**/
1434,
/**/