-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
edit.sh
7499 lines (6788 loc) · 243 KB
/
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 ****
#
# @line.ps1
# @line.text
# @line.info
# @edit.content
# @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
## オプション edit_vbell
## 編集時の visible bell の有効・無効を設定します。
## bleopt_edit_vbell=1
## 有効です。
## bleopt_edit_vbell=
## 無効です。
bleopt/declare -v edit_vbell ''
## オプション edit_abell
## 編集時の audible bell (BEL 文字出力) の有効・無効を設定します。
## bleopt_edit_abell=1
## 有効です。
## bleopt_edit_abell=
## 無効です。
bleopt/declare -v edit_abell 1
## オプション history_lazyload
## bleopt_history_lazyload=1
## ble-attach 後、初めて必要になった時に履歴の読込を行います。
## bleopt_history_lazyload=
## ble-attach 時に履歴の読込を行います。
##
## bash-3.1 未満では history -s が思い通りに動作しないので、
## このオプションの値に関係なく ble-attach の時に履歴の読み込みを行います。
bleopt/declare -v history_lazyload 1
## オプション delete_selection_mode
## 文字挿入時に選択範囲をどうするかについて設定します。
## bleopt_delete_selection_mode=1 (既定)
## 選択範囲の内容を新しい文字で置き換えます。
## bleopt_delete_selection_mode=
## 選択範囲を解除して現在位置に新しい文字を挿入します。
bleopt/declare -v delete_selection_mode 1
## オプション indent_offset
## シェルのインデント幅を指定します。既定では 4 です。
bleopt/declare -n indent_offset 4
## オプション indent_tabs
## インデントにタブを使用するかどうかを指定します。
## 0 を指定するとインデントに空白だけを用います。
## それ以外の場合はインデントにタブを使用します。
bleopt/declare -n indent_tabs 1
## オプション undo_point
## undo/redo 実行直後のカーソル位置を設定します。
##
## undo_point=beg
## undo/redo によって変化のあった範囲の先頭に移動します。
## undo_point=end
## undo/redo によって変化のあった範囲の末端に移動します。
## その他の時
## undo/redo 後の状態が記録された時のカーソル位置を復元します。
##
bleopt/declare -v undo_point end
## オプション edit_forced_textmap
## 1 が設定されているとき、矩形選択に先立って配置計算を強制します。
## 0 が設定されているとき、配置情報があるときにそれを使い、
## 配置情報がないときは論理行・論理列による矩形選択にフォールバックします。
##
bleopt/declare -n 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
}
## オプション rps1
bleopt/declare -v rps1 ''
bleopt/declare -v rps1_transient ''
function bleopt/check:rps1 { [[ $_ble_attached ]] && ble-edit/prompt/clear; return 0; }
## オプション prompt_eol_mark
bleopt/declare -v prompt_eol_mark $'\e[94m[ble: EOF]\e[m'
## オプション internal_exec_type (内部使用)
## コマンドの実行の方法を指定します。
##
## internal_exec_type=exec
## 関数内で実行します (従来の方法です。将来的に削除されます)
## internal_exec_type=gexec
## グローバルな文脈で実行します (新しい方法です)
##
## 要件: 関数 ble-edit/exec:$bleopt_internal_exec_type/process が定義されていること。
bleopt/declare -n internal_exec_type gexec
function bleopt/check:internal_exec_type {
if ! ble/is-function "ble-edit/exec:$value/process"; then
echo "bleopt: Invalid value internal_exec_type='$value'. A function 'ble-edit/exec:$value/process' is not defined." >&2
return 1
fi
}
## オプション internal_suppress_bash_output (内部使用)
## bash 自体の出力を抑制するかどうかを指定します。
## bleopt_internal_suppress_bash_output=1
## 抑制します。bash のエラーメッセージは visible-bell で表示します。
## bleopt_internal_suppress_bash_output=
## 抑制しません。bash のメッセージは全て端末に出力されます。
## これはデバグ用の設定です。bash の出力を制御するためにちらつきが発生する事があります。
## bash-3 ではこの設定では C-d を捕捉できません。
bleopt/declare -v internal_suppress_bash_output 1
## オプション internal_ignoreeof_trap (内部使用)
## bash-3.0 の時に使用します。C-d を捕捉するのに用いるメッセージです。
## これは自分の bash の設定に合わせる必要があります。
bleopt/declare -n internal_ignoreeof_trap 'Use "exit" to leave the shell.'
## オプション allow_exit_with_jobs
## この変数に空文字列が設定されている時、
## ジョブが残っている時には ble/widget/exit からシェルは終了しません。
## この変数に空文字列以外が設定されている時、
## ジョブがある場合でも条件を満たした時に exit を実行します。
## 停止中のジョブがある場合、または、shopt -s checkjobs かつ実行中のジョブが存在する時は、
## 二回連続で同じ widget から exit を呼び出した時にシェルを終了します。
## それ以外の場合は常にシェルを終了します。
## 既定値は空文字列です。
bleopt/declare -v allow_exit_with_jobs ''
#
#------------------------------------------------------------------------------
# **** 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
local ret
ble/util/s2c "$c"
ble/util/c2s $((ret+32))
c=$ret
fi
fi
windir=/cygdrive/$c/${path//$bsl/$sl}
fi
if [[ -e $windir && -w $windir ]]; then
_ble_edit_prompt__string_root='#'
fi
elif [[ $OSTYPE == msys* ]]; then
# msys64/etc/bash.bashrc に倣う
if ble/bin#has id getent &>/dev/null; then
local id getent
ble/util/assign id 'id -G'
ble/util/assign getent 'getent -w group S-1-16-12288'
ble/string#split getent : "$getent"
[[ " $id " == *" ${getent[1]} "* ]] &&
_ble_edit_prompt__string_root='#'
fi
fi
}
## 変数 _ble_edit_prompt
## 構築した prompt の情報をキャッシュします。
## @var _ble_edit_prompt[0] version
## prompt 情報を作成した時の _ble_edit_LINENO を表します。
## @var _ble_edit_prompt[1..3] x y g
## prompt を表示し終わった時のカーソルの位置と描画属性を表します。
## @var _ble_edit_prompt[4..5] lc lg
## bleopt_internal_suppress_bash_output= の時、
## prompt を表示し終わった時の左側にある文字とその描画属性を表します。
## それ以外の時はこの値は使われません。
## @var _ble_edit_prompt[6] ps1out
## prompt を表示する為に出力する制御シーケンスを含んだ文字列です。
## @var _ble_edit_prompt[7] trace_hash
## COLUMNS:ps1esc の形式の文字列です。
## 調整前の ps1out を格納します。
## ps1out の計算 (trace) を省略する為に使用します。
_ble_edit_prompt_dirty=
_ble_edit_prompt=("" 0 0 0 32 0 "" "")
_ble_edit_rprompt_bbox=()
_ble_edit_rprompt=()
_ble_edit_rprompt_dirty=
_ble_edit_rprompt_shown=
## 関数 ble-edit/prompt/.load
## @var[out] x y g
## @var[out] lc lg
## @var[out] ret
## プロンプトを描画するための文字列
function ble-edit/prompt/.load {
x=${_ble_edit_prompt[1]}
y=${_ble_edit_prompt[2]}
g=${_ble_edit_prompt[3]}
lc=${_ble_edit_prompt[4]}
lg=${_ble_edit_prompt[5]}
ret=${_ble_edit_prompt[6]}
}
## 関数 ble-edit/prompt/print text
## プロンプト構築中に呼び出す関数です。
## 指定された文字列を、後の評価に対するエスケープをして出力します。
## @param[in] text
## エスケープされる文字列を指定します。
## @var[out] DRAW_BUFF[]
## 出力先の配列です。
function ble-edit/prompt/print {
local text=$1 a b
if [[ $text == *['$\"`']* ]]; then
a='\' b='\\' text=${text//"$a"/$b}
a='$' b='\$' text=${text//"$a"/$b}
a='"' b='\"' text=${text//"$a"/$b}
a='`' b='\`' text=${text//"$a"/$b}
fi
ble/canvas/put.draw "$text"
}
## 関数 ble-edit/prompt/process-prompt-string prompt_string
## プロンプト構築中に呼び出す関数です。
## 指定した引数を PS1 と同様の形式と解釈して処理します。
## @param[in] prompt_string
## @arr[in,out] DRAW_BUFF
function ble-edit/prompt/process-prompt-string {
local ps1=$1
local i=0 iN=${#ps1}
local rex_letters='^[^\]+|\\$'
while ((i<iN)); do
local tail=${ps1:i}
if [[ $tail == '\'?* ]]; then
ble-edit/prompt/.process-backslash
elif [[ $tail =~ $rex_letters ]]; then
ble/canvas/put.draw "$BASH_REMATCH"
((i+=${#BASH_REMATCH}))
else
# ? ここには本来来ないはず。
ble/canvas/put.draw "${tail::1}"
((i++))
fi
done
}
## 関数 ble-edit/prompt/.process-backslash
## @var[in] tail
## @arr[in.out] DRAW_BUFF
function ble-edit/prompt/.process-backslash {
((i+=2))
# \\ の次の文字
local c=${tail:1:1} pat='[]#!$\'
if [[ ! ${pat##*"$c"*} ]]; then
case "$c" in
(\[) ble/canvas/put.draw $'\e[99s' ;; # \[ \] は後処理の為、適当な識別用の文字列を出力する。
(\]) ble/canvas/put.draw $'\e[99u' ;;
('#') # コマンド番号 (本当は history に入らない物もある…)
ble/canvas/put.draw "$_ble_edit_CMD" ;;
(\!) # 編集行の履歴番号
local count
ble-edit/history/get-count -v count
ble/canvas/put.draw $((count+1)) ;;
('$') # # or $
ble-edit/prompt/print "$_ble_edit_prompt__string_root" ;;
(\\)
# '\\' は '\' と出力された後に、更に "" 内で評価された時に次の文字をエスケープする。
# 例えば '\\$' は一旦 '\$' となり、更に展開されて '$' となる。'\\\\' も同様に '\' になる。
ble/canvas/put.draw '\' ;;
esac
elif ! ble/function#try ble-edit/prompt/backslash:"$c"; then
# その他の文字はそのまま出力される。
# - '\"' '\`' はそのまま出力された後に "" 内で評価され '"' '`' となる。
# - それ以外の場合は '\?' がそのまま出力された後に、"" 内で評価されても変わらず '\?' 等となる。
ble/canvas/put.draw "\\$c"
fi
}
## 設定関数 ble-edit/prompt/backslash:*
## プロンプト PS1 内で使用するバックスラッシュシーケンスを定義します。
## 内部では ble/canvas/put.draw escaped_text もしくは
## ble-edit/prompt/print unescaped_text を用いて
## シーケンスの展開結果を追記します。
##
## @exit
## 対応する文字列を出力した時に成功します。
## 0 以外の終了ステータスを返した場合、
## シーケンスが処理されなかったと見做され、
## 呼び出し元によって \c (c: 文字) が代わりに書き込まれます。
##
function ble-edit/prompt/backslash:0 { # 8進表現
local rex='^\\[0-7]{1,3}'
if [[ $tail =~ $rex ]]; then
local seq=${BASH_REMATCH[0]}
((i+=${#seq}-2))
builtin eval "c=\$'$seq'"
fi
ble-edit/prompt/print "$c"
return 0
}
function ble-edit/prompt/backslash:1 { ble-edit/prompt/backslash:0; }
function ble-edit/prompt/backslash:2 { ble-edit/prompt/backslash:0; }
function ble-edit/prompt/backslash:3 { ble-edit/prompt/backslash:0; }
function ble-edit/prompt/backslash:4 { ble-edit/prompt/backslash:0; }
function ble-edit/prompt/backslash:5 { ble-edit/prompt/backslash:0; }
function ble-edit/prompt/backslash:6 { ble-edit/prompt/backslash:0; }
function ble-edit/prompt/backslash:7 { ble-edit/prompt/backslash:0; }
function ble-edit/prompt/backslash:a { # 0 BEL
ble/canvas/put.draw ""
return 0
}
function ble-edit/prompt/backslash:d { # ? 日付
[[ $cache_d ]] || ble/util/strftime -v cache_d '%a %b %d'
ble-edit/prompt/print "$cache_d"
return 0
}
function ble-edit/prompt/backslash:t { # 8 時刻
[[ $cache_t ]] || ble/util/strftime -v cache_t '%H:%M:%S'
ble-edit/prompt/print "$cache_t"
return 0
}
function ble-edit/prompt/backslash:A { # 5 時刻
[[ $cache_A ]] || ble/util/strftime -v cache_A '%H:%M'
ble-edit/prompt/print "$cache_A"
return 0
}
function ble-edit/prompt/backslash:T { # 8 時刻
[[ $cache_T ]] || ble/util/strftime -v cache_T '%I:%M:%S'
ble-edit/prompt/print "$cache_T"
return 0
}
function ble-edit/prompt/backslash:@ { # ? 時刻
[[ $cache_at ]] || ble/util/strftime -v cache_at '%I:%M %p'
ble-edit/prompt/print "$cache_at"
return 0
}
function ble-edit/prompt/backslash:D {
local rex='^\\D\{([^{}]*)\}' cache_D
if [[ $tail =~ $rex ]]; then
ble/util/strftime -v cache_D "${BASH_REMATCH[1]}"
ble-edit/prompt/print "$cache_D"
((i+=${#BASH_REMATCH}-2))
else
ble-edit/prompt/print "\\$c"
fi
return 0
}
function ble-edit/prompt/backslash:e {
ble/canvas/put.draw $'\e'
return 0
}
function ble-edit/prompt/backslash:h { # = ホスト名
ble-edit/prompt/print "$_ble_edit_prompt__string_h"
return 0
}
function ble-edit/prompt/backslash:H { # = ホスト名
ble-edit/prompt/print "$_ble_edit_prompt__string_H"
return 0
}
function ble-edit/prompt/backslash:j { # ジョブの数
if [[ ! $cache_j ]]; then
local joblist
ble/util/joblist
cache_j=${#joblist[@]}
fi
ble/canvas/put.draw "$cache_j"
return 0
}
function ble-edit/prompt/backslash:l { # tty basename
ble-edit/prompt/print "$_ble_edit_prompt__string_l"
return 0
}
function ble-edit/prompt/backslash:n {
ble/canvas/put.draw $'\n'
return 0
}
function ble-edit/prompt/backslash:r {
ble/canvas/put.draw "$_ble_term_cr"
return 0
}
function ble-edit/prompt/backslash:s { # 4 "bash"
ble-edit/prompt/print "$_ble_edit_prompt__string_s"
return 0
}
function ble-edit/prompt/backslash:u { # = ユーザ名
ble-edit/prompt/print "$_ble_edit_prompt__string_u"
return 0
}
function ble-edit/prompt/backslash:v { # = bash version %d.%d
ble-edit/prompt/print "$_ble_edit_prompt__string_v"
return 0
}
function ble-edit/prompt/backslash:V { # = bash version %d.%d.%d
ble-edit/prompt/print "$_ble_edit_prompt__string_V"
return 0
}
function ble-edit/prompt/backslash:w { # PWD
ble-edit/prompt/.update-working-directory
ble-edit/prompt/print "$cache_wd"
return 0
}
function ble-edit/prompt/backslash:W { # PWD短縮
if [[ ! ${PWD//'/'} ]]; then
ble-edit/prompt/print "$PWD"
else
ble-edit/prompt/.update-working-directory
ble-edit/prompt/print "${cache_wd##*/}"
fi
return 0
}
## 関数 ble-edit/prompt/.update-working-directory
## @var[in,out] cache_wd
function ble-edit/prompt/.update-working-directory {
[[ $cache_wd ]] && return
if [[ ! ${PWD//'/'} ]]; then
cache_wd=$PWD
return
fi
local head= body=${PWD%/}
if [[ $body == "$HOME" ]]; then
cache_wd='~'
return
elif [[ $body == "$HOME"/* ]]; then
head='~/'
body=${body#"$HOME"/}
fi
if [[ $PROMPT_DIRTRIM ]]; then
local dirtrim=$((PROMPT_DIRTRIM))
local pat='[^/]'
local count=${body//$pat}
if ((${#count}>=dirtrim)); then
local ret
ble/string#repeat '/*' "$dirtrim"
local omit=${body%$ret}
((${#omit}>3)) &&
body=...${body:${#omit}}
fi
fi
cache_wd=$head$body
}
function ble-edit/prompt/.escape/check-double-quotation {
if [[ $tail == '"'* ]]; then
if [[ ! $nest ]]; then
out=$out'\"'
tail=${tail:1}
else
out=$out'"'
tail=${tail:1}
nest=\"$nest
ble-edit/prompt/.escape/update-rex_skip
fi
return 0
else
return 1
fi
}
function ble-edit/prompt/.escape/check-command-substitution {
if [[ $tail == '$('* ]]; then
out=$out'$('
tail=${tail:2}
nest=')'$nest
ble-edit/prompt/.escape/update-rex_skip
return 0
else
return 1
fi
}
function ble-edit/prompt/.escape/check-parameter-expansion {
if [[ $tail == '${'* ]]; then
out=$out'${'
tail=${tail:2}
nest='}'$nest
ble-edit/prompt/.escape/update-rex_skip
return 0
else
return 1
fi
}
function ble-edit/prompt/.escape/check-incomplete-quotation {
if [[ $tail == '`'* ]]; then
local rex='^`([^\`]|\\.)*\\$'
[[ $tail =~ $rex ]] && tail=$tail'\'
out=$out$tail'`'
tail=
return 0
elif [[ $nest == ['})']* && $tail == \'* ]]; then
out=$out$tail$q
tail=
return 0
elif [[ $nest == ['})']* && $tail == \$\'* ]]; then
local rex='^\$'$q'([^\'$q']|\\.)*\\$'
[[ $tail =~ $rex ]] && tail=$tail'\'
out=$out$tail$q
tail=
return 0
elif [[ $tail == '\' ]]; then
out=$out'\\'
tail=
return 0
else
return 1
fi
}
function ble-edit/prompt/.escape/update-rex_skip {
if [[ $nest == \)* ]]; then
rex_skip=$rex_skip_paren
elif [[ $nest == \}* ]]; then
rex_skip=$rex_skip_brace
else
rex_skip=$rex_skip_dquot
fi
}
function ble-edit/prompt/.escape {
local tail=$1 out= nest=
# 地の文の " だけをエスケープする。
local q=\'
local rex_bq='`([^\`]|\\.)*`'
local rex_sq=$q'[^'$q']*'$q'|\$'$q'([^\'$q']|\\.)*'$q
local rex_skip
local rex_skip_dquot='^([^\"$`]|'$rex_bq'|\\.)+'
local rex_skip_brace='^([^\"$`'$q'}]|'$rex_bq'|'$rex_sq'|\\.)+'
local rex_skip_paren='^([^\"$`'$q'()]|'$rex_bq'|'$rex_sq'|\\.)+'
ble-edit/prompt/.escape/update-rex_skip
while [[ $tail ]]; do
if [[ $tail =~ $rex_skip ]]; then
out=$out$BASH_REMATCH
tail=${tail:${#BASH_REMATCH}}
elif [[ $nest == ['})"']* && $tail == "${nest::1}"* ]]; then
out=$out${nest::1}
tail=${tail:1}
nest=${nest:1}
ble-edit/prompt/.escape/update-rex_skip
elif [[ $nest == \)* && $tail == \(* ]]; then
out=$out'('
tail=${tail:1}
nest=')'$nest
elif ble-edit/prompt/.escape/check-double-quotation; then
continue
elif ble-edit/prompt/.escape/check-command-substitution; then
continue
elif ble-edit/prompt/.escape/check-parameter-expansion; then
continue
elif ble-edit/prompt/.escape/check-incomplete-quotation; then
continue
else
out=$out${tail::1}
tail=${tail:1}
fi
done
ret=$out$nest
}
## 関数 ble-edit/prompt/.instantiate ps opts [x0 y0 g0 lc0 lg0 val0 esc0]
## @var[out] val esc x y g lc lg
## @var[in,out] x1 x2 y1 y2
## @var[in,out] cache_d cache_t cache_A cache_T cache_at cache_j cache_wd
function ble-edit/prompt/.instantiate {
trace_hash= esc= x=0 y=0 g=0 lc=32 lg=0
local ps=$1 opts=$2 x0=$3 y0=$4 g0=$5 lc0=$6 lg0=$7 esc0=$8 trace_hash0=$9
[[ ! $ps ]] && return 0
# 1. PS1 に含まれる \c を処理する
local -a DRAW_BUFF=()
ble-edit/prompt/process-prompt-string "$ps"
local processed; ble/canvas/sflush.draw -v processed
# 2. PS1 に含まれる \\ や " をエスケープし、
# eval して各種シェル展開を実行する。
local ret
ble-edit/prompt/.escape "$processed"; local escaped=$ret
local expanded=${trace_hash0#*:} # Note: これは次行が失敗した時の既定値
builtin eval "expanded=\"$escaped\""
# 3. 端末への出力を構成する
trace_hash=$COLUMNS:$expanded
if [[ $trace_hash != "$trace_hash0" ]]; then
x=0 y=0 g=0 lc=32 lg=0
ble/canvas/trace "$expanded" "$opts:left-char"; local traced=$ret
((lc<0&&(lc=0)))
esc=$traced
return 0
else
x=$x0 y=$y0 g=$g0 lc=$lc0 lg=$lg0
esc=$esc0
return 2
fi
}
function ble-edit/prompt/update/.eval-prompt_command {
# return 等と記述されていた時対策として関数内評価。
eval "$PROMPT_COMMAND"
}
## 関数 ble-edit/prompt/update
## _ble_edit_PS1 からプロンプトを構築します。
## @var[in] _ble_edit_PS1
## 構築されるプロンプトの内容を指定します。
## @var[out] _ble_edit_prompt
## 構築したプロンプトの情報を格納します。
## @var[out] ret
## プロンプトを描画する為の文字列を返します。
## @var[in,out] x y g
## プロンプトの描画開始点を指定します。
## プロンプトを描画した後の位置を返します。
## @var[in,out] lc lg
## bleopt_internal_suppress_bash_output= の際に、
## 描画開始点の左の文字コードを指定します。
## 描画終了点の左の文字コードが分かる場合にそれを返します。
function ble-edit/prompt/update {
local version=$COLUMNS:$_ble_edit_LINENO
if [[ ${_ble_edit_prompt[0]} == "$version" ]]; then
ble-edit/prompt/.load
return
fi
local cache_d= cache_t= cache_A= cache_T= cache_at= cache_j= cache_wd=
# update PS1
if [[ $PROMPT_COMMAND ]]; then
ble-edit/restore-PS1
ble-edit/prompt/update/.eval-prompt_command
ble-edit/adjust-PS1
fi
local trace_hash esc
ble-edit/prompt/.instantiate "$_ble_edit_PS1" '' "${_ble_edit_prompt[@]:1}" &&
_ble_edit_prompt_dirty=1
_ble_edit_prompt=("$version" "$x" "$y" "$g" "$lc" "$lg" "$esc" "$trace_hash")
ret=$esc
# Note #D1392: mc (midnight commander) の中では補助プロンプトは全て off
[[ $MC_SID == $$ ]] && return 0
# update edit_rps1
if [[ $bleopt_rps1 ]]; then
local ps1_height=$((y+1))
local trace_hash esc x y g lc lg # Note: これ以降は local の x y g lc lg
local x1=${_ble_edit_rprompt_bbox[0]}
local y1=${_ble_edit_rprompt_bbox[1]}
local x2=${_ble_edit_rprompt_bbox[2]}
local y2=${_ble_edit_rprompt_bbox[3]}
LINES=$ps1_height ble-edit/prompt/.instantiate "$bleopt_rps1" confine:relative:measure-bbox "${_ble_edit_rprompt[@]:1}" &&
_ble_edit_rprompt_dirty=1
_ble_edit_rprompt=("$version" "$x" "$y" "$g" "$lc" "$lg" "$esc" "$trace_hash")
_ble_edit_rprompt_bbox=("$x1" "$y1" "$x2" "$y2")
elif [[ $_ble_edit_rprompt ]]; then
# 新しい rps1 が空の場合、前回の rps1 が残っていればクリア
_ble_edit_rprompt_dirty=1
_ble_edit_rprompt_bbox=()
_ble_edit_rprompt=()
fi
}
function ble-edit/prompt/clear {
_ble_edit_prompt[0]=
ble/textarea#invalidate
}
#
# **** information pane **** @line.info
## 関数 ble-edit/info/.initialize-size
## @var[out] cols lines
function ble-edit/info/.initialize-size {
local ret
ble/canvas/panel/layout/.get-available-height "$_ble_edit_info_panel"
cols=${COLUMNS-80} lines=$ret
}
_ble_edit_info_panel=2
_ble_edit_info=(0 0 "")
function ble-edit/info#get-height {
if [[ ${_ble_edit_info[2]} ]]; then
height=1:$((_ble_edit_info[1]+1))
else
height=0:0
fi
}
## 関数 ble-edit/info/.construct-content type text
## @var[out] x y
## @var[out] content
function ble-edit/info/.construct-content {
local cols lines
ble-edit/info/.initialize-size
x=0 y=0 content=
local type=$1 text=$2
case "$1" in
(ansi|esc)
local trace_opts=truncate
[[ $1 == esc ]] && trace_opts=$trace_opts:terminfo
local ret= g=0
LINES=$lines ble/canvas/trace "$text" "$trace_opts"
content=$ret ;;
(text)
local ret
ble/canvas/trace-text "$text"
content=$ret ;;
(store)
x=$2 y=$3 content=$4
# 現在の高さに入らない時は計測し直す。
((y<lines)) || ble-edit/info/.construct-content esc "$content" ;;
(*)
echo "usage: ble-edit/info/.construct-content type text" >&2 ;;
esac
}
function ble-edit/info/.clear-content {
[[ ${_ble_edit_info[2]} ]] || return
local -a DRAW_BUFF=()
ble/canvas/panel#set-height.draw "$_ble_edit_info_panel" 0
ble/canvas/bflush.draw
_ble_edit_info=(0 0 "")
}
## 関数 ble-edit/info/.render-content x y content
## @param[in] x y content
function ble-edit/info/.render-content {
local x=$1 y=$2 content=$3
# 既に同じ内容で表示されているとき…。
[[ $content == "${_ble_edit_info[2]}" ]] && return
if [[ ! $content ]]; then
ble-edit/info/.clear-content
return
fi
_ble_edit_info=("$x" "$y" "$content")
local -a DRAW_BUFF=()
ble/canvas/panel#reallocate-height.draw
ble/canvas/panel#clear.draw "$_ble_edit_info_panel"
ble/canvas/panel#goto.draw "$_ble_edit_info_panel"
ble/canvas/put.draw "$content"
ble/canvas/bflush.draw
((_ble_canvas_y+=y,_ble_canvas_x=x))
}
_ble_edit_info_default=(0 0 "")
_ble_edit_info_scene=default
## 関数 ble-edit/info/show type text
##
## @param[in] type
##
## 以下の何れかを指定する。
##
## text, ansi, esc, store
##
## @param[in] text
##
## type=text のとき、引数 text は表示する文字列を含む。
## 改行などの制御文字は代替表現に置き換えられる。
## type=ansi のとき、引数 text はANSI制御シーケンスを含む文字列を指定する。
## type=esc のとき、引数 text は現在の端末の制御シーケンスを含む文字列を指定する。
##
## これらの文字列について
## 画面からはみ出る文字列に関しては自動で truncate される。
##
function ble-edit/info/show {
local type=$1 text=$2
if [[ $text ]]; then
local x y content=
ble-edit/info/.construct-content "$@"
ble-edit/info/.render-content "$x" "$y" "$content"
ble/util/buffer.flush >&2
_ble_edit_info_scene=show
else
ble-edit/info/default
fi
}
function ble-edit/info/set-default {
local type=$1 text=$2
local x y content
ble-edit/info/.construct-content "$type" "$text"
_ble_edit_info_default=("$x" "$y" "$content")
}
function ble-edit/info/default {
_ble_edit_info_scene=default
(($#)) && ble-edit/info/set-default "$@"
return 0
}
function ble-edit/info/clear {
ble-edit/info/default
}
## 関数 ble-edit/info/hide
## 関数 ble-edit/info/reveal
##
## これらの関数は .newline 前後に一時的に info の表示を抑制するための関数である。
## この関数の呼び出しの後に flush が入ることを想定して ble/util/buffer.flush は実行しない。
##
function ble-edit/info/hide {
ble-edit/info/.clear-content
}
function ble-edit/info/reveal {
if [[ $_ble_edit_info_scene == default ]]; then
ble-edit/info/.render-content "${_ble_edit_info_default[@]}"
fi
}
function ble-edit/info/immediate-show {
local x=$_ble_canvas_x y=$_ble_canvas_y
ble-edit/info/show "$@"
local -a DRAW_BUFF=()
ble/canvas/goto.draw "$x" "$y"
ble/canvas/bflush.draw
ble/util/buffer.flush >&2
}
function ble-edit/info/immediate-clear {
local x=$_ble_canvas_x y=$_ble_canvas_y
ble-edit/info/clear
ble-edit/info/reveal
local -a DRAW_BUFF=()
ble/canvas/goto.draw "$x" "$y"
ble/canvas/bflush.draw
ble/util/buffer.flush >&2
}
#
#------------------------------------------------------------------------------
# **** edit **** @edit
_ble_edit_VARNAMES=(
_ble_edit_str
_ble_edit_ind
_ble_edit_mark
_ble_edit_mark_active
_ble_edit_overwrite_mode
_ble_edit_line_disabled
_ble_edit_arg
_ble_edit_dirty_draw_beg
_ble_edit_dirty_draw_end
_ble_edit_dirty_draw_end0
_ble_edit_dirty_syntax_beg
_ble_edit_dirty_syntax_end
_ble_edit_dirty_syntax_end0
_ble_edit_kill_ring
_ble_edit_kill_type
_ble_edit_dirty_observer)
_ble_edit_ARRNAMES=()
# 現在の編集状態は以下の変数で表現される
_ble_edit_str=
_ble_edit_ind=0
_ble_edit_mark=0
_ble_edit_mark_active=
_ble_edit_overwrite_mode=
_ble_edit_line_disabled=
_ble_edit_arg=
# 以下は複数の編集文字列が合ったとして全体で共有して良いもの
_ble_edit_kill_ring=
_ble_edit_kill_type=
# _ble_edit_str は以下の関数を通して変更する。
# 変更範囲を追跡する為。
function ble-edit/content/replace {
local beg=$1 end=$2
local ins=$3 reason=${4:-edit}
# cf. Note#1
_ble_edit_str="${_ble_edit_str::beg}""$ins""${_ble_edit_str:end}"
ble-edit/content/.update-dirty-range "$beg" $((beg+${#ins})) "$end" "$reason"
#%if !release
# Note: 何処かのバグで _ble_edit_ind に変な値が入ってエラーになるので、
# ここで誤り訂正を行う。想定として、この関数を呼出した時の _ble_edit_ind の値は、
# replace を実行する前の値とする。この関数の呼び出し元では、
# _ble_edit_ind の更新はこの関数の呼び出しより後で行う様にする必要がある。
# Note: このバグは恐らく #D0411 で解決したが暫く様子見する。
if ! ((0<=_ble_edit_dirty_syntax_beg&&_ble_edit_dirty_syntax_end<=${#_ble_edit_str})); then
ble/util/stackdump "0 <= beg=$_ble_edit_dirty_syntax_beg <= end=$_ble_edit_dirty_syntax_end <= len=${#_ble_edit_str}; beg=$beg, end=$end, ins(${#ins})=$ins"
_ble_edit_dirty_syntax_beg=0
_ble_edit_dirty_syntax_end=${#_ble_edit_str}
_ble_edit_dirty_syntax_end0=0
local olen=$((${#_ble_edit_str}-${#ins}+end-beg))
((olen<0&&(olen=0),
_ble_edit_ind>olen&&(_ble_edit_ind=olen),
_ble_edit_mark>olen&&(_ble_edit_mark=olen)))
fi
#%end
}
function ble-edit/content/reset {
local str=$1 reason=${2:-edit}
local beg=0 end=${#str} end0=${#_ble_edit_str}
_ble_edit_str=$str
ble-edit/content/.update-dirty-range "$beg" "$end" "$end0" "$reason"
#%if !release
if ! ((0<=_ble_edit_dirty_syntax_beg&&_ble_edit_dirty_syntax_end<=${#_ble_edit_str})); then
ble/util/stackdump "0 <= beg=$_ble_edit_dirty_syntax_beg <= end=$_ble_edit_dirty_syntax_end <= len=${#_ble_edit_str}; str(${#str})=$str"
_ble_edit_dirty_syntax_beg=0
_ble_edit_dirty_syntax_end=${#_ble_edit_str}
_ble_edit_dirty_syntax_end0=0
fi
#%end
}
function ble-edit/content/reset-and-check-dirty {
local str=$1 reason=${2:-edit}
[[ $_ble_edit_str == "$str" ]] && return
local ret pref suff
ble/string#common-prefix "$_ble_edit_str" "$str"; pref=$ret
local dmin=${#pref}
ble/string#common-suffix "${_ble_edit_str:dmin}" "${str:dmin}"; suff=$ret
local dmax0=$((${#_ble_edit_str}-${#suff})) dmax=$((${#str}-${#suff}))
_ble_edit_str=$str
ble-edit/content/.update-dirty-range "$dmin" "$dmax" "$dmax0" "$reason"
}
_ble_edit_dirty_draw_beg=-1
_ble_edit_dirty_draw_end=-1
_ble_edit_dirty_draw_end0=-1
_ble_edit_dirty_syntax_beg=0
_ble_edit_dirty_syntax_end=0
_ble_edit_dirty_syntax_end0=1
_ble_edit_dirty_observer=()
## 関数 ble-edit/content/.update-dirty-range beg end end0 [reason]
## @param[in] beg end end0
## 変更範囲を指定します。
## @param[in] reason
## 変更の理由を表す文字列を指定します。
function ble-edit/content/.update-dirty-range {
ble/dirty-range#update --prefix=_ble_edit_dirty_draw_ "${@:1:3}"
ble/dirty-range#update --prefix=_ble_edit_dirty_syntax_ "${@:1:3}"
ble/textmap#update-dirty-range "${@:1:3}"
local obs
for obs in "${_ble_edit_dirty_observer[@]}"; do "$obs" "$@"; done
}
function ble-edit/content/update-syntax {
if ble/is-function ble/syntax/parse; then
local beg end end0
ble/dirty-range#load --prefix=_ble_edit_dirty_syntax_