patch 7.4.1191
Problem: The channel feature isn't working yet.
Solution: Add the connect(), disconnect(), sendexpr() and sendraw()
functions. Add initial documentation. Add a demo server.
This commit is contained in:
218
runtime/doc/channel.txt
Normal file
218
runtime/doc/channel.txt
Normal file
@ -0,0 +1,218 @@
|
||||
*channel.txt* For Vim version 7.4. Last change: 2016 Jan 28
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
|
||||
|
||||
Inter-process communication *channel*
|
||||
|
||||
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*
|
||||
|
||||
Vim current supports up to 10 simultanious channels.
|
||||
The Netbeans interface also uses a channel. |netbeans|
|
||||
|
||||
1. Demo |channel-demo|
|
||||
2. Opening a channel |channel-open|
|
||||
3. Using a JSON channel |channel-use|
|
||||
4. Vim commands |channel-commands|
|
||||
5. Using a raw channel |channel-use|
|
||||
6. Job control |job-control|
|
||||
|
||||
{Vi does not have any of these features}
|
||||
{only available when compiled with the |+channel| feature}
|
||||
|
||||
==============================================================================
|
||||
1. 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 = connect('localhost:8765', 'json')
|
||||
|
||||
In T1 you should see:
|
||||
=== socket opened === ~
|
||||
|
||||
You can now send a message to the server: >
|
||||
echo sendexpr(handle, '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:
|
||||
[1,"hello!"] ~
|
||||
And the response is:
|
||||
[1,"got it"] ~
|
||||
The number will increase every time you send a message.
|
||||
|
||||
The server can send a command to Vim. Type this on T1 (literally, including
|
||||
the quotes): >
|
||||
NOT IMPLEMENTED YET
|
||||
["ex","echo 'hi there'"]
|
||||
And you should see the message in Vim.
|
||||
|
||||
To handle asynchronous communication a callback needs to be used: >
|
||||
func MyHandler(handle, msg)
|
||||
echo "from the handler: " . a:msg
|
||||
endfunc
|
||||
call sendexpr(handle, 'hello!', "MyHandler")
|
||||
|
||||
Instead of giving a callback with every send call, it can also be specified
|
||||
when opening the channel: >
|
||||
call disconnect(handle)
|
||||
let handle = connect('localhost:8765', 'json', "MyHandler")
|
||||
call sendexpr(handle, 'hello!', 0)
|
||||
|
||||
==============================================================================
|
||||
2. Opening a channel *channel-open*
|
||||
|
||||
To open a channel:
|
||||
let handle = connect({address}, {mode}, {callback})
|
||||
|
||||
{address} has the form "hostname:port". E.g., "localhost:8765".
|
||||
|
||||
{mode} can be: *channel-mode*
|
||||
"json" - Use JSON, see below; most convenient way
|
||||
"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)
|
||||
echo 'Received: ' . a:msg
|
||||
endfunc
|
||||
let handle = connect("localhost:8765", 'json', "Handle")
|
||||
|
||||
When {mode} is "json" the "msg" argument is the body of the received message,
|
||||
converted to Vim types.
|
||||
When {mode} is "raw" the "msg" argument is the whole message as a string.
|
||||
|
||||
When {mode} is "json" 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 sethandler(handle, {callback})
|
||||
When {callback} is empty (zero or an empty string) the handler is removed.
|
||||
|
||||
Once done with the channel, disconnect it like this: >
|
||||
call disconnect(handle)
|
||||
|
||||
==============================================================================
|
||||
3. Using a JSON channel *channel-use*
|
||||
|
||||
If {mode} is "json" then a message can be sent synchronously like this: >
|
||||
let response = sendexpr(handle, {expr})
|
||||
This awaits a response from the other side.
|
||||
|
||||
To send a message, without handling a response: >
|
||||
call sendexpr(handle, {expr}, 0)
|
||||
|
||||
To send a message and letting the response handled by a specific function,
|
||||
asynchronously: >
|
||||
call sendexpr(handle, {expr}, {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":
|
||||
[12,"hello"] ~
|
||||
|
||||
The format of the JSON sent is:
|
||||
[{number},{expr}]
|
||||
|
||||
In which {number} is different every time. It must be used in the response
|
||||
(if any):
|
||||
|
||||
[{number},{response}]
|
||||
|
||||
This way Vim knows which sent message matches with which received message and
|
||||
can call the right handler. Also when the messages arrive out of order.
|
||||
|
||||
The sender must always send valid JSON to Vim. Vim can check for the end of
|
||||
the message by parsing the JSON. It will only accept the message if the end
|
||||
was received.
|
||||
|
||||
When the process wants to send a message to Vim without first receiving a
|
||||
message, it must use the number zero:
|
||||
[0,{response}]
|
||||
|
||||
Then channel handler will then get {response} converted to Vim types. If the
|
||||
channel does not have a handler the message is dropped.
|
||||
|
||||
On read error or disconnect() the string "DETACH" is sent, if still possible.
|
||||
The channel will then be inactive.
|
||||
|
||||
==============================================================================
|
||||
4. Vim commands *channel-commands*
|
||||
|
||||
NOT IMPLEMENTED YET
|
||||
|
||||
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:
|
||||
["ex", {Ex command}]
|
||||
["normal", {Normal mode command}]
|
||||
["eval", {number}, {expression}]
|
||||
["expr", {expression}]
|
||||
|
||||
With all of these: Be careful what these commands do! You can easily
|
||||
interfere with what the user is doing. To avoid trouble use |mode()| to check
|
||||
that the editor is in the expected state. E.g., to send keys that must be
|
||||
inserted as text, not executed as a command: >
|
||||
["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"]
|
||||
|
||||
The "ex" command is executed as any Ex command. There is no response for
|
||||
completion or error. You could use functions in an |autoload| script.
|
||||
You can also invoke |feedkeys()| to insert anything.
|
||||
|
||||
The "normal" command is executed like with |:normal|.
|
||||
|
||||
The "eval" command will result in sending back the result of the expression:
|
||||
[{number}, {result}]
|
||||
Here {number} is the same as what was in the request.
|
||||
|
||||
The "expr" command is similar, but does not send back any response.
|
||||
Example:
|
||||
["expr","setline('$', ['one', 'two', 'three'])"]
|
||||
|
||||
==============================================================================
|
||||
5. Using a raw channel *channel-raw*
|
||||
|
||||
If {mode} is "raw" then a message can be send like this: >
|
||||
let response = sendraw(handle, {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.
|
||||
|
||||
To send a message, without expecting a response: >
|
||||
call sendraw(handle, {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 sendraw(handle, {string}, {callback})
|
||||
|
||||
This {string} can also be JSON, use |jsonencode()| to create it and
|
||||
|jsondecode()| to handle a received JSON message.
|
||||
|
||||
==============================================================================
|
||||
6. Job control *job-control*
|
||||
|
||||
NOT IMPLEMENTED YET
|
||||
|
||||
To start another process: >
|
||||
call startjob({command})
|
||||
|
||||
This does not wait for {command} to exit.
|
||||
|
||||
TODO:
|
||||
|
||||
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
|
||||
|
||||
|
||||
vim:tw=78:ts=8:ft=help:norl:
|
||||
Reference in New Issue
Block a user