-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathchannel.jax
1602 lines (1278 loc) · 76.4 KB
/
channel.jax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
*channel.txt* For Vim バージョン 9.1. Last change: 2024 Jul 17
VIMリファレンスマニュアル by Bram Moolenaar
プロセス間通信 *channel*
Vim は別のプロセスと通信するのにチャネルを用います。
チャネルはソケットまたはパイプを用います。 *socket-interface*
ジョブはプロセスを開始し、プロセスと通信するために使用できます。
Netbeans インターフェイスもチャネルを使っています。|netbeans|
1. 概要 |job-channel-overview|
2. チャネルデモ |channel-demo|
3. チャネルを開く |channel-open|
4. JSON、JS チャネルを使う |channel-use|
5. チャネルコマンド |channel-commands|
6. RAW、NL チャネルを使う |channel-raw|
7. その他のチャネル機能 |channel-more|
8. チャネル関数詳細 |channel-functions-details|
9. チャネルでジョブを開始する |job-start|
10. チャネルなしでジョブを開始する |job-start-nochannel|
11. ジョブ関数 |job-functions-details|
12. ジョブオプション |job-options|
13. ジョブを制御する |job-control|
14. プロンプトバッファを使う |prompt-buffer|
15. Language Server Protocol |language-server-protocol|
*E1277*
{Vim が |+channel| 機能付きでコンパイルされたときのみ有効}
`has('channel')` でこれを確認できる
{Vim が |+job| 機能付きでコンパイルされたときのみ有効}
`has('job')` でこれを確認できる
==============================================================================
1. 概要 *job-channel-overview*
主に 4 種類のジョブがあります:
1. いくつかの Vim インスタンスを扱うデーモン。Vim はソケットで接続します。
2. 1 つの Vim インスタンスを 1 つのジョブが非同期に処理する。ソケットまたはパ
イプを使用します。
3. 短時間、非同期で仕事をするジョブ。ソケットまたはパイプを使用します。
4. フィルタを同期して実行する。パイプを使用します。
ソケットを使用する場合 |job-start|、|job-start-nochannel|、および
|channel-open| 参照。2 と 3 の場合は、パイプを使用する 1 つ以上のジョブです
(|job-start| 参照)。
4 の場合、":{range}!cmd" コマンドを使用します (|filter| 参照)。
ソケットとパイプ上でこれらのプロトコルを利用できます:
RAW 何も知られていない、Vim はメッセージの終わりを知らせない。
NL すべてのメッセージは NL (改行) 文字で終わります。
JSON JSON エンコーディング |json_encode()|
JS JavaScript スタイルの JSON 風のエンコーディング |js_encode()|
LSP Language Server Protocol のエンコーディング |language-server-protocol|
共通の組み合わせ:
- NL モードでパイプを介して接続されたジョブを使用します。例えば、スタイルチェッ
カーを実行し、エラーと警告を受け取ります。
- デーモンを使用して、JSON モードでソケットに接続します。例えば、データベース
内の相互参照を参照します。
==============================================================================
2. チャネルデモ *channel-demo* *demoserver.py*
デモには Python が必要です。デモプログラムは次の場所にあります。
$VIMRUNTIME/tools/demoserver.py
それをあるターミナルで実行しましょう。そのターミナルを T1 と呼びます。
次に別のターミナルでVimを実行します。そして以下のコマンドでサーバーに接続しま
す: >
let channel = ch_open('localhost:8765')
T1 の中に次のように表示されます:
=== socket opened === ~
これでサーバーにメッセージを送信できます: >
echo ch_evalexpr(channel, 'hello!')
このメッセージは T1 で受信され、Vim には応答が送り返されます。
T1 では Vim が送った生のメッセージを確認できます:
[1,"hello!"] ~
そしてレスポンスはこうなります:
[1,"got it"] ~
この数値はメッセージを送るたびに増加していきます。
サーバーは Vim にコマンドを送信できます。T1 において、次のように正確に (引用符
を含めて文字通りに) タイプしてください:
["ex","echo 'hi there'"] ~
するとそのメッセージが Vim に表示されます。カーソルを1単語先に移動することがで
きます:
["normal","w"] ~
非同期通信を取り扱うためにはコールバック (以下ハンドラー) が必要です: >
func MyHandler(channel, msg)
echo "from the handler: " .. a:msg
endfunc
call ch_sendexpr(channel, 'hello!', {'callback': "MyHandler"})
Vim は応答を待つことはありません。これで、サーバーは応答を後で送信し、
MyHandler が呼び出されます。
send を呼ぶたびに毎回コールバックを指定する代わりに、チャネルを開く際に指定す
ることもできます: >
call ch_close(channel)
let channel = ch_open('localhost:8765', {'callback': "MyHandler"})
call ch_sendexpr(channel, 'hello channel!')
チャネルを試してみると、何が起こっているのかを知ることができます。あなたは Vim
にログファイルに行を書くよう指示することができます: >
call ch_logfile('channellog', 'w')
|ch_logfile()| 参照.
==============================================================================
3. チャネルを開く *channel-open*
チャネルを開くには次のようにします: >
let channel = ch_open({address} [, {options}])
if ch_status(channel) == "open"
" チャネルを使う
|ch_status()| を使用して、チャネルを開くことができたかどうかを確認します。
*channel-address*
{address} はドメイン名か IP アドレスで、それにポート番号を続ける、あるいは
"unix:" プリフィックスを付けて Unix ドメインソケットパス にできます。例 >
www.example.com:80 " ドメイン + ポート
127.0.0.1:1234 " IPv4 + ポート
[2001:db8::1]:8765 " IPv6 + ポート
unix:/tmp/my-socket " Unix ドメインソケットパス
{options} はオプションのエントリを持つ辞書です: *channel-open-options*
"mode" は次のいずれかです: *channel-mode*
"json" - JSONを使う (詳しくは下記を参照。もっとも使いやすい方法。既定)
"js" - JS (JavaScript) エンコーディングを使用し、JSON よりも効率的。
"nl" - NL 文字で終わるメッセージを使う
"raw" - raw メッセージを使う
"lsp" - language server protocol エンコーディングを使う
*channel-callback* *E921*
"callback" メッセージ受信時に他のハンドラーで扱われない時に呼ばれます
(例えば、ID が0の JSON メッセージ)。これはチャネルのハンドル
と、受信したメッセージの 2 つの引数を取ります。例: >
func Handle(channel, msg)
echo '受信した: ' .. a:msg
endfunc
let channel = ch_open("localhost:8765", {"callback": "Handle"})
<
"mode" が "json", "js", "lsp" の時には、"msg" 引数は受信した
メッセージの本文で、Vim の型に変換されています。
"mode" が "nl" の時には、"msg" 引数は NL を除く 1 つのメッセー
ジです。
"mode" が "raw" の時には、"msg" 引数はメッセージ全体を格納し
た文字列です。
すべてのコールバック: |function()| を使用して、引数および/また
は辞書にバインドします。または、"dict.function" という形式を使
用して辞書をバインドします。
コールバックは、通常、Vim がユーザーが文字を入力するのを待って
いるとき、「安全な」瞬間にのみ呼び出されます。Vim はマルチス
レッドを使用しません。
*close_cb*
"close_cb" |ch_close()| を呼び出す以外に、チャネルが閉じられたときに呼び
出される関数。このように定義する必要があります: >
func MyCloseHandler(channel)
< Vim は close_cb を呼び出す前にデータを処理するコールバックを呼
び出します。したがって、この関数が呼び出されると、それ以上の
データはコールバックに渡されません。ただし、コールバックにより
Vim のメッセージのチェックが発生するなら、コールバック中に
close_cb が呼び出されることがあります。プラグインは何とかこれ
を処理する必要があり、これ以上データが来ていないことを知ってお
くと便利です。
読み込むメッセージがあるか不明な場合は、try/catch ブロックを使
います: >
try
let msg = ch_readraw(a:channel)
catch
let msg = 'no message'
endtry
try
let err = ch_readraw(a:channel, #{part: 'err'})
catch
let err = 'no error'
endtry
< *channel-drop*
"drop" メッセージをいつドロップするかを指定します:
"auto" メッセージを処理するコールバックがない場合。
"close_cb" もこのために考慮されます。
"never" すべてのメッセージが保存されます。
*channel-noblock*
"noblock" |job-noblock| と同じ効果です。書込みの為だけの事項です。
*waittime*
"waittime" 接続がミリ秒単位で待機する時間。負の数は永遠に待ちます。
デフォルトはゼロで、待機しません。これは、ローカルサーバーがす
でに実行されている場合に便利です。Unix Vim では実際には 1ms の
タイムアウトが使われます。多くのシステムではそれが必要なためで
す。リモートサーバーには大きな値を使用してください。例: 少なく
とも 10msec。
*channel-timeout*
"timeout" ブロッキング時にリクエストを待つ時間 (例: |ch_evalexpr()| を使
用するとき。ミリ秒単位。デフォルトは 2000 (2 秒) です。
"mode" が "json" か "js" の時には "callback" はオプションです。これを省略した
場合、メッセージを 1 つ受信するにはメッセージを 1 つ送信する必要があります。
チャネルオプションを開いた後に変更するには、|ch_setoptions()| を使用します。
引数は |ch_open()| に渡されるものと似ていますが、"waittime" は与えられません。
これはチャネルを開く場合にのみ適用されるためです。
例えば、ハンドラーは後から追加したり、変更したりできます: >
call ch_setoptions(channel, {'callback': callback})
"callback" が空の場合 (一度も指定しないか、空文字列を指定した場合) ハンドラー
は削除されます。
コールバックが呼び出された後、Vim は画面を更新し、カーソルをそれが属する場所に
戻します。コールバックは `:redraw` を行う必要はありません。
タイムアウトは次のように変更できます: >
call ch_setoptions(channel, {'timeout': msec})
<
*channel-close* *E906*
チャネルを使い終わったら、以下のように切断してください: >
call ch_close(channel)
ソケットが使用されていると、両方向のソケットが閉じられます。パイプが使用されて
いると (stdin/stdout/stderr)、それらはすべて閉じられます。これはあなたが望むも
のではないかもしれません!|job_stop()| でジョブを停止する方が良いかもしれませ
ん。すべての先読みは破棄され、コールバックは呼び出されなくなります。
チャネルは 3 つの段階で閉じられることに注意してください:
- I/O が終了し、ログメッセージ: "Closing channel" が表示されます。呼び出すた
めの読み込みまたはコールバックのキューに入れられたメッセージがまだ残ってい
る可能性があります。
- 先読みがクリアされ、ログメッセージ: "Clearing channel" が表示されます。変
数によっては引き続きチャネルを参照することがあります。
- チャネルが解放され、ログメッセージ: "Freeing channel" が表示されます。
チャネルを開くことができない場合、エラーメッセージが表示されます。MS-Windows
と Unix には違いがあります: Unix では、ポートが存在しないとき、|ch_open()| は
すぐに失敗します。MS-Windows では "waittime" が適用されます。
*E898* *E901* *E902*
チャネルを読み書きする際にエラーが発生した場合、チャネルは閉じられます。
*E630* *E631*
==============================================================================
4. JSON、JS チャネルを使う *channel-use*
"mode" が JSON の場合は、以下のようにメッセージを同期的に送信できます: >
let response = ch_evalexpr(channel, {expr})
これは通信相手から応答があるまで待ち合わせます。
mode が JS の場合は、メッセージが JavaScript エンコーディングを使用する点を除
いて、これは同じです。その違いについては、|js_encode()| 参照。
応答を処理せずにメッセージを送信する、またはチャネルコールバックに応答を処理さ
せるには: >
call ch_sendexpr(channel, {expr})
メッセージを送信し、応答を特別な関数で非同期的に処理する場合には、このようにし
ます: >
call ch_sendexpr(channel, {expr}, {'callback': Handler})
Vim は、メッセージIDを使用して要求との応答を照合します。応答が受信されると、
コールバックが呼び出されます。同じ ID を持つさらなる応答は無視されます。あなた
のサーバーが複数の応答を返信する場合、ID ゼロで送信する必要があります。それら
はチャネルコールバックに渡されます。
{expr} は JSON に変換され、配列で包まれます。{expr} として文字列 "hello" を送
信した場合に、通信相手が受け取るメッセージの例は次のようになります:
[12,"hello"] ~
送信される JSON のフォーマットはこのようになっています:
[{number},{expr}]
{number} には毎回異なる値が入ります。これは応答があるならば、必ず使われます:
[{number},{response}]
このようにして、受信したメッセージがどの送信メッセージに対応するかを知ることが
でき、正しいハンドラーを呼び出すことができます。これによって応答メッセージの到
着順序を気にしなくても良くなります。
改行文字が JSON テキストを終了しています。これは、読み込まれたテキストを区切る
ために使用できます。例えば Python では:
splitidx = read_text.find('\n')
message = read_text[:splitidx]
rest = read_text[splitidx + 1:]
送信側はかならず有効な JSON を Vim へ送らなければなりません。Vim は JSON とし
て解釈することで、受信メッセージの終端をチェックします。終端を受信することが、
メッセージを受理する唯一の方法です。メッセージの後の改行はオプションです。
サーバープロセスが Vim からのメッセージを受信すること無く、メッセージを送信す
るには、数値に 0 を使う必要があります。
[0,{response}]
するとチャネルのハンドラーが {response} を Vim の方に変換したものを受け取るで
しょう。チャネルにハンドラーが関連付けられていない場合には、メッセージは破棄さ
れます。
JSON または JS チャネルで |ch_sendraw()| および |ch_evalraw()| を使用すること
もできます。その場合呼び出し元は、正しくエンコードとデコードを行う完全な責任が
あります。
==============================================================================
5. チャネルコマンド *channel-commands*
JSON チャネルを使用すると、サーバープロセス側は Vim へコマンドを送信できます。
そのコマンドはチャネルのハンドラーを介さずに、Vim の内部で実行されます。
実行可能なコマンドは以下のとおりです: *E903* *E904* *E905*
["redraw", {forced}]
["ex", {Ex コマンド}]
["normal", {ノーマルモードコマンド}]
["eval", {式}, {数値}]
["expr", {式}]
["call", {関数名}, {引数リスト}, {数値}]
["call", {関数名}, {引数リスト}]
これらを使うときは、これらのコマンドが何をするかに十分気をつけてください!
ユーザーが何をしているかによっては容易に干渉してしまいます。トラブルを避けるに
は |mode()| を使い、エディタが期待した状態にあるかチェックしてください。例え
ば、コマンド実行ではなくテキストとして入力させたい文字列を送るには、以下のよう
にします:
["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"] ~
これらのコマンドのエラーは、表示が乱れないようにするため、通常は報告されませ
ん。表示したい場合は、'verbose' オプションを 3 以上に設定してください。
コマンド "redraw" ~
他のコマンドは明示的に画面を更新しないので、カーソルを動かさずに一連のコマンド
を送ることができます。再描画は他のコマンドの副作用として発生することがありま
す。変更されたテキストを表示し、それが属する場所にカーソルを表示するには、
"redraw" コマンドで終了する必要があります。
引数は通常は空の文字列です:
["redraw", ""] ~
最初に画面をクリアするには "force" を渡してください:
["redraw", "force"] ~
コマンド "ex" ~
"ex" コマンドは Ex コマンドを実行します。完了やエラーの応答はありません。
|autoload| スクリプトの中の関数を使えます:
["ex","call myscript#MyFunc(arg)"]
"call |feedkeys()|" を使用してキーシーケンスを挿入することもできます。
エラーが発生すると、チャネルログにメッセージが書き込まれ、存在する場合は
v:errmsg にエラーが設定されます。
コマンド "normal" ~
"normal" コマンドは ":normal!" のように実行され、コマンドはマップされません。
カーソルの下の折り畳みを開く例:
["normal" "zO"]
コマンド "expr" (応答あり) ~
"expr" コマンドは、式の結果を得るために使うことができます。例えば、現在のバッ
ファ内の行数を取得するには、次のようにします:
["expr","line('$')", -2] ~
式の結果を返します:
[-2, "last line"] ~
形式は次のとおりです:
[{number}, {result}]
{number} は、リクエストに指定したのと同じものです。Vim が送信するメッセージと
の混乱を避けるには、負の数を使用します。リクエストとレスポンスを一致させるに
は、リクエストごとに異なる番号を使用します。
{result} は評価の結果であり、JSON エンコードされています。評価が失敗したり、結
果を JSON でエンコードできない場合は、文字列 "ERROR" となります。
コマンド "expr" (応答なし) ~
このコマンドは上記の "expr" に近いのですが、応答を返信しません。
例:
["expr","setline('$', ['one', 'two', 'three'])"] ~
リクエストに第 3 引数はありません。
コマンド "call" ~
これは "expr" に似ていますが、式全体を文字列として渡す代わりに、関数の名前と引
数のリストを渡します。これは、引数の文字列への変換を避け、エスケープして連結し
ます。例:
["call", "line", ["$"], -2] ~
応答が送信されない場合は、第 4 引数を省いてください:
["call", "setline", ["$", ["one", "two", "three"]]] ~
==============================================================================
6. RAW、NL チャネルを使う *channel-raw*
モードが RAW か NL の場合には、以下のようにしてメッセージを送信します: >
let response = ch_evalraw(channel, {string})
{string} はそのまま送信されます。受信した応答メッセージは直ちにチャネルから読
み込み可能になります。この時、Vim にはメッセージの終了をどう判断するかがわかり
ませんから、あなた自身が面倒を見る必要があります。タイムアウトは、最初のバイト
を読み取るために適用され、その後は何も待つことはありません。
mode が "nl" の場合、同様の方法でメッセージを送信できます。あなたは各メッセー
ジの後に NL に入れなければなりません。したがって、一度に NL で終わる複数のメッ
セージを送信することもできます。応答は最初の NL までのテキストとなります。これ
は空のレスポンスの NL だけでもかまいません。チャネルタイムアウトの前に NL が読
み取られなかった場合、空の文字列が返されます。
応答を必要としないメッセージを送信するには以下のようにします: >
call ch_sendraw(channel, {string})
プロセス {訳注:サーバーのこと} はレスポンスを返し、チャネルのハンドラーに渡さ
れます。
*channel-onetime-callback*
メッセージを送信し、レスポンスを特定の関数で非同期的に取り扱うには以下のように
します: >
call ch_sendraw(channel, {string}, {'callback': 'MyHandler'})
この {string} は JSON にもできます。その場合、|json_encode()| でそれを作成し
|json_decode()| で受信した JSON メッセージを取り扱います。
生のチャネルで |ch_evalexpr()| または |ch_sendexpr()| を使用することはできませ
ん。
Vim の文字列に NUL バイトを含めることはできません。NUL バイトを送受信するには、
バッファから読み書きしてください。|in_io-buffer| と |out_io-buffer| 参照。
==============================================================================
7. その他のチャネル機能 *channel-more*
チャネルのステータスを取得するには、ch_status(channel) を使用します。ありうる
結果は次のとおりです:
"fail" チャネルを開くことができませんでした。
"open" チャネルを使用することができます。
"buffered" チャネルは閉じられましたが読み込むデータがあります。
"closed" チャネルが閉じられました。
チャネルに関連付けられたジョブを取得するには: ch_getjob(channel)
チャネルから 1 つのメッセージを読むには: >
let output = ch_read(channel)
これは、チャネルのタイムアウトを使用します。タイムアウトなしで読むには、利用可
能なメッセージを取得するだけです: >
let output = ch_read(channel, {'timeout': 0})
メッセージが利用できなかった場合、結果は JSON または JS モードのチャネルでは
v:none、RAW または NL チャネルでは空の文字列です。|ch_canread()| を使用して、
何かがあるかどうかを調べることができます。
コールバックメッセージがない場合、メッセージは破棄されます。これを回避するに
は、チャネルにコールバックを追加します。
使用可能な RAW チャネルからすべての通常出力を読み込むには: >
let output = ch_readraw(channel)
使用可能な RAW チャネルからすべてのエラー出力を読み込むには: >
let output = ch_readraw(channel, {"part": "err"})
Note チャネルが NL モードの場合、ch_readraw() は各呼び出しで1行しか返しません。
ch_read() と ch_readraw() はチャネルタイムアウトを使用します。その時間内に何も
読み込めない場合、空の文字列が返されます。別のタイムアウトをミリ秒で指定するに
は、"timeout" オプションを使用します:
{"timeout": 123} ~
エラー出力から読み込むには、"part" オプションを使用します:
{"part": "err"} ~
特定の ID を持つメッセージを JS または JSON チャネルで読み取るには:
{"id": 99} ~
ID が指定されていないか、または ID が -1 の場合、最初のメッセージが返されます。
これは、このメッセージを待っているコールバックをすべて無効にします。
RAW チャネルの場合、Vim はメッセージの終わりを知らないので、利用可能なものを返
します。
NL チャネルの場合、これは 1 つのメッセージを返します。
JS または JSON チャネルの場合、これは1つのデコードされたメッセージを返します。
これには、任意のシーケンス番号が含まれます。
==============================================================================
8. チャネル関数詳細 *channel-functions-details*
ch_canread({handle}) *ch_canread()*
{handle} から何か読むものがあれば非ゼロを返す。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
これはチャネルから、都合のよいときに読むのに便利である。例え
ば、タイマーから。
チャンルがコールバックを持っていない場合、メッセージはドロップ
されることに注意。それを防ぐには close コールバックを追加する
こと。
|method| としても使用できる: >
GetChannel()->ch_canread()
<
戻り値の型: |Number|
ch_close({handle}) *ch_close()*
{handle} を閉じる。|channel-close| を参照。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
閉じられたコールバックは呼び出されない。
|method| としても使用できる: >
GetChannel()->ch_close()
<
戻り値の型: |Number|
ch_close_in({handle}) *ch_close_in()*
{handle} の "入力" を閉じる。|channel-close-in| を参照。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
閉じられたコールバックは呼び出されない。
|method| としても使用できる: >
GetChannel()->ch_close_in()
<
戻り値の型: |Number|
ch_evalexpr({handle}, {expr} [, {options}]) *ch_evalexpr()*
{handle} へ {expr} を送信する。{expr} はチャネル側と同じ型にエ
ンコードされる。この関数は生のチャネルでは使用できない。
|channel-use| を参照。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
"lsp" モードでチャネル使用時は、{expr} は |Dict| でなければな
らない。
*E917*
{options} は辞書でなければならない。また "callback" のエントリ
を持ってはならない。また個別のリクエストに対して "timeout" を
持つ事ができる。
ch_evalexpr() は応答を待ち、式をデコードした物が返される。エ
ラーもしくはタイムアウトの場合は空の |String|、あるいは "lsp"
モードでチャネル使用時は空の |Dict| が返る。
Note 応答を待っている間、Vimは他のメッセージを処理する。これが
トラブルを引き起こさないことを確認する必要がある。
|method| としても使用できる: >
GetChannel()->ch_evalexpr(expr)
<
戻り値の型: dict<any> または |String|
ch_evalraw({handle}, {string} [, {options}]) *ch_evalraw()*
{handle} へ {string} を送信する。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
|ch_evalexpr()| と同様に動作する。しかしリクエストをエンコード
したり応答をデコードしたりはしない。呼び出しは正しいコンテンツ
である事が保証される。また NL モードでは改行が行われるが、ここ
では改行が付与されない。NL は応答から削除される。
Note: Vim は Raw チャネル上で受け取るテキストがいつ完了するの
か分からない。最初の部分だけを返す可能性もあり、残りを取り出す
ために |ch_readraw()| を使う必要がある。
|channel-use| を参照。
|method| としても使用できる: >
GetChannel()->ch_evalraw(rawstring)
<
戻り値の型: dict<any> または |String|
ch_getbufnr({handle}, {what}) *ch_getbufnr()*
文字列 {what} に使用されている {handle} のバッファ番号を得る。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
{what} は標準エラーの為の "err"、標準出力の為の "out"、もしく
はソケット出力の為の空文字列が指定できる。
バッファが存在しない場合は -1 が返る。
|method| としても使用できる: >
GetChannel()->ch_getbufnr(what)
<
戻り値の型: |Number|
ch_getjob({channel}) *ch_getjob()*
{channel} に関連付けられた Job を得る。
もしジョブが無い場合、戻り値の Job で |job_status()| を呼び出
すと "fail" が返される。
|method| としても使用できる: >
GetChannel()->ch_getjob()
<
戻り値の型: |job| または |String|
ch_info({handle}) *ch_info()*
{handle} に関する情報を辞書で返す。アイテムは:
"id" チャネル番号
"status" ch_status() と同様に、"open", "buffered" ま
たは "closed"
ch_open() で開いた場合:
"hostname" アドレスのホスト名
"port" アドレスのポート
"path" Unix ドメインソケットのパス
"sock_status" "open" または "closed"
"sock_mode" "NL", "RAW", "JSON" または "JS"
"sock_io" "socket"
"sock_timeout" タイムアウト(ミリ秒)
Note "path" は Unix ドメインソケットの場合にのみ存在し、通常は
"hostname" と "port" が代わりに存在する。
job_start() で開いた場合:
"out_status" "open", "buffered" または "closed"
"out_mode" "NL", "RAW", "JSON" または "JS"
"out_io" "null", "pipe", "file" または "buffer"
"out_timeout" タイムアウト(ミリ秒)
"err_status" "open", "buffered" または "closed"
"err_mode" "NL", "RAW", "JSON" または "JS"
"err_io" "out", "null", "pipe", "file" または "buffer"
"err_timeout" タイムアウト(ミリ秒)
"in_status" "open" または "closed"
"in_mode" "NL", "RAW", "JSON", "JS" または "LSP"
"in_io" "null", "pipe", "file" または "buffer"
"in_timeout" タイムアウト(ミリ秒)
|method| としても使用できる: >
GetChannel()->ch_info()
<
戻り値の型: dict<any>
ch_log({msg} [, {handle}]) *ch_log()*
|ch_logfile()| によってログファイルが開かれている場合はチャネ
ルのログファイルに文字列 {msg} を書き込む。
テキスト "ch_log():" はメッセージの前に追加され、この関数の呼
び出しからであることを明確にし、ログファイルの中から見付けるの
を容易にする。
{handle} が渡されている場合はチャネル番号がメッセージの中で使
われる。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
使用されるチャネル番号のチャネルは開いていなければならない。
|method| としても使用できる: >
'did something'->ch_log()
<
戻り値の型: dict<any>
ch_logfile({fname} [, {mode}]) *ch_logfile()*
{fname} へチャネルの挙動ログ出力を開始する。
{fname} が空の場合、ロギングは停止する。
{mode} が省略されるか "a" を含むか "o" の場合、ファイルへの追
加になる。
{mode} が "w" を含み "a" を含まない場合、空のファイルで開始さ
れる。
{mode} が "o" を含む場合、全ての端末出力が記録される。
その他の場合は、興味深い端末出力のみがログに記録される。
ログメッセージを書き込むには |ch_log()| を使用する。UNIX で
"tail -f" にてリアルタイムで何が行われているかが見える様に、
ファイルはメッセージ毎にフラッシュされる。
最初期にログを有効にし、初期化中に端末から何を受信したのかを参
照するには、|--log| ("ao" モードを使用) を使う: >
vim --log logfile
<
この関数は |sandbox| 内では無効である。
Note: チャネルとの通信はファイルに格納される。これには、あなた
が端末ウィンドウ上でタイプしたパスワードのような、機密やプライ
バシーに関する情報を含むことがあることに注意すること。
|method| としても使用できる: >
'logfile'->ch_logfile('w')
<
戻り値の型: |Number|
ch_open({address} [, {options}]) *ch_open()*
{address}へのチャネルを開く。|channel|を参照。
チャネルを返す。失敗をチェックするには |ch_status()| を使用す
る。
{address} は文字列で、受け付け可能な形式は |channel-address|
を参照のこと。
{options} が与えられる場合は辞書でなければならない。
|channel-open-options| を参照。
|method| としても使用できる: >
GetAddress()->ch_open()
<
戻り値の型: |channel|
ch_read({handle} [, {options}]) *ch_read()*
{handle} から読み込みメッセージを受信する。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
NL チャネルの場合、何も読み込むものがない (チャネルが閉じられ
た) 場合を除いて NL を受信するまで待つ。
|channel-more| を参照。
|method| としても使用できる: >
GetChannel()->ch_read()
<
戻り値の型: |String|
ch_readblob({handle} [, {options}]) *ch_readblob()*
ch_read() と同様に動作するが、バイナリデータを読み込んで
|Blob| を返す。
|channel-more| を参照。
|method| としても使用できる: >
GetChannel()->ch_readblob()
<
戻り値の型: |Blob|
ch_readraw({handle} [, {options}]) *ch_readraw()*
ch_read() と同様に動作するが JS や JSON の場合でもメッセージは
デコードされない。NL チャネルの場合、NL を受信するまで待つこと
はないが、それ以外は ch_read() と同様に動作する。
|channel-more| を参照。
|method| としても使用できる: >
GetChannel()->ch_readraw()
<
戻り値の型: |String|
ch_sendexpr({handle}, {expr} [, {options}]) *ch_sendexpr()*
{handle} へ {expr} を送信する。{expr} はチャネル側と同じ型にエ
ンコードされる。この関数は生のチャネルでは使用できない。
|channel-use| を参照。 *E912*
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
チャネルは開いていなければならない。
"lsp" モードでチャネル使用時は、{expr} は |Dict| でなければな
らない。
チャネルのモードが "lsp" の場合、辞書を返す。それ以外は空の文
字列を返す。{options} に "callback" の項目が存在する場合、リク
エストメッセージのIDを含む辞書を返す。IDはLSPサーバーへキャン
セルのリクエスト(必要な場合)を送るのに使うことができる。エラー
のときは空の辞書を返す。
{expr} に対して応答メッセージを受けないのであれば、{options}
に "callback" 項目を指定しないこと。
|method| としても使用できる: >
GetChannel()->ch_sendexpr(expr)
<
戻り値の型: dict<any> または |String|
ch_sendraw({handle}, {expr} [, {options}]) *ch_sendraw()*
文字列 |String| または |Blob| {expr} を {handle} に送る。
|ch_sendexpr()| と同様に動作するが、リクエストをエンコードした
り応答をデコードしたりはしない。呼び出しは正しいコンテンツで
ある事が保証される。また NL モードでは改行が行われるが、ここ
では改行が付与されない。NL は応答から削除される。
|channel-use| を参照。
|method| としても使用できる: >
GetChannel()->ch_sendraw(rawexpr)
<
戻り値の型: dict<any> または |String|
ch_setoptions({handle}, {options}) *ch_setoptions()*
{handle} にオプションを設定する:
"callback" チャネルのコールバック
"timeout" デフォルトの読み込みタイムアウト(ミリ秒)
"mode" チャネル全体のモード
より詳しい説明は |ch_open()| を参照。
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
Note: モードの変更はキューイングされているメッセージを失ってし
まうかもしれない。
以下のオプションは変更できない:
"waittime" |ch_open()|だけで適用できる
|method| としても使用できる: >
GetChannel()->ch_setoptions(options)
<
戻り値の型: |Number|
ch_status({handle} [, {options}]) *ch_status()*
{handle} の状態を返す:
"fail" チャネルのオープンに失敗
"open" チャネルは利用可能
"buffered" チャネルは読込可能、または書き込まれて
いない
"closed" チャネルは利用不可
{handle} はチャネルもしくはチャネルを持つジョブであっても良い。
チャネルは閉じられているが |ch_read()| を使って残ったデータを
まだ読み取る事ができる場合には "buffered" が利用できる。
{options} が指定された場合、"part" 要素でチャネルのどのパート
("out" または "err") の状態を返すかを指定できる。例えば、エ
ラーの状態を得るには: >
ch_status(job, {"part": "err"})
<
|method| としても使用できる: >
GetChannel()->ch_status()
<
戻り値の型: |String|
==============================================================================
9. チャネルでジョブを開始する *job-start* *job*
ジョブを開始し、stdin/stdout/stderr のチャネルを開くには: >
let job = job_start(command, {options})
チャネルを得るには: >
let channel = job_getchannel(job)
チャネルは NL モードを使用します。別のモードが必要な場合は、{options} でこれを
指定することをお勧めします。後でモードを変更すると、一部のテキストがすでに受信
され、正しく解析されていない可能性があります。
コマンドが処理したい出力行を生成する場合は、stdout のハンドラを指定します: >
let job = job_start(command, {"out_cb": "MyHandler"})
この関数は、チャネルとメッセージで呼び出されます。あなたはこれをこのように定義
します: >
func MyHandler(channel, msg)
ハンドラがなければ、|ch_read()| または |ch_readraw()| で出力を読み取る必要があ
ります。クローズコールバックでこれを行うことができます。|read-in-close-cb| 参
照。
出力を読み取る前にジョブが終了すると、出力が失われる可能性があることに注意して
ください。これはシステムによって異なります (Unix 上では、パイプの書き込み終了
を閉じると EOF が得られます)。これを避けるには、ジョブが終了する前にそれをしば
らくスリープさせること。
"out_cb" に定義されたハンドラは stderr を受け取りません。もし個別に扱いたい場
合は、"err_cb" ハンドラを追加します: >
let job = job_start(command, {"out_cb": "MyHandler",
\ "err_cb": "ErrHandler"})
1 つのハンドラで stderr と stdout の両方を処理する場合は、"callback" オプショ
ンを使用します: >
let job = job_start(command, {"callback": "MyHandler"})
システムによっては、ジョブを開始するとVimをバックグラウンドに移動することがあ
り、開始されたジョブはフォーカスを取得します。これを避けるには `foreground()`
関数を使用してください。これは、早く呼び出されたとき、コールバックハンドラ内に
置いたとき、またはジョブが開始した後にタイマーを使用して呼び出すときは、必ずし
も機能しない場合があります。
ch_evalraw() でコマンドにメッセージを送ることができます。チャネルが JSON また
は JS モードの場合、ch_evalexpr() を使用できます。
使用できるオプションがいくつかあります。|job-options| 参照。
例えば、ジョブを開始し、その出力をバッファ "dummy" に書き込むには: >
let logjob = job_start("tail -f /tmp/log",
\ {'out_io': 'buffer', 'out_name': 'dummy'})
sbuf dummy
バッファからのジョブ入力 ~
*in_io-buffer*
バッファから読み取るジョブを実行するには: >
let job = job_start({command},
\ {'in_io': 'buffer', 'in_name': 'mybuffer'})
<
*E915* *E918*
バッファは、|bufnr()| と同様の名前で見つけられます。バッファは、job_start()
が呼び出されたときに存在し、ロードされていなければなりません。
デフォルトでは、これはバッファ全体を読み込みます。これは "in_top" と "in_bot"
オプションで変更できます。
特殊モードは、"in_top" が 0 に設定され、"in_bot" が設定されていない場合です。
バッファに行が追加されるたびに、最後の 1 行がジョブ stdin に送信されます。これ
により、最後の行を編集し、Enter を押したときに送信することができます。
*channel-close-in*
特殊モードを使用しないときは、最後の行が書き込まれた後にパイプまたはソケットが
閉じられます。これは、入力が終了した読み取り終了を知らせます。|ch_close_in()|
を使用すると、より早く終了することもできます。
テキストの NUL バイトはジョブに渡されます (内部では Vim はこれらを NL バイトと
して格納します)。
クローズコールバックでジョブ出力を読み込む ~
*read-in-close-cb*
ジョブに時間がかかり、中間結果が必要ない場合は、クローズコールバックを追加して
そこの出力を読み取ることができます: >
func! CloseHandler(channel)
while ch_status(a:channel, {'part': 'out'}) == 'buffered'
echomsg ch_read(a:channel)
endwhile
endfunc
let job = job_start(command, {'close_cb': 'CloseHandler'})
あなたは "echomsg" よりも役に立つ何かをしたいでしょう。
==============================================================================
10. チャネルなしでジョブを開始する *job-start-nochannel*
チャネルを作成せずに別のプロセスを開始するには: >
let job = job_start(command,
\ {"in_io": "null", "out_io": "null", "err_io": "null"})
これはバックグラウンドで {command} を開始し、Vim はそれが完了するのを待ちませ
ん。
Vim が stdin、stdout、stderr のいずれも接続されていないと判断すると、チャネル
は作成されません。コマンドが停止するのを避けるために、リダイレクションをコマン
ドに含めることがよくあります。
使用できるオプションがいくつかあります。|job-options| 参照。
*job-start-if-needed*
アドレスへの接続が動作しない時にのみジョブを開始するには、次のような操作を行い
ます: >
let channel = ch_open(address, {"waittime": 0})
if ch_status(channel) == "fail"
let job = job_start(command)
let channel = ch_open(address, {"waittime": 1000})
endif
Note ch_open() の待ち時間は、ポートを利用可能にするためにジョブに 1 秒を与える
ことに注意してください。
==============================================================================
11. ジョブ関数 *job-functions-details*
job_getchannel({job}) *job_getchannel()*
{job}が使用しているチャネルハンドルを取得する。
ジョブにチャネルがないかどうかを確認するには: >
if string(job_getchannel(job)) == 'channel fail'
<
|method| としても使用できる: >
GetJob()->job_getchannel()
<
戻り値の型: |channel|
job_info([{job}]) *job_info()*
{job}に関する情報を持つ辞書を返す:
"status" |job_status()|が返すもの
"channel" |job_getchannel()|が返すもの
"cmd" ジョブを開始するのに使われるコマンド引数のリス
ト
"process" プロセス ID
"tty_in" 端末入力名、何もないときには空
"tty_out" 端末出力名、何もないときには空
"exitval" "status" が "dead" のときのみ有効
"exit_cb" 終了時に呼び出される関数
"stoponexit" |job-stoponexit|
Unixのみ:
"termsig" プロセスを終了させたシグナル
(値については |job_stop()| を参照)
"status"が "dead" の場合にのみ有効である
MS-Windowsのみ:
"tty_type" 使用している仮想コンソールのタイプ。
値は "winpty" または "conpty"。
'termwintype' を参照。
引数なしの場合、すべてのジョブオブジェクトのリストを返す。
|method| としても使用できる: >
GetJob()->job_info()
<
戻り値の型: {job} が指定されたかどうかによって、dict<any> また
は list<job>
job_setoptions({job}, {options}) *job_setoptions()*
{job}のオプションを変更する。サポートされているものは:
"stoponexit" |job-stoponexit|
"exit_cb" |job-exit_cb|
|method| としても使用できる: >
GetJob()->job_setoptions(options)
<
戻り値の型: |Number|
job_start({command} [, {options}]) *job_start()*
ジョブを開始し、ジョブオブジェクトを返す。|system()|と|:!cmd|
とは異なり、これはジョブが終了するのを待つことはない。
端末ウィンドウ内でジョブを開始する方法については
|term_start()| を参照。
ジョブが起動に失敗した場合、返されたジョブオブジェクトの
|job_status()| は "fail" となり、どのコールバックも呼び出され
ない。
{command}は文字列にできる。これはMS-Windowsで最も効果的である。
Unixでは、それはexecvp()に渡すために空白で区切られたパーツに分
割される。二重引用符で囲まれた引数には空白を含められる。
{command}はリストにでき、最初の項目は実行可能ファイルであり、
残りの項目は引数である。すべての項目は文字列に変換される。これ
はUnixで最も効果的である。
MS-Windowsでは、|job_start()|はGUIアプリケーションを隠す。それ
を表示したい場合は、|:!start|を代わりに使用すること。
コマンドはシェルではなく直接実行され、'shell' オプションは使用