forked from vim-jp/vimdoc-ja-working
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvim9.jax
2441 lines (2063 loc) · 119 KB
/
vim9.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
*vim9.txt* For Vim バージョン 9.1. Last change: 2025 Mar 06
VIMリファレンスマニュアル by Bram Moolenaar
Vim9 script のコマンドと文法 *Vim9* *vim9*
ほとんどの文法については |eval.txt| で解説されています。このファイルには Vim9
script の新しい文法と機能について書かれています。
1. Vim9 script とは |Vim9-script|
2. 変更点 |vim9-differences|
3. 新しいスタイルの関数 |fast-functions|
4. 型 |vim9-types|
5. 名前空間、Import と Export |vim9script|
6. クラスとインターフェイス |vim9-classes|
9. 理論的根拠 |vim9-rationale|
==============================================================================
1. Vim9 script とは *Vim9-script*
Vim script は、互換性の維持に気を配りながら成長してきました。そのため、古い悪
しき仕様を変更できないことが多いほか、Vi との互換性に制約を受けて、より良い解
決策を採用できなくなっています。処理は遅く、実行するたびに各行のパースが行われ
ています。
Vim9 script の主な目的は劇的な性能の向上です。これは、コマンドをより効率よく実
行できる命令にコンパイルすることで実現しています。これにより、10倍から100倍の
実行速度の向上が期待できます。
第2の目的は、Vim script 特有の文法を回避し、より一般的に使われる JavaScript や
TypeScript、Java のようなプログラミング言語に近づけることです。
パフォーマンスの向上は、100% の下位互換性を捨てることによってのみ達成しうるも
のです。例えば、関数の引数を辞書 "a:" から利用できるようにするためには、かなり
のオーバーヘッドが必要になります。そのため、Vim9 script では、この辞書が利用で
きなくなりました。その他の違いは、エラーの処理方法など、より微細なものです。
Vim9 script は以下の場所で使用することができます:
- コマンド `:def` で定義された関数の中
- コマンド `vim9script` で始まるスクリプトファイルの中
- 上記のコンテキストで定義された自動コマンド
- コマンド修飾子 `vim9cmd` が先頭に付いたコマンド
Vim9 script ファイルの中でコマンド `:function` で関数を定義すると、その中では
旧来の Vim script の記法が、最新の |scriptversion| とともに有効になります。し
かし、これは混乱を招く可能性があるため、推奨できません。
Vim9 script と旧来の Vim script は同時に利用できます。古いスクリプトを書き換え
なくとも、以前と同様に実行することが可能です。高速化が必要なコードには、`:def`
で定義する関数を使ったほうが良いかもしれません。
:vim9[cmd] {cmd} *:vim9* *:vim9cmd* *E1164*
Vim9 script の文法と方式を使用して {cmd} を評価、実行します。
コマンドを入力する時と、旧来のスクリプトや関数内で使用する時に
便利です。
:leg[acy] {cmd} *:leg* *:legacy* *E1189* *E1234*
旧来の Vim script の文法と方式を利用して {cmd} を評価、実行し
します。これは Vim9 script、あるいは `:def` で定義する関数での
み便利です。
Note {cmd} は旧来の Vim script の式として解釈されるため、{cmd}
ではローカル変数 {訳注: Vim9 script におけるローカル変数} を用
いることはできない。
|52.6| の Vim9 script の例を参照してください。
==============================================================================
2. 旧来の Vim script からの変更点 *vim9-differences*
概要 ~
*E1146*
Vim9 script と `:def` で定義する関数を使用する際に最もよく遭遇する変更点の概要
は以下のとおりです:
- コメントは " ではなく、# で始めます: >
echo "hello" # コメント
- 行継続文字 (\) はほとんどの場合、必要ありません: >
echo "hello "
.. yourName
.. ", how are you?"
- 可読性を上げるため、多くの場所にスペースが必要になります。
- 値の代入には `:let` *E1126* を使用せず、変数の宣言には `:var` を使用します: >
var count = 0
count += 3
- `:final` と `:const` を使用して、定数を宣言できます: >
final matches = [] # 後でこのリストに追加する
const names = ['Betty', 'Peter'] # 変更できない
- `:final` は `:finally` の略語として使用することはできません。
- 変数と関数のスコープは、明示しない限りスクリプトローカルです。
- 関数を引数の型、戻り値の型とともに宣言します: >
def CallMe(count: number, message: string): bool
- 関数は `:call` なしで呼び出します: >
writefile(['done'], 'file.txt')
- 古い Exコマンドは使用できません:
`:Print`
`:append`
`:change`
`:d` 直接 'd' か 'p' かが続いているもの。
`:insert`
`:k`
`:mode`
`:open`
`:s` フラグのみ与えて使用されたとき
`:t`
`:xit`
- 一部のコマンド、特に制御構文として使われるコマンドは、省略することはできませ
ん。例えば、`:throw` を `:th` と書くことはできません。 *vim9-no-shorten*
- 波括弧変数は使用できません。
- コマンドの前に範囲指定を置くときは、コロン (:) を前置しなくてはなりません: >
:%s/this/that
- "@r" としてレジスタを実行することはできません。コロン (:) を前置するか、
`:exe` を使ってください: >
:exe @a
- 特に指定しない限り、最新の |scriptversion| が使われます。
- 式による指定のマッピングを定義する際は、その式はそのマッピングが定義されたス
クリプトのコンテキストで評価されます。
- 文字列にインデックスを付ける場合、インデックスはバイト数ではなく文字数でカウ
ントされます: |vim9-string-index|
- 予想外の違いがいくつかあるかもしれません: |vim9-gotchas|.
# から始まるコメント ~
旧来の Vim script のコメントは、ダブルクォーテーションで始めます。Vim9 script
のコメントは # で始めます。 >
# 宣言
var count = 0 # 出現回数
これは、ダブルクォーテーションは文字列の開始を表す文字でもあるからです。多くの
場所、特に改行を含む式の途中では、文字列とコメントの両方が現れるため、どちらを
意味しているのかわかりにくくなってしまいます。この混乱を避けるために、Vim9
script では、# のみをコメントとして認識します。このコメント形式はシェルスクリ
プトやPythonのコードと同じです。
Vi において # は行番号付きでテキストを表示します。Vim9 script では、代わりに
`:number` を使用します。 >
:101 number
可読性を向上するために、コマンドと #、コメント文の間にはスペースをおいてくださ
い: >
var name = value # コメント
var name = value# エラー!
< *E1170*
コメントを #{ で始めてはいけません。旧来の Vim script の辞書リテラルと似てお
り、どちらか判別がつきにくいところではエラーになるからです。折り畳みの開始に使
える #{{ や #{{{ はコメントの始まりになっても良いです。
スクリプトファイルの先頭では、Vim は `vim9script` コマンドが見つかるまでそのス
クリプトが |Vim9| script かを知るすべがありません。なのでその行までは旧来のコ
メントを使う必要があります。: >
" 旧来のコメント
vim9script
# Vim9 のコメント
これは不恰好なので、`vim9script` を一番最初の行に書くのが良いでしょう: >
vim9script
# Vim9 コメント
旧来の Vim script では # は代替ファイル名としても使われます。Vim9 script で
は、代わりに %% を使う必要があります。## の代わりに %%% を使います。(すべての
引数を意味します)
Vim9 関数 ~
*E1099*
`:def` で定義された関数はコンパイルされます。処理の実行は多くの場合、通常の関
数に比べて10倍から100倍ほど速くなります。
多くのエラーは関数が実行される前に、コンパイルされる段階で検出されます。読みや
すく理解しやすいコードを強制するために、構文は厳密に定められています。
コンパイルは以下のいずれかのタイミングで実行されます:
- 関数が最初に呼び出されるとき
- 関数が定義された後ろの位置で、スクリプト中に `:defcompile` コマンドが見つ
かったとき
- 関数に対してコマンド `:disassemble` が実行されたとき
- コンパイルされた関数から呼び出されたり、関数リファレンスとして使用されたとき
(引数と戻り値の型をチェックできるようにするため)
*E1091* *E1191*
もし関数のコンパイルに失敗した場合は、次その関数が呼ばれたときも再度コンパイル
を試みることはなく、代わりに "E1091: Function is not compiled: {name}" という
エラーを発生させます。{訳注: 日本語メッセージの場合: "E1091: 関数はコンパイル
されていません: {name}"}
コンパイルはまだ作成されていないユーザーコマンドと遭遇したときに失敗するでしょ
う。この場合は `execute()` を使うことでエラーを関数の実行時に発生するようにす
ることができます。 >
def MyFunc()
execute('DefinedLater')
enddef
`:def` は `:function` が持っているようなオプションを持っていません:
"range"、"abort"、"dict" や "closure" のこと。`:def` で定義される関数は常にエ
ラーが発生し次第、実行を中断します (`:silent!` がコマンドに対して使われた場合
やエラーが `:try` ブロック内で捕捉された場合でない限り) 。また与えられた「範
囲」も受け取らず、"dict" 属性を持つ関数になることもできません。そして常にク
ロージャとなれます。
*vim9-no-dict-function* *E1182*
「辞書関数」の代わりに Vim9 クラス (|Vim9-class|) を使用できます。辞書を明示的
に渡すこともできます: >
def DictFunc(self: dict<any>, arg: string)
echo self[arg]
enddef
var ad = {item: 'value', func: DictFunc}
ad.func(ad, 'item')
一方、旧来の辞書関数を呼ぶことはできます: >
func Legacy() dict
echo self.value
endfunc
def CallLegacy()
var d = {func: Legacy, value: 'text'}
d.func()
enddef
< *E1096* *E1174* *E1175*
引数の型と戻り値の型を指定する必要があります。型には "any" を指定することがで
き、型のチェックは旧来の関数と同様に実行時に行われます。
*E1106*
引数を参照する際は、他のプログラミング言語と同様、"a:" をつけずに名前だけで指定
することができます。
引数辞書 "a:" と 引数リスト "a:000" はありません。
*vim9-variable-arguments* *E1055* *E1160* *E1180*
可変長引数を定義する場合は TypeScript のように、最後の引数として名前とlist型で
定義します。例えば、数値の可変長引数の例は以下のとおりです: >
def MyFunc(...itemlist: list<number>)
for item in itemlist
...
関数の引数が任意 (引数に既定値が指定されている場合) のときは、その引数に
`v:none` を渡すことでその既定値を使うことができます。これは既定値を使いたい引数
の後ろの引数に値を指定したいときに便利です。例: >
def MyFunc(one = 'one', last = 'last')
...
enddef
MyFunc(v:none, 'LAST') # 第 1 引数は既定値の 'one' を使う
<
*vim9-ignored-argument* *E1181*
引数 "_" (アンダースコア) は引数を無視するのに使えます。これは使わないが呼び出
す際に一致するように引数を与えないといけないようなコールバックにおいて一番便利
です。例えば、map() を使っていて、キーと値の 2 つの引数が与えられる時に引数の
キーを無視するには: >
map(numberList, (_, v) => v * 2)
引数に "_" を複数回使ってもエラーにはなりません。また、型も指定する必要はあり
ません。
関数と変数はデフォルトでスクリプトローカル ~
*vim9-scopes*
Vim9 script でスクリプト直下に `:function` や `:def` を使って関数を定義する
と、関数はプリフィックス "s:" をつけた際のように、スクリプトローカルで定義され
ます。グローバルスコープの関数や変数を定義するにはプリフィックス "g:" をつける
必要があります。スクリプト内の関数のうち他のスクリプトから import されるものと
オートロードスクリプト内の関数について、他のスクリプトで利用できるようにするた
めには "export" をつける必要があります。 >
def ThisFunction() # スクリプトローカル
def g:ThatFunction() # グローバル
export def Function() # import と import autoload 関数
< *E1058* *E1075*
`:def` で定義される関数内で `:function` か `:def` でネストした関数を名前空間の
指定なしに作成したときは、ネストした関数はその関数が定義されたブロックにローカ
ルな関数になります。またその関数は `function()` に文字列を用いて渡すことはでき
ず、その関数自身の参照を渡さなければいけません: >
def Outer()
def Inner()
echo 'inner'
enddef
var Fok = function(Inner) # OK
var Fbad = function('Inner') # 動作しない
詳細: これは "Inner" が実際には生成された名前 {訳注: <lambda>XXX のこと。} を
もつ関数への関数参照になるからです。
関数の中でスクリプトローカル関数を定義することはできません。代わりにローカル関
数を定義して、それをスクリプトローカルな Funcref (これはスクリプトレベルで定義
されていないといけません) に代入することができます。グローバル関数はプリフィッ
クス "g:" を使うことで定義できます。
関数をプリフィックス "s:" や "g:" をつけずに参照した場合、Vim は関数を次のよう
に探します:
- 同じ関数の中、ブロックスコープの中
- スクリプトスコープの中
import された関数は、`:import` コマンドで決まる名前を前置して見つけられます。
スクリプトローカル関数の参照が "s:" をつけることなく使えるので、スクリプトロー
カル関数の名前はプリフィックス "s:" をつけて宣言した場合でも大文字から始まる必
要があります。旧来の Vim script では "s:funcref" とすることができました。なぜ
なら、"s:funcref" を "funcref" として参照することができなかったからです。しか
し Vim9 script ではそれが可能なので、組み込み関数との名前の干渉を避けるため
に "s:Funcref" のように名前が指定される必要があります。
*vim9-s-namespace* *E1268*
Vim9 script において、スクリプトレベルでのプリフィックス "s:" の使用はサポート
されていません。プリフィックスのない全ての関数と変数は全てスクリプトローカルに
なります。
`:def` で定義される関数内においては、"s:" の使用はスクリプト依存です: 旧来の
Vim script 内ではスクリプトローカルな関数と変数に対して "s:" を使いますが、
Vim9 script 内では使いません。これはこのドキュメントの以下の説明でも同様です。
旧来の関数内においては、スクリプトローカルな項目に対しての "s:" の指定は従来通
り必要です。これはスクリプトが Vim9 script であろうが旧来の Vim script であろ
うが関係ありません。
いずれの場合でも、関数は使用されるよりも前に定義されていなくてはなりません。使
用されるタイミングは、コマンド `:defcompile` によってコンパイルされるとき、ま
たは関数を呼び出す関数がコンパイルされているとき(戻り値の型を確認するため)で
す。
その結果として、名前空間を持たない関数や変数は通常、スクリプト内で定義されてい
るか、import されたものかのどちらかで見つけることができます。グローバルな関数
や変数はどこでも定義できます (どこで定義されているか、見つかるといいですね!し
ばしば |:verbose| を使ってどこで最後に値がセットされたか調べることができます)。
*E1102*
グローバル関数は引き続き、ほとんどいつでも定義し、削除することができます。Vim9
script でのスクリプトローカル関数は、スクリプトが読み込まれたときに一度定義さ
れたきり、そのスクリプト内で削除や置き換えはできません (スクリプトローカル関数の
削除や置き換えはスクリプトの再読み込みをすることでできます)。
関数のコンパイルや、関数の呼び出しが未定義の関数に遭遇したとき、自動コマンド
|FuncUndefined| は呼び出されません。必要であればオートロード関数を使用したり、
旧来の関数を呼び出すことで |FuncUndefined| イベントが発生します。
デフォルトでは Vim9 script の再読み込みにより関数と変数がクリアされる ~
*vim9-reload* *E1149* *E1150*
旧来の Vim script を2回目に読み込んだときは、何も削除されることはなく、コマン
ドはすでにある変数や関数を置き換えて新しいものを作り、置き換えられなかったもの
はそのまま残しておきます。
Vim9 script を2回目に読み込んだときは、存在するすべてのスクリプトローカルの関
数や変数は削除され、クリーンな状態から開始します。これはプラグインを開発中に、
新しいバージョンを試す際には便利です。いずれかの名前を変えたとしても、古い名前
が残る心配はありません。
消さずに残すには、以下を使用します: >
vim9script noclear
これを使用することで、再読み込みの際に任意の場所で `finish` コマンドにより脱出
することができます。例えば、バッファローカルオプションが関数に設定され、その関
数を2回以上定義する必要がないとき: >
vim9script noclear
setlocal completefunc=SomeFunc
if exists('*SomeFunc')
finish
endif
def SomeFunc()
....
:var、:final や :const で宣言する変数 ~
*vim9-declaration* *:var* *E1079*
*E1017* *E1020* *E1054* *E1087* *E1124*
ローカル変数は `:var` で定義する必要があります。ローカル定数は `:final` または
`:const` で定義する必要があります。このセクションでは、両者を "変数" と呼ぶこ
とにします。
変数はスクリプトローカルや、関数、コードブロックのスコープで定義できます: >
vim9script
var script_var = 123
def SomeFunc()
var func_var = script_var
if cond
var block_var = func_var
...
変数は、定義されたコードブロックか、ネストされた配下のブロックで参照することが
できます。コードブロックが終わったあとの処理から参照することはできません: >
if cond
var inner = 5
else
var inner = 0
endif
echo inner # エラー!
参照したい場合には、ブロックよりも前で宣言しなくてはなりません: >
var inner: number
if cond
inner = 5
else
inner = 0
endif
echo inner
こちらの方が単純な値については簡潔で早くはありますが。: >
var inner = 0
if cond
inner = 5
endif
echo inner
< *E1025* *E1128*
意図的に続く処理から変数を隠したいとき、ブロックを使うことができます: >
{
var temp = 'temp'
...
}
echo temp # エラー!
これは特にユーザーコマンドで便利です: >
command -range Rename {
var save = @a
@a = 'some expression'
echo 'do something with ' .. @a
@a = save
}
また、自動コマンドでも便利です: >
au BufWritePre *.go {
var save = winsaveview()
silent! exe ':%! some formatting command'
winrestview(save)
}
多分 `:def` で定義される関数を使う方が良く動くでしょうが。
*E1022* *E1103* *E1130* *E1131* *E1133*
*E1134*
変数を型を指定し、初期値なしで宣言した場合、変数は false (bool 型のとき)、空
(string、list、dict などの型のとき)、あるいはゼロ (number、any などの型のとき)
で初期化されます。これは "any" 型を使う時に特に重要で、初期値は数字のゼロとな
ります。例えば、リストを宣言したとき、要素を追加することができます: >
var myList: list<number>
myList->add(7)
変数を null、例えば `null_list`、で初期化することは変数を初期化しないこととは
異なります。これはエラーになります: >
var myList = null_list
myList->add(7) # E1130: null リストには追加できません
< *E1016* *E1052* *E1066*
Vim9 script では `:let` は使用できません。すでに存在する変数に対してはコマンド
を使用せずに代入します。実際に宣言されることがないので、グローバル変数、ウィン
ドウ変数、タブ変数、バッファ変数、そして Vim の定義済変数についてもコマンドを
使用せずに代入します。またそれらの変数は `:unlet` によって削除することもできま
す。
*E1065*
変数を `:va` で宣言することはできず、それは必ず完全な名前の `:var` として書か
れなければなりません。これはコードを読みやすくするためのものです。
*E1178*
`:lockvar` はローカル変数に対しては動作しません。代わりに `:const` か `:final`
を使ってください。
`exists()` 関数と `exists_compiled()` 関数はローカル変数あるいは引数に対しては
動作しません。
*E1006* *E1041* *E1167* *E1168* *E1213*
変数と関数と関数の引数は、同じスクリプトファイル内で、すでに定義された、または
import された変数と関数をシャドーイングすることはできません。一方で変数は
Ex コマンドをシャドーイングするので、必要であれば変数の名前を変更してください。
グローバル変数の前には、スクリプトレベルでも "g:" を付けなければなりません。 >
vim9script
var script_local = 'text'
g:global = 'value'
var Funcref = g:ThatFunction
グローバル関数は必ず先頭に "g:" を付けなければなりません: >
vim9script
def g:GlobalFunc(): string
return 'text'
enddef
echo g:GlobalFunc()
プリフィックス "g:" はオートロード関数に対しては必要ありません。
*vim9-function-defined-later*
グローバル関数はプリフィックス "g:" なしに呼び出すことができますが、それらはコ
ンパイル時に存在していなければなりません。プリフィックスを "g:" をつけること
で、関数が後で定義されても良くなります。例: >
def CallPluginFunc()
if exists('g:loaded_plugin')
g:PluginFunc()
endif
enddef
もしこのようにすると、たとえ "g:loaded_plugin" が存在しない場合でも、コンパイ
ル時に "PluginFunc" が存在しないというエラーが発生します: >
def CallPluginFunc()
if exists('g:loaded_plugin')
PluginFunc() # エラー、関数が見つからない
endif
enddef
`exists_compiled()` を使うことでエラーを回避できますが、この場合は
"g:loaded_plugin" が後で定義されている場合でもその関数は呼ばれません: >
def CallPluginFunc()
if exists_compiled('g:loaded_plugin')
PluginFunc() # 関数が呼ばれることはないかもしれない
endif
enddef
現在、`&opt = value` は "opt" オプションに値を設定する目的で使用されているた
め、`:substitute` コマンドをリピートする目的で ":&" を使用することはできません。
*vim9-unpack-ignore*
アンパック代入において、アンダースコアは、関数の引数を無視するのと似たように
リストの要素を無視するのに使えます: >
[a, _, c] = theList
残りの要素全部を無視するには: >
[a, b; _] = longList
< *E1163* *E1080*
アンパックの記法を用いて、一つ以上の変数を一度に宣言することが可能です。
それぞれの変数は型を持つか、値から型を推測することができます: >
var [v1: number, v2] = GetValues()
これは値を持つリストがある時にのみ利用してください。1行に 1変数を宣言する方が
より読みやすく、後の変更も行いやすいです。
定数 ~
*vim9-const* *vim9-final*
定数の働きは言語によって異なります。別の値を代入できない変数を定数とする場合も
あります。JavaScript がその一例です。また、値そのものを不変にすることもあり、
例えばリスト定数の内容を変更することができないとしている場合もあります。
Vim9ではこのどちらも定義することができます。
*E1021* *E1307*
変数とその値、両方を定数とするには、`:const` を使用します。何らかの複合的な値
が変更できないようにする際に使用します。例: >
const myList = [1, 2]
myList = [3, 4] # エラー!
myList[0] = 9 # エラー!
myList->add(3) # エラー!
< *:final* *E1125*
変数の変更のみを禁止するには、`:final` を使用します。この場合は、中の値自体を
変えることはできます。Java でよく知られるものです。例: >
final myList = [1, 2]
myList = [3, 4] # エラー!
myList[0] = 9 # OK
myList->add(3) # OK
一般に、定数はすべて大文字 (例: ALL_CAPS) で書かれますが、必ずしもそうしなくて
も構いません。
定数宣言は値そのものにのみ適用され、参照先の変数には影響しません。 >
final females = ["Mary"]
const NAMES = [["John", "Peter"], females]
NAMES[0] = ["Jack"] # エラー!
NAMES[0][0] = "Jack" # エラー!
NAMES[1] = ["Emma"] # エラー!
NAMES[1][0] = "Emma" # OK, females[0] == "Emma"
:call と :eval は不要に ~
*E1190*
関数は `:call` なしで呼ぶことができます: >
writefile(lines, 'file')
`:call` は引き続き使用できますが、やめたほうが良いでしょう。
メソッド呼び出しには `eval` は必要ありません。Exコマンドと同名の識別子ではない
限り、直接に識別子から呼び出すことができます。関数の場合は、"(" または "->"の
どちらかを改行せずに続けなければなりません。例: >
myList->add(123)
g:myList->add(123)
[1, 2, 3]->Process()
{a: 1, b: 2}->Process()
"foobar"->Process()
("foobar")->Process()
'foobar'->Process()
('foobar')->Process()
一部の関数と Ex コマンドが紛らわしい場合、コロン (:) を前置することでそれが Ex
コマンドであることを明示することができます。例えば、`:substitute` コマンドと
`substitute()` が該当します。`substitute(` で始まる場合は関数呼び出しですが、
コロンを前置することでコマンドを代わりに使用することができます: >
:substitute(pattern (replacement (
もし式が "!" で始まっているのであれば、それは条件の否定ではなくシェルコマンド
であると解釈されます。したがって、これはシェルコマンドとなります: >
!shellCommand->something
"!" を否定として用いるには、式を丸カッコで囲んでください: >
(!expression)->Method()
Note 変数は使用する前に宣言する必要がありますが、関数は宣言するより前に使用で
きます。これは関数の循環参照を可能にするためです。関数を名前で探さなければなら
ないので、少し効率が悪いです。また、関数名のタイプミスは、関数が呼び出されると
きまで見つかりません。
function() は不要に ~
ユーザー定義の関数は、`function()` を使わずとも関数リファレンスとして使用する
ことができます。引数の型と戻り値の型がチェックされます。関数はすでに定義されて
いる必要があります。 >
var Funcref = MyFunction
`function()` を使って "func" 型のリファレンスを得た場合、その関数は任意の個数
の引数と任意の戻り値の型 (void を含めて) を持つものとされます。この場合、もし
関数名がクォートで囲まれてるなら、その関数は後から宣言できます。
ラムダ式には -> の代わりに => を使う ~
*vim9-lambda*
旧来のスクリプトでは "->" はメソッド呼び出しとラムダ式で混同するおそれがありま
す。また、"{" が見つかったとき、パーサーはラムダ式と辞書の開始を見分けねばなら
ず、そしてそれは引数の型指定により複雑になっています。
この問題を回避するため、Vim9 script ではラムダ式のために違う書式を使用し、それ
は JavaScript に似ています: >
var Lambda = (arg) => expression
var Lambda = (arg): type => expression
< *E1157*
"=>" まで含めて、ラムダ式の引数の定義の中では改行することはできません (Vim が
丸カッコで囲まれた式とラムダ式の引数の区別をつけられるようにするため)。これは
OKです: >
filter(list, (k, v) =>
v > 0)
以下のように記述することはできません: >
filter(list, (k, v)
=> v > 0)
以下のように記述することもできません: >
filter(list, (k,
v) => v > 0)
ただし、バックスラッシュを使ってパースする前に行をつなげることができます: >
filter(list, (k,
\ v)
\ => v > 0)
< *vim9-lambda-arguments* *E1172*
旧来の Vim script においては、ラムダ関数はいくつもの余分な引数を与えて呼ぶこと
ができ、そしてその余分な引数を使わないことに対しての警告をする方法がありません
でした。Vim9 script では引数の数は必ず一致しなければなりません。もし任意の
引数、またはその他の引数を受け入れたい場合は、関数が |vim9-variable-arguments|
を受け入れられるようにする "..._" を使ってください。例: >
var Callback = (..._) => 'anything'
echo Callback(1, 2, 3) # "anything" を表示する
< *inline-function* *E1171*
加えて、ラムダ式には {} に複数のステートメントを含むことができます: >
var Lambda = (arg) => {
g:was_called = 'yes'
return expression
}
これはタイマーに便利です。例えば: >
var count = 0
var timer = timer_start(500, (_) => {
count += 1
echom 'Handler called ' .. count
}, {repeat: 3})
閉じの "}" は行の先頭にこなければなりません。後ろに他の文字が続いても良いで
す。例: >
var d = mapnew(dict, (k, v): string => {
return 'value'
})
いかなるコマンドも "{" の後ろに続いてはいけません。コメントのみが利用可能で
す。
*command-block* *E1026*
ブロックはユーザーコマンドを定義するのにも使えます。ブロックの内側では Vim9
script の文法が使われます。
これはヒアドキュメントの使用例です: >
com SomeCommand {
g:someVar =<< trim eval END
ccc
ddd
END
}
もしブロックが辞書を含むのであれば、辞書の閉じカッコは行頭に書かれてはいけませ
ん。さもなくば閉じカッコがブロックの終了としてパースされてしまいます。これは動
作しません: >
command NewCommand {
g:mydict = {
'key': 'value',
} # エラー: ブロックの終了として認識される
}
これを避けるには、'}' を最後の要素の後ろにおいてください: >
command NewCommand {
g:mydict = {
'key': 'value' }
}
根拠: "}" がコマンドの後にきてはならないのは、ブロックの閉じカッコを見つけるの
にコマンドのパースが必要だろうからです。一貫性のために、いかなるコマンドも "{"
に続けることはできません。残念ながら、これは "() => { command }" が動作せず、
常に改行が必要であることを意味します。
*vim9-curly*
辞書リテラルの "{" がステートメントブロックと認識されてしまうのを回避するため
には、括弧で包みます: >
var Lambda = (arg) => ({key: 42})
さらに、コマンドブロックの開始と混同してしまう場合: >
({
key: value
})->method()
自動行継続 ~
*vim9-line-continuation* *E1097*
多くの場合、式が次の行に続くことは明らかです。継続行の先頭に行継続のためのバッ
クスラッシュ (|line-continuation| 参照) を置く必要はありません。例えば、複数行
にまたぐリストの場合: >
var mylist = [
'one',
'two',
]
辞書の場合: >
var mydict = {
one: 1,
two: 2,
}
関数の呼び出しで: >
var result = Func(
arg1,
arg2
)
角カッコ []、波カッコ {}、または丸カッコの中‘以外で’二項演算子御使用する場
合、その前後で改行することができます。例: >
var text = lead
.. middle
.. end
var total = start +
end -
correction
var result = positive
? PosFunc(arg)
: NegFunc(arg)
"->" を使用したメソッド呼び出し、そしてドット (.) を使用したメンバー参照の場
合、その前に改行を置くことができます: >
var result = GetBuilder()
->BuilderSetWidth(333)
->BuilderSetHeight(777)
->BuilderBuild()
var result = MyDict
.member
複数のコマンドのリストを引数に持つコマンドでは、行の先頭に置かれた文字 | は行
継続を表します: >
autocmd BufNewFile *.match if condition
| echo 'match'
| endif
Note これはヒアドキュメントの最初の行は | で始めることができないことを意味しま
す: >
var lines =<< trim END
| これは動作しない
END
ヒアドキュメントの先頭行を空行にする、あるいはヒアドキュメントを使わないように
してください。あるいは一時的にフラグ "C" を 'cpoptions' に追加してください: >
set cpo+=C
var lines =<< trim END
| これは動作する
END
set cpo-=C
もしヒアドキュメントが関数の中で使われているのであれば、'cpoptions' は :def の
前で変更され、かつ :enddef の後ろで元に戻されなければなりません。
例えば長い Ex コマンドを分割しているときのような、依然として行連結にバックス
ラッシュが必要な場所では、'#\ ' でコメントを開始することができます: >
syn region Text
\ start='foo'
#\ コメント
\ end='bar'
これは旧来の Vim script で '"\ ' が使われているのと似ています。またこれはバッ
クスラッシュ抜きで行連結が使用され、かつ行が | で開始しているときにも必要で
す: >
au CursorHold * echom 'BEFORE bar'
#\ 何かのコメント
| echom 'AFTER bar'
<
*E1050*
行頭の演算子と識別できるようにするために、範囲指定の前にはコロンを置きます。
"start" と "print" をつなげる例: >
var result = start
+ print
これは以下の記述と同じです: >
var result = start + print
次のように書くと、"start" を代入して、1行表示します: >
var result = start
:+ print
「範囲」の後ろには必ず Ex コマンドが続かなければなりません。コロンを付けてい
ない時は `:call` 抜きで関数を呼ぶことができますが、「範囲」の後ろではそれが必
要です: >
MyFunc()
:% call MyFunc()
Note |+cmd| の引数にはコロンは不要です: >
edit +6 fname
関数の定義部においても、引数の間で改行をおくことができます: >
def MyFunc(
text: string,
separator = '-'
): string
継続行を識別することは容易ではないため、コマンドの解析はより厳格化されていま
す。例えば、一行目のエラーにより、2行目は別のコマンドとみなされます: >
popup_create(some invalid expression, {
exit_cb: Func})
ここで "exit_cb: Func})" は実際に有効なコマンドです: 変更をファイル
"_cb: Func})" に保存して閉じます。Vim9 script の中ではこの種のミスを回避するた
めに、コマンド名と引数の間にはスペースを置かなくてはなりません。
*E1144*
ただし、コマンドの引数に置いたコマンドは認識されません。例えば、"windo echo
expr" に続く "expr" の式の中で改行しても認識されません。
Notes:
- "enddef" は継続行の先頭に置くことはできません。それは関数の終端を意味します。
- 代入式の左辺を複数の行に分割できません。特にリストのアンパック |:let-unpack|
を使用する場合は注意が必要です。これはOKです: >
[var1, var2] =
Func()
< 以下のように記述することはできません: >
[var1,
var2] =
Func()
- `:echo` や `:execute` のようなコマンドの引数は複数の行に分割できません。これ
はOKです: >
echo [1,
2] [3,
4]
< 以下のように記述することはできません: >
echo [1, 2]
[3, 4]
- いくつかの場合、特に `:windo` のようなコマンドが他のコマンドの引数として使わ
れるような場合では、Vim にとってコマンドのパースが困難です。このような場合で
では、バックスラッシュを使った行継続を使わなければなりません。
ホワイトスペース ~
*E1004* *E1068* *E1069* *E1074* *E1127* *E1202*
Vim9 script ではホワイトスペースの適切な使用を強制します。これはもはや許可され
ません: >
var name=234 # エラー!
var name= 234 # エラー!
var name =234 # エラー!
"=" の前後にホワイトスペースがなければいけません: >
var name = 234 # OK
コマンドの後ろでコメントを開始する # の前にもホワイトスペースが置かれなければ
なりません: >
var name = 234# エラー!
var name = 234 # OK
ホワイトスペースは大抵の演算子の周りで必須です。
始まりと終わりと除いて、サブリスト (リストのスライス) の ":" の周りにホワイト
スペースが必要です: >
otherlist = mylist[v : count] # v:count は異なる意味を持つ
otherlist = mylist[:] # リストのコピーを作る
otherlist = mylist[v :]
otherlist = mylist[: v]
ホワイトスペースは許可されません:
- 関数名と "(" の間: >
Func (arg) # エラー!
Func
\ (arg) # エラー!
Func
(arg) # エラー!
Func(arg) # OK
Func(
arg) # OK
Func(
arg # OK
)
< *E1205*
`:set` コマンドでのオプション名と続く "&"、"!"、"<"、"="、"+="、"-=" や "^="
の間にはホワイトスペースは許可されません。
波括弧変数の廃止 ~
波括弧変数 |curly-braces-names| は使用できません。
コマンド修飾子は無視されない ~
*E1176*
コマンド修飾子を使わないコマンドにコマンド修飾子を使うとエラーになります。
*E1082*
同様に、続くコマンドなしにコマンド修飾子を使うことも今はエラーになります。
辞書リテラル ~
*vim9-literal-dict* *E1014*
従来、Vim は波括弧 {} で辞書リテラルの表記をサポートしてきました: >
let dict = {'key': value}
後に、辞書にシンプルなキーを使用することが非常に一般的であることが明らかになっ
たため、キーをクォーテーションなしで指定できる表記が後方互換的に導入されまし
た: >
let dict = #{key: value}
しかし、この #{} という表記は他の言語に比べて異色なものです。キーには式よりも
リテラルを使うほうが一般的で、JavaScript が使っている構文を考えると、辞書リテ
ラルに {} の表記を使うほうがずっと便利です: >
var dict = {key: value}
これは英数字、アンダースコアとダッシュのキーで利用できます。異なる文字を使用す
る場合は、シングルクォートまたはダブルクォートで囲まれた文字列を使用します: >
var dict = {'key with space': value}
var dict = {"key\twith\ttabs": value}
var dict = {'': value} # 空のキー
< *E1139*
キーに式を使用する必要がある場合は、JavaScript と同様に角括弧を使用することが
できます: >
var dict = {["key" .. nr]: value}
キーの型には、文字列、数値、真偽値、浮動小数点のいずれかを指定できます。その他
の型の場合はエラーが発生します。[] を使わない場合は文字列として扱われ、先頭の
0 を保持します。[] を使って式が与えられた場合は、式を評価し、文字列に変換しま
す。先頭の 0 は省かれます: >
var dict = {000123: 'without', [000456]: 'with'}
echo dict
{'456': 'with', '000123': 'without'}
[] 外ではドットは受け入れられないので、浮動小数点数は [] の中でのみ動作しま
す: >
var dict = {[00.013]: 'float'}
echo dict
{'0.013': 'float'}
:xit、:t、:k、:append、:change、:insert の廃止 ~
*E1100*
これらのコマンドは容易にローカル変数の名前と混同します。
`:x` や `:xit` の代わりに `:exit` を使用できます。
`:t` の代わりに `:copy` を使用できます。
`:k` の代わりに `:mark` を使用できます。
比較 ~
オプション 'ignorecase' は文字列の比較には作用しません。なので、"=~" は "=~#"
と同じように動作します。
現状では、"is" と "isnot" (|expr-is| と |expr-isnot|) を文字列に対して使うと
常に偽を返します。旧来の Vim script では文字列の比較を行うだけでしたが、Vim9
script ではそれらは文字列オブジェクトが同一であることをチェックします。文字列
は使われるときに複製されるので、二つの文字列は同一と判定されることはありませ
ん。(いつか、もし文字列が複製されるのではなく参照カウントで管理されるようにな
ると、この挙動は変更されるかもしれません)
エラー後の中断 ~
旧来の Vim script では、エラーに遭遇したとき、Vim は後続の行の実行を続けます。
これは長いエラーの列を生みかねず、そしてそのエラーを止めるための CTRL-C の入力
が必要になります。Vim9 script ではコマンドの実行は最初のエラーに遭遇した段階で
終了します。例: >
vim9script
var x = does-not-exist
echo 'not executed'
For ループ ~
*E1254*
ループ変数は先に宣言されていてはいけません: >
var i = 1
for i in [1, 2, 3] # エラー!
ただ、グローバル変数を使うことは可能です: >
g:i = 1
for g:i in [1, 2, 3]
echo g:i
endfor
旧来の Vim script では、リストのループ内で現在または前の項目を削除するための
for ループをつくるために幾つかのトリックがあります。Vim9 script では、単純にイ
ンデックスを使用することで、リストから削除された場合はスキップされます。
旧来のスクリプトの例: >
let l = [1, 2, 3, 4]
for i in l
echo i
call remove(l, index(l, i))
endfor
出力は以下の通り:
1
2
3
4
コンパイルされた Vim9 script での出力は以下の通り:
1
3
一般的に、反復しているリストを変更してはいけません。必要であれば最初にコピーを
作ります。
リストのリストをループする場合、ネストされたリストを変更できます。ループ変数は
"final" であり、変更することはできませんが、その値は変更できます。
*E1306*
:for ループと :while ループを合わせたループの深さは、10 を超えることはできませ
ん。
条件と式 ~
*vim9-boolean*
条件と式は、他の言語とおよそ同じように扱われます。いくつかの値は旧来の Vim
script と扱いが異なります:
値 旧来の Vim script Vim9 script ~
0 falsy falsy
1 truthy truthy
99 truthy エラー!
"0" falsy エラー!
"99" truthy エラー!
"text" falsy エラー!
"??" 演算子か "!" を使用している場合はエラーとなることはなく、すべての値は