decode.sh (144886B)
1 #! /bin/bash 2 3 bleopt/declare -v decode_error_char_abell '' 4 bleopt/declare -v decode_error_char_vbell 1 5 bleopt/declare -v decode_error_char_discard '' 6 bleopt/declare -v decode_error_cseq_abell '' 7 bleopt/declare -v decode_error_cseq_vbell '' 8 bleopt/declare -v decode_error_cseq_discard 1 9 bleopt/declare -v decode_error_kseq_abell 1 10 bleopt/declare -v decode_error_kseq_vbell 1 11 bleopt/declare -v decode_error_kseq_discard 1 12 13 ## @bleopt default_keymap 14 ## 既定の編集モードに使われるキーマップを指定します。 15 ## bleopt_default_keymap=auto 16 ## [[ -o emacs/vi ]] の状態に応じて emacs/vi を切り替えます。 17 ## bleopt_default_keymap=emacs 18 ## emacs と同様の編集モードを使用します。 19 ## bleopt_default_keymap=vi 20 ## vi と同様の編集モードを使用します。 21 bleopt/declare -n default_keymap auto 22 23 function bleopt/check:default_keymap { 24 case $value in 25 (auto|emacs|vi|safe) 26 if [[ $_ble_decode_bind_state != none ]]; then 27 local bleopt_default_keymap=$value 28 ble/decode/reset-default-keymap 29 fi 30 return 0 ;; 31 (*) 32 ble/util/print "bleopt: Invalid value default_keymap='value'. The value should be one of \`auto', \`emacs', \`vi'." >&2 33 return 1 ;; 34 esac 35 } 36 37 ## @fn bleopt/get:default_keymap 38 ## @var[out] ret 39 function bleopt/get:default_keymap { 40 ret=$bleopt_default_keymap 41 if [[ $ret == auto ]]; then 42 if [[ -o vi ]]; then 43 ret=vi 44 else 45 ret=emacs 46 fi 47 fi 48 } 49 50 ## @bleopt decode_isolated_esc 51 ## bleopt decode_isolated_esc=meta 52 ## 単体で受信した ESC を、前置詞として受信した ESC と同様に、 53 ## Meta 修飾または特殊キーのエスケープシーケンスとして扱います。 54 ## bleopt decode_isolated_esc=esc 55 ## 単体で受信した ESC を、C-[ として扱います。 56 bleopt/declare -n decode_isolated_esc auto 57 58 function bleopt/check:decode_isolated_esc { 59 case $value in 60 (meta|esc|auto) ;; 61 (*) 62 ble/util/print "bleopt: Invalid value decode_isolated_esc='$value'. One of the values 'auto', 'meta' or 'esc' is expected." >&2 63 return 1 ;; 64 esac 65 } 66 function ble/decode/uses-isolated-esc { 67 if [[ $bleopt_decode_isolated_esc == esc ]]; then 68 return 0 69 elif [[ $bleopt_decode_isolated_esc == auto ]]; then 70 if local ret; bleopt/get:default_keymap; [[ $ret == vi ]]; then 71 return 0 72 elif [[ ! $_ble_decode_key__seq ]]; then 73 local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_ key=$((_ble_decode_Ctrl|91)) 74 builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[key]-}" 75 [[ ${ent:2} ]] && return 0 76 fi 77 fi 78 79 return 1 80 } 81 82 ## @bleopt decode_abort_char 83 bleopt/declare -n decode_abort_char 28 84 85 ## @bleopt decode_macro_limit 86 bleopt/declare -n decode_macro_limit 1024 87 88 # **** key names **** 89 90 _ble_decode_Meta=0x08000000 91 _ble_decode_Ctrl=0x04000000 92 _ble_decode_Shft=0x02000000 93 _ble_decode_Hypr=0x01000000 94 _ble_decode_Supr=0x00800000 95 _ble_decode_Altr=0x00400000 96 _ble_decode_MaskChar=0x001FFFFF 97 _ble_decode_MaskFlag=0x7FC00000 98 99 ## @var _ble_decode_Erro 100 ## 文字復号に異常があった事を表します。 101 ## @var _ble_decode_Macr 102 ## マクロ再生で生成された文字である事を表します。 103 _ble_decode_Erro=0x40000000 104 _ble_decode_Macr=0x20000000 105 106 _ble_decode_Flag3=0x10000000 # unused 107 _ble_decode_FlagA=0x00200000 # unused 108 109 _ble_decode_IsolatedESC=$((0x07FF)) 110 _ble_decode_EscapedNUL=$((0x07FE)) # charlog#encode で用いる 111 _ble_decode_FunctionKeyBase=0x110000 112 113 ## @fn ble-decode-kbd/.set-keycode keyname key 114 ## 115 ## @fn ble-decode-kbd/.get-keycode keyname 116 ## @var[out] ret 117 _ble_decode_kbd_ver=gdict 118 _ble_decode_kbd__n=0 119 _ble_decode_kbd__c2k=() 120 builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_decode_kbd__k2c}" 121 ble/is-assoc _ble_decode_kbd__k2c || _ble_decode_kbd_ver=adict 122 123 function ble-decode-kbd/.set-keycode { 124 local keyname=$1 125 local code=$2 126 : "${_ble_decode_kbd__c2k[code]:=$keyname}" 127 ble/gdict#set _ble_decode_kbd__k2c "$keyname" "$code" 128 } 129 function ble-decode-kbd/.get-keycode { 130 ble/gdict#get _ble_decode_kbd__k2c "$1" 131 } 132 133 ## @fn ble-decode-kbd/.get-keyname keycode 134 ## 135 ## keycode に対応するキーの名前を求めます。 136 ## 対応するキーが存在しない場合には空文字列を返します。 137 ## 138 ## @param[in] keycode keycode 139 ## @var[out] ret keyname 140 ## 141 function ble-decode-kbd/.get-keyname { 142 local keycode=$1 143 ret=${_ble_decode_kbd__c2k[keycode]} 144 if [[ ! $ret ]] && ((keycode<_ble_decode_FunctionKeyBase)); then 145 ble/util/c2s "$keycode" 146 fi 147 } 148 ## @fn ble-decode-kbd/generate-keycode keyname 149 ## 指定した名前に対応する keycode を取得します。 150 ## 指定した名前の key が登録されていない場合は、 151 ## 新しく kecode を割り当てて返します。 152 ## @param[in] keyname keyname 153 ## @var [out] ret keycode 154 function ble-decode-kbd/generate-keycode { 155 local keyname=$1 156 if ((${#keyname}==1)); then 157 ble/util/s2c "$1" 158 elif [[ $keyname && ! ${keyname//[_a-zA-Z0-9]} ]]; then 159 ble-decode-kbd/.get-keycode "$keyname" 160 if [[ ! $ret ]]; then 161 ((ret=_ble_decode_FunctionKeyBase+_ble_decode_kbd__n++)) 162 ble-decode-kbd/.set-keycode "$keyname" "$ret" 163 fi 164 else 165 ret=-1 166 return 1 167 fi 168 } 169 170 function ble-decode-kbd/.initialize { 171 ble-decode-kbd/.set-keycode TAB 9 172 ble-decode-kbd/.set-keycode RET 13 173 174 ble-decode-kbd/.set-keycode NUL 0 175 ble-decode-kbd/.set-keycode SOH 1 176 ble-decode-kbd/.set-keycode STX 2 177 ble-decode-kbd/.set-keycode ETX 3 178 ble-decode-kbd/.set-keycode EOT 4 179 ble-decode-kbd/.set-keycode ENQ 5 180 ble-decode-kbd/.set-keycode ACK 6 181 ble-decode-kbd/.set-keycode BEL 7 182 ble-decode-kbd/.set-keycode BS 8 183 ble-decode-kbd/.set-keycode HT 9 # aka TAB 184 ble-decode-kbd/.set-keycode LF 10 185 ble-decode-kbd/.set-keycode VT 11 186 ble-decode-kbd/.set-keycode FF 12 187 ble-decode-kbd/.set-keycode CR 13 # aka RET 188 ble-decode-kbd/.set-keycode SO 14 189 ble-decode-kbd/.set-keycode SI 15 190 191 ble-decode-kbd/.set-keycode DLE 16 192 ble-decode-kbd/.set-keycode DC1 17 193 ble-decode-kbd/.set-keycode DC2 18 194 ble-decode-kbd/.set-keycode DC3 19 195 ble-decode-kbd/.set-keycode DC4 20 196 ble-decode-kbd/.set-keycode NAK 21 197 ble-decode-kbd/.set-keycode SYN 22 198 ble-decode-kbd/.set-keycode ETB 23 199 ble-decode-kbd/.set-keycode CAN 24 200 ble-decode-kbd/.set-keycode EM 25 201 ble-decode-kbd/.set-keycode SUB 26 202 ble-decode-kbd/.set-keycode ESC 27 203 ble-decode-kbd/.set-keycode FS 28 204 ble-decode-kbd/.set-keycode GS 29 205 ble-decode-kbd/.set-keycode RS 30 206 ble-decode-kbd/.set-keycode US 31 207 208 ble-decode-kbd/.set-keycode SP 32 209 ble-decode-kbd/.set-keycode DEL 127 210 211 ble-decode-kbd/.set-keycode PAD 128 212 ble-decode-kbd/.set-keycode HOP 129 213 ble-decode-kbd/.set-keycode BPH 130 214 ble-decode-kbd/.set-keycode NBH 131 215 ble-decode-kbd/.set-keycode IND 132 216 ble-decode-kbd/.set-keycode NEL 133 217 ble-decode-kbd/.set-keycode SSA 134 218 ble-decode-kbd/.set-keycode ESA 135 219 ble-decode-kbd/.set-keycode HTS 136 220 ble-decode-kbd/.set-keycode HTJ 137 221 ble-decode-kbd/.set-keycode VTS 138 222 ble-decode-kbd/.set-keycode PLD 139 223 ble-decode-kbd/.set-keycode PLU 140 224 ble-decode-kbd/.set-keycode RI 141 225 ble-decode-kbd/.set-keycode SS2 142 226 ble-decode-kbd/.set-keycode SS3 143 227 228 ble-decode-kbd/.set-keycode DCS 144 229 ble-decode-kbd/.set-keycode PU1 145 230 ble-decode-kbd/.set-keycode PU2 146 231 ble-decode-kbd/.set-keycode STS 147 232 ble-decode-kbd/.set-keycode CCH 148 233 ble-decode-kbd/.set-keycode MW 149 234 ble-decode-kbd/.set-keycode SPA 150 235 ble-decode-kbd/.set-keycode EPA 151 236 ble-decode-kbd/.set-keycode SOS 152 237 ble-decode-kbd/.set-keycode SGCI 153 238 ble-decode-kbd/.set-keycode SCI 154 239 ble-decode-kbd/.set-keycode CSI 155 240 ble-decode-kbd/.set-keycode ST 156 241 ble-decode-kbd/.set-keycode OSC 157 242 ble-decode-kbd/.set-keycode PM 158 243 ble-decode-kbd/.set-keycode APC 159 244 245 ble-decode-kbd/.set-keycode @ESC "$_ble_decode_IsolatedESC" 246 ble-decode-kbd/.set-keycode @NUL "$_ble_decode_EscapedNUL" 247 248 local ret 249 ble-decode-kbd/generate-keycode __batch_char__ 250 _ble_decode_KCODE_BATCH_CHAR=$ret 251 ble-decode-kbd/generate-keycode __defchar__ 252 _ble_decode_KCODE_DEFCHAR=$ret 253 ble-decode-kbd/generate-keycode __default__ 254 _ble_decode_KCODE_DEFAULT=$ret 255 ble-decode-kbd/generate-keycode __before_widget__ 256 _ble_decode_KCODE_BEFORE_WIDGET=$ret 257 ble-decode-kbd/generate-keycode __after_widget__ 258 _ble_decode_KCODE_AFTER_WIDGET=$ret 259 ble-decode-kbd/generate-keycode __attach__ 260 _ble_decode_KCODE_ATTACH=$ret 261 ble-decode-kbd/generate-keycode __detach__ 262 _ble_decode_KCODE_DETACH=$ret 263 264 ble-decode-kbd/generate-keycode shift 265 _ble_decode_KCODE_SHIFT=$ret 266 ble-decode-kbd/generate-keycode alter 267 _ble_decode_KCODE_ALTER=$ret 268 ble-decode-kbd/generate-keycode control 269 _ble_decode_KCODE_CONTROL=$ret 270 ble-decode-kbd/generate-keycode meta 271 _ble_decode_KCODE_META=$ret 272 ble-decode-kbd/generate-keycode super 273 _ble_decode_KCODE_SUPER=$ret 274 ble-decode-kbd/generate-keycode hyper 275 _ble_decode_KCODE_HYPER=$ret 276 277 # Note: 無視するキー。ble-decode-char に於いて 278 # 端末からの通知などを処理した時に使う。 279 ble-decode-kbd/generate-keycode __ignore__ 280 _ble_decode_KCODE_IGNORE=$ret 281 282 # Note: bleopt decode_error_cseq_discard 283 ble-decode-kbd/generate-keycode __error__ 284 _ble_decode_KCODE_ERROR=$ret 285 286 # Note: line_limit による制限超過時のイベント 287 ble-decode-kbd/generate-keycode __line_limit__ 288 _ble_decode_KCODE_LINE_LIMIT=$ret 289 290 # Note: 暫定的な対応なので後で変更するかもしれない 291 ble-decode-kbd/generate-keycode mouse 292 _ble_decode_KCODE_MOUSE=$ret 293 ble-decode-kbd/generate-keycode mouse_move 294 _ble_decode_KCODE_MOUSE_MOVE=$ret 295 296 # Note: 以下は改めてそれぞれのファイルで参照される 297 # コードを固定する為にここで定義しておく。 298 ble-decode-kbd/generate-keycode auto_complete_enter 299 300 # Note: ここに新しく kcode を追加した時には init-cmap.sh に何か変更をして、 301 # cmap 及び keymap が更新される様にする必要がある。emacs.sh, vi.sh については 302 # init-cmap.sh を見て自動的に更新されるので特別な処置は必要ない筈。 303 } 304 305 ble-decode-kbd/.initialize 306 307 ## @fn ble-decode-kbd [TYPE:]VALUE... 308 ## @param[in] TYPE VALUE 309 ## キー列を指定します。TYPE はキー列の解釈方法を指定します。 310 ## TYPE の値に応じて VALUE には以下の物を指定します。TYPE の既定値は kbd です。 311 ## kspecs ... kspecs を指定します。 312 ## keys ... キーコードの整数列を指定します。 313 ## chars ... 文字コードの整数列を指定します。 314 ## keyseq ... bash bind の keyseq を指定します。 315 ## raw ... バイト列を直接文字列として指定します。 316 ## 317 ## @var[out] ret 318 ## キー列を空白区切りの整数列として返します。 319 function ble-decode-kbd { 320 local IFS=$_ble_term_IFS 321 local spec="$*" 322 case $spec in 323 (keys:*) 324 ret="${spec#*:}" 325 return 0 ;; 326 (chars:*) 327 local chars 328 ble/string#split-words chars "${spec#*:}" 329 ble/decode/cmap/decode-chars "${ret[@]}" 330 ret="${keys[*]}" 331 return 0 ;; 332 (keyseq:*) # i.e. untranslated keyseq 333 local keys 334 ble/util/keyseq2chars "${spec#*:}" 335 ble/decode/cmap/decode-chars "${ret[@]}" 336 ret="${keys[*]}" 337 return 0 ;; 338 (raw:*) # i.e. translated keyseq 339 ble/util/s2chars "${spec#*:}" 340 ble/decode/cmap/decode-chars "${ret[@]}" 341 ret="${keys[*]}" 342 return 0 ;; 343 (kspecs:*) 344 spec=${spec#*:} ;; 345 esac 346 347 local kspecs; ble/string#split-words kspecs "$spec" 348 local kspec code codes 349 codes=() 350 for kspec in "${kspecs[@]}"; do 351 code=0 352 while [[ $kspec == ?-* ]]; do 353 case ${kspec::1} in 354 (S) ((code|=_ble_decode_Shft)) ;; 355 (C) ((code|=_ble_decode_Ctrl)) ;; 356 (M) ((code|=_ble_decode_Meta)) ;; 357 (A) ((code|=_ble_decode_Altr)) ;; 358 (s) ((code|=_ble_decode_Supr)) ;; 359 (H) ((code|=_ble_decode_Hypr)) ;; 360 (*) ((code|=_ble_decode_Erro)) ;; 361 esac 362 kspec=${kspec:2} 363 done 364 365 if [[ $kspec == ? ]]; then 366 ble/util/s2c "$kspec" 367 ((code|=ret)) 368 elif [[ $kspec && ! ${kspec//[@_a-zA-Z0-9]} ]]; then 369 ble-decode-kbd/.get-keycode "$kspec" 370 [[ $ret ]] || ble-decode-kbd/generate-keycode "$kspec" 371 ((code|=ret)) 372 elif [[ $kspec == ^? ]]; then 373 if [[ $kspec == '^?' ]]; then 374 ((code|=0x7F)) 375 elif [[ $kspec == '^`' ]]; then 376 ((code|=0x20)) 377 else 378 ble/util/s2c "${kspec:1}" 379 ((code|=ret&0x1F)) 380 fi 381 elif local rex='^U\+([0-9a-fA-F]+)$'; [[ $kspec =~ $rex ]]; then 382 ((code|=0x${BASH_REMATCH[1]})) 383 else 384 ((code|=_ble_decode_Erro)) 385 fi 386 387 codes[${#codes[@]}]=$code 388 done 389 390 ret="${codes[*]}" 391 } 392 393 ## @fn ble-decode-unkbd/.single-key key 394 ## @var[in] key 395 ## キーを表す整数値 396 ## @var[out] ret 397 ## key の文字列表現を返します。 398 function ble-decode-unkbd/.single-key { 399 local key=$1 400 401 local f_unknown= 402 local char=$((key&_ble_decode_MaskChar)) 403 ble-decode-kbd/.get-keyname "$char" 404 if [[ ! $ret ]]; then 405 f_unknown=1 406 ret=__UNKNOWN__ 407 fi 408 409 ((key&_ble_decode_Shft)) && ret=S-$ret 410 ((key&_ble_decode_Meta)) && ret=M-$ret 411 ((key&_ble_decode_Ctrl)) && ret=C-$ret 412 ((key&_ble_decode_Altr)) && ret=A-$ret 413 ((key&_ble_decode_Supr)) && ret=s-$ret 414 ((key&_ble_decode_Hypr)) && ret=H-$ret 415 416 [[ ! $f_unknown ]] 417 } 418 419 ## @fn ble-decode-unkbd keys... 420 ## @param[in] keys 421 ## キーを表す整数値の列を指定します。 422 ## @var[out] ret 423 function ble-decode-unkbd { 424 local IFS=$_ble_term_IFS 425 local -a kspecs 426 local key 427 for key in $*; do 428 ble-decode-unkbd/.single-key "$key" 429 kspecs[${#kspecs[@]}]=$ret 430 done 431 ret="${kspecs[*]}" 432 } 433 434 # **** ble-decode-byte **** 435 436 ## @fn[custom] ble-decode/PROLOGUE 437 ## @fn[custom] ble-decode/EPILOGUE 438 function ble-decode/PROLOGUE { :; } 439 function ble-decode/EPILOGUE { :; } 440 441 _ble_decode_input_buffer=() 442 _ble_decode_input_count=0 443 _ble_decode_input_original_info=() 444 445 _ble_decode_show_progress_hook=ble-decode/.hook/show-progress 446 _ble_decode_erase_progress_hook=ble-decode/.hook/erase-progress 447 function ble-decode/.hook/show-progress { 448 if [[ $_ble_edit_info_scene == store ]]; then 449 _ble_decode_input_original_info=("${_ble_edit_info[@]}") 450 return 0 451 elif [[ $_ble_edit_info_scene == default ]]; then 452 _ble_decode_input_original_info=() 453 elif [[ $_ble_edit_info_scene != decode_input_progress ]]; then 454 return 0 455 fi 456 457 local progress_opts= opt_percentage=1 458 if [[ $ble_batch_insert_count ]]; then 459 local total=$ble_batch_insert_count 460 local value=$ble_batch_insert_index 461 local label='constructing text...' 462 local sgr=$'\e[1;38;5;204;48;5;253m' 463 elif ((${#_ble_decode_input_buffer[@]})); then 464 local total=10000 465 local value=$((${#_ble_decode_input_buffer[@]}%10000)) 466 local label="${#_ble_decode_input_buffer[@]} bytes received..." 467 local sgr=$'\e[1;38;5;135;48;5;253m' 468 progress_opts=unlimited 469 opt_percentage= 470 elif ((_ble_decode_input_count)); then 471 local total=${#chars[@]} 472 local value=$((total-_ble_decode_input_count-1)) 473 local label='decoding input...' 474 local sgr=$'\e[1;38;5;69;48;5;253m' 475 elif ((ble_decode_char_total)); then 476 local total=$ble_decode_char_total 477 local value=$((total-ble_decode_char_rest-1)) 478 local label='processing input...' 479 local sgr=$'\e[1;38;5;71;48;5;253m' 480 else 481 return 0 482 fi 483 484 if [[ $opt_percentage ]]; then 485 local mill=$((value*1000/total)) 486 local cent=${mill::${#mill}-1} frac=${mill:${#mill}-1} 487 label="${cent:-0}.$frac% $label" 488 fi 489 490 local text="($label)" 491 if ble/util/is-unicode-output; then 492 local ret 493 ble/string#create-unicode-progress-bar "$value" "$total" 10 "$progress_opts" 494 text=$sgr$ret$'\e[m '$text 495 fi 496 497 ble/edit/info/show ansi "$text" 498 499 _ble_edit_info_scene=decode_input_progress 500 } 501 function ble-decode/.hook/erase-progress { 502 [[ $_ble_edit_info_scene == decode_input_progress ]] || return 1 503 if ((${#_ble_decode_input_original_info[@]})); then 504 ble/edit/info/show store "${_ble_decode_input_original_info[@]}" 505 else 506 ble/edit/info/default 507 fi 508 } 509 510 ## @fn ble-decode/.check-abort byte 511 ## bleopt_decode_abort_char による decode abort を検出します。 512 ## 513 ## @remarks modifyOtherKeys も考慮に入れると実は C-x の形式のキーは 514 ## "CSI 27;5; code ~" や "CSI code ;5u" の形式で送られてくる。 515 ## _ble_decode_input_buffer に記録されている受信済みバイトも検査して 516 ## これらのシーケンスを構成していないか確認する必要がある。 517 ## 518 function ble-decode/.check-abort { 519 if (($1==bleopt_decode_abort_char)); then 520 local nbytes=${#_ble_decode_input_buffer[@]} 521 local nchars=${#_ble_decode_char_buffer[@]} 522 ((nbytes||nchars)); return "$?" 523 fi 524 525 (($1==0x7e||$1==0x75)) || return 1 526 527 local i=$((${#_ble_decode_input_buffer[@]}-1)) 528 local n 529 ((n=bleopt_decode_abort_char, 530 n+=(1<=n&&n<=26?96:64))) 531 532 if (($1==0x7e)); then 533 # Check "CSI >? 27 ; 5 ; XXX ~" 534 535 # Check code 536 for ((;n;n/=10)); do 537 ((i>=0)) && ((_ble_decode_input_buffer[i--]==n%10+48)) || return 1 538 done 539 540 # Check "27;5;" 541 ((i>=4)) || return 1 542 ((_ble_decode_input_buffer[i--]==59)) || return 1 543 ((_ble_decode_input_buffer[i--]==53)) || return 1 544 ((_ble_decode_input_buffer[i--]==59)) || return 1 545 ((_ble_decode_input_buffer[i--]==55)) || return 1 546 ((_ble_decode_input_buffer[i--]==50)) || return 1 547 548 elif (($1==0x75)); then 549 # Check "CSI >? XXX ; 5 u" 550 551 # Check ";5" 552 ((i>=1)) || return 1 553 ((_ble_decode_input_buffer[i--]==53)) || return 1 554 ((_ble_decode_input_buffer[i--]==59)) || return 1 555 556 # Check code 557 for ((;n;n/=10)); do 558 ((i>=0)) && ((_ble_decode_input_buffer[i--]==n%10+48)) || return 1 559 done 560 fi 561 562 # Skip ">" 563 ((i>=0)) && ((_ble_decode_input_buffer[i]==62&&i--)) 564 565 # Check CSI ("\e[", "\xC0\x9B[" or "\xC2\x9B") 566 # ENCODING: UTF-8 (\xC0\x9B) 567 ((i>=0)) || return 1 568 if ((_ble_decode_input_buffer[i]==0x5B)); then 569 if ((i>=1&&_ble_decode_input_buffer[i-1]==0x1B)); then 570 ((i-=2)) 571 elif ((i>=2&&_ble_decode_input_buffer[i-1]==0x9B&&_ble_decode_input_buffer[i-2]==0xC0)); then 572 ((i-=3)) 573 else 574 return 1 575 fi 576 elif ((_ble_decode_input_buffer[i]==0x9B)); then 577 ((--i>=0)) && ((_ble_decode_input_buffer[i--]==0xC2)) || return 1 578 else 579 return 1 580 fi 581 (((i>=0||${#_ble_decode_char_buffer[@]}))); return "$?" 582 return 0 583 } 584 585 if ((_ble_bash>=40400)); then 586 function ble/decode/nonblocking-read { 587 local timeout=${1:-0.01} ntimeout=${2:-1} loop=${3:-100} 588 local LC_ALL= LC_CTYPE=C IFS= 589 local -a data=() 590 local line buff ext 591 while ((loop--)); do 592 ble/bash/read-timeout "$timeout" -r -d '' buff; ext=$? 593 [[ $buff ]] && line=$line$buff 594 if ((ext==0)); then 595 ble/array#push data "$line" 596 line= 597 elif ((ext>128)); then 598 # timeout 599 ((--ntimeout)) || break 600 [[ $buff ]] || break 601 else 602 break 603 fi 604 done 605 606 ble/util/assign ret '{ 607 ((${#data[@]})) && printf %s\\0 "${data[@]}" 608 [[ $line ]] && printf %s "$line" 609 } | ble/bin/od -A n -t u1 -v' 610 ble/string#split-words ret "$ret" 611 } 612 # suppress locale error #D1440 613 ble/function#suppress-stderr ble/decode/nonblocking-read 614 elif ((_ble_bash>=40000)); then 615 function ble/decode/nonblocking-read { 616 local timeout=${1:-0.01} ntimeout=${2:-1} loop=${3:-100} 617 local LC_ALL= LC_CTYPE=C IFS= 2>/dev/null 618 local -a data=() 619 local line buff 620 while ((loop--)); do 621 builtin read -t 0 || break 622 ble/bash/read -d '' -n 1 buff || break 623 if [[ $buff ]]; then 624 line=$line$buff 625 else 626 ble/array#push data "$line" 627 line= 628 fi 629 done 630 631 ble/util/assign ret '{ 632 ((${#data[@]})) && printf %s\\0 "${data[@]}" 633 [[ $line ]] && printf %s "$line" 634 } | ble/bin/od -A n -t u1 -v' 635 ble/string#split-words ret "$ret" 636 } 637 # suppress locale error #D1440 638 ble/function#suppress-stderr ble/decode/nonblocking-read 639 fi 640 641 function ble-decode/.hook/adjust-volatile-options { 642 # Note: bind -x 内の set +v は揮発性なのでできるだけ先頭で set +v しておく。 643 # (PROLOGUE 内から呼ばれる) stdout.on より前であれば大丈夫 #D0930 644 if [[ $_ble_bash_options_adjusted ]]; then 645 set +ev 646 fi 647 if [[ $_ble_bash_POSIXLY_CORRECT_adjusted && ${POSIXLY_CORRECT+set} ]]; then 648 set +o posix 649 ble/base/workaround-POSIXLY_CORRECT 650 fi 651 } 652 653 ## @var _ble_decode_hook_count 654 ## これまでに呼び出された ble-decode/.hook の回数を記録する。(同じ 655 ## bash プロセス内の前の ble.sh session も含めて) 今までに一度も呼び 656 ## 出された事がない場合には空文字列を設定する。 657 _ble_decode_hook_count=${_ble_decode_hook_count:+0} 658 _ble_decode_hook_Processing= 659 function ble-decode/.hook { 660 #%if leakvar 661 ble/debug/leakvar#check $"leakvar" H0-begin 662 #%end.i 663 ((_ble_decode_hook_count++)) 664 if ble/util/is-stdin-ready; then 665 ble/array#push _ble_decode_input_buffer "$@" 666 667 local buflen=${#_ble_decode_input_buffer[@]} 668 if ((buflen%257==0&&buflen>=2000)); then 669 ble-decode/.hook/adjust-volatile-options 670 671 local IFS=$_ble_term_IFS 672 local _ble_decode_hook_Processing=prologue 673 ble-decode/PROLOGUE 674 _ble_decode_hook_Processing=body 675 676 # その場で標準入力を読み切る 677 local char=${_ble_decode_input_buffer[buflen-1]} 678 if ((_ble_bash<40000||char==0xC0||char==0xDF)); then 679 # Note: これらの文字は bind -s マクロの非終端文字。 680 # 現在マクロの処理中である可能性があるので標準入力から 681 # 読み取るとバイトの順序が変わる可能性がある。 682 # 従って読み取りは行わない。 683 builtin eval -- "$_ble_decode_show_progress_hook" 684 else 685 while ble/util/is-stdin-ready; do 686 builtin eval -- "$_ble_decode_show_progress_hook" 687 local ret; ble/decode/nonblocking-read 0.02 1 527 688 ble/array#push _ble_decode_input_buffer "${ret[@]}" 689 done 690 fi 691 _ble_decode_hook_Processing=epilogue 692 ble-decode/EPILOGUE 693 ble/util/unlocal _ble_decode_hook_Processing 694 #%if leakvar 695 ble/debug/leakvar#check $"leakvar" H0b1-1 696 #%end.i 697 698 local ret 699 ble/array#pop _ble_decode_input_buffer 700 ble-decode/.hook "$ret" 701 #%if leakvar 702 ble/debug/leakvar#check $"leakvar" H0b1-2 703 #%end.i 704 fi 705 #%if leakvar 706 ble/debug/leakvar#check $"leakvar" H0b2 707 #%end.i 708 709 return 0 710 fi 711 712 ble-decode/.hook/adjust-volatile-options 713 714 local IFS=$_ble_term_IFS 715 local _ble_decode_hook_Processing=prologue 716 ble-decode/PROLOGUE 717 _ble_decode_hook_Processing=body 718 #%if leakvar 719 ble/debug/leakvar#check $"leakvar" H1-PROLOGUE 720 #%end.i 721 722 # abort #D0998 723 if ble-decode/.check-abort "$1"; then 724 _ble_decode_char__hook= 725 _ble_decode_input_buffer=() 726 _ble_decode_char_buffer=() 727 ble/term/visible-bell "Abort by 'bleopt decode_abort_char=$bleopt_decode_abort_char'" 728 shift 729 # 何れにしても EPILOGUE を実行する必要があるので下に流れる。 730 # ble/term/visible-bell を表示する為には PROLOGUE の後でなければならない事にも注意する。 731 fi 732 #%if leakvar 733 ble/debug/leakvar#check $"leakvar" H2-abort 734 #%end.i 735 736 local chars 737 # Note: Bash-4.4 で遅いので ble/array#set 経由で設定する 738 ble/array#set chars "${_ble_decode_input_buffer[@]}" "$@" 739 _ble_decode_input_buffer=() 740 _ble_decode_input_count=${#chars[@]} 741 742 if ((_ble_decode_input_count>=200)); then 743 local i N=${#chars[@]} 744 local B=$((N/100)) 745 ((B<100)) && B=100 || ((B>1000)) && B=1000 746 for ((i=0;i<N;i+=B)); do 747 ((_ble_decode_input_count=N-i-B)) 748 ((_ble_decode_input_count<0)) && _ble_decode_input_count=0 749 builtin eval -- "$_ble_decode_show_progress_hook" 750 #%if debug_keylogger 751 ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_bytes "${chars[@]:i:B}" 752 #%end 753 #%if leakvar 754 ble/debug/leakvar#check $"leakvar" "[H3b1: before decode $chars...]" 755 #%end.i 756 "ble/encoding:$bleopt_input_encoding/decode" "${chars[@]:i:B}" 757 #%if leakvar 758 ble/debug/leakvar#check $"leakvar" "[H3b1: after decode $chars...]" 759 #%end.i 760 done 761 else 762 local c 763 for c in "${chars[@]}"; do 764 ((--_ble_decode_input_count)) 765 #%if debug_keylogger 766 ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_bytes "$c" 767 #%end 768 #%if leakvar 769 ble/debug/leakvar#check $"leakvar" "[H3b2: before decode $c]" 770 #%end.i 771 "ble/encoding:$bleopt_input_encoding/decode" "$c" 772 #%if leakvar 773 ble/debug/leakvar#check $"leakvar" "[H3b2: after decode $c]" 774 #%end.i 775 done 776 fi 777 778 #%if leakvar 779 ble/debug/leakvar#check $"leakvar" H4 780 #%end.i 781 ble/decode/has-input || ble-decode-key/batch/flush 782 #%if leakvar 783 ble/debug/leakvar#check $"leakvar" H4-batch 784 #%end.i 785 786 builtin eval -- "$_ble_decode_erase_progress_hook" 787 _ble_decode_hook_Processing=epilogue 788 ble-decode/EPILOGUE 789 #%if leakvar 790 ble/debug/leakvar#check $"leakvar" H4-EPILOGUE 791 #%end.i 792 } 793 794 ## @fn ble-decode-byte bytes... 795 ## バイト値を整数で受け取って、現在の文字符号化方式に従ってデコードをします。 796 ## デコードした結果得られた文字は ble-decode-char を呼び出す事によって処理します。 797 ## 798 ## Note: 現在 ble.sh 内部では使用されていません。 799 ## この関数はユーザが呼び出す事を想定した関数です。 800 function ble-decode-byte { 801 while (($#)); do 802 "ble/encoding:$bleopt_input_encoding/decode" "$1" 803 shift 804 done 805 } 806 807 # **** ble-decode-char/csi **** 808 809 _ble_decode_csi_mode=0 810 _ble_decode_csi_args= 811 _ble_decode_csimap_tilde=() 812 _ble_decode_csimap_alpha=() 813 function ble-decode-char/csi/print/.print-csidef { 814 local qalpha qkey ret q=\' Q="'\''" 815 if [[ $sgrq ]]; then 816 ble/string#quote-word "$1" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qalpha=$ret 817 ble/string#quote-word "$2" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qkey=$ret 818 else 819 qalpha="'${1//$q/$Q}'" 820 qkey="'${2//$q/$Q}'" 821 fi 822 ble/util/print "${sgrf}ble-bind$sgr0 $sgro--csi$sgr0 $qalpha $qkey" 823 824 } 825 ## @fn ble-decode-char/csi/print 826 ## @var[in] ble_bind_print sgr0 sgrf sgrq sgrc sgro 827 function ble-decode-char/csi/print { 828 [[ $ble_bind_print ]] || local sgr0= sgrf= sgrq= sgrc= sgro= 829 local num ret 830 for num in "${!_ble_decode_csimap_tilde[@]}"; do 831 ble-decode-unkbd "${_ble_decode_csimap_tilde[num]}" 832 ble-decode-char/csi/print/.print-csidef "$num~" "$ret" 833 done 834 835 for num in "${!_ble_decode_csimap_alpha[@]}"; do 836 local s; ble/util/c2s "$num"; s=$ret 837 ble-decode-unkbd "${_ble_decode_csimap_alpha[num]}" 838 ble-decode-char/csi/print/.print-csidef "$s" "$ret" 839 done 840 } 841 842 function ble-decode-char/csi/clear { 843 _ble_decode_csi_mode=0 844 } 845 846 # Initialized in lib/init-cmap.sh 847 _ble_decode_csimap_kitty_u=() 848 849 ## @fn ble-decode/char/csi/.translate-kitty-csi-u 850 ## @var[in,out] key 851 function ble-decode/char/csi/.translate-kitty-csi-u { 852 local name=${_ble_decode_csimap_kitty_u[key]} 853 if [[ $name ]]; then 854 local ret 855 ble-decode-kbd/generate-keycode "$name" 856 key=$ret 857 fi 858 } 859 function ble-decode-char/csi/.modify-key { 860 local mod=$(($1-1)) 861 if ((mod>=0)); then 862 # Note: xterm, mintty では modifyOtherKeys で通常文字に対するシフトは 863 # 文字自体もそれに応じて変化させ、更に修飾フラグも設定する。 864 # Note: RLogin は修飾がある場合は常に英大文字に統一する。 865 if ((33<=key&&key<_ble_decode_FunctionKeyBase)); then 866 local term=${_ble_term_TERM[0]+${_ble_term_TERM[${#_ble_term_TERM[@]}-1]}} 867 if (((mod&0x01)&&0x31<=key&&key<=0x39)) && [[ $term == RLogin:* ]]; then 868 # RLogin は数字に対する S- 修飾の解決はしてくれない。 869 ((key-=16,mod&=~0x01)) 870 elif ((mod==0x01)); then 871 if [[ $term != contra:* ]]; then 872 # S- だけの時には単に S- を外す 873 ((mod&=~0x01)) 874 fi 875 elif ((65<=key&&key<=90)); then 876 # 他の修飾がある時は英大文字は小文字に統一する 877 ((key|=0x20)) 878 fi 879 fi 880 881 # Note: Supr 0x08 以降は独自 882 ((mod&0x01&&(key|=_ble_decode_Shft), 883 mod&0x02&&(key|=_ble_decode_Meta), 884 mod&0x04&&(key|=_ble_decode_Ctrl), 885 mod&0x08&&(key|=_ble_decode_Supr), 886 mod&0x10&&(key|=_ble_decode_Hypr), 887 mod&0x20&&(key|=_ble_decode_Altr))) 888 fi 889 } 890 function ble-decode-char/csi/.decode { 891 local char=$1 rex key 892 if ((char==126)); then # ~ 893 if rex='^>?27;([0-9]+);?([0-9]+)$' && [[ $_ble_decode_csi_args =~ $rex ]]; then 894 # xterm "CSI 2 7 ; <mod> ; <char> ~" sequences 895 local param1=$((10#0${BASH_REMATCH[1]})) 896 local param2=$((10#0${BASH_REMATCH[2]})) 897 local key=$((param2&_ble_decode_MaskChar)) 898 ble-decode-char/csi/.modify-key "$param1" 899 csistat=$key 900 return 0 901 fi 902 903 if rex='^>?([0-9]+)(;([0-9]+))?$' && [[ $_ble_decode_csi_args =~ $rex ]]; then 904 # "CSI <key> ; <mod> ~" sequences 905 local param1=$((10#0${BASH_REMATCH[1]})) 906 local param3=$((10#0${BASH_REMATCH[3]})) 907 key=${_ble_decode_csimap_tilde[param1]} 908 if [[ $key ]]; then 909 ble-decode-char/csi/.modify-key "$param3" 910 csistat=$key 911 return 0 912 fi 913 fi 914 elif ((char==117)); then # u 915 if rex='^([0-9]*)(;[0-9]*)?$'; [[ $_ble_decode_csi_args =~ $rex ]]; then 916 # xterm/mlterm "CSI <char> ; <mode> u" sequences 917 # Note: 実は "CSI 1 ; mod u" が kp5 とする端末がある事に注意する。 918 local rematch1=${BASH_REMATCH[1]} 919 if [[ $rematch1 != 1 ]]; then 920 local key=$((10#0$rematch1)) mods=$((10#0${BASH_REMATCH:${#rematch1}+1})) 921 [[ $_ble_term_TERM == kitty:* ]] && ble-decode/char/csi/.translate-kitty-csi-u 922 ble-decode-char/csi/.modify-key "$mods" 923 csistat=$key 924 fi 925 return 0 926 fi 927 elif ((char==94||char==64)); then # ^, @ 928 if rex='^[0-9]+$' && [[ $_ble_decode_csi_args =~ $rex ]]; then 929 # rxvt "CSI <key> ^", "CSI <key> @" sequences 930 local param1=$((10#0${BASH_REMATCH[1]})) 931 local param3=$((10#0${BASH_REMATCH[3]})) 932 key=${_ble_decode_csimap_tilde[param1]} 933 if [[ $key ]]; then 934 ((key|=_ble_decode_Ctrl, 935 char==64&&(key|=_ble_decode_Shft))) 936 ble-decode-char/csi/.modify-key "$param3" 937 csistat=$key 938 return 0 939 fi 940 fi 941 elif ((char==99)); then # c 942 if rex='^[?>]'; [[ $_ble_decode_csi_args =~ $rex ]]; then 943 # DA1 応答 "CSI ? Pm c" (何故か DA2 要求に対して DA1 で返す端末がある?) 944 # DA2 応答 "CSI > Pm c" 945 if [[ $_ble_decode_csi_args == '?'* ]]; then 946 ble/term/DA1/notify "${_ble_decode_csi_args:1}" 947 else 948 ble/term/DA2/notify "${_ble_decode_csi_args:1}" 949 fi 950 csistat=$_ble_decode_KCODE_IGNORE 951 return 0 952 fi 953 elif ((char==82||char==110)); then # R or n 954 if rex='^([0-9]+);([0-9]+)$'; [[ $_ble_decode_csi_args =~ $rex ]]; then 955 # DSR(6) に対する応答 CPR "CSI Pn ; Pn R" 956 # Note: Poderosa は DSR(Pn;Pn) "CSI Pn ; Pn n" で返す。 957 local param1=$((10#0${BASH_REMATCH[1]})) 958 local param2=$((10#0${BASH_REMATCH[2]})) 959 ble/term/CPR/notify "$param1" "$param2" 960 csistat=$_ble_decode_KCODE_IGNORE 961 return 0 962 fi 963 elif ((char==77||char==109)); then # M or m 964 if rex='^<([0-9]+);([0-9]+);([0-9]+)$'; [[ $_ble_decode_csi_args =~ $rex ]]; then 965 # マウスイベント 966 # button の bit 達 967 # modifiers (mask 0x1C): 4 shift, 8 meta, 16 control 968 # button: 0 mouse1, 1 mouse2, 2 mouse3, 3 release, 64 wheel_up, 65 wheel_down 969 # 他のフラグ: 32 移動 970 # 可能な button のパターン: 971 # mouse1 mouse2 mouse3 mouse4 mouse5 972 # mouse1up mouse2up mouse3up mouse4up mouse5up 973 # mouse1drag mouse2drag mouse3drag mouse4drag mouse5drag 974 # wheelup wheeldown mouse_move 975 local param1=$((10#0${BASH_REMATCH[1]})) 976 local param2=$((10#0${BASH_REMATCH[2]})) 977 local param3=$((10#0${BASH_REMATCH[3]})) 978 local button=$param1 979 ((_ble_term_mouse_button=button&~0x1C, 980 char==109&&(_ble_term_mouse_button|=0x70), 981 _ble_term_mouse_x=param2-1, 982 _ble_term_mouse_y=param3-1)) 983 local key=$_ble_decode_KCODE_MOUSE 984 ((button&32)) && key=$_ble_decode_KCODE_MOUSE_MOVE 985 ble-decode-char/csi/.modify-key "$((button>>2&0x07))" 986 csistat=$key 987 return 0 988 fi 989 elif ((char==116)); then # t 990 if rex='^<([0-9]+);([0-9]+)$'; [[ $_ble_decode_csi_args =~ $rex ]]; then 991 ## mouse_select 992 local param1=$((10#0${BASH_REMATCH[1]})) 993 local param2=$((10#0${BASH_REMATCH[2]})) 994 ((_ble_term_mouse_button=128, 995 _ble_term_mouse_x=param1-1, 996 _ble_term_mouse_y=param2-1)) 997 local key=$_ble_decode_KCODE_MOUSE 998 csistat=$key 999 fi 1000 fi 1001 1002 # pc-style "CSI 1; <mod> A" sequences 1003 key=${_ble_decode_csimap_alpha[char]} 1004 if [[ $key ]]; then 1005 if rex='^(1?|>?1;([0-9]+))$' && [[ $_ble_decode_csi_args =~ $rex ]]; then 1006 local param2=$((10#0${BASH_REMATCH[2]})) 1007 ble-decode-char/csi/.modify-key "$param2" 1008 csistat=$key 1009 return 0 1010 fi 1011 fi 1012 1013 csistat=$_ble_decode_KCODE_ERROR 1014 } 1015 1016 ## @fn ble-decode-char/csi/consume char 1017 ## @param[in] char 1018 ## @var[out] csistat 1019 function ble-decode-char/csi/consume { 1020 csistat= 1021 1022 # 一番頻度の高い物 1023 ((_ble_decode_csi_mode==0&&$1!=27&&$1!=155)) && return 1 1024 1025 local char=$1 1026 case $_ble_decode_csi_mode in 1027 (0) 1028 # CSI (155) もしくは ESC (27) 1029 ((_ble_decode_csi_mode=$1==155?2:1)) 1030 _ble_decode_csi_args= 1031 csistat=_ ;; 1032 (1) 1033 if ((char!=91)); then 1034 _ble_decode_csi_mode=0 1035 return 1 1036 else 1037 _ble_decode_csi_mode=2 1038 _ble_decode_csi_args= 1039 csistat=_ 1040 fi ;; 1041 (2) 1042 if ((32<=char&&char<64)); then 1043 local ret; ble/util/c2s "$char" 1044 _ble_decode_csi_args=$_ble_decode_csi_args$ret 1045 csistat=_ 1046 elif ((64<=char&&char<127)); then 1047 _ble_decode_csi_mode=0 1048 ble-decode-char/csi/.decode "$char" 1049 ((csistat==27)) && csistat=$_ble_decode_IsolatedESC 1050 else 1051 _ble_decode_csi_mode=0 1052 fi ;; 1053 esac 1054 } 1055 1056 # **** ble-decode-char **** 1057 1058 # 内部で使用する変数 1059 # ble_decode_char_nest= 1060 # ble_decode_char_sync= 1061 # ble_decode_char_rest= 1062 1063 _ble_decode_char_buffer=() 1064 function ble/decode/has-input-for-char { 1065 ((_ble_decode_input_count)) || 1066 ble/util/is-stdin-ready || 1067 ble/encoding:"$bleopt_input_encoding"/is-intermediate 1068 } 1069 1070 _ble_decode_char__hook= 1071 1072 ## @arr _ble_decode_cmap_${_ble_decode_char__seq}[char] 1073 ## 文字列からキーへの写像を保持する。 1074 ## 各要素は文字の列 ($_ble_decode_char__seq $char) に対する定義を保持する。 1075 ## 各要素は以下の形式の何れかである。 1076 ## key+ 文字の列がキー key に一意に対応する事を表す。 1077 ## _ 文字の列が何らかのキーを表す文字列の prefix になっている事を表す。 1078 ## key_ 文字の列がキー key に対応すると同時に、 1079 ## 他のキーの文字列の prefix になっている事を表す。 1080 _ble_decode_cmap_=() 1081 1082 # _ble_decode_char__seq が設定されている時は、 1083 # 必ず _ble_decode_char2_reach_key も設定されている様にする。 1084 _ble_decode_char2_seq= 1085 _ble_decode_char2_reach_key= 1086 _ble_decode_char2_reach_seq= 1087 _ble_decode_char2_modifier= 1088 _ble_decode_char2_modkcode= 1089 _ble_decode_char2_modseq= 1090 function ble-decode-char { 1091 # 入れ子の ble-decode-char 呼び出しによる入力は後で実行。 1092 if [[ $ble_decode_char_nest && ! $ble_decode_char_sync ]]; then 1093 ble/array#push _ble_decode_char_buffer "$@" 1094 return 148 1095 fi 1096 local ble_decode_char_nest=1 1097 1098 local iloop=0 1099 local ble_decode_char_total=$# 1100 local ble_decode_char_rest=$# 1101 local ble_decode_char_char= 1102 # Note: ループ中で set -- ... を使っている。 1103 1104 local chars ichar char ent 1105 chars=("$@") ichar=0 1106 while 1107 if ((iloop++%50==0)); then 1108 ((iloop>=200)) && builtin eval -- "$_ble_decode_show_progress_hook" 1109 if [[ ! $ble_decode_char_sync ]] && ble/decode/has-input-for-char; then 1110 ble/array#push _ble_decode_char_buffer "${chars[@]:ichar}" 1111 return 148 1112 fi 1113 fi 1114 # 入れ子の ble-decode-char 呼び出しによる入力。 1115 if ((${#_ble_decode_char_buffer[@]})); then 1116 ((ble_decode_char_total+=${#_ble_decode_char_buffer[@]})) 1117 ((ble_decode_char_rest+=${#_ble_decode_char_buffer[@]})) 1118 ble/array#set chars "${_ble_decode_char_buffer[@]}" "${chars[@]:ichar}" 1119 ichar=0 1120 _ble_decode_char_buffer=() 1121 fi 1122 ((ble_decode_char_rest)) 1123 do 1124 char=${chars[ichar]} 1125 ble_decode_char_char=$char # 補正前 char (_ble_decode_Macr 判定の為) 1126 ((ble_decode_char_rest--,ichar++)) 1127 #%if debug_keylogger 1128 ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_chars "$char" 1129 #%end 1130 if [[ $_ble_decode_keylog_chars_enabled ]]; then 1131 if ! ((char&_ble_decode_Macr)); then 1132 ble/array#push _ble_decode_keylog_chars "$char" 1133 ((_ble_decode_keylog_chars_count++)) 1134 fi 1135 fi 1136 ((char&=~_ble_decode_Macr)) 1137 1138 # decode error character 1139 if ((char&_ble_decode_Erro)); then 1140 ((char&=~_ble_decode_Erro)) 1141 if [[ $bleopt_decode_error_char_vbell ]]; then 1142 local name; ble/util/sprintf name 'U+%04x' "$char" 1143 ble/term/visible-bell "received a misencoded char $name" 1144 fi 1145 [[ $bleopt_decode_error_char_abell ]] && ble/term/audible-bell 1146 [[ $bleopt_decode_error_char_discard ]] && continue 1147 # ((char&_ble_decode_Erro)) : 最適化(過去 sequence は全部吐く)? 1148 fi 1149 1150 # hook for quoted-insert etc 1151 if [[ $_ble_decode_char__hook ]]; then 1152 ((char==_ble_decode_IsolatedESC)) && char=27 # isolated ESC -> ESC 1153 local hook=$_ble_decode_char__hook 1154 _ble_decode_char__hook= 1155 ble-decode/widget/.call-async-read "$hook $char" "$char" 1156 continue 1157 fi 1158 1159 ble-decode-char/.getent # -> ent 1160 if [[ ! $ent ]]; then 1161 # シーケンスが登録されていない時 1162 if [[ $_ble_decode_char2_reach_key ]]; then 1163 local key=$_ble_decode_char2_reach_key 1164 local seq=$_ble_decode_char2_reach_seq 1165 local rest=${_ble_decode_char2_seq:${#seq}} 1166 ble/string#split-words rest "${rest//_/ } $ble_decode_char_char" 1167 1168 _ble_decode_char2_seq= 1169 _ble_decode_char2_reach_key= 1170 _ble_decode_char2_reach_seq= 1171 ble-decode-char/csi/clear 1172 1173 ble-decode-char/.send-modified-key "$key" "$seq" 1174 ((ble_decode_char_total+=${#rest[@]})) 1175 ((ble_decode_char_rest+=${#rest[@]})) 1176 chars=("${rest[@]}" "${chars[@]:ichar}") ichar=0 1177 else 1178 ble-decode-char/.send-modified-key "$char" "_$char" 1179 fi 1180 elif [[ $ent == *_ ]]; then 1181 # /\d*_/ (_ は続き (1つ以上の有効なシーケンス) がある事を示す) 1182 _ble_decode_char2_seq=${_ble_decode_char2_seq}_$char 1183 if [[ ${ent%_} ]]; then 1184 _ble_decode_char2_reach_key=${ent%_} 1185 _ble_decode_char2_reach_seq=$_ble_decode_char2_seq 1186 elif [[ ! $_ble_decode_char2_reach_key ]]; then 1187 # 1文字目 1188 _ble_decode_char2_reach_key=$char 1189 _ble_decode_char2_reach_seq=$_ble_decode_char2_seq 1190 fi 1191 else 1192 # /\d+/ (続きのシーケンスはなく ent で確定である事を示す) 1193 local seq=${_ble_decode_char2_seq}_$char 1194 _ble_decode_char2_seq= 1195 _ble_decode_char2_reach_key= 1196 _ble_decode_char2_reach_seq= 1197 ble-decode-char/csi/clear 1198 ble-decode-char/.send-modified-key "$ent" "$seq" 1199 fi 1200 done 1201 return 0 1202 } 1203 1204 ## @fn ble-decode-char/hook/next-char 1205 ## _ble_decode_char__hook で次の文字を 1206 ## その場で読み出す時に使います。 1207 ## これは bracketed paste の高速化の為に使います。 1208 ## @var[out] char 1209 ## @var[in,out] iloop ichar chars ble_decode_char_rest 1210 ## 1211 ## @remarks 1212 ## この関数を経由して読み取られた文字は keylog に残りません。 1213 ## 正しい動作を期待する為には _ble_debug_keylog_enabled (非零) 1214 ## 及び _ble_decode_keylog_chars_enabled (非空) が設定されて 1215 ## いない事を確認してから呼び出す必要があります。 1216 ## 1217 function ble/decode/char-hook/next-char { 1218 ((ble_decode_char_rest)) || return 1 1219 ((char=chars[ichar]&~_ble_decode_Macr)) 1220 ((char&_ble_decode_Erro)) && return 1 1221 ((iloop%1000==0)) && return 1 1222 ((char==_ble_decode_IsolatedESC)) && char=27 1223 ((ble_decode_char_rest--,ichar++,iloop++)) 1224 return 0 1225 } 1226 1227 ## @fn ble-decode-char/.getent 1228 ## @var[in] _ble_decode_char2_seq 1229 ## @var[in] char 1230 ## @var[out] ent 1231 function ble-decode-char/.getent { 1232 builtin eval "ent=\${_ble_decode_cmap_$_ble_decode_char2_seq[char]-}" 1233 if [[ $ent == ?*_ || $ent == _ && $_ble_decode_char2_seq == _27 ]]; then 1234 ble/decode/wait-input 5 char || ent=${ent%_} 1235 fi 1236 1237 # CSI sequence 1238 # ent= の時 → (CSI の結果) 1239 # ent=_ の時 → (CSI の結果) + _ 1240 # ent=num の時 → num のまま (CSI の結果に拘わらず確定) 1241 # ent=num_ の時 → num_ のまま 1242 local csistat= 1243 ble-decode-char/csi/consume "$char" 1244 if [[ $csistat && ! ${ent%_} ]]; then 1245 if ((csistat==_ble_decode_KCODE_ERROR)); then 1246 if [[ $bleopt_decode_error_cseq_vbell ]]; then 1247 local ret; ble-decode-unkbd ${_ble_decode_char2_seq//_/ } $char 1248 ble/term/visible-bell "unrecognized CSI sequence: $ret" 1249 fi 1250 [[ $bleopt_decode_error_cseq_abell ]] && ble/term/audible-bell 1251 if [[ $bleopt_decode_error_cseq_discard ]]; then 1252 csistat=$_ble_decode_KCODE_IGNORE 1253 else 1254 csistat= 1255 fi 1256 fi 1257 if [[ ! $ent ]]; then 1258 ent=$csistat 1259 else 1260 ent=${csistat%_}_ 1261 fi 1262 fi 1263 1264 # ble/util/assert '[[ $ent =~ ^[0-9]*_?$ ]]' 1265 } 1266 1267 function ble-decode-char/.process-modifier { 1268 local mflag1=$1 mflag=$_ble_decode_char2_modifier 1269 if ((mflag1&mflag)); then 1270 # 既に同じ修飾がある場合は通常と同じ処理をする。 1271 # 例えば ESC ESC は3番目に来る文字に Meta 修飾をするのではなく、 1272 # 2番目の ESC (C-[ に翻訳される) に対して 1273 # 更に Meta 修飾をして C-M-[ を出力する。 1274 return 1 1275 else 1276 # ※以下では key 内に既に mflag 1277 # と重複する修飾がある場合は考慮していない。 1278 # 重複があったという情報はここで消える。 1279 ((_ble_decode_char2_modkcode=key|mflag, 1280 _ble_decode_char2_modifier=mflag1|mflag)) 1281 _ble_decode_char2_modseq=${_ble_decode_char2_modseq}$2 1282 return 0 1283 fi 1284 } 1285 1286 ## @fn ble-decode-char/.send-modified-key key seq 1287 ## 指定されたキーを修飾して ble-decode-key に渡します。 1288 ## key = 0..31,127 は C-@ C-a ... C-z C-[ C-\ C-] C-^ C-_ C-? に変換されます。 1289 ## ESC は次に来る文字を meta 修飾します。 1290 ## _ble_decode_IsolatedESC は meta にならずに ESC として渡されます。 1291 ## @param[in] key 1292 ## 処理対象のキーコードを指定します。 1293 ## @param[in] seq 1294 ## 指定したキーを表現する文字シーケンスを指定します。 1295 ## /(_文字コード)+/ の形式の文字コードの列です。 1296 function ble-decode-char/.send-modified-key { 1297 local key=$1 seq=$2 1298 ((key==_ble_decode_KCODE_IGNORE)) && return 0 1299 1300 if ((0<=key&&key<32)); then 1301 ((key|=(key==0||key>26?64:96)|_ble_decode_Ctrl)) 1302 elif ((key==127)); then # C-? 1303 ((key=63|_ble_decode_Ctrl)) 1304 fi 1305 1306 if (($1==27)); then 1307 ble-decode-char/.process-modifier "$_ble_decode_Meta" "$seq" && return 0 1308 elif (($1==_ble_decode_IsolatedESC)); then 1309 ((key=(_ble_decode_Ctrl|91))) 1310 if ! ble/decode/uses-isolated-esc; then 1311 ble-decode-char/.process-modifier "$_ble_decode_Meta" "$seq" && return 0 1312 fi 1313 elif ((_ble_decode_KCODE_SHIFT<=$1&&$1<=_ble_decode_KCODE_HYPER)); then 1314 case $1 in 1315 ($_ble_decode_KCODE_SHIFT) 1316 ble-decode-char/.process-modifier "$_ble_decode_Shft" "$seq" && return 0 ;; 1317 ($_ble_decode_KCODE_CONTROL) 1318 ble-decode-char/.process-modifier "$_ble_decode_Ctrl" "$seq" && return 0 ;; 1319 ($_ble_decode_KCODE_ALTER) 1320 ble-decode-char/.process-modifier "$_ble_decode_Altr" "$seq" && return 0 ;; 1321 ($_ble_decode_KCODE_META) 1322 ble-decode-char/.process-modifier "$_ble_decode_Meta" "$seq" && return 0 ;; 1323 ($_ble_decode_KCODE_SUPER) 1324 ble-decode-char/.process-modifier "$_ble_decode_Supr" "$seq" && return 0 ;; 1325 ($_ble_decode_KCODE_HYPER) 1326 ble-decode-char/.process-modifier "$_ble_decode_Hypr" "$seq" && return 0 ;; 1327 esac 1328 fi 1329 1330 if [[ $_ble_decode_char2_modifier ]]; then 1331 local mflag=$_ble_decode_char2_modifier 1332 local mcode=$_ble_decode_char2_modkcode 1333 local mseq=$_ble_decode_char2_modseq 1334 _ble_decode_char2_modifier= 1335 _ble_decode_char2_modkcode= 1336 _ble_decode_char2_modseq= 1337 if ((key&mflag)); then 1338 local CHARS 1339 ble/string#split-words CHARS "${mseq//_/ }" 1340 ble-decode-key "$mcode" 1341 else 1342 seq=$mseq$seq 1343 ((key|=mflag)) 1344 fi 1345 fi 1346 1347 local CHARS 1348 ble/string#split-words CHARS "${seq//_/ }" 1349 ble-decode-key "$key" 1350 } 1351 1352 function ble-decode-char/is-intermediate { [[ $_ble_decode_char2_seq ]]; } 1353 1354 function ble-decode-char/bind { 1355 local -a seq; ble/string#split-words seq "$1" 1356 local kc=$2 1357 1358 local i iN=${#seq[@]} char tseq= 1359 for ((i=0;i<iN;i++)); do 1360 local char=${seq[i]} 1361 1362 builtin eval "local okc=\${_ble_decode_cmap_$tseq[char]-}" 1363 if ((i+1==iN)); then 1364 if [[ ${okc//[0-9]} == _ ]]; then 1365 builtin eval "_ble_decode_cmap_$tseq[char]=\${kc}_" 1366 else 1367 builtin eval "_ble_decode_cmap_$tseq[char]=\${kc}" 1368 fi 1369 else 1370 if [[ ! $okc ]]; then 1371 builtin eval "_ble_decode_cmap_$tseq[char]=_" 1372 else 1373 builtin eval "_ble_decode_cmap_$tseq[char]=\${okc%_}_" 1374 fi 1375 tseq=${tseq}_$char 1376 fi 1377 done 1378 } 1379 function ble-decode-char/unbind { 1380 local -a seq; ble/string#split-words seq "$1" 1381 1382 local tseq= 1383 local i iN=${#seq} 1384 for ((i=0;i<iN-1;i++)); do 1385 tseq=${tseq}_${seq[i]} 1386 done 1387 1388 local char=${seq[iN-1]} 1389 local isfirst=1 ent= 1390 while 1391 builtin eval "ent=\${_ble_decode_cmap_$tseq[char]-}" 1392 1393 if [[ $isfirst ]]; then 1394 # 数字を消す 1395 isfirst= 1396 if [[ $ent == *_ ]]; then 1397 # ent = 1234_ (両方在る時は片方消して終わり) 1398 builtin eval "_ble_decode_cmap_$tseq[char]=_" 1399 break 1400 fi 1401 else 1402 # _ を消す 1403 if [[ $ent != _ ]]; then 1404 # ent = 1234_ (両方在る時は片方消して終わり) 1405 builtin eval "_ble_decode_cmap_$tseq[char]=${ent%_}" 1406 break 1407 fi 1408 fi 1409 1410 builtin unset -v "_ble_decode_cmap_$tseq[char]" 1411 builtin eval "((\${#_ble_decode_cmap_$tseq[@]}!=0))" && break 1412 1413 [[ $tseq ]] 1414 do 1415 char=${tseq##*_} 1416 tseq=${tseq%_*} 1417 done 1418 } 1419 ## @fn ble-decode-char/print [tseq nseq...] 1420 ## @var[in] ble_bind_print sgr0 sgrf sgrq sgrc sgro 1421 function ble-decode-char/print { 1422 [[ $ble_bind_print ]] || local sgr0= sgrf= sgrq= sgrc= sgro= 1423 local IFS=$_ble_term_IFS q=\' Q="'\''" 1424 local tseq=$1 nseq ccode 1425 nseq=("${@:2}") 1426 builtin eval "local -a ccodes; ccodes=(\${!_ble_decode_cmap_$tseq[@]})" 1427 for ccode in "${ccodes[@]}"; do 1428 local ret; ble-decode-unkbd "$ccode" 1429 local cnames 1430 cnames=("${nseq[@]}" "$ret") 1431 1432 builtin eval "local ent=\${_ble_decode_cmap_$tseq[ccode]}" 1433 if [[ ${ent%_} ]]; then 1434 local key=${ent%_} ret 1435 1436 local qkspec qcnames 1437 if [[ $sgrq ]]; then 1438 ble-decode-unkbd "$key" 1439 ble/string#quote-word "$ret" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qkspec=$ret 1440 ble/string#quote-word "${cnames[*]}" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qcnames=$ret 1441 else 1442 ble-decode-unkbd "$key" 1443 qkspec="'${ret//$q/$Q}'" 1444 qcnames="'${cnames[*]//$q/$Q}'" # WA #D1570 checked 1445 fi 1446 ble/util/print "${sgrf}ble-bind$sgr0 $sgro-k$sgr0 $qcnames $qkspec" 1447 fi 1448 1449 if [[ ${ent//[0-9]} == _ ]]; then 1450 ble-decode-char/print "${tseq}_$ccode" "${cnames[@]}" 1451 fi 1452 done 1453 } 1454 1455 # **** ble-decode-key **** 1456 1457 ## @arr _ble_decode_${keymap}_kmap_${_ble_decode_key__seq}[key] 1458 ## 各 keymap は (キーシーケンス, コマンド) の集合と等価です。 1459 ## この配列は keymap の内容を以下の形式で格納します。 1460 ## 1461 ## @param[in] keymap 1462 ## 対象の keymap の名称を指定します。 1463 ## 1464 ## @param[in] _ble_decode_key__seq 1465 ## @param[in] key 1466 ## _ble_decode_key__seq key の組合せでキーシーケンスを表します。 1467 ## 1468 ## @value 1469 ## 以下の形式の何れかです。 1470 ## - "_" [TIMEOUT] 1471 ## - "_" [TIMEOUT] ":command" 1472 ## - "1:command" 1473 ## 1474 ## 始めの文字が "_" の場合はキーシーケンスに続きがある事を表します。 1475 ## つまり、このキーシーケンスを prefix とするより長いキーシーケンスが登録されている事を表します。 1476 ## command が指定されている場合には、より長いシーケンスでの一致に全て失敗した時点で 1477 ## command が実行されます。シーケンスを受け取った段階では実行されません。 1478 ## TIMEOUT (整数値) が指定されている場合は、このキーを受け取った後に続きのキーが TIMEOUT msec 1479 ## 以内に到着しなかった時に限りその場で command を実行します。 1480 ## 1481 ## 初めの文字が "1" の場合はキーシーケンスが確定的である事を表します。 1482 ## つまり、このキーシーケンスを prefix とするより長いシーケンスが登録されてなく、 1483 ## このシーケンスを受け取った段階で command を実行する事が確定する事を表します。 1484 ## 1485 1486 ## @var _ble_decode_keymap_list := ( ':' kmap )+ 1487 ## 初期化済みの kmap の名前の一覧を保持します。 1488 ## 既定の kmap (名前無し) は含まれません。 1489 _ble_decode_keymap_list= 1490 function ble/decode/keymap#registered { 1491 [[ :$_ble_decode_keymap_list: == *:"$1":* ]] 1492 } 1493 ## @fn ble/decode/keymap#.register kmap 1494 ## @exit 新しく keymap が登録された時に成功します。 1495 ## 既存の keymap だった時に失敗します。 1496 ## @remarks 1497 ## この関数は keymap cache から読み出されます。 1498 function ble/decode/keymap#.register { 1499 local kmap=$1 1500 if [[ $kmap && :$_ble_decode_keymap_list: != *:"$kmap":* ]]; then 1501 _ble_decode_keymap_list=$_ble_decode_keymap_list:$kmap 1502 fi 1503 } 1504 function ble/decode/keymap#.unregister { 1505 _ble_decode_keymap_list=$_ble_decode_keymap_list: 1506 _ble_decode_keymap_list=${_ble_decode_keymap_list//:"$1":/:} 1507 _ble_decode_keymap_list=${_ble_decode_keymap_list%:} 1508 } 1509 function ble/decode/is-keymap { 1510 ble/decode/keymap#registered "$1" || ble/is-function "ble-decode/keymap:$1/define" 1511 } 1512 1513 function ble/decode/keymap#is-empty { 1514 ! ble/is-array "_ble_decode_${1}_kmap_" || 1515 builtin eval -- "((\${#_ble_decode_${1}_kmap_[*]}==0))" 1516 } 1517 1518 function ble/decode/keymap#.onload { 1519 local kmap=$1 1520 local delay=$_ble_base_run/$$.bind.delay.$kmap 1521 if [[ -s $delay ]]; then 1522 source "$delay" 1523 : >| "$delay" 1524 fi 1525 } 1526 function ble/decode/keymap#load { 1527 local opts=:$2: 1528 ble/decode/keymap#registered "$1" && return 0 1529 1530 local init=ble-decode/keymap:$1/define 1531 ble/is-function "$init" || return 1 1532 1533 ble/decode/keymap#.register "$1" 1534 local ble_bind_keymap=$1 1535 if ! "$init" || ble/decode/keymap#is-empty "$1"; then 1536 ble/decode/keymap#.unregister "$1" 1537 return 1 1538 fi 1539 1540 [[ $opts == *:dump:* ]] && 1541 ble/decode/keymap#dump "$1" >&3 1542 ble/decode/keymap#.onload "$1" 1543 return 0 1544 } 1545 ## @fn ble/decode/keymap#unload [keymap_name...] 1546 function ble/decode/keymap#unload { 1547 if (($#==0)); then 1548 local list; ble/string#split-words list "${_ble_decode_keymap_list//:/ }" 1549 set -- "${list[@]}" 1550 fi 1551 1552 while (($#)); do 1553 local array_names array_name 1554 builtin eval -- "array_names=(\"\${!_ble_decode_${1}_kmap_@}\")" 1555 for array_name in "${array_names[@]}"; do 1556 builtin unset -v "$array_name" 1557 done 1558 ble/decode/keymap#.unregister "$1" 1559 shift 1560 done 1561 } 1562 1563 if [[ ${_ble_decode_kmaps-} ]]; then 1564 ## @fn ble/decode/keymap/cleanup-old-keymaps 1565 ## 古い形式の keymap を削除する (#D1076) 1566 ## 0.4.0-devel1+e13e979 以前は unload 時に keymaps を削除していなかった為に、 1567 ## reload した時に keycode 不整合で無限ループになってしまうバグがあった。 1568 function ble/decode/keymap/cleanup-old-keymaps { 1569 # Note: 古い形式では必ずしも _ble_decode_kmaps に keymap 1570 # が登録されていなかったので、配列データから抽出する必要がある。 1571 local -a list=() 1572 local var 1573 for var in "${!_ble_decode_@}"; do 1574 [[ $var == _ble_decode_*_kmap_ ]] || continue 1575 var=${var#_ble_decode_} 1576 var=${var%_kmap_} 1577 ble/array#push list "$var" 1578 done 1579 1580 local keymap_name 1581 for keymap_name in "${list[@]}"; do 1582 ble/decode/keymap#unload "$keymap_name" 1583 done 1584 builtin unset -v _ble_decode_kmaps 1585 } 1586 ble/decode/keymap/cleanup-old-keymaps 1587 fi 1588 1589 function ble/decode/keymap#dump { 1590 if (($#)); then 1591 local kmap=$1 arrays 1592 builtin eval "arrays=(\"\${!_ble_decode_${kmap}_kmap_@}\")" 1593 ble/util/print "ble/decode/keymap#.register $kmap" 1594 ble/util/declare-print-definitions "${arrays[@]}" 1595 ble/util/print "ble/decode/keymap#.onload $kmap" 1596 else 1597 local list; ble/string#split-words list "${_ble_decode_keymap_list//:/ }" 1598 local keymap_name 1599 for keymap_name in "${list[@]}"; do 1600 ble/decode/keymap#dump "$keymap_name" 1601 done 1602 fi 1603 } 1604 1605 ## @fn ble-decode/GET_BASEMAP -v varname 1606 ## 既定の基底 keymap を返します。 1607 function ble-decode/GET_BASEMAP { 1608 [[ $1 == -v ]] || return 1 1609 local ret; bleopt/get:default_keymap 1610 [[ $ret == vi ]] && ret=vi_imap 1611 builtin eval "$2=\$ret" 1612 } 1613 ## @fn[custom] ble-decode/INITIALIZE_DEFMAP -v varname 1614 ## 既定の keymap を決定します。 1615 ## ble-decode.sh 使用コードで上書きして使用します。 1616 function ble-decode/INITIALIZE_DEFMAP { 1617 ble-decode/GET_BASEMAP "$@" && 1618 ble/decode/keymap#load "${!2}" && 1619 return 0 1620 1621 # fallback 1622 ble/decode/keymap#load safe && 1623 builtin eval -- "$2=safe" && 1624 bleopt_default_keymap=safe 1625 } 1626 1627 ## @fn[custom] ble/widget/.SHELL_COMMAND command 1628 ## ble-bind -c で登録されたコマンドを処理します。 1629 function ble/widget/.SHELL_COMMAND { local IFS=$_ble_term_IFS; builtin eval -- "$*"; } 1630 ## @fn[custom] ble/widget/.EDIT_COMMAND command 1631 ## ble-bind -x で登録されたコマンドを処理します。 1632 function ble/widget/.EDIT_COMMAND { local IFS=$_ble_term_IFS; builtin eval -- "$*"; } 1633 1634 ## @fn ble-decode-key/bind keymap keys command 1635 ## @param[in] keymap keys command 1636 function ble-decode-key/bind { 1637 if ! ble/decode/keymap#registered "$1"; then 1638 ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$1" 1639 return 0 1640 fi 1641 1642 local kmap=$1 keys=$2 cmd=$3 1643 1644 # Check existence of widget 1645 if local widget=${cmd%%[$_ble_term_IFS]*}; ! ble/is-function "$widget"; then 1646 local message="ble-bind: Unknown widget \`${widget#'ble/widget/'}'." 1647 [[ $command == ble/widget/ble/widget/* ]] && 1648 message="$message Note: The prefix 'ble/widget/' is redundant." 1649 ble/util/print "$message" 1>&2 1650 return 1 1651 fi 1652 1653 local dicthead=_ble_decode_${kmap}_kmap_ 1654 local -a seq; ble/string#split-words seq "$keys" 1655 1656 local i iN=${#seq[@]} tseq= 1657 for ((i=0;i<iN;i++)); do 1658 local key=${seq[i]} 1659 1660 builtin eval "local ocmd=\${$dicthead$tseq[key]}" 1661 if ((i+1==iN)); then 1662 if [[ ${ocmd::1} == _ ]]; then 1663 builtin eval "$dicthead$tseq[key]=${ocmd%%:*}:\$cmd" 1664 else 1665 builtin eval "$dicthead$tseq[key]=1:\$cmd" 1666 fi 1667 else 1668 if [[ ! $ocmd ]]; then 1669 builtin eval "$dicthead$tseq[key]=_" 1670 elif [[ ${ocmd::1} == 1 ]]; then 1671 builtin eval "$dicthead$tseq[key]=_:\${ocmd#*:}" 1672 fi 1673 tseq=${tseq}_$key 1674 fi 1675 done 1676 } 1677 1678 function ble-decode-key/set-timeout { 1679 if ! ble/decode/keymap#registered "$1"; then 1680 ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$1" 1681 return 0 1682 fi 1683 1684 local kmap=$1 keys=$2 timeout=$3 1685 local dicthead=_ble_decode_${kmap}_kmap_ 1686 local -a seq; ble/string#split-words seq "$keys" 1687 [[ $timeout == - ]] && timeout= 1688 1689 local i iN=${#seq[@]} 1690 local key=${seq[iN-1]} 1691 local tseq= 1692 for ((i=0;i<iN-1;i++)); do 1693 tseq=${tseq}_${seq[i]} 1694 done 1695 1696 builtin eval "local ent=\${$dicthead$tseq[key]}" 1697 if [[ $ent == _* ]]; then 1698 local cmd=; [[ $ent == *:* ]] && cmd=${ent#*:} 1699 builtin eval "$dicthead$tseq[key]=_$timeout${cmd:+:}\$cmd" 1700 else 1701 ble/util/print "ble-bind -T: specified partial keyspec not found." >&2 1702 return 1 1703 fi 1704 } 1705 1706 ## @fn ble-decode-key/unbind keymap keys 1707 function ble-decode-key/unbind { 1708 if ! ble/decode/keymap#registered "$1"; then 1709 ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$1" 1710 return 0 1711 fi 1712 1713 local kmap=$1 keys=$2 1714 local dicthead=_ble_decode_${kmap}_kmap_ 1715 local -a seq; ble/string#split-words seq "$keys" 1716 1717 local i iN=${#seq[@]} 1718 local key=${seq[iN-1]} 1719 local tseq= 1720 for ((i=0;i<iN-1;i++)); do 1721 tseq=${tseq}_${seq[i]} 1722 done 1723 1724 local isfirst=1 ent= 1725 while 1726 builtin eval "ent=\${$dicthead$tseq[key]}" 1727 1728 if [[ $isfirst ]]; then 1729 # command を消す 1730 isfirst= 1731 if [[ ${ent::1} == _ ]]; then 1732 # ent = _[TIMEOUT] または _[TIMEOUT]:command の時は、単に command を消して終わる。 1733 # (未だ bind が残っているので、登録は削除せず break)。 1734 builtin eval "$dicthead$tseq[key]=\${ent%%:*}" 1735 break 1736 fi 1737 else 1738 # prefix の ent は _ か _:command のどちらかの筈。 1739 if [[ $ent == *:* ]]; then 1740 # _:command の場合には 1:command に書き換える。 1741 # (1:command の bind が残っているので登録は削除せず break)。 1742 builtin eval "$dicthead$tseq[key]=1:\${ent#*:}" 1743 break 1744 fi 1745 fi 1746 1747 builtin unset -v "$dicthead$tseq[key]" 1748 builtin eval "((\${#$dicthead$tseq[@]}!=0))" && break 1749 1750 [[ $tseq ]] 1751 do 1752 key=${tseq##*_} 1753 tseq=${tseq%_*} 1754 done 1755 } 1756 1757 function ble/decode/keymap#get-cursor { 1758 cursor=_ble_decode_${1}_kmap_cursor 1759 cursor=${!cursor-} 1760 } 1761 function ble/decode/keymap#set-cursor { 1762 local keymap=$1 cursor=$2 1763 if ! ble/decode/keymap#registered "$keymap"; then 1764 ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$keymap" 1765 return 0 1766 fi 1767 builtin eval "_ble_decode_${keymap}_kmap_cursor=\$cursor" 1768 if [[ $keymap == "$_ble_decode_keymap" && $cursor ]]; then 1769 ble/term/cursor-state/set-internal "$((cursor))" 1770 fi 1771 } 1772 1773 ## @fn ble/decode/keymap#print keymap [tseq nseq] 1774 ## @param keymap 1775 ## @param[in,internal] tseq nseq 1776 ## @var[in] ble_bind_print sgr0 sgrf sgrq sgrc sgro 1777 function ble/decode/keymap#print { 1778 # 引数の無い場合: 全ての kmap を dump 1779 local kmap 1780 if (($#==0)); then 1781 for kmap in ${_ble_decode_keymap_list//:/ }; do 1782 ble/util/print "$sgrc# keymap $kmap$sgr0" 1783 ble/decode/keymap#print "$kmap" 1784 done 1785 return 0 1786 fi 1787 1788 [[ $ble_bind_print ]] || local sgr0= sgrf= sgrq= sgrc= sgro= 1789 local kmap=$1 tseq=$2 nseq=$3 1790 local dicthead=_ble_decode_${kmap}_kmap_ 1791 local kmapopt= 1792 [[ $kmap ]] && kmapopt=" $sgro-m$sgr0 $sgrq'$kmap'$sgr0" 1793 1794 local q=\' Q="'\''" 1795 local key keys 1796 builtin eval "keys=(\${!$dicthead$tseq[@]})" 1797 for key in "${keys[@]}"; do 1798 local ret; ble-decode-unkbd "$key" 1799 local knames=$nseq${nseq:+ }$ret 1800 builtin eval "local ent=\${$dicthead$tseq[key]}" 1801 1802 local qknames 1803 if [[ $sgrq ]]; then 1804 ble/string#quote-word "$knames" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qknames=$ret 1805 else 1806 qknames="'${knames//$q/$Q}'" 1807 fi 1808 if [[ $ent == *:* ]]; then 1809 local cmd=${ent#*:} 1810 1811 local o v 1812 case $cmd in 1813 ('ble/widget/.SHELL_COMMAND '*) o=c v=${cmd#'ble/widget/.SHELL_COMMAND '}; builtin eval "v=$v" ;; 1814 ('ble/widget/.EDIT_COMMAND '*) o=x v=${cmd#'ble/widget/.EDIT_COMMAND '} ; builtin eval "v=$v" ;; 1815 ('ble/widget/.MACRO '*) o=s; ble/util/chars2keyseq ${cmd#*' '}; v=$ret ;; 1816 ('ble/widget/'*) o=f v=${cmd#ble/widget/} ;; 1817 (*) o=@ v=$cmd ;; 1818 esac 1819 1820 local qv 1821 if [[ $sgrq ]]; then 1822 ble/string#quote-word "$v" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qv=$ret 1823 else 1824 qv="'${v//$q/$Q}'" 1825 fi 1826 ble/util/print "${sgrf}ble-bind$sgr0$kmapopt $sgro-$o$sgr0 $qknames $qv" 1827 fi 1828 1829 if [[ ${ent::1} == _ ]]; then 1830 ble/decode/keymap#print "$kmap" "${tseq}_$key" "$knames" 1831 if [[ $ent == _[0-9]* ]]; then 1832 local timeout=${ent%%:*}; timeout=${timeout:1} 1833 ble/util/print "${sgrf}ble-bind$sgr0$kmapopt $sgro-T$sgr0 $qknames $timeout" 1834 fi 1835 fi 1836 done 1837 } 1838 1839 ## @var _ble_decode_keymap 1840 ## 1841 ## 現在選択されている keymap 1842 ## 1843 ## @arr _ble_decode_keymap_stack 1844 ## 1845 ## 呼び出し元の keymap を記録するスタック 1846 ## 1847 _ble_decode_keymap= 1848 _ble_decode_keymap_stack=() 1849 1850 ## @fn ble/decode/keymap/push kmap 1851 function ble/decode/keymap/push { 1852 if ble/decode/keymap#registered "$1"; then 1853 ble/array#push _ble_decode_keymap_stack "$_ble_decode_keymap" 1854 _ble_decode_keymap=$1 1855 1856 # set cursor-state 1857 local cursor; ble/decode/keymap#get-cursor "$1" 1858 [[ $cursor ]] && ble/term/cursor-state/set-internal "$((cursor))" 1859 return 0 1860 elif ble/decode/keymap#load "$1" && ble/decode/keymap#registered "$1"; then 1861 ble/decode/keymap/push "$1" # 再実行 1862 else 1863 ble/util/print "[ble: keymap '$1' not found]" >&2 1864 return 1 1865 fi 1866 } 1867 ## @fn ble/decode/keymap/pop 1868 function ble/decode/keymap/pop { 1869 local count=${#_ble_decode_keymap_stack[@]} 1870 local last=$((count-1)) 1871 ble/util/assert '((last>=0))' || return 1 1872 1873 # reset cursor-state 1874 local cursor 1875 ble/decode/keymap#get-cursor "$_ble_decode_keymap" 1876 if [[ $cursor ]]; then 1877 local i 1878 for ((i=last;i>=0;i--)); do 1879 ble/decode/keymap#get-cursor "${_ble_decode_keymap_stack[i]}" 1880 [[ $cursor ]] && break 1881 done 1882 ble/term/cursor-state/set-internal "$((${cursor:-0}))" 1883 fi 1884 1885 local old_keymap=_ble_decode_keymap 1886 _ble_decode_keymap=${_ble_decode_keymap_stack[last]} 1887 builtin unset -v '_ble_decode_keymap_stack[last]' 1888 } 1889 ## @fn ble/decode/keymap/get-parent 1890 ## @var[out] ret 1891 function ble/decode/keymap/get-parent { 1892 local len=${#_ble_decode_keymap_stack[@]} 1893 if ((len)); then 1894 ret=${_ble_decode_keymap_stack[len-1]} 1895 else 1896 ret= 1897 fi 1898 } 1899 1900 ## @var _ble_decode_key__seq 1901 ## 今迄に入力された未処理のキーの列を保持します 1902 ## /(_\d+)*/ の形式の文字列です。 1903 _ble_decode_key__seq= 1904 1905 ## @var _ble_decode_key__hook 1906 ## キー処理に対する hook を外部から設定する為の変数です。 1907 _ble_decode_key__hook= 1908 1909 ## @fn ble-decode-key/is-intermediate 1910 ## 未処理のキーがあるかどうかを判定します。 1911 function ble-decode-key/is-intermediate { [[ $_ble_decode_key__seq ]]; } 1912 1913 ## @arr _ble_decode_key_batch 1914 _ble_decode_key_batch=() 1915 1916 ## @fn ble-decode-key/batch/flush 1917 function ble-decode-key/batch/flush { 1918 ((${#_ble_decode_key_batch[@]})) || return 1 1919 local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_ 1920 builtin eval "local command=\${${dicthead}[_ble_decode_KCODE_BATCH_CHAR]-}" 1921 command=${command:2} 1922 if [[ $command ]]; then 1923 local chars; chars=("${_ble_decode_key_batch[@]}") 1924 _ble_decode_key_batch=() 1925 ble/decode/widget/call-interactively "$command" "${chars[@]}"; local ext=$? 1926 ((ext!=125)) && return 0 1927 fi 1928 1929 ble/decode/widget/call-interactively ble/widget/__batch_char__.default "${chars[@]}"; local ext=$? 1930 return "$ext" 1931 } 1932 function ble/widget/__batch_char__.default { 1933 builtin eval "local widget_defchar=\${${dicthead}[_ble_decode_KCODE_DEFCHAR]-}" 1934 widget_defchar=${widget_defchar:2} 1935 builtin eval "local widget_default=\${${dicthead}[_ble_decode_KCODE_DEFAULT]-}" 1936 widget_default=${widget_default:2} 1937 1938 local -a unprocessed_chars=() 1939 local key command 1940 for key in "${KEYS[@]}"; do 1941 if [[ $widget_defchar ]]; then 1942 ble/decode/widget/call-interactively "$widget_defchar" "$key"; local ext=$? 1943 ((ext!=125)) && continue 1944 fi 1945 if [[ $widget_default ]]; then 1946 ble/decode/widget/call-interactively "$widget_default" "$key"; local ext=$? 1947 ((ext!=125)) && continue 1948 fi 1949 1950 ble/array#push unprocessed_chars "$key" 1951 done 1952 1953 if ((${#unprocessed_chars[@]})); then 1954 local ret; ble-decode-unkbd "${unprocessed_chars[@]}" 1955 [[ $bleopt_decode_error_kseq_vbell ]] && ble/term/visible-bell "unprocessed chars: $ret" 1956 [[ $bleopt_decode_error_kseq_abell ]] && ble/term/audible-bell 1957 fi 1958 return 0 1959 } 1960 1961 1962 ## @fn ble-decode-key key... 1963 ## キー入力の処理を行います。登録されたキーシーケンスに一致した場合、 1964 ## 関連付けられたコマンドを実行します。 1965 ## 登録されたキーシーケンスの前方部分に一致する場合、即座に処理は行わず 1966 ## 入力されたキーの列を _ble_decode_key__seq に記録します。 1967 ## 1968 ## @param[in] key 1969 ## 入力されたキー 1970 ## 1971 function ble-decode-key { 1972 local key 1973 while (($#)); do 1974 key=$1; shift 1975 #%if debug_keylogger 1976 ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_keys "$key" 1977 #%end 1978 if [[ $_ble_decode_keylog_keys_enabled && $_ble_decode_keylog_depth == 0 ]]; then 1979 ble/array#push _ble_decode_keylog_keys "$key" 1980 ((_ble_decode_keylog_keys_count++)) 1981 fi 1982 1983 # Note: マウス移動はシーケンスの一部と見做さず独立に処理する。 1984 # widget が登録されていれば処理しそれ以外は無視。 1985 local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_ 1986 if (((key&_ble_decode_MaskChar)==_ble_decode_KCODE_MOUSE_MOVE)); then 1987 builtin eval "local command=\${${dicthead}[key]-}" 1988 command=${command:2} 1989 ble-decode/widget/.call-keyseq 1990 continue 1991 fi 1992 1993 if [[ $_ble_decode_key__hook ]]; then 1994 local hook=$_ble_decode_key__hook 1995 _ble_decode_key__hook= 1996 ble-decode/widget/.call-async-read "$hook $key" "$key" 1997 continue 1998 fi 1999 2000 builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[key]-}" 2001 2002 # TIMEOUT: timeout が設定されている場合はその時間だけ待って 2003 # 続きを処理するかその場で確定するか判断する。 2004 if [[ $ent == _[0-9]* ]]; then 2005 local node_type=_ 2006 if (($#==0)) && ! ble/decode/has-input; then 2007 local timeout=${ent%%:*}; timeout=${timeout:1} 2008 ble/decode/wait-input "$timeout" || node_type=1 2009 fi 2010 if [[ $ent == *:* ]]; then 2011 ent=$node_type:${ent#*:} 2012 else 2013 ent=$node_type 2014 fi 2015 fi 2016 2017 if [[ $ent == 1:* ]]; then 2018 # /1:command/ (続きのシーケンスはなく ent で確定である事を示す) 2019 local command=${ent:2} 2020 if [[ $command ]]; then 2021 ble-decode/widget/.call-keyseq 2022 else 2023 _ble_decode_key__seq= 2024 fi 2025 elif [[ $ent == _ || $ent == _:* ]]; then 2026 # /_(:command)?/ (続き (1つ以上の有効なシーケンス) がある事を示す) 2027 _ble_decode_key__seq=${_ble_decode_key__seq}_$key 2028 else 2029 # 遡って適用 (部分一致、または、既定動作) 2030 ble-decode-key/.invoke-partial-match "$key" && continue 2031 2032 # エラーの表示 2033 local kseq=${_ble_decode_key__seq}_$key ret 2034 ble-decode-unkbd "${kseq//_/ }" 2035 local kspecs=$ret 2036 [[ $bleopt_decode_error_kseq_vbell ]] && ble/term/visible-bell "unbound keyseq: $kspecs" 2037 [[ $bleopt_decode_error_kseq_abell ]] && ble/term/audible-bell 2038 2039 # 残っている文字の処理 2040 if [[ $_ble_decode_key__seq ]]; then 2041 if [[ $bleopt_decode_error_kseq_discard ]]; then 2042 _ble_decode_key__seq= 2043 else 2044 local -a keys 2045 ble/string#split-words keys "${_ble_decode_key__seq//_/ } $key" 2046 _ble_decode_key__seq= 2047 # 2文字目以降を処理 2048 ble-decode-key "${keys[@]:1}" 2049 fi 2050 fi 2051 fi 2052 2053 done 2054 2055 if ((${#_ble_decode_key_batch[@]})); then 2056 if ! ble/decode/has-input || ((${#_ble_decode_key_batch[@]}>=50)); then 2057 ble-decode-key/batch/flush 2058 fi 2059 fi 2060 return 0 2061 } 2062 2063 ## @fn ble-decode-key/.invoke-partial-match fail 2064 ## これまでのキー入力に対する部分一致を試みます。 2065 ## 登録されている部分一致がない場合には単体のキーに対して既定の動作を呼び出します。 2066 ## 既定の動作も登録されていない場合には関数は失敗します。 2067 ## @var[in,out] _ble_decode_key__seq 2068 ## @var[in] next 2069 ## _ble_decode_key__seq は既に入力された未処理のキー列を指定します。 2070 ## next には今回入力されたキーの列を指定します。 2071 ## この関数は _ble_decode_key__seq next からなるキー列に対する部分一致を試みます。 2072 ## 2073 ## この関数は以下の様に動作します。 2074 ## 1 先ず、_ble_decode_key__seq に対して部分一致がないか確認し、部分一致する 2075 ## binding があればそれを実行します。 2076 ## - _ble_decode_key__seq + key の全体に対する一致は試みない事に注意して下 2077 ## さい。全体一致については既にチェックして失敗しているという前提です。 2078 ## 何故なら部分一致を試みるのは常に最長一致が失敗した時だけだからです。 2079 ## 2 _ble_decode_key__seq に対する部分一致が存在しない場合には、 2080 ## ch = _ble_decode_key__seq + key の最初のキーについて登録されている既定の 2081 ## 動作を実行します。ch はつまり、_ble_decode_key__seq が空でない時はその先 2082 ## 頭で、空の場合は key になります。 2083 ## 3 一致が存在して処理が実行された場合には、その後一旦 _ble_decode_key__seq 2084 ## がクリアされ、一致しなかった残りの部分に対して再度 ble-decode-key を呼 2085 ## び出して再解釈が行われます。 2086 ## 1, 2 のいずれでも一致が見付からなかった場合には、_ble_decode_key__seq を 2087 ## 呼出時の状態に戻し関数は失敗します。つまり、この場合 _ble_decode_key__seq 2088 ## は、呼出元からは変化していない様に見えます。 2089 ## 2090 function ble-decode-key/.invoke-partial-match { 2091 local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_ 2092 2093 local next=$1 2094 if [[ $_ble_decode_key__seq ]]; then 2095 local last=${_ble_decode_key__seq##*_} 2096 _ble_decode_key__seq=${_ble_decode_key__seq%_*} 2097 2098 builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[last]-}" 2099 if [[ $ent == _*:* ]]; then 2100 local command=${ent#*:} 2101 if [[ $command ]]; then 2102 ble-decode/widget/.call-keyseq 2103 else 2104 _ble_decode_key__seq= 2105 fi 2106 ble-decode-key "$next" 2107 return 0 2108 else # ent = _ 2109 if ble-decode-key/.invoke-partial-match "$last"; then 2110 ble-decode-key "$next" 2111 return 0 2112 else 2113 # 元に戻す 2114 _ble_decode_key__seq=${_ble_decode_key__seq}_$last 2115 return 1 2116 fi 2117 fi 2118 else 2119 # ここでは指定した単体のキーに対する既定の処理を実行する 2120 # $next 単体でも設定がない場合はここに来る。 2121 # 通常の文字などは全てここに流れてくる事になる。 2122 2123 # 既定の文字ハンドラ 2124 local key=$1 2125 if ble-decode-key/ischar "$key"; then 2126 if ble/decode/has-input && builtin eval "[[ \${${dicthead}[_ble_decode_KCODE_BATCH_CHAR]-} ]]"; then 2127 ble/array#push _ble_decode_key_batch "$key" 2128 return 0 2129 fi 2130 2131 builtin eval "local command=\${${dicthead}[_ble_decode_KCODE_DEFCHAR]-}" 2132 command=${command:2} 2133 if [[ $command ]]; then 2134 local seq_save=$_ble_decode_key__seq 2135 ble-decode/widget/.call-keyseq; local ext=$? 2136 ((ext!=125)) && return 0 2137 _ble_decode_key__seq=$seq_save # 125 の時はまた元に戻して次の試行を行う 2138 fi 2139 fi 2140 2141 # 既定のキーハンドラ 2142 builtin eval "local command=\${${dicthead}[_ble_decode_KCODE_DEFAULT]-}" 2143 command=${command:2} 2144 ble-decode/widget/.call-keyseq; local ext=$? 2145 ((ext!=125)) && return 0 2146 2147 return 1 2148 fi 2149 } 2150 2151 function ble-decode-key/ischar { 2152 local key=$1 2153 (((key&_ble_decode_MaskFlag)==0&&32<=key&&key<_ble_decode_FunctionKeyBase)) 2154 } 2155 2156 #------------------------------------------------------------------------------ 2157 # ble-decode/widget 2158 2159 ## @var _ble_decode_widget_last 2160 ## 次のコマンドで LASTWIDGET として使用するコマンド名を保持します。 2161 ## 以下の関数で使用されます。 2162 ## 2163 ## - ble-decode/widget/.call-keyseq 2164 ## - ble-decode/widget/.call-async-read 2165 ## - ble/decode/widget/call 2166 ## - ble/decode/widget/call-interactively 2167 ## - (keymap/vi.sh) ble/keymap:vi/repeat/invoke 2168 ## 2169 _ble_decode_widget_last= 2170 2171 function ble-decode/widget/.invoke-hook { 2172 local key=$1 2173 local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_ 2174 builtin eval "local hook=\${$dicthead[key]-}" 2175 hook=${hook:2} 2176 #%if leakvar 2177 ble/debug/leakvar#check $"leakvar" "widget.hook.0" 2178 #%end.i 2179 [[ $hook ]] && builtin eval -- "$hook" 2180 #%if leakvar 2181 ble/debug/leakvar#check $"leakvar" "widget.hook.1 $hook" 2182 #%end.i 2183 } 2184 2185 ## @fn ble-decode/widget/.call-keyseq 2186 ## コマンドが有効な場合に、指定したコマンドを適切な環境で実行します。 2187 ## @var[in] command 2188 ## 起動するコマンドを指定します。空の場合コマンドは実行されません。 2189 ## @var[in] _ble_decode_key__seq 2190 ## @var[in] key 2191 ## _ble_decode_key__seq は前回までに受け取ったキーの列です。 2192 ## key は今回新しく受け取ったキーの列です。 2193 ## _ble_decode_key__seq と key の組合せで現在入力されたキーシーケンスになります。 2194 ## コマンドを実行した場合 _ble_decode_key__seq はクリアされます。 2195 ## コマンドを実行しなかった場合 2196 ## @return 2197 ## コマンドが実行された場合に 0 を返します。それ以外の場合は 1 です。 2198 ## 2199 ## コマンドの実行時に次の変数が定義されます。 2200 ## これらの変数はコマンドの内部から参照する事ができます。 2201 ## @var[out] KEYS 2202 ## このコマンドの起動に用いられたキーシーケンスが格納されます。 2203 ## 2204 # 2205 # 実装の注意 2206 # 2207 # 呼び出したコマンドの内部で keymap の switch があっても良い様に、 2208 # _ble_decode_key__seq + key は厳密に現在のコマンドに対応するシーケンスである必要がある事、 2209 # コマンドを呼び出す時には常に _ble_decode_key__seq が空になっている事に注意。 2210 # 部分一致などの場合に後続のキーが存在する場合には、それらは呼出元で管理しなければならない。 2211 # 2212 function ble-decode/widget/.call-keyseq { 2213 ble-decode-key/batch/flush 2214 [[ $command ]] || return 125 2215 2216 # for keylog suppress 2217 local _ble_decode_keylog_depth=$((_ble_decode_keylog_depth+1)) 2218 2219 # set up variables 2220 local WIDGET=$command KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last 2221 local -a KEYS; ble/string#split-words KEYS "${_ble_decode_key__seq//_/ } $key" 2222 _ble_decode_widget_last=$WIDGET 2223 _ble_decode_key__seq= 2224 2225 ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_BEFORE_WIDGET" 2226 #%if leakvar 2227 ble/debug/leakvar#check $"leakvar" widget.0 2228 #%end.i 2229 builtin eval -- "$WIDGET"; local ext=$? 2230 #%if leakvar 2231 ble/debug/leakvar#check $"leakvar" "widget $WIDGET" 2232 #%end.i 2233 ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_AFTER_WIDGET" 2234 ((_ble_decode_keylog_depth==1)) && 2235 _ble_decode_keylog_chars_count=0 _ble_decode_keylog_keys_count=0 2236 return "$ext" 2237 } 2238 ## @fn ble-decode/widget/.call-async-read widget keys 2239 ## _ble_decode_{char,key}__hook の呼び出しに使用します。 2240 ## _ble_decode_widget_last は更新しません。 2241 function ble-decode/widget/.call-async-read { 2242 # for keylog suppress 2243 local _ble_decode_keylog_depth=$((_ble_decode_keylog_depth+1)) 2244 2245 # set up variables 2246 local WIDGET=$1 KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last 2247 local -a KEYS; ble/string#split-words KEYS "$2" 2248 builtin eval -- "$WIDGET"; local ext=$? 2249 ((_ble_decode_keylog_depth==1)) && 2250 _ble_decode_keylog_chars_count=0 _ble_decode_keylog_keys_count=0 2251 return "$ext" 2252 } 2253 ## @fn ble/decode/widget/call-interactively widget keys... 2254 ## @fn ble/decode/widget/call widget keys... 2255 ## 指定した名前の widget を呼び出します。 2256 ## call-interactively では、現在の keymap に応じた __before_widget__ 2257 ## 及び __after_widget__ フックも呼び出します。 2258 function ble/decode/widget/call-interactively { 2259 local WIDGET=$1 KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last 2260 local -a KEYS; KEYS=("${@:2}") 2261 _ble_decode_widget_last=$WIDGET 2262 ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_BEFORE_WIDGET" 2263 #%if leakvar 2264 ble/debug/leakvar#check $"leakvar" widget.0 2265 #%end.i 2266 builtin eval -- "$WIDGET"; local ext=$? 2267 #%if leakvar 2268 ble/debug/leakvar#check $"leakvar" "widget $WIDGET" 2269 #%end.i 2270 ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_AFTER_WIDGET" 2271 return "$ext" 2272 } 2273 function ble/decode/widget/call { 2274 local WIDGET=$1 KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last 2275 local -a KEYS; KEYS=("${@:2}") 2276 _ble_decode_widget_last=$WIDGET 2277 #%if leakvar 2278 ble/debug/leakvar#check $"leakvar" widget.0 2279 #%end.i 2280 builtin eval -- "$WIDGET" 2281 #%if leakvar 2282 ble/debug/leakvar#check $"leakvar" "widget $WIDGET" 2283 #%end.i 2284 } 2285 ## @fn ble/decode/widget/dispatch widget args... 2286 function ble/decode/widget/dispatch { 2287 local ret; ble/string#quote-command "ble/widget/$@" 2288 local WIDGET=$ret 2289 _ble_decode_widget_last=$WIDGET 2290 #%if leakvar 2291 ble/debug/leakvar#check $"leakvar" widget.0 2292 #%end.i 2293 builtin eval -- "$WIDGET" 2294 #%if leakvar 2295 ble/debug/leakvar#check $"leakvar" "widget $WIDGET" 2296 #%end.i 2297 } 2298 ## @fn ble/decode/widget/suppress-widget 2299 ## __before_widget__ に登録された関数から呼び出します。 2300 ## __before_widget__ 内で必要な処理を完了した時に、 2301 ## WIDGET の呼び出しをキャンセルします。 2302 ## __after_widget__ の呼び出しはキャンセルされません。 2303 function ble/decode/widget/suppress-widget { 2304 WIDGET= 2305 } 2306 2307 ## @fn ble/decode/widget/redispatch-by-keys 2308 ## @var[in] KEYS 2309 ## @var[out] _ble_decode_keylog_depth 2310 function ble/decode/widget/redispatch-by-keys { 2311 if ((_ble_decode_keylog_depth==1)); then 2312 # Note: 一旦 pop してから _ble_decode_keylog_depth=0 2313 # で ble-decode-key を呼び出す事により再記録させる。 2314 # Note: 更に _ble_decode_keylog_depth=0 にする事で、 2315 # _ble_decode_keylog_chars_count の呼び出し元によるクリアを抑制する。 2316 ble/decode/keylog#pop 2317 _ble_decode_keylog_depth=0 2318 fi 2319 ble-decode-key "$@" 2320 } 2321 function ble/decode/widget/skip-lastwidget { 2322 _ble_decode_widget_last=$LASTWIDGET 2323 } 2324 2325 ## @fn ble/decode/widget/keymap-dispatch args 2326 ## 関数 ble/widget/NAME の中から呼び出します。 2327 ## 現在の keymap に固有の同名の関数 "ble/widget/KEYMAP/NAME" が 2328 ## 存在する場合にはそれを呼びします。 2329 ## それ以外の場合には "ble/widget/default/NAME" を呼び出します。 2330 function ble/decode/widget/keymap-dispatch { 2331 local name=${FUNCNAME[1]#ble/widget/} 2332 local widget=ble/widget/$_ble_decode_keymap/$name 2333 ble/is-function "$widget" || widget=ble/widget/default/$name 2334 "$widget" "$@" 2335 } 2336 2337 #------------------------------------------------------------------------------ 2338 # ble/decode/has-input 2339 2340 ## @fn ble/decode/has-input 2341 ## ユーザからの未処理の入力があるかどうかを判定します。 2342 ## 2343 ## @exit 2344 ## ユーザからの未処理の入力がある場合に成功します。 2345 ## それ以外の場合に失敗します。 2346 ## 2347 ## Note: Bash 4.0 未満では read -t 0 が使えない為、 2348 ## 正しく判定する事ができません。 2349 ## 2350 function ble/decode/has-input { 2351 ((_ble_decode_input_count||ble_decode_char_rest)) || 2352 ble/util/is-stdin-ready || 2353 ble/encoding:"$bleopt_input_encoding"/is-intermediate || 2354 ble-decode-char/is-intermediate 2355 2356 # Note: 文字の途中やキーのエスケープシーケンスの途中の時には、 2357 # 標準有力に文字がなくても Readline が先読みして溜めているので、 2358 # それも考慮に入れて未処理の入力があるかどうかを判定する。 2359 # 2360 # Note: キーシーケンスの途中の時には Readline が溜めているという事もないし、 2361 # またユーザが続きを入力するのを待っている状態なので idle と思って良い。 2362 # 従って ble-decode-key/is-intermediate についてはチェックしない。 2363 } 2364 2365 ## @fn ble/decode/has-input-char 2366 ## cseq (char -> key) にとって次の文字が来ているかどうか 2367 function ble/decode/has-input-char { 2368 ((_ble_decode_input_count||ble_decode_char_rest)) || 2369 ble/util/is-stdin-ready || 2370 ble/encoding:"$bleopt_input_encoding"/is-intermediate 2371 } 2372 2373 ## @fn ble/decode/wait-input timeout [type] 2374 function ble/decode/wait-input { 2375 local timeout=$1 type=${2-} 2376 if [[ $type == char ]]; then 2377 ble/decode/has-input-char && return 0 2378 else 2379 ble/decode/has-input && return 0 2380 fi 2381 2382 while ((timeout>0)); do 2383 local w=$((timeout<20?timeout:20)) 2384 ble/util/msleep "$w" 2385 ((timeout-=w)) 2386 ble/util/is-stdin-ready && return 0 2387 done 2388 return 1 2389 } 2390 2391 function ble/util/idle/IS_IDLE { 2392 ! ble/decode/has-input 2393 } 2394 2395 # 2396 #------------------------------------------------------------------------------ 2397 # logging 2398 2399 #%if debug_keylogger 2400 _ble_debug_keylog_enabled=0 2401 _ble_debug_keylog_bytes=() 2402 _ble_debug_keylog_chars=() 2403 _ble_debug_keylog_keys=() 2404 function ble/debug/keylog#start { 2405 _ble_debug_keylog_enabled=1 2406 } 2407 function ble/debug/keylog#end { 2408 { 2409 local IFS=$_ble_term_IFS 2410 ble/util/print '===== bytes =====' 2411 ble/util/print "${_ble_debug_keylog_bytes[*]}" 2412 ble/util/print 2413 ble/util/print '===== chars =====' 2414 local ret; ble-decode-unkbd "${_ble_debug_keylog_chars[@]}" 2415 ble/string#split ret ' ' "$ret" 2416 ble/util/print "${ret[*]}" 2417 ble/util/print 2418 ble/util/print '===== keys =====' 2419 local ret; ble-decode-unkbd "${_ble_debug_keylog_keys[@]}" 2420 ble/string#split ret ' ' "$ret" 2421 ble/util/print "${ret[*]}" 2422 ble/util/print 2423 } | fold -w 40 2424 2425 _ble_debug_keylog_enabled=0 2426 _ble_debug_keylog_bytes=() 2427 _ble_debug_keylog_chars=() 2428 _ble_debug_keylog_keys=() 2429 } 2430 #%else 2431 _ble_debug_keylog_enabled=0 2432 #%end 2433 2434 ## @var _ble_decode_keylog_depth 2435 ## 現在の widget 呼び出しの深さを表します。 2436 ## 入れ子の ble-decode-char, ble-decode-key による 2437 ## 文字・キーを記録しない様にする為に用います。 2438 ## @var _ble_decode_keylog_keys_enabled 2439 ## 現在キーの記録が有効かどうかを保持します。 2440 ## @arr _ble_decode_keylog_keys 2441 ## 記録したキーを保持します。 2442 ## @var _ble_decode_keylog_chars_enabled 2443 ## 現在文字の記録が有効かどうかを保持します。 2444 ## @arr _ble_decode_keylog_chars 2445 ## 記録した文字を保持します。 2446 ## @var _ble_decode_keylog_chars_count 2447 ## 1 widget を呼び出す迄に記録された文字の数です。 2448 _ble_decode_keylog_depth=0 2449 _ble_decode_keylog_keys_enabled= 2450 _ble_decode_keylog_keys_count=0 2451 _ble_decode_keylog_keys=() 2452 _ble_decode_keylog_chars_enabled= 2453 _ble_decode_keylog_chars_count=0 2454 _ble_decode_keylog_chars=() 2455 2456 ## @fn ble/decode/keylog#start [tag] 2457 function ble/decode/keylog#start { 2458 [[ $_ble_decode_keylog_keys_enabled ]] && return 1 2459 _ble_decode_keylog_keys_enabled=${1:-1} 2460 _ble_decode_keylog_keys=() 2461 } 2462 ## @fn ble/decode/keylog#end 2463 ## @var[out] ret 2464 function ble/decode/keylog#end { 2465 ret=("${_ble_decode_keylog_keys[@]}") 2466 _ble_decode_keylog_keys_enabled= 2467 _ble_decode_keylog_keys=() 2468 } 2469 ## @fn ble/decode/keylog#pop 2470 ## 現在の WIDGET 呼び出しに対応する KEYS が記録されているとき、これを削除します。 2471 ## @var[in] _ble_decode_keylog_depth 2472 ## @var[in] _ble_decode_keylog_keys_enabled 2473 ## @arr[in] KEYS 2474 function ble/decode/keylog#pop { 2475 [[ $_ble_decode_keylog_keys_enabled && $_ble_decode_keylog_depth == 1 ]] || return 1 2476 local new_size=$((${#_ble_decode_keylog_keys[@]}-_ble_decode_keylog_keys_count)) 2477 ((new_size<0)) && new_size=0 2478 _ble_decode_keylog_keys=("${_ble_decode_keylog_keys[@]::new_size}") 2479 _ble_decode_keylog_keys_count=0 2480 } 2481 2482 ## @fn ble/decode/charlog#start [tag] 2483 function ble/decode/charlog#start { 2484 [[ $_ble_decode_keylog_chars_enabled ]] && return 1 2485 _ble_decode_keylog_chars_enabled=${1:-1} 2486 _ble_decode_keylog_chars=() 2487 } 2488 ## @fn ble/decode/charlog#end 2489 ## @var[out] ret 2490 function ble/decode/charlog#end { 2491 [[ $_ble_decode_keylog_chars_enabled ]] || { ret=(); return 1; } 2492 ret=("${_ble_decode_keylog_chars[@]}") 2493 _ble_decode_keylog_chars_enabled= 2494 _ble_decode_keylog_chars=() 2495 } 2496 ## @fn ble/decode/charlog#end-exclusive 2497 ## 現在の WIDGET 呼び出しに対応する文字を除いて記録を取得して完了します。 2498 ## @var[out] ret 2499 function ble/decode/charlog#end-exclusive { 2500 ret=() 2501 [[ $_ble_decode_keylog_chars_enabled ]] || return 1 2502 local size=$((${#_ble_decode_keylog_chars[@]}-_ble_decode_keylog_chars_count)) 2503 ((size>0)) && ret=("${_ble_decode_keylog_chars[@]::size}") 2504 _ble_decode_keylog_chars_enabled= 2505 _ble_decode_keylog_chars=() 2506 } 2507 ## @fn ble/decode/charlog#end-exclusive-depth1 2508 ## トップレベルの WIDGET 呼び出しの時は end-exclusive にします。 2509 ## 二次的な WIDGET 呼び出しの時には inclusive に end します。 2510 ## 2511 ## @var[out] ret 2512 ## 記録を返します。 2513 ## 2514 ## これは exit-default -> end-keyboard-macro という具合に 2515 ## WIDGET が呼び出されて記録が完了する場合がある為です。 2516 ## この場合 exit-default は記録に残したいので自身を呼び出した 2517 ## 文字の列も記録に含ませる必要があります。 2518 ## 但し、マクロ再生中に呼び出される end-keyboard-macro 2519 ## は無視する必要があります。 2520 ## 2521 function ble/decode/charlog#end-exclusive-depth1 { 2522 if ((_ble_decode_keylog_depth==1)); then 2523 ble/decode/charlog#end-exclusive 2524 else 2525 ble/decode/charlog#end 2526 fi 2527 } 2528 2529 ## @fn ble/decode/charlog#encode chars... 2530 function ble/decode/charlog#encode { 2531 local -a buff=() 2532 for char; do 2533 ((char==0)) && char=$_ble_decode_EscapedNUL 2534 ble/util/c2s "$char" 2535 ble/array#push buff "$ret" 2536 done 2537 IFS= builtin eval 'ret="${buff[*]}"' 2538 } 2539 ## @fn ble/decode/charlog#decode text 2540 function ble/decode/charlog#decode { 2541 local text=$1 n=${#1} i chars 2542 chars=() 2543 for ((i=0;i<n;i++)); do 2544 ble/util/s2c "${text:i:1}" 2545 ((ret==_ble_decode_EscapedNUL)) && ret=0 2546 ble/array#push chars "$ret" 2547 done 2548 ret=("${chars[@]}") 2549 } 2550 2551 ## @fn ble/decode/keylog#encode keys... 2552 ## キーの列からそれに対応する文字列を構築します 2553 function ble/decode/keylog#encode { 2554 ret= 2555 ble/util/c2s 155; local csi=$ret 2556 2557 local key 2558 local -a buff=() 2559 for key; do 2560 # 通常の文字 2561 if ble-decode-key/ischar "$key"; then 2562 ble/util/c2s "$key" 2563 2564 # Note: 現在の LC_CTYPE で表現できない Unicode の時、 2565 # ret == \u???? もしくは \U???????? の形式になる。 2566 # その場合はここで処理せず、後の部分で CSI 27;1;code ~ の形式で記録する。 2567 if ((${#ret}==1)); then 2568 ble/array#push buff "$ret" 2569 continue 2570 fi 2571 fi 2572 2573 local c=$((key&_ble_decode_MaskChar)) 2574 2575 # C-? は制御文字として登録する 2576 if (((key&_ble_decode_MaskFlag)==_ble_decode_Ctrl&&(c==64||91<=c&&c<=95||97<=c&&c<=122))); then 2577 # Note: ^@ (NUL) は文字列にできないので除外 2578 if ((c!=64)); then 2579 ble/util/c2s "$((c&0x1F))" 2580 ble/array#push buff "$ret" 2581 continue 2582 fi 2583 fi 2584 2585 # Note: Meta 修飾は単体の ESC と紛らわしいので CSI 27 で記録する。 2586 local mod=1 2587 (((key&_ble_decode_Shft)&&(mod+=0x01), 2588 (key&_ble_decode_Altr)&&(mod+=0x02), 2589 (key&_ble_decode_Ctrl)&&(mod+=0x04), 2590 (key&_ble_decode_Supr)&&(mod+=0x08), 2591 (key&_ble_decode_Hypr)&&(mod+=0x10), 2592 (key&_ble_decode_Meta)&&(mod+=0x20))) 2593 ble/array#push buff "${csi}27;$mod;$c~" 2594 done 2595 IFS= builtin eval 'ret="${buff[*]-}"' 2596 } 2597 ## @fn ble/decode/keylog#decode-chars text 2598 function ble/decode/keylog#decode-chars { 2599 local text=$1 n=${#1} i 2600 local -a chars=() 2601 for ((i=0;i<n;i++)); do 2602 ble/util/s2c "${text:i:1}" 2603 ((ret==27)) && ret=$_ble_decode_IsolatedESC 2604 ble/array#push chars "$ret" 2605 done 2606 ret=("${chars[@]}") 2607 } 2608 2609 ## @fn ble/widget/.MACRO char... 2610 ## bind '"keyseq":"macro"' の束縛に使用する。 2611 _ble_decode_macro_count=0 2612 function ble/widget/.MACRO { 2613 # マクロ無限再帰検出 2614 if ((ble_decode_char_char&_ble_decode_Macr)); then 2615 if ((_ble_decode_macro_count++>=bleopt_decode_macro_limit)); then 2616 ((_ble_decode_macro_count==bleopt_decode_macro_limit+1)) && 2617 ble/term/visible-bell "Macro invocation is cancelled by decode_macro_limit" 2618 return 1 2619 fi 2620 else 2621 _ble_decode_macro_count=0 2622 fi 2623 2624 local -a chars=() 2625 local char 2626 for char; do 2627 ble/array#push chars "$((char|_ble_decode_Macr))" 2628 done 2629 ble-decode-char "${chars[@]}" 2630 } 2631 2632 ## @fn ble/widget/.CHARS char... 2633 ## lib/init-bind.sh で特別なバイト列を受信するのに使う関数 2634 function ble/widget/.CHARS { 2635 ble-decode-char "$@" 2636 } 2637 2638 #------------------------------------------------------------------------------ 2639 # key definitions (c.f. init-cmap.sh) @decode.cmap 2640 2641 ## @fn ble/decode/c2dqs code 2642 ## bash builtin bind で用いる事のできるキー表記に変換します。 2643 ## @var[out] ret 2644 function ble/decode/c2dqs { 2645 local i=$1 2646 2647 # bind で用いる 2648 # リテラル "~" 内で特別な表記にする必要がある物 2649 if ((0<=i&&i<32)); then 2650 # C0 characters 2651 if ((1<=i&&i<=26)); then 2652 ble/util/c2s "$((i+96))" 2653 ret="\\C-$ret" 2654 elif ((i==27)); then 2655 ret="\\e" 2656 elif ((i==28)); then 2657 # Workaround \C-\\, \C-\ in Bash-3.0..5.0 2658 ret="\\x1c" 2659 else 2660 ble/decode/c2dqs "$((i+64))" 2661 ret="\\C-$ret" 2662 fi 2663 elif ((32<=i&&i<127)); then 2664 ble/util/c2s "$i" 2665 2666 # \" and \\ 2667 if ((i==34||i==92)); then 2668 ret='\'"$ret" 2669 fi 2670 elif ((128<=i&&i<160)); then 2671 # C1 characters 2672 ble/util/sprintf ret '\\%03o' "$i" 2673 else 2674 # others 2675 ble/util/sprintf ret '\\%03o' "$i" 2676 # ble/util/c2s だと UTF-8 encode されてしまうので駄目 2677 fi 2678 } 2679 2680 ## @fn binder; ble/decode/cmap/.generate-binder-template 2681 ## 3文字以上の bind -x を _ble_decode_cmap から自動的に行うソースを生成 2682 ## binder には bind を行う関数を指定する。 2683 # 2684 # ※この関数は bash-3.1 では使えない。 2685 # bash-3.1 ではバグで呼出元と同名の配列を定義できないので 2686 # local -a ccodes が空になってしまう。 2687 # 幸いこの関数は bash-3.1 では使っていないのでこのままにしてある。 2688 # 追記: 公開されている patch を見たら bash-3.1.4 で修正されている様だ。 2689 # 2690 function ble/decode/cmap/.generate-binder-template { 2691 local tseq=$1 qseq=$2 nseq=$3 depth=${4:-1} ccode 2692 local apos="'" escapos="'\\''" 2693 builtin eval "local -a ccodes; ccodes=(\${!_ble_decode_cmap_$tseq[@]})" 2694 for ccode in "${ccodes[@]}"; do 2695 local ret 2696 ble/decode/c2dqs "$ccode" 2697 local qseq1=$qseq$ret 2698 local nseq1="$nseq $ccode" 2699 2700 builtin eval "local ent=\${_ble_decode_cmap_$tseq[ccode]}" 2701 if [[ ${ent%_} ]]; then 2702 if ((depth>=3)); then 2703 ble/util/print "\$binder \"$qseq1\" \"${nseq1# }\"" 2704 fi 2705 fi 2706 2707 if [[ ${ent//[0-9]} == _ ]]; then 2708 ble/decode/cmap/.generate-binder-template "${tseq}_$ccode" "$qseq1" "$nseq1" "$((depth+1))" 2709 fi 2710 done 2711 } 2712 2713 function ble/decode/cmap/.emit-bindx { 2714 local q="'" Q="'\''" 2715 ble/util/print "builtin bind -x '\"${1//$q/$Q}\":ble-decode/.hook $2; builtin eval -- \"\$_ble_decode_bind_hook\"'" 2716 } 2717 function ble/decode/cmap/.emit-bindr { 2718 ble/util/print "builtin bind -r \"$1\"" 2719 } 2720 2721 _ble_decode_cmap_initialized= 2722 function ble/decode/cmap/initialize { 2723 [[ $_ble_decode_cmap_initialized ]] && return 0 2724 _ble_decode_cmap_initialized=1 2725 2726 local init=$_ble_base/lib/init-cmap.sh 2727 local dump=$_ble_base_cache/decode.cmap.$_ble_decode_kbd_ver.$TERM.dump 2728 if [[ -s $dump && $dump -nt $init ]]; then 2729 source "$dump" 2730 else 2731 ble/edit/info/immediate-show text 'ble.sh: generating "'"$dump"'"...' 2732 source "$init" 2733 ble-bind -D | ble/bin/awk ' 2734 { 2735 sub(/^declare +(-[aAilucnrtxfFgGI]+ +)?/, ""); 2736 sub(/^-- +/, ""); 2737 } 2738 /^_ble_decode_(cmap|csimap|kbd)/ { 2739 if (!($0 ~ /^_ble_decode_csimap_kitty_u/)) 2740 gsub(/["'\'']/, ""); 2741 print 2742 } 2743 ' >| "$dump" 2744 fi 2745 2746 if ((_ble_bash>=40300)); then 2747 # 3文字以上 bind/unbind ソースの生成 (init-bind.sh bindAllSeq で使用) 2748 local fbinder=$_ble_base_cache/decode.cmap.allseq 2749 _ble_decode_bind_fbinder=$fbinder 2750 if ! [[ -s $_ble_decode_bind_fbinder.bind && $_ble_decode_bind_fbinder.bind -nt $init && 2751 -s $_ble_decode_bind_fbinder.unbind && $_ble_decode_bind_fbinder.unbind -nt $init ]]; then 2752 ble/edit/info/immediate-show text 'ble.sh: initializing multichar sequence binders... ' 2753 ble/decode/cmap/.generate-binder-template >| "$fbinder" 2754 binder=ble/decode/cmap/.emit-bindx source "$fbinder" >| "$fbinder.bind" 2755 binder=ble/decode/cmap/.emit-bindr source "$fbinder" >| "$fbinder.unbind" 2756 ble/edit/info/immediate-show text 'ble.sh: initializing multichar sequence binders... done' 2757 fi 2758 fi 2759 } 2760 2761 function ble/decode/cmap/decode-chars.hook { 2762 ble/array#push ble_decode_bind_keys "$1" 2763 _ble_decode_key__hook=ble/decode/cmap/decode-chars.hook 2764 } 2765 ## @fn ble/decode/cmap/decode-chars chars... 2766 ## 文字コードの列からキーの列へ変換します。 2767 ## @arr[out] keys 2768 function ble/decode/cmap/decode-chars { 2769 ble/decode/cmap/initialize 2770 2771 # initialize 2772 local _ble_decode_csi_mode=0 2773 local _ble_decode_csi_args= 2774 local _ble_decode_char2_seq= 2775 local _ble_decode_char2_reach_key= 2776 local _ble_decode_char2_reach_seq= 2777 local _ble_decode_char2_modifier= 2778 local _ble_decode_char2_modkcode= 2779 2780 # suppress unrelated triggers 2781 local _ble_decode_char__hook= 2782 #%if debug_keylogger 2783 local _ble_debug_keylog_enabled= 2784 #%end 2785 local _ble_decode_keylog_keys_enabled= 2786 local _ble_decode_keylog_chars_enabled= 2787 local _ble_decode_show_progress_hook= 2788 local _ble_decode_erase_progress_hook= 2789 2790 # suppress errors 2791 local bleopt_decode_error_cseq_abell= 2792 local bleopt_decode_error_cseq_vbell= 2793 local bleopt_decode_error_cseq_discard= 2794 2795 # set up hook and run 2796 local -a ble_decode_bind_keys=() 2797 local _ble_decode_key__hook=ble/decode/cmap/decode-chars.hook 2798 local ble_decode_char_sync=1 # ユーザ入力があっても中断しない 2799 ble-decode-char "$@" 2800 2801 keys=("${ble_decode_bind_keys[@]}") 2802 } 2803 2804 #------------------------------------------------------------------------------ 2805 # **** binder for bash input **** @decode.bind 2806 2807 _ble_decode_bind_hook= 2808 2809 # **** ^U ^V ^W ^? 対策 **** @decode.bind.uvw 2810 2811 # ref #D0003, #D1092 2812 _ble_decode_bind__uvwflag= 2813 function ble/decode/bind/adjust-uvw { 2814 [[ $_ble_decode_bind__uvwflag ]] && return 0 2815 _ble_decode_bind__uvwflag=1 2816 2817 # 何故か stty 設定直後には bind できない物たち 2818 # Note: bind 'set bind-tty-special-chars on' の時に以下が必要である (#D1092) 2819 builtin bind -x $'"\025":ble-decode/.hook 21; builtin eval -- "$_ble_decode_bind_hook"' # ^U 2820 builtin bind -x $'"\026":ble-decode/.hook 22; builtin eval -- "$_ble_decode_bind_hook"' # ^V 2821 builtin bind -x $'"\027":ble-decode/.hook 23; builtin eval -- "$_ble_decode_bind_hook"' # ^W 2822 builtin bind -x $'"\177":ble-decode/.hook 127; builtin eval -- "$_ble_decode_bind_hook"' # ^? 2823 # Note: 更に terminology は erase を DEL ではなく HT に設定しているので、以下 2824 # も再設定する必要がある。他の端末でも似た物があるかもしれないので、念の為端 2825 # 末判定はせずに常に上書きを実行する様にする。 2826 builtin bind -x $'"\010":ble-decode/.hook 8; builtin eval -- "$_ble_decode_bind_hook"' # ^H 2827 } 2828 2829 # **** POSIXLY_CORRECT workaround **** 2830 2831 # ble.pp の関数を上書き 2832 # 2833 # Note: bash で set -o vi の時、 2834 # builtin unset -v POSIXLY_CORRECT や local POSIXLY_CORRECT が設定されると、 2835 # C-i の既定の動作の切り替えに伴って C-i の束縛が消滅する。 2836 # ユーザが POSIXLY_CORRECT を触った時や自分で触った時に、 2837 # 改めて束縛し直す必要がある。 2838 # 2839 function ble/base/workaround-POSIXLY_CORRECT { 2840 [[ $_ble_decode_bind_state == none ]] && return 0 2841 builtin bind -x '"\C-i":ble-decode/.hook 9; builtin eval -- "$_ble_decode_bind_hook"' 2842 } 2843 2844 # **** ble-decode-bind **** @decode.bind.main 2845 2846 ## @fn ble/decode/bind/.generate-source-to-unbind-default 2847 ## 既存の ESC で始まる binding を削除するコードを生成し標準出力に出力します。 2848 ## 更に、既存の binding を復元する為のコードを同時に生成し tmp/$$.bind.save に保存します。 2849 function ble/decode/bind/.generate-source-to-unbind-default { 2850 # 1 ESC で始まる既存の binding を全て削除 2851 # 2 bind を全て記録 at $$.bind.save 2852 { 2853 if ((_ble_bash>=40300)); then 2854 ble/util/print '__BINDX__' 2855 builtin bind -X 2856 fi 2857 ble/util/print '__BINDP__' 2858 builtin bind -sp 2859 } | ble/decode/bind/.generate-source-to-unbind-default/.process 2860 2861 # Note: 2>/dev/null は、(1) bind -X のエラーメッセージ、及び、 2862 # (2) LC_ALL 復元時のエラーメッセージ (外側の値が不正な時) を捨てる為に必要。 2863 } 2>/dev/null 2864 function ble/decode/bind/.generate-source-to-unbind-default/.process { 2865 # Note: #D1355 LC_ALL 切り替えに伴うエラーメッセージは呼び出し元で /dev/null に繋いでいる。 2866 local q=\' Q="'\''" 2867 LC_ALL=C ble/bin/awk -v q="$q" ' 2868 BEGIN { 2869 IS_XPG4 = AWKTYPE == "xpg4"; 2870 rep_Q = str2rep(q "\\" q q); 2871 rep_bslash = str2rep("\\"); 2872 rep_kseq_1c5c = str2rep("\"\\x1c\\x5c\""); 2873 rep_kseq_1c = str2rep("\"\\x1c\""); 2874 mode = 1; 2875 } 2876 2877 #% # Note: Solaris xpg4 awk では gsub の置換後のエスケープシーケンス 2878 #% # も処理されるので、バックスラッシュをエスケープする。 2879 function str2rep(str) { 2880 if (IS_XPG4) sub(/\\/, "\\\\\\\\", str); 2881 return str; 2882 } 2883 2884 function quote(text) { 2885 gsub(q, rep_Q, text); 2886 return q text q; 2887 } 2888 2889 function unescape_control_modifier(str, _, i, esc, chr) { 2890 for (i = 0; i < 32; i++) { 2891 if (i == 0 || i == 31) 2892 esc = sprintf("\\\\C-%c", i + 64); 2893 else if (27 <= i && i <= 30) 2894 esc = sprintf("\\\\C-\\%c", i + 64); 2895 else 2896 esc = sprintf("\\\\C-%c", i + 96); 2897 2898 chr = sprintf("%c", i); 2899 gsub(esc, chr, str); 2900 } 2901 gsub(/\\C-\?/, sprintf("%c", 127), str); 2902 return str; 2903 } 2904 function unescape(str) { 2905 if (str ~ /\\C-/) 2906 str = unescape_control_modifier(str); 2907 gsub(/\\e/, sprintf("%c", 27), str); 2908 gsub(/\\"/, "\"", str); 2909 gsub(/\\\\/, rep_bslash, str); 2910 return str; 2911 } 2912 2913 function output_bindr(line0, _seq) { 2914 if (match(line0, /^"(([^"\\]|\\.)+)"/) > 0) { 2915 _seq = substr(line0, 2, RLENGTH - 2); 2916 2917 #% # ※bash-3.1 では bind -sp で \e ではなく \M- と表示されるが、 2918 #% # bind -r では \M- ではなく \e と指定しなければ削除できない。 2919 gsub(/\\M-/, "\\e", _seq); 2920 2921 print "builtin bind -r " quote(_seq); 2922 } 2923 } 2924 2925 /^__BINDP__$/ { mode = 1; next; } 2926 /^__BINDX__$/ { mode = 2; next; } 2927 2928 mode == 1 && $0 ~ /^"/ { 2929 # Workaround Bash-5.0 bug (cf #D1078) 2930 sub(/^"\\C-\\\\\\"/, rep_kseq_1c5c); 2931 sub(/^"\\C-\\\\?"/, rep_kseq_1c); 2932 2933 output_bindr($0); 2934 2935 print "builtin bind " quote($0) > "/dev/stderr"; 2936 } 2937 2938 mode == 2 && $0 ~ /^"/ { 2939 output_bindr($0); 2940 2941 line = $0; 2942 2943 #% # ※bash-4.3..5.0 では bind -r しても bind -X に残る。 2944 #% # 再登録を防ぐ為 ble-decode-bind を明示的に避ける 2945 if (line ~ /(^|[^[:alnum:]])ble-decode\/.hook($|[^[:alnum:]])/) next; 2946 2947 #% # ※bind -X で得られた物は直接 bind -x に用いる事はできない。 2948 #% # コマンド部分の "" を外して中の escape を外す必要がある。 2949 #% # escape には以下の種類がある: \C-a など \C-? \e \\ \" 2950 #% # \n\r\f\t\v\b\a 等は使われない様だ。 2951 if (match(line, /^("([^"\\]|\\.)*":) "(([^"\\]|\\.)*)"/) > 0) { 2952 rlen = RLENGTH; 2953 match(line, /^"([^"\\]|\\.)*":/); 2954 rlen1 = RLENGTH; 2955 rlen2 = rlen - rlen1 - 3; 2956 sequence = substr(line, 1 , rlen1); 2957 command = substr(line, rlen1 + 3, rlen2); 2958 2959 if (command ~ /\\/) 2960 command = unescape(command); 2961 2962 line = sequence command; 2963 } 2964 2965 print "builtin bind -x " quote(line) > "/dev/stderr"; 2966 } 2967 ' 2>| "$_ble_base_run/$$.bind.save" 2968 } 2969 2970 ## @var _ble_decode_bind_state 2971 ## none, emacs, vi 2972 _ble_decode_bind_state=none 2973 _ble_decode_bind_bindp= 2974 _ble_decode_bind_encoding= 2975 2976 function ble/decode/bind/bind { 2977 _ble_decode_bind_encoding=$bleopt_input_encoding 2978 local file=$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.bind 2979 [[ -s $file && $file -nt $_ble_base/lib/init-bind.sh ]] || source "$_ble_base/lib/init-bind.sh" 2980 2981 # * 一時的に 'set convert-meta off' にする。 2982 # 2983 # bash-3.0 - 5.0a 全てにおいて 'set convert-meta on' の時、 2984 # 128-255 を bind しようとすると 0-127 を bind してしまう。 2985 # 32 bit 環境で LC_CTYPE=C で起動すると 'set convert-meta on' になる様だ。 2986 # 2987 # 一応、以下の関数は ble/term/initialize で呼び出しているので、 2988 # ble/decode/bind/bind の呼び出しが ble/term/initialize より後なら大丈夫の筈だが、 2989 # 念の為にここでも呼び出しておく事にする。 2990 # 2991 ble/term/rl-convert-meta/enter 2992 2993 source "$file" 2994 _ble_decode_bind__uvwflag= 2995 ble/util/assign _ble_decode_bind_bindp 'builtin bind -p' # TERM 変更検出用 2996 } 2997 function ble/decode/bind/unbind { 2998 ble/function#try ble/encoding:"$bleopt_input_encoding"/clear 2999 source "$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.unbind" 3000 } 3001 function ble/decode/rebind { 3002 [[ $_ble_decode_bind_state == none ]] && return 0 3003 ble/decode/bind/unbind 3004 ble/decode/bind/bind 3005 } 3006 3007 #------------------------------------------------------------------------------ 3008 # ble-bind @decode.blebind 3009 3010 function ble-bind/.initialize-kmap { 3011 [[ $kmap ]] && return 0 3012 ble-decode/GET_BASEMAP -v kmap 3013 if ! ble/decode/is-keymap "$kmap"; then 3014 ble/util/print "ble-bind: the default keymap '$kmap' is unknown." >&2 3015 flags=R$flags 3016 return 1 3017 fi 3018 return 0 3019 } 3020 3021 function ble-bind/option:help { 3022 ble/util/cat <<EOF 3023 ble-bind --help 3024 ble-bind -k [TYPE:]cspecs [[TYPE:]kspec] 3025 ble-bind --csi PsFt [TYPE:]kspec 3026 ble-bind [-m keymap] -fxc@s [TYPE:]kspecs command 3027 ble-bind [-m keymap] -T [TYPE:]kspecs timeout 3028 ble-bind [-m keymap] --cursor cursor_code 3029 ble-bind [-m keymap]... (-PD|--print|--dump) 3030 ble-bind (-L|--list-widgets) 3031 3032 TYPE:SPEC 3033 TYPE specifies the format of SPEC. The default is "kspecs". 3034 3035 kspecs ble.sh keyboard spec 3036 keys List of key codes 3037 chars List of character codes in Unicode 3038 keyseq Key sequence in the Readline format 3039 raw Raw byte sequence 3040 3041 TIMEOUT 3042 specifies the timeout duration in milliseconds. 3043 3044 CURSOR_CODE 3045 specifies the cursor shape by the DECSCUSR code. 3046 3047 EOF 3048 } 3049 3050 function ble-bind/check-argument { 3051 if (($3<$2)); then 3052 flags=E$flags 3053 if (($2==1)); then 3054 ble/util/print "ble-bind: the option \`$1' requires an argument." >&2 3055 else 3056 ble/util/print "ble-bind: the option \`$1' requires $2 arguments." >&2 3057 fi 3058 return 2 3059 fi 3060 } 3061 3062 function ble-bind/option:csi { 3063 local ret key= 3064 if [[ $2 ]]; then 3065 ble-decode-kbd "$2" 3066 ble/string#split-words key "$ret" 3067 if ((${#key[@]}!=1)); then 3068 ble/util/print "ble-bind --csi: the second argument is not a single key!" >&2 3069 return 1 3070 elif ((key&~_ble_decode_MaskChar)); then 3071 ble/util/print "ble-bind --csi: the second argument should not have modifiers!" >&2 3072 return 1 3073 fi 3074 fi 3075 3076 local rex 3077 if rex='^([1-9][0-9]*)~$' && [[ $1 =~ $rex ]]; then 3078 # --csi '<num>~' kname 3079 # 3080 # 以下のシーケンスを有効にする。 3081 # - CSI <num> ~ kname 3082 # - CSI <num> ; <mod> ~ Mod-kname (modified function key) 3083 # - CSI <num> $ S-kname (rxvt) 3084 # - CSI <num> ^ C-kname (rxvt) 3085 # - CSI <num> @ C-S-kname (rxvt) 3086 # 3087 _ble_decode_csimap_tilde[BASH_REMATCH[1]]=$key 3088 3089 # "CSI <num> $" は CSI sequence の形式に沿っていないので、 3090 # 個別に登録する必要がある。 3091 local -a cseq 3092 cseq=(27 91) 3093 local ret i iN num="${BASH_REMATCH[1]}\$" 3094 for ((i=0,iN=${#num};i<iN;i++)); do 3095 ble/util/s2c "${num:i:1}" 3096 ble/array#push cseq "$ret" 3097 done 3098 3099 local IFS=$_ble_term_IFS 3100 if [[ $key ]]; then 3101 ble-decode-char/bind "${cseq[*]}" "$((key|_ble_decode_Shft))" 3102 else 3103 ble-decode-char/unbind "${cseq[*]}" 3104 fi 3105 elif [[ $1 == [a-zA-Z] ]]; then 3106 # --csi '<Ft>' kname 3107 local ret; ble/util/s2c "$1" 3108 _ble_decode_csimap_alpha[ret]=$key 3109 else 3110 ble/util/print "ble-bind --csi: not supported type of csi sequences: CSI \`$1'." >&2 3111 return 1 3112 fi 3113 } 3114 3115 function ble-bind/option:list-widgets { 3116 declare -f | ble/bin/sed -n 's/^ble\/widget\/\([a-zA-Z][^.[:space:]();&|]\{1,\}\)[[:space:]]*()[[:space:]]*$/\1/p' 3117 } 3118 function ble-bind/option:dump { 3119 if (($#)); then 3120 local keymap 3121 for keymap; do 3122 ble/decode/keymap#dump "$keymap" 3123 done 3124 else 3125 ble/util/declare-print-definitions "${!_ble_decode_kbd__@}" "${!_ble_decode_cmap_@}" "${!_ble_decode_csimap_@}" 3126 ble/decode/keymap#dump 3127 fi 3128 } 3129 ## @fn ble-bind/option:print 3130 ## @var[in] flags 3131 function ble-bind/option:print { 3132 local ble_bind_print=1 3133 local sgr0= sgrf= sgrq= sgrc= sgro= 3134 if [[ $flags == *c* || $flags != *n* && -t 1 ]]; then 3135 local ret 3136 ble/color/face2sgr command_function; sgrf=$ret 3137 ble/color/face2sgr syntax_quoted; sgrq=$ret 3138 ble/color/face2sgr syntax_comment; sgrc=$ret 3139 ble/color/face2sgr argument_option; sgro=$ret 3140 sgr0=$_ble_term_sgr0 3141 fi 3142 3143 local keymap 3144 ble-decode/INITIALIZE_DEFMAP -v keymap # 初期化を強制する 3145 if (($#)); then 3146 for keymap; do 3147 ble/decode/keymap#print "$keymap" 3148 done 3149 else 3150 ble-decode-char/csi/print 3151 ble-decode-char/print 3152 ble/decode/keymap#print 3153 fi 3154 } 3155 3156 function ble-bind { 3157 # @var flags 3158 # D ... something done 3159 # E ... parse error 3160 # R ... runtime error 3161 # c ... color=always 3162 # n ... color=none 3163 local flags= kmap=${ble_bind_keymap-} ret 3164 local -a keymaps; keymaps=() 3165 ble/decode/initialize 3166 3167 local IFS=$_ble_term_IFS q=\' Q="''\'" 3168 3169 local arg c 3170 while (($#)); do 3171 local arg=$1; shift 3172 if [[ $arg == --?* ]]; then 3173 case ${arg:2} in 3174 (color|color=always) 3175 flags=c${flags//[cn]} ;; 3176 (color=never) 3177 flags=n${flags//[cn]} ;; 3178 (color=auto) 3179 flags=${flags//[cn]} ;; 3180 (help) 3181 ble-bind/option:help 3182 flags=D$flags ;; 3183 (csi) 3184 flags=D$flags 3185 ble-bind/check-argument --csi 2 $# || break 3186 ble-bind/option:csi "$1" "$2" 3187 shift 2 ;; 3188 (cursor) 3189 flags=D$flags 3190 ble-bind/check-argument --cursor 1 $# || break 3191 ble-bind/.initialize-kmap && 3192 ble/decode/keymap#set-cursor "$kmap" "$1" 3193 shift 1 ;; 3194 (list-widgets|list-functions) 3195 flags=D$flags 3196 ble-bind/option:list-widgets ;; 3197 (dump) 3198 flags=D$flags 3199 ble-bind/option:dump "${keymaps[@]}" ;; 3200 (print) 3201 flags=D$flags 3202 ble-bind/option:print "${keymaps[@]}" ;; 3203 (*) 3204 flags=E$flags 3205 ble/util/print "ble-bind: unrecognized long option $arg" >&2 ;; 3206 esac 3207 elif [[ $arg == -?* ]]; then 3208 arg=${arg:1} 3209 while ((${#arg})); do 3210 c=${arg::1} arg=${arg:1} 3211 case $c in 3212 (k) 3213 flags=D$flags 3214 if (($#<2)); then 3215 ble/util/print "ble-bind: the option \`-k' requires two arguments." >&2 3216 flags=E$flags 3217 break 3218 fi 3219 3220 ble-decode-kbd "$1"; local cseq=$ret 3221 if [[ $2 && $2 != - ]]; then 3222 ble-decode-kbd "$2"; local kc=$ret 3223 ble-decode-char/bind "$cseq" "$kc" 3224 else 3225 ble-decode-char/unbind "$cseq" 3226 fi 3227 shift 2 ;; 3228 (m) 3229 ble-bind/check-argument -m 1 $# || break 3230 if ! ble/decode/is-keymap "$1"; then 3231 ble/util/print "ble-bind: the keymap '$1' is unknown." >&2 3232 flags=E$flags 3233 shift 3234 continue 3235 fi 3236 kmap=$1 3237 ble/array#push keymaps "$1" 3238 shift ;; 3239 (D) 3240 flags=D$flags 3241 ble-bind/option:dump "${keymaps[@]}" ;; 3242 ([Pd]) 3243 flags=D$flags 3244 ble-bind/option:print "${keymaps[@]}" ;; 3245 (['fxc@s']) 3246 flags=D$flags 3247 3248 # 旧形式の指定 -xf や -cf に対応する処理 3249 [[ $c != f && $arg == f* ]] && arg=${arg:1} 3250 ble-bind/check-argument "-$c" 2 $# || break 3251 3252 ble-decode-kbd "$1"; local kbd=$ret 3253 if [[ $2 && $2 != - ]]; then 3254 local command=$2 3255 3256 # コマンドの種類 3257 case $c in 3258 (f) command=ble/widget/$command ;; # ble/widget/ 関数 3259 (x) command="ble/widget/.EDIT_COMMAND '${command//$q/$Q}'" ;; # 編集用の関数 3260 (c) command="ble/widget/.SHELL_COMMAND '${command//$q/$Q}'" ;; # コマンド実行 3261 (s) local ret; ble/util/keyseq2chars "$command"; command="ble/widget/.MACRO ${ret[*]}" ;; 3262 ('@') ;; # 直接実行 3263 (*) 3264 ble/util/print "error: unsupported binding type \`-$c'." 1>&2 3265 continue ;; 3266 esac 3267 3268 ble-bind/.initialize-kmap && 3269 ble-decode-key/bind "$kmap" "$kbd" "$command" 3270 else 3271 ble-bind/.initialize-kmap && 3272 ble-decode-key/unbind "$kmap" "$kbd" 3273 fi 3274 shift 2 ;; 3275 (T) 3276 flags=D$flags 3277 ble-decode-kbd "$1"; local kbd=$ret 3278 ble-bind/check-argument -T 2 $# || break 3279 ble-bind/.initialize-kmap && 3280 ble-decode-key/set-timeout "$kmap" "$kbd" "$2" 3281 shift 2 ;; 3282 (L) 3283 flags=D$flags 3284 ble-bind/option:list-widgets ;; 3285 (*) 3286 ble/util/print "ble-bind: unrecognized short option \`-$c'." >&2 3287 flags=E$flags ;; 3288 esac 3289 done 3290 else 3291 ble/util/print "ble-bind: unrecognized argument \`$arg'." >&2 3292 flags=E$flags 3293 fi 3294 done 3295 3296 [[ $flags == *E* ]] && return 2 3297 [[ $flags == *R* ]] && return 1 3298 [[ $flags == *D* ]] || ble-bind/option:print "${keymaps[@]}" 3299 return 0 3300 } 3301 3302 #------------------------------------------------------------------------------ 3303 # ble/decode/read-inputrc @decode.inputrc 3304 3305 function ble/decode/read-inputrc/test { 3306 local text=$1 3307 if [[ ! $text ]]; then 3308 ble/util/print "ble.sh (bind):\$if: test condition is not supplied." >&2 3309 return 1 3310 elif local rex=$'[ \t]*([<>]=?|[=!]?=)[ \t]*(.*)$'; [[ $text =~ $rex ]]; then 3311 local op=${BASH_REMATCH[1]} 3312 local rhs=${BASH_REMATCH[2]} 3313 local lhs=${text::${#text}-${#BASH_REMATCH}} 3314 else 3315 local lhs=application 3316 local rhs=$text 3317 fi 3318 3319 case $lhs in 3320 (application) 3321 local ret; ble/string#tolower "$rhs" 3322 [[ $ret == bash || $ret == blesh ]] 3323 return "$?" ;; 3324 3325 (mode) 3326 if [[ -o emacs ]]; then 3327 builtin test emacs "$op" "$rhs" 3328 elif [[ -o vi ]]; then 3329 builtin test vi "$op" "$rhs" 3330 else 3331 false 3332 fi 3333 return "$?" ;; 3334 3335 (term) 3336 if [[ $op == '!=' ]]; then 3337 builtin test "$TERM" "$op" "$rhs" && builtin test "${TERM%%-*}" "$op" "$rhs" 3338 else 3339 builtin test "$TERM" "$op" "$rhs" || builtin test "${TERM%%-*}" "$op" "$rhs" 3340 fi 3341 return "$?" ;; 3342 3343 (version) 3344 local lhs_major lhs_minor 3345 if ((_ble_bash<40400)); then 3346 ((lhs_major=2+_ble_bash/10000, 3347 lhs_minor=_ble_bash/100%100)) 3348 elif ((_ble_bash<50000)); then 3349 ((lhs_major=7,lhs_minor=0)) 3350 else 3351 ((lhs_major=3+_ble_bash/10000, 3352 lhs_minor=_ble_bash/100%100)) 3353 fi 3354 3355 local rhs_major rhs_minor 3356 if [[ $rhs == *.* ]]; then 3357 local version 3358 ble/string#split version . "$rhs" 3359 rhs_major=${version[0]} 3360 rhs_minor=${version[1]} 3361 else 3362 ((rhs_major=rhs,rhs_minor=0)) 3363 fi 3364 3365 local lhs_ver=$((lhs_major*10000+lhs_minor)) 3366 local rhs_ver=$((rhs_major*10000+rhs_minor)) 3367 [[ $op == '=' ]] && op='==' 3368 let "$lhs_ver$op$rhs_ver" 3369 return "$?" ;; 3370 3371 (*) 3372 if local ret; ble/util/rlvar#read "$lhs"; then 3373 builtin test "$ret" "$op" "$rhs" 3374 return "$?" 3375 else 3376 ble/util/print "ble.sh (bind):\$if: unknown readline variable '${lhs//$q/$Q}'." >&2 3377 return 1 3378 fi ;; 3379 esac 3380 } 3381 3382 function ble/decode/read-inputrc { 3383 local file=$1 ref=$2 q=\' Q="''\'" 3384 if [[ -f $ref && $ref == */* && $file != /* ]]; then 3385 local relative_file=${ref%/*}/$file 3386 [[ -f $relative_file ]] && file=$relative_file 3387 fi 3388 if [[ ! -f $file ]]; then 3389 ble/util/print "ble.sh (bind):\$include: the file '${1//$q/$Q}' not found." >&2 3390 return 1 3391 fi 3392 3393 local -a script=() 3394 local ret line= iline=0 3395 while ble/bash/read line || [[ $line ]]; do 3396 ((++iline)) 3397 ble/string#trim "$line"; line=$ret 3398 [[ ! $line || $line == '#'* ]] && continue 3399 3400 if [[ $line == '$'* ]]; then 3401 local directive=${line%%[$IFS]*} 3402 case $directive in 3403 ('$if') 3404 local args=${line#'$if'} 3405 ble/string#trim "$args"; args=$ret 3406 ble/array#push script "if ble/decode/read-inputrc/test '${args//$q/$Q}'; then :" ;; 3407 ('$else') ble/array#push script 'else :' ;; 3408 ('$endif') ble/array#push script 'fi' ;; 3409 ('$include') 3410 local args=${line#'$include'} 3411 ble/string#trim "$args"; args=$ret 3412 ble/array#push script "ble/decode/read-inputrc '${args//$q/$Q}' '${file//$q/$Q}'" ;; 3413 (*) 3414 ble/util/print "ble.sh (bind):$file:$iline: unrecognized directive '$directive'." >&2 ;; 3415 esac 3416 else 3417 ble/array#push script "ble/builtin/bind/.process -- '${line//$q/$Q}'" 3418 fi 3419 done < "$file" 3420 3421 IFS=$'\n' builtin eval 'script="${script[*]}"' 3422 builtin eval -- "$script" 3423 } 3424 3425 #------------------------------------------------------------------------------ 3426 # ble/builtin/bind @builtin.bind 3427 3428 _ble_builtin_bind_keymap= 3429 function ble/builtin/bind/set-keymap { 3430 local opt_keymap= flags= 3431 ble/builtin/bind/option:m "$1" && 3432 _ble_builtin_bind_keymap=$opt_keymap 3433 return 0 3434 } 3435 3436 ## @fn ble/builtin/bind/option:m keymap 3437 ## @var[in,out] opt_keymap flags 3438 function ble/builtin/bind/option:m { 3439 local name=$1 3440 local ret; ble/string#tolower "$name"; local keymap=$ret 3441 case $keymap in 3442 (emacs|emacs-standard|emacs-meta|emacs-ctlx) ;; 3443 (vi|vi-command|vi-move|vi-insert) ;; 3444 (*) keymap= ;; 3445 esac 3446 if [[ ! $keymap ]]; then 3447 ble/util/print "ble.sh (bind): unrecognized keymap name '$name'" >&2 3448 flags=e$flags 3449 return 1 3450 else 3451 opt_keymap=$keymap 3452 return 0 3453 fi 3454 } 3455 ## @fn ble/builtin/bind/.decompose-pair spec 3456 ## keyseq:command の形式の文字列を keyseq と command に分離します。 3457 ## @var[out] keyseq value 3458 function ble/builtin/bind/.decompose-pair { 3459 local LC_ALL= LC_CTYPE=C 3460 local ret; ble/string#trim "$1" 3461 local spec=$ret ifs=$_ble_term_IFS q=\' Q="'\''" 3462 keyseq= value= 3463 3464 # bind '' と指定した時は無視する 3465 [[ ! $spec || $spec == 'set'["$ifs"]* ]] && return 3 3466 3467 # split keyseq / value 3468 local rex='^(("([^\"]|\\.)*"|[^":'$ifs'])*("([^\"]|\\.)*)?)['$ifs']*(:['$ifs']*)?' 3469 [[ $spec =~ $rex ]] 3470 keyseq=${BASH_REMATCH[1]} value=${spec:${#BASH_REMATCH}} 3471 3472 # check values 3473 if [[ $keyseq == '$'* ]]; then 3474 # Parser directives such as $if, $else, $endif, $include 3475 return 3 3476 elif [[ ! $keyseq ]]; then 3477 ble/util/print "ble.sh (bind): empty keyseq in spec:'${spec//$q/$Q}'" >&2 3478 flags=e$flags 3479 return 1 3480 elif rex='^"([^\"]|\\.)*$'; [[ $keyseq =~ $rex ]]; then 3481 ble/util/print "ble.sh (bind): no closing '\"' in keyseq:'${keyseq//$q/$Q}'" >&2 3482 flags=e$flags 3483 return 1 3484 elif rex='^"([^\"]|\\.)*"'; [[ $keyseq =~ $rex ]]; then 3485 local rematch=${BASH_REMATCH[0]} 3486 if ((${#rematch}<${#keyseq})); then 3487 local fragment=${keyseq:${#rematch}} 3488 ble/util/print "ble.sh (bind): warning: unprocessed fragments in keyseq '${fragment//$q/$Q}'" >&2 3489 fi 3490 keyseq=$rematch 3491 return 0 3492 else 3493 return 0 3494 fi 3495 } 3496 ble/function#suppress-stderr ble/builtin/bind/.decompose-pair 3497 ## @fn ble/builtin/bind/.parse-keyname keyname 3498 ## @var[out] chars 3499 function ble/builtin/bind/.parse-keyname { 3500 local ret mflags= 3501 ble/string#tolower "$1"; local lower=$ret 3502 if [[ $1 == *-* ]]; then 3503 ble/string#split ret - "$lower" 3504 local mod 3505 for mod in "${ret[@]::${#ret[@]}-1}"; do 3506 case $mod in 3507 (*m|*meta) mflags=m$mflags ;; 3508 (*c|*ctrl|*control) mflags=c$mflags ;; 3509 esac 3510 done 3511 fi 3512 3513 local name=${lower##*-} ch= 3514 case $name in 3515 (rubout|del) ch=$'\177' ;; 3516 (escape|esc) ch=$'\033' ;; 3517 (newline|lfd) ch=$'\n' ;; 3518 (return|ret) ch=$'\r' ;; 3519 (space|spc) ch=' ' ;; 3520 (tab) ch=$'\t' ;; 3521 (*) ble/util/substr "${1##*-}" 0 1; ch=$ret ;; 3522 esac 3523 ble/util/s2c "$ch"; local key=$ret 3524 3525 [[ $mflags == *c* ]] && ((key&=0x1F)) 3526 [[ $mflags == *m* ]] && ((key|=0x80)) 3527 chars=("$key") 3528 } 3529 3530 ## @fn ble/builtin/bind/.initialize-kmap keymap 3531 ## @var[in,out] keys 3532 ## @var[out] kmap 3533 function ble/builtin/bind/.initialize-kmap { 3534 local keymap=$1 3535 kmap= 3536 case $keymap in 3537 (emacs|emacs-standard) kmap=emacs ;; 3538 (emacs-ctlx) kmap=emacs; keys=(24 "${keys[@]}") ;; 3539 (emacs-meta) kmap=emacs; keys=(27 "${keys[@]}") ;; 3540 (vi-insert) kmap=vi_imap ;; 3541 (vi|vi-command|vi-move) kmap=vi_nmap ;; 3542 (*) ble-decode/GET_BASEMAP -v kmap ;; 3543 esac 3544 3545 if ! ble/decode/is-keymap "$kmap"; then 3546 ble/util/print "ble/builtin/bind: the keymap '$kmap' is unknown." >&2 3547 return 1 3548 fi 3549 3550 return 0 3551 } 3552 ## @fn ble/builtin/bind/.initialize-keys-and-value 3553 ## @var[out] keys value 3554 function ble/builtin/bind/.initialize-keys-and-value { 3555 local spec=$1 opts=$2 3556 keys= value= 3557 3558 local keyseq 3559 ble/builtin/bind/.decompose-pair "$spec" || return "$?" 3560 3561 local chars 3562 if [[ $keyseq == \"*\" ]]; then 3563 local ret; ble/util/keyseq2chars "${keyseq:1:${#keyseq}-2}" 3564 chars=("${ret[@]}") 3565 ((${#chars[@]})) || ble/util/print "ble.sh (bind): warning: empty keyseq" >&2 3566 else 3567 [[ :$opts: == *:nokeyname:* ]] && 3568 ble/util/print "ble.sh (bind): warning: readline \"bind -x\" does not support \"keyname\" spec" >&2 3569 ble/builtin/bind/.parse-keyname "$keyseq" 3570 fi 3571 ble/decode/cmap/decode-chars "${chars[@]}" 3572 } 3573 3574 ## @fn ble/builtin/bind/option:x spec 3575 ## @var[in] opt_keymap 3576 function ble/builtin/bind/option:x { 3577 local q=\' Q="''\'" 3578 local keys value kmap 3579 if ! ble/builtin/bind/.initialize-keys-and-value "$1" nokeyname; then 3580 ble/util/print "ble.sh (bind): unrecognized readline command '${1//$q/$Q}'." >&2 3581 flags=e$flags 3582 return 1 3583 elif ! ble/builtin/bind/.initialize-kmap "$opt_keymap"; then 3584 ble/util/print "ble.sh (bind): sorry, failed to initialize keymap:'$opt_keymap'." >&2 3585 flags=e$flags 3586 return 1 3587 fi 3588 3589 if [[ $value == \"* ]]; then 3590 local ifs=$_ble_term_IFS 3591 local rex='^"(([^\"]|\\.)*)"' 3592 if ! [[ $value =~ $rex ]]; then 3593 ble/util/print "ble.sh (bind): no closing '\"' in spec:'${1//$q/$Q}'" >&2 3594 flags=e$flags 3595 return 1 3596 fi 3597 3598 if ((${#BASH_REMATCH}<${#value})); then 3599 local fragment=${value:${#BASH_REMATCH}} 3600 ble/util/print "ble.sh (bind): warning: unprocessed fragments:'${fragment//$q/$Q}' in spec:'${1//$q/$Q}'" >&2 3601 fi 3602 3603 value=${BASH_REMATCH[1]} 3604 fi 3605 3606 [[ $value == \"*\" ]] && value=${value:1:${#value}-2} 3607 local command="ble/widget/.EDIT_COMMAND '${value//$q/$Q}'" 3608 ble-decode-key/bind "$kmap" "${keys[*]}" "$command" 3609 } 3610 ## @fn ble/builtin/bind/option:r keyseq 3611 ## @var[in] opt_keymap 3612 function ble/builtin/bind/option:r { 3613 local keyseq=$1 3614 3615 local ret chars keys 3616 ble/util/keyseq2chars "$keyseq"; chars=("${ret[@]}") 3617 ble/decode/cmap/decode-chars "${chars[@]}" 3618 3619 local kmap 3620 ble/builtin/bind/.initialize-kmap "$opt_keymap" || return 1 3621 ble-decode-key/unbind "$kmap" "${keys[*]}" 3622 } 3623 3624 _ble_decode_rlfunc2widget_emacs=() 3625 _ble_decode_rlfunc2widget_vi_imap=() 3626 _ble_decode_rlfunc2widget_vi_nmap=() 3627 function ble/builtin/bind/rlfunc2widget { 3628 local kmap=$1 rlfunc=$2 3629 local IFS=$_ble_term_IFS 3630 3631 local rlfunc_file= rlfunc_dict= 3632 case $kmap in 3633 (emacs) rlfunc_file=$_ble_base/lib/core-decode.emacs-rlfunc.txt 3634 rlfunc_dict=_ble_decode_rlfunc2widget_emacs ;; 3635 (vi_imap) rlfunc_file=$_ble_base/lib/core-decode.vi_imap-rlfunc.txt 3636 rlfunc_dict=_ble_decode_rlfunc2widget_vi_imap ;; 3637 (vi_nmap) rlfunc_file=$_ble_base/lib/core-decode.vi_nmap-rlfunc.txt 3638 rlfunc_dict=_ble_decode_rlfunc2widget_vi_nmap ;; 3639 esac 3640 3641 if [[ $rlfunc_file ]]; then 3642 local dict script=' 3643 ((${#DICT[@]})) || 3644 ble/util/mapfile DICT < "$rlfunc_file" 3645 dict=("${DICT[@]}")' 3646 builtin eval -- "${script//DICT/$rlfunc_dict}" 3647 3648 local line 3649 for line in "${dict[@]}"; do 3650 [[ $line == "$rlfunc "* ]] || continue 3651 local rl widget; ble/bash/read rl widget <<< "$line" 3652 if [[ $widget == - ]]; then 3653 ble/util/print "ble.sh (bind): unsupported readline function '${rlfunc//$q/$Q}' for keymap '$kmap'." >&2 3654 return 1 3655 elif [[ $widget == '<IGNORE>' ]]; then 3656 return 2 3657 fi 3658 ret=ble/widget/$widget 3659 return 0 3660 done 3661 fi 3662 3663 if ble/is-function ble/widget/"${rlfunc%%[$IFS]*}"; then 3664 ret=ble/widget/$rlfunc 3665 return 0 3666 fi 3667 3668 ble/util/print "ble.sh (bind): unsupported readline function '${rlfunc//$q/$Q}'." >&2 3669 return 1 3670 } 3671 3672 ## @fn ble/builtin/bind/option:u function 3673 ## @var[in] opt_keymap 3674 function ble/builtin/bind/option:u { 3675 local rlfunc=$1 3676 3677 local kmap 3678 if ! ble/builtin/bind/.initialize-kmap "$opt_keymap" || ! ble/decode/keymap#load "$kmap"; then 3679 ble/util/print "ble.sh (bind): sorry, failed to initialize keymap:'$opt_keymap'." >&2 3680 flags=e$flags 3681 return 1 3682 fi 3683 local ret 3684 ble/builtin/bind/rlfunc2widget "$kmap" "$rlfunc" || return 0 3685 local command=$ret 3686 3687 # recursive search 3688 local -a unbind_keys_list=() 3689 ble/builtin/bind/option:u/search-recursive "$kmap" 3690 3691 # unbind 3692 local keys 3693 for keys in "${unbind_keys_list[@]}"; do 3694 ble-decode-key/unbind "$kmap" "$keys" 3695 done 3696 } 3697 function ble/builtin/bind/option:u/search-recursive { 3698 local kmap=$1 tseq=$2 3699 local dicthead=_ble_decode_${kmap}_kmap_ 3700 local key keys 3701 builtin eval "keys=(\${!$dicthead$tseq[@]})" 3702 for key in "${keys[@]}"; do 3703 builtin eval "local ent=\${$dicthead$tseq[key]}" 3704 if [[ ${ent:2} == "$command" ]]; then 3705 ble/array#push unbind_keys_list "${tseq//_/ } $key" 3706 fi 3707 if [[ ${ent::1} == _ ]]; then 3708 ble/builtin/bind/option:u/search-recursive "$kmap" "${tseq}_$key" 3709 fi 3710 done 3711 } 3712 ## @fn ble/builtin/bind/option:- 3713 ## @var[in] opt_keymap 3714 function ble/builtin/bind/option:- { 3715 local ret; ble/string#trim "$1"; local arg=$ret 3716 3717 # Note (#D1820): これまで行の途中から始まるコメントを除去していたが、実際に 3718 # inputrc 色々書き込んで調べると特に無視されている訳では無い事が分かった。 3719 # なので、行頭に # がある場合にのみ処理を中断することにする。 3720 [[ ! $arg || $arg == '#'* ]] && return 0 3721 3722 # # コメント除去 (quote されていない "空白+#" 以降はコメント) 3723 # local q=\' ifs=$_ble_term_IFS 3724 # local rex='^(([^\"'$q$ifs']|"([^\"]|\\.)*"|'$q'([^\'$q']|\\.)*'$q'|\\.|['$ifs']+[^#'$_ifs'])*)['$ifs']+#' 3725 # [[ $arg =~ $rex ]] && arg=${BASH_REMATCH[1]} 3726 3727 local ifs=$_ble_term_IFS 3728 if [[ $arg == 'set'["$ifs"]* ]]; then 3729 if [[ $_ble_decode_bind_state != none ]]; then 3730 local variable= value= rex=$'^set[ \t]+([^ \t]+)[ \t]+([^ \t].*)$' 3731 [[ $arg =~ $rex ]] && variable=${BASH_REMATCH[1]} value=${BASH_REMATCH[2]} 3732 3733 case $variable in 3734 (keymap) 3735 ble/builtin/bind/set-keymap "$value" 3736 return 0 ;; 3737 (editing-mode) 3738 _ble_builtin_bind_keymap= ;; 3739 esac 3740 3741 ble/function#try ble/builtin/bind/set:"$variable" "$value" && return 0 3742 builtin bind "$arg" 3743 fi 3744 return 0 3745 fi 3746 3747 local keys value kmap 3748 if ! ble/builtin/bind/.initialize-keys-and-value "$arg"; then 3749 local q=\' Q="''\'" 3750 ble/util/print "ble.sh (bind): unrecognized readline command '${arg//$q/$Q}'." >&2 3751 flags=e$flags 3752 return 1 3753 elif ! ble/builtin/bind/.initialize-kmap "$opt_keymap"; then 3754 ble/util/print "ble.sh (bind): sorry, failed to initialize keymap:'$opt_keymap'." >&2 3755 flags=e$flags 3756 return 1 3757 fi 3758 3759 if [[ $value == \"* ]]; then 3760 # keyboard macro 3761 local bind_keys="${keys[*]}" 3762 value=${value#\"} value=${value%\"} 3763 local ret chars; ble/util/keyseq2chars "$value"; chars=("${ret[@]}") 3764 local command="ble/widget/.MACRO ${chars[*]}" 3765 ble/decode/cmap/decode-chars "${chars[@]}" 3766 [[ ${keys[*]} != "$bind_keys" ]] && 3767 ble-decode-key/bind "$kmap" "$bind_keys" "$command" 3768 elif [[ $value ]]; then 3769 local ret; ble/builtin/bind/rlfunc2widget "$kmap" "$value"; local ext=$? 3770 if ((ext==0)); then 3771 local command=$ret 3772 ble-decode-key/bind "$kmap" "${keys[*]}" "$command" 3773 return 0 3774 elif ((ext==2)); then 3775 return 0 3776 else 3777 flags=e$flags 3778 return 1 3779 fi 3780 else 3781 ble/util/print "ble.sh (bind): readline function name is not specified ($arg)." >&2 3782 return 1 3783 fi 3784 } 3785 function ble/builtin/bind/.process { 3786 flags= 3787 local IFS=$_ble_term_IFS 3788 local opt_literal= opt_keymap=$_ble_builtin_bind_keymap opt_print= 3789 local -a opt_queries=() 3790 while (($#)); do 3791 local arg=$1; shift 3792 if [[ ! $opt_literal ]]; then 3793 case $arg in 3794 (--) opt_literal=1 3795 continue ;; 3796 (--help) 3797 if ((_ble_bash<40400)); then 3798 ble/util/print "ble.sh (bind): unrecognized option $arg" >&2 3799 flags=e$flags 3800 else 3801 # Note: Bash-4.4, 5.0 のバグで unwind_frame が壊れているので 3802 # サブシェルで評価 #D0918 3803 # https://lists.gnu.org/archive/html/bug-bash/2019-02/msg00033.html 3804 [[ $_ble_decode_bind_state != none ]] && 3805 (builtin bind --help) 3806 flags=h$flags 3807 fi 3808 continue ;; 3809 (--*) 3810 ble/util/print "ble.sh (bind): unrecognized option $arg" >&2 3811 flags=e$flags 3812 continue ;; 3813 (-*) 3814 local i n=${#arg} c 3815 for ((i=1;i<n;i++)); do 3816 c=${arg:i:1} 3817 case $c in 3818 ([lpPsSvVX]) 3819 opt_print=$opt_print$c ;; 3820 ([mqurfx]) 3821 if ((!$#)); then 3822 ble/util/print "ble.sh (bind): missing option argument for -$c" >&2 3823 flags=e$flags 3824 else 3825 local optarg=$1; shift 3826 case $c in 3827 (m) ble/builtin/bind/option:m "$optarg" ;; 3828 (x) ble/builtin/bind/option:x "$optarg" ;; 3829 (r) ble/builtin/bind/option:r "$optarg" ;; 3830 (u) ble/builtin/bind/option:u "$optarg" ;; 3831 (q) ble/array#push opt_queries "$optarg" ;; 3832 (f) ble/decode/read-inputrc "$optarg" ;; 3833 (*) 3834 ble/util/print "ble.sh (bind): unsupported option -$c $optarg" >&2 3835 flags=e$flags ;; 3836 esac 3837 fi ;; 3838 (*) 3839 ble/util/print "ble.sh (bind): unrecognized option -$c" >&2 3840 flags=e$flags ;; 3841 esac 3842 done 3843 continue ;; 3844 esac 3845 fi 3846 3847 ble/builtin/bind/option:- "$arg" 3848 opt_literal=1 3849 done 3850 3851 if [[ $_ble_decode_bind_state != none ]]; then 3852 if [[ $opt_print == *[pPsSX]* ]] || ((${#opt_queries[@]})); then 3853 # Note: サブシェル内でバインディングを復元してから出力 3854 ( ble/decode/bind/unbind 3855 [[ -s "$_ble_base_run/$$.bind.save" ]] && 3856 source "$_ble_base_run/$$.bind.save" 3857 [[ $opt_print ]] && 3858 builtin bind ${opt_keymap:+-m $opt_keymap} -$opt_print 3859 declare rlfunc 3860 for rlfunc in "${opt_queries[@]}"; do 3861 builtin bind ${opt_keymap:+-m $opt_keymap} -q "$rlfunc" 3862 done ) 3863 elif [[ $opt_print ]]; then 3864 builtin bind ${opt_keymap:+-m $opt_keymap} -$opt_print 3865 fi 3866 fi 3867 3868 return 0 3869 } 3870 # inputrc の読み込み 3871 _ble_builtin_bind_inputrc_done= 3872 function ble/builtin/bind/initialize-inputrc { 3873 [[ $_ble_builtin_bind_inputrc_done ]] && return 0 3874 _ble_builtin_bind_inputrc_done=1 3875 3876 if [[ $1 == all ]]; then 3877 local sys_inputrc=/etc/inputrc 3878 [[ -e $sys_inputrc ]] && ble/decode/read-inputrc "$sys_inputrc" 3879 fi 3880 local inputrc=${INPUTRC:-$HOME/.inputrc} 3881 [[ -e $inputrc ]] && ble/decode/read-inputrc "$inputrc" 3882 } 3883 3884 # user 設定の読み込み 3885 _ble_builtin_bind_user_settings_loaded= 3886 function ble/builtin/bind/read-user-settings/.collect { 3887 local map 3888 for map in vi-insert vi-command emacs; do 3889 local cache=$_ble_base_cache/decode.readline.$_ble_bash.$map.txt 3890 if ! [[ -s $cache && $cache -nt $_ble_base/ble.sh ]]; then 3891 INPUTRC=/dev/null "$BASH" --noprofile --norc -i -c "builtin bind -m $map -p" | 3892 LC_ALL= LC_CTYPE=C ble/bin/sed '/^#/d;s/"\\M-/"\\e/' >| "$cache.part" && 3893 ble/bin/mv "$cache.part" "$cache" || continue 3894 fi 3895 local cache_content 3896 ble/util/readfile cache_content "$cache" 3897 3898 ble/util/print __CLEAR__ 3899 ble/util/print KEYMAP="$map" 3900 ble/util/print __BIND0__ 3901 ble/util/print "${cache_content%$_ble_term_nl}" 3902 if ((_ble_bash>=40300)); then 3903 ble/util/print __BINDX__ 3904 builtin bind -m "$map" -X 3905 fi 3906 ble/util/print __BINDS__ 3907 builtin bind -m "$map" -s 3908 ble/util/print __BINDP__ 3909 builtin bind -m "$map" -p 3910 ble/util/print __PRINT__ 3911 done 3912 } 3913 function ble/builtin/bind/read-user-settings/.reconstruct { 3914 local collect q=\' 3915 ble/util/assign collect ble/builtin/bind/read-user-settings/.collect 3916 <<< "$collect" LC_ALL= LC_CTYPE=C ble/bin/awk -v q="$q" -v _ble_bash="$_ble_bash" ' 3917 function keymap_register(key, val, type) { 3918 if (!haskey[key]) { 3919 keys[nkey++] = key; 3920 haskey[key] = 1; 3921 } 3922 keymap[key] = val; 3923 keymap_type[key] = type; 3924 } 3925 function keymap_clear(_, i, key) { 3926 for(i = 0; i < nkey; i++) { 3927 key = keys[i]; 3928 delete keymap[key]; 3929 delete keymap_type[key]; 3930 delete keymap0[key]; 3931 haskey[key] = 0; 3932 } 3933 nkey = 0; 3934 } 3935 function keymap_print(_, i, key, type, value, text, line) { 3936 for (i = 0; i < nkey; i++) { 3937 key = keys[i]; 3938 type = keymap_type[key]; 3939 value = keymap[key]; 3940 if (type == "" && value == keymap0[key]) continue; 3941 3942 text = key ": " value; 3943 gsub(/'$q'/, q "\\" q q, text); 3944 3945 line = "bind"; 3946 if (KEYMAP != "") line = line " -m " KEYMAP; 3947 if (type == "x") line = line " -x"; 3948 line = line " " q text q; 3949 print line; 3950 } 3951 } 3952 3953 /^__BIND0__$/ { mode = 0; next; } 3954 /^__BINDX__$/ { mode = 1; next; } 3955 /^__BINDS__$/ { mode = 2; next; } 3956 /^__BINDP__$/ { mode = 3; next; } 3957 /^__CLEAR__$/ { keymap_clear(); next; } 3958 /^__PRINT__$/ { keymap_print(); next; } 3959 sub(/^KEYMAP=/, "") { KEYMAP = $0; } 3960 3961 /ble-decode\/.hook / { next; } 3962 3963 function workaround_bashbug(keyseq, _, rex, out, unit) { 3964 out = ""; 3965 while (keyseq != "") { 3966 if (mode == 0 || mode == 3) { 3967 match(keyseq, /^\\C-\\(\\"$)?|^\\M-|^\\.|^./); 3968 } else { 3969 #% # bind -X, bind -s には問題はない 3970 match(keyseq, /^\\[CM]-|^\\.|^./); 3971 } 3972 unit = substr(keyseq, 1, RLENGTH); 3973 keyseq = substr(keyseq, 1 + RLENGTH); 3974 3975 if (unit == "\\C-\\") { 3976 #% # Bash 3.0--5.0 Bug https://lists.gnu.org/archive/html/bug-bash/2020-01/msg00037.html 3977 unit = unit "\\"; 3978 } else if (unit == "\\M-") { 3979 #% # Bash 3.1 以下では ESC は \M- と出力される 3980 unit = "\\e"; 3981 } 3982 out = out unit; 3983 } 3984 return out; 3985 } 3986 3987 match($0, /^"(\\.|[^"])+": /) { 3988 key = substr($0, 1, RLENGTH - 2); 3989 val = substr($0, 1 + RLENGTH); 3990 if (_ble_bash < 50100) 3991 key = workaround_bashbug(key); 3992 if (mode) { 3993 type = mode == 1 ? "x" : mode == 2 ? "s" : ""; 3994 keymap_register(key, val, type); 3995 } else { 3996 keymap0[key] = val; 3997 } 3998 } 3999 ' 2>/dev/null # suppress LC_ALL error messages 4000 } 4001 4002 ## @fn ble/builtin/bind/read-user-settings/.cache-enabled 4003 ## @var[in] delay_prefix 4004 function ble/builtin/bind/read-user-settings/.cache-enabled { 4005 local keymap use_cache=1 4006 for keymap in emacs vi_imap vi_nmap; do 4007 ble/decode/keymap#registered "$keymap" && return 1 4008 [[ -s $delay_prefix.$keymap ]] && return 1 4009 done 4010 return 0 4011 } 4012 ## @fn ble/builtin/bind/read-user-settings/.cache-alive 4013 ## @var[in] settings 4014 ## @var[in] cache_prefix 4015 function ble/builtin/bind/read-user-settings/.cache-alive { 4016 [[ -e $cache_prefix.settings ]] || return 1 4017 [[ $cache_prefix.settings -nt $_ble_base/lib/init-cmap.sh ]] || return 1 4018 local keymap 4019 for keymap in emacs vi_imap vi_nmap; do 4020 [[ $cache_prefix.settings -nt $_ble_base/core-decode.$cache-rlfunc.txt ]] || return 1 4021 [[ -e $cache_prefix.$keymap ]] || return 1 4022 done 4023 local content 4024 ble/util/readfile content "$cache_prefix.settings" 4025 [[ ${content%$'\n'} == "$settings" ]] 4026 } 4027 ## @fn ble/builtin/bind/read-user-settings/.cache-save 4028 ## @var[in] delay_prefix 4029 ## @var[in] cache_prefix 4030 function ble/builtin/bind/read-user-settings/.cache-save { 4031 local keymap content fail= 4032 for keymap in emacs vi_imap vi_nmap; do 4033 if [[ -s $delay_prefix.$keymap ]]; then 4034 ble/util/copyfile "$delay_prefix.$keymap" "$cache_prefix.$keymap" 4035 else 4036 : >| "$cache_prefix.$keymap" 4037 fi || fail=1 4038 done 4039 [[ $fail ]] && return 1 4040 ble/util/print "$settings" >| "$cache_prefix.settings" 4041 } 4042 ## @fn ble/builtin/bind/read-user-settings/.cache-load 4043 ## @var[in] delay_prefix 4044 ## @var[in] cache_prefix 4045 function ble/builtin/bind/read-user-settings/.cache-load { 4046 local keymap 4047 for keymap in emacs vi_imap vi_nmap; do 4048 ble/util/copyfile "$cache_prefix.$keymap" "$delay_prefix.$keymap" 4049 done 4050 } 4051 4052 function ble/builtin/bind/read-user-settings { 4053 if [[ $_ble_decode_bind_state == none ]]; then 4054 [[ $_ble_builtin_bind_user_settings_loaded ]] && return 0 4055 _ble_builtin_bind_user_settings_loaded=1 4056 builtin bind # inputrc を読ませる 4057 local settings 4058 ble/util/assign settings ble/builtin/bind/read-user-settings/.reconstruct 4059 [[ $settings ]] || return 0 4060 4061 local cache_prefix=$_ble_base_cache/decode.inputrc.$_ble_decode_kbd_ver.$TERM 4062 local delay_prefix=$_ble_base_run/$$.bind.delay 4063 if ble/builtin/bind/read-user-settings/.cache-enabled; then 4064 if ble/builtin/bind/read-user-settings/.cache-alive; then 4065 ble/builtin/bind/read-user-settings/.cache-load 4066 else 4067 builtin eval -- "$settings" 4068 ble/builtin/bind/read-user-settings/.cache-save 4069 fi 4070 else 4071 builtin eval -- "$settings" 4072 fi 4073 fi 4074 } 4075 4076 function ble/builtin/bind { 4077 local set shopt; ble/base/.adjust-bash-options set shopt 4078 4079 [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] && 4080 ble/base/adjust-BASH_REMATCH 4081 4082 ble/decode/initialize 4083 local flags= ext=0 4084 ble/builtin/bind/.process "$@" 4085 if [[ $_ble_decode_bind_state == none ]]; then 4086 builtin bind "$@"; ext=$? 4087 elif [[ $flags == *[eh]* ]]; then 4088 [[ $flags == *e* ]] && 4089 builtin bind --usage 2>&1 1>/dev/null | ble/bin/grep ^bind >&2 4090 ext=2 4091 fi 4092 4093 [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] && 4094 ble/base/restore-BASH_REMATCH 4095 ble/base/.restore-bash-options set shopt 4096 return "$ext" 4097 } 4098 function bind { ble/builtin/bind "$@"; } 4099 4100 #------------------------------------------------------------------------------ 4101 # ble/decode/initialize, attach, detach @decode.attach 4102 4103 function ble/decode/initialize/.has-broken-suse-inputrc { 4104 # 1. Check if this is openSUSE and has /etc/input.keys. 4105 local content= 4106 [[ -s /etc/inputrc.keys && -r /etc/os-release ]] && 4107 ble/util/readfile content /etc/os-release && 4108 [[ $content == *'openSUSE'* ]] || return 1 4109 4110 # Note #1926: Even after the fix 4111 # https://github.com/openSUSE/aaa_base/pull/84, "inputrc.keys" causes 4112 # problems through extra bindings of the [home]/[end] escape sequences to 4113 # [prior], [Enter] to "accept-line", etc. Thus, we comment out the following 4114 # part of codes and always return 0 when there is "/etc/inputrc.keys". 4115 4116 # 2. Check if the file "inputrc.keys" has the bug. 4117 # ((_ble_bash<50000)) || return 1 # Bash 5.0+ are not suffered 4118 # ble/util/readfile content /etc/inputrc.keys && 4119 # [[ $content == *'"\M-[2~":'* ]] || return 1 4120 4121 return 0 4122 } 4123 4124 _ble_decode_initialized= 4125 _ble_decode_initialize_inputrc=auto 4126 function ble/decode/initialize { 4127 [[ $_ble_decode_initialized ]] && return 0 4128 _ble_decode_initialized=1 4129 ble/decode/cmap/initialize 4130 4131 if [[ $_ble_decode_initialize_inputrc == auto ]]; then 4132 if ble/decode/initialize/.has-broken-suse-inputrc; then 4133 # Note: #D1662 WA openSUSE (aaa_base < 202102) has broken /etc/inputrc 4134 [[ ${INPUTRC-} == /etc/inputrc || ${INPUTRC-} == /etc/inputrc.keys ]] && 4135 local INPUTRC=~/.inputrc 4136 _ble_decode_initialize_inputrc=user 4137 else 4138 _ble_decode_initialize_inputrc=diff 4139 fi 4140 fi 4141 case $_ble_decode_initialize_inputrc in 4142 (all) 4143 ble/builtin/bind/initialize-inputrc all ;; 4144 (user) 4145 ble/builtin/bind/initialize-inputrc ;; 4146 (diff) 4147 ble/builtin/bind/read-user-settings ;; 4148 esac 4149 } 4150 4151 function ble/decode/reset-default-keymap { 4152 # 現在の ble-decode/keymap の設定 4153 local old_base_keymap=${_ble_decode_keymap_stack[0]:-$_ble_decode_keymap} 4154 ble-decode/INITIALIZE_DEFMAP -v _ble_decode_keymap # 0ms 4155 _ble_decode_keymap_stack=() 4156 if [[ $_ble_decode_keymap != "$old_base_keymap" ]]; then 4157 [[ $old_base_keymap ]] && 4158 _ble_decode_keymap=$old_base_keymap ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_DETACH" 4159 ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_ATTACH" # 7ms for vi-mode 4160 4161 # update cursor 4162 local cursor; ble/decode/keymap#get-cursor "$_ble_decode_keymap" 4163 [[ $cursor ]] && ble/term/cursor-state/set-internal "$((cursor))" 4164 fi 4165 } 4166 4167 ## @fn ble/decode/attach 4168 ## @var[in] _ble_decode_keymap 4169 ## この関数を呼び出す前に ble/decode/reset-default-keymap を用いて 4170 ## _ble_decode_keymap が使用可能な状態になっている必要がある。 4171 function ble/decode/attach { 4172 # 失敗すると悲惨なことになるのでチェック 4173 if ble/decode/keymap#is-empty "$_ble_decode_keymap"; then 4174 ble/util/print "ble.sh: The keymap '$_ble_decode_keymap' is empty." >&2 4175 return 1 4176 fi 4177 4178 [[ $_ble_decode_bind_state != none ]] && return 0 4179 ble/util/save-editing-mode _ble_decode_bind_state 4180 [[ $_ble_decode_bind_state == none ]] && return 1 4181 4182 # bind/unbind 中に C-c で中断されると大変なので先に stty を設定する必要がある 4183 ble/term/initialize # 3ms 4184 4185 # 既定の keymap に戻す 4186 ble/util/reset-keymap-of-editing-mode 4187 4188 # 元のキー割り当ての保存・unbind 4189 builtin eval -- "$(ble/decode/bind/.generate-source-to-unbind-default)" # 21ms 4190 4191 # ble.sh bind の設置 4192 ble/decode/bind/bind # 20ms 4193 4194 case $TERM in 4195 (linux) 4196 # Note #D1213: linux コンソール (kernel 5.0.0) は "\e[>" 4197 # でエスケープシーケンスを閉じてしまう。5.4.8 は大丈夫。 4198 _ble_term_TERM=linux:- ;; 4199 (st|st-*) 4200 # st の unknown csi sequence メッセージに対して文句を言う人がいた。 4201 # st は TERM で判定できるので DA2 はスキップできる。 4202 _ble_term_TERM=st:- ;; 4203 (*) 4204 ble/util/buffer $'\e[>c' # DA2 要求 (ble-decode-char/csi/.decode で受信) 4205 esac 4206 return 0 4207 } 4208 4209 function ble/decode/detach { 4210 [[ $_ble_decode_bind_state != none ]] || return 1 4211 4212 local current_editing_mode= 4213 ble/util/save-editing-mode current_editing_mode 4214 [[ $_ble_decode_bind_state == "$current_editing_mode" ]] || ble/util/restore-editing-mode _ble_decode_bind_state 4215 4216 ble/term/finalize 4217 4218 # ble.sh bind の削除 4219 ble/decode/bind/unbind 4220 4221 # 元のキー割り当ての復元 4222 if [[ -s "$_ble_base_run/$$.bind.save" ]]; then 4223 source "$_ble_base_run/$$.bind.save" 4224 : >| "$_ble_base_run/$$.bind.save" 4225 fi 4226 4227 [[ $_ble_decode_bind_state == "$current_editing_mode" ]] || ble/util/restore-editing-mode current_editing_mode 4228 4229 _ble_decode_bind_state=none 4230 } 4231 4232 #------------------------------------------------------------------------------ 4233 # **** encoding = UTF-8 **** 4234 4235 function ble/encoding:UTF-8/generate-binder { :; } 4236 4237 # 以下は lib/init-bind.sh の中にある物と等価なので殊更に設定しなくて良い。 4238 4239 # ## @fn ble/encoding:UTF-8/generate-binder 4240 # ## lib/init-bind.sh の esc1B==3 の設定用。 4241 # ## lib/init-bind.sh の中から呼び出される。 4242 # function ble/encoding:UTF-8/generate-binder { 4243 # ble/init:bind/bind-s '"\C-@":"\xC0\x80"' 4244 # ble/init:bind/bind-s '"\e":"\xDF\xBF"' # isolated ESC (U+07FF) 4245 # local i ret 4246 # for i in {0..255}; do 4247 # ble/decode/c2dqs "$i" 4248 # ble/init:bind/bind-s "\"\e$ret\": \"\xC0\x9B$ret\"" 4249 # done 4250 # } 4251 4252 _ble_encoding_utf8_decode_mode=0 4253 _ble_encoding_utf8_decode_code=0 4254 _ble_encoding_utf8_decode_table=( 4255 'M&&E,A[i++]='{0..127} 4256 'C=C<<6|'{0..63}',--M==0&&(A[i++]=C)' 4257 'M&&E,C='{0..31}',M=1' 4258 'M&&E,C='{0..15}',M=2' 4259 'M&&E,C='{0..7}',M=3' 4260 'M&&E,C='{0..3}',M=4' 4261 'M&&E,C='{0..1}',M=5' 4262 'M&&E,A[i++]=_ble_decode_Erro|'{254,255} 4263 ) 4264 function ble/encoding:UTF-8/clear { 4265 _ble_encoding_utf8_decode_mode=0 4266 _ble_encoding_utf8_decode_code=0 4267 } 4268 function ble/encoding:UTF-8/is-intermediate { 4269 ((_ble_encoding_utf8_decode_mode)) 4270 } 4271 function ble/encoding:UTF-8/decode { 4272 local C=$_ble_encoding_utf8_decode_code 4273 local M=$_ble_encoding_utf8_decode_mode 4274 local E='M=0,A[i++]=_ble_decode_Erro|C' 4275 local -a A=() 4276 local i=0 b 4277 for b; do 4278 ((_ble_encoding_utf8_decode_table[b&255])) 4279 done 4280 _ble_encoding_utf8_decode_code=$C 4281 _ble_encoding_utf8_decode_mode=$M 4282 ((i)) && ble-decode-char "${A[@]}" 4283 } 4284 4285 ## @fn ble/encoding:UTF-8/c2bc code 4286 ## @param[in] code 4287 ## @var [out] ret 4288 function ble/encoding:UTF-8/c2bc { 4289 local code=$1 4290 ((ret=code<0x80?1: 4291 (code<0x800?2: 4292 (code<0x10000?3: 4293 (code<0x200000?4:5))))) 4294 } 4295 4296 ## @fn ble/encoding:C/generate-binder 4297 ## lib/init-bind.sh の esc1B==3 の設定用。 4298 ## lib/init-bind.sh の中から呼び出される。 4299 function ble/encoding:C/generate-binder { 4300 ble/init:bind/bind-s '"\C-@":"\x9B\x80"' 4301 ble/init:bind/bind-s '"\e":"\x9B\x8B"' # isolated ESC (U+07FF) 4302 local i ret 4303 for i in {0..255}; do 4304 ble/decode/c2dqs "$i" 4305 ble/init:bind/bind-s "\"\e$ret\": \"\x9B\x9B$ret\"" 4306 done 4307 } 4308 4309 ## @fn ble/encoding:C/decode byte 4310 ## 4311 ## 受け取ったバイトをそのまま文字コードと解釈する。 4312 ## 但し、bind の都合 (bashbug の回避) により以下の変換を行う。 4313 ## 4314 ## \x9B\x80 (155 128) → C-@ 4315 ## \x9B\x8B (155 139) → isolated ESC \u07FF (2047) 4316 ## \x9B\x9B (155 155) → ESC 4317 ## 4318 ## 実際にこの組み合わせの入力が来ると誤変換されるが、 4319 ## この組み合わせは不正な CSI シーケンスなので、 4320 ## 入力に混入した時の動作は元々保証外である。 4321 ## 4322 _ble_encoding_c_csi= 4323 function ble/encoding:C/clear { 4324 _ble_encoding_c_csi= 4325 } 4326 function ble/encoding:C/is-intermediate { 4327 [[ $_ble_encoding_c_csi ]] 4328 } 4329 function ble/encoding:C/decode { 4330 local -a A=() 4331 local i=0 b 4332 for b; do 4333 if [[ $_ble_encoding_c_csi ]]; then 4334 _ble_encoding_c_csi= 4335 case $b in 4336 (155) A[i++]=27 # ESC 4337 continue ;; 4338 (139) A[i++]=2047 # isolated ESC 4339 continue ;; 4340 (128) A[i++]=0 # C-@ 4341 continue ;; 4342 esac 4343 A[i++]=155 4344 fi 4345 4346 if ((b==155)); then 4347 _ble_encoding_c_csi=1 4348 else 4349 A[i++]=$b 4350 fi 4351 done 4352 ((i)) && ble-decode-char "${A[@]}" 4353 } 4354 4355 ## @fn ble/encoding:C/c2bc charcode 4356 ## @var[out] ret 4357 function ble/encoding:C/c2bc { 4358 ret=1 4359 }