|
| 1 | +*channel.txt* For Vim version 7.4. Last change: 2016 Jan 28 |
| 2 | + |
| 3 | + |
| 4 | + VIM REFERENCE MANUAL by Bram Moolenaar |
| 5 | + |
| 6 | + |
| 7 | + Inter-process communication *channel* |
| 8 | + |
| 9 | +DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT |
| 10 | + |
| 11 | +Vim uses channels to communicate with other processes. |
| 12 | +A channel uses a socket. *socket-interface* |
| 13 | + |
| 14 | +Vim current supports up to 10 simultanious channels. |
| 15 | +The Netbeans interface also uses a channel. |netbeans| |
| 16 | + |
| 17 | +1. Demo |channel-demo| |
| 18 | +2. Opening a channel |channel-open| |
| 19 | +3. Using a JSON channel |channel-use| |
| 20 | +4. Vim commands |channel-commands| |
| 21 | +5. Using a raw channel |channel-use| |
| 22 | +6. Job control |job-control| |
| 23 | + |
| 24 | +{Vi does not have any of these features} |
| 25 | +{only available when compiled with the |+channel| feature} |
| 26 | + |
| 27 | +============================================================================== |
| 28 | +1. Demo *channel-demo* |
| 29 | + |
| 30 | +This requires Python. The demo program can be found in |
| 31 | +$VIMRUNTIME/tools/demoserver.py |
| 32 | +Run it in one terminal. We will call this T1. |
| 33 | + |
| 34 | +Run Vim in another terminal. Connect to the demo server with: > |
| 35 | + let handle = connect('localhost:8765', 'json') |
| 36 | +
|
| 37 | +In T1 you should see: |
| 38 | + === socket opened === ~ |
| 39 | + |
| 40 | +You can now send a message to the server: > |
| 41 | + echo sendexpr(handle, 'hello!') |
| 42 | +
|
| 43 | +The message is received in T1 and a response is sent back to Vim. |
| 44 | +You can see the raw messages in T1. What Vim sends is: |
| 45 | + [1,"hello!"] ~ |
| 46 | +And the response is: |
| 47 | + [1,"got it"] ~ |
| 48 | +The number will increase every time you send a message. |
| 49 | + |
| 50 | +The server can send a command to Vim. Type this on T1 (literally, including |
| 51 | +the quotes): > |
| 52 | + NOT IMPLEMENTED YET |
| 53 | + ["ex","echo 'hi there'"] |
| 54 | +And you should see the message in Vim. |
| 55 | + |
| 56 | +To handle asynchronous communication a callback needs to be used: > |
| 57 | + func MyHandler(handle, msg) |
| 58 | + echo "from the handler: " . a:msg |
| 59 | + endfunc |
| 60 | + call sendexpr(handle, 'hello!', "MyHandler") |
| 61 | +
|
| 62 | +Instead of giving a callback with every send call, it can also be specified |
| 63 | +when opening the channel: > |
| 64 | + call disconnect(handle) |
| 65 | + let handle = connect('localhost:8765', 'json', "MyHandler") |
| 66 | + call sendexpr(handle, 'hello!', 0) |
| 67 | +
|
| 68 | +============================================================================== |
| 69 | +2. Opening a channel *channel-open* |
| 70 | + |
| 71 | +To open a channel: |
| 72 | + let handle = connect({address}, {mode}, {callback}) |
| 73 | + |
| 74 | +{address} has the form "hostname:port". E.g., "localhost:8765". |
| 75 | + |
| 76 | +{mode} can be: *channel-mode* |
| 77 | + "json" - Use JSON, see below; most convenient way |
| 78 | + "raw" - Use raw messages |
| 79 | + |
| 80 | + *channel-callback* |
| 81 | +{callback} is a function that is called when a message is received that is not |
| 82 | +handled otherwise. It gets two arguments: the channel handle and the received |
| 83 | +message. Example: > |
| 84 | + func Handle(handle, msg) |
| 85 | + echo 'Received: ' . a:msg |
| 86 | + endfunc |
| 87 | + let handle = connect("localhost:8765", 'json', "Handle") |
| 88 | +
|
| 89 | +When {mode} is "json" the "msg" argument is the body of the received message, |
| 90 | +converted to Vim types. |
| 91 | +When {mode} is "raw" the "msg" argument is the whole message as a string. |
| 92 | + |
| 93 | +When {mode} is "json" the {callback} is optional. When omitted it is only |
| 94 | +possible to receive a message after sending one. |
| 95 | + |
| 96 | +The handler can be added or changed later: > |
| 97 | + call sethandler(handle, {callback}) |
| 98 | +When {callback} is empty (zero or an empty string) the handler is removed. |
| 99 | + |
| 100 | +Once done with the channel, disconnect it like this: > |
| 101 | + call disconnect(handle) |
| 102 | +
|
| 103 | +============================================================================== |
| 104 | +3. Using a JSON channel *channel-use* |
| 105 | + |
| 106 | +If {mode} is "json" then a message can be sent synchronously like this: > |
| 107 | + let response = sendexpr(handle, {expr}) |
| 108 | +This awaits a response from the other side. |
| 109 | + |
| 110 | +To send a message, without handling a response: > |
| 111 | + call sendexpr(handle, {expr}, 0) |
| 112 | +
|
| 113 | +To send a message and letting the response handled by a specific function, |
| 114 | +asynchronously: > |
| 115 | + call sendexpr(handle, {expr}, {callback}) |
| 116 | +
|
| 117 | +The {expr} is converted to JSON and wrapped in an array. An example of the |
| 118 | +message that the receiver will get when {expr} is the string "hello": |
| 119 | + [12,"hello"] ~ |
| 120 | + |
| 121 | +The format of the JSON sent is: |
| 122 | + [{number},{expr}] |
| 123 | + |
| 124 | +In which {number} is different every time. It must be used in the response |
| 125 | +(if any): |
| 126 | + |
| 127 | + [{number},{response}] |
| 128 | + |
| 129 | +This way Vim knows which sent message matches with which received message and |
| 130 | +can call the right handler. Also when the messages arrive out of order. |
| 131 | + |
| 132 | +The sender must always send valid JSON to Vim. Vim can check for the end of |
| 133 | +the message by parsing the JSON. It will only accept the message if the end |
| 134 | +was received. |
| 135 | + |
| 136 | +When the process wants to send a message to Vim without first receiving a |
| 137 | +message, it must use the number zero: |
| 138 | + [0,{response}] |
| 139 | + |
| 140 | +Then channel handler will then get {response} converted to Vim types. If the |
| 141 | +channel does not have a handler the message is dropped. |
| 142 | + |
| 143 | +On read error or disconnect() the string "DETACH" is sent, if still possible. |
| 144 | +The channel will then be inactive. |
| 145 | + |
| 146 | +============================================================================== |
| 147 | +4. Vim commands *channel-commands* |
| 148 | + |
| 149 | +NOT IMPLEMENTED YET |
| 150 | + |
| 151 | +With a "json" channel the process can send commands to Vim that will be |
| 152 | +handled by Vim internally, it does not require a handler for the channel. |
| 153 | + |
| 154 | +Possible commands are: |
| 155 | + ["ex", {Ex command}] |
| 156 | + ["normal", {Normal mode command}] |
| 157 | + ["eval", {number}, {expression}] |
| 158 | + ["expr", {expression}] |
| 159 | + |
| 160 | +With all of these: Be careful what these commands do! You can easily |
| 161 | +interfere with what the user is doing. To avoid trouble use |mode()| to check |
| 162 | +that the editor is in the expected state. E.g., to send keys that must be |
| 163 | +inserted as text, not executed as a command: > |
| 164 | + ["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"] |
| 165 | +
|
| 166 | +The "ex" command is executed as any Ex command. There is no response for |
| 167 | +completion or error. You could use functions in an |autoload| script. |
| 168 | +You can also invoke |feedkeys()| to insert anything. |
| 169 | + |
| 170 | +The "normal" command is executed like with |:normal|. |
| 171 | + |
| 172 | +The "eval" command will result in sending back the result of the expression: |
| 173 | + [{number}, {result}] |
| 174 | +Here {number} is the same as what was in the request. |
| 175 | + |
| 176 | +The "expr" command is similar, but does not send back any response. |
| 177 | +Example: |
| 178 | + ["expr","setline('$', ['one', 'two', 'three'])"] |
| 179 | + |
| 180 | +============================================================================== |
| 181 | +5. Using a raw channel *channel-raw* |
| 182 | + |
| 183 | +If {mode} is "raw" then a message can be send like this: > |
| 184 | + let response = sendraw(handle, {string}) |
| 185 | +The {string} is sent as-is. The response will be what can be read from the |
| 186 | +channel right away. Since Vim doesn't know how to recognize the end of the |
| 187 | +message you need to take care of it yourself. |
| 188 | + |
| 189 | +To send a message, without expecting a response: > |
| 190 | + call sendraw(handle, {string}, 0) |
| 191 | +The process can send back a response, the channel handler will be called with |
| 192 | +it. |
| 193 | + |
| 194 | +To send a message and letting the response handled by a specific function, |
| 195 | +asynchronously: > |
| 196 | + call sendraw(handle, {string}, {callback}) |
| 197 | +
|
| 198 | +This {string} can also be JSON, use |jsonencode()| to create it and |
| 199 | +|jsondecode()| to handle a received JSON message. |
| 200 | + |
| 201 | +============================================================================== |
| 202 | +6. Job control *job-control* |
| 203 | + |
| 204 | +NOT IMPLEMENTED YET |
| 205 | + |
| 206 | +To start another process: > |
| 207 | + call startjob({command}) |
| 208 | +
|
| 209 | +This does not wait for {command} to exit. |
| 210 | + |
| 211 | +TODO: |
| 212 | + |
| 213 | + let handle = startjob({command}, 's') # uses stdin/stdout |
| 214 | + let handle = startjob({command}, '', {address}) # uses socket |
| 215 | + let handle = startjob({command}, 'd', {address}) # start if connect fails |
| 216 | + |
| 217 | + |
| 218 | + vim:tw=78:ts=8:ft=help:norl: |
0 commit comments