-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy patheval.jax
4815 lines (4015 loc) · 210 KB
/
eval.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
*eval.txt* For Vim バージョン 9.1. Last change: 2025 Feb 23
VIMリファレンスマニュアル by Bram Moolenaar
式の評価 *expression* *expr* *E15* *eval*
*E1002*
式の評価についてはユーザーマニュアルの41章|usr_41.txt|でも解説されている。
Note: 式の評価はコンパイル時に無効化できる。無効化されている場合、このドキュメ
ントに書かれている事は有効ではない。|+eval| と |no-eval-feature| を参照。
このファイルは主に後方互換の(旧来の) Vim script について書かれている。より高速
に実行でき、型チェックや多くの機能に対応する Vim9 script については |vim9.txt|
を参照のこと。構文およびセマンティクスが異る場合は注釈が付く。
1. 変数 |variables|
1.1 変数の型
1.2 関数への参照 |Funcref|
1.3 リスト |Lists|
1.4 辞書 |Dictionaries|
1.5 Blobs |Blobs|
1.6 変数について補足 |more-variables|
2. 式の文法 |expression-syntax|
3. 内部変数 |internal-variables|
4. 組み込み関数 |functions|
5. 関数定義 |user-functions|
6. 波括弧{}変数 |curly-braces-names|
7. コマンド |expression-commands|
8. 例外処理 |exception-handling|
9. 例 |eval-examples|
10. Vim scriptバージョン |vimscript-version|
11. +eval機能が無効 |no-eval-feature|
12. サンドボックス |eval-sandbox|
13. テキストロック |textlock|
14. Vim script ライブラリ |vim-script-library|
テストのサポートは |testing.txt| を参照。
プロファイリングは |profiling| に記録されている。
==============================================================================
1. 変数 *variables*
1.1 変数の型 ~
*E712* *E896* *E897* *E899* *E1098*
*E1107* *E1135* *E1138*
変数には10種類の型がある:
*Number* *Integer*
数値 32ビットまたは64ビットの符号有整数。|expr-number|
ビット数は |v:numbersize| で得られる。
例: -123 0x10 0177 0o177 0b1011
浮動小数点数 浮動小数点数。|floating-point-format| *Float*
例: 123.456 1.15e-6 -1.1e3
文字列 終端がNUL文字である8ビットの符号無し文字(バイト)。
|expr-string| 例: "ab\txx\"--" 'x-z''a,c'
リスト 要素の順序つきの列。詳細は |List| を参照。
例: [1, 2, ['a', 'b']]
辞書 順序を持たない連想配列: 各要素はキーと値を持つ。|Dictionary|
例:
{'blue': "#0000ff", 'red': "#ff0000"}
#{blue: "0000ff", red: "ff0000"}
Funcref 関数への参照 |Funcref|。
例: function("strlen")
辞書や引数とバインドすることができ、そのときは部分適用(Partial)
のように働く。
例: function("Callback", [arg], myDict)
特殊値 |v:false|, |v:true|, |v:none| と |v:null|。 *Special*
ジョブ ジョブに使われる。|job_start()|を参照。 *Job* *Jobs*
チャネル チャネルに使われる。|ch_open()|を参照。 *Channel* *Channels*
Blob バイナリラージオブジェクト。任意のバイトシーケンスを格納する。
詳細は |Blob| を参照。
例: 0zFF00ED015DAF
0z は空のBlobである。
数値と文字列は文脈に応じて相互に変換される。
数値から文字列への変換は数字のASCII表現によって行われる。例:
数値 123 --> 文字列 "123" ~
数値 0 --> 文字列 "0" ~
数値 -1 --> 文字列 "-1" ~
*octal*
文字列から数値への変換は旧来の Vim script のみで行われ、Vim9 script では行われ
ない。最初に出る数字を用いて数値に変換する。16進表記 "0xf9" や8進表記 "017" も
しくは "0o17"、2進表記の "0b10" も認識される。
NOTE: |Vim9| script か |scriptversion-4| を使用する場合、先頭が "0" の8進数は
認識されない。"0o" 記法はパッチ 8.2.0886 が必要になる。
文字列が数字で始まらない場合結果は0となる。
例:
文字列 "456" --> 数値 456 ~
文字列 "6bar" --> 数値 6 ~
文字列 "foo" --> 数値 0 ~
文字列 "0xf1" --> 数値 241 ~
文字列 "0100" --> 数値 64 ~
文字列 "0o100" --> 数値 64 ~
文字列 "0b101" --> 数値 5 ~
文字列 "-8" --> 数値 -8 ~
文字列 "+8" --> 数値 0 ~
文字列を強制的に数値に変換するには0を足す: >
:echo "0100" + 0
< 64 ~
先頭の0によって8進数とみなされるのを防いだり、異なる基数を使うには|str2nr()|を
使う。
*TRUE* *FALSE* *Boolean*
ブール(真偽値)演算には数値が使われる。0は偽を意味し、非0は真を表す。また、
|v:false| と |v:true| を使うこともでき、Vim9 script では |false| と |true| に
なる。
関数から真が返されたときは数値の 1 であり、偽が返されたときは数値の 0 である。
Note 次のコマンドをみると >
:if "foo"
:" 実行されない
"foo" は 0 に変換され、それは偽を意味する。もし文字列がゼロでない数値から始ま
る場合は真を意味する: >
:if "8foo"
:" 実行される
文字列が空ではないか調べるためには empty() を使用して次のようにする。 >
:if !empty("foo")
< *falsy* *truthy*
式は、型を無視した値が「真の一種」か「偽の一種」のどちらであるかだけを利用し
て、判定条件として使用できる。Falsy は:
値が0
空の文字列、Blob、リスト、辞書
それ以外の値は truthy。例:
0 falsy
1 truthy
-1 truthy
0.0 falsy
0.1 truthy
'' falsy
'x' truthy
[] falsy
[0] truthy
{} falsy
#{x: 1} truthy
0z falsy
0z00 truthy
*non-zero-arg*
関数の引数は、|TRUE| とは少し異なる場合がある: 引数が存在し、それが非ゼロの
Number、|v:true| または空でない String に評価される場合、値は TRUE と見なされ
る。
Note: " " と "0" も空文字列ではないので、TRUE と見なされる。List、Dictionary、
または Float は数値または文字列ではないため、FALSE と評価される。
*E611* *E745* *E728* *E703* *E729* *E730* *E731* *E908* *E910*
*E913* *E974* *E975* *E976* *E1319* *E1320* *E1321* *E1322*
*E1323* *E1324*
リスト |List|, 辞書 |Dictionary|, |Funcref|, ジョブ |Job|, チャネル |Channel|,
|Blob|, クラス |Class| および |object| は自動的に変換されない。
*E805* *E806* *E808*
数値と浮動小数点数をまぜると浮動小数点数になる。それ以外には浮動小数点数への自
動的な変換は存在しない。文字列から浮動小数点数へは str2float() を使い、浮動小
数点数から文字列へは printf() を、浮動小数点数から数値へは float2nr() を使う。
*E362* *E891* *E892* *E893* *E894* *E907* *E911* *E914*
浮動小数点数が予期されているところでは数値も使用可能だが、それ以外は使用できな
い。
*no-type-checking*
変数の型を変更しようとしてもエラーは発生しない。
1.2 関数への参照 ~
*Funcref* *E695* *E718* *E1192*
関数への参照は、関数 |function()|、関数 |funcref()|、(|Vim9| script 内で)関数
の名前あるいはラムダ式 |expr-lambda| による生成で得られる。関数への参照は、式
の中で関数名が要求される場所で使うと参照先の関数を呼び出す。|Vim9| script での
例: >
:var Fn = MyFunc
:echo Fn()
旧来のスクリプトでは: >
:let Fn = function("MyFunc")
:echo Fn()
< *E704* *E705* *E707*
関数参照の変数名は、大文字、"s:"、"w:"、"t:"、"b:" のいずれかで始めなければな
らない。"g:" も使えるが、あとに続く名前は大文字で始めなければならない。関数参
照と参照先の関数の名前を同じにすることはできない。
関数を定義して、それへの参照を直接辞書に入れるための特別な形式がある。例: >
:function dict.init() dict
: let self.val = 0
:endfunction
この辞書のキーは小文字で始めなければならない。実際の関数名はここでは使われない。
|numbered-function|も参照。
|:call|コマンドでも関数参照を使うことができる: >
:call Fn()
:call dict.init()
参照先の関数名は|string()|で得られる。 >
:let func = string(Fn)
|call()|を使うと、リスト型の変数を引数として関数参照を呼び出すことができる: >
:let r = call(Fn, mylist)
<
*Partial*
関数参照は、辞書および/もしくは引数とバインドすることができる。これは部分適用
(Partial)とも呼ばれる。これは、辞書および/もしくは引数を function() または
funcref() に渡すことで作成される。その関数を呼び出すと、その辞書および/もしく
は引数がその関数に渡される。例: >
let Cb = function('Callback', ['foo'], myDict)
call Cb('bar')
これは、関数を以下のようにして呼び出す: >
call myDict.Callback('foo', 'bar')
これは関数を何かに渡す場合、例えば |ch_open()| の引数とする場合などに非常に有
用である。
Note 関数の辞書へのバインドは、その関数が辞書のメンバーであるときにも発生する
ことに注意: >
let myDict.myFunction = MyFunction
call myDict.myFunction()
ここで、MyFunction() は myDict を "self" として受け取る。これは、"myFunction"
メンバーがアクセスされたときに起こる。"myFunction" を別の辞書 otherDict に代入
して呼び出すと、それは otherDict にバインドされる: >
let otherDict.myFunction = myDict.myFunction
call otherDict.myFunction()
今度は、"self" は "otherDict" になる。しかし、辞書を明示的にバインドしたときに
はこれは起こらない: >
let myDict.myFunction = function(MyFunction, myDict)
let otherDict.myFunction = myDict.myFunction
call otherDict.myFunction()
ここでは、"self" は "myDict" である。なぜなら明示的にバインドされているからで
ある。
1.3 リスト ~
*list* *List* *Lists* *E686*
リストとは順序を保つ要素の列である。要素はどんな型でもよい。要素へはインデック
ス番号を使ってアクセスする。列の任意の位置に要素を追加したり削除することができ
る。
リストの作成 ~
*E696* *E697*
リストを作るには、[]の中にコンマで区切って要素を書く。
例: >
:let mylist = [1, two, 3, "four"]
:let emptylist = []
要素はどんな式でもよい。要素としてリストを指定すると、リストのリストができる:
>
:let nestlist = [[11, 12], [21, 22], [31, 32]]
最後の要素の後に余分なコンマがあると無視される。
リストのインデックス ~
*list-index* *E684*
リストの要素にアクセスするには、リスト名の後に[]を書き、その中にインデックスを
書く。インデックスは0基点(つまり最初の要素のインデックスは0)である。 >
:let item = mylist[0] " 最初の要素(1)を取得
:let item = mylist[2] " 3番目の要素(3)を取得
取得した要素がリストならば、さらに続けてインデックスを書くことができる: >
:let item = nestlist[0][1] " 最初のリストの2番目の要素(12)を取得
<
負のインデックスを指定すると、リストの末尾から数えられる。インデックス-1は最後
の要素を示し、-2は最後から2番目を指す >
:let last = mylist[-1] " 最後の要素("four")を取得
無効なインデックスによるエラーを回避するには関数|get()|を使う。するとインデッ
クスが無効な場合は、0かまたは自分で指定した既定値が返る: >
:echo get(mylist, idx)
:echo get(mylist, idx, "NONE")
リストの連結 ~
*list-concatenation*
2つのリストを連結するには演算子 "+" を使う: >
:let longlist = mylist + [5, 6]
:let longlist = [5, 6] + mylist
1個の要素を先頭または末尾に付け加えるには、[]で囲んでリストにして連結する。
リストは |:let+=| もしくは |extend()| を使うことで、他のリストとその場で連結す
ることができる: >
:let mylist += [7, 8]
:call extend(mylist, [7, 8])
<
リストをその場で変更する他の方法については |list-modification| を参照。
部分リスト ~
*sublist*
リストの一部分を取り出すには、[]の中に始点と終点のインデックスを書き、コロンで
区切る: >
:let shortlist = mylist[2:-1] " リスト[3, "four"]を得る
始点のインデックスを省略すると0となる。終点のインデックスを省略すると-1となる >
:let endlist = mylist[2:] " 2番目から最後まで: [3, "four"]
:let shortlist = mylist[2:2] " 1個の要素からなるリスト: [3]
:let otherlist = mylist[:] " リストのコピーを作る
最後のインデックスが含まれることに注意。排他的なインデックスを利用するなら
|slice()| メソッドを利用する。
終点のインデックスが始点のインデックスよりも前になってしまった場合は空リストと
なる。エラーメッセージは表示されない。
終点のインデックスがリストの長さより大きい場合は、長さ-1を指定したときと同じに
なる: >
:let mylist = [0, 1, 2, 3]
:echo mylist[2:8] " 結果: [2, 3]
NOTE: mylist[s:e]と書くと変数 "s:e" をインデックスとして使ったと解釈される。
":" の前に1文字の変数を使うときは十分注意すること。必要ならこのようにスペース
を入れるとよい: mylist[s : e].
リストの同一性 ~
*list-identity*
変数 "aa" がリストであり、それを別の変数 "bb" に代入したとすると、両方とも同じ
変数を参照するようになる。よってリスト "aa" を変更すると "bb" も変更される: >
:let aa = [1, 2, 3]
:let bb = aa
:call add(aa, 4)
:echo bb
< [1, 2, 3, 4]
リストのコピーを作るには関数|copy()|を使う。前述の通り[:]を使ってもできる。こ
れは浅いコピーである。つまりリストの要素であるリストに変更を加えると、コピーさ
れたリスト内の同じ要素も変更される: >
:let aa = [[1, 'a'], 2, 3]
:let bb = copy(aa)
:call add(aa, 4)
:let aa[0][1] = 'aaa'
:echo aa
< [[1, aaa], 2, 3, 4] >
:echo bb
< [[1, aaa], 2, 3]
完全に独立したコピーを作るには|deepcopy()|を使う。これは再帰的にリストの要素の
コピーを作る。ただし深さは100レベルまでである。
2つの変数が同じリストを指しているかは演算子 "is" で判定できる。"isnot" はその
逆である。一方、"==" は2つのリストが同じ値を持っているかを判定する。 >
:let alist = [1, 2, 3]
:let blist = [1, 2, 3]
:echo alist is blist
< 0 >
:echo alist == blist
< 1
Note リストの比較について注意: 2つのリストは、同じ長さを持ち、全要素が "==" の
意味で等しいとき、等しいとみなされる。ただ、1つ例外がある: 数値と文字列を比較
するとそれらは異なるとみなされる。変数に対して "==" で比較したときに行われるよ
うな自動的な型変換は行われない。例: >
echo 4 == "4"
< 1 >
echo [4] == ["4"]
< 0
つまり、リストの比較は数値や文字列の比較よりも厳格である。単純な値もリストに入
れることによりこの方法で比較することができる: >
:let a = 5
:let b = "5"
:echo a == b
< 1 >
:echo [a] == [b]
< 0
リストのアンパック ~
リストの要素を個々の変数としてアンパックするには、[]の中に変数を書く: >
:let [var1, var2] = mylist
変数の個数とリストの要素数が一致しないときはエラーになる。リストにある余分な要
素をまとめて受け取るには、";" と受け取る変数名を書いておく: >
:let [var1, var2; rest] = mylist
上の例は次とほぼ同じである: >
:let var1 = mylist[0]
:let var2 = mylist[1]
:let rest = mylist[2:]
要素が 2 つしかないときでもエラーにはならない。"rest" は空リストになる。
リストの変更 ~
*list-modification*
リストの中の特定の要素を変更するには次のように|:let|を使う: >
:let list[4] = "four"
:let listlist[0][3] = item
始点と終点を指定してリストの一部分を変更することができる。代入する値は、少なく
とも削除する範囲の要素数と同じ数だけ必要である: >
:let list[3:5] = [3, 4, 5]
リストに要素をその場で追加するには、|:let+=| (|list-concatenation|) を使うこと
ができる: >
:let listA = [1, 2]
:let listA += [3, 4]
<
2 つのリストが同じリストを参照している時は、片方のリストをその場で変更すると、
他方のリストもその場で変更される: >
:let listA = [1, 2]
:let listB = listA
:let listB += [3, 4]
:echo listA
[1, 2, 3, 4]
<
リストに要素を追加したり削除するには関数を使う。いくつか例を示す: >
:call insert(list, 'a') " 先頭に要素 'a' を挿入する
:call insert(list, 'a', 3) " 要素 'a' をlist[3]の前に挿入する
:call add(list, "new") " 文字列の要素を最後に追加する
:call add(list, [1, 2]) " 1個の要素としてリストを追加する
:call extend(list, [1, 2]) " 2個の要素からなるリストを連結する
:let i = remove(list, 3) " 要素3を削除する
:unlet list[3] " 同上
:let l = remove(list, 3, -1) " 要素3から最後までを削除する
:unlet list[3 : ] " 同上
:call filter(list, 'v:val !~ "x"') " 要素 'x' を削除
要素の順番を変更する: >
:call sort(list) " リストをアルファベット順にソート
:call reverse(list) " 要素の順序を反転させる
:call uniq(sort(list)) " ソートして重複を削除する
for ループ ~
|:for| ループは、リスト、文字列または Blob の各要素に対してコマンドを実行する。
変数に各要素が順番に代入される。リストを使った例: >
:for item in mylist
: call Doit(item)
:endfor
上の例は次と同じ: >
:let index = 0
:while index < len(mylist)
: let item = mylist[index]
: :call Doit(item)
: let index = index + 1
:endwhile
やりたいことがリストの各要素を変更するだけなら、forループを使うより関数|map()|
を使った方がよりシンプルになる。
|:let|コマンドと同じように、|:for|は変数のリストをループ変数にすることができる。
この場合、引数はリストのリストでなければならない。 >
:for [lnum, col] in [[1, 3], [2, 8], [3, 0]]
: call Doit(lnum, col)
:endfor
これはリストの各要素に対して|:let|コマンドを実行するかのように実行される。また
この場合も引数の型は全て同じでないとエラーになる。
引数の残りを1個のリスト変数に代入することもできる: >
:for [i, j; rest] in listlist
: call Doit(i, j)
: if !empty(rest)
: echo "remainder: " .. string(rest)
: endif
:endfor
Blob の場合、一度に 1 バイトが使われる。
文字列の場合、任意の合成文字を含む 1 文字が文字列として使われる。例: >
for c in text
echo 'This character is ' .. c
endfor
リスト操作関数 ~
*E714*
以下はリスト操作に使える関数である: >
:let r = call(funcname, list) " 引数リストをつけて関数を呼び出す
:if empty(list) " リストが空かどうか判定する
:let l = len(list) " リストの要素数
:let big = max(list) " リスト中の最大値
:let small = min(list) " リスト中の最小値
:let xs = count(list, 'x') " 'x' の出現回数を数える
:let i = index(list, 'x') " 最初に 'x' が現れる位置のインデックス
:let lines = getline(1, 10) " バッファから10行を取得
:call append('$', lines) " バッファに行を追加する
:let list = split("a b c") " 文字列を分割してリストにする
:let string = join(list, ', ') " リストの要素を連結して文字列にする
:let s = string(list) " リストの文字列表現
:call map(list, '">> " .. v:val') " 各要素の前に ">> " をつける
機能を組み合わせると、処理を単純に記述できることを覚えておくとよい。例えば、リ
スト中の全ての数値の和を求める例: >
:exe 'let sum = ' .. join(nrlist, '+')
1.4 辞書 ~
*dict* *Dict* *Dictionaries* *Dictionary*
辞書とは連想配列である。各要素はキーと値を持つ。要素はキーによって特定できる。
要素は特に順序を持たずに保持される。
辞書の作成 ~
*E720* *E721* *E722* *E723*
辞書を作るには、{}の中にコンマで区切って要素を書く。各要素のキーと値はコロンで
区切る。それぞれのキーは1度しか現れてはならない。例: >
:let mydict = {1: 'one', 2: 'two', 3: 'three'}
:let emptydict = {}
< *E713* *E716* *E717*
キーは必ず文字列である。数値を使うこともできるが、自動的に文字列に変換される。
よって文字列 '4' のキーと数値4のキーは同一の要素を参照する。
Note 文字列 '04' と数値04は異なることに注意。先頭の0が削除されてから数値が文字
列 '4' に変換されるためである。空文字列もまたキーとして使用できる。
|Vim9| script では、キーが英数字、アンダースコア、ダッシュのみで構成されている
場合に、リテラルのキーが使える。|vim9-literal-dict| を参照。
*literal-Dict* *#{}*
すべてのキーを引用符で囲む必要を避けるために、旧来のスクリプトでは #{} 形式を
使用できる。この形式は、ASCII文字、数字、'-' および '_' のみで構成されるキーを
必要とする。
例: >
:let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3}
Note ここでは 333 は 文字列 "333" であることに注意。空のキーは #{} を使うこと
ができない。
|Vim9| script では #{} 形式は使用できない、なぜならコメントの開始と紛らわしい
ためである。
値はどんな式でもよい。辞書を値にすると、ネストした辞書ができる: >
:let nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}}
最後の要素の後に余分なコンマがあると無視される。
要素にアクセスする ~
通常、要素にアクセスするには[]の中にキーを書く: >
:let val = mydict["one"]
:let mydict["four"] = 4
また、この書き方で既存の辞書に要素を追加できる。この点はリストと異なる。
キー名がアルファベット、数字、アンダースコアだけからなる場合は、以下の形式が使
える|expr-entry|: >
:let val = mydict.one
:let mydict.four = 4
要素はリストや辞書を含むどんな型でもよいため、インデックス参照とキー参照を続け
て書くことができる: >
:echo dict.key[idx].key
辞書からリストへの変換 ~
辞書の全要素に対してループを行いたい場合がある。そのためには辞書をリストに変換
し、そのリストに対して|:for|ループを行う。
多くの場合はキーに対してループを行う。これには関数|keys()|を使う: >
:for key in keys(mydict)
: echo key .. ': ' .. mydict[key]
:endfor
このキーのリストはソートされていない。ソートさせるには関数|sort()|を使う: >
:for key in sort(keys(mydict))
値に対してループを行うには関数|values()|を使う: >
:for v in values(mydict)
: echo "value: " .. v
:endfor
キーと値両方を得るには関数|items()|を使う。この関数は、キーと値の2個の要素から
なるリストのリストを返す: >
:for [key, value] in items(mydict)
: echo key .. ': ' .. value
:endfor
辞書の同一性 ~
*dict-identity*
辞書のコピーを作るにはリストと同様に|copy()|と|deepcopy()|を使う必要がある。そ
うでなく代入を行うと同一の辞書を参照するようになる: >
:let onedict = {'a': 1, 'b': 2}
:let adict = onedict
:let adict['a'] = 11
:echo onedict['a']
11
2つの辞書は、全てのキー・値のペアが等しいとき等しいとみなされる。より詳しくは
|list-identity|を参照。
辞書の変更 ~
*dict-modification*
辞書の要素を変更したり、新しい要素を追加するには|:let|を使う: >
:let dict[4] = "four"
:let dict['one'] = item
辞書から要素を取り除くには|remove()|か|:unlet|を使う。以下のように辞書からキー
"aaa" を取り除くには3つの方法がある: >
:let i = remove(dict, 'aaa')
:unlet dict.aaa
:unlet dict['aaa']
2つの辞書を併合させるには|extend()|を使う: >
:call extend(adict, bdict)
上のコマンドはbdictの全ての要素をadictに追加する。キーが重複した要素はbdictの
要素により上書きされる。この動作は3番目の引数により変更できる。
Note 辞書の要素間に順序は定まっていない。そのため ":echo adict" としたとき、も
ともとadictにあった要素が先に、bdictから追加された要素が後に表示されると考えて
はならない。
辞書から条件を指定して要素を取り除くには|filter()|が使える: >
:call filter(dict, 'v:val =~ "x"')
このコマンドは "dict" から 'x' にマッチしない要素を全て取り除く。
このコマンドで全てのエントリを除去することもできる: >
call filter(dict, 0)
状況によっては辞書から項目削除や追加が許可されない。とりわけ全項目を列挙してい
る時がそうである。その場合 *E1313* あるいは他のエラーが発生する。
関数を辞書に入れる ~
*Dictionary-function* *self* *E725* *E862*
関数が "dict" 属性つきで定義されると、特殊な方法で呼び出すことができる。例: >
:function Mylen() dict
: return len(self.data)
:endfunction
:let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
:echo mydict.len()
これはオブジェクト指向プログラミングのメソッドに似ている。この辞書の要素は
|Funcref|である。暗黙に定義されるローカル変数 "self" は、この関数を呼び出した
辞書を参照している。|Vim9| script 使用時は、クラスとオブジェクトを使うことがで
きる、`:class` を参照。
"dict" 属性をつけないでFuncrefを辞書に入れることもできる。しかしその場合、変
数 "self" は定義されない。
*numbered-function* *anonymous-function*
関数に名前をつける必要をなくすために、関数を定義して直接辞書に代入することがで
きる: >
:let mydict = {'data': [0, 1, 2, 3]}
:function mydict.len()
: return len(self.data)
:endfunction
:echo mydict.len()
こうすると関数に番号がふられ、dict.lenがこの関数を参照する|Funcref|となる。こ
の関数は|Funcref|を通してのみ呼び出せる。参照している|Funcref|がなくなると、こ
の関数は自動的に削除される。
番号付き関数には "dict" 属性を付ける必要はない。
番号付き関数でエラーが発生したときは、あるトリックを使うことで発生源を確認でき
る。例えば 42 という関数なら次のようにする: >
:function g:42
辞書操作関数 ~
*E715*
以下は辞書操作に使える関数である: >
:if has_key(dict, 'foo') " 辞書がキー "foo" の要素を持つなら真
:if empty(dict) " 辞書が空なら真
:let l = len(dict) " 辞書の要素数
:let big = max(dict) " 辞書中の最大値
:let small = min(dict) " 辞書中の最小値
:let xs = count(dict, 'x') " 'x' の出現回数を数える
:let s = string(dict) " 辞書の文字列表現
:call map(dict, '">> " .. v:val') " 各要素の前に ">> " をつける
1.5 Blobs ~
*blob* *Blob* *Blobs* *E978*
Blobは、バイナリオブジェクトである。例えば、ファイルから画像を読んでチャネルを
通し送信することなどに使える。
Blobは、ほとんどの場合、数値の |List| のように振る舞う。数値は、0 から 255 の
8ビットの値を持つ。
Blobの作成 ~
BlobはBlobリテラル |blob-literal| を使って作成できる: >
:let b = 0zFF00ED015DAF
読みやすくするために、ドットをバイト間(16進文字のペア)に挿入することができる。
ドットは値を変更しない: >
:let b = 0zFF00.ED01.5DAF
Blobは |readfile()| で引数{type}を "B" に設定してファイルから読み込むことがで
きる。例: >
:let b = readfile('image.png', 'B')
Blobは、|ch_readblob()| 関数を使用してチャネルから読み取ることができる。
Blobのインデックス ~
*blob-index* *E979*
Blob内のバイトは、Blobの後ろに角括弧でインデックスを入れることによってアクセス
することができる。インデックスは 0 から始まるため、最初のバイトのインデックス
は 0 になる。 >
:let myblob = 0z00112233
:let byte = myblob[0] " 1番目のバイトを取得: 0x00
:let byte = myblob[2] " 3番目のバイトを取得: 0x22
負のインデックスは終端から数えられる。インデックス -1 はBlobの最後のバイト、-2
は最後の1つ前のバイトを表す。 >
:let last = myblob[-1] " 最後のバイトを取得: 0x33
無効なインデックスに対するエラーを回避するには、|get()| 関数を使用すること。項
目が利用できない場合、-1 または指定したデフォルト値が返される: >
:echo get(myblob, idx)
:echo get(myblob, idx, 999)
Blobの繰り返し ~
|:for| ループは、Blobの各バイトに対してコマンドを実行する。ループ変数はBlobの
各バイトに設定される。例: >
:for byte in 0z112233
: call Doit(byte)
:endfor
これは、0x11, 0x22 および 0x33 で Doit() を呼び出す。
Blobの連結 ~
*blob-concatenation*
2つのBlobは "+" 演算子で連結できる: >
:let longblob = myblob + 0z4455
:let longblob = 0z4455 + myblob
<
Blob は |:let+=| を使うことで、他の Blob とその場で連結することができる: >
:let myblob += 0z6677
<
Blob をその場で変更する他の方法については、|blob-modification| を参照。
Blobの一部 ~
Blobの一部は、角括弧内のコロンで区切られた最初と最後のインデックスを指定するこ
とによって取得できる: >
:let myblob = 0z00112233
:let shortblob = myblob[1:2] " 0z1122 を取得
:let shortblob = myblob[2:-1] " 0z2233 を取得
最初のインデックスを省略することはゼロと同じである。最後のインデックスを省略す
ることは -1 と同じである。 >
:let endblob = myblob[2:] " 項目2から終端まで: 0z2233
:let shortblob = myblob[2:2] " 1バイトのBlob: 0z22
:let otherblob = myblob[:] " Blobのコピーを作成
最初のインデックスがBlobの最後のバイトを超えている場合、または2番目のインデッ
クスが最初のインデックスより前にある場合、結果は空のBlobになる。エラーメッセー
ジはない。
2番目のインデックスがリストの長さ以上の場合、長さから 1 を引いたものが使用され
る: >
:echo myblob[2:8] " result: 0z2233
Blobの変更 ~
*blob-modification* *E1184*
Blobの特定のバイトを変更するには、 |:let| を使用する: >
:let blob[4] = 0x44
インデックスがBlobの終端を1つ超える場合は、それが追加される。それより上のイン
デックスはエラーである。
バイトシーケンスを変更するには、[:] 表記が使用できる: >
let blob[1:3] = 0z445566
置き換えられたバイトの長さは、提供された値と丁度同じでなければならない。 *E972*
Blobの一部を変更するには、変更する最初と最後のバイトを指定する。値の範囲内のバ
イト数は同じでなければならない: >
:let blob[3:5] = 0z334455
Blob に要素をその場で追加するには、|:let+=| (|blob-concatenation|)を使うことが
できる: >
:let blobA = 0z1122
:let blobA += 0z3344
<
2 つの Blob が同じ Blob を参照している時は、片方の Blob をその場で変更すると、
他方の Blob もその場で変更される: >
:let blobA = 0z1122
:let blobB = blobA
:let blobB += 0z3344
:echo blobA
0z11223344
<
関数 |add()|, |remove()| および |insert()| も使用できる。
Blobの同一性 ~
Blobは等しいかどうか比較することができる: >
if blob == 0z001122
または、同一性の等しさのために: >
if blob is otherblob
< *blob-identity* *E977*
変数 "aa" がBlobで、別の変数 "bb" に代入すると、両方の変数は同じBlobを参照す
る。そして、"is" 演算子はtrueを返す。
[:] または |copy()| を使用してコピーを作成する場合、値は同じだが、同一性は異な
る: >
:let blob = 0z112233
:let blob2 = blob
:echo blob == blob2
< 1 >
:echo blob is blob2
< 1 >
:let blob3 = blob[:]
:echo blob == blob3
< 1 >
:echo blob is blob3
< 0
Blobのコピーを作成するには、|copy()| 関数を使用する。[:] を使っても上で説明し
たように動作する。
1.6 変数について補足 ~
*more-variables*
変数や式の結果の型を知りたいのならば、関数|type()|を使う。
オプション 'viminfo' にフラグ '!' が含まれるならば、大文字で始まり小文字を含ま
ない名前のグローバル変数は、viminfoファイル|viminfo-file|に格納される。
オプション 'sessionoptions' が "global" を含むなら、大文字で始まり少なくとも一
文字以上の小文字を含む名前のグローバル変数は、sessionファイル|session-file|に
格納される。
変数名 何処に保存されるか ~
my_var_6 されない
My_Var_6 sessionファイル
MY_VAR_6 viminfoファイル
旧来のスクリプトでは波括弧を使って変数名を構成できる。詳細は
|curly-braces-names| を参照。
==============================================================================
2. 式の文法 *expression-syntax*
*E1143*
式文法一覧、優先順位の低いものから高い順に:
|expr1| expr2
expr2 ? expr1 : expr1 if-then-else 条件式
|expr2| expr3
expr3 || expr3 ... 論理和
|expr3| expr4
expr4 && expr4 ... 論理積
|expr4| expr5
expr5 == expr5 等しい
expr5 != expr5 等しくない
expr5 > expr5 より大きい
expr5 >= expr5 大きいか等しい
expr5 < expr5 より小さい
expr5 <= expr5 小さいか等しい
expr5 =~ expr5 正規表現にマッチする
expr5 !~ expr5 正規表現にマッチしない
expr5 ==? expr5 文字列として等しい(大文字/小文字区別無し)
expr5 ==# expr5 文字列として等しい(大文字/小文字区別有り)
etc. 上記の各式は大小文字の区別を、?を付加すると行
わず、#を付加すると行う
expr5 is expr5 同一のリスト |List|、辞書 |Dictionary| または
|Blob| のインスタンス
expr5 isnot expr5 異なるリスト |List|、辞書 |Dictionary| または
|Blob| のインスタンス
|expr5| expr6
expr6 << expr6 ビット単位の左シフト
expr6 >> expr6 ビット単位の右シフト
|expr6| expr7
expr7 + expr7 ... 足し算、リストまたはBlobの連結
expr7 - expr7 ... 引き算
expr7 . expr7 ... 文字列の連結
expr7 .. expr7 ... 文字列の連結
|expr7| expr8
expr8 * expr8 ... 掛け算
expr8 / expr8 ... 割り算
expr8 % expr8 ... 剰余(割った余り)
|expr8| expr9
<type>expr9 型のチェックと変換 (|Vim9| のみ)
|expr9| expr10
! expr9 論理否定
- expr9 単項のマイナス
+ expr9 単項のプラス
|expr10| expr11
expr10[expr1] 文字列のバイト、またはリストの要素
expr10[expr1 : expr1] 文字列の部分文字列、またはリストの部分リスト
expr10.name 辞書 |Dictionary| の要素
expr10(expr1, ...) |Funcref| 変数による関数呼び出し
expr10->name(expr1, ...) |method| 呼び出し
|expr11| number 数定数
"string" 文字列定数。バックスラッシュは特別な意味を持つ
'string' リテラル文字列定数。'を含めるには2重にする
[expr1, ...] リスト |List|
{expr1: expr1, ...} 辞書 |Dictionary|
#{key: expr1, ...} 旧来の辞書 |Dictionary|
&option オプション変数
(expr1) 式の入れ子
variable 内部変数
va{ria}ble 波括弧付きの内部変数
$VAR 環境変数
@r レジスタ 'r' の値
function(expr1, ...) 関数呼出し
func{ti}on(expr1, ...) 波括弧付きの関数呼出し
{args -> expr1} 旧来のラムダ式
(args) => expr1 Vim9 のラムダ式
"..." はその演算が、その後に他の演算を続ける事ができることを示している。
例: >
&nu || &list && &shell == "csh"
一つのレベルにある全ての式は左から右に解釈される。
式のネストはスタックの不足とクラッシュの回避のため深さ1000段(MSVCでのビルドで
は300)までに制限されている。 *E1169*
expr1 *expr1* *ternary* *falsy-operator* *??* *E109*
-----
三項演算子: expr2 ? expr1 : expr1
Falsy 演算子: expr2 ?? expr1
三項演算子 ~
旧来のスクリプトでは '?' より前の式は数値として評価される。その結果が|TRUE|で
あった場合、'?' と ':' に挟まれた式の値がこの式全体の値となり、そうでなかった
場合は ':' 以降の式の値が全体の値となる。
|Vim9| script では最初の式は真偽値として評価される必要がある。|vim9-boolean|
を参照。
例: >
:echo lnum == 1 ? "先頭" : lnum
始めの式が "expr2" であるから、そこに別の?:を含むことはできない。残り二つの式
については以下のように再帰的な?:の利用が許される。
例: >
:echo lnum == 1 ? "top" : lnum == 1000 ? "last" : lnum
読み易くするために、行継続|line-continuation|を利用することが推奨される: >
:echo lnum == 1
:\ ? "top"
:\ : lnum == 1000
:\ ? "last"
:\ : lnum
':' の前には必ずスペースを入れること。そうでないと "a:1" のような変数の使用と
間違えてしまう可能性がある。
Falsy 演算子 ~
これは "null合体演算子" としても知られている、しかし複雑すぎるため、単に Falsy
演算子と呼ぶことにした。
'??' の前の式が評価される。|truthy| と評価された場合、これが結果として使われ
る。
そうでないなら、'??' の後の式が評価され、結果として使われる。これがもっとも便
利なのは、ゼロや空な結果になりうる式でデフォルト値を持つ場合: >
echo theList ?? 'list is empty'
echo GetName() ?? 'unknown'
これは同等だが、同じではない: >
expr2 ?? expr1
expr2 ? expr2 : expr1
2行目は "expr2" が2度評価される。そして |Vim9| script であれば "?" 前の expr2
の型が真偽値でなければならない。