diff runtime/doc/channel.txt @ 8061:abd64cf67bcf

commit https://github.com/vim/vim/commit/38a55639d603823efcf2d2fdf542dbffdeb60b75 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Feb 15 22:07:32 2016 +0100 Update runtime files.
author Christian Brabandt <cb@256bit.org>
date Mon, 15 Feb 2016 22:45:05 +0100
parents 78106b0f2c56
children 18a3f0f05244
line wrap: on
line diff
--- a/runtime/doc/channel.txt
+++ b/runtime/doc/channel.txt
@@ -1,4 +1,4 @@
-*channel.txt*      For Vim version 7.4.  Last change: 2016 Feb 07
+*channel.txt*      For Vim version 7.4.  Last change: 2016 Feb 15
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -9,36 +9,72 @@
 DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT  DRAFT
 
 Vim uses channels to communicate with other processes.
-A channel uses a socket.				*socket-interface*
+A channel uses a socket or pipes			*socket-interface*
+Jobs can be used to start processes and communicate with them.
 
 Vim current supports up to 10 simultaneous channels.
 The Netbeans interface also uses a channel. |netbeans|
 
-1. Demo					|channel-demo|
-2. Opening a channel			|channel-open|
-3. Using a JSON or JS channel		|channel-use|
-4. Vim commands				|channel-commands|
-5. Using a raw channel			|channel-use|
-6. Job control				|job-control|
+1. Overview				|job-channel-overview|
+2. Channel demo				|channel-demo|
+3. Opening a channel			|channel-open|
+4. Using a JSON or JS channel		|channel-use|
+5. Channel commands			|channel-commands|
+6. Using a RAW or NL channel		|channel-raw|
+7. More channel functions		|channel-more|
+8. Starting a job with a channel	|job-start|
+9. Starting a job without a channel	|job-start-nochannel|
+10. Job options				|job-options|
+11. Controlling a job			|job-control|
 
 {Vi does not have any of these features}
-{only available when compiled with the |+channel| feature}
+{only when compiled with the |+channel| feature for channel stuff}
+{only when compiled with the |+job| feature for job stuff}
 
 ==============================================================================
-1. Demo							*channel-demo*
+1. Overview						*job-channel-overview*
+
+There are four main types of jobs:
+1. A deamon, serving several Vim instances.
+   Vim connects to it with a socket.
+2. One job working with one Vim instance, asynchronously.
+   Uses a socket or pipes.
+3. A job performing some work for a short time, asynchronously.
+   Uses a socket or pipes.
+4. Running a filter, synchronously.
+   Uses pipes.
+
+For when using sockets See |job-start|, |job-may-start| and |channel-open|.
+For 2 and 3, one or more jobs using pipes, see |job-start|.
+For 4 use the ":{range}!cmd" command, see |filter|.
+
+Over the socket and pipes these protocols are available:
+RAW	nothing known, Vim cannot tell where a message ends
+NL	every message ends in a NL (newline) character
+JSON	JSON encoding |json_encode()|
+JS	JavaScript style JSON-like encoding |js_encode()|
+
+Common combination are:
+- Using a job connected through pipes in NL mode.  E.g., to run a style
+  checker and receive errors and warnings.
+- Using a deamon, connecting over a socket in JSON mode.  E.g. to lookup
+  crosss-refrences in a database.
+
+==============================================================================
+2. Channel demo						*channel-demo*
 
 This requires Python.  The demo program can be found in
 $VIMRUNTIME/tools/demoserver.py
 Run it in one terminal.  We will call this T1.
 
 Run Vim in another terminal.  Connect to the demo server with: >
-	let handle = ch_open('localhost:8765')
+	let channel = ch_open('localhost:8765')
 
 In T1 you should see:
 	=== socket opened === ~
 
 You can now send a message to the server: >
-	echo ch_sendexpr(handle, 'hello!')
+	echo ch_sendexpr(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:
@@ -54,47 +90,63 @@ And you should see the message in Vim. Y
 	["normal","w"] ~
 
 To handle asynchronous communication a callback needs to be used: >
-	func MyHandler(handle, msg)
+	func MyHandler(channel, msg)
 	  echo "from the handler: " . a:msg
 	endfunc
-	call ch_sendexpr(handle, 'hello!', "MyHandler")
+	call ch_sendexpr(channel, 'hello!', "MyHandler")
+Vim will not wait for a response.  Now the server can send the response later
+and MyHandler will be invoked.
 
 Instead of giving a callback with every send call, it can also be specified
 when opening the channel: >
-	call ch_close(handle)
-	let handle = ch_open('localhost:8765', {'callback': "MyHandler"})
-	call ch_sendexpr(handle, 'hello!', 0)
+	call ch_close(channel)
+	let channel = ch_open('localhost:8765', {'callback': "MyHandler"})
+	call ch_sendexpr(channel, 'hello!', 0)
 
 ==============================================================================
-2. Opening a channel					*channel-open*
+3. Opening a channel					*channel-open*
 
 To open a channel: >
-    let handle = ch_open({address} [, {argdict}])
+    let channel = ch_open({address} [, {options}])
+
+Use |ch_status()| to see if the channel could be opened.
 
 {address} has the form "hostname:port".  E.g., "localhost:8765".
 
-{argdict} is a dictionary with optional entries:
+{options} is a dictionary with optional entries:
 
 "mode" can be:						*channel-mode*
 	"json" - Use JSON, see below; most convenient way. Default.
 	"js"   - Use JavaScript encoding, more efficient than JSON.
+	"nl"   - Use messages that end in a NL character
 	"raw"  - Use raw messages
 
 							*channel-callback*
-"callback" is a function that is called when a message is received that is not
-handled otherwise.  It gets two arguments: the channel handle and the received
-message. Example: >
-	func Handle(handle, msg)
+"callback"	A function that is called when a message is received that is
+		not handled otherwise.  It gets two arguments: the channel
+		handle and the received message. Example: >
+	func Handle(channel, msg)
 	  echo 'Received: ' . a:msg
 	endfunc
-	let handle = ch_open("localhost:8765", {"callback": "Handle"})
+	let channel = ch_open("localhost:8765", {"callback": "Handle"})
+<
+		TODO:
+"err-cb"	A function like "callback" but used for stderr.  Only for when
+		the channel uses pipes.
 
-"waittime" is the time to wait for the connection to be made in milliseconds.
-The default is zero, don't wait, which is useful if the server is supposed to
-be running already.  A negative number waits forever.
+		TODO:
+"close-cb"	A function that is called when the channel gets closed, other
+		than by calling ch_close().  It should be defined like this: >
+	func MyCloseHandler(channel)
 
-"timeout" is the time to wait for a request when blocking, using
-ch_sendexpr().  Again in milliseconds.  The default is 2000 (2 seconds).
+"waittime"	The time to wait for the connection to be made in
+		milliseconds.  The default is zero, don't wait, which is
+		useful if the server is supposed to be running already.  A
+		negative number waits forever.
+
+"timeout"	The time to wait for a request when blocking, using
+		ch_sendexpr().  Again in milliseconds.  The default is 2000 (2
+		seconds).
 
 When "mode" is "json" or "js" the "msg" argument is the body of the received
 message, converted to Vim types.
@@ -103,18 +155,26 @@ When "mode" is "raw" the "msg" argument 
 When "mode" is "json" or "js" the "callback" is optional.  When omitted it is
 only possible to receive a message after sending one.
 
-The handler can be added or changed later: >
-    call ch_setcallback(handle, {callback})
+TODO:
+To change the channel options after opening it use ch_setoptions().  The
+arguments are similar to what is passed to ch_open(), but "waittime" cannot be
+given, since that only applies to opening the channel.
+
+The handler can be added or changed: >
+    call ch_setoptions(channel, {'callback': callback})
 When "callback" is empty (zero or an empty string) the handler is removed.
-NOT IMPLEMENTED YET
 
-The timeout can be changed later: >
-    call ch_settimeout(handle, {msec})
-NOT IMPLEMENTED YET
+The timeout can be changed: >
+    call ch_setoptions(channel, {'timeout': msec})
+<
 							  *E906*
 Once done with the channel, disconnect it like this: >
-    call ch_close(handle)
+    call ch_close(channel)
+When a socket is used this will close the socket for both directions.  When
+pipes are used (stdin/stdout/stderr) they are all closed.  This might not be
+what you want!  Stopping the job with job_stop() might be better.
 
+TODO:
 Currently up to 10 channels can be in use at the same time. *E897*
 
 When the channel can't be opened you will get an error message.  There is a
@@ -126,21 +186,26 @@ If there is an error reading or writing 
 *E896* *E630* *E631* 
 
 ==============================================================================
-3. Using a JSON or JS channel					*channel-use*
+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(handle, {expr})
+    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
-JavaScript encoding.  See |jsencode()| for the difference.
+JavaScript encoding.  See |js_encode()| for the difference.
 
 To send a message, without handling a response: >
-    call ch_sendexpr(handle, {expr}, 0)
+    call ch_sendexpr(channel, {expr}, 0)
 
 To send a message and letting the response handled by a specific function,
 asynchronously: >
-    call ch_sendexpr(handle, {expr}, {callback})
+    call ch_sendexpr(channel, {expr}, {callback})
+
+Vim will match the response with the request using the message ID.  Once the
+response is received the callback will be invoked.  Further responses with the
+same ID will be ignored.  If your server sends back multiple responses you
+need to send them with ID zero, they will be passed to the channel callback.
 
 The {expr} is converted to JSON and wrapped in an array.  An example of the
 message that the receiver will get when {expr} is the string "hello":
@@ -175,9 +240,7 @@ It is also possible to use ch_sendraw() 
 is then completely responsible for correct encoding and decoding.
 
 ==============================================================================
-4. Vim commands						*channel-commands*
-
-PARTLY IMPLEMENTED: only "ex" and "normal" work
+5. Channel commands					*channel-commands*
 
 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.
@@ -251,43 +314,202 @@ Example:
 	["expr","setline('$', ['one', 'two', 'three'])"] ~
 
 ==============================================================================
-5. Using a raw channel					*channel-raw*
+6. Using a RAW or NL channel				*channel-raw*
 
 If {mode} is "raw" then a message can be send like this: >
-    let response = ch_sendraw(handle, {string})
+    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.
+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
+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.
+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(handle, {string}, 0)
+    call ch_sendraw(channel, {string}, 0)
 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(handle, {string}, {callback})
+    call ch_sendraw(channel, {string}, {callback})
 
-This {string} can also be JSON, use |jsonencode()| to create it and
-|jsondecode()| to handle a received JSON message.
+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.
 
 ==============================================================================
-6. Job control						*job-control*
+7. More channel functions				*channel-more*
+
+To obtain the status of a channel: ch_status(channel).  The possible results
+are:
+	"fail"		Failed to open the channel.
+	"open"		The channel can be used.
+	"closed"	The channel was closed.
+
+TODO:
+To objain the job associated with a channel: ch_getjob(channel)
 
-NOT IMPLEMENTED YET
+TODO:
+To read one message from a channel: >
+	let output = ch_read(channel)
+This uses the channel timeout.  To read without a timeout, just get any
+message that is available: >
+	let output = ch_read(channel, 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.
+
+To read all output from a RAW or NL channel that is available: >
+	let output = ch_readall(channel)
+To read the error output: >
+	let output = ch_readall(channel, "err")
+TODO: use channel timeout, no timeout or specify timeout?
+
+==============================================================================
+8. Starting a job with a channel			*job-start* *job*
+
+To start a job and open a channel for stdin/stdout/stderr: >
+    let job = job_start(command, {options})
+
+You can get the channel with: >
+    let channel = job_getchannel(job)
 
-To start another process: >
-    call startjob({command})
+The channel will use NL mode.  If you want another mode it's best to specify
+this in {options}.  When changing the mode later some text may have already
+been received and not parsed correctly.
+
+If the command produces a line of output that you want to deal with, specify
+a handler for stdout: >
+    let job = job_start(command, {"out-cb": "MyHandler"})
+The function will be called with the channel and a message. You would define
+it like this: >
+    func MyHandler(channel, msg)
+
+Without the handler you need to read the output with ch_read().
+
+The handler defined for "out-cb" will also receive stderr.  If you want to
+handle that separately, add an "err-cb" handler: >
+    let job = job_start(command, {"out-cb": "MyHandler",
+	    \			  "err-cb": "ErrHandler"})
 
-This does not wait for {command} to exit.
+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().
+
+There are several options you can use, see |job-options|.
+
+TODO:
+To run a job and read its output once it is done: >
+
+	let job = job_start({command}, {'exit-cb': 'MyHandler'})
+	func MyHandler(job, status)
+	  let channel = job_getchannel()
+	  let output = ch_readall(channel)
+	  " parse output
+	endfunc
+
+==============================================================================
+9. Starting a job without a channel			*job-start-nochannel*
+
+To start another process without creating a channel: >
+    let job = job_start(command, {"in-io": "null", "out-io": "null"})
+
+This starts {command} in the background, Vim does not wait for it to finish.
 
 TODO:
+When Vim sees that neither stdin, stdout or stderr are connected, no channel
+will be created.  Often you will want to include redirection in the command to
+avoid it getting stuck.
 
-    let handle = startjob({command}, 's')            # uses stdin/stdout
-    let handle = startjob({command}, '', {address})  # uses socket
-    let handle = startjob({command}, 'd', {address}) # start if connect fails
+There are several options you can use, see |job-options|.
+
+TODO:							*job-may-start*
+To start a job only when connecting to an address does not work use
+job_maystart('command', {address}, {options}), For Example: >
+	let job = job_maystart(command, address, {"waittime": 1000})
+	let channel = job_gethandle(job)
+
+This comes down to: >
+	let channel = ch_open(address, {"waittime": 0})
+	if ch_status(channel) == "fail"
+	  let job = job_start(command)
+	  let channel = ch_open(address, {"waittime": 1000})
+	  call job_sethandle(channel)
+	endif
+Note that the specified waittime applies to when the job has been started.
+This gives the job some time to make the port available.
+
+==============================================================================
+10. Job options						*job-options*
+
+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*
+"out-cb": handler	Callback for when there is something to read on
+			stdout.
+TODO:						*job-err-cb*
+"err-cb": handler	Callback for when there is something to read on
+			stderr.  Defaults to the same callback as "out-cb".
+TODO:						*job-close-cb*
+"close-cb": handler	Callback for when the channel is closed.  Same as
+			"close-cb" on ch_open().
+TODO:						*job-exit-cb*
+"exit-cb": handler	Callback for when the job ends.  The arguments are the
+			job and the exit status.
+TODO:						*job-killonexit*
+"killonexit": 1		Stop the job when Vim exits.
+"killonexit": 0		Do not stop the job when Vim exits.
+			The default is 1.
+TODO:						*job-term*
+"term": "open"		Start a terminal and connect the job
+			stdin/stdout/stderr to it.
+
+TODO:						*job-in-io*
+"in-io": "null"		disconnect stdin
+"in-io": "pipe"		stdin is connected to the channel (default)
+"in-io": "file"		stdin reads from a file
+"in-file": "/path/file"	the file to read from
+
+TODO:						*job-out-io*
+"out-io": "null"	disconnect stdout
+"out-io": "pipe"	stdout is connected to the channel (default)
+"out-io": "file"	stdout writes to a file
+"out-file": "/path/file" the file to write to
+"out-io": "buffer" 	stdout appends to a buffer
+"out-buffer": "name" 	buffer to append to
+
+TODO:						*job-err-io*
+"err-io": "out"		same 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
+"err-file": "/path/file" the file to write to
+"err-io": "buffer" 	stderr appends to a buffer
+"err-buffer": "name" 	buffer to append to
+
+TODO: more options
+
+
+==============================================================================
+11. Controlling a job					*job-control*
+
+To get the status of a job: >
+	echo job_status(job)
+
+To make a job stop running: >
+	job_stop(job)
+
+This is the normal way to end a job. On Unix it sends a SIGTERM to the job.
+It is possible to use other ways to stop the job, or even send arbitrary
+signals.  E.g. to force a job to stop, "kill it": >
+	job_stop(job, "kill")
+
+For more options see |job_stop()|.
 
 
  vim:tw=78:ts=8:ft=help:norl: