From e2ad64a61868c81387035d93b4a530213f50ee4c Mon Sep 17 00:00:00 2001 From: MURAOKA Taro Date: Fri, 29 Jan 2016 23:51:45 +0900 Subject: [PATCH] channel roughly translated --- doc/channel.jax | 223 ++++++++++++++++++++++++++++++++++++++++++++++++ en/channel.txt | 218 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 441 insertions(+) create mode 100644 doc/channel.jax create mode 100644 en/channel.txt diff --git a/doc/channel.jax b/doc/channel.jax new file mode 100644 index 000000000..af8b92bb7 --- /dev/null +++ b/doc/channel.jax @@ -0,0 +1,223 @@ +*channel.txt* For Vim バージョン 7.4. Last change: 2016 Jan 28 + + + VIMリファレンスマニュアル by Bram Moolenaar + + + プロセス間通信 *channel* + +ドラフト ドラフト ドラフト ドラフト ドラフト ドラフト ドラフト + +Vimは別のプロセスと通信するのにチャンネルを用います。 +チャンネルはソケットを用います。 *socket-interface* + +現在のところVimは同時に10個までのチャンネルをサポートします。 +Netbeansインターフェースもチャンネルを使っています。 |netbeans| + +1. デモ |channel-demo| +2. チャンネルを開く |channel-open| +3. JSONチャンネルを使う |channel-use| +4. Vimコマンド |channel-commands| +5. rawチャンネルを使う |channel-use| +6. ジョブ制御 |job-control| + +{Vi does not have any of these features} +{only available when compiled with the |+channel| feature} + +============================================================================== +1. デモ *channel-demo* + +デモにはPythonが必要です。でもプログラムは次の場所にあります。 +$VIMRUNTIME/tools/demoserver.py +それをあるターミナルで実行しましょう。そのターミナルをT1と呼びます。 + +次に別のターミナルでVimを実行します。そして以下のコマンドででもサーバーに接続 +します: > + let handle = connect('localhost:8765', 'json') + +T1の中に次のようなに表示されます: + === socket opened === ~ + +ついにサーバーにメッセージを送信できます: > + echo sendexpr(handle, 'hello!') + +このメッセージはT1で受信され、Vimには応答が送り返されます。 +T1ではVimが送った生のメッセージを確認できます: + [1,"hello!"] ~ +そしてレスポンスはこうなります: + [1,"got it"] ~ +この数値はメッセージを送るたびに増加していきます。 + +サーバーはVimにコマンドを送信できます。T1に於いて、次のように正確に(引用符を含 +めて文字通りに)タイプしてください: > + ま だ 実 装 さ れ て い ま せ ん + ["ex","echo 'hi there'"] +するとそのメッセージがVimに表示されます。 + +非同期通信を取り扱うためにはコールバック(以下ハンドラー)が必要です: > + func MyHandler(handle, msg) + echo "from the handler: " . a:msg + endfunc + call sendexpr(handle, 'hello!', "MyHandler") + +sendを呼ぶたびに毎回コールバックを指定する代わりに、チャンネルを開く際に指定す +ることもできます: > + call disconnect(handle) + let handle = connect('localhost:8765', 'json', "MyHandler") + call sendexpr(handle, 'hello!', 0) + +============================================================================== +2. チャンネルを開く *channel-open* + +チャンネルを開くには次のようにします: > + let handle = connect({address}, {mode}, {callback}) + +{address} は "ホスト名:ポート番号" の形式です。 例:"localhost:8765" + +{mode} でモード(通信フォーマット)を指定します: *channel-mode* + "json" - JSONを使う(詳しくは下記を参照。もっとも使いやすい方法) + "raw" - rawメッセージを使う + + *channel-callback* +{callback} はメッセージ受信時に他のハンドラーで扱われない時に呼ばれます。 +これはチャンネルのハンドルと、受信したメッセージの2つの引数を取ります。例: > + func Handle(handle, msg) + echo '受信した: ' . a:msg + endfunc + let handle = connect("localhost:8765", 'json', "Handle") + + +{mode} が "json" の時には、"msg" 引数は受信たメッセージの本文で、Vimの型に変換 +されています。 +一方 {mode} が "raw" の時には、 "msg" 引数はメッセージ全体を格納した文字列で +す。 + +{mode} が "json" の時には {callback} はオプションです。これを省略した場合、 +メッセージを1つ受信するにはメッセージを1つ送信する必要があります。 + +ハンドラーは後から追加したり、変更したりできます: > + call sethandler(handle, {callback}) +{callback} が空の場合 (一度も指定しないか、空文字列を指定した場合) ハンドラー +は削除されます。 + +チャンネルを使い終わったら、以下のように切断してください: > + call disconnect(handle) + +============================================================================== +3. JSONチャンネルを使う *channel-use* + +{mode} が "json" 場合は、以下のようにメッセージを同期的に送信できます: > + let response = sendexpr(handle, {expr}) +これは通信相手から応答があるまで待ち合わせます。 + +応答を処理する必要が無いのであれば、以下のように送れます: > + call sendexpr(handle, {expr}, 0) + +メッセージを送信し、応答を特別な関数で非同期的に処理する場合には、このようにし +ます: > + call sendexpr(handle, {expr}, {callback}) + +{expr} は JSON に変換され、配列で包まれます。{expr} として文字列 "hello" を送 +信した場合に、通信相手が受け取るメッセージの例は次のようになります: + [12,"hello"] ~ + +送信されるJSONのフォーマットはこのようになっています: + [{number},{expr}] + +{number} には毎回異なる値が入ります。これは応答(があるならば)、必ず使われま +す: + + [{number},{response}] + +このようにして、受信したメッセージがどの送信メッセージに対応するかを知ることが +でき、正しいハンドラーを呼び出すことができます。これによって応答メッセージの到 +着順序を気にしなくても良くなります。 + +送信側はかならず有効なJSONをVimへ送らなければなりません。VimはJSONとして解釈す +ることで、受信メッセージの終端をチェックします。終端を受信することが、 +メッセージを受理する唯一の方法です。 + +サーバープロセスがVimからのメッセージを受信すること無く、メッセージを送信する +には、数値に 0 を使う必要があります。 + [0,{response}] + +するとチャンネルのハンドラーが {response} をVimの方に変換したものを受け取るで +しょう。チャンネルにハンドラーが関連付けられていない場合には、メッセージは破棄 +されます。 + +読み込みエラーが発生した場合や |disconnect()| した場合には、可能であるなら文字 +列 "DETACH" が送られます。チャンネルはそれから非アクティブになります。 + +============================================================================== +4. Vimコマンド *channel-commands* + +ま だ 実 装 さ れ て い ま せ ん + +"json" チャンネルを使用すると、サーバープロセス側はVimへコマンドを送信できま +す。そのコマンドはチャンネルのハンドラーを介さずに、Vimの内部で実行されます。 + +実行可能なコマンドは以下のとおりです: > + ["ex", {Ex コマンド}] + ["normal", {ノーマルモードコマンド}] + ["eval", {数値}, {式}] + ["expr", {式}] + +これらを使うときは、これらのコマンドが何をするかに十分気をつけてください! +ユーザーが何をしているかによっては容易に干渉してしまいます。トラブルを避けるに +は |mode()| を使い、エディタが期待した状態にあるかチェックしてください。例え +ば、コマンド実行ではなくテキストとして入力させたい文字列を送るには、以下のよう +にします: > + ["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"] + +"ex" コマンドは Ex コマンドを実行します。完了やエラーの応答はありませ +ん。|autoload| スクリプトの中の関数を使えます。何かを入力するのに |feedkeys()| +を実行することもできます。 + +"normal" コマンドは |:normal| のように実行されます。 + +"eval" コマンドは式の評価結果を以下の様に返信します: > + [{数値}, {result}] +{数値} は、リクエストに指定したのと同じものです。 + +"expr" コマンドはそれに近いのですが、応答を返信しません。例: > + ["expr","setline('$', ['one', 'two', 'three'])"] + +============================================================================== +5. rawチャンネルを使う *channel-raw* + +{mode} が "raw" の場合には、以下のようにしてメッセージを送信します: + let response = sendraw(handle, {string}) +{string} はそのまま送信されます。受信した応答メッセージは直ちにチャンネルから +読み込み可能になります。この時、Vimにはメッセージの終了をどう判断するかがわか +りませんから、あなた自身が面倒を見る必要があります。 + +応答を必要としないメッセージを送信するには以下のようにします: > + call sendraw(handle, {string}, 0) +プロセス(訳注:サーバーのこと)はレスポンスを返し、チャンネルのハンドラーに渡さ +れます。 + +メッセージを送信し、レスポンスを特定の関数で非同期的に取り扱うには以下のように +します: > + call sendraw(handle, {string}, {callback}) + +この {string} はJSONにもできます。その場合 |jsonencode()| それを作成し +|jsondecode()| で受信したJSONメッセージを取り扱います。 + +============================================================================== +6. ジョブ制御 *job-control* + +ま だ 実 装 さ れ て い ま せ ん + +別のプロセスを開始するには: > + call startjob({command}) + +これは {command} の終了を待ちません。 + +TODO: + + let handle = startjob({command}, 's') # 標準入出力を使う + let handle = startjob({command}, '', {address}) # ソケットを使う + let handle = startjob({command}, 'd', {address}) # 接続に失敗したら開始 + + + vim:tw=78:ts=8:ft=help:norl: diff --git a/en/channel.txt b/en/channel.txt new file mode 100644 index 000000000..21ce4ebda --- /dev/null +++ b/en/channel.txt @@ -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: