-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
ble-edit.sh
7374 lines (6660 loc) · 233 KB
/
ble-edit.sh
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
#!/bin/bash
# **** sections ****
#
# @text.c2w
# @edit/draw
# @line.ps1
# @textmap
# @line.text
# @line.info
# @edit
# @edit.ps1
# @textarea
# @textarea.buffer
# @textarea.render
# @widget.clear
# @widget.mark
# @edit.bell
# @edit.insert
# @edit.delete
# @edit.cursor
# @edit.word
# @edit.exec
# @edit.accept
# @history
# @history.isearch
# @comp
# @bind
# @bind.bind
## オプション char_width_mode
## 文字の表示幅の計算方法を指定します。
## bleopt_char_width_mode=east
## Unicode East_Asian_Width=A (Ambiguous) の文字幅を全て 2 とします
## bleopt_char_width_mode=west
## Unicode East_Asian_Width=A (Ambiguous) の文字幅を全て 1 とします
## bleopt_char_width_mode=emacs
## emacs で用いられている既定の文字幅の設定です
## 定義 ble/util/c2w+$bleopt_char_width_mode
: ${bleopt_char_width_mode:=east}
: ${bleopt_emoji_width:=2}
function bleopt/check:char_width_mode {
if ! ble/util/isfunction "ble/util/c2w+$value"; then
echo "bleopt: Invalid value char_width_mode='$value'. A function 'ble/util/c2w+$value' is not defined." >&2
return 1
fi
}
## オプション edit_vbell
## 編集時の visible bell の有効・無効を設定します。
## bleopt_edit_vbell=1
## 有効です。
## bleopt_edit_vbell=
## 無効です。
: ${bleopt_edit_vbell=}
## オプション edit_abell
## 編集時の audible bell (BEL 文字出力) の有効・無効を設定します。
## bleopt_edit_abell=1
## 有効です。
## bleopt_edit_abell=
## 無効です。
: ${bleopt_edit_abell=1}
## オプション history_lazyload
## bleopt_history_lazyload=1
## ble-attach 後、初めて必要になった時に履歴の読込を行います。
## bleopt_history_lazyload=
## ble-attach 時に履歴の読込を行います。
##
## bash-3.1 未満では history -s が思い通りに動作しないので、
## このオプションの値に関係なく ble-attach の時に履歴の読み込みを行います。
: ${bleopt_history_lazyload=1}
## オプション delete_selection_mode
## 文字挿入時に選択範囲をどうするかについて設定します。
## bleopt_delete_selection_mode=1 (既定)
## 選択範囲の内容を新しい文字で置き換えます。
## bleopt_delete_selection_mode=
## 選択範囲を解除して現在位置に新しい文字を挿入します。
: ${bleopt_delete_selection_mode=1}
## オプション default_keymap
## 既定の編集モードに使われるキーマップを指定します。
## bleopt_default_keymap=auto
## [[ -o emacs/vi ]] の状態に応じて emacs/vi を切り替えます。
## bleopt_default_keymap=emacs
## emacs と同様の編集モードを使用します。
## bleopt_default_keymap=vi
## vi と同様の編集モードを使用します。
: ${bleopt_default_keymap:=auto}
function bleopt/check:default_keymap {
case $value in
(auto|emacs|vi|safe) ;;
(*)
echo "bleopt: Invalid value default_keymap='value'. The value should be one of \`auto', \`emacs', \`vi'." >&2
return 1 ;;
esac
}
## オプション indent_offset
## シェルのインデント幅を指定します。既定では 4 です。
: ${bleopt_indent_offset:=4}
## オプション indent_tabs
## インデントにタブを使用するかどうかを指定します。
## 0 を指定するとインデントに空白だけを用います。
## それ以外の場合はインデントにタブを使用します。
: ${bleopt_indent_tabs:=1}
## オプション tab_width
## タブの表示幅を指定します。
##
## bleopt_tab_width= (既定)
## 空文字列を指定したときは $(tput it) を用います。
## bleopt_tab_width=NUM
## 数字を指定したときはその値をタブの幅として用います。
: ${bleopt_tab_width:=}
function bleopt/check:tab_width {
if [[ $value ]] && (((value=value)<=0)); then
echo "bleopt: an empty string or a positive value is required for tab_width." >&2
return 1
fi
}
## オプション undo_point
## undo/redo 実行直後のカーソル位置を設定します。
##
## undo_point=beg
## undo/redo によって変化のあった範囲の先頭に移動します。
## undo_point=end
## undo/redo によって変化のあった範囲の末端に移動します。
## その他の時
## undo/redo 後の状態が記録された時のカーソル位置を復元します。
##
: ${bleopt_undo_point=end}
## オプション edit_forced_textmap
## 1 が設定されているとき、矩形選択に先立って配置計算を強制します。
## 0 が設定されているとき、配置情報があるときにそれを使い、
## 配置情報がないときは論理行・論理列による矩形選択にフォールバックします。
##
: ${bleopt_edit_forced_textmap:=1}
function ble/edit/use-textmap {
ble/textmap#is-up-to-date && return 0
((bleopt_edit_forced_textmap)) || return 1
ble/widget/.update-textmap
return 0
}
## オプション exec_type (内部使用)
## コマンドの実行の方法を指定します。
##
## exec_type=exec
## 関数内で実行します (従来の方法です。将来的に削除されます)
## exec_type=gexec
## グローバルな文脈で実行します (新しい方法です)
##
## 要件: 関数 ble-edit/exec:$bleopt_exec_type/process が定義されていること。
: ${bleopt_exec_type:=gexec}
function bleopt/check:exec_type {
if ! ble/util/isfunction "ble-edit/exec:$value/process"; then
echo "bleopt: Invalid value exec_type='$value'. A function 'ble-edit/exec:$value/process' is not defined." >&2
return 1
fi
}
## オプション suppress_bash_output (内部使用)
## bash 自体の出力を抑制するかどうかを指定します。
## bleopt_suppress_bash_output=1
## 抑制します。bash のエラーメッセージは visible-bell で表示します。
## bleopt_suppress_bash_output=
## 抑制しません。bash のメッセージは全て端末に出力されます。
## これはデバグ用の設定です。bash の出力を制御するためにちらつきが発生する事があります。
## bash-3 ではこの設定では C-d を捕捉できません。
: ${bleopt_suppress_bash_output=1}
## オプション ignoreeof_message (内部使用)
## bash-3.0 の時に使用します。C-d を捕捉するのに用いるメッセージです。
## これは自分の bash の設定に合わせる必要があります。
: ${bleopt_ignoreeof_message:='Use "exit" to leave the shell.'}
#
#------------------------------------------------------------------------------
# **** char width **** @text.c2w
# ※注意 [ -~] の範囲の文字は全て幅1であるという事を仮定したコードが幾らかある
# もしこれらの範囲の文字を幅1以外で表示する端末が有ればそれらのコードを実装し
# 直す必要がある。その様な変な端末があるとは思えないが。
## 関数 ble/util/c2w ccode
## @var[out] ret
function ble/util/c2w {
"ble/util/c2w+$bleopt_char_width_mode" "$1"
}
## 関数 ble/util/c2w-edit ccode
## 編集画面での表示上の文字幅を返します。
## @var[out] ret
function ble/util/c2w-edit {
if (($1<32||127<=$1&&$1<160)); then
# 制御文字は ^? と表示される。
ret=2
# TAB は???
# 128-159: M-^?
((128<=$1&&(ret=4)))
else
ble/util/c2w "$1"
fi
}
# ## 関数 ble/util/c2w-edit ccode
# ## @var[out] ret
# function ble/util/s2w {
# ble/util/s2c "$1" "$2"
# "ble/util/c2w+$bleopt_char_width_mode" "$ret"
# }
# ---- 文字種判定 -------------------------------------------------------------
## 配列 _ble_util_c2w_non_zenkaku
## 飛び地になっている全角でない文字
_ble_util_c2w_non_zenkaku=(
[0x303F]=1 # 半角スペース
[0x3030]=-2 [0x303d]=-2 [0x3297]=-2 [0x3299]=-2 # 絵文字
)
## 関数 ble/util/c2w/.determine-unambiguous
## @var[out] ret
function ble/util/c2w/.determine-unambiguous {
local code=$1
if ((code<0xA0)); then
ret=1
return
fi
# 取り敢えず曖昧
ret=-1
# 以下は全角に確定している範囲
if ((code<0xFB00)); then
((0x2E80<=code&&code<0xA4D0&&!_ble_util_c2w_non_zenkaku[code]||
0xAC00<=code&&code<0xD7A4||
0xF900<=code||
0x1100<=code&&code<0x1160||
code==0x2329||code==0x232A)) && ret=2
elif ((code<0x10000)); then
((0xFF00<=code&&code<0xFF61||
0xFE30<=code&&code<0xFE70||
0xFFE0<=code&&code<0xFFE7)) && ret=2
else
((0x20000<=code&&code<0x2FFFE||
0x30000<=code&&code<0x3FFFE)) && ret=2
fi
}
## 配列 _ble_text_c2w_emoji_wranges
##
## https://github.com/vim-jp/issues/issues/1086 にある表を
## 以下の関数で加工した。
##
## function process {
## local -i begin=$1 end=$(($2+1))
## printf ' %s %s' "$begin" "$end"
## }
##
_ble_text_c2w_emoji_wranges=(
8252 8253 8265 8266 8482 8483 8505 8506 8596 8602 8617 8619 8986 8988
9000 9001 9167 9168 9193 9204 9208 9211 9410 9411 9642 9644 9654 9655
9664 9665 9723 9727 9728 9733 9742 9743 9745 9746 9748 9750 9752 9753
9757 9758 9760 9761 9762 9764 9766 9767 9770 9771 9774 9776 9784 9787
9792 9793 9794 9795 9800 9812 9824 9825 9827 9828 9829 9831 9832 9833
9851 9852 9855 9856 9874 9880 9881 9882 9883 9885 9888 9890 9898 9900
9904 9906 9917 9919 9924 9926 9928 9929 9934 9936 9937 9938 9939 9941
9961 9963 9968 9974 9975 9979 9981 9982 9986 9987 9989 9990 9992 9998
9999 10000 10002 10003 10004 10005 10006 10007 10013 10014 10017 10018
10024 10025 10035 10037 10052 10053 10055 10056 10060 10061 10062 10063
10067 10070 10071 10072 10083 10085 10133 10136 10145 10146 10160 10161
10175 10176 10548 10550 11013 11016 11035 11037 11088 11089 11093 11094
# 12336 12337 12349 12350 12951 12952 12953 12954 これらは特別に処理する。
126980 126981
127183 127184 127344 127346 127358 127360 127374 127375 127377 127387
127462 127488 127489 127491 127514 127515 127535 127536 127538 127547
127568 127570 127744 127778 127780 127892 127894 127896 127897 127900
127902 127985 127987 127990 127991 128254 128255 128318 128329 128335
128336 128360 128367 128369 128371 128379 128391 128392 128394 128398
128400 128401 128405 128407 128420 128422 128424 128425 128433 128435
128444 128445 128450 128453 128465 128468 128476 128479 128481 128482
128483 128484 128488 128489 128495 128496 128499 128500 128506 128592
128640 128710 128715 128723 128736 128742 128745 128746 128747 128749
128752 128753 128755 128761 129296 129339 129340 129343 129344 129350
129351 129357 129360 129388 129408 129432 129472 129473 129488 129511)
## 関数 ble/util/c2w/is-emoji code
## @param[in] code
function ble/util/c2w/is-emoji {
local code=$1
((8252<=code&&code<=0x2b55||0x1f004<code&&code<=0x1f9e6)) || return 1
# 0x3030 - 0x3299
((0x3030<=code&&code<=0x3299&&_ble_util_c2w_non_zenkaku[code]!=-2)) && return 1
local l=0 u=${#_ble_text_c2w_emoji_wranges[@]} m
while ((l+1<u)); do
((_ble_text_c2w_emoji_wranges[m=(l+u)/2]<=code?(l=m):(u=m)))
done
(((l&1)==0)); return
}
# ---- char_width_mode ---------------------------------------------------------
## 関数 ble/util/c2w+emacs
## emacs-24.2.1 default char-width-table
## @var[out] ret
_ble_text_c2w__emacs_wranges=(
162 164 167 169 172 173 176 178 180 181 182 183 215 216 247 248 272 273 276 279
280 282 284 286 288 290 293 295 304 305 306 308 315 316 515 516 534 535 545 546
555 556 608 618 656 660 722 723 724 725 768 769 770 772 775 777 779 780 785 787
794 795 797 801 805 806 807 813 814 815 820 822 829 830 850 851 864 866 870 872
874 876 898 900 902 904 933 934 959 960 1042 1043 1065 1067 1376 1396 1536 1540 1548 1549
1551 1553 1555 1557 1559 1561 1563 1566 1568 1569 1571 1574 1576 1577 1579 1581 1583 1585 1587 1589
1591 1593 1595 1597 1599 1600 1602 1603 1611 1612 1696 1698 1714 1716 1724 1726 1734 1736 1739 1740
1742 1744 1775 1776 1797 1799 1856 1857 1858 1859 1898 1899 1901 1902 1903 1904)
function ble/util/c2w+emacs {
local code=$1 al=0 ah=0 tIndex=
# bash-4.0 bug workaround
# 中で使用している変数に日本語などの文字列が入っているとエラーになる。
# その値を参照していなくても、その分岐に入らなくても関係ない。
# なので ret に予め適当な値を設定しておく事にする。
ret=1
((code<0xA0)) && return
if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$1"; then
((ret=bleopt_emoji_width))
return
fi
((
0x3100<=code&&code<0xA4D0||0xAC00<=code&&code<0xD7A4?(
ret=2
):(0x2000<=code&&code<0x2700?(
tIndex=0x0100+code-0x2000
):(
al=code&0xFF,
ah=code/256,
ah==0x00?(
tIndex=al
):(ah==0x03?(
ret=0xFF&((al-0x91)&~0x20),
ret=ret<25&&ret!=17?2:1
):(ah==0x04?(
ret=al==1||0x10<=al&&al<=0x50||al==0x51?2:1
):(ah==0x11?(
ret=al<0x60?2:1
):(ah==0x2e?(
ret=al>=0x80?2:1
):(ah==0x2f?(
ret=2
):(ah==0x30?(
ret=al!=0x3f?2:1
):(ah==0xf9||ah==0xfa?(
ret=2
):(ah==0xfe?(
ret=0x30<=al&&al<0x70?2:1
):(ah==0xff?(
ret=0x01<=al&&al<0x61||0xE0<=al&&al<=0xE7?2:1
):(ret=1))))))))))
))
))
[[ $tIndex ]] || return 0
if ((tIndex<_ble_text_c2w__emacs_wranges[0])); then
ret=1
return
fi
local l=0 u=${#_ble_text_c2w__emacs_wranges[@]} m
while ((l+1<u)); do
((_ble_text_c2w__emacs_wranges[m=(l+u)/2]<=tIndex?(l=m):(u=m)))
done
((ret=((l&1)==0)?2:1))
return 0
}
## 関数 ble/util/c2w+west
## @var[out] ret
function ble/util/c2w+west {
ble/util/c2w/.determine-unambiguous "$1"
if ((ret<0)); then
if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$1"; then
((ret=bleopt_emoji_width))
else
((ret=1))
fi
fi
}
## 関数 ble/util/c2w+east
## @var[out] ret
_ble_text_c2w__east_wranges=(
161 162 164 165 167 169 170 171 174 175 176 181 182 187 188 192 198 199 208 209
215 217 222 226 230 231 232 235 236 238 240 241 242 244 247 251 252 253 254 255
257 258 273 274 275 276 283 284 294 296 299 300 305 308 312 313 319 323 324 325
328 332 333 334 338 340 358 360 363 364 462 463 464 465 466 467 468 469 470 471
472 473 474 475 476 477 593 594 609 610 708 709 711 712 713 716 717 718 720 721
728 732 733 734 735 736 913 930 931 938 945 962 963 970 1025 1026 1040 1104 1105 1106
8208 8209 8211 8215 8216 8218 8220 8222 8224 8227 8228 8232 8240 8241 8242 8244 8245 8246 8251 8252
8254 8255 8308 8309 8319 8320 8321 8325 8364 8365 8451 8452 8453 8454 8457 8458 8467 8468 8470 8471
8481 8483 8486 8487 8491 8492 8531 8533 8539 8543 8544 8556 8560 8570 8592 8602 8632 8634 8658 8659
8660 8661 8679 8680 8704 8705 8706 8708 8711 8713 8715 8716 8719 8720 8721 8722 8725 8726 8730 8731
8733 8737 8739 8740 8741 8742 8743 8749 8750 8751 8756 8760 8764 8766 8776 8777 8780 8781 8786 8787
8800 8802 8804 8808 8810 8812 8814 8816 8834 8836 8838 8840 8853 8854 8857 8858 8869 8870 8895 8896
8978 8979 9312 9450 9451 9548 9552 9588 9600 9616 9618 9622 9632 9634 9635 9642 9650 9652 9654 9656
9660 9662 9664 9666 9670 9673 9675 9676 9678 9682 9698 9702 9711 9712 9733 9735 9737 9738 9742 9744
9748 9750 9756 9757 9758 9759 9792 9793 9794 9795 9824 9826 9827 9830 9831 9835 9836 9838 9839 9840
10045 10046 10102 10112 57344 63744 65533 65534 983040 1048574 1048576 1114110)
function ble/util/c2w+east {
ble/util/c2w/.determine-unambiguous "$1"
((ret>=0)) && return
if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$1"; then
((ret=bleopt_emoji_width))
return
fi
local code=$1
if ((code<_ble_text_c2w__east_wranges[0])); then
ret=1
return
fi
local l=0 u=${#_ble_text_c2w__east_wranges[@]} m
while ((l+1<u)); do
((_ble_text_c2w__east_wranges[m=(l+u)/2]<=code?(l=m):(u=m)))
done
((ret=((l&1)==0)?2:1))
}
#
#------------------------------------------------------------------------------
# **** ble-edit/draw **** @edit/draw
function ble-edit/draw/put {
DRAW_BUFF[${#DRAW_BUFF[*]}]="$*"
}
function ble-edit/draw/put.ind {
local -i count=${1-1}
local ret; ble/string#repeat "${_ble_term_ind}" "$count"
DRAW_BUFF[${#DRAW_BUFF[*]}]=$ret
}
function ble-edit/draw/put.il {
local -i value=${1-1}
((value>0)) || return 0
DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_il//'%d'/$value}
DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
}
function ble-edit/draw/put.dl {
local -i value=${1-1}
((value>0)) || return 0
DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value}
}
function ble-edit/draw/put.cuu {
local -i value=${1-1}
DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cuu//'%d'/$value}
}
function ble-edit/draw/put.cud {
local -i value=${1-1}
DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cud//'%d'/$value}
}
function ble-edit/draw/put.cuf {
local -i value=${1-1}
DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cuf//'%d'/$value}
}
function ble-edit/draw/put.cub {
local -i value=${1-1}
DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cub//'%d'/$value}
}
function ble-edit/draw/put.cup {
local -i l=${1-1} c=${2-1}
local out=$_ble_term_cup
out=${out//'%l'/$l}
out=${out//'%c'/$c}
out=${out//'%y'/$((l-1))}
out=${out//'%x'/$((c-1))}
DRAW_BUFF[${#DRAW_BUFF[*]}]=$out
}
function ble-edit/draw/put.hpa {
local -i c=${1-1}
local out=$_ble_term_hpa
out=${out//'%c'/$c}
out=${out//'%x'/$((c-1))}
DRAW_BUFF[${#DRAW_BUFF[*]}]=$out
}
function ble-edit/draw/put.vpa {
local -i l=${1-1}
local out=$_ble_term_vpa
out=${out//'%l'/$l}
out=${out//'%y'/$((l-1))}
DRAW_BUFF[${#DRAW_BUFF[*]}]=$out
}
function ble-edit/draw/flush {
IFS= builtin eval 'builtin echo -n "${DRAW_BUFF[*]}"'
DRAW_BUFF=()
}
## 関数 ble-edit/draw/sflush [-v var]
## @param[in] var
## 出力先の変数名を指定します。
## @var[out] !var
function ble-edit/draw/sflush {
local _var=ret
[[ $1 == -v ]] && _var=$2
IFS= builtin eval "$_var=\"\${DRAW_BUFF[*]}\""
DRAW_BUFF=()
}
function ble-edit/draw/bflush {
IFS= builtin eval 'ble/util/buffer "${DRAW_BUFF[*]}"'
DRAW_BUFF=()
}
function ble-edit/draw/trace/SC {
trace_scosc="$x $y $g $lc $lg"
ble-edit/draw/put "$_ble_term_sc"
}
function ble-edit/draw/trace/RC {
local -a scosc
scosc=($trace_scosc)
x=${scosc[0]}
y=${scosc[1]}
g=${scosc[2]}
lc=${scosc[3]}
lg=${scosc[4]}
ble-edit/draw/put "$_ble_term_rc"
}
function ble-edit/draw/trace/NEL {
ble-edit/draw/put "$_ble_term_cr"
ble-edit/draw/put "$_ble_term_nl"
((y++,x=0,lc=32,lg=0))
}
## 関数 ble-edit/draw/trace/SGR/arg_next
## @var[in ] f
## @var[in,out] j
## @var[ out] arg
function ble-edit/draw/trace/SGR/arg_next {
local _var=arg _ret
if [[ $1 == -v ]]; then
_var=$2
shift 2
fi
if ((j<${#f[*]})); then
_ret=${f[j++]}
else
((i++))
_ret=${specs[i]%%:*}
fi
(($_var=_ret))
}
function ble-edit/draw/trace/SGR {
local param=$1 seq=$2 specs i iN
ble/string#split specs \; "$param"
if ((${#specs[*]}==0)); then
g=0
ble-edit/draw/put "$_ble_term_sgr0"
return
fi
for ((i=0,iN=${#specs[@]};i<iN;i++)); do
local spec=${specs[i]} f
ble/string#split f : "$spec"
if ((30<=f[0]&&f[0]<50)); then
# colors
if ((30<=f[0]&&f[0]<38)); then
local color=$((f[0]-30))
((g=g&~_ble_color_gflags_MaskFg|_ble_color_gflags_ForeColor|color<<8))
elif ((40<=f[0]&&f[0]<48)); then
local color=$((f[0]-40))
((g=g&~_ble_color_gflags_MaskBg|_ble_color_gflags_BackColor|color<<16))
elif ((f[0]==38)); then
local j=1 color cspace
ble-edit/draw/trace/SGR/arg_next -v cspace
if ((cspace==5)); then
ble-edit/draw/trace/SGR/arg_next -v color
((g=g&~_ble_color_gflags_MaskFg|_ble_color_gflags_ForeColor|color<<8))
fi
elif ((f[0]==48)); then
local j=1 color cspace
ble-edit/draw/trace/SGR/arg_next -v cspace
if ((cspace==5)); then
ble-edit/draw/trace/SGR/arg_next -v color
((g=g&~_ble_color_gflags_MaskBg|_ble_color_gflags_BackColor|color<<16))
fi
elif ((f[0]==39)); then
((g&=~(_ble_color_gflags_MaskFg|_ble_color_gflags_ForeColor)))
elif ((f[0]==49)); then
((g&=~(_ble_color_gflags_MaskBg|_ble_color_gflags_BackColor)))
fi
elif ((90<=f[0]&&f[0]<98)); then
local color=$((f[0]-90+8))
((g=g&~_ble_color_gflags_MaskFg|_ble_color_gflags_ForeColor|color<<8))
elif ((100<=f[0]&&f[0]<108)); then
local color=$((f[0]-100+8))
((g=g&~_ble_color_gflags_MaskBg|_ble_color_gflags_BackColor|color<<16))
elif ((f[0]==0)); then
g=0
elif ((f[0]==1)); then
((g|=_ble_color_gflags_Bold))
elif ((f[0]==22)); then
((g&=~_ble_color_gflags_Bold))
elif ((f[0]==4)); then
((g|=_ble_color_gflags_Underline))
elif ((f[0]==24)); then
((g&=~_ble_color_gflags_Underline))
elif ((f[0]==7)); then
((g|=_ble_color_gflags_Revert))
elif ((f[0]==27)); then
((g&=~_ble_color_gflags_Revert))
elif ((f[0]==3)); then
((g|=_ble_color_gflags_Italic))
elif ((f[0]==23)); then
((g&=~_ble_color_gflags_Italic))
elif ((f[0]==5)); then
((g|=_ble_color_gflags_Blink))
elif ((f[0]==25)); then
((g&=~_ble_color_gflags_Blink))
elif ((f[0]==8)); then
((g|=_ble_color_gflags_Invisible))
elif ((f[0]==28)); then
((g&=~_ble_color_gflags_Invisible))
elif ((f[0]==9)); then
((g|=_ble_color_gflags_Strike))
elif ((f[0]==29)); then
((g&=~_ble_color_gflags_Strike))
fi
done
ble-color-g2sgr -v seq "$g"
ble-edit/draw/put "$seq"
}
function ble-edit/draw/trace/process-csi-sequence {
local seq=$1 seq1=${1:2} rex
local char=${seq1:${#seq1}-1:1} param=${seq1::${#seq1}-1}
if [[ ! ${param//[0-9:;]} ]]; then
# CSI 数字引数 + 文字
case "$char" in
(m) # SGR
ble-edit/draw/trace/SGR "$param" "$seq"
return ;;
([ABCDEFGIZ\`ade])
local arg=0
[[ $param =~ ^[0-9]+$ ]] && arg=$param
((arg==0&&(arg=1)))
local x0=$x y0=$y
if [[ $char == A ]]; then
# CUU "CSI A"
((y-=arg,y<0&&(y=0)))
((y<y0)) && ble-edit/draw/put.cuu $((y0-y))
elif [[ $char == [Be] ]]; then
# CUD "CSI B"
# VPR "CSI e"
((y+=arg,y>=lines&&(y=lines-1)))
((y>y0)) && ble-edit/draw/put.cud $((y-y0))
elif [[ $char == [Ca] ]]; then
# CUF "CSI C"
# HPR "CSI a"
((x+=arg,x>=cols&&(x=cols-1)))
((x>x0)) && ble-edit/draw/put.cuf $((x-x0))
elif [[ $char == D ]]; then
# CUB "CSI D"
((x-=arg,x<0&&(x=0)))
((x<x0)) && ble-edit/draw/put.cub $((x0-x))
elif [[ $char == E ]]; then
# CNL "CSI E"
((y+=arg,y>=lines&&(y=lines-1),x=0))
((y>y0)) && ble-edit/draw/put.cud $((y-y0))
ble-edit/draw/put "$_ble_term_cr"
elif [[ $char == F ]]; then
# CPL "CSI F"
((y-=arg,y<0&&(y=0),x=0))
((y<y0)) && ble-edit/draw/put.cuu $((y0-y))
ble-edit/draw/put "$_ble_term_cr"
elif [[ $char == [G\`] ]]; then
# CHA "CSI G"
# HPA "CSI `"
((x=arg-1,x<0&&(x=0),x>=cols&&(x=cols-1)))
ble-edit/draw/put.hpa $((x+1))
elif [[ $char == d ]]; then
# VPA "CSI d"
((y=arg-1,y<0&&(y=0),y>=lines&&(y=lines-1)))
ble-edit/draw/put.vpa $((y+1))
elif [[ $char == I ]]; then
# CHT "CSI I"
local _x
((_x=(x/it+arg)*it,
_x>=cols&&(_x=cols-1)))
if ((_x>x)); then
ble-edit/draw/put.cuf $((_x-x))
((x=_x))
fi
elif [[ $char == Z ]]; then
# CHB "CSI Z"
local _x
((_x=((x+it-1)/it-arg)*it,
_x<0&&(_x=0)))
if ((_x<x)); then
ble-edit/draw/put.cub $((x-_x))
((x=_x))
fi
fi
lc=-1 lg=0
return ;;
([Hf])
# CUP "CSI H"
# HVP "CSI f"
local -a params
params=(${param//[^0-9]/ })
((x=params[1]-1))
((y=params[0]-1))
((x<0&&(x=0),x>=cols&&(x=cols-1),
y<0&&(y=0),y>=lines&&(y=lines-1)))
ble-edit/draw/put.cup $((y+1)) $((x+1))
lc=-1 lg=0
return ;;
([su]) # SCOSC SCORC
if [[ $param == 99 ]]; then
# PS1 の \[ ... \] の処理。
# ble-edit/prompt/update で \e[99s, \e[99u に変換している。
if [[ $char == s ]]; then
trace_brack[${#trace_brack[*]}]="$x $y"
else
local lastIndex=$((${#trace_brack[*]}-1))
if ((lastIndex>=0)); then
local -a scosc
scosc=(${trace_brack[lastIndex]})
((x=scosc[0]))
((y=scosc[1]))
unset "trace_brack[$lastIndex]"
fi
fi
return
else
if [[ $char == s ]]; then
ble-edit/draw/trace/SC
else
ble-edit/draw/trace/RC
fi
return
fi ;;
# ■その他色々?
# ([JPX@MKL]) # 挿入削除→カーソルの位置は不変 lc?
# ([hl]) # SM RM DECSM DECRM
esac
fi
ble-edit/draw/put "$seq"
}
function ble-edit/draw/trace/process-esc-sequence {
local seq=$1 char=${1:1}
case "$char" in
(7) # DECSC
ble-edit/draw/trace/SC
return ;;
(8) # DECRC
ble-edit/draw/trace/RC
return ;;
(D) # IND
((y++))
ble-edit/draw/put "$_ble_term_ind"
[[ $_ble_term_ind != $'\eD' ]] &&
ble-edit/draw/put.hpa $((x+1)) # tput ind が唯の改行の時がある
lc=-1 lg=0
return ;;
(M) # RI
((y--,y<0&&(y=0)))
ble-edit/draw/put "$_ble_term_ri"
lc=-1 lg=0
return ;;
(E) # NEL
ble-edit/draw/trace/NEL
lc=32 lg=0
return ;;
# (H) # HTS 面倒だから無視。
# ([KL]) PLD PLU は何か?
esac
ble-edit/draw/put "$seq"
}
## 関数 ble-edit/draw/trace text
## 制御シーケンスを含む文字列を出力すると共にカーソル位置の移動を計算します。
##
## @param[in] text
## 出力する (制御シーケンスを含む) 文字列を指定します。
## @var[in,out] DRAW_BUFF[]
## 出力先の配列を指定します。
## @var[in,out] x y g
## 出力の開始位置を指定します。出力終了時の位置を返します。
## @var[in,out] lc lg
## bleopt_suppress_bash_output= の時、
## 出力開始時のカーソル左の文字コードを指定します。
## 出力終了時のカーソル左の文字コードが分かる場合にそれを返します。
##
## 以下のシーケンスを認識します
##
## - Control Characters (C0 の文字 及び DEL)
## BS HT LF VT CR はカーソル位置の変更を行います。
## それ以外の文字はカーソル位置の変更は行いません。
##
## - CSI Sequence (Control Sequence)
## | CUU CSI A | CHB CSI Z |
## | CUD CSI B | HPR CSI a |
## | CUF CSI C | VPR CSI e |
## | CUB CSI D | HPA CSI ` |
## | CNL CSI E | VPA CSI d |
## | CPL CSI F | HVP CSI f |
## | CHA CSI G | SGR CSI m |
## | CUP CSI H | SCOSC CSI s |
## | CHT CSI I | SCORC CSI u |
## 上記のシーケンスはカーソル位置の計算に含め、
## また、端末 (TERM) に応じた出力を実施します。
## 上記以外のシーケンスはカーソル位置を変更しません。
##
## - SOS, DCS, SOS, PM, APC, ESC k ~ ESC \
## - ISO-2022 に含まれる 3 byte 以上のシーケンス
## これらはそのまま通します。位置計算の考慮には入れません。
##
## - ESC Sequence
## DECSC DECRC IND RI NEL はカーソル位置の変更を行います。
## それ以外はカーソル位置の変更は行いません。
##
function ble-edit/draw/trace {
local LC_ALL= LC_COLLATE=C
# cygwin では LC_COLLATE=C にしないと
# 正規表現の range expression が期待通りに動かない。
ble-edit/draw/trace.impl "$@"
} 2>/dev/null
function ble-edit/draw/trace.impl {
local text=$1
# Note: 文字符号化方式によっては対応する文字が存在しない可能性がある。
# その時は st='\u009C' になるはず。2文字以上のとき変換に失敗したと見做す。
local ret
ble/util/c2s 156; local st=$ret # (ST)
((${#st}>=2)) && st=
# constants
local cols=${COLUMNS:-80} lines=${LINES:-25}
local it=${bleopt_tab_width:-$_ble_term_it} xenl=$_ble_term_xenl
_ble_util_string_prototype.reserve "$it"
# CSI
local rex_csi='^\[[ -?]*[@-~]'
# OSC, DCS, SOS, PM, APC Sequences + "GNU screen ESC k"
local rex_osc='^([]PX^_k])([^'$st']|+[^\'$st'])*(\\|'${st:+'|'}$st'|$)'
# ISO-2022 関係 (3byte以上の物)
local rex_2022='^[ -/]+[@-~]'
# ESC ?
local rex_esc='^[ -~]'
# variables
local -a trace_brack=()
local trace_scosc=
local i=0 iN=${#text}
while ((i<iN)); do
local tail=${text:i}
local w=0
if [[ $tail == [-]* ]]; then
local s=${tail::1}
((i++))
case "$s" in
('')
if [[ $tail =~ $rex_osc ]]; then
# 各種メッセージ (素通り)
s=$BASH_REMATCH
[[ ${BASH_REMATCH[3]} ]] || s="$s\\" # 終端の追加
((i+=${#BASH_REMATCH}-1))
elif [[ $tail =~ $rex_csi ]]; then
# Control sequences
s=
((i+=${#BASH_REMATCH}-1))
ble-edit/draw/trace/process-csi-sequence "$BASH_REMATCH"
elif [[ $tail =~ $rex_2022 ]]; then
# ISO-2022 (素通り)
s=$BASH_REMATCH
((i+=${#BASH_REMATCH}-1))
elif [[ $tail =~ $rex_esc ]]; then
s=
((i+=${#BASH_REMATCH}-1))
ble-edit/draw/trace/process-esc-sequence "$BASH_REMATCH"
fi ;;
('') # BS
((x>0&&(x--,lc=32,lg=g))) ;;
($'\t') # HT
local _x
((_x=(x+it)/it*it,
_x>=cols&&(_x=cols-1)))
if ((x<_x)); then
s=${_ble_util_string_prototype::_x-x}
((x=_x,lc=32,lg=g))
else
s=
fi ;;
($'\n') # LF = CR+LF
s=
ble-edit/draw/trace/NEL ;;
('') # VT
s=
ble-edit/draw/put "$_ble_term_cr"
ble-edit/draw/put "$_ble_term_nl"
((x)) && ble-edit/draw/put.cuf "$x"
((y++,lc=32,lg=0)) ;;
($'\r') # CR ^M
s=$_ble_term_cr
((x=0,lc=-1,lg=0)) ;;
# その他の制御文字は (BEL) (FF) も含めてゼロ幅と解釈する
esac
[[ $s ]] && ble-edit/draw/put "$s"
elif ble/util/isprint+ "$tail"; then
w=${#BASH_REMATCH}
ble-edit/draw/put "$BASH_REMATCH"
((i+=${#BASH_REMATCH}))
if [[ ! $bleopt_suppress_bash_output ]]; then
local ret
ble/util/s2c "$BASH_REMATCH" $((w-1))
lc=$ret lg=$g
fi
else
local w ret
ble/util/s2c "$tail" 0
lc=$ret lg=$g
ble/util/c2w "$lc"
w=$ret
if ((w>=2&&x+w>cols)); then
# 行に入りきらない場合の調整
ble-edit/draw/put "${_ble_util_string_prototype::x+w-cols}"
((x=cols))
fi
ble-edit/draw/put "${tail::1}"
((i++))
fi
if ((w>0)); then
((x+=w,y+=x/cols,x%=cols,
xenl&&x==0&&(y--,x=cols)))
((x==0&&(lc=32,lg=0)))
fi
done
}
# **** prompt **** @line.ps1
## called by ble-edit-initialize
function ble-edit/prompt/initialize {
# hostname
_ble_edit_prompt__string_H=${HOSTNAME}
if local rex='^[0-9]+(\.[0-9]){3}$'; [[ $HOSTNAME =~ $rex ]]; then
# IPv4 の形式の場合には省略しない
_ble_edit_prompt__string_h=$HOSTNAME
else
_ble_edit_prompt__string_h=${HOSTNAME%%.*}
fi
# tty basename
local tmp; ble/util/assign tmp 'tty 2>/dev/null'
_ble_edit_prompt__string_l=${tmp##*/}
# command name
_ble_edit_prompt__string_s=${0##*/}
# user
_ble_edit_prompt__string_u=${USER}
# bash versions
ble/util/sprintf _ble_edit_prompt__string_v '%d.%d' "${BASH_VERSINFO[0]}" "${BASH_VERSINFO[1]}"
ble/util/sprintf _ble_edit_prompt__string_V '%d.%d.%d' "${BASH_VERSINFO[0]}" "${BASH_VERSINFO[1]}" "${BASH_VERSINFO[2]}"
# uid
if [[ $EUID -eq 0 ]]; then
_ble_edit_prompt__string_root='#'
else
_ble_edit_prompt__string_root='$'
fi
if [[ $OSTYPE == cygwin* ]]; then
local windir=/cygdrive/c/Windows
if [[ $WINDIR == [A-Za-z]:\\* ]]; then
local bsl='\' sl=/
local c=${WINDIR::1} path=${WINDIR:3}
if [[ $c == [A-Z] ]]; then
if ((_ble_bash>=40000)); then
c=${c,?}
else