summaryrefslogtreecommitdiff
path: root/.local/src/blesh
diff options
context:
space:
mode:
Diffstat (limited to '.local/src/blesh')
-rw-r--r--.local/src/blesh/ble.sh23963
-rw-r--r--.local/src/blesh/contrib/airline/atomic.bash42
-rw-r--r--.local/src/blesh/contrib/airline/dark.bash30
-rw-r--r--.local/src/blesh/contrib/airline/dark_minimal.bash13
-rw-r--r--.local/src/blesh/contrib/airline/google_dark.bash28
-rw-r--r--.local/src/blesh/contrib/airline/google_light.bash28
-rw-r--r--.local/src/blesh/contrib/airline/landscape.bash34
-rw-r--r--.local/src/blesh/contrib/airline/light.bash29
-rw-r--r--.local/src/blesh/contrib/airline/minimalist.bash31
-rw-r--r--.local/src/blesh/contrib/airline/monochrome.bash22
-rw-r--r--.local/src/blesh/contrib/airline/solarized.bash33
-rw-r--r--.local/src/blesh/contrib/airline/solarized_flood.bash49
-rw-r--r--.local/src/blesh/contrib/airline/term.bash38
-rw-r--r--.local/src/blesh/contrib/airline/term_light.bash38
-rw-r--r--.local/src/blesh/contrib/airline/transparent.bash33
-rw-r--r--.local/src/blesh/contrib/airline/xtermlight.bash29
-rw-r--r--.local/src/blesh/contrib/bash-preexec.bash154
-rw-r--r--.local/src/blesh/contrib/config/execmark.bash111
-rw-r--r--.local/src/blesh/contrib/fzf-completion.bash49
-rw-r--r--.local/src/blesh/contrib/fzf-git.bash110
-rw-r--r--.local/src/blesh/contrib/fzf-initialize.bash52
-rw-r--r--.local/src/blesh/contrib/fzf-key-bindings.bash54
-rw-r--r--.local/src/blesh/contrib/prompt-defer.bash150
-rw-r--r--.local/src/blesh/contrib/prompt-elapsed.bash91
-rw-r--r--.local/src/blesh/contrib/prompt-git.bash250
-rw-r--r--.local/src/blesh/contrib/prompt-vim-mode.bash20
-rw-r--r--.local/src/blesh/doc/CONTRIBUTING.md119
-rw-r--r--.local/src/blesh/doc/ChangeLog.md2702
-rw-r--r--.local/src/blesh/doc/LICENSE.md12
-rw-r--r--.local/src/blesh/doc/README-ja_JP.md563
-rw-r--r--.local/src/blesh/doc/README.md538
-rw-r--r--.local/src/blesh/doc/Release.md238
-rw-r--r--.local/src/blesh/doc/contrib/LICENSE28
-rw-r--r--.local/src/blesh/doc/contrib/README-ja.md97
-rw-r--r--.local/src/blesh/doc/contrib/README.md172
-rw-r--r--.local/src/blesh/keymap/emacs.sh163
-rw-r--r--.local/src/blesh/keymap/vi.sh6171
-rw-r--r--.local/src/blesh/keymap/vi_digraph.sh51
-rw-r--r--.local/src/blesh/keymap/vi_digraph.txt1304
-rw-r--r--.local/src/blesh/keymap/vi_test.sh363
-rw-r--r--.local/src/blesh/lib/core-cmdspec.sh66
-rw-r--r--.local/src/blesh/lib/core-complete.sh6327
-rw-r--r--.local/src/blesh/lib/core-decode.emacs-rlfunc.txt170
-rw-r--r--.local/src/blesh/lib/core-decode.vi_imap-rlfunc.txt169
-rw-r--r--.local/src/blesh/lib/core-decode.vi_nmap-rlfunc.txt170
-rw-r--r--.local/src/blesh/lib/core-edit.ignoreeof-messages.txt32
-rw-r--r--.local/src/blesh/lib/core-syntax.sh5355
-rw-r--r--.local/src/blesh/lib/core-test.sh200
-rw-r--r--.local/src/blesh/lib/init-bind.sh92
-rw-r--r--.local/src/blesh/lib/init-cmap.sh186
-rw-r--r--.local/src/blesh/lib/init-msys1.sh130
-rw-r--r--.local/src/blesh/lib/init-term.sh228
-rw-r--r--.local/src/blesh/lib/test-canvas.sh479
-rw-r--r--.local/src/blesh/lib/test-complete.sh28
-rw-r--r--.local/src/blesh/lib/test-decode.sh39
-rw-r--r--.local/src/blesh/lib/test-edit.sh8
-rw-r--r--.local/src/blesh/lib/test-main.sh79
-rw-r--r--.local/src/blesh/lib/test-syntax.sh39
-rw-r--r--.local/src/blesh/lib/test-util.sh1555
-rw-r--r--.local/src/blesh/lib/vim-airline.sh306
-rw-r--r--.local/src/blesh/lib/vim-arpeggio.sh48
-rw-r--r--.local/src/blesh/lib/vim-surround.sh551
62 files changed, 54259 insertions, 0 deletions
diff --git a/.local/src/blesh/ble.sh b/.local/src/blesh/ble.sh
new file mode 100644
index 0000000..f16d91b
--- /dev/null
+++ b/.local/src/blesh/ble.sh
@@ -0,0 +1,23963 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+{
+_ble_init_version=0.4.0-devel3+a4a779e
+ _ble_init_exit=
+ _ble_init_command=
+ for _ble_init_arg; do
+ case $_ble_init_arg in
+ --version)
+ _ble_init_exit=0
+ echo "ble.sh (Bash Line Editor), version $_ble_init_version" ;;
+ --help)
+ _ble_init_exit=0
+ printf '%s\n' \
+ "# ble.sh (Bash Line Editor), version $_ble_init_version" \
+ 'usage: source ble.sh [OPTION...]' \
+ '' \
+ 'OPTION' \
+ '' \
+ ' --help' \
+ ' Show this help and exit' \
+ ' --version' \
+ ' Show version and exit' \
+ ' --test' \
+ ' Run test and exit' \
+ ' --update' \
+ ' Update ble.sh and exit' \
+ ' --clear-cache' \
+ ' Clear ble.sh cache and exit' \
+ '' \
+ ' --rcfile=BLERC' \
+ ' --init-file=BLERC' \
+ ' Specify the ble init file. The default is ~/.blerc.' \
+ '' \
+ ' --norc' \
+ ' Do not load the ble init file.' \
+ '' \
+ ' --attach=ATTACH' \
+ ' --noattach' \
+ ' The option "--attach" selects the strategy of "ble-attach" from the' \
+ ' list: ATTACH = "attach" | "prompt" | "none". The default strategy is' \
+ ' "prompt". The option "--noattach" is a synonym for "--attach=none".' \
+ '' \
+ ' --noinputrc' \
+ ' Do not read inputrc settings for ble.sh' \
+ '' \
+ ' --keep-rlvars' \
+ ' Do not change readline settings for ble.sh' \
+ '' \
+ ' -o BLEOPT=VALUE' \
+ ' Set a value for the specified bleopt option.' \
+ ' --debug-bash-output' \
+ ' Internal settings for debugging' \
+ '' ;;
+ --test | --update | --clear-cache) _ble_init_command=1 ;;
+ esac
+ done
+ if [ -n "$_ble_init_exit" ]; then
+ unset _ble_init_version
+ unset _ble_init_arg
+ unset _ble_init_exit
+ unset _ble_init_command
+ return 0 2>/dev/null || exit 0
+ fi
+} 2>/dev/null # set -x 対策 #D0930
+if [ -z "${BASH_VERSION-}" ]; then
+ echo "ble.sh: This shell is not Bash. Please use this script with Bash." >&3
+ return 1 2>/dev/null || exit 1
+fi 3>&2 >/dev/null 2>&1 # set -x 対策 #D0930
+if [ -z "${BASH_VERSINFO-}" ] || [ "${BASH_VERSINFO-0}" -lt 3 ]; then
+ echo "ble.sh: Bash with a version under 3.0 is not supported." >&3
+ return 1 2>/dev/null || exit 1
+fi 3>&2 >/dev/null 2>&1 # set -x 対策 #D0930
+if [[ ! $_ble_init_command ]]; then
+ if [[ ${BASH_EXECUTION_STRING+set} ]]; then
+ return 1 2>/dev/null || builtin exit 1
+ fi
+ if ((BASH_SUBSHELL)); then
+ builtin echo "ble.sh: ble.sh cannot be loaded into a subshell." >&3
+ return 1 2>/dev/null || builtin exit 1
+ elif [[ $- != *i* ]]; then
+ case " ${BASH_SOURCE[*]##*/} " in
+ (*' .bashrc '* | *' .bash_profile '* | *' .profile '* | *' bashrc '* | *' profile '*) false ;;
+ esac &&
+ builtin echo "ble.sh: This is not an interactive session." >&3 || ((1))
+ return 1 2>/dev/null || builtin exit 1
+ elif ! [[ -t 0 && -t 1 ]] && ! ((1)) >/dev/tty; then
+ builtin echo "ble.sh: cannot find a controlling TTY/PTY in this session." >&3
+ return 1 2>/dev/null || builtin exit 1
+ fi
+fi 3>&2 &>/dev/null # set -x 対策 #D0930
+{
+ _ble_bash_POSIXLY_CORRECT_adjusted=1
+ _ble_bash_POSIXLY_CORRECT_set=${POSIXLY_CORRECT+set}
+ _ble_bash_POSIXLY_CORRECT=${POSIXLY_CORRECT-}
+ POSIXLY_CORRECT=y
+ _ble_bash_expand_aliases=
+ \shopt -q expand_aliases &&
+ _ble_bash_expand_aliases=1 &&
+ \shopt -u expand_aliases || ((1))
+ _ble_bash_FUNCNEST_adjusted=
+ _ble_bash_FUNCNEST=
+ _ble_bash_FUNCNEST_set=
+ _ble_bash_FUNCNEST_adjust='
+ if [[ ! $_ble_bash_FUNCNEST_adjusted ]]; then
+ _ble_bash_FUNCNEST_adjusted=1
+ _ble_bash_FUNCNEST_set=${FUNCNEST+set}
+ _ble_bash_FUNCNEST=${FUNCNEST-}
+ builtin unset -v FUNCNEST
+ fi 2>/dev/null'
+ _ble_bash_FUNCNEST_restore='
+ if [[ $_ble_bash_FUNCNEST_adjusted ]]; then
+ _ble_bash_FUNCNEST_adjusted=
+ if [[ $_ble_bash_FUNCNEST_set ]]; then
+ FUNCNEST=$_ble_bash_FUNCNEST
+ else
+ builtin unset -v FUNCNEST
+ fi
+ fi 2>/dev/null'
+ \builtin eval -- "$_ble_bash_FUNCNEST_adjust"
+ \builtin unset -v POSIXLY_CORRECT
+} 2>/dev/null
+function ble/base/workaround-POSIXLY_CORRECT {
+ true
+}
+function ble/base/unset-POSIXLY_CORRECT {
+ if [[ ${POSIXLY_CORRECT+set} ]]; then
+ builtin unset -v POSIXLY_CORRECT
+ ble/base/workaround-POSIXLY_CORRECT
+ fi
+}
+function ble/base/adjust-POSIXLY_CORRECT {
+ if [[ $_ble_bash_POSIXLY_CORRECT_adjusted ]]; then return 0; fi # Note: set -e 対策
+ _ble_bash_POSIXLY_CORRECT_adjusted=1
+ _ble_bash_POSIXLY_CORRECT_set=${POSIXLY_CORRECT+set}
+ _ble_bash_POSIXLY_CORRECT=${POSIXLY_CORRECT-}
+ if [[ $_ble_bash_POSIXLY_CORRECT_set ]]; then
+ builtin unset -v POSIXLY_CORRECT
+ fi
+ ble/base/workaround-POSIXLY_CORRECT
+}
+function ble/base/restore-POSIXLY_CORRECT {
+ if [[ ! $_ble_bash_POSIXLY_CORRECT_adjusted ]]; then return 0; fi # Note: set -e の為 || は駄目
+ _ble_bash_POSIXLY_CORRECT_adjusted=
+ if [[ $_ble_bash_POSIXLY_CORRECT_set ]]; then
+ POSIXLY_CORRECT=$_ble_bash_POSIXLY_CORRECT
+ else
+ ble/base/unset-POSIXLY_CORRECT
+ fi
+}
+function ble/base/is-POSIXLY_CORRECT {
+ if [[ $_ble_bash_POSIXLY_CORRECT_adjusted ]]; then
+ [[ $_ble_bash_POSIXLY_CORRECT_set ]]
+ else
+ [[ ${POSIXLY_CORRECT+set} ]]
+ fi
+}
+{
+ _ble_bash_builtins_adjusted=
+ _ble_bash_builtins_save=
+} 2>/dev/null # set -x 対策
+function ble/base/adjust-builtin-wrappers/.assign {
+ if [[ ${_ble_util_assign_base-} ]]; then
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$1" >| "$_ble_local_tmpfile"
+ IFS= builtin read -r -d '' defs < "$_ble_local_tmpfile"
+ ble/util/assign/.rmtmp
+ else
+ defs=$(builtin eval -- "$1")
+ fi || ((1))
+}
+function ble/base/adjust-builtin-wrappers-1 {
+ unset -f builtin
+ builtin local POSIXLY_CORRECT=y builtins1 keywords1
+ builtins1=(builtin unset enable unalias return break continue declare local typeset readonly eval exec set)
+ keywords1=(if then elif else case esac while until for select do done '{' '}' '[[' function)
+ if [[ ! $_ble_bash_builtins_adjusted ]]; then
+ _ble_bash_builtins_adjusted=1
+ builtin local defs
+ ble/base/adjust-builtin-wrappers/.assign '
+ \builtin declare -f "${builtins1[@]}" || ((1))
+ \builtin alias "${builtins1[@]}" "${keywords1[@]}" || ((1))' # set -e 対策
+ _ble_bash_builtins_save=$defs
+ fi
+ builtin unset -f "${builtins1[@]}"
+ builtin unalias "${builtins1[@]}" "${keywords1[@]}" || ((1)) # set -e 対策
+ ble/base/unset-POSIXLY_CORRECT
+} 2>/dev/null
+function ble/base/adjust-builtin-wrappers-2 {
+ local defs
+ ble/base/adjust-builtin-wrappers/.assign 'LC_ALL= LC_MESSAGES=C builtin type :; alias :' || ((1)) # set -e 対策
+ defs=${defs#$': is a function\n'}
+ _ble_bash_builtins_save=$_ble_bash_builtins_save$'\n'$defs
+ builtin unset -f :
+ builtin unalias : || ((1)) # set -e 対策
+} 2>/dev/null
+function ble/base/restore-builtin-wrappers {
+ if [[ $_ble_bash_builtins_adjusted ]]; then
+ _ble_bash_builtins_adjusted=
+ builtin eval -- "$_ble_bash_builtins_save"
+ fi
+}
+{
+ ble/base/adjust-builtin-wrappers-1
+ ble/base/adjust-builtin-wrappers-2
+ if [[ $_ble_bash_expand_aliases ]]; then
+ shopt -s expand_aliases
+ fi
+} 2>/dev/null # set -x 対策
+function ble/variable#copy-state {
+ local src=$1 dst=$2
+ if [[ ${!src+set} ]]; then
+ builtin eval -- "$dst=\${$src}"
+ else
+ builtin unset -v "$dst[0]" 2>/dev/null || builtin unset -v "$dst"
+ fi
+}
+function ble/base/.adjust-bash-options {
+ builtin eval -- "$1=\$-"
+ set +exvukT -B
+ [[ $2 == shopt ]] || local shopt
+ if ((_ble_bash>=40100)); then
+ shopt=$BASHOPTS
+ else
+ shopt=
+ shopt -q extdebug 2>/dev/null && shopt=$shopt:extdebug
+ shopt -q nocasematch 2>/dev/null && shopt=$shopt:nocasematch
+ fi
+ [[ $2 == shopt ]] || builtin eval -- "$2=\$shopt"
+ shopt -u extdebug
+ shopt -u nocasematch 2>/dev/null
+ return 0
+} 2>/dev/null # set -x 対策
+function ble/base/.restore-bash-options {
+ local set=${!1} shopt=${!2}
+ [[ :$shopt: == *:nocasematch:* ]] && shopt -s nocasematch
+ [[ :$shopt: == *:extdebug:* ]] && shopt -s extdebug
+ [[ $set == *B* ]] || set +B
+ [[ $set == *T* ]] && set -T
+ [[ $set == *k* ]] && set -k
+ [[ $set == *u* ]] && set -u
+ [[ $set == *v* ]] && set -v
+ [[ $set == *x* ]] && set -x
+ [[ $set == *e* ]] && set -e # set -e は最後
+ return 0
+} 2>/dev/null # set -x 対策
+{
+ : "${_ble_bash_options_adjusted=}"
+ _ble_bash_set=$-
+ _ble_bash_shopt=${BASHOPTS-}
+} 2>/dev/null # set -x 対策
+function ble/base/adjust-bash-options {
+ [[ $_ble_bash_options_adjusted ]] && return 1 || ((1)) # set -e 対策
+ _ble_bash_options_adjusted=1
+ ble/base/.adjust-bash-options _ble_bash_set _ble_bash_shopt
+ _ble_bash_expand_aliases=
+ shopt -q expand_aliases 2>/dev/null &&
+ _ble_bash_expand_aliases=1
+ ble/variable#copy-state LC_ALL _ble_bash_LC_ALL
+ if [[ ${LC_ALL-} ]]; then
+ ble/variable#copy-state LC_CTYPE _ble_bash_LC_CTYPE
+ ble/variable#copy-state LC_MESSAGES _ble_bash_LC_MESSAGES
+ ble/variable#copy-state LC_NUMERIC _ble_bash_LC_NUMERIC
+ ble/variable#copy-state LC_TIME _ble_bash_LC_TIME
+ ble/variable#copy-state LANG _ble_bash_LANG
+ [[ ${LC_CTYPE-} ]] && LC_CTYPE=$LC_ALL
+ [[ ${LC_MESSAGES-} ]] && LC_MESSAGES=$LC_ALL
+ [[ ${LC_NUMERIC-} ]] && LC_NUMERIC=$LC_ALL
+ [[ ${LC_TIME-} ]] && LC_TIME=$LC_ALL
+ LANG=$LC_ALL
+ LC_ALL=
+ fi
+ ble/variable#copy-state LC_COLLATE _ble_bash_LC_COLLATE
+ LC_COLLATE=C
+ if local TMOUT= 2>/dev/null; then # #D1630 WA
+ _ble_bash_tmout_wa=()
+ else
+ _ble_bash_tmout_wa=(-t 2147483647)
+ fi
+} 2>/dev/null # set -x 対策 #D0930 / locale 変更
+function ble/base/restore-bash-options {
+ [[ $_ble_bash_options_adjusted ]] || return 1
+ _ble_bash_options_adjusted=
+ ble/variable#copy-state _ble_bash_LC_COLLATE LC_COLLATE
+ if [[ $_ble_bash_LC_ALL ]]; then
+ ble/variable#copy-state _ble_bash_LC_CTYPE LC_CTYPE
+ ble/variable#copy-state _ble_bash_LC_MESSAGES LC_MESSAGES
+ ble/variable#copy-state _ble_bash_LC_NUMERIC LC_NUMERIC
+ ble/variable#copy-state _ble_bash_LC_TIME LC_TIME
+ ble/variable#copy-state _ble_bash_LANG LANG
+ fi
+ ble/variable#copy-state _ble_bash_LC_ALL LC_ALL
+ [[ $_ble_bash_nocasematch ]] && shopt -s nocasematch
+ ble/base/.restore-bash-options _ble_bash_set _ble_bash_shopt
+} 2>/dev/null # set -x 対策 #D0930 / locale 変更
+function ble/base/recover-bash-options {
+ if [[ $_ble_bash_expand_aliases ]]; then
+ shopt -s expand_aliases
+ else
+ shopt -u expand_aliases
+ fi
+}
+{ ble/base/adjust-bash-options; } &>/dev/null # set -x 対策 #D0930
+builtin bind &>/dev/null # force to load .inputrc
+if [[ $OSTYPE == msys* ]]; then
+ [[ $(builtin bind -m emacs -p | grep '"\\C-?"') == '"\C-?": backward-kill-line' ]] &&
+ builtin bind -m emacs '"\C-?": backward-delete-char'
+fi
+if [[ ! -o emacs && ! -o vi && ! $_ble_init_command ]]; then
+ builtin echo "ble.sh: ble.sh is not intended to be used with the line-editing mode disabled (--noediting)." >&2
+ ble/base/restore-bash-options
+ ble/base/restore-builtin-wrappers
+ ble/base/restore-POSIXLY_CORRECT
+ builtin eval -- "$_ble_bash_FUNCNEST_restore"
+ return 1 2>/dev/null || builtin exit 1
+fi
+if shopt -q restricted_shell; then
+ builtin echo "ble.sh: ble.sh is not intended to be used in restricted shells (--restricted)." >&2
+ ble/base/restore-bash-options
+ ble/base/restore-builtin-wrappers
+ ble/base/restore-POSIXLY_CORRECT
+ builtin eval -- "$_ble_bash_FUNCNEST_restore"
+ return 1 2>/dev/null || builtin exit 1
+fi
+function ble/init/adjust-IFS {
+ _ble_init_original_IFS_set=${IFS+set}
+ _ble_init_original_IFS=$IFS
+ IFS=$' \t\n'
+}
+function ble/init/restore-IFS {
+ if [[ $_ble_init_original_IFS_set ]]; then
+ IFS=$_ble_init_original_IFS
+ else
+ builtin unset -v IFS
+ fi
+ builtin unset -v _ble_init_original_IFS_set
+ builtin unset -v _ble_init_original_IFS
+}
+if ((_ble_bash>=50100)); then
+ _ble_bash_BASH_REMATCH_level=0
+ _ble_bash_BASH_REMATCH=()
+ function ble/base/adjust-BASH_REMATCH {
+ ((_ble_bash_BASH_REMATCH_level++==0)) || return 0
+ _ble_bash_BASH_REMATCH=("${BASH_REMATCH[@]}")
+ }
+ function ble/base/restore-BASH_REMATCH {
+ ((_ble_bash_BASH_REMATCH_level>0&&
+ --_ble_bash_BASH_REMATCH_level==0)) || return 0
+ BASH_REMATCH=("${_ble_bash_BASH_REMATCH[@]}")
+ }
+else
+ _ble_bash_BASH_REMATCH_level=0
+ _ble_bash_BASH_REMATCH=()
+ _ble_bash_BASH_REMATCH_rex=none
+ function ble/base/adjust-BASH_REMATCH/increase {
+ local delta=$1
+ ((delta)) || return 1
+ ((i+=delta))
+ if ((delta==1)); then
+ rex=$rex.
+ else
+ rex=$rex.{$delta}
+ fi
+ }
+ function ble/base/adjust-BASH_REMATCH/is-updated {
+ local i n=${#_ble_bash_BASH_REMATCH[@]}
+ ((n!=${#BASH_REMATCH[@]})) && return 0
+ for ((i=0;i<n;i++)); do
+ [[ ${_ble_bash_BASH_REMATCH[i]} != "${BASH_REMATCH[i]}" ]] && return 0
+ done
+ return 1
+ }
+ function ble/base/adjust-BASH_REMATCH/.find-substr {
+ local t=${1#*"$2"}
+ ((ret=${#1}-${#t}-${#2},ret<0&&(ret=-1),ret>=0))
+ }
+ function ble/base/adjust-BASH_REMATCH {
+ ((_ble_bash_BASH_REMATCH_level++==0)) || return 0
+ ble/base/adjust-BASH_REMATCH/is-updated || return 1
+ local size=${#BASH_REMATCH[@]}
+ if ((size==0)); then
+ _ble_bash_BASH_REMATCH=()
+ _ble_bash_BASH_REMATCH_rex=none
+ return 0
+ fi
+ local rex= i=0
+ local text=$BASH_REMATCH sub ret isub
+ local -a rparens=()
+ local isub rex i=0 count=0
+ for ((isub=1;isub<size;isub++)); do
+ local sub=${BASH_REMATCH[isub]}
+ while ((count>=1)); do
+ local end=${rparens[count-1]}
+ if ble/base/adjust-BASH_REMATCH/.find-substr "${text:i:end-i}" "$sub"; then
+ ble/base/adjust-BASH_REMATCH/increase "$ret"
+ ((rparens[count++]=i+${#sub}))
+ rex=$rex'('
+ break
+ else
+ ble/base/adjust-BASH_REMATCH/increase $((end-i))
+ rex=$rex')'
+ builtin unset -v 'rparens[--count]'
+ fi
+ done
+ ((count>0)) && continue
+ if ble/base/adjust-BASH_REMATCH/.find-substr "${text:i}" "$sub"; then
+ ble/base/adjust-BASH_REMATCH/increase "$ret"
+ ((rparens[count++]=i+${#sub}))
+ rex=$rex'('
+ else
+ break # 復元失敗
+ fi
+ done
+ while ((count>=1)); do
+ local end=${rparens[count-1]}
+ ble/base/adjust-BASH_REMATCH/increase $((end-i))
+ rex=$rex')'
+ builtin unset -v 'rparens[--count]'
+ done
+ ble/base/adjust-BASH_REMATCH/increase $((${#text}-i))
+ _ble_bash_BASH_REMATCH=("${BASH_REMATCH[@]}")
+ _ble_bash_BASH_REMATCH_rex=$rex
+ }
+ function ble/base/restore-BASH_REMATCH {
+ ((_ble_bash_BASH_REMATCH_level>0&&
+ --_ble_bash_BASH_REMATCH_level==0)) || return 0
+ [[ $_ble_bash_BASH_REMATCH =~ $_ble_bash_BASH_REMATCH_rex ]]
+ }
+fi
+ble/init/adjust-IFS
+ble/base/adjust-BASH_REMATCH
+function ble/init/clean-up {
+ local ext=$? opts=$1 # preserve exit status
+ builtin unset -v _ble_init_version
+ builtin unset -v _ble_init_arg
+ builtin unset -v _ble_init_exit
+ builtin unset -v _ble_init_command
+ builtin unset -v _ble_init_attached
+ ble/base/restore-BASH_REMATCH
+ ble/init/restore-IFS
+ if [[ :$opts: != *:check-attach:* && ! $_ble_attached ]]; then
+ ble/base/restore-bash-options
+ ble/base/restore-POSIXLY_CORRECT
+ ble/base/restore-builtin-wrappers
+ builtin eval -- "$_ble_bash_FUNCNEST_restore"
+ fi
+ return "$ext"
+}
+function ble/util/put { builtin printf '%s' "$1"; }
+function ble/util/print { builtin printf '%s\n' "$1"; }
+function ble/util/print-lines { builtin printf '%s\n' "$@"; }
+_ble_base_arguments_opts=
+_ble_base_arguments_attach=
+_ble_base_arguments_rcfile=
+function ble/base/read-blesh-arguments {
+ local opts=
+ local opt_attach=prompt
+ _ble_init_command= # 再解析
+ while (($#)); do
+ local arg=$1; shift
+ case $arg in
+ (--noattach|noattach)
+ opt_attach=none ;;
+ (--attach=*) opt_attach=${arg#*=} ;;
+ (--attach)
+ if (($#)); then
+ opt_attach=$1; shift
+ else
+ opt_attach=attach
+ opts=$opts:E
+ ble/util/print "ble.sh ($arg): an option argument is missing." >&2
+ fi ;;
+ (--noinputrc)
+ opts=$opts:noinputrc ;;
+ (--rcfile=*|--init-file=*|--rcfile|--init-file)
+ if [[ $arg != *=* ]]; then
+ local rcfile=$1; shift
+ else
+ local rcfile=${arg#*=}
+ fi
+ _ble_base_arguments_rcfile=${rcfile:-/dev/null}
+ if [[ ! $rcfile || ! -e $rcfile ]]; then
+ ble/util/print "ble.sh ($arg): '$rcfile' does not exist." >&2
+ opts=$opts:E
+ elif [[ ! -r $rcfile ]]; then
+ ble/util/print "ble.sh ($arg): '$rcfile' is not readable." >&2
+ opts=$opts:E
+ fi ;;
+ (--norc)
+ _ble_base_arguments_rcfile=/dev/null ;;
+ (--keep-rlvars)
+ opts=$opts:keep-rlvars ;;
+ (--debug-bash-output)
+ bleopt_internal_suppress_bash_output= ;;
+ (--test | --update | --clear-cache)
+ if [[ $_ble_init_command ]]; then
+ ble/util/print "ble.sh ($arg): the option '--$_ble_init_command' has already been specified." >&2
+ opts=$opts:E
+ else
+ _ble_init_command=${arg#--}
+ fi ;;
+ (--*)
+ ble/util/print "ble.sh: unrecognized long option '$arg'" >&2
+ opts=$opts:E ;;
+ (-?*)
+ local i c
+ for ((i=1;i<${#arg};i++)); do
+ c=${arg:i:1}
+ case -$c in
+ (-o)
+ if ((i+1<${#arg})); then
+ local oarg=${arg:i+1}
+ i=${#arg}
+ elif (($#)); then
+ local oarg=$1; shift
+ else
+ opts=$opts:E
+ i=${#arg}
+ continue
+ fi
+ local rex='^[_a-zA-Z][_a-zA-Z0-9]*='
+ if [[ $oarg =~ $rex ]]; then
+ builtin eval -- "bleopt_${oarg%%=*}=\${oarg#*=}"
+ else
+ ble/util/print "ble.sh: unrecognized option '-o $oarg'" >&2
+ opts=$opts:E
+ fi ;;
+ (-*)
+ ble/util/print "ble.sh: unrecognized option '-$c'" >&2
+ opts=$opts:E ;;
+ esac
+ done
+ ;;
+ (*)
+ ble/util/print "ble.sh: unrecognized argument '$arg'" >&2
+ opts=$opts:E ;;
+ esac
+ done
+ _ble_base_arguments_opts=$opts
+ _ble_base_arguments_attach=$opt_attach
+ [[ :$opts: != *:E:* ]]
+}
+if ! ble/base/read-blesh-arguments "$@"; then
+ builtin echo "ble.sh: cancel initialization." >&2
+ ble/init/clean-up 2>/dev/null # set -x 対策 #D0930
+ return 2 2>/dev/null || builtin exit 2
+fi
+if [[ ${_ble_base-} ]]; then
+ [[ $_ble_init_command ]] && _ble_init_attached=$_ble_attached
+ if ! ble/base/unload-for-reload; then
+ builtin echo "ble.sh: an old version of ble.sh seems to be already loaded." >&2
+ ble/init/clean-up 2>/dev/null # set -x 対策 #D0930
+ return 1 2>/dev/null || builtin exit 1
+ fi
+fi
+case ${BASH_VERSINFO[4]} in
+(alp*|bet*|dev*|rc*|releng*|maint*)
+ ble/util/print-lines \
+ "ble.sh may become very slow because this is a debug version of Bash" \
+ " (version '$BASH_VERSION', release status: '${BASH_VERSINFO[4]}')." \
+ " We recommend using ble.sh with a release version of Bash." >&2 ;;
+esac
+_ble_bash=$((BASH_VERSINFO[0]*10000+BASH_VERSINFO[1]*100+BASH_VERSINFO[2]))
+_ble_bash_loaded_in_function=0
+local _ble_local_test 2>/dev/null && _ble_bash_loaded_in_function=1
+_ble_version=0
+BLE_VERSION=$_ble_init_version
+function ble/base/initialize-version-information {
+ local version=$BLE_VERSION
+ local hash=
+ if [[ $version == *+* ]]; then
+ hash=${version#*+}
+ version=${version%%+*}
+ fi
+ local status=release
+ if [[ $version == *-* ]]; then
+ status=${version#*-}
+ version=${version%%-*}
+ fi
+ local major=${version%%.*}; version=${version#*.}
+ local minor=${version%%.*}; version=${version#*.}
+ local patch=${version%%.*}
+ BLE_VERSINFO=("$major" "$minor" "$patch" "$hash" "$status" noarch)
+ ((_ble_version=major*10000+minor*100+patch))
+}
+ble/base/initialize-version-information
+function ble/util/assign { builtin eval "$1=\$(builtin eval -- \"\$2\")"; }
+function ble/bin/.default-utility-path {
+ local cmd
+ for cmd; do
+ builtin eval "function ble/bin/$cmd { command $cmd \"\$@\"; }"
+ done
+}
+function ble/bin/.freeze-utility-path {
+ local cmd path q=\' Q="'\''" fail=
+ for cmd; do
+ ble/bin#has "ble/bin/.frozen:$cmd" && continue
+ if ble/util/assign path "builtin type -P -- $cmd 2>/dev/null" && [[ $path ]]; then
+ builtin eval "function ble/bin/$cmd { '${path//$q/$Q}' \"\$@\"; }"
+ else
+ fail=1
+ fi
+ done
+ ((!fail))
+}
+if ((_ble_bash>=40000)); then
+ function ble/bin#has { type -t "$@" &>/dev/null; }
+else
+ function ble/bin#has {
+ local cmd
+ for cmd; do type -t "$cmd" || return 1; done &>/dev/null
+ return 0
+ }
+fi
+_ble_init_posix_command_list=(sed date rm mkdir mkfifo sleep stty tty sort awk chmod grep cat wc mv sh od cp ps)
+function ble/init/check-environment {
+ if ! ble/bin#has "${_ble_init_posix_command_list[@]}"; then
+ local cmd commandMissing=
+ for cmd in "${_ble_init_posix_command_list[@]}"; do
+ if ! type "$cmd" &>/dev/null; then
+ commandMissing="$commandMissing\`$cmd', "
+ fi
+ done
+ ble/util/print "ble.sh: insane environment: The command(s), ${commandMissing}not found. Check your environment variable PATH." >&2
+ local default_path=$(command -p getconf PATH 2>/dev/null)
+ [[ $default_path ]] || return 1
+ local original_path=$PATH
+ export PATH=${default_path}${PATH:+:}${PATH}
+ [[ :$PATH: == *:/bin:* ]] || PATH=/bin${PATH:+:}$PATH
+ [[ :$PATH: == *:/usr/bin:* ]] || PATH=/usr/bin${PATH:+:}$PATH
+ if ! ble/bin#has "${_ble_init_posix_command_list[@]}"; then
+ PATH=$original_path
+ return 1
+ fi
+ ble/util/print "ble.sh: modified PATH=${PATH::${#PATH}-${#original_path}}\$PATH" >&2
+ fi
+ if [[ ! $USER ]]; then
+ ble/util/print "ble.sh: insane environment: \$USER is empty." >&2
+ if type id &>/dev/null; then
+ export USER=$(id -un)
+ ble/util/print "ble.sh: modified USER=$USER" >&2
+ fi
+ fi
+ ble/bin/.default-utility-path "${_ble_init_posix_command_list[@]}"
+ return 0
+}
+if ! ble/init/check-environment; then
+ ble/util/print "ble.sh: failed to adjust the environment. canceling the load of ble.sh." 1>&2
+ builtin unset -v _ble_bash BLE_VERSION BLE_VERSINFO
+ ble/init/clean-up 2>/dev/null # set -x 対策 #D0930
+ return 1
+fi
+_ble_bin_awk_type=
+function ble/bin/awk/.instantiate {
+ local path q=\' Q="'\''"
+ if [[ $OSTYPE == solaris* ]] && type /usr/xpg4/bin/awk >/dev/null; then
+ _ble_bin_awk_type=xpg4
+ function ble/bin/awk { /usr/xpg4/bin/awk -v AWKTYPE=xpg4 "$@"; }
+ elif ble/util/assign path "builtin type -P -- nawk 2>/dev/null" && [[ $path ]]; then
+ _ble_bin_awk_type=nawk
+ builtin eval "function ble/bin/awk { '${path//$q/$Q}' -v AWKTYPE=nawk \"\$@\"; }"
+ elif ble/util/assign path "builtin type -P -- mawk 2>/dev/null" && [[ $path ]]; then
+ _ble_bin_awk_type=mawk
+ builtin eval "function ble/bin/awk { '${path//$q/$Q}' -v AWKTYPE=mawk \"\$@\"; }"
+ elif ble/util/assign path "builtin type -P -- gawk 2>/dev/null" && [[ $path ]]; then
+ _ble_bin_awk_type=gawk
+ builtin eval "function ble/bin/awk { '${path//$q/$Q}' -v AWKTYPE=gawk \"\$@\"; }"
+ elif ble/util/assign path "builtin type -P -- awk 2>/dev/null" && [[ $path ]]; then
+ local version
+ ble/util/assign version '"$path" --version 2>&1'
+ if [[ $version == *'GNU Awk'* ]]; then
+ _ble_bin_awk_type=gawk
+ elif [[ $version == *mawk* ]]; then
+ _ble_bin_awk_type=mawk
+ elif [[ $version == 'awk version '[12][0-9][0-9][0-9][01][0-9][0-3][0-9] ]]; then
+ _ble_bin_awk_type=nawk
+ else
+ _ble_bin_awk_type=unknown
+ fi
+ builtin eval "function ble/bin/awk { '${path//$q/$Q}' -v AWKTYPE=$_ble_bin_awk_type \"\$@\"; }"
+ else
+ return 1
+ fi
+}
+function ble/bin/awk {
+ ble/bin/awk/.instantiate &&
+ ble/bin/awk "$@"
+}
+function ble/bin/.frozen:awk { :; }
+function ble/util/mkd {
+ local dir
+ for dir; do
+ [[ -d $dir ]] && continue
+ [[ -e $dir || -L $dir ]] && ble/bin/rm -f "$dir"
+ ble/bin/mkdir -p "$dir"
+ done
+}
+_ble_bin_awk_supports_null_RS=
+function ble/bin/awk.supports-null-record-separator {
+ if [[ ! $_ble_bin_awk_supports_null_RS ]]; then
+ local count=0 awk_script='BEGIN { RS = "\0"; } { count++; } END { print count; }'
+ ble/util/assign count 'printf "a\0b\0" | ble/bin/awk "$awk_script" '
+ if ((count==2)); then
+ _ble_bin_awk_supports_null_RS=yes
+ else
+ _ble_bin_awk_supports_null_RS=no
+ fi
+ fi
+ [[ $_ble_bin_awk_supports_null_RS == yes ]]
+}
+if ((_ble_bash>=40000)); then
+ _ble_util_readlink_visited_init='local -A visited=()'
+ function ble/util/readlink/.visited {
+ [[ ${visited[$1]+set} ]] && return 0
+ visited[$1]=1
+ return 1
+ }
+else
+ _ble_util_readlink_visited_init="local -a visited=()"
+ function ble/util/readlink/.visited {
+ local key
+ for key in "${visited[@]}"; do
+ [[ $1 == "$key" ]] && return 0
+ done
+ visited=("$1" "${visited[@]}")
+ return 1
+ }
+fi
+function ble/util/readlink/.readlink {
+ local path=$1
+ if ble/bin#has ble/bin/readlink; then
+ ble/util/assign link 'ble/bin/readlink -- "$path"'
+ [[ $link ]]
+ elif ble/bin#has ble/bin/ls; then
+ ble/util/assign link 'ble/bin/ls -ld -- "$path"' &&
+ [[ $link == *" $path -> "?* ]] &&
+ link=${link#*" $path -> "}
+ else
+ false
+ fi
+} 2>/dev/null
+function ble/util/readlink/.resolve-physical-directory {
+ [[ $path == */?* ]] || return 0
+ local PWD=$PWD OLDPWD=$OLDPWD CDPATH=
+ builtin cd -L . &&
+ local pwd=$PWD &&
+ builtin cd -P "${path%/*}/" &&
+ path=${PWD%/}/${path##*/}
+ builtin cd -L "$pwd"
+ return 0
+}
+function ble/util/readlink/.resolve-loop {
+ local path=$ret
+ builtin eval -- "$_ble_util_readlink_visited_init"
+ while [[ -h $path ]]; do
+ local link
+ ble/util/readlink/.visited "$path" && break
+ ble/util/readlink/.readlink "$path" || break
+ if [[ $link == /* || $path != */* ]]; then
+ path=$link
+ else
+ ble/util/readlink/.resolve-physical-directory
+ path=${path%/}/$link
+ fi
+ while [[ $path == ?*/ ]]; do path=${path%/}; done
+ done
+ ret=$path
+}
+function ble/util/readlink/.resolve {
+ _ble_util_readlink_type=
+ case $OSTYPE in
+ (cygwin | msys | linux-gnu)
+ local readlink
+ ble/util/assign readlink 'type -P readlink'
+ case $readlink in
+ (/bin/readlink | /usr/bin/readlink)
+ _ble_util_readlink_type=readlink-f
+ builtin eval "function ble/util/readlink/.resolve { ble/util/assign ret '$readlink -f -- \"\$ret\"'; }" ;;
+ esac ;;
+ esac
+ if [[ ! $_ble_util_readlink_type ]]; then
+ _ble_util_readlink_type=loop
+ ble/bin/.freeze-utility-path readlink ls
+ function ble/util/readlink/.resolve { ble/util/readlink/.resolve-loop; }
+ fi
+ ble/util/readlink/.resolve
+}
+function ble/util/readlink {
+ ret=$1
+ if [[ -h $ret ]]; then ble/util/readlink/.resolve; fi
+}
+_ble_bash_path=
+function ble/bin/.load-builtin {
+ local name=$1 path=$2
+ if [[ ! $_ble_bash_path ]]; then
+ local ret; ble/util/readlink "$BASH"
+ _ble_bash_path=$ret
+ fi
+ if [[ ! $path ]]; then
+ local bash_prefix=${ret%/*/*}
+ path=$bash_prefix/lib/bash/$name
+ [[ -s $path ]] || return 1
+ fi
+ if (enable -f "$path" "$name") &>/dev/null; then
+ enable -f "$path" "$name"
+ builtin eval -- "function ble/bin/$name { builtin $name \"\$@\"; }"
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/base/.create-user-directory {
+ local var=$1 dir=$2
+ if [[ ! -d $dir ]]; then
+ [[ ! -e $dir && -h $dir ]] && ble/bin/rm -f "$dir"
+ if [[ -e $dir || -h $dir ]]; then
+ ble/util/print "ble.sh: cannot create a directory '$dir' since there is already a file." >&2
+ return 1
+ fi
+ if ! (umask 077; ble/bin/mkdir -p "$dir" && [[ -O $dir ]]); then
+ ble/util/print "ble.sh: failed to create a directory '$dir'." >&2
+ return 1
+ fi
+ elif ! [[ -r $dir && -w $dir && -x $dir ]]; then
+ ble/util/print "ble.sh: permission of '$dir' is not correct." >&2
+ return 1
+ elif [[ ! -O $dir ]]; then
+ ble/util/print "ble.sh: owner of '$dir' is not correct." >&2
+ return 1
+ fi
+ builtin eval "$var=\$dir"
+}
+function ble/base/initialize-base-directory {
+ local src=$1
+ local defaultDir=${2-}
+ _ble_base_blesh_raw=$src
+ if [[ -h $src ]]; then
+ local ret; ble/util/readlink "$src"; src=$ret
+ fi
+ _ble_base_blesh=$src
+ if [[ -s $src && $src != */* ]]; then
+ _ble_base=$PWD
+ elif [[ $src == */* ]]; then
+ local dir=${src%/*}
+ if [[ ! $dir ]]; then
+ _ble_base=/
+ elif [[ $dir != /* ]]; then
+ _ble_base=$PWD/$dir
+ else
+ _ble_base=$dir
+ fi
+ else
+ _ble_base=${defaultDir:-$HOME/.local/share/blesh}
+ fi
+ [[ -d $_ble_base ]]
+}
+if ! ble/base/initialize-base-directory "${BASH_SOURCE[0]}"; then
+ ble/util/print "ble.sh: ble base directory not found!" 1>&2
+ builtin unset -v _ble_bash BLE_VERSION BLE_VERSINFO
+ ble/init/clean-up 2>/dev/null # set -x 対策 #D0930
+ return 1
+fi
+function ble/base/initialize-runtime-directory/.xdg {
+ local runtime_dir=
+ if [[ $XDG_RUNTIME_DIR ]]; then
+ if [[ ! -d $XDG_RUNTIME_DIR ]]; then
+ ble/util/print "ble.sh: XDG_RUNTIME_DIR='$XDG_RUNTIME_DIR' is not a directory." >&2
+ return 1
+ elif [[ -O $XDG_RUNTIME_DIR ]]; then
+ runtime_dir=$XDG_RUNTIME_DIR
+ else
+ false
+ fi
+ fi
+ if [[ ! $runtime_dir ]]; then
+ runtime_dir=/run/user/$UID
+ [[ -d $runtime_dir && -O $runtime_dir ]] || return 1
+ fi
+ if ! [[ -r $runtime_dir && -w $runtime_dir && -x $runtime_dir ]]; then
+ [[ $runtime_dir == "$XDG_RUNTIME_DIR" ]] &&
+ ble/util/print "ble.sh: XDG_RUNTIME_DIR='$XDG_RUNTIME_DIR' doesn't have a proper permission." >&2
+ return 1
+ fi
+ ble/base/.create-user-directory _ble_base_run "$runtime_dir/blesh"
+}
+function ble/base/initialize-runtime-directory/.tmp {
+ [[ -r /tmp && -w /tmp && -x /tmp ]] || return 1
+ local tmp_dir=/tmp/blesh
+ if [[ ! -d $tmp_dir ]]; then
+ [[ ! -e $tmp_dir && -h $tmp_dir ]] && ble/bin/rm -f "$tmp_dir"
+ if [[ -e $tmp_dir || -h $tmp_dir ]]; then
+ ble/util/print "ble.sh: cannot create a directory '$tmp_dir' since there is already a file." >&2
+ return 1
+ fi
+ ble/bin/mkdir -p "$tmp_dir" || return 1
+ ble/bin/chmod a+rwxt "$tmp_dir" || return 1
+ elif ! [[ -r $tmp_dir && -w $tmp_dir && -x $tmp_dir ]]; then
+ ble/util/print "ble.sh: permission of '$tmp_dir' is not correct." >&2
+ return 1
+ fi
+ ble/base/.create-user-directory _ble_base_run "$tmp_dir/$UID"
+}
+function ble/base/initialize-runtime-directory {
+ ble/base/initialize-runtime-directory/.xdg && return 0
+ ble/base/initialize-runtime-directory/.tmp && return 0
+ local tmp_dir=$_ble_base/run
+ if [[ ! -d $tmp_dir ]]; then
+ ble/bin/mkdir -p "$tmp_dir" || return 1
+ ble/bin/chmod a+rwxt "$tmp_dir" || return 1
+ fi
+ ble/base/.create-user-directory _ble_base_run "$tmp_dir/${USER:-$UID}@$HOSTNAME"
+}
+if ! ble/base/initialize-runtime-directory; then
+ ble/util/print "ble.sh: failed to initialize \$_ble_base_run." 1>&2
+ builtin unset -v _ble_bash BLE_VERSION BLE_VERSINFO
+ ble/init/clean-up 2>/dev/null # set -x 対策 #D0930
+ return 1
+fi
+: >| "$_ble_base_run/$$.load"
+function ble/base/clean-up-runtime-directory {
+ local file pid mark removed
+ mark=() removed=()
+ for file in "$_ble_base_run"/[1-9]*.*; do
+ [[ -e $file ]] || continue
+ pid=${file##*/}; pid=${pid%%.*}
+ [[ ${mark[pid]+set} ]] && continue
+ mark[pid]=1
+ if ! builtin kill -0 "$pid" &>/dev/null; then
+ removed=("${removed[@]}" "$_ble_base_run/$pid."*)
+ fi
+ done
+ ((${#removed[@]})) && ble/bin/rm -rf "${removed[@]}"
+}
+if shopt -q failglob &>/dev/null; then
+ shopt -u failglob
+ ble/base/clean-up-runtime-directory
+ shopt -s failglob
+else
+ ble/base/clean-up-runtime-directory
+fi
+function ble/base/initialize-cache-directory/.xdg {
+ [[ $_ble_base != */out ]] || return 1
+ local cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}
+ if [[ ! -d $cache_dir ]]; then
+ [[ $XDG_CACHE_HOME ]] &&
+ ble/util/print "ble.sh: XDG_CACHE_HOME='$XDG_CACHE_HOME' is not a directory." >&2
+ return 1
+ fi
+ if ! [[ -r $cache_dir && -w $cache_dir && -x $cache_dir ]]; then
+ [[ $XDG_CACHE_HOME ]] &&
+ ble/util/print "ble.sh: XDG_CACHE_HOME='$XDG_CACHE_HOME' doesn't have a proper permission." >&2
+ return 1
+ fi
+ local ver=${BLE_VERSINFO[0]}.${BLE_VERSINFO[1]}
+ ble/base/.create-user-directory _ble_base_cache "$cache_dir/blesh/$ver"
+}
+function ble/base/initialize-cache-directory {
+ ble/base/initialize-cache-directory/.xdg && return 0
+ local cache_dir=$_ble_base/cache.d
+ if [[ ! -d $cache_dir ]]; then
+ ble/bin/mkdir -p "$cache_dir" || return 1
+ ble/bin/chmod a+rwxt "$cache_dir" || return 1
+ local old_cache_dir=$_ble_base/cache
+ if [[ -d $old_cache_dir && ! -h $old_cache_dir ]]; then
+ mv "$old_cache_dir" "$cache_dir/$UID"
+ ln -s "$cache_dir/$UID" "$old_cache_dir"
+ fi
+ fi
+ ble/base/.create-user-directory _ble_base_cache "$cache_dir/$UID"
+}
+function ble/base/migrate-cache-directory/.move {
+ local old=$1 new=$2
+ [[ -e $old ]] || return 0
+ if [[ -e $new || -L $old ]]; then
+ ble/bin/rm -rf "$old"
+ else
+ ble/bin/mv "$old" "$new"
+ fi
+}
+function ble/base/migrate-cache-directory/.check-old-prefix {
+ local old_prefix=$_ble_base_cache/$1
+ local new_prefix=$_ble_base_cache/$2
+ local file
+ for file in "$old_prefix"*; do
+ local old=$file
+ local new=$new_prefix${file#"$old_prefix"}
+ ble/base/migrate-cache-directory/.move "$old" "$new"
+ done
+}
+function ble/base/migrate-cache-directory {
+ local failglob=
+ shopt -q failglob && { failglob=1; shopt -u failglob; }
+ ble/base/migrate-cache-directory/.check-old-prefix cmap+default.binder-source decode.cmap.allseq
+ ble/base/migrate-cache-directory/.check-old-prefix cmap+default decode.cmap
+ ble/base/migrate-cache-directory/.check-old-prefix ble-decode-bind decode.bind
+ local file
+ for file in "$_ble_base_cache"/*.term; do
+ local old=$file
+ local new=$_ble_base_cache/term.${file#"$_ble_base_cache/"}; new=${new%.term}
+ ble/base/migrate-cache-directory/.move "$old" "$new"
+ done
+ ble/base/migrate-cache-directory/.move "$_ble_base_cache/man" "$_ble_base_cache/complete.mandb"
+ [[ $failglob ]] && shopt -s failglob
+}
+if ! ble/base/initialize-cache-directory; then
+ ble/util/print "ble.sh: failed to initialize \$_ble_base_cache." 1>&2
+ builtin unset -v _ble_bash BLE_VERSION BLE_VERSINFO
+ ble/init/clean-up 2>/dev/null # set -x 対策 #D0930
+ return 1
+fi
+ble/base/migrate-cache-directory
+function ble/base/print-usage-for-no-argument-command {
+ local name=${FUNCNAME[1]} desc=$1; shift
+ ble/util/print-lines \
+ "usage: $name" \
+ "$desc" >&2
+ [[ $1 != --help ]] && return 2
+ return 0
+}
+function ble-reload { source "$_ble_base/ble.sh"; }
+_ble_base_repository='/home/saumit/ble.sh'
+_ble_base_branch=master
+function ble-update/.check-install-directory-ownership {
+ if [[ ! -O $_ble_base ]]; then
+ ble/uti/print 'ble-update: install directory is owned by another user:' >&2
+ ls -ld "$_ble_base"
+ return 1
+ elif [[ ! -r $_ble_base || ! -w $_ble_base || ! -x $_ble_base ]]; then
+ ble/uti/print 'ble-update: install directory permission denied:' >&2
+ ls -ld "$_ble_base"
+ return 1
+ fi
+}
+function ble-update/.make {
+ local sudo=
+ if [[ $1 == --sudo ]]; then
+ sudo=1
+ shift
+ fi
+ if ! "$MAKE" -q "$@"; then
+ if [[ $sudo ]]; then
+ sudo "$MAKE" "$@"
+ else
+ "$MAKE" "$@"
+ fi
+ else
+ return 6
+ fi
+}
+function ble-update/.reload {
+ local ext=$1
+ if [[ $ext -eq 0 || $ext -eq 6 && $_ble_base/ble.sh -nt $_ble_base_run/$$.load ]]; then
+ if [[ ! -e $_ble_base/ble.sh ]]; then
+ ble/util/print "ble-update: new ble.sh not found at '$_ble_base/ble.sh'." >&2
+ return 1
+ elif [[ ! -s $_ble_base/ble.sh ]]; then
+ ble/util/print "ble-update: new ble.sh '$_ble_base/ble.sh' is empty." >&2
+ return 1
+ elif [[ $- == *i* && $_ble_attached ]] && ! ble/util/is-running-in-subshell; then
+ ble-reload
+ fi
+ return $?
+ fi
+ ((ext==6)) && ext=0
+ return "$ext"
+}
+function ble-update {
+ if (($#)); then
+ ble/base/print-usage-for-no-argument-command 'Update and reload ble.sh.' "$@"
+ return "$?"
+ fi
+ if [[ $_ble_base_package_type ]] && ble/is-function ble/base/package:"$_ble_base_package_type"/update; then
+ ble/util/print "ble-update: delegate to '$_ble_base_package_type' package manager..." >&2
+ ble/base/package:"$_ble_base_package_type"/update; local ext=$?
+ if ((ext==125)); then
+ ble/util/print 'ble-update: fallback to the default update process.' >&2
+ else
+ ble-update/.reload "$ext"
+ return $?
+ fi
+ fi
+ local MAKE=
+ if type gmake &>/dev/null; then
+ MAKE=gmake
+ elif type make &>/dev/null && make --version 2>&1 | ble/bin/grep -qiF 'GNU Make'; then
+ MAKE=make
+ else
+ ble/util/print "ble-update: GNU Make is not available." >&2
+ return 1
+ fi
+ if ! ble/bin#has git gawk; then
+ local command
+ for command in git gawk; do
+ type "$command" &>/dev/null ||
+ ble/util/print "ble-update: '$command' command is not available." >&2
+ done
+ return 1
+ fi
+ local insdir_doc=$_ble_base/doc
+ [[ ! -d $insdir_doc && -d ${_ble_base%/*}/doc/blesh ]] &&
+ insdir_doc=${_ble_base%/*}/doc/blesh
+ if [[ $_ble_base_repository && $_ble_base_repository != release:* ]]; then
+ if [[ ! -e $_ble_base_repository/.git ]]; then
+ ble/util/print "ble-update: git repository not found at '$_ble_base_repository'." >&2
+ elif [[ ! -O $_ble_base_repository ]]; then
+ ble/util/print "ble-update: git repository is owned by another user:" >&2
+ ls -ld "$_ble_base_repository"
+ elif [[ ! -r $_ble_base_repository || ! -w $_ble_base_repository || ! -x $_ble_base_repository ]]; then
+ ble/util/print 'ble-update: git repository permission denied:' >&2
+ ls -ld "$_ble_base_repository"
+ else
+ ( ble/util/print "cd into $_ble_base_repository..." >&2 &&
+ builtin cd "$_ble_base_repository" &&
+ git pull && git submodule update --recursive --remote &&
+ if [[ $_ble_base == "$_ble_base_repository"/out ]]; then
+ ble-update/.make all
+ elif ((EUID!=0)) && ! ble-update/.check-install-directory-ownership; then
+ ble-update/.make all
+ ble-update/.make --sudo INSDIR="$_ble_base" INSDIR_DOC="$insdir_doc" install
+ else
+ ble-update/.make INSDIR="$_ble_base" INSDIR_DOC="$insdir_doc" install
+ fi )
+ ble-update/.reload $?
+ return $?
+ fi
+ fi
+ if ((EUID!=0)) && ! ble-update/.check-install-directory-ownership; then
+ sudo "$BASH" "$_ble_base/ble.sh" --update &&
+ ble-update/.reload 6
+ return $?
+ else
+ local branch=${_ble_base_branch:-master}
+ ( ble/bin/mkdir -p "$_ble_base/src" && builtin cd "$_ble_base/src" &&
+ git clone --recursive --depth 1 https://github.com/akinomyoga/ble.sh "$_ble_base/src/ble.sh" -b "$branch" &&
+ builtin cd ble.sh && "$MAKE" all &&
+ "$MAKE" INSDIR="$_ble_base" INSDIR_DOC="$insdir_doc" install ) &&
+ ble-update/.reload
+ return "$?"
+ fi
+ return 1
+}
+_ble_attached=
+BLE_ATTACHED=
+_ble_term_nl=$'\n'
+_ble_term_FS=$'\034'
+_ble_term_SOH=$'\001'
+_ble_term_DEL=$'\177'
+_ble_term_IFS=$' \t\n'
+_ble_term_CR=$'\r'
+function blehook/declare {
+ local name=$1
+ builtin eval "_ble_hook_h_$name=()"
+ builtin eval "_ble_hook_c_$name=0"
+}
+blehook/declare EXIT
+blehook/declare INT
+blehook/declare ERR
+blehook/declare unload
+blehook/declare ATTACH
+blehook/declare DETACH
+blehook/declare DA1R
+blehook/declare DA2R
+blehook/declare color_defface_load
+blehook/declare color_setface_load
+blehook/declare ADDHISTORY
+blehook/declare history_reset_background
+blehook/declare history_onleave
+blehook/declare history_delete
+blehook/declare history_insert
+blehook/declare history_clear
+blehook/declare history_message
+blehook/declare WINCH
+blehook/declare CHPWD
+blehook/declare PRECMD
+blehook/declare PREEXEC
+blehook/declare POSTEXEC
+blehook/declare widget_bell
+blehook/declare textarea_render_defer
+blehook/declare info_reveal
+function ble-edit/prompt/print { ble/prompt/print "$@"; }
+function ble-edit/prompt/process-prompt-string { ble/prompt/process-prompt-string "$@"; }
+blehook/declare keymap_load
+blehook/declare keymap_vi_load
+blehook/declare keymap_emacs_load
+blehook/declare syntax_load
+blehook/declare complete_load
+blehook/declare complete_insert
+function blehook/.compatibility-ble-0.3 {
+ blehook keymap_load+='ble/util/invoke-hook _ble_keymap_default_load_hook'
+ blehook keymap_emacs_load+='ble/util/invoke-hook _ble_keymap_emacs_load_hook'
+ blehook keymap_vi_load+='ble/util/invoke-hook _ble_keymap_vi_load_hook'
+ blehook complete_load+='ble/util/invoke-hook _ble_complete_load_hook'
+}
+function blehook/.compatibility-ble-0.3/check {
+ if ble/is-array _ble_keymap_default_load_hook ||
+ ble/is-array _ble_keymap_vi_load_hook ||
+ ble/is-array _ble_keymap_emacs_load_hook ||
+ ble/is-array _ble_complete_load_hook
+ then
+ ble/bin/cat << EOF
+# [Change in ble-0.4.0]
+#
+# Please update your blerc settings for ble-0.4+.
+# In ble-0.4+, use the following form:
+#
+# blehook/eval-after-load keymap SHELL-COMMAND
+# blehook/eval-after-load keymap_vi SHELL-COMMAND
+# blehook/eval-after-load keymap_emacs SHELL-COMMAND
+# blehook/eval-after-load complete SHELL-COMMAND
+#
+# instead of the following older form:
+#
+# ble/array#push _ble_keymap_default_load_hook SHELL-COMMAND
+# ble/array#push _ble_keymap_vi_load_hook SHELL-COMMAND
+# ble/array#push _ble_keymap_emacs_load_hook SHELL-COMMAND
+# ble/array#push _ble_complete_load_hook SHELL-COMMAND
+#
+# Note: "blehook/eval-after-load" should be called
+# after you defined SHELL-COMMAND.
+#
+EOF
+ fi
+}
+function ble/complete/action/inherit-from {
+ ble/complete/action#inherit-from "$@"
+}
+function bleopt/.read-arguments/process-option {
+ local name=$1
+ case $name in
+ (help)
+ flags=H$flags ;;
+ (color|color=always)
+ flags=c${flags//[cn]} ;;
+ (color=never)
+ flags=n${flags//[cn]} ;;
+ (color=auto)
+ flags=${flags//[cn]} ;;
+ (color=*)
+ ble/util/print "bleopt: '${name#*=}': unrecognized option argument for '--color'." >&2
+ flags=E$flags ;;
+ (reset) flags=r$flags ;;
+ (changed) flags=u$flags ;;
+ (initialize) flags=I$flags ;;
+ (*)
+ ble/util/print "bleopt: unrecognized long option '--$name'." >&2
+ flags=E$flags ;;
+ esac
+}
+function bleopt/expand-variable-pattern {
+ ret=()
+ local pattern=$1
+ if [[ $pattern == *@* ]]; then
+ builtin eval -- "ret=(\"\${!${pattern%%@*}@}\")"
+ ble/array#filter-by-glob ret "${pattern//@/?*}"
+ elif [[ ${!pattern+set} || :$opts: == :allow-undefined: ]]; then
+ ret=("$pattern")
+ fi
+ ((${#ret[@]}))
+}
+function bleopt/.read-arguments {
+ flags= pvars=() specs=()
+ while (($#)); do
+ local arg=$1; shift
+ case $arg in
+ (--)
+ ble/array#push specs "$@"
+ break ;;
+ (-)
+ ble/util/print "bleopt: unrecognized argument '$arg'." >&2
+ flags=E$flags ;;
+ (--*)
+ bleopt/.read-arguments/process-option "${arg:2}" ;;
+ (-*)
+ local i c
+ for ((i=1;i<${#arg};i++)); do
+ c=${arg:i:1}
+ case $c in
+ (r) bleopt/.read-arguments/process-option reset ;;
+ (u) bleopt/.read-arguments/process-option changed ;;
+ (I) bleopt/.read-arguments/process-option initialize ;;
+ (*)
+ ble/util/print "bleopt: unrecognized option '-$c'." >&2
+ flags=E$flags ;;
+ esac
+ done ;;
+ (*)
+ if local rex='^([_a-zA-Z0-9@]+)(:?=|$)(.*)'; [[ $arg =~ $rex ]]; then
+ local name=${BASH_REMATCH[1]#bleopt_}
+ local var=bleopt_$name
+ local op=${BASH_REMATCH[2]}
+ local value=${BASH_REMATCH[3]}
+ if [[ $op == ':=' ]]; then
+ if [[ $var == *@* ]]; then
+ ble/util/print "bleopt: \`${var#bleopt_}': wildcard cannot be used in the definition." >&2
+ flags=E$flags
+ continue
+ fi
+ else
+ local ret; bleopt/expand-variable-pattern "$var"
+ var=()
+ local v i=0
+ for v in "${ret[@]}"; do
+ ble/is-function "bleopt/obsolete:${v#bleopt_}" && continue
+ var[i++]=$v
+ done
+ [[ ${#var[@]} == 0 ]] && var=("${ret[@]}")
+ if ((${#var[@]}==0)); then
+ ble/util/print "bleopt: option \`$name' not found" >&2
+ flags=E$flags
+ continue
+ fi
+ fi
+ if [[ $op ]]; then
+ var=("${var[@]}") # #D1570: WA bash-3.0 ${scal[@]/x} bug
+ if ((_ble_bash>=40300)) && ! shopt -q compat42; then
+ ble/array#push specs "${var[@]/%/"=$value"}" # #D1570 #D1751 WA checked
+ else
+ ble/array#push specs "${var[@]/%/=$value}" # #D1570 #D1738 WA checked
+ fi
+ else
+ ble/array#push pvars "${var[@]}"
+ fi
+ else
+ ble/util/print "bleopt: unrecognized argument '$arg'" >&2
+ flags=E$flags
+ fi ;;
+ esac
+ done
+}
+function bleopt/changed.predicate {
+ local cur=$1 def=_ble_opt_def_${1#bleopt_}
+ [[ ! ${!def+set} || ${!cur} != "${!def}" ]]
+}
+function bleopt {
+ local flags pvars specs
+ bleopt/.read-arguments "$@"
+ if [[ $flags == *E* ]]; then
+ return 2
+ elif [[ $flags == *H* ]]; then
+ ble/util/print-lines \
+ 'usage: bleopt [OPTION] [NAME|NAME=VALUE|NAME:=VALUE]...' \
+ ' Set ble.sh options. Without arguments, this prints all the settings.' \
+ '' \
+ ' Options' \
+ ' --help Print this help.' \
+ ' -r, --reset Reset options to the default values' \
+ ' -I, --initialize Re-initialize settings' \
+ ' -u, --changed Only select changed options' \
+ ' --color[=always|never|auto]' \
+ ' Change color settings.' \
+ '' \
+ ' Arguments' \
+ ' NAME Print the value of the option.' \
+ ' NAME=VALUE Set the value to the option.' \
+ ' NAME:=VALUE Set or create the value to the option.' \
+ '' \
+ ' NAME can contain "@" as a wildcard.' \
+ ''
+ return 0
+ fi
+ if ((${#pvars[@]}==0&&${#specs[@]}==0)); then
+ local var ip=0
+ for var in "${!bleopt_@}"; do
+ ble/is-function "bleopt/obsolete:${var#bleopt_}" && continue
+ pvars[ip++]=$var
+ done
+ fi
+ [[ $flags == *u* ]] &&
+ ble/array#filter pvars bleopt/changed.predicate
+ if [[ $flags == *r* ]]; then
+ local var
+ for var in "${pvars[@]}"; do
+ local name=${var#bleopt_}
+ ble/is-function bleopt/obsolete:"$name" && continue
+ local def=_ble_opt_def_$name
+ [[ ${!def+set} && ${!var-} != "${!def}" ]] &&
+ ble/array#push specs "$var=${!def}"
+ done
+ pvars=()
+ elif [[ $flags == *I* ]]; then
+ local var
+ for var in "${pvars[@]}"; do
+ bleopt/reinitialize "${var#bleopt_}"
+ done
+ pvars=()
+ fi
+ if ((${#specs[@]})); then
+ local spec
+ for spec in "${specs[@]}"; do
+ local var=${spec%%=*} value=${spec#*=}
+ [[ ${!var+set} && ${!var} == "$value" ]] && continue
+ if ble/is-function bleopt/check:"${var#bleopt_}"; then
+ local bleopt_source=${BASH_SOURCE[1]}
+ local bleopt_lineno=${BASH_LINENO[0]}
+ if ! bleopt/check:"${var#bleopt_}"; then
+ flags=E$flags
+ continue
+ fi
+ fi
+ builtin eval -- "$var=\"\$value\""
+ done
+ fi
+ if ((${#pvars[@]})); then
+ local sgr0= sgr1= sgr2= sgr3=
+ if [[ $flags == *c* || $flags != *n* && -t 1 ]]; then
+ local ret
+ ble/color/face2sgr command_function; sgr1=$ret
+ ble/color/face2sgr syntax_varname; sgr2=$ret
+ ble/color/face2sgr syntax_quoted; sgr3=$ret
+ sgr0=$_ble_term_sgr0
+ fi
+ local var
+ for var in "${pvars[@]}"; do
+ local ret
+ ble/string#quote-word "${!var}" sgrq="$sgr3":sgr0="$sgr0"
+ ble/util/print "${sgr1}bleopt$sgr0 ${sgr2}${var#bleopt_}$sgr0=$ret"
+ done
+ fi
+ [[ $flags != *E* ]]
+}
+function bleopt/declare/.check-renamed-option {
+ var=bleopt_$2
+ local sgr0= sgr1= sgr2= sgr3=
+ if [[ -t 2 ]]; then
+ sgr0=$_ble_term_sgr0
+ sgr1=${_ble_term_setaf[2]}
+ sgr2=${_ble_term_setaf[1]}$_ble_term_bold
+ sgr3=${_ble_term_setaf[4]}$_ble_term_bold
+ fi
+ local locate=$sgr1${BASH_SOURCE[3]-'(stdin)'}:${BASH_LINENO[2]}$sgr0
+ ble/util/print "$locate (bleopt): The option '$sgr2$1$sgr0' has been renamed. Please use '$sgr3$2$sgr0' instead." >&2
+ if ble/is-function bleopt/check:"$2"; then
+ bleopt/check:"$2"
+ return "$?"
+ fi
+ return 0
+}
+function bleopt/declare {
+ local type=$1 name=bleopt_$2 default_value=$3
+ case $type in
+ (-o)
+ builtin eval -- "$name='[obsolete: renamed to $3]'"
+ builtin eval -- "function bleopt/check:$2 { bleopt/declare/.check-renamed-option $2 $3; }"
+ builtin eval -- "function bleopt/obsolete:$2 { :; }" ;;
+ (-n)
+ builtin eval -- "_ble_opt_def_$2=\$3"
+ builtin eval -- ": \"\${$name:=\$default_value}\"" ;;
+ (*)
+ builtin eval -- "_ble_opt_def_$2=\$3"
+ builtin eval -- ": \"\${$name=\$default_value}\"" ;;
+ esac
+ return 0
+}
+function bleopt/reinitialize {
+ local name=$1
+ local defname=_ble_opt_def_$name
+ local varname=bleopt_$name
+ [[ ${!defname+set} ]] || return 1
+ [[ ${!varname} == "${!defname}" ]] && return 0
+ ble/is-function bleopt/obsolete:"$name" && return 0
+ ble/is-function bleopt/check:"$name" || return 0
+ local value=${!varname}
+ builtin eval -- "$varname=\$$defname"
+ bleopt/check:"$name" &&
+ builtin eval "$varname=\$value"
+}
+bleopt/declare -n input_encoding UTF-8
+function bleopt/check:input_encoding {
+ if ! ble/is-function "ble/encoding:$value/decode"; then
+ ble/util/print "bleopt: Invalid value input_encoding='$value'." \
+ "A function 'ble/encoding:$value/decode' is not defined." >&2
+ return 1
+ elif ! ble/is-function "ble/encoding:$value/b2c"; then
+ ble/util/print "bleopt: Invalid value input_encoding='$value'." \
+ "A function 'ble/encoding:$value/b2c' is not defined." >&2
+ return 1
+ elif ! ble/is-function "ble/encoding:$value/c2bc"; then
+ ble/util/print "bleopt: Invalid value input_encoding='$value'." \
+ "A function 'ble/encoding:$value/c2bc' is not defined." >&2
+ return 1
+ elif ! ble/is-function "ble/encoding:$value/generate-binder"; then
+ ble/util/print "bleopt: Invalid value input_encoding='$value'." \
+ "A function 'ble/encoding:$value/generate-binder' is not defined." >&2
+ return 1
+ elif ! ble/is-function "ble/encoding:$value/is-intermediate"; then
+ ble/util/print "bleopt: Invalid value input_encoding='$value'." \
+ "A function 'ble/encoding:$value/is-intermediate' is not defined." >&2
+ return 1
+ fi
+ if [[ $bleopt_input_encoding != "$value" ]]; then
+ local bleopt_input_encoding=$value
+ ble/decode/rebind
+ fi
+ return 0
+}
+bleopt/declare -v internal_stackdump_enabled 0
+bleopt/declare -n openat_base 30
+bleopt/declare -v pager ''
+bleopt/declare -v editor ''
+shopt -s checkwinsize
+function ble/util/setexit { return "$1"; }
+_ble_util_upvar_setup='local var=ret ret; [[ $1 == -v ]] && var=$2 && shift 2'
+_ble_util_upvar='local "${var%%\[*\]}" && ble/util/upvar "$var" "$ret"'
+if ((_ble_bash>=50000)); then
+ function ble/util/unlocal {
+ if shopt -q localvar_unset; then
+ shopt -u localvar_unset
+ builtin unset -v "$@"
+ shopt -s localvar_unset
+ else
+ builtin unset -v "$@"
+ fi
+ }
+ function ble/util/upvar { ble/util/unlocal "${1%%\[*\]}" && builtin eval "$1=\"\$2\""; }
+ function ble/util/uparr { ble/util/unlocal "$1" && builtin eval "$1=(\"\${@:2}\")"; }
+else
+ function ble/util/unlocal { builtin unset -v "$@"; }
+ function ble/util/upvar { builtin unset -v "${1%%\[*\]}" && builtin eval "$1=\"\$2\""; }
+ function ble/util/uparr { builtin unset -v "$1" && builtin eval "$1=(\"\${@:2}\")"; }
+fi
+function ble/util/save-vars {
+ local __name __prefix=$1; shift
+ for __name; do
+ if ble/is-array "$__name"; then
+ builtin eval "$__prefix$__name=(\"\${$__name[@]}\")"
+ else
+ builtin eval "$__prefix$__name=\"\$$__name\""
+ fi
+ done
+}
+function ble/util/restore-vars {
+ local __name __prefix=$1; shift
+ for __name; do
+ if ble/is-array "$__prefix$__name"; then
+ builtin eval "$__name=(\"\${$__prefix$__name[@]}\")"
+ else
+ builtin eval "$__name=\"\$$__prefix$__name\""
+ fi
+ done
+}
+function ble/debug/setdbg {
+ ble/bin/rm -f "$_ble_base_run/dbgerr"
+ local ret
+ ble/util/readlink /proc/self/fd/3 3>&1
+ ln -s "$ret" "$_ble_base_run/dbgerr"
+}
+function ble/debug/print {
+ if [[ -e $_ble_base_run/dbgerr ]]; then
+ ble/util/print "$1" >> "$_ble_base_run/dbgerr"
+ else
+ ble/util/print "$1" >&2
+ fi
+}
+_ble_debug_check_leak_variable='local @var=__t1wJltaP9nmow__'
+function ble/debug/.check-leak-variable {
+ if [[ ${!1} != __t1wJltaP9nmow__ ]]; then
+ local IFS=$_ble_term_IFS
+ ble/util/print "$1=${!1}:${*:2}" >> a.txt # DEBUG_LEAKVAR
+ builtin eval "$1=__t1wJltaP9nmow__"
+ fi
+}
+function ble/debug/.list-leak-variable {
+ local _ble_local_exclude_file=${_ble_base_repository:-$_ble_base}/make/debug.leakvar.exclude-list.txt
+ if [[ ! -f $_ble_local_exclude_file ]]; then
+ ble/util/print "$_ble_local_exclude_file: not found." >&2
+ return 1
+ fi
+ set | ble/bin/grep -Eo '^[[:alnum:]_]+=' | ble/bin/grep -Evf "$_ble_local_exclude_file"
+}
+function ble/debug/print-variables/.append {
+ local q=\' Q="'\''"
+ _ble_local_out=$_ble_local_out"$1='${2//$q/$Q}'"
+}
+function ble/debug/print-variables/.append-array {
+ local ret; ble/string#quote-words "${@:2}"
+ _ble_local_out=$_ble_local_out"$1=($ret)"
+}
+function ble/debug/print-variables {
+ (($#)) || return 0
+ local flags= tag= arg
+ local -a _ble_local_vars=()
+ while (($#)); do
+ arg=$1; shift
+ case $arg in
+ (-t) tag=$1; shift ;;
+ (-*) ble/util/print "print-variables: unknown option '$arg'" >&2
+ flags=${flags}e ;;
+ (*) ble/array#push _ble_local_vars "$arg" ;;
+ esac
+ done
+ [[ $flags == *e* ]] && return 1
+ local _ble_local_out= _ble_local_var=
+ [[ $tag ]] && _ble_local_out="$tag: "
+ ble/util/unlocal flags tag arg
+ for _ble_local_var in "${_ble_local_vars[@]}"; do
+ if ble/is-array "$_ble_local_var"; then
+ builtin eval -- "ble/debug/print-variables/.append-array \"\$_ble_local_var\" \"\${$_ble_local_var[@]}\""
+ else
+ ble/debug/print-variables/.append "$_ble_local_var" "${!_ble_local_var}"
+ fi
+ _ble_local_out=$_ble_local_out' '
+ done
+ ble/debug/print "${_ble_local_out%' '}"
+}
+if ((_ble_bash>=40400)); then
+ function ble/variable#get-attr { attr=${!1@a}; }
+ function ble/variable#has-attr { [[ ${!1@a} == *["$2"]* ]]; }
+else
+ function ble/variable#get-attr {
+ attr=
+ local __ble_tmp=$1
+ ble/util/assign __ble_tmp 'declare -p "$__ble_tmp" 2>/dev/null'
+ local rex='^declare -([a-zA-Z]*)'
+ [[ $__ble_tmp =~ $rex ]] && attr=${BASH_REMATCH[1]}
+ return 0
+ }
+ function ble/variable#has-attr {
+ local __ble_tmp=$1
+ ble/util/assign __ble_tmp 'declare -p "$__ble_tmp" 2>/dev/null'
+ local rex='^declare -([a-zA-Z]*)'
+ [[ $__ble_tmp =~ $rex && ${BASH_REMATCH[1]} == *["$2"]* ]]
+ }
+fi
+function ble/is-inttype { ble/variable#has-attr "$1" i; }
+function ble/is-readonly { ble/variable#has-attr "$1" r; }
+function ble/is-transformed { ble/variable#has-attr "$1" luc; }
+function ble/variable#is-global/.test { ! local "$1" 2>/dev/null; }
+function ble/variable#is-global {
+ (readonly "$1"; ble/variable#is-global/.test "$1")
+}
+function ble/variable#copy-state {
+ local src=$1 dst=$2
+ if [[ ${!src+set} ]]; then
+ builtin eval -- "$dst=\${$src}"
+ else
+ builtin unset -v "$dst[0]" 2>/dev/null || builtin unset -v "$dst"
+ fi
+}
+_ble_array_prototype=()
+function ble/array#reserve-prototype {
+ local n=$1 i
+ for ((i=${#_ble_array_prototype[@]};i<n;i++)); do
+ _ble_array_prototype[i]=
+ done
+}
+if ((_ble_bash>=40400)); then
+ function ble/is-array { [[ ${!1@a} == *a* ]]; }
+ function ble/is-assoc { [[ ${!1@a} == *A* ]]; }
+else
+ function ble/is-array {
+ local "decl$1"
+ ble/util/assign "decl$1" "declare -p $1" 2>/dev/null || return 1
+ local rex='^declare -[b-zA-Z]*a'
+ builtin eval "[[ \$decl$1 =~ \$rex ]]"
+ }
+ function ble/is-assoc {
+ local "decl$1"
+ ble/util/assign "decl$1" "declare -p $1" 2>/dev/null || return 1
+ local rex='^declare -[a-zB-Z]*A'
+ builtin eval "[[ \$decl$1 =~ \$rex ]]"
+ }
+ ((_ble_bash>=40000)) ||
+ function ble/is-assoc { false; }
+fi
+function ble/array#set { builtin eval "$1=(\"\${@:2}\")"; }
+if ((_ble_bash>=40000)); then
+ function ble/array#push {
+ builtin eval "$1+=(\"\${@:2}\")"
+ }
+elif ((_ble_bash>=30100)); then
+ function ble/array#push {
+ IFS=$_ble_term_IFS builtin eval "$1+=(\"\${@:2}\")"
+ }
+else
+ function ble/array#push {
+ while (($#>=2)); do
+ builtin eval -- "$1[\${#$1[@]}]=\"\$2\""
+ set -- "$1" "${@:3}"
+ done
+ }
+fi
+function ble/array#pop {
+ builtin eval "local i$1=\$((\${#$1[@]}-1))"
+ if ((i$1>=0)); then
+ builtin eval "ret=\${$1[i$1]}"
+ builtin unset -v "$1[i$1]"
+ return 0
+ else
+ ret=
+ return 1
+ fi
+}
+function ble/array#unshift {
+ builtin eval -- "$1=(\"\${@:2}\" \"\${$1[@]}\")"
+}
+function ble/array#shift {
+ builtin eval -- "$1=(\"\${$1[@]:$((${2:-1}))}\")"
+}
+function ble/array#reverse {
+ builtin eval "
+ set -- \"\${$1[@]}\"; $1=()
+ local e$1 i$1=\$#
+ for e$1; do $1[--i$1]=\"\$e$1\"; done"
+}
+function ble/array#insert-at {
+ builtin eval "$1=(\"\${$1[@]::$2}\" \"\${@:3}\" \"\${$1[@]:$2}\")"
+}
+function ble/array#insert-after {
+ local _ble_local_script='
+ local iARR=0 eARR aARR=
+ for eARR in "${ARR[@]}"; do
+ ((iARR++))
+ [[ $eARR == "$2" ]] && aARR=iARR && break
+ done
+ [[ $aARR ]] && ble/array#insert-at "$1" "$aARR" "${@:3}"
+ '; builtin eval -- "${_ble_local_script//ARR/$1}"
+}
+function ble/array#insert-before {
+ local _ble_local_script='
+ local iARR=0 eARR aARR=
+ for eARR in "${ARR[@]}"; do
+ [[ $eARR == "$2" ]] && aARR=iARR && break
+ ((iARR++))
+ done
+ [[ $aARR ]] && ble/array#insert-at "$1" "$aARR" "${@:3}"
+ '; builtin eval -- "${_ble_local_script//ARR/$1}"
+}
+function ble/array#filter {
+ local _ble_local_script='
+ local -a aARR=() eARR
+ for eARR in "${ARR[@]}"; do
+ "$2" "$eARR" && ble/array#push "aARR" "$eARR"
+ done
+ ARR=("${aARR[@]}")
+ '; builtin eval -- "${_ble_local_script//ARR/$1}"
+}
+function ble/array#filter/not.predicate { ! "$_ble_local_pred" "$1"; }
+function ble/array#remove-if {
+ local _ble_local_pred=$2
+ ble/array#filter "$1" ble/array#filter/not.predicate
+}
+function ble/array#filter/regex.predicate { [[ $1 =~ $_ble_local_rex ]]; }
+function ble/array#filter-by-regex {
+ local _ble_local_rex=$2
+ local LC_ALL= LC_COLLATE=C 2>/dev/null
+ ble/array#filter "$1" ble/array#filter/regex.predicate
+ ble/util/unlocal LC_COLLATE LC_ALL 2>/dev/null
+}
+function ble/array#remove-by-regex {
+ local _ble_local_rex=$2
+ local LC_ALL= LC_COLLATE=C 2>/dev/null
+ ble/array#remove-if "$1" ble/array#filter/regex.predicate
+ ble/util/unlocal LC_COLLATE LC_ALL 2>/dev/null
+}
+function ble/array#filter/glob.predicate { [[ $1 == $_ble_local_glob ]]; }
+function ble/array#filter-by-glob {
+ local _ble_local_glob=$2
+ local LC_ALL= LC_COLLATE=C 2>/dev/null
+ ble/array#filter "$1" ble/array#filter/glob.predicate
+ ble/util/unlocal LC_COLLATE LC_ALL 2>/dev/null
+}
+function ble/array#remove-by-glob {
+ local _ble_local_glob=$2
+ local LC_ALL= LC_COLLATE=C 2>/dev/null
+ ble/array#remove-if "$1" ble/array#filter/glob.predicate
+ ble/util/unlocal LC_COLLATE LC_ALL 2>/dev/null
+}
+function ble/array#remove/.predicate { [[ $1 != "$_ble_local_value" ]]; }
+function ble/array#remove {
+ local _ble_local_value=$2
+ ble/array#filter "$1" ble/array#remove/.predicate
+}
+function ble/array#index {
+ local _ble_local_script='
+ local eARR iARR=0
+ for eARR in "${ARR[@]}"; do
+ if [[ $eARR == "$2" ]]; then ret=$iARR; return 0; fi
+ ((++iARR))
+ done
+ ret=-1; return 1
+ '; builtin eval -- "${_ble_local_script//ARR/$1}"
+}
+function ble/array#last-index {
+ local _ble_local_script='
+ local eARR iARR=${#ARR[@]}
+ while ((iARR--)); do
+ [[ ${ARR[iARR]} == "$2" ]] && { ret=$iARR; return 0; }
+ done
+ ret=-1; return 1
+ '; builtin eval -- "${_ble_local_script//ARR/$1}"
+}
+function ble/array#remove-at {
+ local _ble_local_script='
+ builtin unset -v "ARR[$2]"
+ ARR=("${ARR[@]}")
+ '; builtin eval -- "${_ble_local_script//ARR/$1}"
+}
+function ble/array#fill-range {
+ ble/array#reserve-prototype $(($3-$2))
+ local _ble_script='
+ local -a sARR; sARR=("${_ble_array_prototype[@]::$3-$2}")
+ ARR=("${ARR[@]::$2}" "${sARR[@]/#/$4}" "${ARR[@]:$3}")' # WA #D1570 #D1738 checked
+ ((_ble_bash>=40300)) && ! shopt -q compat42 &&
+ _ble_script=${_ble_script//'$4'/'"$4"'}
+ builtin eval -- "${_ble_script//ARR/$1}"
+}
+function ble/idict#replace {
+ local _ble_local_script='
+ local iARR=0 extARR=1
+ for iARR in "${!ARR[@]}"; do
+ [[ ${ARR[iARR]} == "$2" ]] || continue
+ extARR=0
+ if (($#>=3)); then
+ ARR[iARR]=$3
+ else
+ builtin unset -v '\''ARR[iARR]'\''
+ fi
+ done
+ return "$extARR"
+ '; builtin eval -- "${_ble_local_script//ARR/$1}"
+}
+function ble/idict#copy {
+ local _ble_script='
+ '$1'=()
+ local i'$1$2'
+ for i'$1$2' in "${!'$2'[@]}"; do
+ '$1'[i'$1$2']=${'$2'[i'$1$2']}
+ done'
+ builtin eval -- "$_ble_script"
+}
+_ble_string_prototype=' '
+function ble/string#reserve-prototype {
+ local n=$1 c
+ for ((c=${#_ble_string_prototype};c<n;c*=2)); do
+ _ble_string_prototype=$_ble_string_prototype$_ble_string_prototype
+ done
+}
+function ble/string#repeat {
+ ble/string#reserve-prototype "$2"
+ ret=${_ble_string_prototype::$2}
+ ret=${ret// /"$1"}
+}
+function ble/string#common-prefix {
+ local a=$1 b=$2
+ ((${#a}>${#b})) && local a=$b b=$a
+ b=${b::${#a}}
+ if [[ $a == "$b" ]]; then
+ ret=$a
+ return 0
+ fi
+ local l=0 u=${#a} m
+ while ((l+1<u)); do
+ ((m=(l+u)/2))
+ if [[ ${a::m} == "${b::m}" ]]; then
+ ((l=m))
+ else
+ ((u=m))
+ fi
+ done
+ ret=${a::l}
+}
+function ble/string#common-suffix {
+ local a=$1 b=$2
+ ((${#a}>${#b})) && local a=$b b=$a
+ b=${b:${#b}-${#a}}
+ if [[ $a == "$b" ]]; then
+ ret=$a
+ return 0
+ fi
+ local l=0 u=${#a} m
+ while ((l+1<u)); do
+ ((m=(l+u+1)/2))
+ if [[ ${a:m} == "${b:m}" ]]; then
+ ((u=m))
+ else
+ ((l=m))
+ fi
+ done
+ ret=${a:u}
+}
+function ble/string#split {
+ if [[ -o noglob ]]; then
+ IFS=$2 builtin eval "$1=(\${*:3}\$2)"
+ else
+ set -f
+ IFS=$2 builtin eval "$1=(\${*:3}\$2)"
+ set +f
+ fi
+}
+function ble/string#split-words {
+ if [[ -o noglob ]]; then
+ IFS=$_ble_term_IFS builtin eval "$1=(\${*:2})"
+ else
+ set -f
+ IFS=$_ble_term_IFS builtin eval "$1=(\${*:2})"
+ set +f
+ fi
+}
+if ((_ble_bash>=40000)); then
+ function ble/string#split-lines {
+ mapfile -t "$1" <<< "$2"
+ }
+else
+ function ble/string#split-lines {
+ ble/util/mapfile "$1" <<< "$2"
+ }
+fi
+function ble/string#count-char {
+ local text=$1 char=$2
+ text=${text//[!"$char"]}
+ ret=${#text}
+}
+function ble/string#count-string {
+ local text=${1//"$2"}
+ ((ret=(${#1}-${#text})/${#2}))
+}
+function ble/string#index-of {
+ local haystack=$1 needle=$2 count=${3:-1}
+ ble/string#repeat '*"$needle"' "$count"; local pattern=$ret
+ builtin eval "local transformed=\${haystack#$pattern}"
+ ((ret=${#haystack}-${#transformed}-${#needle},
+ ret<0&&(ret=-1),ret>=0))
+}
+function ble/string#last-index-of {
+ local haystack=$1 needle=$2 count=${3:-1}
+ ble/string#repeat '"$needle"*' "$count"; local pattern=$ret
+ builtin eval "local transformed=\${haystack%$pattern}"
+ if [[ $transformed == "$haystack" ]]; then
+ ret=-1
+ else
+ ret=${#transformed}
+ fi
+ ((ret>=0))
+}
+_ble_util_string_lower_list=abcdefghijklmnopqrstuvwxyz
+_ble_util_string_upper_list=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+function ble/string#toggle-case.impl {
+ local LC_ALL= LC_COLLATE=C
+ local text=$1 ch i
+ local -a buff
+ for ((i=0;i<${#text};i++)); do
+ ch=${text:i:1}
+ if [[ $ch == [A-Z] ]]; then
+ ch=${_ble_util_string_upper_list%%"$ch"*}
+ ch=${_ble_util_string_lower_list:${#ch}:1}
+ elif [[ $ch == [a-z] ]]; then
+ ch=${_ble_util_string_lower_list%%"$ch"*}
+ ch=${_ble_util_string_upper_list:${#ch}:1}
+ fi
+ ble/array#push buff "$ch"
+ done
+ IFS= builtin eval 'ret="${buff[*]-}"'
+}
+function ble/string#toggle-case {
+ ble/string#toggle-case.impl "$1" 2>/dev/null # suppress locale error #D1440
+}
+if ((_ble_bash>=40000)); then
+ function ble/string#tolower { ret=${1,,}; }
+ function ble/string#toupper { ret=${1^^}; }
+else
+ function ble/string#tolower.impl {
+ local LC_ALL= LC_COLLATE=C
+ local i text=$1 ch
+ local -a buff=()
+ for ((i=0;i<${#text};i++)); do
+ ch=${text:i:1}
+ if [[ $ch == [A-Z] ]]; then
+ ch=${_ble_util_string_upper_list%%"$ch"*}
+ ch=${_ble_util_string_lower_list:${#ch}:1}
+ fi
+ ble/array#push buff "$ch"
+ done
+ IFS= builtin eval 'ret="${buff[*]-}"'
+ }
+ function ble/string#toupper.impl {
+ local LC_ALL= LC_COLLATE=C
+ local i text=$1 ch
+ local -a buff=()
+ for ((i=0;i<${#text};i++)); do
+ ch=${text:i:1}
+ if [[ $ch == [a-z] ]]; then
+ ch=${_ble_util_string_lower_list%%"$ch"*}
+ ch=${_ble_util_string_upper_list:${#ch}:1}
+ fi
+ ble/array#push buff "$ch"
+ done
+ IFS= builtin eval 'ret="${buff[*]-}"'
+ }
+ function ble/string#tolower {
+ ble/string#tolower.impl "$1" 2>/dev/null # suppress locale error #D1440
+ }
+ function ble/string#toupper {
+ ble/string#toupper.impl "$1" 2>/dev/null # suppress locale error #D1440
+ }
+fi
+function ble/string#capitalize {
+ local tail=$1
+ local rex='^[^a-zA-Z0-9]*'
+ [[ $tail =~ $rex ]]
+ local out=$BASH_REMATCH
+ tail=${tail:${#BASH_REMATCH}}
+ rex='^[a-zA-Z0-9]+[^a-zA-Z0-9]*'
+ while [[ $tail =~ $rex ]]; do
+ local rematch=$BASH_REMATCH
+ ble/string#toupper "${rematch::1}"; out=$out$ret
+ ble/string#tolower "${rematch:1}" ; out=$out$ret
+ tail=${tail:${#rematch}}
+ done
+ ret=$out$tail
+}
+function ble/string#trim {
+ ret=$1
+ local rex=$'^[ \t\n]+'
+ [[ $ret =~ $rex ]] && ret=${ret:${#BASH_REMATCH}}
+ local rex=$'[ \t\n]+$'
+ [[ $ret =~ $rex ]] && ret=${ret::${#ret}-${#BASH_REMATCH}}
+}
+function ble/string#ltrim {
+ ret=$1
+ local rex=$'^[ \t\n]+'
+ [[ $ret =~ $rex ]] && ret=${ret:${#BASH_REMATCH}}
+}
+function ble/string#rtrim {
+ ret=$1
+ local rex=$'[ \t\n]+$'
+ [[ $ret =~ $rex ]] && ret=${ret::${#ret}-${#BASH_REMATCH}}
+}
+if ((_ble_bash>=50200)); then
+ function ble/string#escape-characters {
+ ret=$1
+ if [[ $ret == *["$2"]* ]]; then
+ if [[ ! $3 ]]; then
+ local patsub_replacement=
+ shopt -q patsub_replacement && patsub_replacement=1
+ shopt -s patsub_replacement
+ ret=${ret//["$2"]/\\&} # #D1738 patsub_replacement
+ [[ $patsub_replacement ]] || shopt -u patsub_replacement
+ else
+ local chars1=$2 chars2=${3:-$2}
+ local i n=${#chars1} a b
+ for ((i=0;i<n;i++)); do
+ a=${chars1:i:1} b=\\${chars2:i:1} ret=${ret//"$a"/"$b"}
+ done
+ fi
+ fi
+ }
+else
+ function ble/string#escape-characters {
+ ret=$1
+ if [[ $ret == *["$2"]* ]]; then
+ local chars1=$2 chars2=${3:-$2}
+ local i n=${#chars1} a b
+ for ((i=0;i<n;i++)); do
+ a=${chars1:i:1} b=\\${chars2:i:1} ret=${ret//"$a"/"$b"}
+ done
+ fi
+ }
+fi
+function ble/string#escape-for-sed-regex {
+ ble/string#escape-characters "$1" '\.[*^$/'
+}
+function ble/string#escape-for-awk-regex {
+ ble/string#escape-characters "$1" '\.[*?+|^$(){}/'
+}
+function ble/string#escape-for-extended-regex {
+ ble/string#escape-characters "$1" '\.[*?+|^$(){}'
+}
+function ble/string#escape-for-bash-glob {
+ ble/string#escape-characters "$1" '\*?[('
+}
+function ble/string#escape-for-bash-single-quote {
+ local q="'" Q="'\''"
+ ret=${1//$q/$Q}
+}
+function ble/string#escape-for-bash-double-quote {
+ ble/string#escape-characters "$1" '\"$`'
+ local a b
+ a='!' b='"\!"' ret=${ret//"$a"/"$b"} # WA #D1751 checked
+}
+function ble/string#escape-for-bash-escape-string {
+ ble/string#escape-characters "$1" $'\\\a\b\e\f\n\r\t\v'\' '\abefnrtv'\'
+}
+function ble/string#escape-for-bash-specialchars {
+ local chars='\ "'\''`$|&;<>()!^'
+ [[ $2 != *G* ]] && chars=$chars'*?['
+ [[ $2 == *c* ]] && chars=$chars'=:'
+ [[ $2 == *b* ]] && chars=$chars'{,}'
+ ble/string#escape-characters "$1" "$chars"
+ [[ $2 != *[HT]* && $ret == '~'* ]] && ret=\\$ret
+ [[ $2 != *H* && $ret == '#'* ]] && ret=\\$ret
+ if [[ $ret == *[$']\n\t']* ]]; then
+ local a b
+ a=']' b=\\$a ret=${ret//"$a"/"$b"}
+ a=$'\n' b="\$'\n'" ret=${ret//"$a"/"$b"} # WA #D1751 checked
+ a=$'\t' b=$'\\\t' ret=${ret//"$a"/"$b"}
+ fi
+ if [[ $2 == *G* ]] && shopt -q extglob; then
+ a='!\(' b='!(' ret=${ret//"$a"/"$b"}
+ a='@\(' b='@(' ret=${ret//"$a"/"$b"}
+ a='?\(' b='?(' ret=${ret//"$a"/"$b"}
+ a='*\(' b='*(' ret=${ret//"$a"/"$b"}
+ a='+\(' b='+(' ret=${ret//"$a"/"$b"}
+ fi
+}
+function ble/string#escape-for-display {
+ local head= tail=$1 opts=$2
+ local sgr0= sgr1=
+ local rex_csi=$'\e\\[[ -?]*[@-~]'
+ if [[ :$opts: == *:revert:* ]]; then
+ ble/color/g2sgr "$_ble_color_gflags_Revert"
+ sgr1=$ret sgr0=$_ble_term_sgr0
+ else
+ if local rex=':sgr1=(('$rex_csi'|[^:])*):'; [[ :$opts: =~ $rex ]]; then
+ sgr1=${BASH_REMATCH[1]} sgr0=$_ble_term_sgr0
+ fi
+ if local rex=':sgr0=(('$rex_csi'|[^:])*):'; [[ :$opts: =~ $rex ]]; then
+ sgr0=${BASH_REMATCH[1]}
+ fi
+ fi
+ while [[ $tail ]]; do
+ if ble/util/isprint+ "$tail"; then
+ head=$head${BASH_REMATCH}
+ tail=${tail:${#BASH_REMATCH}}
+ else
+ ble/util/s2c "${tail::1}"
+ local code=$ret
+ if ((code<32)); then
+ ble/util/c2s $((code+64))
+ ret=$sgr1^$ret$sgr0
+ elif ((code==127)); then
+ ret=$sgr1^?$sgr0
+ elif ((128<=code&&code<160)); then
+ ble/util/c2s $((code-64))
+ ret=${sgr1}M-^$ret$sgr0
+ else
+ ret=${tail::1}
+ fi
+ head=$head$ret
+ tail=${tail:1}
+ fi
+ done
+ ret=$head
+}
+if ((_ble_bash>=40400)); then
+ function ble/string#quote-words {
+ local IFS=$_ble_term_IFS
+ ret="${*@Q}"
+ }
+ function ble/string#quote-command {
+ local IFS=$_ble_term_IFS
+ ret=$1; shift
+ (($#)) && ret="$ret ${*@Q}"
+ }
+else
+ function ble/string#quote-words {
+ local q=\' Q="'\''" IFS=$_ble_term_IFS
+ ret=("${@//$q/$Q}")
+ ret=("${ret[@]/%/$q}") # WA #D1570 #D1738 ok
+ ret="${ret[*]/#/$q}" # WA #D1570 #D1738 ok
+ }
+ function ble/string#quote-command {
+ if (($#<=1)); then
+ ret=$1
+ return
+ fi
+ local q=\' Q="'\''" IFS=$_ble_term_IFS
+ ret=("${@:2}")
+ ret=("${ret[@]//$q/$Q}") # WA #D1570 #D1738 ok
+ ret=("${ret[@]/%/$q}") # WA #D1570 #D1738 ok
+ ret="$1 ${ret[*]/#/$q}" # WA #D1570 #D1738 ok
+ }
+fi
+function ble/string#quote-word {
+ ret=$1
+ local rex_csi=$'\e\\[[ -?]*[@-~]'
+ local opts=$2 sgrq= sgr0=
+ if [[ $opts ]]; then
+ local rex=':sgrq=(('$rex_csi'|[^:])*):'
+ [[ :$opts: =~ $rex ]] &&
+ sgrq=${BASH_REMATCH[1]} sgr0=$_ble_term_sgr0
+ rex=':sgr0=(('$rex_csi'|[^:])*):'
+ if [[ :$opts: =~ $rex ]]; then
+ sgr0=${BASH_REMATCH[1]}
+ elif [[ :$opts: == *:ansi:* ]]; then
+ sgr0=$'\e[m'
+ fi
+ fi
+ if [[ ! $ret ]]; then
+ [[ :$opts: == *:quote-empty:* ]] &&
+ ret=$sgrq\'\'$sgr0
+ return
+ fi
+ local chars=$'\a\b\e\f\n\r\t\v'
+ if [[ $ret == *["$chars"]* ]]; then
+ ble/string#escape-for-bash-escape-string "$ret"
+ ret=$sgrq\$\'$ret\'$sgr0
+ return
+ fi
+ local chars=$_ble_term_IFS'"`$\<>()|&;*?[]!^=:{,}#~' q=\'
+ if [[ $ret == *["$chars"]* ]]; then
+ local Q="'$sgr0\'$sgrq'"
+ ret=$sgrq$q${ret//$q/$Q}$q$sgr0
+ ret=${ret#"$sgrq$q$q$sgr0"} ret=${ret%"$sgrq$q$q$sgr0"}
+ elif [[ $ret == *["$q"]* ]]; then
+ local Q="\'"
+ ret=${ret//$q/$Q}
+ fi
+}
+function ble/string#match { [[ $1 =~ $2 ]]; }
+function ble/string#create-unicode-progress-bar/.block {
+ local block=$1
+ if ((block<=0)); then
+ ble/util/c2w $((0x2588))
+ ble/string#repeat ' ' "$ret"
+ elif ((block>=8)); then
+ ble/util/c2s $((0x2588))
+ ((${#ret}==1)) || ret='*' # LC_CTYPE が非対応の文字の時
+ else
+ ble/util/c2s $((0x2590-block))
+ if ((${#ret}!=1)); then
+ ble/util/c2w $((0x2588))
+ ble/string#repeat ' ' $((ret-1))
+ ret=$block$ret
+ fi
+ fi
+}
+function ble/string#create-unicode-progress-bar {
+ local value=$1 max=$2 width=$3 opts=:$4:
+ local opt_unlimited=
+ if [[ $opts == *:unlimited:* ]]; then
+ opt_unlimited=1
+ ((value%=max,width--))
+ fi
+ local progress=$((value*8*width/max))
+ local progress_fraction=$((progress%8)) progress_integral=$((progress/8))
+ local out=
+ if ((progress_integral)); then
+ if [[ $opt_unlimited ]]; then
+ ble/string#create-unicode-progress-bar/.block 0
+ else
+ ble/string#create-unicode-progress-bar/.block 8
+ fi
+ ble/string#repeat "$ret" "$progress_integral"
+ out=$ret
+ fi
+ if ((progress_fraction)); then
+ if [[ $opt_unlimited ]]; then
+ ble/string#create-unicode-progress-bar/.block "$progress_fraction"
+ out=$out$'\e[7m'$ret$'\e[27m'
+ fi
+ ble/string#create-unicode-progress-bar/.block "$progress_fraction"
+ out=$out$ret
+ ((progress_integral++))
+ else
+ if [[ $opt_unlimited ]]; then
+ ble/string#create-unicode-progress-bar/.block 8
+ out=$out$ret
+ fi
+ fi
+ if ((progress_integral<width)); then
+ ble/string#create-unicode-progress-bar/.block 0
+ ble/string#repeat "$ret" $((width-progress_integral))
+ out=$out$ret
+ fi
+ ret=$out
+}
+function ble/util/strlen.impl {
+ local LC_ALL= LC_CTYPE=C
+ ret=${#1}
+}
+function ble/util/strlen {
+ ble/util/strlen.impl "$@" 2>/dev/null # suppress locale error #D1440
+}
+function ble/util/substr.impl {
+ local LC_ALL= LC_CTYPE=C
+ ret=${1:$2:$3}
+}
+function ble/util/substr {
+ ble/util/substr.impl "$@" 2>/dev/null # suppress locale error #D1440
+}
+function ble/path#append {
+ local _ble_local_script='opts=$opts${opts:+:}$2'
+ _ble_local_script=${_ble_local_script//opts/"$1"}
+ builtin eval -- "$_ble_local_script"
+}
+function ble/path#prepend {
+ local _ble_local_script='opts=$2${opts:+:}$opts'
+ _ble_local_script=${_ble_local_script//opts/"$1"}
+ builtin eval -- "$_ble_local_script"
+}
+function ble/path#remove {
+ [[ $2 ]] || return 1
+ local _ble_local_script='
+ opts=:${opts//:/::}:
+ opts=${opts//:"$2":}
+ opts=${opts//::/:} opts=${opts#:} opts=${opts%:}'
+ _ble_local_script=${_ble_local_script//opts/"$1"}
+ builtin eval -- "$_ble_local_script"
+}
+function ble/path#remove-glob {
+ [[ $2 ]] || return 1
+ local _ble_local_script='
+ opts=:${opts//:/::}:
+ opts=${opts//:$2:}
+ opts=${opts//::/:} opts=${opts#:} opts=${opts%:}'
+ _ble_local_script=${_ble_local_script//opts/"$1"}
+ builtin eval -- "$_ble_local_script"
+}
+function ble/path#contains {
+ builtin eval "[[ :\${$1}: == *:\"\$2\":* ]]"
+}
+function ble/opts#has {
+ local rex=':'$2'[=[]'
+ [[ :$1: =~ $rex ]]
+}
+function ble/opts#extract-first-optarg {
+ ret=
+ local rex=':'$2'(=[^:]*)?:'
+ [[ :$1: =~ $rex ]] || return 1
+ if [[ ${BASH_REMATCH[1]} ]]; then
+ ret=${BASH_REMATCH[1]:1}
+ elif [[ ${3+set} ]]; then
+ ret=$3
+ fi
+ return 0
+}
+function ble/opts#extract-last-optarg {
+ ret=
+ local rex='.*:'$2'(=[^:]*)?:'
+ [[ :$1: =~ $rex ]] || return 1
+ if [[ ${BASH_REMATCH[1]} ]]; then
+ ret=${BASH_REMATCH[1]:1}
+ elif [[ ${3+set} ]]; then
+ ret=$3
+ fi
+ return 0
+}
+function ble/opts#extract-all-optargs {
+ ret=()
+ local value=:$1: rex=':'$2'(=[^:]*)?(:.*)$' count=0
+ while [[ $value =~ $rex ]]; do
+ ((count++))
+ if [[ ${BASH_REMATCH[1]} ]]; then
+ ble/array#push ret "${BASH_REMATCH[1]:1}"
+ elif [[ ${3+set} ]]; then
+ ble/array#push ret "$3"
+ fi
+ value=${BASH_REMATCH[2]}
+ done
+ ((count))
+}
+if ((_ble_bash>=40000)); then
+ _ble_util_set_declare=(declare -A NAME)
+ function ble/set#add { builtin eval -- "$1[x\$2]=1"; }
+ function ble/set#remove { builtin unset -v "$1[x\$2]"; }
+ function ble/set#contains { builtin eval "[[ \${$1[x\$2]+set} ]]"; }
+else
+ _ble_util_set_declare=(declare NAME)
+ function ble/set#.escape {
+ _ble_local_value=${_ble_local_value//$_ble_term_FS/"$_ble_term_FS$_ble_term_FS"}
+ _ble_local_value=${_ble_local_value//:/"$_ble_term_FS."}
+ }
+ function ble/set#add {
+ local _ble_local_value=$2; ble/set#.escape
+ ble/path#append "$1" "$_ble_local_value"
+ }
+ function ble/set#remove {
+ local _ble_local_value=$2; ble/set#.escape
+ ble/path#remove "$1" "$_ble_local_value"
+ }
+ function ble/set#contains {
+ local _ble_local_value=$2; ble/set#.escape
+ builtin eval "[[ :\$$1: == *:\"\$_ble_local_value\":* ]]"
+ }
+fi
+_ble_util_adict_declare='declare NAME NAME_keylist'
+function ble/adict#.resolve {
+ _ble_local_key=$2
+ _ble_local_key=${_ble_local_key//$_ble_term_FS/"$_ble_term_FS,"}
+ _ble_local_key=${_ble_local_key//:/"$_ble_term_FS."}
+ local keylist=${1}_keylist; keylist=:${!keylist}
+ local vec=${keylist%%:"$_ble_local_key":*}
+ if [[ $vec != "$keylist" ]]; then
+ vec=${vec//[!:]}
+ _ble_local_index=${#vec}
+ else
+ _ble_local_index=-1
+ fi
+}
+function ble/adict#set {
+ local _ble_local_key _ble_local_index
+ ble/adict#.resolve "$1" "$2"
+ if ((_ble_local_index>=0)); then
+ builtin eval -- "$1[_ble_local_index]=\$3"
+ else
+ local _ble_local_script='
+ local _ble_local_vec=${NAME_keylist//[!:]}
+ NAME[${#_ble_local_vec}]=$3
+ NAME_keylist=$NAME_keylist$_ble_local_key:
+ '
+ builtin eval -- "${_ble_local_script//NAME/$1}"
+ fi
+ return 0
+}
+function ble/adict#get {
+ local _ble_local_key _ble_local_index
+ ble/adict#.resolve "$1" "$2"
+ if ((_ble_local_index>=0)); then
+ builtin eval -- "ret=\${$1[_ble_local_index]}; [[ \${$1[_ble_local_index]+set} ]]"
+ else
+ builtin eval -- ret=
+ return 1
+ fi
+}
+function ble/adict#unset {
+ local _ble_local_key _ble_local_index
+ ble/adict#.resolve "$1" "$2"
+ ((_ble_local_index>=0)) &&
+ builtin eval -- "builtin unset -v '$1[_ble_local_index]'"
+ return 0
+}
+function ble/adict#has {
+ local _ble_local_key _ble_local_index
+ ble/adict#.resolve "$1" "$2"
+ ((_ble_local_index>=0)) &&
+ builtin eval -- "[[ \${$1[_ble_local_index]+set} ]]"
+}
+function ble/adict#clear {
+ builtin eval -- "${1}_keylist= $1=()"
+}
+function ble/adict#keys {
+ local _ble_local_keylist=${1}_keylist
+ _ble_local_keylist=${!_ble_local_keylist%:}
+ ble/string#split ret : "$_ble_local_keylist"
+ if [[ $_ble_local_keylist == *"$_ble_term_FS"* ]]; then
+ ret=("${ret[@]//$_ble_term_FS./:}") # WA #D1570 checked
+ ret=("${ret[@]//$_ble_term_FS,/$_ble_term_FS}") # WA #D1570 #D1738 checked
+ fi
+ local _ble_local_keys _ble_local_i _ble_local_ref=$1[_ble_local_i]
+ _ble_local_keys=("${ret[@]}") ret=()
+ for _ble_local_i in "${!_ble_local_keys[@]}"; do
+ [[ ${_ble_local_ref+set} ]] &&
+ ble/array#push ret "${_ble_local_keys[_ble_local_i]}"
+ done
+}
+if ((_ble_bash>=40000)); then
+ _ble_util_dict_declare='declare -A NAME'
+ function ble/dict#set { builtin eval -- "$1[x\$2]=\$3"; }
+ function ble/dict#get { builtin eval -- "ret=\${$1[x\$2]-}; [[ \${$1[x\$2]+set} ]]"; }
+ function ble/dict#unset { builtin eval -- "builtin unset -v '$1[x\$2]'"; }
+ function ble/dict#has { builtin eval -- "[[ \${$1[x\$2]+set} ]]"; }
+ function ble/dict#clear { builtin eval -- "$1=()"; }
+ function ble/dict#keys { builtin eval -- 'ret=("${!'"$1"'[@]}"); ret=("${ret[@]#x}")'; }
+else
+ _ble_util_dict_declare='declare NAME NAME_keylist='
+ function ble/dict#set { ble/adict#set "$@"; }
+ function ble/dict#get { ble/adict#get "$@"; }
+ function ble/dict#unset { ble/adict#unset "$@"; }
+ function ble/dict#has { ble/adict#has "$@"; }
+ function ble/dict#clear { ble/adict#clear "$@"; }
+ function ble/dict#keys { ble/adict#keys "$@"; }
+fi
+if ((_ble_bash>=40200)); then
+ _ble_util_gdict_declare='{ builtin unset -v NAME; declare -gA NAME; NAME=(); }'
+ function ble/gdict#set { ble/dict#set "$@"; }
+ function ble/gdict#get { ble/dict#get "$@"; }
+ function ble/gdict#unset { ble/dict#unset "$@"; }
+ function ble/gdict#has { ble/dict#has "$@"; }
+ function ble/gdict#clear { ble/dict#clear "$@"; }
+ function ble/gdict#keys { ble/dict#keys "$@"; }
+elif ((_ble_bash>=40000)); then
+ _ble_util_gdict_declare='{ if ! ble/is-assoc NAME; then if local _ble_local_test 2>/dev/null; then NAME_keylist=; else builtin unset -v NAME NAME_keylist; declare -A NAME; fi fi; NAME=(); }'
+ function ble/gdict#.is-adict {
+ local keylist=${1}_keylist
+ [[ ${!keylist+set} ]]
+ }
+ function ble/gdict#set { if ble/gdict#.is-adict "$1"; then ble/adict#set "$@"; else ble/dict#set "$@"; fi; }
+ function ble/gdict#get { if ble/gdict#.is-adict "$1"; then ble/adict#get "$@"; else ble/dict#get "$@"; fi; }
+ function ble/gdict#unset { if ble/gdict#.is-adict "$1"; then ble/adict#unset "$@"; else ble/dict#unset "$@"; fi; }
+ function ble/gdict#has { if ble/gdict#.is-adict "$1"; then ble/adict#has "$@"; else ble/dict#has "$@"; fi; }
+ function ble/gdict#clear { if ble/gdict#.is-adict "$1"; then ble/adict#clear "$@"; else ble/dict#clear "$@"; fi; }
+ function ble/gdict#keys { if ble/gdict#.is-adict "$1"; then ble/adict#keys "$@"; else ble/dict#keys "$@"; fi; }
+else
+ _ble_util_gdict_declare='{ builtin unset -v NAME NAME_keylist; NAME_keylist= NAME=(); }'
+ function ble/gdict#set { ble/adict#set "$@"; }
+ function ble/gdict#get { ble/adict#get "$@"; }
+ function ble/gdict#unset { ble/adict#unset "$@"; }
+ function ble/gdict#has { ble/adict#has "$@"; }
+ function ble/gdict#clear { ble/adict#clear "$@"; }
+ function ble/gdict#keys { ble/adict#keys "$@"; }
+fi
+function ble/dict/.print {
+ declare -p "$2" &>/dev/null || return 1
+ local ret _ble_local_key _ble_local_value
+ ble/util/print "builtin eval -- \"\${_ble_util_${1}_declare//NAME/$2}\""
+ ble/"$1"#keys "$2"
+ for _ble_local_key in "${ret[@]}"; do
+ ble/"$1"#get "$2" "$_ble_local_key"
+ ble/string#quote-word "$ret" quote-empty
+ _ble_local_value=$ret
+ ble/string#quote-word "$_ble_local_key" quote-empty
+ _ble_local_key=$ret
+ ble/util/print "ble/$1#set $2 $_ble_local_key $_ble_local_value"
+ done
+}
+function ble/dict#print { ble/dict/.print dict "$1"; }
+function ble/adict#print { ble/dict/.print adict "$1"; }
+function ble/gdict#print { ble/dict/.print gdict "$1"; }
+function ble/dict/.copy {
+ local ret
+ ble/"$1"#keys "$2"
+ ble/"$1"#clear "$3"
+ local _ble_local_key
+ for _ble_local_key in "${ret[@]}"; do
+ ble/"$1"#get "$2" "$_ble_local_key"
+ ble/"$1"#set "$3" "$_ble_local_key" "$ret"
+ done
+}
+function ble/dict#cp { ble/dict/.copy dict "$1" "$2"; }
+function ble/adict#cp { ble/dict/.copy adict "$1" "$2"; }
+function ble/gdict#cp { ble/dict/.copy gdict "$1" "$2"; }
+function blehook/.print {
+ (($#)) || return
+ local out= q=\' Q="'\''" nl=$'\n'
+ local sgr0= sgr1= sgr2= sgr3=
+ if [[ $flags == *c* ]]; then
+ local ret
+ ble/color/face2sgr command_function; sgr1=$ret
+ ble/color/face2sgr syntax_varname; sgr2=$ret
+ ble/color/face2sgr syntax_quoted; sgr3=$ret
+ sgr0=$_ble_term_sgr0
+ Q=$q$sgr0"\'"$sgr3$q
+ fi
+ local elem code='
+ if ((${#_ble_hook_h_NAME[@]})); then
+ for elem in "${_ble_hook_h_NAME[@]}"; do
+ out="${out}${sgr1}blehook$sgr0 ${sgr2}NAME$sgr0+=${sgr3}$q${elem//$q/$Q}$q$sgr0$nl"
+ done
+ else
+ out="${out}${sgr1}blehook$sgr0 ${sgr2}NAME$sgr0=$nl"
+ fi'
+ local hookname
+ for hookname; do
+ ble/is-array "$hookname" || continue
+ builtin eval -- "${code//NAME/${hookname#_ble_hook_h_}}"
+ done
+ ble/util/put "$out"
+}
+function blehook/.print-help {
+ ble/util/print-lines \
+ 'usage: blehook [NAME[[=|+=|-=|-+=]COMMAND]]...' \
+ ' Add or remove hooks. Without arguments, this prints all the existing hooks.' \
+ '' \
+ ' Options:' \
+ ' --help Print this help.' \
+ ' -a, --all Print all including internal hooks.' \
+ ' --color[=always|never|auto]' \
+ ' Change color settings.' \
+ '' \
+ ' Arguments:' \
+ ' NAME Print the corresponding hooks.' \
+ ' NAME=COMMAND Set hook after removing the existing hooks.' \
+ ' NAME+=COMMAND Add hook.' \
+ ' NAME-=COMMAND Remove hook.' \
+ ' NAME!=COMMAND Add hook if the command is not registered.' \
+ ' NAME-+=COMMAND Append the hook and remove the duplicates.' \
+ ' NAME+-=COMMAND Prepend the hook and remove the duplicates.' \
+ ''
+}
+function blehook/.read-arguments {
+ flags= print=() process=()
+ local opt_color=always
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $arg == -* ]]; then
+ case $arg in
+ (--help)
+ flags=H$flags ;;
+ (--color) opt_color=always ;;
+ (--color=always|--color=auto|--color=never)
+ opt_color=${arg#*=} ;;
+ (--color=*)
+ ble/util/print "blehook: '${arg#*=}': unrecognized option argument for '--color'." >&2
+ flags=E$flags ;;
+ (--all) flags=a$flags ;;
+ (--*)
+ ble/util/print "blehook: unrecognized long option '$arg'." >&2
+ flags=E$flags ;;
+ (-)
+ ble/util/print "blehook: unrecognized argument '$arg'." >&2
+ flags=E$flags ;;
+ (*)
+ local i c
+ for ((i=1;i<${#arg};i++)); do
+ c=${arg:i:1}
+ case $c in
+ (a) flags=a$flags ;;
+ (*)
+ ble/util/print "blehook: unrecognized option '-$c'." >&2
+ flags=E$flags ;;
+ esac
+ done ;;
+ esac
+ elif [[ $arg =~ $rex1 ]]; then
+ local hookvar=_ble_hook_h_$arg
+ if ble/is-array "$hookvar"; then
+ ble/array#push print "$hookvar"
+ else
+ ble/util/print "blehook: undefined hook '$arg'." >&2
+ flags=E$flags
+ fi
+ elif [[ $arg =~ $rex2 ]]; then
+ local name=${BASH_REMATCH[1]}
+ local var_counter=_ble_hook_c_$name
+ if [[ ! ${!var_counter+set} ]]; then
+ if [[ ${BASH_REMATCH[2]} == :* ]]; then
+ (($var_counter=0))
+ else
+ ble/util/print "blehook: hook \"$name\" is not defined." >&2
+ flags=E$flags
+ fi
+ fi
+ ble/array#push process "$arg"
+ else
+ ble/util/print "blehook: invalid hook spec \"$arg\"" >&2
+ flags=E$flags
+ fi
+ done
+ [[ $opt_color == always || $opt_color == auto && -t 1 ]] && flags=c$flags
+}
+function blehook {
+ local set shopt
+ ble/base/adjust-BASH_REMATCH
+ ble/base/.adjust-bash-options set shopt
+ local flags print process
+ local rex1='^([a-zA-Z_][a-zA-Z_0-9]*)$'
+ local rex2='^([a-zA-Z_][a-zA-Z_0-9]*)(:?([-+!]|-\+|\+-)?=)(.*)$'
+ blehook/.read-arguments "$@"
+ if [[ $flags == *[HE]* ]]; then
+ if [[ $flags == *H* ]]; then
+ [[ $flags == *E* ]] &&
+ ble/util/print >&2
+ blehook/.print-help
+ fi
+ [[ $flags != *E* ]]; local ext=$?
+ ble/base/.restore-bash-options set shopt
+ ble/base/restore-BASH_REMATCH
+ return "$ext"
+ fi
+ if ((${#print[@]}==0&&${#process[@]}==0)); then
+ print=("${!_ble_hook_h_@}")
+ [[ $flags == *a* ]] || ble/array#remove-by-glob print '_ble_hook_h_*[a-z]*'
+ fi
+ local proc ext=0
+ for proc in "${process[@]}"; do
+ [[ $proc =~ $rex2 ]]
+ local name=${BASH_REMATCH[1]}
+ local type=${BASH_REMATCH[3]}
+ local value=${BASH_REMATCH[4]}
+ local append=$value
+ case $type in
+ (*-*) # -=, -+=, +-=
+ local ret
+ ble/array#last-index "_ble_hook_h_$name" "$value"
+ if ((ret>=0)); then
+ ble/array#remove-at "_ble_hook_h_$name" "$ret"
+ elif [[ ${type#:} == '-=' ]]; then
+ ext=1
+ fi
+ if [[ $type != -+ ]]; then
+ append=
+ [[ $type == +- ]] &&
+ ble/array#unshift "_ble_hook_h_$name" "$value"
+ fi ;;
+ ('!') # !=
+ local ret
+ ble/array#last-index "_ble_hook_h_$name" "$value"
+ ((ret>=0)) && append= ;;
+ ('') builtin eval "_ble_hook_h_$name=()" ;; # =
+ ('+'|*) ;; # +=
+ esac
+ [[ $append ]] && ble/array#push "_ble_hook_h_$name" "$append"
+ done
+ if ((${#print[@]})); then
+ blehook/.print "${print[@]}"
+ fi
+ ble/base/.restore-bash-options set shopt
+ ble/base/restore-BASH_REMATCH
+ return "$ext"
+}
+blehook/.compatibility-ble-0.3
+function blehook/has-hook {
+ builtin eval "local count=\${#_ble_hook_h_$1[@]}"
+ ((count))
+}
+function blehook/invoke.sandbox {
+ if type "$_ble_local_hook" &>/dev/null; then
+ ble/util/setexit "$_ble_local_lastexit" "$_ble_local_lastarg"
+ "$_ble_local_hook" "$@" 2>&3
+ else
+ ble/util/setexit "$_ble_local_lastexit" "$_ble_local_lastarg"
+ builtin eval -- "$_ble_local_hook" 2>&3
+ fi
+}
+function blehook/invoke {
+ local _ble_local_lastexit=$? _ble_local_lastarg=$_ FUNCNEST=
+ ((_ble_hook_c_$1++))
+ local -a _ble_local_hooks
+ builtin eval "_ble_local_hooks=(\"\${_ble_hook_h_$1[@]}\")"; shift
+ local _ble_local_hook _ble_local_ext=0
+ for _ble_local_hook in "${_ble_local_hooks[@]}"; do
+ blehook/invoke.sandbox "$@" || _ble_local_ext=$?
+ done
+ return "$_ble_local_ext"
+} 3>&2 2>/dev/null # set -x 対策 #D0930
+function blehook/eval-after-load {
+ local hook_name=${1}_load value=$2
+ if ((_ble_hook_c_$hook_name)); then
+ builtin eval -- "$value"
+ else
+ blehook "$hook_name+=$value"
+ fi
+}
+function ble/builtin/trap/.read-arguments {
+ flags= command= sigspecs=()
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $arg == -?* && flags != *A* ]]; then
+ if [[ $arg == -- ]]; then
+ flags=A$flags
+ continue
+ elif [[ $arg == --* ]]; then
+ case $arg in
+ (--help)
+ flags=h$flags
+ continue ;;
+ (*)
+ ble/util/print "ble/builtin/trap: unknown long option \"$arg\"." >&2
+ flags=E$flags
+ continue ;;
+ esac
+ fi
+ local i
+ for ((i=1;i<${#arg};i++)); do
+ case ${arg:i:1} in
+ (l) flags=l$flags ;;
+ (p) flags=p$flags ;;
+ (*)
+ ble/util/print "ble/builtin/trap: unknown option \"-${arg:i:1}\"." >&2
+ flags=E$flags ;;
+ esac
+ done
+ else
+ if [[ $flags != *[pc]* ]]; then
+ command=$arg
+ flags=c$flags
+ else
+ ble/array#push sigspecs "$arg"
+ fi
+ fi
+ done
+ if [[ $flags != *[hlpE]* ]]; then
+ if [[ $flags != *c* ]]; then
+ flags=p$flags
+ elif ((${#sigspecs[@]}==0)); then
+ sigspecs=("$command")
+ command=-
+ fi
+ fi
+}
+_ble_builtin_trap_signames=()
+_ble_builtin_trap_reserved=()
+_ble_builtin_trap_handlers=()
+_ble_builtin_trap_DEBUG=
+_ble_builtin_trap_inside= # ble/builtin/trap 処理中かどうか
+_ble_builtin_trap_processing= # ble/buitlin/trap/.handler 実行中かどうか
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_builtin_trap_n2i}"
+function ble/builtin/trap/.register {
+ local index=$1 name=$2
+ _ble_builtin_trap_signames[index]=$name
+ ble/gdict#set _ble_builtin_trap_n2i "$name" "$index"
+}
+function ble/builtin/trap/.get-sig-index {
+ if [[ $1 && ! ${1//[0-9]} ]]; then
+ ret=$1
+ return 0
+ else
+ ble/gdict#get _ble_builtin_trap_n2i "$1"
+ [[ $ret ]] && return 0
+ ble/string#toupper "$1"; local upper=$ret
+ ble/gdict#get _ble_builtin_trap_n2i "$upper" ||
+ ble/gdict#get _ble_builtin_trap_n2i "SIG$upper" ||
+ return 1
+ ble/gdict#set _ble_builtin_trap_n2i "$1" "$ret"
+ return 0
+ fi
+}
+function ble/builtin/trap/.initialize {
+ function ble/builtin/trap/.initialize { :; }
+ local ret i
+ ble/util/assign ret 'builtin trap -l' 2>/dev/null
+ ble/string#split-words ret "$ret"
+ for ((i=0;i<${#ret[@]};i+=2)); do
+ local index=${ret[i]%')'}
+ local name=${ret[i+1]}
+ ble/builtin/trap/.register "$index" "$name"
+ done
+ ble/builtin/trap/.register 0 EXIT
+ ble/builtin/trap/.register 1000 DEBUG
+ ble/builtin/trap/.register 1001 RETURN
+ ble/builtin/trap/.register 1002 ERR
+ _ble_builtin_trap_DEBUG=1000
+}
+function ble/builtin/trap/reserve {
+ local ret
+ ble/builtin/trap/.initialize
+ ble/builtin/trap/.get-sig-index "$1" || return 1
+ _ble_builtin_trap_reserved[ret]=1
+}
+function ble/builtin/trap/finalize {
+ local sig
+ for sig in "${!_ble_builtin_trap_reserved[@]}"; do
+ local name=${_ble_builtin_trap_signames[index]}
+ [[ $name && ${_ble_builtin_trap_reserved[sig]} ]] || continue
+ if [[ ${_ble_builtin_trap_handlers[sig]+set} ]]; then
+ builtin trap -- "${_ble_builtin_trap_handlers[sig]+set}" "$name"
+ else
+ builtin trap -- - "$name"
+ fi
+ done
+}
+function ble/builtin/trap {
+ local set shopt; ble/base/.adjust-bash-options set shopt
+ local flags command sigspecs
+ ble/builtin/trap/.read-arguments "$@"
+ if [[ $flags == *h* ]]; then
+ builtin trap --help
+ ble/base/.restore-bash-options set shopt
+ return 2
+ elif [[ $flags == *E* ]]; then
+ builtin trap --usage 2>&1 1>/dev/null | ble/bin/grep ^trap >&2
+ ble/base/.restore-bash-options set shopt
+ return 2
+ elif [[ $flags == *l* ]]; then
+ builtin trap -l
+ fi
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/adjust-BASH_REMATCH
+ if [[ $flags == *p* ]]; then
+ ble/builtin/trap/.initialize
+ local -a indices=()
+ if ((${#sigspecs[@]})); then
+ local spec ret
+ for spec in "${sigspecs[@]}"; do
+ if ! ble/builtin/trap/.get-sig-index "$spec"; then
+ ble/util/print "ble/builtin/trap: invalid signal specification \"$spec\"." >&2
+ continue
+ fi
+ ble/array#push indices "$ret"
+ done
+ else
+ indices=("${!_ble_builtin_trap_handlers[@]}")
+ fi
+ local q=\' Q="'\''" index
+ for index in "${indices[@]}"; do
+ if [[ ${_ble_builtin_trap_handlers[index]+set} ]]; then
+ local h=${_ble_builtin_trap_handlers[index]}
+ local n=${_ble_builtin_trap_signames[index]}
+ ble/util/print "trap -- '${h//$q/$Q}' $n"
+ fi
+ done
+ else
+ local _ble_builtin_trap_inside=1
+ local spec ret
+ for spec in "${sigspecs[@]}"; do
+ if ! ble/builtin/trap/.get-sig-index "$spec"; then
+ ble/util/print "ble/builtin/trap: invalid signal specification \"$spec\"." >&2
+ continue
+ fi
+ if [[ $command == - ]]; then
+ builtin unset -v "_ble_builtin_trap_handlers[ret]"
+ else
+ _ble_builtin_trap_handlers[ret]=$command
+ fi
+ if [[ ${_ble_builtin_trap_reserved[ret]} ]]; then
+ ble/function#try ble/builtin/trap:"${_ble_builtin_trap_signames[ret]}" "$command" "$spec"
+ else
+ builtin trap -- "$command" "$spec"
+ fi
+ done
+ fi
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/restore-BASH_REMATCH
+ ble/base/.restore-bash-options set shopt
+ return 0
+}
+function trap { ble/builtin/trap "$@"; }
+_ble_builtin_trap_user_lastcmd=
+_ble_builtin_trap_user_lastarg=
+_ble_builtin_trap_user_lastexit=
+function ble/builtin/trap/invoke.sandbox {
+ local _ble_trap_count
+ for ((_ble_trap_count=0;_ble_trap_count<1;_ble_trap_count++)); do
+ _ble_trap_done=return
+ ble/util/setexit "$_ble_trap_lastexit" "$_ble_trap_lastarg"
+ builtin eval -- "$_ble_trap_handler"$'\n_ble_trap_lastexit=$? _ble_trap_lastarg=$_' 2>&3
+ _ble_trap_done=done
+ return 0
+ done
+ _ble_trap_lastexit=$? _ble_trap_lastarg=$_
+ if ((_ble_trap_count==0)); then
+ _ble_trap_done=break
+ else
+ _ble_trap_done=continue
+ fi
+ return 0
+}
+function ble/builtin/trap/invoke {
+ local _ble_trap_lastexit=$? _ble_trap_lastarg=$_ _ble_trap_sig=$1
+ if [[ ${_ble_trap_sig//[0-9]} ]]; then
+ local ret
+ ble/builtin/trap/.initialize
+ ble/builtin/trap/.get-sig-index "$1" || return 1
+ _ble_trap_sig=$ret
+ fi
+ local _ble_trap_handler=${_ble_builtin_trap_handlers[_ble_trap_sig]-}
+ [[ $_ble_trap_handler ]] || return 0
+ if [[ $_ble_attached && ! $_ble_edit_exec_inside_userspace ]]; then
+ if [[ $_ble_builtin_trap_user_lastcmd != $_ble_edit_CMD ]]; then
+ _ble_builtin_trap_user_lastcmd=$_ble_edit_CMD
+ _ble_builtin_trap_user_lastexit=$_ble_edit_exec_lastexit
+ _ble_builtin_trap_user_lastarg=$_ble_edit_exec_lastarg
+ fi
+ _ble_trap_lastexit=$_ble_builtin_trap_user_lastexit
+ _ble_trap_lastarg=$_ble_builtin_trap_user_lastarg
+ fi
+ local _ble_trap_done=
+ ble/builtin/trap/invoke.sandbox; local ext=$?
+ case $_ble_trap_done in
+ (done)
+ _ble_builtin_trap_lastarg=$_ble_trap_lastarg
+ _ble_builtin_trap_postproc="ble/util/setexit $_ble_trap_lastexit" ;;
+ (break | continue)
+ _ble_builtin_trap_lastarg=$_ble_trap_lastarg
+ if ble/string#match "$_ble_trap_lastarg" '^-?[0-9]+$'; then
+ _ble_builtin_trap_postproc="$_ble_trap_done $_ble_trap_lastarg"
+ else
+ _ble_builtin_trap_postproc=$_ble_trap_done
+ fi ;;
+ (return)
+ _ble_builtin_trap_lastarg=$ext
+ _ble_builtin_trap_postproc="return $ext" ;;
+ (exit)
+ _ble_builtin_trap_lastarg=$_ble_trap_lastarg
+ _ble_builtin_trap_postproc="ble/builtin/exit $_ble_trap_lastarg" ;;
+ esac
+ if [[ $_ble_attached && ! $_ble_edit_exec_inside_userspace ]]; then
+ _ble_builtin_trap_user_lastexit=$_ble_trap_lastexit
+ _ble_builtin_trap_user_lastarg=$_ble_trap_lastarg
+ fi
+ return 0
+} 3>&2 2>/dev/null # set -x 対策 #D0930
+function ble/builtin/trap/.handler {
+ local _ble_trap_lastexit=$? _ble_trap_lastarg=$_ FUNCNEST=
+ local _ble_trap_sig=$1 _ble_trap_name=$2
+ local FUNCNEST= IFS=$_ble_term_IFS
+ local set shopt; ble/base/.adjust-bash-options set shopt
+ local _ble_builtin_trap_processing=$_ble_trap_sig
+ local _ble_local_q=\' _ble_local_Q="'\''"
+ _ble_builtin_trap_lastarg=$_ble_trap_lastarg
+ _ble_builtin_trap_postproc="ble/util/setexit $_ble_trap_lastexit"
+ if [[ $_ble_builtin_exit_processing ]]; then
+ exec 1>&- 1>&"$_ble_builtin_exit_stdout"
+ exec 2>&- 2>&"$_ble_builtin_exit_stderr"
+ fi
+ ble/util/joblist.check
+ ble/util/setexit "$_ble_trap_lastexit" "$_ble_trap_lastarg"
+ blehook/invoke "$_ble_trap_name"
+ ble/util/joblist.check ignore-volatile-jobs
+ ble/util/setexit "$_ble_trap_lastexit" "$_ble_trap_lastarg"
+ ble/builtin/trap/invoke "$_ble_trap_sig"
+ if [[ $_ble_builtin_trap_processing == exit:* && $_ble_builtin_trap_postproc != 'ble/builtin/exit '* ]]; then
+ _ble_builtin_trap_postproc="ble/builtin/exit ${_ble_builtin_trap_processing#exit:}"
+ fi
+ [[ $_ble_builtin_trap_lastarg == *$'\n'* ]] &&
+ _ble_builtin_trap_lastarg=
+ ((_ble_trap_sig==0)) && ble/base/unload
+ ble/base/.restore-bash-options set shopt
+}
+function ble/builtin/trap/install-hook {
+ local ret opts=:${2-}:
+ ble/builtin/trap/.initialize
+ ble/builtin/trap/.get-sig-index "$1"
+ local sig=$ret name=${_ble_builtin_trap_signames[ret]}
+ ble/builtin/trap/reserve "$sig"
+ local handler="ble/builtin/trap/.handler $sig ${name#SIG}; builtin eval -- \"\$_ble_builtin_trap_postproc\" \\# \"\$_ble_builtin_trap_lastarg\""
+ local trap_command="trap -- '$handler' $name"
+ local trap_string; ble/util/assign trap_string "builtin trap -p $name"
+ if [[ $opts == *:readline:* ]] && ! ble/util/is-running-in-subshell; then
+ [[ $trap_command == "$trap_string" ]] && return 0
+ fi
+ builtin eval "builtin $trap_command"; local ext=$?
+ case $trap_string in
+ ("trap -- 'ble/builtin/trap/"*) ;; # ble-0.4
+ ("trap -- 'ble/base/unload"*|"trap -- 'ble-edit/"*) ;; # bash-0.3 以前
+ ("trap -- '"*)
+ [[ ! ${_ble_builtin_trap_handlers[sig]+set} ]] &&
+ ((sig<1000)) &&
+ builtin eval -- "ble/builtin/$trap_string" ;;
+ esac
+ return "$ext"
+}
+if ((_ble_bash>=40000)); then
+ function ble/util/readfile { # 155ms for man bash
+ local -a _ble_local_buffer=()
+ mapfile _ble_local_buffer < "$2"; local _ble_local_ext=$?
+ IFS= builtin eval "$1=\"\${_ble_local_buffer[*]-}\""
+ return "$_ble_local_ext"
+ }
+ function ble/util/mapfile {
+ mapfile -t "$1"
+ }
+else
+ function ble/util/readfile { # 465ms for man bash
+ [[ -r $2 && ! -d $2 ]] || return 1
+ local TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ IFS= builtin read "${_ble_bash_tmout_wa[@]}" -r -d '' "$1" < "$2"
+ return 0
+ }
+ function ble/util/mapfile {
+ local IFS= TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ local _ble_local_i=0 _ble_local_val _ble_local_arr; _ble_local_arr=()
+ while builtin read "${_ble_bash_tmout_wa[@]}" -r _ble_local_val || [[ $_ble_local_val ]]; do
+ _ble_local_arr[_ble_local_i++]=$_ble_local_val
+ done
+ builtin eval "$1=(\"\${_ble_local_arr[@]}\")"
+ }
+fi
+function ble/util/copyfile {
+ local src=$1 dst=$2 content
+ ble/util/readfile content "$1" || return $?
+ ble/util/put "$content" >| "$dst"
+}
+function ble/util/writearray/.read-arguments {
+ _ble_local_array=
+ _ble_local_nlfix=
+ _ble_local_delim=$'\n'
+ local flags=
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $flags != *-* && $arg == -* ]]; then
+ case $arg in
+ (--nlfix) _ble_local_nlfix=1 ;;
+ (-d)
+ if (($#)); then
+ _ble_local_delim=$1; shift
+ else
+ ble/util/print "${FUNCNAME[1]}: '$arg': missing option argument." >&2
+ flags=E$flags
+ fi ;;
+ (--) flags=-$flags ;;
+ (*)
+ ble/util/print "${FUNCNAME[1]}: '$arg': unrecognized option." >&2
+ flags=E$flags ;;
+ esac
+ else
+ if local rex='^[a-zA-Z_][a-zA-Z_0-9]*$'; ! [[ $arg =~ $rex ]]; then
+ ble/util/print "${FUNCNAME[1]}: '$arg': invalid array name." >&2
+ flags=E$flags
+ elif [[ $flags == *A* ]]; then
+ ble/util/print "${FUNCNAME[1]}: '$arg': an array name has been already specified." >&2
+ flags=E$flags
+ else
+ _ble_local_array=$arg
+ flags=A$flags
+ fi
+ fi
+ done
+ [[ $_ble_local_nlfix ]] && _ble_local_delim=$'\n'
+ [[ $flags != *E* ]]
+}
+function ble/util/writearray {
+ local _ble_local_array
+ local -x _ble_local_nlfix _ble_local_delim
+ ble/util/writearray/.read-arguments "$@" || return 2
+ local rex_dq='^"([^\\"]|\\.)*"'
+ local rex_es='^\$'\''([^\\'\'']|\\.)*'\'''
+ local rex_sq='^'\''([^'\'']|'\'\\\\\'\'')*'\'''
+ local rex_normal='^[^[:space:]$`"'\''()|&;<>\\]' # Note: []{}?*#!~^, @(), +() は quote されていなくても OK とする
+ declare -p "$_ble_local_array" | ble/bin/awk -v _ble_bash="$_ble_bash" '
+ BEGIN {
+ DELIM = ENVIRON["_ble_local_delim"];
+ FLAG_NLFIX = ENVIRON["_ble_local_nlfix"];
+ if (FLAG_NLFIX) DELIM = "\n";
+ IS_GAWK = AWKTYPE == "gawk";
+ IS_XPG4 = AWKTYPE == "xpg4";
+ REP_SL = "\\";
+ if (IS_XPG4) REP_SL = "\\\\";
+ REP_DBL_SL = "\\\\";
+ sub(/.*/, REP_DBL_SL, tmp);
+ if (tmp == "\\") REP_DBL_SL = "\\\\\\\\";
+ s2i_initialize();
+ c2s_initialize();
+ es_initialize();
+ decl = "";
+ }
+ function str2rep(str) {
+ if (IS_XPG4) sub(/\\/, "\\\\\\\\", str);
+ return str;
+ }
+ function s2i_initialize() {
+ for (i = 0; i < 16; i++)
+ xdigit2int[sprintf("%x", i)] = i;
+ for (i = 10; i < 16; i++)
+ xdigit2int[sprintf("%X", i)] = i;
+ }
+ function s2i(s, base, _, i, n, r) {
+ if (!base) base = 10;
+ r = 0;
+ n = length(s);
+ for (i = 1; i <= n; i++)
+ r = r * base + xdigit2int[substr(s, i, 1)];
+ return r;
+ }
+ function c2s_initialize(_, i) {
+ if (sprintf("%c", 945) == "α") {
+ C2S_UNICODE_PRINTF_C = 1;
+ } else {
+ C2S_UNICODE_PRINTF_C = 0;
+ for (i = 1; i <= 255; i++)
+ c2s_byte2char[i] = sprintf("%c", i);
+ }
+ }
+ function c2s(code, _, leadbyte_mark, leadbyte_sup, tail) {
+ if (C2S_UNICODE_PRINTF_C)
+ return sprintf("%c", code);
+ leadbyte_sup = 128; # 0x80
+ leadbyte_mark = 0;
+ tail = "";
+ while (leadbyte_sup && code >= leadbyte_sup) {
+ leadbyte_sup /= 2;
+ leadbyte_mark = leadbyte_mark ? leadbyte_mark / 2 : 65472; # 0xFFC0
+ tail = c2s_byte2char[128 + int(code % 64)] tail;
+ code = int(code / 64);
+ }
+ return c2s_byte2char[(leadbyte_mark + code) % 256] tail;
+ }
+ function es_initialize() {
+ es_control_chars["a"] = "\a";
+ es_control_chars["b"] = "\b";
+ es_control_chars["t"] = "\t";
+ es_control_chars["n"] = "\n";
+ es_control_chars["v"] = "\v";
+ es_control_chars["f"] = "\f";
+ es_control_chars["r"] = "\r";
+ es_control_chars["e"] = "\033";
+ es_control_chars["E"] = "\033";
+ es_control_chars["?"] = "?";
+ es_control_chars["'\''"] = "'\''";
+ es_control_chars["\""] = "\"";
+ es_control_chars["\\"] = "\\";
+ for (c = 32; c < 127; c++)
+ es_s2c[sprintf("%c", c)] = c;
+ }
+ function es_unescape(s, _, head, c) {
+ head = "";
+ while (match(s, /^[^\\]*\\/)) {
+ head = head substr(s, 1, RLENGTH - 1);
+ s = substr(s, RLENGTH + 1);
+ if ((c = es_control_chars[substr(s, 1, 1)])) {
+ head = head c;
+ s = substr(s, 2);
+ } else if (match(s, /^[0-9]([0-9][0-9]?)?/)) {
+ head = head c2s(s2i(substr(s, 1, RLENGTH), 8) % 256);
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^x[0-9a-fA-F][0-9a-fA-F]?/)) {
+ head = head c2s(s2i(substr(s, 2, RLENGTH - 1), 16));
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^U[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]([0-9a-fA-F]([0-9a-fA-F][0-9a-fA-F]?)?)?/)) {
+ head = head c2s(s2i(substr(s, 2, RLENGTH - 1), 16));
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^[uU][0-9a-fA-F]([0-9a-fA-F]([0-9a-fA-F][0-9a-fA-F]?)?)?/)) {
+ head = head c2s(s2i(substr(s, 2, RLENGTH - 1), 16));
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^c[ -~]/)) {
+ c = es_s2c[substr(s, 2, 1)];
+ head = head c2s(_ble_bash >= 40400 && c == 63 ? 127 : c % 32);
+ s = substr(s, 3);
+ } else {
+ head = head "\\";
+ }
+ }
+ return head s;
+ }
+ function unquote_dq(s, _, head) {
+ head = "";
+ while (match(s, /^([^\\]|\\[^$`"\\])*\\[$`"\\]/)) {
+ head = head substr(s, 1, RLENGTH - 2) substr(s, RLENGTH, 1);
+ s = substr(s, RLENGTH + 1);
+ }
+ return head s;
+ }
+ function unquote_sq(s) {
+ gsub(/'\'\\\\\'\''/, "'\''", s);
+ return s;
+ }
+ function unquote(s, _, c) {
+ c = substr(s, 1, 1);
+ if (c == "\"")
+ return unquote_dq(substr(s, 2, length(s) - 2));
+ else if (c == "$")
+ return es_unescape(substr(s, 3, length(s) - 3));
+ else if (c == "'\''")
+ return unquote_sq(substr(s, 2, length(s) - 2));
+ else if (c == "\\")
+ return substr(s, 2, 1);
+ else
+ return s;
+ }
+ function analyze_elements_dq(decl, _, arr, i, n) {
+ if (decl ~ /^\[[0-9]+\]="([^'$'\1\2''"\n\\]|\\.)*"( \[[0-9]+\]="([^\1\2"\\]|\\.)*")*$/) {
+ if (IS_GAWK) {
+ decl = gensub(/\[[0-9]+\]="(([^"\\]|\\.)*)" ?/, "\\1\001", "g", decl);
+ sub(/\001$/, "", decl);
+ decl = gensub(/\\([\\$"`])/, "\\1", decl);
+ } else {
+ gsub(/\[[0-9]+\]="([^"\\]|\\.)*" /, "&\001", decl);
+ gsub(/" \001\[[0-9]+\]="/, "\001", decl);
+ sub(/^\[[0-9]+\]="/, "", decl);
+ sub(/"$/, "", decl);
+ gsub(/\\\\/, "\002", decl);
+ gsub(/\\\$/, "$", decl);
+ gsub(/\\"/, "\"", decl);
+ gsub(/\\`/, "`", decl);
+ gsub(/\002/, REP_SL, decl);
+ }
+ if (DELIM != "") {
+ gsub(/\001/, str2rep(DELIM), decl);
+ printf("%s", decl DELIM);
+ } else {
+ n = split(decl, arr, /\001/);
+ for (i = 1; i <= n; i++)
+ printf("%s%c", arr[i], 0);
+ }
+ if (FLAG_NLFIX) printf("\n");
+ return 1;
+ }
+ return 0;
+ }
+ function analyze_elements_general(decl, _, arr, i, n, nlfix_indices) {
+ n = split(decl, arr, / /);
+ nlfix_indices = "";
+ for (i = 1; i <= n; i++) {
+ elem = arr[i];
+ sub(/^\[[0-9]+\]=/, "", elem);
+ line = "";
+ while (1) {
+ if (match(elem, /'"$rex_dq"'|'"$rex_es"'|'"$rex_sq"'|'"$rex_normal"'|^\\./)) {
+ mlen = RLENGTH;
+ line = line unquote(substr(elem, 1, mlen));
+ elem = substr(elem, mlen + 1);
+ } else if (elem ~ /^[$"'\''\\]/ && i + 1 <= n) {
+ elem = elem " " arr[++i];
+ } else {
+ break;
+ }
+ }
+ if (FLAG_NLFIX) {
+ if (line ~ /\n/) {
+ gsub(/\\/, REP_DBL_SL, line);
+ gsub(/'\''/, REP_SL "'\''", line);
+ gsub(/\a/, REP_SL "a", line);
+ gsub(/\b/, REP_SL "b", line);
+ gsub(/\t/, REP_SL "t", line);
+ gsub(/\n/, REP_SL "n", line);
+ gsub(/\v/, REP_SL "v", line);
+ gsub(/\f/, REP_SL "f", line);
+ gsub(/\r/, REP_SL "r", line);
+ printf("$'\''%s'\''\n", line);
+ nlfix_indices = nlfix_indices != "" ? nlfix_indices " " (i - 1) : (i - 1);
+ } else {
+ printf("%s\n", line);
+ }
+ } else if (DELIM != "") {
+ printf("%s", line DELIM);
+ } else {
+ printf("%s%c", line, 0);
+ }
+ }
+ if (FLAG_NLFIX)
+ printf("%s\n", nlfix_indices);
+ return 1;
+ }
+ function process_declaration(decl, _, mlen, line) {
+ sub(/^declare +(-[-aAilucnrtxfFgGI]+ +)?(-- +)?/, "", decl);
+ if (decl ~ /^([_a-zA-Z][_a-zA-Z0-9]*)='\''\(.*\)'\''$/) {
+ sub(/='\''\(/, "=(", decl);
+ sub(/\)'\''$/, ")", decl);
+ gsub(/'\'\\\\\'\''/, "'\''", decl);
+ }
+ if (_ble_bash < 30100) gsub(/\\\n/, "\n", decl);
+ if (_ble_bash < 40400) {
+ gsub(/\001\001/, "\001", decl);
+ gsub(/\001\177/, "\177", decl);
+ }
+ sub(/^([_a-zA-Z][_a-zA-Z0-9]*)=\([[:space:]]*/, "", decl);
+ sub(/[[:space:]]*\)[[:space:]]*$/, "", decl);
+ if (decl == "") return 1;
+ if (AWKTYPE != "mawk" && analyze_elements_dq(decl)) return 1;
+ return analyze_elements_general(decl);
+ }
+ { decl = decl ? decl "\n" $0: $0; }
+ END { process_declaration(decl); }
+ '
+}
+function ble/util/readarray {
+ local _ble_local_array
+ local -x _ble_local_nlfix _ble_local_delim
+ ble/util/writearray/.read-arguments "$@" || return 2
+ if ((_ble_bash>=40400)); then
+ local _ble_local_script='
+ mapfile -t -d "$_ble_local_delim" ARR'
+ elif ((_ble_bash>=40000)) && [[ $_ble_local_delim == $'\n' ]]; then
+ local _ble_local_script='
+ mapfile -t ARR'
+ else
+ local _ble_local_script='
+ local IFS= ARRI=0; ARR=()
+ while builtin read -r -d "" "ARR[ARRI++]"; do :; done'
+ fi
+ if [[ $_ble_local_nlfix ]]; then
+ _ble_local_script=$_ble_local_script'
+ local ARRN=${#ARR[@]} ARRF ARRI
+ if ((ARRN--)); then
+ ble/string#split-words ARRF "${ARR[ARRN]}"
+ builtin unset -v "ARR[ARRN]"
+ for ARRI in "${ARRF[@]}"; do
+ builtin eval -- "ARR[ARRI]=${ARR[ARRI]}"
+ done
+ fi'
+ fi
+ builtin eval -- "${_ble_local_script//ARR/$_ble_local_array}"
+}
+_ble_util_assign_base=$_ble_base_run/$$.util.assign.tmp
+_ble_util_assign_level=0
+if ((_ble_bash>=40000)); then
+ function ble/util/assign/.mktmp {
+ _ble_local_tmpfile=$_ble_util_assign_base.$((_ble_util_assign_level++))
+ ((BASH_SUBSHELL)) && _ble_local_tmpfile=$_ble_local_tmpfile.$BASHPID
+ }
+else
+ function ble/util/assign/.mktmp {
+ _ble_local_tmpfile=$_ble_util_assign_base.$((_ble_util_assign_level++))
+ ((BASH_SUBSHELL)) && _ble_local_tmpfile=$_ble_local_tmpfile.$RANDOM
+ }
+fi
+function ble/util/assign/.rmtmp {
+ ((_ble_util_assign_level--))
+ if ((BASH_SUBSHELL)); then
+ printf 'caller %s\n' "${FUNCNAME[@]}" >| "$_ble_local_tmpfile"
+ else
+ : >| "$_ble_local_tmpfile"
+ fi
+}
+if ((_ble_bash>=40000)); then
+ function ble/util/assign {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$2" >| "$_ble_local_tmpfile"
+ local _ble_local_ret=$? _ble_local_arr=
+ mapfile -t _ble_local_arr < "$_ble_local_tmpfile"
+ ble/util/assign/.rmtmp
+ IFS=$'\n' builtin eval "$1=\"\${_ble_local_arr[*]}\""
+ return "$_ble_local_ret"
+ }
+else
+ function ble/util/assign {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$2" >| "$_ble_local_tmpfile"
+ local _ble_local_ret=$? TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ IFS= builtin read "${_ble_bash_tmout_wa[@]}" -r -d '' "$1" < "$_ble_local_tmpfile"
+ ble/util/assign/.rmtmp
+ builtin eval "$1=\${$1%$_ble_term_nl}"
+ return "$_ble_local_ret"
+ }
+fi
+if ((_ble_bash>=40000)); then
+ function ble/util/assign-array {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$2" >| "$_ble_local_tmpfile"
+ local _ble_local_ret=$?
+ mapfile -t "$1" < "$_ble_local_tmpfile"
+ ble/util/assign/.rmtmp
+ return "$_ble_local_ret"
+ }
+else
+ function ble/util/assign-array {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$2" >| "$_ble_local_tmpfile"
+ local _ble_local_ret=$?
+ ble/util/mapfile "$1" < "$_ble_local_tmpfile"
+ ble/util/assign/.rmtmp
+ return "$_ble_local_ret"
+ }
+fi
+if ! ((_ble_bash>=40400)); then
+ function ble/util/assign-array0 {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$2" >| "$_ble_local_tmpfile"
+ local _ble_local_ret=$?
+ mapfile -d '' -t "$1" < "$_ble_local_tmpfile"
+ ble/util/assign/.rmtmp
+ return "$_ble_local_ret"
+ }
+else
+ function ble/util/assign-array0 {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$2" >| "$_ble_local_tmpfile"
+ local _ble_local_ret=$?
+ local IFS= i=0 _ble_local_arr
+ while builtin read -r -d '' "_ble_local_arr[i++]"; do :; done < "$_ble_local_tmpfile"
+ ble/util/assign/.rmtmp
+ [[ ${_ble_local_arr[--i]} ]] || builtin unset -v "_ble_local_arr[i]"
+ ble/util/unlocal i IFS
+ builtin eval "$1=(\"\${_ble_local_arr[@]}\")"
+ return "$_ble_local_ret"
+ }
+fi
+function ble/util/assign.has-output {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ builtin eval -- "$1" >| "$_ble_local_tmpfile"
+ [[ -s $_ble_local_tmpfile ]]
+ local _ble_local_ret=$?
+ ble/util/assign/.rmtmp
+ return "$_ble_local_ret"
+}
+ble/bin/awk/.instantiate
+if ((_ble_bash>=30200)); then
+ function ble/is-function {
+ declare -F "$1" &>/dev/null
+ }
+else
+ function ble/is-function {
+ local type
+ ble/util/type type "$1"
+ [[ $type == function ]]
+ }
+fi
+if ((_ble_bash>=30200)); then
+ function ble/function#getdef {
+ local name=$1
+ ble/is-function "$name" || return 1
+ if [[ -o posix ]]; then
+ ble/util/assign def 'type "$name"'
+ def=${def#*$'\n'}
+ else
+ ble/util/assign def 'declare -f "$name"'
+ fi
+ }
+else
+ function ble/function#getdef {
+ local name=$1
+ ble/is-function "$name" || return 1
+ ble/util/assign def 'type "$name"'
+ def=${def#*$'\n'}
+ }
+fi
+function ble/function#evaldef {
+ local reset_extglob=
+ if ! shopt -q extglob; then
+ reset_extglob=1
+ shopt -s extglob
+ fi
+ builtin eval -- "$1"; local ext=$?
+ [[ $reset_extglob ]] && shopt -u extglob
+ return "$ext"
+}
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_util_function_traced}"
+function ble/function#trace {
+ declare -ft "$1" &>/dev/null &&
+ ble/gdict#set _ble_util_function_traced "$1" 1
+}
+function ble/function#has-trace {
+ ble/gdict#has _ble_util_function_traced "$1"
+}
+function ble/function/is-global-trace-context {
+ local func depth=1 ndepth=${#FUNCNAME[*]}
+ for func in "${FUNCNAME[@]:1}"; do
+ local src=${BASH_SOURCE[depth]}
+ [[ $- == *T* && ( $func == ble || $func == ble[-/]* || $func == source && $src == "$_ble_base_blesh_raw" ) ]] ||
+ [[ $func == source && depth -eq ndepth-1 && BASH_LINENO[depth] -eq 0 && ( ${src##*/} == .bashrc || ${src##*/} == .bash_profile || ${src##*/} == .profile ) ]] ||
+ ble/gdict#has _ble_util_function_traced "$func" || return 1
+ ((depth++))
+ done
+ return 0
+}
+function ble/function#try {
+ local lastexit=$?
+ ble/is-function "$1" || return 127
+ ble/util/setexit "$lastexit"
+ "$@"
+}
+function ble/function#get-source-and-lineno {
+ local ret unset_extdebug=
+ shopt -q extdebug || { unset_extdebug=1; shopt -s extdebug; }
+ ble/util/assign ret "declare -F '$1' 2>/dev/null"; local ext=$?
+ [[ ! $unset_extdebug ]] || shopt -u extdebug
+ if ((ext==0)); then
+ ret=${ret#*' '}
+ lineno=${ret%%' '*}
+ source=${ret#*' '}
+ [[ $lineno && ! ${lineno//[0-9]} && $source ]] || return 1
+ fi
+ return "$ext"
+}
+function ble/function#advice/do {
+ ble/function#advice/original:"${ADVICE_WORDS[@]}"
+ ADVICE_EXIT=$?
+}
+function ble/function#advice/.proc {
+ local ADVICE_WORDS ADVICE_EXIT=127
+ ADVICE_WORDS=("$@")
+ ble/function#try "ble/function#advice/before:$1"
+ if ble/is-function "ble/function#advice/around:$1"; then
+ "ble/function#advice/around:$1"
+ else
+ ble/function#advice/do
+ fi
+ ble/function#try "ble/function#advice/after:$1"
+ return "$ADVICE_EXIT"
+}
+function ble/function#advice {
+ local type=$1 name=$2 proc=$3
+ if ! ble/is-function "$name"; then
+ local t=; ble/util/type t "$name"
+ case $t in
+ (builtin|file) builtin eval "function $name { : ZBe85Oe28nBdg; command $name \"\$@\"; }" ;;
+ (*)
+ ble/util/print "ble/function#advice: $name is not a function." >&2
+ return 1 ;;
+ esac
+ fi
+ local def; ble/function#getdef "$name"
+ case $type in
+ (remove)
+ if [[ $def == *'ble/function#advice/.proc'* ]]; then
+ ble/function#getdef "ble/function#advice/original:$name"
+ if [[ $def ]]; then
+ if [[ $def == *ZBe85Oe28nBdg* ]]; then
+ builtin unset -f "$name"
+ else
+ ble/function#evaldef "${def#*:}"
+ fi
+ fi
+ fi
+ builtin unset -f ble/function#advice/{before,after,around,original}:"$name" 2>/dev/null
+ return 0 ;;
+ (before|after|around)
+ if [[ $def != *'ble/function#advice/.proc'* ]]; then
+ ble/function#evaldef "ble/function#advice/original:$def"
+ builtin eval "function $name { ble/function#advice/.proc \"\${FUNCNAME#*:}\" \"\$@\"; }"
+ fi
+ local q=\' Q="'\''"
+ builtin eval "ble/function#advice/$type:$name() { builtin eval '${proc//$q/$Q}'; }"
+ return 0 ;;
+ (*)
+ ble/util/print "ble/function#advice unknown advice type '$type'" >&2
+ return 2 ;;
+ esac
+}
+function ble/function#push {
+ local name=$1 proc=$2
+ if ble/is-function "$name"; then
+ local index=0
+ while ble/is-function "ble/function#push/$index:$name"; do
+ ((index++))
+ done
+ local def; ble/function#getdef "$name"
+ ble/function#evaldef "ble/function#push/$index:$def"
+ fi
+ if [[ $proc ]]; then
+ local q=\' Q="'\''"
+ builtin eval "function $name { builtin eval -- '${proc//$q/$Q}'; }"
+ else
+ builtin unset -f "$name"
+ fi
+ return 0
+}
+function ble/function#pop {
+ local name=$1 proc=$2
+ local index=-1
+ while ble/is-function "ble/function#push/$((index+1)):$name"; do
+ ((index++))
+ done
+ if ((index<0)); then
+ if ble/is-function "$name"; then
+ builtin unset -f "$name"
+ return 0
+ else
+ ble/util/print "ble/function#push: $name is not a function." >&2
+ return 1
+ fi
+ else
+ local def; ble/function#getdef "ble/function#push/$index:$name"
+ ble/function#evaldef "${def#*:}"
+ builtin unset -f "ble/function#push/$index:$name"
+ return 0
+ fi
+}
+function ble/function#push/call-top {
+ local func=${FUNCNAME[1]}
+ if ! ble/is-function "$func"; then
+ ble/util/print "ble/function#push/call-top: This function should be called from a function" >&2
+ return 1
+ fi
+ local index=0
+ if [[ $func == ble/function#push/?*:?* ]]; then
+ index=${func#*/*/}; index=${index%%:*}
+ func=${func#*:}
+ else
+ while ble/is-function "ble/function#push/$index:$func"; do ((index++)); done
+ fi
+ if ((index==0)); then
+ command "$func" "$@"
+ else
+ "ble/function#push/$((index-1)):$func" "$@"
+ fi
+}
+: "${_ble_util_lambda_count:=0}"
+function ble/function#lambda {
+ local _ble_local_q=\' _ble_local_Q="'\''"
+ ble/util/set "$1" ble/function#lambda/$((_ble_util_lambda_count++))
+ builtin eval -- "function ${!1} { builtin eval -- '${2//$_ble_local_q/$_ble_local_Q}'; }"
+}
+function ble/function#suppress-stderr {
+ local name=$1
+ if ! ble/is-function "$name"; then
+ ble/util/print "$FUNCNAME: '$name' is not a function name" >&2
+ return 2
+ fi
+ local lambda=ble/function#suppress-stderr:$name
+ if ! ble/is-function "$lambda"; then
+ local def; ble/function#getdef "$name"
+ ble/function#evaldef "ble/function#suppress-stderr:$def"
+ fi
+ builtin eval "function $name { $lambda \"\$@\" 2>/dev/null; }"
+ return 0
+}
+if ((_ble_bash>=40100)); then
+ function ble/util/set {
+ builtin printf -v "$1" %s "$2"
+ }
+else
+ function ble/util/set {
+ builtin eval -- "$1=\"\$2\""
+ }
+fi
+if ((_ble_bash>=30100)); then
+ function ble/util/sprintf {
+ builtin printf -v "$@"
+ }
+else
+ function ble/util/sprintf {
+ local -a args; args=("${@:2}")
+ ble/util/assign "$1" 'builtin printf "${args[@]}"'
+ }
+fi
+function ble/util/type {
+ ble/util/assign-array "$1" 'builtin type -a -t -- "$3" 2>/dev/null' "$2"; local ext=$?
+ return "$ext"
+}
+if ((_ble_bash>=40000)); then
+ function ble/is-alias {
+ [[ ${BASH_ALIASES[$1]+set} ]]
+ }
+ function ble/alias#active {
+ shopt -q expand_aliases &&
+ [[ ${BASH_ALIASES[$1]+set} ]]
+ }
+ function ble/alias#expand {
+ ret=$1
+ shopt -q expand_aliases &&
+ ret=${BASH_ALIASES[$ret]-$ret}
+ }
+ function ble/alias/list {
+ ret=("${!BASH_ALIASES[@]}")
+ }
+else
+ function ble/is-alias {
+ [[ $1 != *=* ]] && alias "$1" &>/dev/null
+ }
+ function ble/alias#active {
+ shopt -q expand_aliases &&
+ [[ $1 != *=* ]] && alias "$1" &>/dev/null
+ }
+ function ble/alias#expand {
+ ret=$1
+ local type; ble/util/type type "$ret"
+ [[ $type != alias ]] && return 1
+ local data; ble/util/assign data 'LC_ALL=C alias "$ret"' &>/dev/null
+ [[ $data == 'alias '*=* ]] && builtin eval "ret=${data#alias *=}"
+ }
+ function ble/alias/list {
+ ret=()
+ local data iret=0
+ ble/util/assign-array data 'alias -p'
+ for data in "${data[@]}"; do
+ [[ $data == 'alias '*=* ]] &&
+ data=${data%%=*} &&
+ builtin eval "ret[iret++]=${data#alias }"
+ done
+ }
+fi
+if ((_ble_bash>=40000)); then
+ function ble/util/is-stdin-ready {
+ local IFS= LC_ALL= LC_CTYPE=C
+ builtin read -t 0
+ }
+ ble/function#suppress-stderr ble/util/is-stdin-ready
+else
+ function ble/util/is-stdin-ready { false; }
+fi
+if ((_ble_bash>=40000)); then
+ function ble/util/getpid { :; }
+ function ble/util/is-running-in-subshell { [[ $$ != $BASHPID ]]; }
+else
+ function ble/util/getpid {
+ local command='echo $PPID'
+ ble/util/assign BASHPID 'ble/bin/sh -c "$command"'
+ }
+ function ble/util/is-running-in-subshell {
+ ((BASH_SUBSHELL==0)) || return 0
+ local BASHPID; ble/util/getpid
+ [[ $$ != $BASHPID ]]
+ }
+fi
+function ble/fd#is-open { : >&"$1"; } 2>/dev/null
+_ble_util_openat_nextfd=
+function ble/fd#alloc/.nextfd {
+ [[ $_ble_util_openat_nextfd ]] ||
+ _ble_util_openat_nextfd=$bleopt_openat_base
+ while ble/fd#is-open "$_ble_util_openat_nextfd"; do
+ ((_ble_util_openat_nextfd++))
+ done
+ (($1=_ble_util_openat_nextfd++))
+}
+_ble_util_openat_fdlist=()
+function ble/fd#alloc {
+ local _ble_local_preserve=
+ if [[ :$3: == *:inherit:* ]]; then
+ [[ ${!1-} ]] &&
+ ble/fd#is-open "${!1}" &&
+ return 0
+ fi
+ if [[ :$3: == *:share:* ]]; then
+ local _ble_local_ret='[<>]&['$_ble_term_IFS']*([0-9]+)['$_ble_term_IFS']*$'
+ if [[ $2 =~ $rex ]]; then
+ builtin eval -- "$1=${BASH_REMATCH[1]}"
+ return 0
+ fi
+ fi
+ if [[ ${!1-} && :$3: == *:overwrite:* ]]; then
+ _ble_local_preserve=1
+ builtin eval "exec ${!1}$2"
+ elif ((_ble_bash>=40100)) && [[ :$3: != *:base:* ]]; then
+ builtin eval "exec {$1}$2"
+ else
+ ble/fd#alloc/.nextfd "$1"
+ builtin eval "exec ${!1}>&- ${!1}$2"
+ fi; local _ble_local_ext=$?
+ if [[ :$3: == *:inherit:* || :$3: == *:export:* ]]; then
+ export "$1"
+ elif [[ ! $_ble_local_preserve ]]; then
+ ble/array#push _ble_util_openat_fdlist "${!1}"
+ fi
+ return "$_ble_local_ext"
+}
+function ble/fd#finalize {
+ local fd
+ for fd in "${_ble_util_openat_fdlist[@]}"; do
+ builtin eval "exec $fd>&-"
+ done
+ _ble_util_openat_fdlist=()
+}
+function ble/fd#close {
+ set -- $(($1))
+ (($1>=3)) || return 1
+ builtin eval "exec $1>&-"
+ ble/array#remove _ble_util_openat_fdlist "$1"
+ return 0
+}
+if [[ $_ble_init_command ]]; then
+ _ble_util_fd_stdin=0
+ _ble_util_fd_stdout=1
+ _ble_util_fd_stderr=2
+else
+ if [[ -t 0 ]]; then
+ ble/fd#alloc _ble_util_fd_stdin '<&0' base:overwrite:export
+ else
+ ble/fd#alloc _ble_util_fd_stdin '< /dev/tty' base:inherit
+ fi
+ if [[ -t 1 ]]; then
+ ble/fd#alloc _ble_util_fd_stdout '>&1' base:overwrite:export
+ else
+ ble/fd#alloc _ble_util_fd_stdout '> /dev/tty' base:inherit
+ fi
+ if [[ -t 2 ]]; then
+ ble/fd#alloc _ble_util_fd_stderr '>&2' base:overwrite:export
+ else
+ ble/fd#alloc _ble_util_fd_stderr ">&$_ble_util_fd_stdout" base:inherit:share
+ fi
+fi
+ble/fd#alloc _ble_util_fd_null '<> /dev/null' base:inherit
+[[ -c /dev/zero ]] &&
+ ble/fd#alloc _ble_util_fd_zero '< /dev/zero' base:inherit
+function ble/util/print-quoted-command {
+ local ret; ble/string#quote-command "$@"
+ ble/util/print "$ret"
+}
+function ble/util/declare-print-definitions {
+ (($#==0)) && return 0
+ declare -p "$@" | ble/bin/awk -v _ble_bash="$_ble_bash" -v OSTYPE="$OSTYPE" '
+ BEGIN {
+ decl = "";
+ flag_escape_cr = OSTYPE == "msys";
+ }
+ function fix_value(value) {
+ if (_ble_bash < 30100) gsub(/\\\n/, "\n", value);
+ if (_ble_bash < 30100) {
+ gsub(/\001\001/, "\"\"${_ble_term_SOH}\"\"", value);
+ gsub(/\001\177/, "\"\"${_ble_term_DEL}\"\"", value);
+ } else if (_ble_bash < 40400) {
+ gsub(/\001\001/, "${_ble_term_SOH}", value);
+ gsub(/\001\177/, "${_ble_term_DEL}", value);
+ }
+ if (flag_escape_cr)
+ gsub(/\015/, "${_ble_term_CR}", value);
+ return value;
+ }
+ function print_array_elements(decl, _, name, out, key, value) {
+ if (match(decl, /^[_a-zA-Z][_a-zA-Z0-9]*=\(/) == 0) return 0;
+ name = substr(decl, 1, RLENGTH - 2);
+ decl = substr(decl, RLENGTH + 1, length(decl) - RLENGTH - 1);
+ sub(/^[[:space:]]+/, decl);
+ out = name "=()\n";
+ while (match(decl, /^\[[0-9]+\]=/)) {
+ key = substr(decl, 2, RLENGTH - 3);
+ decl = substr(decl, RLENGTH + 1);
+ value = "";
+ if (match(decl, /^('\''[^'\'']*'\''|\$'\''([^\\'\'']|\\.)*'\''|\$?"([^\\"]|\\.)*"|\\.|[^[:space:]"'\''`;&|()])*/)) {
+ value = substr(decl, 1, RLENGTH)
+ decl = substr(decl, RLENGTH + 1)
+ }
+ out = out name "[" key "]=" fix_value(value) "\n";
+ sub(/^[[:space:]]+/, decl);
+ }
+ if (decl != "") return 0;
+ print out;
+ return 1;
+ }
+ function declflush(_, isArray) {
+ if (!decl) return 0;
+ isArray = (decl ~ /^declare +-[ilucnrtxfFgGI]*[aA]/);
+ sub(/^declare +(-[-aAilucnrtxfFgGI]+ +)?(-- +)?/, "", decl);
+ if (isArray) {
+ if (decl ~ /^([_a-zA-Z][_a-zA-Z0-9]*)='\''\(.*\)'\''$/) {
+ sub(/='\''\(/, "=(", decl);
+ sub(/\)'\''$/, ")", decl);
+ gsub(/'\'\\\\\'\''/, "'\''", decl);
+ }
+ if (_ble_bash < 40000 && decl ~ /[\001\177]/)
+ if (print_array_elements(decl))
+ return 1;
+ }
+ print fix_value(decl);
+ decl = "";
+ return 1;
+ }
+ /^declare / {
+ declflush();
+ decl = $0;
+ next;
+ }
+ { decl = decl "\n" $0; }
+ END { declflush(); }
+ '
+}
+function ble/util/print-global-definitions/.save-decl {
+ local __ble_name=$1
+ if [[ ! ${!__ble_name+set} ]]; then
+ __ble_decl="declare $__ble_name; builtin unset -v $__ble_name"
+ elif ble/variable#has-attr "$__ble_name" aA; then
+ if ((_ble_bash>=40000)); then
+ ble/util/assign __ble_decl "declare -p $__ble_name" 2>/dev/null
+ __ble_decl=${__ble_decl#declare -* }
+ else
+ ble/util/assign __ble_decl "ble/util/declare-print-definitions $__ble_name" 2>/dev/null
+ fi
+ if ble/is-array "$__ble_name"; then
+ __ble_decl="declare -a $__ble_decl"
+ else
+ __ble_decl="declare -A $__ble_decl"
+ fi
+ else
+ __ble_decl=${!__ble_name}
+ __ble_decl="declare $__ble_name='${__ble_decl//$__ble_q/$__ble_Q}'"
+ fi
+}
+function ble/util/print-global-definitions {
+ local __ble_hidden_only=
+ [[ $1 == --hidden-only ]] && { __ble_hidden_only=1; shift; }
+ (
+ ((_ble_bash>=50000)) && shopt -u localvar_unset
+ __ble_error=
+ __ble_q="'" __ble_Q="'\''"
+ __ble_MaxLoop=20
+ for __ble_name; do
+ [[ ${__ble_name//[0-9a-zA-Z_]} || $__ble_name == __ble_* ]] && continue
+ ((__ble_processed_$__ble_name)) && continue
+ ((__ble_processed_$__ble_name=1))
+ [[ $__ble_name == __ble_* ]] && continue
+ __ble_decl=
+ if ((_ble_bash>=40200)); then
+ declare -g -r "$__ble_name"
+ for ((__ble_i=0;__ble_i<__ble_MaxLoop;__ble_i++)); do
+ if ! builtin unset -v "$__ble_name"; then
+ ble/variable#is-global "$__ble_name" &&
+ ble/util/print-global-definitions/.save-decl "$__ble_name"
+ break
+ fi
+ done
+ else
+ for ((__ble_i=0;__ble_i<__ble_MaxLoop;__ble_i++)); do
+ if ble/variable#is-global "$__ble_name"; then
+ ble/util/print-global-definitions/.save-decl "$__ble_name"
+ break
+ fi
+ builtin unset -v "$__ble_name" || break
+ done
+ fi
+ [[ $__ble_decl ]] ||
+ __ble_error=1 __ble_decl="declare $__ble_name; builtin unset -v $__ble_name" # not found
+ [[ $__ble_hidden_only && $__ble_i == 0 ]] && continue
+ ble/util/print "$__ble_decl"
+ done
+ [[ ! $__ble_error ]]
+ ) 2>/dev/null
+}
+function ble/util/has-glob-pattern {
+ [[ $1 ]] || return 1
+ local restore=:
+ if ! shopt -q nullglob 2>/dev/null; then
+ restore="$restore;shopt -u nullglob"
+ shopt -s nullglob
+ fi
+ if shopt -q failglob 2>/dev/null; then
+ restore="$restore;shopt -s failglob"
+ shopt -u failglob
+ fi
+ local dummy=$_ble_base_run/$$.dummy ret
+ builtin eval "ret=(\"\$dummy\"/${1#/})" 2>/dev/null
+ builtin eval -- "$restore"
+ [[ ! $ret ]]
+}
+function ble/util/is-cygwin-slow-glob {
+ [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && ${1#\'} == //* && ! -o noglob ]] &&
+ ble/util/has-glob-pattern "$1"
+}
+function ble/util/eval-pathname-expansion {
+ ret=()
+ if ble/util/is-cygwin-slow-glob; then # Note: #D1168
+ if shopt -q failglob &>/dev/null; then
+ return 1
+ elif shopt -q nullglob &>/dev/null; then
+ return 0
+ else
+ set -f
+ ble/util/eval-pathname-expansion "$1"; local ext=$1
+ set +f
+ return "$ext"
+ fi
+ fi
+ local canon=
+ if [[ :$2: == *:canonical:* ]]; then
+ canon=1
+ local set=$- shopt=$BASHOPTS gignore=$GLOBIGNORE
+ shopt -u failglob
+ shopt -s nullglob
+ shopt -s extglob
+ set +f
+ GLOBIGNORE=
+ fi
+ builtin eval "ret=($1)" 2>/dev/null; local ext=$?
+ if [[ $canon ]]; then
+ GLOBIGNORE=$gignore
+ if [[ :$shopt: == *:dotglob:* ]]; then shopt -s dotglob; else shopt -u dotglob; fi
+ [[ $set == *f* ]] && set -f
+ [[ :$shopt: != *:extglob:* ]] && shopt -u extglob
+ [[ :$shopt: != *:nullglob:* ]] && shopt -u nullglob
+ [[ :$shopt: == *:failglob:* ]] && shopt -s failglob
+ fi
+ return "$ext"
+}
+_ble_util_rex_isprint='^[ -~]+'
+function ble/util/isprint+ {
+ local LC_ALL= LC_COLLATE=C
+ [[ $1 =~ $_ble_util_rex_isprint ]]
+}
+ble/function#suppress-stderr ble/util/isprint+
+if ((_ble_bash>=40200)); then
+ function ble/util/strftime {
+ if [[ $1 = -v ]]; then
+ builtin printf -v "$2" "%($3)T" "${4:--1}"
+ else
+ builtin printf "%($1)T" "${2:--1}"
+ fi
+ }
+else
+ function ble/util/strftime {
+ if [[ $1 = -v ]]; then
+ local fmt=$3 time=$4
+ ble/util/assign "$2" 'ble/bin/date +"$fmt" $time'
+ else
+ ble/bin/date +"$1" $2
+ fi
+ }
+fi
+if ! type ble/util/print &>/dev/null; then
+ function ble/util/unlocal { builtin unset -v "$@"; }
+ function ble/util/print { builtin printf '%s\n' "$1"; }
+ function ble/util/print-lines { builtin printf '%s\n' "$@"; }
+fi
+function ble-measure/.loop {
+ builtin eval "function _target { ${2:+$2; }return 0; }"
+ local _i _n=$1
+ for ((_i=0;_i<_n;_i++)); do
+ _target
+ done
+}
+if [[ ${ZSH_VERSION-} ]]; then
+ _ble_measure_resolution=1000 # [usec]
+ function ble-measure/.time {
+ local result
+ result=$({ time ( ble-measure/.loop "$n" "$1" ; ) } 2>&1 )
+ result=${result##*cpu }
+ local rex='(([0-9]+):)?([0-9]+)\.([0-9]+) total$'
+ if [[ $result =~ $rex ]]; then
+ if [[ -o KSH_ARRAYS ]]; then
+ local m=${match[1]} s=${match[2]} ms=${match[3]}
+ else
+ local m=${match[1]} s=${match[2]} ms=${match[3]}
+ fi
+ m=${m:-0} ms=${ms}000; ms=${ms:0:3}
+ ((utot=((10#0$m*60+10#0$s)*1000+10#0$ms)*1000,
+ usec=utot/n))
+ return 0
+ else
+ builtin echo "ble-measure: failed to read the result of \`time': $result." >&2
+ utot=0 usec=0
+ return 1
+ fi
+ }
+elif ((BASH_VERSINFO[0]>=5)); then
+ _ble_measure_resolution=1 # [usec]
+ function ble-measure/.get-realtime {
+ local LC_ALL= LC_NUMERIC=C
+ time=$EPOCHREALTIME
+ }
+ function ble-measure/.time {
+ local command=$1
+ local time
+ ble-measure/.get-realtime 2>/dev/null; local time1=${time//.}
+ ble-measure/.loop "$n" "$command" &>/dev/null
+ ble-measure/.get-realtime 2>/dev/null; local time2=${time//.}
+ ((utot=time2-time1,usec=utot/n))
+ ((utot>0))
+ }
+else
+ _ble_measure_resolution=1000 # [usec]
+ function ble-measure/.time {
+ utot=0 usec=0
+ local result TIMEFORMAT='[%R]' command=$1
+ if declare -f ble/util/assign &>/dev/null; then
+ ble/util/assign result '{ time ble-measure/.loop "$n" "$command" &>/dev/null;} 2>&1'
+ else
+ result=$({ time ble-measure/.loop "$n" "$1" &>/dev/null;} 2>&1)
+ fi
+ local rex='\[([0-9]+)(\.([0-9]+))?\]'
+ [[ $result =~ $rex ]] || return 1
+ local s=${BASH_REMATCH[1]}
+ local ms=${BASH_REMATCH[3]}000; ms=${ms::3}
+ ((utot=(10#0$s*1000+10#0$ms)*1000,usec=utot1/n))
+ return 0
+ }
+fi
+_ble_measure_base= # [nsec]
+_ble_measure_base_real=()
+_ble_measure_base_nestcost=0 # [nsec/10]
+_ble_measure_count=1 # 同じ倍率で _ble_measure_count 回計測して最小を取る。
+_ble_measure_threshold=100000 # 一回の計測が threshold [usec] 以上になるようにする
+function ble-measure/calibrate.0 { ble-measure -qc"$calibrate_count" ''; }
+function ble-measure/calibrate.1 { ble-measure/calibrate.0; }
+function ble-measure/calibrate.2 { ble-measure/calibrate.1; }
+function ble-measure/calibrate.3 { ble-measure/calibrate.2; }
+function ble-measure/calibrate.4 { ble-measure/calibrate.3; }
+function ble-measure/calibrate.5 { ble-measure/calibrate.4; }
+function ble-measure/calibrate.6 { ble-measure/calibrate.5; }
+function ble-measure/calibrate.7 { ble-measure/calibrate.6; }
+function ble-measure/calibrate.8 { ble-measure/calibrate.7; }
+function ble-measure/calibrate.9 { ble-measure/calibrate.8; }
+function ble-measure/calibrate.A { ble-measure/calibrate.9; }
+function ble-measure/calibrate {
+ local ret nsec
+ local calibrate_count=1
+ _ble_measure_base=0
+ _ble_measure_base_nestcost=0
+ local nest0=$((${#FUNCNAME[@]}+2))
+ ble-measure/calibrate.0; local x0=$nsec
+ ble-measure/calibrate.A; local xA=$nsec
+ local nest_cost=$((xA-x0))
+ _ble_measure_base=$((x0-nest_cost*nest0/10))
+ _ble_measure_base_nestcost=$nest_cost
+}
+function ble-measure/fit {
+ local ret nsec
+ _ble_measure_base=0
+ _ble_measure_base_nestcost=0
+ local calibrate_count=10
+ local c nest_level=${#FUNCNAME[@]}
+ for c in {0..9} A; do
+ "ble-measure/calibrate.$c"
+ ble/util/print "$((nest_level++)) $nsec"
+ done > a.txt
+ gnuplot - <<EOF
+f(x) = a * x + b
+b=4500;a=100
+fit f(x) 'a.txt' via a,b
+EOF
+}
+function ble-measure/.read-arguments.get-optarg {
+ if ((i+1<${#arg})); then
+ optarg=${arg:i+1}
+ i=${#arg}
+ return 0
+ elif ((iarg<${#args[@]})); then
+ optarg=${args[iarg++]}
+ return 0
+ else
+ ble/util/print "ble-measure: missing option argument for '-$c'."
+ flags=E$flags
+ return 1
+ fi
+}
+function ble-measure/.read-arguments {
+ local -a args; args=("$@")
+ local iarg=0 optarg=
+ while [[ ${args[iarg]} == -* ]]; do
+ local arg=${args[iarg++]}
+ case $arg in
+ (--) break ;;
+ (--help) flags=h$flags ;;
+ (--*)
+ ble/util/print "ble-measure: unrecognized option '$arg'."
+ flags=E$flags ;;
+ (-?*)
+ local i c
+ for ((i=1;i<${#arg};i++)); do
+ c=${arg:i:1}
+ case $c in
+ (q) flags=q$flags ;;
+ ([ca])
+ [[ $c == a ]] && flags=a$flags
+ ble-measure/.read-arguments.get-optarg && count=$optarg ;;
+ (T)
+ ble-measure/.read-arguments.get-optarg &&
+ measure_threshold=$optarg ;;
+ (B)
+ ble-measure/.read-arguments.get-optarg &&
+ __base=$optarg ;;
+ (*)
+ ble/util/print "ble-measure: unrecognized option '-$c'."
+ flags=E$flags ;;
+ esac
+ done ;;
+ (-)
+ ble/util/print "ble-measure: unrecognized option '$arg'."
+ flags=E$flags ;;
+ esac
+ done
+ local IFS=$' \t\n'
+ command="${args[*]:iarg}"
+ [[ $flags != *E* ]]
+}
+function ble-measure {
+ local __level=${#FUNCNAME[@]} __base=
+ local flags= command= count=$_ble_measure_count
+ local measure_threshold=$_ble_measure_threshold
+ ble-measure/.read-arguments "$@" || return "$?"
+ if [[ $flags == *h* ]]; then
+ ble/util/print-lines \
+ 'usage: ble-measure [-q|-ac COUNT|-TB TIME] [--] COMMAND' \
+ ' Measure the time of command.' \
+ '' \
+ ' Options:' \
+ ' -q Do not print results to stdout.' \
+ ' -a COUNT Measure COUNT times and average.' \
+ ' -c COUNT Measure COUNT times and take minimum.' \
+ ' -T TIME Set minimal measuring time.' \
+ ' -B BASE Set base time (overhead of ble-measure).' \
+ ' -- The rest arguments are treated as command.' \
+ ' --help Print this help.' \
+ '' \
+ ' Arguments:' \
+ ' COMMAND Command to be executed repeatedly.' \
+ '' \
+ ' Exit status:' \
+ ' Returns 1 for the failure in measuring the time. Returns 2 after printing' \
+ ' help. Otherwise, returns 0.'
+ return 2
+ fi
+ if [[ ! $__base ]]; then
+ if [[ $_ble_measure_base ]]; then
+ __base=$((_ble_measure_base+_ble_measure_base_nestcost*__level/10))
+ else
+ if [[ ! $ble_measure_calibrate && ! ${_ble_measure_base[__level]} ]]; then
+ if [[ ! ${_ble_measure_base_real[__level+1]} ]]; then
+ local ble_measure_calibrate=1
+ local a; ble-measure -qc3 -B 0 ''
+ ble/util/unlocal ble_measure_calibrate a
+ _ble_measure_base_real[__level+1]=$nsec
+ _ble_measure_base[__level+1]=$nsec
+ fi
+ local A=6598 B=435675
+ nsec=${_ble_measure_base_real[__level+1]}
+ _ble_measure_base[__level]=$((nsec*(B+A*(__level-1))/(B+A*__level)))
+ ble/util/unlocal A B
+ fi
+ __base=${_ble_measure_base[__level]:-0}
+ fi
+ fi
+ local prev_n= prev_utot=
+ local -i n
+ for n in {1,10,100,1000,10000}\*{1,2,5}; do
+ [[ $prev_n ]] && ((n/prev_n<=10 && prev_utot*n/prev_n<measure_threshold*2/5 && n!=50000)) && continue
+ local utot=0 usec=0
+ [[ $flags != *q* ]] && printf '%s (x%d)...' "$command" "$n" >&2
+ ble-measure/.time "$command" || return 1
+ [[ $flags != *q* ]] && printf '\r\e[2K' >&2
+ ((utot >= measure_threshold)) || continue
+ prev_n=$n prev_utot=$utot
+ local min_utot=$utot
+ if [[ $count ]]; then
+ local sum_utot=$utot sum_count=1 i
+ for ((i=2;i<=count;i++)); do
+ [[ $flags != *q* ]] && printf '%s' "$command (x$n $i/$count)..." >&2
+ if ble-measure/.time "$command"; then
+ ((utot<min_utot)) && min_utot=$utot
+ ((sum_utot+=utot,sum_count++))
+ fi
+ [[ $flags != *q* ]] && printf '\r\e[2K' >&2
+ done
+ if [[ $flags == *a* ]]; then
+ ((utot=sum_utot/sum_count))
+ else
+ utot=$min_utot
+ fi
+ fi
+ if ((min_utot<0x7FFFFFFFFFFFFFFF/1000)); then
+ local __real=$((min_utot*1000/n))
+ [[ ${_ble_measure_base_real[__level]} ]] &&
+ ((__real<_ble_measure_base_real[__level])) &&
+ _ble_measure_base_real[__level]=$__real
+ [[ ${_ble_measure_base[__level]} ]] &&
+ ((__real<_ble_measure_base[__level])) &&
+ _ble_measure_base[__level]=$__real
+ ((__real<__base)) &&
+ __base=$__real
+ fi
+ local nsec0=$__base
+ if [[ $flags != *q* ]]; then
+ local reso=$_ble_measure_resolution
+ local awk=ble/bin/awk
+ type "$awk" &>/dev/null || awk=awk
+ "$awk" -v utot=$utot -v nsec0=$nsec0 -v n=$n -v reso=$reso -v title="$command (x$n)" \
+ ' function genround(x, mod) { return int(x / mod + 0.5) * mod; }
+ BEGIN { printf("%12.3f usec/eval: %s\n", genround(utot / n - nsec0 / 1000, reso / 10.0 / n), title); exit }'
+ fi
+ ((ret=utot/n))
+ if ((n>=1000)); then
+ ((nsec=utot/(n/1000)))
+ else
+ ((nsec=utot*1000/n))
+ fi
+ ((ret-=nsec0/1000,nsec-=nsec0))
+ return 0
+ done
+}
+function ble/util/msleep/.check-builtin-sleep {
+ local ret; ble/util/readlink "$BASH"
+ local bash_prefix=${ret%/*/*}
+ if [[ -s $bash_prefix/lib/bash/sleep ]] &&
+ (enable -f "$bash_prefix/lib/bash/sleep" sleep && builtin sleep 0.0) &>/dev/null; then
+ enable -f "$bash_prefix/lib/bash/sleep" sleep
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/util/msleep/.check-sleep-decimal-support {
+ local version; ble/util/assign version 'LC_ALL=C ble/bin/sleep --version 2>&1' 2>/dev/null # suppress locale error #D1440
+ [[ $version == *'GNU coreutils'* || $OSTYPE == darwin* && $version == 'usage: sleep seconds' ]]
+}
+_ble_util_msleep_delay=2000 # [usec]
+function ble/util/msleep/.core {
+ local sec=${1%%.*}
+ ((10#0${1##*.}&&sec++)) # 小数部分は切り上げ
+ ble/bin/sleep "$sec"
+}
+function ble/util/msleep {
+ local v=$((1000*$1-_ble_util_msleep_delay))
+ ((v<=0)) && v=0
+ ble/util/sprintf v '%d.%06d' $((v/1000000)) $((v%1000000))
+ ble/util/msleep/.core "$v"
+}
+_ble_util_msleep_calibrate_count=0
+function ble/util/msleep/.calibrate-loop {
+ local _ble_measure_threshold=10000
+ local ret nsec _ble_measure_count=1 v=0
+ _ble_util_msleep_delay=0 ble-measure 'ble/util/msleep 1'
+ local delay=$((nsec/1000-1000)) count=$_ble_util_msleep_calibrate_count
+ ((count<=0||delay<_ble_util_msleep_delay)) && _ble_util_msleep_delay=$delay # 最小値
+}
+function ble/util/msleep/calibrate {
+ ble/util/msleep/.calibrate-loop &>/dev/null
+ ((++_ble_util_msleep_calibrate_count<5)) &&
+ ble/util/idle.continue
+}
+function ble/util/msleep/.use-read-timeout {
+ local msleep_type=$1 opts=${2-}
+ _ble_util_msleep_fd=
+ case $msleep_type in
+ (socket)
+ _ble_util_msleep_delay1=10000 # short msleep にかかる時間 [usec]
+ _ble_util_msleep_delay2=50000 # /bin/sleep 0 にかかる時間 [usec]
+ function ble/util/msleep/.core2 {
+ ((v-=_ble_util_msleep_delay2))
+ ble/bin/sleep $((v/1000000))
+ ((v%=1000000))
+ }
+ function ble/util/msleep {
+ local v=$((1000*$1-_ble_util_msleep_delay1))
+ ((v<=0)) && v=100
+ ((v>1000000+_ble_util_msleep_delay2)) &&
+ ble/util/msleep/.core2
+ ble/util/sprintf v '%d.%06d' $((v/1000000)) $((v%1000000))
+ ! builtin read -t "$v" v < /dev/udp/0.0.0.0/80
+ }
+ function ble/util/msleep/.calibrate-loop {
+ local _ble_measure_threshold=10000
+ local ret nsec _ble_measure_count=1 v=0
+ _ble_util_msleep_delay1=0 ble-measure 'ble/util/msleep 1'
+ local delay=$((nsec/1000-1000)) count=$_ble_util_msleep_calibrate_count
+ ((count<=0||delay<_ble_util_msleep_delay1)) && _ble_util_msleep_delay1=$delay # 最小値
+ _ble_util_msleep_delay2=0 ble-measure 'ble/util/msleep/.core2'
+ local delay=$((nsec/1000))
+ ((count<=0||delay<_ble_util_msleep_delay2)) && _ble_util_msleep_delay2=$delay # 最小値
+ } ;;
+ (procsub)
+ _ble_util_msleep_delay=300
+ ble/fd#alloc _ble_util_msleep_fd '< <(
+ [[ $- == *i* ]] && builtin trap -- '' INT QUIT
+ while kill -0 $$; do command sleep 300; done &>/dev/null
+ )'
+ function ble/util/msleep {
+ local v=$((1000*$1-_ble_util_msleep_delay))
+ ((v<=0)) && v=100
+ ble/util/sprintf v '%d.%06d' $((v/1000000)) $((v%1000000))
+ ! builtin read -t "$v" -u "$_ble_util_msleep_fd" v
+ } ;;
+ (*.*)
+ if local rex='^(fifo|zero|ptmx)\.(open|exec)([12])(-[a-z]+)?$'; [[ $msleep_type =~ $rex ]]; then
+ local file=${BASH_REMATCH[1]}
+ local open=${BASH_REMATCH[2]}
+ local direction=${BASH_REMATCH[3]}
+ local fall=${BASH_REMATCH[4]}
+ case $file in
+ (fifo)
+ _ble_util_msleep_tmp=$_ble_base_run/$$.util.msleep.pipe
+ if [[ ! -p $_ble_util_msleep_tmp ]]; then
+ [[ -e $_ble_util_msleep_tmp ]] && ble/bin/rm -rf "$_ble_util_msleep_tmp"
+ ble/bin/mkfifo "$_ble_util_msleep_tmp"
+ fi ;;
+ (zero)
+ open=dup
+ _ble_util_msleep_tmp=$_ble_util_fd_zero ;;
+ (ptmx)
+ _ble_util_msleep_tmp=/dev/ptmx ;;
+ esac
+ local redir='<'
+ ((direction==2)) && redir='<>'
+ if [[ $open == dup ]]; then
+ _ble_util_msleep_fd=$_ble_util_msleep_tmp
+ _ble_util_msleep_read='! builtin read -t "$v" -u "$_ble_util_msleep_fd" v'
+ elif [[ $open == exec ]]; then
+ ble/fd#alloc _ble_util_msleep_fd "$redir \"\$_ble_util_msleep_tmp\""
+ _ble_util_msleep_read='! builtin read -t "$v" -u "$_ble_util_msleep_fd" v'
+ else
+ _ble_util_msleep_read='! builtin read -t "$v" v '$redir' "$_ble_util_msleep_tmp"'
+ fi
+ if [[ $fall == '-coreutil' ]]; then
+ _ble_util_msleep_switch=200 # [msec]
+ _ble_util_msleep_delay1=2000 # short msleep にかかる時間 [usec]
+ _ble_util_msleep_delay2=50000 # /bin/sleep 0 にかかる時間 [usec]
+ function ble/util/msleep {
+ if (($1<_ble_util_msleep_switch)); then
+ local v=$((1000*$1-_ble_util_msleep_delay1))
+ ((v<=0)) && v=100
+ ble/util/sprintf v '%d.%06d' $((v/1000000)) $((v%1000000))
+ builtin eval -- "$_ble_util_msleep_read"
+ else
+ local v=$((1000*$1-_ble_util_msleep_delay2))
+ ((v<=0)) && v=100
+ ble/util/sprintf v '%d.%06d' $((v/1000000)) $((v%1000000))
+ ble/bin/sleep "$v"
+ fi
+ }
+ function ble/util/msleep/.calibrate-loop {
+ local _ble_measure_threshold=10000
+ local ret nsec _ble_measure_count=1
+ _ble_util_msleep_switch=200
+ _ble_util_msleep_delay1=0 ble-measure 'ble/util/msleep 1'
+ local delay=$((nsec/1000-1000)) count=$_ble_util_msleep_calibrate_count
+ ((count<=0||delay<_ble_util_msleep_delay1)) && _ble_util_msleep_delay1=$delay # 最小値を選択
+ _ble_util_msleep_delay2=0 ble-measure 'ble/bin/sleep 0'
+ local delay=$((nsec/1000))
+ ((count<=0||delay<_ble_util_msleep_delay2)) && _ble_util_msleep_delay2=$delay # 最小値を選択
+ ((_ble_util_msleep_switch=_ble_util_msleep_delay2/1000+10))
+ }
+ else
+ function ble/util/msleep {
+ local v=$((1000*$1-_ble_util_msleep_delay))
+ ((v<=0)) && v=100
+ ble/util/sprintf v '%d.%06d' $((v/1000000)) $((v%1000000))
+ builtin eval -- "$_ble_util_msleep_read"
+ }
+ fi
+ fi ;;
+ esac
+ if [[ :$opts: == *:check:* && $_ble_util_msleep_fd ]]; then
+ if builtin read -t 0.000001 -u "$_ble_util_msleep_fd" _ble_util_msleep_dummy 2>/dev/null; (($?<=128)); then
+ ble/fd#close _ble_util_msleep_fd
+ _ble_util_msleep_fd=
+ return 1
+ fi
+ fi
+ return 0
+}
+_ble_util_msleep_builtin_available=
+if ((_ble_bash>=40400)) && ble/util/msleep/.check-builtin-sleep; then
+ _ble_util_msleep_builtin_available=1
+ _ble_util_msleep_delay=300
+ function ble/util/msleep/.core { builtin sleep "$1"; }
+ function ble/builtin/sleep/.read-time {
+ a1=0 b1=0
+ local unit= exp=
+ if local rex='^\+?([0-9]*)\.([0-9]*)([eE][-+]?[0-9]+)?([smhd]?)$'; [[ $1 =~ $rex ]]; then
+ a1=${BASH_REMATCH[1]}
+ b1=${BASH_REMATCH[2]}00000000000000
+ b1=$((10#0${b1::14}))
+ exp=${BASH_REMATCH[3]}
+ unit=${BASH_REMATCH[4]}
+ elif rex='^\+?([0-9]+)([eE][-+]?[0-9]+)?([smhd]?)$'; [[ $1 =~ $rex ]]; then
+ a1=${BASH_REMATCH[1]}
+ exp=${BASH_REMATCH[2]}
+ unit=${BASH_REMATCH[3]}
+ else
+ ble/util/print "ble/builtin/sleep: invalid time spec '$1'" >&2
+ flags=E$flags
+ return 2
+ fi
+ if [[ $exp ]]; then
+ case $exp in
+ ([eE]-*)
+ ((exp=10#0${exp:2}))
+ while ((exp--)); do
+ ((b1=a1%10*frac_scale/10+b1/10,a1/=10))
+ done ;;
+ ([eE]*)
+ exp=${exp:1}
+ ((exp=${exp#+}))
+ while ((exp--)); do
+ ((b1*=10,a1=a1*10+b1/frac_scale,b1%=frac_scale))
+ done ;;
+ esac
+ fi
+ local scale=
+ case $unit in
+ (d) ((scale=24*3600)) ;;
+ (h) ((scale=3600)) ;;
+ (m) ((scale=60)) ;;
+ esac
+ if [[ $scale ]]; then
+ ((b1*=scale))
+ ((a1=a1*scale+b1/frac_scale))
+ ((b1%=frac_scale))
+ fi
+ return 0
+ }
+ function ble/builtin/sleep {
+ local set shopt; ble/base/.adjust-bash-options set shopt
+ local frac_scale=100000000000000
+ local a=0 b=0 flags=
+ if (($#==0)); then
+ ble/util/print "ble/builtin/sleep: no argument" >&2
+ flags=E$flags
+ fi
+ while (($#)); do
+ case $1 in
+ (--version) flags=v$flags ;;
+ (--help) flags=h$flags ;;
+ (-*)
+ flags=E$flags
+ ble/util/print "ble/builtin/sleep: unknown option '$1'" >&2 ;;
+ (*)
+ if local a1 b1; ble/builtin/sleep/.read-time "$1"; then
+ ((b+=b1))
+ ((a=a+a1+b/frac_scale))
+ ((b%=frac_scale))
+ fi ;;
+ esac
+ shift
+ done
+ if [[ $flags == *h* ]]; then
+ ble/util/print-lines \
+ 'usage: sleep NUMBER[SUFFIX]...' \
+ 'Pause for the time specified by the sum of the arguments. SUFFIX is one of "s"' \
+ '(seconds), "m" (minutes), "h" (hours) or "d" (days).' \
+ '' \
+ 'OPTIONS' \
+ ' --help Show this help.' \
+ ' --version Show version.'
+ fi
+ if [[ $flags == *v* ]]; then
+ ble/util/print "sleep (ble) $BLE_VERSION"
+ fi
+ if [[ $flags == *E* ]]; then
+ ble/util/setexit 2
+ elif [[ $flags == *[vh]* ]]; then
+ ble/util/setexit 0
+ else
+ b=00000000000000$b
+ b=${b:${#b}-14}
+ builtin sleep "$a.$b"
+ fi
+ local ext=$?
+ ble/base/.restore-bash-options set shopt 1
+ return "$ext"
+ }
+ function sleep { ble/builtin/sleep "$@"; }
+elif [[ -f $_ble_base/lib/init-msleep.sh ]] &&
+ source "$_ble_base/lib/init-msleep.sh" &&
+ ble/util/msleep/.load-compiled-builtin
+then
+ function ble/util/msleep { ble/builtin/msleep "$1"; }
+elif ((40000<=_ble_bash&&!(40300<=_ble_bash&&_ble_bash<50200))) &&
+ [[ $OSTYPE != cygwin* && $OSTYPE != mingw* && $OSTYPE != haiku* && $OSTYPE != minix* ]]
+then
+ ble/util/msleep/.use-read-timeout fifo.exec2
+elif ((_ble_bash>=40000)) && ble/fd#is-open "$_ble_util_fd_zero"; then
+ ble/util/msleep/.use-read-timeout zero.exec1-coreutil
+elif ble/bin/.freeze-utility-path sleepenh; then
+ function ble/util/msleep/.core { ble/bin/sleepenh "$1" &>/dev/null; }
+elif ble/bin/.freeze-utility-path usleep; then
+ function ble/util/msleep {
+ local v=$((1000*$1-_ble_util_msleep_delay))
+ ((v<=0)) && v=0
+ ble/bin/usleep "$v" &>/dev/null
+ }
+elif ble/util/msleep/.check-sleep-decimal-support; then
+ function ble/util/msleep/.core { ble/bin/sleep "$1"; }
+fi
+function ble/util/sleep {
+ local msec=$((${1%%.*}*1000))
+ if [[ $1 == *.* ]]; then
+ frac=${1##*.}000
+ ((msec+=10#0${frac::3}))
+ fi
+ ble/util/msleep "$msec"
+}
+function ble/util/conditional-sync/.collect-descendant-pids {
+ local pid=$1 awk_script='
+ $1 ~ /^[0-9]+$/ && $2 ~ /^[0-9]+$/ {
+ child[$2,child[$2]++]=$1;
+ }
+ function print_recursive(pid, _, n, i) {
+ if (child[pid]) {
+ n = child[pid];
+ child[pid] = 0; # avoid infinite loop
+ for (i = 0; i < n; i++) {
+ print_recursive(child[pid, i]);
+ }
+ }
+ print pid;
+ }
+ END { print_recursive(pid); }
+ '
+ ble/util/assign ret 'ble/bin/ps -A -o pid,ppid'
+ ble/util/assign-array ret 'ble/bin/awk -v pid="$pid" "$awk_script" <<< "$ret"'
+}
+function ble/util/conditional-sync/.kill {
+ local kill_pids
+ if [[ :$__opts: == *:killall:* ]]; then
+ ble/util/conditional-sync/.collect-descendant-pids "$__pid"
+ kill_pids=("${ret[@]}")
+ else
+ kill_pids=("$__pid")
+ fi
+ if [[ :$__opts: == *:SIGKILL:* ]]; then
+ builtin kill "${kill_pids[@]}" &>/dev/null
+ else
+ builtin kill -9 "${kill_pids[@]}" &>/dev/null
+ fi
+} &>/dev/null
+function ble/util/conditional-sync {
+ local __command=$1
+ local __continue=${2:-'! ble/decode/has-input'}
+ local __weight=$3; ((__weight<=0&&(__weight=100)))
+ local __opts=$4
+ local __timeout= __rex=':timeout=([^:]+):'
+ [[ :$__opts: =~ $__rex ]] && ((__timeout=BASH_REMATCH[1]))
+ [[ :$__opts: == *:progressive-weight:* ]] &&
+ local __weight_max=$__weight __weight=1
+ [[ $__timeout ]] && ((__timeout<=0)) && return 142
+ builtin eval -- "$__continue" || return 148
+ (
+ builtin eval -- "$__command" & local __pid=$!
+ while
+ if [[ $__timeout ]]; then
+ if ((__timeout<=0)); then
+ ble/util/conditional-sync/.kill
+ return 142
+ fi
+ ((__weight>__timeout)) && __weight=$__timeout
+ ((__timeout-=__weight))
+ fi
+ ble/util/msleep "$__weight"
+ [[ :$__opts: == *:progressive-weight:* ]] &&
+ ((__weight<<=1,__weight>__weight_max&&(__weight=__weight_max)))
+ builtin kill -0 "$__pid" &>/dev/null
+ do
+ if ! builtin eval -- "$__continue"; then
+ ble/util/conditional-sync/.kill
+ return 148
+ fi
+ done
+ wait "$__pid"
+ )
+}
+function ble/util/cat/.impl {
+ local content= TMOUT= IFS= 2>/dev/null # #D1630 WA readonly TMOUT
+ while builtin read "${_ble_bash_tmout_wa[@]}" -r -d '' content; do
+ printf '%s\0' "$content"
+ done
+ [[ $content ]] && printf '%s' "$content"
+}
+function ble/util/cat {
+ if (($#)); then
+ local file
+ for file; do ble/util/cat/.impl < "$1"; done
+ else
+ ble/util/cat/.impl
+ fi
+}
+_ble_util_less_fallback=
+function ble/util/get-pager {
+ if [[ ! $_ble_util_less_fallback ]]; then
+ if type -t less &>/dev/null; then
+ _ble_util_less_fallback=less
+ elif type -t pager &>/dev/null; then
+ _ble_util_less_fallback=pager
+ elif type -t more &>/dev/null; then
+ _ble_util_less_fallback=more
+ else
+ _ble_util_less_fallback=cat
+ fi
+ fi
+ builtin eval "$1=\${bleopt_pager:-\${PAGER:-\$_ble_util_less_fallback}}"
+}
+function ble/util/pager {
+ local pager; ble/util/get-pager pager
+ builtin eval -- "$pager \"\$@\""
+}
+if ble/bin/date -r / +%s &>/dev/null; then
+ function ble/util/getmtime { ble/bin/date -r "$1" +'%s %N' 2>/dev/null; }
+elif ble/bin/.freeze-utility-path stat; then
+ if ble/bin/stat -c %Y / &>/dev/null; then
+ function ble/util/getmtime { ble/bin/stat -c %Y "$1" 2>/dev/null; }
+ elif ble/bin/stat -f %m / &>/dev/null; then
+ function ble/util/getmtime { ble/bin/stat -f %m "$1" 2>/dev/null; }
+ fi
+fi
+ble/is-function ble/util/getmtime ||
+ function ble/util/getmtime { ble/util/strftime '%s %N'; }
+_ble_util_buffer=()
+function ble/util/buffer {
+ _ble_util_buffer[${#_ble_util_buffer[@]}]=$1
+}
+function ble/util/buffer.print {
+ ble/util/buffer "$1"$'\n'
+}
+function ble/util/buffer.flush {
+ IFS= builtin eval 'local text="${_ble_util_buffer[*]-}"'
+ [[ $_ble_term_state == internal ]] &&
+ [[ $_ble_term_cursor_hidden_internal != hidden ]] &&
+ text=$_ble_term_civis$text$_ble_term_cvvis
+ ble/util/put "$text"
+ _ble_util_buffer=()
+}
+function ble/util/buffer.clear {
+ _ble_util_buffer=()
+}
+function ble/dirty-range#load {
+ local _prefix=
+ if [[ $1 == --prefix=* ]]; then
+ _prefix=${1#--prefix=}
+ ((beg=${_prefix}beg,
+ end=${_prefix}end,
+ end0=${_prefix}end0))
+ fi
+}
+function ble/dirty-range#clear {
+ local _prefix=
+ if [[ $1 == --prefix=* ]]; then
+ _prefix=${1#--prefix=}
+ shift
+ fi
+ ((${_prefix}beg=-1,
+ ${_prefix}end=-1,
+ ${_prefix}end0=-1))
+}
+function ble/dirty-range#update {
+ local _prefix=
+ if [[ $1 == --prefix=* ]]; then
+ _prefix=${1#--prefix=}
+ shift
+ [[ $_prefix ]] && local beg end end0
+ fi
+ local begB=$1 endB=$2 endB0=$3
+ ((begB<0)) && return 1
+ local begA endA endA0
+ ((begA=${_prefix}beg,endA=${_prefix}end,endA0=${_prefix}end0))
+ local delta
+ if ((begA<0)); then
+ ((beg=begB,
+ end=endB,
+ end0=endB0))
+ else
+ ((beg=begA<begB?begA:begB))
+ if ((endA<0||endB<0)); then
+ ((end=-1,end0=-1))
+ else
+ ((end=endB,end0=endA0,
+ (delta=endA-endB0)>0?(end+=delta):(end0-=delta)))
+ fi
+ fi
+ if [[ $_prefix ]]; then
+ ((${_prefix}beg=beg,
+ ${_prefix}end=end,
+ ${_prefix}end0=end0))
+ fi
+}
+function ble/urange#clear {
+ local prefix=
+ if [[ $1 == --prefix=* ]]; then
+ prefix=${1#*=}; shift
+ fi
+ ((${prefix}umin=-1,${prefix}umax=-1))
+}
+function ble/urange#update {
+ local prefix=
+ if [[ $1 == --prefix=* ]]; then
+ prefix=${1#*=}; shift
+ fi
+ local min=$1 max=$2
+ ((0<=min&&min<max)) || return 1
+ (((${prefix}umin<0||min<${prefix}umin)&&(${prefix}umin=min),
+ (${prefix}umax<0||${prefix}umax<max)&&(${prefix}umax=max)))
+}
+function ble/urange#shift {
+ local prefix=
+ if [[ $1 == --prefix=* ]]; then
+ prefix=${1#*=}; shift
+ fi
+ local dbeg=$1 dend=$2 dend0=$3 shift=$4
+ ((dbeg>=0)) || return 1
+ [[ $shift ]] || ((shift=dend-dend0))
+ ((${prefix}umin>=0&&(
+ dbeg<=${prefix}umin&&(${prefix}umin<=dend0?(${prefix}umin=dend):(${prefix}umin+=shift)),
+ dbeg<=${prefix}umax&&(${prefix}umax<=dend0?(${prefix}umax=dbeg):(${prefix}umax+=shift))),
+ ${prefix}umin<${prefix}umax||(
+ ${prefix}umin=-1,
+ ${prefix}umax=-1)))
+}
+_ble_util_joblist_jobs=
+_ble_util_joblist_list=()
+_ble_util_joblist_events=()
+function ble/util/joblist {
+ local opts=$1 jobs0
+ ble/util/assign jobs0 'jobs'
+ if [[ $jobs0 == "$_ble_util_joblist_jobs" ]]; then
+ joblist=("${_ble_util_joblist_list[@]}")
+ return 0
+ elif [[ ! $jobs0 ]]; then
+ _ble_util_joblist_jobs=
+ _ble_util_joblist_list=()
+ joblist=()
+ return 0
+ fi
+ local lines list ijob
+ ble/string#split lines $'\n' "$jobs0"
+ if ((${#lines[@]})); then
+ ble/util/joblist.split list "${lines[@]}"
+ else
+ list=()
+ fi
+ if [[ $jobs0 != "$_ble_util_joblist_jobs" ]]; then
+ for ijob in "${!list[@]}"; do
+ if [[ ${_ble_util_joblist_list[ijob]} && ${list[ijob]#'['*']'[-+ ]} != "${_ble_util_joblist_list[ijob]#'['*']'[-+ ]}" ]]; then
+ if [[ ${list[ijob]} != *'__ble_suppress_joblist__'* ]]; then
+ ble/array#push _ble_util_joblist_events "${list[ijob]}"
+ fi
+ list[ijob]=
+ fi
+ done
+ fi
+ ble/util/assign _ble_util_joblist_jobs 'jobs'
+ _ble_util_joblist_list=()
+ if [[ $_ble_util_joblist_jobs != "$jobs0" ]]; then
+ ble/string#split lines $'\n' "$_ble_util_joblist_jobs"
+ ble/util/joblist.split _ble_util_joblist_list "${lines[@]}"
+ if [[ :$opts: != *:ignore-volatile-jobs:* ]]; then
+ for ijob in "${!list[@]}"; do
+ local job0=${list[ijob]}
+ if [[ $job0 && ! ${_ble_util_joblist_list[ijob]} ]]; then
+ if [[ $job0 != *'__ble_suppress_joblist__'* ]]; then
+ ble/array#push _ble_util_joblist_events "$job0"
+ fi
+ fi
+ done
+ fi
+ else
+ for ijob in "${!list[@]}"; do
+ [[ ${list[ijob]} ]] &&
+ _ble_util_joblist_list[ijob]=${list[ijob]}
+ done
+ fi
+ joblist=("${_ble_util_joblist_list[@]}")
+} 2>/dev/null
+function ble/util/joblist.split {
+ local arr=$1; shift
+ local line ijob= rex_ijob='^\[([0-9]+)\]'
+ for line; do
+ [[ $line =~ $rex_ijob ]] && ijob=${BASH_REMATCH[1]}
+ [[ $ijob ]] && builtin eval "$arr[ijob]=\${$arr[ijob]}\${$arr[ijob]:+\$_ble_term_nl}\$line"
+ done
+}
+function ble/util/joblist.check {
+ local joblist
+ ble/util/joblist "$@"
+}
+function ble/util/joblist.has-events {
+ local joblist
+ ble/util/joblist
+ ((${#_ble_util_joblist_events[@]}))
+}
+function ble/util/joblist.flush {
+ local joblist
+ ble/util/joblist
+ ((${#_ble_util_joblist_events[@]})) || return 1
+ printf '%s\n' "${_ble_util_joblist_events[@]}"
+ _ble_util_joblist_events=()
+}
+function ble/util/joblist.bflush {
+ local joblist out
+ ble/util/joblist
+ ((${#_ble_util_joblist_events[@]})) || return 1
+ ble/util/sprintf out '%s\n' "${_ble_util_joblist_events[@]}"
+ ble/util/buffer "$out"
+ _ble_util_joblist_events=()
+}
+function ble/util/joblist.clear {
+ _ble_util_joblist_jobs=
+ _ble_util_joblist_list=()
+}
+function ble/util/save-editing-mode {
+ if [[ -o emacs ]]; then
+ builtin eval "$1=emacs"
+ elif [[ -o vi ]]; then
+ builtin eval "$1=vi"
+ else
+ builtin eval "$1=none"
+ fi
+}
+function ble/util/restore-editing-mode {
+ case "${!1}" in
+ (emacs) set -o emacs ;;
+ (vi) set -o vi ;;
+ (none) set +o emacs ;;
+ esac
+}
+function ble/util/reset-keymap-of-editing-mode {
+ if [[ -o emacs ]]; then
+ set -o emacs
+ elif [[ -o vi ]]; then
+ set -o vi
+ fi
+}
+function ble/util/test-rl-variable {
+ local rl_variables; ble/util/assign rl_variables 'builtin bind -v'
+ if [[ $rl_variables == *"set $1 on"* ]]; then
+ return 0
+ elif [[ $rl_variables == *"set $1 off"* ]]; then
+ return 1
+ elif (($#>=2)); then
+ (($2))
+ return "$?"
+ else
+ return 2
+ fi
+}
+function ble/util/read-rl-variable {
+ ret=$2
+ local rl_variables; ble/util/assign rl_variables 'builtin bind -v'
+ local rhs=${rl_variables#*$'\n'"set $1 "}
+ [[ $rhs != "$rl_variables" ]] && ret=${rhs%%$'\n'*}
+}
+function ble/util/invoke-hook {
+ local -a hooks; builtin eval "hooks=(\"\${$1[@]}\")"
+ local hook ext=0
+ for hook in "${hooks[@]}"; do builtin eval -- "$hook \"\${@:2}\"" || ext=$?; done
+ return "$ext"
+}
+function ble/util/.read-arguments-for-no-option-command {
+ local commandname=$1; shift
+ flags= args=()
+ local flag_literal=
+ while (($#)); do
+ local arg=$1; shift
+ if [[ ! $flag_literal ]]; then
+ case $arg in
+ (--) flag_literal=1 ;;
+ (--help) flags=h$flags ;;
+ (-*)
+ ble/util/print "$commandname: unrecognized option '$arg'" >&2
+ flags=e$flags ;;
+ (*)
+ ble/array#push args "$arg" ;;
+ esac
+ else
+ ble/array#push args "$arg"
+ fi
+ done
+}
+function ble/util/autoload {
+ local file=$1; shift
+ ble/util/import/is-loaded "$file" && return 0
+ local q=\' Q="'\''" funcname
+ for funcname; do
+ builtin eval "function $funcname {
+ builtin unset -f $funcname
+ ble-import '${file//$q/$Q}' &&
+ $funcname \"\$@\"
+ }"
+ done
+}
+function ble/util/autoload/.print-usage {
+ ble/util/print 'usage: ble-autoload SCRIPTFILE FUNCTION...'
+ ble/util/print ' Setup delayed loading of functions defined in the specified script file.'
+} >&2
+function ble/util/autoload/.read-arguments {
+ file= flags= functions=()
+ local args
+ ble/util/.read-arguments-for-no-option-command ble-autoload "$@"
+ local arg index=0
+ for arg in "${args[@]}"; do
+ if [[ ! $arg ]]; then
+ if ((index==0)); then
+ ble/util/print 'ble-autoload: the script filename should not be empty.' >&2
+ else
+ ble/util/print 'ble-autoload: function names should not be empty.' >&2
+ fi
+ flags=e$flags
+ fi
+ ((index++))
+ done
+ [[ $flags == *h* ]] && return 0
+ if ((${#args[*]}==0)); then
+ ble/util/print 'ble-autoload: script filename is not specified.' >&2
+ flags=e$flags
+ elif ((${#args[*]}==1)); then
+ ble/util/print 'ble-autoload: function names are not specified.' >&2
+ flags=e$flags
+ fi
+ file=${args[0]} functions=("${args[@]:1}")
+}
+function ble-autoload {
+ local file flags
+ local -a functions=()
+ ble/util/autoload/.read-arguments "$@"
+ if [[ $flags == *[eh]* ]]; then
+ [[ $flags == *e* ]] && builtin printf '\n'
+ ble/util/autoload/.print-usage
+ [[ $flags == *e* ]] && return 2
+ return 0
+ fi
+ ble/util/autoload "$file" "${functions[@]}"
+}
+_ble_util_import_files=()
+bleopt/declare -n import_path "${XDG_DATA_HOME:-$HOME/.local/share}/blesh/local"
+function ble/util/import/search/.check-directory {
+ local name=$1 dir=${2%/}
+ [[ -d ${dir:=/} ]] || return 1
+ if [[ $name == lib/* ]]; then
+ [[ $dir == */lib ]] || return 1
+ dir=${dir%/lib}
+ elif [[ $name == contrib/* ]]; then
+ [[ $dir == */contrib ]] || return 1
+ dir=${dir%/contrib}
+ fi
+ if [[ -f $dir/$name ]]; then
+ ret=$dir/$name
+ return 0
+ elif [[ $name != *.bash && -f $dir/$name.bash ]]; then
+ ret=$dir/$name.bash
+ return 0
+ elif [[ $name != *.sh && -f $dir/$name.sh ]]; then
+ ret=$dir/$name.sh
+ return 0
+ fi
+ return 1
+}
+function ble/util/import/search {
+ ret=$1
+ if [[ $ret != /* && $ret != ./* && $ret != ../* ]]; then
+ local -a dirs=()
+ if [[ $bleopt_import_path ]]; then
+ local tmp; ble/string#split tmp : "$bleopt_import_path"
+ ble/array#push dirs "${tmp[@]}"
+ fi
+ ble/array#push dirs "$_ble_base"{,/contrib,/lib}
+ "${_ble_util_set_declare[@]//NAME/checked}" # #D1570
+ local path
+ for path in "${dirs[@]}"; do
+ ble/set#contains checked "$path" && continue
+ ble/set#add checked "$path"
+ ble/util/import/search/.check-directory "$ret" "$path" && break
+ done
+ fi
+ [[ -e $ret && ! -d $ret ]]
+}
+function ble/util/import/encode-filename {
+ ret=$1
+ local chars=%$'\t\n !"$&\'();<>\\^`|' # <emacs bug `>
+ if [[ $ret == *["$chars"]* ]]; then
+ local i n=${#chars} reps a b
+ reps=(%{25,08,0A,2{0..2},24,2{6..9},3B,3C,3E,5C,5E,60,7C})
+ for ((i=0;i<n;i++)); do
+ a=${chars:i:1} b=${reps[i]} ret=${ret//"$a"/"$b"}
+ done
+ fi
+ return 0
+}
+function ble/util/import/is-loaded {
+ local ret
+ ble/util/import/search "$1" &&
+ ble/util/import/encode-filename "$ret" &&
+ ble/is-function ble/util/import/guard:"$ret"
+}
+function ble/util/import/finalize {
+ local file ret
+ for file in "${_ble_util_import_files[@]}"; do
+ ble/util/import/encode-filename "$file"; local enc=$ret
+ local guard=ble/util/import/guard:$enc
+ builtin unset -f "$guard"
+ local onload=ble/util/import/onload:$enc
+ if ble/is-function "$onload"; then
+ "$onload" ble/util/unlocal
+ builtin unset -f "$onload"
+ fi
+ done
+ _ble_util_import_files=()
+}
+function ble/util/import/.read-arguments {
+ flags= files=()
+ local -a not_found=()
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $flags != *-* ]]; then
+ case $arg in
+ (--)
+ flags=-$flags
+ continue ;;
+ (--*)
+ case $arg in
+ (--delay) flags=d$flags ;;
+ (--help) flags=h$flags ;;
+ (--force) flags=f$flags ;;
+ (*)
+ ble/util/print "ble-import: unrecognized option '$arg'" >&2
+ flags=E$flags ;;
+ esac
+ continue ;;
+ (-?*)
+ local i c
+ for ((i=1;i<${#arg};i++)); do
+ c=${arg:i:1}
+ case $c in
+ ([df]) flags=$c$flags ;;
+ (*)
+ ble/util/print "ble-import: unrecognized option '-$c'" >&2
+ flags=E$flags ;;
+ esac
+ done
+ continue ;;
+ esac
+ fi
+ local ret
+ if ! ble/util/import/search "$arg"; then
+ ble/array#push not_found "$arg"
+ continue
+ fi; local file=$ret
+ ble/array#push files "$file"
+ done
+ if [[ $flags != *f* ]] && ((${#not_found[@]})); then
+ local file
+ for file in "${not_found[@]}"; do
+ ble/util/print "ble-import: file '$file' not found" >&2
+ done
+ flags=E$flags
+ fi
+ return 0
+}
+function ble/util/import {
+ local file ext=0 ret enc
+ for file; do
+ ble/util/import/encode-filename "$file"; enc=$ret
+ local guard=ble/util/import/guard:$enc
+ ble/is-function "$guard" && return 0
+ [[ -e $file ]] || return 1
+ source "$file" || { ext=$?; continue; }
+ builtin eval "function $guard { :; }"
+ ble/array#push _ble_util_import_files "$file"
+ local onload=ble/util/import/onload:$enc
+ ble/function#try "$onload" ble/util/invoke-hook
+ done
+ return "$ext"
+}
+function ble-import {
+ local files flags
+ ble/util/import/.read-arguments "$@"
+ if [[ $flags == *[Eh]* ]]; then
+ [[ $flags == *E* ]] && ble/util/print
+ {
+ ble/util/print 'usage: ble-import [-df] SCRIPTFILE...'
+ ble/util/print ' Search and source script files that have not yet been loaded.'
+ } >&2
+ [[ $flags == *E* ]] && return 2
+ return 0
+ elif ((!${#files[@]})); then
+ [[ $flags == *f* ]] && return 0
+ ble/util/print 'ble-import: files are not specified.' >&2
+ return 2
+ fi
+ if [[ $flags == *d* ]] && ble/is-function ble/util/idle.push; then
+ local ret
+ ble/string#quote-command ble/util/import "${files[@]}"
+ ble/util/idle.push "$ret"
+ return 0
+ fi
+ ble/util/import "${files[@]}"
+}
+_ble_util_import_onload_count=0
+function ble/util/import/eval-after-load {
+ local ret file
+ if ! ble/util/import/search "$1"; then
+ ble/util/print "ble-import: file '$1' not found." >&2
+ return 2
+ fi; file=$ret
+ ble/util/import/encode-filename "$file"; local enc=$ret
+ local guard=ble/util/import/guard:$enc
+ if ble/is-function "$guard"; then
+ builtin eval -- "$2"
+ else
+ local onload=ble/util/import/onload:$enc
+ if ! ble/is-function "$onload"; then
+ local q=\' Q="'\''" list=_ble_util_import_onload_$((_ble_util_import_onload_count++))
+ builtin eval -- "$list=(); function $onload { \"\$1\" $list \"\${@:2}\"; }"
+ fi
+ "$onload" ble/array#push "$2"
+ fi
+}
+_ble_util_stackdump_title=stackdump
+_ble_util_stackdump_start=
+function ble/util/stackdump {
+ ((bleopt_internal_stackdump_enabled)) || return 1
+ local message=$1 nl=$'\n' IFS=$_ble_term_IFS
+ message="$_ble_term_sgr0$_ble_util_stackdump_title: $message$nl"
+ local extdebug= iarg=$BASH_ARGC args=
+ shopt -q extdebug 2>/dev/null && extdebug=1
+ local i i0=${_ble_util_stackdump_start:-1} iN=${#FUNCNAME[*]}
+ for ((i=i0;i<iN;i++)); do
+ if [[ $extdebug ]] && ((BASH_ARGC[i])); then
+ args=("${BASH_ARGV[@]:iarg:BASH_ARGC[i]}")
+ ble/array#reverse args
+ args=" ${args[*]}"
+ ((iarg+=BASH_ARGC[i]))
+ else
+ args=
+ fi
+ message="$message @ ${BASH_SOURCE[i]}:${BASH_LINENO[i-1]} (${FUNCNAME[i]}$args)$nl"
+ done
+ ble/util/put "$message"
+}
+function ble-stackdump {
+ local flags args
+ ble/util/.read-arguments-for-no-option-command ble-stackdump "$@"
+ if [[ $flags == *[eh]* ]]; then
+ [[ $flags == *e* ]] && ble/util/print
+ {
+ ble/util/print 'usage: ble-stackdump command [message]'
+ ble/util/print ' Print stackdump.'
+ } >&2
+ [[ $flags == *e* ]] && return 2
+ return 0
+ fi
+ local _ble_util_stackdump_start=2
+ local IFS=$_ble_term_IFS
+ ble/util/stackdump "${args[*]}"
+}
+function ble/util/assert {
+ local expr=$1 message=$2
+ if ! builtin eval -- "$expr"; then
+ shift
+ local _ble_util_stackdump_title='assertion failure'
+ local _ble_util_stackdump_start=3
+ ble/util/stackdump "$expr$_ble_term_nl$message" >&2
+ return 1
+ else
+ return 0
+ fi
+}
+function ble-assert {
+ local flags args
+ ble/util/.read-arguments-for-no-option-command ble-assert "$@"
+ if [[ $flags != *h* ]]; then
+ if ((${#args[@]}==0)); then
+ ble/util/print 'ble-assert: command is not specified.' >&2
+ flags=e$flags
+ fi
+ fi
+ if [[ $flags == *[eh]* ]]; then
+ [[ $flags == *e* ]] && ble/util/print
+ {
+ ble/util/print 'usage: ble-assert command [message]'
+ ble/util/print ' Evaluate command and print stackdump on fail.'
+ } >&2
+ [[ $flags == *e* ]] && return 2
+ return 0
+ fi
+ local IFS=$_ble_term_IFS
+ ble/util/assert "${args[0]}" "${args[*]:1}"
+}
+_ble_util_clock_base=
+_ble_util_clock_reso=
+_ble_util_clock_type=
+function ble/util/clock/.initialize {
+ local LC_ALL= LC_NUMERIC=C
+ if ((_ble_bash>=50000)) && {
+ local now=$EPOCHREALTIME
+ [[ $now == *.???* && $now != $EPOCHREALTIME ]]; }; then
+ readonly EPOCHREALTIME
+ _ble_util_clock_base=$((10#0${now%.*}))
+ _ble_util_clock_reso=1
+ _ble_util_clock_type=EPOCHREALTIME
+ function ble/util/clock {
+ local LC_ALL= LC_NUMERIC=C
+ local now=$EPOCHREALTIME
+ local integral=$((10#0${now%%.*}-_ble_util_clock_base))
+ local mantissa=${now#*.}000; mantissa=${mantissa::3}
+ ((ret=integral*1000+10#0$mantissa))
+ }
+ ble/function#suppress-stderr ble/util/clock # locale
+ elif [[ -r /proc/uptime ]] && {
+ local uptime
+ ble/util/readfile uptime /proc/uptime
+ ble/string#split-words uptime "$uptime"
+ [[ $uptime == *.* ]]; }; then
+ _ble_util_clock_base=$((10#0${uptime%.*}))
+ _ble_util_clock_reso=10
+ _ble_util_clock_type=uptime
+ function ble/util/clock {
+ local now
+ ble/util/readfile now /proc/uptime
+ ble/string#split-words now "$now"
+ local integral=$((10#0${now%%.*}-_ble_util_clock_base))
+ local fraction=${now#*.}000; fraction=${fraction::3}
+ ((ret=integral*1000+10#0$fraction))
+ }
+ elif ((_ble_bash>=40200)); then
+ printf -v _ble_util_clock_base '%(%s)T'
+ _ble_util_clock_reso=1000
+ _ble_util_clock_type=printf
+ function ble/util/clock {
+ local now; printf -v now '%(%s)T'
+ ((ret=(now-_ble_util_clock_base)*1000))
+ }
+ elif [[ $SECONDS && ! ${SECONDS//[0-9]} ]]; then
+ readonly SECONDS
+ _ble_util_clock_base=$SECONDS
+ _ble_util_clock_reso=1000
+ _ble_util_clock_type=SECONDS
+ function ble/util/clock {
+ local now=$SECONDS
+ ((ret=(now-_ble_util_clock_base)*1000))
+ }
+ else
+ ble/util/strftime -v _ble_util_clock_base '%s'
+ _ble_util_clock_reso=1000
+ _ble_util_clock_type=date
+ function ble/util/clock {
+ ble/util/strftime -v ret '%s'
+ ((ret=(ret-_ble_util_clock_base)*1000))
+ }
+ fi
+}
+ble/util/clock/.initialize 2>/dev/null
+if ((_ble_bash>=40000)); then
+ function ble/util/idle/IS_IDLE { ! ble/util/is-stdin-ready; }
+ _ble_util_idle_sclock=0
+ function ble/util/idle/.sleep {
+ local msec=$1
+ ((msec<=0)) && return 0
+ ble/util/msleep "$msec"
+ ((_ble_util_idle_sclock+=msec))
+ }
+ function ble/util/idle.clock/.initialize {
+ function ble/util/idle.clock/.initialize { :; }
+ function ble/util/idle.clock/.restart { :; }
+ if [[ ! $_ble_util_clock_type || $_ble_util_clock_type == date ]]; then
+ function ble/util/idle.clock {
+ ret=$_ble_util_idle_sclock
+ }
+ elif ((_ble_util_clock_reso<=100)); then
+ function ble/util/idle.clock {
+ ble/util/clock
+ }
+ else
+ _ble_util_idle_aclock_shift=
+ _ble_util_idle_aclock_tick_rclock=
+ _ble_util_idle_aclock_tick_sclock=
+ function ble/util/idle.clock/.restart {
+ _ble_util_idle_aclock_shift=
+ _ble_util_idle_aclock_tick_rclock=
+ _ble_util_idle_aclock_tick_sclock=
+ }
+ function ble/util/idle/.adjusted-clock {
+ local resolution=$_ble_util_clock_reso
+ local sclock=$_ble_util_idle_sclock
+ local ret; ble/util/clock; local rclock=$((ret/resolution*resolution))
+ if [[ $_ble_util_idle_aclock_tick_rclock != "$rclock" ]]; then
+ if [[ $_ble_util_idle_aclock_tick_rclock && ! $_ble_util_idle_aclock_shift ]]; then
+ local delta=$((sclock-_ble_util_idle_aclock_tick_sclock))
+ ((_ble_util_idle_aclock_shift=delta<resolution?resolution-delta:0))
+ fi
+ _ble_util_idle_aclock_tick_rclock=$rclock
+ _ble_util_idle_aclock_tick_sclock=$sclock
+ fi
+ ((ret=rclock+(sclock-_ble_util_idle_aclock_tick_sclock)-_ble_util_idle_aclock_shift))
+ }
+ function ble/util/idle.clock {
+ ble/util/idle/.adjusted-clock
+ }
+ fi
+ }
+ function ble/util/idle/.initialize-options {
+ local interval='ble_util_idle_elapsed>600000?500:(ble_util_idle_elapsed>60000?200:(ble_util_idle_elapsed>5000?100:20))'
+ ((_ble_bash>50000)) && [[ $_ble_util_msleep_builtin_available ]] && interval=20
+ bleopt/declare -v idle_interval "$interval"
+ }
+ ble/util/idle/.initialize-options
+ _ble_util_idle_task=()
+ _ble_util_idle_lasttask=
+ _ble_util_idle_SEP=$_ble_term_FS
+ function ble/util/idle.do {
+ local IFS=$_ble_term_IFS
+ ble/util/idle/IS_IDLE || return 1
+ ((${#_ble_util_idle_task[@]}==0)) && return 1
+ ble/util/buffer.flush >&2
+ local ret
+ ble/util/idle.clock/.initialize
+ ble/util/idle.clock/.restart
+ ble/util/idle.clock
+ local _idle_clock_start=$ret
+ local _idle_sclock_start=$_ble_util_idle_sclock
+ local _idle_is_first=1
+ local _idle_processed=
+ while :; do
+ local _idle_key
+ local _idle_next_time= _idle_next_itime= _idle_running= _idle_waiting=
+ for _idle_key in "${!_ble_util_idle_task[@]}"; do
+ ble/util/idle/IS_IDLE || { [[ $_idle_processed ]]; return "$?"; }
+ local _idle_to_process=
+ local _idle_status=${_ble_util_idle_task[_idle_key]%%"$_ble_util_idle_SEP"*}
+ case ${_idle_status::1} in
+ (R) _idle_to_process=1 ;;
+ (I) [[ $_idle_is_first ]] && _idle_to_process=1 ;;
+ (S) ble/util/idle/.check-clock "$_idle_status" && _idle_to_process=1 ;;
+ (W) ble/util/idle/.check-clock "$_idle_status" && _idle_to_process=1 ;;
+ (F) [[ -s ${_idle_status:1} ]] && _idle_to_process=1 ;;
+ (E) [[ -e ${_idle_status:1} ]] && _idle_to_process=1 ;;
+ (P) ! builtin kill -0 ${_idle_status:1} &>/dev/null && _idle_to_process=1 ;;
+ (C) builtin eval -- "${_idle_status:1}" && _idle_to_process=1 ;;
+ (Z) ;;
+ (*) builtin unset -v '_ble_util_idle_task[_idle_key]'
+ esac
+ if [[ $_idle_to_process ]]; then
+ local _idle_command=${_ble_util_idle_task[_idle_key]#*"$_ble_util_idle_SEP"}
+ _idle_processed=1
+ ble/util/idle.do/.call-task "$_idle_command"
+ elif [[ $_idle_status == [FEPC]* ]]; then
+ _idle_waiting=1
+ fi
+ done
+ _idle_is_first=
+ ble/util/idle.do/.sleep-until-next; local ext=$?
+ ((ext==148)) && break
+ [[ $_idle_next_itime$_idle_next_time$_idle_running$_idle_waiting ]] || break
+ done
+ [[ $_idle_processed ]]
+ }
+ function ble/util/idle.do/.call-task {
+ local _command=$1
+ local ble_util_idle_status=
+ local ble_util_idle_elapsed=$((_ble_util_idle_sclock-_idle_sclock_start))
+ builtin eval -- "$_command"; local ext=$?
+ if ((ext==148)); then
+ _ble_util_idle_task[_idle_key]=R$_ble_util_idle_SEP$_command
+ elif [[ $ble_util_idle_status ]]; then
+ _ble_util_idle_task[_idle_key]=$ble_util_idle_status$_ble_util_idle_SEP$_command
+ if [[ $ble_util_idle_status == [WS]* ]]; then
+ local scheduled_time=${ble_util_idle_status:1}
+ if [[ $ble_util_idle_status == W* ]]; then
+ local next=_idle_next_itime
+ else
+ local next=_idle_next_time
+ fi
+ if [[ ! ${!next} ]] || ((scheduled_time<next)); then
+ builtin eval "$next=\$scheduled_time"
+ fi
+ elif [[ $ble_util_idle_status == R ]]; then
+ _idle_running=1
+ elif [[ $ble_util_idle_status == [FEPC]* ]]; then
+ _idle_waiting=1
+ fi
+ else
+ builtin unset -v '_ble_util_idle_task[_idle_key]'
+ fi
+ return "$ext"
+ }
+ function ble/util/idle/.check-clock {
+ local status=$1
+ if [[ $status == W* ]]; then
+ local next=_idle_next_itime
+ local current_time=$_ble_util_idle_sclock
+ elif [[ $status == S* ]]; then
+ local ret
+ local next=_idle_next_time
+ ble/util/idle.clock; local current_time=$ret
+ else
+ return 1
+ fi
+ local scheduled_time=${status:1}
+ if ((scheduled_time<=current_time)); then
+ return 0
+ elif [[ ! ${!next} ]] || ((scheduled_time<next)); then
+ builtin eval "$next=\$scheduled_time"
+ fi
+ return 1
+ }
+ function ble/util/idle.do/.sleep-until-next {
+ ble/util/idle/IS_IDLE || return 148
+ [[ $_idle_running ]] && return 0
+ local isfirst=1
+ while
+ local sleep_amount=
+ if [[ $_idle_next_itime ]]; then
+ local clock=$_ble_util_idle_sclock
+ local sleep1=$((_idle_next_itime-clock))
+ if [[ ! $sleep_amount ]] || ((sleep1<sleep_amount)); then
+ sleep_amount=$sleep1
+ fi
+ fi
+ if [[ $_idle_next_time ]]; then
+ local ret; ble/util/idle.clock; local clock=$ret
+ local sleep1=$((_idle_next_time-clock))
+ if [[ ! $sleep_amount ]] || ((sleep1<sleep_amount)); then
+ sleep_amount=$sleep1
+ fi
+ fi
+ [[ $isfirst && $_idle_waiting ]] || ((sleep_amount>0))
+ do
+ local ble_util_idle_elapsed=$((_ble_util_idle_sclock-_idle_sclock_start))
+ local interval=$((bleopt_idle_interval))
+ if [[ ! $sleep_amount ]] || ((interval<sleep_amount)); then
+ sleep_amount=$interval
+ fi
+ ble/util/idle/.sleep "$sleep_amount"
+ ble/util/idle/IS_IDLE || return 148
+ isfirst=
+ done
+ }
+ function ble/util/idle.push/.impl {
+ local base=$1 entry=$2
+ local i=$base
+ while [[ ${_ble_util_idle_task[i]-} ]]; do ((i++)); done
+ _ble_util_idle_task[i]=$entry
+ _ble_util_idle_lasttask=$i
+ }
+ function ble/util/idle.push {
+ local status=R nice=0
+ while [[ $1 == -* ]]; do
+ case $1 in
+ (-[SWPFEC]) status=${1:1}$2; shift 2 ;;
+ (-[SWPFECIRZ]*) status=${1:1}; shift ;;
+ (-n) nice=$2; shift 2 ;;
+ (-n*) nice=${1#-n}; shift ;;
+ (*) break ;;
+ esac
+ done
+ ble/util/idle.push/.impl "$nice" "$status$_ble_util_idle_SEP$1"
+ }
+ function ble/util/idle.push-background {
+ ble/util/idle.push -n 10000 "$@"
+ }
+ function ble/util/idle.cancel {
+ local command=$1 i removed=
+ for i in "${!_ble_util_idle_task[@]}"; do
+ [[ ${_ble_util_idle_task[i]} == *"$_ble_util_idle_SEP$command" ]] &&
+ builtin unset -v '_ble_util_idle_task[i]' &&
+ removed=1
+ done
+ [[ $removed ]]
+ }
+ function ble/util/is-running-in-idle {
+ [[ ${ble_util_idle_status+set} ]]
+ }
+ function ble/util/idle.suspend {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=Z
+ }
+ function ble/util/idle.sleep {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ local ret; ble/util/idle.clock
+ ble_util_idle_status=S$((ret+$1))
+ }
+ function ble/util/idle.isleep {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=W$((_ble_util_idle_sclock+$1))
+ }
+ function ble/util/idle.sleep-until {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ if [[ :$2: == *:checked:* ]]; then
+ local ret; ble/util/idle.clock
+ (($1>ret)) || return 1
+ fi
+ ble_util_idle_status=S$1
+ }
+ function ble/util/idle.isleep-until {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ if [[ :$2: == *:checked:* ]]; then
+ (($1>_ble_util_idle_sclock)) || return 1
+ fi
+ ble_util_idle_status=W$1
+ }
+ function ble/util/idle.wait-user-input {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=I
+ }
+ function ble/util/idle.wait-process {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=P$1
+ }
+ function ble/util/idle.wait-file-content {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=F$1
+ }
+ function ble/util/idle.wait-filename {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=E$1
+ }
+ function ble/util/idle.wait-condition {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=C$1
+ }
+ function ble/util/idle.continue {
+ [[ ${ble_util_idle_status+set} ]] || return 2
+ ble_util_idle_status=R
+ }
+ function ble/util/idle/.delare-external-modifier {
+ local name=$1
+ builtin eval -- 'function ble/util/idle#'$name' {
+ local index=$1
+ [[ ${_ble_util_idle_task[index]+set} ]] || return 2
+ local ble_util_idle_status=${_ble_util_idle_task[index]%%"$_ble_util_idle_SEP"*}
+ local ble_util_idle_command=${_ble_util_idle_task[index]#*"$_ble_util_idle_SEP"}
+ ble/util/idle.'$name' "${@:2}"
+ _ble_util_idle_task[index]=$ble_util_idle_status$_ble_util_idle_SEP$ble_util_idle_command
+ }'
+ }
+ ble/util/idle/.delare-external-modifier suspend
+ ble/util/idle/.delare-external-modifier sleep
+ ble/util/idle/.delare-external-modifier isleep
+ ble/util/idle.push-background 'ble/util/msleep/calibrate'
+else
+ function ble/util/idle.do { false; }
+fi
+_ble_util_fiberchain=()
+_ble_util_fiberchain_prefix=
+function ble/util/fiberchain#initialize {
+ _ble_util_fiberchain=()
+ _ble_util_fiberchain_prefix=$1
+}
+function ble/util/fiberchain#resume/.core {
+ _ble_util_fiberchain=()
+ local fib_clock=0
+ local fib_ntask=$#
+ while (($#)); do
+ ((fib_ntask--))
+ local fiber=${1%%:*} fib_suspend= fib_kill=
+ local argv; ble/string#split-words argv "$fiber"
+ [[ $1 == *:* ]] && fib_suspend=${1#*:}
+ "$_ble_util_fiberchain_prefix/$argv.fib" "${argv[@]:1}"
+ if [[ $fib_kill ]]; then
+ break
+ elif [[ $fib_suspend ]]; then
+ _ble_util_fiberchain=("$fiber:$fib_suspend" "${@:2}")
+ return 148
+ fi
+ shift
+ done
+}
+function ble/util/fiberchain#resume {
+ ble/util/fiberchain#resume/.core "${_ble_util_fiberchain[@]}"
+}
+function ble/util/fiberchain#push {
+ ble/array#push _ble_util_fiberchain "$@"
+}
+function ble/util/fiberchain#clear {
+ _ble_util_fiberchain=()
+}
+bleopt/declare -v vbell_default_message ' Wuff, -- Wuff!! '
+bleopt/declare -v vbell_duration 2000
+bleopt/declare -n vbell_align left
+function ble/term:cygwin/initialize.hook {
+ printf '\eM\e[B' >&$_ble_util_fd_stderr
+ _ble_term_ri=$'\e[A'
+ function ble/canvas/put-dl.draw {
+ local value=${1-1} i
+ ((value)) || return 1
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$'\e[2K'
+ if ((value>1)); then
+ local ret
+ ble/string#repeat $'\e[B\e[2K' $((value-1)); local a=$ret
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$ret$'\e['$((value-1))'A'
+ fi
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value}
+ }
+}
+function ble/term/DA2R.hook {
+ blehook DA2R-=ble/term/DA2R.hook
+ case $_ble_term_TERM in
+ (contra:*)
+ _ble_term_cuu=$'\e[%dk'
+ _ble_term_cud=$'\e[%de'
+ _ble_term_cuf=$'\e[%da'
+ _ble_term_cub=$'\e[%dj'
+ _ble_term_cup=$'\e[%l;%cf' ;;
+ (cygwin:*)
+ ble/term:cygwin/initialize.hook ;;
+ esac
+}
+function ble/term/.initialize {
+ if [[ -s $_ble_base_cache/term.$TERM && $_ble_base_cache/term.$TERM -nt $_ble_base/lib/init-term.sh ]]; then
+ source "$_ble_base_cache/term.$TERM"
+ else
+ source "$_ble_base/lib/init-term.sh"
+ fi
+ ble/string#reserve-prototype "$_ble_term_it"
+ blehook DA2R+=ble/term/DA2R.hook
+}
+ble/term/.initialize
+function ble/term/put {
+ BUFF[${#BUFF[@]}]=$1
+}
+function ble/term/cup {
+ local x=$1 y=$2 esc=$_ble_term_cup
+ esc=${esc//'%x'/$x}
+ esc=${esc//'%y'/$y}
+ esc=${esc//'%c'/$((x+1))}
+ esc=${esc//'%l'/$((y+1))}
+ BUFF[${#BUFF[@]}]=$esc
+}
+function ble/term/flush {
+ IFS= builtin eval 'ble/util/put "${BUFF[*]}"'
+ BUFF=()
+}
+function ble/term/audible-bell {
+ ble/util/put '' 1>&2
+}
+_ble_term_visible_bell_prev=()
+_ble_term_visible_bell_ftime=$_ble_base_run/$$.visible-bell.time
+_ble_term_visible_bell_show='%message%'
+_ble_term_visible_bell_clear=
+function ble/term/visible-bell:term/init {
+ if [[ ! $_ble_term_visible_bell_clear ]]; then
+ local -a BUFF=()
+ ble/term/put "$_ble_term_ri_or_cuu1$_ble_term_sc$_ble_term_sgr0"
+ ble/term/cup 0 0
+ ble/term/put "$_ble_term_el%message%$_ble_term_sgr0$_ble_term_rc${_ble_term_cud//'%d'/1}"
+ IFS= builtin eval '_ble_term_visible_bell_show="${BUFF[*]}"'
+ BUFF=()
+ ble/term/put "$_ble_term_sc$_ble_term_sgr0"
+ ble/term/cup 0 0
+ ble/term/put "$_ble_term_el2$_ble_term_rc"
+ IFS= builtin eval '_ble_term_visible_bell_clear="${BUFF[*]}"'
+ fi
+ local cols=${COLUMNS:-80}
+ ((_ble_term_xenl||cols--))
+ local message=${1::cols}
+ _ble_term_visible_bell_prev=(term "$message")
+}
+function ble/term/visible-bell:term/show {
+ local sgr=$1 message=${_ble_term_visible_bell_prev[1]}
+ message=${_ble_term_visible_bell_show//'%message%'/"$sgr$message"}
+ ble/util/put "$message" >&2
+}
+function ble/term/visible-bell:term/update {
+ ble/term/visible-bell:term/show "$@"
+}
+function ble/term/visible-bell:term/clear {
+ local sgr=$1
+ ble/util/put "$_ble_term_visible_bell_clear" >&2
+}
+function ble/term/visible-bell:canvas/init {
+ local message=$1
+ local lines=1 cols=${COLUMNS:-80}
+ ((_ble_term_xenl||cols--))
+ local x= y=
+ local ret sgr0= sgr1=
+ ble/canvas/trace-text "$message" nonewline:external-sgr
+ message=$ret
+ local x0=0 y0=0
+ if [[ $bleopt_vbell_align == right ]]; then
+ ((x0=COLUMNS-1-x,x0<0&&(x0=0)))
+ elif [[ $bleopt_vbell_align == center ]]; then
+ ((x0=(COLUMNS-1-x)/2,x0<0&&(x0=0)))
+ fi
+ _ble_term_visible_bell_prev=(canvas "$message" "$x0" "$y0" "$x" "$y")
+}
+function ble/term/visible-bell:canvas/show {
+ local sgr=$1 opts=$2
+ local message=${_ble_term_visible_bell_prev[1]}
+ local x0=${_ble_term_visible_bell_prev[2]}
+ local y0=${_ble_term_visible_bell_prev[3]}
+ local x=${_ble_term_visible_bell_prev[4]}
+ local y=${_ble_term_visible_bell_prev[5]}
+ local -a DRAW_BUFF=()
+ [[ :$opts: != *:update:* && $_ble_attached ]] && # WA #D1495
+ [[ $_ble_term_ri || :$opts: != *:erased:* && :$opts: != *:update:* ]] &&
+ ble/canvas/panel/ensure-tmargin.draw
+ if [[ $_ble_term_rc ]]; then
+ local ret=
+ [[ :$opts: != *:update:* && $_ble_attached ]] && ble/canvas/panel/save-position goto-top-dock # WA #D1495
+ ble/canvas/put.draw "$_ble_term_ri_or_cuu1$_ble_term_sc$_ble_term_sgr0"
+ ble/canvas/put-cup.draw $((y0+1)) $((x0+1))
+ ble/canvas/put.draw "$sgr$message$_ble_term_sgr0"
+ ble/canvas/put.draw "$_ble_term_rc"
+ ble/canvas/put-cud.draw 1
+ [[ :$opts: != *:update:* && $_ble_attached ]] && ble/canvas/panel/load-position.draw "$ret" # WA #D1495
+ else
+ ble/canvas/put.draw "$_ble_term_ri_or_cuu1$_ble_term_sgr0"
+ ble/canvas/put-hpa.draw $((1+x0))
+ ble/canvas/put.draw "$sgr$message$_ble_term_sgr0"
+ ble/canvas/put-cud.draw 1
+ ble/canvas/put-hpa.draw $((1+_ble_canvas_x))
+ fi
+ ble/canvas/bflush.draw
+ ble/util/buffer.flush >&2
+}
+function ble/term/visible-bell:canvas/update {
+ ble/term/visible-bell:canvas/show "$@"
+}
+function ble/term/visible-bell:canvas/clear {
+ local sgr=$1
+ local x0=${_ble_term_visible_bell_prev[2]}
+ local y0=${_ble_term_visible_bell_prev[3]}
+ local x=${_ble_term_visible_bell_prev[4]}
+ local y=${_ble_term_visible_bell_prev[5]}
+ local -a DRAW_BUFF=()
+ if [[ $_ble_term_rc ]]; then
+ local ret=
+ ble/canvas/put.draw "$_ble_term_sc$_ble_term_sgr0"
+ ble/canvas/put-cup.draw $((y0+1)) $((x0+1))
+ ble/canvas/put.draw "$sgr"
+ ble/canvas/put-spaces.draw "$x"
+ ble/canvas/put.draw "$_ble_term_sgr0$_ble_term_rc"
+ else
+ : # 親プロセスの _ble_canvas_x が分からないので座標がずれる
+ fi
+ ble/canvas/flush.draw >&2
+}
+function ble/term/visible-bell/defface.hook {
+ ble/color/defface vbell reverse
+ ble/color/defface vbell_flash reverse,fg=green
+ ble/color/defface vbell_erase bg=252
+}
+blehook color_defface_load+=ble/term/visible-bell/defface.hook
+function ble/term/visible-bell/.show {
+ local bell_type=${_ble_term_visible_bell_prev[0]}
+ ble/term/visible-bell:"$bell_type"/show "$@"
+}
+function ble/term/visible-bell/.update {
+ local bell_type=${_ble_term_visible_bell_prev[0]}
+ ble/term/visible-bell:"$bell_type"/update "$1" "$2:update"
+}
+function ble/term/visible-bell/.clear {
+ local bell_type=${_ble_term_visible_bell_prev[0]}
+ ble/term/visible-bell:"$bell_type"/clear "$@"
+ >| "$_ble_term_visible_bell_ftime"
+}
+function ble/term/visible-bell/.erase-previous-visible-bell {
+ local ret workers
+ ble/util/eval-pathname-expansion '"$_ble_base_run/$$.visible-bell."*' canonical
+ workers=("${ret[@]}")
+ local workerfile
+ for workerfile in "${workers[@]}"; do
+ if [[ -s $workerfile && ! ( $workerfile -ot $_ble_term_visible_bell_ftime ) ]]; then
+ ble/term/visible-bell/.clear "$sgr0"
+ return 0
+ fi
+ done
+ return 1
+}
+function ble/term/visible-bell/.create-workerfile {
+ local i=0
+ while
+ workerfile=$_ble_base_run/$$.visible-bell.$i
+ [[ -s $workerfile ]]
+ do ((i++)); done
+ ble/util/print 1 >| "$workerfile"
+}
+function ble/term/visible-bell/.worker {
+ ble/util/msleep 50
+ [[ $workerfile -ot $_ble_term_visible_bell_ftime ]] && return 0 >| "$workerfile"
+ ble/term/visible-bell/.update "$sgr2"
+ if [[ :$opts: == *:persistent:* ]]; then
+ local dead_workerfile=$_ble_base_run/$$.visible-bell.Z
+ ble/util/print 1 >| "$dead_workerfile"
+ return 0 >| "$workerfile"
+ fi
+ local msec=$bleopt_vbell_duration
+ ble/util/msleep "$msec"
+ [[ $workerfile -ot $_ble_term_visible_bell_ftime ]] && return 0 >| "$workerfile"
+ ble/term/visible-bell/.clear "$sgr0"
+ >| "$workerfile"
+}
+function ble/term/visible-bell {
+ local message=$1 opts=$2
+ message=${message:-$bleopt_vbell_default_message}
+ ((LINES==1)) && return 0
+ if ble/is-function ble/canvas/trace-text; then
+ ble/term/visible-bell:canvas/init "$message"
+ else
+ ble/term/visible-bell:term/init "$message"
+ fi
+ local sgr0=$_ble_term_sgr0
+ local sgr1=${_ble_term_setaf[2]}$_ble_term_rev
+ local sgr2=$_ble_term_rev
+ if ble/is-function ble/color/face2sgr; then
+ local ret
+ ble/color/face2sgr vbell_flash; sgr1=$ret
+ ble/color/face2sgr vbell; sgr2=$ret
+ ble/color/face2sgr vbell_erase; sgr0=$ret
+ fi
+ local show_opts=
+ ble/term/visible-bell/.erase-previous-visible-bell && show_opts=erased
+ ble/term/visible-bell/.show "$sgr1" "$show_opts"
+ local workerfile; ble/term/visible-bell/.create-workerfile
+ ( ble/term/visible-bell/.worker __ble_suppress_joblist__ 1>/dev/null & )
+}
+function ble/term/visible-bell/cancel-erasure {
+ >| "$_ble_term_visible_bell_ftime"
+}
+function ble/term/visible-bell/erase {
+ local sgr0=$_ble_term_sgr0
+ if ble/is-function ble/color/face2sgr; then
+ local ret
+ ble/color/face2sgr vbell_erase; sgr0=$ret
+ fi
+ ble/term/visible-bell/.erase-previous-visible-bell
+}
+_ble_term_stty_state=
+_ble_term_stty_flags_enter=()
+_ble_term_stty_flags_leave=()
+ble/array#push _ble_term_stty_flags_enter intr undef quit undef susp undef
+ble/array#push _ble_term_stty_flags_leave intr '' quit '' susp ''
+function ble/term/stty/.initialize-flags {
+ if [[ $TERM == minix ]]; then
+ local stty; ble/util/assign stty 'stty -a'
+ if [[ $stty == *' rprnt '* ]]; then
+ ble/array#push _ble_term_stty_flags_enter rprnt undef
+ ble/array#push _ble_term_stty_flags_leave rprnt ''
+ elif [[ $stty == *' reprint '* ]]; then
+ ble/array#push _ble_term_stty_flags_enter reprint undef
+ ble/array#push _ble_term_stty_flags_leave reprint ''
+ fi
+ fi
+}
+ble/term/stty/.initialize-flags
+function ble/term/stty/initialize {
+ ble/bin/stty -ixon -echo -nl -icrnl -icanon \
+ "${_ble_term_stty_flags_enter[@]}"
+ _ble_term_stty_state=1
+}
+function ble/term/stty/leave {
+ [[ ! $_ble_term_stty_state ]] && return 0
+ ble/bin/stty echo -nl icanon \
+ "${_ble_term_stty_flags_leave[@]}"
+ _ble_term_stty_state=
+}
+function ble/term/stty/enter {
+ [[ $_ble_term_stty_state ]] && return 0
+ ble/bin/stty -echo -nl -icrnl -icanon \
+ "${_ble_term_stty_flags_enter[@]}"
+ _ble_term_stty_state=1
+}
+function ble/term/stty/finalize {
+ ble/term/stty/leave
+}
+function ble/term/stty/TRAPEXIT {
+ ble/bin/stty echo -nl \
+ "${_ble_term_stty_flags_leave[@]}"
+}
+bleopt/declare -v term_cursor_external 0
+_ble_term_cursor_current=unknown
+_ble_term_cursor_internal=0
+_ble_term_cursor_hidden_current=unknown
+_ble_term_cursor_hidden_internal=reveal
+_ble_term_cursor_current=0
+function ble/term/cursor-state/.update {
+ local state=$(($1))
+ [[ $_ble_term_cursor_current == "$state" ]] && return 0
+ if [[ ! $_ble_term_Ss ]]; then
+ case $_ble_term_TERM in
+ (mintty:*|xterm:*|RLogin:*|kitty:*|screen:*|tmux:*|contra:*|cygwin:*|wezterm:*|wt:*)
+ local _ble_term_Ss=$'\e[@1 q' ;;
+ esac
+ fi
+ local ret=${_ble_term_Ss//@1/"$state"}
+ [[ $ret && $ret != $'\eP'*$'\e\\' ]] &&
+ ble/term/quote-passthrough "$ret" '' all
+ ble/util/buffer "$ret"
+ _ble_term_cursor_current=$state
+}
+function ble/term/cursor-state/set-internal {
+ _ble_term_cursor_internal=$1
+ [[ $_ble_term_state == internal ]] &&
+ ble/term/cursor-state/.update "$1"
+}
+function ble/term/cursor-state/.update-hidden {
+ local state=$1
+ [[ $state != hidden ]] && state=reveal
+ [[ $_ble_term_cursor_hidden_current == "$state" ]] && return 0
+ if [[ $state == hidden ]]; then
+ ble/util/buffer "$_ble_term_civis"
+ else
+ ble/util/buffer "$_ble_term_cvvis"
+ fi
+ _ble_term_cursor_hidden_current=$state
+}
+function ble/term/cursor-state/hide {
+ _ble_term_cursor_hidden_internal=hidden
+ [[ $_ble_term_state == internal ]] &&
+ ble/term/cursor-state/.update-hidden hidden
+}
+function ble/term/cursor-state/reveal {
+ _ble_term_cursor_hidden_internal=reveal
+ [[ $_ble_term_state == internal ]] &&
+ ble/term/cursor-state/.update-hidden reveal
+}
+function ble/term/bracketed-paste-mode/enter {
+ ble/util/buffer $'\e[?2004h'
+}
+function ble/term/bracketed-paste-mode/leave {
+ ble/util/buffer $'\e[?2004l'
+}
+if [[ $TERM == minix ]]; then
+ function ble/term/bracketed-paste-mode/enter { :; }
+ function ble/term/bracketed-paste-mode/leave { :; }
+fi
+_ble_term_TERM=()
+_ble_term_DA1R=()
+_ble_term_DA2R=()
+function ble/term/DA2/initialize-term {
+ local depth=$1
+ local DA2R=${_ble_term_DA2R[depth]}
+ local rex='^[0-9]*(;[0-9]*)*$'; [[ $DA2R =~ $rex ]] || return
+ local da2r
+ ble/string#split da2r ';' "$DA2R"
+ da2r=("${da2r[@]/#/10#0}") # 0で始まっていても10進数で解釈 (#D1570 is-array OK)
+ case $DA2R in
+ ('0;0;0')
+ _ble_term_TERM[depth]=wezterm:0 ;;
+ ('0;10;1') # Windows Terminal
+ _ble_term_TERM[depth]=wt:0 ;;
+ ('0;'*';1')
+ if ((da2r[1]>=1001)); then
+ _ble_term_TERM[depth]=alacritty:$((da2r[1]))
+ fi ;;
+ ('1;0'?????';0')
+ _ble_term_TERM[depth]=foot:${DA2R:3:5} ;;
+ ('1;'*)
+ if ((4000<=da2r[1]&&da2r[1]<=4009&&3<=da2r[2])); then
+ _ble_term_TERM[depth]=kitty:$((da2r[1]-4000))
+ elif ((2000<=da2r[1]&&da2r[1]<5400&&da2r[2]==0)); then
+ local version=$((da2r[1]))
+ _ble_term_TERM[depth]=vte:$version
+ if ((version<4000)); then
+ _ble_term_Ss=
+ fi
+ fi ;;
+ ('65;'*)
+ if ((5300<=da2r[1]&&da2r[2]==1)); then
+ _ble_term_TERM[depth]=vte:$((da2r[1]))
+ elif ((da2r[1]>=100)); then
+ _ble_term_TERM[depth]=RLogin:$((da2r[1]))
+ fi ;;
+ ('67;'*)
+ local rex='^67;[0-9]{3,};0$'
+ if [[ $TERM == cygwin && $DA2R =~ $rex ]]; then
+ _ble_term_TERM[depth]=cygwin:$((da2r[1]))
+ fi ;;
+ ('77;'*';0')
+ _ble_term_TERM[depth]=mintty:$((da2r[1])) ;;
+ ('83;'*)
+ local rex='^83;[0-9]+;0$'
+ [[ $DA2R =~ $rex ]] && _ble_term_TERM[depth]=screen:$((da2r[1])) ;;
+ ('84;0;0')
+ _ble_term_TERM[depth]=tmux:0 ;;
+ ('99;'*)
+ _ble_term_TERM[depth]=contra:$((da2r[1])) ;;
+ esac
+ [[ ${_ble_term_TERM[depth]} ]] && return 0
+ if rex='^xterm(-|$)'; [[ $TERM =~ $rex ]]; then
+ local version=$((da2r[1]))
+ if rex='^1;[0-9]+;0$'; [[ $DA2R =~ $rex ]]; then
+ true
+ elif rex='^0;[0-9]+;0$'; [[ $DA2R =~ $rex ]]; then
+ ((95<=version))
+ elif rex='^(2|24|1[89]|41|6[145]);[0-9]+;0$'; [[ $DA2R =~ $rex ]]; then
+ ((280<=version))
+ elif rex='^32;[0-9]+;0$'; [[ $DA2R =~ $rex ]]; then
+ ((354<=version&&version<2000))
+ else
+ false
+ fi && { _ble_term_TERM[depth]=xterm:$version; return; }
+ fi
+ _ble_term_TERM[depth]=unknown:-
+ return 0
+}
+function ble/term/DA1/notify { _ble_term_DA1R=$1; blehook/invoke DA1R; }
+function ble/term/DA2/notify {
+ local depth=${#_ble_term_DA2R[@]}
+ if ((depth==0)) || ble/string#match "${_ble_term_TERM[depth-1]}" '^(screen|tmux):'; then
+ _ble_term_DA2R[depth]=$1
+ ble/term/DA2/initialize-term "$depth"
+ case ${_ble_term_TERM[depth]} in
+ (screen:*|tmux:*)
+ local ret
+ ble/term/quote-passthrough $'\e[>c' $((depth+1))
+ ble/util/buffer "$ret" ;;
+ (contra:*)
+ if [[ ! ${_ble_term_Ss-} ]]; then
+ _ble_term_Ss=$'\e[@1 q'
+ fi ;;
+ esac
+ ((depth)) && return 0
+ fi
+ blehook/invoke DA2R
+}
+function ble/term/quote-passthrough {
+ local seq=$1 level=${2:-$((${#_ble_term_DA2R[@]}-1))} opts=$3
+ local all=; [[ :$opts: == *:all:* ]] && all=1
+ ret=$seq
+ [[ $seq ]] || return 0
+ local i
+ for ((i=level;--i>=0;)); do
+ if [[ ${_ble_term_TERM[i]} == tmux:* ]]; then
+ ret=$'\ePtmux;'${ret//$'\e'/$'\e\e'}$'\e\\'${all:+$seq}
+ else
+ ret=$'\eP'${ret//$'\e\\'/$'\e\e\\\eP\\'}$'\e\\'${all:+$seq}
+ fi
+ done
+}
+_ble_term_DECSTBM=
+_ble_term_DECSTBM_reset=
+function ble/term/test-DECSTBM.hook1 {
+ (($1==2)) && _ble_term_DECSTBM=$'\e[%s;%sr'
+}
+function ble/term/test-DECSTBM.hook2 {
+ if [[ $_ble_term_DECSTBM ]]; then
+ if (($1==2)); then
+ _ble_term_DECSTBM_reset=$'\e[r'
+ else
+ _ble_term_DECSTBM_reset=$'\e[;r'
+ fi
+ fi
+}
+function ble/term/test-DECSTBM {
+ local -a DRAW_BUFF=()
+ ble/canvas/panel/goto-top-dock.draw
+ ble/canvas/put.draw "$_ble_term_sc"$'\e[1;2r'
+ ble/canvas/put-cup.draw 2 1
+ ble/canvas/put-cud.draw 1
+ ble/term/CPR/request.draw ble/term/test-DECSTBM.hook1
+ ble/canvas/put.draw $'\e[;r'
+ ble/canvas/put-cup.draw 2 1
+ ble/canvas/put-cud.draw 1
+ ble/term/CPR/request.draw ble/term/test-DECSTBM.hook2
+ ble/canvas/put.draw $'\e[r'"$_ble_term_rc"
+ ble/canvas/bflush.draw
+}
+_ble_term_CPR_timeout=60
+_ble_term_CPR_last_seconds=$SECONDS
+_ble_term_CPR_hook=()
+function ble/term/CPR/request.buff {
+ ((SECONDS>_ble_term_CPR_last_seconds+_ble_term_CPR_timeout)) &&
+ _ble_term_CPR_hook=()
+ _ble_term_CPR_last_seconds=$SECONDS
+ ble/array#push _ble_term_CPR_hook "$1"
+ ble/util/buffer $'\e[6n'
+ return 147
+}
+function ble/term/CPR/request.draw {
+ ((SECONDS>_ble_term_CPR_last_seconds+_ble_term_CPR_timeout)) &&
+ _ble_term_CPR_hook=()
+ _ble_term_CPR_last_seconds=$SECONDS
+ ble/array#push _ble_term_CPR_hook "$1"
+ ble/canvas/put.draw $'\e[6n'
+ return 147
+}
+function ble/term/CPR/notify {
+ local hook=${_ble_term_CPR_hook[0]}
+ ble/array#shift _ble_term_CPR_hook
+ [[ ! $hook ]] || builtin eval -- "$hook $1 $2"
+}
+bleopt/declare -v term_modifyOtherKeys_external auto
+bleopt/declare -v term_modifyOtherKeys_internal auto
+_ble_term_modifyOtherKeys_current=
+function ble/term/modifyOtherKeys/.update {
+ [[ $1 == "$_ble_term_modifyOtherKeys_current" ]] && return 0
+ case $_ble_term_TERM in
+ (RLogin:*)
+ case $1 in
+ (0) ble/util/buffer $'\e[>5;0m' ;;
+ (1) ble/util/buffer $'\e[>5;1m' ;;
+ (2) ble/util/buffer $'\e[>5;1m\e[>5;2m' ;;
+ esac ;;
+ (kitty:*)
+ local da2r
+ ble/string#split da2r ';' "$_ble_term_DA2R"
+ if ((da2r[2]>=23)); then
+ case $1 in
+ (0|1) # pop keyboard mode
+ [[ $_ble_term_modifyOtherKeys_current ]] || return 0
+ ((_ble_term_modifyOtherKeys_current>=2)) &&
+ ble/util/buffer $'\e[<u' ;;
+ (2) # push keyboard mode
+ ((_ble_term_modifyOtherKeys_current>=2)) &&
+ ble/util/buffer $'\e[>1u' ;;
+ esac
+ else
+ case $1 in
+ (0|1) ble/util/buffer $'\e[>4;0m\e[>4m' ;;
+ (2) ble/util/buffer $'\e[>4;1m\e[>4;2m\e[m' ;;
+ esac
+ fi
+ _ble_term_modifyOtherKeys_current=$1
+ return 0 ;;
+ esac
+ case $1 in
+ (0) ble/util/buffer $'\e[>4;0m\e[m' ;;
+ (1) ble/util/buffer $'\e[>4;1m\e[m' ;;
+ (2) ble/util/buffer $'\e[>4;1m\e[>4;2m\e[m' ;;
+ esac
+ _ble_term_modifyOtherKeys_current=$1
+}
+function ble/term/modifyOtherKeys/.supported {
+ [[ $_ble_term_TERM == vte:* ]] && return 1
+ [[ $MWG_LOGINTERM == rosaterm ]] && return 1
+ case $TERM in
+ (linux)
+ return 1 ;;
+ (minix|sun*)
+ return 1 ;;
+ (st|st-*)
+ return 1 ;;
+ esac
+ return 0
+}
+function ble/term/modifyOtherKeys/enter {
+ local value=$bleopt_term_modifyOtherKeys_internal
+ if [[ $value == auto ]]; then
+ value=2
+ ble/term/modifyOtherKeys/.supported || value=
+ fi
+ ble/term/modifyOtherKeys/.update "$value"
+}
+function ble/term/modifyOtherKeys/leave {
+ local value=$bleopt_term_modifyOtherKeys_external
+ if [[ $value == auto ]]; then
+ value=1
+ ble/term/modifyOtherKeys/.supported || value=
+ fi
+ ble/term/modifyOtherKeys/.update "$value"
+}
+_ble_term_altscr_state=
+function ble/term/enter-altscr {
+ [[ $_ble_term_altscr_state ]] && return 0
+ _ble_term_altscr_state=("$_ble_canvas_x" "$_ble_canvas_y")
+ if [[ $_ble_term_rmcup ]]; then
+ ble/util/buffer "$_ble_term_smcup"
+ else
+ local -a DRAW_BUFF=()
+ ble/canvas/put.draw $'\e[?1049h'
+ ble/canvas/put-cup.draw "$LINES" 0
+ ble/canvas/put-ind.draw "$LINES"
+ ble/canvas/bflush.draw
+ fi
+}
+function ble/term/leave-altscr {
+ [[ $_ble_term_altscr_state ]] || return 0
+ if [[ $_ble_term_rmcup ]]; then
+ ble/util/buffer "$_ble_term_rmcup"
+ else
+ local -a DRAW_BUFF=()
+ ble/canvas/put-cup.draw "$LINES" 0
+ ble/canvas/put-ind.draw
+ ble/canvas/put.draw $'\e[?1049l'
+ ble/canvas/bflush.draw
+ fi
+ _ble_canvas_x=${_ble_term_altscr_state[0]}
+ _ble_canvas_y=${_ble_term_altscr_state[1]}
+ _ble_term_altscr_state=()
+}
+_ble_term_rl_convert_meta_adjusted=
+_ble_term_rl_convert_meta_external=
+function ble/term/rl-convert-meta/enter {
+ [[ $_ble_term_rl_convert_meta_adjusted ]] && return 0
+ _ble_term_rl_convert_meta_adjusted=1
+ if ble/util/test-rl-variable convert-meta; then
+ _ble_term_rl_convert_meta_external=on
+ builtin bind 'set convert-meta off'
+ else
+ _ble_term_rl_convert_meta_external=off
+ fi
+}
+function ble/term/rl-convert-meta/leave {
+ [[ $_ble_term_rl_convert_meta_adjusted ]] || return 1
+ _ble_term_rl_convert_meta_adjusted=
+ [[ $_ble_term_rl_convert_meta_external == on ]] &&
+ builtin bind 'set convert-meta on'
+}
+function ble/term/enter-for-widget {
+ ble/term/bracketed-paste-mode/enter
+ ble/term/modifyOtherKeys/enter
+ ble/term/cursor-state/.update "$_ble_term_cursor_internal"
+ ble/term/cursor-state/.update-hidden "$_ble_term_cursor_hidden_internal"
+}
+function ble/term/leave-for-widget {
+ ble/term/visible-bell/erase
+ ble/term/bracketed-paste-mode/leave
+ ble/term/modifyOtherKeys/leave
+ ble/term/cursor-state/.update "$bleopt_term_cursor_external"
+ ble/term/cursor-state/.update-hidden reveal
+}
+_ble_term_state=external
+function ble/term/enter {
+ [[ $_ble_term_state == internal ]] && return 0
+ ble/term/stty/enter
+ ble/term/rl-convert-meta/enter
+ ble/term/enter-for-widget
+ _ble_term_state=internal
+}
+function ble/term/leave {
+ [[ $_ble_term_state == external ]] && return 0
+ ble/term/stty/leave
+ ble/term/rl-convert-meta/leave
+ ble/term/leave-for-widget
+ _ble_term_cursor_current=unknown # vim は復元してくれない
+ _ble_term_cursor_hidden_current=unknown
+ _ble_term_state=external
+}
+function ble/term/finalize {
+ ble/term/stty/finalize
+ ble/term/leave
+ ble/util/buffer.flush >&2
+}
+function ble/term/initialize {
+ ble/term/stty/initialize
+ ble/term/test-DECSTBM
+ ble/term/enter
+}
+_ble_util_s2c_table_enabled=
+if ((_ble_bash>=40100)); then
+ function ble/util/s2c {
+ builtin printf -v ret %d "'$1"
+ }
+elif ((_ble_bash>=40000&&!_ble_bash_loaded_in_function)); then
+ declare -A _ble_util_s2c_table
+ _ble_util_s2c_table_enabled=1
+ function ble/util/s2c {
+ [[ $_ble_util_locale_triple != "$LC_ALL:$LC_CTYPE:$LANG" ]] &&
+ ble/util/.cache/update-locale
+ local s=${1::1}
+ ret=${_ble_util_s2c_table[x$s]}
+ [[ $ret ]] && return 0
+ ble/util/sprintf ret %d "'$s"
+ _ble_util_s2c_table[x$s]=$ret
+ }
+elif ((_ble_bash>=40000)); then
+ function ble/util/s2c {
+ ble/util/sprintf ret %d "'${1::1}"
+ }
+else
+ function ble/util/s2c {
+ local s=${1::1}
+ if [[ $s == [$'\x01'-$'\x7F'] ]]; then
+ if [[ $s == $'\x7F' ]]; then
+ ret=127
+ else
+ ble/util/sprintf ret %d "'$s"
+ fi
+ return 0
+ fi
+ local bytes byte TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ ble/util/assign bytes '
+ while IFS= builtin read "${_ble_bash_tmout_wa[@]}" -r -n 1 byte; do
+ builtin printf "%d " "'\''$byte"
+ done <<< "$s"
+ '
+ "ble/encoding:$bleopt_input_encoding/b2c" $bytes
+ }
+fi
+if ((_ble_bash>=40200)); then
+ function ble/util/.has-bashbug-printf-uffff {
+ ((40200<=_ble_bash&&_ble_bash<40500)) || return 1
+ local LC_ALL=C.UTF-8 2>/dev/null # Workaround: CentOS 7 に C.UTF-8 がなかった
+ local ret
+ builtin printf -v ret '\uFFFF'
+ ((${#ret}==2))
+ }
+ ble/function#suppress-stderr ble/util/.has-bashbug-printf-uffff
+ if ble/util/.has-bashbug-printf-uffff; then
+ function ble/util/c2s.impl {
+ if ((0xE000<=$1&&$1<=0xFFFF)) && [[ $_ble_util_locale_encoding == UTF-8 ]]; then
+ builtin printf -v ret '\\x%02x' $((0xE0|$1>>12&0x0F)) $((0x80|$1>>6&0x3F)) $((0x80|$1&0x3F))
+ else
+ builtin printf -v ret '\\U%08x' "$1"
+ fi
+ builtin eval "ret=\$'$ret'"
+ }
+ function ble/util/chars2s.impl {
+ if [[ $_ble_util_locale_encoding == UTF-8 ]]; then
+ local -a buff=()
+ local c i=0
+ for c; do
+ ble/util/c2s.cached "$c"
+ buff[i++]=$ret
+ done
+ IFS= builtin eval 'ret="${buff[*]}"'
+ else
+ builtin printf -v ret '\\U%08x' "$@"
+ builtin eval "ret=\$'$ret'"
+ fi
+ }
+ else
+ function ble/util/c2s.impl {
+ builtin printf -v ret '\\U%08x' "$1"
+ builtin eval "ret=\$'$ret'"
+ }
+ function ble/util/chars2s.impl {
+ builtin printf -v ret '\\U%08x' "$@"
+ builtin eval "ret=\$'$ret'"
+ }
+ fi
+else
+ _ble_text_xdigit=(0 1 2 3 4 5 6 7 8 9 A B C D E F)
+ _ble_text_hexmap=()
+ for ((i=0;i<256;i++)); do
+ _ble_text_hexmap[i]=${_ble_text_xdigit[i>>4&0xF]}${_ble_text_xdigit[i&0xF]}
+ done
+ function ble/util/c2s.impl {
+ if (($1<0x80)); then
+ builtin eval "ret=\$'\\x${_ble_text_hexmap[$1]}'"
+ return 0
+ fi
+ local bytes i iN seq=
+ ble/encoding:"$_ble_util_locale_encoding"/c2b "$1"
+ for ((i=0,iN=${#bytes[@]};i<iN;i++)); do
+ seq="$seq\\x${_ble_text_hexmap[bytes[i]&0xFF]}"
+ done
+ builtin eval "ret=\$'$seq'"
+ }
+ function ble/util/chars2s.loop {
+ for c; do
+ ble/util/c2s.cached "$c"
+ buff[i++]=$ret
+ done
+ }
+ function ble/util/chars2s.impl {
+ local -a buff=()
+ local c i=0 b N=$# B=160
+ for ((b=0;b+B<N;b+=B)); do
+ ble/util/chars2s.loop "${@:b+1:B}"
+ done
+ ble/util/chars2s.loop "${@:b+1:N-b}"
+ IFS= builtin eval 'ret="${buff[*]}"'
+ }
+fi
+_ble_util_c2s_table=()
+function ble/util/c2s {
+ [[ $_ble_util_locale_triple != "$LC_ALL:$LC_CTYPE:$LANG" ]] &&
+ ble/util/.cache/update-locale
+ ret=${_ble_util_c2s_table[$1]-}
+ if [[ ! $ret ]]; then
+ ble/util/c2s.impl "$1"
+ _ble_util_c2s_table[$1]=$ret
+ fi
+}
+function ble/util/c2s.cached {
+ ret=${_ble_util_c2s_table[$1]-}
+ if [[ ! $ret ]]; then
+ ble/util/c2s.impl "$1"
+ _ble_util_c2s_table[$1]=$ret
+ fi
+}
+function ble/util/chars2s {
+ [[ $_ble_util_locale_triple != "$LC_ALL:$LC_CTYPE:$LANG" ]] &&
+ ble/util/.cache/update-locale
+ ble/util/chars2s.impl "$@"
+}
+function ble/util/c2bc {
+ "ble/encoding:$bleopt_input_encoding/c2bc" "$1"
+}
+_ble_util_locale_triple=
+_ble_util_locale_ctype=
+_ble_util_locale_encoding=UTF-8
+function ble/util/.cache/update-locale {
+ _ble_util_locale_triple=$LC_ALL:$LC_CTYPE:$LANG
+ local ret; ble/string#tolower "${LC_ALL:-${LC_CTYPE:-$LANG}}"
+ if [[ $_ble_util_locale_ctype != "$ret" ]]; then
+ _ble_util_locale_ctype=$ret
+ _ble_util_c2s_table=()
+ [[ $_ble_util_s2c_table_enabled ]] &&
+ _ble_util_s2c_table=()
+ _ble_util_locale_encoding=C
+ if local rex='\.([^@]+)'; [[ $_ble_util_locale_ctype =~ $rex ]]; then
+ local enc=${BASH_REMATCH[1]}
+ if [[ $enc == utf-8 || $enc == utf8 ]]; then
+ enc=UTF-8
+ fi
+ ble/is-function "ble/encoding:$enc/b2c" &&
+ _ble_util_locale_encoding=$enc
+ fi
+ fi
+}
+function ble/util/s2chars {
+ local text=$1 n=${#1} i chars
+ chars=()
+ for ((i=0;i<n;i++)); do
+ ble/util/s2c "${text:i:1}"
+ ble/array#push chars "$ret"
+ done
+ ret=("${chars[@]}")
+}
+function ble/util/s2bytes {
+ local LC_ALL= LC_CTYPE=C
+ ble/util/s2chars "$1"
+}
+ble/function#suppress-stderr ble/util/s2bytes
+function ble/util/c2keyseq {
+ local char=$(($1))
+ case $char in
+ (7) ret='\a' ;;
+ (8) ret='\b' ;;
+ (9) ret='\t' ;;
+ (10) ret='\n' ;;
+ (11) ret='\v' ;;
+ (12) ret='\f' ;;
+ (13) ret='\r' ;;
+ (27) ret='\e' ;;
+ (92) ret='\\' ;;
+ (127) ret='\d' ;;
+ (28) ret='\x1c' ;; # workaround \C-\, \C-\\
+ (156) ret='\x9c' ;; # workaround \M-\C-\, \M-\C-\\
+ (*)
+ if ((char<32||128<=char&&char<160)); then
+ local char7=$((char&0x7F))
+ if ((1<=char7&&char7<=26)); then
+ ble/util/c2s $((char7+96))
+ else
+ ble/util/c2s $((char7+64))
+ fi
+ ret='\C-'$ret
+ ((char&0x80)) && ret='\M-'$ret
+ else
+ ble/util/c2s "$char"
+ fi ;;
+ esac
+}
+function ble/util/chars2keyseq {
+ local char str=
+ for char; do
+ ble/util/c2keyseq "$char"
+ str=$str$ret
+ done
+ ret=$str
+}
+function ble/util/keyseq2chars {
+ local keyseq=$1
+ local -a chars=()
+ local mods=
+ local rex='^([^\]+)|^\\([CM]-|[0-7]{1,3}|x[0-9a-fA-F]{1,2}|.)?'
+ while [[ $keyseq ]]; do
+ local text=${keyseq::1}
+ [[ $keyseq =~ $rex ]] &&
+ text=${BASH_REMATCH[1]} esc=${BASH_REMATCH[2]}
+ if [[ $text ]]; then
+ keyseq=${keyseq:${#text}}
+ ble/util/s2chars "$text"
+ else
+ keyseq=${keyseq:1+${#esc}}
+ ret=()
+ case $esc in
+ ([CM]-) mods=$mods${esc::1}; continue ;;
+ (x?*) ret=$((16#${esc#x})) ;;
+ ([0-7]*) ret=$((8#$esc)) ;;
+ (a) ret=7 ;;
+ (b) ret=8 ;;
+ (t) ret=9 ;;
+ (n) ret=10 ;;
+ (v) ret=11 ;;
+ (f) ret=12 ;;
+ (r) ret=13 ;;
+ (e) ret=27 ;;
+ (d) ret=127 ;;
+ (*) ble/util/s2c "$esc" ;;
+ esac
+ fi
+ [[ $mods == *C* ]] && ((ret=ret==63?127:(ret&0x1F)))
+ [[ $mods == *M* ]] && ble/array#push chars 27
+ mods=
+ ble/array#push chars "${ret[@]}"
+ done
+ if [[ $mods ]]; then
+ [[ $mods == *M* ]] && ble/array#push chars 27
+ ble/array#push chars 0
+ fi
+ ret=("${chars[@]}")
+}
+function ble/encoding:UTF-8/b2c {
+ local bytes b0 n i
+ bytes=("$@")
+ ret=0
+ ((b0=bytes[0]&0xFF))
+ ((n=b0>0xF0
+ ?(b0>0xFC?5:(b0>0xF8?4:3))
+ :(b0>0xE0?2:(b0>0xC0?1:0)),
+ ret=n?b0&0x7F>>n:b0))
+ for ((i=1;i<=n;i++)); do
+ ((ret=ret<<6|0x3F&bytes[i]))
+ done
+}
+function ble/encoding:UTF-8/c2b {
+ local code=$1 n i
+ ((code=code&0x7FFFFFFF,
+ n=code<0x80?0:(
+ code<0x800?1:(
+ code<0x10000?2:(
+ code<0x200000?3:(
+ code<0x4000000?4:5))))))
+ if ((n==0)); then
+ bytes=("$code")
+ else
+ bytes=()
+ for ((i=n;i;i--)); do
+ ((bytes[i]=0x80|code&0x3F,
+ code>>=6))
+ done
+ ((bytes[0]=code&0x3F>>n|0xFF80>>n&0xFF))
+ fi
+}
+function ble/encoding:C/b2c {
+ local byte=$1
+ ((ret=byte&0xFF))
+}
+function ble/encoding:C/c2b {
+ local code=$1
+ bytes=($((code&0xFF)))
+}
+function ble/util/is-unicode-output {
+ [[ $_ble_util_locale_triple != "$LC_ALL:$LC_CTYPE:$LANG" ]] &&
+ ble/util/.cache/update-locale
+ [[ $_ble_util_locale_encoding == UTF-8 ]]
+}
+ble/bin/.freeze-utility-path "${_ble_init_posix_command_list[@]}" # <- this uses ble/util/assign.
+ble/bin/.freeze-utility-path man
+ble/bin/.freeze-utility-path groff nroff mandoc gzip bzcat lzcat xzcat # used by core-complete.sh
+ble/builtin/trap/install-hook EXIT
+ble/builtin/trap/install-hook INT
+blehook ERR+='ble/builtin/trap/invoke ERR'
+blehook ERR+='ble/function#try TRAPERR'
+bleopt/declare -v decode_error_char_abell ''
+bleopt/declare -v decode_error_char_vbell 1
+bleopt/declare -v decode_error_char_discard ''
+bleopt/declare -v decode_error_cseq_abell ''
+bleopt/declare -v decode_error_cseq_vbell ''
+bleopt/declare -v decode_error_cseq_discard 1
+bleopt/declare -v decode_error_kseq_abell 1
+bleopt/declare -v decode_error_kseq_vbell 1
+bleopt/declare -v decode_error_kseq_discard 1
+bleopt/declare -n default_keymap auto
+function bleopt/check:default_keymap {
+ case $value in
+ (auto|emacs|vi|safe)
+ if [[ $_ble_decode_bind_state != none ]]; then
+ local bleopt_default_keymap=$value
+ ble/decode/reset-default-keymap
+ fi
+ return 0 ;;
+ (*)
+ ble/util/print "bleopt: Invalid value default_keymap='value'. The value should be one of \`auto', \`emacs', \`vi'." >&2
+ return 1 ;;
+ esac
+}
+function bleopt/get:default_keymap {
+ ret=$bleopt_default_keymap
+ if [[ $ret == auto ]]; then
+ if [[ -o vi ]]; then
+ ret=vi
+ else
+ ret=emacs
+ fi
+ fi
+}
+bleopt/declare -n decode_isolated_esc auto
+function bleopt/check:decode_isolated_esc {
+ case $value in
+ (meta|esc|auto) ;;
+ (*)
+ ble/util/print "bleopt: Invalid value decode_isolated_esc='$value'. One of the values 'auto', 'meta' or 'esc' is expected." >&2
+ return 1 ;;
+ esac
+}
+function ble/decode/uses-isolated-esc {
+ if [[ $bleopt_decode_isolated_esc == esc ]]; then
+ return 0
+ elif [[ $bleopt_decode_isolated_esc == auto ]]; then
+ if local ret; bleopt/get:default_keymap; [[ $ret == vi ]]; then
+ return 0
+ elif [[ ! $_ble_decode_key__seq ]]; then
+ local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_ key=$((_ble_decode_Ctrl|91))
+ builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[key]-}"
+ [[ ${ent:2} ]] && return 0
+ fi
+ fi
+ return 1
+}
+bleopt/declare -n decode_abort_char 28
+bleopt/declare -n decode_macro_limit 1024
+_ble_decode_Meta=0x08000000
+_ble_decode_Ctrl=0x04000000
+_ble_decode_Shft=0x02000000
+_ble_decode_Hypr=0x01000000
+_ble_decode_Supr=0x00800000
+_ble_decode_Altr=0x00400000
+_ble_decode_MaskChar=0x001FFFFF
+_ble_decode_MaskFlag=0x7FC00000
+_ble_decode_Erro=0x40000000
+_ble_decode_Macr=0x20000000
+_ble_decode_Flag3=0x10000000 # unused
+_ble_decode_FlagA=0x00200000 # unused
+_ble_decode_IsolatedESC=$((0x07FF))
+_ble_decode_EscapedNUL=$((0x07FE)) # charlog#encode で用いる
+_ble_decode_FunctionKeyBase=0x110000
+_ble_decode_kbd_ver=gdict
+_ble_decode_kbd__n=0
+_ble_decode_kbd__c2k=()
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_decode_kbd__k2c}"
+ble/is-assoc _ble_decode_kbd__k2c || _ble_decode_kbd_ver=adict
+function ble-decode-kbd/.set-keycode {
+ local keyname=$1
+ local code=$2
+ : "${_ble_decode_kbd__c2k[code]:=$keyname}"
+ ble/gdict#set _ble_decode_kbd__k2c "$keyname" "$code"
+}
+function ble-decode-kbd/.get-keycode {
+ ble/gdict#get _ble_decode_kbd__k2c "$1"
+}
+function ble-decode-kbd/.get-keyname {
+ local keycode=$1
+ ret=${_ble_decode_kbd__c2k[keycode]}
+ if [[ ! $ret ]] && ((keycode<_ble_decode_FunctionKeyBase)); then
+ ble/util/c2s "$keycode"
+ fi
+}
+function ble-decode-kbd/generate-keycode {
+ local keyname=$1
+ if ((${#keyname}==1)); then
+ ble/util/s2c "$1"
+ elif [[ $keyname && ! ${keyname//[a-zA-Z_0-9]} ]]; then
+ ble-decode-kbd/.get-keycode "$keyname"
+ if [[ ! $ret ]]; then
+ ((ret=_ble_decode_FunctionKeyBase+_ble_decode_kbd__n++))
+ ble-decode-kbd/.set-keycode "$keyname" "$ret"
+ fi
+ else
+ ret=-1
+ return 1
+ fi
+}
+function ble-decode-kbd/.initialize {
+ ble-decode-kbd/.set-keycode TAB 9
+ ble-decode-kbd/.set-keycode RET 13
+ ble-decode-kbd/.set-keycode NUL 0
+ ble-decode-kbd/.set-keycode SOH 1
+ ble-decode-kbd/.set-keycode STX 2
+ ble-decode-kbd/.set-keycode ETX 3
+ ble-decode-kbd/.set-keycode EOT 4
+ ble-decode-kbd/.set-keycode ENQ 5
+ ble-decode-kbd/.set-keycode ACK 6
+ ble-decode-kbd/.set-keycode BEL 7
+ ble-decode-kbd/.set-keycode BS 8
+ ble-decode-kbd/.set-keycode HT 9 # aka TAB
+ ble-decode-kbd/.set-keycode LF 10
+ ble-decode-kbd/.set-keycode VT 11
+ ble-decode-kbd/.set-keycode FF 12
+ ble-decode-kbd/.set-keycode CR 13 # aka RET
+ ble-decode-kbd/.set-keycode SO 14
+ ble-decode-kbd/.set-keycode SI 15
+ ble-decode-kbd/.set-keycode DLE 16
+ ble-decode-kbd/.set-keycode DC1 17
+ ble-decode-kbd/.set-keycode DC2 18
+ ble-decode-kbd/.set-keycode DC3 19
+ ble-decode-kbd/.set-keycode DC4 20
+ ble-decode-kbd/.set-keycode NAK 21
+ ble-decode-kbd/.set-keycode SYN 22
+ ble-decode-kbd/.set-keycode ETB 23
+ ble-decode-kbd/.set-keycode CAN 24
+ ble-decode-kbd/.set-keycode EM 25
+ ble-decode-kbd/.set-keycode SUB 26
+ ble-decode-kbd/.set-keycode ESC 27
+ ble-decode-kbd/.set-keycode FS 28
+ ble-decode-kbd/.set-keycode GS 29
+ ble-decode-kbd/.set-keycode RS 30
+ ble-decode-kbd/.set-keycode US 31
+ ble-decode-kbd/.set-keycode SP 32
+ ble-decode-kbd/.set-keycode DEL 127
+ ble-decode-kbd/.set-keycode PAD 128
+ ble-decode-kbd/.set-keycode HOP 129
+ ble-decode-kbd/.set-keycode BPH 130
+ ble-decode-kbd/.set-keycode NBH 131
+ ble-decode-kbd/.set-keycode IND 132
+ ble-decode-kbd/.set-keycode NEL 133
+ ble-decode-kbd/.set-keycode SSA 134
+ ble-decode-kbd/.set-keycode ESA 135
+ ble-decode-kbd/.set-keycode HTS 136
+ ble-decode-kbd/.set-keycode HTJ 137
+ ble-decode-kbd/.set-keycode VTS 138
+ ble-decode-kbd/.set-keycode PLD 139
+ ble-decode-kbd/.set-keycode PLU 140
+ ble-decode-kbd/.set-keycode RI 141
+ ble-decode-kbd/.set-keycode SS2 142
+ ble-decode-kbd/.set-keycode SS3 143
+ ble-decode-kbd/.set-keycode DCS 144
+ ble-decode-kbd/.set-keycode PU1 145
+ ble-decode-kbd/.set-keycode PU2 146
+ ble-decode-kbd/.set-keycode STS 147
+ ble-decode-kbd/.set-keycode CCH 148
+ ble-decode-kbd/.set-keycode MW 149
+ ble-decode-kbd/.set-keycode SPA 150
+ ble-decode-kbd/.set-keycode EPA 151
+ ble-decode-kbd/.set-keycode SOS 152
+ ble-decode-kbd/.set-keycode SGCI 153
+ ble-decode-kbd/.set-keycode SCI 154
+ ble-decode-kbd/.set-keycode CSI 155
+ ble-decode-kbd/.set-keycode ST 156
+ ble-decode-kbd/.set-keycode OSC 157
+ ble-decode-kbd/.set-keycode PM 158
+ ble-decode-kbd/.set-keycode APC 159
+ ble-decode-kbd/.set-keycode @ESC "$_ble_decode_IsolatedESC"
+ ble-decode-kbd/.set-keycode @NUL "$_ble_decode_EscapedNUL"
+ local ret
+ ble-decode-kbd/generate-keycode __batch_char__
+ _ble_decode_KCODE_BATCH_CHAR=$ret
+ ble-decode-kbd/generate-keycode __defchar__
+ _ble_decode_KCODE_DEFCHAR=$ret
+ ble-decode-kbd/generate-keycode __default__
+ _ble_decode_KCODE_DEFAULT=$ret
+ ble-decode-kbd/generate-keycode __before_widget__
+ _ble_decode_KCODE_BEFORE_WIDGET=$ret
+ ble-decode-kbd/generate-keycode __after_widget__
+ _ble_decode_KCODE_AFTER_WIDGET=$ret
+ ble-decode-kbd/generate-keycode __attach__
+ _ble_decode_KCODE_ATTACH=$ret
+ ble-decode-kbd/generate-keycode __detach__
+ _ble_decode_KCODE_DETACH=$ret
+ ble-decode-kbd/generate-keycode shift
+ _ble_decode_KCODE_SHIFT=$ret
+ ble-decode-kbd/generate-keycode alter
+ _ble_decode_KCODE_ALTER=$ret
+ ble-decode-kbd/generate-keycode control
+ _ble_decode_KCODE_CONTROL=$ret
+ ble-decode-kbd/generate-keycode meta
+ _ble_decode_KCODE_META=$ret
+ ble-decode-kbd/generate-keycode super
+ _ble_decode_KCODE_SUPER=$ret
+ ble-decode-kbd/generate-keycode hyper
+ _ble_decode_KCODE_HYPER=$ret
+ ble-decode-kbd/generate-keycode __ignore__
+ _ble_decode_KCODE_IGNORE=$ret
+ ble-decode-kbd/generate-keycode __error__
+ _ble_decode_KCODE_ERROR=$ret
+ ble-decode-kbd/generate-keycode __line_limit__
+ _ble_decode_KCODE_LINE_LIMIT=$ret
+ ble-decode-kbd/generate-keycode mouse
+ _ble_decode_KCODE_MOUSE=$ret
+ ble-decode-kbd/generate-keycode mouse_move
+ _ble_decode_KCODE_MOUSE_MOVE=$ret
+ ble-decode-kbd/generate-keycode auto_complete_enter
+}
+ble-decode-kbd/.initialize
+function ble-decode-kbd {
+ local IFS=$_ble_term_IFS
+ local spec="$*"
+ case $spec in
+ (keys:*)
+ ret="${spec#*:}"
+ return ;;
+ (chars:*)
+ local chars
+ ble/string#split-words chars "${spec#*:}"
+ ble/decode/cmap/decode-chars "${ret[@]}"
+ ret="${keys[*]}"
+ return ;;
+ (keyseq:*) # i.e. untranslated keyseq
+ local keys
+ ble/util/keyseq2chars "${spec#*:}"
+ ble/decode/cmap/decode-chars "${ret[@]}"
+ ret="${keys[*]}"
+ return ;;
+ (raw:*) # i.e. translated keyseq
+ ble/util/s2chars "${spec#*:}"
+ ble/decode/cmap/decode-chars "${ret[@]}"
+ ret="${keys[*]}"
+ return ;;
+ (kspecs:*)
+ spec=${spec#*:} ;;
+ esac
+ local kspecs; ble/string#split-words kspecs "$spec"
+ local kspec code codes
+ codes=()
+ for kspec in "${kspecs[@]}"; do
+ code=0
+ while [[ $kspec == ?-* ]]; do
+ case "${kspec::1}" in
+ (S) ((code|=_ble_decode_Shft)) ;;
+ (C) ((code|=_ble_decode_Ctrl)) ;;
+ (M) ((code|=_ble_decode_Meta)) ;;
+ (A) ((code|=_ble_decode_Altr)) ;;
+ (s) ((code|=_ble_decode_Supr)) ;;
+ (H) ((code|=_ble_decode_Hypr)) ;;
+ (*) ((code|=_ble_decode_Erro)) ;;
+ esac
+ kspec=${kspec:2}
+ done
+ if [[ $kspec == ? ]]; then
+ ble/util/s2c "$kspec"
+ ((code|=ret))
+ elif [[ $kspec && ! ${kspec//[@_0-9a-zA-Z]} ]]; then
+ ble-decode-kbd/.get-keycode "$kspec"
+ [[ $ret ]] || ble-decode-kbd/generate-keycode "$kspec"
+ ((code|=ret))
+ elif [[ $kspec == ^? ]]; then
+ if [[ $kspec == '^?' ]]; then
+ ((code|=0x7F))
+ elif [[ $kspec == '^`' ]]; then
+ ((code|=0x20))
+ else
+ ble/util/s2c "${kspec:1}"
+ ((code|=ret&0x1F))
+ fi
+ elif local rex='^U\+([0-9a-fA-F]+)$'; [[ $kspec =~ $rex ]]; then
+ ((code|=0x${BASH_REMATCH[1]}))
+ else
+ ((code|=_ble_decode_Erro))
+ fi
+ codes[${#codes[@]}]=$code
+ done
+ ret="${codes[*]}"
+}
+function ble-decode-unkbd/.single-key {
+ local key=$1
+ local f_unknown=
+ local char=$((key&_ble_decode_MaskChar))
+ ble-decode-kbd/.get-keyname "$char"
+ if [[ ! $ret ]]; then
+ f_unknown=1
+ ret=__UNKNOWN__
+ fi
+ ((key&_ble_decode_Shft)) && ret=S-$ret
+ ((key&_ble_decode_Meta)) && ret=M-$ret
+ ((key&_ble_decode_Ctrl)) && ret=C-$ret
+ ((key&_ble_decode_Altr)) && ret=A-$ret
+ ((key&_ble_decode_Supr)) && ret=s-$ret
+ ((key&_ble_decode_Hypr)) && ret=H-$ret
+ [[ ! $f_unknown ]]
+}
+function ble-decode-unkbd {
+ local IFS=$_ble_term_IFS
+ local -a kspecs
+ local key
+ for key in $*; do
+ ble-decode-unkbd/.single-key "$key"
+ kspecs[${#kspecs[@]}]=$ret
+ done
+ ret="${kspecs[*]}"
+}
+function ble-decode/PROLOGUE { :; }
+function ble-decode/EPILOGUE { :; }
+_ble_decode_input_buffer=()
+_ble_decode_input_count=0
+_ble_decode_input_original_info=()
+_ble_decode_show_progress_hook=ble-decode/.hook/show-progress
+_ble_decode_erase_progress_hook=ble-decode/.hook/erase-progress
+function ble-decode/.hook/show-progress {
+ if [[ $_ble_edit_info_scene == store ]]; then
+ _ble_decode_input_original_info=("${_ble_edit_info[@]}")
+ return 0
+ elif [[ $_ble_edit_info_scene == default ]]; then
+ _ble_decode_input_original_info=()
+ elif [[ $_ble_edit_info_scene != decode_input_progress ]]; then
+ return 0
+ fi
+ local progress_opts= opt_percentage=1
+ if [[ $ble_batch_insert_count ]]; then
+ local total=$ble_batch_insert_count
+ local value=$ble_batch_insert_index
+ local label='constructing text...'
+ local sgr=$'\e[1;38;5;204;48;5;253m'
+ elif ((${#_ble_decode_input_buffer[@]})); then
+ local total=10000
+ local value=$((${#_ble_decode_input_buffer[@]}%10000))
+ local label="${#_ble_decode_input_buffer[@]} bytes received..."
+ local sgr=$'\e[1;38;5;135;48;5;253m'
+ progress_opts=unlimited
+ opt_percentage=
+ elif ((_ble_decode_input_count)); then
+ local total=${#chars[@]}
+ local value=$((total-_ble_decode_input_count-1))
+ local label='decoding input...'
+ local sgr=$'\e[1;38;5;69;48;5;253m'
+ elif ((ble_decode_char_total)); then
+ local total=$ble_decode_char_total
+ local value=$((total-ble_decode_char_rest-1))
+ local label='processing input...'
+ local sgr=$'\e[1;38;5;71;48;5;253m'
+ else
+ return 0
+ fi
+ if [[ $opt_percentage ]]; then
+ local mill=$((value*1000/total))
+ local cent=${mill::${#mill}-1} frac=${mill:${#mill}-1}
+ label="${cent:-0}.$frac% $label"
+ fi
+ local text="($label)"
+ if ble/util/is-unicode-output; then
+ local ret
+ ble/string#create-unicode-progress-bar "$value" "$total" 10 "$progress_opts"
+ text=$sgr$ret$'\e[m '$text
+ fi
+ ble/edit/info/show ansi "$text"
+ _ble_edit_info_scene=decode_input_progress
+}
+function ble-decode/.hook/erase-progress {
+ [[ $_ble_edit_info_scene == decode_input_progress ]] || return 1
+ if ((${#_ble_decode_input_original_info[@]})); then
+ ble/edit/info/show store "${_ble_decode_input_original_info[@]}"
+ else
+ ble/edit/info/default
+ fi
+}
+function ble-decode/.check-abort {
+ if (($1==bleopt_decode_abort_char)); then
+ local nbytes=${#_ble_decode_input_buffer[@]}
+ local nchars=${#_ble_decode_char_buffer[@]}
+ ((nbytes||nchars)); return "$?"
+ fi
+ (($1==0x7e||$1==0x75)) || return 1
+ local i=$((${#_ble_decode_input_buffer[@]}-1))
+ local n
+ ((n=bleopt_decode_abort_char,
+ n+=(1<=n&&n<=26?96:64)))
+ if (($1==0x7e)); then
+ for ((;n;n/=10)); do
+ ((i>=0)) && ((_ble_decode_input_buffer[i--]==n%10+48)) || return 1
+ done
+ ((i>=4)) || return 1
+ ((_ble_decode_input_buffer[i--]==59)) || return 1
+ ((_ble_decode_input_buffer[i--]==53)) || return 1
+ ((_ble_decode_input_buffer[i--]==59)) || return 1
+ ((_ble_decode_input_buffer[i--]==55)) || return 1
+ ((_ble_decode_input_buffer[i--]==50)) || return 1
+ elif (($1==0x75)); then
+ ((i>=1)) || return 1
+ ((_ble_decode_input_buffer[i--]==53)) || return 1
+ ((_ble_decode_input_buffer[i--]==59)) || return 1
+ for ((;n;n/=10)); do
+ ((i>=0)) && ((_ble_decode_input_buffer[i--]==n%10+48)) || return 1
+ done
+ fi
+ ((i>=0)) && ((_ble_decode_input_buffer[i]==62&&i--))
+ ((i>=0)) || return 1
+ if ((_ble_decode_input_buffer[i]==0x5B)); then
+ if ((i>=1&&_ble_decode_input_buffer[i-1]==0x1B)); then
+ ((i-=2))
+ elif ((i>=2&&_ble_decode_input_buffer[i-1]==0x9B&&_ble_decode_input_buffer[i-2]==0xC0)); then
+ ((i-=3))
+ else
+ return 1
+ fi
+ elif ((_ble_decode_input_buffer[i]==0x9B)); then
+ ((--i>=0)) && ((_ble_decode_input_buffer[i--]==0xC2)) || return 1
+ else
+ return 1
+ fi
+ (((i>=0||${#_ble_decode_char_buffer[@]}))); return "$?"
+ return 0
+}
+if ((_ble_bash>=40400)); then
+ function ble/decode/nonblocking-read {
+ local timeout=${1:-0.01} ntimeout=${2:-1} loop=${3:-100}
+ local LC_ALL= LC_CTYPE=C IFS=
+ local -a data=()
+ local line buff ext
+ while ((loop--)); do
+ builtin read -t "$timeout" -r -d '' buff; ext=$?
+ [[ $buff ]] && line=$line$buff
+ if ((ext==0)); then
+ ble/array#push data "$line"
+ line=
+ elif ((ext>128)); then
+ ((--ntimeout)) || break
+ [[ $buff ]] || break
+ else
+ break
+ fi
+ done
+ ble/util/assign ret '{
+ ((${#data[@]})) && printf %s\\0 "${data[@]}"
+ [[ $line ]] && printf %s "$line"
+ } | ble/bin/od -A n -t u1 -v'
+ ble/string#split-words ret "$ret"
+ }
+ ble/function#suppress-stderr ble/decode/nonblocking-read
+elif ((_ble_bash>=40000)); then
+ function ble/decode/nonblocking-read {
+ local timeout=${1:-0.01} ntimeout=${2:-1} loop=${3:-100}
+ local LC_ALL= LC_CTYPE=C TMOUT= IFS= 2>/dev/null # #D1630 WA readonly TMOUT
+ local -a data=()
+ local line buff
+ while ((loop--)); do
+ builtin read -t 0 || break
+ builtin read "${_ble_bash_tmout_wa[@]}" -r -d '' -n 1 buff || break
+ if [[ $buff ]]; then
+ line=$line$buff
+ else
+ ble/array#push data "$line"
+ line=
+ fi
+ done
+ ble/util/assign ret '{
+ ((${#data[@]})) && printf %s\\0 "${data[@]}"
+ [[ $line ]] && printf %s "$line"
+ } | ble/bin/od -A n -t u1 -v'
+ ble/string#split-words ret "$ret"
+ }
+ ble/function#suppress-stderr ble/decode/nonblocking-read
+fi
+_ble_decode_hook_Processing=
+function ble-decode/.hook {
+ if ble/util/is-stdin-ready; then
+ ble/array#push _ble_decode_input_buffer "$@"
+ local buflen=${#_ble_decode_input_buffer[@]}
+ if ((buflen%257==0&&buflen>=2000)); then
+ local IFS=$_ble_term_IFS
+ ble-decode/PROLOGUE
+ local char=${_ble_decode_input_buffer[buflen-1]}
+ if ((_ble_bash<40000||char==0xC0||char==0xDF)); then
+ builtin eval -- "$_ble_decode_show_progress_hook"
+ else
+ while ble/util/is-stdin-ready; do
+ builtin eval -- "$_ble_decode_show_progress_hook"
+ local ret; ble/decode/nonblocking-read 0.02 1 527
+ ble/array#push _ble_decode_input_buffer "${ret[@]}"
+ done
+ fi
+ ble-decode/EPILOGUE
+ ble/array#pop _ble_decode_input_buffer
+ ble-decode/.hook "$ret"
+ fi
+ return 0
+ fi
+ [[ $_ble_bash_options_adjusted ]] && set +v || :
+ local IFS=$_ble_term_IFS
+ local _ble_decode_hook_Processing=prologue
+ ble-decode/PROLOGUE
+ _ble_decode_hook_Processing=body
+ if ble-decode/.check-abort "$1"; then
+ _ble_decode_char__hook=
+ _ble_decode_input_buffer=()
+ _ble_decode_char_buffer=()
+ ble/term/visible-bell "Abort by 'bleopt decode_abort_char=$bleopt_decode_abort_char'"
+ shift
+ fi
+ local chars
+ ble/array#set chars "${_ble_decode_input_buffer[@]}" "$@"
+ _ble_decode_input_buffer=()
+ _ble_decode_input_count=${#chars[@]}
+ if ((_ble_decode_input_count>=200)); then
+ local decode=ble/encoding:$bleopt_input_encoding/decode
+ local i N=${#chars[@]}
+ local B=$((N/100))
+ ((B<100)) && B=100 || ((B>1000)) && B=1000
+ for ((i=0;i<N;i+=B)); do
+ ((_ble_decode_input_count=N-i-B))
+ ((_ble_decode_input_count<0)) && _ble_decode_input_count=0
+ builtin eval -- "$_ble_decode_show_progress_hook"
+ ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_bytes "${chars[@]:i:B}"
+ "$decode" "${chars[@]:i:B}"
+ done
+ else
+ local c
+ for c in "${chars[@]}"; do
+ ((--_ble_decode_input_count))
+ ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_bytes "$c"
+ "ble/encoding:$bleopt_input_encoding/decode" "$c"
+ done
+ fi
+ ble/decode/has-input || ble-decode-key/batch/flush
+ builtin eval -- "$_ble_decode_erase_progress_hook"
+ _ble_decode_hook_Processing=epilogue
+ ble-decode/EPILOGUE
+}
+function ble-decode-byte {
+ while (($#)); do
+ "ble/encoding:$bleopt_input_encoding/decode" "$1"
+ shift
+ done
+}
+_ble_decode_csi_mode=0
+_ble_decode_csi_args=
+_ble_decode_csimap_tilde=()
+_ble_decode_csimap_alpha=()
+function ble-decode-char/csi/print/.print-csidef {
+ local qalpha qkey ret q=\' Q="'\''"
+ if [[ $sgrq ]]; then
+ ble/string#quote-word "$1" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qalpha=$ret
+ ble/string#quote-word "$2" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qkey=$ret
+ else
+ qalpha="'${1//$q/$Q}'"
+ qkey="'${2//$q/$Q}'"
+ fi
+ ble/util/print "${sgrf}ble-bind$sgr0 $sgro--csi$sgr0 $qalpha $qkey"
+}
+function ble-decode-char/csi/print {
+ [[ $ble_bind_print ]] || local sgr0= sgrf= sgrq= sgrc= sgro=
+ local num ret
+ for num in "${!_ble_decode_csimap_tilde[@]}"; do
+ ble-decode-unkbd "${_ble_decode_csimap_tilde[num]}"
+ ble-decode-char/csi/print/.print-csidef "$num~" "$ret"
+ done
+ for num in "${!_ble_decode_csimap_alpha[@]}"; do
+ local s; ble/util/c2s "$num"; s=$ret
+ ble-decode-unkbd "${_ble_decode_csimap_alpha[num]}"
+ ble-decode-char/csi/print/.print-csidef "$s" "$ret"
+ done
+}
+function ble-decode-char/csi/clear {
+ _ble_decode_csi_mode=0
+}
+_ble_decode_csimap_kitty_u=()
+function ble-decode/char/csi/.translate-kitty-csi-u {
+ local name=${_ble_decode_csimap_kitty_u[key]}
+ if [[ $name ]]; then
+ local ret
+ ble-decode-kbd/generate-keycode "$name"
+ key=$ret
+ fi
+}
+function ble-decode-char/csi/.modify-key {
+ local mod=$(($1-1))
+ if ((mod>=0)); then
+ if ((33<=key&&key<_ble_decode_FunctionKeyBase)); then
+ if (((mod&0x01)&&0x31<=key&&key<=0x39)) && [[ $_ble_term_TERM == RLogin:* ]]; then
+ ((key-=16,mod&=~0x01))
+ elif ((mod==0x01)); then
+ mod=0
+ elif ((65<=key&&key<=90)); then
+ ((key|=0x20))
+ fi
+ fi
+ ((mod&0x01&&(key|=_ble_decode_Shft),
+ mod&0x02&&(key|=_ble_decode_Meta),
+ mod&0x04&&(key|=_ble_decode_Ctrl),
+ mod&0x08&&(key|=_ble_decode_Supr),
+ mod&0x10&&(key|=_ble_decode_Hypr),
+ mod&0x20&&(key|=_ble_decode_Altr)))
+ fi
+}
+function ble-decode-char/csi/.decode {
+ local char=$1 rex key
+ if ((char==126)); then # ~
+ if rex='^>?27;([0-9]+);?([0-9]+)$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local param1=$((10#0${BASH_REMATCH[1]}))
+ local param2=$((10#0${BASH_REMATCH[2]}))
+ local key=$((param2&_ble_decode_MaskChar))
+ ble-decode-char/csi/.modify-key "$param1"
+ csistat=$key
+ return 0
+ fi
+ if rex='^>?([0-9]+)(;([0-9]+))?$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local param1=$((10#0${BASH_REMATCH[1]}))
+ local param3=$((10#0${BASH_REMATCH[3]}))
+ key=${_ble_decode_csimap_tilde[param1]}
+ if [[ $key ]]; then
+ ble-decode-char/csi/.modify-key "$param3"
+ csistat=$key
+ return 0
+ fi
+ fi
+ elif ((char==117)); then # u
+ if rex='^([0-9]*)(;[0-9]*)?$'; [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ if [[ $rematch1 != 1 ]]; then
+ local key=$((10#0$rematch1)) mods=$((10#0${BASH_REMATCH:${#rematch1}+1}))
+ [[ $_ble_term_TERM == kitty:* ]] && ble-decode/char/csi/.translate-kitty-csi-u
+ ble-decode-char/csi/.modify-key "$mods"
+ csistat=$key
+ fi
+ return 0
+ fi
+ elif ((char==94||char==64)); then # ^, @
+ if rex='^[0-9]+$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local param1=$((10#0${BASH_REMATCH[1]}))
+ local param3=$((10#0${BASH_REMATCH[3]}))
+ key=${_ble_decode_csimap_tilde[param1]}
+ if [[ $key ]]; then
+ ((key|=_ble_decode_Ctrl,
+ char==64&&(key|=_ble_decode_Shft)))
+ ble-decode-char/csi/.modify-key "$param3"
+ csistat=$key
+ return 0
+ fi
+ fi
+ elif ((char==99)); then # c
+ if rex='^[?>]'; [[ $_ble_decode_csi_args =~ $rex ]]; then
+ if [[ $_ble_decode_csi_args == '?'* ]]; then
+ ble/term/DA1/notify "${_ble_decode_csi_args:1}"
+ else
+ ble/term/DA2/notify "${_ble_decode_csi_args:1}"
+ fi
+ csistat=$_ble_decode_KCODE_IGNORE
+ return 0
+ fi
+ elif ((char==82||char==110)); then # R or n
+ if rex='^([0-9]+);([0-9]+)$'; [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local param1=$((10#0${BASH_REMATCH[1]}))
+ local param2=$((10#0${BASH_REMATCH[2]}))
+ ble/term/CPR/notify "$param1" "$param2"
+ csistat=$_ble_decode_KCODE_IGNORE
+ return 0
+ fi
+ elif ((char==77||char==109)); then # M or m
+ if rex='^<([0-9]+);([0-9]+);([0-9]+)$'; [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local param1=$((10#0${BASH_REMATCH[1]}))
+ local param2=$((10#0${BASH_REMATCH[2]}))
+ local param3=$((10#0${BASH_REMATCH[3]}))
+ local button=$param1
+ ((_ble_term_mouse_button=button&~0x1C,
+ char==109&&(_ble_term_mouse_button|=0x70),
+ _ble_term_mouse_x=param2-1,
+ _ble_term_mouse_y=param3-1))
+ local key=$_ble_decode_KCODE_MOUSE
+ ((button&32)) && key=$_ble_decode_KCODE_MOUSE_MOVE
+ ble-decode-char/csi/.modify-key $((button>>2&0x07))
+ csistat=$key
+ return 0
+ fi
+ elif ((char==116)); then # t
+ if rex='^<([0-9]+);([0-9]+)$'; [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local param1=$((10#0${BASH_REMATCH[1]}))
+ local param2=$((10#0${BASH_REMATCH[2]}))
+ ((_ble_term_mouse_button=128,
+ _ble_term_mouse_x=param1-1,
+ _ble_term_mouse_y=param2-1))
+ local key=$_ble_decode_KCODE_MOUSE
+ csistat=$key
+ fi
+ fi
+ key=${_ble_decode_csimap_alpha[char]}
+ if [[ $key ]]; then
+ if rex='^(1?|>?1;([0-9]+))$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
+ local param2=$((10#0${BASH_REMATCH[2]}))
+ ble-decode-char/csi/.modify-key "$param2"
+ csistat=$key
+ return 0
+ fi
+ fi
+ csistat=$_ble_decode_KCODE_ERROR
+}
+function ble-decode-char/csi/consume {
+ csistat=
+ ((_ble_decode_csi_mode==0&&$1!=27&&$1!=155)) && return 1
+ local char=$1
+ case "$_ble_decode_csi_mode" in
+ (0)
+ ((_ble_decode_csi_mode=$1==155?2:1))
+ _ble_decode_csi_args=
+ csistat=_ ;;
+ (1)
+ if ((char!=91)); then
+ _ble_decode_csi_mode=0
+ return 1
+ else
+ _ble_decode_csi_mode=2
+ _ble_decode_csi_args=
+ csistat=_
+ fi ;;
+ (2)
+ if ((32<=char&&char<64)); then
+ local ret; ble/util/c2s "$char"
+ _ble_decode_csi_args=$_ble_decode_csi_args$ret
+ csistat=_
+ elif ((64<=char&&char<127)); then
+ _ble_decode_csi_mode=0
+ ble-decode-char/csi/.decode "$char"
+ ((csistat==27)) && csistat=$_ble_decode_IsolatedESC
+ else
+ _ble_decode_csi_mode=0
+ fi ;;
+ esac
+}
+_ble_decode_char_buffer=()
+function ble/decode/has-input-for-char {
+ ((_ble_decode_input_count)) ||
+ ble/util/is-stdin-ready ||
+ ble/encoding:"$bleopt_input_encoding"/is-intermediate
+}
+_ble_decode_char__hook=
+_ble_decode_cmap_=()
+_ble_decode_char2_seq=
+_ble_decode_char2_reach_key=
+_ble_decode_char2_reach_seq=
+_ble_decode_char2_modifier=
+_ble_decode_char2_modkcode=
+_ble_decode_char2_modseq=
+function ble-decode-char {
+ if [[ $ble_decode_char_nest && ! $ble_decode_char_sync ]]; then
+ ble/array#push _ble_decode_char_buffer "$@"
+ return 148
+ fi
+ local ble_decode_char_nest=1
+ local iloop=0
+ local ble_decode_char_total=$#
+ local ble_decode_char_rest=$#
+ local ble_decode_char_char=
+ local chars ichar char ent
+ chars=("$@") ichar=0
+ while
+ if ((iloop++%50==0)); then
+ ((iloop>=200)) && builtin eval -- "$_ble_decode_show_progress_hook"
+ if [[ ! $ble_decode_char_sync ]] && ble/decode/has-input-for-char; then
+ ble/array#push _ble_decode_char_buffer "${chars[@]:ichar}"
+ return 148
+ fi
+ fi
+ if ((${#_ble_decode_char_buffer[@]})); then
+ ((ble_decode_char_total+=${#_ble_decode_char_buffer[@]}))
+ ((ble_decode_char_rest+=${#_ble_decode_char_buffer[@]}))
+ ble/array#set chars "${_ble_decode_char_buffer[@]}" "${chars[@]:ichar}"
+ ichar=0
+ _ble_decode_char_buffer=()
+ fi
+ ((ble_decode_char_rest))
+ do
+ char=${chars[ichar]}
+ ble_decode_char_char=$char # 補正前 char (_ble_decode_Macr 判定の為)
+ ((ble_decode_char_rest--,ichar++))
+ ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_chars "$char"
+ if [[ $_ble_decode_keylog_chars_enabled ]]; then
+ if ! ((char&_ble_decode_Macr)); then
+ ble/array#push _ble_decode_keylog_chars "$char"
+ ((_ble_decode_keylog_chars_count++))
+ fi
+ fi
+ ((char&=~_ble_decode_Macr))
+ if ((char&_ble_decode_Erro)); then
+ ((char&=~_ble_decode_Erro))
+ if [[ $bleopt_decode_error_char_vbell ]]; then
+ local name; ble/util/sprintf name 'U+%04x' "$char"
+ ble/term/visible-bell "received a misencoded char $name"
+ fi
+ [[ $bleopt_decode_error_char_abell ]] && ble/term/audible-bell
+ [[ $bleopt_decode_error_char_discard ]] && continue
+ fi
+ if [[ $_ble_decode_char__hook ]]; then
+ ((char==_ble_decode_IsolatedESC)) && char=27 # isolated ESC -> ESC
+ local hook=$_ble_decode_char__hook
+ _ble_decode_char__hook=
+ ble-decode/widget/.call-async-read "$hook $char" "$char"
+ continue
+ fi
+ ble-decode-char/.getent # -> ent
+ if [[ ! $ent ]]; then
+ if [[ $_ble_decode_char2_reach_key ]]; then
+ local key=$_ble_decode_char2_reach_key
+ local seq=$_ble_decode_char2_reach_seq
+ local rest=${_ble_decode_char2_seq:${#seq}}
+ ble/string#split-words rest "${rest//_/ } $ble_decode_char_char"
+ _ble_decode_char2_seq=
+ _ble_decode_char2_reach_key=
+ _ble_decode_char2_reach_seq=
+ ble-decode-char/csi/clear
+ ble-decode-char/.send-modified-key "$key" "$seq"
+ ((ble_decode_char_total+=${#rest[@]}))
+ ((ble_decode_char_rest+=${#rest[@]}))
+ chars=("${rest[@]}" "${chars[@]:ichar}") ichar=0
+ else
+ ble-decode-char/.send-modified-key "$char" "_$char"
+ fi
+ elif [[ $ent == *_ ]]; then
+ _ble_decode_char2_seq=${_ble_decode_char2_seq}_$char
+ if [[ ${ent%_} ]]; then
+ _ble_decode_char2_reach_key=${ent%_}
+ _ble_decode_char2_reach_seq=$_ble_decode_char2_seq
+ elif [[ ! $_ble_decode_char2_reach_key ]]; then
+ _ble_decode_char2_reach_key=$char
+ _ble_decode_char2_reach_seq=$_ble_decode_char2_seq
+ fi
+ else
+ local seq=${_ble_decode_char2_seq}_$char
+ _ble_decode_char2_seq=
+ _ble_decode_char2_reach_key=
+ _ble_decode_char2_reach_seq=
+ ble-decode-char/csi/clear
+ ble-decode-char/.send-modified-key "$ent" "$seq"
+ fi
+ done
+ return 0
+}
+function ble/decode/char-hook/next-char {
+ ((ble_decode_char_rest)) || return 1
+ ((char=chars[ichar]&~_ble_decode_Macr))
+ ((char&_ble_decode_Erro)) && return 1
+ ((iloop%1000==0)) && return 1
+ ((char==_ble_decode_IsolatedESC)) && char=27
+ ((ble_decode_char_rest--,ichar++,iloop++))
+ return 0
+}
+function ble-decode-char/.getent {
+ builtin eval "ent=\${_ble_decode_cmap_$_ble_decode_char2_seq[char]-}"
+ local csistat=
+ ble-decode-char/csi/consume "$char"
+ if [[ $csistat && ! ${ent%_} ]]; then
+ if ((csistat==_ble_decode_KCODE_ERROR)); then
+ if [[ $bleopt_decode_error_cseq_vbell ]]; then
+ local ret; ble-decode-unkbd ${_ble_decode_char2_seq//_/ } $char
+ ble/term/visible-bell "unrecognized CSI sequence: $ret"
+ fi
+ [[ $bleopt_decode_error_cseq_abell ]] && ble/term/audible-bell
+ if [[ $bleopt_decode_error_cseq_discard ]]; then
+ csistat=$_ble_decode_KCODE_IGNORE
+ else
+ csistat=
+ fi
+ fi
+ if [[ ! $ent ]]; then
+ ent=$csistat
+ else
+ ent=${csistat%_}_
+ fi
+ fi
+}
+function ble-decode-char/.process-modifier {
+ local mflag1=$1 mflag=$_ble_decode_char2_modifier
+ if ((mflag1&mflag)); then
+ return 1
+ else
+ ((_ble_decode_char2_modkcode=key|mflag,
+ _ble_decode_char2_modifier=mflag1|mflag))
+ _ble_decode_char2_modseq=${_ble_decode_char2_modseq}$2
+ return 0
+ fi
+}
+function ble-decode-char/.send-modified-key {
+ local key=$1 seq=$2
+ ((key==_ble_decode_KCODE_IGNORE)) && return 0
+ if ((0<=key&&key<32)); then
+ ((key|=(key==0||key>26?64:96)|_ble_decode_Ctrl))
+ elif ((key==127)); then # C-?
+ ((key=63|_ble_decode_Ctrl))
+ fi
+ if (($1==27)); then
+ ble-decode-char/.process-modifier "$_ble_decode_Meta" "$seq" && return 0
+ elif (($1==_ble_decode_IsolatedESC)); then
+ ((key=(_ble_decode_Ctrl|91)))
+ if ! ble/decode/uses-isolated-esc; then
+ ble-decode-char/.process-modifier "$_ble_decode_Meta" "$seq" && return 0
+ fi
+ elif ((_ble_decode_KCODE_SHIFT<=$1&&$1<=_ble_decode_KCODE_HYPER)); then
+ case "$1" in
+ ($_ble_decode_KCODE_SHIFT)
+ ble-decode-char/.process-modifier "$_ble_decode_Shft" "$seq" && return 0 ;;
+ ($_ble_decode_KCODE_CONTROL)
+ ble-decode-char/.process-modifier "$_ble_decode_Ctrl" "$seq" && return 0 ;;
+ ($_ble_decode_KCODE_ALTER)
+ ble-decode-char/.process-modifier "$_ble_decode_Altr" "$seq" && return 0 ;;
+ ($_ble_decode_KCODE_META)
+ ble-decode-char/.process-modifier "$_ble_decode_Meta" "$seq" && return 0 ;;
+ ($_ble_decode_KCODE_SUPER)
+ ble-decode-char/.process-modifier "$_ble_decode_Supr" "$seq" && return 0 ;;
+ ($_ble_decode_KCODE_HYPER)
+ ble-decode-char/.process-modifier "$_ble_decode_Hypr" "$seq" && return 0 ;;
+ esac
+ fi
+ if [[ $_ble_decode_char2_modifier ]]; then
+ local mflag=$_ble_decode_char2_modifier
+ local mcode=$_ble_decode_char2_modkcode
+ local mseq=$_ble_decode_char2_modseq
+ _ble_decode_char2_modifier=
+ _ble_decode_char2_modkcode=
+ _ble_decode_char2_modseq=
+ if ((key&mflag)); then
+ local CHARS
+ ble/string#split-words CHARS "${mseq//_/ }"
+ ble-decode-key "$mcode"
+ else
+ seq=$mseq$seq
+ ((key|=mflag))
+ fi
+ fi
+ local CHARS
+ ble/string#split-words CHARS "${seq//_/ }"
+ ble-decode-key "$key"
+}
+function ble-decode-char/is-intermediate { [[ $_ble_decode_char2_seq ]]; }
+function ble-decode-char/bind {
+ local -a seq; ble/string#split-words seq "$1"
+ local kc=$2
+ local i iN=${#seq[@]} char tseq=
+ for ((i=0;i<iN;i++)); do
+ local char=${seq[i]}
+ builtin eval "local okc=\${_ble_decode_cmap_$tseq[char]-}"
+ if ((i+1==iN)); then
+ if [[ ${okc//[0-9]} == _ ]]; then
+ builtin eval "_ble_decode_cmap_$tseq[char]=\${kc}_"
+ else
+ builtin eval "_ble_decode_cmap_$tseq[char]=\${kc}"
+ fi
+ else
+ if [[ ! $okc ]]; then
+ builtin eval "_ble_decode_cmap_$tseq[char]=_"
+ else
+ builtin eval "_ble_decode_cmap_$tseq[char]=\${okc%_}_"
+ fi
+ tseq=${tseq}_$char
+ fi
+ done
+}
+function ble-decode-char/unbind {
+ local -a seq; ble/string#split-words seq "$1"
+ local tseq=
+ local i iN=${#seq}
+ for ((i=0;i<iN-1;i++)); do
+ tseq=${tseq}_${seq[i]}
+ done
+ local char=${seq[iN-1]}
+ local isfirst=1 ent=
+ while
+ builtin eval "ent=\${_ble_decode_cmap_$tseq[char]-}"
+ if [[ $isfirst ]]; then
+ isfirst=
+ if [[ $ent == *_ ]]; then
+ builtin eval "_ble_decode_cmap_$tseq[char]=_"
+ break
+ fi
+ else
+ if [[ $ent != _ ]]; then
+ builtin eval "_ble_decode_cmap_$tseq[char]=${ent%_}"
+ break
+ fi
+ fi
+ builtin unset -v "_ble_decode_cmap_$tseq[char]"
+ builtin eval "((\${#_ble_decode_cmap_$tseq[@]}!=0))" && break
+ [[ $tseq ]]
+ do
+ char=${tseq##*_}
+ tseq=${tseq%_*}
+ done
+}
+function ble-decode-char/print {
+ [[ $ble_bind_print ]] || local sgr0= sgrf= sgrq= sgrc= sgro=
+ local IFS=$_ble_term_IFS q=\' Q="'\''"
+ local tseq=$1 nseq ccode
+ nseq=("${@:2}")
+ builtin eval "local -a ccodes; ccodes=(\${!_ble_decode_cmap_$tseq[@]})"
+ for ccode in "${ccodes[@]}"; do
+ local ret; ble-decode-unkbd "$ccode"
+ local cnames
+ cnames=("${nseq[@]}" "$ret")
+ builtin eval "local ent=\${_ble_decode_cmap_$tseq[ccode]}"
+ if [[ ${ent%_} ]]; then
+ local key=${ent%_} ret
+ local qkspec qcnames
+ if [[ $sgrq ]]; then
+ ble-decode-unkbd "$key"
+ ble/string#quote-word "$ret" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qkspec=$ret
+ ble/string#quote-word "${cnames[*]}" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qcnames=$ret
+ else
+ ble-decode-unkbd "$key"
+ qkspec="'${ret//$q/$Q}'"
+ qcnames="'${cnames[*]//$q/$Q}'" # WA #D1570 checked
+ fi
+ ble/util/print "${sgrf}ble-bind$sgr0 $sgro-k$sgr0 $qcnames $qkspec"
+ fi
+ if [[ ${ent//[0-9]} == _ ]]; then
+ ble-decode-char/print "${tseq}_$ccode" "${cnames[@]}"
+ fi
+ done
+}
+_ble_decode_keymap_list=
+function ble/decode/keymap#registered {
+ [[ :$_ble_decode_keymap_list: == *:"$1":* ]]
+}
+function ble/decode/keymap#.register {
+ local kmap=$1
+ if [[ $kmap && :$_ble_decode_keymap_list: != *:"$kmap":* ]]; then
+ _ble_decode_keymap_list=$_ble_decode_keymap_list:$kmap
+ fi
+}
+function ble/decode/keymap#.unregister {
+ _ble_decode_keymap_list=$_ble_decode_keymap_list:
+ _ble_decode_keymap_list=${_ble_decode_keymap_list//:"$1":/:}
+ _ble_decode_keymap_list=${_ble_decode_keymap_list%:}
+}
+function ble/decode/is-keymap {
+ ble/decode/keymap#registered "$1" || ble/is-function "ble-decode/keymap:$1/define"
+}
+function ble/decode/keymap#is-empty {
+ ! ble/is-array "_ble_decode_${1}_kmap_" ||
+ builtin eval -- "((\${#_ble_decode_${1}_kmap_[*]}==0))"
+}
+function ble/decode/keymap#.onload {
+ local kmap=$1
+ local delay=$_ble_base_run/$$.bind.delay.$kmap
+ if [[ -s $delay ]]; then
+ source "$delay"
+ : >| "$delay"
+ fi
+}
+function ble/decode/keymap#load {
+ local opts=:$2:
+ ble/decode/keymap#registered "$1" && return 0
+ local init=ble-decode/keymap:$1/define
+ ble/is-function "$init" || return 1
+ ble/decode/keymap#.register "$1"
+ local ble_bind_keymap=$1
+ if ! "$init" || ble/decode/keymap#is-empty "$1"; then
+ ble/decode/keymap#.unregister "$1"
+ return 1
+ fi
+ [[ $opts == *:dump:* ]] &&
+ ble/decode/keymap#dump "$1" >&3
+ ble/decode/keymap#.onload "$1"
+ return 0
+}
+function ble/decode/keymap#unload {
+ if (($#==0)); then
+ local list; ble/string#split-words list "${_ble_decode_keymap_list//:/ }"
+ set -- "${list[@]}"
+ fi
+ while (($#)); do
+ local array_names array_name
+ builtin eval -- "array_names=(\"\${!_ble_decode_${1}_kmap_@}\")"
+ for array_name in "${array_names[@]}"; do
+ builtin unset -v "$array_name"
+ done
+ ble/decode/keymap#.unregister "$1"
+ shift
+ done
+}
+if [[ ${_ble_decode_kmaps-} ]]; then
+ function ble/decode/keymap/cleanup-old-keymaps {
+ local -a list=()
+ local var
+ for var in "${!_ble_decode_@}"; do
+ [[ $var == _ble_decode_*_kmap_ ]] || continue
+ var=${var#_ble_decode_}
+ var=${var%_kmap_}
+ ble/array#push list "$var"
+ done
+ local keymap_name
+ for keymap_name in "${list[@]}"; do
+ ble/decode/keymap#unload "$keymap_name"
+ done
+ builtin unset -v _ble_decode_kmaps
+ }
+ ble/decode/keymap/cleanup-old-keymaps
+fi
+function ble/decode/keymap#dump {
+ if (($#)); then
+ local kmap=$1 arrays
+ builtin eval "arrays=(\"\${!_ble_decode_${kmap}_kmap_@}\")"
+ ble/util/print "ble/decode/keymap#.register $kmap"
+ ble/util/declare-print-definitions "${arrays[@]}"
+ ble/util/print "ble/decode/keymap#.onload $kmap"
+ else
+ local list; ble/string#split-words list "${_ble_decode_keymap_list//:/ }"
+ local keymap_name
+ for keymap_name in "${list[@]}"; do
+ ble/decode/keymap#dump "$keymap_name"
+ done
+ fi
+}
+function ble-decode/GET_BASEMAP {
+ [[ $1 == -v ]] || return 1
+ local ret; bleopt/get:default_keymap
+ [[ $ret == vi ]] && ret=vi_imap
+ builtin eval "$2=\$ret"
+}
+function ble-decode/INITIALIZE_DEFMAP {
+ ble-decode/GET_BASEMAP "$@" &&
+ ble/decode/keymap#load "${!2}" &&
+ return 0
+ ble/decode/keymap#load safe &&
+ builtin eval -- "$2=safe" &&
+ bleopt_default_keymap=safe
+}
+function ble/widget/.SHELL_COMMAND { local IFS=$_ble_term_IFS; builtin eval -- "$*"; }
+function ble/widget/.EDIT_COMMAND { local IFS=$_ble_term_IFS; builtin eval -- "$*"; }
+function ble-decode-key/bind {
+ if ! ble/decode/keymap#registered "$1"; then
+ ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$1"
+ return 0
+ fi
+ local kmap=$1 keys=$2 cmd=$3
+ if local widget=${cmd%%[$_ble_term_IFS]*}; ! ble/is-function "$widget"; then
+ local message="ble-bind: Unknown widget \`${widget#'ble/widget/'}'."
+ [[ $command == ble/widget/ble/widget/* ]] &&
+ message="$message Note: The prefix 'ble/widget/' is redundant."
+ ble/util/print "$message" 1>&2
+ return 1
+ fi
+ local dicthead=_ble_decode_${kmap}_kmap_
+ local -a seq; ble/string#split-words seq "$keys"
+ local i iN=${#seq[@]} tseq=
+ for ((i=0;i<iN;i++)); do
+ local key=${seq[i]}
+ builtin eval "local ocmd=\${$dicthead$tseq[key]}"
+ if ((i+1==iN)); then
+ if [[ ${ocmd::1} == _ ]]; then
+ builtin eval "$dicthead$tseq[key]=${ocmd%%:*}:\$cmd"
+ else
+ builtin eval "$dicthead$tseq[key]=1:\$cmd"
+ fi
+ else
+ if [[ ! $ocmd ]]; then
+ builtin eval "$dicthead$tseq[key]=_"
+ elif [[ ${ocmd::1} == 1 ]]; then
+ builtin eval "$dicthead$tseq[key]=_:\${ocmd#*:}"
+ fi
+ tseq=${tseq}_$key
+ fi
+ done
+}
+function ble-decode-key/set-timeout {
+ if ! ble/decode/keymap#registered "$1"; then
+ ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$1"
+ return 0
+ fi
+ local kmap=$1 keys=$2 timeout=$3
+ local dicthead=_ble_decode_${kmap}_kmap_
+ local -a seq; ble/string#split-words seq "$keys"
+ [[ $timeout == - ]] && timeout=
+ local i iN=${#seq[@]}
+ local key=${seq[iN-1]}
+ local tseq=
+ for ((i=0;i<iN-1;i++)); do
+ tseq=${tseq}_${seq[i]}
+ done
+ builtin eval "local ent=\${$dicthead$tseq[key]}"
+ if [[ $ent == _* ]]; then
+ local cmd=; [[ $ent == *:* ]] && cmd=${ent#*:}
+ builtin eval "$dicthead$tseq[key]=_$timeout${cmd:+:}\$cmd"
+ else
+ ble/util/print "ble-bind -T: specified partial keyspec not found." >&2
+ return 1
+ fi
+}
+function ble-decode-key/unbind {
+ if ! ble/decode/keymap#registered "$1"; then
+ ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$1"
+ return 0
+ fi
+ local kmap=$1 keys=$2
+ local dicthead=_ble_decode_${kmap}_kmap_
+ local -a seq; ble/string#split-words seq "$keys"
+ local i iN=${#seq[@]}
+ local key=${seq[iN-1]}
+ local tseq=
+ for ((i=0;i<iN-1;i++)); do
+ tseq=${tseq}_${seq[i]}
+ done
+ local isfirst=1 ent=
+ while
+ builtin eval "ent=\${$dicthead$tseq[key]}"
+ if [[ $isfirst ]]; then
+ isfirst=
+ if [[ ${ent::1} == _ ]]; then
+ builtin eval "$dicthead$tseq[key]=\${ent%%:*}"
+ break
+ fi
+ else
+ if [[ $ent == *:* ]]; then
+ builtin eval "$dicthead$tseq[key]=1:\${ent#*:}"
+ break
+ fi
+ fi
+ builtin unset -v "$dicthead$tseq[key]"
+ builtin eval "((\${#$dicthead$tseq[@]}!=0))" && break
+ [[ $tseq ]]
+ do
+ key=${tseq##*_}
+ tseq=${tseq%_*}
+ done
+}
+function ble/decode/keymap#get-cursor {
+ cursor=_ble_decode_${1}_kmap_cursor
+ cursor=${!cursor-}
+}
+function ble/decode/keymap#set-cursor {
+ local keymap=$1 cursor=$2
+ if ! ble/decode/keymap#registered "$keymap"; then
+ ble/util/print-quoted-command "$FUNCNAME" "$@" >> "$_ble_base_run/$$.bind.delay.$keymap"
+ return 0
+ fi
+ builtin eval "_ble_decode_${keymap}_kmap_cursor=\$cursor"
+}
+function ble/decode/keymap#print {
+ local kmap
+ if (($#==0)); then
+ for kmap in ${_ble_decode_keymap_list//:/ }; do
+ ble/util/print "$sgrc# keymap $kmap$sgr0"
+ ble/decode/keymap#print "$kmap"
+ done
+ return 0
+ fi
+ [[ $ble_bind_print ]] || local sgr0= sgrf= sgrq= sgrc= sgro=
+ local kmap=$1 tseq=$2 nseq=$3
+ local dicthead=_ble_decode_${kmap}_kmap_
+ local kmapopt=
+ [[ $kmap ]] && kmapopt=" $sgro-m$sgr0 $sgrq'$kmap'$sgr0"
+ local q=\' Q="'\''"
+ local key keys
+ builtin eval "keys=(\${!$dicthead$tseq[@]})"
+ for key in "${keys[@]}"; do
+ local ret; ble-decode-unkbd "$key"
+ local knames=$nseq${nseq:+ }$ret
+ builtin eval "local ent=\${$dicthead$tseq[key]}"
+ local qknames
+ if [[ $sgrq ]]; then
+ ble/string#quote-word "$knames" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qknames=$ret
+ else
+ qknames="'${knames//$q/$Q}'"
+ fi
+ if [[ $ent == *:* ]]; then
+ local cmd=${ent#*:}
+ local o v
+ case "$cmd" in
+ ('ble/widget/.SHELL_COMMAND '*) o=c v=${cmd#'ble/widget/.SHELL_COMMAND '} ;;
+ ('ble/widget/.EDIT_COMMAND '*) o=x v=${cmd#'ble/widget/.EDIT_COMMAND '} ;;
+ ('ble/widget/.MACRO '*) o=s; ble/util/chars2keyseq ${cmd#*' '}; v=$ret ;;
+ ('ble/widget/'*) o=f v=${cmd#ble/widget/} ;;
+ (*) o=@ v=$cmd ;;
+ esac
+ local qv
+ if [[ $sgrq ]]; then
+ ble/string#quote-word "$v" quote-empty:sgrq="$sgrq":sgr0="$sgr0"; qv=$ret
+ else
+ qv="'${v//$q/$Q}'"
+ fi
+ ble/util/print "${sgrf}ble-bind$sgr0$kmapopt $sgro-$o$sgr0 $qknames $qv"
+ fi
+ if [[ ${ent::1} == _ ]]; then
+ ble/decode/keymap#print "$kmap" "${tseq}_$key" "$knames"
+ if [[ $ent == _[0-9]* ]]; then
+ local timeout=${ent%%:*}; timeout=${timeout:1}
+ ble/util/print "${sgrf}ble-bind$sgr0$kmapopt $sgro-T$sgr0 $qknames $timeout"
+ fi
+ fi
+ done
+}
+_ble_decode_keymap=
+_ble_decode_keymap_stack=()
+function ble/decode/keymap/push {
+ if ble/decode/keymap#registered "$1"; then
+ ble/array#push _ble_decode_keymap_stack "$_ble_decode_keymap"
+ _ble_decode_keymap=$1
+ local cursor; ble/decode/keymap#get-cursor "$1"
+ [[ $cursor ]] && ble/term/cursor-state/set-internal $((cursor))
+ return 0
+ elif ble/decode/keymap#load "$1" && ble/decode/keymap#registered "$1"; then
+ ble/decode/keymap/push "$1" # 再実行
+ else
+ ble/util/print "[ble: keymap '$1' not found]" >&2
+ return 1
+ fi
+}
+function ble/decode/keymap/pop {
+ local count=${#_ble_decode_keymap_stack[@]}
+ local last=$((count-1))
+ ble/util/assert '((last>=0))' || return 1
+ local cursor
+ ble/decode/keymap#get-cursor "$_ble_decode_keymap"
+ if [[ $cursor ]]; then
+ local i
+ for ((i=last;i>=0;i--)); do
+ ble/decode/keymap#get-cursor "${_ble_decode_keymap_stack[i]}"
+ [[ $cursor ]] && break
+ done
+ ble/term/cursor-state/set-internal $((${cursor:-0}))
+ fi
+ local old_keymap=_ble_decode_keymap
+ _ble_decode_keymap=${_ble_decode_keymap_stack[last]}
+ builtin unset -v '_ble_decode_keymap_stack[last]'
+}
+function ble/decode/keymap/get-parent {
+ local len=${#_ble_decode_keymap_stack[@]}
+ if ((len)); then
+ ret=${_ble_decode_keymap_stack[len-1]}
+ else
+ ret=
+ fi
+}
+_ble_decode_key__seq=
+_ble_decode_key__hook=
+function ble-decode-key/is-intermediate { [[ $_ble_decode_key__seq ]]; }
+_ble_decode_key_batch=()
+function ble-decode-key/batch/flush {
+ ((${#_ble_decode_key_batch[@]})) || return 1
+ local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_
+ builtin eval "local command=\${${dicthead}[_ble_decode_KCODE_BATCH_CHAR]-}"
+ command=${command:2}
+ if [[ $command ]]; then
+ local chars; chars=("${_ble_decode_key_batch[@]}")
+ _ble_decode_key_batch=()
+ ble/decode/widget/call-interactively "$command" "${chars[@]}"; local ext=$?
+ ((ext!=125)) && return 0
+ fi
+ ble/decode/widget/call-interactively ble/widget/__batch_char__.default "${chars[@]}"; local ext=$?
+ return "$ext"
+}
+function ble/widget/__batch_char__.default {
+ builtin eval "local widget_defchar=\${${dicthead}[_ble_decode_KCODE_DEFCHAR]-}"
+ widget_defchar=${widget_defchar:2}
+ builtin eval "local widget_default=\${${dicthead}[_ble_decode_KCODE_DEFAULT]-}"
+ widget_default=${widget_default:2}
+ local -a unprocessed_chars=()
+ local key command
+ for key in "${KEYS[@]}"; do
+ if [[ $widget_defchar ]]; then
+ ble/decode/widget/call-interactively "$widget_defchar" "$key"; local ext=$?
+ ((ext!=125)) && continue
+ fi
+ if [[ $widget_default ]]; then
+ ble/decode/widget/call-interactively "$widget_default" "$key"; local ext=$?
+ ((ext!=125)) && continue
+ fi
+ ble/array#push unprocessed_chars "$key"
+ done
+ if ((${#unprocessed_chars[@]})); then
+ local ret; ble-decode-unkbd "${unprocessed_chars[@]}"
+ [[ $bleopt_decode_error_kseq_vbell ]] && ble/term/visible-bell "unprocessed chars: $ret"
+ [[ $bleopt_decode_error_kseq_abell ]] && ble/term/audible-bell
+ fi
+ return 0
+}
+function ble-decode-key {
+ local key
+ while (($#)); do
+ key=$1; shift
+ ((_ble_debug_keylog_enabled)) && ble/array#push _ble_debug_keylog_keys "$key"
+ if [[ $_ble_decode_keylog_keys_enabled && $_ble_decode_keylog_depth == 0 ]]; then
+ ble/array#push _ble_decode_keylog_keys "$key"
+ ((_ble_decode_keylog_keys_count++))
+ fi
+ local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_
+ if (((key&_ble_decode_MaskChar)==_ble_decode_KCODE_MOUSE_MOVE)); then
+ builtin eval "local command=\${${dicthead}[key]-}"
+ command=${command:2}
+ ble-decode/widget/.call-keyseq
+ continue
+ fi
+ if [[ $_ble_decode_key__hook ]]; then
+ local hook=$_ble_decode_key__hook
+ _ble_decode_key__hook=
+ ble-decode/widget/.call-async-read "$hook $key" "$key"
+ continue
+ fi
+ builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[key]-}"
+ if [[ $ent == _[0-9]* ]]; then
+ local node_type=_
+ if (($#==0)) && ! ble/decode/has-input; then
+ local timeout=${ent%%:*}; timeout=${timeout:1}
+ ble/decode/wait-input "$timeout" || node_type=1
+ fi
+ if [[ $ent == *:* ]]; then
+ ent=$node_type:${ent#*:}
+ else
+ ent=$node_type
+ fi
+ fi
+ if [[ $ent == 1:* ]]; then
+ local command=${ent:2}
+ if [[ $command ]]; then
+ ble-decode/widget/.call-keyseq
+ else
+ _ble_decode_key__seq=
+ fi
+ elif [[ $ent == _ || $ent == _:* ]]; then
+ _ble_decode_key__seq=${_ble_decode_key__seq}_$key
+ else
+ ble-decode-key/.invoke-partial-match "$key" && continue
+ local kseq=${_ble_decode_key__seq}_$key ret
+ ble-decode-unkbd "${kseq//_/ }"
+ local kspecs=$ret
+ [[ $bleopt_decode_error_kseq_vbell ]] && ble/term/visible-bell "unbound keyseq: $kspecs"
+ [[ $bleopt_decode_error_kseq_abell ]] && ble/term/audible-bell
+ if [[ $_ble_decode_key__seq ]]; then
+ if [[ $bleopt_decode_error_kseq_discard ]]; then
+ _ble_decode_key__seq=
+ else
+ local -a keys
+ ble/string#split-words keys "${_ble_decode_key__seq//_/ } $key"
+ _ble_decode_key__seq=
+ ble-decode-key "${keys[@]:1}"
+ fi
+ fi
+ fi
+ done
+ if ((${#_ble_decode_key_batch[@]})); then
+ if ! ble/decode/has-input || ((${#_ble_decode_key_batch[@]}>=50)); then
+ ble-decode-key/batch/flush
+ fi
+ fi
+ return 0
+}
+function ble-decode-key/.invoke-partial-match {
+ local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_
+ local next=$1
+ if [[ $_ble_decode_key__seq ]]; then
+ local last=${_ble_decode_key__seq##*_}
+ _ble_decode_key__seq=${_ble_decode_key__seq%_*}
+ builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[last]-}"
+ if [[ $ent == _*:* ]]; then
+ local command=${ent#*:}
+ if [[ $command ]]; then
+ ble-decode/widget/.call-keyseq
+ else
+ _ble_decode_key__seq=
+ fi
+ ble-decode-key "$next"
+ return 0
+ else # ent = _
+ if ble-decode-key/.invoke-partial-match "$last"; then
+ ble-decode-key "$next"
+ return 0
+ else
+ _ble_decode_key__seq=${_ble_decode_key__seq}_$last
+ return 1
+ fi
+ fi
+ else
+ local key=$1
+ if ble-decode-key/ischar "$key"; then
+ if ble/decode/has-input && builtin eval "[[ \${${dicthead}[_ble_decode_KCODE_BATCH_CHAR]-} ]]"; then
+ ble/array#push _ble_decode_key_batch "$key"
+ return 0
+ fi
+ builtin eval "local command=\${${dicthead}[_ble_decode_KCODE_DEFCHAR]-}"
+ command=${command:2}
+ if [[ $command ]]; then
+ local seq_save=$_ble_decode_key__seq
+ ble-decode/widget/.call-keyseq; local ext=$?
+ ((ext!=125)) && return 0
+ _ble_decode_key__seq=$seq_save # 125 の時はまた元に戻して次の試行を行う
+ fi
+ fi
+ builtin eval "local command=\${${dicthead}[_ble_decode_KCODE_DEFAULT]-}"
+ command=${command:2}
+ ble-decode/widget/.call-keyseq; local ext=$?
+ ((ext!=125)) && return 0
+ return 1
+ fi
+}
+function ble-decode-key/ischar {
+ local key=$1
+ (((key&_ble_decode_MaskFlag)==0&&32<=key&&key<_ble_decode_FunctionKeyBase))
+}
+_ble_decode_widget_last=
+function ble-decode/widget/.invoke-hook {
+ local key=$1
+ local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_
+ builtin eval "local hook=\${$dicthead[key]-}"
+ hook=${hook:2}
+ [[ $hook ]] && builtin eval -- "$hook"
+}
+function ble-decode/widget/.call-keyseq {
+ ble-decode-key/batch/flush
+ [[ $command ]] || return 125
+ local _ble_decode_keylog_depth=$((_ble_decode_keylog_depth+1))
+ local WIDGET=$command KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last
+ local -a KEYS; ble/string#split-words KEYS "${_ble_decode_key__seq//_/ } $key"
+ _ble_decode_widget_last=$WIDGET
+ _ble_decode_key__seq=
+ ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_BEFORE_WIDGET"
+ builtin eval -- "$WIDGET"; local ext=$?
+ ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_AFTER_WIDGET"
+ ((_ble_decode_keylog_depth==1)) &&
+ _ble_decode_keylog_chars_count=0 _ble_decode_keylog_keys_count=0
+ return "$ext"
+}
+function ble-decode/widget/.call-async-read {
+ local _ble_decode_keylog_depth=$((_ble_decode_keylog_depth+1))
+ local WIDGET=$1 KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last
+ local -a KEYS; ble/string#split-words KEYS "$2"
+ builtin eval -- "$WIDGET"; local ext=$?
+ ((_ble_decode_keylog_depth==1)) &&
+ _ble_decode_keylog_chars_count=0 _ble_decode_keylog_keys_count=0
+ return "$ext"
+}
+function ble/decode/widget/call-interactively {
+ local WIDGET=$1 KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last
+ local -a KEYS; KEYS=("${@:2}")
+ _ble_decode_widget_last=$WIDGET
+ ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_BEFORE_WIDGET"
+ builtin eval -- "$WIDGET"; local ext=$?
+ ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_AFTER_WIDGET"
+ return "$ext"
+}
+function ble/decode/widget/call {
+ local WIDGET=$1 KEYMAP=$_ble_decode_keymap LASTWIDGET=$_ble_decode_widget_last
+ local -a KEYS; KEYS=("${@:2}")
+ _ble_decode_widget_last=$WIDGET
+ builtin eval -- "$WIDGET"
+}
+function ble/decode/widget/dispatch {
+ local ret; ble/string#quote-command "ble/widget/$@"
+ local WIDGET=$ret
+ _ble_decode_widget_last=$WIDGET
+ builtin eval -- "$WIDGET"
+}
+function ble/decode/widget/suppress-widget {
+ WIDGET=
+}
+function ble/decode/widget/redispatch-by-keys {
+ if ((_ble_decode_keylog_depth==1)); then
+ ble/decode/keylog#pop
+ _ble_decode_keylog_depth=0
+ fi
+ ble-decode-key "$@"
+}
+function ble/decode/widget/skip-lastwidget {
+ _ble_decode_widget_last=$LASTWIDGET
+}
+function ble/decode/widget/keymap-dispatch {
+ local name=${FUNCNAME[1]#ble/widget/}
+ local widget=ble/widget/$_ble_decode_keymap/$name
+ ble/is-function "$widget" || widget=ble/widget/default/$name
+ "$widget" "$@"
+}
+function ble/decode/has-input {
+ ((_ble_decode_input_count||ble_decode_char_rest)) ||
+ ble/util/is-stdin-ready ||
+ ble/encoding:"$bleopt_input_encoding"/is-intermediate ||
+ ble-decode-char/is-intermediate
+}
+function ble/decode/wait-input {
+ local timeout=$1
+ while ((timeout>0)); do
+ ble/decode/has-input && return 0
+ local w=$((timeout<20?timeout:20))
+ ble/util/msleep "$w"
+ ((timeout-=w))
+ done
+ return 1
+}
+function ble/util/idle/IS_IDLE {
+ ! ble/decode/has-input
+}
+_ble_debug_keylog_enabled=0
+_ble_debug_keylog_bytes=()
+_ble_debug_keylog_chars=()
+_ble_debug_keylog_keys=()
+function ble/debug/keylog#start {
+ _ble_debug_keylog_enabled=1
+}
+function ble/debug/keylog#end {
+ {
+ local IFS=$_ble_term_IFS
+ ble/util/print '===== bytes ====='
+ ble/util/print "${_ble_debug_keylog_bytes[*]}"
+ ble/util/print
+ ble/util/print '===== chars ====='
+ local ret; ble-decode-unkbd "${_ble_debug_keylog_chars[@]}"
+ ble/string#split ret ' ' "$ret"
+ ble/util/print "${ret[*]}"
+ ble/util/print
+ ble/util/print '===== keys ====='
+ local ret; ble-decode-unkbd "${_ble_debug_keylog_keys[@]}"
+ ble/string#split ret ' ' "$ret"
+ ble/util/print "${ret[*]}"
+ ble/util/print
+ } | fold -w 40
+ _ble_debug_keylog_enabled=0
+ _ble_debug_keylog_bytes=()
+ _ble_debug_keylog_chars=()
+ _ble_debug_keylog_keys=()
+}
+_ble_decode_keylog_depth=0
+_ble_decode_keylog_keys_enabled=
+_ble_decode_keylog_keys_count=0
+_ble_decode_keylog_keys=()
+_ble_decode_keylog_chars_enabled=
+_ble_decode_keylog_chars_count=0
+_ble_decode_keylog_chars=()
+function ble/decode/keylog#start {
+ [[ $_ble_decode_keylog_keys_enabled ]] && return 1
+ _ble_decode_keylog_keys_enabled=${1:-1}
+ _ble_decode_keylog_keys=()
+}
+function ble/decode/keylog#end {
+ ret=("${_ble_decode_keylog_keys[@]}")
+ _ble_decode_keylog_keys_enabled=
+ _ble_decode_keylog_keys=()
+}
+function ble/decode/keylog#pop {
+ [[ $_ble_decode_keylog_keys_enabled && $_ble_decode_keylog_depth == 1 ]] || return 1
+ local new_size=$((${#_ble_decode_keylog_keys[@]}-_ble_decode_keylog_keys_count))
+ ((new_size<0)) && new_size=0
+ _ble_decode_keylog_keys=("${_ble_decode_keylog_keys[@]::new_size}")
+ _ble_decode_keylog_keys_count=0
+}
+function ble/decode/charlog#start {
+ [[ $_ble_decode_keylog_chars_enabled ]] && return 1
+ _ble_decode_keylog_chars_enabled=${1:-1}
+ _ble_decode_keylog_chars=()
+}
+function ble/decode/charlog#end {
+ [[ $_ble_decode_keylog_chars_enabled ]] || { ret=(); return 1; }
+ ret=("${_ble_decode_keylog_chars[@]}")
+ _ble_decode_keylog_chars_enabled=
+ _ble_decode_keylog_chars=()
+}
+function ble/decode/charlog#end-exclusive {
+ ret=()
+ [[ $_ble_decode_keylog_chars_enabled ]] || return 1
+ local size=$((${#_ble_decode_keylog_chars[@]}-_ble_decode_keylog_chars_count))
+ ((size>0)) && ret=("${_ble_decode_keylog_chars[@]::size}")
+ _ble_decode_keylog_chars_enabled=
+ _ble_decode_keylog_chars=()
+}
+function ble/decode/charlog#end-exclusive-depth1 {
+ if ((_ble_decode_keylog_depth==1)); then
+ ble/decode/charlog#end-exclusive
+ else
+ ble/decode/charlog#end
+ fi
+}
+function ble/decode/charlog#encode {
+ local -a buff=()
+ for char; do
+ ((char==0)) && char=$_ble_decode_EscapedNUL
+ ble/util/c2s "$char"
+ ble/array#push buff "$ret"
+ done
+ IFS= builtin eval 'ret="${buff[*]}"'
+}
+function ble/decode/charlog#decode {
+ local text=$1 n=${#1} i chars
+ chars=()
+ for ((i=0;i<n;i++)); do
+ ble/util/s2c "${text:i:1}"
+ ((ret==_ble_decode_EscapedNUL)) && ret=0
+ ble/array#push chars "$ret"
+ done
+ ret=("${chars[@]}")
+}
+function ble/decode/keylog#encode {
+ ret=
+ ble/util/c2s 155; local csi=$ret
+ local key
+ local -a buff=()
+ for key; do
+ if ble-decode-key/ischar "$key"; then
+ ble/util/c2s "$key"
+ if ((${#ret}==1)); then
+ ble/array#push buff "$ret"
+ continue
+ fi
+ fi
+ local c=$((key&_ble_decode_MaskChar))
+ if (((key&_ble_decode_MaskFlag)==_ble_decode_Ctrl&&(c==64||91<=c&&c<=95||97<=c&&c<=122))); then
+ if ((c!=64)); then
+ ble/util/c2s $((c&0x1F))
+ ble/array#push buff "$ret"
+ continue
+ fi
+ fi
+ local mod=1
+ (((key&_ble_decode_Shft)&&(mod+=0x01),
+ (key&_ble_decode_Altr)&&(mod+=0x02),
+ (key&_ble_decode_Ctrl)&&(mod+=0x04),
+ (key&_ble_decode_Supr)&&(mod+=0x08),
+ (key&_ble_decode_Hypr)&&(mod+=0x10),
+ (key&_ble_decode_Meta)&&(mod+=0x20)))
+ ble/array#push buff "${csi}27;$mod;$c~"
+ done
+ IFS= builtin eval 'ret="${buff[*]-}"'
+}
+function ble/decode/keylog#decode-chars {
+ local text=$1 n=${#1} i
+ local -a chars=()
+ for ((i=0;i<n;i++)); do
+ ble/util/s2c "${text:i:1}"
+ ((ret==27)) && ret=$_ble_decode_IsolatedESC
+ ble/array#push chars "$ret"
+ done
+ ret=("${chars[@]}")
+}
+_ble_decode_macro_count=0
+function ble/widget/.MACRO {
+ if ((ble_decode_char_char&_ble_decode_Macr)); then
+ if ((_ble_decode_macro_count++>=bleopt_decode_macro_limit)); then
+ ((_ble_decode_macro_count==bleopt_decode_macro_limit+1)) &&
+ ble/term/visible-bell "Macro invocation is cancelled by decode_macro_limit"
+ return 1
+ fi
+ else
+ _ble_decode_macro_count=0
+ fi
+ local -a chars=()
+ local char
+ for char; do
+ ble/array#push chars $((char|_ble_decode_Macr))
+ done
+ ble-decode-char "${chars[@]}"
+}
+function ble/widget/.CHARS {
+ ble-decode-char "$@"
+}
+function ble/decode/c2dqs {
+ local i=$1
+ if ((0<=i&&i<32)); then
+ if ((1<=i&&i<=26)); then
+ ble/util/c2s $((i+96))
+ ret="\\C-$ret"
+ elif ((i==27)); then
+ ret="\\e"
+ elif ((i==28)); then
+ ret="\\x1c"
+ else
+ ble/decode/c2dqs $((i+64))
+ ret="\\C-$ret"
+ fi
+ elif ((32<=i&&i<127)); then
+ ble/util/c2s "$i"
+ if ((i==34||i==92)); then
+ ret='\'"$ret"
+ fi
+ elif ((128<=i&&i<160)); then
+ ble/util/sprintf ret '\\%03o' "$i"
+ else
+ ble/util/sprintf ret '\\%03o' "$i"
+ fi
+}
+function ble/decode/cmap/.generate-binder-template {
+ local tseq=$1 qseq=$2 nseq=$3 depth=${4:-1} ccode
+ local apos="'" escapos="'\\''"
+ builtin eval "local -a ccodes; ccodes=(\${!_ble_decode_cmap_$tseq[@]})"
+ for ccode in "${ccodes[@]}"; do
+ local ret
+ ble/decode/c2dqs "$ccode"
+ qseq1=$qseq$ret
+ nseq1="$nseq $ccode"
+ builtin eval "local ent=\${_ble_decode_cmap_$tseq[ccode]}"
+ if [[ ${ent%_} ]]; then
+ if ((depth>=3)); then
+ ble/util/print "\$binder \"$qseq1\" \"${nseq1# }\""
+ fi
+ fi
+ if [[ ${ent//[0-9]} == _ ]]; then
+ ble/decode/cmap/.generate-binder-template "${tseq}_$ccode" "$qseq1" "$nseq1" $((depth+1))
+ fi
+ done
+}
+function ble/decode/cmap/.emit-bindx {
+ local q="'" Q="'\''"
+ ble/util/print "builtin bind -x '\"${1//$q/$Q}\":ble-decode/.hook $2; builtin eval -- \"\$_ble_decode_bind_hook\"'"
+}
+function ble/decode/cmap/.emit-bindr {
+ ble/util/print "builtin bind -r \"$1\""
+}
+_ble_decode_cmap_initialized=
+function ble/decode/cmap/initialize {
+ [[ $_ble_decode_cmap_initialized ]] && return 0
+ _ble_decode_cmap_initialized=1
+ local init=$_ble_base/lib/init-cmap.sh
+ local dump=$_ble_base_cache/decode.cmap.$_ble_decode_kbd_ver.$TERM.dump
+ if [[ -s $dump && $dump -nt $init ]]; then
+ source "$dump"
+ else
+ ble/edit/info/immediate-show text 'ble.sh: generating "'"$dump"'"...'
+ source "$init"
+ ble-bind -D | ble/bin/awk '
+ {
+ sub(/^declare +(-[aAilucnrtxfFgGI]+ +)?/, "");
+ sub(/^-- +/, "");
+ }
+ /^_ble_decode_(cmap|csimap|kbd)/ {
+ if (!($0 ~ /^_ble_decode_csimap_kitty_u/))
+ gsub(/["'\'']/, "");
+ print
+ }
+ ' >| "$dump"
+ fi
+ if ((_ble_bash>=40300)); then
+ local fbinder=$_ble_base_cache/decode.cmap.allseq
+ _ble_decode_bind_fbinder=$fbinder
+ if ! [[ -s $_ble_decode_bind_fbinder.bind && $_ble_decode_bind_fbinder.bind -nt $init &&
+ -s $_ble_decode_bind_fbinder.unbind && $_ble_decode_bind_fbinder.unbind -nt $init ]]; then
+ ble/edit/info/immediate-show text 'ble.sh: initializing multichar sequence binders... '
+ ble/decode/cmap/.generate-binder-template >| "$fbinder"
+ binder=ble/decode/cmap/.emit-bindx source "$fbinder" >| "$fbinder.bind"
+ binder=ble/decode/cmap/.emit-bindr source "$fbinder" >| "$fbinder.unbind"
+ ble/edit/info/immediate-show text 'ble.sh: initializing multichar sequence binders... done'
+ fi
+ fi
+}
+function ble/decode/cmap/decode-chars.hook {
+ ble/array#push ble_decode_bind_keys "$1"
+ _ble_decode_key__hook=ble/decode/cmap/decode-chars.hook
+}
+function ble/decode/cmap/decode-chars {
+ ble/decode/cmap/initialize
+ local _ble_decode_csi_mode=0
+ local _ble_decode_csi_args=
+ local _ble_decode_char2_seq=
+ local _ble_decode_char2_reach_key=
+ local _ble_decode_char2_reach_seq=
+ local _ble_decode_char2_modifier=
+ local _ble_decode_char2_modkcode=
+ local _ble_decode_char__hook=
+ local _ble_debug_keylog_enabled=
+ local _ble_decode_keylog_keys_enabled=
+ local _ble_decode_keylog_chars_enabled=
+ local _ble_decode_show_progress_hook=
+ local _ble_decode_erase_progress_hook=
+ local bleopt_decode_error_cseq_abell=
+ local bleopt_decode_error_cseq_vbell=
+ local bleopt_decode_error_cseq_discard=
+ local -a ble_decode_bind_keys=()
+ local _ble_decode_key__hook=ble/decode/cmap/decode-chars.hook
+ local ble_decode_char_sync=1 # ユーザ入力があっても中断しない
+ ble-decode-char "$@"
+ keys=("${ble_decode_bind_keys[@]}")
+}
+_ble_decode_bind_hook=
+_ble_decode_bind__uvwflag=
+function ble/decode/bind/adjust-uvw {
+ [[ $_ble_decode_bind__uvwflag ]] && return 0
+ _ble_decode_bind__uvwflag=1
+ builtin bind -x '"":ble-decode/.hook 21; builtin eval -- "$_ble_decode_bind_hook"'
+ builtin bind -x '"":ble-decode/.hook 22; builtin eval -- "$_ble_decode_bind_hook"'
+ builtin bind -x '"":ble-decode/.hook 23; builtin eval -- "$_ble_decode_bind_hook"'
+ builtin bind -x '"":ble-decode/.hook 127; builtin eval -- "$_ble_decode_bind_hook"'
+}
+function ble/base/workaround-POSIXLY_CORRECT {
+ [[ $_ble_decode_bind_state == none ]] && return 0
+ builtin bind -x '"\C-i":ble-decode/.hook 9; builtin eval -- "$_ble_decode_bind_hook"'
+}
+function ble/decode/bind/.generate-source-to-unbind-default {
+ {
+ if ((_ble_bash>=40300)); then
+ ble/util/print '__BINDX__'
+ builtin bind -X
+ fi
+ ble/util/print '__BINDP__'
+ builtin bind -sp
+ } | ble/decode/bind/.generate-source-to-unbind-default/.process
+} 2>/dev/null
+function ble/decode/bind/.generate-source-to-unbind-default/.process {
+ local q=\' Q="'\''"
+ LC_ALL=C ble/bin/awk -v q="$q" '
+ BEGIN {
+ IS_XPG4 = AWKTYPE == "xpg4";
+ rep_Q = str2rep(q "\\" q q);
+ rep_bslash = str2rep("\\");
+ rep_kseq_1c5c = str2rep("\"\\x1c\\x5c\"");
+ rep_kseq_1c = str2rep("\"\\x1c\"");
+ mode = 1;
+ }
+ function str2rep(str) {
+ if (IS_XPG4) sub(/\\/, "\\\\\\\\", str);
+ return str;
+ }
+ function quote(text) {
+ gsub(q, rep_Q, text);
+ return q text q;
+ }
+ function unescape_control_modifier(str, _, i, esc, chr) {
+ for (i = 0; i < 32; i++) {
+ if (i == 0 || i == 31)
+ esc = sprintf("\\\\C-%c", i + 64);
+ else if (27 <= i && i <= 30)
+ esc = sprintf("\\\\C-\\%c", i + 64);
+ else
+ esc = sprintf("\\\\C-%c", i + 96);
+ chr = sprintf("%c", i);
+ gsub(esc, chr, str);
+ }
+ gsub(/\\C-\?/, sprintf("%c", 127), str);
+ return str;
+ }
+ function unescape(str) {
+ if (str ~ /\\C-/)
+ str = unescape_control_modifier(str);
+ gsub(/\\e/, sprintf("%c", 27), str);
+ gsub(/\\"/, "\"", str);
+ gsub(/\\\\/, rep_bslash, str);
+ return str;
+ }
+ function output_bindr(line0, _seq) {
+ if (match(line0, /^"(([^"\\]|\\.)+)"/) > 0) {
+ _seq = substr(line0, 2, RLENGTH - 2);
+ gsub(/\\M-/, "\\e", _seq);
+ print "builtin bind -r " quote(_seq);
+ }
+ }
+ /^__BINDP__$/ { mode = 1; next; }
+ /^__BINDX__$/ { mode = 2; next; }
+ mode == 1 && $0 ~ /^"/ {
+ sub(/^"\\C-\\\\\\"/, rep_kseq_1c5c);
+ sub(/^"\\C-\\\\?"/, rep_kseq_1c);
+ output_bindr($0);
+ print "builtin bind " quote($0) > "/dev/stderr";
+ }
+ mode == 2 && $0 ~ /^"/ {
+ output_bindr($0);
+ line = $0;
+ if (line ~ /(^|[^[:alnum:]])ble-decode\/.hook($|[^[:alnum:]])/) next;
+ if (match(line, /^("([^"\\]|\\.)*":) "(([^"\\]|\\.)*)"/) > 0) {
+ rlen = RLENGTH;
+ match(line, /^"([^"\\]|\\.)*":/);
+ rlen1 = RLENGTH;
+ rlen2 = rlen - rlen1 - 3;
+ sequence = substr(line, 1 , rlen1);
+ command = substr(line, rlen1 + 3, rlen2);
+ if (command ~ /\\/)
+ command = unescape(command);
+ line = sequence command;
+ }
+ print "builtin bind -x " quote(line) > "/dev/stderr";
+ }
+ ' 2>| "$_ble_base_run/$$.bind.save"
+}
+_ble_decode_bind_state=none
+_ble_decode_bind_bindp=
+_ble_decode_bind_encoding=
+function ble/decode/bind/bind {
+ _ble_decode_bind_encoding=$bleopt_input_encoding
+ local file=$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.bind
+ [[ -s $file && $file -nt $_ble_base/lib/init-bind.sh ]] || source "$_ble_base/lib/init-bind.sh"
+ ble/term/rl-convert-meta/enter
+ source "$file"
+ _ble_decode_bind__uvwflag=
+ ble/util/assign _ble_decode_bind_bindp 'builtin bind -p' # TERM 変更検出用
+}
+function ble/decode/bind/unbind {
+ ble/function#try ble/encoding:"$bleopt_input_encoding"/clear
+ source "$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.unbind"
+}
+function ble/decode/rebind {
+ [[ $_ble_decode_bind_state == none ]] && return 0
+ ble/decode/bind/unbind
+ ble/decode/bind/bind
+}
+function ble-bind/.initialize-kmap {
+ [[ $kmap ]] && return 0
+ ble-decode/GET_BASEMAP -v kmap
+ if ! ble/decode/is-keymap "$kmap"; then
+ ble/util/print "ble-bind: the default keymap '$kmap' is unknown." >&2
+ flags=R$flags
+ return 1
+ fi
+ return 0
+}
+function ble-bind/option:help {
+ ble/util/cat <<EOF
+ble-bind --help
+ble-bind -k [TYPE:]cspecs [[TYPE:]kspec]
+ble-bind --csi PsFt [TYPE:]kspec
+ble-bind [-m keymap] -fxc@s [TYPE:]kspecs command
+ble-bind [-m keymap] -T [TYPE:]kspecs timeout
+ble-bind [-m keymap] --cursor cursor_code
+ble-bind [-m keymap]... (-PD|--print|--dump)
+ble-bind (-L|--list-widgets)
+
+TYPE:SPEC
+ TYPE specifies the format of SPEC. The default is "kspecs".
+
+ kspecs ble.sh keyboard spec
+ keys List of key codes
+ chars List of character codes in Unicode
+ keyseq Key sequence in the Readline format
+ raw Raw byte sequence
+
+TIMEOUT
+ specifies the timeout duration in milliseconds.
+
+CURSOR_CODE
+ specifies the cursor shape by the DECSCUSR code.
+
+EOF
+}
+function ble-bind/check-argument {
+ if (($3<$2)); then
+ flags=E$flags
+ if (($2==1)); then
+ ble/util/print "ble-bind: the option \`$1' requires an argument." >&2
+ else
+ ble/util/print "ble-bind: the option \`$1' requires $2 arguments." >&2
+ fi
+ return 2
+ fi
+}
+function ble-bind/option:csi {
+ local ret key=
+ if [[ $2 ]]; then
+ ble-decode-kbd "$2"
+ ble/string#split-words key "$ret"
+ if ((${#key[@]}!=1)); then
+ ble/util/print "ble-bind --csi: the second argument is not a single key!" >&2
+ return 1
+ elif ((key&~_ble_decode_MaskChar)); then
+ ble/util/print "ble-bind --csi: the second argument should not have modifiers!" >&2
+ return 1
+ fi
+ fi
+ local rex
+ if rex='^([1-9][0-9]*)~$' && [[ $1 =~ $rex ]]; then
+ _ble_decode_csimap_tilde[BASH_REMATCH[1]]=$key
+ local -a cseq
+ cseq=(27 91)
+ local ret i iN num="${BASH_REMATCH[1]}\$"
+ for ((i=0,iN=${#num};i<iN;i++)); do
+ ble/util/s2c "${num:i:1}"
+ ble/array#push cseq "$ret"
+ done
+ local IFS=$_ble_term_IFS
+ if [[ $key ]]; then
+ ble-decode-char/bind "${cseq[*]}" $((key|_ble_decode_Shft))
+ else
+ ble-decode-char/unbind "${cseq[*]}"
+ fi
+ elif [[ $1 == [a-zA-Z] ]]; then
+ local ret; ble/util/s2c "$1"
+ _ble_decode_csimap_alpha[ret]=$key
+ else
+ ble/util/print "ble-bind --csi: not supported type of csi sequences: CSI \`$1'." >&2
+ return 1
+ fi
+}
+function ble-bind/option:list-widgets {
+ declare -f | ble/bin/sed -n 's/^ble\/widget\/\([a-zA-Z][^.[:space:]();&|]\{1,\}\)[[:space:]]*()[[:space:]]*$/\1/p'
+}
+function ble-bind/option:dump {
+ if (($#)); then
+ local keymap
+ for keymap; do
+ ble/decode/keymap#dump "$keymap"
+ done
+ else
+ ble/util/declare-print-definitions "${!_ble_decode_kbd__@}" "${!_ble_decode_cmap_@}" "${!_ble_decode_csimap_@}"
+ ble/decode/keymap#dump
+ fi
+}
+function ble-bind/option:print {
+ local ble_bind_print=1
+ local sgr0= sgrf= sgrq= sgrc= sgro=
+ if [[ $flags == *c* || $flags != *n* && -t 1 ]]; then
+ local ret
+ ble/color/face2sgr command_function; sgrf=$ret
+ ble/color/face2sgr syntax_quoted; sgrq=$ret
+ ble/color/face2sgr syntax_comment; sgrc=$ret
+ ble/color/face2sgr argument_option; sgro=$ret
+ sgr0=$_ble_term_sgr0
+ fi
+ local keymap
+ ble-decode/INITIALIZE_DEFMAP -v keymap # 初期化を強制する
+ if (($#)); then
+ for keymap; do
+ ble/decode/keymap#print "$keymap"
+ done
+ else
+ ble-decode-char/csi/print
+ ble-decode-char/print
+ ble/decode/keymap#print
+ fi
+}
+function ble-bind {
+ local flags= kmap=${ble_bind_keymap-} ret
+ local -a keymaps; keymaps=()
+ ble/decode/initialize
+ local IFS=$_ble_term_IFS q=\' Q="''\'"
+ local arg c
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $arg == --?* ]]; then
+ case "${arg:2}" in
+ (color|color=always)
+ flags=c${flags//[cn]} ;;
+ (color=never)
+ flags=n${flags//[cn]} ;;
+ (color=auto)
+ flags=${flags//[cn]} ;;
+ (help)
+ ble-bind/option:help
+ flags=D$flags ;;
+ (csi)
+ flags=D$flags
+ ble-bind/check-argument --csi 2 $# || break
+ ble-bind/option:csi "$1" "$2"
+ shift 2 ;;
+ (cursor)
+ flags=D$flags
+ ble-bind/check-argument --cursor 1 $# || break
+ ble-bind/.initialize-kmap &&
+ ble/decode/keymap#set-cursor "$kmap" "$1"
+ shift 1 ;;
+ (list-widgets|list-functions)
+ flags=D$flags
+ ble-bind/option:list-widgets ;;
+ (dump)
+ flags=D$flags
+ ble-bind/option:dump "${keymaps[@]}" ;;
+ (print)
+ flags=D$flags
+ ble-bind/option:print "${keymaps[@]}" ;;
+ (*)
+ flags=E$flags
+ ble/util/print "ble-bind: unrecognized long option $arg" >&2 ;;
+ esac
+ elif [[ $arg == -?* ]]; then
+ arg=${arg:1}
+ while ((${#arg})); do
+ c=${arg::1} arg=${arg:1}
+ case $c in
+ (k)
+ flags=D$flags
+ if (($#<2)); then
+ ble/util/print "ble-bind: the option \`-k' requires two arguments." >&2
+ flags=E$flags
+ break
+ fi
+ ble-decode-kbd "$1"; local cseq=$ret
+ if [[ $2 && $2 != - ]]; then
+ ble-decode-kbd "$2"; local kc=$ret
+ ble-decode-char/bind "$cseq" "$kc"
+ else
+ ble-decode-char/unbind "$cseq"
+ fi
+ shift 2 ;;
+ (m)
+ ble-bind/check-argument -m 1 $# || break
+ if ! ble/decode/is-keymap "$1"; then
+ ble/util/print "ble-bind: the keymap '$1' is unknown." >&2
+ flags=E$flags
+ shift
+ continue
+ fi
+ kmap=$1
+ ble/array#push keymaps "$1"
+ shift ;;
+ (D)
+ flags=D$flags
+ ble-bind/option:dump "${keymaps[@]}" ;;
+ ([Pd])
+ flags=D$flags
+ ble-bind/option:print "${keymaps[@]}" ;;
+ (['fxc@s'])
+ flags=D$flags
+ [[ $c != f && $arg == f* ]] && arg=${arg:1}
+ ble-bind/check-argument "-$c" 2 $# || break
+ ble-decode-kbd "$1"; local kbd=$ret
+ if [[ $2 && $2 != - ]]; then
+ local command=$2
+ case $c in
+ (f) command=ble/widget/$command ;; # ble/widget/ 関数
+ (x) command="ble/widget/.EDIT_COMMAND '${command//$q/$Q}'" ;; # 編集用の関数
+ (c) command="ble/widget/.SHELL_COMMAND '${command//$q/$Q}'" ;; # コマンド実行
+ (s) local ret; ble/util/keyseq2chars "$command"; command="ble/widget/.MACRO ${ret[*]}" ;;
+ ('@') ;; # 直接実行
+ (*)
+ ble/util/print "error: unsupported binding type \`-$c'." 1>&2
+ continue ;;
+ esac
+ ble-bind/.initialize-kmap &&
+ ble-decode-key/bind "$kmap" "$kbd" "$command"
+ else
+ ble-bind/.initialize-kmap &&
+ ble-decode-key/unbind "$kmap" "$kbd"
+ fi
+ shift 2 ;;
+ (T)
+ flags=D$flags
+ ble-decode-kbd "$1"; local kbd=$ret
+ ble-bind/check-argument -T 2 $# || break
+ ble-bind/.initialize-kmap &&
+ ble-decode-key/set-timeout "$kmap" "$kbd" "$2"
+ shift 2 ;;
+ (L)
+ flags=D$flags
+ ble-bind/option:list-widgets ;;
+ (*)
+ ble/util/print "ble-bind: unrecognized short option \`-$c'." >&2
+ flags=E$flags ;;
+ esac
+ done
+ else
+ ble/util/print "ble-bind: unrecognized argument \`$arg'." >&2
+ flags=E$flags
+ fi
+ done
+ [[ $flags == *E* ]] && return 2
+ [[ $flags == *R* ]] && return 1
+ [[ $flags == *D* ]] || ble-bind/option:print "${keymaps[@]}"
+ return 0
+}
+function ble/decode/read-inputrc/test {
+ local text=$1
+ if [[ ! $text ]]; then
+ ble/util/print "ble.sh (bind):\$if: test condition is not supplied." >&2
+ return 1
+ elif local rex=$'[ \t]*([<>]=?|[=!]?=)[ \t]*(.*)$'; [[ $text =~ $rex ]]; then
+ local op=${BASH_REMATCH[1]}
+ local rhs=${BASH_REMATCH[2]}
+ local lhs=${text::${#text}-${#BASH_REMATCH}}
+ else
+ local lhs=application
+ local rhs=$text
+ fi
+ case $lhs in
+ (application)
+ local ret; ble/string#tolower "$rhs"
+ [[ $ret == bash || $ret == blesh ]]
+ return "$?" ;;
+ (mode)
+ if [[ -o emacs ]]; then
+ test emacs "$op" "$rhs"
+ elif [[ -o vi ]]; then
+ test vi "$op" "$rhs"
+ else
+ false
+ fi
+ return "$?" ;;
+ (term)
+ if [[ $op == '!=' ]]; then
+ test "$TERM" "$op" "$rhs" && test "${TERM%%-*}" "$op" "$rhs"
+ else
+ test "$TERM" "$op" "$rhs" || test "${TERM%%-*}" "$op" "$rhs"
+ fi
+ return "$?" ;;
+ (version)
+ local lhs_major lhs_minor
+ if ((_ble_bash<40400)); then
+ ((lhs_major=2+_ble_bash/10000,
+ lhs_minor=_ble_bash/100%100))
+ elif ((_ble_bash<50000)); then
+ ((lhs_major=7,lhs_minor=0))
+ else
+ ((lhs_major=3+_ble_bash/10000,
+ lhs_minor=_ble_bash/100%100))
+ fi
+ local rhs_major rhs_minor
+ if [[ $rhs == *.* ]]; then
+ local version
+ ble/string#split version . "$rhs"
+ rhs_major=${version[0]}
+ rhs_minor=${version[1]}
+ else
+ ((rhs_major=rhs,rhs_minor=0))
+ fi
+ local lhs_ver=$((lhs_major*10000+lhs_minor))
+ local rhs_ver=$((rhs_major*10000+rhs_minor))
+ [[ $op == '=' ]] && op='=='
+ let "$lhs_ver$op$rhs_ver"
+ return "$?" ;;
+ (*)
+ if local ret; ble/util/read-rl-variable "$lhs"; then
+ test "$ret" "$op" "$rhs"
+ return "$?"
+ else
+ ble/util/print "ble.sh (bind):\$if: unknown readline variable '${lhs//$q/$Q}'." >&2
+ return 1
+ fi ;;
+ esac
+}
+function ble/decode/read-inputrc {
+ local file=$1 ref=$2 q=\' Q="''\'"
+ if [[ -f $ref && $ref == */* && $file != /* ]]; then
+ local relative_file=${ref%/*}/$file
+ [[ -f $relative_file ]] && file=$relative_file
+ fi
+ if [[ ! -f $file ]]; then
+ ble/util/print "ble.sh (bind):\$include: the file '${1//$q/$Q}' not found." >&2
+ return 1
+ fi
+ local -a script=()
+ local ret line= iline=0 TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ while builtin read "${_ble_bash_tmout_wa[@]}" -r line || [[ $line ]]; do
+ ((++iline))
+ ble/string#trim "$line"; line=$ret
+ [[ ! $line || $line == '#'* ]] && continue
+ if [[ $line == '$'* ]]; then
+ local directive=${line%%[$IFS]*}
+ case $directive in
+ ('$if')
+ local args=${line#'$if'}
+ ble/string#trim "$args"; args=$ret
+ ble/array#push script "if ble/decode/read-inputrc/test '${args//$q/$Q}'; then :" ;;
+ ('$else') ble/array#push script 'else :' ;;
+ ('$endif') ble/array#push script 'fi' ;;
+ ('$include')
+ local args=${line#'$include'}
+ ble/string#trim "$args"; args=$ret
+ ble/array#push script "ble/decode/read-inputrc '${args//$q/$Q}' '${file//$q/$Q}'" ;;
+ (*)
+ ble/util/print "ble.sh (bind):$file:$iline: unrecognized directive '$directive'." >&2 ;;
+ esac
+ else
+ ble/array#push script "ble/builtin/bind/.process -- '${line//$q/$Q}'"
+ fi
+ done < "$file"
+ IFS=$'\n' builtin eval 'script="${script[*]}"'
+ builtin eval -- "$script"
+}
+_ble_builtin_bind_keymap=
+function ble/builtin/bind/set-keymap {
+ local opt_keymap= flags=
+ ble/builtin/bind/option:m "$1" &&
+ _ble_builtin_bind_keymap=$opt_keymap
+ return 0
+}
+function ble/builtin/bind/option:m {
+ local name=$1
+ local ret; ble/string#tolower "$name"; local keymap=$ret
+ case $keymap in
+ (emacs|emacs-standard|emacs-meta|emacs-ctlx) ;;
+ (vi|vi-command|vi-move|vi-insert) ;;
+ (*) keymap= ;;
+ esac
+ if [[ ! $keymap ]]; then
+ ble/util/print "ble.sh (bind): unrecognized keymap name '$name'" >&2
+ flags=e$flags
+ return 1
+ else
+ opt_keymap=$keymap
+ return 0
+ fi
+}
+function ble/builtin/bind/.decompose-pair {
+ local LC_ALL= LC_CTYPE=C
+ local ret; ble/string#trim "$1"
+ local spec=$ret ifs=$_ble_term_IFS q=\' Q="'\''"
+ keyseq= value=
+ [[ ! $spec || $spec == 'set'["$ifs"]* ]] && return 3
+ local rex='^(("([^\"]|\\.)*"|[^":'$ifs'])*("([^\"]|\\.)*)?)['$ifs']*(:['$ifs']*)?'
+ [[ $spec =~ $rex ]]
+ keyseq=${BASH_REMATCH[1]} value=${spec:${#BASH_REMATCH}}
+ if [[ $keyseq == '$'* ]]; then
+ return 3
+ elif [[ ! $keyseq ]]; then
+ ble/util/print "ble.sh (bind): empty keyseq in spec:'${spec//$q/$Q}'" >&2
+ flags=e$flags
+ return 1
+ elif rex='^"([^\"]|\\.)*$'; [[ $keyseq =~ $rex ]]; then
+ ble/util/print "ble.sh (bind): no closing '\"' in keyseq:'${keyseq//$q/$Q}'" >&2
+ flags=e$flags
+ return 1
+ elif rex='^"([^\"]|\\.)*"'; [[ $keyseq =~ $rex ]]; then
+ local rematch=${BASH_REMATCH[0]}
+ if ((${#rematch}<${#keyseq})); then
+ local fragment=${keyseq:${#rematch}}
+ ble/util/print "ble.sh (bind): warning: unprocessed fragments in keyseq '${fragment//$q/$Q}'" >&2
+ fi
+ keyseq=$rematch
+ return 0
+ else
+ return 0
+ fi
+}
+ble/function#suppress-stderr ble/builtin/bind/.decompose-pair
+function ble/builtin/bind/.parse-keyname {
+ local ret mflags=
+ ble/string#tolower "$1"; local lower=$ret
+ if [[ $1 == *-* ]]; then
+ ble/string#split ret - "$lower"
+ local mod
+ for mod in "${ret[@]::${#ret[@]}-1}"; do
+ case $mod in
+ (*m|*meta) mflags=m$mflags ;;
+ (*c|*ctrl|*control) mflags=c$mflags ;;
+ esac
+ done
+ fi
+ local name=${lower##*-} ch=
+ case $name in
+ (rubout|del) ch=$'\177' ;;
+ (escape|esc) ch=$'\033' ;;
+ (newline|lfd) ch=$'\n' ;;
+ (return|ret) ch=$'\r' ;;
+ (space|spc) ch=' ' ;;
+ (tab) ch=$'\t' ;;
+ (*) ble/util/substr "${1##*-}" 0 1; ch=$ret ;;
+ esac
+ ble/util/s2c "$ch"; local key=$ret
+ [[ $mflags == *c* ]] && ((key&=0x1F))
+ [[ $mflags == *m* ]] && ((key|=0x80))
+ chars=("$key")
+}
+function ble/builtin/bind/.initialize-kmap {
+ local keymap=$1
+ kmap=
+ case $keymap in
+ (emacs|emacs-standard) kmap=emacs ;;
+ (emacs-ctlx) kmap=emacs; keys=(24 "${keys[@]}") ;;
+ (emacs-meta) kmap=emacs; keys=(27 "${keys[@]}") ;;
+ (vi-insert) kmap=vi_imap ;;
+ (vi|vi-command|vi-move) kmap=vi_nmap ;;
+ (*) ble-decode/GET_BASEMAP -v kmap ;;
+ esac
+ if ! ble/decode/is-keymap "$kmap"; then
+ ble/util/print "ble/builtin/bind: the keymap '$kmap' is unknown." >&2
+ return 1
+ fi
+ return 0
+}
+function ble/builtin/bind/.initialize-keys-and-value {
+ local spec=$1 opts=$2
+ keys= value=
+ local keyseq
+ ble/builtin/bind/.decompose-pair "$spec" || return "$?"
+ local chars
+ if [[ $keyseq == \"*\" ]]; then
+ local ret; ble/util/keyseq2chars "${keyseq:1:${#keyseq}-2}"
+ chars=("${ret[@]}")
+ ((${#chars[@]})) || ble/util/print "ble.sh (bind): warning: empty keyseq" >&2
+ else
+ [[ :$opts: == *:nokeyname:* ]] &&
+ ble/util/print "ble.sh (bind): warning: readline \"bind -x\" does not support \"keyname\" spec" >&2
+ ble/builtin/bind/.parse-keyname "$keyseq"
+ fi
+ ble/decode/cmap/decode-chars "${chars[@]}"
+}
+function ble/builtin/bind/option:x {
+ local q=\' Q="''\'"
+ local keys value kmap
+ if ! ble/builtin/bind/.initialize-keys-and-value "$1" nokeyname; then
+ ble/util/print "ble.sh (bind): unrecognized readline command '${1//$q/$Q}'." >&2
+ flags=e$flags
+ return 1
+ elif ! ble/builtin/bind/.initialize-kmap "$opt_keymap"; then
+ ble/util/print "ble.sh (bind): sorry, failed to initialize keymap:'$opt_keymap'." >&2
+ flags=e$flags
+ return 1
+ fi
+ if [[ $value == \"* ]]; then
+ local ifs=$_ble_term_IFS
+ local rex='^"(([^\"]|\\.)*)"'
+ if ! [[ $value =~ $rex ]]; then
+ ble/util/print "ble.sh (bind): no closing '\"' in spec:'${1//$q/$Q}'" >&2
+ flags=e$flags
+ return 1
+ fi
+ if ((${#BASH_REMATCH}<${#value})); then
+ local fragment=${value:${#BASH_REMATCH}}
+ ble/util/print "ble.sh (bind): warning: unprocessed fragments:'${fragment//$q/$Q}' in spec:'${1//$q/$Q}'" >&2
+ fi
+ value=${BASH_REMATCH[1]}
+ fi
+ [[ $value == \"*\" ]] && value=${value:1:${#value}-2}
+ local command="ble/widget/.EDIT_COMMAND '${value//$q/$Q}'"
+ ble-decode-key/bind "$kmap" "${keys[*]}" "$command"
+}
+function ble/builtin/bind/option:r {
+ local keyseq=$1
+ local ret chars keys
+ ble/util/keyseq2chars "$keyseq"; chars=("${ret[@]}")
+ ble/decode/cmap/decode-chars "${chars[@]}"
+ local kmap
+ ble/builtin/bind/.initialize-kmap "$opt_keymap" || return 1
+ ble-decode-key/unbind "$kmap" "${keys[*]}"
+}
+_ble_decode_rlfunc2widget_emacs=()
+_ble_decode_rlfunc2widget_vi_imap=()
+_ble_decode_rlfunc2widget_vi_nmap=()
+function ble/builtin/bind/rlfunc2widget {
+ local kmap=$1 rlfunc=$2
+ local IFS=$_ble_term_IFS
+ local rlfunc_file= rlfunc_dict=
+ case $kmap in
+ (emacs) rlfunc_file=$_ble_base/lib/core-decode.emacs-rlfunc.txt
+ rlfunc_dict=_ble_decode_rlfunc2widget_emacs ;;
+ (vi_imap) rlfunc_file=$_ble_base/lib/core-decode.vi_imap-rlfunc.txt
+ rlfunc_dict=_ble_decode_rlfunc2widget_vi_imap ;;
+ (vi_nmap) rlfunc_file=$_ble_base/lib/core-decode.vi_nmap-rlfunc.txt
+ rlfunc_dict=_ble_decode_rlfunc2widget_vi_nmap ;;
+ esac
+ if [[ $rlfunc_file ]]; then
+ local dict script='
+ ((${#DICT[@]})) ||
+ ble/util/mapfile DICT < "$rlfunc_file"
+ dict=("${DICT[@]}")'
+ builtin eval -- "${script//DICT/$rlfunc_dict}"
+ local line TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ for line in "${dict[@]}"; do
+ [[ $line == "$rlfunc "* ]] || continue
+ local rl widget; builtin read "${_ble_bash_tmout_wa[@]}" -r rl widget <<< "$line"
+ if [[ $widget == - ]]; then
+ ble/util/print "ble.sh (bind): unsupported readline function '${rlfunc//$q/$Q}' for keymap '$kmap'." >&2
+ return 1
+ elif [[ $widget == '<IGNORE>' ]]; then
+ return 2
+ fi
+ ret=ble/widget/$widget
+ return 0
+ done
+ fi
+ if ble/is-function ble/widget/"${rlfunc%%[$IFS]*}"; then
+ ret=ble/widget/$rlfunc
+ return 0
+ fi
+ ble/util/print "ble.sh (bind): unsupported readline function '${rlfunc//$q/$Q}'." >&2
+ return 1
+}
+function ble/builtin/bind/option:u {
+ local rlfunc=$1
+ local kmap
+ if ! ble/builtin/bind/.initialize-kmap "$opt_keymap" || ! ble/decode/keymap#load "$kmap"; then
+ ble/util/print "ble.sh (bind): sorry, failed to initialize keymap:'$opt_keymap'." >&2
+ flags=e$flags
+ return 1
+ fi
+ local ret
+ ble/builtin/bind/rlfunc2widget "$kmap" "$rlfunc" || return 0
+ local command=$ret
+ local -a unbind_keys_list=()
+ ble/builtin/bind/option:u/search-recursive "$kmap"
+ local keys
+ for keys in "${unbind_keys_list[@]}"; do
+ ble-decode-key/unbind "$kmap" "$keys"
+ done
+}
+function ble/builtin/bind/option:u/search-recursive {
+ local kmap=$1 tseq=$2
+ local dicthead=_ble_decode_${kmap}_kmap_
+ local key keys
+ builtin eval "keys=(\${!$dicthead$tseq[@]})"
+ for key in "${keys[@]}"; do
+ builtin eval "local ent=\${$dicthead$tseq[key]}"
+ if [[ ${ent:2} == "$command" ]]; then
+ ble/array#push unbind_keys_list "${tseq//_/ } $key"
+ fi
+ if [[ ${ent::1} == _ ]]; then
+ ble/builtin/bind/option:u/search-recursive "$kmap" "${tseq}_$key"
+ fi
+ done
+}
+function ble/builtin/bind/option:- {
+ local ret; ble/string#trim "$1"; local arg=$ret
+ local q=\' ifs=$_ble_term_IFS
+ local rex='^(([^\"'$q$ifs']|"([^\"]|\\.)*"|'$q'([^\'$q']|\\.)*'$q'|\\.|['$ifs']+[^#'$_ifs'])*)['$ifs']+#'
+ [[ $arg =~ $rex ]] && arg=${BASH_REMATCH[1]}
+ local ifs=$_ble_term_IFS
+ if [[ $arg == 'set'["$ifs"]* ]]; then
+ if [[ $_ble_decode_bind_state != none ]]; then
+ local variable= value= rex=$'^set[ \t]+([^ \t]+)[ \t]+([^ \t].*)$'
+ [[ $arg =~ $rex ]] && variable=${BASH_REMATCH[1]} value=${BASH_REMATCH[2]}
+ case $variable in
+ (keymap)
+ ble/builtin/bind/set-keymap "$value"
+ return 0 ;;
+ (editing-mode)
+ _ble_builtin_bind_keymap= ;;
+ esac
+ builtin bind "$arg"
+ fi
+ return 0
+ fi
+ local keys value kmap
+ if ! ble/builtin/bind/.initialize-keys-and-value "$arg"; then
+ local q=\' Q="''\'"
+ ble/util/print "ble.sh (bind): unrecognized readline command '${arg//$q/$Q}'." >&2
+ flags=e$flags
+ return 1
+ elif ! ble/builtin/bind/.initialize-kmap "$opt_keymap"; then
+ ble/util/print "ble.sh (bind): sorry, failed to initialize keymap:'$opt_keymap'." >&2
+ flags=e$flags
+ return 1
+ fi
+ if [[ $value == \"* ]]; then
+ local bind_keys="${keys[*]}"
+ value=${value#\"} value=${value%\"}
+ local ret chars; ble/util/keyseq2chars "$value"; chars=("${ret[@]}")
+ local command="ble/widget/.MACRO ${chars[*]}"
+ ble/decode/cmap/decode-chars "${chars[@]}"
+ [[ ${keys[*]} != "$bind_keys" ]] &&
+ ble-decode-key/bind "$kmap" "$bind_keys" "$command"
+ elif [[ $value ]]; then
+ local ret; ble/builtin/bind/rlfunc2widget "$kmap" "$value"; local ext=$?
+ if ((ext==0)); then
+ local command=$ret
+ ble-decode-key/bind "$kmap" "${keys[*]}" "$command"
+ return 0
+ elif ((ext==2)); then
+ return 0
+ else
+ flags=e$flags
+ return 1
+ fi
+ else
+ ble/util/print "ble.sh (bind): readline function name is not specified ($arg)." >&2
+ return 1
+ fi
+}
+function ble/builtin/bind/.process {
+ flags=
+ local IFS=$_ble_term_IFS
+ local opt_literal= opt_keymap=$_ble_builtin_bind_keymap opt_print=
+ local -a opt_queries=()
+ while (($#)); do
+ local arg=$1; shift
+ if [[ ! $opt_literal ]]; then
+ case $arg in
+ (--) opt_literal=1
+ continue ;;
+ (--help)
+ if ((_ble_bash<40400)); then
+ ble/util/print "ble.sh (bind): unrecognized option $arg" >&2
+ flags=e$flags
+ else
+ [[ $_ble_decode_bind_state != none ]] &&
+ (builtin bind --help)
+ flags=h$flags
+ fi
+ continue ;;
+ (--*)
+ ble/util/print "ble.sh (bind): unrecognized option $arg" >&2
+ flags=e$flags
+ continue ;;
+ (-*)
+ local i n=${#arg} c
+ for ((i=1;i<n;i++)); do
+ c=${arg:i:1}
+ case $c in
+ ([lpPsSvVX])
+ opt_print=$opt_print$c ;;
+ ([mqurfx])
+ if ((!$#)); then
+ ble/util/print "ble.sh (bind): missing option argument for -$c" >&2
+ flags=e$flags
+ else
+ local optarg=$1; shift
+ case $c in
+ (m) ble/builtin/bind/option:m "$optarg" ;;
+ (x) ble/builtin/bind/option:x "$optarg" ;;
+ (r) ble/builtin/bind/option:r "$optarg" ;;
+ (u) ble/builtin/bind/option:u "$optarg" ;;
+ (q) ble/array#push opt_queries "$optarg" ;;
+ (f) ble/decode/read-inputrc "$optarg" ;;
+ (*)
+ ble/util/print "ble.sh (bind): unsupported option -$c $optarg" >&2
+ flags=e$flags ;;
+ esac
+ fi ;;
+ (*)
+ ble/util/print "ble.sh (bind): unrecognized option -$c" >&2
+ flags=e$flags ;;
+ esac
+ done
+ continue ;;
+ esac
+ fi
+ ble/builtin/bind/option:- "$arg"
+ opt_literal=1
+ done
+ if [[ $_ble_decode_bind_state != none ]]; then
+ if [[ $opt_print == *[pPsSX]* ]] || ((${#opt_queries[@]})); then
+ ( ble/decode/bind/unbind
+ [[ -s "$_ble_base_run/$$.bind.save" ]] &&
+ source "$_ble_base_run/$$.bind.save"
+ [[ $opt_print ]] &&
+ builtin bind ${opt_keymap:+-m $opt_keymap} -$opt_print
+ declare rlfunc
+ for rlfunc in "${opt_queries[@]}"; do
+ builtin bind ${opt_keymap:+-m $opt_keymap} -q "$rlfunc"
+ done )
+ elif [[ $opt_print ]]; then
+ builtin bind ${opt_keymap:+-m $opt_keymap} -$opt_print
+ fi
+ fi
+ return 0
+}
+_ble_builtin_bind_inputrc_done=
+function ble/builtin/bind/initialize-inputrc {
+ [[ $_ble_builtin_bind_inputrc_done ]] && return 0
+ _ble_builtin_bind_inputrc_done=1
+ local inputrc=${INPUTRC:-$HOME/.inputrc}
+ [[ -e $inputrc ]] && ble/decode/read-inputrc "$inputrc"
+}
+_ble_builtin_bind_user_settings_loaded=
+function ble/builtin/bind/read-user-settings/.collect {
+ local map
+ for map in vi-insert vi-command emacs; do
+ local cache=$_ble_base_cache/decode.readline.$_ble_bash.$map.txt
+ if ! [[ -s $cache && $cache -nt $_ble_base/ble.sh ]]; then
+ INPUTRC=/dev/null "$BASH" --noprofile --norc -i -c "builtin bind -m $map -p" |
+ LC_ALL= LC_CTYPE=C ble/bin/sed '/^#/d;s/"\\M-/"\\e/' >| "$cache.part" &&
+ ble/bin/mv "$cache.part" "$cache" || continue
+ fi
+ local cache_content
+ ble/util/readfile cache_content "$cache"
+ ble/util/print __CLEAR__
+ ble/util/print KEYMAP="$map"
+ ble/util/print __BIND0__
+ ble/util/print "${cache_content%$_ble_term_nl}"
+ if ((_ble_bash>=40300)); then
+ ble/util/print __BINDX__
+ builtin bind -m "$map" -X
+ fi
+ ble/util/print __BINDS__
+ builtin bind -m "$map" -s
+ ble/util/print __BINDP__
+ builtin bind -m "$map" -p
+ ble/util/print __PRINT__
+ done
+}
+function ble/builtin/bind/read-user-settings/.reconstruct {
+ local collect q=\'
+ ble/util/assign collect ble/builtin/bind/read-user-settings/.collect
+ <<< "$collect" LC_ALL= LC_CTYPE=C ble/bin/awk -v q="$q" -v _ble_bash="$_ble_bash" '
+ function keymap_register(key, val, type) {
+ if (!haskey[key]) {
+ keys[nkey++] = key;
+ haskey[key] = 1;
+ }
+ keymap[key] = val;
+ keymap_type[key] = type;
+ }
+ function keymap_clear(_, i, key) {
+ for(i = 0; i < nkey; i++) {
+ key = keys[i];
+ delete keymap[key];
+ delete keymap_type[key];
+ delete keymap0[key];
+ haskey[key] = 0;
+ }
+ nkey = 0;
+ }
+ function keymap_print(_, i, key, type, value, text, line) {
+ for (i = 0; i < nkey; i++) {
+ key = keys[i];
+ type = keymap_type[key];
+ value = keymap[key];
+ if (type == "" && value == keymap0[key]) continue;
+ text = key ": " value;
+ gsub(/'$q'/, q "\\" q q, text);
+ line = "bind";
+ if (KEYMAP != "") line = line " -m " KEYMAP;
+ if (type == "x") line = line " -x";
+ line = line " " q text q;
+ print line;
+ }
+ }
+ /^__BIND0__$/ { mode = 0; next; }
+ /^__BINDX__$/ { mode = 1; next; }
+ /^__BINDS__$/ { mode = 2; next; }
+ /^__BINDP__$/ { mode = 3; next; }
+ /^__CLEAR__$/ { keymap_clear(); next; }
+ /^__PRINT__$/ { keymap_print(); next; }
+ sub(/^KEYMAP=/, "") { KEYMAP = $0; }
+ /ble-decode\/.hook / { next; }
+ function workaround_bashbug(keyseq, _, rex, out, unit) {
+ out = "";
+ while (keyseq != "") {
+ if (mode == 0 || mode == 3) {
+ match(keyseq, /^\\C-\\(\\"$)?|^\\M-|^\\.|^./);
+ } else {
+ match(keyseq, /^\\[CM]-|^\\.|^./);
+ }
+ unit = substr(keyseq, 1, RLENGTH);
+ keyseq = substr(keyseq, 1 + RLENGTH);
+ if (unit == "\\C-\\") {
+ unit = unit "\\";
+ } else if (unit == "\\M-") {
+ unit = "\\e";
+ }
+ out = out unit;
+ }
+ return out;
+ }
+ match($0, /^"(\\.|[^"])+": /) {
+ key = substr($0, 1, RLENGTH - 2);
+ val = substr($0, 1 + RLENGTH);
+ if (_ble_bash < 50100)
+ key = workaround_bashbug(key);
+ if (mode) {
+ type = mode == 1 ? "x" : mode == 2 ? "s" : "";
+ keymap_register(key, val, type);
+ } else {
+ keymap0[key] = val;
+ }
+ }
+ ' 2>/dev/null # suppress LC_ALL error messages
+}
+function ble/builtin/bind/read-user-settings/.cache-enabled {
+ local keymap use_cache=1
+ for keymap in emacs vi_imap vi_nmap; do
+ ble/decode/keymap#registered "$keymap" && return 1
+ [[ -s $delay_prefix.$keymap ]] && return 1
+ done
+ return 0
+}
+function ble/builtin/bind/read-user-settings/.cache-alive {
+ [[ -e $cache_prefix.settings ]] || return 1
+ [[ $cache_prefix.settings -nt $_ble_base/lib/init-cmap.sh ]] || return 1
+ local keymap
+ for keymap in emacs vi_imap vi_nmap; do
+ [[ $cache_prefix.settings -nt $_ble_base/core-decode.$cache-rlfunc.txt ]] || return 1
+ [[ -e $cache_prefix.$keymap ]] || return 1
+ done
+ local content
+ ble/util/readfile content "$cache_prefix.settings"
+ [[ ${content%$'\n'} == "$settings" ]]
+}
+function ble/builtin/bind/read-user-settings/.cache-save {
+ local keymap content fail=
+ for keymap in emacs vi_imap vi_nmap; do
+ if [[ -s $delay_prefix.$keymap ]]; then
+ ble/util/copyfile "$delay_prefix.$keymap" "$cache_prefix.$keymap"
+ else
+ : >| "$cache_prefix.$keymap"
+ fi || fail=1
+ done
+ [[ $fail ]] && return 1
+ ble/util/print "$settings" >| "$cache_prefix.settings"
+}
+function ble/builtin/bind/read-user-settings/.cache-load {
+ local keymap
+ for keymap in emacs vi_imap vi_nmap; do
+ ble/util/copyfile "$cache_prefix.$keymap" "$delay_prefix.$keymap"
+ done
+}
+function ble/builtin/bind/read-user-settings {
+ if [[ $_ble_decode_bind_state == none ]]; then
+ [[ $_ble_builtin_bind_user_settings_loaded ]] && return 0
+ _ble_builtin_bind_user_settings_loaded=1
+ builtin bind # inputrc を読ませる
+ local settings
+ ble/util/assign settings ble/builtin/bind/read-user-settings/.reconstruct
+ [[ $settings ]] || return 0
+ local cache_prefix=$_ble_base_cache/decode.inputrc.$_ble_decode_kbd_ver.$TERM
+ local delay_prefix=$_ble_base_run/$$.bind.delay
+ if ble/builtin/bind/read-user-settings/.cache-enabled; then
+ if ble/builtin/bind/read-user-settings/.cache-alive; then
+ ble/builtin/bind/read-user-settings/.cache-load
+ else
+ builtin eval -- "$settings"
+ ble/builtin/bind/read-user-settings/.cache-save
+ fi
+ else
+ builtin eval -- "$settings"
+ fi
+ fi
+}
+function ble/builtin/bind {
+ local set shopt; ble/base/.adjust-bash-options set shopt
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/adjust-BASH_REMATCH
+ ble/decode/initialize
+ local flags= ext=0
+ ble/builtin/bind/.process "$@"
+ if [[ $_ble_decode_bind_state == none ]]; then
+ builtin bind "$@"; ext=$?
+ elif [[ $flags == *[eh]* ]]; then
+ [[ $flags == *e* ]] &&
+ builtin bind --usage 2>&1 1>/dev/null | ble/bin/grep ^bind >&2
+ ext=2
+ fi
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/restore-BASH_REMATCH
+ ble/base/.restore-bash-options set shopt
+ return "$ext"
+}
+function bind { ble/builtin/bind "$@"; }
+function ble/decode/initialize/.has-broken-suse-inputrc {
+ ((_ble_bash<50000)) || return 1 # Bash 5.0+ are not suffered
+ [[ -s /etc/inputrc.keys ]] || return 1
+ local content
+ ble/util/readfile content /etc/inputrc.keys
+ [[ $content == *'"\M-[2~":'* ]]
+}
+_ble_decode_initialized=
+function ble/decode/initialize {
+ [[ $_ble_decode_initialized ]] && return 0
+ _ble_decode_initialized=1
+ ble/decode/cmap/initialize
+ if ble/decode/initialize/.has-broken-suse-inputrc; then
+ [[ ${INPUTRC-} == /etc/inputrc || ${INPUTRC-} == /etc/inputrc.keys ]] &&
+ local INPUTRC=~/.inputrc
+ ble/builtin/bind/initialize-inputrc
+ else
+ ble/builtin/bind/read-user-settings
+ fi
+}
+function ble/decode/reset-default-keymap {
+ local old_base_keymap=${_ble_decode_keymap_stack[0]:-$_ble_decode_keymap}
+ ble-decode/INITIALIZE_DEFMAP -v _ble_decode_keymap # 0ms
+ _ble_decode_keymap_stack=()
+ if [[ $_ble_decode_keymap != "$old_base_keymap" ]]; then
+ [[ $old_base_keymap ]] &&
+ _ble_decode_keymap=$old_base_keymap ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_DETACH"
+ ble-decode/widget/.invoke-hook "$_ble_decode_KCODE_ATTACH" # 7ms for vi-mode
+ fi
+}
+function ble/decode/attach {
+ if ble/decode/keymap#is-empty "$_ble_decode_keymap"; then
+ ble/util/print "ble.sh: The keymap '$_ble_decode_keymap' is empty." >&2
+ return 1
+ fi
+ [[ $_ble_decode_bind_state != none ]] && return 0
+ ble/util/save-editing-mode _ble_decode_bind_state
+ [[ $_ble_decode_bind_state == none ]] && return 1
+ ble/term/initialize # 3ms
+ ble/util/reset-keymap-of-editing-mode
+ builtin eval -- "$(ble/decode/bind/.generate-source-to-unbind-default)" # 21ms
+ ble/decode/bind/bind # 20ms
+ case $TERM in
+ (linux)
+ _ble_term_TERM=linux:- ;;
+ (st|st-*)
+ _ble_term_TERM=st:- ;;
+ (*)
+ ble/util/buffer $'\e[>c' # DA2 要求 (ble-decode-char/csi/.decode で受信)
+ esac
+ return 0
+}
+function ble/decode/detach {
+ [[ $_ble_decode_bind_state != none ]] || return 1
+ local current_editing_mode=
+ ble/util/save-editing-mode current_editing_mode
+ [[ $_ble_decode_bind_state == "$current_editing_mode" ]] || ble/util/restore-editing-mode _ble_decode_bind_state
+ ble/term/finalize
+ ble/decode/bind/unbind
+ if [[ -s "$_ble_base_run/$$.bind.save" ]]; then
+ source "$_ble_base_run/$$.bind.save"
+ : >| "$_ble_base_run/$$.bind.save"
+ fi
+ [[ $_ble_decode_bind_state == "$current_editing_mode" ]] || ble/util/restore-editing-mode current_editing_mode
+ _ble_decode_bind_state=none
+}
+function ble/encoding:UTF-8/generate-binder { :; }
+_ble_encoding_utf8_decode_mode=0
+_ble_encoding_utf8_decode_code=0
+_ble_encoding_utf8_decode_table=(
+ 'M&&E,A[i++]='{0..127}
+ 'C=C<<6|'{0..63}',--M==0&&(A[i++]=C)'
+ 'M&&E,C='{0..31}',M=1'
+ 'M&&E,C='{0..15}',M=2'
+ 'M&&E,C='{0..7}',M=3'
+ 'M&&E,C='{0..3}',M=4'
+ 'M&&E,C='{0..1}',M=5'
+ 'M&&E,A[i++]=_ble_decode_Erro|'{254,255}
+)
+function ble/encoding:UTF-8/clear {
+ _ble_encoding_utf8_decode_mode=0
+ _ble_encoding_utf8_decode_code=0
+}
+function ble/encoding:UTF-8/is-intermediate {
+ ((_ble_encoding_utf8_decode_mode))
+}
+function ble/encoding:UTF-8/decode {
+ local C=$_ble_encoding_utf8_decode_code
+ local M=$_ble_encoding_utf8_decode_mode
+ local E='M=0,A[i++]=_ble_decode_Erro|C'
+ local -a A=()
+ local i=0 b
+ for b; do
+ ((_ble_encoding_utf8_decode_table[b&255]))
+ done
+ _ble_encoding_utf8_decode_code=$C
+ _ble_encoding_utf8_decode_mode=$M
+ ((i)) && ble-decode-char "${A[@]}"
+}
+function ble/encoding:UTF-8/c2bc {
+ local code=$1
+ ((ret=code<0x80?1:
+ (code<0x800?2:
+ (code<0x10000?3:
+ (code<0x200000?4:5)))))
+}
+function ble/encoding:C/generate-binder {
+ ble/init:bind/bind-s '"\C-@":"\x9B\x80"'
+ ble/init:bind/bind-s '"\e":"\x9B\x8B"' # isolated ESC (U+07FF)
+ local i ret
+ for i in {0..255}; do
+ ble/decode/c2dqs "$i"
+ ble/init:bind/bind-s "\"\e$ret\": \"\x9B\x9B$ret\""
+ done
+}
+_ble_encoding_c_csi=
+function ble/encoding:C/clear {
+ _ble_encoding_c_csi=
+}
+function ble/encoding:C/is-intermediate {
+ [[ $_ble_encoding_c_csi ]]
+}
+function ble/encoding:C/decode {
+ local -a A=()
+ local i=0 b
+ for b; do
+ if [[ $_ble_encoding_c_csi ]]; then
+ _ble_encoding_c_csi=
+ case $b in
+ (155) A[i++]=27 # ESC
+ continue ;;
+ (139) A[i++]=2047 # isolated ESC
+ continue ;;
+ (128) A[i++]=0 # C-@
+ continue ;;
+ esac
+ A[i++]=155
+ fi
+ if ((b==155)); then
+ _ble_encoding_c_csi=1
+ else
+ A[i++]=$b
+ fi
+ done
+ ((i)) && ble-decode-char "${A[@]}"
+}
+function ble/encoding:C/c2bc {
+ ret=1
+}
+_ble_color_gflags_Bold=0x01
+_ble_color_gflags_Italic=0x02
+_ble_color_gflags_Underline=0x04
+_ble_color_gflags_Revert=0x08
+_ble_color_gflags_Invisible=0x10
+_ble_color_gflags_Strike=0x20
+_ble_color_gflags_Blink=0x40
+_ble_color_gflags_DecorationMask=0x77
+_ble_color_gflags_FgMask=0x00000000FFFFFF00
+_ble_color_gflags_BgMask=0x00FFFFFF00000000
+_ble_color_gflags_FgIndexed=0x0100000000000000
+_ble_color_gflags_BgIndexed=0x0200000000000000
+function ble/color/define-options {
+ local ncolor=0
+ if [[ $TERM == xterm* || $TERM == *-256color || $TERM == kterm* ]]; then
+ ncolor=256
+ elif [[ $TERM == *-88color ]]; then
+ ncolor=88
+ fi
+ bleopt/declare -v term_true_colors semicolon
+ bleopt/declare -v term_index_colors "$ncolor"
+}
+ble/color/define-options
+function bleopt/check:term_true_colors {
+ ble/color/g2sgr/.clear-cache
+ return 0
+}
+function bleopt/check:term_index_colors {
+ ble/color/g2sgr/.clear-cache
+ return 0
+}
+function ble/color/initialize-term-colors {
+ local fields
+ ble/string#split fields \; "$_ble_term_DA2R"
+ if [[ $bleopt_term_true_colors == auto ]]; then
+ local value=
+ if [[ $TERM == *-24bit || $TERM == *-direct ]]; then
+ value=colon
+ elif [[ $TERM == *-24bits || $TERM == *-truecolor || $COLORTERM == *24bit* || $COLORTERM == *truecolor* ]]; then
+ value=semicolon
+ else
+ case ${fields[0]} in
+ (83) # screen (truecolor on にしている必要がある。判定方法は不明)
+ if ((fields[1]>=49900)); then
+ value=semicolon
+ fi ;;
+ (67)
+ if ((fields[1]>=100000)); then
+ : # cygwin terminal
+ else
+ value=colon
+ fi ;;
+ esac
+ fi
+ [[ $value ]] &&
+ bleopt term_true_colors="$value"
+ fi
+}
+blehook DA2R+=ble/color/initialize-term-colors
+function ble-color-show {
+ if (($#)); then
+ ble/base/print-usage-for-no-argument-command 'Update and reload ble.sh.' "$@"
+ return "$?"
+ fi
+ local cols=16
+ local bg bg0 bgN ret gflags=$((_ble_color_gflags_BgIndexed|_ble_color_gflags_FgIndexed))
+ for ((bg0=0;bg0<256;bg0+=cols)); do
+ ((bgN=bg0+cols,bgN<256||(bgN=256)))
+ for ((bg=bg0;bg<bgN;bg++)); do
+ ble/color/g2sgr $((gflags|bg<<32))
+ printf '%s%03d ' "$ret" "$bg"
+ done
+ printf '%s\n' "$_ble_term_sgr0"
+ for ((bg=bg0;bg<bgN;bg++)); do
+ ble/color/g2sgr $((gflags|bg<<32|15<<8))
+ printf '%s%03d ' "$ret" "$bg"
+ done
+ printf '%s\n' "$_ble_term_sgr0"
+ done
+}
+_ble_color_g2sgr=()
+_ble_color_g2sgr_ansi=()
+function ble/color/g2sgr/.impl {
+ local g=$(($1))
+ local sgr=0
+ ((g&_ble_color_gflags_Bold)) && sgr="$sgr;${_ble_term_sgr_bold:-1}"
+ ((g&_ble_color_gflags_Italic)) && sgr="$sgr;${_ble_term_sgr_sitm:-3}"
+ ((g&_ble_color_gflags_Underline)) && sgr="$sgr;${_ble_term_sgr_smul:-4}"
+ ((g&_ble_color_gflags_Blink)) && sgr="$sgr;${_ble_term_sgr_blink:-5}"
+ ((g&_ble_color_gflags_Revert)) && sgr="$sgr;${_ble_term_sgr_rev:-7}"
+ ((g&_ble_color_gflags_Invisible)) && sgr="$sgr;${_ble_term_sgr_invis:-8}"
+ ((g&_ble_color_gflags_Strike)) && sgr="$sgr;${_ble_term_sgr_strike:-9}"
+ if ((g&_ble_color_gflags_FgIndexed)); then
+ local fg=$((g>>8&0xFF))
+ ble/color/.color2sgrfg "$fg"
+ sgr="$sgr;$ret"
+ elif ((g&_ble_color_gflags_FgMask)); then
+ local rgb=$((1<<24|g>>8&0xFFFFFF))
+ ble/color/.color2sgrfg "$rgb"
+ sgr="$sgr;$ret"
+ fi
+ if ((g&_ble_color_gflags_BgIndexed)); then
+ local bg=$((g>>32&0xFF))
+ ble/color/.color2sgrbg "$bg"
+ sgr="$sgr;$ret"
+ elif ((g&_ble_color_gflags_BgMask)); then
+ local rgb=$((1<<24|g>>32&0xFFFFFF))
+ ble/color/.color2sgrbg "$rgb"
+ sgr="$sgr;$ret"
+ fi
+ ret=$'\e['$sgr'm'
+ _ble_color_g2sgr[$1]=$ret
+}
+function ble/color/g2sgr/.clear-cache {
+ _ble_color_g2sgr=()
+}
+function ble/color/g2sgr {
+ ret=${_ble_color_g2sgr[$1]}
+ [[ $ret ]] || ble/color/g2sgr/.impl "$1"
+}
+function ble/color/g2sgr-ansi/.impl {
+ local g=$(($1))
+ local sgr=0
+ ((g&_ble_color_gflags_Bold)) && sgr="$sgr;1"
+ ((g&_ble_color_gflags_Italic)) && sgr="$sgr;3"
+ ((g&_ble_color_gflags_Underline)) && sgr="$sgr;4"
+ ((g&_ble_color_gflags_Blink)) && sgr="$sgr;5"
+ ((g&_ble_color_gflags_Revert)) && sgr="$sgr;7"
+ ((g&_ble_color_gflags_Invisible)) && sgr="$sgr;8"
+ ((g&_ble_color_gflags_Strike)) && sgr="$sgr;9"
+ if ((g&_ble_color_gflags_FgIndexed)); then
+ local fg=$((g>>8&0xFF))
+ sgr="$sgr;38:5:$fg"
+ elif ((g&_ble_color_gflags_FgMask)); then
+ local rgb=$((1<<24|g>>8&0xFFFFFF))
+ local R=$((rgb>>16&0xFF)) G=$((rgb>>8&0xFF)) B=$((rgb&0xFF))
+ sgr="$sgr;38:2::$r:$g:$b"
+ fi
+ if ((g&_ble_color_gflags_BgIndexed)); then
+ local bg=$((g>>32&0xFF))
+ sgr="$sgr;48:5:$bg"
+ elif ((g&_ble_color_gflags_BgMask)); then
+ local rgb=$((1<<24|g>>32&0xFFFFFF))
+ local R=$((rgb>>16&0xFF)) G=$((rgb>>8&0xFF)) B=$((rgb&0xFF))
+ sgr="$sgr;48:2::$r:$g:$b"
+ fi
+ ret=$'\e['$sgr'm'
+ _ble_color_g2sgr_ansi[$1]=$ret
+}
+function ble/color/g2sgr-ansi {
+ ret=${_ble_color_g2sgr_ansi[$1]}
+ [[ $ret ]] || ble/color/g2sgr-ansi/.impl "$1"
+}
+function ble/color/g#setfg-clear {
+ (($1&=~(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask)))
+}
+function ble/color/g#setbg-clear {
+ (($1&=~(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask)))
+}
+function ble/color/g#setfg-index {
+ local __color=$2
+ (($1=$1&~_ble_color_gflags_FgMask|_ble_color_gflags_FgIndexed|(__color&0xFF)<<8)) # index color
+}
+function ble/color/g#setbg-index {
+ local __color=$2
+ (($1=$1&~_ble_color_gflags_BgMask|_ble_color_gflags_BgIndexed|(__color&0xFF)<<32)) # index color
+}
+function ble/color/g#setfg-rgb {
+ local __R=$2 __G=$3 __B=$4
+ ((__R&=0xFF,__G&=0xFF,__B&=0xFF))
+ if ((__R==0&&__G==0&&__B==0)); then
+ ble/color/g#setfg-index "$1" 16
+ else
+ (($1=$1&~(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask)|__R<<24|__G<<16|__B<<8)) # true color
+ fi
+}
+function ble/color/g#setbg-rgb {
+ local __R=$2 __G=$3 __B=$4
+ ((__R&=0xFF,__G&=0xFF,__B&=0xFF))
+ if ((__R==0&&__G==0&&__B==0)); then
+ ble/color/g#setbg-index "$1" 16
+ else
+ (($1=$1&~(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask)|__R<<48|__G<<40|__B<<32)) # true color
+ fi
+}
+function ble/color/g#setfg-cmyk {
+ local __C=$2 __M=$3 __Y=$4 __K=${5:-0}
+ ((__K=~__K&0xFF,
+ __C=(~__C&0xFF)*__K/255,
+ __M=(~__M&0xFF)*__K/255,
+ __Y=(~__Y&0xFF)*__K/255))
+ ble/color/g#setfg-rgb "$__C" "$__M" "$__Y"
+}
+function ble/color/g#setbg-cmyk {
+ local __C=$2 __M=$3 __Y=$4 __K=${5:-0}
+ ((__K=~__K&0xFF,
+ __C=(~__C&0xFF)*__K/255,
+ __M=(~__M&0xFF)*__K/255,
+ __Y=(~__Y&0xFF)*__K/255))
+ ble/color/g#setbg-rgb "$1" "$__C" "$__M" "$__Y"
+}
+function ble/color/g#setfg {
+ local __color=$2
+ if ((__color<0)); then
+ ble/color/g#setfg-clear "$1"
+ elif ((__color>=0x1000000)); then
+ if ((__color==0x1000000)); then
+ ble/color/g#setfg-index "$1" 16
+ else
+ (($1=$1&~(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask)|(__color&0xFFFFFF)<<8)) # true color
+ fi
+ else
+ ble/color/g#setfg-index "$1" "$__color"
+ fi
+}
+function ble/color/g#setbg {
+ local __color=$2
+ if ((__color<0)); then
+ ble/color/g#setbg-clear "$1"
+ elif ((__color>=0x1000000)); then
+ if ((__color==0x1000000)); then
+ ble/color/g#setbg-index "$1" 16
+ else
+ (($1=$1&~(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask)|(__color&0xFFFFFF)<<32)) # true color
+ fi
+ else
+ ble/color/g#setbg-index "$1" "$__color"
+ fi
+}
+function ble/color/g#append {
+ local __g2=$2
+ ((__g2&(_ble_color_gflags_FgMask|_ble_color_gflags_FgIndexed))) &&
+ (($1&=~(_ble_color_gflags_FgMask|_ble_color_gflags_FgIndexed)))
+ ((__g2&(_ble_color_gflags_BgMask|_ble_color_gflags_BgIndexed))) &&
+ (($1&=~(_ble_color_gflags_BgMask|_ble_color_gflags_BgIndexed)))
+ (($1|=__g2))
+}
+function ble/color/g#compose {
+ (($1=($2)))
+ local __g2
+ for __g2 in "${@:3}"; do
+ ble/color/g#append "$1" "$__g2"
+ done
+}
+function ble/color/g.setfg { ble/color/g#setfg g "$@"; }
+function ble/color/g.setbg { ble/color/g#setbg g "$@"; }
+function ble/color/g.setfg-clear { ble/color/g#setfg-clear g "$@"; }
+function ble/color/g.setbg-clear { ble/color/g#setbg-clear g "$@"; }
+function ble/color/g.setfg-index { ble/color/g#setfg-index g "$@"; }
+function ble/color/g.setbg-index { ble/color/g#setbg-index g "$@"; }
+function ble/color/g.setfg-rgb { ble/color/g#setfg-rgb g "$@"; }
+function ble/color/g.setbg-rgb { ble/color/g#setbg-rgb g "$@"; }
+function ble/color/g.setfg-cmyk { ble/color/g#setfg-cmyk g "$@"; }
+function ble/color/g.setbg-cmyk { ble/color/g#setbg-cmyk g "$@"; }
+function ble/color/g.append { ble/color/g#append g "$@"; }
+function ble/color/g.compose { ble/color/g#compose g "$@"; }
+function ble/color/g#getfg {
+ local g=$1
+ if ((g&_ble_color_gflags_FgIndexed)); then
+ ((ret=g>>8&0xFF))
+ elif ((g&_ble_color_gflags_FgMask)); then
+ ((ret=0x1000000|(g>>8&0xFFFFFF)))
+ else
+ ((ret=-1))
+ fi
+}
+function ble/color/g#getbg {
+ local g=$1
+ if ((g&_ble_color_gflags_BgIndexed)); then
+ ((ret=g>>32&0xFF))
+ elif ((g&_ble_color_gflags_BgMask)); then
+ ((ret=0x1000000|(g>>32&0xFFFFFF)))
+ else
+ ((ret=-1))
+ fi
+}
+function ble/color/g#compute-fg {
+ local g=$1
+ if ((g&_ble_color_gflags_Invisible)); then
+ ble/color/g#compute-bg "$g"
+ elif ((g&_ble_color_gflags_Revert)); then
+ ble/color/g#getbg "$g"
+ else
+ ble/color/g#getfg "$g"
+ fi
+}
+function ble/color/g#compute-bg {
+ local g=$1
+ if ((g&_ble_color_gflags_Revert)); then
+ ble/color/g#getfg "$g"
+ else
+ ble/color/g#getbg "$g"
+ fi
+}
+function ble/color/gspec2g {
+ local g=0 entry
+ for entry in ${1//,/ }; do
+ case "$entry" in
+ (bold) ((g|=_ble_color_gflags_Bold)) ;;
+ (underline) ((g|=_ble_color_gflags_Underline)) ;;
+ (blink) ((g|=_ble_color_gflags_Blink)) ;;
+ (invis) ((g|=_ble_color_gflags_Invisible)) ;;
+ (reverse) ((g|=_ble_color_gflags_Revert)) ;;
+ (strike) ((g|=_ble_color_gflags_Strike)) ;;
+ (italic) ((g|=_ble_color_gflags_Italic)) ;;
+ (standout) ((g|=_ble_color_gflags_Revert|_ble_color_gflags_Bold)) ;;
+ (fg=*)
+ ble/color/.name2color "${entry:3}"
+ ble/color/g.setfg "$ret" ;;
+ (bg=*)
+ ble/color/.name2color "${entry:3}"
+ ble/color/g.setbg "$ret" ;;
+ (none)
+ g=0 ;;
+ esac
+ done
+ ret=$g
+}
+function ble/color/g2gspec {
+ local g=$1 gspec=
+ if ((g&_ble_color_gflags_FgIndexed)); then
+ local fg=$((g>>8&0xFF))
+ ble/color/.color2name "$fg"
+ gspec=$gspec,fg=$ret
+ elif ((g&_ble_color_gflags_FgMask)); then
+ local rgb=$((1<<24|g>>8&0xFFFFFF))
+ ble/color/.color2name "$rgb"
+ gspec=$gspec,fg=$ret
+ fi
+ if ((g&_ble_color_gflags_BgIndexed)); then
+ local bg=$((g>>32&0xFF))
+ ble/color/.color2name "$bg"
+ gspec=$gspec,bg=$ret
+ elif ((g&_ble_color_gflags_BgMask)); then
+ local rgb=$((1<<24|g>>32&0xFFFFFF))
+ ble/color/.color2name "$rgb"
+ gspec=$gspec,bg=$ret
+ fi
+ ((g&_ble_color_gflags_Bold)) && gspec=$gspec,bold
+ ((g&_ble_color_gflags_Underline)) && gspec=$gspec,underline
+ ((g&_ble_color_gflags_Blink)) && gspec=$gspec,blink
+ ((g&_ble_color_gflags_Invisible)) && gspec=$gspec,invis
+ ((g&_ble_color_gflags_Revert)) && gspec=$gspec,reverse
+ ((g&_ble_color_gflags_Strike)) && gspec=$gspec,strike
+ ((g&_ble_color_gflags_Italic)) && gspec=$gspec,italic
+ gspec=${gspec#,}
+ ret=${gspec:-none}
+}
+function ble/color/gspec2sgr {
+ local sgr=0 entry
+ for entry in ${1//,/ }; do
+ case "$entry" in
+ (bold) sgr="$sgr;${_ble_term_sgr_bold:-1}" ;;
+ (underline) sgr="$sgr;${_ble_term_sgr_smul:-4}" ;;
+ (blink) sgr="$sgr;${_ble_term_sgr_blink:-5}" ;;
+ (invis) sgr="$sgr;${_ble_term_sgr_invis:-8}" ;;
+ (reverse) sgr="$sgr;${_ble_term_sgr_rev:-7}" ;;
+ (strike) sgr="$sgr;${_ble_term_sgr_strike:-9}" ;;
+ (italic) sgr="$sgr;${_ble_term_sgr_sitm:-3}" ;;
+ (standout) sgr="$sgr;${_ble_term_sgr_bold:-1};${_ble_term_sgr_rev:-7}" ;;
+ (fg=*)
+ ble/color/.name2color "${entry:3}"
+ ble/color/.color2sgrfg "$ret"
+ sgr="$sgr;$ret" ;;
+ (bg=*)
+ ble/color/.name2color "${entry:3}"
+ ble/color/.color2sgrbg "$ret"
+ sgr="$sgr;$ret" ;;
+ (none)
+ sgr=0 ;;
+ esac
+ done
+ ret="[${sgr}m"
+}
+function ble/color/.name2color/.clamp {
+ local text=$1 max=$2
+ if [[ $text == *% ]]; then
+ ((ret=10#0${text%'%'}*max/100))
+ else
+ ((ret=10#0$text))
+ fi
+ ((ret>max)) && ret=max
+}
+function ble/color/.name2color/.wrap {
+ local text=$1 max=$2
+ if [[ $text == *% ]]; then
+ ((ret=10#0${text%'%'}*max/100))
+ else
+ ((ret=10#0$text))
+ fi
+ ((ret%=max))
+}
+function ble/color/.hxx2color {
+ local H=$1 Min=$2 Range=$3 Unit=$4
+ local h1 h2 x=$Min y=$Min z=$Min
+ ((h1=H%120,h2=120-h1,
+ x+=Range*(h2<60?h2:60)/60,
+ y+=Range*(h1<60?h1:60)/60))
+ ((x=x*255/Unit,
+ y=y*255/Unit,
+ z=z*255/Unit))
+ case $((H/120)) in
+ (0) local R=$x G=$y B=$z ;;
+ (1) local R=$z G=$x B=$y ;;
+ (2) local R=$y G=$z B=$x ;;
+ esac
+ ((ret=1<<24|R<<16|G<<8|B))
+}
+function ble/color/.hsl2color {
+ local H=$1 S=$2 L=$3 Unit=$4
+ local Range=$((2*(L<=Unit/2?L:Unit-L)*S/Unit))
+ local Min=$((L-Range/2))
+ ble/color/.hxx2color "$H" "$Min" "$Range" "$Unit"
+}
+function ble/color/.hsb2color {
+ local H=$1 S=$2 B=$3 Unit=$4
+ local Range=$((B*S/Unit))
+ local Min=$((B-Range))
+ ble/color/.hxx2color "$H" "$Min" "$Range" "$Unit"
+}
+function ble/color/.name2color {
+ local colorName=$1
+ if [[ ! ${colorName//[0-9]} ]]; then
+ ((ret=10#0$colorName&255))
+ elif [[ $colorName == '#'* ]]; then
+ if local rex='^#[0-9a-fA-F]{3}$'; [[ $colorName =~ $rex ]]; then
+ let "ret=1<<24|16#${colorName:1:1}*0x11<<16|16#${colorName:2:1}*0x11<<8|16#${colorName:3:1}*0x11"
+ elif rex='^#[0-9a-fA-F]{6}$'; [[ $colorName =~ $rex ]]; then
+ let "ret=1<<24|16#${colorName:1:2}<<16|16#${colorName:3:2}<<8|16#${colorName:5:2}"
+ else
+ ret=-1
+ fi
+ elif [[ $colorName == *:* ]]; then
+ if local rex='^rgb:([0-9]+%?)/([0-9]+%?)/([0-9]+%?)$'; [[ $colorName =~ $rex ]]; then
+ ble/color/.name2color/.clamp "${BASH_REMATCH[1]}" 255; local R=$ret
+ ble/color/.name2color/.clamp "${BASH_REMATCH[2]}" 255; local G=$ret
+ ble/color/.name2color/.clamp "${BASH_REMATCH[3]}" 255; local B=$ret
+ ((ret=1<<24|R<<16|G<<8|B))
+ elif
+ local rex1='^cmy:([0-9]+%?)/([0-9]+%?)/([0-9]+%?)$'
+ local rex2='^cmyk:([0-9]+%?)/([0-9]+%?)/([0-9]+%?)/([0-9]+%?)$'
+ [[ $colorName =~ $rex1 || $colorName =~ $rex2 ]]
+ then
+ ble/color/.name2color/.clamp "${BASH_REMATCH[1]}" 255; local C=$ret
+ ble/color/.name2color/.clamp "${BASH_REMATCH[2]}" 255; local M=$ret
+ ble/color/.name2color/.clamp "${BASH_REMATCH[3]}" 255; local Y=$ret
+ ble/color/.name2color/.clamp "${BASH_REMATCH[4]:-0}" 255; local K=$ret
+ local K=$((~K&0xFF))
+ local R=$(((~C&0xFF)*K/255))
+ local G=$(((~M&0xFF)*K/255))
+ local B=$(((~Y&0xFF)*K/255))
+ ((ret=1<<24|R<<16|G<<8|B))
+ elif rex='^hs[lvb]:([0-9]+)/([0-9]+%)/([0-9]+%)$'; [[ $colorName =~ $rex ]]; then
+ ble/color/.name2color/.wrap "${BASH_REMATCH[1]}" 360; local H=$ret
+ ble/color/.name2color/.clamp "${BASH_REMATCH[2]}" 1000; local S=$ret
+ ble/color/.name2color/.clamp "${BASH_REMATCH[3]}" 1000; local X=$ret
+ if [[ $colorName == hsl:* ]]; then
+ ble/color/.hsl2color "$H" "$S" "$X" 1000
+ else
+ ble/color/.hsb2color "$H" "$S" "$X" 1000
+ fi
+ else
+ ret=-1
+ fi
+ else
+ case "$colorName" in
+ (black) ret=0 ;;
+ (brown) ret=1 ;;
+ (green) ret=2 ;;
+ (olive) ret=3 ;;
+ (navy) ret=4 ;;
+ (purple) ret=5 ;;
+ (teal) ret=6 ;;
+ (silver) ret=7 ;;
+ (gr[ae]y) ret=8 ;;
+ (red) ret=9 ;;
+ (lime) ret=10 ;;
+ (yellow) ret=11 ;;
+ (blue) ret=12 ;;
+ (magenta) ret=13 ;;
+ (cyan) ret=14 ;;
+ (white) ret=15 ;;
+ (orange) ret=202 ;;
+ (transparent|default) ret=-1 ;;
+ (*) ret=-1 ;;
+ esac
+ fi
+}
+function ble/color/.color2name {
+ if (($1>=0x1000000)); then
+ ble/util/sprintf ret '#%06x' $(($1&0xFFFFFF))
+ return 0
+ fi
+ ((ret=(10#0$1&255)))
+ case $ret in
+ (0) ret=black ;;
+ (1) ret=brown ;;
+ (2) ret=green ;;
+ (3) ret=olive ;;
+ (4) ret=navy ;;
+ (5) ret=purple ;;
+ (6) ret=teal ;;
+ (7) ret=silver ;;
+ (8) ret=gray ;;
+ (9) ret=red ;;
+ (10) ret=lime ;;
+ (11) ret=yellow ;;
+ (12) ret=blue ;;
+ (13) ret=magenta ;;
+ (14) ret=cyan ;;
+ (15) ret=white ;;
+ (202) ret=orange ;;
+ esac
+}
+function ble/color/convert-color88-to-color256 {
+ local color=$1
+ if ((color>=16)); then
+ if ((color>=80)); then
+ local L=$((((color-80+1)*25+4)/9))
+ ((color=L==0?16:(L==25?231:232+(L-1))))
+ else
+ ((color-=16))
+ local R=$((color/16)) G=$((color/4%4)) B=$((color%4))
+ ((R=(R*5+1)/3,G=(G*5+1)/3,B=(B*5+1)/3,
+ color=16+R*36+G*6+B))
+ fi
+ fi
+ ret=$color
+}
+function ble/color/convert-color256-to-color88 {
+ local color=$1
+ if ((color>=16)); then
+ if ((color>=232)); then
+ local L=$((((color-232+1)*9+12)/25))
+ ((color=L==0?16:(L==9?79:80+(L-1))))
+ else
+ ((color-=16))
+ local R=$((color/36)) G=$((color/6%6)) B=$((color%6))
+ ((R=(R*3+2)/5,G=(G*3+2)/5,B=(B*3+2)/5,
+ color=16+R*16+G*4+B))
+ fi
+ fi
+ ret=$color
+}
+function ble/color/convert-rgb24-to-color256 {
+ local R=$1 G=$2 B=$3
+ if ((R==G&&G==B)); then
+ if ((R<=3)); then
+ ret=16
+ elif ((R>=247)); then
+ ret=231
+ elif ((R>=92&&(R-92)%40<5)); then
+ ((ret=59+43*(R-92)/40))
+ else
+ local level=$(((R-3)/10))
+ ((ret=232+(level<=23?level:23)))
+ fi
+ else
+ ((R=R<=47?0:(R<=95?1:(R-35)/40)))
+ ((G=G<=47?0:(G<=95?1:(G-35)/40)))
+ ((B=B<=47?0:(B<=95?1:(B-35)/40)))
+ ((ret=16+36*R+6*G+B))
+ fi
+}
+function ble/color/convert-rgb24-to-color88 {
+ local R=$1 G=$2 B=$3
+ if ((R==G&&G==B)); then
+ if ((R<=22)); then
+ ret=16 # 4x4x4 cube (0,0,0)=0:0:0
+ elif ((R>=239)); then
+ ret=79 # 4x4x4 cube (3,3,3)=255:255:255
+ elif ((131<=R&&R<=142)); then
+ ret=37 # 4x4x4 cube (1,1,1)=139:139:139
+ elif ((197<=R&&R<=208)); then
+ ret=58 # 4x4x4 cube (2,2,2)=197:197:197
+ else
+ local level=$(((R-34)/25))
+ ((ret=80+(level<=7?level:7)))
+ fi
+ else
+ ((R=R<=69?0:(R<=168?1:(R-52)/58)))
+ ((G=G<=69?0:(G<=168?1:(G-52)/58)))
+ ((B=B<=69?0:(B<=168?1:(B-52)/58)))
+ ((ret=16+16*R+4*G+B))
+ fi
+}
+function ble/color/.color2sgr-impl {
+ local ccode=$1 prefix=$2 # 3 for fg, 4 for bg
+ if ((ccode<0)); then
+ ret=${prefix}9
+ elif ((ccode<16&&ccode<_ble_term_colors)); then
+ if ((prefix==4)); then
+ ret=${_ble_term_sgr_ab[ccode]}
+ else
+ ret=${_ble_term_sgr_af[ccode]}
+ fi
+ elif ((ccode<256)); then
+ if ((_ble_term_colors>=256||bleopt_term_index_colors==256)); then
+ ret="${prefix}8;5;$ccode"
+ elif ((_ble_term_colors>=88||bleopt_term_index_colors==88)); then
+ ble/color/convert-color256-to-color88 "$ccode"
+ ret="${prefix}8;5;$ret"
+ elif ((ccode<_ble_term_colors||ccode<bleopt_term_index_colors)); then
+ ret="${prefix}8;5;$ccode"
+ elif ((_ble_term_colors>=16||_ble_term_colors==8)); then
+ if ((ccode>=16)); then
+ if ((ccode>=232)); then
+ local L=$((((ccode-232+1)*3+12)/25))
+ ((ccode=L==0?0:(L==1?8:(L==2?7:15))))
+ else
+ ((ccode-=16))
+ local R=$((ccode/36)) G=$((ccode/6%6)) B=$((ccode%6))
+ if ((R==G&&G==B)); then
+ local L=$(((R*3+2)/5))
+ ((ccode=L==0?0:(L==1?8:(L==2?7:15))))
+ else
+ local min max
+ ((R<G?(min=R,max=G):(min=G,max=R),
+ B<min?(min=B):(B>max&&(max=B))))
+ local Range=$((max-min))
+ ((R=(R-min+Range/2)/Range,
+ G=(G-min+Range/2)/Range,
+ B=(B-min+Range/2)/Range,
+ ccode=R+G*2+B*4+(min+max>=5?8:0)))
+ fi
+ fi
+ fi
+ ((_ble_term_colors==8&&ccode>=8&&(ccode-=8)))
+ if ((prefix==4)); then
+ ret=${_ble_term_sgr_ab[ccode]}
+ else
+ ret=${_ble_term_sgr_af[ccode]}
+ fi
+ else
+ ret=${prefix}9
+ fi
+ elif ((0x1000000<=ccode&&ccode<0x2000000)); then
+ local R=$((ccode>>16&0xFF)) G=$((ccode>>8&0xFF)) B=$((ccode&0xFF))
+ if [[ $bleopt_term_true_colors == semicolon ]]; then
+ ret="${prefix}8;2;$R;$G;$B"
+ elif [[ $bleopt_term_true_colors == colon ]]; then
+ ret="${prefix}8:2:$R:$G:$B"
+ elif ((_ble_term_colors>=256||bleopt_term_index_colors==256)); then
+ ble/color/convert-rgb24-to-color256 "$R" "$G" "$B"
+ ret="${prefix}8;5;$ret"
+ elif ((_ble_term_colors>=88||bleopt_term_index_colors==88)); then
+ ble/color/convert-rgb24-to-color88 "$R" "$G" "$B"
+ ret="${prefix}8;5;$ret"
+ else
+ ble/color/convert-rgb24-to-color256 "$R" "$G" "$B"
+ ble/color/.color2sgr-impl "$ret" "$prefix"
+ fi
+ else
+ ret=${prefix}9
+ fi
+}
+function ble/color/.color2sgrfg {
+ ble/color/.color2sgr-impl "$1" 3
+}
+function ble/color/.color2sgrbg {
+ ble/color/.color2sgr-impl "$1" 4
+}
+function ble/color/read-sgrspec/.arg-next {
+ local _var=arg _ret
+ if [[ $1 == -v ]]; then
+ _var=$2
+ shift 2
+ fi
+ if ((j<${#fields[*]})); then
+ ((_ret=10#0${fields[j++]}))
+ else
+ ((i++))
+ ((_ret=10#0${specs[i]%%:*}))
+ fi
+ (($_var=_ret))
+}
+function ble/color/read-sgrspec {
+ local specs i iN
+ ble/string#split specs \; "$1"
+ for ((i=0,iN=${#specs[@]};i<iN;i++)); do
+ local spec=${specs[i]} fields
+ ble/string#split fields : "$spec"
+ local arg=$((10#0${fields[0]}))
+ if ((arg==0)); then
+ g=0
+ continue
+ elif [[ :$opts: != *:ansi:* ]]; then
+ [[ ${_ble_term_sgr_term2ansi[arg]} ]] &&
+ arg=${_ble_term_sgr_term2ansi[arg]}
+ fi
+ if ((30<=arg&&arg<50)); then
+ if ((30<=arg&&arg<38)); then
+ local color=$((arg-30))
+ ble/color/g.setfg-index "$color"
+ elif ((40<=arg&&arg<48)); then
+ local color=$((arg-40))
+ ble/color/g.setbg-index "$color"
+ elif ((arg==38)); then
+ local j=1 color cspace
+ ble/color/read-sgrspec/.arg-next -v cspace
+ if ((cspace==5)); then
+ ble/color/read-sgrspec/.arg-next -v color
+ if [[ :$opts: != *:ansi:* ]] && ((bleopt_term_index_colors==88)); then
+ local ret; ble/color/convert-color88-to-color256 "$color"; color=$ret
+ fi
+ ble/color/g.setfg-index "$color"
+ elif ((cspace==2)); then
+ local S R G B
+ ((${#fields[@]}>5)) &&
+ ble/color/read-sgrspec/.arg-next -v S
+ ble/color/read-sgrspec/.arg-next -v R
+ ble/color/read-sgrspec/.arg-next -v G
+ ble/color/read-sgrspec/.arg-next -v B
+ ble/color/g.setfg-rgb "$R" "$G" "$B"
+ elif ((cspace==3||cspace==4)); then
+ local S C M Y K=0
+ ((${#fields[@]}>2+cspace)) &&
+ ble/color/read-sgrspec/.arg-next -v S
+ ble/color/read-sgrspec/.arg-next -v C
+ ble/color/read-sgrspec/.arg-next -v M
+ ble/color/read-sgrspec/.arg-next -v Y
+ ((cspace==4)) &&
+ ble/color/read-sgrspec/.arg-next -v K
+ ble/color/g.setfg-cmyk "$C" "$M" "$Y" "$K"
+ else
+ ble/color/g.setfg-clear
+ fi
+ elif ((arg==48)); then
+ local j=1 color cspace
+ ble/color/read-sgrspec/.arg-next -v cspace
+ if ((cspace==5)); then
+ ble/color/read-sgrspec/.arg-next -v color
+ if [[ :$opts: != *:ansi:* ]] && ((bleopt_term_index_colors==88)); then
+ local ret; ble/color/convert-color88-to-color256 "$color"; color=$ret
+ fi
+ ble/color/g.setbg-index "$color"
+ elif ((cspace==2)); then
+ local S R G B
+ ((${#fields[@]}>5)) &&
+ ble/color/read-sgrspec/.arg-next -v S
+ ble/color/read-sgrspec/.arg-next -v R
+ ble/color/read-sgrspec/.arg-next -v G
+ ble/color/read-sgrspec/.arg-next -v B
+ ble/color/g.setbg-rgb "$R" "$G" "$B"
+ elif ((cspace==3||cspace==4)); then
+ local S C M Y K=0
+ ((${#fields[@]}>2+cspace)) &&
+ ble/color/read-sgrspec/.arg-next -v S
+ ble/color/read-sgrspec/.arg-next -v C
+ ble/color/read-sgrspec/.arg-next -v M
+ ble/color/read-sgrspec/.arg-next -v Y
+ ((cspace==4)) &&
+ ble/color/read-sgrspec/.arg-next -v K
+ ble/color/g.setbg-cmyk "$C" "$M" "$Y" "$K"
+ else
+ ble/color/g.setbg-clear
+ fi
+ elif ((arg==39)); then
+ ble/color/g.setfg-clear
+ elif ((arg==49)); then
+ ble/color/g.setbg-clear
+ fi
+ elif ((90<=arg&&arg<98)); then
+ local color=$((arg-90+8))
+ ble/color/g.setfg-index "$color"
+ elif ((100<=arg&&arg<108)); then
+ local color=$((arg-100+8))
+ ble/color/g.setbg-index "$color"
+ else
+ case $arg in
+ (1) ((g|=_ble_color_gflags_Bold)) ;;
+ (22) ((g&=~_ble_color_gflags_Bold)) ;;
+ (4) ((g|=_ble_color_gflags_Underline)) ;;
+ (24) ((g&=~_ble_color_gflags_Underline)) ;;
+ (7) ((g|=_ble_color_gflags_Revert)) ;;
+ (27) ((g&=~_ble_color_gflags_Revert)) ;;
+ (9807) ((g^=_ble_color_gflags_Revert)) ;; # toggle (for internal use)
+ (3) ((g|=_ble_color_gflags_Italic)) ;;
+ (23) ((g&=~_ble_color_gflags_Italic)) ;;
+ (5) ((g|=_ble_color_gflags_Blink)) ;;
+ (25) ((g&=~_ble_color_gflags_Blink)) ;;
+ (8) ((g|=_ble_color_gflags_Invisible)) ;;
+ (28) ((g&=~_ble_color_gflags_Invisible)) ;;
+ (9) ((g|=_ble_color_gflags_Strike)) ;;
+ (29) ((g&=~_ble_color_gflags_Strike)) ;;
+ esac
+ fi
+ done
+}
+function ble/color/sgrspec2g {
+ local g=0
+ ble/color/read-sgrspec "$1"
+ ret=$g
+}
+function ble/color/ansi2g {
+ local x=0 y=0 g=0
+ ble/function#try ble/canvas/trace "$1" # -> ret
+ ret=$g
+}
+if [[ ! ${_ble_faces_count-} ]]; then # reload #D0875
+ _ble_faces_count=0
+ _ble_faces=()
+fi
+function ble/color/setface/.check-argument {
+ local rex='^[a-zA-Z0-9_]+$'
+ [[ $# == 2 && $1 =~ $rex && $2 ]] && return 0
+ local flags=a
+ while (($#)); do
+ local arg=$1; shift
+ case $arg in
+ (--help) flags=H$flags ;;
+ (--color|--color=always) flags=c${flags//[ac]} ;;
+ (--color=auto) flags=a${flags//[ac]} ;;
+ (--color=never) flags=${flags//[ac]} ;;
+ (-*)
+ ble/util/print "${FUNCNAME[1]}: unrecognized option '$arg'." >&2
+ flags=E$flags ;;
+ (*)
+ ble/util/print "${FUNCNAME[1]}: unrecognized argument '$arg'." >&2
+ flags=E$flags ;;
+ esac
+ done
+ if [[ $flags == *E* ]]; then
+ ext=2; return 1
+ elif [[ $flags == *H* ]]; then
+ ble/util/print-lines \
+ "usage: $name FACE_NAME [TYPE:]SPEC" \
+ ' Set face.' \
+ '' \
+ ' TYPE Specifies the format of SPEC. The following values are available.' \
+ ' gspec Comma separated graphic attribute list' \
+ ' g Integer value' \
+ ' ref Face name or id (reference)' \
+ ' copy Face name or id (copy value)' \
+ ' sgrspec Parameters to the control function SGR' \
+ ' ansi ANSI Sequences' >&2
+ ext=0; return 1
+ fi
+ local opts=
+ [[ $flags == *c* || $flags == *a* && -t 1 ]] && opts=$opts:color
+ ble/color/list-faces "$opts"; ext=$?; return 1
+}
+function ble-color-defface {
+ local ext; ble/color/setface/.check-argument "$@" || return "$ext"
+ ble/color/defface "$@"
+}
+function ble-color-setface {
+ local ext; ble/color/setface/.check-argument "$@" || return "$ext"
+ ble/color/setface "$@"
+}
+function ble/color/defface { local q=\' Q="'\''"; blehook color_defface_load+="ble/color/defface '${1//$q/$Q}' '${2//$q/$Q}'"; }
+function ble/color/setface { local q=\' Q="'\''"; blehook color_setface_load+="ble/color/setface '${1//$q/$Q}' '${2//$q/$Q}'"; }
+function ble/color/face2g { ble/color/initialize-faces && ble/color/face2g "$@"; }
+function ble/color/face2sgr { ble/color/initialize-faces && ble/color/face2sgr "$@"; }
+function ble/color/iface2g { ble/color/initialize-faces && ble/color/iface2g "$@"; }
+function ble/color/iface2sgr { ble/color/initialize-faces && ble/color/iface2sgr "$@"; }
+function ble/color/face2sgr-ansi { ble/color/initialize-faces && ble/color/face2sgr "$@"; }
+_ble_color_faces_initialized=
+function ble/color/initialize-faces {
+ local _ble_color_faces_initializing=1
+ local -a _ble_color_faces_errors=()
+ function ble/color/face2g {
+ ((ret=_ble_faces[_ble_faces__$1]))
+ }
+ function ble/color/face2sgr { ble/color/g2sgr $((_ble_faces[_ble_faces__$1])); }
+ function ble/color/face2sgr-ansi { ble/color/g2sgr-ansi $((_ble_faces[_ble_faces__$1])); }
+ function ble/color/iface2g {
+ ((ret=_ble_faces[$1]))
+ }
+ function ble/color/iface2sgr {
+ ble/color/g2sgr $((_ble_faces[$1]))
+ }
+ function ble/color/setface/.spec2g {
+ local spec=$1 value=${spec#*:}
+ case $spec in
+ (gspec:*) ble/color/gspec2g "$value" ;;
+ (g:*) ret=$(($value)) ;;
+ (ref:*)
+ if [[ ! ${value//[0-9]} ]]; then
+ ret=_ble_faces[$((value))]
+ else
+ ret=_ble_faces[_ble_faces__$value]
+ fi ;;
+ (copy:*|face:*|iface:*)
+ [[ $spec == copy:* ]] ||
+ ble/util/print "ble-face: \"${spec%%:*}:*\" is obsoleted. Use \"copy:*\" instead." >&2
+ if [[ ! ${value//[0-9]} ]]; then
+ ble/color/iface2g "$value"
+ else
+ ble/color/face2g "$value"
+ fi ;;
+ (sgrspec:*) ble/color/sgrspec2g "$value" ;;
+ (ansi:*) ble/color/ansi2g "$value" ;;
+ (*) ble/color/gspec2g "$spec" ;;
+ esac
+ }
+ function ble/color/defface {
+ local name=_ble_faces__$1 spec=$2 ret
+ (($name)) && return 0
+ (($name=++_ble_faces_count))
+ ble/color/setface/.spec2g "$spec"
+ _ble_faces[$name]=$ret
+ _ble_faces_def[$name]=$ret
+ }
+ function ble/color/setface {
+ local name=_ble_faces__$1 spec=$2 ret
+ if [[ ${!name} ]]; then
+ ble/color/setface/.spec2g "$spec"; _ble_faces[$name]=$ret
+ else
+ local message="ble.sh: the specified face \`$1' is not defined."
+ if [[ $_ble_color_faces_initializing ]]; then
+ ble/array#push _ble_color_faces_errors "$message"
+ else
+ ble/util/print "$message" >&2
+ fi
+ return 1
+ fi
+ }
+ _ble_color_faces_initialized=1
+ blehook/invoke color_defface_load
+ blehook/invoke color_setface_load
+ blehook color_defface_load=
+ blehook color_setface_load=
+ if ((${#_ble_color_faces_errors[@]})); then
+ if ((_ble_edit_attached)) && [[ ! $_ble_textarea_invalidated && $_ble_term_state == internal ]]; then
+ IFS=$'\n' builtin eval 'local message="${_ble_color_faces_errors[*]}"'
+ ble/widget/print "$message"
+ else
+ printf '%s\n' "${_ble_color_faces_errors[@]}" >&2
+ fi
+ return 1
+ else
+ return 0
+ fi
+}
+ble/function#try ble/util/idle.push ble/color/initialize-faces
+function ble/color/list-faces {
+ local flags=
+ [[ :$1: == *:color:* ]] && flags=c
+ local ret sgr0= sgr1= sgr2=
+ if [[ $flags == *c* ]]; then
+ sgr0=$_ble_term_sgr0
+ ble/color/face2sgr command_function; sgr1=$ret
+ ble/color/face2sgr syntax_varname; sgr2=$ret
+ fi
+ local key
+ for key in "${!_ble_faces__@}"; do
+ ble-face/.print-face "$key"
+ done
+}
+function ble-face/.read-arguments/process-set {
+ local o=$1 face=$2 value=$3
+ if local rex='^[_a-zA-Z0-9@][_a-zA-Z0-9@]*$'; ! [[ $face =~ $rex ]]; then
+ ble/util/print "ble-face: invalid face name '$face'." >&2
+ flags=E$flags
+ return 1
+ elif [[ $o == '-d' && $face == *@* ]]; then
+ ble/util/print "ble-face: wildcards cannot be used in the face name '$face' for definition." >&2
+ flags=E$flags
+ return 1
+ fi
+ local assign='='
+ [[ $o == -d ]] && assign=':='
+ ble/array#push setface "$face$assign$value"
+}
+function ble-face/.read-arguments {
+ flags= setface=() print=()
+ local opt_color=auto
+ local args iarg narg=$#; args=("$@")
+ for ((iarg=0;iarg<narg;)); do
+ local arg=${args[iarg++]}
+ if [[ $arg == -* ]]; then
+ if [[ $flags == *L* ]]; then
+ ble/util/print "ble-face: unrecognized argument '$arg'." >&2
+ flags=E$flags
+ else
+ case $arg in
+ (--help) flags=H$flags ;;
+ (--color)
+ opt_color=always ;;
+ (--color=always|--color=auto|--color=never)
+ opt_color=${arg#*=} ;;
+ (--color=*)
+ ble/util/print "ble-face: '${arg#*=}': unrecognized option argument for '--color'." >&2
+ flags=E$flags ;;
+ (--reset) flags=r$flags ;;
+ (--changed) flags=u$flags ;;
+ (--) flags=L$flags ;;
+ (--*)
+ ble/util/print "ble-face: unrecognized long option '$arg'." >&2
+ flags=E$flags ;;
+ (-?*)
+ local i c
+ for ((i=1;i<${#arg};i++)); do
+ c=${arg:i:1}
+ case $c in
+ ([ru]) flags=$c$flags ;;
+ ([sd])
+ if ((i+1<${#arg})); then
+ local lhs=${arg:i+1}
+ else
+ local lhs=${args[iarg++]}
+ fi
+ local rhs=${args[iarg++]}
+ if ((iarg>narg)); then
+ ble/util/print "ble-face: missing option argument for '-$c FACE SPEC'." >&2
+ flags=E$flags
+ continue
+ fi
+ ble-face/.read-arguments/process-set "${arg::2}" "$lhs" "$rhs"
+ break ;;
+ (*)
+ ble/util/print "ble-face: unrecognized option '-$c'." >&2
+ flags=E$flags ;;
+ esac
+ done ;;
+ (-)
+ ble/util/print "ble-face: unrecognized argument '$arg'." >&2
+ flags=E$flags ;;
+ esac
+ fi
+ elif [[ $arg == *=* ]]; then
+ if local rex='^[_a-zA-Z@][_a-zA-Z0-9@]*:?='; [[ $arg =~ $rex ]]; then
+ ble/array#push setface "$arg"
+ else
+ local lhs=${arg%%=*}; lhs=${lhs%:}
+ ble/util/print "ble-face: invalid left-hand side '$lhs' ($arg)." >&2
+ flags=E$flags
+ fi
+ else
+ if local rex='^[_a-zA-Z@][_a-zA-Z0-9@]*$'; [[ $arg =~ $rex ]]; then
+ ble/array#push print "$arg"
+ else
+ ble/util/print "ble-face: unrecognized form of argument '$arg'." >&2
+ flags=E$flags
+ fi
+ fi
+ done
+ [[ $opt_color == auto && -t 1 || $opt_color == always ]] && flags=c$flags
+ [[ $flags != *E* ]]
+}
+function ble-face/.print-help {
+ ble/util/print-lines >&2 \
+ 'ble-face --help' \
+ 'ble-face [FACEPAT[:=|=][TYPE:]SPEC | -[sd] FACEPAT [TYPE:]SPEC]]...' \
+ 'ble-face [-ur|--color[=WHEN]] [FACE...]' \
+ '' \
+ ' OPTIONS/ARGUMENTS' \
+ '' \
+ ' FACEPAT=[TYPE:]SPEC' \
+ ' -s FACEPAT [TYPE:]SPEC' \
+ ' Set a face. FACEPAT can include a wildcard @ which matches one or' \
+ ' more characters.' \
+ '' \
+ ' FACE:=[TYPE:]SPEC' \
+ ' -d FACE [TYPE:]SPEC' \
+ ' Define a face' \
+ '' \
+ ' [-u | --color[=always|never|auto]]... FACEPAT...' \
+ ' Print faces. If faces are not specified, all faces are selected.' \
+ ' If -u is specified, only the faces with different values from their' \
+ ' default will be printed. The option "--color" controls the output' \
+ ' color settings. The default is "auto".' \
+ '' \
+ ' -r FACEPAT...' \
+ ' Reset faces. If faces are not specified, all faces are selected.' \
+ '' \
+ ' FACEPAT Specifies a face name. The character @ in the face name is treated' \
+ ' as a wildcard.' \
+ '' \
+ ' FACE Specifies a face name. Wildcard @ cannot be used.' \
+ '' \
+ ' TYPE Specifies the format of SPEC. The following values are available.' \
+ ' gspec Comma separated graphic attribute list' \
+ ' g Integer value' \
+ ' ref Face name or id (reference)' \
+ ' copy Face name or id (copy value)' \
+ ' sgrspec Parameters to the control function SGR' \
+ ' ansi ANSI Sequences' \
+ ''
+ return 0
+}
+function ble-face/.print-face {
+ local key=$1 ret
+ local name=${key#_ble_faces__}
+ local cur=${_ble_faces[key]}
+ if [[ $flags == *u* ]]; then
+ local def=_ble_faces_def[key]
+ [[ ${!def+set} && $cur == "${!def}" ]] && return 0
+ fi
+ local def=${_ble_faces[key]}
+ if [[ $cur == '_ble_faces['*']' ]]; then
+ cur=${cur#'_ble_faces['}
+ cur=${cur%']'}
+ cur=ref:${cur#_ble_faces__}
+ else
+ ble/color/g2gspec $((cur)); cur=$ret
+ fi
+ if [[ $flags == *c* ]]; then
+ ble/color/iface2sgr $((key))
+ cur=$ret$cur$_ble_term_sgr0
+ fi
+ printf '%s %s=%s\n' "${sgr1}ble-face$sgr0" "$sgr2$name$sgr0" "$cur"
+}
+function ble-face/.reset-face {
+ local key=$1 ret
+ [[ ${_ble_faces_def[key]+set} ]] &&
+ _ble_faces[key]=${_ble_faces_def[key]}
+}
+function ble-face {
+ local flags setface print
+ ble-face/.read-arguments "$@"
+ if [[ $flags == *H* ]]; then
+ ble-face/.print-help
+ return 2
+ elif [[ $flags == *E* ]]; then
+ return 2
+ fi
+ if ((!${#print[@]}&&!${#setface[@]})); then
+ print=(@)
+ fi
+ ((${#print[@]})) && ble/color/initialize-faces
+ if [[ ! $_ble_color_faces_initialized ]]; then
+ local ret
+ ble/string#quote-command ble-face "${setface[@]}"
+ blehook color_setface_load+="$ret"
+ return 0
+ fi
+ local spec
+ for spec in "${setface[@]}"; do
+ if local rex='^([_a-zA-Z@][_a-zA-Z0-9@]*)(:?=)(.*)$'; ! [[ $spec =~ $rex ]]; then
+ ble/util/print "ble-face: unrecognized setting '$spec'" >&2
+ flags=E$flags
+ continue
+ fi
+ local var=${BASH_REMATCH[1]}
+ local type=${BASH_REMATCH[2]}
+ local value=${BASH_REMATCH[3]}
+ if [[ $type == ':=' ]]; then
+ if [[ $var == *@* ]]; then
+ ble/util/print "ble-face: wild card @ cannot be used for face definition ($spec)." >&2
+ flags=E$flags
+ else
+ ble/color/defface "$var" "$value"
+ fi
+ else
+ local ret face
+ if bleopt/expand-variable-pattern "_ble_faces__$var"; then
+ for face in "${ret[@]}"; do
+ ble/color/setface "${face#_ble_faces__}" "$value"
+ done
+ else
+ ble/util/print "ble-face: face '$var' not found" >&2
+ flags=E$flags
+ fi
+ fi
+ done
+ if ((${#print[@]})); then
+ local ret sgr0= sgr1= sgr2=
+ if [[ $flags == *c* ]]; then
+ sgr0=$_ble_term_sgr0
+ ble/color/face2sgr command_function; sgr1=$ret
+ ble/color/face2sgr syntax_varname; sgr2=$ret
+ fi
+ local spec
+ for spec in "${print[@]}"; do
+ local ret face
+ if bleopt/expand-variable-pattern "_ble_faces__$spec"; then
+ if [[ $flags == *r* ]]; then
+ for face in "${ret[@]}"; do
+ ble-face/.reset-face "$face"
+ done
+ else
+ for face in "${ret[@]}"; do
+ ble-face/.print-face "$face"
+ done
+ fi
+ else
+ ble/util/print "ble-face: face '$spec' not found" >&2
+ flags=E$flags
+ fi
+ done
+ fi
+ [[ $flags != *E* ]]
+}
+_ble_highlight_layer__list=(plain)
+function ble/highlight/layer/update {
+ local text=$1 iN=${#1} opts=$2
+ local DMIN=${3:-0} DMAX=${4:-$iN} DMAX0=${5:-0}
+ local PREV_BUFF=_ble_highlight_layer_plain_buff
+ local PREV_UMIN=-1
+ local PREV_UMAX=-1
+ local layer player=plain LEVEL
+ local nlevel=${#_ble_highlight_layer__list[@]}
+ for ((LEVEL=0;LEVEL<nlevel;LEVEL++)); do
+ layer=${_ble_highlight_layer__list[LEVEL]}
+ "ble/highlight/layer:$layer/update" "$text" "$player"
+ player=$layer
+ done
+ HIGHLIGHT_BUFF=$PREV_BUFF
+ HIGHLIGHT_UMIN=$PREV_UMIN
+ HIGHLIGHT_UMAX=$PREV_UMAX
+}
+function ble/highlight/layer/update/add-urange {
+ local umin=$1 umax=$2
+ (((PREV_UMIN<0||PREV_UMIN>umin)&&(PREV_UMIN=umin),
+ (PREV_UMAX<0||PREV_UMAX<umax)&&(PREV_UMAX=umax)))
+}
+function ble/highlight/layer/update/shift {
+ local __dstArray=$1
+ local __srcArray=${2:-$__dstArray}
+ if ((DMIN>=0)); then
+ ble/array#reserve-prototype $((DMAX-DMIN))
+ builtin eval "
+ $__dstArray=(
+ \"\${$__srcArray[@]::DMIN}\"
+ \"\${_ble_array_prototype[@]::DMAX-DMIN}\"
+ \"\${$__srcArray[@]:DMAX0}\")"
+ else
+ [[ $__dstArray != "$__srcArray" ]] && builtin eval "$__dstArray=(\"\${$__srcArray[@]}\")"
+ fi
+}
+function ble/highlight/layer/update/getg {
+ g=
+ local LEVEL=$LEVEL
+ while ((--LEVEL>=0)); do
+ "ble/highlight/layer:${_ble_highlight_layer__list[LEVEL]}/getg" "$1"
+ [[ $g ]] && return 0
+ done
+ g=0
+}
+function ble/highlight/layer/getg {
+ LEVEL=${#_ble_highlight_layer__list[*]} ble/highlight/layer/update/getg "$1"
+}
+_ble_highlight_layer_plain_VARNAMES=(
+ _ble_highlight_layer_plain_buff)
+function ble/highlight/layer:plain/initialize-vars {
+ _ble_highlight_layer_plain_buff=()
+}
+ble/highlight/layer:plain/initialize-vars
+function ble/highlight/layer:plain/update/.getch {
+ [[ $ch == [' '-'~'] ]] && return 0
+ if [[ $ch == [$'\t\n\177'] ]]; then
+ if [[ $ch == $'\t' ]]; then
+ ch=${_ble_string_prototype::it}
+ elif [[ $ch == $'\n' ]]; then
+ ch=$_ble_term_el$_ble_term_nl
+ elif [[ $ch == $'\177' ]]; then
+ ch='^?'
+ fi
+ else
+ local ret; ble/util/s2c "$ch"
+ local cs=${_ble_unicode_GraphemeCluster_ControlRepresentation[ret]}
+ if [[ $cs ]]; then
+ ch=$cs
+ elif ((ret<0x20)); then
+ ble/util/c2s $((ret+64))
+ ch="^$ret"
+ elif ((0x80<=ret&&ret<=0x9F)); then
+ ble/util/c2s $((ret-64))
+ ch="M-^$ret"
+ fi
+ fi
+}
+function ble/highlight/layer:plain/update {
+ if ((DMIN>=0)); then
+ ble/highlight/layer/update/shift _ble_highlight_layer_plain_buff
+ local i text=$1 ch
+ local it=$_ble_term_it
+ for ((i=DMIN;i<DMAX;i++)); do
+ ch=${text:i:1}
+ local LC_ALL= LC_COLLATE=C
+ ble/highlight/layer:plain/update/.getch
+ _ble_highlight_layer_plain_buff[i]=$ch
+ done
+ fi
+ PREV_BUFF=_ble_highlight_layer_plain_buff
+ ((PREV_UMIN=DMIN,PREV_UMAX=DMAX))
+}
+ble/function#suppress-stderr ble/highlight/layer:plain/update
+function ble/highlight/layer:plain/getg {
+ g=0
+}
+function ble/color/defface.onload {
+ ble/color/defface region bg=60,fg=white
+ ble/color/defface region_target bg=153,fg=black
+ ble/color/defface region_match bg=55,fg=white
+ ble/color/defface region_insert fg=12,bg=252
+ ble/color/defface disabled fg=242
+ ble/color/defface overwrite_mode fg=black,bg=51
+}
+blehook color_defface_load+=ble/color/defface.onload
+_ble_highlight_layer_region_VARNAMES=(
+ _ble_highlight_layer_region_buff
+ _ble_highlight_layer_region_osel
+ _ble_highlight_layer_region_osgr)
+function ble/highlight/layer:region/initialize-vars {
+ _ble_highlight_layer_region_buff=()
+ _ble_highlight_layer_region_osel=()
+ _ble_highlight_layer_region_osgr=
+}
+ble/highlight/layer:region/initialize-vars
+function ble/highlight/layer:region/.update-dirty-range {
+ local a=$1 b=$2 p q
+ ((a==b)) && return 0
+ (((a<b?(p=a,q=b):(p=b,q=a)),
+ (umin<0||umin>p)&&(umin=p),
+ (umax<0||umax<q)&&(umax=q)))
+}
+function ble/highlight/layer:region/update {
+ local IFS=$_ble_term_IFS
+ local omin=-1 omax=-1 osgr= olen=${#_ble_highlight_layer_region_osel[@]}
+ if ((olen)); then
+ omin=${_ble_highlight_layer_region_osel[0]}
+ omax=${_ble_highlight_layer_region_osel[olen-1]}
+ osgr=$_ble_highlight_layer_region_osgr
+ fi
+ if ((DMIN>=0)); then
+ ((DMAX0<=omin?(omin+=DMAX-DMAX0):(DMIN<omin&&(omin=DMIN)),
+ DMAX0<=omax?(omax+=DMAX-DMAX0):(DMIN<omax&&(omax=DMIN))))
+ fi
+ local sgr=
+ local -a selection=()
+ if [[ $_ble_edit_mark_active ]]; then
+ if ! ble/function#try ble/highlight/layer:region/mark:"$_ble_edit_mark_active"/get-selection; then
+ if ((_ble_edit_mark>_ble_edit_ind)); then
+ selection=("$_ble_edit_ind" "$_ble_edit_mark")
+ elif ((_ble_edit_mark<_ble_edit_ind)); then
+ selection=("$_ble_edit_mark" "$_ble_edit_ind")
+ fi
+ fi
+ local face=region
+ ble/function#try ble/highlight/layer:region/mark:"$_ble_edit_mark_active"/get-face
+ local ret; ble/color/face2sgr "$face"; sgr=$ret
+ fi
+ local rlen=${#selection[@]}
+ if ((DMIN<0&&(PREV_UMIN<0||${#selection[*]}>=2&&selection[0]<=PREV_UMIN&&PREV_UMAX<=selection[1]))); then
+ if [[ $sgr == "$osgr" && ${selection[*]} == "${_ble_highlight_layer_region_osel[*]}" ]]; then
+ [[ ${selection[*]} ]] && PREV_BUFF=_ble_highlight_layer_region_buff
+ return 0
+ fi
+ else
+ [[ ! ${selection[*]} && ! ${_ble_highlight_layer_region_osel[*]} ]] && return 0
+ fi
+ local umin=-1 umax=-1
+ if ((rlen)); then
+ local rmin=${selection[0]}
+ local rmax=${selection[rlen-1]}
+ local -a buff=()
+ local g ret
+ local k=0 inext iprev=0
+ for inext in "${selection[@]}"; do
+ if ((inext>iprev)); then
+ if ((k==0)); then
+ ble/array#push buff "\"\${$PREV_BUFF[@]::$inext}\""
+ elif ((k%2)); then
+ ble/array#push buff "\"$sgr\${_ble_highlight_layer_plain_buff[@]:$iprev:$((inext-iprev))}\""
+ else
+ ble/highlight/layer/update/getg "$iprev"
+ ble/color/g2sgr "$g"
+ ble/array#push buff "\"$ret\${$PREV_BUFF[@]:$iprev:$((inext-iprev))}\""
+ fi
+ fi
+ ((iprev=inext,k++))
+ done
+ ble/highlight/layer/update/getg "$iprev"
+ ble/color/g2sgr "$g"
+ ble/array#push buff "\"$ret\${$PREV_BUFF[@]:$iprev}\""
+ builtin eval "_ble_highlight_layer_region_buff=(${buff[*]})"
+ PREV_BUFF=_ble_highlight_layer_region_buff
+ if ((DMIN>=0)); then
+ ble/highlight/layer:region/.update-dirty-range "$DMIN" "$DMAX"
+ fi
+ if ((omin>=0)); then
+ if [[ $osgr != "$sgr" ]]; then
+ ble/highlight/layer:region/.update-dirty-range "$omin" "$omax"
+ ble/highlight/layer:region/.update-dirty-range "$rmin" "$rmax"
+ else
+ ble/highlight/layer:region/.update-dirty-range "$omin" "$rmin"
+ ble/highlight/layer:region/.update-dirty-range "$omax" "$rmax"
+ if ((olen>1||rlen>1)); then
+ ble/highlight/layer:region/.update-dirty-range "$rmin" "$rmax"
+ fi
+ fi
+ else
+ ble/highlight/layer:region/.update-dirty-range "$rmin" "$rmax"
+ fi
+ local pmin=$PREV_UMIN pmax=$PREV_UMAX
+ if ((rlen==2)); then
+ ((rmin<=pmin&&pmin<rmax&&(pmin=rmax),
+ rmin<pmax&&pmax<=rmax&&(pmax=rmin)))
+ fi
+ ble/highlight/layer:region/.update-dirty-range "$pmin" "$pmax"
+ else
+ umin=$PREV_UMIN umax=$PREV_UMAX
+ ble/highlight/layer:region/.update-dirty-range "$omin" "$omax"
+ fi
+ _ble_highlight_layer_region_osel=("${selection[@]}")
+ _ble_highlight_layer_region_osgr=$sgr
+ ((PREV_UMIN=umin,
+ PREV_UMAX=umax))
+}
+function ble/highlight/layer:region/getg {
+ if [[ $_ble_edit_mark_active ]]; then
+ local index=$1 olen=${#_ble_highlight_layer_region_osel[@]}
+ ((olen)) || return 1
+ ((_ble_highlight_layer_region_osel[0]<=index&&index<_ble_highlight_layer_region_osel[olen-1])) || return 1
+ local flag_region=
+ if ((olen>=4)); then
+ local l=0 u=$((olen-1)) m
+ while ((l+1<u)); do
+ ((_ble_highlight_layer_region_osel[m=(l+u)/2]<=index?(l=m):(u=m)))
+ done
+ ((l%2==0)) && flag_region=1
+ else
+ flag_region=1
+ fi
+ if [[ $flag_region ]]; then
+ local face=region
+ ble/function#try ble/highlight/layer:region/mark:"$_ble_edit_mark_active"/get-face
+ local ret; ble/color/face2g "$face"; g=$ret
+ fi
+ fi
+}
+_ble_highlight_layer_disabled_VARNAMES=(
+ _ble_highlight_layer_disabled_prev
+ _ble_highlight_layer_disabled_buff)
+function ble/highlight/layer:disabled/initialize-vars {
+ _ble_highlight_layer_disabled_prev=
+ _ble_highlight_layer_disabled_buff=()
+}
+ble/highlight/layer:disabled/initialize-vars
+function ble/highlight/layer:disabled/update {
+ if [[ $_ble_edit_line_disabled ]]; then
+ if ((DMIN>=0)) || [[ ! $_ble_highlight_layer_disabled_prev ]]; then
+ local ret; ble/color/face2sgr disabled; local sgr=$ret
+ _ble_highlight_layer_disabled_buff=("$sgr""${_ble_highlight_layer_plain_buff[@]}")
+ fi
+ PREV_BUFF=_ble_highlight_layer_disabled_buff
+ if [[ $_ble_highlight_layer_disabled_prev ]]; then
+ PREV_UMIN=$DMIN PREV_UMAX=$DMAX
+ else
+ PREV_UMIN=0 PREV_UMAX=${#1}
+ fi
+ else
+ if [[ $_ble_highlight_layer_disabled_prev ]]; then
+ PREV_UMIN=0 PREV_UMAX=${#1}
+ fi
+ fi
+ _ble_highlight_layer_disabled_prev=$_ble_edit_line_disabled
+}
+function ble/highlight/layer:disabled/getg {
+ if [[ $_ble_highlight_layer_disabled_prev ]]; then
+ local ret; ble/color/face2g disabled; g=$ret
+ fi
+}
+_ble_highlight_layer_overwrite_mode_VARNAMES=(
+ _ble_highlight_layer_overwrite_mode_index
+ _ble_highlight_layer_overwrite_mode_buff)
+function ble/highlight/layer:overwrite_mode/initialize-vars {
+ _ble_highlight_layer_overwrite_mode_index=-1
+ _ble_highlight_layer_overwrite_mode_buff=()
+}
+ble/highlight/layer:overwrite_mode/initialize-vars
+function ble/highlight/layer:overwrite_mode/update {
+ local oindex=$_ble_highlight_layer_overwrite_mode_index
+ if ((DMIN>=0)); then
+ if ((oindex>=DMAX0)); then
+ ((oindex+=DMAX-DMAX0))
+ elif ((oindex>=DMIN)); then
+ oindex=-1
+ fi
+ fi
+ local index=-1
+ if [[ $_ble_edit_overwrite_mode && ! $_ble_edit_mark_active ]]; then
+ local next=${_ble_edit_str:_ble_edit_ind:1}
+ if [[ $next && $next != [$'\n\t'] ]]; then
+ index=$_ble_edit_ind
+ local g ret
+ if ((PREV_UMIN<0&&oindex>=0)); then
+ ble/highlight/layer/update/getg "$oindex"
+ ble/color/g2sgr "$g"
+ _ble_highlight_layer_overwrite_mode_buff[oindex]=$ret${_ble_highlight_layer_plain_buff[oindex]}
+ else
+ builtin eval "_ble_highlight_layer_overwrite_mode_buff=(\"\${$PREV_BUFF[@]}\")"
+ fi
+ PREV_BUFF=_ble_highlight_layer_overwrite_mode_buff
+ ble/color/face2g overwrite_mode
+ ble/color/g2sgr "$ret"
+ _ble_highlight_layer_overwrite_mode_buff[index]=$ret${_ble_highlight_layer_plain_buff[index]}
+ if ((index+1<${#1})); then
+ ble/highlight/layer/update/getg $((index+1))
+ ble/color/g2sgr "$g"
+ _ble_highlight_layer_overwrite_mode_buff[index+1]=$ret${_ble_highlight_layer_plain_buff[index+1]}
+ fi
+ fi
+ fi
+ if ((index>=0)); then
+ ble/term/cursor-state/hide
+ else
+ ble/term/cursor-state/reveal
+ fi
+ if ((index!=oindex)); then
+ ((oindex>=0)) && ble/highlight/layer/update/add-urange "$oindex" $((oindex+1))
+ ((index>=0)) && ble/highlight/layer/update/add-urange "$index" $((index+1))
+ fi
+ _ble_highlight_layer_overwrite_mode_index=$index
+}
+function ble/highlight/layer:overwrite_mode/getg {
+ local index=$_ble_highlight_layer_overwrite_mode_index
+ if ((index>=0&&index==$1)); then
+ local ret; ble/color/face2g overwrite_mode; g=$ret
+ fi
+}
+_ble_highlight_layer_RandomColor_VARNAMES=(
+ _ble_highlight_layer_RandomColor_buff)
+function ble/highlight/layer:RandomColor/initialize-vars {
+ _ble_highlight_layer_RandomColor_buff=()
+}
+ble/highlight/layer:RandomColor/initialize-vars
+function ble/highlight/layer:RandomColor/update {
+ local text=$1 ret i
+ _ble_highlight_layer_RandomColor_buff=()
+ for ((i=0;i<${#text};i++)); do
+ ble/color/gspec2sgr "fg=$((RANDOM%256))"
+ _ble_highlight_layer_RandomColor_buff[i]=$ret${_ble_highlight_layer_plain_buff[i]}
+ done
+ PREV_BUFF=_ble_highlight_layer_RandomColor_buff
+ ((PREV_UMIN=0,PREV_UMAX=${#text}))
+}
+function ble/highlight/layer:RandomColor/getg {
+ local ret; ble/color/gspec2g "fg=$((RANDOM%256))"; g=$ret
+}
+_ble_highlight_layer_RandomColor2_buff=()
+function ble/highlight/layer:RandomColor2/update {
+ local text=$1 ret i x
+ ble/highlight/layer/update/shift _ble_highlight_layer_RandomColor2_buff
+ for ((i=DMIN;i<DMAX;i++)); do
+ ble/color/gspec2sgr "fg=$((16+(x=RANDOM%27)*4-x%9*2-x%3))"
+ _ble_highlight_layer_RandomColor2_buff[i]=$ret${_ble_highlight_layer_plain_buff[i]}
+ done
+ PREV_BUFF=_ble_highlight_layer_RandomColor2_buff
+ ((PREV_UMIN=0,PREV_UMAX=${#text}))
+}
+function ble/highlight/layer:RandomColor2/getg {
+ local x ret
+ ble/color/gspec2g "fg=$((16+(x=RANDOM%27)*4-x%9*2-x%3))"; g=$ret
+}
+_ble_highlight_layer__list=(plain syntax region overwrite_mode disabled)
+bleopt/declare -v tab_width ''
+function bleopt/check:tab_width {
+ if [[ $value ]] && (((value=value)<=0)); then
+ ble/util/print "bleopt: an empty string or a positive value is required for tab_width." >&2
+ return 1
+ fi
+}
+function ble/arithmetic/sum {
+ IFS=+ builtin eval 'let "ret=$*+0"'
+}
+_ble_util_c2w=()
+_ble_util_c2w_cache=()
+function ble/util/c2w/clear-cache {
+ _ble_util_c2w_cache=()
+}
+bleopt/declare -n char_width_mode auto
+function bleopt/check:char_width_mode {
+ if ! ble/is-function "ble/util/c2w:$value"; then
+ ble/util/print "bleopt: Invalid value char_width_mode='$value'. A function 'ble/util/c2w:$value' is not defined." >&2
+ return 1
+ fi
+ case $value in
+ (auto)
+ _ble_unicode_c2w_ambiguous=1
+ ble && ble/util/c2w:auto/test.buff first-line ;;
+ (west) _ble_unicode_c2w_ambiguous=1 ;;
+ (east) _ble_unicode_c2w_ambiguous=2 ;;
+ esac
+ ((_ble_prompt_version++))
+ ble/util/c2w/clear-cache
+}
+function ble/util/c2w {
+ ret=${_ble_util_c2w_cache[$1]:-${_ble_util_c2w[$1]}}
+ if [[ ! $ret ]]; then
+ "ble/util/c2w:$bleopt_char_width_mode" "$1"
+ _ble_util_c2w_cache[$1]=$ret
+ fi
+}
+function ble/util/c2w-edit {
+ local cs=${_ble_unicode_GraphemeCluster_ControlRepresentation[$1]}
+ if [[ $cs ]]; then
+ ret=${#cs}
+ elif (($1<32||127<=$1&&$1<160)); then
+ ret=2
+ ((128<=$1&&(ret=4)))
+ else
+ ble/util/c2w "$1"
+ fi
+}
+function ble/util/s2w-edit {
+ local text=$1 iN=${#1} flags=$2 i
+ ret=0
+ for ((i=0;i<iN;i++)); do
+ local c w cs cb extend
+ ble/unicode/GraphemeCluster/match "$text" "$i" "$flags"
+ ((ret+=w,i+=extend))
+ done
+}
+function ble/util/s2w {
+ ble/util/s2w-edit "$1" R
+}
+_ble_unicode_c2w_UnicodeVersionCount=16
+_ble_unicode_c2w_UnicodeVersionMapping=(
+ 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0
+ -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0
+ -1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0
+ -1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 1 1
+ -1 -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1 1
+ -1 -1 -1 -1 1 1 1 0 0 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 1 0 0 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1
+ -1 -1 -1 1 1 1 1 0 0 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 0
+ -1 -1 1 1 1 1 1 0 0 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 1 1 1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0
+ -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 1 1 1 1 1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 1 1 1 1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0
+ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+ -1 -1 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+ -1 -1 2 2 2 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1
+ 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0
+ -1 -1 -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1
+ -1 -1 3 3 3 3 3 3 3 3 3 3 3 3 3 3
+ 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ -1 -1 -1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2
+ -1 -1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ -1 -1 3 3 3 3 3 3 3 2 2 2 2 2 2 2
+ -1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0
+ -1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2 2
+ -1 -1 -1 2 2 2 2 2 2 2 2 2 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2
+ -1 -1 2 2 2 2 2 -2 -2 -2 -2 -2 -2 -2 2 2
+ -1 -1 2 2 2 2 2 -2 2 2 2 2 2 2 2 2
+ -1 -1 2 2 2 2 2 -2 -2 -2 2 2 2 2 2 2
+ -1 -1 2 2 2 2 2 -2 -2 -2 -2 2 2 2 2 2
+ -1 -1 2 2 2 2 2 -2 -2 -2 -2 -2 -2 -2 -2 2
+ -1 -1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
+ -1 -1 2 2 2 2 2 -2 -2 -2 -2 -2 -2 -2 -2 -2
+ -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 0 0 0 0 0
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2
+ -1 -1 -1 3 3 3 3 3 3 3 3 3 3 3 3 3
+ -1 -1 -1 3 3 3 3 3 3 2 2 2 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 3 3 3 3 3 3 3
+ -1 -1 -1 -1 -1 -1 -1 -1 1 2 2 2 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 1 1 2 2 2 2 2 2 2
+ -1 -1 -1 -1 1 1 1 1 1 2 2 2 2 2 2 2
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2 2 1 1
+ 2 2 2 2 2 2 2 -2 -2 -2 -2 -2 -2 -2 2 2
+ 2 2 2 2 2 2 2 -2 -2 -2 -2 -2 -2 -2 -2 2
+ 2 2 2 2 2 2 2 -2 -2 -2 -2 -2 -2 -2 -2 -2
+ 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 -2 -2 -2 2 2 2 2 2 2
+)
+_ble_unicode_c2w=([0]=0 [32]=1 [127]=0 [160]=1 [161]=2 [162]=1 [164]=2 [165]=1 [167]=2 [169]=1 [170]=2 [171]=1 [173]=3 [174]=2
+ [175]=1 [176]=2 [181]=1 [182]=2 [187]=1 [188]=2 [192]=1 [198]=2 [199]=1 [208]=2 [209]=1 [215]=2 [217]=1 [222]=2 [226]=1 [230]=2
+ [231]=1 [232]=2 [235]=1 [236]=2 [238]=1 [240]=2 [241]=1 [242]=2 [244]=1 [247]=2 [251]=1 [252]=2 [253]=1 [254]=2 [255]=1 [257]=2
+ [258]=1 [273]=2 [274]=1 [275]=2 [276]=1 [283]=2 [284]=1 [294]=2 [296]=1 [299]=2 [300]=1 [305]=2 [308]=1 [312]=2 [313]=1 [319]=2
+ [323]=1 [324]=2 [325]=1 [328]=2 [332]=1 [333]=2 [334]=1 [338]=2 [340]=1 [358]=2 [360]=1 [363]=2 [364]=1 [462]=2 [463]=1 [464]=2
+ [465]=1 [466]=2 [467]=1 [468]=2 [469]=1 [470]=2 [471]=1 [472]=2 [473]=1 [474]=2 [475]=1 [476]=2 [477]=1 [578]=4 [592]=1 [593]=2
+ [594]=1 [609]=2 [610]=1 [708]=2 [709]=1 [711]=2 [712]=1 [713]=2 [716]=1 [717]=2 [718]=1 [720]=2 [721]=1 [728]=2 [732]=1 [733]=2
+ [734]=1 [735]=2 [736]=1 [768]=3 [880]=4 [884]=1 [886]=4 [888]=5 [890]=1 [891]=4 [894]=1 [895]=6 [896]=5 [900]=1 [907]=5 [908]=1
+ [909]=5 [910]=1 [913]=2 [930]=5 [931]=2 [938]=1 [945]=2 [962]=1 [963]=2 [970]=1 [975]=4 [976]=1 [1025]=2 [1026]=1 [1040]=2
+ [1104]=1 [1105]=2 [1106]=1 [1155]=7 [1159]=8 [1160]=7 [1162]=1 [1231]=4 [1232]=1 [1274]=4 [1280]=1 [1296]=4 [1316]=9 [1318]=10
+ [1320]=6 [1328]=5 [1329]=1 [1367]=5 [1369]=1 [1376]=11 [1377]=1 [1416]=11 [1417]=1 [1419]=5 [1421]=6 [1423]=12 [1424]=5 [1425]=7
+ [1466]=8 [1467]=7 [1470]=1 [1471]=7 [1472]=1 [1473]=7 [1475]=1 [1476]=7 [1478]=1 [1479]=7 [1480]=5 [1488]=1 [1515]=5 [1519]=11
+ [1520]=1 [1525]=5 [1536]=7 [1540]=13 [1541]=14 [1542]=4 [1547]=1 [1552]=7 [1558]=8 [1563]=1 [1564]=15 [1565]=16 [1566]=1
+ [1568]=10 [1569]=1 [1595]=4 [1600]=1 [1611]=7 [1631]=17 [1632]=1 [1648]=7 [1649]=1 [1750]=7 [1758]=1 [1759]=7 [1765]=1 [1767]=7
+ [1769]=1 [1770]=7 [1774]=1 [1806]=5 [1807]=7 [1808]=1 [1809]=7 [1810]=1 [1840]=7 [1867]=5 [1869]=1 [1902]=4 [1920]=1 [1958]=7
+ [1969]=1 [1970]=5 [1984]=4 [2027]=8 [2036]=4 [2043]=5 [2045]=18 [2046]=11 [2048]=9 [2070]=19 [2074]=9 [2075]=19 [2084]=9
+ [2085]=19 [2088]=9 [2089]=19 [2094]=5 [2096]=9 [2111]=5 [2112]=10 [2137]=17 [2140]=5 [2142]=10 [2143]=5 [2144]=20 [2155]=5
+ [2160]=16 [2191]=5 [2192]=21 [2194]=5 [2200]=21 [2208]=12 [2209]=6 [2210]=12 [2221]=6 [2227]=22 [2229]=16 [2230]=23 [2238]=24
+ [2248]=16 [2250]=21 [2259]=18 [2260]=25 [2275]=26 [2276]=13 [2303]=14 [2304]=19 [2305]=7 [2307]=1 [2362]=17 [2363]=10 [2364]=7
+ [2365]=1 [2369]=7 [2377]=1 [2381]=7 [2382]=9 [2383]=10 [2384]=1 [2385]=7 [2389]=19 [2390]=17 [2392]=1 [2402]=7 [2404]=1 [2417]=4
+ [2419]=10 [2424]=6 [2425]=9 [2427]=4 [2429]=1 [2430]=4 [2432]=6 [2433]=7 [2434]=1 [2436]=5 [2437]=1 [2445]=5 [2447]=1 [2449]=5
+ [2451]=1 [2473]=5 [2474]=1 [2481]=5 [2482]=1 [2483]=5 [2486]=1 [2490]=5 [2492]=7 [2493]=1 [2497]=7 [2501]=5 [2503]=1 [2505]=5
+ [2507]=1 [2509]=7 [2510]=1 [2511]=5 [2519]=1 [2520]=5 [2524]=1 [2526]=5 [2527]=1 [2530]=7 [2532]=5 [2534]=1 [2555]=9 [2556]=20
+ [2558]=18 [2559]=5 [2561]=7 [2563]=1 [2564]=5 [2565]=1 [2571]=5 [2575]=1 [2577]=5 [2579]=1 [2601]=5 [2602]=1 [2609]=5 [2610]=1
+ [2612]=5 [2613]=1 [2615]=5 [2616]=1 [2618]=5 [2620]=7 [2621]=5 [2622]=1 [2625]=7 [2627]=5 [2631]=7 [2633]=5 [2635]=7 [2638]=5
+ [2641]=8 [2642]=5 [2649]=1 [2653]=5 [2654]=1 [2655]=5 [2662]=1 [2672]=7 [2674]=1 [2677]=8 [2678]=11 [2679]=5 [2689]=7 [2691]=1
+ [2692]=5 [2693]=1 [2702]=5 [2703]=1 [2706]=5 [2707]=1 [2729]=5 [2730]=1 [2737]=5 [2738]=1 [2740]=5 [2741]=1 [2746]=5 [2748]=7
+ [2749]=1 [2753]=7 [2758]=5 [2759]=7 [2761]=1 [2762]=5 [2763]=1 [2765]=7 [2766]=5 [2768]=1 [2769]=5 [2784]=1 [2786]=7 [2788]=5
+ [2790]=1 [2800]=12 [2801]=1 [2802]=5 [2809]=22 [2810]=27 [2816]=5 [2817]=7 [2818]=1 [2820]=5 [2821]=1 [2829]=5 [2831]=1 [2833]=5
+ [2835]=1 [2857]=5 [2858]=1 [2865]=5 [2866]=1 [2868]=5 [2869]=1 [2874]=5 [2876]=7 [2877]=1 [2879]=7 [2880]=1 [2881]=7 [2884]=8
+ [2885]=5 [2887]=1 [2889]=5 [2891]=1 [2893]=7 [2894]=5 [2901]=28 [2902]=7 [2903]=1 [2904]=5 [2908]=1 [2910]=5 [2911]=1 [2914]=8
+ [2916]=5 [2918]=1 [2930]=10 [2936]=5 [2946]=7 [2947]=1 [2948]=5 [2949]=1 [2955]=5 [2958]=1 [2961]=5 [2962]=1 [2966]=5 [2969]=1
+ [2971]=5 [2972]=1 [2973]=5 [2974]=1 [2976]=5 [2979]=1 [2981]=5 [2984]=1 [2987]=5 [2990]=1 [3002]=5 [3006]=1 [3008]=7 [3009]=1
+ [3011]=5 [3014]=1 [3017]=5 [3018]=1 [3021]=7 [3022]=5 [3024]=4 [3025]=5 [3031]=1 [3032]=5 [3046]=1 [3067]=5 [3072]=14 [3073]=1
+ [3076]=18 [3077]=1 [3085]=5 [3086]=1 [3089]=5 [3090]=1 [3113]=5 [3114]=1 [3124]=6 [3125]=1 [3130]=5 [3132]=21 [3133]=4 [3134]=7
+ [3137]=1 [3141]=5 [3142]=7 [3145]=5 [3146]=7 [3150]=5 [3157]=7 [3159]=5 [3160]=4 [3162]=22 [3163]=5 [3165]=16 [3166]=5 [3168]=1
+ [3170]=8 [3172]=5 [3174]=1 [3184]=5 [3191]=29 [3192]=4 [3200]=23 [3201]=14 [3202]=1 [3204]=11 [3205]=1 [3213]=5 [3214]=1
+ [3217]=5 [3218]=1 [3241]=5 [3242]=1 [3252]=5 [3253]=1 [3258]=5 [3260]=7 [3261]=1 [3263]=7 [3264]=1 [3269]=5 [3270]=7 [3271]=1
+ [3273]=5 [3274]=1 [3276]=7 [3278]=5 [3285]=1 [3287]=5 [3293]=16 [3294]=1 [3295]=5 [3296]=1 [3298]=8 [3300]=5 [3302]=1 [3312]=5
+ [3313]=4 [3315]=5 [3328]=27 [3329]=14 [3330]=1 [3332]=24 [3333]=1 [3341]=5 [3342]=1 [3345]=5 [3346]=1 [3369]=10 [3370]=1
+ [3386]=10 [3387]=27 [3389]=4 [3390]=1 [3393]=7 [3396]=8 [3397]=5 [3398]=1 [3401]=5 [3402]=1 [3405]=7 [3406]=10 [3407]=23
+ [3408]=5 [3412]=23 [3415]=1 [3416]=23 [3423]=22 [3424]=1 [3426]=8 [3428]=5 [3430]=1 [3440]=4 [3446]=23 [3449]=4 [3456]=5
+ [3457]=28 [3458]=1 [3460]=5 [3461]=1 [3479]=5 [3482]=1 [3506]=5 [3507]=1 [3516]=5 [3517]=1 [3518]=5 [3520]=1 [3527]=5 [3530]=7
+ [3531]=5 [3535]=1 [3538]=7 [3541]=5 [3542]=7 [3543]=5 [3544]=1 [3552]=5 [3558]=6 [3568]=5 [3570]=1 [3573]=5 [3585]=1 [3633]=7
+ [3634]=1 [3636]=7 [3643]=5 [3647]=1 [3655]=7 [3663]=1 [3676]=5 [3713]=1 [3715]=5 [3716]=1 [3717]=5 [3718]=29 [3719]=1 [3721]=29
+ [3722]=1 [3723]=5 [3724]=29 [3725]=1 [3726]=29 [3732]=1 [3736]=29 [3737]=1 [3744]=29 [3745]=1 [3748]=5 [3749]=1 [3750]=5
+ [3751]=1 [3752]=29 [3754]=1 [3756]=29 [3757]=1 [3761]=7 [3762]=1 [3764]=7 [3770]=30 [3771]=7 [3773]=1 [3774]=5 [3776]=1 [3781]=5
+ [3782]=1 [3783]=5 [3784]=7 [3790]=5 [3792]=1 [3802]=5 [3804]=1 [3806]=12 [3808]=5 [3840]=1 [3864]=7 [3866]=1 [3893]=7 [3894]=1
+ [3895]=7 [3896]=1 [3897]=7 [3898]=1 [3912]=5 [3913]=1 [3947]=4 [3949]=5 [3953]=7 [3967]=1 [3968]=7 [3973]=1 [3974]=7 [3976]=1
+ [3980]=10 [3981]=17 [3984]=7 [3992]=5 [3993]=7 [4029]=5 [4030]=1 [4038]=7 [4039]=1 [4045]=5 [4046]=4 [4047]=1 [4050]=4 [4053]=9
+ [4057]=10 [4059]=5 [4096]=1 [4130]=4 [4131]=1 [4136]=4 [4137]=1 [4139]=4 [4140]=1 [4141]=7 [4145]=1 [4146]=7 [4147]=8 [4150]=7
+ [4152]=1 [4153]=7 [4154]=8 [4155]=4 [4157]=8 [4159]=4 [4160]=1 [4184]=7 [4186]=4 [4190]=8 [4193]=4 [4209]=8 [4213]=4 [4226]=8
+ [4227]=4 [4229]=8 [4231]=4 [4237]=8 [4238]=4 [4250]=9 [4253]=19 [4254]=4 [4256]=1 [4294]=5 [4295]=12 [4296]=5 [4301]=12 [4302]=5
+ [4304]=1 [4349]=12 [4352]=31 [4442]=32 [4447]=31 [4448]=1 [4515]=33 [4520]=1 [4602]=33 [4608]=1 [4681]=5 [4682]=1 [4686]=5
+ [4688]=1 [4695]=5 [4696]=1 [4697]=5 [4698]=1 [4702]=5 [4704]=1 [4745]=5 [4746]=1 [4750]=5 [4752]=1 [4785]=5 [4786]=1 [4790]=5
+ [4792]=1 [4799]=5 [4800]=1 [4801]=5 [4802]=1 [4806]=5 [4808]=1 [4823]=5 [4824]=1 [4881]=5 [4882]=1 [4886]=5 [4888]=1 [4955]=5
+ [4957]=17 [4959]=7 [4960]=1 [4989]=5 [4992]=1 [5018]=5 [5024]=1 [5109]=22 [5110]=5 [5112]=22 [5118]=5 [5120]=9 [5121]=1 [5751]=9
+ [5760]=1 [5789]=5 [5792]=1 [5873]=6 [5881]=5 [5888]=1 [5901]=16 [5902]=1 [5906]=7 [5909]=16 [5910]=5 [5919]=16 [5920]=1 [5938]=7
+ [5940]=34 [5941]=1 [5943]=5 [5952]=1 [5970]=7 [5972]=5 [5984]=1 [5997]=5 [5998]=1 [6001]=5 [6002]=7 [6004]=5 [6016]=1 [6068]=7
+ [6070]=1 [6071]=7 [6078]=1 [6086]=7 [6087]=1 [6089]=7 [6100]=1 [6109]=7 [6110]=5 [6112]=1 [6122]=5 [6128]=1 [6138]=5 [6144]=1
+ [6155]=7 [6159]=21 [6160]=1 [6170]=5 [6176]=1 [6264]=11 [6265]=5 [6272]=1 [6277]=35 [6279]=1 [6313]=7 [6314]=4 [6315]=5 [6320]=9
+ [6390]=5 [6400]=1 [6429]=6 [6431]=5 [6432]=7 [6435]=1 [6439]=7 [6441]=1 [6444]=5 [6448]=1 [6450]=7 [6451]=1 [6457]=7 [6460]=5
+ [6464]=1 [6465]=5 [6468]=1 [6510]=5 [6512]=1 [6517]=5 [6528]=1 [6570]=9 [6572]=5 [6576]=1 [6602]=5 [6608]=1 [6618]=9 [6619]=5
+ [6622]=1 [6679]=7 [6681]=1 [6683]=7 [6684]=5 [6686]=1 [6688]=9 [6742]=19 [6743]=9 [6744]=19 [6751]=5 [6752]=19 [6753]=9
+ [6754]=19 [6755]=9 [6757]=19 [6765]=9 [6771]=19 [6781]=5 [6783]=19 [6784]=9 [6794]=5 [6800]=9 [6810]=5 [6816]=9 [6830]=5
+ [6832]=14 [6847]=28 [6849]=21 [6863]=5 [6912]=8 [6916]=4 [6964]=8 [6965]=4 [6966]=8 [6971]=4 [6972]=8 [6973]=4 [6978]=8 [6979]=4
+ [6988]=16 [6989]=5 [6992]=4 [7019]=8 [7028]=4 [7037]=16 [7039]=5 [7040]=8 [7042]=4 [7074]=8 [7078]=4 [7080]=8 [7082]=4 [7083]=13
+ [7086]=4 [7098]=12 [7104]=10 [7142]=17 [7143]=10 [7144]=17 [7146]=10 [7149]=17 [7150]=10 [7151]=17 [7154]=10 [7156]=5 [7164]=10
+ [7168]=4 [7212]=8 [7220]=4 [7222]=8 [7224]=5 [7227]=4 [7242]=5 [7245]=4 [7296]=23 [7305]=5 [7312]=11 [7355]=5 [7357]=11
+ [7360]=12 [7368]=5 [7376]=19 [7379]=9 [7380]=19 [7393]=9 [7394]=19 [7401]=9 [7405]=19 [7406]=9 [7411]=12 [7412]=13 [7413]=12
+ [7415]=20 [7416]=14 [7418]=29 [7419]=5 [7424]=1 [7616]=7 [7620]=8 [7655]=14 [7670]=27 [7674]=21 [7675]=25 [7676]=17 [7677]=19
+ [7678]=8 [7680]=1 [7836]=4 [7840]=1 [7930]=4 [7936]=1 [7958]=5 [7960]=1 [7966]=5 [7968]=1 [8006]=5 [8008]=1 [8014]=5 [8016]=1
+ [8024]=5 [8025]=1 [8026]=5 [8027]=1 [8028]=5 [8029]=1 [8030]=5 [8031]=1 [8062]=5 [8064]=1 [8117]=5 [8118]=1 [8133]=5 [8134]=1
+ [8148]=5 [8150]=1 [8156]=5 [8157]=1 [8176]=5 [8178]=1 [8181]=5 [8182]=1 [8191]=5 [8192]=1 [8203]=7 [8208]=2 [8209]=1 [8211]=2
+ [8215]=1 [8216]=2 [8218]=1 [8220]=2 [8222]=1 [8224]=2 [8227]=1 [8228]=2 [8232]=0 [8234]=7 [8239]=1 [8240]=2 [8241]=1 [8242]=2
+ [8244]=1 [8245]=2 [8246]=1 [8251]=2 [8252]=1 [8254]=2 [8255]=1 [8288]=7 [8292]=8 [8293]=5 [8294]=15 [8298]=7 [8304]=1 [8306]=5
+ [8308]=2 [8309]=1 [8319]=2 [8320]=1 [8321]=2 [8325]=1 [8335]=5 [8336]=1 [8341]=10 [8349]=5 [8352]=1 [8364]=2 [8365]=1 [8374]=9
+ [8377]=10 [8378]=36 [8379]=6 [8382]=22 [8383]=20 [8384]=16 [8385]=5 [8400]=7 [8428]=8 [8433]=5 [8448]=1 [8451]=2 [8452]=1
+ [8453]=2 [8454]=1 [8457]=2 [8458]=1 [8467]=2 [8468]=1 [8470]=2 [8471]=1 [8481]=2 [8483]=1 [8486]=2 [8487]=1 [8491]=2 [8492]=1
+ [8525]=4 [8528]=9 [8531]=2 [8533]=1 [8539]=2 [8543]=1 [8544]=2 [8556]=1 [8560]=2 [8570]=1 [8580]=4 [8585]=37 [8586]=22 [8588]=5
+ [8592]=2 [8602]=1 [8632]=2 [8634]=1 [8658]=2 [8659]=1 [8660]=2 [8661]=1 [8679]=2 [8680]=1 [8704]=2 [8705]=1 [8706]=2 [8708]=1
+ [8711]=2 [8713]=1 [8715]=2 [8716]=1 [8719]=2 [8720]=1 [8721]=2 [8722]=1 [8725]=2 [8726]=1 [8730]=2 [8731]=1 [8733]=2 [8737]=1
+ [8739]=2 [8740]=1 [8741]=2 [8742]=1 [8743]=2 [8749]=1 [8750]=2 [8751]=1 [8756]=2 [8760]=1 [8764]=2 [8766]=1 [8776]=2 [8777]=1
+ [8780]=2 [8781]=1 [8786]=2 [8787]=1 [8800]=2 [8802]=1 [8804]=2 [8808]=1 [8810]=2 [8812]=1 [8814]=2 [8816]=1 [8834]=2 [8836]=1
+ [8838]=2 [8840]=1 [8853]=2 [8854]=1 [8857]=2 [8858]=1 [8869]=2 [8870]=1 [8895]=2 [8896]=1 [8978]=2 [8979]=1 [8986]=38 [8988]=1
+ [9001]=31 [9003]=1 [9180]=4 [9192]=9 [9193]=39 [9197]=10 [9200]=39 [9201]=10 [9203]=39 [9204]=6 [9211]=23 [9215]=20 [9216]=1
+ [9255]=5 [9280]=1 [9291]=5 [9312]=2 [9450]=1 [9451]=2 [9548]=1 [9552]=2 [9588]=1 [9600]=2 [9616]=1 [9618]=2 [9622]=1 [9632]=2
+ [9634]=1 [9635]=2 [9642]=1 [9650]=2 [9652]=1 [9654]=2 [9656]=1 [9660]=2 [9662]=1 [9664]=2 [9666]=1 [9670]=2 [9673]=1 [9675]=2
+ [9676]=1 [9678]=2 [9682]=1 [9698]=2 [9702]=1 [9711]=2 [9712]=1 [9725]=38 [9727]=1 [9733]=2 [9735]=1 [9737]=2 [9738]=1 [9742]=2
+ [9744]=1 [9748]=40 [9750]=1 [9756]=2 [9757]=1 [9758]=2 [9759]=1 [9792]=2 [9793]=1 [9794]=2 [9795]=1 [9800]=38 [9812]=1 [9824]=2
+ [9826]=1 [9827]=2 [9830]=1 [9831]=2 [9835]=1 [9836]=2 [9838]=1 [9839]=2 [9840]=1 [9855]=38 [9856]=1 [9875]=38 [9876]=1 [9885]=4
+ [9886]=37 [9888]=1 [9889]=38 [9890]=1 [9898]=38 [9900]=1 [9906]=4 [9917]=41 [9918]=42 [9919]=37 [9920]=4 [9924]=42 [9926]=37
+ [9934]=39 [9935]=37 [9940]=42 [9941]=37 [9954]=10 [9955]=37 [9956]=10 [9960]=37 [9962]=42 [9963]=37 [9970]=42 [9972]=37
+ [9973]=42 [9974]=37 [9978]=42 [9979]=37 [9981]=42 [9982]=37 [9984]=6 [9985]=1 [9989]=39 [9990]=1 [9994]=39 [9996]=1 [10024]=39
+ [10025]=1 [10045]=2 [10046]=1 [10060]=39 [10061]=1 [10062]=39 [10063]=1 [10067]=39 [10070]=1 [10071]=42 [10072]=1 [10079]=10
+ [10081]=1 [10102]=2 [10112]=1 [10133]=39 [10136]=1 [10160]=39 [10161]=1 [10175]=39 [10176]=1 [10183]=4 [10187]=12 [10188]=4
+ [10189]=12 [10190]=10 [10192]=1 [10220]=4 [10224]=1 [11028]=4 [11035]=43 [11037]=4 [11085]=6 [11088]=43 [11089]=4 [11093]=42
+ [11094]=37 [11098]=6 [11124]=5 [11126]=6 [11158]=5 [11159]=24 [11160]=6 [11194]=11 [11197]=6 [11209]=29 [11210]=6 [11218]=20
+ [11219]=11 [11244]=22 [11248]=11 [11263]=29 [11264]=1 [11311]=16 [11312]=1 [11359]=16 [11360]=4 [11376]=9 [11377]=4 [11390]=9
+ [11392]=1 [11499]=9 [11503]=19 [11506]=12 [11508]=5 [11513]=1 [11558]=5 [11559]=12 [11560]=5 [11565]=12 [11566]=5 [11568]=1
+ [11622]=12 [11624]=5 [11631]=1 [11632]=10 [11633]=5 [11647]=17 [11648]=1 [11671]=5 [11680]=1 [11687]=5 [11688]=1 [11695]=5
+ [11696]=1 [11703]=5 [11704]=1 [11711]=5 [11712]=1 [11719]=5 [11720]=1 [11727]=5 [11728]=1 [11735]=5 [11736]=1 [11743]=5
+ [11744]=8 [11776]=1 [11800]=4 [11804]=1 [11806]=4 [11825]=9 [11826]=12 [11836]=6 [11843]=23 [11845]=20 [11850]=11 [11855]=29
+ [11856]=24 [11859]=16 [11870]=5 [11904]=31 [11930]=5 [11931]=31 [12020]=5 [12032]=31 [12246]=5 [12272]=31 [12284]=5 [12288]=31
+ [12330]=44 [12334]=31 [12351]=1 [12352]=5 [12353]=31 [12439]=5 [12441]=44 [12443]=31 [12544]=5 [12549]=31 [12589]=45 [12590]=46
+ [12591]=47 [12592]=5 [12593]=31 [12687]=5 [12688]=31 [12728]=48 [12731]=49 [12736]=31 [12752]=45 [12772]=5 [12784]=31 [12831]=5
+ [12832]=31 [12868]=32 [12872]=37 [12880]=31 [13055]=50 [13056]=31 [19894]=51 [19904]=1 [19968]=31 [40892]=45 [40900]=32
+ [40909]=52 [40918]=53 [40939]=54 [40944]=51 [40957]=55 [40960]=31 [42125]=5 [42128]=31 [42183]=5 [42192]=9 [42240]=4 [42540]=5
+ [42560]=4 [42592]=10 [42594]=4 [42607]=8 [42611]=4 [42612]=13 [42620]=8 [42622]=4 [42648]=6 [42654]=26 [42655]=13 [42656]=9
+ [42736]=19 [42738]=9 [42744]=5 [42752]=1 [42775]=4 [42893]=10 [42895]=22 [42896]=10 [42898]=12 [42900]=6 [42912]=10 [42922]=12
+ [42923]=6 [42926]=23 [42927]=11 [42928]=6 [42930]=22 [42936]=11 [42938]=29 [42944]=16 [42946]=29 [42951]=24 [42955]=5 [42960]=16
+ [42962]=5 [42963]=16 [42964]=5 [42965]=16 [42970]=5 [42994]=16 [42997]=24 [42999]=6 [43000]=12 [43002]=10 [43003]=4 [43008]=1
+ [43010]=7 [43011]=1 [43014]=7 [43015]=1 [43019]=7 [43020]=1 [43045]=7 [43047]=1 [43052]=28 [43053]=5 [43056]=9 [43066]=5
+ [43072]=4 [43128]=5 [43136]=4 [43204]=8 [43205]=25 [43206]=5 [43214]=4 [43226]=5 [43232]=19 [43250]=9 [43260]=22 [43262]=11
+ [43263]=18 [43264]=4 [43302]=8 [43310]=4 [43335]=8 [43346]=4 [43348]=5 [43359]=4 [43360]=32 [43389]=5 [43392]=19 [43395]=9
+ [43443]=19 [43444]=9 [43446]=19 [43450]=9 [43452]=19 [43453]=56 [43454]=9 [43470]=5 [43471]=9 [43482]=5 [43486]=9 [43488]=6
+ [43493]=14 [43494]=6 [43519]=5 [43520]=4 [43561]=8 [43567]=4 [43569]=8 [43571]=4 [43573]=8 [43575]=5 [43584]=4 [43587]=8
+ [43588]=4 [43596]=8 [43597]=4 [43598]=5 [43600]=4 [43610]=5 [43612]=4 [43616]=9 [43644]=14 [43645]=6 [43648]=9 [43696]=19
+ [43697]=9 [43698]=19 [43701]=9 [43703]=19 [43705]=9 [43710]=19 [43712]=9 [43713]=19 [43714]=9 [43715]=5 [43739]=9 [43744]=12
+ [43756]=13 [43758]=12 [43766]=13 [43767]=5 [43777]=10 [43783]=5 [43785]=10 [43791]=5 [43793]=10 [43799]=5 [43808]=10 [43815]=5
+ [43816]=10 [43823]=5 [43824]=6 [43872]=22 [43876]=6 [43878]=29 [43880]=24 [43884]=5 [43888]=22 [43968]=9 [44005]=19 [44006]=9
+ [44008]=19 [44009]=9 [44013]=19 [44014]=5 [44016]=9 [44026]=5 [44032]=31 [55204]=5 [55216]=33 [55239]=5 [55243]=33 [55292]=5
+ [55296]=0 [57344]=2 [63744]=31 [64046]=32 [64048]=31 [64107]=32 [64110]=57 [64112]=31 [64218]=57 [64256]=1 [64263]=5 [64275]=1
+ [64280]=5 [64285]=1 [64286]=7 [64287]=1 [64311]=5 [64312]=1 [64317]=5 [64318]=1 [64319]=5 [64320]=1 [64322]=5 [64323]=1
+ [64325]=5 [64326]=1 [64434]=10 [64450]=16 [64451]=5 [64467]=1 [64832]=16 [64848]=1 [64912]=5 [64914]=1 [64968]=5 [64975]=16
+ [64976]=5 [65008]=1 [65022]=16 [65024]=3 [65040]=31 [65050]=5 [65056]=7 [65060]=8 [65063]=14 [65070]=26 [65072]=31 [65107]=5
+ [65108]=31 [65127]=5 [65128]=31 [65132]=5 [65136]=1 [65141]=5 [65142]=1 [65277]=5 [65279]=7 [65280]=5 [65281]=31 [65377]=1
+ [65471]=5 [65474]=1 [65480]=5 [65482]=1 [65488]=5 [65490]=1 [65496]=5 [65498]=1 [65501]=5 [65504]=31 [65511]=5 [65512]=1
+ [65519]=5 [65529]=7 [65532]=1 [65533]=2 [65534]=5 [65536]=1 [65548]=5 [65549]=1 [65575]=5 [65576]=1 [65595]=5 [65596]=1
+ [65598]=5 [65599]=1 [65614]=5 [65616]=1 [65630]=5 [65664]=1 [65787]=5 [65792]=1 [65795]=5 [65799]=1 [65844]=5 [65847]=1
+ [65931]=6 [65933]=23 [65935]=5 [65936]=4 [65948]=24 [65949]=5 [65952]=6 [65953]=5 [66000]=4 [66045]=8 [66046]=5 [66176]=4
+ [66205]=5 [66208]=4 [66257]=5 [66272]=14 [66273]=6 [66300]=5 [66304]=1 [66335]=6 [66336]=1 [66340]=5 [66349]=20 [66352]=1
+ [66379]=5 [66384]=6 [66422]=14 [66427]=5 [66432]=1 [66462]=5 [66463]=1 [66500]=5 [66504]=1 [66518]=5 [66560]=1 [66718]=5
+ [66720]=1 [66730]=5 [66736]=23 [66772]=5 [66776]=23 [66812]=5 [66816]=6 [66856]=5 [66864]=6 [66916]=5 [66927]=6 [66928]=16
+ [66939]=5 [66940]=16 [66955]=5 [66956]=16 [66963]=5 [66964]=16 [66966]=5 [66967]=16 [66978]=5 [66979]=16 [66994]=5 [66995]=16
+ [67002]=5 [67003]=16 [67005]=5 [67072]=6 [67383]=5 [67392]=6 [67414]=5 [67424]=6 [67432]=5 [67456]=16 [67462]=5 [67463]=16
+ [67505]=5 [67506]=16 [67515]=5 [67584]=1 [67590]=5 [67592]=1 [67593]=5 [67594]=1 [67638]=5 [67639]=1 [67641]=5 [67644]=1
+ [67645]=5 [67647]=1 [67648]=9 [67670]=5 [67671]=9 [67680]=6 [67743]=5 [67751]=6 [67760]=5 [67808]=22 [67827]=5 [67828]=22
+ [67830]=5 [67835]=22 [67840]=4 [67866]=9 [67868]=5 [67871]=4 [67898]=5 [67903]=4 [67904]=5 [67968]=12 [68024]=5 [68028]=22
+ [68030]=12 [68032]=22 [68048]=5 [68050]=22 [68096]=1 [68097]=7 [68100]=5 [68101]=7 [68103]=5 [68108]=7 [68112]=1 [68116]=5
+ [68117]=1 [68120]=5 [68121]=1 [68148]=11 [68150]=5 [68152]=7 [68155]=5 [68159]=7 [68160]=1 [68168]=11 [68169]=5 [68176]=1
+ [68185]=5 [68192]=9 [68224]=6 [68256]=5 [68288]=6 [68325]=14 [68327]=5 [68331]=6 [68343]=5 [68352]=9 [68406]=5 [68409]=9
+ [68438]=5 [68440]=9 [68467]=5 [68472]=9 [68480]=6 [68498]=5 [68505]=6 [68509]=5 [68521]=6 [68528]=5 [68608]=9 [68681]=5
+ [68736]=22 [68787]=5 [68800]=22 [68851]=5 [68858]=22 [68864]=11 [68900]=18 [68904]=5 [68912]=11 [68922]=5 [69216]=9 [69247]=5
+ [69248]=24 [69290]=5 [69291]=28 [69293]=24 [69294]=5 [69296]=24 [69298]=5 [69376]=11 [69416]=5 [69424]=11 [69446]=18 [69457]=11
+ [69466]=5 [69488]=16 [69506]=21 [69510]=16 [69514]=5 [69552]=24 [69580]=5 [69600]=29 [69623]=5 [69632]=10 [69633]=17 [69634]=10
+ [69688]=17 [69703]=10 [69710]=5 [69714]=10 [69744]=21 [69745]=16 [69747]=21 [69749]=16 [69750]=5 [69759]=14 [69760]=19 [69762]=9
+ [69811]=19 [69815]=9 [69817]=19 [69819]=9 [69821]=19 [69822]=9 [69826]=21 [69827]=5 [69837]=18 [69838]=5 [69840]=12 [69865]=5
+ [69872]=12 [69882]=5 [69888]=13 [69891]=12 [69927]=13 [69932]=12 [69933]=13 [69941]=5 [69942]=12 [69956]=11 [69959]=24 [69960]=5
+ [69968]=6 [70003]=14 [70004]=6 [70007]=5 [70016]=13 [70018]=12 [70070]=13 [70079]=12 [70089]=58 [70090]=26 [70093]=6 [70094]=24
+ [70095]=28 [70096]=12 [70106]=6 [70107]=22 [70112]=5 [70113]=6 [70133]=5 [70144]=6 [70162]=5 [70163]=6 [70191]=14 [70194]=6
+ [70196]=14 [70197]=6 [70198]=14 [70200]=6 [70206]=25 [70207]=5 [70272]=22 [70279]=5 [70280]=22 [70281]=5 [70282]=22 [70286]=5
+ [70287]=22 [70302]=5 [70303]=22 [70314]=5 [70320]=6 [70367]=14 [70368]=6 [70371]=14 [70379]=5 [70384]=6 [70394]=5 [70400]=26
+ [70401]=14 [70402]=6 [70404]=5 [70405]=6 [70413]=5 [70415]=6 [70417]=5 [70419]=6 [70441]=5 [70442]=6 [70449]=5 [70450]=6
+ [70452]=5 [70453]=6 [70458]=5 [70459]=18 [70460]=14 [70461]=6 [70464]=14 [70465]=6 [70469]=5 [70471]=6 [70473]=5 [70475]=6
+ [70478]=5 [70480]=22 [70481]=5 [70487]=6 [70488]=5 [70493]=6 [70500]=5 [70502]=14 [70509]=5 [70512]=14 [70517]=5 [70656]=23
+ [70712]=25 [70720]=23 [70722]=25 [70725]=23 [70726]=25 [70727]=23 [70746]=24 [70747]=23 [70748]=5 [70749]=23 [70750]=18
+ [70751]=29 [70752]=24 [70754]=5 [70784]=6 [70835]=14 [70841]=6 [70842]=14 [70843]=6 [70847]=14 [70849]=6 [70850]=14 [70852]=6
+ [70856]=5 [70864]=6 [70874]=5 [71040]=6 [71090]=14 [71094]=5 [71096]=6 [71100]=14 [71102]=6 [71103]=14 [71105]=6 [71114]=22
+ [71132]=26 [71134]=5 [71168]=6 [71219]=14 [71227]=6 [71229]=14 [71230]=6 [71231]=14 [71233]=6 [71237]=5 [71248]=6 [71258]=5
+ [71264]=23 [71277]=5 [71296]=12 [71339]=13 [71340]=12 [71341]=13 [71342]=12 [71344]=13 [71350]=12 [71351]=13 [71352]=29
+ [71353]=16 [71354]=5 [71360]=12 [71370]=5 [71424]=22 [71450]=11 [71451]=5 [71453]=26 [71456]=22 [71458]=26 [71462]=22 [71463]=26
+ [71468]=5 [71472]=22 [71488]=16 [71495]=5 [71680]=11 [71727]=18 [71736]=11 [71737]=18 [71739]=11 [71740]=5 [71840]=6 [71923]=5
+ [71935]=6 [71936]=24 [71943]=5 [71945]=24 [71946]=5 [71948]=24 [71956]=5 [71957]=24 [71959]=5 [71960]=24 [71990]=5 [71991]=24
+ [71993]=5 [71995]=28 [71997]=24 [71998]=28 [71999]=24 [72003]=28 [72004]=24 [72007]=5 [72016]=24 [72026]=5 [72096]=29 [72104]=5
+ [72106]=29 [72148]=30 [72152]=5 [72154]=30 [72156]=29 [72160]=30 [72161]=29 [72165]=5 [72192]=20 [72193]=27 [72199]=59
+ [72201]=27 [72203]=20 [72243]=27 [72249]=20 [72251]=27 [72255]=20 [72263]=27 [72264]=5 [72272]=20 [72273]=27 [72279]=20
+ [72281]=27 [72284]=20 [72324]=29 [72326]=20 [72330]=27 [72343]=20 [72344]=27 [72346]=20 [72349]=11 [72350]=20 [72355]=5
+ [72368]=16 [72384]=6 [72441]=5 [72704]=23 [72713]=5 [72714]=23 [72752]=25 [72759]=5 [72760]=25 [72766]=23 [72767]=25 [72768]=23
+ [72774]=5 [72784]=23 [72813]=5 [72816]=23 [72848]=5 [72850]=25 [72872]=5 [72873]=23 [72874]=25 [72881]=23 [72882]=25 [72884]=23
+ [72885]=25 [72887]=5 [72960]=20 [72967]=5 [72968]=20 [72970]=5 [72971]=20 [73009]=27 [73015]=5 [73018]=27 [73019]=5 [73020]=27
+ [73022]=5 [73023]=27 [73030]=20 [73031]=27 [73032]=5 [73040]=20 [73050]=5 [73056]=11 [73062]=5 [73063]=11 [73065]=5 [73066]=11
+ [73103]=5 [73104]=18 [73106]=5 [73107]=11 [73109]=18 [73110]=11 [73111]=18 [73112]=11 [73113]=5 [73120]=11 [73130]=5 [73440]=11
+ [73459]=18 [73461]=11 [73465]=5 [73648]=24 [73649]=5 [73664]=29 [73714]=5 [73727]=29 [73728]=4 [74607]=6 [74649]=22 [74650]=5
+ [74752]=4 [74851]=6 [74863]=5 [74864]=4 [74868]=6 [74869]=5 [74880]=22 [75076]=5 [77712]=16 [77811]=5 [77824]=9 [78895]=5
+ [78896]=30 [78905]=5 [82944]=22 [83527]=5 [92160]=10 [92729]=5 [92736]=6 [92767]=5 [92768]=6 [92778]=5 [92782]=6 [92784]=16
+ [92863]=5 [92864]=16 [92874]=5 [92880]=6 [92910]=5 [92912]=14 [92917]=6 [92918]=5 [92928]=6 [92976]=14 [92983]=6 [92998]=5
+ [93008]=6 [93018]=5 [93019]=6 [93026]=5 [93027]=6 [93048]=5 [93053]=6 [93072]=5 [93760]=11 [93851]=5 [93952]=12 [94021]=29
+ [94027]=5 [94031]=30 [94032]=12 [94079]=29 [94088]=5 [94095]=13 [94099]=12 [94112]=5 [94176]=60 [94177]=46 [94178]=61 [94180]=28
+ [94181]=5 [94192]=49 [94194]=5 [94208]=60 [100333]=47 [100338]=61 [100344]=5 [100352]=60 [101107]=49 [101590]=5 [101632]=49
+ [101641]=5 [110576]=62 [110580]=5 [110581]=62 [110588]=5 [110589]=62 [110591]=5 [110592]=48 [110594]=46 [110879]=62 [110883]=5
+ [110928]=61 [110931]=5 [110948]=61 [110952]=5 [110960]=46 [111356]=5 [113664]=6 [113771]=5 [113776]=6 [113789]=5 [113792]=6
+ [113801]=5 [113808]=6 [113818]=5 [113820]=6 [113821]=14 [113823]=6 [113824]=14 [113828]=5 [118528]=21 [118574]=5 [118576]=21
+ [118599]=5 [118608]=16 [118724]=5 [118784]=1 [119030]=5 [119040]=1 [119079]=5 [119081]=4 [119082]=1 [119143]=7 [119146]=1
+ [119155]=7 [119171]=1 [119173]=7 [119180]=1 [119210]=7 [119214]=1 [119262]=22 [119273]=16 [119275]=5 [119296]=1 [119362]=7
+ [119365]=1 [119366]=5 [119520]=11 [119540]=5 [119552]=1 [119639]=5 [119648]=4 [119666]=11 [119673]=5 [119808]=1 [119893]=5
+ [119894]=1 [119965]=5 [119966]=1 [119968]=5 [119970]=1 [119971]=5 [119973]=1 [119975]=5 [119977]=1 [119981]=5 [119982]=1
+ [119994]=5 [119995]=1 [119996]=5 [119997]=1 [120004]=5 [120005]=1 [120070]=5 [120071]=1 [120075]=5 [120077]=1 [120085]=5
+ [120086]=1 [120093]=5 [120094]=1 [120122]=5 [120123]=1 [120127]=5 [120128]=1 [120133]=5 [120134]=1 [120135]=5 [120138]=1
+ [120145]=5 [120146]=1 [120486]=5 [120488]=1 [120778]=4 [120780]=5 [120782]=1 [120832]=22 [121344]=26 [121399]=22 [121403]=26
+ [121453]=22 [121461]=26 [121462]=22 [121476]=26 [121477]=22 [121484]=5 [121499]=26 [121504]=5 [121505]=26 [121520]=5 [122624]=16
+ [122655]=5 [122880]=25 [122887]=5 [122888]=25 [122905]=5 [122907]=25 [122914]=5 [122915]=25 [122917]=5 [122918]=25 [122923]=5
+ [123136]=29 [123181]=5 [123184]=30 [123191]=29 [123198]=5 [123200]=29 [123210]=5 [123214]=29 [123216]=5 [123536]=16 [123566]=21
+ [123567]=5 [123584]=29 [123628]=30 [123632]=29 [123642]=5 [123647]=29 [123648]=5 [124896]=16 [124903]=5 [124904]=16 [124908]=5
+ [124909]=16 [124911]=5 [124912]=16 [124927]=5 [124928]=6 [125125]=5 [125127]=6 [125136]=14 [125143]=5 [125184]=23 [125252]=25
+ [125259]=29 [125260]=5 [125264]=23 [125274]=5 [125278]=23 [125280]=5 [126065]=11 [126133]=5 [126209]=29 [126270]=5 [126464]=12
+ [126468]=5 [126469]=12 [126496]=5 [126497]=12 [126499]=5 [126500]=12 [126501]=5 [126503]=12 [126504]=5 [126505]=12 [126515]=5
+ [126516]=12 [126520]=5 [126521]=12 [126522]=5 [126523]=12 [126524]=5 [126530]=12 [126531]=5 [126535]=12 [126536]=5 [126537]=12
+ [126538]=5 [126539]=12 [126540]=5 [126541]=12 [126544]=5 [126545]=12 [126547]=5 [126548]=12 [126549]=5 [126551]=12 [126552]=5
+ [126553]=12 [126554]=5 [126555]=12 [126556]=5 [126557]=12 [126558]=5 [126559]=12 [126560]=5 [126561]=12 [126563]=5 [126564]=12
+ [126565]=5 [126567]=12 [126571]=5 [126572]=12 [126579]=5 [126580]=12 [126584]=5 [126585]=12 [126589]=5 [126590]=12 [126591]=5
+ [126592]=12 [126602]=5 [126603]=12 [126620]=5 [126625]=12 [126628]=5 [126629]=12 [126634]=5 [126635]=12 [126652]=5 [126704]=12
+ [126706]=5 [126976]=4 [126980]=43 [126981]=4 [127020]=5 [127024]=4 [127124]=5 [127136]=10 [127151]=5 [127153]=10 [127167]=6
+ [127168]=5 [127169]=10 [127183]=39 [127184]=5 [127185]=10 [127200]=6 [127222]=5 [127232]=37 [127243]=6 [127245]=24 [127248]=37
+ [127278]=9 [127279]=11 [127280]=63 [127281]=37 [127282]=63 [127293]=37 [127294]=63 [127295]=37 [127296]=63 [127298]=37
+ [127299]=63 [127302]=37 [127303]=63 [127306]=37 [127311]=63 [127319]=37 [127320]=63 [127327]=37 [127328]=63 [127338]=12
+ [127340]=29 [127341]=24 [127344]=63 [127353]=37 [127354]=63 [127355]=37 [127357]=63 [127359]=37 [127360]=63 [127370]=37
+ [127374]=64 [127375]=63 [127376]=37 [127377]=64 [127387]=65 [127405]=24 [127406]=5 [127462]=10 [127488]=32 [127489]=48
+ [127491]=5 [127504]=32 [127538]=48 [127547]=60 [127548]=5 [127552]=32 [127561]=5 [127568]=48 [127570]=5 [127584]=46 [127590]=5
+ [127744]=39 [127777]=6 [127789]=66 [127792]=39 [127798]=6 [127799]=39 [127869]=6 [127870]=66 [127872]=39 [127892]=6 [127904]=39
+ [127941]=67 [127942]=39 [127947]=6 [127951]=66 [127956]=6 [127968]=39 [127985]=6 [127988]=67 [127989]=6 [127992]=66 [128000]=39
+ [128063]=6 [128064]=39 [128065]=6 [128066]=39 [128248]=67 [128249]=39 [128253]=6 [128255]=66 [128256]=39 [128318]=6 [128320]=12
+ [128324]=6 [128331]=66 [128335]=22 [128336]=39 [128360]=6 [128378]=60 [128379]=6 [128405]=67 [128407]=6 [128420]=60 [128421]=6
+ [128507]=39 [128512]=68 [128513]=39 [128529]=68 [128530]=39 [128533]=68 [128534]=39 [128535]=68 [128536]=39 [128537]=68
+ [128538]=39 [128539]=68 [128540]=39 [128543]=68 [128544]=39 [128550]=68 [128552]=39 [128556]=68 [128557]=39 [128558]=68
+ [128560]=39 [128564]=68 [128565]=39 [128577]=67 [128579]=66 [128581]=39 [128592]=6 [128640]=39 [128710]=6 [128716]=67 [128717]=6
+ [128720]=66 [128721]=60 [128723]=20 [128725]=61 [128726]=49 [128728]=5 [128733]=62 [128736]=6 [128747]=67 [128749]=5 [128752]=6
+ [128756]=60 [128759]=46 [128761]=47 [128762]=61 [128763]=49 [128765]=5 [128768]=10 [128884]=5 [128896]=6 [128981]=11 [128985]=5
+ [128992]=61 [129004]=5 [129008]=62 [129009]=5 [129024]=6 [129036]=5 [129040]=6 [129096]=5 [129104]=6 [129114]=5 [129120]=6
+ [129160]=5 [129168]=6 [129198]=5 [129200]=24 [129202]=5 [129280]=20 [129292]=49 [129293]=61 [129296]=66 [129305]=60 [129311]=46
+ [129312]=60 [129320]=46 [129328]=60 [129329]=46 [129331]=60 [129339]=69 [129340]=60 [129343]=61 [129344]=60 [129350]=69
+ [129351]=60 [129356]=46 [129357]=47 [129360]=60 [129375]=46 [129388]=47 [129393]=61 [129394]=49 [129395]=47 [129399]=49
+ [129401]=62 [129402]=47 [129403]=61 [129404]=47 [129408]=66 [129413]=60 [129426]=46 [129432]=47 [129443]=49 [129445]=61
+ [129451]=49 [129454]=61 [129456]=47 [129466]=61 [129472]=66 [129473]=47 [129475]=61 [129483]=49 [129484]=62 [129485]=61
+ [129488]=46 [129511]=47 [129536]=29 [129620]=5 [129632]=11 [129646]=5 [129648]=61 [129652]=49 [129653]=5 [129656]=61 [129659]=62
+ [129661]=5 [129664]=61 [129667]=49 [129671]=5 [129680]=61 [129686]=49 [129705]=62 [129709]=5 [129712]=49 [129719]=62 [129723]=5
+ [129728]=49 [129731]=62 [129734]=5 [129744]=49 [129751]=62 [129754]=5 [129760]=62 [129768]=5 [129776]=62 [129783]=5 [129792]=24
+ [129939]=5 [129940]=24 [129995]=5 [130032]=24 [130042]=5 [131072]=31 [173783]=70 [173790]=71 [173792]=72 [173824]=31 [177973]=71
+ [177977]=72 [177984]=31 [178206]=72 [178208]=73 [183970]=72 [183984]=74 [191457]=72 [194560]=31 [195102]=72 [196606]=5
+ [196608]=70 [201547]=72 [262142]=5 [917505]=7 [917506]=5 [917536]=7 [917632]=5 [917760]=3 [918000]=5 [983040]=2 [1048574]=5
+ [1048576]=2 [1114110]=5)
+_ble_unicode_c2w_ranges=(0 32 127 162 165 167 171 176 182 188 192 199 209 215 217 222 226 232 236 238 242 244 247 255 258 276 284
+ 294 296 300 305 308 313 319 325 328 334 338 340 358 360 364 477 578 594 610 709 713 718 721 728 736 768 880 884 886 888 891 896
+ 900 910 913 931 938 945 963 970 976 1026 1040 1106 1155 1160 1162 1232 1274 1280 1296 1316 1318 1320 1329 1367 1369 1377 1417
+ 1419 1421 1425 1467 1473 1476 1480 1488 1515 1520 1525 1536 1542 1547 1552 1558 1566 1569 1595 1600 1611 1632 1649 1750 1759
+ 1765 1767 1770 1774 1810 1840 1867 1869 1902 1920 1958 1970 1984 2027 2036 2043 2046 2048 2070 2075 2085 2089 2094 2096 2112
+ 2137 2140 2144 2155 2160 2192 2194 2200 2210 2221 2227 2230 2238 2248 2250 2260 2276 2305 2307 2365 2369 2377 2385 2390 2392
+ 2402 2404 2417 2419 2425 2427 2430 2434 2437 2445 2447 2449 2451 2474 2483 2486 2490 2493 2497 2501 2503 2505 2507 2511 2520
+ 2524 2527 2530 2532 2534 2556 2559 2561 2565 2571 2575 2577 2579 2602 2610 2613 2616 2618 2622 2625 2627 2631 2633 2635 2638
+ 2642 2649 2655 2662 2672 2674 2679 2689 2693 2703 2707 2730 2738 2741 2746 2749 2753 2759 2763 2766 2769 2784 2786 2788 2790
+ 2802 2810 2818 2821 2829 2831 2833 2835 2858 2866 2869 2874 2877 2881 2885 2887 2889 2891 2894 2904 2908 2911 2914 2916 2918
+ 2930 2936 2949 2955 2958 2962 2966 2969 2974 2976 2979 2981 2984 2987 2990 3002 3006 3009 3011 3014 3018 3022 3025 3032 3046
+ 3067 3073 3077 3086 3090 3114 3125 3130 3134 3137 3142 3146 3150 3157 3160 3163 3166 3168 3170 3172 3174 3184 3192 3202 3205
+ 3214 3218 3242 3253 3258 3261 3264 3271 3274 3276 3278 3285 3287 3296 3298 3300 3302 3313 3315 3330 3333 3342 3346 3370 3387
+ 3390 3393 3398 3402 3408 3412 3416 3424 3426 3428 3430 3440 3446 3449 3458 3461 3479 3482 3507 3518 3520 3527 3531 3535 3538
+ 3544 3552 3558 3568 3570 3573 3585 3634 3636 3643 3647 3655 3663 3676 3713 3719 3726 3732 3737 3745 3752 3754 3757 3762 3764
+ 3771 3774 3776 3784 3790 3792 3802 3804 3806 3808 3840 3864 3866 3898 3913 3947 3949 3953 3968 3974 3976 3981 3984 3993 4030
+ 4039 4047 4050 4053 4057 4059 4096 4131 4137 4141 4147 4150 4155 4157 4160 4184 4186 4190 4193 4209 4213 4227 4229 4231 4238
+ 4250 4254 4256 4296 4302 4304 4349 4352 4442 4448 4515 4520 4602 4608 4682 4686 4688 4698 4702 4704 4746 4750 4752 4786 4790
+ 4792 4802 4806 4808 4824 4882 4886 4888 4955 4957 4960 4989 4992 5018 5024 5110 5112 5118 5121 5751 5760 5789 5792 5873 5881
+ 5888 5902 5906 5910 5920 5938 5941 5943 5952 5970 5972 5984 5998 6002 6004 6016 6068 6071 6078 6087 6089 6100 6110 6112 6122
+ 6128 6138 6144 6155 6160 6170 6176 6265 6272 6277 6279 6315 6320 6390 6400 6429 6432 6435 6439 6441 6444 6448 6451 6457 6460
+ 6465 6468 6510 6512 6517 6528 6570 6572 6576 6602 6608 6619 6622 6679 6681 6684 6686 6688 6744 6755 6757 6765 6771 6781 6784
+ 6794 6800 6810 6816 6830 6832 6847 6849 6863 6912 6916 6966 6973 6979 6989 6992 7019 7028 7037 7040 7042 7074 7078 7080 7083
+ 7086 7098 7104 7144 7146 7151 7154 7156 7164 7168 7212 7220 7222 7224 7227 7242 7245 7296 7305 7312 7355 7357 7360 7368 7376
+ 7380 7394 7401 7406 7413 7416 7419 7424 7616 7620 7655 7670 7678 7680 7836 7840 7930 7936 7958 7960 7966 7968 8006 8008 8014
+ 8016 8031 8062 8064 8118 8134 8148 8150 8157 8176 8178 8182 8192 8203 8209 8211 8216 8218 8220 8222 8224 8228 8232 8234 8242
+ 8246 8252 8255 8288 8294 8298 8304 8306 8309 8321 8325 8336 8341 8349 8352 8365 8374 8379 8385 8400 8428 8433 8448 8454 8458
+ 8468 8471 8481 8483 8487 8492 8525 8528 8531 8533 8539 8544 8556 8560 8570 8580 8586 8588 8592 8602 8632 8634 8661 8680 8706
+ 8708 8711 8713 8716 8722 8726 8731 8733 8737 8743 8751 8756 8760 8764 8766 8777 8781 8787 8800 8802 8804 8808 8810 8812 8814
+ 8816 8834 8836 8838 8840 8854 8858 8870 8896 8979 8986 8988 9001 9003 9180 9193 9197 9201 9204 9211 9216 9255 9280 9291 9312
+ 9451 9548 9552 9588 9600 9616 9618 9622 9632 9635 9642 9650 9652 9654 9656 9660 9662 9664 9666 9670 9673 9676 9678 9682 9698
+ 9702 9712 9725 9727 9733 9735 9738 9742 9744 9748 9750 9759 9795 9800 9812 9824 9827 9831 9836 9840 9856 9876 9886 9890 9898
+ 9900 9906 9920 9924 9926 9935 9941 9956 9960 9963 9970 9974 9979 9982 9985 9990 9994 9996 10025 10046 10063 10067 10072 10079
+ 10081 10102 10112 10133 10136 10161 10176 10183 10190 10192 10220 10224 11028 11035 11037 11085 11089 11094 11098 11124 11126
+ 11160 11194 11197 11210 11219 11244 11248 11264 11312 11360 11377 11390 11392 11499 11503 11506 11508 11513 11560 11566 11568
+ 11622 11624 11633 11648 11671 11680 11688 11696 11704 11712 11720 11728 11736 11744 11776 11800 11804 11806 11826 11836 11843
+ 11845 11850 11856 11859 11870 11904 11931 12020 12032 12246 12272 12284 12288 12330 12334 12353 12439 12441 12443 12544 12549
+ 12593 12688 12728 12731 12736 12752 12772 12784 12832 12868 12872 12880 13056 19894 19904 19968 40892 40900 40909 40918 40939
+ 40944 40957 40960 42125 42128 42183 42192 42240 42540 42560 42592 42594 42607 42612 42620 42622 42648 42656 42736 42738 42744
+ 42752 42775 42893 42896 42898 42900 42912 42923 42928 42930 42936 42938 42944 42946 42951 42955 42960 42965 42970 42994 42997
+ 43000 43003 43008 43011 43015 43020 43045 43047 43053 43056 43066 43072 43128 43136 43206 43214 43226 43232 43250 43260 43264
+ 43302 43310 43335 43346 43348 43360 43389 43392 43395 43444 43446 43450 43454 43471 43482 43486 43488 43494 43520 43561 43567
+ 43569 43571 43573 43575 43584 43588 43598 43600 43610 43612 43616 43645 43648 43698 43701 43703 43705 43710 43715 43739 43744
+ 43756 43758 43767 43777 43783 43785 43791 43793 43799 43808 43816 43824 43872 43876 43878 43880 43884 43888 43968 44006 44009
+ 44014 44016 44026 44032 55204 55216 55239 55243 55292 55296 57344 63744 64046 64048 64107 64110 64112 64218 64256 64263 64275
+ 64280 64287 64312 64320 64323 64326 64434 64451 64467 64832 64848 64912 64914 64968 64976 65008 65022 65024 65040 65050 65056
+ 65060 65063 65070 65072 65108 65128 65132 65136 65142 65277 65281 65377 65471 65474 65480 65482 65488 65490 65496 65498 65501
+ 65504 65512 65519 65529 65534 65536 65549 65576 65596 65599 65614 65616 65630 65664 65787 65792 65795 65799 65844 65847 65931
+ 65933 65936 65949 65953 66000 66046 66176 66205 66208 66257 66273 66300 66304 66336 66340 66349 66352 66379 66384 66422 66427
+ 66432 66463 66500 66504 66518 66560 66718 66720 66730 66736 66772 66776 66812 66816 66856 66864 66916 66928 66940 66956 66964
+ 66967 66979 66995 67003 67005 67072 67383 67392 67414 67424 67432 67456 67463 67506 67515 67584 67590 67594 67639 67641 67645
+ 67648 67671 67680 67743 67751 67760 67808 67828 67830 67835 67840 67866 67868 67871 67898 67904 67968 68024 68028 68030 68032
+ 68048 68050 68097 68101 68103 68108 68112 68117 68121 68148 68150 68152 68155 68160 68169 68176 68185 68192 68224 68256 68288
+ 68325 68327 68331 68343 68352 68406 68409 68438 68440 68467 68472 68480 68498 68505 68509 68521 68528 68608 68681 68736 68787
+ 68800 68851 68858 68864 68900 68904 68912 68922 69216 69248 69291 69294 69296 69298 69376 69416 69424 69446 69457 69466 69488
+ 69506 69510 69514 69552 69580 69600 69623 69634 69688 69703 69710 69714 69745 69747 69750 69760 69762 69811 69815 69817 69819
+ 69822 69827 69838 69840 69865 69872 69882 69888 69891 69927 69933 69942 69956 69960 69968 70004 70007 70016 70018 70070 70079
+ 70090 70096 70107 70113 70133 70144 70163 70191 70194 70198 70200 70207 70272 70282 70287 70303 70314 70320 70368 70371 70379
+ 70384 70394 70402 70405 70413 70415 70417 70419 70442 70450 70453 70461 70465 70469 70471 70473 70475 70478 70481 70488 70493
+ 70500 70502 70509 70512 70517 70656 70712 70720 70722 70727 70752 70754 70784 70835 70843 70847 70850 70852 70856 70864 70874
+ 71040 71090 71094 71096 71100 71103 71105 71114 71132 71134 71168 71219 71227 71231 71233 71237 71248 71258 71264 71277 71296
+ 71342 71344 71354 71360 71370 71424 71451 71453 71456 71458 71463 71468 71472 71488 71495 71680 71727 71737 71740 71840 71923
+ 71936 71943 71946 71948 71957 71960 71991 71993 71995 71999 72004 72007 72016 72026 72096 72104 72106 72148 72152 72154 72156
+ 72161 72165 72193 72199 72201 72203 72243 72249 72251 72255 72264 72273 72279 72281 72284 72324 72326 72330 72344 72346 72350
+ 72355 72368 72384 72441 72704 72714 72752 72760 72768 72774 72784 72813 72816 72848 72850 72874 72882 72885 72887 72960 72968
+ 72971 73009 73015 73020 73023 73032 73040 73050 73056 73063 73066 73104 73107 73113 73120 73130 73440 73459 73461 73465 73649
+ 73664 73714 73728 74607 74650 74752 74851 74864 74869 74880 75076 77712 77811 77824 78896 78905 82944 83527 92160 92729 92736
+ 92768 92778 92782 92784 92864 92874 92880 92910 92912 92918 92928 92976 92983 92998 93008 93019 93027 93048 93053 93072 93760
+ 93851 93952 94021 94027 94032 94079 94088 94095 94099 94112 94178 94181 94192 94194 94208 100333 100338 100344 100352 101107
+ 101590 101632 101641 110576 110581 110589 110592 110594 110879 110883 110928 110931 110948 110952 110960 111356 113664 113771
+ 113776 113789 113792 113801 113808 113818 113821 113824 113828 118528 118574 118576 118599 118608 118724 118784 119030 119040
+ 119079 119082 119143 119146 119155 119171 119173 119180 119210 119214 119262 119273 119275 119296 119362 119366 119520 119540
+ 119552 119639 119648 119666 119673 119808 119894 119966 119968 119971 119973 119975 119977 119982 119997 120005 120071 120075
+ 120077 120086 120094 120123 120128 120135 120138 120146 120486 120488 120778 120780 120782 120832 121344 121399 121403 121453
+ 121462 121477 121484 121499 121505 121520 122624 122655 122880 122888 122905 122907 122915 122918 122923 123136 123181 123184
+ 123191 123198 123200 123210 123214 123216 123536 123567 123584 123628 123632 123642 123648 124896 124904 124909 124912 124928
+ 125125 125127 125136 125143 125184 125252 125260 125264 125274 125278 125280 126065 126133 126209 126270 126464 126469 126497
+ 126501 126505 126516 126524 126531 126541 126545 126549 126561 126565 126567 126572 126580 126585 126592 126603 126620 126625
+ 126629 126635 126652 126704 126706 126976 126981 127020 127024 127124 127136 127151 127153 127169 127185 127200 127222 127232
+ 127243 127245 127248 127282 127296 127299 127303 127306 127311 127320 127328 127338 127341 127344 127355 127357 127360 127370
+ 127377 127387 127406 127462 127489 127491 127504 127538 127548 127552 127561 127568 127570 127584 127590 127744 127777 127789
+ 127792 127799 127870 127872 127892 127904 127942 127947 127951 127956 127968 127985 127989 127992 128000 128066 128249 128253
+ 128256 128318 128320 128324 128331 128336 128360 128379 128405 128407 128421 128507 128513 128530 128540 128544 128550 128552
+ 128558 128560 128565 128577 128579 128581 128592 128640 128710 128717 128721 128723 128726 128728 128733 128736 128747 128749
+ 128752 128756 128759 128763 128765 128768 128884 128896 128981 128985 128992 129004 129009 129024 129036 129040 129096 129104
+ 129114 129120 129160 129168 129198 129200 129202 129280 129293 129296 129305 129312 129320 129329 129331 129340 129344 129351
+ 129357 129360 129375 129388 129395 129399 129404 129408 129413 129426 129432 129443 129445 129451 129454 129456 129466 129473
+ 129475 129485 129488 129511 129536 129620 129632 129646 129648 129653 129656 129659 129661 129664 129667 129671 129680 129686
+ 129705 129709 129712 129719 129723 129728 129731 129734 129744 129751 129754 129760 129768 129776 129783 129792 129940 129995
+ 130032 130042 131072 173783 173790 173792 173824 177973 177977 177984 178206 178208 183970 183984 191457 194560 195102 196606
+ 196608 201547 262142 917506 917536 917632 917760 918000 983040 1048574 1048576 1114110 1114112)
+_ble_unicode_c2w_index=(0:24 23:43 42:53 52:68 67:77 76:98 97:115 114:129 128:153 152:193 192:238 237:287 286:330 329:367 366:397
+ 396:418 417:444 443:450 449:466 465:479 478:480 1 479:487 486:514 513:526 525:549 548:571 570:596 595:619 618:625 624:629
+ 628:649 648:684 683:710 709:745 744:757 756:762 761:790 789:825 824:847 1 1 1 846:864 863:874 873:892 891:907 906:911 910:918
+ 917:927 926:932 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 931:935 31 31 31 31 31 31 31 31 31
+ 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31
+ 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 934:943 31 31 31 31 942:948 4 947:962
+ 961:985 984:1003 1002:1022 1021:1048 1047:1070 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31
+ 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 1069:1076 0 0 0 0 0 0 0 1075:1077 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+ 2 1076:1078 31 1077:1085 1084:1096 1 1095:1105 1104:1118 1117:1135 1134:1145 1144:1156 1155:1163 1162:1177 1176:1185 1184:1198 6
+ 1197:1208 1207:1224 1223:1236 1235:1260 1259:1273 1272:1280 1279:1284 1283:1291 1290:1304 1303:1326 1325:1345 1344:1362
+ 1361:1387 1386:1402 1401:1413 1412:1429 1428:1439 1438:1445 1444:1467 1466:1490 1489:1491 1490:1506 1505:1523 1522:1527
+ 1526:1531 4 4 4 1530:1534 1533:1538 1537:1539 5 5 5 5 5 5 5 5 5 1538:1542 9 9 9 9 1541:1544 5 5 5 5 5 5 5 5 5 5 5 5 5 5
+ 1543:1545 22 22 1544:1546 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1545:1547 10 10 1546:1560 1559:1569 5
+ 5 1568:1572 1571:1585 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 1584:1589 60 60 1588:1590 49
+ 1589:1592 1591:1593 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1592:1597 1596:1598 1597:1605 1604:1606 5
+ 5 5 5 5 5 5 5 1605:1607 1606:1617 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1616:1618 1617:1624 1623:1626 1625:1640 1639:1645 1644:1650
+ 1649:1660 1659:1670 1669:1672 1671:1676 22 1675:1677 1676:1686 5 5 5 1685:1687 1686:1689 1688:1696 1695:1704 1703:1711 5 5 5 5
+ 1710:1716 1715:1721 1720:1727 5 5 1726:1729 1728:1732 1731:1757 1756:1758 1757:1770 1769:1792 1791:1804 1803:1821 1820:1825
+ 1824:1836 1835:1866 1865:1874 1873:1886 1885:1919 1918:1948 1947:1952 5 5 5 1951:1953 31 31 31 31 31 31 31 31 31 31 1952:1957
+ 1956:1962 1961:1964 74 1963:1965 1964:1969 70 1968:1970 72 72 72 72 72 72 72 72 72 72 72 72 72 1969:1971 5 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1970:1976 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1975:1977 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1976:1979
+ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1978:1980)
+function ble/unicode/c2w/version2index {
+ case $1 in
+ (4.1) ret=0 ;;
+ (5.0) ret=1 ;;
+ (5.2) ret=2 ;;
+ (6.0) ret=3 ;;
+ (6.1) ret=4 ;;
+ (6.2) ret=5 ;;
+ (6.3) ret=6 ;;
+ (7.0) ret=7 ;;
+ (8.0) ret=8 ;;
+ (9.0) ret=9 ;;
+ (10.0) ret=10 ;;
+ (11.0) ret=11 ;;
+ (12.0) ret=12 ;;
+ (12.1) ret=13 ;;
+ (13.0) ret=14 ;;
+ (14.0) ret=15 ;;
+ (*) return 1 ;;
+ esac
+}
+_ble_unicode_c2w_version=15
+_ble_unicode_c2w_version=14
+_ble_unicode_c2w_ambiguous=1
+_ble_unicode_c2w_invalid=1
+_ble_unicode_c2w_custom=()
+bleopt/declare -n char_width_version auto
+function bleopt/check:char_width_version {
+ if [[ $value == auto ]]; then
+ ble && ble/util/c2w:auto/test.buff first-line
+ ((_ble_prompt_version++))
+ ble/util/c2w/clear-cache
+ return 0
+ elif local ret; ble/unicode/c2w/version2index "$value"; then
+ _ble_unicode_c2w_version=$ret
+ ((_ble_prompt_version++))
+ ble/util/c2w/clear-cache
+ return 0
+ else
+ ble/util/print "bleopt: char_width_version: invalid value '$value'." >&2
+ return 1
+ fi
+}
+_ble_unicode_c2w_custom[173]=1 # U+00ad Cf A SHY(soft-hyphen)
+let '_ble_unicode_c2w_custom['{1536..1541}']=1' # U+0600..0605 Cf 1 アラブの数字?
+_ble_unicode_c2w_custom[1757]=1 # U+06dd Cf 1 ARABIC END OF AYAH
+_ble_unicode_c2w_custom[1807]=1 # U+070f Cf 1 SYRIAC ABBREVIATION MARK
+_ble_unicode_c2w_custom[2274]=1 # U+08e2 Cf 1 ARABIC DISPUTED END OF AYAH
+_ble_unicode_c2w_custom[69821]=1 # U+110bd Cf 1 KAITHI NUMBER SIGN
+_ble_unicode_c2w_custom[69837]=1 # U+110cd Cf 1 KAITHI NUMBER SIGN ABOVE
+let '_ble_unicode_c2w_custom['{12872..12879}']=2' # U+3248..324f No A 囲み文字10-80 (8字)
+let '_ble_unicode_c2w_custom['{19904..19967}']=2' # U+4dc0..4dff So 1 易経記号 (6字)
+let '_ble_unicode_c2w_custom['{4448..4607}']=0' # U+1160..11ff Lo 1 HANGUL JAMO (160字)
+let '_ble_unicode_c2w_custom['{55216..55238}']=0' # U+d7b0..d7c6 Lo 1 HANGUL JAMO EXTENDED-B (1) (23字)
+let '_ble_unicode_c2w_custom['{55243..55291}']=0' # U+d7cb..d7fb Lo 1 HANGUL JAMO EXTENDED-B (2) (49字)
+function ble/unicode/c2w {
+ local c=$1
+ ret=${_ble_unicode_c2w_custom[c]}
+ [[ $ret ]] && return 0
+ ret=${_ble_unicode_c2w[c]}
+ if [[ ! $ret ]]; then
+ ret=${_ble_unicode_c2w_index[c<0x20000?c>>8:((c>>12)-32+512)]}
+ if [[ $ret == *:* ]]; then
+ local l=${ret%:*} u=${ret#*:} m
+ while ((l+1<u)); do
+ ((m=(l+u)/2))
+ if ((_ble_unicode_c2w_ranges[m]<=c)); then
+ l=$m
+ else
+ u=$m
+ fi
+ done
+ ret=${_ble_unicode_c2w[_ble_unicode_c2w_ranges[l]]}
+ fi
+ fi
+ ret=${_ble_unicode_c2w_UnicodeVersionMapping[ret*_ble_unicode_c2w_UnicodeVersionCount+_ble_unicode_c2w_version]}
+ ((ret<0)) && ret=${_ble_unicode_c2w_invalid:-$((-ret))}
+ ((ret==3)) &&
+ ret=${_ble_unicode_c2w_ambiguous:-1}
+ return 0
+}
+_ble_unicode_EmojiStatus_None=0
+_ble_unicode_EmojiStatus_FullyQualified=1
+_ble_unicode_EmojiStatus_MinimallyQualified=2
+_ble_unicode_EmojiStatus_Unqualified=3
+_ble_unicode_EmojiStatus_Component=4
+_ble_unicode_EmojiStatus_xmaybe='8596<=code&&code<=11036||127344<=code&&code<=129782'
+_ble_unicode_EmojiStatus=([169]=3 [174]=3 [8252]=3 [8265]=3 [8482]=3 [8505]=3 [8596]=3 [8602]=0 [8617]=3 [8619]=0 [8986]=1
+ [8988]=0 [9000]='V>=2?3:0' [9167]='V>=2?3:0' [9193]=1 [9197]='V>=1?3:0' [9199]='V>=2?3:0' [9200]=1 [9201]='V>=2?3:0' [9203]=1
+ [9204]=0 [9208]='V>=1?3:0' [9211]=0 [9410]=3 [9642]=3 [9644]=0 [9654]=3 [9664]=3 [9723]=3 [9725]=1 [9727]=0 [9728]=3
+ [9730]='V>=1?3:0' [9732]='V>=2?3:0' [9733]=0 [9742]=3 [9745]=3 [9748]=1 [9750]=0 [9752]='V>=2?3:0' [9757]=3 [9760]='V>=2?3:0'
+ [9761]=0 [9762]='V>=2?3:0' [9764]=0 [9766]='V>=2?3:0' [9770]='V>=1?3:0' [9774]='V>=2?3:0' [9775]='V>=1?3:0' [9784]='V>=1?3:0'
+ [9786]=3 [9787]=0 [9792]='V>=5?3:0' [9793]=0 [9794]='V>=5?3:0' [9800]=1 [9812]=0 [9823]='V>=7?3:0' [9824]=3 [9827]=3 [9828]=0
+ [9829]=3 [9831]=0 [9832]=3 [9833]=0 [9851]=3 [9854]='V>=7?3:0' [9855]=1 [9874]='V>=2?3:0' [9875]=1 [9876]='V>=2?3:0'
+ [9877]='V>=5?3:0' [9878]='V>=2?3:0' [9880]=0 [9881]='V>=2?3:0' [9882]=0 [9885]=0 [9888]=3 [9889]=1 [9895]='V>=10?3:0' [9898]=1
+ [9900]=0 [9904]='V>=2?3:0' [9906]=0 [9917]=1 [9919]=0 [9924]=1 [9926]=0 [9928]='V>=1?3:0' [9934]=1 [9935]='V>=1?3:0' [9936]=0
+ [9937]='V>=1?3:0' [9938]=0 [9939]='V>=1?3:0' [9940]=1 [9961]='V>=1?3:0' [9962]=1 [9968]='V>=1?3:0' [9970]=1 [9972]='V>=1?3:0'
+ [9973]=1 [9974]=0 [9975]='V>=1?3:0' [9978]=1 [9979]=0 [9981]=1 [9986]=3 [9989]=1 [9992]=3 [9994]=1 [9996]=3 [9997]='V>=1?3:0'
+ [9998]=0 [9999]=3 [10000]=0 [10002]=3 [10003]=0 [10004]=3 [10005]=0 [10006]=3 [10013]='V>=1?3:0' [10017]='V>=1?3:0' [10024]=1
+ [10035]=3 [10037]=0 [10052]=3 [10055]=3 [10060]=1 [10061]=0 [10062]=1 [10067]=1 [10070]=0 [10071]=1 [10072]=0 [10083]='V>=2?3:0'
+ [10084]=3 [10133]=1 [10136]=0 [10145]=3 [10160]=1 [10175]='V>=2?1:0' [10548]=3 [10550]=0 [11013]=3 [11016]=0 [11035]=1 [11037]=0
+ [11088]=1 [11093]=1 [12336]=3 [12349]=3 [12951]=3 [12952]=0 [12953]=3 [126980]=1 [127183]=1 [127344]=3 [127346]=0 [127358]=3
+ [127360]=0 [127374]=1 [127377]=1 [127387]=0 [127462]=1 [127488]=0 [127489]=1 [127490]=3 [127491]=0 [127514]=1 [127535]=1
+ [127538]=1 [127543]=3 [127547]=0 [127568]=1 [127570]=0 [127744]=1 [127757]='V>=1?1:0' [127759]=1 [127760]='V>=2?1:0' [127761]=1
+ [127762]='V>=2?1:0' [127763]=1 [127766]='V>=2?1:0' [127769]=1 [127770]='V>=2?1:0' [127771]=1 [127772]='V>=1?1:0' [127775]=1
+ [127777]='V>=1?3:0' [127778]=0 [127780]='V>=1?3:0' [127789]='V>=2?1:0' [127792]=1 [127794]='V>=2?1:0' [127796]=1
+ [127798]='V>=1?3:0' [127819]='V>=2?1:0' [127824]='V>=2?1:0' [127868]='V>=2?1:0' [127869]='V>=1?3:0' [127870]='V>=2?1:0'
+ [127872]=1 [127892]=0 [127894]='V>=1?3:0' [127896]=0 [127900]=0 [127902]='V>=1?3:0' [127904]=1 [127941]='V>=2?1:0' [127942]=1
+ [127943]='V>=2?1:0' [127944]=1 [127945]='V>=2?1:0' [127946]=1 [127947]='V>=1?3:0' [127951]='V>=2?1:0' [127956]='V>=1?3:0'
+ [127968]=1 [127972]='V>=2?1:0' [127985]=0 [127987]='V>=1?3:0' [127988]='V>=2?1:0' [127989]='V>=1?3:0' [127990]=0
+ [127991]='V>=1?3:0' [127992]='V>=2?1:0' [127995]='V>=2?4:0' [128000]='V>=2?1:0' [128008]='V>=1?1:0' [128012]=1
+ [128015]='V>=2?1:0' [128017]=1 [128019]='V>=2?1:0' [128020]=1 [128021]='V>=1?1:0' [128022]='V>=2?1:0' [128042]='V>=2?1:0'
+ [128063]='V>=1?3:0' [128064]=1 [128065]='V>=1?3:0' [128101]='V>=2?1:0' [128108]='V>=2?1:0' [128110]=1 [128173]='V>=2?1:0'
+ [128182]='V>=2?1:0' [128184]=1 [128236]='V>=1?1:0' [128238]=1 [128239]='V>=2?1:0' [128240]=1 [128245]='V>=2?1:0'
+ [128248]='V>=2?1:0' [128253]='V>=1?3:0' [128254]=0 [128255]='V>=2?1:0' [128259]=1 [128264]='V>=1?1:0' [128265]='V>=2?1:0'
+ [128266]=1 [128277]='V>=2?1:0' [128300]='V>=2?1:0' [128302]=1 [128318]=0 [128329]='V>=1?3:0' [128331]='V>=2?1:0' [128335]=0
+ [128336]=1 [128348]='V>=1?1:0' [128360]=0 [128367]='V>=1?3:0' [128369]=0 [128371]='V>=1?3:0' [128378]='V>=4?1:0' [128379]=0
+ [128391]='V>=1?3:0' [128394]='V>=1?3:0' [128398]=0 [128400]='V>=1?3:0' [128405]='V>=2?1:0' [128407]=0 [128420]='V>=4?1:0'
+ [128421]='V>=1?3:0' [128424]='V>=1?3:0' [128433]='V>=1?3:0' [128435]=0 [128444]='V>=1?3:0' [128450]='V>=1?3:0' [128453]=0
+ [128465]='V>=1?3:0' [128468]=0 [128476]='V>=1?3:0' [128479]=0 [128481]='V>=1?3:0' [128482]=0 [128483]='V>=1?3:0'
+ [128488]='V>=3?3:0' [128495]='V>=1?3:0' [128499]='V>=1?3:0' [128506]='V>=1?3:0' [128507]=1 [128512]='V>=2?1:0'
+ [128519]='V>=2?1:0' [128521]=1 [128526]='V>=2?1:0' [128527]=1 [128528]='V>=1?1:0' [128529]='V>=2?1:0' [128533]='V>=2?1:0'
+ [128534]=1 [128535]='V>=2?1:0' [128536]=1 [128537]='V>=2?1:0' [128538]=1 [128539]='V>=2?1:0' [128543]='V>=2?1:0'
+ [128550]='V>=2?1:0' [128552]=1 [128556]='V>=2?1:0' [128557]=1 [128558]='V>=2?1:0' [128560]=1 [128564]='V>=2?1:0' [128565]=1
+ [128566]='V>=2?1:0' [128577]='V>=2?1:0' [128581]=1 [128592]=0 [128640]=1 [128641]='V>=2?1:0' [128643]=1 [128646]='V>=2?1:0'
+ [128647]=1 [128648]='V>=2?1:0' [128649]=1 [128650]='V>=2?1:0' [128652]=1 [128653]='V>=1?1:0' [128654]='V>=2?1:0' [128655]=1
+ [128656]='V>=2?1:0' [128657]=1 [128660]='V>=1?1:0' [128661]=1 [128662]='V>=2?1:0' [128663]=1 [128664]='V>=1?1:0'
+ [128667]='V>=2?1:0' [128674]=1 [128675]='V>=2?1:0' [128676]=1 [128678]='V>=2?1:0' [128686]='V>=2?1:0' [128690]=1 [128694]=1
+ [128697]=1 [128703]='V>=2?1:0' [128704]=1 [128705]='V>=2?1:0' [128710]=0 [128715]='V>=1?3:0' [128716]='V>=2?1:0'
+ [128717]='V>=1?3:0' [128720]='V>=2?1:0' [128721]='V>=4?1:0' [128723]=0 [128725]='V>=8?1:0' [128726]='V>=10?1:0' [128728]=0
+ [128733]='V>=12?1:0' [128736]='V>=1?3:0' [128742]=0 [128745]='V>=1?3:0' [128746]=0 [128747]='V>=2?1:0' [128749]=0
+ [128752]='V>=1?3:0' [128755]='V>=1?3:0' [128756]='V>=4?1:0' [128759]='V>=6?1:0' [128761]='V>=7?1:0' [128762]='V>=8?1:0'
+ [128763]='V>=10?1:0' [128765]=0 [128992]='V>=8?1:0' [129004]=0 [129008]='V>=12?1:0' [129292]='V>=10?1:0' [129293]='V>=8?1:0'
+ [129296]='V>=2?1:0' [129305]='V>=4?1:0' [129311]='V>=6?1:0' [129320]='V>=6?1:0' [129328]='V>=4?1:0' [129331]='V>=4?1:0'
+ [129339]=0 [129343]='V>=8?1:0' [129350]=0 [129356]='V>=6?1:0' [129357]='V>=7?1:0' [129360]='V>=4?1:0' [129375]='V>=6?1:0'
+ [129388]='V>=7?1:0' [129393]='V>=8?1:0' [129394]='V>=10?1:0' [129399]='V>=10?1:0' [129401]='V>=12?1:0' [129402]='V>=7?1:0'
+ [129403]='V>=8?1:0' [129404]='V>=7?1:0' [129408]='V>=2?1:0' [129413]='V>=4?1:0' [129426]='V>=6?1:0' [129432]='V>=7?1:0'
+ [129443]='V>=10?1:0' [129445]='V>=8?1:0' [129451]='V>=10?1:0' [129454]='V>=8?1:0' [129456]='V>=7?4:0' [129460]='V>=7?1:0'
+ [129466]='V>=8?1:0' [129472]='V>=2?1:0' [129473]='V>=7?1:0' [129475]='V>=8?1:0' [129483]='V>=10?1:0' [129484]='V>=12?1:0'
+ [129488]='V>=6?1:0' [129511]='V>=7?1:0' [129536]=0 [129648]='V>=8?1:0' [129652]='V>=10?1:0' [129653]=0 [129656]='V>=8?1:0'
+ [129659]='V>=12?1:0' [129661]=0 [129664]='V>=8?1:0' [129667]='V>=10?1:0' [129671]=0 [129680]='V>=8?1:0' [129686]='V>=10?1:0'
+ [129705]='V>=12?1:0' [129709]=0 [129712]='V>=10?1:0' [129719]='V>=12?1:0' [129723]=0 [129728]='V>=10?1:0' [129731]='V>=12?1:0'
+ [129734]=0 [129744]='V>=10?1:0' [129751]='V>=12?1:0' [129754]=0 [129760]='V>=12?1:0' [129768]=0 [129776]='V>=12?1:0' [129783]=0)
+_ble_unicode_EmojiStatus_ranges=(8596 8602 8617 8619 8986 8988 9193 9197 9201 9204 9208 9211 9642 9644 9723 9725 9728 9730 9733
+ 9748 9750 9762 9764 9784 9787 9800 9812 9829 9833 9878 9885 9898 9900 9904 9906 9917 9919 9924 9926 9968 9970 9975 9979 9992
+ 9994 10000 10035 10037 10067 10072 10133 10136 10548 10550 11013 11016 11035 11037 127344 127346 127358 127360 127377 127387
+ 127462 127491 127538 127547 127568 127570 127744 127757 127763 127766 127775 127778 127780 127789 127792 127794 127796 127870
+ 127872 127892 127894 127900 127902 127904 127947 127951 127956 127968 127985 127992 127995 128000 128012 128015 128017 128108
+ 128110 128182 128184 128236 128240 128255 128266 128300 128302 128318 128329 128331 128336 128348 128360 128367 128369 128371
+ 128379 128394 128398 128405 128407 128433 128435 128450 128453 128465 128468 128476 128479 128507 128519 128521 128550 128552
+ 128558 128560 128577 128581 128592 128641 128643 128650 128657 128667 128676 128686 128697 128705 128710 128717 128721 128723
+ 128726 128728 128733 128736 128742 128747 128749 128756 128759 128763 128765 128992 129004 129293 129296 129305 129320 129331
+ 129357 129360 129375 129388 129399 129404 129408 129413 129426 129432 129443 129445 129451 129454 129456 129460 129466 129473
+ 129475 129488 129511 129536 129648 129653 129656 129659 129661 129664 129667 129671 129680 129686 129705 129709 129712 129719
+ 129723 129728 129731 129734 129744 129751 129754 129760 129768 129776 129783)
+function ble/unicode/EmojiStatus/version2index {
+ case $1 in
+ (0.6) ret=0 ;;
+ (0.7) ret=1 ;;
+ (1.0) ret=2 ;;
+ (2.0) ret=3 ;;
+ (3.0) ret=4 ;;
+ (4.0) ret=5 ;;
+ (5.0) ret=6 ;;
+ (11.0) ret=7 ;;
+ (12.0) ret=8 ;;
+ (12.1) ret=9 ;;
+ (13.0) ret=10 ;;
+ (13.1) ret=11 ;;
+ (14.0) ret=12 ;;
+ (*) return 1 ;;
+ esac
+}
+_ble_unicode_EmojiStatus_version=12
+bleopt/declare -n emoji_version 14.0
+bleopt/declare -v emoji_width 2
+bleopt/declare -v emoji_opts ri
+function bleopt/check:emoji_version {
+ local ret
+ if ! ble/unicode/EmojiStatus/version2index "$value"; then
+ local rex='^0*([0-9]+)\.0*([0-9]+)$'
+ if ! [[ $value =~ $rex ]]; then
+ ble/util/print "bleopt: Invalid format for emoji_version: '$value'." >&2
+ return 1
+ else
+ ble/util/print "bleopt: Unsupported emoji_version: '$value'." >&2
+ return 1
+ fi
+ fi
+ _ble_unicode_EmojiStatus_version=$ret
+ ((_ble_prompt_version++))
+ ble/util/c2w/clear-cache
+ return 0
+}
+function bleopt/check:emoji_width { ble/util/c2w/clear-cache; }
+_ble_unicode_EmojiStatus_xIsEmoji='ret&&ret!=_ble_unicode_EmojiStatus_Unqualified'
+function bleopt/check:emoji_opts {
+ _ble_unicode_EmojiStatus_xIsEmoji='ret'
+ [[ :$value: != *:unqualified:* ]] &&
+ _ble_unicode_EmojiStatus_xIsEmoji=$_ble_unicode_EmojiStatus_xIsEmoji'&&ret!=_ble_unicode_EmojiStatus_Unqualified'
+ local rex=':min=U\+([0-9a-fA-F]+):'
+ [[ :$value: =~ $rex ]] &&
+ _ble_unicode_EmojiStatus_xIsEmoji=$_ble_unicode_EmojiStatus_xIsEmoji'&&code>=0x'${BASH_REMATCH[1]}
+ ((_ble_prompt_version++))
+ ble/util/c2w/clear-cache
+ return 0
+}
+function ble/unicode/EmojiStatus {
+ local code=$1 V=$_ble_unicode_EmojiStatus_version
+ ret=${_ble_unicode_EmojiStatus[code]}
+ if [[ ! $ret ]]; then
+ ret=$_ble_unicode_EmojiStatus_None
+ if ((_ble_unicode_EmojiStatus_xmaybe)); then
+ local l=0 u=${#_ble_unicode_EmojiStatus_ranges[@]} m
+ while ((l+1<u)); do
+ ((_ble_unicode_EmojiStatus_ranges[m=(l+u)/2]<=code?(l=m):(u=m)))
+ done
+ ret=${_ble_unicode_EmojiStatus[_ble_unicode_EmojiStatus_ranges[l]]:-0}
+ fi
+ _ble_unicode_EmojiStatus[code]=$ret
+ fi
+ ((ret=ret))
+ return 0
+}
+function ble/util/c2w/is-emoji {
+ local code=$1 ret
+ ble/unicode/EmojiStatus "$code"
+ ((_ble_unicode_EmojiStatus_xIsEmoji))
+}
+function ble/util/c2w:west {
+ if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$1"; then
+ ((ret=bleopt_emoji_width))
+ else
+ ble/unicode/c2w "$1"
+ fi
+}
+function ble/util/c2w:east {
+ if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$1"; then
+ ((ret=bleopt_emoji_width))
+ else
+ ble/unicode/c2w "$1"
+ fi
+}
+_ble_util_c2w_emacs_wranges=(
+ 162 164 167 169 172 173 176 178 180 181 182 183 215 216 247 248 272 273 276 279
+ 280 282 284 286 288 290 293 295 304 305 306 308 315 316 515 516 534 535 545 546
+ 555 556 608 618 656 660 722 723 724 725 768 769 770 772 775 777 779 780 785 787
+ 794 795 797 801 805 806 807 813 814 815 820 822 829 830 850 851 864 866 870 872
+ 874 876 898 900 902 904 933 934 959 960 1042 1043 1065 1067 1376 1396 1536 1540 1548 1549
+ 1551 1553 1555 1557 1559 1561 1563 1566 1568 1569 1571 1574 1576 1577 1579 1581 1583 1585 1587 1589
+ 1591 1593 1595 1597 1599 1600 1602 1603 1611 1612 1696 1698 1714 1716 1724 1726 1734 1736 1739 1740
+ 1742 1744 1775 1776 1797 1799 1856 1857 1858 1859 1898 1899 1901 1902 1903 1904)
+function ble/util/c2w:emacs {
+ local code=$1
+ ret=1
+ ((code<0xA0)) && return 0
+ if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$code"; then
+ ((ret=bleopt_emoji_width))
+ return 0
+ fi
+ local al=0 ah=0 tIndex=
+ ((
+ 0x3100<=code&&code<0xA4D0||0xAC00<=code&&code<0xD7A4?(
+ ret=2
+ ):(0x2000<=code&&code<0x2700?(
+ tIndex=0x0100+code-0x2000
+ ):(
+ al=code&0xFF,
+ ah=code/256,
+ ah==0x00?(
+ tIndex=al
+ ):(ah==0x03?(
+ ret=0xFF&((al-0x91)&~0x20),
+ ret=ret<25&&ret!=17?2:1
+ ):(ah==0x04?(
+ ret=al==1||0x10<=al&&al<=0x50||al==0x51?2:1
+ ):(ah==0x11?(
+ ret=al<0x60?2:1
+ ):(ah==0x2e?(
+ ret=al>=0x80?2:1
+ ):(ah==0x2f?(
+ ret=2
+ ):(ah==0x30?(
+ ret=al!=0x3f?2:1
+ ):(ah==0xf9||ah==0xfa?(
+ ret=2
+ ):(ah==0xfe?(
+ ret=0x30<=al&&al<0x70?2:1
+ ):(ah==0xff?(
+ ret=0x01<=al&&al<0x61||0xE0<=al&&al<=0xE7?2:1
+ ):(ret=1))))))))))
+ ))
+ ))
+ [[ $tIndex ]] || return 0
+ if ((tIndex<_ble_util_c2w_emacs_wranges[0])); then
+ ret=1
+ return 0
+ fi
+ local l=0 u=${#_ble_util_c2w_emacs_wranges[@]} m
+ while ((l+1<u)); do
+ ((_ble_util_c2w_emacs_wranges[m=(l+u)/2]<=tIndex?(l=m):(u=m)))
+ done
+ ((ret=((l&1)==0)?2:1))
+ return 0
+}
+_ble_util_c2w_musl=([0]=0 [1]=1 [768]=0 [880]=1 [1155]=0 [1162]=1 [1425]=0 [1470]=1 [1471]=0 [1472]=1 [1473]=0 [1475]=1 [1476]=0
+ [1478]=1 [1479]=0 [1480]=1 [1536]=0 [1541]=1 [1552]=0 [1563]=1 [1611]=0 [1632]=1 [1648]=0 [1649]=1 [1750]=0 [1758]=1 [1759]=0
+ [1765]=1 [1767]=0 [1769]=1 [1770]=0 [1774]=1 [1807]=0 [1808]=1 [1809]=0 [1810]=1 [1840]=0 [1867]=1 [1958]=0 [1969]=1 [2027]=0
+ [2036]=1 [2070]=0 [2074]=1 [2075]=0 [2084]=1 [2085]=0 [2088]=1 [2089]=0 [2094]=1 [2137]=0 [2140]=1 [2276]=0 [2303]=1 [2304]=0
+ [2307]=1 [2362]=0 [2363]=1 [2364]=0 [2365]=1 [2369]=0 [2377]=1 [2381]=0 [2382]=1 [2385]=0 [2392]=1 [2402]=0 [2404]=1 [2433]=0
+ [2434]=1 [2492]=0 [2493]=1 [2497]=0 [2501]=1 [2509]=0 [2510]=1 [2530]=0 [2532]=1 [2561]=0 [2563]=1 [2620]=0 [2621]=1 [2625]=0
+ [2627]=1 [2631]=0 [2633]=1 [2635]=0 [2638]=1 [2641]=0 [2642]=1 [2672]=0 [2674]=1 [2677]=0 [2678]=1 [2689]=0 [2691]=1 [2748]=0
+ [2749]=1 [2753]=0 [2758]=1 [2759]=0 [2761]=1 [2765]=0 [2766]=1 [2786]=0 [2788]=1 [2817]=0 [2818]=1 [2876]=0 [2877]=1 [2879]=0
+ [2880]=1 [2881]=0 [2885]=1 [2893]=0 [2894]=1 [2902]=0 [2903]=1 [2914]=0 [2916]=1 [2946]=0 [2947]=1 [3008]=0 [3009]=1 [3021]=0
+ [3022]=1 [3134]=0 [3137]=1 [3142]=0 [3145]=1 [3146]=0 [3150]=1 [3157]=0 [3159]=1 [3170]=0 [3172]=1 [3260]=0 [3261]=1 [3263]=0
+ [3264]=1 [3270]=0 [3271]=1 [3276]=0 [3278]=1 [3298]=0 [3300]=1 [3393]=0 [3397]=1 [3405]=0 [3406]=1 [3426]=0 [3428]=1 [3530]=0
+ [3531]=1 [3538]=0 [3541]=1 [3542]=0 [3543]=1 [3633]=0 [3634]=1 [3636]=0 [3643]=1 [3655]=0 [3663]=1 [3761]=0 [3762]=1 [3764]=0
+ [3770]=1 [3771]=0 [3773]=1 [3784]=0 [3790]=1 [3864]=0 [3866]=1 [3893]=0 [3894]=1 [3895]=0 [3896]=1 [3897]=0 [3898]=1 [3953]=0
+ [3967]=1 [3968]=0 [3973]=1 [3974]=0 [3976]=1 [3981]=0 [3992]=1 [3993]=0 [4029]=1 [4038]=0 [4039]=1 [4141]=0 [4145]=1 [4146]=0
+ [4152]=1 [4153]=0 [4155]=1 [4157]=0 [4159]=1 [4184]=0 [4186]=1 [4190]=0 [4193]=1 [4209]=0 [4213]=1 [4226]=0 [4227]=1 [4229]=0
+ [4231]=1 [4237]=0 [4238]=1 [4253]=0 [4254]=1 [4352]=2 [4448]=1 [4515]=2 [4520]=1 [4602]=2 [4608]=1 [4957]=0 [4960]=1 [5906]=0
+ [5909]=1 [5938]=0 [5941]=1 [5970]=0 [5972]=1 [6002]=0 [6004]=1 [6068]=0 [6070]=1 [6071]=0 [6078]=1 [6086]=0 [6087]=1 [6089]=0
+ [6100]=1 [6109]=0 [6110]=1 [6155]=0 [6158]=1 [6313]=0 [6314]=1 [6432]=0 [6435]=1 [6439]=0 [6441]=1 [6450]=0 [6451]=1 [6457]=0
+ [6460]=1 [6679]=0 [6681]=1 [6742]=0 [6743]=1 [6744]=0 [6751]=1 [6752]=0 [6753]=1 [6754]=0 [6755]=1 [6757]=0 [6765]=1 [6771]=0
+ [6781]=1 [6783]=0 [6784]=1 [6912]=0 [6916]=1 [6964]=0 [6965]=1 [6966]=0 [6971]=1 [6972]=0 [6973]=1 [6978]=0 [6979]=1 [7019]=0
+ [7028]=1 [7040]=0 [7042]=1 [7074]=0 [7078]=1 [7080]=0 [7082]=1 [7083]=0 [7084]=1 [7142]=0 [7143]=1 [7144]=0 [7146]=1 [7149]=0
+ [7150]=1 [7151]=0 [7154]=1 [7212]=0 [7220]=1 [7222]=0 [7224]=1 [7376]=0 [7379]=1 [7380]=0 [7393]=1 [7394]=0 [7401]=1 [7405]=0
+ [7406]=1 [7412]=0 [7413]=1 [7616]=0 [7655]=1 [7676]=0 [7680]=1 [8203]=0 [8208]=1 [8234]=0 [8239]=1 [8288]=0 [8293]=1 [8298]=0
+ [8304]=1 [8400]=0 [8433]=1 [9001]=2 [9003]=1 [11503]=0 [11506]=1 [11647]=0 [11648]=1 [11744]=0 [11776]=1 [11904]=2 [11930]=1
+ [11931]=2 [12020]=1 [12032]=2 [12246]=1 [12272]=2 [12284]=1 [12288]=2 [12330]=0 [12334]=2 [12351]=1 [12353]=2 [12439]=1
+ [12441]=0 [12443]=2 [12544]=1 [12549]=2 [12590]=1 [12593]=2 [12687]=1 [12688]=2 [12731]=1 [12736]=2 [12772]=1 [12784]=2
+ [12831]=1 [12832]=2 [12872]=1 [12880]=2 [13055]=1 [13056]=2 [19904]=1 [19968]=2 [42125]=1 [42128]=2 [42183]=1 [42607]=0
+ [42611]=1 [42612]=0 [42622]=1 [42655]=0 [42656]=1 [42736]=0 [42738]=1 [43010]=0 [43011]=1 [43014]=0 [43015]=1 [43019]=0
+ [43020]=1 [43045]=0 [43047]=1 [43204]=0 [43205]=1 [43232]=0 [43250]=1 [43302]=0 [43310]=1 [43335]=0 [43346]=1 [43360]=2
+ [43389]=1 [43392]=0 [43395]=1 [43443]=0 [43444]=1 [43446]=0 [43450]=1 [43452]=0 [43453]=1 [43561]=0 [43567]=1 [43569]=0
+ [43571]=1 [43573]=0 [43575]=1 [43587]=0 [43588]=1 [43596]=0 [43597]=1 [43696]=0 [43697]=1 [43698]=0 [43701]=1 [43703]=0
+ [43705]=1 [43710]=0 [43712]=1 [43713]=0 [43714]=1 [43756]=0 [43758]=1 [43766]=0 [43767]=1 [44005]=0 [44006]=1 [44008]=0
+ [44009]=1 [44013]=0 [44014]=1 [44032]=2 [55204]=1 [55216]=2 [55239]=1 [55243]=2 [55292]=1 [63744]=2 [64256]=1 [64286]=0
+ [64287]=1 [65024]=0 [65040]=2 [65050]=1 [65056]=0 [65063]=1 [65072]=2 [65107]=1 [65108]=2 [65127]=1 [65128]=2 [65132]=1
+ [65279]=0 [65280]=1 [65281]=2 [65377]=1 [65504]=2 [65511]=1 [65529]=0 [65532]=1 [66045]=0 [66046]=1 [68097]=0 [68100]=1
+ [68101]=0 [68103]=1 [68108]=0 [68112]=1 [68152]=0 [68155]=1 [68159]=0 [68160]=1 [69633]=0 [69634]=1 [69688]=0 [69703]=1
+ [69760]=0 [69762]=1 [69811]=0 [69815]=1 [69817]=0 [69819]=1 [69821]=0 [69822]=1 [69888]=0 [69891]=1 [69927]=0 [69932]=1
+ [69933]=0 [69941]=1 [70016]=0 [70018]=1 [70070]=0 [70079]=1 [71339]=0 [71340]=1 [71341]=0 [71342]=1 [71344]=0 [71350]=1
+ [71351]=0 [71352]=1 [94095]=0 [94099]=1 [110592]=2 [110594]=1 [119143]=0 [119146]=1 [119155]=0 [119171]=1 [119173]=0 [119180]=1
+ [119210]=0 [119214]=1 [119362]=0 [119365]=1 [127488]=2 [127491]=1 [127504]=2 [127547]=1 [127552]=2 [127561]=1 [127568]=2
+ [127570]=1 [131072]=2 [196606]=1 [196608]=2 [262142]=1 [262144]=0 [327678]=1 [327680]=0 [393214]=1 [393216]=0 [458750]=1
+ [458752]=0 [524286]=1 [524288]=0 [589822]=1 [589824]=0 [655358]=1 [655360]=0 [720894]=1 [720896]=0 [786430]=1 [786432]=0
+ [851966]=1 [851968]=0 [917502]=1 [917504]=0 [917999]=1)
+_ble_util_c2w_musl_ranges=(0 1 768 880 1155 1162 1425 1470 1471 1472 1473 1475 1476 1478 1479 1480 1536 1541 1552 1563 1611 1632
+ 1648 1649 1750 1758 1759 1765 1767 1769 1770 1774 1807 1808 1809 1810 1840 1867 1958 1969 2027 2036 2070 2074 2075 2084 2085
+ 2088 2089 2094 2137 2140 2276 2303 2304 2307 2362 2363 2364 2365 2369 2377 2381 2382 2385 2392 2402 2404 2433 2434 2492 2493
+ 2497 2501 2509 2510 2530 2532 2561 2563 2620 2621 2625 2627 2631 2633 2635 2638 2641 2642 2672 2674 2677 2678 2689 2691 2748
+ 2749 2753 2758 2759 2761 2765 2766 2786 2788 2817 2818 2876 2877 2879 2880 2881 2885 2893 2894 2902 2903 2914 2916 2946 2947
+ 3008 3009 3021 3022 3134 3137 3142 3145 3146 3150 3157 3159 3170 3172 3260 3261 3263 3264 3270 3271 3276 3278 3298 3300 3393
+ 3397 3405 3406 3426 3428 3530 3531 3538 3541 3542 3543 3633 3634 3636 3643 3655 3663 3761 3762 3764 3770 3771 3773 3784 3790
+ 3864 3866 3893 3894 3895 3896 3897 3898 3953 3967 3968 3973 3974 3976 3981 3992 3993 4029 4038 4039 4141 4145 4146 4152 4153
+ 4155 4157 4159 4184 4186 4190 4193 4209 4213 4226 4227 4229 4231 4237 4238 4253 4254 4352 4448 4515 4520 4602 4608 4957 4960
+ 5906 5909 5938 5941 5970 5972 6002 6004 6068 6070 6071 6078 6086 6087 6089 6100 6109 6110 6155 6158 6313 6314 6432 6435 6439
+ 6441 6450 6451 6457 6460 6679 6681 6742 6743 6744 6751 6752 6753 6754 6755 6757 6765 6771 6781 6783 6784 6912 6916 6964 6965
+ 6966 6971 6972 6973 6978 6979 7019 7028 7040 7042 7074 7078 7080 7082 7083 7084 7142 7143 7144 7146 7149 7150 7151 7154 7212
+ 7220 7222 7224 7376 7379 7380 7393 7394 7401 7405 7406 7412 7413 7616 7655 7676 7680 8203 8208 8234 8239 8288 8293 8298 8304
+ 8400 8433 9001 9003 11503 11506 11647 11648 11744 11776 11904 11930 11931 12020 12032 12246 12272 12284 12288 12330 12334 12351
+ 12353 12439 12441 12443 12544 12549 12590 12593 12687 12688 12731 12736 12772 12784 12831 12832 12872 12880 13055 13056 19904
+ 19968 42125 42128 42183 42607 42611 42612 42622 42655 42656 42736 42738 43010 43011 43014 43015 43019 43020 43045 43047 43204
+ 43205 43232 43250 43302 43310 43335 43346 43360 43389 43392 43395 43443 43444 43446 43450 43452 43453 43561 43567 43569 43571
+ 43573 43575 43587 43588 43596 43597 43696 43697 43698 43701 43703 43705 43710 43712 43713 43714 43756 43758 43766 43767 44005
+ 44006 44008 44009 44013 44014 44032 55204 55216 55239 55243 55292 63744 64256 64286 64287 65024 65040 65050 65056 65063 65072
+ 65107 65108 65127 65128 65132 65279 65280 65281 65377 65504 65511 65529 65532 66045 66046 68097 68100 68101 68103 68108 68112
+ 68152 68155 68159 68160 69633 69634 69688 69703 69760 69762 69811 69815 69817 69819 69821 69822 69888 69891 69927 69932 69933
+ 69941 70016 70018 70070 70079 71339 71340 71341 71342 71344 71350 71351 71352 94095 94099 110592 110594 119143 119146 119155
+ 119171 119173 119180 119210 119214 119362 119365 127488 127491 127504 127547 127552 127561 127568 127570 131072 196606 196608
+ 262142 262144 327678 327680 393214 393216 458750 458752 524286 524288 589822 589824 655358 655360 720894 720896 786430 786432
+ 851966 851968 917502 917504 917999)
+function ble/util/c2w:musl {
+ local code=$1
+ ret=1
+ ((code&&code<0x300)) && return 0
+ if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$code"; then
+ ((ret=bleopt_emoji_width))
+ return 0
+ fi
+ local l=0 u=${#_ble_util_c2w_musl_ranges[@]} m
+ while ((l+1<u)); do
+ ((_ble_util_c2w_musl_ranges[m=(l+u)/2]<=code?(l=m):(u=m)))
+ done
+ ret=${_ble_util_c2w_musl[_ble_util_c2w_musl_ranges[l]]}
+}
+_ble_util_c2w_auto_update_x0=0
+_ble_util_c2w_auto_update_result=()
+_ble_util_c2w_auto_update_processing=0
+function ble/util/c2w:auto {
+ if [[ $bleopt_emoji_width ]] && ble/util/c2w/is-emoji "$1"; then
+ ((ret=bleopt_emoji_width))
+ else
+ ble/unicode/c2w "$1"
+ fi
+}
+function ble/util/c2w:auto/check {
+ [[ $bleopt_char_width_mode == auto || $bleopt_char_width_version == auto ]] &&
+ ble/util/c2w:auto/test.buff
+ return 0
+}
+function ble/util/c2w:auto/test.buff {
+ local opts=$1
+ local -a DRAW_BUFF=()
+ local ret saved_pos=
+ ((_ble_util_c2w_auto_update_processing)) && return 0
+ [[ $_ble_attached ]] && { ble/canvas/panel/save-position goto-top-dock; saved_pos=$ret; }
+ ble/canvas/put.draw "$_ble_term_sc"
+ if ble/util/is-unicode-output; then
+ local -a codes=(
+ 0x25bd 0x25b6
+ 0x9FBC 0x9FC4 0x31B8 0xD7B0 0x3099
+ 0x9FCD 0x1F93B 0x312E 0x312F 0x16FE2
+ 0x32FF 0x31BB 0x9FFD)
+ _ble_util_c2w_auto_update_processing=${#codes[@]}
+ _ble_util_c2w_auto_update_result=()
+ if [[ :$opts: == *:first-line:* ]]; then
+ local cols=${COLUMNS:-80}
+ local x0=$((cols-4)); ((x0<0)) && x0=0
+ _ble_util_c2w_auto_update_x0=$x0
+ local code index=0
+ for code in "${codes[@]}"; do
+ ble/canvas/put-cup.draw 1 $((x0+1))
+ ble/canvas/put.draw "$_ble_term_el"
+ ble/util/c2s $((code))
+ ble/canvas/put.draw "$ret"
+ ble/term/CPR/request.draw "ble/util/c2w/test.hook $((index++))"
+ done
+ ble/canvas/put-cup.draw 1 $((x0+1))
+ ble/canvas/put.draw "$_ble_term_el"
+ else
+ _ble_util_c2w_auto_update_x0=2
+ local code index=0
+ for code in "${codes[@]}"; do
+ ble/util/c2s $((code))
+ ble/canvas/put.draw "$_ble_term_cr$_ble_term_el[$ret]"
+ ble/term/CPR/request.draw "ble/util/c2w/test.hook $((index++))"
+ done
+ ble/canvas/put.draw "$_ble_term_cr$_ble_term_el"
+ fi
+ fi
+ ble/canvas/put.draw "$_ble_term_rc"
+ [[ $_ble_attached ]] && ble/canvas/panel/load-position.draw "$saved_pos"
+ ble/canvas/bflush.draw
+}
+function ble/util/c2w/test.hook {
+ local index=$1 l=$2 c=$3
+ local w=$((c-1-_ble_util_c2w_auto_update_x0))
+ _ble_util_c2w_auto_update_result[index]=$w
+ ((index==_ble_util_c2w_auto_update_processing-1)) || return 0
+ _ble_util_c2w_auto_update_processing=0
+ local ws
+ if [[ $bleopt_char_width_mode == auto ]]; then
+ IFS=: builtin eval 'ws="${_ble_util_c2w_auto_update_result[*]::2}:${_ble_util_c2w_auto_update_result[*]:5:2}"'
+ case $ws in
+ (2:2:*:*) bleopt char_width_mode=east ;;
+ (2:1:*:*) bleopt char_width_mode=emacs ;;
+ (1:1:2:0) bleopt char_width_mode=musl ;;
+ (*) bleopt char_width_mode=west ;;
+ esac
+ fi
+ if [[ $bleopt_char_width_version == auto ]]; then
+ ws=("${_ble_util_c2w_auto_update_result[@]:2}")
+ if ((ws[11]==2)); then
+ if ((ws[12]==2)); then
+ bleopt char_width_version=14.0
+ else
+ bleopt char_width_version=13.0
+ fi
+ elif ((ws[10]==2)); then
+ bleopt char_width_version=12.1
+ elif ((ws[9]==2)); then
+ bleopt char_width_version=12.0
+ elif ((ws[8]==2)); then
+ bleopt char_width_version=11.0
+ elif ((ws[7]==2)); then
+ bleopt char_width_version=10.0
+ elif ((ws[6]==2)); then
+ bleopt char_width_version=9.0
+ elif ((ws[4]==0)); then
+ if ((ws[5]==2)); then
+ bleopt char_width_version=8.0
+ else
+ bleopt char_width_version=7.0
+ fi
+ elif ((ws[3]==1&&ws[1]==2)); then
+ bleopt char_width_version=6.3 # or 6.2
+ elif ((ws[2]==2)); then
+ bleopt char_width_version=6.1 # or 6.0
+ elif ((ws[1]==2)); then
+ bleopt char_width_version=5.2
+ elif ((ws[0]==2)); then
+ bleopt char_width_version=5.0
+ else
+ bleopt char_width_version=4.1
+ fi
+ fi
+ return 0
+}
+bleopt/declare -v grapheme_cluster extended
+function bleopt/check:grapheme_cluster {
+ case $value in
+ (extended|legacy|'') return 0 ;;
+ (*)
+ ble/util/print "bleopt: invalid value for grapheme_cluster: '$value'." >&2
+ return 1 ;;
+ esac
+}
+_ble_unicode_GraphemeClusterBreak_Count=13
+_ble_unicode_GraphemeClusterBreak_ZWJ=2
+_ble_unicode_GraphemeClusterBreak_Regional_Indicator=6
+_ble_unicode_GraphemeClusterBreak_Prepend=3
+_ble_unicode_GraphemeClusterBreak_SpacingMark=5
+_ble_unicode_GraphemeClusterBreak_LVT=11
+_ble_unicode_GraphemeClusterBreak_Pictographic=12
+_ble_unicode_GraphemeClusterBreak_LV=10
+_ble_unicode_GraphemeClusterBreak_T=9
+_ble_unicode_GraphemeClusterBreak_V=8
+_ble_unicode_GraphemeClusterBreak_Control=1
+_ble_unicode_GraphemeClusterBreak_Extend=4
+_ble_unicode_GraphemeClusterBreak_Other=0
+_ble_unicode_GraphemeClusterBreak_L=7
+_ble_unicode_GraphemeClusterBreak_MaxCode=921600
+_ble_unicode_GraphemeClusterBreak=(
+ [169]=12 [173]=1 [174]=12 [1470]=0 [1471]=4 [1472]=0 [1473]=4 [1474]=4 [1475]=0 [1476]=4 [1477]=4 [1478]=0 [1479]=4 [1563]=0 [1564]=1 [1648]=4
+ [1757]=3 [1758]=0 [1765]=0 [1766]=0 [1767]=4 [1768]=4 [1769]=0 [1807]=3 [1808]=0 [1809]=4 [2045]=4 [2074]=0 [2084]=0 [2088]=0 [2274]=3 [2307]=5
+ [2362]=4 [2363]=5 [2364]=4 [2365]=0 [2381]=4 [2382]=5 [2383]=5 [2384]=0 [2402]=4 [2403]=4 [2433]=4 [2434]=5 [2435]=5 [2492]=4 [2493]=0 [2494]=4
+ [2495]=5 [2496]=5 [2501]=0 [2502]=0 [2503]=5 [2504]=5 [2505]=0 [2506]=0 [2507]=5 [2508]=5 [2509]=4 [2519]=4 [2530]=4 [2531]=4 [2558]=4 [2559]=0
+ [2560]=0 [2561]=4 [2562]=4 [2563]=5 [2620]=4 [2621]=0 [2625]=4 [2626]=4 [2631]=4 [2632]=4 [2633]=0 [2634]=0 [2641]=4 [2672]=4 [2673]=4 [2677]=4
+ [2689]=4 [2690]=4 [2691]=5 [2748]=4 [2749]=0 [2758]=0 [2759]=4 [2760]=4 [2761]=5 [2762]=0 [2763]=5 [2764]=5 [2765]=4 [2786]=4 [2787]=4 [2816]=0
+ [2817]=4 [2818]=5 [2819]=5 [2876]=4 [2877]=0 [2878]=4 [2879]=4 [2880]=5 [2885]=0 [2886]=0 [2887]=5 [2888]=5 [2889]=0 [2890]=0 [2891]=5 [2892]=5
+ [2893]=4 [2914]=4 [2915]=4 [2946]=4 [3006]=4 [3007]=5 [3008]=4 [3009]=5 [3010]=5 [3017]=0 [3021]=4 [3031]=4 [3072]=4 [3076]=4 [3141]=0 [3145]=0
+ [3157]=4 [3158]=4 [3170]=4 [3171]=4 [3201]=4 [3202]=5 [3203]=5 [3260]=4 [3261]=0 [3262]=5 [3263]=4 [3264]=5 [3265]=5 [3266]=4 [3267]=5 [3268]=5
+ [3269]=0 [3270]=4 [3271]=5 [3272]=5 [3273]=0 [3274]=5 [3275]=5 [3276]=4 [3277]=4 [3285]=4 [3286]=4 [3298]=4 [3299]=4 [3328]=4 [3329]=4 [3330]=5
+ [3331]=5 [3387]=4 [3388]=4 [3389]=0 [3390]=4 [3391]=5 [3392]=5 [3397]=0 [3401]=0 [3405]=4 [3406]=3 [3415]=4 [3426]=4 [3427]=4 [3457]=4 [3458]=5
+ [3459]=5 [3530]=4 [3535]=4 [3536]=5 [3537]=5 [3541]=0 [3542]=4 [3543]=0 [3551]=4 [3570]=5 [3571]=5 [3633]=4 [3634]=0 [3635]=5 [3761]=4 [3762]=0
+ [3763]=5 [3864]=4 [3865]=4 [3893]=4 [3894]=0 [3895]=4 [3896]=0 [3897]=4 [3902]=5 [3903]=5 [3967]=5 [3973]=0 [3974]=4 [3975]=4 [3992]=0 [4038]=4
+ [4145]=5 [4152]=0 [4153]=4 [4154]=4 [4155]=5 [4156]=5 [4157]=4 [4158]=4 [4182]=5 [4183]=5 [4184]=4 [4185]=4 [4226]=4 [4227]=0 [4228]=5 [4229]=4
+ [4230]=4 [4237]=4 [4253]=4 [5970]=4 [5971]=4 [6002]=4 [6003]=4 [6068]=4 [6069]=4 [6070]=5 [6086]=4 [6087]=5 [6088]=5 [6109]=4 [6158]=1 [6277]=4
+ [6278]=4 [6313]=4 [6439]=4 [6440]=4 [6448]=5 [6449]=5 [6450]=4 [6679]=4 [6680]=4 [6681]=5 [6682]=5 [6683]=4 [6741]=5 [6742]=4 [6743]=5 [6751]=0
+ [6752]=4 [6753]=0 [6754]=4 [6755]=0 [6756]=0 [6781]=0 [6782]=0 [6783]=4 [6916]=5 [6971]=5 [6972]=4 [6978]=4 [6979]=5 [6980]=5 [7040]=4 [7041]=4
+ [7042]=5 [7073]=5 [7078]=5 [7079]=5 [7080]=4 [7081]=4 [7082]=5 [7142]=4 [7143]=5 [7144]=4 [7145]=4 [7149]=4 [7150]=5 [7154]=5 [7155]=5 [7220]=5
+ [7221]=5 [7222]=4 [7223]=4 [7379]=0 [7393]=5 [7405]=4 [7412]=4 [7413]=0 [7414]=0 [7415]=5 [7416]=4 [7417]=4 [7674]=0 [8203]=1 [8204]=4 [8205]=2
+ [8206]=1 [8207]=1 [8252]=12 [8265]=12 [8482]=12 [8505]=12 [8617]=12 [8618]=12 [8986]=12 [8987]=12 [9000]=12 [9096]=12 [9167]=12 [9410]=12 [9642]=12 [9643]=12
+ [9654]=12 [9664]=12 [9727]=0 [9734]=0 [9747]=0 [9990]=0 [9991]=0 [10003]=0 [10004]=12 [10005]=0 [10006]=12 [10013]=12 [10017]=12 [10024]=12 [10035]=12 [10036]=12
+ [10052]=12 [10053]=0 [10054]=0 [10055]=12 [10060]=12 [10061]=0 [10062]=12 [10070]=0 [10071]=12 [10145]=12 [10160]=12 [10175]=12 [10548]=12 [10549]=12 [11035]=12 [11036]=12
+ [11088]=12 [11093]=12 [11647]=4 [12336]=12 [12349]=12 [12441]=4 [12442]=4 [12951]=12 [12952]=0 [12953]=12 [42611]=0 [42654]=4 [42655]=4 [42736]=4 [42737]=4 [43010]=4
+ [43014]=4 [43019]=4 [43043]=5 [43044]=5 [43045]=4 [43046]=4 [43047]=5 [43052]=4 [43136]=5 [43137]=5 [43204]=4 [43205]=4 [43263]=4 [43346]=5 [43347]=5 [43395]=5
+ [43443]=4 [43444]=5 [43445]=5 [43450]=5 [43451]=5 [43452]=4 [43453]=4 [43493]=4 [43567]=5 [43568]=5 [43569]=4 [43570]=4 [43571]=5 [43572]=5 [43573]=4 [43574]=4
+ [43587]=4 [43596]=4 [43597]=5 [43644]=4 [43696]=4 [43697]=0 [43701]=0 [43702]=0 [43703]=4 [43704]=4 [43710]=4 [43711]=4 [43712]=0 [43713]=4 [43755]=5 [43756]=4
+ [43757]=4 [43758]=5 [43759]=5 [43765]=5 [43766]=4 [44003]=5 [44004]=5 [44005]=4 [44006]=5 [44007]=5 [44008]=4 [44009]=5 [44010]=5 [44011]=0 [44012]=5 [44013]=4
+ [44032]=10 [44060]=10 [44088]=10 [44116]=10 [44144]=10 [44172]=10 [44200]=10 [44228]=10 [44256]=10 [44284]=10 [44312]=10 [44340]=10 [44368]=10 [44396]=10 [44424]=10 [44452]=10
+ [44480]=10 [44508]=10 [44536]=10 [44564]=10 [44592]=10 [44620]=10 [44648]=10 [44676]=10 [44704]=10 [44732]=10 [44760]=10 [44788]=10 [44816]=10 [44844]=10 [44872]=10 [44900]=10
+ [44928]=10 [44956]=10 [44984]=10 [45012]=10 [45040]=10 [45068]=10 [45096]=10 [45124]=10 [45152]=10 [45180]=10 [45208]=10 [45236]=10 [45264]=10 [45292]=10 [45320]=10 [45348]=10
+ [45376]=10 [45404]=10 [45432]=10 [45460]=10 [45488]=10 [45516]=10 [45544]=10 [45572]=10 [45600]=10 [45628]=10 [45656]=10 [45684]=10 [45712]=10 [45740]=10 [45768]=10 [45796]=10
+ [45824]=10 [45852]=10 [45880]=10 [45908]=10 [45936]=10 [45964]=10 [45992]=10 [46020]=10 [46048]=10 [46076]=10 [46104]=10 [46132]=10 [46160]=10 [46188]=10 [46216]=10 [46244]=10
+ [46272]=10 [46300]=10 [46328]=10 [46356]=10 [46384]=10 [46412]=10 [46440]=10 [46468]=10 [46496]=10 [46524]=10 [46552]=10 [46580]=10 [46608]=10 [46636]=10 [46664]=10 [46692]=10
+ [46720]=10 [46748]=10 [46776]=10 [46804]=10 [46832]=10 [46860]=10 [46888]=10 [46916]=10 [46944]=10 [46972]=10 [47000]=10 [47028]=10 [47056]=10 [47084]=10 [47112]=10 [47140]=10
+ [47168]=10 [47196]=10 [47224]=10 [47252]=10 [47280]=10 [47308]=10 [47336]=10 [47364]=10 [47392]=10 [47420]=10 [47448]=10 [47476]=10 [47504]=10 [47532]=10 [47560]=10 [47588]=10
+ [47616]=10 [47644]=10 [47672]=10 [47700]=10 [47728]=10 [47756]=10 [47784]=10 [47812]=10 [47840]=10 [47868]=10 [47896]=10 [47924]=10 [47952]=10 [47980]=10 [48008]=10 [48036]=10
+ [48064]=10 [48092]=10 [48120]=10 [48148]=10 [48176]=10 [48204]=10 [48232]=10 [48260]=10 [48288]=10 [48316]=10 [48344]=10 [48372]=10 [48400]=10 [48428]=10 [48456]=10 [48484]=10
+ [48512]=10 [48540]=10 [48568]=10 [48596]=10 [48624]=10 [48652]=10 [48680]=10 [48708]=10 [48736]=10 [48764]=10 [48792]=10 [48820]=10 [48848]=10 [48876]=10 [48904]=10 [48932]=10
+ [48960]=10 [48988]=10 [49016]=10 [49044]=10 [49072]=10 [49100]=10 [49128]=10 [49156]=10 [49184]=10 [49212]=10 [49240]=10 [49268]=10 [49296]=10 [49324]=10 [49352]=10 [49380]=10
+ [49408]=10 [49436]=10 [49464]=10 [49492]=10 [49520]=10 [49548]=10 [49576]=10 [49604]=10 [49632]=10 [49660]=10 [49688]=10 [49716]=10 [49744]=10 [49772]=10 [49800]=10 [49828]=10
+ [49856]=10 [49884]=10 [49912]=10 [49940]=10 [49968]=10 [49996]=10 [50024]=10 [50052]=10 [50080]=10 [50108]=10 [50136]=10 [50164]=10 [50192]=10 [50220]=10 [50248]=10 [50276]=10
+ [50304]=10 [50332]=10 [50360]=10 [50388]=10 [50416]=10 [50444]=10 [50472]=10 [50500]=10 [50528]=10 [50556]=10 [50584]=10 [50612]=10 [50640]=10 [50668]=10 [50696]=10 [50724]=10
+ [50752]=10 [50780]=10 [50808]=10 [50836]=10 [50864]=10 [50892]=10 [50920]=10 [50948]=10 [50976]=10 [51004]=10 [51032]=10 [51060]=10 [51088]=10 [51116]=10 [51144]=10 [51172]=10
+ [51200]=10 [51228]=10 [51256]=10 [51284]=10 [51312]=10 [51340]=10 [51368]=10 [51396]=10 [51424]=10 [51452]=10 [51480]=10 [51508]=10 [51536]=10 [51564]=10 [51592]=10 [51620]=10
+ [51648]=10 [51676]=10 [51704]=10 [51732]=10 [51760]=10 [51788]=10 [51816]=10 [51844]=10 [51872]=10 [51900]=10 [51928]=10 [51956]=10 [51984]=10 [52012]=10 [52040]=10 [52068]=10
+ [52096]=10 [52124]=10 [52152]=10 [52180]=10 [52208]=10 [52236]=10 [52264]=10 [52292]=10 [52320]=10 [52348]=10 [52376]=10 [52404]=10 [52432]=10 [52460]=10 [52488]=10 [52516]=10
+ [52544]=10 [52572]=10 [52600]=10 [52628]=10 [52656]=10 [52684]=10 [52712]=10 [52740]=10 [52768]=10 [52796]=10 [52824]=10 [52852]=10 [52880]=10 [52908]=10 [52936]=10 [52964]=10
+ [52992]=10 [53020]=10 [53048]=10 [53076]=10 [53104]=10 [53132]=10 [53160]=10 [53188]=10 [53216]=10 [53244]=10 [53272]=10 [53300]=10 [53328]=10 [53356]=10 [53384]=10 [53412]=10
+ [53440]=10 [53468]=10 [53496]=10 [53524]=10 [53552]=10 [53580]=10 [53608]=10 [53636]=10 [53664]=10 [53692]=10 [53720]=10 [53748]=10 [53776]=10 [53804]=10 [53832]=10 [53860]=10
+ [53888]=10 [53916]=10 [53944]=10 [53972]=10 [54000]=10 [54028]=10 [54056]=10 [54084]=10 [54112]=10 [54140]=10 [54168]=10 [54196]=10 [54224]=10 [54252]=10 [54280]=10 [54308]=10
+ [54336]=10 [54364]=10 [54392]=10 [54420]=10 [54448]=10 [54476]=10 [54504]=10 [54532]=10 [54560]=10 [54588]=10 [54616]=10 [54644]=10 [54672]=10 [54700]=10 [54728]=10 [54756]=10
+ [54784]=10 [54812]=10 [54840]=10 [54868]=10 [54896]=10 [54924]=10 [54952]=10 [54980]=10 [55008]=10 [55036]=10 [55064]=10 [55092]=10 [55120]=10 [55148]=10 [55176]=10 [64286]=4
+ [65279]=1 [65438]=4 [65439]=4 [66045]=4 [66272]=4 [68100]=0 [68101]=4 [68102]=4 [68159]=4 [68325]=4 [68326]=4 [69291]=4 [69292]=4 [69632]=5 [69633]=4 [69634]=5
+ [69762]=5 [69815]=5 [69816]=5 [69817]=4 [69818]=4 [69819]=0 [69820]=0 [69821]=3 [69837]=3 [69932]=5 [69957]=5 [69958]=5 [70003]=4 [70016]=4 [70017]=4 [70018]=5
+ [70079]=5 [70080]=5 [70081]=0 [70082]=3 [70083]=3 [70093]=0 [70094]=5 [70095]=4 [70194]=5 [70195]=5 [70196]=4 [70197]=5 [70198]=4 [70199]=4 [70206]=4 [70367]=4
+ [70400]=4 [70401]=4 [70402]=5 [70403]=5 [70459]=4 [70460]=4 [70461]=0 [70462]=4 [70463]=5 [70464]=4 [70469]=0 [70470]=0 [70471]=5 [70472]=5 [70473]=0 [70474]=0
+ [70487]=4 [70498]=5 [70499]=5 [70500]=0 [70501]=0 [70720]=5 [70721]=5 [70725]=5 [70726]=4 [70750]=4 [70832]=4 [70833]=5 [70834]=5 [70841]=5 [70842]=4 [70843]=5
+ [70844]=5 [70845]=4 [70846]=5 [70847]=4 [70848]=4 [70849]=5 [70850]=4 [70851]=4 [71087]=4 [71088]=5 [71089]=5 [71094]=0 [71095]=0 [71100]=4 [71101]=4 [71102]=5
+ [71103]=4 [71104]=4 [71132]=4 [71133]=4 [71227]=5 [71228]=5 [71229]=4 [71230]=5 [71231]=4 [71232]=4 [71339]=4 [71340]=5 [71341]=4 [71342]=5 [71343]=5 [71350]=5
+ [71351]=4 [71456]=5 [71457]=5 [71462]=5 [71736]=5 [71737]=4 [71738]=4 [71984]=4 [71990]=0 [71991]=5 [71992]=5 [71993]=0 [71994]=0 [71995]=4 [71996]=4 [71997]=5
+ [71998]=4 [71999]=3 [72000]=5 [72001]=3 [72002]=5 [72003]=4 [72152]=0 [72153]=0 [72154]=4 [72155]=4 [72160]=4 [72164]=5 [72249]=5 [72250]=3 [72263]=4 [72279]=5
+ [72280]=5 [72343]=5 [72344]=4 [72345]=4 [72751]=5 [72759]=0 [72766]=5 [72767]=4 [72872]=0 [72873]=5 [72881]=5 [72882]=4 [72883]=4 [72884]=5 [72885]=4 [72886]=4
+ [73018]=4 [73019]=0 [73020]=4 [73021]=4 [73022]=0 [73030]=3 [73031]=4 [73103]=0 [73104]=4 [73105]=4 [73106]=0 [73107]=5 [73108]=5 [73109]=4 [73110]=5 [73111]=4
+ [73459]=4 [73460]=4 [73461]=5 [73462]=5 [94031]=4 [94032]=0 [94180]=4 [94192]=5 [94193]=5 [113821]=4 [113822]=4 [113823]=0 [119141]=4 [119142]=5 [119149]=5 [119171]=0
+ [119172]=0 [121461]=4 [121476]=4 [121504]=0 [122887]=0 [122905]=0 [122906]=0 [122914]=0 [122915]=4 [122916]=4 [122917]=0 [127279]=12 [127358]=12 [127359]=12 [127374]=12 [127375]=0
+ [127376]=0 [127488]=0 [127514]=12 [127535]=12 [127536]=0 [127537]=0 [127547]=0 [129339]=0 [129350]=0
+ [0]=1 [32]=0 [127]=1 [160]=0 [768]=4 [880]=0 [1155]=4 [1162]=0 [1425]=4 [1480]=0 [1536]=3 [1542]=0 [1552]=4 [1565]=0 [1611]=4 [1632]=0
+ [1750]=4 [1774]=0 [1840]=4 [1867]=0 [1958]=4 [1969]=0 [2027]=4 [2036]=0 [2070]=4 [2094]=0 [2137]=4 [2140]=0 [2259]=4 [2308]=0 [2366]=5 [2369]=4
+ [2377]=5 [2385]=4 [2392]=0 [2497]=4 [2510]=0 [2622]=5 [2627]=0 [2635]=4 [2638]=0 [2750]=5 [2753]=4 [2766]=0 [2810]=4 [2820]=0 [2881]=4 [2894]=0
+ [2901]=4 [2904]=0 [3014]=5 [3022]=0 [3073]=5 [3077]=0 [3134]=4 [3137]=5 [3142]=4 [3150]=0 [3393]=4 [3398]=5 [3407]=0 [3538]=4 [3544]=5 [3552]=0
+ [3636]=4 [3643]=0 [3655]=4 [3663]=0 [3764]=4 [3773]=0 [3784]=4 [3790]=0 [3953]=4 [3976]=0 [3981]=4 [4029]=0 [4141]=4 [4159]=0 [4190]=4 [4193]=0
+ [4209]=4 [4213]=0 [4352]=7 [4448]=8 [4520]=9 [4608]=0 [4957]=4 [4960]=0 [5906]=4 [5909]=0 [5938]=4 [5941]=0 [6071]=4 [6078]=5 [6089]=4 [6100]=0
+ [6155]=4 [6159]=0 [6432]=4 [6435]=5 [6444]=0 [6451]=5 [6457]=4 [6460]=0 [6744]=4 [6765]=5 [6771]=4 [6784]=0 [6832]=4 [6849]=0 [6912]=4 [6917]=0
+ [6964]=4 [6973]=5 [6981]=0 [7019]=4 [7028]=0 [7074]=4 [7086]=0 [7146]=5 [7151]=4 [7156]=0 [7204]=5 [7212]=4 [7224]=0 [7376]=4 [7401]=0 [7616]=4
+ [7680]=0 [8232]=1 [8239]=0 [8288]=1 [8304]=0 [8400]=4 [8433]=0 [8596]=12 [8602]=0 [9193]=12 [9204]=0 [9208]=12 [9211]=0 [9723]=12 [9862]=0 [9872]=12
+ [10007]=0 [10067]=12 [10072]=0 [10083]=12 [10088]=0 [10133]=12 [10136]=0 [11013]=12 [11016]=0 [11503]=4 [11506]=0 [11744]=4 [11776]=0 [12330]=4 [12337]=0 [42607]=4
+ [42622]=0 [43188]=5 [43206]=0 [43232]=4 [43250]=0 [43302]=4 [43310]=0 [43335]=4 [43348]=0 [43360]=7 [43389]=0 [43392]=4 [43396]=0 [43446]=4 [43454]=5 [43457]=0
+ [43561]=4 [43575]=0 [43698]=4 [43705]=0 [44033]=11 [55204]=0 [55216]=8 [55239]=0 [55243]=9 [55292]=0 [65024]=4 [65040]=0 [65056]=4 [65072]=0 [65520]=1 [65532]=0
+ [66422]=4 [66427]=0 [68097]=4 [68103]=0 [68108]=4 [68112]=0 [68152]=4 [68155]=0 [68900]=4 [68904]=0 [69446]=4 [69457]=0 [69688]=4 [69703]=0 [69759]=4 [69763]=0
+ [69808]=5 [69811]=4 [69822]=0 [69888]=4 [69891]=0 [69927]=4 [69941]=0 [70067]=5 [70070]=4 [70084]=0 [70089]=4 [70096]=0 [70188]=5 [70191]=4 [70200]=0 [70368]=5
+ [70371]=4 [70379]=0 [70465]=5 [70478]=0 [70502]=4 [70509]=0 [70512]=4 [70517]=0 [70709]=5 [70712]=4 [70727]=0 [70835]=4 [70852]=0 [71090]=4 [71096]=5 [71105]=0
+ [71216]=5 [71219]=4 [71233]=0 [71344]=4 [71352]=0 [71453]=4 [71468]=0 [71724]=5 [71727]=4 [71739]=0 [71985]=5 [72004]=0 [72145]=5 [72148]=4 [72156]=5 [72161]=0
+ [72193]=4 [72203]=0 [72243]=4 [72255]=0 [72273]=4 [72284]=0 [72324]=3 [72330]=4 [72346]=0 [72752]=4 [72768]=0 [72850]=4 [72887]=0 [73009]=4 [73015]=0 [73023]=4
+ [73032]=0 [73098]=5 [73112]=0 [78896]=1 [78905]=0 [92912]=4 [92917]=0 [92976]=4 [92983]=0 [94033]=5 [94088]=0 [94095]=4 [94099]=0 [113824]=1 [113828]=0 [119143]=4
+ [119146]=0 [119150]=4 [119155]=1 [119163]=4 [119180]=0 [119210]=4 [119214]=0 [119362]=4 [119365]=0 [121344]=4 [121399]=0 [121403]=4 [121453]=0 [121499]=4 [121520]=0 [122880]=4
+ [122923]=0 [123184]=4 [123191]=0 [123628]=4 [123632]=0 [125136]=4 [125143]=0 [125252]=4 [125259]=0 [126976]=12 [127232]=0 [127245]=12 [127248]=0 [127340]=12 [127346]=0 [127377]=12
+ [127387]=0 [127405]=12 [127462]=6 [127489]=12 [127504]=0 [127538]=12 [127552]=0 [127561]=12 [127995]=4 [128000]=12 [128318]=0 [128326]=12 [128592]=0 [128640]=12 [128768]=0 [128884]=12
+ [128896]=0 [128981]=12 [129024]=0 [129036]=12 [129040]=0 [129096]=12 [129104]=0 [129114]=12 [129120]=0 [129160]=12 [129168]=0 [129198]=12 [129280]=0 [129292]=12 [129792]=0 [130048]=12
+ [131070]=0 [917504]=1 [917536]=4 [917632]=1 [917760]=4 [918000]=1
+)
+_ble_unicode_GraphemeClusterBreak_ranges=(
+ 0 32 127 160 768 880 1155 1162 1425 1480 1536 1542 1552 1565 1611 1632 1750 1774 1840 1867 1958 1969 2027 2036 2070 2094 2137 2140 2259 2308 2366 2369
+ 2377 2385 2392 2497 2510 2622 2627 2635 2638 2750 2753 2766 2810 2820 2881 2894 2901 2904 3014 3022 3073 3077 3134 3137 3142 3150 3393 3398 3407 3538 3544 3552
+ 3636 3643 3655 3663 3764 3773 3784 3790 3953 3976 3981 4029 4141 4159 4190 4193 4209 4213 4352 4448 4520 4608 4957 4960 5906 5909 5938 5941 6071 6078 6089 6100
+ 6155 6159 6432 6435 6444 6451 6457 6460 6744 6765 6771 6784 6832 6849 6912 6917 6964 6973 6981 7019 7028 7074 7086 7146 7151 7156 7204 7212 7224 7376 7401 7616
+ 7680 8232 8239 8288 8304 8400 8433 8596 8602 9193 9204 9208 9211 9723 9862 9872 10007 10067 10072 10083 10088 10133 10136 11013 11016 11503 11506 11744 11776 12330 12337 42607
+ 42622 43188 43206 43232 43250 43302 43310 43335 43348 43360 43389 43392 43396 43446 43454 43457 43561 43575 43698 43705 44033 55204 55216 55239 55243 55292 65024 65040 65056 65072 65520 65532
+ 66422 66427 68097 68103 68108 68112 68152 68155 68900 68904 69446 69457 69688 69703 69759 69763 69808 69811 69822 69888 69891 69927 69941 70067 70070 70084 70089 70096 70188 70191 70200 70368
+ 70371 70379 70465 70478 70502 70509 70512 70517 70709 70712 70727 70835 70852 71090 71096 71105 71216 71219 71233 71344 71352 71453 71468 71724 71727 71739 71985 72004 72145 72148 72156 72161
+ 72193 72203 72243 72255 72273 72284 72324 72330 72346 72752 72768 72850 72887 73009 73015 73023 73032 73098 73112 78896 78905 92912 92917 92976 92983 94033 94088 94095 94099 113824 113828 119143
+ 119146 119150 119155 119163 119180 119210 119214 119362 119365 121344 121399 121403 121453 121499 121520 122880 122923 123184 123191 123628 123632 125136 125143 125252 125259 126976 127232 127245 127248 127340 127346 127377
+ 127387 127405 127462 127489 127504 127538 127552 127561 127995 128000 128318 128326 128592 128640 128768 128884 128896 128981 129024 129036 129040 129096 129104 129114 129120 129160 129168 129198 129280 129292 129792 130048
+ 131070 917504 917536 917632 917760 918000 921600
+)
+_ble_unicode_GraphemeClusterBreak_rule=(
+ 0 0 1 0 1 2 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 1 0 1 2 0 0 0 0 0 0 3
+ 2 0 1 2 1 2 2 2 2 2 2 2 2
+ 0 0 1 0 1 2 0 0 0 0 0 0 0
+ 0 0 1 0 1 2 0 0 0 0 0 0 0
+ 0 0 1 0 1 2 4 0 0 0 0 0 0
+ 0 0 1 0 1 2 0 1 1 0 1 1 0
+ 0 0 1 0 1 2 0 0 1 1 0 0 0
+ 0 0 1 0 1 2 0 0 0 1 0 0 0
+ 0 0 1 0 1 2 0 0 1 1 0 0 0
+ 0 0 1 0 1 2 0 0 0 1 0 0 0
+ 0 0 1 0 1 2 0 0 0 0 0 0 0
+)
+function ble/unicode/GraphemeCluster/c2break {
+ local code=$1
+ ret=${_ble_unicode_GraphemeClusterBreak[code]}
+ [[ $ret ]] && return 0
+ ((ret>_ble_unicode_GraphemeClusterBreak_MaxCode)) && { ret=0; return 0; }
+ local l=0 u=${#_ble_unicode_GraphemeClusterBreak_ranges[@]} m
+ while ((l+1<u)); do
+ ((_ble_unicode_GraphemeClusterBreak_ranges[m=(l+u)/2]<=code?(l=m):(u=m)))
+ done
+ ret=${_ble_unicode_GraphemeClusterBreak[_ble_unicode_GraphemeClusterBreak_ranges[l]]:-0}
+ _ble_unicode_GraphemeClusterBreak[code]=$ret
+ return 0
+}
+function ble/unicode/GraphemeCluster/find-previous-boundary/.ZWJ {
+ if [[ :$bleopt_emoji_opts: != *:zwj:* ]]; then
+ ((ret=i))
+ return 0
+ fi
+ local j=$((i-1))
+ for ((j=i-1;j>0;j--)); do
+ ble/util/s2c "${text:j-1:1}"
+ ble/unicode/GraphemeCluster/c2break "$ret"
+ ((ret==_ble_unicode_GraphemeClusterBreak_Extend)) || break
+ done
+ if ((j==0||ret!=_ble_unicode_GraphemeClusterBreak_Pictographic)); then
+ ((ret=i))
+ return 0
+ else
+ ((i=j-1,b1=ret))
+ return 1
+ fi
+}
+function ble/unicode/GraphemeCluster/find-previous-boundary/.RI {
+ if [[ :$bleopt_emoji_opts: != *:ri:* ]]; then
+ ((ret=i))
+ return 0
+ fi
+ local j=$((i-1))
+ for ((j=i-1;j>0;j--)); do
+ ble/util/s2c "${text:j-1:1}"
+ ble/unicode/GraphemeCluster/c2break "$ret"
+ ((ret==_ble_unicode_GraphemeClusterBreak_Regional_Indicator)) || break
+ done
+ if ((i-j==1)); then
+ ((i=j,b1=_ble_unicode_GraphemeClusterBreak_Regional_Indicator))
+ return 1
+ else
+ ((ret=(i-j)%2==1?i-1:i))
+ return 0
+ fi
+}
+function ble/unicode/GraphemeCluster/find-previous-boundary {
+ local text=$1 i=$2
+ if [[ $bleopt_grapheme_cluster ]] && ((i&&--i)); then
+ ble/util/s2c "${text:i:1}"
+ ble/unicode/GraphemeCluster/c2break "$ret"; local b1=$ret
+ while ((i>0)); do
+ local b2=$b1
+ ble/util/s2c "${text:i-1:1}"
+ ble/unicode/GraphemeCluster/c2break "$ret"; local b1=$ret
+ case ${_ble_unicode_GraphemeClusterBreak_rule[b1*_ble_unicode_GraphemeClusterBreak_Count+b2]} in
+ (0) break ;;
+ (1) ((i--)) ;;
+ (2) [[ $bleopt_grapheme_cluster != extended ]] && break; ((i--)) ;;
+ (3) ble/unicode/GraphemeCluster/find-previous-boundary/.ZWJ && return 0 ;;
+ (4) ble/unicode/GraphemeCluster/find-previous-boundary/.RI && return 0 ;;
+ esac
+ done
+ fi
+ ret=$i
+ return 0
+}
+_ble_unicode_GraphemeClusterBreak_isCore=()
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_Other]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_Control]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_Regional_Indicator]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_L]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_V]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_T]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_LV]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_LVT]=1
+_ble_unicode_GraphemeClusterBreak_isCore[_ble_unicode_GraphemeClusterBreak_Pictographic]=1
+function ble/unicode/GraphemeCluster/extend-ascii {
+ extend=0
+ [[ $_ble_util_locale_encoding != UTF-8 || ! $bleopt_grapheme_cluster ]] && return 1
+ local text=$1 iN=${#1} i=$2 ret
+ for ((;i<iN;i++,extend++)); do
+ ble/util/s2c "${text:i:1}"
+ ble/unicode/GraphemeCluster/c2break "$ret"
+ case $ret in
+ ("$_ble_unicode_GraphemeClusterBreak_Extend"|"$_ble_unicode_GraphemeClusterBreak_ZWJ") ;;
+ ("$_ble_unicode_GraphemeClusterBreak_SpacingMark")
+ [[ $bleopt_grapheme_cluster == extended ]] || break ;;
+ (*) break ;;
+ esac
+ done
+ ((extend))
+}
+_ble_unicode_GraphemeCluster_ControlRepresentation=()
+function ble/unicode/GraphemeCluster/.get-ascii-rep {
+ local c=$1
+ cs=${_ble_unicode_GraphemeCluster_ControlRepresentation[c]}
+ if [[ ! $cs ]]; then
+ if ((c<32)); then
+ ble/util/c2s $((c+64))
+ cs=^$ret
+ elif ((c==127)); then
+ cs=^?
+ elif ((128<=c&&c<160)); then
+ ble/util/c2s $((c-64))
+ cs=M-^$ret
+ else
+ ble/util/sprintf cs 'U+%X' "$c"
+ fi
+ _ble_unicode_GraphemeCluster_ControlRepresentation[c]=$cs
+ fi
+}
+function ble/unicode/GraphemeCluster/match {
+ local text=$1 iN=${#1} i=$2 j=$2 flags=$3 ret
+ if ((i>=iN)); then
+ c=0 w=0 cs= cb= extend=0
+ return 1
+ elif [[ $_ble_util_locale_encoding != UTF-8 || ! $bleopt_grapheme_cluster ]]; then
+ cs=${text:i:1}
+ ble/util/s2c "$cs"; c=$ret
+ if [[ $flags != *R* ]] && {
+ ble/unicode/GraphemeCluster/c2break "$c"
+ ((ret==_ble_unicode_GraphemeClusterBreak_Control)); }; then
+ ble/unicode/GraphemeCluster/.get-ascii-rep "$c"
+ w=${#cs}
+ else
+ ble/util/c2w "$c"; w=$ret
+ fi
+ extend=0
+ return 0
+ fi
+ local b0 b1 b2 c0 c2
+ ble/util/s2c "${text:i:1}"; c0=$ret
+ ble/unicode/GraphemeCluster/c2break "$c0"; b0=$ret
+ local coreb= corec= npre=0 vs= ri=
+ c2=$c0 b2=$b0
+ while ((j<iN)); do
+ if ((_ble_unicode_GraphemeClusterBreak_isCore[b2])); then
+ [[ $coreb ]] || coreb=$b2 corec=$c2
+ elif ((b2==_ble_unicode_GraphemeClusterBreak_Prepend)); then
+ ((npre++))
+ elif ((c2==0xFE0E)); then # Variation selector TPVS
+ vs=tpvs
+ elif ((c2==0xFE0F)); then # Variation selector EPVS
+ vs=epvs
+ fi
+ ((j++))
+ b1=$b2
+ ble/util/s2c "${text:j:1}"; c2=$ret
+ ble/unicode/GraphemeCluster/c2break "$c2"; b2=$ret
+ case ${_ble_unicode_GraphemeClusterBreak_rule[b1*_ble_unicode_GraphemeClusterBreak_Count+b2]} in
+ (0) break ;;
+ (1) continue ;;
+ (2) [[ $bleopt_grapheme_cluster != extended ]] && break ;;
+ (3) [[ :$bleopt_emoji_opts: == *:zwj:* ]] &&
+ ((coreb==_ble_unicode_GraphemeClusterBreak_Pictographic)) || break ;;
+ (4) [[ :$bleopt_emoji_opts: == *:ri:* && ! $ri ]] || break; ri=1 ;;
+ esac
+ done
+ c=$corec cb=$coreb cs=${text:i:j-i}
+ ((extend=j-i-1))
+ if [[ ! $corec ]]; then
+ if [[ $flags != *R* ]]; then
+ ((c=c0,cb=0,corec=0x25CC)) # 基底が存在しない時は点線円
+ ble/util/c2s "$corec"
+ cs=${text:i:npre}$ret${text:i+npre:j-i-npre}
+ else
+ ble/util/s2c "$cs"; c=$ret corec=$ret
+ ble/unicode/GraphemeCluster/c2break "$c"; cb=$ret
+ fi
+ fi
+ if ((cb==_ble_unicode_GraphemeClusterBreak_Control)); then
+ if [[ $flags != *R* ]]; then
+ ble/unicode/GraphemeCluster/.get-ascii-rep "$c"
+ w=${#cs}
+ else
+ w=0
+ fi
+ else
+ if [[ $vs == tpvs && :$bleopt_emoji_opts: == *:tpvs:* ]]; then
+ bleopt_emoji_width= ble/util/c2w "$corec"; w=$ret
+ elif [[ $vs == epvs && :$bleopt_emoji_opts: == *:epvs:* ]]; then
+ w=${bleopt_emoji_width:-2}
+ else
+ ble/util/c2w "$corec"; w=$ret
+ fi
+ fi
+ return 0
+}
+function ble/canvas/attach {
+ ble/util/c2w:auto/check
+}
+function ble/canvas/put.draw {
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$1
+}
+function ble/canvas/put-ind.draw {
+ local count=${1-1} ind=$_ble_term_ind
+ [[ :$2: == *:true-ind:* ]] && ind=$'\eD'
+ local ret; ble/string#repeat "$ind" "$count"
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$ret
+}
+function ble/canvas/put-ri.draw {
+ local count=${1-1}
+ local ret; ble/string#repeat "$_ble_term_ri" "$count"
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$ret
+}
+function ble/canvas/put-il.draw {
+ local value=${1-1}
+ ((value>0)) || return 0
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_il//'%d'/$value}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
+}
+function ble/canvas/put-dl.draw {
+ local value=${1-1}
+ ((value>0)) || return 0
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value}
+}
+if ((_ble_bash>=40000)) && [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $TERM == xterm-256color ]]; then
+ function ble/canvas/.is-il-workaround-required {
+ local value=$1 opts=$2
+ [[ ! $_ble_term_DA2R ]] || return 1
+ ((value==1)) || return 1
+ [[ :$opts: == *:vfill:* || :$opts: == *:no-lastline:* ]] && return 1
+ [[ :$opts: == *:panel:* ]] &&
+ ! ble/canvas/panel/is-last-line &&
+ return 1
+ return 0
+ }
+ function ble/canvas/put-il.draw {
+ local value=${1-1} opts=$2
+ ((value>0)) || return 0
+ if ble/canvas/.is-il-workaround-required "$value" "$2"; then
+ if [[ :$opts: == *:panel:* ]]; then
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2
+ else
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$'\e[S\e[A\e[L\e[B\e[T'
+ fi
+ else
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_il//'%d'/$value}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
+ fi
+ }
+ function ble/canvas/put-dl.draw {
+ local value=${1-1} opts=$2
+ ((value>0)) || return 0
+ if ble/canvas/.is-il-workaround-required "$value" "$2"; then
+ if [[ :$opts: == *:panel:* ]]; then
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2
+ else
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$'\e[S\e[A\e[M\e[B\e[T'
+ fi
+ else
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value}
+ fi
+ }
+fi
+function ble/canvas/put-cuu.draw {
+ local value=${1-1}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cuu//'%d'/$value}
+}
+function ble/canvas/put-cud.draw {
+ local value=${1-1}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cud//'%d'/$value}
+}
+function ble/canvas/put-cuf.draw {
+ local value=${1-1}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cuf//'%d'/$value}
+}
+function ble/canvas/put-cub.draw {
+ local value=${1-1}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cub//'%d'/$value}
+}
+function ble/canvas/put-cup.draw {
+ local l=${1-1} c=${2-1}
+ local out=$_ble_term_cup
+ out=${out//'%l'/$l}
+ out=${out//'%c'/$c}
+ out=${out//'%y'/$((l-1))}
+ out=${out//'%x'/$((c-1))}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$out
+}
+function ble/canvas/put-hpa.draw {
+ local c=${1-1}
+ local out=$_ble_term_hpa
+ out=${out//'%c'/$c}
+ out=${out//'%x'/$((c-1))}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$out
+}
+function ble/canvas/put-vpa.draw {
+ local l=${1-1}
+ local out=$_ble_term_vpa
+ out=${out//'%l'/$l}
+ out=${out//'%y'/$((l-1))}
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$out
+}
+function ble/canvas/put-ech.draw {
+ local value=${1:-1} esc
+ if [[ $_ble_term_ech ]]; then
+ esc=${_ble_term_ech//'%d'/$value}
+ else
+ ble/string#reserve-prototype "$value"
+ esc=${_ble_string_prototype::value}${_ble_term_cub//'%d'/$value}
+ fi
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=$esc
+}
+function ble/canvas/put-spaces.draw {
+ local value=${1:-1}
+ ble/string#reserve-prototype "$value"
+ DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_string_prototype::value}
+}
+function ble/canvas/put-move-x.draw {
+ local dx=$1
+ ((dx)) || return 1
+ if ((dx>0)); then
+ ble/canvas/put-cuf.draw "$dx"
+ else
+ ble/canvas/put-cub.draw $((-dx))
+ fi
+}
+function ble/canvas/put-move-y.draw {
+ local dy=$1
+ ((dy)) || return 1
+ if ((dy>0)); then
+ if [[ $MC_SID == $$ ]]; then
+ ble/canvas/put-ind.draw "$dy" true-ind
+ else
+ ble/canvas/put-cud.draw "$dy"
+ fi
+ else
+ ble/canvas/put-cuu.draw $((-dy))
+ fi
+}
+function ble/canvas/put-move.draw {
+ ble/canvas/put-move-x.draw "$1"
+ ble/canvas/put-move-y.draw "$2"
+}
+function ble/canvas/flush.draw {
+ IFS= builtin eval 'ble/util/put "${DRAW_BUFF[*]}"'
+ DRAW_BUFF=()
+}
+function ble/canvas/sflush.draw {
+ local _var=ret
+ [[ $1 == -v ]] && _var=$2
+ IFS= builtin eval "$_var=\"\${DRAW_BUFF[*]}\""
+ DRAW_BUFF=()
+}
+function ble/canvas/bflush.draw {
+ IFS= builtin eval 'ble/util/buffer "${DRAW_BUFF[*]}"'
+ DRAW_BUFF=()
+}
+function ble/canvas/put-clear-lines.draw {
+ local old=${1:-1}
+ local new=${2:-$old}
+ if ((old==1&&new==1)); then
+ ble/canvas/put.draw "$_ble_term_el2"
+ else
+ ble/canvas/put-dl.draw "$old" "$3"
+ ble/canvas/put-il.draw "$new" "$3"
+ fi
+}
+function ble/canvas/trace/.put-sgr.draw {
+ local ret g=$1
+ if ((g==0)); then
+ ble/canvas/put.draw "$opt_sgr0"
+ else
+ ble/color/g.compose "$opt_g0" "$g"
+ "$trace_g2sgr" "$g"
+ ble/canvas/put.draw "$ret"
+ fi
+}
+function ble/canvas/trace/.measure-point {
+ if [[ $flag_bbox ]]; then
+ ((x<x1?(x1=x):(x2<x&&(x2=x))))
+ ((y<y1?(y1=y):(y2<y&&(y2=y))))
+ fi
+}
+function ble/canvas/trace/.goto {
+ local dstx=$1 dsty=$2
+ if [[ ! $flag_clip ]]; then
+ if [[ $trace_flags == *[RJ]* ]]; then
+ ble/canvas/put-move.draw $((dstx-x)) $((dsty-y))
+ else
+ ble/canvas/put-cup.draw $((dsty+1)) $((dstx+1))
+ fi
+ fi
+ ((x=dstx,y=dsty))
+ ble/canvas/trace/.measure-point
+}
+function ble/canvas/trace/.implicit-move {
+ local w=$1 type=$2
+ ((w>0)) || return 0
+ if [[ $flag_gbox ]]; then
+ if [[ ! $gx1 ]]; then
+ ((gx1=gx2=x,gy1=gy2=y))
+ else
+ ((x<gx1?(gx1=x):(gx2<x&&(gx2=x))))
+ ((y<gy1?(gy1=y):(gy2<y&&(gy2=y))))
+ fi
+ fi
+ ((x+=w))
+ if ((x<=cols)); then
+ [[ $flag_bbox ]] && ((x>x2)) && x2=$x
+ [[ $flag_gbox ]] && ((x>gx2)) && gx2=$x
+ if ((x==cols&&!xenl)); then
+ ((y++,x=0))
+ if [[ $flag_bbox ]]; then
+ ((x<x1)) && x1=0
+ ((y>y2)) && y2=$y
+ fi
+ fi
+ else
+ if [[ $type == atomic ]]; then
+ ((y++,x=w<xlimit?w:xlimit))
+ else
+ ((y+=x/cols,x%=cols,
+ xenl&&x==0&&(y--,x=cols)))
+ fi
+ if [[ $flag_bbox ]]; then
+ ((x1>0&&(x1=0)))
+ ((x2<cols&&(x2=cols)))
+ ((y>y2)) && y2=$y
+ fi
+ if [[ $flag_gbox ]]; then
+ ((gx1>0&&(gx1=0)))
+ ((gx2<cols&&(gx2=cols)))
+ ((y>gy2)) && gy2=$y
+ fi
+ fi
+ ((x==0&&(lc=32,lg=0)))
+ return 0
+}
+function ble/canvas/trace/.put-atomic.draw {
+ local c=$1 w=$2
+ if [[ $flag_clip ]]; then
+ ((cy1<=y&&y<cy2&&cx1<=x&&x<cx2&&x+w<=cx2)) || return 0
+ if [[ $cg != "$g" ]]; then
+ ble/canvas/trace/.put-sgr.draw "$g"
+ cg=$g
+ fi
+ ble/canvas/put-move.draw $((x-cx)) $((y-cy))
+ ble/canvas/put.draw "$c"
+ ((cx+=x+w,cy=y))
+ else
+ ble/canvas/put.draw "$c"
+ fi
+ ble/canvas/trace/.implicit-move "$w" atomic
+}
+function ble/canvas/trace/.put-ascii.draw {
+ local value=$1 w=${#1}
+ [[ $value ]] || return
+ if [[ $flag_clip ]]; then
+ local xL=$x xR=$((x+w))
+ ((xR<=cx1||cx2<=xL||y+1<=cy1||cy2<=y)) && return 0
+ if [[ $cg != "$g" ]]; then
+ ble/canvas/trace/.put-sgr.draw "$g"
+ cg=$g
+ fi
+ ((xL<cx1)) && value=${value:cx1-xL} xL=$cx1
+ ((xR>cx2)) && value=${value::${#value}-(xR-cx2)} xR=$cx2
+ ble/canvas/put-move.draw $((x-cx)) $((y-cy))
+ ble/canvas/put.draw "$value"
+ ((cx=xR,cy=y))
+ else
+ ble/canvas/put.draw "$value"
+ fi
+ ble/canvas/trace/.implicit-move "$w"
+}
+function ble/canvas/trace/.process-overflow {
+ [[ :$opts: == *:truncate:* ]] && i=$iN # stop
+ if ((y+1==lines)) && [[ :$opts: == *:ellipsis:* ]]; then
+ local ellipsis=... w=3 wmax=$xlimit
+ ((w>wmax)) && ellipsis=${ellipsis::wmax} w=$wmax
+ if ble/util/is-unicode-output; then
+ local symbol='…' ret
+ ble/util/s2c "$symbol"
+ ble/util/c2w "$ret"
+ ((ret<=wmax)) && ellipsis=$symbol w=$ret
+ fi
+ local ox=$x oy=$y
+ ble/canvas/trace/.goto $((wmax-w)) $((lines-1))
+ ble/canvas/trace/.put-atomic.draw "$ellipsis" "$w"
+ ble/canvas/trace/.goto "$ox" "$oy"
+ fi
+}
+function ble/canvas/trace/.justify/inc-quote {
+ [[ $trace_flags == *J* ]] || return 0
+ ((trace_sclevel++))
+ flag_justify=
+}
+function ble/canvas/trace/.justify/dec-quote {
+ [[ $trace_flags == *J* ]] || return 0
+ ((--trace_sclevel)) || flag_justify=1
+}
+function ble/canvas/trace/.justify/begin-line {
+ ((jx0=x1=x2=x,jy0=y1=y2=y))
+ gx1= gx2= gy1= gy2=
+ [[ $justify_align == *[cr]* ]] &&
+ ble/canvas/trace/.justify/next-field
+}
+function ble/canvas/trace/.justify/next-field {
+ local sep=$1 wmin=0
+ local esc; ble/canvas/sflush.draw -v esc
+ [[ $sep == ' ' ]] && wmin=1
+ ble/array#push justify_fields "${sep:-\$}:$wmin:$jx0,$jy0,$x,$y:$x1,$y1,$x2,$y2:$gx1,$gy1,$gx2,$gy2:$esc"
+ ((x+=wmin,jx0=x1=x2=x,jy0=y1=y2=y))
+}
+function ble/canvas/trace/.justify/unpack {
+ local data=$1 buff
+ sep=${data::1}; data=${data:2}
+ wmin=${data%%:*}; data=${data#*:}
+ ble/string#split buff , "${data%%:*}"; data=${data#*:}
+ xI=${buff[0]} yI=${buff[1]} xF=${buff[2]} yF=${buff[3]}
+ ble/string#split buff , "${data%%:*}"; data=${data#*:}
+ x1=${buff[0]} y1=${buff[1]} x2=${buff[2]} y2=${buff[3]}
+ ble/string#split buff , "${data%%:*}"; data=${data#*:}
+ gx1=${buff[0]} gy1=${buff[1]} gx2=${buff[2]} gy2=${buff[3]}
+ esc=$data
+}
+function ble/canvas/trace/.justify/end-line {
+ if [[ $trace_flags == *B* ]]; then
+ ((y<jy1&&(jy1=y)))
+ ((y>jy2&&(jy2=y)))
+ fi
+ ((${#justify_fields[@]}||${#DRAW_BUFF[@]})) || return 0
+ ble/canvas/trace/.justify/next-field
+ [[ $justify_align == *c* ]] &&
+ ble/canvas/trace/.justify/next-field
+ local i width=0 ispan=0 has_content=
+ for ((i=0;i<${#justify_fields[@]};i++)); do
+ local sep wmin xI yI xF yF x1 y1 x2 y2 gx1 gy1 gx2 gy2 esc
+ ble/canvas/trace/.justify/unpack "${justify_fields[i]}"
+ ((width+=xF-xI))
+ [[ $esc ]] && has_content=1
+ ((i+1==${#justify_fields[@]})) && break
+ ((width+=wmin))
+ ((ispan++))
+ done
+ [[ $has_content ]] || return 0
+ local nspan=$ispan
+ local -a DRAW_BUFF=()
+ local xlimit=$cols
+ [[ $_ble_term_xenl$opt_relative ]] || ((xlimit--))
+ local span=$((xlimit-width))
+ x= y=
+ local ispan=0 vx=0 spanx=0
+ for ((i=0;i<${#justify_fields[@]};i++)); do
+ local sep wmin xI yI xF yF x1 y1 x2 y2 gx1 gy1 gx2 gy2 esc
+ ble/canvas/trace/.justify/unpack "${justify_fields[i]}"
+ if [[ ! $x ]]; then
+ x=$xI y=$yI
+ if [[ $justify_align == right ]]; then
+ ble/canvas/put-move-x.draw $((cols-1-x))
+ ((x=cols-1))
+ fi
+ fi
+ if [[ $esc ]]; then
+ local delta=0
+ ((vx+x1-xI<0)) && ((delta=-(vx+x1-xI)))
+ ((vx+x2-xI>xlimit)) && ((delta=xlimit-(vx+x2-xI)))
+ ble/canvas/put-move-x.draw $((vx+delta-x))
+ ((x=vx+delta))
+ ble/canvas/put.draw "$esc"
+ if [[ $trace_flags == *B* ]]; then
+ ((x+x1-xI<jx1&&(jx1=x+x1-xI)))
+ ((y+y1-yI<jy1&&(jy1=y+y1-yI)))
+ ((x+x2-xI>jx2&&(jx2=x+x2-xI)))
+ ((y+y2-yI>jy2&&(jy2=y+y2-yI)))
+ fi
+ if [[ $flag_gbox && $gx1 ]]; then
+ ((gx1+=x-xI,gx2+=x-xI))
+ ((gy1+=y-yI,gy2+=y-yI))
+ if [[ ! $jgx1 ]]; then
+ ((jgx1=gx1,jgy1=gy1,jgx2=gx2,jgy2=gy2))
+ else
+ ((gx1<jgx1&&(jgx1=gx1)))
+ ((gy1<jgy1&&(jgy1=gy1)))
+ ((gx2>jgx2&&(jgx2=gx2)))
+ ((gy2>jgy2&&(jgy2=gy2)))
+ fi
+ fi
+ ((x+=xF-xI,y+=yF-yI,vx+=xF-xI))
+ fi
+ ((i+1==${#justify_fields[@]})) && break
+ local new_spanx=$((span*++ispan/nspan))
+ local wfill=$((wmin+new_spanx-spanx))
+ ((vx+=wfill,spanx=new_spanx))
+ if [[ $sep == ' ' ]]; then
+ ble/string#reserve-prototype "$wfill"
+ ble/canvas/put.draw "${_ble_string_prototype::wfill}"
+ ((x+=wfill))
+ fi
+ done
+ local ret
+ ble/canvas/sflush.draw
+ ble/array#push justify_buff "$ret"
+ justify_fields=()
+}
+function ble/canvas/trace/.decsc {
+ [[ ${trace_decsc[5]} ]] || ble/canvas/trace/.justify/inc-quote
+ trace_decsc=("$x" "$y" "$g" "$lc" "$lg" active)
+ if [[ ! $flag_clip ]]; then
+ [[ :$opts: == *:noscrc:* ]] ||
+ ble/canvas/put.draw "$_ble_term_sc"
+ fi
+}
+function ble/canvas/trace/.decrc {
+ [[ ${trace_decsc[5]} ]] && ble/canvas/trace/.justify/dec-quote
+ if [[ ! $flag_clip ]]; then
+ ble/canvas/trace/.put-sgr.draw "${trace_decsc[2]}" # g を明示的に復元。
+ if [[ :$opts: == *:noscrc:* ]]; then
+ ble/canvas/put-move.draw $((trace_decsc[0]-x)) $((trace_decsc[1]-y))
+ else
+ ble/canvas/put.draw "$_ble_term_rc"
+ fi
+ fi
+ x=${trace_decsc[0]}
+ y=${trace_decsc[1]}
+ g=${trace_decsc[2]}
+ lc=${trace_decsc[3]}
+ lg=${trace_decsc[4]}
+ trace_decsc[5]=
+}
+function ble/canvas/trace/.scosc {
+ [[ ${trace_scosc[5]} ]] || ble/canvas/trace/.justify/inc-quote
+ trace_scosc=("$x" "$y" "$g" "$lc" "$lg" active)
+ if [[ ! $flag_clip ]]; then
+ [[ :$opts: == *:noscrc:* ]] ||
+ ble/canvas/put.draw "$_ble_term_sc"
+ fi
+}
+function ble/canvas/trace/.scorc {
+ [[ ${trace_scosc[5]} ]] && ble/canvas/trace/.justify/dec-quote
+ if [[ ! $flag_clip ]]; then
+ ble/canvas/trace/.put-sgr.draw "$g" # g は変わらない様に。
+ if [[ :$opts: == *:noscrc:* ]]; then
+ ble/canvas/put-move.draw $((trace_scosc[0]-x)) $((trace_scosc[1]-y))
+ else
+ ble/canvas/put.draw "$_ble_term_rc"
+ fi
+ fi
+ x=${trace_scosc[0]}
+ y=${trace_scosc[1]}
+ lc=${trace_scosc[3]}
+ lg=${trace_scosc[4]}
+ trace_scosc[5]=
+}
+function ble/canvas/trace/.ps1sc {
+ ble/canvas/trace/.justify/inc-quote
+ trace_brack[${#trace_brack[*]}]="$x $y"
+}
+function ble/canvas/trace/.ps1rc {
+ local lastIndex=$((${#trace_brack[*]}-1))
+ if ((lastIndex>=0)); then
+ ble/canvas/trace/.justify/dec-quote
+ local -a scosc
+ ble/string#split-words scosc "${trace_brack[lastIndex]}"
+ ((x=scosc[0]))
+ ((y=scosc[1]))
+ builtin unset -v "trace_brack[$lastIndex]"
+ fi
+}
+function ble/canvas/trace/.NEL {
+ if [[ $opt_nooverflow ]] && ((y+1>=lines)); then
+ ble/canvas/trace/.process-overflow
+ return 1
+ fi
+ [[ $flag_justify ]] &&
+ ble/canvas/trace/.justify/end-line
+ if [[ ! $flag_clip ]]; then
+ if [[ $opt_relative ]]; then
+ ((x)) && ble/canvas/put-cub.draw "$x"
+ ble/canvas/put-cud.draw 1
+ else
+ ble/canvas/put.draw "$_ble_term_cr"
+ ble/canvas/put.draw "$_ble_term_nl"
+ fi
+ fi
+ ((y++,x=0,lc=32,lg=0))
+ if [[ $flag_bbox ]]; then
+ ((x<x1)) && x1=$x
+ ((y>y2)) && y2=$y
+ fi
+ [[ $flag_justify ]] &&
+ ble/canvas/trace/.justify/begin-line
+ return 0
+}
+function ble/canvas/trace/.SGR {
+ local param=$1 seq=$2 specs i iN
+ if [[ ! $param ]]; then
+ g=0
+ [[ $flag_clip ]] || ble/canvas/put.draw "$opt_sgr0"
+ return 0
+ fi
+ if [[ $opt_terminfo ]]; then
+ ble/color/read-sgrspec "$param"
+ else
+ ble/color/read-sgrspec "$param" ansi
+ fi
+ [[ $flag_clip ]] || ble/canvas/trace/.put-sgr.draw "$g"
+}
+function ble/canvas/trace/.process-csi-sequence {
+ local seq=$1 seq1=${1:2} rex
+ local char=${seq1:${#seq1}-1:1} param=${seq1::${#seq1}-1}
+ if [[ ! ${param//[0-9:;]} ]]; then
+ case $char in
+ (m) # SGR
+ ble/canvas/trace/.SGR "$param" "$seq"
+ return 0 ;;
+ ([ABCDEFGIZ\`ade])
+ local arg=0
+ [[ $param =~ ^[0-9]+$ ]] && ((arg=10#0$param))
+ ((arg==0&&(arg=1)))
+ local ox=$x oy=$y
+ if [[ $char == A ]]; then
+ ((y-=arg,y<0&&(y=0)))
+ ((!flag_clip&&y<oy)) && ble/canvas/put-cuu.draw $((oy-y))
+ elif [[ $char == [Be] ]]; then
+ ((y+=arg,y>=lines&&(y=lines-1)))
+ ((!flag_clip&&y>oy)) && ble/canvas/put-cud.draw $((y-oy))
+ elif [[ $char == [Ca] ]]; then
+ ((x+=arg,x>=cols&&(x=cols-1)))
+ ((!flag_clip&&x>ox)) && ble/canvas/put-cuf.draw $((x-ox))
+ elif [[ $char == D ]]; then
+ ((x-=arg,x<0&&(x=0)))
+ ((!flag_clip&&x<ox)) && ble/canvas/put-cub.draw $((ox-x))
+ elif [[ $char == E ]]; then
+ ((y+=arg,y>=lines&&(y=lines-1),x=0))
+ if [[ ! $flag_clip ]]; then
+ ((y>oy)) && ble/canvas/put-cud.draw $((y-oy))
+ ble/canvas/put.draw "$_ble_term_cr"
+ fi
+ elif [[ $char == F ]]; then
+ ((y-=arg,y<0&&(y=0),x=0))
+ if [[ ! $flag_clip ]]; then
+ ((y<oy)) && ble/canvas/put-cuu.draw $((oy-y))
+ ble/canvas/put.draw "$_ble_term_cr"
+ fi
+ elif [[ $char == [G\`] ]]; then
+ ((x=arg-1,x<0&&(x=0),x>=cols&&(x=cols-1)))
+ if [[ ! $flag_clip ]]; then
+ if [[ $opt_relative ]]; then
+ ble/canvas/put-move-x.draw $((x-ox))
+ else
+ ble/canvas/put-hpa.draw $((x+1))
+ fi
+ fi
+ elif [[ $char == d ]]; then
+ ((y=arg-1,y<0&&(y=0),y>=lines&&(y=lines-1)))
+ if [[ ! $flag_clip ]]; then
+ if [[ $opt_relative ]]; then
+ ble/canvas/put-move-y.draw $((y-oy))
+ else
+ ble/canvas/put-vpa.draw $((y+1))
+ fi
+ fi
+ elif [[ $char == I ]]; then
+ local _x
+ ((_x=(x/it+arg)*it,
+ _x>=cols&&(_x=cols-1)))
+ if ((_x>x)); then
+ [[ $flag_clip ]] || ble/canvas/put-cuf.draw $((_x-x))
+ ((x=_x))
+ fi
+ elif [[ $char == Z ]]; then
+ local _x
+ ((_x=((x+it-1)/it-arg)*it,
+ _x<0&&(_x=0)))
+ if ((_x<x)); then
+ [[ $flag_clip ]] || ble/canvas/put-cub.draw $((x-_x))
+ ((x=_x))
+ fi
+ fi
+ ble/canvas/trace/.measure-point
+ lc=-1 lg=0
+ return 0 ;;
+ ([Hf])
+ local -a params
+ ble/string#split-words params "${param//[^0-9]/ }"
+ params=("${params[@]/#/10#0}") # #D1570 is-array OK
+ local dstx dsty
+ ((dstx=params[1]-1))
+ ((dsty=params[0]-1))
+ ((dstx<0&&(dstx=0),dstx>=cols&&(dstx=cols-1),
+ dsty<0&&(dsty=0),dsty>=lines&&(dsty=lines-1)))
+ ble/canvas/trace/.goto "$dstx" "$dsty"
+ lc=-1 lg=0
+ return 0 ;;
+ ([su]) # SCOSC SCORC
+ if [[ $char == s ]]; then
+ ble/canvas/trace/.scosc
+ else
+ ble/canvas/trace/.scorc
+ fi
+ return 0 ;;
+ esac
+ fi
+ ble/canvas/put.draw "$seq"
+}
+function ble/canvas/trace/.process-esc-sequence {
+ local seq=$1 char=${1:1}
+ case $char in
+ (7) # DECSC
+ ble/canvas/trace/.decsc
+ return 0 ;;
+ (8) # DECRC
+ ble/canvas/trace/.decrc
+ return 0 ;;
+ (D) # IND
+ [[ $opt_nooverflow ]] && ((y+1>=lines)) && return 0
+ if [[ $flag_clip || $opt_relative || $flag_justify ]]; then
+ ((y+1>=lines)) && return 0
+ ((y++))
+ [[ $flag_clip ]] ||
+ ble/canvas/put-cud.draw 1
+ else
+ ((y++))
+ ble/canvas/put.draw "$_ble_term_ind"
+ [[ $_ble_term_ind != $'\eD' ]] &&
+ ble/canvas/put-hpa.draw $((x+1)) # tput ind が唯の改行の時がある
+ fi
+ lc=-1 lg=0
+ ble/canvas/trace/.measure-point
+ return 0 ;;
+ (M) # RI
+ [[ $opt_nooverflow ]] && ((y==0)) && return 0
+ if [[ $flag_clip || $opt_relative || $flag_justify ]]; then
+ ((y==0)) && return 0
+ ((y--))
+ [[ $flag_clip ]] ||
+ ble/canvas/put-cuu.draw 1
+ else
+ ((y--))
+ ble/canvas/put.draw "$_ble_term_ri"
+ fi
+ lc=-1 lg=0
+ ble/canvas/trace/.measure-point
+ return 0 ;;
+ (E) # NEL
+ ble/canvas/trace/.NEL
+ return 0 ;;
+ esac
+ ble/canvas/put.draw "$seq"
+}
+function ble/canvas/trace/.impl {
+ local text=$1 opts=$2
+ local LC_ALL= LC_COLLATE=C
+ local cols=${COLUMNS:-80} lines=${LINES:-25}
+ local it=${bleopt_tab_width:-$_ble_term_it} xenl=$_ble_term_xenl
+ ble/string#reserve-prototype "$it"
+ local ret rex
+ ble/util/c2s 156; local st=$ret # œ (ST)
+ ((${#st}>=2)) && st=
+ local xinit=$x yinit=$y ginit=$g
+ local trace_flags=
+ local opt_nooverflow=; [[ :$opts: == *:truncate:* || :$opts: == *:confine:* ]] && opt_nooverflow=1
+ local opt_relative=; [[ :$opts: == *:relative:* ]] && trace_flags=R$trace_flags opt_relative=1
+ [[ :$opts: == *:measure-bbox:* ]] && trace_flags=B$trace_flags
+ [[ :$opts: == *:measure-gbox:* ]] && trace_flags=G$trace_flags
+ [[ :$opts: == *:left-char:* ]] && trace_flags=L$trace_flags
+ local opt_terminfo=; [[ :$opts: == *:terminfo:* ]] && opt_terminfo=1
+ if local rex=':(justify(=[^:]+)?|center|right):'; [[ :$opts: =~ $rex ]]; then
+ trace_flags=J$trace_flags
+ local jx0=$x jy0=$y
+ local justify_sep= justify_align=
+ local -a justify_buff=()
+ local -a justify_fields=()
+ case ${BASH_REMATCH[1]} in
+ (justify*) justify_sep=${BASH_REMATCH[2]:1}${BASH_REMATCH[2]:-' '} ;;
+ (center) justify_align=c ;;
+ (right) justify_align=r ;;
+ esac
+ fi
+ if local rex=':clip=([0-9]*),([0-9]*)([-+])([0-9]*),([0-9]*):'; [[ :$opts: =~ $rex ]]; then
+ local cx1 cy1 cx2 cy2 cx cy cg
+ trace_flags=C$trace_flags
+ cx1=${BASH_REMATCH[1]} cy1=${BASH_REMATCH[2]}
+ cx2=${BASH_REMATCH[4]} cy2=${BASH_REMATCH[5]}
+ [[ ${BASH_REMATCH[3]} == + ]] && ((cx2+=cx1,cy2+=cy1))
+ ((cx1<=cx2)) || local cx1=$cx2 cx2=$cx1
+ ((cy1<=cy2)) || local cy1=$cy2 cy2=$cy1
+ ((cx1<0)) && cx1=0
+ ((cy1<0)) && cy1=0
+ ((cols<cx2)) && cx2=$cols
+ ((lines<cy2)) && cy2=$lines
+ local cx=$cx1 cy=$cy1 cg=
+ fi
+ local trace_g2sgr=ble/color/g2sgr
+ [[ :$opts: == *:ansi:* || $trace_flags == *C*J* ]] &&
+ trace_g2sgr=ble/color/g2sgr-ansi
+ local opt_g0= opt_sgr0=$_ble_term_sgr0
+ if rex=':g0=([^:]+):'; [[ :$opts: =~ $rex ]]; then
+ opt_g0=${BASH_REMATCH[1]}
+ elif rex=':face0=([^:]+):'; [[ :$opts: =~ $rex ]]; then
+ ble/color/face2g "${BASH_REMATCH[1]}"; opt_g0=$ret
+ fi
+ if [[ $opt_g0 ]]; then
+ "$trace_g2sgr" "$opt_g0"; opt_sgr0=$ret
+ ble/canvas/put.draw "$opt_sgr0"
+ g=$opt_g0
+ fi
+ local rex_csi='^\[[ -?]*[@-~]'
+ local rex_osc='^([]PX^_k])([^'$st']|+[^\'$st'])*(\\|'${st:+'|'}$st'|$)'
+ local rex_2022='^[ -/]+[@-~]'
+ local rex_esc='^[ -~]'
+ local trace_sclevel=0
+ local -a trace_brack=()
+ local -a trace_scosc=()
+ local -a trace_decsc=()
+ local flag_lchar=
+ if [[ $trace_flags == *L* ]]; then
+ flag_lchar=1
+ else
+ local lc=32 lg=0
+ fi
+ local flag_bbox= flag_gbox=
+ if [[ $trace_flags == *[BJ]* ]]; then
+ flag_bbox=1
+ [[ $trace_flags != *B* ]] && local x1 x2 y1 y2
+ [[ $trace_flags != *G* ]] && local gx1= gx2= gy1= gy2=
+ ((x1=x2=x,y1=y2=y))
+ [[ $trace_flags == *J*B* ]] &&
+ local jx1=$x jy1=$y jx2=$x jy2=$y
+ fi
+ if [[ $trace_flags == *G* ]]; then
+ ((flag_gbox=1))
+ gx1= gx2= gy1= gy2=
+ [[ $trace_flags == *J* ]] &&
+ local jgx1= jgy1= jgx2= jgy2=
+ fi
+ local flag_clip=
+ [[ $trace_flags == *C* && $trace_flags != *J* ]] && flag_clip=1
+ local xenl=$_ble_term_xenl
+ [[ $opt_relative || $trace_flags == *J* ]] && xenl=1
+ local xlimit=$((xenl?cols:cols-1))
+ local flag_justify=
+ if [[ $trace_flags == *J* ]]; then
+ flag_justify=1
+ ble/canvas/trace/.justify/begin-line
+ fi
+ local i=0 iN=${#text}
+ while ((i<iN)); do
+ local tail=${text:i}
+ local is_overflow=
+ if [[ $flag_justify && $justify_sep && $tail == ["$justify_sep"]* ]]; then
+ ble/canvas/trace/.justify/next-field "${tail::1}"
+ ((i++))
+ elif [[ $tail == [-]* ]]; then
+ local s=${tail::1}
+ ((i++))
+ case "$s" in
+ ($'\e')
+ if [[ $tail =~ $rex_osc ]]; then
+ s=$BASH_REMATCH
+ [[ ${BASH_REMATCH[3]} ]] || s="$s\\" # 終端の追加
+ ((i+=${#BASH_REMATCH}-1))
+ ble/canvas/trace/.put-atomic.draw "$s" 0
+ elif [[ $tail =~ $rex_csi ]]; then
+ ((i+=${#BASH_REMATCH}-1))
+ ble/canvas/trace/.process-csi-sequence "$BASH_REMATCH"
+ elif [[ $tail =~ $rex_2022 ]]; then
+ ble/canvas/trace/.put-atomic.draw "$BASH_REMATCH" 0
+ ((i+=${#BASH_REMATCH}-1))
+ elif [[ $tail =~ $rex_esc ]]; then
+ ((i+=${#BASH_REMATCH}-1))
+ ble/canvas/trace/.process-esc-sequence "$BASH_REMATCH"
+ else
+ ble/canvas/trace/.put-atomic.draw "$s" 0
+ fi ;;
+ ($'\b') # BS
+ if ((x>0)); then
+ [[ $flag_clip ]] || ble/canvas/put.draw "$s"
+ ((x--,lc=32,lg=g))
+ ble/canvas/trace/.measure-point
+ fi ;;
+ ($'\t') # HT
+ local _x
+ ((_x=(x+it)/it*it,
+ _x>=cols&&(_x=cols-1)))
+ if ((x<_x)); then
+ ((lc=32,lg=g))
+ ble/canvas/trace/.put-ascii.draw "${_ble_string_prototype::_x-x}"
+ fi ;;
+ ($'\n') # LF = CR+LF
+ ble/canvas/trace/.NEL ;;
+ ($'\v') # VT
+ if ((y+1<lines||!opt_nooverflow)); then
+ if [[ $flag_clip || $opt_relative || $flag_justify ]]; then
+ if ((y+1<lines)); then
+ [[ $flag_clip ]] ||
+ ble/canvas/put-cud.draw 1
+ ((y++,lc=32,lg=0))
+ fi
+ else
+ ble/canvas/put.draw "$_ble_term_cr"
+ ble/canvas/put.draw "$_ble_term_nl"
+ ((x)) && ble/canvas/put-cuf.draw "$x"
+ ((y++,lc=32,lg=0))
+ fi
+ ble/canvas/trace/.measure-point
+ fi ;;
+ ($'\r') # CR ^M
+ local ox=$x
+ ((x=0,lc=-1,lg=0))
+ if [[ ! $flag_clip ]]; then
+ if [[ $flag_justify ]]; then
+ ble/canvas/put-move-x.draw $((jx0-ox))
+ ((x=jx0))
+ elif [[ $opt_relative ]]; then
+ ble/canvas/put-cub.draw "$ox"
+ else
+ ble/canvas/put.draw "$_ble_term_cr"
+ fi
+ fi
+ ble/canvas/trace/.measure-point ;;
+ ($'\001') [[ :$opts: == *:prompt:* ]] && ble/canvas/trace/.ps1sc ;;
+ ($'\002') [[ :$opts: == *:prompt:* ]] && ble/canvas/trace/.ps1rc ;;
+ (*) ble/canvas/put.draw "$s" ;;
+ esac
+ elif ble/util/isprint+ "$tail"; then
+ local s=$BASH_REMATCH
+ [[ $flag_justify && $justify_sep ]] && s=${s%%["$justify_sep"]*}
+ local w=${#s}
+ if [[ $opt_nooverflow ]]; then
+ local wmax=$((lines*cols-(y*cols+x)))
+ ((xenl||wmax--,wmax<0&&(wmax=0)))
+ ((w>wmax)) && w=$wmax is_overflow=1
+ fi
+ local t=${s::w}
+ if [[ $flag_clip || $opt_relative || $flag_justify ]]; then
+ local tlen=$w len=$((cols-x))
+ if ((tlen>len)); then
+ while ((tlen>len)); do
+ ble/canvas/trace/.put-ascii.draw "${t::len}"
+ t=${t:len}
+ ((x=cols,tlen-=len,len=cols))
+ ble/canvas/trace/.NEL
+ done
+ w=${#t}
+ fi
+ fi
+ if [[ $flag_lchar ]]; then
+ local ret
+ ble/util/s2c "${s:w-1:1}"
+ lc=$ret lg=$g
+ fi
+ ble/canvas/trace/.put-ascii.draw "$t"
+ ((i+=${#s}))
+ if local extend; ble/unicode/GraphemeCluster/extend-ascii "$text" "$i"; then
+ ble/canvas/trace/.put-atomic.draw "${text:i:extend}" 0
+ ((i+=extend))
+ fi
+ else
+ local c w cs cb extend
+ ble/unicode/GraphemeCluster/match "$text" "$i" R
+ if [[ $opt_nooverflow ]] && ! ((x+w<=xlimit||y+1<lines&&w<=cols)); then
+ is_overflow=1
+ else
+ if ((x+w>cols)); then
+ if [[ $flag_clip || $opt_relative || $flag_justify ]]; then
+ ble/canvas/trace/.NEL
+ else
+ ble/canvas/trace/.put-ascii.draw "${_ble_string_prototype::cols-x}"
+ fi
+ fi
+ lc=$c lg=$g
+ ble/canvas/trace/.put-atomic.draw "$cs" "$w"
+ fi
+ ((i+=1+extend))
+ fi
+ [[ $is_overflow ]] && ble/canvas/trace/.process-overflow
+ done
+ if [[ $trace_flags == *J* ]]; then
+ if [[ ! $flag_justify ]]; then
+ [[ ${trace_scosc[5]} ]] && ble/canvas/trace/.scorc
+ [[ ${trace_decsc[5]} ]] && ble/canvas/trace/.decrc
+ while [[ ${trace_brack[0]} ]]; do ble/canvas/trace/.ps1rc; done
+ fi
+ ble/canvas/trace/.justify/end-line
+ DRAW_BUFF=("${justify_buff[@]}")
+ [[ $trace_flags == *B* ]] &&
+ ((x1=jx1,y1=jy1,x2=jx2,y2=jy2))
+ [[ $trace_flags == *G* ]] &&
+ gx1=$jgx1 gy1=$jgy1 gx2=$jgx2 gy2=$jgy2
+ if [[ $trace_flags == *C* ]]; then
+ ble/canvas/sflush.draw
+ x=$xinit y=$yinit g=$ginit
+ local trace_opts=clip=$cx1,$cy1-$cx2,$cy2
+ [[ :$opts: == *:ansi:* ]] && trace_opts=$trace_opts:ansi
+ ble/canvas/trace/.impl "$ret" "$trace_opts"
+ cx=$x cy=$y cg=$g
+ fi
+ fi
+ [[ $trace_flags == *B* ]] && ((y2++))
+ [[ $trace_flags == *G* ]] && ((gy2++))
+ if [[ $trace_flags == *C* ]]; then
+ x=$cx y=$cy g=$cg
+ if [[ $trace_flags == *B* ]]; then
+ ((x1<cx1)) && x1=$cx1
+ ((x1>cx2)) && x1=$cx2
+ ((x2<cx1)) && x2=$cx1
+ ((x2>cx2)) && x2=$cx2
+ ((y1<cy1)) && y1=$cy1
+ ((y1>cy2)) && y1=$cy2
+ ((y2<cy1)) && y2=$cy1
+ ((y2>cy2)) && y2=$cy2
+ fi
+ if [[ $trace_flags == *G* ]]; then
+ if ((gx2<=cx1||cx2<=gx1||gy2<=cy1||cy2<=gy1)); then
+ gx1= gx2= gy1= gy2=
+ else
+ ((gx1<cx1)) && gx1=$cx1
+ ((gx2>cx2)) && gx2=$cx2
+ ((gy1<cy1)) && gy1=$cy1
+ ((gy2>cy2)) && gy2=$cy2
+ fi
+ fi
+ fi
+}
+function ble/canvas/trace.draw {
+ ble/canvas/trace/.impl "$@" 2>/dev/null # Note: suppress LC_COLLATE errors #D1205 #D1341 #D1440
+}
+function ble/canvas/trace {
+ local -a DRAW_BUFF=()
+ ble/canvas/trace/.impl "$@" 2>/dev/null # Note: suppress LC_COLLATE errors #D1205 #D1341 #D1440
+ ble/canvas/sflush.draw # -> ret
+}
+function ble/canvas/trace-text/.put-simple {
+ local nchar=$1
+ ((nchar)) || return 0
+ local nput=$((cols*lines-!_ble_term_xenl-(y*cols+x)))
+ ((nput>0)) || return 1
+ ((nput>nchar)) && nput=$nchar
+ out=$out${2::nput}
+ ((x+=nput,y+=x/cols,x%=cols))
+ ((_ble_term_xenl&&x==0&&(y--,x=cols)))
+ ((nput==nchar)); return $?
+}
+function ble/canvas/trace-text/.put-atomic {
+ local w=$1 c=$2
+ ((y*cols+x+w<=cols*lines-!_ble_term_xenl)) || return 1
+ if ((x<cols&&cols<x+w)); then
+ if [[ :$opts: == *:nonewline:* ]]; then
+ ble/string#reserve-prototype $((cols-x))
+ out=$out${_ble_string_prototype::cols-x}
+ ((x=cols))
+ else
+ out=$out$'\n'
+ ((y++,x=0))
+ fi
+ fi
+ ((w&&x==cols&&(y++,x=0)))
+ local limit=$((cols-(y+1==lines&&!_ble_term_xenl)))
+ if ((x+w>limit)); then
+ ble/string#reserve-prototype $((limit-x))
+ local pad=${_ble_string_prototype::limit-x}
+ out=$out$sgr1${pad//?/'#'}$sgr0
+ x=$limit
+ ((y+1<lines)); return $?
+ fi
+ out=$out$c
+ ((x+=w,!_ble_term_xenl&&x==cols&&(y++,x=0)))
+ return 0
+}
+function ble/canvas/trace-text/.put-nl-if-eol {
+ if ((x==cols&&y+1<lines)); then
+ [[ :$opts: == *:nonewline:* ]] && return 0
+ ((_ble_term_xenl)) && out=$out$'\n'
+ ((y++,x=0))
+ fi
+}
+function ble/canvas/trace-text {
+ local LC_ALL= LC_COLLATE=C
+ local out= glob='*[! -~]*'
+ local opts=$2 flag_overflow=
+ [[ :$opts: == *:external-sgr:* ]] ||
+ local sgr0=$_ble_term_sgr0 sgr1=$_ble_term_rev
+ if [[ $1 != $glob ]]; then
+ ble/canvas/trace-text/.put-simple "${#1}" "$1"
+ else
+ local glob='[ -~]*' globx='[! -~]*'
+ local i iN=${#1} text=$1
+ for ((i=0;i<iN;)); do
+ local tail=${text:i}
+ if [[ $tail == $glob ]]; then
+ local span=${tail%%$globx}; ((i+=${#span}))
+ ble/canvas/trace-text/.put-simple "${#span}" "$span"
+ if local extend; ble/unicode/GraphemeCluster/extend-ascii "$text" "$i"; then
+ out=$out${text:i:extend}
+ ((i+=extend))
+ fi
+ else
+ local c w cs cb extend
+ ble/unicode/GraphemeCluster/match "$text" "$i"
+ ((i+=1+extend))
+ ((cb==_ble_unicode_GraphemeClusterBreak_Control)) &&
+ cs=$sgr1$cs$sgr0
+ ble/canvas/trace-text/.put-atomic "$w" "$cs"
+ fi && ((y*cols+x<lines*cols)) ||
+ { flag_overflow=1; break; }
+ done
+ fi
+ ble/canvas/trace-text/.put-nl-if-eol
+ ret=$out
+ [[ ! $flag_overflow ]]
+}
+ble/function#suppress-stderr ble/canvas/trace-text
+_ble_textmap_VARNAMES=(
+ _ble_textmap_cols
+ _ble_textmap_length
+ _ble_textmap_begx
+ _ble_textmap_begy
+ _ble_textmap_endx
+ _ble_textmap_endy
+ _ble_textmap_pos
+ _ble_textmap_glyph
+ _ble_textmap_ichg
+ _ble_textmap_dbeg
+ _ble_textmap_dend
+ _ble_textmap_dend0
+ _ble_textmap_umin
+ _ble_textmap_umax)
+_ble_textmap_cols=80
+_ble_textmap_length=
+_ble_textmap_begx=0
+_ble_textmap_begy=0
+_ble_textmap_endx=0
+_ble_textmap_endy=0
+_ble_textmap_pos=()
+_ble_textmap_glyph=()
+_ble_textmap_ichg=()
+_ble_textmap_dbeg=-1
+_ble_textmap_dend=-1
+_ble_textmap_dend0=-1
+_ble_textmap_umin=-1
+_ble_textmap_umax=-1
+function ble/textmap#update-dirty-range {
+ ble/dirty-range#update --prefix=_ble_textmap_d "$@"
+}
+function ble/textmap#save {
+ local name prefix=$1
+ ble/util/save-vars "$prefix" "${_ble_textmap_VARNAMES[@]}"
+}
+function ble/textmap#restore {
+ local name prefix=$1
+ ble/util/restore-vars "$prefix" "${_ble_textmap_VARNAMES[@]}"
+}
+function ble/textmap#update/.wrap {
+ if [[ :$opts: == *:relative:* ]]; then
+ ((x)) && cs=$cs${_ble_term_cub//'%d'/$x}
+ cs=$cs${_ble_term_cud//'%d'/1}
+ changed=1
+ elif ((xenl)); then
+ cs=$cs$_ble_term_cr
+ changed=1
+ fi
+ ((y++,x=0))
+}
+function ble/textmap#update {
+ local IFS=$_ble_term_IFS
+ local dbeg dend dend0
+ ((dbeg=_ble_textmap_dbeg,
+ dend=_ble_textmap_dend,
+ dend0=_ble_textmap_dend0))
+ ble/dirty-range#clear --prefix=_ble_textmap_d
+ local text=$1 opts=$2
+ local iN=${#text}
+ local _pos="$x $y"
+ _ble_textmap_begx=$x
+ _ble_textmap_begy=$y
+ local cols=${COLUMNS-80} xenl=$_ble_term_xenl
+ ((COLUMNS&&cols<COLUMNS&&(xenl=1)))
+ ble/string#reserve-prototype "$cols"
+ local it=${bleopt_tab_width:-$_ble_term_it}
+ ble/string#reserve-prototype "$it"
+ if ((cols!=_ble_textmap_cols)); then
+ ((dbeg=0,dend0=_ble_textmap_length,dend=iN))
+ _ble_textmap_pos[0]=$_pos
+ elif [[ ${_ble_textmap_pos[0]} != "$_pos" ]]; then
+ ((dbeg<0&&(dend=dend0=0),
+ dbeg=0))
+ _ble_textmap_pos[0]=$_pos
+ else
+ if ((dbeg<0)); then
+ local pos
+ ble/string#split-words pos "${_ble_textmap_pos[iN]}"
+ ((x=pos[0]))
+ ((y=pos[1]))
+ _ble_textmap_endx=$x
+ _ble_textmap_endy=$y
+ return 0
+ elif ((dbeg>0)); then
+ local ret
+ ble/unicode/GraphemeCluster/find-previous-boundary "$text" "$dbeg"; dbeg=$ret
+ local pos
+ ble/string#split-words pos "${_ble_textmap_pos[dbeg]}"
+ ((x=pos[0]))
+ ((y=pos[1]))
+ fi
+ fi
+ _ble_textmap_cols=$cols
+ _ble_textmap_length=$iN
+ ble/util/assert '((dbeg<0||(dbeg<=dend&&dbeg<=dend0)))' "($dbeg $dend $dend0) <- ($_ble_textmap_dbeg $_ble_textmap_dend $_ble_textmap_dend0)"
+ ble/array#reserve-prototype "$iN"
+ local -a old_pos old_ichg
+ old_pos=("${_ble_textmap_pos[@]:dend0:iN-dend+1}")
+ old_ichg=("${_ble_textmap_ichg[@]}")
+ _ble_textmap_pos=(
+ "${_ble_textmap_pos[@]::dbeg+1}"
+ "${_ble_array_prototype[@]::dend-dbeg}"
+ "${_ble_textmap_pos[@]:dend0+1:iN-dend}")
+ _ble_textmap_glyph=(
+ "${_ble_textmap_glyph[@]::dbeg}"
+ "${_ble_array_prototype[@]::dend-dbeg}"
+ "${_ble_textmap_glyph[@]:dend0:iN-dend}")
+ _ble_textmap_ichg=()
+ ble/urange#shift --prefix=_ble_textmap_ "$dbeg" "$dend" "$dend0"
+ local i extend
+ for ((i=dbeg;i<iN;)); do
+ if ble/util/isprint+ "${text:i}"; then
+ local w=${#BASH_REMATCH}
+ local n
+ for ((n=i+w;i<n;i++)); do
+ local cs=${text:i:1}
+ if ((++x==cols)); then
+ local changed=0
+ ble/textmap#update/.wrap
+ ((changed)) && ble/array#push _ble_textmap_ichg "$i"
+ fi
+ _ble_textmap_glyph[i]=$cs
+ _ble_textmap_pos[i+1]="$x $y 0"
+ done
+ ble/unicode/GraphemeCluster/extend-ascii "$text" "$i"
+ else
+ local c w cs cb extend changed=0
+ ble/unicode/GraphemeCluster/match "$text" "$i"
+ if ((c<32)); then
+ if ((c==9)); then
+ if ((x+1>=cols)); then
+ cs=' ' w=0
+ ble/textmap#update/.wrap
+ else
+ local x2
+ ((x2=(x/it+1)*it,
+ x2>=cols&&(x2=cols-1),
+ w=x2-x,
+ w!=it&&(changed=1)))
+ cs=${_ble_string_prototype::w}
+ fi
+ elif ((c==10)); then
+ w=0
+ if [[ :$opts: == *:relative:* ]]; then
+ local pad=$((cols-x)) eraser=
+ if ((pad)); then
+ if [[ $_ble_term_ech ]]; then
+ eraser=${_ble_term_ech//'%d'/$pad}
+ else
+ eraser=${_ble_string_prototype::pad}
+ ((x=cols))
+ fi
+ fi
+ local move=${_ble_term_cub//'%d'/$x}${_ble_term_cud//'%d'/1}
+ cs=$eraser$move
+ changed=1
+ else
+ cs=$_ble_term_el$_ble_term_nl
+ fi
+ ((y++,x=0))
+ fi
+ fi
+ local wrapping=0
+ if ((w>0)); then
+ if ((x<cols&&cols<x+w)); then
+ if [[ :$opts: == *:relative:* ]]; then
+ cs=${_ble_term_cub//'%d'/$cols}${_ble_term_cud//'%d'/1}$cs
+ elif ((xenl)); then
+ cs=$_ble_term_cr$cs
+ fi
+ local pad=$((cols-x))
+ if ((pad)); then
+ if [[ $_ble_term_ech ]]; then
+ cs=${_ble_term_ech//'%d'/$pad}$cs
+ else
+ cs=${_ble_string_prototype::pad}$cs
+ fi
+ fi
+ ((x=cols,changed=1,wrapping=1))
+ fi
+ ((x+=w))
+ while ((x>cols)); do
+ ((y++,x-=cols))
+ done
+ if ((x==cols)); then
+ ble/textmap#update/.wrap
+ fi
+ fi
+ _ble_textmap_glyph[i]=$cs
+ ((changed)) && ble/array#push _ble_textmap_ichg "$i"
+ _ble_textmap_pos[i+1]="$x $y $wrapping"
+ ((i++))
+ fi
+ while ((extend--)); do
+ _ble_textmap_glyph[i]=
+ _ble_textmap_pos[++i]="$x $y 0"
+ done
+ if ((i>=dend)); then
+ [[ ${old_pos[i-dend]} == "${_ble_textmap_pos[i]}" ]] && break
+ if [[ ${old_pos[i-dend]%%[$IFS]*} == "${_ble_textmap_pos[i]%%[$IFS]*}" ]]; then
+ local -a opos npos pos
+ opos=(${old_pos[i-dend]})
+ npos=(${_ble_textmap_pos[i]})
+ local ydelta=$((npos[1]-opos[1]))
+ while ((i<iN)); do
+ ((i++))
+ pos=(${_ble_textmap_pos[i]})
+ ((pos[1]+=ydelta))
+ _ble_textmap_pos[i]="${pos[*]}"
+ done
+ pos=(${_ble_textmap_pos[iN]})
+ x=${pos[0]} y=${pos[1]}
+ break
+ fi
+ fi
+ done
+ if ((i<iN)); then
+ local -a pos
+ pos=(${_ble_textmap_pos[iN]})
+ x=${pos[0]} y=${pos[1]}
+ fi
+ local j jN ichg
+ for ((j=0,jN=${#old_ichg[@]};j<jN;j++)); do
+ if ((ichg=old_ichg[j],
+ (ichg>=dend0)&&(ichg+=dend-dend0),
+ (0<=ichg&&ichg<dbeg||dend<=i&&ichg<iN)))
+ then
+ ble/array#push _ble_textmap_ichg "$ichg"
+ fi
+ done
+ ((dbeg<i)) && ble/urange#update --prefix=_ble_textmap_ "$dbeg" "$i"
+ _ble_textmap_endx=$x
+ _ble_textmap_endy=$y
+}
+function ble/textmap#is-up-to-date {
+ ((_ble_textmap_dbeg==-1))
+}
+function ble/textmap#assert-up-to-date {
+ ble/util/assert 'ble/textmap#is-up-to-date' 'dirty text positions'
+}
+function ble/textmap#getxy.out {
+ ble/textmap#assert-up-to-date
+ local _prefix=
+ if [[ $1 == --prefix=* ]]; then
+ _prefix=${1#--prefix=}
+ shift
+ fi
+ local -a _pos
+ _pos=(${_ble_textmap_pos[$1]})
+ ((${_prefix}x=_pos[0]))
+ ((${_prefix}y=_pos[1]))
+}
+function ble/textmap#getxy.cur {
+ ble/textmap#assert-up-to-date
+ local _prefix=
+ if [[ $1 == --prefix=* ]]; then
+ _prefix=${1#--prefix=}
+ shift
+ fi
+ local -a _pos
+ ble/string#split-words _pos "${_ble_textmap_pos[$1]}"
+ if (($1<_ble_textmap_length)); then
+ local -a _eoc
+ ble/string#split-words _eoc "${_ble_textmap_pos[$1+1]}"
+ ((_eoc[2])) && ((_pos[0]=0,_pos[1]++))
+ fi
+ ((${_prefix}x=_pos[0]))
+ ((${_prefix}y=_pos[1]))
+}
+function ble/textmap#get-index-at {
+ ble/textmap#assert-up-to-date
+ local _var=index
+ if [[ $1 == -v ]]; then
+ _var=$2
+ shift 2
+ fi
+ local _x=$1 _y=$2
+ if ((_y>_ble_textmap_endy)); then
+ (($_var=_ble_textmap_length))
+ elif ((_y<_ble_textmap_begy)); then
+ (($_var=0))
+ else
+ local _l=0 _u=$((_ble_textmap_length+1)) _m
+ local _mx _my
+ while ((_l+1<_u)); do
+ ble/textmap#getxy.cur --prefix=_m $((_m=(_l+_u)/2))
+ (((_y<_my||_y==_my&&_x<_mx)?(_u=_m):(_l=_m)))
+ done
+ (($_var=_l))
+ fi
+}
+function ble/textmap#hit/.getxy.out {
+ local a
+ ble/string#split-words a "${_ble_textmap_pos[$1]}"
+ x=${a[0]} y=${a[1]}
+}
+function ble/textmap#hit/.getxy.cur {
+ local index=$1 a
+ ble/string#split-words a "${_ble_textmap_pos[index]}"
+ x=${a[0]} y=${a[1]}
+ if ((index<_ble_textmap_length)); then
+ ble/string#split-words a "${_ble_textmap_pos[index+1]}"
+ ((a[2])) && ((x=0,y++))
+ fi
+}
+function ble/textmap#hit {
+ ble/textmap#assert-up-to-date
+ local getxy=ble/textmap#hit/.getxy.$1
+ local xh=$2 yh=$3 beg=${4:-0} end=${5:-$_ble_textmap_length}
+ local -a pos
+ if "$getxy" "$end"; ((yh>y||yh==y&&xh>x)); then
+ index=$end
+ lx=$x ly=$y
+ rx=$x ry=$y
+ elif "$getxy" "$beg"; ((yh<y||yh==y&&xh<x)); then
+ index=$beg
+ lx=$x ly=$y
+ rx=$x ry=$y
+ else
+ local l=0 u=$((end+1)) m
+ while ((l+1<u)); do
+ "$getxy" $((m=(l+u)/2))
+ (((yh<y||yh==y&&xh<x)?(u=m):(l=m)))
+ done
+ "$getxy" $((index=l))
+ lx=$x ly=$y
+ (((ly<yh||ly==yh&&lx<xh)&&index<end)) && "$getxy" $((index+1))
+ rx=$x ry=$y
+ fi
+}
+_ble_canvas_x=0
+_ble_canvas_y=0
+_ble_canvas_excursion=
+function ble/canvas/goto.draw {
+ local x=$1 y=$2 opts=$3
+ [[ :$opts: != *:sgr0:* ]] &&
+ ((x==_ble_canvas_x&&y==_ble_canvas_y)) && return 0
+ ble/canvas/put.draw "$_ble_term_sgr0"
+ ble/canvas/put-move-y.draw $((y-_ble_canvas_y))
+ local dx=$((x-_ble_canvas_x))
+ if ((dx!=0)); then
+ if ((x==0)); then
+ ble/canvas/put.draw "$_ble_term_cr"
+ else
+ ble/canvas/put-move-x.draw "$dx"
+ fi
+ fi
+ _ble_canvas_x=$x _ble_canvas_y=$y
+}
+_ble_canvas_excursion_x=
+_ble_canvas_excursion_y=
+function ble/canvas/excursion-start.draw {
+ [[ $_ble_canvas_excursion ]] && return
+ _ble_canvas_excursion=1
+ _ble_canvas_excursion_x=$_ble_canvas_x
+ _ble_canvas_excursion_y=$_ble_canvas_y
+ ble/canvas/put.draw "$_ble_term_sc"
+}
+function ble/canvas/excursion-end.draw {
+ [[ $_ble_canvas_excursion ]] || return
+ _ble_canvas_excursion=
+ ble/canvas/put.draw "$_ble_term_rc"
+ _ble_canvas_x=$_ble_canvas_excursion_x
+ _ble_canvas_y=$_ble_canvas_excursion_y
+}
+_ble_canvas_panel_class=()
+_ble_canvas_panel_height=(1 0 0)
+_ble_canvas_panel_focus=
+_ble_canvas_panel_vfill=
+_ble_canvas_panel_bottom= # 現在下部に居るかどうか
+_ble_canvas_panel_tmargin='LINES!=1?1:0' # for visible-bell
+function ble/canvas/panel/layout/.extract-heights {
+ local i n=${#_ble_canvas_panel_class[@]}
+ for ((i=0;i<n;i++)); do
+ local height=0:0
+ ble/function#try "${_ble_canvas_panel_class[i]}#panel::getHeight" "$i"
+ mins[i]=${height%:*}
+ maxs[i]=${height#*:}
+ done
+}
+function ble/canvas/panel/layout/.determine-heights {
+ local i n=${#_ble_canvas_panel_class[@]} ret
+ ble/arithmetic/sum "${mins[@]}"; local min=$ret
+ ble/arithmetic/sum "${maxs[@]}"; local max=$ret
+ if ((max<=lines)); then
+ heights=("${maxs[@]}")
+ elif ((min<=lines)); then
+ local room=$((lines-min))
+ heights=("${mins[@]}")
+ while ((room)); do
+ local count=0 min_delta=-1 delta
+ for ((i=0;i<n;i++)); do
+ ((delta=maxs[i]-heights[i],delta>0)) || continue
+ ((count++))
+ ((min_delta<0||min_delta>delta)) && min_delta=$delta
+ done
+ ((count==0)) && break
+ if ((count*min_delta<=room)); then
+ for ((i=0;i<n;i++)); do
+ ((maxs[i]-heights[i]>0)) || continue
+ ((heights[i]+=min_delta))
+ done
+ ((room-=count*min_delta))
+ else
+ local delta=$((room/count)) rem=$((room%count)) count=0
+ for ((i=0;i<n;i++)); do
+ ((maxs[i]-heights[i]>0)) || continue
+ ((heights[i]+=delta))
+ ((count++<rem)) && ((heights[i]++))
+ done
+ ((room=0))
+ fi
+ done
+ else
+ heights=("${mins[@]}")
+ local excess=$((min-lines))
+ for ((i=n-1;i>=0;i--)); do
+ local sub=$((heights[i]-heights[i]*lines/min))
+ if ((sub<excess)); then
+ ((excess-=sub))
+ ((heights[i]-=sub))
+ else
+ ((heights[i]-=excess))
+ break
+ fi
+ done
+ fi
+}
+function ble/canvas/panel/layout/.get-available-height {
+ local index=$1
+ local lines=$((${LINES:-25}-_ble_canvas_panel_tmargin))
+ local -a mins=() maxs=()
+ ble/canvas/panel/layout/.extract-heights
+ maxs[index]=${LINES:-25}
+ local -a heights=()
+ ble/canvas/panel/layout/.determine-heights
+ ret=${heights[index]}
+}
+function ble/canvas/panel/reallocate-height.draw {
+ local lines=$((${LINES:-25}-_ble_canvas_panel_tmargin))
+ local i n=${#_ble_canvas_panel_class[@]}
+ local -a mins=() maxs=()
+ ble/canvas/panel/layout/.extract-heights
+ local -a heights=()
+ ble/canvas/panel/layout/.determine-heights
+ for ((i=0;i<n;i++)); do
+ ((heights[i]<_ble_canvas_panel_height[i])) &&
+ ble/canvas/panel#set-height.draw "$i" "${heights[i]}"
+ done
+ for ((i=0;i<n;i++)); do
+ ((heights[i]>_ble_canvas_panel_height[i])) &&
+ ble/canvas/panel#set-height.draw "$i" "${heights[i]}"
+ done
+}
+function ble/canvas/panel/is-last-line {
+ local ret
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]}"
+ ((_ble_canvas_y==ret-1))
+}
+function ble/canvas/panel/goto-bottom-dock.draw {
+ if [[ ! $_ble_canvas_panel_bottom ]]; then
+ _ble_canvas_panel_bottom=1
+ ble/canvas/excursion-start.draw
+ ble/canvas/put-cup.draw "$LINES" 0 # 一番下の行に移動
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]}"
+ ((_ble_canvas_x=0,_ble_canvas_y=ret-1))
+ fi
+}
+function ble/canvas/panel/goto-top-dock.draw {
+ if [[ $_ble_canvas_panel_bottom ]]; then
+ _ble_canvas_panel_bottom=
+ ble/canvas/excursion-end.draw
+ fi
+}
+function ble/canvas/panel/goto-vfill.draw {
+ ble/canvas/panel/has-bottom-dock || return 1
+ local ret
+ ble/canvas/panel/goto-top-dock.draw
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]::_ble_canvas_panel_vfill}"
+ ble/canvas/goto.draw 0 "$ret" sgr0
+ return 0
+}
+function ble/canvas/panel/save-position {
+ ret=$_ble_canvas_x:$_ble_canvas_y:$_ble_canvas_panel_bottom
+ [[ :$2: == *:goto-top-dock:* ]] &&
+ ble/canvas/panel/goto-top-dock.draw
+}
+function ble/canvas/panel/load-position {
+ local -a DRAW_BUFF=()
+ ble/canvas/panel/load-position.draw "$@"
+ ble/canvas/bflush.draw
+}
+function ble/canvas/panel/load-position.draw {
+ local data=$1
+ local x=${data%%:*}; data=${data#*:}
+ local y=${data%%:*}; data=${data#*:}
+ local bottom=$data
+ if [[ $bottom ]]; then
+ ble/canvas/panel/goto-bottom-dock.draw
+ else
+ ble/canvas/panel/goto-top-dock.draw
+ fi
+ ble/canvas/goto.draw "$x" "$y"
+}
+function ble/canvas/panel/has-bottom-dock {
+ local ret; ble/canvas/panel/bottom-dock#height
+ ((ret))
+}
+function ble/canvas/panel/bottom-dock#height {
+ ret=0
+ [[ $_ble_canvas_panel_vfill && $_ble_term_rc ]] || return 0
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]:_ble_canvas_panel_vfill}"
+}
+function ble/canvas/panel/top-dock#height {
+ if [[ $_ble_canvas_panel_vfill && $_ble_term_rc ]]; then
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]::_ble_canvas_panel_vfill}"
+ else
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]}"
+ fi
+}
+function ble/canvas/panel/bottom-dock#invalidate {
+ [[ $_ble_canvas_panel_vfill && $_ble_term_rc ]] || return 0
+ local index n=${#_ble_canvas_panel_class[@]}
+ for ((index=_ble_canvas_panel_vfill;index<n;index++)); do
+ local panel_class=${_ble_canvas_panel_class[index]}
+ local panel_height=${_ble_canvas_panel_height[index]}
+ ((panel_height)) &&
+ ble/function#try "$panel_class#panel::invalidate" "$index" 0 "$panel_height"
+ done
+}
+function ble/canvas/panel#is-bottom {
+ [[ $_ble_canvas_panel_vfill && $_ble_term_rc ]] && (($1>=_ble_canvas_panel_vfill))
+}
+function ble/canvas/panel#get-origin {
+ local ret index=$1 prefix=
+ [[ $2 == --prefix=* ]] && prefix=${2#*=}
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]::index}"
+ ((${prefix}x=0,${prefix}y=ret))
+}
+function ble/canvas/panel#goto.draw {
+ local index=$1 x=${2-0} y=${3-0} opts=$4 ret
+ if ble/canvas/panel#is-bottom "$index"; then
+ ble/canvas/panel/goto-bottom-dock.draw
+ else
+ ble/canvas/panel/goto-top-dock.draw
+ fi
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]::index}"
+ ble/canvas/goto.draw "$x" $((ret+y)) "$opts"
+}
+function ble/canvas/panel#put.draw {
+ ble/canvas/put.draw "$2"
+ ble/canvas/panel#report-cursor-position "$1" "$3" "$4"
+}
+function ble/canvas/panel#report-cursor-position {
+ local index=$1 x=${2-0} y=${3-0} ret
+ ble/arithmetic/sum "${_ble_canvas_panel_height[@]::index}"
+ ((_ble_canvas_x=x,_ble_canvas_y=ret+y))
+}
+function ble/canvas/panel/increase-total-height.draw {
+ local delta=$1
+ ((delta>0)) || return 1
+ local ret
+ ble/canvas/panel/top-dock#height; local top_height=$ret
+ ble/canvas/panel/bottom-dock#height; local bottom_height=$ret
+ if ((bottom_height)); then
+ ble/canvas/panel/goto-top-dock.draw
+ if [[ $_ble_term_DECSTBM ]]; then
+ ble/canvas/excursion-start.draw
+ ble/canvas/put.draw $'\e[1;'$((LINES-bottom_height))'r'
+ ble/canvas/excursion-end.draw
+ ble/canvas/goto.draw 0 $((top_height==0?0:top_height-1)) sgr0
+ ble/canvas/put-ind.draw $((top_height-1+delta-_ble_canvas_y))
+ ((_ble_canvas_y=top_height-1+delta))
+ ble/canvas/excursion-start.draw
+ ble/canvas/put.draw "$_ble_term_DECSTBM_reset"
+ ble/canvas/excursion-end.draw
+ return 0
+ else
+ ble/canvas/panel/bottom-dock#invalidate
+ fi
+ fi
+ local old_height=$((top_height+bottom_height))
+ local new_height=$((old_height+delta))
+ ble/canvas/goto.draw 0 $((top_height==0?0:top_height-1)) sgr0
+ ble/canvas/put-ind.draw $((new_height-1-_ble_canvas_y)); ((_ble_canvas_y=new_height-1))
+ ble/canvas/panel/goto-vfill.draw &&
+ ble/canvas/put-il.draw "$delta" vfill
+}
+function ble/canvas/panel#set-height.draw {
+ local index=$1 new_height=$2 opts=$3
+ ((new_height<0)) && new_height=0
+ local old_height=${_ble_canvas_panel_height[index]}
+ local delta=$((new_height-old_height))
+ if ((delta==0)); then
+ if [[ :$opts: == *:clear:* ]]; then
+ ble/canvas/panel#clear.draw "$index"
+ return $?
+ else
+ return 1
+ fi
+ elif ((delta>0)); then
+ ble/canvas/panel/increase-total-height.draw "$delta"
+ ble/canvas/panel/goto-vfill.draw &&
+ ble/canvas/put-dl.draw "$delta" vfill
+ ((_ble_canvas_panel_height[index]=new_height))
+ case :$opts: in
+ (*:clear:*)
+ ble/canvas/panel#goto.draw "$index" 0 0 sgr0
+ ble/canvas/put-clear-lines.draw "$old_height" "$new_height" panel ;;
+ (*:shift:*) # 先頭に行挿入
+ ble/canvas/panel#goto.draw "$index" 0 0 sgr0
+ ble/canvas/put-il.draw "$delta" panel ;;
+ (*) # 末尾に行挿入
+ ble/canvas/panel#goto.draw "$index" 0 "$old_height" sgr0
+ ble/canvas/put-il.draw "$delta" panel ;;
+ esac
+ else
+ ((delta=-delta))
+ case :$opts: in
+ (*:clear:*)
+ ble/canvas/panel#goto.draw "$index" 0 0 sgr0
+ ble/canvas/put-clear-lines.draw "$old_height" "$new_height" panel ;;
+ (*:shift:*) # 先頭を削除
+ ble/canvas/panel#goto.draw "$index" 0 0 sgr0
+ ble/canvas/put-dl.draw "$delta" panel ;;
+ (*) # 末尾を削除
+ ble/canvas/panel#goto.draw "$index" 0 "$new_height" sgr0
+ ble/canvas/put-dl.draw "$delta" panel ;;
+ esac
+ ((_ble_canvas_panel_height[index]=new_height))
+ ble/canvas/panel/goto-vfill.draw &&
+ ble/canvas/put-il.draw "$delta" vfill
+ fi
+ ble/function#try "${_ble_canvas_panel_class[index]}#panel::onHeightChange" "$index"
+ return 0
+}
+function ble/canvas/panel#increase-height.draw {
+ local index=$1 delta=$2 opts=$3
+ ble/canvas/panel#set-height.draw "$index" $((_ble_canvas_panel_height[index]+delta)) "$opts"
+}
+function ble/canvas/panel#set-height-and-clear.draw {
+ local index=$1 new_height=$2
+ ble/canvas/panel#set-height.draw "$index" "$new_height" clear
+}
+function ble/canvas/panel#clear.draw {
+ local index=$1
+ local height=${_ble_canvas_panel_height[index]}
+ if ((height)); then
+ ble/canvas/panel#goto.draw "$index" 0 0 sgr0
+ ble/canvas/put-clear-lines.draw "$height"
+ fi
+}
+function ble/canvas/panel#clear-after.draw {
+ local index=$1 x=$2 y=$3
+ local height=${_ble_canvas_panel_height[index]}
+ ((y<height)) || return 1
+ ble/canvas/panel#goto.draw "$index" "$x" "$y" sgr0
+ ble/canvas/put.draw "$_ble_term_el"
+ local rest_lines=$((height-(y+1)))
+ if ((rest_lines)); then
+ ble/canvas/put.draw "$_ble_term_ind"
+ [[ $_ble_term_ind != $'\eD' ]] &&
+ ble/canvas/put-hpa.draw $((x+1))
+ ble/canvas/put-clear-lines.draw "$rest_lines"
+ ble/canvas/put-cuu.draw 1
+ fi
+}
+function ble/canvas/panel/clear {
+ local -a DRAW_BUFF=()
+ local index n=${#_ble_canvas_panel_class[@]}
+ for ((index=0;index<n;index++)); do
+ local panel_class=${_ble_canvas_panel_class[index]}
+ local panel_height=${_ble_canvas_panel_height[index]}
+ ((panel_height)) || continue
+ ble/canvas/panel#clear.draw "$index"
+ ble/function#try "$panel_class#panel::invalidate" "$index" 0 "$panel_height"
+ done
+ ble/canvas/bflush.draw
+}
+function ble/canvas/panel/invalidate {
+ local opts=$1
+ if [[ :$opts: == *:height:* ]]; then
+ local -a DRAW_BUFF=()
+ ble/canvas/excursion-end.draw
+ ble/canvas/put.draw "$_ble_term_cr$_ble_term_ed"
+ _ble_canvas_x=0 _ble_canvas_y=0
+ ble/array#fill-range _ble_canvas_panel_height 0 "${#_ble_canvas_panel_height[@]}" 0
+ ble/canvas/panel/reallocate-height.draw
+ ble/canvas/bflush.draw
+ fi
+ local index n=${#_ble_canvas_panel_class[@]}
+ for ((index=0;index<n;index++)); do
+ local panel_class=${_ble_canvas_panel_class[index]}
+ local panel_height=${_ble_canvas_panel_height[index]}
+ ((panel_height)) || continue
+ ble/function#try "$panel_class#panel::invalidate" "$index" 0 "$panel_height"
+ done
+}
+function ble/canvas/panel/render {
+ local index n=${#_ble_canvas_panel_class[@]} pos=
+ for ((index=0;index<n;index++)); do
+ local panel_class=${_ble_canvas_panel_class[index]}
+ local panel_height=${_ble_canvas_panel_height[index]}
+ ble/function#try "$panel_class#panel::render" "$index" 0 "$panel_height"
+ if [[ $_ble_canvas_panel_focus ]] && ((index==_ble_canvas_panel_focus)); then
+ local ret; ble/canvas/panel/save-position; local pos=$ret
+ fi
+ done
+ [[ $pos ]] && ble/canvas/panel/load-position "$pos"
+ return 0
+}
+function ble/canvas/panel/ensure-tmargin.draw {
+ local tmargin=$((_ble_canvas_panel_tmargin))
+ ((tmargin>LINES)) && tmargin=$LINES
+ ((tmargin>0)) || return 0
+ local ret
+ ble/canvas/panel/save-position; local pos=$ret
+ ble/canvas/panel/goto-top-dock.draw
+ ble/canvas/panel/top-dock#height; local top_height=$ret
+ ble/canvas/panel/bottom-dock#height; local bottom_height=$ret
+ if ((bottom_height)); then
+ if [[ $_ble_term_DECSTBM ]]; then
+ ble/canvas/excursion-start.draw
+ ble/canvas/put.draw $'\e[1;'$((LINES-bottom_height))'r'
+ ble/canvas/excursion-end.draw
+ ble/canvas/goto.draw 0 0 sgr0
+ if [[ $_ble_term_ri ]]; then
+ ble/canvas/put-ri.draw "$tmargin"
+ ble/canvas/put-cud.draw "$tmargin"
+ else
+ ble/canvas/put-ind.draw $((top_height-1+tmargin))
+ ble/canvas/put-cuu.draw $((top_height-1+tmargin))
+ ble/canvas/excursion-start.draw
+ ble/canvas/put-cup.draw 1 1
+ ble/canvas/put-il.draw "$tmargin" no-lastline
+ ble/canvas/excursion-end.draw
+ fi
+ ble/canvas/excursion-start.draw
+ ble/canvas/put.draw "$_ble_term_DECSTBM_reset"
+ ble/canvas/excursion-end.draw
+ ble/canvas/panel/load-position.draw "$pos"
+ return 0
+ else
+ ble/canvas/panel/bottom-dock#invalidate
+ fi
+ fi
+ ble/canvas/goto.draw 0 0 sgr0
+ if [[ $_ble_term_ri ]]; then
+ ble/canvas/put-ri.draw "$tmargin"
+ ble/canvas/put-cud.draw "$tmargin"
+ else
+ local total_height=$((top_height+bottom_height))
+ ble/canvas/put-ind.draw $((total_height-1+tmargin))
+ ble/canvas/put-cuu.draw $((total_height-1+tmargin))
+ if [[ $_ble_term_rc ]]; then
+ ble/canvas/excursion-start.draw
+ ble/canvas/put-cup.draw 1 1
+ ble/canvas/put-il.draw "$tmargin" no-lastline
+ ble/canvas/excursion-end.draw
+ else
+ ble/canvas/put-il.draw "$tmargin" no-lastline
+ fi
+ ble/canvas/put-cud.draw "$tmargin"
+ fi
+ ble/canvas/panel/load-position.draw "$pos"
+}
+bleopt/declare -v history_limit_length 10000
+_ble_history=()
+_ble_history_edit=()
+_ble_history_dirt=()
+_ble_history_index=0
+_ble_history_count=
+function ble/builtin/history/is-empty {
+ ! ble/util/assign.has-output 'history 1'
+}
+function ble/builtin/history/.get-min {
+ ble/util/assign min 'builtin history | head -1'
+ ble/string#split-words min "$min"
+}
+function ble/builtin/history/.get-max {
+ ble/util/assign max 'builtin history 1'
+ ble/string#split-words max "$max"
+}
+_ble_history_load_done=
+function ble/history:bash/clear-background-load {
+ blehook/invoke history_reset_background
+}
+if ((_ble_bash>=40000)); then
+ _ble_history_load_resume=0
+ _ble_history_load_bgpid=
+ function ble/history:bash/load/.background-initialize {
+ if ble/builtin/history/is-empty; then
+ builtin history -n
+ fi
+ local HISTTIMEFORMAT=__ble_ext__
+ local -x INDEX_FILE=$history_indfile
+ local -x opt_source= opt_null=
+ if [[ $load_strategy == source ]]; then
+ opt_source=1
+ elif [[ $load_strategy == mapfile ]]; then
+ opt_null=1
+ fi
+ local apos=\'
+ builtin history $arg_count | ble/bin/awk -v apos="$apos" -v arg_offset="$arg_offset" -v _ble_bash="$_ble_bash" '
+ function s2i_initialize() {
+ for (i = 0; i < 16; i++)
+ xdigit2int[sprintf("%x", i)] = i;
+ for (i = 10; i < 16; i++)
+ xdigit2int[sprintf("%X", i)] = i;
+ }
+ function s2i(s, base, _, i, n, r) {
+ if (!base) base = 10;
+ r = 0;
+ n = length(s);
+ for (i = 1; i <= n; i++)
+ r = r * base + xdigit2int[substr(s, i, 1)];
+ return r;
+ }
+ function c2s_initialize(_, i) {
+ if (sprintf("%c", 945) == "α") {
+ C2S_UNICODE_PRINTF_C = 1;
+ } else {
+ C2S_UNICODE_PRINTF_C = 0;
+ for (i = 1; i <= 255; i++)
+ c2s_byte2char[i] = sprintf("%c", i);
+ }
+ }
+ function c2s(code, _, leadbyte_mark, leadbyte_sup, tail) {
+ if (C2S_UNICODE_PRINTF_C)
+ return sprintf("%c", code);
+ leadbyte_sup = 128; # 0x80
+ leadbyte_mark = 0;
+ tail = "";
+ while (leadbyte_sup && code >= leadbyte_sup) {
+ leadbyte_sup /= 2;
+ leadbyte_mark = leadbyte_mark ? leadbyte_mark / 2 : 65472; # 0xFFC0
+ tail = c2s_byte2char[128 + int(code % 64)] tail;
+ code = int(code / 64);
+ }
+ return c2s_byte2char[(leadbyte_mark + code) % 256] tail;
+ }
+ function es_initialize(_, c) {
+ es_control_chars["a"] = "\a";
+ es_control_chars["b"] = "\b";
+ es_control_chars["t"] = "\t";
+ es_control_chars["n"] = "\n";
+ es_control_chars["v"] = "\v";
+ es_control_chars["f"] = "\f";
+ es_control_chars["r"] = "\r";
+ es_control_chars["e"] = "\033";
+ es_control_chars["E"] = "\033";
+ es_control_chars["?"] = "?";
+ es_control_chars[apos] = apos;
+ es_control_chars["\""] = "\"";
+ es_control_chars["\\"] = "\\";
+ for (c = 32; c < 127; c++)
+ es_s2c[sprintf("%c", c)] = c;
+ }
+ function es_unescape(s, _, head, c) {
+ head = "";
+ while (match(s, /^[^\\]*\\/)) {
+ head = head substr(s, 1, RLENGTH - 1);
+ s = substr(s, RLENGTH + 1);
+ if ((c = es_control_chars[substr(s, 1, 1)])) {
+ head = head c;
+ s = substr(s, 2);
+ } else if (match(s, /^[0-9]([0-9][0-9]?)?/)) {
+ head = head c2s(s2i(substr(s, 1, RLENGTH), 8) % 256);
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^x[0-9a-fA-F][0-9a-fA-F]?/)) {
+ head = head c2s(s2i(substr(s, 2, RLENGTH - 1), 16));
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^U[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]([0-9a-fA-F]([0-9a-fA-F][0-9a-fA-F]?)?)?/)) {
+ head = head c2s(s2i(substr(s, 2, RLENGTH - 1), 16));
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^[uU][0-9a-fA-F]([0-9a-fA-F]([0-9a-fA-F][0-9a-fA-F]?)?)?/)) {
+ head = head c2s(s2i(substr(s, 2, RLENGTH - 1), 16));
+ s = substr(s, RLENGTH + 1);
+ } else if (match(s, /^c[ -~]/)) {
+ c = es_s2c[substr(s, 2, 1)];
+ head = head c2s(_ble_bash >= 40400 && c == 63 ? 127 : c % 32);
+ s = substr(s, 3);
+ } else {
+ head = head "\\";
+ }
+ }
+ return head s;
+ }
+ BEGIN {
+ s2i_initialize();
+ c2s_initialize();
+ es_initialize();
+ INDEX_FILE = ENVIRON["INDEX_FILE"];
+ opt_null = ENVIRON["opt_null"];
+ opt_source = ENVIRON["opt_source"];
+ if (!opt_null && !opt_source)
+ printf("") > INDEX_FILE; # create file
+ n = 0;
+ hindex = arg_offset;
+ }
+ function flush_line() {
+ if (n < 1) return;
+ if (opt_null) {
+ if (t ~ /^eval -- \$'$apos'([^'$apos'\\]|\\.)*'$apos'$/)
+ t = es_unescape(substr(t, 11, length(t) - 11));
+ printf("%s%c", t, 0);
+ } else if (opt_source) {
+ if (t ~ /^eval -- \$'$apos'([^'$apos'\\]|\\.)*'$apos'$/)
+ t = es_unescape(substr(t, 11, length(t) - 11));
+ gsub(/'$apos'/, "'$apos'\\'$apos$apos'", t);
+ print "_ble_history[" hindex "]=" apos t apos;
+ } else {
+ if (n == 1) {
+ if (t ~ /^eval -- \$'$apos'([^'$apos'\\]|\\.)*'$apos'$/)
+ print hindex > INDEX_FILE;
+ } else {
+ gsub(/['$apos'\\]/, "\\\\&", t);
+ gsub(/\n/, "\\n", t);
+ print hindex > INDEX_FILE;
+ t = "eval -- $" apos t apos;
+ }
+ print t;
+ }
+ hindex++;
+ n = 0;
+ t = "";
+ }
+ {
+ if (sub(/^ *[0-9]+\*? +(__ble_ext__|\?\?)/, "", $0))
+ flush_line();
+ t = ++n == 1 ? $0 : t "\n" $0;
+ }
+ END { flush_line(); }
+ ' >| "$history_tmpfile.part"
+ ble/bin/mv -f "$history_tmpfile.part" "$history_tmpfile"
+ }
+ function ble/history:bash/load {
+ local opts=$1
+ local opt_async=; [[ :$opts: == *:async:* ]] && opt_async=1
+ local load_strategy=mapfile
+ if [[ $OSTYPE == cygwin* || $OSTYPE == msys* ]]; then
+ load_strategy=source
+ elif ((_ble_bash<50200)); then
+ load_strategy=nlfix
+ fi
+ local arg_count= arg_offset=0
+ [[ :$opts: == *:append:* ]] &&
+ arg_offset=${#_ble_history[@]}
+ local rex=':count=([0-9]+):'; [[ :$opts: =~ $rex ]] && arg_count=${BASH_REMATCH[1]}
+ local history_tmpfile=$_ble_base_run/$$.history.load
+ local history_indfile=$_ble_base_run/$$.history.multiline-index
+ [[ $opt_async || :$opts: == *:init:* ]] || _ble_history_load_resume=0
+ [[ ! $opt_async ]] && ((_ble_history_load_resume<6)) &&
+ blehook/invoke history_message "loading history ..."
+ while :; do
+ case $_ble_history_load_resume in
+ (0) # 履歴ファイル生成を Background で開始
+ if [[ $_ble_history_load_bgpid ]]; then
+ builtin kill -9 "$_ble_history_load_bgpid" &>/dev/null
+ _ble_history_load_bgpid=
+ fi
+ : >| "$history_tmpfile"
+ if [[ $opt_async ]]; then
+ _ble_history_load_bgpid=$(
+ shopt -u huponexit; ble/history:bash/load/.background-initialize </dev/null &>/dev/null & ble/util/print $!)
+ function ble/history:bash/load/.background-initialize-completed {
+ local history_tmpfile=$_ble_base_run/$$.history.load
+ [[ -s $history_tmpfile ]] || ! builtin kill -0 "$_ble_history_load_bgpid"
+ } &>/dev/null
+ ((_ble_history_load_resume++))
+ else
+ ble/history:bash/load/.background-initialize
+ ((_ble_history_load_resume+=3))
+ fi ;;
+ (1) if [[ $opt_async ]] && ble/util/is-running-in-idle; then
+ ble/util/idle.wait-condition ble/history:bash/load/.background-initialize-completed
+ ((_ble_history_load_resume++))
+ return 147
+ fi
+ ((_ble_history_load_resume++)) ;;
+ (2) while ! ble/history:bash/load/.background-initialize-completed; do
+ ble/util/msleep 50
+ [[ $opt_async ]] && ! ble/util/idle/IS_IDLE && return 148
+ done
+ ((_ble_history_load_resume++)) ;;
+ (3) _ble_history_load_bgpid=
+ ((arg_offset==0)) && _ble_history=()
+ if [[ $load_strategy == source ]]; then
+ source "$history_tmpfile"
+ elif [[ $load_strategy == nlfix ]]; then
+ builtin mapfile -O "$arg_offset" -t _ble_history < "$history_tmpfile"
+ else
+ builtin mapfile -O "$arg_offset" -t -d '' _ble_history < "$history_tmpfile"
+ fi
+ ((_ble_history_load_resume++)) ;;
+ (4) ((arg_offset==0)) && _ble_history_edit=()
+ if [[ $load_strategy == source ]]; then
+ _ble_history_edit=("${_ble_history[@]}")
+ elif [[ $load_strategy == nlfix ]]; then
+ builtin mapfile -O "$arg_offset" -t _ble_history_edit < "$history_tmpfile"
+ else
+ builtin mapfile -O "$arg_offset" -t -d '' _ble_history_edit < "$history_tmpfile"
+ fi
+ : >| "$history_tmpfile"
+ if [[ $load_strategy != nlfix ]]; then
+ ((_ble_history_load_resume+=3))
+ return 0
+ else
+ ((_ble_history_load_resume++))
+ fi ;;
+ (5) local -a indices_to_fix
+ ble/util/mapfile indices_to_fix < "$history_indfile"
+ local i rex='^eval -- \$'\''([^\'\'']|\\.)*'\''$'
+ for i in "${indices_to_fix[@]}"; do
+ [[ ${_ble_history[i]} =~ $rex ]] &&
+ builtin eval "_ble_history[i]=${_ble_history[i]:8}"
+ done
+ ((_ble_history_load_resume++)) ;;
+ (6) local -a indices_to_fix
+ [[ ${indices_to_fix+set} ]] ||
+ ble/util/mapfile indices_to_fix < "$history_indfile"
+ for i in "${indices_to_fix[@]}"; do
+ [[ ${_ble_history_edit[i]} =~ $rex ]] &&
+ builtin eval "_ble_history_edit[i]=${_ble_history_edit[i]:8}"
+ done
+ ((_ble_history_load_resume++)) ;;
+ (7) [[ $opt_async ]] || blehook/invoke history_message
+ ((_ble_history_load_resume++))
+ return 0 ;;
+ (*) return 1 ;;
+ esac
+ [[ $opt_async ]] && ! ble/util/idle/IS_IDLE && return 148
+ done
+ }
+ blehook history_reset_background+=_ble_history_load_resume=0
+else
+ function ble/history:bash/load/.generate-source {
+ if ble/builtin/history/is-empty; then
+ builtin history -n
+ fi
+ local HISTTIMEFORMAT=__ble_ext__
+ local apos="'"
+ builtin history $arg_count | ble/bin/awk -v apos="'" '
+ BEGIN { n = ""; }
+ /^ *[0-9]+\*? +(__ble_ext__|\?\?)#[0-9]/ { next; }
+ /^ *[0-9]+\*? +(__ble_ext__|\?\?)/ {
+ if (n != "") {
+ n = "";
+ print " " apos t apos;
+ }
+ n = $1; t = "";
+ sub(/^ *[0-9]+\*? +(__ble_ext__|\?\?)/, "", $0);
+ }
+ {
+ line = $0;
+ if (line ~ /^eval -- \$'$apos'([^'$apos'\\]|\\.)*'$apos'$/)
+ line = apos substr(line, 9) apos;
+ else
+ gsub(apos, apos "\\" apos apos, line);
+ gsub(/\001/, "'$apos'${_ble_term_SOH}'$apos'", line);
+ gsub(/\177/, "'$apos'${_ble_term_DEL}'$apos'", line);
+ gsub(/\015/, "'$apos'${_ble_term_CR}'$apos'", line);
+ t = t != "" ? t "\n" line : line;
+ }
+ END {
+ if (n != "") {
+ n = "";
+ print " " apos t apos;
+ }
+ }
+ '
+ }
+ function ble/history:bash/load {
+ local opts=$1
+ local opt_append=
+ [[ :$opts: == *:append:* ]] && opt_append=1
+ local arg_count= rex=':count=([0-9]+):'
+ [[ :$opts: =~ $rex ]] && arg_count=${BASH_REMATCH[1]}
+ blehook/invoke history_message "loading history..."
+ local result=$(ble/history:bash/load/.generate-source)
+ local IFS=$_ble_term_IFS
+ if [[ $opt_append ]]; then
+ if ((_ble_bash>=30100)); then
+ builtin eval -- "_ble_history+=($result)"
+ builtin eval -- "_ble_history_edit+=($result)"
+ else
+ local -a A; builtin eval -- "A=($result)"
+ _ble_history=("${_ble_history[@]}" "${A[@]}")
+ _ble_history_edit=("${_ble_history[@]}" "${A[@]}")
+ fi
+ else
+ builtin eval -- "_ble_history=($result)"
+ _ble_history_edit=("${_ble_history[@]}")
+ fi
+ ble/util/unlocal IFS
+ blehook/invoke history_message
+ }
+fi
+function ble/history:bash/initialize {
+ [[ $_ble_history_load_done ]] && return 0
+ ble/history:bash/load "init:$@"; local ext=$?
+ ((ext)) && return "$ext"
+ local old_count=$_ble_history_count new_count=${#_ble_history[@]}
+ _ble_history_load_done=1
+ _ble_history_count=$new_count
+ _ble_history_index=$_ble_history_count
+ ble/history/.update-position
+ local delta=$((new_count-old_count))
+ ((delta>0)) && blehook/invoke history_insert "$old_count" "$delta"
+}
+if ((_ble_bash>=30100)); then
+ _ble_history_mlfix_done=
+ _ble_history_mlfix_resume=0
+ _ble_history_mlfix_bgpid=
+ function ble/history:bash/resolve-multiline/.awk {
+ if ((_ble_bash>=50000)); then
+ local -x epoch=$EPOCHSECONDS
+ elif ((_ble_bash>=40400)); then
+ local -x epoch
+ ble/util/strftime -v epoch %s
+ fi
+ local -x reason=$1
+ local apos=\'
+ ble/bin/awk -v apos="$apos" -v _ble_bash="$_ble_bash" '
+ BEGIN {
+ q = apos;
+ Q = apos "\\" apos apos;
+ reason = ENVIRON["reason"];
+ is_resolve = reason == "resolve";
+ TMPBASE = ENVIRON["TMPBASE"];
+ filename_source = TMPBASE ".part";
+ if (is_resolve)
+ print "builtin history -c" > filename_source
+ entry_nline = 0;
+ entry_text = "";
+ entry_time = "";
+ if (_ble_bash >= 40400)
+ entry_time = ENVIRON["epoch"];
+ command_count = 0;
+ multiline_count = 0;
+ modification_count = 0;
+ read_section_count = 0;
+ }
+ function write_flush(_, i, filename_section, t, c) {
+ if (command_count == 0) return;
+ if (command_count >= 2 || entry_time) {
+ filename_section = TMPBASE "." read_section_count++ ".part";
+ for (i = 0; i < command_count; i++) {
+ t = command_time[i];
+ c = command_text[i];
+ if (t) print "#" t > filename_section;
+ print c > filename_section;
+ }
+ print "HISTTIMEFORMAT=%s builtin history -r " filename_section > filename_source;
+ } else {
+ for (i = 0; i < command_count; i++) {
+ c = command_text[i];
+ gsub(/'$apos'/, Q, c);
+ print "builtin history -s -- " q c q > filename_source;
+ }
+ }
+ command_count = 0;
+ }
+ function write_complex(value) {
+ write_flush();
+ print "builtin history -s -- " value > filename_source;
+ }
+ function register_command(cmd) {
+ command_time[command_count] = entry_time;
+ command_text[command_count] = cmd;
+ command_count++;
+ }
+ function is_escaped_command(cmd) {
+ return cmd ~ /^eval -- \$'$apos'([^'$apos'\\]|\\[\\'$apos'nt])*'$apos'$/;
+ }
+ function unescape_command(cmd) {
+ cmd = substr(cmd, 11, length(cmd) - 11);
+ gsub(/\\\\/, "\\q", cmd);
+ gsub(/\\n/, "\n", cmd);
+ gsub(/\\t/, "\t", cmd);
+ gsub(/\\'$apos'/, "'$apos'", cmd);
+ gsub(/\\q/, "\\", cmd);
+ return cmd;
+ }
+ function register_escaped_command(cmd) {
+ multiline_count++;
+ modification_count++;
+ if (_ble_bash >= 40400) {
+ register_command(unescape_command(cmd));
+ } else {
+ write_complex(substr(cmd, 9));
+ }
+ }
+ function register_multiline_command(cmd) {
+ multiline_count++;
+ if (_ble_bash >= 40040) {
+ register_command(cmd);
+ } else {
+ gsub(/'$apos'/, Q, cmd);
+ write_complex(q cmd q);
+ }
+ }
+ function flush_entry() {
+ if (entry_nline < 1) return;
+ if (is_escaped_command(entry_text)) {
+ register_escaped_command(entry_text)
+ } else if (entry_nline > 1) {
+ register_multiline_command(entry_text);
+ } else {
+ register_command(entry_text);
+ }
+ entry_nline = 0;
+ entry_text = "";
+ }
+ function save_timestamp(line) {
+ if (is_resolve) {
+ if (line ~ /^ *[0-9]+\*? +__ble_time_[0-9]+__/) {
+ sub(/^ *[0-9]+\*? +__ble_time_/, "", line);
+ sub(/__.*$/, "", line);
+ entry_time = line;
+ }
+ } else {
+ if (line ~ /^#[0-9]/) {
+ sub(/^#/, "", line);
+ sub(/[^0-9].*$/, "", line);
+ entry_time = line;
+ }
+ }
+ }
+ {
+ if (is_resolve) {
+ save_timestamp($0);
+ if (sub(/^ *[0-9]+\*? +(__ble_time_[0-9]+__|\?\?)/, "", $0))
+ flush_entry();
+ entry_text = ++entry_nline == 1 ? $0 : entry_text "\n" $0;
+ } else {
+ if ($0 ~ /^#[0-9]/) {
+ save_timestamp($0);
+ next;
+ } else {
+ flush_entry();
+ entry_text = $0;
+ entry_nline = 1;
+ }
+ }
+ }
+ END {
+ flush_entry();
+ write_flush();
+ if (is_resolve)
+ print "builtin history -a /dev/null" > filename_source
+ print "multiline_count=" multiline_count;
+ print "modification_count=" modification_count;
+ }
+ '
+ }
+ function ble/history:bash/resolve-multiline/.cleanup {
+ local file
+ for file in "$TMPBASE".*; do : >| "$file"; done
+ }
+ function ble/history:bash/resolve-multiline/.worker {
+ local HISTTIMEFORMAT=__ble_time_%s__
+ local -x TMPBASE=$_ble_base_run/$$.history.mlfix
+ local multiline_count=0 modification_count=0
+ builtin eval -- "$(builtin history | ble/history:bash/resolve-multiline/.awk resolve 2>/dev/null)"
+ if ((modification_count)); then
+ ble/bin/mv -f "$TMPBASE.part" "$TMPBASE.sh"
+ else
+ ble/util/print : >| "$TMPBASE.sh"
+ fi
+ }
+ function ble/history:bash/resolve-multiline/.load {
+ local TMPBASE=$_ble_base_run/$$.history.mlfix
+ local HISTCONTROL= HISTSIZE= HISTIGNORE=
+ source "$TMPBASE.sh"
+ ble/history:bash/resolve-multiline/.cleanup
+ }
+ function ble/history:bash/resolve-multiline.impl {
+ local opts=$1
+ local opt_async=; [[ :$opts: == *:async:* ]] && opt_async=1
+ local history_tmpfile=$_ble_base_run/$$.history.mlfix.sh
+ [[ $opt_async || :$opts: == *:init:* ]] || _ble_history_mlfix_resume=0
+ [[ ! $opt_async ]] && ((_ble_history_mlfix_resume<=4)) &&
+ blehook/invoke history_message "resolving multiline history ..."
+ while :; do
+ case $_ble_history_mlfix_resume in
+ (0) if [[ $opt_async ]] && ble/builtin/history/is-empty; then
+ ble/util/idle.wait-user-input
+ ((_ble_history_mlfix_resume++))
+ return 147
+ fi
+ ((_ble_history_mlfix_resume++)) ;;
+ (1) # 履歴ファイル生成を Background で開始
+ if [[ $_ble_history_mlfix_bgpid ]]; then
+ builtin kill -9 "$_ble_history_mlfix_bgpid" &>/dev/null
+ _ble_history_mlfix_bgpid=
+ fi
+ : >| "$history_tmpfile"
+ if [[ $opt_async ]]; then
+ _ble_history_mlfix_bgpid=$(
+ shopt -u huponexit; ble/history:bash/resolve-multiline/.worker </dev/null &>/dev/null & ble/util/print $!)
+ function ble/history:bash/resolve-multiline/.worker-completed {
+ local history_tmpfile=$_ble_base_run/$$.history.mlfix.sh
+ [[ -s $history_tmpfile ]] || ! builtin kill -0 "$_ble_history_mlfix_bgpid"
+ } &>/dev/null
+ ((_ble_history_mlfix_resume++))
+ else
+ ble/history:bash/resolve-multiline/.worker
+ ((_ble_history_mlfix_resume+=3))
+ fi ;;
+ (2) if [[ $opt_async ]] && ble/util/is-running-in-idle; then
+ ble/util/idle.wait-condition ble/history:bash/resolve-multiline/.worker-completed
+ ((_ble_history_mlfix_resume++))
+ return 147
+ fi
+ ((_ble_history_mlfix_resume++)) ;;
+ (3) while ! ble/history:bash/resolve-multiline/.worker-completed; do
+ ble/util/msleep 50
+ [[ $opt_async ]] && ! ble/util/idle/IS_IDLE && return 148
+ done
+ ((_ble_history_mlfix_resume++)) ;;
+ (4) _ble_history_mlfix_bgpid=
+ ble/history:bash/resolve-multiline/.load
+ [[ $opt_async ]] || blehook/invoke history_message
+ ((_ble_history_mlfix_resume++))
+ return 0 ;;
+ (*) return 1 ;;
+ esac
+ [[ $opt_async ]] && ! ble/util/idle/IS_IDLE && return 148
+ done
+ }
+ function ble/history:bash/resolve-multiline {
+ [[ $_ble_history_mlfix_done ]] && return 0
+ if [[ $1 == sync ]]; then
+ ((_ble_bash>=40000)) && [[ $BASHPID != $$ ]] && return 0
+ ble/builtin/history/is-empty && return 0
+ fi
+ ble/history:bash/resolve-multiline.impl "$@"; local ext=$?
+ ((ext)) && return "$ext"
+ _ble_history_mlfix_done=1
+ return 0
+ }
+ ((_ble_bash>=40000)) &&
+ ble/util/idle.push 'ble/history:bash/resolve-multiline async'
+ blehook history_reset_background+=_ble_history_mlfix_resume=0
+ function ble/history:bash/resolve-multiline/readfile {
+ local filename=$1
+ local -x TMPBASE=$_ble_base_run/$$.history.read
+ ble/history:bash/resolve-multiline/.awk read < "$filename" &>/dev/null
+ source "$TMPBASE.part"
+ ble/history:bash/resolve-multiline/.cleanup
+ }
+fi
+function ble/history:bash/TRAPEXIT {
+ ble/util/is-running-in-subshell && return 0
+ if shopt -q histappend &>/dev/null; then
+ ble/builtin/history -a
+ else
+ ble/builtin/history -w
+ fi
+}
+blehook EXIT+=ble/history:bash/TRAPEXIT
+function ble/history:bash/reset {
+ if ((_ble_bash>=40000)); then
+ _ble_history_load_done=
+ ble/history:bash/clear-background-load
+ ble/util/idle.push 'ble/history:bash/initialize async'
+ elif ((_ble_bash>=30100)) && [[ $bleopt_history_lazyload ]]; then
+ _ble_history_load_done=
+ else
+ ble/history:bash/initialize
+ fi
+}
+function ble/builtin/history/.touch-histfile {
+ local touch=$_ble_base_run/$$.history.touch
+ : >| "$touch"
+}
+if [[ ! ${_ble_builtin_history_initialized+set} ]]; then
+ _ble_builtin_history_initialized=
+ _ble_builtin_history_histnew_count=0
+ _ble_builtin_history_histapp_count=0
+ _ble_builtin_history_wskip=0
+ _ble_builtin_history_prevmax=0
+ builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_builtin_history_rskip_dict}"
+ function ble/builtin/history/.get-rskip {
+ local file=$1 ret
+ ble/gdict#get _ble_builtin_history_rskip_dict "$file"
+ rskip=$ret
+ }
+ function ble/builtin/history/.set-rskip {
+ local file=$1
+ ble/gdict#set _ble_builtin_history_rskip_dict "$file" "$2"
+ }
+ function ble/builtin/history/.add-rskip {
+ local file=$1 ret
+ ble/gdict#get _ble_builtin_history_rskip_dict "$file"
+ ((ret+=$2))
+ ble/gdict#set _ble_builtin_history_rskip_dict "$file" "$ret"
+ }
+fi
+function ble/builtin/history/.initialize {
+ [[ $_ble_builtin_history_initialized ]] && return 0
+ local line; ble/util/assign line 'builtin history 1'
+ [[ ! $line && :$1: == *:skip0:* ]] && return 1
+ _ble_builtin_history_initialized=1
+ local histnew=$_ble_base_run/$$.history.new
+ : >| "$histnew"
+ if [[ $line ]]; then
+ local histini=$_ble_base_run/$$.history.ini
+ local histapp=$_ble_base_run/$$.history.app
+ HISTTIMEFORMAT=1 builtin history -a "$histini"
+ if [[ -s $histini ]]; then
+ ble/bin/sed '/^#\([0-9].*\)/{s// 0 __ble_time_\1__/;N;s/\n//;}' "$histini" >> "$histapp"
+ : >| "$histini"
+ fi
+ else
+ ble/builtin/history/option:r
+ fi
+ local histfile=${HISTFILE:-$HOME/.bash_history}
+ local rskip=$(ble/bin/wc -l "$histfile" 2>/dev/null)
+ ble/string#split-words rskip "$rskip"
+ local min; ble/builtin/history/.get-min
+ local max; ble/builtin/history/.get-max
+ ((max&&max-min+1<rskip&&(rskip=max-min+1)))
+ _ble_builtin_history_wskip=$max
+ _ble_builtin_history_prevmax=$max
+ ble/builtin/history/.set-rskip "$histfile" "$rskip"
+ return 0
+}
+function ble/builtin/history/.delete-range {
+ local beg=$1 end=${2:-$1}
+ if ((_ble_bash>=50000&&beg<end)); then
+ builtin history -d "$beg-$end"
+ else
+ local i
+ for ((i=end;i>=beg;i--)); do
+ builtin history -d "$i"
+ done
+ fi
+}
+function ble/builtin/history/.check-uncontrolled-change {
+ [[ $_ble_decode_bind_state == none ]] && return 0
+ local filename=${1-} opts=${2-} prevmax=$_ble_builtin_history_prevmax
+ local max; ble/builtin/history/.get-max
+ if ((max!=prevmax)); then
+ if [[ $filename && :$opts: == *:append:* ]] && ((_ble_builtin_history_wskip<prevmax&&prevmax<max)); then
+ (
+ ble/builtin/history/.delete-range $((prevmax+1)) "$max"
+ ble/builtin/history/.write "$filename" "$_ble_builtin_history_wskip" append:fetch
+ )
+ fi
+ _ble_builtin_history_wskip=$max
+ _ble_builtin_history_prevmax=$max
+ fi
+}
+function ble/builtin/history/.load-recent-entries {
+ [[ $_ble_decode_bind_state == none ]] && return 0
+ local delta=$1
+ ((delta>0)) || return 0
+ if [[ ! $_ble_history_load_done ]]; then
+ ble/history:bash/clear-background-load
+ _ble_history_count=
+ return 0
+ fi
+ if ((_ble_bash>=40000&&delta>=10000)); then
+ ble/history:bash/reset
+ return 0
+ fi
+ ble/history:bash/load append:count=$delta
+ local ocount=$_ble_history_count ncount=${#_ble_history[@]}
+ ((_ble_history_index==_ble_history_count)) && _ble_history_index=$ncount
+ _ble_history_count=$ncount
+ ble/history/.update-position
+ blehook/invoke history_insert "$ocount" "$delta"
+}
+function ble/builtin/history/.read {
+ local file=$1 skip=${2:-0} fetch=$3
+ local -x histnew=$_ble_base_run/$$.history.new
+ if [[ -s $file ]]; then
+ local script=$(ble/bin/awk -v skip=$skip '
+ BEGIN { histnew = ENVIRON["histnew"]; count = 0; }
+ NR <= skip { next; }
+ { print $0 >> histnew; count++; }
+ END {
+ print "ble/builtin/history/.set-rskip \"$file\" " NR;
+ print "((_ble_builtin_history_histnew_count+=" count "))";
+ }
+ ' "$file")
+ builtin eval -- "$script"
+ else
+ ble/builtin/history/.set-rskip "$file" 0
+ fi
+ if [[ ! $fetch && -s $histnew ]]; then
+ local nline=$_ble_builtin_history_histnew_count
+ ble/history:bash/resolve-multiline/readfile "$histnew"
+ : >| "$histnew"
+ _ble_builtin_history_histnew_count=0
+ ble/builtin/history/.load-recent-entries "$nline"
+ local max; ble/builtin/history/.get-max
+ _ble_builtin_history_wskip=$max
+ _ble_builtin_history_prevmax=$max
+ fi
+}
+function ble/builtin/history/.write {
+ local -x file=$1 skip=${2:-0} opts=$3
+ local -x histapp=$_ble_base_run/$$.history.app
+ declare -p HISTTIMEFORMAT &>/dev/null
+ local -x flag_timestamp=$(($?==0))
+ local min; ble/builtin/history/.get-min
+ local max; ble/builtin/history/.get-max
+ ((skip<min-1&&(skip=min-1)))
+ local delta=$((max-skip))
+ if ((delta>0)); then
+ local HISTTIMEFORMAT=__ble_time_%s__
+ if [[ :$opts: == *:append:* ]]; then
+ builtin history "$delta" >> "$histapp"
+ ((_ble_builtin_history_histapp_count+=delta))
+ else
+ builtin history "$delta" >| "$histapp"
+ _ble_builtin_history_histapp_count=$delta
+ fi
+ fi
+ if [[ :$opts: != *:fetch:* && -s $histapp ]]; then
+ if [[ ! -e $file ]]; then
+ (umask 077; : >| "$file")
+ elif [[ :$opts: != *:append:* ]]; then
+ : >| "$file"
+ fi
+ local apos=\'
+ < "$histapp" ble/bin/awk '
+ BEGIN {
+ file = ENVIRON["file"];
+ flag_timestamp = ENVIRON["flag_timestamp"];
+ timestamp = "";
+ mode = 0;
+ }
+ function flush_line() {
+ if (!mode) return;
+ mode = 0;
+ if (text ~ /\n/) {
+ gsub(/['$apos'\\]/, "\\\\&", text);
+ gsub(/\n/, "\\n", text);
+ gsub(/\t/, "\\t", text);
+ text = "eval -- $'$apos'" text "'$apos'"
+ }
+ if (timestamp != "")
+ print timestamp >> file;
+ print text >> file;
+ }
+ function extract_timestamp(line) {
+ if (!sub(/^ *[0-9]+\*? +__ble_time_/, "", line)) return "";
+ if (!sub(/__.*$/, "", line)) return "";
+ if (!(line ~ /^[0-9]+$/)) return "";
+ return "#" line;
+ }
+ /^ *[0-9]+\*? +(__ble_time_[0-9]+__|\?\?)?/ {
+ flush_line();
+ mode = 1;
+ text = "";
+ if (flag_timestamp)
+ timestamp = extract_timestamp($0);
+ sub(/^ *[0-9]+\*? +(__ble_time_[0-9]+__|\?\?)?/, "", $0);
+ }
+ { text = text != "" ? text "\n" $0 : $0; }
+ END { flush_line(); }
+ '
+ ble/builtin/history/.add-rskip "$file" "$_ble_builtin_history_histapp_count"
+ : >| "$histapp"
+ _ble_builtin_history_histapp_count=0
+ fi
+ _ble_builtin_history_wskip=$max
+ _ble_builtin_history_prevmax=$max
+}
+function ble/builtin/history/array#delete-hindex {
+ local array_name=$1; shift
+ local script='
+ local -a out=()
+ local i shift=0
+ for i in "${!ARR[@]}"; do
+ local delete=
+ while (($#)); do
+ if [[ $1 == *-* ]]; then
+ local b=${1%-*} e=${1#*-}
+ ((i<b)) && break
+ if ((i<e)); then
+ delete=1 # delete
+ break
+ else
+ ((shift+=e-b))
+ shift
+ fi
+ else
+ ((i<$1)) && break
+ ((i==$1)) && delete=1
+ ((shift++))
+ shift
+ fi
+ done
+ [[ ! $delete ]] &&
+ out[i-shift]=${ARR[i]}
+ done
+ ARR=()
+ for i in "${!out[@]}"; do ARR[i]=${out[i]}; done'
+ builtin eval -- "${script//ARR/$array_name}"
+}
+function ble/builtin/history/array#insert-range {
+ local array_name=$1 beg=$2 len=$3
+ local script='
+ local -a out=()
+ local i
+ for i in "${!ARR[@]}"; do
+ out[i<beg?beg:i+len]=${ARR[i]}
+ done
+ ARR=()
+ for i in "${!out[@]}"; do ARR[i]=${out[i]}; done'
+ builtin eval -- "${script//ARR/$array_name}"
+}
+blehook history_delete+=ble/builtin/history/delete.hook
+blehook history_clear+=ble/builtin/history/clear.hook
+blehook history_insert+=ble/builtin/history/insert.hook
+function ble/builtin/history/delete.hook {
+ ble/builtin/history/array#delete-hindex _ble_history_dirt "$@"
+}
+function ble/builtin/history/clear.hook {
+ _ble_history_dirt=()
+}
+function ble/builtin/history/insert.hook {
+ ble/builtin/history/array#insert-range _ble_history_dirt "$@"
+}
+function ble/builtin/history/option:c {
+ ble/builtin/history/.initialize skip0 || return "$?"
+ builtin history -c
+ _ble_builtin_history_wskip=0
+ _ble_builtin_history_prevmax=0
+ if [[ $_ble_decode_bind_state != none ]]; then
+ if [[ $_ble_history_load_done ]]; then
+ _ble_history=()
+ _ble_history_edit=()
+ _ble_history_count=0
+ _ble_history_index=0
+ else
+ ble/history:bash/clear-background-load
+ _ble_history_count=
+ fi
+ ble/history/.update-position
+ blehook/invoke history_clear
+ fi
+}
+function ble/builtin/history/option:d {
+ ble/builtin/history/.initialize skip0 || return "$?"
+ local rex='^(-?[0-9]+)-(-?[0-9]+)$'
+ if [[ $1 =~ $rex ]]; then
+ local beg=${BASH_REMATCH[1]} end=${BASH_REMATCH[2]}
+ else
+ local beg=$(($1))
+ local end=$beg
+ fi
+ local min; ble/builtin/history/.get-min
+ local max; ble/builtin/history/.get-max
+ ((beg<0)) && ((beg+=max+1)); ((beg<min?(beg=min):(beg>max&&(beg=max))))
+ ((end<0)) && ((end+=max+1)); ((end<min?(end=min):(end>max&&(end=max))))
+ ((beg<=end)) || return 0
+ ble/builtin/history/.delete-range "$beg" "$end"
+ if ((_ble_builtin_history_wskip>=end)); then
+ ((_ble_builtin_history_wskip-=end-beg+1))
+ elif ((_ble_builtin_history_wskip>beg-1)); then
+ ((_ble_builtin_history_wskip=beg-1))
+ fi
+ if [[ $_ble_decode_bind_state != none ]]; then
+ if [[ $_ble_history_load_done ]]; then
+ local N=${#_ble_history[@]}
+ local b=$((beg-1+N-max)) e=$((end+N-max))
+ blehook/invoke history_delete "$b-$e"
+ if ((_ble_history_index>=e)); then
+ ((_ble_history_index-=e-b))
+ elif ((_ble_history_index>=b)); then
+ _ble_history_index=$b
+ fi
+ _ble_history=("${_ble_history[@]::b}" "${_ble_history[@]:e}")
+ _ble_history_edit=("${_ble_history_edit[@]::b}" "${_ble_history_edit[@]:e}")
+ _ble_history_count=${#_ble_history[@]}
+ else
+ ble/history:bash/clear-background-load
+ _ble_history_count=
+ fi
+ ble/history/.update-position
+ fi
+ local max; ble/builtin/history/.get-max
+ _ble_builtin_history_prevmax=$max
+}
+function ble/builtin/history/option:a {
+ ble/builtin/history/.initialize skip0 || return "$?"
+ local histfile=${HISTFILE:-$HOME/.bash_history}
+ local filename=${1:-$histfile}
+ ble/builtin/history/.check-uncontrolled-change "$filename" append
+ local rskip; ble/builtin/history/.get-rskip "$filename"
+ ble/builtin/history/.write "$filename" "$_ble_builtin_history_wskip" append:fetch
+ [[ -r $filename ]] && ble/builtin/history/.read "$filename" "$rskip" fetch
+ ble/builtin/history/.write "$filename" "$_ble_builtin_history_wskip" append
+ builtin history -a /dev/null # Bash 終了時に書き込まない
+}
+function ble/builtin/history/option:n {
+ local histfile=${HISTFILE:-$HOME/.bash_history}
+ local filename=${1:-$histfile}
+ if [[ $filename == $histfile ]]; then
+ local touch=$_ble_base_run/$$.history.touch
+ [[ $touch -nt $histfile ]] && return 0
+ : >| "$touch"
+ fi
+ ble/builtin/history/.initialize
+ local rskip; ble/builtin/history/.get-rskip "$filename"
+ ble/builtin/history/.read "$filename" "$rskip"
+}
+function ble/builtin/history/option:w {
+ ble/builtin/history/.initialize skip0 || return "$?"
+ local histfile=${HISTFILE:-$HOME/.bash_history}
+ local filename=${1:-$histfile}
+ local rskip; ble/builtin/history/.get-rskip "$filename"
+ [[ -r $filename ]] && ble/builtin/history/.read "$filename" "$rskip" fetch
+ ble/builtin/history/.write "$filename" 0
+ builtin history -a /dev/null # Bash 終了時に書き込まない
+}
+function ble/builtin/history/option:r {
+ local histfile=${HISTFILE:-$HOME/.bash_history}
+ local filename=${1:-$histfile}
+ ble/builtin/history/.initialize
+ ble/builtin/history/.read "$filename" 0
+}
+function ble/builtin/history/option:p {
+ ((_ble_bash>=40000)) || ble/builtin/history/is-empty ||
+ ble/history:bash/resolve-multiline sync
+ local line1= line2=
+ ble/util/assign line1 'HISTTIMEFORMAT= builtin history 1'
+ builtin history -p -- '' &>/dev/null
+ ble/util/assign line2 'HISTTIMEFORMAT= builtin history 1'
+ if [[ $line1 != "$line2" ]]; then
+ local rex_head='^[[:space:]]*[0-9]+[[:space:]]*'
+ [[ $line1 =~ $rex_head ]] &&
+ line1=${line1:${#BASH_REMATCH}}
+ if ((_ble_bash<30100)); then
+ local tmp=$_ble_base_run/$$.history.tmp
+ printf '%s\n' "$line1" "$line1" >| "$tmp"
+ builtin history -r "$tmp"
+ else
+ builtin history -s -- "$line1"
+ builtin history -s -- "$line1"
+ fi
+ fi
+ builtin history -p -- "$@"
+}
+function ble/builtin/history/option:s {
+ ble/builtin/history/.initialize
+ if [[ $_ble_decode_bind_state == none ]]; then
+ builtin history -s -- "$@"
+ return 0
+ fi
+ local cmd=$1
+ if [[ $HISTIGNORE ]]; then
+ local pats pat
+ ble/string#split pats : "$HISTIGNORE"
+ for pat in "${pats[@]}"; do
+ [[ $cmd == $pat ]] && return 0
+ done
+ fi
+ local histfile=
+ if [[ $_ble_history_load_done ]]; then
+ if [[ $HISTCONTROL ]]; then
+ local ignorespace ignoredups erasedups spec
+ for spec in ${HISTCONTROL//:/ }; do
+ case "$spec" in
+ (ignorespace) ignorespace=1 ;;
+ (ignoredups) ignoredups=1 ;;
+ (ignoreboth) ignorespace=1 ignoredups=1 ;;
+ (erasedups) erasedups=1 ;;
+ esac
+ done
+ if [[ $ignorespace ]]; then
+ [[ $cmd == [' ']* ]] && return 0
+ fi
+ if [[ $ignoredups ]]; then
+ local lastIndex=$((${#_ble_history[@]}-1))
+ ((lastIndex>=0)) && [[ $cmd == "${_ble_history[lastIndex]}" ]] && return 0
+ fi
+ if [[ $erasedups ]]; then
+ local -a delete_indices=()
+ local shift_histindex_next=0
+ local shift_wskip=0
+ local i N=${#_ble_history[@]}
+ for ((i=0;i<N-1;i++)); do
+ if [[ ${_ble_history[i]} == "$cmd" ]]; then
+ builtin unset -v '_ble_history[i]'
+ builtin unset -v '_ble_history_edit[i]'
+ ble/array#push delete_indices "$i"
+ ((i<_ble_builtin_history_wskip&&shift_wskip++))
+ ((i<HISTINDEX_NEXT&&shift_histindex_next++))
+ fi
+ done
+ if ((${#delete_indices[@]})); then
+ _ble_history=("${_ble_history[@]}")
+ _ble_history_edit=("${_ble_history_edit[@]}")
+ blehook/invoke history_delete "${delete_indices[@]}"
+ ((_ble_builtin_history_wskip-=shift_wskip))
+ [[ ${HISTINDEX_NEXT+set} ]] && ((HISTINDEX_NEXT-=shift_histindex_next))
+ fi
+ ((N)) && [[ ${_ble_history[N-1]} == "$cmd" ]] && return 0
+ fi
+ fi
+ local topIndex=${#_ble_history[@]}
+ _ble_history[topIndex]=$cmd
+ _ble_history_edit[topIndex]=$cmd
+ _ble_history_count=$((topIndex+1))
+ _ble_history_index=$_ble_history_count
+ ((_ble_bash<30100)) && histfile=${HISTFILE:-$HOME/.bash_history}
+ else
+ if [[ $HISTCONTROL ]]; then
+ _ble_history_count=
+ else
+ [[ $_ble_history_count ]] &&
+ ((_ble_history_count++))
+ fi
+ fi
+ ble/history/.update-position
+ if [[ $histfile ]]; then
+ if [[ $cmd == *$'\n'* ]]; then
+ ble/util/sprintf cmd 'eval -- %q' "$cmd"
+ fi
+ local tmp=$_ble_base_run/$$.history.tmp
+ [[ $bleopt_history_share ]] ||
+ ble/util/print "$cmd" >> "$histfile"
+ ble/util/print "$cmd" >| "$tmp"
+ builtin history -r "$tmp"
+ else
+ ble/history:bash/clear-background-load
+ builtin history -s -- "$cmd"
+ fi
+ local max; ble/builtin/history/.get-max
+ _ble_builtin_history_prevmax=$max
+}
+function ble/builtin/history {
+ local set shopt; ble/base/.adjust-bash-options set shopt
+ local opt_d= flag_error=
+ local opt_c= opt_p= opt_s=
+ local opt_a= flags=
+ while [[ $1 == -* ]]; do
+ local arg=$1; shift
+ [[ $arg == -- ]] && break
+ if [[ $arg == --help ]]; then
+ flags=h$flags
+ continue
+ fi
+ local i n=${#arg}
+ for ((i=1;i<n;i++)); do
+ local c=${arg:i:1}
+ case $c in
+ (c) opt_c=1 ;;
+ (s) opt_s=1 ;;
+ (p) opt_p=1 ;;
+ (d)
+ if ((!$#)); then
+ ble/util/print 'ble/builtin/history: missing option argument for "-d".' >&2
+ flag_error=1
+ elif ((i+1<n)); then
+ opt_d=${arg:i+1}; i=$n
+ else
+ opt_d=$1; shift
+ fi ;;
+ ([anwr])
+ if [[ $opt_a && $c != $opt_a ]]; then
+ ble/util/print 'ble/builtin/history: cannot use more than one of "-anrw".' >&2
+ flag_error=1
+ elif ((i+1<n)); then
+ opt_a=$c
+ set -- "${arg:i+1}" "$@"
+ else
+ opt_a=$c
+ fi ;;
+ (*)
+ ble/util/print "ble/builtin/history: unknown option \"-$c\"." >&2
+ flag_error=1 ;;
+ esac
+ done
+ done
+ if [[ $flag_error ]]; then
+ builtin history --usage 2>&1 1>/dev/null | ble/bin/grep ^history >&2
+ ble/base/.restore-bash-options set shopt
+ return 2
+ fi
+ if [[ $flags == *h* ]]; then
+ builtin history --help
+ local ext=$?
+ ble/base/.restore-bash-options set shopt
+ return "$ext"
+ fi
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/adjust-BASH_REMATCH
+ local flag_processed=
+ if [[ $opt_c ]]; then
+ ble/builtin/history/option:c
+ flag_processed=1
+ fi
+ if [[ $opt_s ]]; then
+ local IFS=$_ble_term_IFS
+ ble/builtin/history/option:s "$*"
+ flag_processed=1
+ elif [[ $opt_d ]]; then
+ ble/builtin/history/option:d "$opt_d"
+ flag_processed=1
+ elif [[ $opt_a ]]; then
+ ble/builtin/history/option:"$opt_a" "$1"
+ flag_processed=1
+ fi
+ if [[ $flag_processed ]]; then
+ ble/base/.restore-bash-options set shopt
+ return 0
+ fi
+ if [[ $opt_p ]]; then
+ ble/builtin/history/option:p "$@"
+ else
+ builtin history "$@"
+ fi; local ext=$?
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/restore-BASH_REMATCH
+ ble/base/.restore-bash-options set shopt
+ return "$ext"
+}
+function history { ble/builtin/history "$@"; }
+_ble_history_prefix=
+function ble/history/set-prefix {
+ _ble_history_prefix=$1
+ ble/history/.update-position
+}
+_ble_history_COUNT=
+_ble_history_INDEX=
+function ble/history/.update-position {
+ if [[ $_ble_history_prefix ]]; then
+ builtin eval -- "_ble_history_COUNT=\${#${_ble_history_prefix}_history[@]}"
+ ((_ble_history_INDEX=${_ble_history_prefix}_history_index))
+ else
+ if [[ ! $_ble_history_load_done ]]; then
+ if [[ ! $_ble_history_count ]]; then
+ local min max
+ ble/builtin/history/.get-min
+ ble/builtin/history/.get-max
+ ((_ble_history_count=max-min+1))
+ fi
+ _ble_history_index=$_ble_history_count
+ fi
+ _ble_history_COUNT=$_ble_history_count
+ _ble_history_INDEX=$_ble_history_index
+ fi
+}
+function ble/history/update-position {
+ [[ $_ble_history_prefix$_ble_history_load_done ]] ||
+ ble/history/.update-position
+}
+function ble/history/onleave.fire {
+ blehook/invoke history_onleave "$@"
+}
+function ble/history/initialize {
+ [[ ! $_ble_history_prefix ]] &&
+ ble/history:bash/initialize
+}
+function ble/history/get-count {
+ local _var=count _ret
+ [[ $1 == -v ]] && { _var=$2; shift 2; }
+ ble/history/.update-position
+ (($_var=_ble_history_COUNT))
+}
+function ble/history/get-index {
+ local _var=index
+ [[ $1 == -v ]] && { _var=$2; shift 2; }
+ ble/history/.update-position
+ (($_var=_ble_history_INDEX))
+}
+function ble/history/set-index {
+ _ble_history_INDEX=$1
+ ((${_ble_history_prefix:-_ble}_history_index=_ble_history_INDEX))
+}
+function ble/history/get-entry {
+ local __var=entry
+ [[ $1 == -v ]] && { __var=$2; shift 2; }
+ if [[ $_ble_history_prefix$_ble_history_load_done ]]; then
+ builtin eval -- "$__var=\${${_ble_history_prefix:-_ble}_history[\$1]}"
+ else
+ builtin eval -- "$__var="
+ fi
+}
+function ble/history/get-edited-entry {
+ local __var=entry
+ [[ $1 == -v ]] && { __var=$2; shift 2; }
+ if [[ $_ble_history_prefix$_ble_history_load_done ]]; then
+ builtin eval -- "$__var=\${${_ble_history_prefix:-_ble}_history_edit[\$1]}"
+ else
+ builtin eval -- "$__var=\$_ble_edit_str"
+ fi
+}
+function ble/history/set-edited-entry {
+ ble/history/initialize
+ local index=$1 str=$2
+ local code='
+ if [[ ! ${PREFIX_history_edit[index]+set} || ${PREFIX_history_edit[index]} != "$str" ]]; then
+ PREFIX_history_edit[index]=$str
+ PREFIX_history_dirt[index]=1
+ fi'
+ builtin eval -- "${code//PREFIX/${_ble_history_prefix:-_ble}}"
+}
+function ble/history/.add-command-history {
+ [[ -o history ]] || ((_ble_bash<30200)) || return 1
+ [[ $MC_SID == $$ && $LINENO -le 2 && ( $1 == *PROMPT_COMMAND=* || $1 == *PS1=* ) ]] && return 1
+ if [[ $_ble_history_load_done ]]; then
+ _ble_history_index=${#_ble_history[@]}
+ ble/history/.update-position
+ local index
+ for index in "${!_ble_history_dirt[@]}"; do
+ _ble_history_edit[index]=${_ble_history[index]}
+ done
+ _ble_history_dirt=()
+ ble-edit/undo/clear-all
+ fi
+ if [[ $bleopt_history_share ]]; then
+ ble/builtin/history/option:n
+ ble/builtin/history/option:s "$1"
+ ble/builtin/history/option:a
+ ble/builtin/history/.touch-histfile
+ else
+ ble/builtin/history/option:s "$1"
+ fi
+}
+function ble/history/add {
+ local command=$1
+ ((bleopt_history_limit_length>0&&${#command}>bleopt_history_limit_length)) && return 1
+ if [[ $_ble_history_prefix ]]; then
+ local code='
+ local index
+ for index in "${!PREFIX_history_dirt[@]}"; do
+ PREFIX_history_edit[index]=${PREFIX_history[index]}
+ done
+ PREFIX_history_dirt=()
+ local topIndex=${#PREFIX_history[@]}
+ PREFIX_history[topIndex]=$command
+ PREFIX_history_edit[topIndex]=$command
+ PREFIX_history_index=$((++topIndex))
+ _ble_history_COUNT=$topIndex
+ _ble_history_INDEX=$topIndex'
+ builtin eval -- "${code//PREFIX/$_ble_history_prefix}"
+ else
+ blehook/invoke ADDHISTORY "$command" &&
+ ble/history/.add-command-history "$command"
+ fi
+}
+function ble/history/.read-isearch-options {
+ local opts=$1
+ search_type=fixed
+ case :$opts: in
+ (*:regex:*) search_type=regex ;;
+ (*:glob:*) search_type=glob ;;
+ (*:head:*) search_type=head ;;
+ (*:tail:*) search_type=tail ;;
+ (*:condition:*) search_type=condition ;;
+ (*:predicate:*) search_type=predicate ;;
+ esac
+ [[ :$opts: != *:stop_check:* ]]; has_stop_check=$?
+ [[ :$opts: != *:progress:* ]]; has_progress=$?
+ [[ :$opts: != *:backward:* ]]; has_backward=$?
+}
+function ble/history/isearch-backward-blockwise {
+ local opts=$1
+ local search_type has_stop_check has_progress has_backward
+ ble/history/.read-isearch-options "$opts"
+ ble/history/initialize
+ if [[ $_ble_history_prefix ]]; then
+ local -a _ble_history_edit
+ builtin eval "_ble_history_edit=(\"\${${_ble_history_prefix}_history_edit[@]}\")"
+ fi
+ local NSTPCHK=1000 # 十分高速なのでこれぐらい大きくてOK
+ local NPROGRESS=$((NSTPCHK*2)) # 倍数である必要有り
+ local irest block j i=$index
+ index=
+ local flag_cycled= range_min range_max
+ while :; do
+ if ((i<=start)); then
+ range_min=0 range_max=$start
+ else
+ flag_cycled=1
+ range_min=$((start+1)) range_max=$i
+ fi
+ while ((i>=range_min)); do
+ ((block=range_max-i,
+ block<5&&(block=5),
+ block>i+1-range_min&&(block=i+1-range_min),
+ irest=NSTPCHK-isearch_time%NSTPCHK,
+ block>irest&&(block=irest)))
+ case $search_type in
+ (regex) for ((j=i-block;++j<=i;)); do
+ [[ ${_ble_history_edit[j]} =~ $needle ]] && index=$j
+ done ;;
+ (glob) for ((j=i-block;++j<=i;)); do
+ [[ ${_ble_history_edit[j]} == $needle ]] && index=$j
+ done ;;
+ (head) for ((j=i-block;++j<=i;)); do
+ [[ ${_ble_history_edit[j]} == "$needle"* ]] && index=$j
+ done ;;
+ (tail) for ((j=i-block;++j<=i;)); do
+ [[ ${_ble_history_edit[j]} == *"$needle" ]] && index=$j
+ done ;;
+ (condition) builtin eval "function ble-edit/isearch/.search-block.proc {
+ local LINE INDEX
+ for ((j=i-block;++j<=i;)); do
+ LINE=\${_ble_history_edit[j]} INDEX=\$j
+ { $needle; } && index=\$j
+ done
+ }"
+ ble-edit/isearch/.search-block.proc ;;
+ (predicate) for ((j=i-block;++j<=i;)); do
+ "$needle" "${_ble_history_edit[j]}" "$j" && index=$j
+ done ;;
+ (*) for ((j=i-block;++j<=i;)); do
+ [[ ${_ble_history_edit[j]} == *"$needle"* ]] && index=$j
+ done ;;
+ esac
+ ((isearch_time+=block))
+ [[ $index ]] && return 0
+ ((i-=block))
+ if ((has_stop_check&&isearch_time%NSTPCHK==0)) && ble/decode/has-input; then
+ index=$i
+ return 148
+ elif ((has_progress&&isearch_time%NPROGRESS==0)); then
+ "$isearch_progress_callback" "$i"
+ fi
+ done
+ if [[ ! $flag_cycled && :$opts: == *:cyclic:* ]]; then
+ ((i=${#_ble_history_edit[@]}-1))
+ ((start<i)) || return 1
+ else
+ return 1
+ fi
+ done
+}
+function ble/history/forward-isearch.impl {
+ local opts=$1
+ local search_type has_stop_check has_progress has_backward
+ ble/history/.read-isearch-options "$opts"
+ ble/history/initialize
+ if [[ $_ble_history_prefix ]]; then
+ local -a _ble_history_edit
+ builtin eval "_ble_history_edit=(\"\${${_ble_history_prefix}_history_edit[@]}\")"
+ fi
+ while :; do
+ local flag_cycled= expr_cond expr_incr
+ if ((has_backward)); then
+ if ((index<=start)); then
+ expr_cond='index>=0' expr_incr='index--'
+ else
+ expr_cond='index>start' expr_incr='index--' flag_cycled=1
+ fi
+ else
+ if ((index>=start)); then
+ expr_cond="index<${#_ble_history_edit[@]}" expr_incr='index++'
+ else
+ expr_cond="index<start" expr_incr='index++' flag_cycled=1
+ fi
+ fi
+ case $search_type in
+ (regex)
+ for ((;expr_cond;expr_incr)); do
+ ((isearch_time++,has_stop_check&&isearch_time%100==0)) &&
+ ble/decode/has-input && return 148
+ [[ ${_ble_history_edit[index]} =~ $needle ]] && return 0
+ ((has_progress&&isearch_time%1000==0)) &&
+ "$isearch_progress_callback" "$index"
+ done ;;
+ (glob)
+ for ((;expr_cond;expr_incr)); do
+ ((isearch_time++,has_stop_check&&isearch_time%100==0)) &&
+ ble/decode/has-input && return 148
+ [[ ${_ble_history_edit[index]} == $needle ]] && return 0
+ ((has_progress&&isearch_time%1000==0)) &&
+ "$isearch_progress_callback" "$index"
+ done ;;
+ (head)
+ for ((;expr_cond;expr_incr)); do
+ ((isearch_time++,has_stop_check&&isearch_time%100==0)) &&
+ ble/decode/has-input && return 148
+ [[ ${_ble_history_edit[index]} == "$needle"* ]] && return 0
+ ((has_progress&&isearch_time%1000==0)) &&
+ "$isearch_progress_callback" "$index"
+ done ;;
+ (tail)
+ for ((;expr_cond;expr_incr)); do
+ ((isearch_time++,has_stop_check&&isearch_time%100==0)) &&
+ ble/decode/has-input && return 148
+ [[ ${_ble_history_edit[index]} == *"$needle" ]] && return 0
+ ((has_progress&&isearch_time%1000==0)) &&
+ "$isearch_progress_callback" "$index"
+ done ;;
+ (condition)
+ for ((;expr_cond;expr_incr)); do
+ ((isearch_time++,has_stop_check&&isearch_time%100==0)) &&
+ ble/decode/has-input && return 148
+ LINE=${_ble_history_edit[index]} INDEX=$index builtin eval -- "$needle" && return 0
+ ((has_progress&&isearch_time%1000==0)) &&
+ "$isearch_progress_callback" "$index"
+ done ;;
+ (predicate)
+ for ((;expr_cond;expr_incr)); do
+ ((isearch_time++,has_stop_check&&isearch_time%100==0)) &&
+ ble/decode/has-input && return 148
+ "$needle" "${_ble_history_edit[index]}" "$index" && return 0
+ ((has_progress&&isearch_time%1000==0)) &&
+ "$isearch_progress_callback" "$index"
+ done ;;
+ (*)
+ for ((;expr_cond;expr_incr)); do
+ ((isearch_time++,has_stop_check&&isearch_time%100==0)) &&
+ ble/decode/has-input && return 148
+ [[ ${_ble_history_edit[index]} == *"$needle"* ]] && return 0
+ ((has_progress&&isearch_time%1000==0)) &&
+ "$isearch_progress_callback" "$index"
+ done ;;
+ esac
+ if [[ ! $flag_cycled && :$opts: == *:cyclic:* ]]; then
+ if ((has_backward)); then
+ ((index=${#_ble_history_edit[@]}-1))
+ ((index>start)) || return 1
+ else
+ ((index=0))
+ ((index<start)) || return 1
+ fi
+ else
+ return 1
+ fi
+ done
+}
+function ble/history/isearch-forward {
+ ble/history/forward-isearch.impl "$1"
+}
+function ble/history/isearch-backward {
+ ble/history/forward-isearch.impl "$1:backward"
+}
+bleopt/declare -v edit_vbell ''
+bleopt/declare -v edit_abell 1
+bleopt/declare -v history_lazyload 1
+bleopt/declare -v delete_selection_mode 1
+bleopt/declare -n indent_offset 4
+bleopt/declare -n indent_tabs 1
+bleopt/declare -v undo_point end
+bleopt/declare -n edit_forced_textmap 1
+function ble/edit/use-textmap {
+ ble/textmap#is-up-to-date && return 0
+ ((bleopt_edit_forced_textmap)) || return 1
+ ble/widget/.update-textmap
+ return 0
+}
+bleopt/declare -n edit_line_type logical
+function bleopt/check:edit_line_type {
+ if [[ $value != logical && $value != graphical ]]; then
+ ble/util/print "bleopt edit_line_type: Unexpected value '$value'. 'logical' or 'graphical' is expected." >&2
+ return 1
+ fi
+}
+function ble/edit/performs-on-graphical-line {
+ [[ $edit_line_type == graphical ]] || return 1
+ ble/textmap#is-up-to-date && return 0
+ ((bleopt_edit_forced_textmap)) || return 1
+ ble/widget/.update-textmap
+ return 0
+}
+bleopt/declare -n info_display top
+function bleopt/check:info_display {
+ case $value in
+ (top)
+ [[ $_ble_canvas_panel_vfill == 3 ]] && return 0
+ _ble_canvas_panel_vfill=3
+ [[ $_ble_attached ]] && ble/canvas/panel/clear
+ return 0 ;;
+ (bottom)
+ [[ $_ble_canvas_panel_vfill == 2 ]] && return 0
+ _ble_canvas_panel_vfill=2
+ [[ $_ble_attached ]] && ble/canvas/panel/clear
+ return 0 ;;
+ (*)
+ ble/util/print "bleopt: Invalid value for 'info_display': $value"
+ return 1 ;;
+ esac
+}
+bleopt/declare -v prompt_ps1_final ''
+bleopt/declare -v prompt_ps1_transient ''
+bleopt/declare -v prompt_rps1 ''
+bleopt/declare -v prompt_rps1_final ''
+bleopt/declare -v prompt_rps1_transient ''
+bleopt/declare -v prompt_xterm_title ''
+bleopt/declare -v prompt_screen_title ''
+bleopt/declare -v prompt_term_status ''
+bleopt/declare -o rps1 prompt_rps1
+bleopt/declare -o rps1_transient prompt_rps1_transient
+bleopt/declare -v prompt_eol_mark $'\e[94m[ble: EOF]\e[m'
+bleopt/declare -v prompt_ruler ''
+bleopt/declare -v prompt_status_line ''
+bleopt/declare -n prompt_status_align $'justify=\r'
+ble/color/defface prompt_status_line fg=231,bg=240
+bleopt/declare -v prompt_command_changes_layout ''
+function bleopt/check:prompt_status_align {
+ case $value in
+ (left|right|center|justify|justify=?*)
+ ble/prompt/unit#clear _ble_prompt_status hash
+ return 0 ;;
+ (*)
+ ble/util/print "bleopt prompt_status_align: unsupported value: '$value'" >&2
+ return 1 ;;
+ esac
+}
+bleopt/declare -n internal_exec_type gexec
+function bleopt/check:internal_exec_type {
+ if ! ble/is-function "ble-edit/exec:$value/process"; then
+ ble/util/print "bleopt: Invalid value internal_exec_type='$value'. A function 'ble-edit/exec:$value/process' is not defined." >&2
+ return 1
+ fi
+}
+bleopt/declare -v internal_suppress_bash_output 1
+bleopt/declare -n internal_ignoreeof_trap 'Use "exit" to leave the shell.'
+bleopt/declare -v allow_exit_with_jobs ''
+bleopt/declare -v history_share ''
+bleopt/declare -v accept_line_threshold 5
+bleopt/declare -v exec_errexit_mark $'\e[91m[ble: exit %d]\e[m'
+bleopt/declare -v exec_elapsed_mark $'\e[94m[ble: elapsed %s (CPU %s%%)]\e[m'
+bleopt/declare -v exec_elapsed_enabled 'usr+sys>=10000'
+bleopt/declare -v line_limit_length 10000
+bleopt/declare -v line_limit_type none
+_ble_app_render_mode=panel
+_ble_app_winsize=()
+_ble_app_render_Processing=
+function ble/application/.set-up-render-mode {
+ [[ $1 == "$_ble_app_render_mode" ]] && return 0
+ case $1 in
+ (panel)
+ ble/term/leave-altscr
+ ble/canvas/panel/invalidate ;;
+ (forms:*)
+ ble/term/enter-altscr
+ ble/util/buffer "$_ble_term_clear"
+ ble/util/buffer $'\e[H'
+ _ble_canvas_x=0 _ble_canvas_y=0 ;;
+ (*)
+ ble/util/print "ble/edit: unrecognized render mode '$1'."
+ return 1 ;;
+ esac
+}
+function ble/application/push-render-mode {
+ ble/application/.set-up-render-mode "$1" || return 1
+ ble/array#unshift _ble_app_render_mode "$1"
+}
+function ble/application/pop-render-mode {
+ [[ ${_ble_app_render_mode[1]} ]] || return 1
+ ble/application/.set-up-render-mode "${_ble_app_render_mode[1]}"
+ ble/array#shift _ble_app_render_mode
+}
+function ble/application/render {
+ local _ble_app_render_Processing=1
+ {
+ local render=$_ble_app_render_mode
+ case $render in
+ (panel)
+ local _ble_prompt_update=owner
+ ble/prompt/update
+ ble/canvas/panel/render ;;
+ (forms:*)
+ ble/forms/render "${render#*:}" ;;
+ esac
+ _ble_app_winsize=("$COLUMNS" "$LINES")
+ ble/util/buffer.flush >&2
+ }
+ ble/util/unlocal _ble_app_render_Processing
+ if [[ $_ble_application_render_winch ]]; then
+ _ble_application_render_winch=
+ ble/application/onwinch
+ fi
+}
+function ble/application/onwinch {
+ if [[ $_ble_app_render_Processing || $_ble_decode_hook_Processing == body || $_ble_decode_hook_Processing == prologue ]]; then
+ _ble_application_render_winch=1
+ return 0
+ fi
+ _ble_textmap_pos=()
+ local old_size= i
+ for ((i=0;i<20;i++)); do
+ (ble/util/msleep 50)
+ ble/util/joblist.check ignore-volatile-jobs
+ local size=$LINES:$COLUMNS
+ [[ $size == "$old_size" ]] && break
+ local _ble_app_render_Processing=1
+ {
+ old_size=$size
+ case $bleopt_canvas_winch_action in
+ (clear)
+ ble/util/buffer "$_ble_term_clear" ;;
+ (redraw-here)
+ if ((COLUMNS<_ble_app_winsize[0])); then
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#goto.draw 0 0 0
+ ble/canvas/bflush.draw
+ fi ;;
+ (redraw-prev)
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#goto.draw 0 0 0
+ ble/canvas/bflush.draw ;;
+ esac
+ ble/canvas/panel/invalidate height # 高さの再確保も含めて。
+ }
+ ble/util/unlocal _ble_app_render_Processing
+ ble/application/render
+ done
+}
+_ble_canvas_panel_focus=0
+_ble_canvas_panel_class=(ble/textarea ble/textarea ble/edit/info ble/prompt/status)
+_ble_canvas_panel_vfill=3
+_ble_edit_command_layout_level=0
+function ble/edit/enter-command-layout {
+ ((_ble_edit_command_layout_level++==0)) || return 0
+ ble/edit/info#collapse "$_ble_edit_info_panel"
+ ble/prompt/status#collapse
+}
+function ble/edit/leave-command-layout {
+ ((_ble_edit_command_layout_level>0&&
+ --_ble_edit_command_layout_level==0)) || return 0
+ blehook/invoke info_reveal
+ ble/edit/info/default
+}
+function ble/edit/clear-command-layout {
+ ((_ble_edit_command_layout_level>0)) || return 0
+ _ble_edit_command_layout_level=1
+ ble/edit/leave-command-layout
+}
+function ble/edit/is-command-layout {
+ ((_ble_edit_command_layout_level>0))
+}
+_ble_prompt_status_panel=3
+_ble_prompt_status_dirty=
+_ble_prompt_status_data=()
+_ble_prompt_status_bbox=()
+function ble/prompt/status#panel::invalidate {
+ _ble_prompt_status_dirty=1
+}
+function ble/prompt/status#panel::render {
+ [[ $_ble_prompt_status_dirty ]] || return 0
+ _ble_prompt_status_dirty=
+ local index=$1
+ local height; ble/prompt/status#panel::getHeight "$index"
+ [[ ${height#*:} == 1 ]] || return 0
+ local -a DRAW_BUFF=()
+ height=$3
+ if ((height!=1)); then
+ ble/canvas/panel/reallocate-height.draw
+ ble/canvas/bflush.draw
+ height=${_ble_canvas_panel_height[index]}
+ ((height==0)) && return 0
+ fi
+ local esc=${_ble_prompt_status_data[10]}
+ if [[ $esc ]]; then
+ local prox=${_ble_prompt_status_data[11]}
+ local proy=${_ble_prompt_status_data[12]}
+ ble/canvas/panel#goto.draw "$_ble_prompt_status_panel"
+ ble/canvas/panel#put.draw "$_ble_prompt_status_panel" "$esc" "$prox" "$proy"
+ else
+ ble/canvas/panel#clear.draw "$_ble_prompt_status_panel"
+ fi
+ ble/canvas/bflush.draw
+}
+function ble/prompt/status#panel::getHeight {
+ if ble/edit/is-command-layout || [[ ! ${_ble_prompt_status_data[10]} ]]; then
+ height=0:0
+ else
+ height=0:1
+ fi
+}
+function ble/prompt/status#panel::onHeightChange {
+ ble/prompt/status#panel::invalidate
+}
+function ble/prompt/status#collapse {
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#set-height.draw "$_ble_prompt_status_panel" 0
+ ble/canvas/bflush.draw
+}
+_ble_prompt_hash=
+_ble_prompt_version=0
+function ble/prompt/.escape-control-characters {
+ ret=$1
+ local ctrl=$'\001-\037\177'
+ case $_ble_util_locale_encoding in
+ (UTF-8) ctrl=$ctrl$'\302\200-\302\237' ;;
+ (C) ctrl=$ctrl$'\200-\237' ;;
+ esac
+ local LC_ALL= LC_COLLATE=C glob_ctrl=[$ctrl]
+ [[ $ret == *$glob_ctrl* ]] || return 0
+ local out= head tail=$ret cs
+ while head=${tail%%$glob_ctrl*}; [[ $head != "$tail" ]]; do
+ ble/util/s2c "${tail:${#head}:1}"
+ ble/unicode/GraphemeCluster/.get-ascii-rep "$ret" # -> cs
+ out=$out$head$'\e[9807m'$cs$'\e[9807m'
+ tail=${tail#*$glob_ctrl}
+ done
+ ret=$out$tail
+}
+ble/function#suppress-stderr ble/prompt/.escape-control-characters # LC_COLLATE
+function ble/prompt/.initialize-constant {
+ local __ps=$1 __defeval=$2 __opts=$3
+ if ((_ble_bash>=40400)); then
+ ret=${__ps@P}
+ else
+ builtin eval -- "$__defeval"
+ fi
+ if [[ $__opts == *:escape:* ]]; then
+ if ((_ble_bash>=50200)); then
+ if [[ $ret == *\^['A'-'Z[\]^_?']* ]]; then
+ builtin eval -- "$__defeval"
+ ble/prompt/.escape-control-characters "$ret"
+ elif [[ $ret == *$'\t'* ]]; then
+ ble/prompt/.escape-control-characters "$ret"
+ fi
+ else
+ ble/prompt/.escape-control-characters "$_ble_prompt_const_s"
+ fi
+ fi
+}
+function ble/prompt/initialize {
+ local ret
+ ble/prompt/.initialize-constant '\H' 'ret=$HOSTNAME' escape
+ _ble_prompt_const_H=$ret
+ if local rex='^[0-9]+(\.[0-9]){3}$'; [[ $HOSTNAME =~ $rex ]]; then
+ _ble_prompt_const_h=$_ble_prompt_const_H
+ else
+ _ble_prompt_const_h=${_ble_prompt_const_H%%.*}
+ fi
+ ble/prompt/.initialize-constant '\l' 'ble/util/assign ret "ble/bin/tty 2>/dev/null";ret=${ret##*/}'
+ _ble_prompt_const_l=$ret
+ ble/prompt/.initialize-constant '\s' 'ret=${0##*/}' escape
+ _ble_prompt_const_s=$ret
+ ble/prompt/.initialize-constant '\s' 'ret=$USER' escape
+ _ble_prompt_const_u=$ret
+ ble/util/sprintf _ble_prompt_const_v '%d.%d' "${BASH_VERSINFO[0]}" "${BASH_VERSINFO[1]}"
+ ble/util/sprintf _ble_prompt_const_V '%d.%d.%d' "${BASH_VERSINFO[0]}" "${BASH_VERSINFO[1]}" "${BASH_VERSINFO[2]}"
+ if [[ $EUID -eq 0 ]]; then
+ _ble_prompt_const_root='#'
+ else
+ _ble_prompt_const_root='$'
+ fi
+ if [[ $OSTYPE == cygwin* ]]; then
+ local windir=/cygdrive/c/Windows
+ if [[ $WINDIR == [a-zA-Z]:\\* ]]; then
+ local bsl='\' sl=/
+ local c=${WINDIR::1} path=${WINDIR:3}
+ if [[ $c == [A-Z] ]]; then
+ if ((_ble_bash>=40000)); then
+ c=${c,?}
+ else
+ local ret
+ ble/util/s2c "$c"
+ ble/util/c2s $((ret+32))
+ c=$ret
+ fi
+ fi
+ windir=/cygdrive/$c/${path//"$bsl"/"$sl"}
+ fi
+ if [[ -e $windir && -w $windir ]]; then
+ _ble_prompt_const_root='#'
+ fi
+ elif [[ $OSTYPE == msys* ]]; then
+ if ble/bin#has id getent; then
+ local id getent
+ ble/util/assign id 'id -G'
+ ble/util/assign getent 'getent -w group S-1-16-12288'
+ ble/string#split getent : "$getent"
+ [[ " $id " == *" ${getent[1]} "* ]] &&
+ _ble_prompt_const_root='#'
+ fi
+ fi
+}
+function ble/prompt/unit#update {
+ local unit=$1
+ local prompt_unit_changed=
+ local prompt_unit_expired=
+ local ohashref=${unit}_data[1]; ohashref=${!ohashref-}
+ if [[ ! $ohashref ]]; then
+ prompt_unit_expired=1
+ else
+ ble/prompt/unit#update/.update-dependencies "$ohashref"
+ local ohash=${unit}_data[2]; ohash=${!ohash}
+ builtin eval -- "local nhash=\"$ohashref\"" 2>/dev/null
+ [[ $nhash != "$ohash" ]] && prompt_unit_expired=1
+ fi
+ if [[ $prompt_unit_expired ]]; then
+ local prompt_unit=$unit
+ local prompt_hashref_dep= # プロンプト間依存性
+ local prompt_hashref_var= # 変数に対する依存性
+ ble/prompt/unit:"$unit"/update "$unit" &&
+ ((prompt_unit_changed=1,${unit}_data[0]++))
+ local hashref=${prompt_hashref_base-'$_ble_prompt_version'}:$prompt_hashref_dep:$prompt_hashref_var
+ builtin eval -- "${unit}_data[1]=\$hashref"
+ builtin eval -- "${unit}_data[2]=\"$hashref\"" 2>/dev/null
+ ble/util/unlocal prompt_unit prompt_hashref_dep
+ fi
+ if [[ $prompt_unit ]]; then
+ local ref1='$'$unit'_data'
+ [[ ,$prompt_hashref_dep, != *,"$ref1",* ]] &&
+ prompt_hashref_dep=$prompt_hashref_dep${prompt_hashref_dep:+,}$ref1
+ fi
+ [[ $prompt_unit_changed ]]
+}
+function ble/prompt/unit#update/.update-dependencies {
+ local ohashref=$1
+ local otree=${ohashref#*:}; otree=${otree%%:*}
+ if [[ $otree ]]; then
+ ble/string#split otree , "$otree"
+ if [[ ! $ble_prompt_unit_processing ]]; then
+ local ble_prompt_unit_processing=1
+ "${_ble_util_set_declare[@]//NAME/ble_prompt_unit_mark}" # WA #D1570
+ elif ble/set#contains ble_prompt_unit_mark "$unit"; then
+ ble/util/print "ble/prompt: FATAL: detected cyclic dependency ($unit required by $ble_prompt_unit_parent)" >/dev/tty
+ return 1
+ fi
+ local ble_prompt_unit_parent=$unit
+ ble/set#add ble_prompt_unit_mark "$unit"
+ local prompt_unit= # 依存関係の登録はしない
+ local child
+ for child in "${otree[@]}"; do
+ [[ $child == '$'?*'_data' ]] || continue
+ child=${child:1:${#child}-6}
+ ble/is-function ble/prompt/unit:"$child"/update &&
+ ble/prompt/unit#update "$child"
+ done
+ ble/set#remove ble_prompt_unit_mark "$unit"
+ fi
+}
+function ble/prompt/unit#clear {
+ local prefix=$1
+ builtin eval -- "${prefix}_data[2]="
+}
+function ble/prompt/unit/assign {
+ local var=$1 value=$2
+ [[ $value == "${!var}" ]] && return 1
+ prompt_unit_changed=1
+ builtin eval -- "$var=\$value"
+}
+function ble/prompt/unit/add-hash {
+ [[ $prompt_unit && ,$prompt_hashref_var, != *,"$1",* ]] &&
+ prompt_hashref_var=$prompt_hashref_var${prompt_hashref_var:+,}$1
+ return 0
+}
+_ble_prompt_ps1_dirty=
+_ble_prompt_ps1_data=(0 '' '' 0 0 0 32 0 '' '')
+_ble_prompt_rps1_dirty=
+_ble_prompt_rps1_data=()
+_ble_prompt_rps1_gbox=()
+_ble_prompt_rps1_shown=
+_ble_prompt_xterm_title_dirty=
+_ble_prompt_xterm_title_data=()
+_ble_prompt_screen_title_dirty=
+_ble_prompt_screen_title_data=()
+_ble_prompt_term_status_dirty=
+_ble_prompt_term_status_data=()
+function ble/prompt/print {
+ local ret=$1 a b
+ [[ $prompt_noesc ]] ||
+ ble/string#escape-characters "$ret" '\$"`'
+ ble/canvas/put.draw "$ret"
+}
+function ble/prompt/process-prompt-string {
+ local ps1=$1
+ local i=0 iN=${#ps1}
+ local rex_letters='^[^\]+|\\$'
+ while ((i<iN)); do
+ local tail=${ps1:i}
+ if [[ $tail == '\'?* ]]; then
+ ble/prompt/.process-backslash
+ elif [[ $tail =~ $rex_letters ]]; then
+ ble/canvas/put.draw "$BASH_REMATCH"
+ ((i+=${#BASH_REMATCH}))
+ else
+ ble/canvas/put.draw "${tail::1}"
+ ((i++))
+ fi
+ done
+}
+function ble/prompt/.process-backslash {
+ ((i+=2))
+ local c=${tail:1:1} pat='][#!$\'
+ if [[ $c == ["$pat"] ]]; then
+ case "$c" in
+ (\[) ble/canvas/put.draw $'\001' ;; # \[ \] は後処理の為、適当な識別用の文字列を出力する。
+ (\]) ble/canvas/put.draw $'\002' ;;
+ ('#') # コマンド番号 (本当は history に入らない物もある…)
+ ble/prompt/unit/add-hash '$_ble_edit_CMD'
+ ble/canvas/put.draw "$_ble_edit_CMD" ;;
+ (\!) # 編集行の履歴番号
+ local count
+ ble/history/get-count -v count
+ ble/canvas/put.draw $((count+1)) ;;
+ ('$') # # or $
+ ble/prompt/print "$_ble_prompt_const_root" ;;
+ (\\)
+ ble/canvas/put.draw '\' ;;
+ esac
+ elif ble/is-function ble/prompt/backslash:"$c"; then
+ ble/function#try ble/prompt/backslash:"$c"
+ elif ble/is-function ble-edit/prompt/backslash:"$c"; then # deprecated name
+ ble/function#try ble-edit/prompt/backslash:"$c"
+ else
+ ble/canvas/put.draw "\\$c"
+ fi
+}
+function ble/prompt/backslash:0 { # 8進表現
+ local rex='^\\[0-7]{1,3}'
+ if [[ $tail =~ $rex ]]; then
+ local seq=${BASH_REMATCH[0]}
+ ((i+=${#seq}-2))
+ builtin eval "c=\$'$seq'"
+ fi
+ ble/prompt/print "$c"
+ return 0
+}
+function ble/prompt/backslash:1 { ble/prompt/backslash:0; }
+function ble/prompt/backslash:2 { ble/prompt/backslash:0; }
+function ble/prompt/backslash:3 { ble/prompt/backslash:0; }
+function ble/prompt/backslash:4 { ble/prompt/backslash:0; }
+function ble/prompt/backslash:5 { ble/prompt/backslash:0; }
+function ble/prompt/backslash:6 { ble/prompt/backslash:0; }
+function ble/prompt/backslash:7 { ble/prompt/backslash:0; }
+function ble/prompt/backslash:a { # 0 BEL
+ ble/canvas/put.draw ""
+ return 0
+}
+function ble/prompt/backslash:e {
+ ble/canvas/put.draw $'\e'
+ return 0
+}
+function ble/prompt/backslash:n {
+ ble/canvas/put.draw $'\n'
+ return 0
+}
+function ble/prompt/backslash:r {
+ ble/canvas/put.draw "$_ble_term_cr"
+ return 0
+}
+_ble_prompt_cache_vars=(
+ prompt_cache_d
+ prompt_cache_t
+ prompt_cache_A
+ prompt_cache_T
+ prompt_cache_at
+ prompt_cache_j
+ prompt_cache_wd
+)
+function ble/prompt/backslash:d { # ? 日付
+ [[ $prompt_cache_d ]] || ble/util/strftime -v prompt_cache_d '%a %b %d'
+ ble/prompt/print "$prompt_cache_d"
+ return 0
+}
+function ble/prompt/backslash:t { # 8 時刻
+ [[ $prompt_cache_t ]] || ble/util/strftime -v prompt_cache_t '%H:%M:%S'
+ ble/prompt/print "$prompt_cache_t"
+ return 0
+}
+function ble/prompt/backslash:A { # 5 時刻
+ [[ $prompt_cache_A ]] || ble/util/strftime -v prompt_cache_A '%H:%M'
+ ble/prompt/print "$prompt_cache_A"
+ return 0
+}
+function ble/prompt/backslash:T { # 8 時刻
+ [[ $prompt_cache_T ]] || ble/util/strftime -v prompt_cache_T '%I:%M:%S'
+ ble/prompt/print "$prompt_cache_T"
+ return 0
+}
+function ble/prompt/backslash:@ { # ? 時刻
+ [[ $prompt_cache_at ]] || ble/util/strftime -v prompt_cache_at '%I:%M %p'
+ ble/prompt/print "$prompt_cache_at"
+ return 0
+}
+function ble/prompt/backslash:D {
+ local rex='^\\D\{([^{}]*)\}' cache_D
+ if [[ $tail =~ $rex ]]; then
+ ble/util/strftime -v cache_D "${BASH_REMATCH[1]}"
+ ble/prompt/print "$cache_D"
+ ((i+=${#BASH_REMATCH}-2))
+ else
+ ble/prompt/print "\\$c"
+ fi
+ return 0
+}
+function ble/prompt/backslash:h { # = ホスト名
+ ble/prompt/print "$_ble_prompt_const_h"
+ return 0
+}
+function ble/prompt/backslash:H { # = ホスト名
+ ble/prompt/print "$_ble_prompt_const_H"
+ return 0
+}
+function ble/prompt/backslash:j { # ジョブの数
+ if [[ ! $prompt_cache_j ]]; then
+ local joblist
+ ble/util/joblist
+ prompt_cache_j=${#joblist[@]}
+ fi
+ ble/canvas/put.draw "$prompt_cache_j"
+ return 0
+}
+function ble/prompt/backslash:l { # tty basename
+ ble/prompt/print "$_ble_prompt_const_l"
+ return 0
+}
+function ble/prompt/backslash:s { # 4 "bash"
+ ble/prompt/print "$_ble_prompt_const_s"
+ return 0
+}
+function ble/prompt/backslash:u { # = ユーザ名
+ ble/prompt/print "$_ble_prompt_const_u"
+ return 0
+}
+function ble/prompt/backslash:v { # = bash version %d.%d
+ ble/prompt/print "$_ble_prompt_const_v"
+ return 0
+}
+function ble/prompt/backslash:V { # = bash version %d.%d.%d
+ ble/prompt/print "$_ble_prompt_const_V"
+ return 0
+}
+function ble/prompt/backslash:w { # PWD
+ ble/prompt/unit/add-hash '$PWD'
+ ble/prompt/.update-working-directory
+ local ret
+ ble/prompt/.escape-control-characters "$prompt_cache_wd"
+ ble/prompt/print "$ret"
+ return 0
+}
+function ble/prompt/backslash:W { # PWD短縮
+ ble/prompt/unit/add-hash '$PWD'
+ if [[ ! ${PWD//'/'} ]]; then
+ ble/prompt/print "$PWD"
+ else
+ ble/prompt/.update-working-directory
+ local ret
+ ble/prompt/.escape-control-characters "${prompt_cache_wd##*/}"
+ ble/prompt/print "$ret"
+ fi
+ return 0
+}
+function ble/prompt/backslash:q {
+ local rex='^\{([^{}]*)\}'
+ if [[ ${tail:2} =~ $rex ]]; then
+ local rematch=$BASH_REMATCH
+ ((i+=${#rematch}))
+ local word; ble/string#split-words word "${BASH_REMATCH[1]}"
+ if [[ $word ]] && ble/is-function ble/prompt/backslash:"$word"; then
+ ble/util/joblist.check
+ ble/prompt/backslash:"${word[@]}"; local ext=$?
+ ble/util/joblist.check ignore-volatile-jobs
+ return "$?"
+ else
+ if [[ ! $word ]]; then
+ ble/term/visible-bell "ble/prompt: invalid sequence \\q$rematch"
+ elif ! ble/is-function ble/prompt/backslash:"$word"; then
+ ble/term/visible-bell "ble/propmt: undefined named sequence \\q{$word}"
+ fi
+ ble/prompt/print "\\q$BASH_REMATCH"
+ return 2
+ fi
+ else
+ ble/prompt/print "\\$c"
+ fi
+ return 0
+}
+function ble/prompt/backslash:g {
+ local rex='^\{([^{}]*)\}'
+ if [[ ${tail:2} =~ $rex ]]; then
+ ((i+=${#BASH_REMATCH}))
+ local ret
+ ble/color/gspec2g "${BASH_REMATCH[1]}"
+ ble/color/g2sgr-ansi "$ret"
+ ble/prompt/print "$ret"
+ else
+ ble/prompt/print "\\$c"
+ fi
+ return 0
+}
+function ble/prompt/backslash:position {
+ ((_ble_textmap_dbeg>=0)) && ble/widget/.update-textmap
+ local fmt=${1:-'(%s,%s)'} pos
+ ble/prompt/unit/add-hash '${_ble_textmap_pos[_ble_edit_ind]}'
+ ble/string#split-words pos "${_ble_textmap_pos[_ble_edit_ind]}"
+ ble/util/sprintf pos "$fmt" $((pos[1]+1)) $((pos[0]+1))
+ ble/prompt/print "$pos"
+}
+function ble/prompt/backslash:row {
+ ((_ble_textmap_dbeg>=0)) && ble/widget/.update-textmap
+ local pos
+ ble/prompt/unit/add-hash '${_ble_textmap_pos[_ble_edit_ind]}'
+ ble/string#split-words pos "${_ble_textmap_pos[_ble_edit_ind]}"
+ ble/prompt/print $((pos[1]+1))
+}
+function ble/prompt/backslash:column {
+ ((_ble_textmap_dbeg>=0)) && ble/widget/.update-textmap
+ local pos
+ ble/prompt/unit/add-hash '${_ble_textmap_pos[_ble_edit_ind]}'
+ ble/string#split-words pos "${_ble_textmap_pos[_ble_edit_ind]}"
+ ble/prompt/print $((pos[0]+1))
+}
+function ble/prompt/backslash:point {
+ ble/prompt/unit/add-hash '$_ble_edit_ind'
+ ble/prompt/print "$_ble_edit_ind"
+}
+function ble/prompt/backslash:mark {
+ ble/prompt/unit/add-hash '$_ble_edit_mark'
+ ble/prompt/print "$_ble_edit_mark"
+}
+function ble/prompt/backslash:history-index {
+ ble/prompt/unit/add-hash '$_ble_history_INDEX'
+ ble/canvas/put.draw $((_ble_history_INDEX+1))
+}
+function ble/prompt/backslash:history-percentile {
+ ble/prompt/unit/add-hash '$_ble_history_INDEX'
+ ble/prompt/unit/add-hash '$_ble_history_COUNT'
+ local index=$_ble_history_INDEX
+ local count=$_ble_history_COUNT
+ ((count||count++))
+ ble/canvas/put.draw "$((index*100/count))%"
+}
+function ble/prompt/.update-working-directory {
+ [[ $prompt_cache_wd ]] && return 0
+ if [[ ! ${PWD//'/'} ]]; then
+ prompt_cache_wd=$PWD
+ return 0
+ fi
+ local head= body=${PWD%/}
+ if [[ $body == "$HOME" ]]; then
+ prompt_cache_wd='~'
+ return 0
+ elif [[ $body == "$HOME"/* ]]; then
+ head='~/'
+ body=${body#"$HOME"/}
+ fi
+ if [[ $PROMPT_DIRTRIM ]]; then
+ local dirtrim=$((PROMPT_DIRTRIM))
+ local pat='[^/]'
+ local count=${body//$pat}
+ if ((${#count}>=dirtrim)); then
+ local ret
+ ble/string#repeat '/*' "$dirtrim"
+ local omit=${body%$ret}
+ ((${#omit}>3)) &&
+ body=...${body:${#omit}}
+ fi
+ fi
+ prompt_cache_wd=$head$body
+}
+function ble/prompt/.escape/check-double-quotation {
+ if [[ $tail == '"'* ]]; then
+ if [[ ! $nest ]]; then
+ out=$out'\"'
+ tail=${tail:1}
+ else
+ out=$out'"'
+ tail=${tail:1}
+ nest=\"$nest
+ ble/prompt/.escape/update-rex_skip
+ fi
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/prompt/.escape/check-command-substitution {
+ if [[ $tail == '$('* ]]; then
+ out=$out'$('
+ tail=${tail:2}
+ nest=')'$nest
+ ble/prompt/.escape/update-rex_skip
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/prompt/.escape/check-parameter-expansion {
+ if [[ $tail == '${'* ]]; then
+ out=$out'${'
+ tail=${tail:2}
+ nest='}'$nest
+ ble/prompt/.escape/update-rex_skip
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/prompt/.escape/check-incomplete-quotation {
+ if [[ $tail == '`'* ]]; then
+ local rex='^`([^\`]|\\.)*\\$'
+ [[ $tail =~ $rex ]] && tail=$tail'\'
+ out=$out$tail'`'
+ tail=
+ return 0
+ elif [[ $nest == ['})']* && $tail == \'* ]]; then
+ out=$out$tail$q
+ tail=
+ return 0
+ elif [[ $nest == ['})']* && $tail == \$\'* ]]; then
+ local rex='^\$'$q'([^\'$q']|\\.)*\\$'
+ [[ $tail =~ $rex ]] && tail=$tail'\'
+ out=$out$tail$q
+ tail=
+ return 0
+ elif [[ $tail == '\' ]]; then
+ out=$out'\\'
+ tail=
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/prompt/.escape/update-rex_skip {
+ if [[ $nest == \)* ]]; then
+ rex_skip=$rex_skip_paren
+ elif [[ $nest == \}* ]]; then
+ rex_skip=$rex_skip_brace
+ else
+ rex_skip=$rex_skip_dquot
+ fi
+}
+function ble/prompt/.escape {
+ local tail=$1 out= nest=
+ local q=\'
+ local rex_bq='`([^\`]|\\.)*`'
+ local rex_sq=$q'[^'$q']*'$q'|\$'$q'([^\'$q']|\\.)*'$q
+ local rex_skip
+ local rex_skip_dquot='^([^\"$`]|'$rex_bq'|\\.)+'
+ local rex_skip_brace='^([^\"$`'$q'}]|'$rex_bq'|'$rex_sq'|\\.)+'
+ local rex_skip_paren='^([^\"$`'$q'()]|'$rex_bq'|'$rex_sq'|\\.)+'
+ ble/prompt/.escape/update-rex_skip
+ while [[ $tail ]]; do
+ if [[ $tail =~ $rex_skip ]]; then
+ out=$out$BASH_REMATCH
+ tail=${tail:${#BASH_REMATCH}}
+ elif [[ $nest == ['})"']* && $tail == "${nest::1}"* ]]; then
+ out=$out${nest::1}
+ tail=${tail:1}
+ nest=${nest:1}
+ ble/prompt/.escape/update-rex_skip
+ elif [[ $nest == \)* && $tail == \(* ]]; then
+ out=$out'('
+ tail=${tail:1}
+ nest=')'$nest
+ elif ble/prompt/.escape/check-double-quotation; then
+ continue
+ elif ble/prompt/.escape/check-command-substitution; then
+ continue
+ elif ble/prompt/.escape/check-parameter-expansion; then
+ continue
+ elif ble/prompt/.escape/check-incomplete-quotation; then
+ continue
+ else
+ out=$out${tail::1}
+ tail=${tail:1}
+ fi
+ done
+ ret=$out$nest
+}
+function ble/prompt/.get-keymap-for-current-mode {
+ ble/prompt/unit/add-hash '$_ble_decode_keymap,${_ble_decode_keymap_stack[*]}'
+ keymap=$_ble_decode_keymap
+ local index=${#_ble_decode_keymap_stack[@]}
+ while :; do
+ case $keymap in (vi_?map|emacs) return ;; esac
+ ((--index<0)) && break
+ keymap=${_ble_decode_keymap_stack[index]}
+ done
+}
+function ble/prompt/.uses-builtin-prompt-expansion {
+ ((_ble_bash>=40400)) || return 1
+ local ps=$1
+ local chars_safe_esc='][0-7aenrdtAT@DhHjlsuvV!$\wW'
+ [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $_ble_prompt_const_root == '#' ]] &&
+ chars_safe_esc=${chars_safe_esc//'$'} # Note: cygwin では ble.sh 独自の方法で \$ を処理する。
+ [[ $ps == *'\'[!"$chars_safe_esc"]* ]] && return 1
+ local glob_ctrl=$'[\001-\037\177]'
+ [[ $ps == *'\'[wW]* && $PWD == *$glob_ctrl* ]] && return 1
+ [[ $ps == *'\s'* && $_ble_prompt_const_s == *$'\e'* ]] && return 1
+ [[ $ps == *'\u'* && $_ble_prompt_const_u == *$'\e'* ]] && return 1
+ [[ $ps == *'\h'* && $_ble_prompt_const_h == *$'\e'* ]] && return 1
+ [[ $ps == *'\H'* && $_ble_prompt_const_H == *$'\e'* ]] && return 1
+ return 0
+}
+function ble/prompt/.instantiate {
+ trace_hash= esc= x=0 y=0 g=0 lc=32 lg=0
+ local ps=$1 opts=$2 x0=$3 y0=$4 g0=$5 lc0=$6 lg0=$7 esc0=$8 trace_hash0=$9
+ [[ ! $ps ]] && return 0
+ local expanded=
+ if ble/prompt/.uses-builtin-prompt-expansion "$ps"; then
+ [[ $ps == *'\'[wW]* ]] && ble/prompt/unit/add-hash '$PWD'
+ ble-edit/exec/.setexit "$_ble_edit_exec_lastarg"
+ BASH_COMMAND=$_ble_edit_exec_BASH_COMMAND \
+ builtin eval 'expanded=${ps@P}'
+ else
+ local prompt_noesc=
+ shopt -q promptvars &>/dev/null || prompt_noesc=1
+ local -a DRAW_BUFF=()
+ ble/prompt/process-prompt-string "$ps"
+ local processed; ble/canvas/sflush.draw -v processed
+ if [[ ! $prompt_noesc ]]; then
+ local ret
+ ble/prompt/.escape "$processed"; local escaped=$ret
+ expanded=${trace_hash0#*:} # Note: これは次行が失敗した時の既定値
+ ble-edit/exec/.setexit "$_ble_edit_exec_lastarg"
+ BASH_COMMAND=$_ble_edit_exec_BASH_COMMAND \
+ builtin eval "expanded=\"$escaped\""
+ else
+ expanded=$processed
+ fi
+ fi
+ if [[ :$opts: == *:show-mode-in-prompt:* ]]; then
+ if ble/util/test-rl-variable show-mode-in-prompt; then
+ local keymap; ble/prompt/.get-keymap-for-current-mode
+ local ret=
+ case $keymap in
+ (vi_imap) ble/util/read-rl-variable vi-ins-mode-string ;;
+ (vi_[noxs]map) ble/util/read-rl-variable vi-cmd-mode-string ;;
+ (emacs) ble/util/read-rl-variable emacs-mode-string ;;
+ esac
+ [[ $ret ]] && expanded=$expanded$ret
+ fi
+ fi
+ if [[ :$opts: == *:no-trace:* ]]; then
+ x=0 y=0 g=0 lc=32 lg=0
+ esc=$expanded
+ elif
+ local rows=${prompt_rows:-${LINES:-25}}
+ local cols=${prompt_cols:-${COLUMNS:-80}}
+ local bleopt=$bleopt_char_width_mode,$bleopt_char_width_version,$bleopt_emoji_version,$bleopt_emoji_opts
+ trace_hash=$opts#$rows,$cols#$bleopt#$expanded
+ [[ $trace_hash != "$trace_hash0" ]]
+ then
+ local trace_opts=$opts:prompt
+ [[ $bleopt_internal_suppress_bash_output ]] || trace_opts=$trace_opts:left-char
+ x=0 y=0 g=0 lc=32 lg=0
+ local ret
+ LINES=$rows COLUMNS=$cols ble/canvas/trace "$expanded" "$trace_opts"; local traced=$ret
+ ((lc<0&&(lc=0)))
+ esc=$traced
+ return 0
+ else
+ x=$x0 y=$y0 g=$g0 lc=$lc0 lg=$lg0
+ esc=$esc0
+ return 2
+ fi
+}
+function ble/prompt/unit:{section}/clear {
+ local prefix=$1 type=${2:-hash:draw}
+ [[ :$type: == *:hash:* ]] &&
+ builtin eval -- "${prefix}_data[2]="
+ [[ :$type: == *:tail:* ]] &&
+ builtin eval -- "${prefix}_data=(\"\${${prefix}_data[@]::10}\")"
+ [[ :$type: == *:draw:* ]] &&
+ builtin eval -- "${prefix}_dirty=1"
+ [[ :$type: == *:all:* ]] &&
+ builtin eval -- "${prefix}_data=(\"\${${prefix}_data[0]}\")"
+ return 0
+}
+function ble/prompt/unit:{section}/get {
+ local ref=${1}_data[8]; ret=${!ref}
+}
+function ble/prompt/unit:{section}/update {
+ local prefix=$1 ps=$2 opts=$3
+ local -a vars; vars=(data dirty)
+ [[ :$opts: == *:measure-bbox:* ]] && ble/array#push vars bbox
+ [[ :$opts: == *:measure-gbox:* ]] && ble/array#push vars gbox
+ local "${vars[@]/%/=}" # #D1570 OK
+ ble/util/restore-vars "${prefix}_" "${vars[@]}"
+ local has_changed=
+ if [[ $prompt_unit_expired ]]; then
+ local original_esc=${data[8]}:${data[9]}:${data[10]} # esc:trace_hash:tailor
+ if [[ $ps ]]; then
+ [[ :$opts: == *:measure-bbox:* ]] &&
+ local x1=${bbox[0]} y1=${bbox[1]} x2=${bbox[2]} y2=${bbox[3]}
+ [[ :$opts: == *:measure-gbox:* ]] &&
+ local gx1=${gbox[0]} gy1=${gbox[1]} gx2=${gbox[2]} gy2=${gbox[3]}
+ local trace_hash esc x y g lc lg
+ ble/prompt/.instantiate "$ps" "$opts" "${data[@]:3:7}"
+ data=("${data[0]:-0}" '' '' "$x" "$y" "$g" "$lc" "$lg" "$esc" "$trace_hash" "${data[@]:10}")
+ [[ :$opts: == *:measure-bbox:* ]] &&
+ bbox=("$x1" "$y1" "$x2" "$y2")
+ [[ :$opts: == *:measure-gbox:* ]] &&
+ gbox=("$gx1" "$gy1" "$gx2" "$gy2")
+ else
+ data=("${data[0]:-0}" '' '' 0 0 0 32 0 '' '' "${data[@]:10}")
+ [[ :$opts: == *:measure-bbox:* ]] && bbox=()
+ [[ :$opts: == *:measure-gbox:* ]] && gbox=()
+ fi
+ [[ ${data[8]}:${data[9]}:${data[10]} != "$original_esc" ]] && has_changed=1
+ fi
+ [[ $has_changed ]] && ((dirty=1))
+ ble/util/save-vars "${prefix}_" "${vars[@]}"
+ [[ $has_changed ]]
+}
+function ble/prompt/unit:_ble_prompt_ps1/update {
+ ble/prompt/unit/add-hash '$prompt_ps1'
+ ble/prompt/unit:{section}/update _ble_prompt_ps1 "$prompt_ps1" show-mode-in-prompt
+}
+function ble/prompt/unit:_ble_prompt_rps1/update {
+ ble/prompt/unit/add-hash '$prompt_rps1'
+ ble/prompt/unit/add-hash '$_ble_prompt_ps1_data'
+ local cols=${COLUMNS-80}
+ local ps1x=${_ble_prompt_ps1_data[3]}
+ local ps1y=${_ble_prompt_ps1_data[4]}
+ local prompt_rows=$((ps1y+1)) prompt_cols=$cols
+ ble/prompt/unit:{section}/update _ble_prompt_rps1 "$prompt_rps1" confine:relative:right:measure-gbox || return 1
+ local esc=${_ble_prompt_rps1_data[8]} width=
+ if [[ $esc ]]; then
+ ((width=_ble_prompt_rps1_gbox[2]-_ble_prompt_rps1_gbox[0]))
+ ((width&&20+width<cols&&ps1x+10+width<cols)) || esc= width=
+ fi
+ _ble_prompt_rps1_data[10]=$esc
+ _ble_prompt_rps1_data[11]=$width
+ return 0
+}
+function ble/prompt/unit:_ble_prompt_xterm_title/update {
+ ble/prompt/unit/add-hash '$bleopt_prompt_xterm_title'
+ local prompt_rows=1
+ ble/prompt/unit:{section}/update _ble_prompt_xterm_title "$bleopt_prompt_xterm_title" confine:no-trace || return 1
+ local esc=${_ble_prompt_xterm_title_data[8]}
+ [[ $esc ]] && esc=$'\e]0;'${esc//[! -~]/'#'}$'\a'
+ _ble_prompt_xterm_title_data[10]=$esc
+ return 0
+}
+function ble/prompt/unit:_ble_prompt_screen_title/update {
+ ble/prompt/unit/add-hash '$bleopt_prompt_screen_title'
+ local prompt_rows=1
+ ble/prompt/unit:{section}/update _ble_prompt_screen_title "$bleopt_prompt_screen_title" confine:no-trace || return 1
+ local esc=${_ble_prompt_screen_title_data[8]}
+ [[ $esc ]] && esc=$'\ek'${esc//[! -~]/'#'}$'\e\\'
+ _ble_prompt_screen_title_data[10]=$esc
+ return 0
+}
+function ble/prompt/unit:_ble_prompt_term_status/update {
+ ble/prompt/unit/add-hash '$bleopt_prompt_term_status'
+ local prompt_rows=1
+ ble/prompt/unit:{section}/update _ble_prompt_term_status "$bleopt_prompt_term_status" confine:no-trace || return 1
+ local esc=${_ble_prompt_term_status_data[8]}
+ if [[ $esc ]]; then
+ esc=$_ble_term_tsl${esc//[! -~]/'#'}$_ble_term_fsl
+ else
+ esc=$_ble_term_dsl
+ fi
+ _ble_prompt_term_status_data[10]=$esc
+ return 0
+}
+function ble/prompt/unit:_ble_prompt_status/update {
+ ble/prompt/unit/add-hash '$bleopt_prompt_status_align'
+ ble/prompt/unit/add-hash '$bleopt_prompt_status_line'
+ local ps=$bleopt_prompt_status_line
+ local cols=$COLUMNS; ((_ble_term_xenl||cols--))
+ local trace_opts=confine:relative:measure-bbox:noscrc:face0=prompt_status_line
+ local rex='^justify(=[^:]+)?$'
+ [[ $bleopt_prompt_status_align =~ $rex ]] &&
+ trace_opts=$trace_opts:$BASH_REMATCH
+ local prompt_cols=1 prompt_cols=$cols
+ ble/prompt/unit:{section}/update _ble_prompt_status "$ps" "$trace_opts" || return 1
+ local esc=${_ble_prompt_status_data[8]}
+ if [[ $ps && $esc ]]; then
+ local x=${_ble_prompt_status_data[3]}
+ local y=${_ble_prompt_status_data[4]}
+ local x1=${_ble_prompt_status_bbox[0]}
+ local x2=${_ble_prompt_status_bbox[2]}
+ local -a DRAW_BUFF=()
+ local ret
+ ble/color/face2g prompt_status_line; local g0=$ret
+ ble/color/g2sgr "$g0"; local sgr=$ret
+ if ((g0==0||_ble_term_bce)); then
+ ble/canvas/put.draw "$sgr$_ble_term_el$_ble_term_sgr0"
+ else
+ ble/string#reserve-prototype "$cols"
+ ble/canvas/put.draw "$sgr${_ble_string_prototype::cols}"
+ ble/canvas/put-cub.draw "$cols"
+ ble/canvas/put.draw "$_ble_term_sgr0"
+ fi
+ local xshift=0
+ case $bleopt_prompt_status_align in
+ (center) ((xshift=cols/2-(x2+x1)/2)) ;;
+ (right) ((xshift=cols-x2)) ;;
+ esac
+ if ((xshift>0)); then
+ ((x+=xshift))
+ ble/canvas/put-cuf.draw "$xshift"
+ fi
+ ble/canvas/put.draw "$esc"
+ ble/canvas/sflush.draw -v esc
+ _ble_prompt_status_data[10]=$esc
+ _ble_prompt_status_data[11]=$x
+ _ble_prompt_status_data[12]=$y
+ else
+ _ble_prompt_status_data[10]=
+ _ble_prompt_status_data[11]=
+ _ble_prompt_status_data[12]=
+ fi
+ return 0
+}
+if ble/is-function ble/util/idle.push; then
+ _ble_prompt_timeout_task=
+ _ble_prompt_timeout_lineno=
+ function ble/prompt/timeout/process {
+ ble/util/idle.suspend # exit に失敗した時の為 task を suspend にする
+ local msg="${_ble_term_setaf[12]}[ble: auto-logout]$_ble_term_sgr0 timed out waiting for input"
+ ble/widget/.internal-print-command '
+ ble/util/print "$msg"
+ builtin exit 0 &>/dev/null
+ builtin exit 0 &>/dev/null' pre-flush
+ return 1 # exit に失敗した時
+ } >/dev/tty
+ function ble/prompt/timeout/check {
+ [[ $_ble_edit_lineno == "$_ble_prompt_timeout_lineno" ]] && return 0
+ _ble_prompt_timeout_lineno=$_ble_edit_lineno
+ if [[ ${TMOUT:-} =~ ^[0-9]+ ]] && ((BASH_REMATCH>0)); then
+ if [[ ! $_ble_prompt_timeout_task ]]; then
+ ble/util/idle.push -Z 'ble/prompt/timeout/process'
+ _ble_prompt_timeout_task=$_ble_util_idle_lasttask
+ fi
+ ble/util/idle#sleep "$_ble_prompt_timeout_task" $((BASH_REMATCH*1000))
+ elif [[ $_ble_prompt_timeout_task ]]; then
+ ble/util/idle#suspend "$_ble_prompt_timeout_task"
+ fi
+ }
+else
+ function ble/prompt/timeout/check { ((1)); }
+fi
+function ble/prompt/update/.has-prompt_command {
+ [[ ${_ble_edit_PROMPT_COMMAND[*]} == *[![:space:]]* ]]
+}
+function _ble_prompt_update__eval_prompt_command_1 {
+ local _ble_edit_exec_TRAPDEBUG_enabled=1
+ ble-edit/exec/.setexit "$_ble_edit_exec_lastarg"
+ BASH_COMMAND=$_ble_edit_exec_BASH_COMMAND \
+ builtin eval -- "$1"
+}
+ble/function#trace _ble_prompt_update__eval_prompt_command_1
+function ble/prompt/update/.eval-prompt_command {
+ ((${#PROMPT_COMMAND[@]})) || return 0
+ local _command _ble_edit_exec_TRAPDEBUG_adjusted=1
+ ble-edit/exec:gexec/.TRAPDEBUG/restore filter
+ for _command in "${PROMPT_COMMAND[@]}"; do
+ [[ $_command ]] || continue
+ _ble_prompt_update__eval_prompt_command_1 "$_command"
+ done
+ _ble_edit_exec_gexec__TRAPDEBUG_adjust
+}
+_ble_prompt_update=
+_ble_prompt_update_dirty=
+_ble_prompt_rps1_enabled=
+function ble/prompt/update {
+ local opts=:$1: dirty=
+ local count; ble/history/get-count
+ local version=$COLUMNS:$_ble_edit_lineno:$count
+ if [[ :$opts: == *:check-dirty:* && $_ble_prompt_update == owner ]]; then
+ if [[ $_ble_prompt_update_dirty && :$opts: != *:leave:* && $_ble_prompt_hash == "$version" ]]; then
+ [[ $_ble_prompt_update_dirty == dirty ]]; local ext=$?
+ _ble_prompt_update_dirty=done
+ return "$ext"
+ fi
+ fi
+ ble/prompt/timeout/check
+ _ble_prompt_rps1_enabled=
+ if ((_ble_textarea_panel==0)); then # 補助プロンプトに対しては PROMPT_COMMAND は実行しない
+ if [[ ${_ble_prompt_hash%:*} != "${version%:*}" && $opts != *:leave:* ]]; then
+ if ble/prompt/update/.has-prompt_command || blehook/has-hook PRECMD; then
+ if [[ $bleopt_prompt_command_changes_layout ]]; then
+ ble/edit/enter-command-layout # #D1800 pair=leave-command-layout
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#goto.draw 0 0 0 sgr0
+ ble/canvas/bflush.draw
+ ble/util/buffer.flush >&2
+ fi
+ ((_ble_edit_attached)) && ble-edit/restore-PS1
+ ble-edit/exec:gexec/invoke-hook-with-setexit PRECMD
+ ble/prompt/update/.eval-prompt_command
+ ((_ble_edit_attached)) && ble-edit/adjust-PS1
+ if [[ $bleopt_prompt_command_changes_layout ]]; then
+ ble/edit/leave-command-layout # #D1800 pair=enter-command-layout
+ fi
+ fi
+ fi
+ fi
+ local prompt_opts=
+ local prompt_ps1=$_ble_edit_PS1
+ local prompt_rps1=$bleopt_prompt_rps1
+ if [[ $opts == *:leave:* ]]; then
+ local ps1f=$bleopt_prompt_ps1_final
+ local rps1f=$bleopt_prompt_rps1_final
+ local ps1t=$bleopt_prompt_ps1_transient
+ [[ :$ps1t: == *:trim:* || :$ps1t: == *:same-dir:* && $PWD != $_ble_edit_line_opwd ]] && ps1t=
+ if [[ $ps1f || $rps1f || $ps1t ]]; then
+ prompt_opts=$prompt_opts:leave-rewrite
+ [[ $ps1f || $ps1t ]] && prompt_ps1=$ps1f
+ [[ $rps1f ]] && prompt_rps1=$rps1f
+ ble/textarea#invalidate
+ fi
+ fi
+ if [[ :$prompt_opts: == *:leave-rewrite:* || $_ble_prompt_hash != "$version" ]]; then
+ _ble_prompt_hash=$version
+ ((_ble_prompt_version++))
+ fi
+ ble/history/update-position
+ local prompt_hashref_base='$_ble_prompt_version'
+ local prompt_rows=${LINES:-25}
+ local prompt_cols=${COLUMNS:-80}
+ local "${_ble_prompt_cache_vars[@]/%/=}" # #D1570 OK
+ ble/prompt/unit#update _ble_prompt_ps1 && dirty=1
+ [[ $MC_SID == $$ ]] && { [[ $dirty ]]; return $?; }
+ ((_ble_textarea_panel==0)) || { [[ $dirty ]]; return $?; }
+ if [[ :$opts: == *:leave:* && ! $rps1f && $bleopt_prompt_rps1_transient ]]; then
+ [[ ${_ble_prompt_rps1_data[10]} ]] && dirty=1 _ble_prompt_rps1_enabled=erase
+ else
+ [[ $prompt_rps1 || ${_ble_prompt_rps1_data[10]} ]] &&
+ ble/prompt/unit#update _ble_prompt_rps1 && dirty=1
+ [[ ${_ble_prompt_rps1_data[10]} ]] && _ble_prompt_rps1_enabled=1
+ fi
+ case ${_ble_term_TERM:-$TERM:-} in
+ (sun*|minix*) ;; # black list
+ (*)
+ [[ $bleopt_prompt_xterm_title || ${_ble_prompt_xterm_title_data[10]} ]] &&
+ ble/prompt/unit#update _ble_prompt_xterm_title && dirty=1 ;;
+ esac
+ case ${_ble_term_TERM:-$TERM:-} in
+ (screen:*|tmux:*|contra:*|screen.*|screen-*)
+ [[ $bleopt_prompt_screen_title || ${_ble_prompt_screen_title_data[10]} ]] &&
+ ble/prompt/unit#update _ble_prompt_screen_title && dirty=1 ;;
+ esac
+ if [[ $_ble_term_tsl && $_ble_term_fsl ]]; then
+ [[ $bleopt_prompt_term_status || ${_ble_prompt_term_status_data[10]} ]] &&
+ ble/prompt/unit#update _ble_prompt_term_status && dirty=1
+ fi
+ [[ $bleopt_prompt_status_line || ${_ble_prompt_status_data[10]} ]] &&
+ ble/prompt/unit#update _ble_prompt_status && dirty=1
+ [[ $dirty ]] && _ble_prompt_update_dirty=dirty
+ [[ $dirty ]]
+}
+function ble/prompt/clear {
+ _ble_prompt_hash=
+ ble/textarea#invalidate
+}
+_ble_prompt_ruler=('' '' 0)
+function ble/prompt/print-ruler.draw {
+ [[ $bleopt_prompt_ruler ]] || return 0
+ local command=$1 opts=$2 cols=$COLUMNS
+ local rex_eval_prefix='(([!{]|time|if|then|elif|while|until|do|exec|eval|command|env|nice|nohup|xargs|sudo)[[:space:]]+)?'
+ local rex_clear_command='(tput[[:space:]]+)?(clear|reset)'
+ local rex=$'(^|[\n;&|(])[[:space:]]*'$rex_eval_prefix$rex_clear_command'([ \t\n;&|)]|$)'
+ [[ $command =~ $rex ]] && return 0
+ if [[ :$opts: == *:keep-info:* ]]; then
+ ble/canvas/panel#increase-height.draw "$_ble_textarea_panel" 1
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 0
+ ((_ble_canvas_panel_height[_ble_textarea_panel]--))
+ fi
+ if [[ $bleopt_prompt_ruler == empty-line ]]; then
+ ble/canvas/put.draw $'\n'
+ else
+ if [[ $bleopt_prompt_ruler != "${_ble_prompt_ruler[0]}" ]]; then
+ if [[ $bleopt_prompt_ruler ]]; then
+ local ret= x=0 y=0 g=0 x1=0 x2=0 y1=0 y2=0
+ LINES=1 COLUMNS=$cols ble/canvas/trace "$bleopt_prompt_ruler" truncate:measure-bbox
+ _ble_prompt_ruler=("$bleopt_prompt_ruler" "$ret" "$x2")
+ if ((!_ble_prompt_ruler[2])); then
+ _ble_prompt_ruler[1]=${_ble_prompt_ruler[1]}' '
+ ((_ble_prompt_ruler[2]++))
+ fi
+ else
+ _ble_prompt_ruler=('' '' 0)
+ fi
+ fi
+ local w=${_ble_prompt_ruler[2]}
+ local repeat=$((cols/w))
+ ble/string#repeat "${_ble_prompt_ruler[1]}" "$repeat"
+ ble/canvas/put.draw "$ret"
+ ble/string#repeat ' ' $((cols-repeat*w))
+ ble/canvas/put.draw "$ret"
+ ((_ble_term_xenl)) && ble/canvas/put.draw $'\n'
+ fi
+}
+function ble/prompt/print-ruler.buff {
+ local -a DRAW_BUFF=()
+ ble/prompt/print-ruler.draw "$@"
+ ble/canvas/bflush.draw
+}
+function ble/edit/info/.initialize-size {
+ local ret
+ ble/canvas/panel/layout/.get-available-height "$_ble_edit_info_panel"
+ cols=${COLUMNS-80} lines=$ret
+}
+_ble_edit_info_panel=2
+_ble_edit_info=(0 0 "")
+_ble_edit_info_invalidated=
+function ble/edit/info#panel::getHeight {
+ (($1!=_ble_edit_info_panel)) && return 0
+ if ble/edit/is-command-layout || [[ ! ${_ble_edit_info[2]} ]]; then
+ height=0:0
+ else
+ height=1:$((_ble_edit_info[1]+1))
+ fi
+}
+function ble/edit/info#panel::invalidate {
+ (($1!=_ble_edit_info_panel)) && return 0
+ _ble_edit_info_invalidated=1
+}
+function ble/edit/info#panel::render {
+ (($1!=_ble_edit_info_panel)) && return 0
+ ble/edit/is-command-layout && return 0
+ [[ $_ble_edit_info_invalidated ]] || return 0
+ local x=${_ble_edit_info[0]} y=${_ble_edit_info[1]} content=${_ble_edit_info[2]}
+ local -a DRAW_BUFF=()
+ if [[ ! $content ]]; then
+ ble/canvas/panel#set-height.draw "$_ble_edit_info_panel" 0
+ else
+ ble/canvas/panel/reallocate-height.draw
+ if ((y<_ble_canvas_panel_height[$1])); then
+ ble/canvas/panel#clear.draw "$_ble_edit_info_panel"
+ ble/canvas/panel#goto.draw "$_ble_edit_info_panel"
+ ble/canvas/put.draw "$content"
+ ((_ble_canvas_y+=y,_ble_canvas_x=x))
+ else
+ _ble_edit_info=(0 0 "")
+ ble/canvas/panel#set-height.draw "$_ble_edit_info_panel" 0
+ fi
+ fi
+ ble/canvas/bflush.draw
+ _ble_edit_info_invalidated=
+}
+function ble/edit/info#collapse {
+ local panel=${1-$_ble_prompt_info_panel}
+ ((panel!=_ble_edit_info_panel)) && return 0
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#set-height.draw "$panel" 0
+ ble/canvas/bflush.draw
+ _ble_edit_info_invalidated=1
+}
+function ble/edit/info/.construct-content {
+ local cols lines
+ ble/edit/info/.initialize-size
+ x=0 y=0 content=
+ local type=$1 text=$2
+ case "$1" in
+ (clear) ;;
+ (ansi|esc)
+ local trace_opts=truncate
+ [[ $bleopt_info_display == bottom ]] && trace_opts=$trace_opts:noscrc
+ [[ $1 == esc ]] && trace_opts=$trace_opts:terminfo
+ local ret= g=0
+ LINES=$lines ble/canvas/trace "$text" "$trace_opts"
+ content=$ret ;;
+ (text)
+ local ret
+ ble/canvas/trace-text "$text"
+ content=$ret ;;
+ (store)
+ x=$2 y=$3 content=$4
+ ((y<lines)) || ble/edit/info/.construct-content esc "$content" ;;
+ (*)
+ ble/util/print "usage: ble/edit/info/.construct-content type text" >&2 ;;
+ esac
+}
+function ble/edit/info/.render-content {
+ local x=$1 y=$2 content=$3 opts=$4
+ if [[ $content != "${_ble_edit_info[2]}" ]]; then
+ _ble_edit_info=("$x" "$y" "$content")
+ _ble_edit_info_invalidated=1
+ fi
+ [[ :$opts: == *:defer:* ]] && return 0
+ [[ $_ble_app_render_mode == panel ]] || return 0
+ ble/edit/info#panel::render "$_ble_edit_info_panel"
+}
+_ble_edit_info_default=(0 0 "")
+_ble_edit_info_scene=default
+function ble/edit/info/show {
+ local type=$1 text=$2
+ if [[ $text ]]; then
+ local x y content=
+ ble/edit/info/.construct-content "$@"
+ ble/edit/info/.render-content "$x" "$y" "$content"
+ ble/util/buffer.flush >&2
+ _ble_edit_info_scene=show
+ else
+ ble/edit/info/default
+ fi
+}
+function ble/edit/info/set-default {
+ local type=$1 text=$2
+ local x y content
+ ble/edit/info/.construct-content "$type" "$text"
+ _ble_edit_info_default=("$x" "$y" "$content")
+ [[ $_ble_edit_info_scene == default ]] &&
+ ble/edit/info/.render-content "${_ble_edit_info_default[@]}" defer
+}
+function ble/edit/info/default {
+ _ble_edit_info_scene=default
+ if (($#)); then
+ ble/edit/info/set-default "$@"
+ else
+ ble/edit/info/.render-content "${_ble_edit_info_default[@]}" defer
+ fi
+ return 0
+}
+function ble/edit/info/clear {
+ [[ ${_ble_edit_info[2]} ]] || return 1
+ [[ $_ble_app_render_mode == panel ]] || return 0
+ _ble_edit_info_scene=clear
+ ble/edit/info/.render-content 0 0 ""
+}
+function ble/edit/info/immediate-show {
+ local ret; ble/canvas/panel/save-position
+ ble/edit/info/show "$@"
+ ble/canvas/panel/load-position "$ret"
+ ble/util/buffer.flush >&2
+}
+function ble/edit/info/immediate-default {
+ local ret; ble/canvas/panel/save-position
+ ble/edit/info/default
+ ble/edit/info/.render-content "${_ble_edit_info_default[@]}"
+ ble/canvas/panel/load-position "$ret"
+ ble/util/buffer.flush >&2
+}
+_ble_edit_VARNAMES=(
+ _ble_edit_str
+ _ble_edit_ind
+ _ble_edit_mark
+ _ble_edit_mark_active
+ _ble_edit_overwrite_mode
+ _ble_edit_line_disabled
+ _ble_edit_arg
+ _ble_edit_dirty_draw_beg
+ _ble_edit_dirty_draw_end
+ _ble_edit_dirty_draw_end0
+ _ble_edit_dirty_syntax_beg
+ _ble_edit_dirty_syntax_end
+ _ble_edit_dirty_syntax_end0
+ _ble_edit_dirty_observer
+ _ble_edit_kill_index
+ _ble_edit_kill_ring
+ _ble_edit_kill_type)
+_ble_edit_str=
+_ble_edit_ind=0
+_ble_edit_mark=0
+_ble_edit_mark_active=
+_ble_edit_overwrite_mode=
+_ble_edit_line_disabled=
+_ble_edit_arg=
+_ble_edit_kill_index=0
+_ble_edit_kill_ring=()
+_ble_edit_kill_type=()
+function ble-edit/content/replace {
+ local beg=$1 end=$2
+ local ins=$3 reason=${4:-edit}
+ _ble_edit_str="${_ble_edit_str::beg}""$ins""${_ble_edit_str:end}"
+ ble-edit/content/.update-dirty-range "$beg" $((beg+${#ins})) "$end" "$reason"
+ ble/util/assert \
+ '((0<=_ble_edit_dirty_syntax_beg&&_ble_edit_dirty_syntax_end<=${#_ble_edit_str}))' \
+ "0 <= beg=$_ble_edit_dirty_syntax_beg <= end=$_ble_edit_dirty_syntax_end <= len=${#_ble_edit_str}; beg=$beg, end=$end, ins(${#ins})=$ins" ||
+ {
+ _ble_edit_dirty_syntax_beg=0
+ _ble_edit_dirty_syntax_end=${#_ble_edit_str}
+ _ble_edit_dirty_syntax_end0=0
+ local olen=$((${#_ble_edit_str}-${#ins}+end-beg))
+ ((olen<0&&(olen=0),
+ _ble_edit_ind>olen&&(_ble_edit_ind=olen),
+ _ble_edit_mark>olen&&(_ble_edit_mark=olen)))
+ }
+}
+function ble-edit/content/reset {
+ local str=$1 reason=${2:-edit}
+ local beg=0 end=${#str} end0=${#_ble_edit_str}
+ _ble_edit_str=$str
+ ble-edit/content/.update-dirty-range "$beg" "$end" "$end0" "$reason"
+ ble/util/assert \
+ '((0<=_ble_edit_dirty_syntax_beg&&_ble_edit_dirty_syntax_end<=${#_ble_edit_str}))' \
+ "0 <= beg=$_ble_edit_dirty_syntax_beg <= end=$_ble_edit_dirty_syntax_end <= len=${#_ble_edit_str}; str(${#str})=$str" ||
+ {
+ _ble_edit_dirty_syntax_beg=0
+ _ble_edit_dirty_syntax_end=${#_ble_edit_str}
+ _ble_edit_dirty_syntax_end0=0
+ }
+}
+function ble-edit/content/reset-and-check-dirty {
+ local str=$1 reason=${2:-edit}
+ [[ $_ble_edit_str == "$str" ]] && return 0
+ local ret pref suff
+ ble/string#common-prefix "$_ble_edit_str" "$str"; pref=$ret
+ local dmin=${#pref}
+ ble/string#common-suffix "${_ble_edit_str:dmin}" "${str:dmin}"; suff=$ret
+ local dmax0=$((${#_ble_edit_str}-${#suff})) dmax=$((${#str}-${#suff}))
+ _ble_edit_str=$str
+ ble-edit/content/.update-dirty-range "$dmin" "$dmax" "$dmax0" "$reason"
+}
+function ble-edit/content/replace-limited {
+ insert=$3
+ if [[ $bleopt_line_limit_type == discard ]]; then
+ local ibeg=$1 iend=$2 opts=:$4:
+ local limit=$((bleopt_line_limit_length))
+ if ((limit)); then
+ local inslimit=$((limit-${#_ble_edit_str}+(iend-ibeg)))
+ ((inslimit<iend-ibeg&&(inslimit=iend-ibeg)))
+ ((${#insert}>inslimit)) && insert=${insert::inslimit}
+ if [[ ! $insert ]] && ((ibeg==iend)); then
+ [[ $opts == *:nobell:* ]] ||
+ ble/widget/.bell "ble: reached line_limit_length=$limit"
+ return 1
+ fi
+ fi
+ fi
+ ble-edit/content/replace "$1" "$2" "$insert"
+}
+function ble-edit/content/check-limit {
+ local opts=:${1:-truncate:editor}:
+ if [[ $opts == *:${bleopt_line_limit_type:-none}:* ]]; then
+ local limit=$((bleopt_line_limit_length))
+ if ((limit>0&&${#_ble_edit_str}>limit)); then
+ local ble_edit_line_limit=$limit
+ ble-decode-key "$_ble_decode_KCODE_LINE_LIMIT"
+ fi
+ fi
+}
+function ble/widget/__line_limit__ {
+ local editor=ble/widget/${1:-edit-and-execute-command.impl}
+ local limit=$ble_edit_line_limit
+ case ${bleopt_line_limit_type:-none} in
+ (editor)
+ local content=$_ble_edit_str
+ ble-edit/content/reset "# reached line_limit_length=$limit"
+ _ble_edit_ind=0 _ble_edit_mark=0
+ "$editor" "$content"
+ (($?==127)) &&
+ ble-edit/content/reset "${content::limit}"
+ return 1 ;;
+ (truncate|*)
+ ble-edit/content/replace "$limit" "${#_ble_edit_str}" ''
+ ((_ble_edit_ind>limit&&(_ble_edit_ind=limit)))
+ ((_ble_edit_mark>limit&&(_ble_edit_mark=limit)))
+ return 1 ;;
+ esac
+ return 0
+}
+_ble_edit_dirty_draw_beg=-1
+_ble_edit_dirty_draw_end=-1
+_ble_edit_dirty_draw_end0=-1
+_ble_edit_dirty_syntax_beg=0
+_ble_edit_dirty_syntax_end=0
+_ble_edit_dirty_syntax_end0=1
+_ble_edit_dirty_observer=()
+function ble-edit/content/.update-dirty-range {
+ ble/dirty-range#update --prefix=_ble_edit_dirty_draw_ "${@:1:3}"
+ ble/dirty-range#update --prefix=_ble_edit_dirty_syntax_ "${@:1:3}"
+ ble/textmap#update-dirty-range "${@:1:3}"
+ local obs
+ for obs in "${_ble_edit_dirty_observer[@]}"; do "$obs" "$@"; done
+}
+function ble-edit/content/update-syntax {
+ if ble/util/import/is-loaded "$_ble_base/lib/core-syntax.sh"; then
+ local beg end end0
+ ble/dirty-range#load --prefix=_ble_edit_dirty_syntax_
+ if ((beg>=0)); then
+ ble/dirty-range#clear --prefix=_ble_edit_dirty_syntax_
+ ble/syntax/parse "$_ble_edit_str" '' "$beg" "$end" "$end0"
+ fi
+ fi
+}
+function ble-edit/content/eolp {
+ local pos=${1:-$_ble_edit_ind}
+ ((pos==${#_ble_edit_str})) || [[ ${_ble_edit_str:pos:1} == $'\n' ]]
+}
+function ble-edit/content/bolp {
+ local pos=${1:-$_ble_edit_ind}
+ ((pos<=0)) || [[ ${_ble_edit_str:pos-1:1} == $'\n' ]]
+}
+function ble-edit/content/find-logical-eol {
+ local index=${1:-$_ble_edit_ind} offset=${2:-0}
+ if ((offset>0)); then
+ local text=${_ble_edit_str:index}
+ local rex=$'^([^\n]*\n){0,'$((offset-1))$'}([^\n]*\n)?[^\n]*'
+ [[ $text =~ $rex ]]
+ ((ret=index+${#BASH_REMATCH}))
+ [[ ${BASH_REMATCH[2]} ]]
+ elif ((offset<0)); then
+ local text=${_ble_edit_str::index}
+ local rex=$'(\n[^\n]*){0,'$((-offset-1))$'}(\n[^\n]*)?$'
+ [[ $text =~ $rex ]]
+ if [[ $BASH_REMATCH ]]; then
+ ((ret=index-${#BASH_REMATCH}))
+ [[ ${BASH_REMATCH[2]} ]]
+ else
+ ble-edit/content/find-logical-eol "$index" 0
+ return 1
+ fi
+ else
+ local text=${_ble_edit_str:index}
+ text=${text%%$'\n'*}
+ ((ret=index+${#text}))
+ return 0
+ fi
+}
+function ble-edit/content/find-logical-bol {
+ local index=${1:-$_ble_edit_ind} offset=${2:-0}
+ if ((offset>0)); then
+ local rex=$'^([^\n]*\n){0,'$((offset-1))$'}([^\n]*\n)?'
+ [[ ${_ble_edit_str:index} =~ $rex ]]
+ if [[ $BASH_REMATCH ]]; then
+ ((ret=index+${#BASH_REMATCH}))
+ [[ ${BASH_REMATCH[2]} ]]
+ else
+ ble-edit/content/find-logical-bol "$index" 0
+ return 1
+ fi
+ elif ((offset<0)); then
+ ble-edit/content/find-logical-eol "$index" "$offset"; local ext=$?
+ ble-edit/content/find-logical-bol "$ret" 0
+ return "$ext"
+ else
+ local text=${_ble_edit_str::index}
+ text=${text##*$'\n'}
+ ((ret=index-${#text}))
+ return 0
+ fi
+}
+function ble-edit/content/find-non-space {
+ local bol=$1
+ local rex=$'^[ \t]*'; [[ ${_ble_edit_str:bol} =~ $rex ]]
+ ret=$((bol+${#BASH_REMATCH}))
+}
+function ble-edit/content/is-single-line {
+ [[ $_ble_edit_str != *$'\n'* ]]
+}
+function ble-edit/content/get-arg {
+ local default_value=$1
+ local value=$_ble_edit_arg
+ _ble_edit_arg=
+ if [[ $value == +* ]]; then
+ if [[ $value == + ]]; then
+ arg=4
+ return 0
+ fi
+ value=${value#+}
+ fi
+ if [[ $value == -* ]]; then
+ if [[ $value == - ]]; then
+ arg=-1
+ else
+ arg=$((-10#0${value#-}))
+ fi
+ else
+ if [[ $value ]]; then
+ arg=$((10#0$value))
+ else
+ arg=$default_value
+ fi
+ fi
+}
+function ble-edit/content/clear-arg {
+ _ble_edit_arg=
+}
+function ble-edit/content/toggle-arg {
+ if [[ $_ble_edit_arg == + ]]; then
+ _ble_edit_arg=
+ elif [[ $_ble_edit_arg && $_ble_edit_arg != +* ]]; then
+ _ble_edit_arg=+$_ble_edit_arg
+ else
+ _ble_edit_arg=+
+ fi
+}
+function ble/keymap:generic/clear-arg {
+ if [[ $_ble_decode_keymap == vi_[noxs]map ]]; then
+ ble/keymap:vi/clear-arg
+ else
+ ble-edit/content/clear-arg
+ fi
+}
+function ble/widget/append-arg-or {
+ local n=${#KEYS[@]}; ((n&&n--))
+ local code=$((KEYS[n]&_ble_decode_MaskChar))
+ ((code==0)) && return 1
+ local ret; ble/util/c2s "$code"; local ch=$ret
+ if
+ if [[ $_ble_edit_arg == + ]]; then
+ [[ $ch == [-0-9] ]] && _ble_edit_arg=
+ elif [[ $_ble_edit_arg == +* ]]; then
+ false
+ elif [[ $_ble_edit_arg ]]; then
+ [[ $ch == [0-9] ]]
+ else
+ ((KEYS[n]&_ble_decode_MaskFlag))
+ fi
+ then
+ ble/decode/widget/skip-lastwidget
+ _ble_edit_arg=$_ble_edit_arg$ch
+ else
+ ble/widget/"$@"
+ fi
+}
+function ble/widget/append-arg {
+ ble/widget/append-arg-or self-insert
+}
+function ble/widget/universal-arg {
+ ble/decode/widget/skip-lastwidget
+ ble-edit/content/toggle-arg
+}
+function ble-edit/content/prepend-kill-ring {
+ _ble_edit_kill_index=0
+ local otext=${_ble_edit_kill_ring[0]-} ntext=$1
+ local otype=${_ble_edit_kill_type[0]-} ntype=$2
+ if [[ $otype == L || $ntype == L ]]; then
+ ntext=${ntext%$'\n'}$'\n'
+ otext=${otext%$'\n'}$'\n'
+ _ble_edit_kill_ring[0]=$ntext$otext
+ _ble_edit_kill_type[0]=L
+ elif [[ $otype == B:* ]]; then
+ if [[ $ntype != B:* ]]; then
+ ntext=${ntext%$'\n'}$'\n'
+ local ret; ble/string#count-char "$ntext" $'\n'
+ ble/string#repeat '0 ' "$ret"
+ ntype=B:${ret%' '}
+ fi
+ _ble_edit_kill_ring[0]=$ntext$otext
+ _ble_edit_kill_type[0]="B:${ntype#B:} ${otype#B:}"
+ else
+ _ble_edit_kill_ring[0]=$ntext$otext
+ _ble_edit_kill_type[0]=$otype
+ fi
+}
+function ble-edit/content/append-kill-ring {
+ _ble_edit_kill_index=0
+ local otext=${_ble_edit_kill_ring[0]-} ntext=$1
+ local otype=${_ble_edit_kill_type[0]-} ntype=$2
+ if [[ $otype == L || $ntype == L ]]; then
+ ntext=${ntext%$'\n'}$'\n'
+ otext=${otext%$'\n'}$'\n'
+ _ble_edit_kill_ring[0]=$otext$ntext
+ _ble_edit_kill_type[0]=L
+ elif [[ $otype == B:* ]]; then
+ if [[ $ntype != B:* ]]; then
+ ntext=${ntext%$'\n'}$'\n'
+ local ret; ble/string#count-char "$ntext" $'\n'
+ ble/string#repeat '0 ' "$ret"
+ ntype=B:${ret%' '}
+ fi
+ _ble_edit_kill_ring[0]=$otext$ntext
+ _ble_edit_kill_type[0]="B:${otype#B:} ${ntype#B:}"
+ else
+ _ble_edit_kill_ring[0]=$otext$ntext
+ _ble_edit_kill_type[0]=$otype
+ fi
+}
+function ble-edit/content/push-kill-ring {
+ if ((${#_ble_edit_kill_ring[@]})) && [[ ${LASTWIDGET#ble/widget/} == kill-* || ${LASTWIDGET#ble/widget/} == copy-* ]]; then
+ local name; ble/string#split-words name "${WIDGET#ble/widget/}"
+ if [[ $name == kill-backward-* || $name == copy-backward-* ]]; then
+ ble-edit/content/prepend-kill-ring "$1" "$2"
+ return "$?"
+ elif [[ $name != kill-region* && $name != copy-region* ]]; then
+ ble-edit/content/append-kill-ring "$1" "$2"
+ return "$?"
+ fi
+ fi
+ _ble_edit_kill_index=0
+ ble/array#unshift _ble_edit_kill_ring "$1"
+ ble/array#unshift _ble_edit_kill_type "$2"
+}
+_ble_edit_PS1_adjusted=
+_ble_edit_PS1='\s-\v\$ '
+_ble_edit_PROMPT_COMMAND=
+function ble-edit/adjust-PS1 {
+ [[ $_ble_edit_PS1_adjusted ]] && return 0
+ _ble_edit_PS1_adjusted=1
+ _ble_edit_PS1=$PS1
+ if [[ $bleopt_internal_suppress_bash_output ]]; then
+ PS1='[ble: press RET to continue]'
+ else
+ PS1=
+ fi
+ if ble/is-array PROMPT_COMMAND; then
+ ble/idict#copy _ble_edit_PROMPT_COMMAND PROMPT_COMMAND
+ else
+ ble/variable#copy-state PROMPT_COMMAND _ble_edit_PROMPT_COMMAND
+ fi
+ builtin unset -v PROMPT_COMMAND
+}
+function ble-edit/restore-PS1 {
+ [[ $_ble_edit_PS1_adjusted ]] || return 1
+ _ble_edit_PS1_adjusted=
+ PS1=$_ble_edit_PS1
+ if ble/is-array _ble_edit_PROMPT_COMMAND; then
+ ble/idict#copy PROMPT_COMMAND _ble_edit_PROMPT_COMMAND
+ else
+ ble/variable#copy-state _ble_edit_PROMPT_COMMAND PROMPT_COMMAND
+ fi
+}
+_ble_edit_IGNOREEOF_adjusted=
+_ble_edit_IGNOREEOF=
+function ble-edit/adjust-IGNOREEOF {
+ [[ $_ble_edit_IGNOREEOF_adjusted ]] && return 0
+ _ble_edit_IGNOREEOF_adjusted=1
+ if [[ ${IGNOREEOF+set} ]]; then
+ _ble_edit_IGNOREEOF=$IGNOREEOF
+ else
+ builtin unset -v _ble_edit_IGNOREEOF
+ fi
+ if ((_ble_bash>=40000)); then
+ builtin unset -v IGNOREEOF
+ else
+ IGNOREEOF=9999
+ fi
+}
+function ble-edit/restore-IGNOREEOF {
+ [[ $_ble_edit_IGNOREEOF_adjusted ]] || return 1
+ _ble_edit_IGNOREEOF_adjusted=
+ if [[ ${_ble_edit_IGNOREEOF+set} ]]; then
+ IGNOREEOF=$_ble_edit_IGNOREEOF
+ else
+ builtin unset -v IGNOREEOF
+ fi
+}
+_ble_edit_READLINE=()
+function ble-edit/adjust-READLINE {
+ [[ $_ble_edit_READLINE ]] && return 0
+ _ble_edit_READLINE=1
+ ble/variable#copy-state READLINE_LINE '_ble_edit_READLINE[1]'
+ ble/variable#copy-state READLINE_POINT '_ble_edit_READLINE[2]'
+ ble/variable#copy-state READLINE_MARK '_ble_edit_READLINE[3]'
+}
+function ble-edit/restore-READLINE {
+ [[ $_ble_edit_READLINE ]] || return 0
+ _ble_edit_READLINE=
+ ble/variable#copy-state '_ble_edit_READLINE[1]' READLINE_LINE
+ ble/variable#copy-state '_ble_edit_READLINE[2]' READLINE_POINT
+ ble/variable#copy-state '_ble_edit_READLINE[3]' READLINE_MARK
+}
+function ble-edit/eval-IGNOREEOF {
+ local value=
+ if [[ $_ble_edit_IGNOREEOF_adjusted ]]; then
+ value=${_ble_edit_IGNOREEOF-0}
+ else
+ value=${IGNOREEOF-0}
+ fi
+ if [[ $value && ! ${value//[0-9]} ]]; then
+ ret=$((10#0$value))
+ else
+ ret=10
+ fi
+}
+bleopt/declare -n canvas_winch_action redraw-here
+function ble-edit/attach/TRAPWINCH {
+ ((_ble_edit_attached)) && [[ $_ble_term_state == internal ]] || return 0
+ ble/application/onwinch 2>&$_ble_util_fd_stderr
+}
+_ble_edit_attached=0
+function ble-edit/attach/.attach {
+ ((_ble_edit_attached)) && return 0
+ _ble_edit_attached=1
+ if [[ ! ${_ble_edit_LINENO+set} ]]; then
+ _ble_edit_LINENO=${BASH_LINENO[${#BASH_LINENO[@]}-1]}
+ ((_ble_edit_LINENO<0)) && _ble_edit_LINENO=0
+ builtin unset -v LINENO; LINENO=$_ble_edit_LINENO
+ _ble_edit_CMD=$_ble_edit_LINENO
+ fi
+ ble/builtin/trap/install-hook WINCH readline
+ blehook WINCH-+=ble-edit/attach/TRAPWINCH
+ ble-edit/adjust-PS1
+ ble-edit/adjust-READLINE
+ ble-edit/adjust-IGNOREEOF
+ [[ $bleopt_internal_exec_type == exec ]] && _ble_edit_IFS=$IFS
+}
+function ble-edit/attach/.detach {
+ ((!_ble_edit_attached)) && return 0
+ ble-edit/restore-PS1
+ ble-edit/restore-READLINE
+ ble-edit/restore-IGNOREEOF
+ [[ $bleopt_internal_exec_type == exec ]] && IFS=$_ble_edit_IFS
+ _ble_edit_attached=0
+}
+_ble_textarea_VARNAMES=(
+ _ble_textarea_buffer
+ _ble_textarea_bufferName
+ _ble_textarea_cur
+ _ble_textarea_panel
+ _ble_textarea_scroll
+ _ble_textarea_scroll_new
+ _ble_textarea_gendx
+ _ble_textarea_gendy
+ _ble_textarea_invalidated
+ _ble_textarea_version
+ _ble_textarea_caret_state
+ _ble_textarea_cache
+ _ble_textarea_render_defer)
+_ble_textarea_local_VARNAMES=()
+function ble/textarea#panel::getHeight {
+ if [[ $1 == "$_ble_textarea_panel" ]]; then
+ local min=$((_ble_prompt_ps1_data[4]+1)) max=$((_ble_textmap_endy+1))
+ ((min<max&&min++))
+ height=$min:$max
+ else
+ height=0:${_ble_canvas_panel_height[$1]}
+ fi
+}
+function ble/textarea#panel::onHeightChange {
+ [[ $1 == "$_ble_textarea_panel" ]] || return 1
+ if [[ ! $ble_textarea_render_flag ]]; then
+ ble/textarea#invalidate
+ fi
+}
+function ble/textarea#panel::invalidate {
+ if (($1==_ble_textarea_panel)); then
+ ble/textarea#invalidate
+ fi
+}
+function ble/textarea#panel::render {
+ if (($1==_ble_textarea_panel)); then
+ ble/textarea#render
+ fi
+}
+_ble_textarea_buffer=()
+_ble_textarea_bufferName=
+function ble/textarea#update-text-buffer {
+ local iN=${#text}
+ local beg end end0
+ ble/dirty-range#load --prefix=_ble_edit_dirty_draw_
+ ble/dirty-range#clear --prefix=_ble_edit_dirty_draw_
+ local HIGHLIGHT_BUFF HIGHLIGHT_UMIN HIGHLIGHT_UMAX
+ ble/highlight/layer/update "$text" '' "$beg" "$end" "$end0"
+ ble/urange#update "$HIGHLIGHT_UMIN" "$HIGHLIGHT_UMAX"
+ if ((${#_ble_textmap_ichg[@]})); then
+ local ichg g ret
+ builtin eval "_ble_textarea_buffer=(\"\${$HIGHLIGHT_BUFF[@]}\")"
+ HIGHLIGHT_BUFF=_ble_textarea_buffer
+ for ichg in "${_ble_textmap_ichg[@]}"; do
+ ble/highlight/layer/getg "$ichg"
+ ble/color/g2sgr "$g"
+ _ble_textarea_buffer[ichg]=$ret${_ble_textmap_glyph[ichg]}
+ done
+ fi
+ _ble_textarea_bufferName=$HIGHLIGHT_BUFF
+}
+function ble/textarea#update-left-char {
+ local index=$1
+ if [[ $bleopt_internal_suppress_bash_output ]]; then
+ lc=32 lg=0
+ return 0
+ fi
+ if ((index==0)); then
+ lc=${_ble_prompt_ps1_data[6]}
+ lg=${_ble_prompt_ps1_data[7]}
+ return 0
+ fi
+ local cx cy
+ ble/textmap#getxy.cur --prefix=c "$index"
+ local lcs ret
+ if ((cx==0)); then
+ if ((index==iN)); then
+ ret=32
+ else
+ lcs=${_ble_textmap_glyph[index]}
+ ble/util/s2c "$lcs"
+ fi
+ local g; ble/highlight/layer/getg "$index"; lg=$g
+ ((lc=ret==10?32:ret))
+ else
+ lcs=${_ble_textmap_glyph[index-1]}
+ ble/util/s2c "${lcs:${#lcs}-1}"
+ local g; ble/highlight/layer/getg $((index-1)); lg=$g
+ ((lc=ret))
+ fi
+}
+function ble/textarea#slice-text-buffer {
+ ble/textmap#assert-up-to-date
+ local iN=$_ble_textmap_length
+ local i1=${1:-0} i2=${2:-$iN}
+ ((i1<0&&(i1+=iN,i1<0&&(i1=0)),
+ i2<0&&(i2+=iN)))
+ if ((i1<i2&&i1<iN)); then
+ local g
+ ble/highlight/layer/getg "$i1"
+ ble/color/g2sgr "$g"
+ IFS= builtin eval "ret=\"\$ret\${$_ble_textarea_bufferName[*]:i1:i2-i1}\""
+ if [[ $_ble_textarea_bufferName == _ble_textarea_buffer ]]; then
+ local out= rex_nl='^(\[[ -?]*[@-~]|[ -/]+[@-~]|[])*'$_ble_term_nl
+ while [[ $ret == *"$_ble_term_cr"* ]]; do
+ out=$out${ret%%"$_ble_term_cr"*}
+ ret=${ret#*"$_ble_term_cr"}
+ if [[ $ret =~ $rex_nl ]]; then
+ out=$out$_ble_term_nl
+ elif [[ ! $ret ]]; then
+ if ((i2==iN)); then
+ out=$out' '$_ble_term_cr${_ble_term_ech//'%d'/1}
+ else
+ out=$out$_ble_term_nl
+ fi
+ fi
+ done
+ ret=$out$ret
+ fi
+ else
+ ret=
+ fi
+}
+_ble_textarea_cur=(0 0 32 0)
+_ble_textarea_panel=0
+_ble_textarea_scroll=
+_ble_textarea_scroll_new=
+_ble_textarea_gendx=0
+_ble_textarea_gendy=0
+_ble_textarea_invalidated=1
+function ble/textarea#invalidate {
+ if [[ $1 == str || $1 == partial ]]; then
+ ((_ble_textarea_version++))
+ else
+ _ble_textarea_invalidated=1
+ fi
+ return 0
+}
+function ble/textarea#render/.erase-forward-line.draw {
+ local eraser=$_ble_term_sgr0$_ble_term_el
+ if [[ :$render_opts: == *:relative:* ]]; then
+ local width=$((cols-x))
+ if ((width==0)); then
+ eraser=
+ elif [[ $_ble_term_ech ]]; then
+ eraser=$_ble_term_sgr0${_ble_term_ech//'%d'/$width}
+ else
+ ble/string#reserve-prototype "$width"
+ eraser=$_ble_term_sgr0${_ble_string_prototype::width}${_ble_term_cub//'%d'/$width}
+ fi
+ fi
+ ble/canvas/put.draw "$eraser"
+}
+function ble/textarea#render/.determine-scroll {
+ local nline=$((endy+1))
+ if ((height!=nline)); then
+ ble/canvas/panel/reallocate-height.draw
+ height=${_ble_canvas_panel_height[_ble_textarea_panel]}
+ fi
+ if ((height<nline)); then
+ ((scroll<=nline-height)) || ((scroll=nline-height))
+ local _height=$((height-begy)) _nline=$((nline-begy)) _cy=$((cy-begy))
+ local margin=$((_height>=6&&_nline>_height+2?2:1))
+ local smin smax
+ ((smin=_cy-_height+margin,
+ smin>nline-height&&(smin=nline-height),
+ smax=_cy-margin,
+ smax<0&&(smax=0)))
+ if ((scroll>smax)); then
+ scroll=$smax
+ elif ((scroll<smin)); then
+ scroll=$smin
+ fi
+ local wmin=0 wmax index
+ if ((scroll)); then
+ ble/textmap#get-index-at 0 $((scroll+begy+1)); wmin=$index
+ fi
+ ble/textmap#get-index-at "$cols" $((scroll+height-1)); wmax=$index
+ ((umin<umax)) &&
+ ((umin<wmin&&(umin=wmin),
+ umax>wmax&&(umax=wmax)))
+ else
+ scroll=
+ if ! ble/util/assert '((height==nline))'; then
+ ble/canvas/panel#set-height.draw "$_ble_textarea_panel" "$nline"
+ height=$nline
+ fi
+ fi
+}
+function ble/textarea#render/.perform-scroll {
+ local new_scroll=$1
+ if ((new_scroll!=_ble_textarea_scroll)); then
+ local scry=$((begy+1))
+ local scrh=$((height-scry))
+ local fmin fmax index
+ if ((_ble_textarea_scroll>new_scroll)); then
+ local shift=$((_ble_textarea_scroll-new_scroll))
+ local draw_shift=$((shift<scrh?shift:scrh))
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 $((height-draw_shift))
+ ble/canvas/put-dl.draw "$draw_shift" panel
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 "$scry"
+ ble/canvas/put-il.draw "$draw_shift" panel
+ if ((new_scroll==0)); then
+ fmin=0
+ else
+ ble/textmap#get-index-at 0 $((scry+new_scroll)); fmin=$index
+ fi
+ ble/textmap#get-index-at "$cols" $((scry+new_scroll+draw_shift-1)); fmax=$index
+ else
+ local shift=$((new_scroll-_ble_textarea_scroll))
+ local draw_shift=$((shift<scrh?shift:scrh))
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 "$scry"
+ ble/canvas/put-dl.draw "$draw_shift" panel
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 $((height-draw_shift))
+ ble/canvas/put-il.draw "$draw_shift" panel
+ ble/textmap#get-index-at 0 $((new_scroll+height-draw_shift)); fmin=$index
+ ble/textmap#get-index-at "$cols" $((new_scroll+height-1)); fmax=$index
+ fi
+ if ((fmin<fmax)); then
+ local fmaxx fmaxy fminx fminy
+ ble/textmap#getxy.out --prefix=fmin "$fmin"
+ ble/textmap#getxy.out --prefix=fmax "$fmax"
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$fminx" $((fminy-new_scroll))
+ ((new_scroll==0)) &&
+ x=$fminx ble/textarea#render/.erase-forward-line.draw # ... を消す
+ local ret; ble/textarea#slice-text-buffer "$fmin" "$fmax"
+ ble/canvas/put.draw "$ret"
+ ((_ble_canvas_x=fmaxx,
+ _ble_canvas_y+=fmaxy-fminy))
+ ((umin<umax)) &&
+ ((fmin<=umin&&umin<fmax&&(umin=fmax),
+ fmin<umax&&umax<=fmax&&(umax=fmin)))
+ fi
+ _ble_textarea_scroll=$new_scroll
+ ble/textarea#render/.show-scroll-at-first-line
+ fi
+}
+function ble/textarea#render/.show-scroll-at-first-line {
+ if ((_ble_textarea_scroll!=0)); then
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$begx" "$begy"
+ local scroll_status="(line $((_ble_textarea_scroll+2))) ..."
+ scroll_status=${scroll_status::cols-1-begx}
+ x=$begx ble/textarea#render/.erase-forward-line.draw
+ ble/canvas/put.draw "$eraser$_ble_term_bold$scroll_status$_ble_term_sgr0"
+ ((_ble_canvas_x+=${#scroll_status}))
+ fi
+}
+function ble/textarea#render/.erase-rprompt {
+ [[ $_ble_prompt_rps1_shown ]] || return 0
+ _ble_prompt_rps1_shown=
+ local rps1_height=${_ble_prompt_rps1_gbox[3]}
+ local -a DRAW_BUFF=()
+ local y=0
+ for ((y=0;y<rps1_height;y++)); do
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" $((cols+1)) "$y" sgr0
+ ble/canvas/put.draw "$_ble_term_el"
+ done
+ ble/canvas/bflush.draw
+}
+function ble/textarea#render/.cleanup-trailing-spaces-after-newline {
+ local -a DRAW_BUFF=()
+ local -a buffer; ble/string#split-lines buffer "$text"
+ local line index=0 pos
+ for line in "${buffer[@]}"; do
+ ((index+=${#line}))
+ ble/string#split-words pos "${_ble_textmap_pos[index]}"
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "${pos[0]}" "${pos[1]}" sgr0
+ ble/canvas/put.draw "$_ble_term_el"
+ ((index++))
+ done
+ ble/canvas/bflush.draw
+ _ble_prompt_rps1_shown=
+}
+function ble/textarea#render/.show-control-string {
+ local ref_dirty=${1}_dirty ref_output=${1}_data[10] force=$2
+ [[ $force || ${!ref_dirty} ]] || return 0
+ ble/canvas/put.draw "${!ref_output}"
+ builtin eval -- "$ref_dirty="
+ return 0
+}
+function ble/textarea#render/.show-prompt {
+ [[ $1 || $_ble_prompt_ps1_dirty ]] || return 0
+ local esc=${_ble_prompt_ps1_data[8]}
+ local prox=${_ble_prompt_ps1_data[3]}
+ local proy=${_ble_prompt_ps1_data[4]}
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel"
+ ble/canvas/panel#put.draw "$_ble_textarea_panel" "$esc" "$prox" "$proy"
+ _ble_prompt_ps1_dirty=
+}
+function ble/textarea#render/.show-rprompt {
+ [[ $1 || $_ble_prompt_rps1_dirty ]] || return 0
+ local rps1out=${_ble_prompt_rps1_data[8]}
+ local rps1x=$((_ble_prompt_rps1_data[3]+COLUMNS-_ble_prompt_rps1_gbox[2]))
+ local rps1y=${_ble_prompt_rps1_data[4]}
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 0
+ ble/canvas/panel#put.draw "$_ble_textarea_panel" "$rps1out" "$rps1x" "$rps1y"
+ _ble_prompt_rps1_dirty=
+ _ble_prompt_rps1_shown=1
+}
+function ble/textarea#focus {
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "${_ble_textarea_cur[0]}" "${_ble_textarea_cur[1]}"
+ ble/canvas/bflush.draw
+}
+_ble_textarea_caret_state=::
+_ble_textarea_version=0
+function ble/textarea#render {
+ local opts=$1
+ local ble_textarea_render_flag=1 # ble/textarea#panel::onHeightChange から参照する
+ local caret_state=$_ble_textarea_version:$_ble_edit_ind:$_ble_edit_mark:$_ble_edit_mark_active:$_ble_edit_line_disabled:$_ble_edit_overwrite_mode
+ local dirty=
+ if ble/prompt/update "check-dirty:$opts"; then
+ dirty=1
+ elif ((_ble_edit_dirty_draw_beg>=0)); then
+ dirty=1
+ elif [[ $_ble_textarea_invalidated ]]; then
+ dirty=1
+ elif [[ $_ble_textarea_caret_state != "$caret_state" ]]; then
+ dirty=1
+ elif [[ $_ble_textarea_scroll != "$_ble_textarea_scroll_new" ]]; then
+ dirty=1
+ elif [[ :$opts: == *:leave:* || :$opts: == *:update:* ]]; then
+ dirty=1
+ fi
+ if [[ ! $dirty ]]; then
+ ble/textarea#focus
+ return 0
+ fi
+ local cols=${COLUMNS-80}
+ local subprompt_enabled=
+ ((_ble_textarea_panel==0)) && subprompt_enabled=1
+ local rps1_enabled=$_ble_prompt_rps1_enabled
+ local rps1_width=${_ble_prompt_rps1_data[11]}
+ if [[ $rps1_enabled ]]; then
+ ((cols-=rps1_width+1,_ble_term_xenl||cols--))
+ if [[ $rps1_enabled == erase ]]; then
+ ble/textarea#render/.erase-rprompt
+ rps1_enabled=
+ fi
+ fi
+ local text=$_ble_edit_str index=$_ble_edit_ind
+ local iN=${#text}
+ ((index<0?(index=0):(index>iN&&(index=iN))))
+ local umin=-1 umax=-1
+ local x=${_ble_prompt_ps1_data[3]}
+ local y=${_ble_prompt_ps1_data[4]}
+ local render_opts=
+ [[ $rps1_enabled ]] && render_opts=relative
+ COLUMNS=$cols ble/textmap#update "$text" "$render_opts" # [ref] x y
+ ble/urange#update "$_ble_textmap_umin" "$_ble_textmap_umax" # [ref] umin umax
+ ble/urange#clear --prefix=_ble_textmap_
+ local DMIN=$_ble_edit_dirty_draw_beg
+ ble-edit/content/update-syntax
+ ble/textarea#update-text-buffer # [in] text index [ref] lc lg;
+ local lc=32 lg=0
+ [[ $bleopt_internal_suppress_bash_output ]] ||
+ ble/textarea#update-left-char "$index"
+ local -a DRAW_BUFF=()
+ local begx=$_ble_textmap_begx begy=$_ble_textmap_begy
+ local endx=$_ble_textmap_endx endy=$_ble_textmap_endy
+ local cx cy
+ ble/textmap#getxy.cur --prefix=c "$index" # → cx cy
+ local cols=$_ble_textmap_cols
+ local height=${_ble_canvas_panel_height[_ble_textarea_panel]}
+ local scroll=${_ble_textarea_scroll_new:-$_ble_textarea_scroll}
+ ble/textarea#render/.determine-scroll # update: height scroll umin umax
+ local gend gendx gendy
+ if [[ $scroll ]]; then
+ ble/textmap#get-index-at "$cols" $((height+scroll-1)); gend=$index
+ ble/textmap#getxy.out --prefix=gend "$gend"
+ ((gendy-=scroll))
+ else
+ gend=$iN gendx=$endx gendy=$endy
+ fi
+ _ble_textarea_gendx=$gendx _ble_textarea_gendy=$gendy
+ local ret esc_line= esc_line_set=
+ if [[ ! $_ble_textarea_invalidated ]]; then
+ [[ ! $rps1_enabled && $_ble_prompt_rps1_shown || $rps1_enabled && $_ble_prompt_rps1_dirty ]] &&
+ ble/textarea#render/.cleanup-trailing-spaces-after-newline
+ ble/textarea#render/.perform-scroll "$scroll" # update: umin umax
+ _ble_textarea_scroll_new=$_ble_textarea_scroll
+ [[ $rps1_enabled ]] && ble/textarea#render/.show-rprompt
+ ble/textarea#render/.show-prompt
+ if [[ $subprompt_enabled ]]; then
+ ble/textarea#render/.show-control-string _ble_prompt_xterm_title
+ ble/textarea#render/.show-control-string _ble_prompt_screen_title
+ ble/textarea#render/.show-control-string _ble_prompt_term_status
+ fi
+ if ((umin<umax)); then
+ local uminx uminy umaxx umaxy
+ ble/textmap#getxy.out --prefix=umin "$umin"
+ ble/textmap#getxy.out --prefix=umax "$umax"
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$uminx" $((uminy-_ble_textarea_scroll))
+ ble/textarea#slice-text-buffer "$umin" "$umax"
+ ble/canvas/panel#put.draw "$_ble_textarea_panel" "$ret" "$umaxx" $((umaxy-_ble_textarea_scroll))
+ fi
+ if ((DMIN>=0)); then
+ local endY=$((endy-_ble_textarea_scroll))
+ if ((endY<height)); then
+ if [[ :$render_opts: == *:relative:* ]]; then
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$endx" "$endY"
+ x=$endx ble/textarea#render/.erase-forward-line.draw
+ ble/canvas/panel#clear-after.draw "$_ble_textarea_panel" 0 $((endY+1))
+ else
+ ble/canvas/panel#clear-after.draw "$_ble_textarea_panel" "$endx" "$endY"
+ fi
+ fi
+ fi
+ else
+ ble/canvas/panel#clear.draw "$_ble_textarea_panel"
+ _ble_prompt_rps1_shown=
+ [[ $rps1_enabled ]] && ble/textarea#render/.show-rprompt force
+ ble/textarea#render/.show-prompt force
+ if [[ $subprompt_enabled ]]; then
+ ble/textarea#render/.show-control-string _ble_prompt_xterm_title force
+ ble/textarea#render/.show-control-string _ble_prompt_screen_title force
+ ble/textarea#render/.show-control-string _ble_prompt_term_status force
+ fi
+ _ble_textarea_scroll=$scroll
+ _ble_textarea_scroll_new=$_ble_textarea_scroll
+ if [[ ! $_ble_textarea_scroll ]]; then
+ ble/textarea#slice-text-buffer # → ret
+ esc_line=$ret esc_line_set=1
+ ble/canvas/panel#put.draw "$_ble_textarea_panel" "$ret" "$_ble_textarea_gendx" "$_ble_textarea_gendy"
+ else
+ ble/textarea#render/.show-scroll-at-first-line
+ local gbeg=0
+ if ((_ble_textarea_scroll)); then
+ ble/textmap#get-index-at 0 $((_ble_textarea_scroll+begy+1)); gbeg=$index
+ fi
+ local gbegx gbegy
+ ble/textmap#getxy.out --prefix=gbeg "$gbeg"
+ ((gbegy-=_ble_textarea_scroll))
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$gbegx" "$gbegy"
+ ((_ble_textarea_scroll==0)) &&
+ x=$gbegx ble/textarea#render/.erase-forward-line.draw # ... を消す
+ ble/textarea#slice-text-buffer "$gbeg" "$gend"
+ ble/canvas/panel#put.draw "$_ble_textarea_panel" "$ret" "$_ble_textarea_gendx" "$_ble_textarea_gendy"
+ fi
+ fi
+ local gcx=$cx gcy=$((cy-_ble_textarea_scroll))
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$gcx" "$gcy"
+ ble/canvas/bflush.draw
+ _ble_textarea_cur=("$gcx" "$gcy" "$lc" "$lg")
+ _ble_textarea_invalidated= _ble_textarea_caret_state=$caret_state
+ if [[ ! $bleopt_internal_suppress_bash_output ]]; then
+ if [[ ! $esc_line_set ]]; then
+ if [[ ! $_ble_textarea_scroll ]]; then
+ ble/textarea#slice-text-buffer
+ esc_line=$ret
+ else
+ local _ble_canvas_x=$begx _ble_canvas_y=$begy
+ DRAW_BUFF=()
+ ble/textarea#render/.show-scroll-at-first-line
+ local gbeg=0
+ if ((_ble_textarea_scroll)); then
+ ble/textmap#get-index-at 0 $((_ble_textarea_scroll+begy+1)); gbeg=$index
+ fi
+ local gbegx gbegy
+ ble/textmap#getxy.out --prefix=gbeg "$gbeg"
+ ((gbegy-=_ble_textarea_scroll))
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$gbegx" "$gbegy"
+ ((_ble_textarea_scroll==0)) &&
+ x=$gbegx ble/textarea#render/.erase-forward-line.draw # ... を消す
+ ble/textarea#slice-text-buffer "$gbeg" "$gend"
+ ble/canvas/put.draw "$ret"
+ ble/canvas/sflush.draw -v esc_line
+ fi
+ fi
+ local esc=${_ble_prompt_ps1_data[8]}
+ esc=${_ble_prompt_xterm_title_data[10]}$esc
+ esc=${_ble_prompt_screen_title_data[10]}$esc
+ esc=${_ble_prompt_term_status_data[10]}$esc
+ _ble_textarea_cache=(
+ "$esc$esc_line"
+ "${_ble_textarea_cur[@]}"
+ "$_ble_textarea_gendx" "$_ble_textarea_gendy")
+ fi
+}
+function ble/textarea#redraw {
+ ble/textarea#invalidate
+ ble/textarea#render
+}
+_ble_textarea_cache=()
+function ble/textarea#redraw-cache {
+ if [[ ! $_ble_textarea_scroll && ${_ble_textarea_cache[0]+set} ]]; then
+ local -a d; d=("${_ble_textarea_cache[@]}")
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#clear.draw "$_ble_textarea_panel"
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel"
+ ble/canvas/put.draw "${d[0]}"
+ ble/canvas/panel#report-cursor-position "$_ble_textarea_panel" "${d[5]}" "${d[6]}"
+ _ble_textarea_gendx=${d[5]}
+ _ble_textarea_gendy=${d[6]}
+ _ble_textarea_cur=("${d[@]:1:4}")
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "${_ble_textarea_cur[0]}" "${_ble_textarea_cur[1]}"
+ ble/canvas/bflush.draw
+ else
+ ble/textarea#redraw
+ fi
+}
+function ble/textarea#adjust-for-bash-bind {
+ ble-edit/adjust-PS1
+ if [[ $bleopt_internal_suppress_bash_output ]]; then
+ READLINE_LINE=$'\n' READLINE_POINT=0 READLINE_MARK=0
+ else
+ local -a DRAW_BUFF=()
+ local ret lc=${_ble_textarea_cur[2]} lg=${_ble_textarea_cur[3]}
+ ble/util/c2s "$lc"
+ READLINE_LINE=$ret READLINE_MARK=0
+ if ((_ble_textarea_cur[0]==0)); then
+ READLINE_POINT=0
+ else
+ ble/util/c2w "$lc"
+ ((ret>0)) && ble/canvas/put-cub.draw "$ret"
+ ble/util/c2bc "$lc"
+ READLINE_POINT=$ret
+ fi
+ ble/color/g2sgr "$lg"
+ ble/canvas/put.draw "$ret"
+ fi
+}
+function ble/textarea#save-state {
+ local prefix=$1
+ local -a vars=()
+ ble/array#push vars _ble_edit_PS1 _ble_prompt_ps1_data
+ ble/array#push vars "${_ble_edit_VARNAMES[@]}"
+ ble/array#push vars "${_ble_textmap_VARNAMES[@]}"
+ ble/array#push vars _ble_highlight_layer__list
+ local layer names
+ for layer in "${_ble_highlight_layer__list[@]}"; do
+ builtin eval "ble/array#push vars \"\${!_ble_highlight_layer_$layer@}\""
+ done
+ ble/array#push vars "${_ble_textarea_VARNAMES[@]}"
+ ble/array#push vars "${_ble_syntax_VARNAMES[@]}"
+ ble/array#push vars "${_ble_textarea_local_VARNAMES[@]}"
+ builtin eval -- "${prefix}_VARNAMES=(\"\${vars[@]}\")"
+ ble/util/save-vars "$prefix" "${vars[@]}"
+}
+function ble/textarea#restore-state {
+ local prefix=$1
+ if builtin eval "[[ \$prefix && \${${prefix}_VARNAMES+set} ]]"; then
+ builtin eval "ble/util/restore-vars $prefix \"\${${prefix}_VARNAMES[@]}\""
+ else
+ ble/util/print "ble/textarea#restore-state: unknown prefix '$prefix'." >&2
+ return 1
+ fi
+}
+function ble/textarea#clear-state {
+ local prefix=$1
+ if [[ $prefix ]]; then
+ local vars=${prefix}_VARNAMES
+ builtin eval "builtin unset -v \"\${$vars[@]/#/$prefix}\" $vars"
+ else
+ ble/util/print "ble/textarea#restore-state: unknown prefix '$prefix'." >&2
+ return 1
+ fi
+}
+_ble_textarea_render_defer=
+function ble/textarea#render-defer.idle {
+ ble/util/idle.wait-user-input
+ [[ $_ble_textarea_render_defer ]] || return 0
+ local ble_textarea_render_defer_running=1
+ ble/util/buffer.flush >&2
+ _ble_textarea_render_defer=
+ blehook/invoke textarea_render_defer
+ ble/textarea#render update
+ [[ $_ble_textarea_render_defer ]] &&
+ ble/util/idle.continue
+ return 0
+}
+ble/function#try ble/util/idle.push-background ble/textarea#render-defer.idle
+function ble/widget/.update-textmap {
+ local cols=${COLUMNS:-80} render_opts=
+ if [[ $_ble_prompt_rps1_enabled ]]; then
+ local rps1_width=${_ble_prompt_rps1_data[11]}
+ render_opts=relative
+ ((cols-=rps1_width+1,_ble_term_xenl||cols--))
+ fi
+ local x=$_ble_textmap_begx y=$_ble_textmap_begy
+ COLUMNS=$cols ble/textmap#update "$_ble_edit_str" "$render_opts"
+}
+function ble/widget/do-lowercase-version {
+ local n=${#KEYS[@]}; ((n&&n--))
+ local flag=$((KEYS[n]&_ble_decode_MaskFlag))
+ local char=$((KEYS[n]&_ble_decode_MaskChar))
+ if ((65<=char&&char<=90)); then
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys $((flag|char+32)) "${KEYS[@]:1}"
+ else
+ return 125
+ fi
+}
+function ble/widget/redraw-line {
+ ble-edit/content/clear-arg
+ ble/textarea#invalidate
+}
+function ble/widget/clear-screen {
+ ble-edit/content/clear-arg
+ ble/edit/enter-command-layout # #D1800 pair=leave-command-layout
+ ble/textarea#invalidate
+ local -a DRAW_BUFF=()
+ ble/canvas/panel/goto-top-dock.draw
+ ble/canvas/bflush.draw
+ ble/util/buffer "$_ble_term_clear"
+ _ble_canvas_x=0 _ble_canvas_y=0
+ ble/term/visible-bell/cancel-erasure
+ ble/edit/leave-command-layout # #D1800 pair=enter-command-layout
+}
+function ble/widget/clear-display {
+ ble/util/buffer $'\e[3J'
+ ble/widget/clear-screen
+}
+function ble/edit/display-version/git-rev-parse {
+ ret=
+ local git_base opts=$2
+ case $1 in
+ (.) git_base=$PWD ;;
+ (./*) git_base=$PWD/${1#./} ;;
+ (..|../*) git_base=$PWD/$1 ;;
+ (*) git_base=$1 ;;
+ esac
+ "${_ble_util_set_declare[@]//NAME/visited}"
+ until [[ -s $git_base/HEAD || -s $git_base/.git/HEAD ]]; do
+ ble/set#contains visited "$git_base" && return 1
+ ble/set#add visited "$git_base"
+ if [[ -f $git_base/.git ]]; then
+ local content
+ ble/util/mapfile content < "$git_base/.git"
+ if ble/string#match "$content" '^gitdir: (.*)'; then
+ git_base=$git_base/${BASH_REMATCH[1]}
+ continue
+ fi
+ fi
+ if [[ :$opts: == *:parent:* && $git_base == */* ]]; then
+ git_base=${git_base%/*}
+ continue
+ fi
+ break
+ done
+ [[ -s $git_base/HEAD ]] || git_base=$git_base/.git
+ local head=$git_base/HEAD
+ if [[ -f $head ]]; then
+ local content
+ ble/util/mapfile content < "$head"
+ if ble/string#match "$content" '^ref: (.*)$'; then
+ head=$git_base/${BASH_REMATCH[1]}
+ ble/util/mapfile content < "$head"
+ fi
+ if ble/string#match "$content" '^[a-f0-9]+$'; then
+ content=${content::8}
+ fi
+ ret=$content
+ [[ $ret ]]
+ return $?
+ fi
+ return 1
+}
+function ble/edit/display-version/git-hash-object {
+ local file=$1 size
+ if ! ble/util/assign size 'ble/bin/wc -c "$file" 2>/dev/null'; then
+ ret='error'
+ return 1
+ fi
+ ble/string#split-words size "$size"
+ if ble/bin#has git; then
+ ble/util/assign ret 'git hash-object "$file"'
+ ret="hash:$ret, $size bytes"
+ elif ble/bin#has sha1sum; then
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ { printf 'blob %d\0' "$size"; ble/bin/cat "$file"; } >| "$_ble_local_tmpfile"
+ blob_data=$_ble_local_tmpfile ble/util/assign ret 'sha1sum "$blob_data"'
+ ble/util/assign/.rmtmp
+ ble/string#split-words ret "$ret"
+ ret="sha1:$ret, $size bytes"
+ elif ble/bin#has cksum; then
+ ble/util/assign ret 'cksum "$file"'
+ ble/string#split-words ret "$ret"
+ ble/util/sprintf ret 'cksum:%08x, %d bytes' "$ret" "$size"
+ else
+ ret=size:$size
+ fi
+}
+function ble/edit/display-version/add-line {
+ lines[iline++]=$1
+}
+function ble/edit/display-version/check:bash-completion {
+ [[ ${BASH_COMPLETION_VERSINFO[0]-} ]] || return 1
+ local patch=${BASH_COMPLETION_VERSINFO[2]-}
+ local version=${BASH_COMPLETION_VERSINFO[0]}.${BASH_COMPLETION_VERSINFO[1]:-y}${patch:+.$patch}
+ local source lineno ret
+ if ble/function#get-source-and-lineno _init_completion; then
+ if ble/edit/display-version/git-rev-parse "${source%/*}"; then
+ version=$sgrV$version+$ret$sgr0
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="$sgrV$version$sgr0 ($ret)"
+ fi
+ fi
+ ble/edit/display-version/add-line "${sgrF}bash-completion$sgr0, version $version$label_noarch"
+}
+function ble/edit/display-version/check:bash-preexec {
+ local source lineno ret
+ ble/function#get-source-and-lineno __bp_preexec_invoke_exec || return 1
+ local version="${source/#$HOME/~}$label_noarch"
+ if ble/edit/display-version/git-rev-parse "${source%/*}"; then
+ version="version $sgrV+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="($ret)$label_noarch"
+ fi
+ local file=${source##*/}
+ if [[ $file == bash-preexec.sh || $file == bash-preexec.bash ]]; then
+ file=
+ else
+ file=" ($file)"
+ fi
+ local integ=
+ ble/util/import/is-loaded contrib/bash-preexec && integ=$label_integration
+ ble/edit/display-version/add-line "${sgrF}bash-preexec$sgr0$file, $version$integ"
+}
+function ble/edit/display-version/check:fzf {
+ local source lineno ret
+ if ble/function#get-source-and-lineno __fzf_select__; then
+ local version="${source/#$HOME/~}$label_noarch"
+ if ble/edit/display-version/git-rev-parse "${source%/*}" parent; then
+ version="version $sgrV+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="($ret)$label_noarch"
+ fi
+ local integ=
+ ble/util/import/is-loaded contrib/fzf-key-bindings && integ=$label_integration
+ ble/edit/display-version/add-line "${sgrC}fzf$sgr0 ${sgrF}key-bindings$sgr0, $version$integ"
+ fi
+ if ble/function#get-source-and-lineno __fzf_orig_completion; then
+ local version="${source/#$HOME/~}$label_noarch"
+ if ble/edit/display-version/git-rev-parse "${source%/*}" parent; then
+ version="version $sgrV+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="($ret)$label_noarch"
+ fi
+ local integ=
+ ble/util/import/is-loaded contrib/fzf-completion && integ=$label_integration
+ ble/edit/display-version/add-line "${sgrC}fzf$sgr0 ${sgrF}completion$sgr0, $version$integ"
+ fi
+}
+function ble/edit/display-version/check:starship {
+ local source lineno
+ ble/function#get-source-and-lineno starship_precmd || return 1
+ local sed_script='s/^[[:space:]]*PS1="\$(\(.\{1,\}\) prompt .*)";\{0,1\}$/\1/p'
+ ble/util/assign-array starship 'declare -f starship_precmd | ble/bin/sed -n "$sed_script"'
+ if ! ble/bin#has "$starship"; then
+ { builtin eval -- "starship=$starship" && ble/bin#has "$starship"; } ||
+ { starship=starship; ble/bin#has "$starship"; } || return 1
+ fi
+ local awk_script='
+ sub(/^starship /, "") { version = $0; next; }
+ sub(/^branch:/, "") { gsub(/[[:space:]]/, "_"); if ($0 != "") version = version "-" $0; next; }
+ sub(/^commit_hash:/, "") { gsub(/[[:space:]]/, "_"); if ($0 != "") version = version "+" $0; next; }
+ sub(/^build_time:/, "") { build_time = $0; }
+ sub(/^build_env:/, "") { build_env = $0; }
+ END {
+ if (version != "") {
+ print version;
+ print build_env, build_time
+ }
+ }
+ '
+ local version=
+ ble/util/assign-array version '"$starship" --version | ble/bin/awk "$awk_script"'
+ [[ $version ]] || return 1
+ local ret; ble/string#trim "${version[1]}"; local build=$ret
+ ble/edit/display-version/add-line "${sgrF}starship${sgr0}, version $sgrV$version$sgr0${build:+ ($build)}"
+}
+function ble/edit/display-version/check:bash-it {
+ [[ ${BASH_IT-} ]] && ble/is-function bash-it || return 1
+ local version= ret
+ if ble/edit/display-version/git-rev-parse "$BASH_IT"; then
+ version="version $sgrV+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$BASH_IT/bash_it.sh"; then
+ version="($ret)$label_noarch"
+ else
+ version="(bash-it version)"
+ fi
+ local modules=
+ if ble/is-function _bash-it-component-item-is-enabled; then
+ local category subdir suffix
+ for category in aliases:alias completion plugins:plugin; do
+ local subdir=${category%:*} suffix=${category#*:} list
+ list=()
+ local file name
+ for file in "$BASH_IT/$subdir/available"/*.*.bash; do
+ name=${file##*/}
+ name=${name%."$suffix"*.bash}
+ _bash-it-component-item-is-enabled "$suffix" "$name" && ble/array#push list "$name"
+ done
+ modules="$modules, $suffix(${list[*]})"
+ done
+ fi
+ ble/edit/display-version/add-line "${sgrF}bash-it$sgr0${theme:+ ($theme)}, $version$modules"
+}
+function ble/edit/display-version/check:oh-my-bash {
+ local source lineno ret version=
+ if [[ ${OMB_VERSINFO-set} ]] && ble/function#get-source-and-lineno _omb_module_require; then
+ version=${OMB_VERSINFO[0]}.${OMB_VERSINFO[1]}.${OMB_VERSINFO[2]}
+ if ble/edit/display-version/git-rev-parse "${source%/*}"; then
+ version="version $sgrV$version+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="version $sgrV$version$sgr0 ($ret)$label_noarch"
+ else
+ version="version $sgrV$version$sgr0$label_noarch"
+ fi
+ elif [[ ${OSH_CUSTOM-set} ]] && ble/function#get-source-and-lineno is_plugin; then
+ version="${source/#$HOME/~}$label_noarch"
+ if ble/edit/display-version/git-rev-parse "${source%/*}" parent; then
+ version="version $sgrV+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="($ret)$label_noarch"
+ fi
+ fi
+ if [[ $version ]]; then
+ local theme=${OMB_THEME-${OSH_THEME-}}
+ local modules="aliases(${aliases[*]}), completions(${completions[*]}), plugins(${plugins[*]})"
+ ble/edit/display-version/add-line "${sgrF}oh-my-bash$sgr0${theme:+ ($theme)}, $version, $modules"
+ fi
+}
+function ble/edit/display-version/check:sbp {
+ local source lineno ret
+ ble/function#get-source-and-lineno _sbp_set_prompt || return 1
+ local version="${source/#$HOME/~}$label_noarch"
+ if ble/edit/display-version/git-rev-parse "${source%/*}"; then
+ version="version $sgrV+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="($ret)$label_noarch"
+ fi
+ local hooks="hooks(${settings_hooks[*]-${SBP_HOOKS[*]}})"
+ local left="left(${settings_segments_left[*]-${SBP_SEGMENTS_LEFT[*]}})"
+ local right="right(${settings_segments_right[*]-${RBP_SEGMENTS_RIGHT[*]}})"
+ local modules="$hooks, $left, $right"
+ ble/edit/display-version/add-line "${sgrF}sbp$sgr0, $version, $modules"
+}
+function ble/edit/display-version/check:gitstatus {
+ local source lineno ret
+ ble/function#get-source-and-lineno gitstatus_query || return 1
+ local version="${source/#$HOME/~}$label_noarch"
+ if ble/edit/display-version/git-rev-parse "${source%/*}"; then
+ version="version $sgrV+$ret$sgr0$label_noarch"
+ elif ble/edit/display-version/git-hash-object "$source"; then
+ version="($ret)$label_noarch"
+ fi
+ ble/edit/display-version/add-line "${sgrF}romkatv/gitstatus$sgr0, $version"
+}
+function ble/widget/display-shell-version {
+ ble-edit/content/clear-arg
+ local sgrC= sgrF= sgrV= sgrA= sgr2= sgr3= sgr0=
+ if [[ -t 1 ]]; then
+ sgr0=$_ble_term_sgr0
+ ble/color/face2sgr command_file; sgrC=$ret
+ ble/color/face2sgr command_function; sgrF=$ret
+ ble/color/face2sgr syntax_expr; sgrV=$ret
+ ble/color/face2sgr varname_readonly; sgrA=$ret
+ ble/color/face2sgr syntax_varname; sgr2=$ret
+ ble/color/face2sgr syntax_quoted; sgr3=$ret
+ fi
+ local label_noarch=" (${sgrA}noarch$sgr0)"
+ local label_integration=" $_ble_term_bold(integration: on)$sgr0"
+ local lines="${sgrC}GNU bash$sgr0, version $sgrV$BASH_VERSION$sgr0 ($sgrA$MACHTYPE$sgr0)" iline=1
+ lines[iline++]="${sgrF}ble.sh$sgr0, version $sgrV$BLE_VERSION$sgr0$label_noarch"
+ ble/edit/display-version/check:bash-completion
+ ble/edit/display-version/check:fzf
+ ble/edit/display-version/check:bash-preexec
+ ble/edit/display-version/check:starship
+ ble/edit/display-version/check:bash-it
+ ble/edit/display-version/check:oh-my-bash
+ ble/edit/display-version/check:sbp
+ ble/edit/display-version/check:gitstatus
+ local q=\'
+ local ret='(unset)'
+ [[ ${LANG+set} ]] && ble/string#quote-word "$LANG" quote-empty:sgrq="$sgr3":sgr0="$sgr0"
+ local var line="${_ble_term_bold}locale$sgr0: ${sgr2}LANG$sgrV=$sgr0$ret"
+ for var in "${!LC_@}"; do
+ ble/string#quote-word "${!var}" quote-empty:sgrq="$sgr3":sgr0="$sgr0"
+ line="$line $sgr2$var$sgrV=$sgr0$ret"
+ done
+ lines[iline++]=$line
+ ret='(unset)'
+ [[ ${TERM+set} ]] && ble/string#quote-word "$TERM" quote-empty:sgrq="$sgr3":sgr0="$sgr0"
+ local i line="${_ble_term_bold}terminal$sgr0: ${sgr2}TERM$sgrV=$sgr0$ret"
+ line="$line ${sgr2}wcwidth$sgrV=$sgr0$bleopt_char_width_version-$bleopt_char_width_mode${bleopt_emoji_width:+/$bleopt_emoji_version-$bleopt_emoji_width+$bleopt_emoji_opts}"
+ for i in "${!_ble_term_DA2R[@]}"; do
+ line="$line, $sgrC${_ble_term_TERM[i]-unknown}$sgr0 ($sgrV${_ble_term_DA2R[i]}$sgr0)"
+ done
+ lines[iline++]=$line
+ ble/widget/print "${lines[@]}"
+}
+function ble/widget/readline-dump-functions {
+ ble-edit/content/clear-arg
+ local ret
+ ble/util/assign ret 'ble/builtin/bind -P'
+ ble/widget/print "$ret"
+}
+function ble/widget/readline-dump-macros {
+ ble-edit/content/clear-arg
+ local ret
+ ble/util/assign ret 'ble/builtin/bind -S'
+ ble/widget/print "$ret"
+}
+function ble/widget/readline-dump-variables {
+ ble-edit/content/clear-arg
+ local ret
+ ble/util/assign ret 'ble/builtin/bind -V'
+ ble/widget/print "$ret"
+}
+function ble/widget/re-read-init-file {
+ ble-edit/content/clear-arg
+ local inputrc=$INPUTRC
+ [[ $inputrc && -e $inputrc ]] || inputrc=~/.inputrc
+ [[ -e $inputrc ]] || return 0
+ ble/decode/read-inputrc "$inputrc"
+ _ble_builtin_bind_keymap=
+}
+function ble/widget/overwrite-mode {
+ ble-edit/content/clear-arg
+ if [[ $_ble_edit_overwrite_mode ]]; then
+ _ble_edit_overwrite_mode=
+ else
+ _ble_edit_overwrite_mode=1
+ fi
+}
+function ble/widget/set-mark {
+ ble-edit/content/clear-arg
+ _ble_edit_mark=$_ble_edit_ind
+ _ble_edit_mark_active=1
+}
+function ble/widget/kill-forward-text {
+ ble-edit/content/clear-arg
+ ((_ble_edit_ind>=${#_ble_edit_str})) && return 0
+ ble-edit/content/push-kill-ring "${_ble_edit_str:_ble_edit_ind}"
+ ble-edit/content/replace "$_ble_edit_ind" ${#_ble_edit_str} ''
+ ((_ble_edit_mark>_ble_edit_ind&&(_ble_edit_mark=_ble_edit_ind)))
+}
+function ble/widget/kill-backward-text {
+ ble-edit/content/clear-arg
+ ((_ble_edit_ind==0)) && return 0
+ ble-edit/content/push-kill-ring "${_ble_edit_str::_ble_edit_ind}"
+ ble-edit/content/replace 0 "$_ble_edit_ind" ''
+ ((_ble_edit_mark=_ble_edit_mark<=_ble_edit_ind?0:_ble_edit_mark-_ble_edit_ind))
+ _ble_edit_ind=0
+}
+function ble/widget/exchange-point-and-mark {
+ ble-edit/content/clear-arg
+ local m=$_ble_edit_mark p=$_ble_edit_ind
+ _ble_edit_ind=$m _ble_edit_mark=$p
+}
+function ble/widget/@marked {
+ if [[ $_ble_edit_mark_active != S ]]; then
+ _ble_edit_mark=$_ble_edit_ind
+ _ble_edit_mark_active=S
+ fi
+ ble/decode/widget/dispatch "$@"
+}
+function ble/widget/@nomarked {
+ if [[ $_ble_edit_mark_active == S ]]; then
+ _ble_edit_mark_active=
+ fi
+ ble/decode/widget/dispatch "$@"
+}
+function ble/widget/.process-range-argument {
+ p0=$1 p1=$2 len=${#_ble_edit_str}
+ local pt
+ ((
+ p0>len?(p0=len):p0<0&&(p0=0),
+ p1>len?(p1=len):p0<0&&(p1=0),
+ p1<p0&&(pt=p1,p1=p0,p0=pt),
+ (len=p1-p0)>0
+ ))
+}
+function ble/widget/.delete-range {
+ local p0 p1 len
+ ble/widget/.process-range-argument "${@:1:2}" || return 1
+ if ((len)); then
+ ble-edit/content/replace "$p0" "$p1" ''
+ ((
+ _ble_edit_ind>p1? (_ble_edit_ind-=len):
+ _ble_edit_ind>p0&&(_ble_edit_ind=p0),
+ _ble_edit_mark>p1? (_ble_edit_mark-=len):
+ _ble_edit_mark>p0&&(_ble_edit_mark=p0)
+ ))
+ fi
+ return 0
+}
+function ble/widget/.kill-range {
+ local p0 p1 len
+ ble/widget/.process-range-argument "${@:1:2}" || return 1
+ ble-edit/content/push-kill-ring "${_ble_edit_str:p0:len}" "$4"
+ if ((len)); then
+ ble-edit/content/replace "$p0" "$p1" ''
+ ((
+ _ble_edit_ind>p1? (_ble_edit_ind-=len):
+ _ble_edit_ind>p0&&(_ble_edit_ind=p0),
+ _ble_edit_mark>p1? (_ble_edit_mark-=len):
+ _ble_edit_mark>p0&&(_ble_edit_mark=p0)
+ ))
+ fi
+ return 0
+}
+function ble/widget/.copy-range {
+ local p0 p1 len
+ ble/widget/.process-range-argument "${@:1:2}" || return 1
+ ble-edit/content/push-kill-ring "${_ble_edit_str:p0:len}" "$4"
+}
+function ble/widget/.replace-range {
+ local p0 p1 len
+ ble/widget/.process-range-argument "${@:1:2}"
+ local insert; ble-edit/content/replace-limited "$p0" "$p1" "$3"
+ local inslen=${#insert} delta
+ ((delta=inslen-len)) &&
+ ((_ble_edit_ind>p1?(_ble_edit_ind+=delta):
+ _ble_edit_ind>=p0&&(_ble_edit_ind=p0+inslen),
+ _ble_edit_mark>p1?(_ble_edit_mark+=delta):
+ _ble_edit_mark>p0&&(_ble_edit_mark=p0)))
+ return 0
+}
+function ble/widget/delete-region {
+ ble-edit/content/clear-arg
+ ble/widget/.delete-range "$_ble_edit_mark" "$_ble_edit_ind"
+ _ble_edit_mark_active=
+}
+function ble/widget/kill-region {
+ ble-edit/content/clear-arg
+ ble/widget/.kill-range "$_ble_edit_mark" "$_ble_edit_ind"
+ _ble_edit_mark_active=
+}
+function ble/widget/copy-region {
+ ble-edit/content/clear-arg
+ ble/widget/.copy-range "$_ble_edit_mark" "$_ble_edit_ind"
+ _ble_edit_mark_active=
+}
+function ble/widget/delete-region-or {
+ if [[ $_ble_edit_mark_active ]]; then
+ ble/widget/delete-region
+ else
+ ble/decode/widget/dispatch "$@"
+ fi
+}
+function ble/widget/kill-region-or {
+ if [[ $_ble_edit_mark_active ]]; then
+ ble/widget/kill-region
+ else
+ ble/decode/widget/dispatch "$@"
+ fi
+}
+function ble/widget/copy-region-or {
+ if [[ $_ble_edit_mark_active ]]; then
+ ble/widget/copy-region
+ else
+ ble/decode/widget/dispatch "$@"
+ fi
+}
+function ble/widget/yank {
+ local arg; ble-edit/content/get-arg 1
+ local nkill=${#_ble_edit_kill_ring[@]}
+ if ((nkill==0)); then
+ ble/widget/.bell 'no strings in kill-ring'
+ _ble_edit_yank_index=
+ return 1
+ fi
+ local index=$_ble_edit_kill_index
+ local delta=$((arg-1))
+ if ((delta)); then
+ ((index=(index+delta)%nkill,
+ index=(index+nkill)%nkill))
+ _ble_edit_kill_index=$index
+ fi
+ local insert=${_ble_edit_kill_ring[index]}
+ _ble_edit_yank_index=$index
+ if [[ $insert ]]; then
+ ble-edit/content/replace-limited "$_ble_edit_ind" "$_ble_edit_ind" "$insert"
+ ((_ble_edit_mark=_ble_edit_ind,
+ _ble_edit_ind+=${#insert}))
+ _ble_edit_mark_active=
+ fi
+}
+_ble_edit_yank_index=
+function ble/edit/yankpop.impl {
+ local arg=$1
+ local nkill=${#_ble_edit_kill_ring[@]}
+ ((_ble_edit_yank_index=(_ble_edit_yank_index+arg)%nkill,
+ _ble_edit_yank_index=(_ble_edit_yank_index+nkill)%nkill))
+ local insert=${_ble_edit_kill_ring[_ble_edit_yank_index]}
+ ble-edit/content/replace-limited "$_ble_edit_mark" "$_ble_edit_ind" "$insert"
+ ((_ble_edit_ind=_ble_edit_mark+${#insert}))
+}
+function ble/widget/yank-pop {
+ local opts=$1
+ local arg; ble-edit/content/get-arg 1
+ if ! [[ $_ble_edit_yank_index && ${LASTWIDGET%%' '*} == ble/widget/yank ]]; then
+ ble/widget/.bell
+ return 1
+ fi
+ [[ :$opts: == *:backward:* ]] && ((arg=-arg))
+ ble/edit/yankpop.impl "$arg"
+ _ble_edit_mark_active=insert
+ ble/decode/keymap/push yankpop
+}
+function ble/widget/yankpop/next {
+ local arg; ble-edit/content/get-arg 1
+ ble/edit/yankpop.impl "$arg"
+}
+function ble/widget/yankpop/prev {
+ local arg; ble-edit/content/get-arg 1
+ ble/edit/yankpop.impl $((-arg))
+}
+function ble/widget/yankpop/exit {
+ ble/decode/keymap/pop
+ _ble_edit_mark_active=
+}
+function ble/widget/yankpop/cancel {
+ ble-edit/content/replace "$_ble_edit_mark" "$_ble_edit_ind" ''
+ _ble_edit_ind=$_ble_edit_mark
+ ble/widget/yankpop/exit
+}
+function ble/widget/yankpop/exit-default {
+ ble/widget/yankpop/exit
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+}
+function ble-decode/keymap:yankpop/define {
+ ble-decode/keymap:safe/bind-arg yankpop/exit-default
+ ble-bind -f __default__ 'yankpop/exit-default'
+ ble-bind -f __line_limit__ nop
+ ble-bind -f 'C-g' 'yankpop/cancel'
+ ble-bind -f 'C-x C-g' 'yankpop/cancel'
+ ble-bind -f 'C-M-g' 'yankpop/cancel'
+ ble-bind -f 'M-y' 'yankpop/next'
+ ble-bind -f 'M-S-y' 'yankpop/prev'
+ ble-bind -f 'M-Y' 'yankpop/prev'
+}
+function ble/widget/.bell {
+ [[ $bleopt_edit_vbell ]] && ble/term/visible-bell "$1"
+ [[ $bleopt_edit_abell ]] && ble/term/audible-bell
+ return 0
+}
+function ble/widget/bell {
+ ble-edit/content/clear-arg
+ _ble_edit_mark_active=
+ _ble_edit_arg=
+ blehook/invoke widget_bell
+ ble/widget/.bell "$1"
+}
+function ble/widget/nop { :; }
+function ble/widget/insert-string {
+ local IFS=$_ble_term_IFS
+ local content="$*"
+ local arg; ble-edit/content/get-arg 1
+ if ((arg<0)); then
+ ble/widget/.bell "negative repetition number $arg"
+ return 1
+ elif ((arg==0)); then
+ return 0
+ elif ((arg>1)); then
+ local ret; ble/string#repeat "$content" "$arg"; content=$ret
+ fi
+ ble/widget/.insert-string "$content"
+}
+function ble/widget/.insert-string {
+ local insert=$1
+ [[ $insert ]] || return 1
+ ble-edit/content/replace-limited "$_ble_edit_ind" "$_ble_edit_ind" "$insert"
+ local dx=${#insert}
+ ((
+ _ble_edit_mark>_ble_edit_ind&&(_ble_edit_mark+=dx),
+ _ble_edit_ind+=dx
+ ))
+ _ble_edit_mark_active=
+}
+if [[ -c /dev/clipboard ]]; then
+ function ble/widget/paste-from-clipboard {
+ local clipboard
+ if ! ble/util/readfile clipboard /dev/clipboard; then
+ ble/widget/.bell
+ return 1
+ fi
+ ble/widget/insert-string "$clipboard"
+ return 0
+ }
+fi
+_ble_edit_lastarg_index=
+_ble_edit_lastarg_delta=
+_ble_edit_lastarg_nth=
+function ble/widget/insert-arg.impl {
+ local beg=$1 end=$2 index=$3 delta=$4 nth=$5
+ ((delta)) || delta=1
+ ble/history/initialize
+ local hit= lastarg=
+ local decl=$(
+ local original=${_ble_edit_str:beg:end-beg}
+ local count=; ((delta>0)) && count=_ble_history_COUNT
+ while :; do
+ if ((delta>0)); then
+ ((index+1>=count)) && break
+ ((index+=delta,delta=1))
+ ((index>=count&&(index=count-1)))
+ else
+ ((index-1<0)) && break
+ ((index+=delta,delta=-1))
+ ((index<0&&(index=0)))
+ fi
+ local entry; ble/history/get-edited-entry "$index"
+ builtin history -s -- "$entry"
+ local hist_expanded
+ if ble-edit/hist_expanded.update '!!:'"$nth" &&
+ [[ $hist_expanded != "$original" ]]; then
+ hit=1 lastarg=$hist_expanded
+ ble/util/declare-print-definitions hit lastarg
+ break
+ fi
+ done
+ _ble_edit_lastarg_index=$index
+ _ble_edit_lastarg_delta=$delta
+ _ble_edit_lastarg_nth=$nth
+ ble/util/declare-print-definitions \
+ _ble_edit_lastarg_index \
+ _ble_edit_lastarg_delta \
+ _ble_edit_lastarg_nth
+ )
+ builtin eval -- "$decl"
+ if [[ $hit ]]; then
+ local insert; ble-edit/content/replace-limited "$beg" "$end" "$lastarg"
+ ((_ble_edit_mark=beg,_ble_edit_ind=beg+${#insert}))
+ return 0
+ else
+ ble/widget/.bell
+ return 1
+ fi
+}
+function ble/widget/insert-nth-argument {
+ ble/history/initialize
+ local arg; ble-edit/content/get-arg '^'
+ local beg=$_ble_edit_ind end=$_ble_edit_ind
+ local index=$_ble_history_INDEX
+ local delta=-1 nth=$arg
+ ble/widget/insert-arg.impl "$beg" "$end" "$index" "$delta" "$nth"
+}
+function ble/widget/insert-last-argument {
+ ble/history/initialize
+ local arg; ble-edit/content/get-arg '$'
+ local beg=$_ble_edit_ind end=$_ble_edit_ind
+ local index=$_ble_history_INDEX
+ local delta=-1 nth=$arg
+ ble/widget/insert-arg.impl "$beg" "$end" "$index" "$delta" "$nth" || return "$?"
+ _ble_edit_mark_active=insert
+ ble/decode/keymap/push lastarg
+}
+function ble/widget/lastarg/next {
+ local arg; ble-edit/content/get-arg 1
+ local beg=$_ble_edit_mark
+ local end=$_ble_edit_ind
+ local index=$_ble_edit_lastarg_index
+ local delta
+ if [[ $arg ]]; then
+ delta=$((-arg))
+ else
+ ((delta=_ble_edit_lastarg_delta>=0?1:-1))
+ fi
+ local nth=$_ble_edit_lastarg_nth
+ ble/widget/insert-arg.impl "$beg" "$end" "$index" "$delta" "$nth"
+}
+function ble/widget/lastarg/exit {
+ ble/decode/keymap/pop
+ _ble_edit_mark_active=
+}
+function ble/widget/lastarg/cancel {
+ ble-edit/content/replace "$_ble_edit_mark" "$_ble_edit_ind" ''
+ _ble_edit_ind=$_ble_edit_mark
+ ble/widget/lastarg/exit
+}
+function ble/widget/lastarg/exit-default {
+ ble/widget/lastarg/exit
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+}
+function ble/highlight/layer:region/mark:insert/get-face {
+ face=region_insert
+}
+function ble-decode/keymap:lastarg/define {
+ ble-decode/keymap:safe/bind-arg lastarg/exit-default
+ ble-bind -f __default__ 'lastarg/exit-default'
+ ble-bind -f __line_limit__ nop
+ ble-bind -f 'C-g' 'lastarg/cancel'
+ ble-bind -f 'C-x C-g' 'lastarg/cancel'
+ ble-bind -f 'C-M-g' 'lastarg/cancel'
+ ble-bind -f 'M-.' 'lastarg/next'
+ ble-bind -f 'M-_' 'lastarg/next'
+}
+function ble/widget/self-insert/.get-code {
+ if ((${#KEYS[@]})); then
+ code=${KEYS[${#KEYS[@]}-1]}
+ local flag=$((code&_ble_decode_MaskFlag))
+ local char=$((code&_ble_decode_MaskChar))
+ if ((flag==0&&char<_ble_decode_FunctionKeyBase)); then
+ code=$char
+ return 0
+ elif ((flag==_ble_decode_Ctrl&&(char==63||91<=char&&char<=122)&&(char&0x1F)!=0)); then
+ ((char=char==63?127:char&0x1F))
+ code=$char
+ return 0
+ fi
+ fi
+ if ((${#CHARS[@]})); then
+ code=${CHARS[${#CHARS[@]}-1]}
+ return 0
+ fi
+ code=0
+ return 1
+}
+function ble/widget/self-insert {
+ local code; ble/widget/self-insert/.get-code
+ ((code==0)) && return 0
+ ((code==127&&_ble_bash<30100)) && return 0
+ local ibeg=$_ble_edit_ind iend=$_ble_edit_ind
+ local ret ins; ble/util/c2s "$code"; ins=$ret
+ local arg; ble-edit/content/get-arg 1
+ if ((arg<0)); then
+ ble/widget/.bell "negative repetition number $arg"
+ return 1
+ elif ((arg==0)) || [[ ! $ins ]]; then
+ arg=0 ins=
+ elif ((arg>1)); then
+ ble/string#repeat "$ins" "$arg"; ins=$ret
+ fi
+ if [[ $bleopt_delete_selection_mode && $_ble_edit_mark_active ]]; then
+ ((_ble_edit_mark<_ble_edit_ind?(ibeg=_ble_edit_mark):(iend=_ble_edit_mark),
+ _ble_edit_ind=ibeg))
+ ((arg==0&&ibeg==iend)) && return 0
+ elif [[ $_ble_edit_overwrite_mode ]] && ((code!=10&&code!=9)); then
+ ((arg==0)) && return 0
+ local removed_width
+ if [[ $_ble_edit_overwrite_mode == R ]]; then
+ local removed_text=${_ble_edit_str:ibeg:arg}
+ removed_text=${removed_text%%[$'\n\t']*}
+ removed_width=${#removed_text}
+ ((iend+=removed_width))
+ else
+ local ret w; ble/util/c2w-edit "$code"; w=$((arg*ret))
+ local iN=${#_ble_edit_str}
+ for ((removed_width=0;removed_width<w&&iend<iN;iend++)); do
+ local c1 w1
+ ble/util/s2c "${_ble_edit_str:iend:1}"; c1=$ret
+ [[ $c1 == 0 || $c1 == 10 || $c1 == 9 ]] && break
+ ble/util/c2w-edit "$c1"; w1=$ret
+ ((removed_width+=w1))
+ done
+ ((removed_width>w)) && ins=$ins${_ble_string_prototype::removed_width-w}
+ fi
+ if [[ :$ble_widget_self_insert_opts: == *:nolineext:* ]]; then
+ if ((removed_width<arg)); then
+ ble/widget/.bell
+ return 0
+ fi
+ fi
+ fi
+ local insert; ble-edit/content/replace-limited "$ibeg" "$iend" "$ins"
+ ((_ble_edit_ind+=${#insert},
+ _ble_edit_mark>ibeg&&(
+ _ble_edit_mark<iend?(
+ _ble_edit_mark=_ble_edit_ind
+ ):(
+ _ble_edit_mark+=${#insert}-(iend-ibeg)))))
+ _ble_edit_mark_active=
+ return 0
+}
+function ble/widget/batch-insert.progress {
+ ((index%${1:-257}==0&&N>=2000)) || return 1
+ local ble_batch_insert_index=$index
+ local ble_batch_insert_count=$N
+ builtin eval -- "$_ble_decode_show_progress_hook"
+}
+function ble/widget/batch-insert {
+ local -a chars; chars=("${KEYS[@]}")
+ local -a KEYS=()
+ local index=0 N=${#chars[@]}
+ if [[ $_ble_edit_overwrite_mode ]]; then
+ while ((index<N&&_ble_edit_ind<${#_ble_edit_str})); do
+ KEYS=${chars[index]} ble/widget/self-insert
+ ((index++))
+ done
+ ((index<N)) || return 0
+ fi
+ if [[ $bleopt_line_limit_type == discard ]]; then
+ local limit=$((bleopt_line_limit_length))
+ if ((limit&&${#_ble_edit_str}+N-index>=limit)); then
+ chars=("${chars[@]::limit-${#_ble_edit_str}}")
+ N=${#chars[@]}
+ ((index<N)) || { ble/widget/.bell; return 1; }
+ fi
+ fi
+ while ((index<N)) && [[ $_ble_edit_arg || $_ble_edit_mark_active ]]; do
+ KEYS=${chars[index]} ble/widget/self-insert
+ ((index++))
+ ble/widget/batch-insert.progress
+ done
+ if ((index<N)); then
+ local index0=$index ret ins
+ for ((;index<N;index++)); do
+ ((chars[index])) || builtin unset -v 'chars[index]'
+ ble/widget/batch-insert.progress 2357
+ done
+ ble/util/chars2s "${chars[@]:index0}"; ins=$ret
+ ble/widget/insert-string "$ins"
+ fi
+ ble-edit/content/check-limit truncate
+}
+function ble/widget/quoted-insert-char.hook {
+ ble/widget/self-insert
+}
+function ble/widget/quoted-insert-char {
+ _ble_edit_mark_active=
+ _ble_decode_char__hook=ble/widget/quoted-insert-char.hook
+ return 147
+}
+function ble/widget/quoted-insert.hook {
+ local flag=$((KEYS[0]&_ble_decode_MaskFlag))
+ local char=$((KEYS[0]&_ble_decode_MaskChar))
+ if ((flag==0&&char<_ble_decode_FunctionKeyBase)); then
+ ble/widget/self-insert
+ elif ((flag==_ble_decode_Ctrl&&(char==63||91<=char&&char<=122)&&(char&0x1F)!=0)); then
+ ((char=char==63?127:char&0x1F))
+ local -a KEYS; KEYS=("$char")
+ ble/widget/self-insert
+ else
+ local -a KEYS; KEYS=("${CHARS[@]}")
+ ble/widget/batch-insert
+ fi
+}
+function ble/widget/quoted-insert {
+ _ble_edit_mark_active=
+ _ble_decode_key__hook=ble/widget/quoted-insert.hook
+ return 147
+}
+_ble_edit_bracketed_paste=()
+_ble_edit_bracketed_paste_proc=
+_ble_edit_bracketed_paste_count=0
+function ble/widget/bracketed-paste {
+ ble-edit/content/clear-arg
+ _ble_edit_mark_active=
+ _ble_edit_bracketed_paste=()
+ _ble_edit_bracketed_paste_count=0
+ _ble_edit_bracketed_paste_proc=ble/widget/bracketed-paste.proc
+ _ble_decode_char__hook=ble/widget/bracketed-paste.hook
+ return 147
+}
+function ble/widget/bracketed-paste.hook/check-end {
+ local is_end= chars=
+ if ((_ble_edit_bracketed_paste_count>=5)); then
+ IFS=: builtin eval '_ble_edit_bracketed_paste=("${_ble_edit_bracketed_paste[*]}")'
+ chars=:$_ble_edit_bracketed_paste
+ if [[ $chars == *:50:48:49:126 ]]; then
+ if [[ $chars == *:27:91:50:48:49:126 ]]; then # ESC [ 2 0 1 ~
+ chars=${chars%:27:91:50:48:49:126} is_end=1
+ elif [[ $chars == *:155:50:48:49:126 ]]; then # CSI 2 0 1 ~
+ chars=${chars%:155:50:48:49:126} is_end=1
+ fi
+ fi
+ fi
+ [[ $is_end ]] || return 1
+ _ble_decode_char__hook=
+ chars=:${chars//:/::}:
+ chars=${chars//:13::10:/:10:} # CR LF -> LF
+ chars=${chars//:13:/:10:} # CR -> LF
+ ble/string#split-words chars "${chars//:/ }"
+ local proc=$_ble_edit_bracketed_paste_proc
+ _ble_edit_bracketed_paste_proc=
+ [[ $proc ]] && builtin eval -- "$proc \"\${chars[@]}\""
+ return 0
+}
+function ble/widget/bracketed-paste.hook {
+ ((_ble_edit_bracketed_paste_count%1000==0)) &&
+ IFS=: builtin eval '_ble_edit_bracketed_paste=("${_ble_edit_bracketed_paste[*]}")' # contract
+ _ble_edit_bracketed_paste[_ble_edit_bracketed_paste_count++]=$1
+ (($1==126)) && ble/widget/bracketed-paste.hook/check-end && return 0
+ if ((!_ble_debug_keylog_enabled)) && [[ ! $_ble_decode_keylog_chars_enabled ]]; then
+ local char
+ while ble/decode/char-hook/next-char; do
+ _ble_edit_bracketed_paste[_ble_edit_bracketed_paste_count++]=$char
+ ((char==126)) && ble/widget/bracketed-paste.hook/check-end && return 0
+ done
+ fi
+ _ble_decode_char__hook=ble/widget/bracketed-paste.hook
+ return 147
+}
+function ble/widget/bracketed-paste.proc {
+ local -a KEYS; KEYS=("$@")
+ ble/widget/batch-insert
+}
+function ble/widget/transpose-chars {
+ local arg; ble-edit/content/get-arg ''
+ if ((arg==0)); then
+ [[ ! $arg ]] && ble-edit/content/eolp &&
+ ((_ble_edit_ind>0&&_ble_edit_ind--))
+ arg=1
+ fi
+ local p q r
+ if ((arg>0)); then
+ ((p=_ble_edit_ind-1,
+ q=_ble_edit_ind,
+ r=_ble_edit_ind+arg))
+ else # arg<0
+ ((p=_ble_edit_ind-1+arg,
+ q=_ble_edit_ind,
+ r=_ble_edit_ind+1))
+ fi
+ if ((p<0||${#_ble_edit_str}<r)); then
+ ((_ble_edit_ind=arg<0?0:${#_ble_edit_str}))
+ ble/widget/.bell
+ return 1
+ fi
+ local a=${_ble_edit_str:p:q-p}
+ local b=${_ble_edit_str:q:r-q}
+ ble-edit/content/replace "$p" "$r" "$b$a"
+ ((_ble_edit_ind+=arg))
+ return 0
+}
+function ble/widget/.delete-backward-char {
+ local a=${1:-1}
+ if ((_ble_edit_ind-a<0)); then
+ return 1
+ fi
+ local ins=
+ if [[ $_ble_edit_overwrite_mode ]]; then
+ local next=${_ble_edit_str:_ble_edit_ind:1}
+ if [[ $next && $next != [$'\n\t'] ]]; then
+ if [[ $_ble_edit_overwrite_mode == R ]]; then
+ local w=$a
+ else
+ local w=0 ret i
+ for ((i=0;i<a;i++)); do
+ ble/util/s2c "${_ble_edit_str:_ble_edit_ind-a+i:1}"
+ ble/util/c2w-edit "$ret"
+ ((w+=ret))
+ done
+ fi
+ if ((w)); then
+ local ret; ble/string#repeat ' ' "$w"; ins=$ret
+ ((_ble_edit_mark>=_ble_edit_ind&&(_ble_edit_mark+=w)))
+ fi
+ fi
+ fi
+ ble-edit/content/replace $((_ble_edit_ind-a)) "$_ble_edit_ind" "$ins"
+ ((_ble_edit_ind-=a,
+ _ble_edit_ind+a<_ble_edit_mark?(_ble_edit_mark-=a):
+ _ble_edit_ind<_ble_edit_mark&&(_ble_edit_mark=_ble_edit_ind)))
+ return 0
+}
+function ble/widget/.delete-char {
+ local a=${1:-1}
+ if ((a>0)); then
+ if ((${#_ble_edit_str}<_ble_edit_ind+a)); then
+ return 1
+ else
+ ble-edit/content/replace "$_ble_edit_ind" $((_ble_edit_ind+a)) ''
+ fi
+ elif ((a<0)); then
+ ble/widget/.delete-backward-char $((-a)); return "$?"
+ else
+ if ((${#_ble_edit_str}==0)); then
+ return 1
+ elif ((_ble_edit_ind<${#_ble_edit_str})); then
+ ble-edit/content/replace "$_ble_edit_ind" $((_ble_edit_ind+1)) ''
+ else
+ _ble_edit_ind=${#_ble_edit_str}
+ ble/widget/.delete-backward-char 1; return "$?"
+ fi
+ fi
+ ((_ble_edit_mark>_ble_edit_ind&&_ble_edit_mark--))
+ return 0
+}
+function ble/widget/delete-forward-char {
+ local arg; ble-edit/content/get-arg 1
+ ((arg==0)) && return 0
+ ble/widget/.delete-char "$arg" || ble/widget/.bell
+}
+function ble/widget/delete-backward-char {
+ local arg; ble-edit/content/get-arg 1
+ ((arg==0)) && return 0
+ [[ $_ble_decode_keymap == vi_imap ]] && ble/keymap:vi/undo/add more
+ ble/widget/.delete-char $((-arg)) || ble/widget/.bell
+ [[ $_ble_decode_keymap == vi_imap ]] && ble/keymap:vi/undo/add more
+}
+_ble_edit_exit_count=0
+function ble/widget/exit {
+ ble-edit/content/clear-arg
+ if [[ $WIDGET == "$LASTWIDGET" ]]; then
+ ((_ble_edit_exit_count++))
+ else
+ _ble_edit_exit_count=1
+ fi
+ local ret; ble-edit/eval-IGNOREEOF
+ if ((_ble_edit_exit_count<=ret)); then
+ local remain=$((ret-_ble_edit_exit_count+1))
+ ble/widget/.bell 'IGNOREEOF'
+ ble/widget/print "IGNOREEOF($remain): Use \"exit\" to leave the shell."
+ return 0
+ fi
+ local opts=$1
+ ((_ble_bash>=40000)) && shopt -q checkjobs &>/dev/null && opts=$opts:checkjobs
+ if [[ $bleopt_allow_exit_with_jobs ]]; then
+ local ret
+ if ble/util/assign ret 'compgen -A stopped -- ""' 2>/dev/null; [[ $ret ]]; then
+ opts=$opts:twice
+ elif [[ :$opts: == *:checkjobs:* ]]; then
+ if ble/util/assign ret 'compgen -A running -- ""' 2>/dev/null; [[ $ret ]]; then
+ opts=$opts:twice
+ fi
+ else
+ opts=$opts:force
+ fi
+ fi
+ if ! [[ :$opts: == *:force:* || :$opts: == *:twice:* && _ble_edit_exit_count -ge 2 ]]; then
+ local joblist
+ ble/util/joblist
+ if ((${#joblist[@]})); then
+ ble/widget/.bell "exit: There are remaining jobs."
+ local q=\' Q="'\''" message=
+ if [[ :$opts: == *:twice:* ]]; then
+ message='There are remaining jobs. Input the same key to exit the shell anyway.'
+ else
+ message='There are remaining jobs. Use "exit" to leave the shell.'
+ fi
+ ble/widget/internal-command "ble/util/print '${_ble_term_setaf[12]}[ble: ${message//$q/$Q}]$_ble_term_sgr0'; jobs"
+ return "$?"
+ fi
+ elif [[ :$opts: == *:checkjobs:* ]]; then
+ local joblist
+ ble/util/joblist
+ ((${#joblist[@]})) && printf '%s\n' "${#joblist[@]}"
+ fi
+ _ble_edit_line_disabled=1 ble/textarea#render
+ ble/edit/enter-command-layout # #D1800 pair=leave-command-layout
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$_ble_textarea_gendx" "$_ble_textarea_gendy"
+ ble/canvas/bflush.draw
+ ble/util/buffer.print "${_ble_term_setaf[12]}[ble: exit]$_ble_term_sgr0"
+ ble/util/buffer.flush >&2
+ builtin exit 0 &>/dev/null
+ builtin exit 0 &>/dev/null
+ ble/edit/leave-command-layout # #D1800 pair=enter-command-layout
+ return 1
+}
+function ble/widget/delete-forward-char-or-exit {
+ if [[ $_ble_edit_str ]]; then
+ ble/widget/delete-forward-char
+ else
+ ble/widget/exit
+ fi
+}
+function ble/widget/delete-forward-backward-char {
+ ble-edit/content/clear-arg
+ ble/widget/.delete-char 0 || ble/widget/.bell
+}
+function ble/widget/delete-forward-char-or-list {
+ local right=${_ble_edit_str:_ble_edit_ind}
+ if [[ ! $right || $right == $'\n'* ]]; then
+ ble/widget/complete show_menu
+ else
+ ble/widget/delete-forward-char
+ fi
+}
+function ble/widget/delete-horizontal-space {
+ local arg; ble-edit/content/get-arg ''
+ local b=0 rex=$'[ \t]+$'
+ [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]] &&
+ b=${#BASH_REMATCH}
+ local a=0 rex=$'^[ \t]+'
+ [[ ! $arg && ${_ble_edit_str:_ble_edit_ind} =~ $rex ]] &&
+ a=${#BASH_REMATCH}
+ ble/widget/.delete-range $((_ble_edit_ind-b)) $((_ble_edit_ind+a))
+}
+function ble/widget/.forward-char {
+ ((_ble_edit_ind+=${1:-1}))
+ if ((_ble_edit_ind>${#_ble_edit_str})); then
+ _ble_edit_ind=${#_ble_edit_str}
+ return 1
+ elif ((_ble_edit_ind<0)); then
+ _ble_edit_ind=0
+ return 1
+ fi
+}
+function ble/widget/forward-char {
+ local arg; ble-edit/content/get-arg 1
+ ((arg==0)) && return 0
+ ble/widget/.forward-char "$arg" || ble/widget/.bell
+}
+function ble/widget/backward-char {
+ local arg; ble-edit/content/get-arg 1
+ ((arg==0)) && return 0
+ ble/widget/.forward-char $((-arg)) || ble/widget/.bell
+}
+_ble_edit_character_search_arg=
+function ble/widget/character-search-forward {
+ local arg; ble-edit/content/get-arg 1
+ _ble_edit_character_search_arg=$arg
+ _ble_edit_mark_active=
+ _ble_decode_char__hook=ble/widget/character-search.hook
+}
+function ble/widget/character-search-backward {
+ local arg; ble-edit/content/get-arg 1
+ ((_ble_edit_character_search_arg=-arg))
+ _ble_edit_mark_active=
+ _ble_decode_char__hook=ble/widget/character-search.hook
+}
+function ble/widget/character-search.hook {
+ local char=${KEYS[0]}
+ local ret; ble/util/c2s "${KEYS[0]}"; local c=$ret
+ [[ $c ]] || return 1 # Note: C-@ の時は無視
+ local arg=$_ble_edit_character_search_arg
+ if ((arg>0)); then
+ local right=${_ble_edit_str:_ble_edit_ind+1}
+ if ble/string#index-of "$right" "$c" "$arg"; then
+ ((_ble_edit_ind=_ble_edit_ind+1+ret))
+ elif ble/string#last-index-of "$right" "$c"; then
+ ble/widget/.bell "${arg}th character not found"
+ ((_ble_edit_ind=_ble_edit_ind+1+ret))
+ else
+ ble/widget/.bell 'character not found'
+ return 1
+ fi
+ elif ((arg<0)); then
+ local left=${_ble_edit_str::_ble_edit_ind}
+ if ble/string#last-index-of "$left" "$c" $((-arg)); then
+ _ble_edit_ind=$ret
+ elif ble/string#index-of "$left" "$c"; then
+ ble/widget/.bell "$((-arg))th last character not found"
+ _ble_edit_ind=$ret
+ else
+ ble/widget/.bell 'character not found'
+ return 1
+ fi
+ fi
+ return 0
+}
+function ble/widget/.locate-forward-byte {
+ local delta=$1 ret
+ if ((delta==0)); then
+ return 0
+ elif ((delta>0)); then
+ local right=${_ble_edit_str:index:delta}
+ local rlen=${#right}
+ ble/util/strlen "$right"; local rsz=$ret
+ if ((delta>=rsz)); then
+ ((index+=rlen))
+ ((delta==rsz)); return "$?"
+ else
+ while ((delta&&rlen>=2)); do
+ local mlen=$((rlen/2))
+ local m=${right::mlen}
+ ble/util/strlen "$m"; local msz=$ret
+ if ((delta>=msz)); then
+ right=${right:mlen}
+ ((index+=mlen,
+ rlen-=mlen,
+ delta-=msz))
+ ((rlen>delta)) &&
+ right=${right::delta} rlen=$delta
+ else
+ right=$m rlen=$mlen
+ fi
+ done
+ ((delta&&rlen&&index++))
+ return 0
+ fi
+ elif ((delta<0)); then
+ ((delta=-delta))
+ local left=${_ble_edit_str::index}
+ local llen=${#left}
+ ((llen>delta)) && left=${left:llen-delta} llen=$delta
+ ble/util/strlen "$left"; local lsz=$ret
+ if ((delta>=lsz)); then
+ ((index-=llen))
+ ((delta==lsz)); return "$?"
+ else
+ while ((delta&&llen>=2)); do
+ local mlen=$((llen/2))
+ local m=${left:llen-mlen}
+ ble/util/strlen "$m"; local msz=$ret
+ if ((delta>=msz)); then
+ left=${left::llen-mlen}
+ ((index-=mlen,
+ llen-=mlen,
+ delta-=msz))
+ ((llen>delta)) &&
+ left=${left:llen-delta} llen=$delta
+ else
+ left=$m llen=$mlen
+ fi
+ done
+ ((delta&&llen&&index--))
+ return 0
+ fi
+ fi
+}
+function ble/widget/forward-byte {
+ local arg; ble-edit/content/get-arg 1
+ ((arg==0)) && return 0
+ local index=$_ble_edit_ind
+ ble/widget/.locate-forward-byte "$arg" || ble/widget/.bell
+ _ble_edit_ind=$index
+}
+function ble/widget/backward-byte {
+ local arg; ble-edit/content/get-arg 1
+ ((arg==0)) && return 0
+ local index=$_ble_edit_ind
+ ble/widget/.locate-forward-byte $((-arg)) || ble/widget/.bell
+ _ble_edit_ind=$index
+}
+function ble/widget/end-of-text {
+ local arg; ble-edit/content/get-arg ''
+ if [[ $arg ]]; then
+ if ((arg>=10)); then
+ _ble_edit_ind=0
+ else
+ ((arg<0&&(arg=0)))
+ local index=$(((19-2*arg)*${#_ble_edit_str}/20))
+ local ret; ble-edit/content/find-logical-bol "$index"
+ _ble_edit_ind=$ret
+ fi
+ else
+ _ble_edit_ind=${#_ble_edit_str}
+ fi
+}
+function ble/widget/beginning-of-text {
+ local arg; ble-edit/content/get-arg ''
+ if [[ $arg ]]; then
+ if ((arg>=10)); then
+ _ble_edit_ind=${#_ble_edit_str}
+ else
+ ((arg<0&&(arg=0)))
+ local index=$(((2*arg+1)*${#_ble_edit_str}/20))
+ local ret; ble-edit/content/find-logical-bol "$index"
+ _ble_edit_ind=$ret
+ fi
+ else
+ _ble_edit_ind=0
+ fi
+}
+function ble/widget/beginning-of-logical-line {
+ local arg; ble-edit/content/get-arg 1
+ local ret; ble-edit/content/find-logical-bol "$_ble_edit_ind" $((arg-1))
+ _ble_edit_ind=$ret
+}
+function ble/widget/end-of-logical-line {
+ local arg; ble-edit/content/get-arg 1
+ local ret; ble-edit/content/find-logical-eol "$_ble_edit_ind" $((arg-1))
+ _ble_edit_ind=$ret
+}
+function ble/widget/kill-backward-logical-line {
+ local arg; ble-edit/content/get-arg ''
+ if [[ $arg ]]; then
+ local ret; ble-edit/content/find-logical-eol "$_ble_edit_ind" $((-arg)); local index=$ret
+ if ((arg>0)); then
+ if ((_ble_edit_ind<=index)); then
+ index=0
+ else
+ ble/string#count-char "${_ble_edit_str:index:_ble_edit_ind-index}" $'\n'
+ ((ret<arg)) && index=0
+ fi
+ [[ $flag_beg ]] && index=0
+ fi
+ ret=$index
+ else
+ local ret; ble-edit/content/find-logical-bol
+ ((0<ret&&ret==_ble_edit_ind&&ret--))
+ fi
+ ble/widget/.kill-range "$ret" "$_ble_edit_ind"
+}
+function ble/widget/kill-forward-logical-line {
+ local arg; ble-edit/content/get-arg ''
+ if [[ $arg ]]; then
+ local ret; ble-edit/content/find-logical-bol "$_ble_edit_ind" "$arg"; local index=$ret
+ if ((arg>0)); then
+ if ((index<=_ble_edit_ind)); then
+ index=${#_ble_edit_str}
+ else
+ ble/string#count-char "${_ble_edit_str:_ble_edit_ind:index-_ble_edit_ind}" $'\n'
+ ((ret<arg)) && index=${#_ble_edit_str}
+ fi
+ fi
+ ret=$index
+ else
+ local ret; ble-edit/content/find-logical-eol
+ ((ret<${#_ble_edit_str}&&_ble_edit_ind==ret&&ret++))
+ fi
+ ble/widget/.kill-range "$_ble_edit_ind" "$ret"
+}
+function ble/widget/kill-logical-line {
+ local arg; ble-edit/content/get-arg 0
+ local bofs=0 eofs=0 bol=0 eol=${#_ble_edit_str}
+ ((arg>0?(eofs=arg-1):(arg<0&&(bofs=arg+1))))
+ ble-edit/content/find-logical-bol "$_ble_edit_ind" "$bofs" && local bol=$ret
+ ble-edit/content/find-logical-eol "$_ble_edit_ind" "$eofs" && local eol=$ret
+ [[ ${_ble_edit_str:eol:1} == $'\n' ]] && ((eol++))
+ ((bol<eol)) && ble/widget/.kill-range "$bol" "$eol"
+}
+function ble/widget/forward-history-line.impl {
+ local arg=$1
+ ((arg==0)) && return 0
+ local rest=$((arg>0?arg:-arg))
+ if ((arg>0)); then
+ if [[ ! $_ble_history_prefix && ! $_ble_history_load_done ]]; then
+ ble/widget/.bell 'end of history'
+ return 1
+ fi
+ fi
+ ble/history/initialize
+ local index=$_ble_history_INDEX
+ local expr_next='--index>=0'
+ if ((arg>0)); then
+ local count=$_ble_history_COUNT
+ expr_next="++index<=$count"
+ fi
+ while ((expr_next)); do
+ if ((--rest<=0)); then
+ ble-edit/history/goto "$index" # 位置は goto に任せる
+ return "$?"
+ fi
+ local entry; ble/history/get-edited-entry "$index"
+ if [[ $entry == *$'\n'* ]]; then
+ local ret; ble/string#count-char "$entry" $'\n'
+ if ((rest<=ret)); then
+ ble-edit/history/goto "$index"
+ if ((arg>0)); then
+ ble-edit/content/find-logical-eol 0 "$rest"
+ else
+ ble-edit/content/find-logical-eol ${#entry} $((-rest))
+ fi
+ _ble_edit_ind=$ret
+ return 0
+ fi
+ ((rest-=ret))
+ fi
+ done
+ if ((arg>0)); then
+ ble-edit/history/goto "$count"
+ _ble_edit_ind=${#_ble_edit_str}
+ ble/widget/.bell 'end of history'
+ else
+ ble-edit/history/goto 0
+ _ble_edit_ind=0
+ ble/widget/.bell 'beginning of history'
+ fi
+ return 0
+}
+function ble/widget/forward-logical-line.impl {
+ local arg=$1 opts=$2
+ ((arg==0)) && return 0
+ local ind=$_ble_edit_ind
+ if ((arg>0)); then
+ ((ind<${#_ble_edit_str})) || return 1
+ else
+ ((ind>0)) || return 1
+ fi
+ local ret; ble-edit/content/find-logical-bol "$ind" "$arg"; local bol2=$ret
+ if ((arg>0)); then
+ if ((ind<bol2)); then
+ ble/string#count-char "${_ble_edit_str:ind:bol2-ind}" $'\n'
+ ((arg-=ret))
+ fi
+ else
+ if ((ind>bol2)); then
+ ble/string#count-char "${_ble_edit_str:bol2:ind-bol2}" $'\n'
+ ((arg+=ret))
+ fi
+ fi
+ if ((arg==0)); then
+ ble-edit/content/find-logical-bol "$ind" ; local bol1=$ret
+ ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret
+ local dst=$((bol2+ind-bol1))
+ ((_ble_edit_ind=dst<eol2?dst:eol2))
+ return 0
+ fi
+ if ((arg>0)); then
+ ble-edit/content/find-logical-eol "$bol2"
+ else
+ ret=$bol2
+ fi
+ _ble_edit_ind=$ret
+ if [[ :$opts: == *:history:* && ! $_ble_edit_mark_active ]]; then
+ ble/widget/forward-history-line.impl "$arg"
+ return "$?"
+ fi
+ if ((arg>0)); then
+ ble/widget/.bell 'end of string'
+ else
+ ble/widget/.bell 'beginning of string'
+ fi
+ return 0
+}
+function ble/widget/forward-logical-line {
+ local opts=$1
+ local arg; ble-edit/content/get-arg 1
+ ble/widget/forward-logical-line.impl "$arg" "$opts"
+}
+function ble/widget/backward-logical-line {
+ local opts=$1
+ local arg; ble-edit/content/get-arg 1
+ ble/widget/forward-logical-line.impl $((-arg)) "$opts"
+}
+function ble/keymap:emacs/find-graphical-eol {
+ local axis=${1:-$_ble_edit_ind} arg=${2:-0}
+ local x y index
+ ble/textmap#getxy.cur "$axis"
+ ble/textmap#get-index-at 0 $((y+arg+1))
+ if ((index>0)); then
+ local ax ay
+ ble/textmap#getxy.cur --prefix=a "$index"
+ ((ay>y+arg&&index--))
+ fi
+ ret=$index
+}
+function ble/widget/beginning-of-graphical-line {
+ ble/textmap#is-up-to-date || ble/widget/.update-textmap
+ local arg; ble-edit/content/get-arg 1
+ local x y index
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at 0 $((y+arg-1))
+ _ble_edit_ind=$index
+}
+function ble/widget/end-of-graphical-line {
+ ble/textmap#is-up-to-date || ble/widget/.update-textmap
+ local arg; ble-edit/content/get-arg 1
+ local ret; ble/keymap:emacs/find-graphical-eol "$_ble_edit_ind" $((arg-1))
+ _ble_edit_ind=$ret
+}
+function ble/widget/kill-backward-graphical-line {
+ ble/textmap#is-up-to-date || ble/widget/.update-textmap
+ local arg; ble-edit/content/get-arg ''
+ if [[ ! $arg ]]; then
+ local x y index
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at 0 "$y"
+ ((index==_ble_edit_ind&&index>0&&index--))
+ ble/widget/.kill-range "$index" "$_ble_edit_ind"
+ else
+ local ret; ble/keymap:emacs/find-graphical-eol "$_ble_edit_ind" $((-arg))
+ ble/widget/.kill-range "$ret" "$_ble_edit_ind"
+ fi
+}
+function ble/widget/kill-forward-graphical-line {
+ ble/textmap#is-up-to-date || ble/widget/.update-textmap
+ local arg; ble-edit/content/get-arg ''
+ local x y index ax ay
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at 0 $((y+${arg:-1}))
+ if [[ ! $arg ]] && ((_ble_edit_ind<index-1)); then
+ ble/textmap#getxy.cur --prefix=a "$index"
+ ((ay>y&&index--))
+ fi
+ ble/widget/.kill-range "$_ble_edit_ind" "$index"
+}
+function ble/widget/kill-graphical-line {
+ ble/textmap#is-up-to-date || ble/widget/.update-textmap
+ local arg; ble-edit/content/get-arg 0
+ local bofs=0 eofs=0
+ ((arg>0?(eofs=arg-1):(arg<0&&(bofs=arg+1))))
+ local x y index ax ay
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at 0 $((y+bofs)) ; local bol=$index
+ ble/textmap#get-index-at 0 $((y+eofs+1)); local eol=$index
+ ((bol<eol)) && ble/widget/.kill-range "$bol" "$eol"
+}
+function ble/widget/forward-graphical-line.impl {
+ ble/textmap#is-up-to-date || ble/widget/.update-textmap
+ local arg=$1 opts=$2
+ ((arg==0)) && return 0
+ local x y index ax ay
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at "$x" $((y+arg))
+ ble/textmap#getxy.cur --prefix=a "$index"
+ ((arg-=ay-y))
+ _ble_edit_ind=$index # 何れにしても移動は行う
+ ((arg==0)) && return 0
+ if [[ :$opts: == *:history:* && ! $_ble_edit_mark_active ]]; then
+ ble/widget/forward-history-line.impl "$arg"
+ return "$?"
+ fi
+ if ((arg>0)); then
+ ble/widget/.bell 'end of string'
+ else
+ ble/widget/.bell 'beginning of string'
+ fi
+ return 0
+}
+function ble/widget/forward-graphical-line {
+ local opts=$1
+ local arg; ble-edit/content/get-arg 1
+ ble/widget/forward-graphical-line.impl "$arg" "$opts"
+}
+function ble/widget/backward-graphical-line {
+ local opts=$1
+ local arg; ble-edit/content/get-arg 1
+ ble/widget/forward-graphical-line.impl $((-arg)) "$opts"
+}
+function ble/widget/beginning-of-line {
+ if ble/edit/performs-on-graphical-line; then
+ ble/widget/beginning-of-graphical-line
+ else
+ ble/widget/beginning-of-logical-line
+ fi
+}
+function ble/widget/non-space-beginning-of-line {
+ local old=$_ble_edit_ind
+ ble/widget/beginning-of-logical-line
+ local bol=$_ble_edit_ind ret=
+ ble-edit/content/find-non-space "$bol"
+ [[ $ret == $old ]] && ret=$bol # toggle
+ _ble_edit_ind=$ret
+ return 0
+}
+function ble/widget/end-of-line {
+ if ble/edit/performs-on-graphical-line; then
+ ble/widget/end-of-graphical-line
+ else
+ ble/widget/end-of-logical-line
+ fi
+}
+function ble/widget/kill-backward-line {
+ if ble/edit/performs-on-graphical-line; then
+ ble/widget/kill-backward-graphical-line
+ else
+ ble/widget/kill-backward-logical-line
+ fi
+}
+function ble/widget/kill-forward-line {
+ if ble/edit/performs-on-graphical-line; then
+ ble/widget/kill-forward-graphical-line
+ else
+ ble/widget/kill-forward-logical-line
+ fi
+}
+function ble/widget/kill-line {
+ if ble/edit/performs-on-graphical-line; then
+ ble/widget/kill-graphical-line
+ else
+ ble/widget/kill-logical-line
+ fi
+}
+function ble/widget/forward-line {
+ if ble/edit/use-textmap; then
+ ble/widget/forward-graphical-line "$@"
+ else
+ ble/widget/forward-logical-line "$@"
+ fi
+}
+function ble/widget/backward-line {
+ if ble/edit/use-textmap; then
+ ble/widget/backward-graphical-line "$@"
+ else
+ ble/widget/backward-logical-line "$@"
+ fi
+}
+function ble/edit/word:eword/setup {
+ WSET='a-zA-Z0-9'; WSEP="^$WSET"
+}
+function ble/edit/word:cword/setup {
+ WSET='_a-zA-Z0-9'; WSEP="^$WSET"
+}
+function ble/edit/word:uword/setup {
+ WSEP="$_ble_term_IFS"; WSET="^$WSEP"
+}
+function ble/edit/word:sword/setup {
+ WSEP=$'|&;()<> \t\n'; WSET="^$WSEP"
+}
+function ble/edit/word:fword/setup {
+ WSEP="/$_ble_term_IFS"; WSET="^$WSEP"
+}
+function ble/edit/word/skip-backward {
+ local set=$1 head=${_ble_edit_str::x}
+ head=${head##*[$set]}
+ ((x-=${#head},${#head}))
+}
+function ble/edit/word/skip-forward {
+ local set=$1 tail=${_ble_edit_str:x}
+ tail=${tail%%[$set]*}
+ ((x+=${#tail},${#tail}))
+}
+function ble/edit/word/locate-backward {
+ local x=${1:-$_ble_edit_ind} arg=${2:-1}
+ while ((arg--)); do
+ ble/edit/word/skip-backward "$WSET"; c=$x
+ ble/edit/word/skip-backward "$WSEP"; b=$x
+ done
+ ble/edit/word/skip-backward "$WSET"; a=$x
+}
+function ble/edit/word/locate-forward {
+ local x=${1:-$_ble_edit_ind} arg=${2:-1}
+ while ((arg--)); do
+ ble/edit/word/skip-forward "$WSET"; s=$x
+ ble/edit/word/skip-forward "$WSEP"; t=$x
+ done
+ ble/edit/word/skip-forward "$WSET"; u=$x
+}
+function ble/edit/word/forward-range {
+ local arg=$1; ((arg)) || arg=1
+ if ((arg<0)); then
+ ble/edit/word/backward-range $((-arg))
+ return "$?"
+ fi
+ local s t u; ble/edit/word/locate-forward "$x" "$arg"; y=$t
+}
+function ble/edit/word/backward-range {
+ local arg=$1; ((arg)) || arg=1
+ if ((arg<0)); then
+ ble/edit/word/forward-range $((-arg))
+ return "$?"
+ fi
+ local a b c; ble/edit/word/locate-backward "$x" "$arg"; y=$b
+}
+function ble/edit/word/current-range {
+ local arg=$1; ((arg)) || arg=1
+ if ((arg>0)); then
+ local a b c; ble/edit/word/locate-backward "$x"
+ local s t u; ble/edit/word/locate-forward "$a" "$arg"
+ ((y=a,x<t&&(x=t)))
+ elif ((arg<0)); then
+ local s t u; ble/edit/word/locate-forward "$x"
+ local a b c; ble/edit/word/locate-backward "$u" $((-arg))
+ ((b<x&&(x=b),y=u))
+ fi
+ return 0
+}
+function ble/widget/word.impl {
+ local operator=$1 direction=$2 wtype=$3
+ local arg; ble-edit/content/get-arg 1
+ local WSET WSEP; ble/edit/word:"$wtype"/setup
+ local x=$_ble_edit_ind y=$_ble_edit_ind
+ ble/function#try ble/edit/word/"$direction"-range "$arg"
+ if ((x==y)); then
+ ble/widget/.bell
+ return 1
+ fi
+ case $operator in
+ (goto) _ble_edit_ind=$y ;;
+ (delete)
+ [[ $_ble_decode_keymap == vi_imap && $direction == backward ]] &&
+ ble/keymap:vi/undo/add more
+ ble/widget/.delete-range "$x" "$y"
+ [[ $_ble_decode_keymap == vi_imap && $direction == backward ]] &&
+ ble/keymap:vi/undo/add more ;;
+ (kill) ble/widget/.kill-range "$x" "$y" ;;
+ (copy) ble/widget/.copy-range "$x" "$y" ;;
+ (*) ble/widget/.bell; return 1 ;;
+ esac
+}
+function ble/widget/transpose-words.impl1 {
+ local wtype=$1 arg=$2
+ local WSET WSEP; ble/edit/word:"$wtype"/setup
+ if ((arg==0)); then
+ local x=$_ble_edit_ind
+ ble/edit/word/skip-forward "$WSET"
+ ble/edit/word/skip-forward "$WSEP"; local e1=$x
+ ble/edit/word/skip-backward "$WSEP"; local b1=$x
+ local x=$_ble_edit_mark
+ ble/edit/word/skip-forward "$WSET"
+ ble/edit/word/skip-forward "$WSEP"; local e2=$x
+ ble/edit/word/skip-backward "$WSEP"; local b2=$x
+ else
+ local x=$_ble_edit_ind
+ ble/edit/word/skip-backward "$WSET"
+ ble/edit/word/skip-backward "$WSEP"; local b1=$x
+ ble/edit/word/skip-forward "$WSEP"; local e1=$x
+ if ((arg>0)); then
+ x=$e1
+ ble/edit/word/skip-forward "$WSET"; local b2=$x
+ while ble/edit/word/skip-forward "$WSEP" || return 1; ((--arg>0)); do
+ ble/edit/word/skip-forward "$WSET"
+ done; local e2=$x
+ else
+ x=$b1
+ ble/edit/word/skip-backward "$WSET"; local e2=$x
+ while ble/edit/word/skip-backward "$WSEP" || return 1; ((++arg<0)); do
+ ble/edit/word/skip-backward "$WSET"
+ done; local b2=$x
+ fi
+ fi
+ ((b1>b2)) && local b1=$b2 e1=$e2 b2=$b1 e2=$e1
+ if ! ((b1<e1&&e1<=b2&&b2<e2)); then
+ ble/widget/.bell
+ return 1
+ fi
+ local word1=${_ble_edit_str:b1:e1-b1}
+ local word2=${_ble_edit_str:b2:e2-b2}
+ local sep=${_ble_edit_str:e1:b2-e1}
+ ble/widget/.replace-range "$b1" "$e2" "$word2$sep$word1"
+ _ble_edit_ind=$e2
+}
+function ble/widget/transpose-words.impl {
+ local wtype=$1 arg; ble-edit/content/get-arg 1
+ ble/widget/transpose-words.impl1 "$wtype" "$arg" && return 0
+ ble/widget/.bell
+ return 1
+}
+function ble/widget/filter-word.impl {
+ local xword=$1 filter=$2
+ if [[ $_ble_decode_keymap == vi_nmap ]]; then
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local arg=$ARG
+ else
+ local arg; ble-edit/content/get-arg 1
+ fi
+ local WSET WSEP; ble/edit/word:"$xword"/setup
+ local x=$_ble_edit_ind s t u
+ ble/edit/word/locate-forward "$x" "$arg"
+ if ((x==t)); then
+ ble/widget/.bell
+ [[ $_ble_decode_keymap == vi_nmap ]] &&
+ ble/keymap:vi/adjust-command-mode
+ return 1
+ fi
+ local word=${_ble_edit_str:x:t-x}
+ "$filter" "$word"
+ [[ $word != $ret ]] &&
+ ble-edit/content/replace "$x" "$t" "$ret"
+ if [[ $_ble_decode_keymap == vi_nmap ]]; then
+ ble/keymap:vi/mark/set-previous-edit-area "$x" "$t"
+ ble/keymap:vi/repeat/record
+ ble/keymap:vi/adjust-command-mode
+ fi
+ _ble_edit_ind=$t
+}
+function ble/widget/forward-eword { ble/widget/word.impl goto forward eword; }
+function ble/widget/backward-eword { ble/widget/word.impl goto backward eword; }
+function ble/widget/delete-forward-eword { ble/widget/word.impl delete forward eword; }
+function ble/widget/delete-backward-eword { ble/widget/word.impl delete backward eword; }
+function ble/widget/delete-eword { ble/widget/word.impl delete current eword; }
+function ble/widget/kill-forward-eword { ble/widget/word.impl kill forward eword; }
+function ble/widget/kill-backward-eword { ble/widget/word.impl kill backward eword; }
+function ble/widget/kill-eword { ble/widget/word.impl kill current eword; }
+function ble/widget/copy-forward-eword { ble/widget/word.impl copy forward eword; }
+function ble/widget/copy-backward-eword { ble/widget/word.impl copy backward eword; }
+function ble/widget/copy-eword { ble/widget/word.impl copy current eword; }
+function ble/widget/capitalize-eword { ble/widget/filter-word.impl eword ble/string#capitalize; }
+function ble/widget/downcase-eword { ble/widget/filter-word.impl eword ble/string#tolower; }
+function ble/widget/upcase-eword { ble/widget/filter-word.impl eword ble/string#toupper; }
+function ble/widget/transpose-ewords { ble/widget/transpose-words.impl eword; }
+function ble/widget/forward-cword { ble/widget/word.impl goto forward cword; }
+function ble/widget/backward-cword { ble/widget/word.impl goto backward cword; }
+function ble/widget/delete-forward-cword { ble/widget/word.impl delete forward cword; }
+function ble/widget/delete-backward-cword { ble/widget/word.impl delete backward cword; }
+function ble/widget/delete-cword { ble/widget/word.impl delete current cword; }
+function ble/widget/kill-forward-cword { ble/widget/word.impl kill forward cword; }
+function ble/widget/kill-backward-cword { ble/widget/word.impl kill backward cword; }
+function ble/widget/kill-cword { ble/widget/word.impl kill current cword; }
+function ble/widget/copy-forward-cword { ble/widget/word.impl copy forward cword; }
+function ble/widget/copy-backward-cword { ble/widget/word.impl copy backward cword; }
+function ble/widget/copy-cword { ble/widget/word.impl copy current cword; }
+function ble/widget/capitalize-cword { ble/widget/filter-word.impl cword ble/string#capitalize; }
+function ble/widget/downcase-cword { ble/widget/filter-word.impl cword ble/string#tolower; }
+function ble/widget/upcase-cword { ble/widget/filter-word.impl cword ble/string#toupper; }
+function ble/widget/transpose-cwords { ble/widget/transpose-words.impl cword; }
+function ble/widget/forward-uword { ble/widget/word.impl goto forward uword; }
+function ble/widget/backward-uword { ble/widget/word.impl goto backward uword; }
+function ble/widget/delete-forward-uword { ble/widget/word.impl delete forward uword; }
+function ble/widget/delete-backward-uword { ble/widget/word.impl delete backward uword; }
+function ble/widget/delete-uword { ble/widget/word.impl delete current uword; }
+function ble/widget/kill-forward-uword { ble/widget/word.impl kill forward uword; }
+function ble/widget/kill-backward-uword { ble/widget/word.impl kill backward uword; }
+function ble/widget/kill-uword { ble/widget/word.impl kill current uword; }
+function ble/widget/copy-forward-uword { ble/widget/word.impl copy forward uword; }
+function ble/widget/copy-backward-uword { ble/widget/word.impl copy backward uword; }
+function ble/widget/copy-uword { ble/widget/word.impl copy current uword; }
+function ble/widget/capitalize-uword { ble/widget/filter-word.impl uword ble/string#capitalize; }
+function ble/widget/downcase-uword { ble/widget/filter-word.impl uword ble/string#tolower; }
+function ble/widget/upcase-uword { ble/widget/filter-word.impl uword ble/string#toupper; }
+function ble/widget/transpose-uwords { ble/widget/transpose-words.impl uword; }
+function ble/widget/forward-sword { ble/widget/word.impl goto forward sword; }
+function ble/widget/backward-sword { ble/widget/word.impl goto backward sword; }
+function ble/widget/delete-forward-sword { ble/widget/word.impl delete forward sword; }
+function ble/widget/delete-backward-sword { ble/widget/word.impl delete backward sword; }
+function ble/widget/delete-sword { ble/widget/word.impl delete current sword; }
+function ble/widget/kill-forward-sword { ble/widget/word.impl kill forward sword; }
+function ble/widget/kill-backward-sword { ble/widget/word.impl kill backward sword; }
+function ble/widget/kill-sword { ble/widget/word.impl kill current sword; }
+function ble/widget/copy-forward-sword { ble/widget/word.impl copy forward sword; }
+function ble/widget/copy-backward-sword { ble/widget/word.impl copy backward sword; }
+function ble/widget/copy-sword { ble/widget/word.impl copy current sword; }
+function ble/widget/capitalize-sword { ble/widget/filter-word.impl sword ble/string#capitalize; }
+function ble/widget/downcase-sword { ble/widget/filter-word.impl sword ble/string#tolower; }
+function ble/widget/upcase-sword { ble/widget/filter-word.impl sword ble/string#toupper; }
+function ble/widget/transpose-swords { ble/widget/transpose-words.impl sword; }
+function ble/widget/forward-fword { ble/widget/word.impl goto forward fword; }
+function ble/widget/backward-fword { ble/widget/word.impl goto backward fword; }
+function ble/widget/delete-forward-fword { ble/widget/word.impl delete forward fword; }
+function ble/widget/delete-backward-fword { ble/widget/word.impl delete backward fword; }
+function ble/widget/delete-fword { ble/widget/word.impl delete current fword; }
+function ble/widget/kill-forward-fword { ble/widget/word.impl kill forward fword; }
+function ble/widget/kill-backward-fword { ble/widget/word.impl kill backward fword; }
+function ble/widget/kill-fword { ble/widget/word.impl kill current fword; }
+function ble/widget/copy-forward-fword { ble/widget/word.impl copy forward fword; }
+function ble/widget/copy-backward-fword { ble/widget/word.impl copy backward fword; }
+function ble/widget/copy-fword { ble/widget/word.impl copy current fword; }
+function ble/widget/capitalize-fword { ble/widget/filter-word.impl fword ble/string#capitalize; }
+function ble/widget/downcase-fword { ble/widget/filter-word.impl fword ble/string#tolower; }
+function ble/widget/upcase-fword { ble/widget/filter-word.impl fword ble/string#toupper; }
+function ble/widget/transpose-fwords { ble/widget/transpose-words.impl fword; }
+_ble_edit_exec_lines=()
+_ble_edit_exec_lastexit=0
+_ble_edit_exec_lastarg=$BASH
+_ble_edit_exec_BASH_COMMAND=$BASH
+function ble-edit/exec/register {
+ if [[ $1 != *[!"$_ble_term_IFS"]* ]]; then
+ ble/edit/leave-command-layout
+ return 1
+ fi
+ ble/array#push _ble_edit_exec_lines "$1"
+}
+function ble-edit/exec/has-pending-commands {
+ ((${#_ble_edit_exec_lines[@]}))
+}
+function ble-edit/exec/.setexit {
+ return "$_ble_edit_exec_lastexit"
+}
+_ble_prompt_eol_mark=('' '' 0)
+function ble-edit/exec/.adjust-eol {
+ local cols=${COLUMNS:-80}
+ local -a DRAW_BUFF=()
+ if [[ $bleopt_prompt_eol_mark ]]; then
+ if [[ $bleopt_prompt_eol_mark != "${_ble_prompt_eol_mark[0]}" ]]; then
+ if [[ $bleopt_prompt_eol_mark ]]; then
+ local ret= x=0 y=0 g=0 x1=0 x2=0 y1=0 y2=0
+ LINES=1 COLUMNS=80 ble/canvas/trace "$bleopt_prompt_eol_mark" truncate:measure-bbox
+ _ble_prompt_eol_mark=("$bleopt_prompt_eol_mark" "$ret" "$x2")
+ else
+ _ble_prompt_eol_mark=('' '' 0)
+ fi
+ fi
+ local eol_mark=${_ble_prompt_eol_mark[1]}
+ ble/canvas/put.draw "$_ble_term_sgr0$_ble_term_sc"
+ local width=${_ble_prompt_eol_mark[2]} limit=$cols
+ [[ $_ble_term_rc ]] || ((limit--))
+ if ((width>limit)); then
+ local x=0 y=0 g=0
+ LINES=1 COLUMNS=$limit ble/canvas/trace.draw "$bleopt_prompt_eol_mark" truncate
+ width=$x
+ else
+ ble/canvas/put.draw "$eol_mark"
+ fi
+ [[ $_ble_term_rc ]] || ble/canvas/put-cub.draw "$width"
+ ble/canvas/put.draw "$_ble_term_sgr0$_ble_term_rc"
+ fi
+ local advance=$((_ble_term_xenl?cols-2:cols-3))
+ if [[ $_ble_term_TERM == cygwin:* ]]; then
+ while ((advance)); do
+ ble/canvas/put-cuf.draw $((advance-advance/2))
+ ((advance/=2))
+ done
+ else
+ ble/canvas/put-cuf.draw "$advance"
+ fi
+ ble/canvas/put.draw " $_ble_term_cr$_ble_term_el"
+ ble/prompt/print-ruler.draw "$_ble_edit_exec_BASH_COMMAND"
+ ble/canvas/bflush.draw
+}
+_ble_prompt_ps10_data=()
+function ble/prompt/unit:_ble_prompt_ps10/update {
+ ble/prompt/unit:{section}/update _ble_prompt_ps10 "$PS0" ''
+}
+function ble-edit/exec/print-PS0 {
+ if [[ $PS0 ]]; then
+ local version=$COLUMNS,$_ble_edit_lineno,$_ble_history_count,$_ble_edit_CMD
+ local prompt_hashref_base='$version'
+ local prompt_rows=${LINES:-25}
+ local prompt_cols=${COLUMNS:-80}
+ local "${_ble_prompt_cache_vars[@]/%/=}" # #D1570 OK
+ ble/prompt/unit#update _ble_prompt_ps10
+ ble/prompt/unit:{section}/get _ble_prompt_ps10
+ ble/util/put "$ret"
+ fi
+}
+_ble_builtin_exit_processing=
+function ble/builtin/exit/.read-arguments {
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/adjust-BASH_REMATCH
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $arg == --help ]]; then
+ opt_flags=${opt_flags}H
+ elif local rex='^[-+]?[0-9]+$'; [[ $arg =~ $rex ]]; then
+ ble/array#push opt_args "$arg"
+ else
+ ble/util/print "exit: unrecognized argument '$arg'" >&2
+ opt_flags=${opt_flags}E
+ fi
+ done
+ if ((${#opt_args[@]}>=2)); then
+ ble/util/print "exit: too many arguments" >&2
+ opt_flags=${opt_flags}E
+ fi
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
+ ble/base/restore-BASH_REMATCH
+}
+function ble/builtin/exit {
+ local ext=$?
+ if [[ ! $_ble_builtin_trap_processing ]] && { ble/util/is-running-in-subshell || [[ $_ble_decode_bind_state == none ]]; }; then
+ (($#)) || set -- "$ext"
+ builtin exit "$@"
+ return $? # オプションの指定間違いなどで失敗する可能性がある。
+ fi
+ local set shopt; ble/base/.adjust-bash-options set shopt
+ local opt_flags=
+ local -a opt_args=()
+ ble/builtin/exit/.read-arguments "$@"
+ if [[ $opt_flags == *[EH]* ]]; then
+ [[ $opt_flags == *H* ]] && builtin exit --help
+ ble/base/.restore-bash-options set shopt
+ return 2
+ fi
+ ((${#opt_args[@]})) || ble/array#push opt_args "$ext"
+ if [[ $_ble_builtin_trap_processing ]]; then
+ shopt -s extdebug
+ _ble_edit_exec_TRAPDEBUG_EXIT=$opt_args
+ ble-edit/exec:gexec/.TRAPDEBUG/trap
+ return 0
+ fi
+ if [[ ! $_ble_builtin_exit_processing ]]; then
+ local joblist
+ ble/util/joblist
+ if ((${#joblist[@]})); then
+ local ret
+ while
+ local cancel_reason=
+ if ble/util/assign ret 'compgen -A stopped -- ""' 2>/dev/null; [[ $ret ]]; then
+ cancel_reason='stopped jobs'
+ elif [[ :$opts: == *:checkjobs:* ]]; then
+ if ble/util/assign ret 'compgen -A running -- ""' 2>/dev/null; [[ $ret ]]; then
+ cancel_reason='running jobs'
+ fi
+ fi
+ [[ $cancel_reason ]]
+ do
+ jobs
+ ble/builtin/read -ep "\e[38;5;12m[ble: There are $cancel_reason]\e[m Leave the shell anyway? [yes/No] " ret
+ case $ret in
+ ([yY]|[yY][eE][sS]) break ;;
+ ([nN]|[nN][oO]|'')
+ ble/base/.restore-bash-options set shopt
+ return 0 ;;
+ esac
+ done
+ fi
+ ble/util/print "${_ble_term_setaf[12]}[ble: exit]$_ble_term_sgr0" >&2
+ fi
+ if ((40400<=_ble_bash&&_ble_bash<50200)); then
+ local global_TIMEFORMAT local_TIMEFORMAT
+ ble/util/assign global_TIMEFORMAT 'ble/util/print-global-definitions TIMEFORMAT'
+ if [[ $global_TIMEFORMAT == 'declare TIMEFORMAT; builtin unset -v TIMEFORMAT' ]]; then
+ global_TIMEFORMAT='declare -g TIMEFORMAT=$'\''\nreal\t%3lR\nuser\t%3lU\nsys %3lS'\'
+ else
+ global_TIMEFORMAT="declare -g ${global_TIMEFORMAT#declare }"
+ fi
+ ble/variable#copy-state TIMEFORMAT local_TIMEFORMAT
+ declare -g TIMEFORMAT=
+ TIMEFORMAT=
+ fi
+ ble/base/.restore-bash-options set shopt
+ _ble_builtin_exit_processing=1
+ ble/fd#alloc _ble_builtin_exit_stdout '>&1' # EXIT trap で stdin/stdout を復元する
+ ble/fd#alloc _ble_builtin_exit_stderr '>&2'
+ builtin exit "${opt_args[@]}" &>/dev/null
+ builtin exit "${opt_args[@]}" &>/dev/null
+ _ble_builtin_exit_processing=
+ ble/fd#close _ble_builtin_exit_stdout
+ ble/fd#close _ble_builtin_exit_stderr
+ if ((40400<=_ble_bash&&_ble_bash<50200)); then
+ builtin eval -- "$global_TIMEFORMAT"
+ ble/variable#copy-state local_TIMEFORMAT TIMEFORMAT
+ fi
+ return 1 # exit できなかった場合は 1 らしい
+}
+function exit { ble/builtin/exit "$@"; }
+_ble_exec_time_TIMEFILE=$_ble_base_run/$$.exec.time
+_ble_exec_time_TIMEFORMAT=
+_ble_exec_time_tot=
+_ble_exec_time_usr=
+_ble_exec_time_sys=
+function ble/exec/time#adjust-TIMEFORMAT {
+ if [[ ${TIMEFORMAT+set} ]]; then
+ _ble_exec_time_TIMEFORMAT=$TIMEFORMAT
+ else
+ builtin unset -v _ble_exec_time_TIMEFORMAT
+ fi
+ TIMEFORMAT='%R %U %S'
+}
+function ble/exec/time#restore-TIMEFORMAT {
+ if [[ ${_ble_exec_time_TIMEFORMAT+set} ]]; then
+ TIMEFORMAT=$_ble_exec_time_TIMEFORMAT
+ else
+ builtin unset -v 'TIMEFORMAT[0]'
+ fi
+ local tot usr sys dummy
+ IFS=' ' builtin read -r tot usr sys dummy < "$_ble_exec_time_TIMEFILE"
+ ((_ble_exec_time_tot=10#0${tot//[!0-9]}))
+ ((_ble_exec_time_usr=10#0${usr//[!0-9]}))
+ ((_ble_exec_time_sys=10#0${sys//[!0-9]}))
+}
+_ble_exec_time_TIMES=$_ble_base_run/$$.exec.times
+_ble_exec_time_usr_self=
+_ble_exec_time_sys_self=
+function ble/exec/time/times.parse-time {
+ local rex='^([0-9]+m)?([0-9]*)([^0-9ms][0-9]{3})?s?$'
+ [[ $1 =~ $rex ]] || return 1
+ local min=$((10#0${BASH_REMATCH[1]%m}))
+ local sec=$((10#0${BASH_REMATCH[2]}))
+ local msc=$((10#0${BASH_REMATCH[3]#?}))
+ ((ret=(min*60+sec)*1000+msc))
+ return 0
+} 2>/dev/tty
+function ble/exec/time/times.start {
+ builtin times >| "$_ble_exec_time_TIMES"
+}
+function ble/exec/time/times.end {
+ builtin times >> "$_ble_exec_time_TIMES"
+ local times
+ ble/util/readfile times "$_ble_exec_time_TIMES"
+ ble/string#split-words times "$times"
+ _ble_exec_time_usr_self=
+ _ble_exec_time_sys_self=
+ local ret= t1 t2
+ ble/exec/time/times.parse-time "${times[0]}" && t1=$ret &&
+ ble/exec/time/times.parse-time "${times[4]}" && t2=$ret &&
+ ((_ble_exec_time_usr_self=t2>t1?t2-t1:0,
+ _ble_exec_time_usr_self>_ble_exec_time_usr&&(
+ _ble_exec_time_usr_self=_ble_exec_time_usr)))
+ ble/exec/time/times.parse-time "${times[1]}" && t1=$ret &&
+ ble/exec/time/times.parse-time "${times[5]}" && t2=$ret &&
+ ((_ble_exec_time_sys_self=t2>t1?t2-t1:0,
+ _ble_exec_time_sys_self>_ble_exec_time_sys&&(
+ _ble_exec_time_sys_self=_ble_exec_time_sys)))
+ return 0
+}
+function ble/exec/time#mark-enabled {
+ local real=$_ble_exec_time_tot
+ local usr=$_ble_exec_time_usr usr_self=$_ble_exec_time_usr_self
+ local sys=$_ble_exec_time_sys sys_self=$_ble_exec_time_sys_self
+ local usr_child=$((usr-usr_self))
+ local sys_child=$((sys-sys_self))
+ local cpu=$((real>0?(usr+sys)*100/real:0))
+ ((bleopt_exec_elapsed_enabled))
+}
+_ble_exec_time_beg=
+_ble_exec_time_end=
+_ble_exec_time_ata=
+function ble/exec/time#start {
+ if ((_ble_bash>=50000)); then
+ _ble_exec_time_EPOCHREALTIME_delay=0
+ _ble_exec_time_EPOCHREALTIME_beg=
+ _ble_exec_time_EPOCHREALTIME_end=
+ function ble/exec/time#start {
+ ble/exec/time/times.start
+ _ble_exec_time_EPOCHREALTIME_beg=
+ _ble_exec_time_EPOCHREALTIME_end=
+ }
+ function ble/exec/time#end {
+ local beg=${_ble_exec_time_EPOCHREALTIME_beg//[!0-9]}
+ local end=${_ble_exec_time_EPOCHREALTIME_end//[!0-9]}
+ ((beg+=delay,beg>end)) && beg=$end
+ _ble_exec_time_beg=$beg
+ _ble_exec_time_end=$end
+ _ble_exec_time_ata=$((end-beg))
+ _ble_exec_time_LINENO=$LINENO
+ ble/exec/time/times.end
+ }
+ function ble/exec/time#calibrate.restore-lastarg {
+ _ble_exec_time_EPOCHREALTIME_beg=$EPOCHREALTIME
+ return "$_ble_edit_exec_lastexit"
+ }
+ function ble/exec/time#calibrate.save-lastarg {
+ _ble_exec_time_EPOCHREALTIME_end=$EPOCHREALTIME
+ ble/exec/time#adjust-TIMEFORMAT
+ }
+ function ble/exec/time#calibrate {
+ local _ble_edit_exec_lastexit=0
+ local _ble_edit_exec_lastarg=hello
+ local _ble_exec_time_EPOCHREALTIME_beg=
+ local _ble_exec_time_EPOCHREALTIME_end=
+ local _ble_exec_time_tot=
+ local _ble_exec_time_usr=
+ local _ble_exec_time_sys=
+ local TIMEFORMAT=
+ local script1='ble/exec/time#calibrate.restore-lastarg "$_ble_edit_exec_lastarg"'
+ local script2='{ ble/exec/time#calibrate.save-lastarg; } &>/dev/null'
+ local script=$script1$_ble_term_nl$script2$_ble_term_nl
+ local -a hist=()
+ local i
+ for i in {00..99}; do
+ { builtin eval -- "$script" 2>&$_ble_util_fd_stderr; } 2>| "$_ble_exec_time_TIMEFILE"
+ ble/exec/time#restore-TIMEFORMAT
+ local beg=${_ble_exec_time_EPOCHREALTIME_beg//[!0-9]}
+ local end=${_ble_exec_time_EPOCHREALTIME_end//[!0-9]}
+ ((hist[end-beg]++))
+ done
+ local -a keys; keys=("${!hist[@]}")
+ keys=("${keys[@]::(${#keys[@]}+1)/2}") # Remove outliers
+ local s=0 n=0 t
+ for t in "${keys[@]}"; do ((s+=t*hist[t],n+=hist[t])); done
+ ((_ble_exec_time_EPOCHREALTIME_delay=s/n))
+ }
+ ble/exec/time#calibrate
+ builtin unset -f ble/exec/time#calibrate
+ builtin unset -f ble/exec/time#calibrate.restore-lastarg
+ builtin unset -f ble/exec/time#calibrate.save-lastarg
+ else
+ _ble_exec_time_CLOCK_base=0
+ _ble_exec_time_CLOCK_beg=
+ _ble_exec_time_CLOCK_end=
+ function ble/exec/time#end.adjust {
+ ((_ble_exec_time_beg<prev_end)) && _ble_exec_time_beg=$prev_end
+ local delta=$((_ble_exec_time_end-_ble_exec_time_beg))
+ if ((delta<_ble_exec_time_ata)); then
+ _ble_exec_time_end=$((_ble_exec_time_beg+_ble_exec_time_ata))
+ else
+ _ble_exec_time_beg=$((_ble_exec_time_end-_ble_exec_time_ata))
+ fi
+ _ble_exec_time_LINENO=$LINENO
+ }
+ function ble/exec/time#start {
+ ble/exec/time/times.start
+ _ble_exec_time_CLOCK_beg=
+ _ble_exec_time_CLOCK_end=
+ local ret; ble/util/clock
+ _ble_exec_time_CLOCK_beg=$ret
+ }
+ function ble/exec/time#end {
+ local ret; ble/util/clock
+ _ble_exec_time_CLOCK_end=$ret
+ local prev_end=$_ble_exec_time_end
+ _ble_exec_time_beg=$((_ble_exec_time_CLOCK_base+_ble_exec_time_CLOCK_beg*1000))
+ _ble_exec_time_end=$((_ble_exec_time_CLOCK_base+_ble_exec_time_CLOCK_end*1000))
+ _ble_exec_time_ata=$((_ble_exec_time_tot*1000))
+ ble/exec/time#end.adjust
+ ble/exec/time/times.end
+ }
+ case $_ble_util_clock_type in
+ (printf) ;;
+ (uptime|SECONDS)
+ ble/util/assign _ble_exec_time_SECONDS_base 'ble/bin/date +%s000000'
+ local ret; ble/util/clock
+ ((_ble_exec_time_SECONDS_base-=ret*1000)) ;;
+ (date)
+ if ble/util/assign ret 'ble/bin/date +%6N' 2>/dev/null && [[ $ret ]]; then
+ function ble/exec/time#start {
+ ble/exec/time/times.start
+ _ble_exec_time_CLOCK_beg=
+ _ble_exec_time_CLOCK_end=
+ ble/util/assign _ble_exec_time_CLOCK_beg 'ble/bin/date +%s%6N'
+ }
+ function ble/exec/time#end {
+ ble/util/assign _ble_exec_time_CLOCK_end 'ble/bin/date +%s%6N'
+ local prev_end=$_ble_exec_time_end
+ _ble_exec_time_beg=$_ble_exec_time_CLOCK_beg
+ _ble_exec_time_end=$_ble_exec_time_CLOCK_end
+ _ble_exec_time_ata=$((_ble_exec_time_tot*1000))
+ ble/exec/time#end.adjust
+ ble/exec/time/times.end
+ }
+ fi ;;
+ esac
+ fi
+ ble/exec/time#start
+}
+_ble_edit_exec_TRAPDEBUG_enabled=
+_ble_edit_exec_TRAPDEBUG_lastexit=
+_ble_edit_exec_TRAPDEBUG_lastarg=
+_ble_edit_exec_TRAPDEBUG_postproc=
+_ble_edit_exec_TRAPDEBUG_INT=
+_ble_edit_exec_TRAPDEBUG_EXIT=
+_ble_edit_exec_inside_begin=
+_ble_edit_exec_inside_prologue=
+_ble_edit_exec_inside_userspace=
+ble/builtin/trap/reserve DEBUG
+function ble-edit/exec:gexec/.TRAPDEBUG/trap {
+ builtin trap -- 'ble-edit/exec:gexec/.TRAPDEBUG "$*"; builtin eval -- "$_ble_edit_exec_TRAPDEBUG_postproc"' DEBUG
+}
+_ble_edit_exec_TRAPDEBUG_adjusted=
+function _ble_edit_exec_gexec__TRAPDEBUG_adjust {
+ builtin trap - DEBUG
+ _ble_edit_exec_TRAPDEBUG_adjusted=1
+}
+ble/function#trace _ble_edit_exec_gexec__TRAPDEBUG_adjust
+function ble-edit/exec:gexec/.TRAPDEBUG/restore {
+ _ble_edit_exec_TRAPDEBUG_adjusted=
+ local opts=$1
+ ble/builtin/trap/.initialize
+ if [[ ${_ble_builtin_trap_handlers[_ble_builtin_trap_DEBUG]} ]]; then
+ ble-edit/exec:gexec/.TRAPDEBUG/trap "$opts"
+ fi
+}
+function ble-edit/exec:gexec/.TRAPDEBUG {
+ local __lastexit=$? __lastarg=$_ bash_command=$BASH_COMMAND # Note XXXX: bash-3.0 では BASH_COMMAND が異なる。
+ _ble_edit_exec_TRAPDEBUG_postproc=
+ [[ $_ble_edit_exec_TRAPDEBUG_enabled || ! $_ble_attached ]] || return 0
+ [[ $bash_command != *ble-edit/exec:gexec/.* ]] || return 0
+ [[ ! ( ${FUNCNAME[1]-} == _ble_prompt_update__eval_prompt_command_1 && ( $bash_command == 'ble-edit/exec/.setexit '* || $bash_command == 'BASH_COMMAND='*' builtin eval -- '* ) ) ]] || return 0
+ [[ ! ${_ble_builtin_trap_inside-} ]] || return 0
+ if [[ $_ble_edit_exec_TRAPDEBUG_EXIT ]]; then
+ local flag_clear= flag_exit= postproc=
+ if [[ ! $_ble_builtin_trap_processing ]] || ((${#FUNCNAME[*]}<=1)); then
+ flag_clear=2
+ flag_exit=$_ble_edit_exec_TRAPDEBUG_EXIT
+ else
+ case " ${FUNCNAME[*]:1} " in
+ (' ble/builtin/trap/invoke.sandbox ble/builtin/trap/invoke '*)
+ _ble_trap_done=exit
+ _ble_trap_lastarg=$_ble_edit_exec_TRAPDEBUG_EXIT
+ postproc='ble/util/setexit 2'
+ shopt -q extdebug || postproc='return 0' ;;
+ (' blehook/invoke.sandbox blehook/invoke ble/builtin/trap/.handler '*)
+ _ble_local_ext=$_ble_edit_exec_TRAPDEBUG_EXIT
+ _ble_builtin_trap_processing=exit:$_ble_edit_exec_TRAPDEBUG_EXIT
+ postproc='ble/util/setexit 2'
+ shopt -q extdebug || postproc='return 0' ;;
+ (' ble/builtin/trap/invoke '* | ' blehook/invoke '*)
+ flag_clear=1 ;;
+ (' ble/builtin/trap/.handler '* | ' ble-edit/exec:gexec/.TRAPDEBUG '*)
+ flag_clear=2 ;;
+ (*)
+ postproc='ble/util/setexit 2'
+ shopt -q extdebug || postproc='return 128' ;;
+ esac
+ fi
+ if [[ $flag_clear ]]; then
+ [[ $flag_clear == 2 ]] || shopt -u extdebug
+ _ble_edit_exec_TRAPDEBUG_EXIT=
+ [[ ${_ble_builtin_trap_handlers[_ble_builtin_trap_DEBUG]+set} ]] ||
+ postproc="builtin trap - DEBUG${postproc:+;$postproc}"
+ if [[ $flag_exit ]]; then
+ builtin exit "$flag_exit"
+ fi
+ fi
+ _ble_edit_exec_TRAPDEBUG_postproc=$postproc
+ elif [[ $_ble_edit_exec_TRAPDEBUG_INT ]]; then
+ local IFS=$_ble_term_IFS __set __shopt
+ ble/base/.adjust-bash-options __set __shopt
+ local _ble_builtin_trap_processing=$_ble_builtin_trap_DEBUG
+ local _ble_builtin_trap_postproc
+ ble/util/setexit "$__lastexit" "$__lastarg"
+ ble/builtin/trap/invoke DEBUG
+ _ble_edit_exec_TRAPDEBUG_postproc=$_ble_builtin_trap_postproc # unused
+ local depth=${#FUNCNAME[*]}
+ if ((depth>=2)) && ! ble/string#match "${FUNCNAME[*]:1}" '^ble-edit/exec:gexec/\.|(^| )ble/builtin/trap/\.handler'; then
+ local source=${_ble_term_setaf[5]}${BASH_SOURCE[1]}
+ local sep=${_ble_term_setaf[6]}:
+ local lineno=${_ble_term_setaf[2]}${BASH_LINENO[0]}
+ local func=${_ble_term_setaf[6]}' ('${_ble_term_setaf[4]}${FUNCNAME[1]}${1:+ $1}${_ble_term_setaf[6]}')'
+ ble/util/print "${_ble_term_setaf[9]}[SIGINT]$_ble_term_sgr0 $source$sep$lineno$func$_ble_term_sgr0" >/dev/tty
+ _ble_edit_exec_TRAPDEBUG_postproc="{ return $_ble_edit_exec_TRAPDEBUG_INT || break; } &>/dev/null"
+ elif ((depth==1)) && ! ble/string#match "$bash_command" '^ble-edit/exec:gexec/\.'; then
+ local source=${_ble_term_setaf[5]}global
+ local sep=${_ble_term_setaf[6]}:
+ ble/util/print "${_ble_term_setaf[9]}[SIGINT]$_ble_term_sgr0 $source$sep$_ble_term_sgr0 $bash_command" >/dev/tty
+ _ble_edit_exec_TRAPDEBUG_postproc="break &>/dev/null"
+ fi
+ ble/base/.restore-bash-options __set __shopt
+ elif [[ ${_ble_builtin_trap_handlers[_ble_builtin_trap_DEBUG]+set} ]]; then
+ _ble_edit_exec_TRAPDEBUG_lastexit=$__lastexit
+ _ble_edit_exec_TRAPDEBUG_lastarg=$__lastarg
+ _ble_edit_exec_TRAPDEBUG_postproc='ble/util/setexit "$_ble_edit_exec_TRAPDEBUG_lastexit" "$_ble_edit_exec_TRAPDEBUG_lastarg"'
+ local user_trap=${_ble_builtin_trap_handlers[_ble_builtin_trap_DEBUG]}
+ if [[ $user_trap == *[![:space:]]* ]]; then
+ _ble_edit_exec_TRAPDEBUG_postproc="$_ble_edit_exec_TRAPDEBUG_postproc;$user_trap"
+ fi
+ else
+ _ble_edit_exec_TRAPDEBUG_postproc='builtin trap -- - DEBUG'
+ fi
+ return 0
+}
+_ble_builtin_trap_DEBUG_userTrapInitialized=
+function ble/builtin/trap:DEBUG {
+ _ble_builtin_trap_DEBUG_userTrapInitialized=1
+ if [[ $1 != - && ( $_ble_edit_exec_TRAPDEBUG_enabled || ! $_ble_attached ) ]]; then
+ ble-edit/exec:gexec/.TRAPDEBUG/trap
+ fi
+}
+function _ble_builtin_trap_DEBUG__initialize {
+ if [[ $_ble_builtin_trap_DEBUG_userTrapInitialized ]]; then
+ builtin eval -- "function $FUNCNAME() ((1))"
+ return 0
+ elif [[ $1 == force ]] || ble/function/is-global-trace-context; then
+ _ble_builtin_trap_DEBUG_userTrapInitialized=1
+ builtin eval -- "function $FUNCNAME() ((1))"
+ local tmp=$_ble_base_run/$$.trap.DEBUG ret
+ builtin trap -p DEBUG >| "$tmp"
+ local content; ble/util/readfile content "$tmp"
+ ble/util/put '' >| "$tmp"
+ case ${content#"trap -- '"} in
+ (ble-edit/exec:gexec/.TRAPDEBUG*) ;; # ble-0.4
+ (ble-edit/exec:exec/.eval-TRAPDEBUG*|ble-edit/exec:gexec/.eval-TRAPDEBUG*) ;; # ble-0.2
+ (.ble-edit/exec:exec/eval-TRAPDEBUG*|.ble-edit/exec:gexec/eval-TRAPDEBUG*) ;; # ble-0.1
+ (*) builtin eval -- "$content" ;; # ble/builtin/trap に処理させる
+ esac
+ return 0
+ fi
+}
+ble/function#trace _ble_builtin_trap_DEBUG__initialize
+_ble_builtin_trap_DEBUG__initialize
+function ble-edit/exec:gexec/.TRAPINT {
+ local sig=130
+ ((_ble_bash>=40300)) || sig=128 # bash-4.2 以下は 128
+ if [[ $_ble_attached ]]; then
+ ble/util/print "$_ble_term_bold^C$_ble_term_sgr0" >&2
+ _ble_edit_exec_TRAPDEBUG_INT=$sig
+ ble-edit/exec:gexec/.TRAPDEBUG/trap
+ else
+ _ble_builtin_trap_postproc="{ return $sig || break; } &>/dev/tty"
+ fi
+}
+function ble-edit/exec:gexec/.TRAPINT/reset {
+ blehook INT-='ble-edit/exec:gexec/.TRAPINT'
+}
+function ble-edit/exec:gexec/invoke-hook-with-setexit {
+ local -a BLE_PIPESTATUS
+ BLE_PIPESTATUS=("${_ble_edit_exec_PIPESTATUS[@]}")
+ ble-edit/exec/.setexit "$_ble_edit_exec_lastarg"
+ BASH_COMMAND=$_ble_edit_exec_BASH_COMMAND \
+ blehook/invoke "$@"
+} >&$_ble_util_fd_stdout 2>&$_ble_util_fd_stderr
+_ble_edit_exec_TERM=
+function ble-edit/exec:gexec/TERM/is-dirty {
+ [[ $TERM != "$_ble_edit_exec_TERM" ]] && return 0
+ local bindp
+ ble/util/assign bindp 'builtin bind -p'
+ [[ $bindp != "$_ble_decode_bind_bindp" ]]
+}
+function ble-edit/exec:gexec/TERM/leave {
+ _ble_edit_exec_TERM=$TERM
+}
+function ble-edit/exec:gexec/TERM/enter {
+ if [[ $_ble_decode_bind_state != none ]] && ble-edit/exec:gexec/TERM/is-dirty; then
+ ble/edit/info/immediate-show text 'ble: TERM has changed. rebinding...'
+ ble/decode/detach
+ if ! ble/decode/attach; then
+ ble-detach
+ ble-edit/bind/.check-detach && return 1
+ fi
+ ble/edit/info/immediate-default
+ fi
+}
+function ble-edit/exec:gexec/.begin {
+ _ble_edit_exec_inside_begin=1
+ local IFS=$_ble_term_IFS
+ _ble_edit_exec_PWD=$PWD
+ ble-edit/exec:gexec/TERM/leave
+ ble/term/leave
+ ble-edit/bind/stdout.on
+ ble/util/buffer.flush >&2
+ ble/builtin/trap/install-hook INT # 何故か改めて実行しないと有効にならない
+ blehook INT+='ble-edit/exec:gexec/.TRAPINT'
+ ble-edit/exec:gexec/.TRAPDEBUG/restore
+}
+function ble-edit/exec:gexec/.end {
+ _ble_edit_exec_inside_begin=
+ local IFS=$_ble_term_IFS
+ ble-edit/exec:gexec/.TRAPINT/reset
+ builtin trap -- - DEBUG
+ [[ $PWD != "$_ble_edit_exec_PWD" ]] && blehook/invoke CHPWD
+ ble/util/joblist.flush >&2
+ ble-edit/bind/.check-detach && return 0
+ ble/term/enter
+ ble-edit/exec:gexec/TERM/enter || return 0 # rebind に失敗した時 .tail せずに抜ける
+ ble/util/c2w:auto/check
+ ble/edit/clear-command-layout
+ [[ $1 == restore ]] && return 0 # Note: 前回の呼出で .end に失敗した時 #D1170
+ ble-edit/bind/.tail # flush will be called here
+}
+function ble-edit/exec:gexec/.prologue {
+ _ble_edit_exec_inside_prologue=1
+ local IFS=$_ble_term_IFS
+ _ble_edit_exec_BASH_COMMAND=$1
+ ble-edit/restore-PS1
+ ble-edit/restore-READLINE
+ ble-edit/restore-IGNOREEOF
+ builtin unset -v HISTCMD; ble/history/get-count -v HISTCMD
+ _ble_edit_exec_TRAPDEBUG_INT=
+ ble/util/joblist.clear
+ ble-edit/exec:gexec/invoke-hook-with-setexit PREEXEC "$_ble_edit_exec_BASH_COMMAND"
+ ble-edit/exec/print-PS0 >&$_ble_util_fd_stdout 2>&$_ble_util_fd_stderr
+ ((++_ble_edit_CMD))
+ ble/exec/time#start
+ ble/base/restore-BASH_REMATCH
+}
+function ble-edit/exec:gexec/.restore-lastarg {
+ ble/base/restore-bash-options
+ ble/base/restore-POSIXLY_CORRECT
+ ble/base/restore-builtin-wrappers
+ builtin eval -- "$_ble_bash_FUNCNEST_restore"
+ _ble_edit_exec_TRAPDEBUG_enabled=1
+ _ble_edit_exec_inside_userspace=1
+ _ble_exec_time_EPOCHREALTIME_beg=$EPOCHREALTIME
+ return "$_ble_edit_exec_lastexit" # set $?
+} &>/dev/null # set -x 対策 #D0930
+function ble-edit/exec:gexec/.save-lastarg {
+ _ble_exec_time_EPOCHREALTIME_end=$EPOCHREALTIME \
+ _ble_edit_exec_lastexit=$? \
+ _ble_edit_exec_lastarg=$_ \
+ _ble_edit_exec_PIPESTATUS=("${PIPESTATUS[@]}")
+ _ble_edit_exec_inside_userspace=
+ _ble_edit_exec_TRAPDEBUG_enabled=
+ builtin eval -- "$_ble_bash_FUNCNEST_adjust"
+ ble/base/adjust-bash-options
+ ble/exec/time#adjust-TIMEFORMAT
+ return "$_ble_edit_exec_lastexit"
+}
+function ble-edit/exec:gexec/.epilogue {
+ _ble_exec_time_EPOCHREALTIME_end=${_ble_exec_time_EPOCHREALTIME_end:-$EPOCHREALTIME} \
+ _ble_edit_exec_lastexit=$?
+ _ble_edit_exec_inside_userspace=
+ _ble_edit_exec_TRAPDEBUG_enabled=
+ builtin eval -- "$_ble_bash_FUNCNEST_adjust"
+ ble/base/adjust-builtin-wrappers-1
+ if [[ $_ble_edit_exec_TRAPDEBUG_INT ]]; then
+ if ((_ble_edit_exec_lastexit==0)); then
+ _ble_edit_exec_lastexit=$_ble_edit_exec_TRAPDEBUG_INT
+ fi
+ _ble_edit_exec_TRAPDEBUG_INT=
+ fi
+ local IFS=$_ble_term_IFS
+ builtin trap -- - DEBUG
+ ble/base/adjust-bash-options
+ ble/base/adjust-POSIXLY_CORRECT
+ ble/base/adjust-builtin-wrappers-2
+ ble/base/adjust-BASH_REMATCH
+ ble-edit/adjust-IGNOREEOF
+ ble-edit/adjust-READLINE
+ ble-edit/adjust-PS1
+ ble/exec/time#restore-TIMEFORMAT
+ ble/exec/time#end
+ ble/util/reset-keymap-of-editing-mode
+ ble-edit/exec/.adjust-eol
+ _ble_edit_exec_inside_prologue=
+ ble/util/buffer.flush >&$_ble_util_fd_stderr
+ ble-edit/exec:gexec/invoke-hook-with-setexit POSTEXEC
+ local msg=
+ if ((_ble_edit_exec_lastexit)); then
+ ble-edit/exec:gexec/invoke-hook-with-setexit ERR
+ if [[ $bleopt_exec_errexit_mark ]]; then
+ local ret
+ ble/util/sprintf ret "$bleopt_exec_errexit_mark" "$_ble_edit_exec_lastexit"
+ msg=$ret
+ fi
+ fi
+ if ble/exec/time#mark-enabled; then
+ local format=$bleopt_exec_elapsed_mark
+ if [[ $format ]]; then
+ local ata=$((_ble_exec_time_ata/1000))
+ if ((ata<1000)); then
+ ata="${ata}ms"
+ elif ((ata<1000*1000)); then
+ ata="${ata::${#ata}-3}.${ata:${#ata}-3}s"
+ elif ((ata/=1000,ata<3600*100)); then # ata [s]
+ local min
+ ((min=ata/60,ata%=60))
+ if ((min<100)); then
+ ata="${min}m${ata}s"
+ else
+ ata="$((min/60))h$((min%60))m${ata}s"
+ fi
+ else
+ local hour
+ ((ata/=60,hour=ata/60,ata%=60))
+ ata="$((hour/24))d$((hour%24))h${ata}m"
+ fi
+ local cpu='--.-'
+ if ((_ble_exec_time_tot)); then
+ cpu=$(((_ble_exec_time_usr+_ble_exec_time_sys)*1000/_ble_exec_time_tot))
+ cpu=$((cpu/10)).$((cpu%10))
+ fi
+ local ret
+ ble/util/sprintf ret "$format" "$ata" "$cpu"
+ msg=$msg$ret
+ ble/string#ltrim "$_ble_edit_exec_BASH_COMMAND"
+ msg="$msg $ret"
+ fi
+ fi
+ if [[ $msg ]]; then
+ x=0 y=0 g=0 LINES=1 ble/canvas/trace "$msg" confine:truncate
+ ble/util/buffer.print "$ret"
+ fi
+}
+function ble-edit/exec:gexec/.setup {
+ ((${#_ble_edit_exec_lines[@]})) || [[ ! $_ble_edit_exec_TRAPDEBUG_adjusted ]] || return 1
+ local buff='_ble_decode_bind_hook=' ibuff=1
+ if [[ ! $_ble_edit_exec_TRAPDEBUG_adjusted ]]; then
+ buff[ibuff++]='_ble_builtin_trap_DEBUG__initialize force'
+ buff[ibuff++]=_ble_edit_exec_gexec__TRAPDEBUG_adjust
+ fi
+ local count=${#_ble_edit_exec_lines[@]}
+ if ((count)); then
+ ble/util/buffer.flush >&2
+ local q=\' Q="'\''" cmd
+ buff[ibuff++]=ble-edit/exec:gexec/.begin
+ for cmd in "${_ble_edit_exec_lines[@]}"; do
+ local prologue=""
+ buff[ibuff++]="ble-edit/exec:gexec/.prologue '${cmd//$q/$Q}'"
+ buff[ibuff++]='{ time builtin eval -- "ble-edit/exec:gexec/.restore-lastarg \"\$_ble_edit_exec_lastarg\"'
+ buff[ibuff++]='$_ble_edit_exec_BASH_COMMAND'
+ buff[ibuff++]='{ ble-edit/exec:gexec/.save-lastarg; } &>/dev/null' # Note: &>/dev/null は set -x 対策 #D0930
+ buff[ibuff++]='" 2>&$_ble_util_fd_stderr; } 2>| "$_ble_exec_time_TIMEFILE"'
+ buff[ibuff++]='{ ble-edit/exec:gexec/.epilogue; } 3>&2 &>/dev/null'
+ done
+ _ble_edit_exec_lines=()
+ buff[ibuff++]=_ble_edit_exec_gexec__TRAPDEBUG_adjust
+ buff[ibuff++]=ble-edit/exec:gexec/.end
+ fi
+ if ((ibuff>=2)); then
+ IFS=$'\n' builtin eval '_ble_decode_bind_hook="${buff[*]}"'
+ fi
+ ((count>=1)); return $?
+}
+function ble-edit/exec:gexec/process {
+ ble-edit/exec:gexec/.setup
+ return $?
+}
+function ble-edit/exec:gexec/restore-state {
+ [[ $_ble_edit_exec_inside_prologue ]] && ble-edit/exec:gexec/.epilogue 3>&2 &>/dev/null
+ [[ $_ble_edit_exec_inside_begin ]] && ble-edit/exec:gexec/.end restore
+}
+: ${_ble_edit_lineno:=0}
+_ble_edit_line_opwd=
+function ble/widget/.insert-newline/trim-prompt {
+ local ps1f=$bleopt_prompt_ps1_final
+ local ps1t=$bleopt_prompt_ps1_transient
+ if [[ ! $ps1f && :$ps1t: == *:trim:* ]]; then
+ [[ :$ps1t: == *:same-dir:* && $PWD != $_ble_edit_line_opwd ]] && return
+ local y=${_ble_prompt_ps1_data[4]}
+ if ((y)); then
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 0
+ ble/canvas/panel#increase-height.draw "$_ble_textarea_panel" $((-y)) shift
+ ((_ble_textarea_gendy-=y))
+ fi
+ fi
+}
+function ble/widget/.insert-newline {
+ local opts=$1
+ local -a DRAW_BUFF=()
+ if [[ :$opts: == *:keep-info:* && $_ble_textarea_panel == 0 ]] &&
+ ! ble/util/joblist.has-events
+ then
+ ble/textarea#render leave
+ ble/widget/.insert-newline/trim-prompt
+ local textarea_height=${_ble_canvas_panel_height[_ble_textarea_panel]}
+ ble/canvas/panel#increase-height.draw "$_ble_textarea_panel" 1
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 "$textarea_height" sgr0
+ ble/canvas/bflush.draw
+ else
+ ble/edit/enter-command-layout # #D1800 checked=.insert-newline
+ ble/textarea#render leave
+ ble/widget/.insert-newline/trim-prompt
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "$_ble_textarea_gendx" "$_ble_textarea_gendy" sgr0
+ ble/canvas/put.draw "$_ble_term_nl"
+ ble/canvas/bflush.draw
+ ble/util/joblist.bflush
+ fi
+ ((_ble_edit_lineno++))
+ _ble_edit_line_opwd=$PWD
+ ble/textarea#invalidate
+ _ble_canvas_x=0 _ble_canvas_y=0
+ _ble_textarea_gendx=0 _ble_textarea_gendy=0
+ _ble_canvas_panel_height[_ble_textarea_panel]=1
+}
+function ble/widget/.hide-current-line {
+ local opts=$1 y_erase=0
+ [[ :$opts: == *:keep-header:* ]] && y_erase=${_ble_prompt_ps1_data[4]}
+ local -a DRAW_BUFF=()
+ if ((y_erase)); then
+ ble/canvas/panel#clear-after.draw "$_ble_textarea_panel" 0 "$y_erase"
+ else
+ ble/canvas/panel#clear.draw "$_ble_textarea_panel"
+ fi
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 "$y_erase"
+ ble/canvas/bflush.draw
+ ble/textarea#invalidate
+ _ble_canvas_x=0 _ble_canvas_y=$y_erase
+ _ble_textarea_gendx=0 _ble_textarea_gendy=$y_erase
+ ((_ble_canvas_panel_height[_ble_textarea_panel]=1+y_erase))
+}
+function ble/widget/.newline/clear-content {
+ [[ $_ble_edit_overwrite_mode ]] &&
+ ble/term/cursor-state/reveal
+ ble-edit/content/reset '' newline
+ _ble_edit_ind=0
+ _ble_edit_mark=0
+ _ble_edit_mark_active=
+ _ble_edit_overwrite_mode=
+}
+function ble/widget/.newline {
+ local opts=$1
+ _ble_edit_mark_active=
+ if [[ $_ble_complete_menu_active ]]; then
+ [[ $_ble_highlight_layer_menu_filter_beg ]] &&
+ ble/textarea#invalidate str # (#D0995)
+ fi
+ _ble_complete_menu_active= ble/widget/.insert-newline "$opts" # #D1800 checked=.newline
+ local ret; ble/string#count-char "$_ble_edit_str" $'\n'
+ ((_ble_edit_LINENO+=1+ret))
+ ((LINENO=_ble_edit_LINENO))
+ ble/history/onleave.fire
+ ble/widget/.newline/clear-content
+}
+function ble/widget/discard-line {
+ ble-edit/content/clear-arg
+ [[ $bleopt_history_share ]] && ble/builtin/history/option:n
+ _ble_edit_line_disabled=1 ble/widget/.newline keep-info
+ ble/textarea#render
+}
+function ble/edit/hist_expanded/.core {
+ ble/builtin/history/option:p "$command"
+}
+function ble-edit/hist_expanded/.expand {
+ ble/edit/hist_expanded/.core 2>/dev/null; local ext=$?
+ ((ext)) && ble/util/print "$command"
+ ble/util/put :
+ return "$ext"
+}
+function ble-edit/hist_expanded.update {
+ local command=$1
+ if [[ ! -o histexpand || ! ${command//[ ]} ]]; then
+ hist_expanded=$command
+ return 0
+ elif ble/util/assign hist_expanded 'ble-edit/hist_expanded/.expand'; then
+ hist_expanded=${hist_expanded%$_ble_term_nl:}
+ return 0
+ else
+ hist_expanded=$command
+ return 1
+ fi
+}
+function ble/widget/accept-line {
+ ble/decode/widget/keymap-dispatch "$@"
+}
+function ble/widget/default/accept-line {
+ if [[ :$1: == *:syntax:* || $MC_SID == $$ && $LINENO == 0 ]]; then
+ ble-edit/content/update-syntax
+ if ! ble/syntax:bash/is-complete; then
+ ble/widget/newline
+ return "$?"
+ fi
+ fi
+ ble-edit/content/clear-arg
+ local command=$_ble_edit_str
+ if [[ ! ${command//["$_ble_term_IFS"]} ]]; then
+ [[ $bleopt_history_share ]] &&
+ ble/builtin/history/option:n
+ ble/widget/.newline keep-info
+ ble/prompt/print-ruler.buff '' keep-info
+ ble/textarea#render
+ ble/util/buffer.flush >&2
+ return 0
+ fi
+ local hist_expanded
+ if ! ble-edit/hist_expanded.update "$command"; then
+ ble/widget/.internal-print-command \
+ 'ble/edit/hist_expanded/.core 1>/dev/null' pre-flush # エラーメッセージを表示
+ shopt -q histreedit &>/dev/null || ble/widget/.newline/clear-content
+ return "$?"
+ fi
+ local hist_is_expanded=
+ if [[ $hist_expanded != "$command" ]]; then
+ if shopt -q histverify &>/dev/null; then
+ _ble_edit_line_disabled=1 ble/widget/.insert-newline keep-info
+ ble-edit/content/reset-and-check-dirty "$hist_expanded"
+ _ble_edit_ind=${#hist_expanded}
+ _ble_edit_mark=0
+ _ble_edit_mark_active=
+ return 0
+ fi
+ command=$hist_expanded
+ hist_is_expanded=1
+ fi
+ ble/widget/.newline # #D1800 register
+ [[ $hist_is_expanded ]] && ble/util/buffer.print "${_ble_term_setaf[12]}[ble: expand]$_ble_term_sgr0 $command"
+ ble/history/add "$command"
+ ble-edit/exec/register "$command"
+}
+function ble/widget/accept-and-next {
+ ble-edit/content/clear-arg
+ ble/history/initialize
+ local index=$_ble_history_INDEX
+ local count=$_ble_history_COUNT
+ if ((index+1<count)); then
+ local HISTINDEX_NEXT=$((index+1)) # to be modified in accept-line
+ ble/widget/accept-line
+ ble-edit/history/goto "$HISTINDEX_NEXT"
+ else
+ local content=$_ble_edit_str
+ ble/widget/accept-line
+ count=$_ble_history_COUNT
+ if ((count)); then
+ local entry; ble/history/get-entry $((count-1))
+ if [[ $entry == "$content" ]]; then
+ ble-edit/history/goto $((count-1))
+ fi
+ fi
+ [[ $_ble_edit_str != "$content" ]] &&
+ ble-edit/content/reset "$content"
+ fi
+}
+function ble/widget/newline {
+ ble/decode/widget/keymap-dispatch "$@"
+}
+function ble/widget/default/newline {
+ local -a KEYS=(10)
+ ble/widget/self-insert
+}
+function ble/widget/tab-insert {
+ local -a KEYS=(9)
+ ble/widget/self-insert
+}
+function ble-edit/is-single-complete-line {
+ ble-edit/content/is-single-line || return 1
+ [[ $_ble_edit_str ]] && ble/decode/has-input &&
+ ((0<=bleopt_accept_line_threshold&&bleopt_accept_line_threshold<=_ble_decode_input_count+ble_decode_char_rest)) &&
+ return 1
+ if shopt -q cmdhist &>/dev/null; then
+ ble-edit/content/update-syntax
+ ble/syntax:bash/is-complete || return 1
+ fi
+ return 0
+}
+function ble/widget/accept-single-line-or {
+ ble/decode/widget/keymap-dispatch "$@"
+}
+function ble/widget/default/accept-single-line-or {
+ if ble-edit/is-single-complete-line; then
+ ble/widget/accept-line
+ else
+ ble/widget/"$@"
+ fi
+}
+function ble/widget/accept-single-line-or-newline {
+ ble/widget/accept-single-line-or newline
+}
+function ble/widget/edit-and-execute-command.edit {
+ local content=$1 opts=:$2:
+ local file=$_ble_base_run/$$.blesh-fc.bash
+ ble/util/print "$content" >| "$file"
+ local fallback=vi
+ if type emacs &>/dev/null; then
+ fallback='emacs -nw'
+ elif type vim &>/dev/null; then
+ fallback=vim
+ elif type nano &>/dev/null; then
+ fallback=nano
+ fi
+ [[ $opts == *:no-newline:* ]] ||
+ _ble_edit_line_disabled=1 ble/widget/.newline # #D1800 (呼び出し元で exec/register)
+ ble/term/leave
+ ${bleopt_editor:-${VISUAL:-${EDITOR:-$fallback}}} "$file"; local ext=$?
+ ble/term/enter
+ if ((ext)); then
+ ble/widget/.bell
+ return 127
+ fi
+ ble/util/readfile ret "$file"
+ return 0
+}
+function ble/widget/edit-and-execute-command.impl {
+ local ret=
+ ble/widget/edit-and-execute-command.edit "$1"
+ local command=$ret
+ ble/string#match "$command" $'[\n]+$' &&
+ command=${command::${#command}-${#BASH_REMATCH}}
+ if [[ $command != *[!"$_ble_term_IFS"]* ]]; then
+ ble/edit/leave-command-layout
+ ble/widget/.bell
+ return 1
+ fi
+ ble/util/buffer.print "${_ble_term_setaf[12]}[ble: fc]$_ble_term_sgr0 $command"
+ ble/history/add "$command"
+ ble-edit/exec/register "$command"
+}
+function ble/widget/edit-and-execute-command {
+ ble-edit/content/clear-arg
+ ble/widget/edit-and-execute-command.impl "$_ble_edit_str"
+}
+function ble/widget/insert-comment/.remove-comment {
+ local comment_begin=$1
+ ret=
+ [[ $comment_begin ]] || return 1
+ ble/string#escape-for-extended-regex "$comment_begin"; local rex_comment_begin=$ret
+ local rex1=$'([ \t]*'$rex_comment_begin$')[^\n]*(\n|$)|[ \t]+(\n|$)|\n'
+ local rex=$'^('$rex1')*$'; [[ $_ble_edit_str =~ $rex ]] || return 1
+ local tail=$_ble_edit_str out=
+ while [[ $tail && $tail =~ ^$rex1 ]]; do
+ local rematch1=${BASH_REMATCH[1]}
+ if [[ $rematch1 ]]; then
+ out=$out${rematch1%?}${BASH_REMATCH:${#rematch1}}
+ else
+ out=$out$BASH_REMATCH
+ fi
+ tail=${tail:${#BASH_REMATCH}}
+ done
+ [[ $tail ]] && return 1
+ ret=$out
+}
+function ble/widget/insert-comment/.insert {
+ local arg=$1
+ local ret='#'; ble/util/read-rl-variable comment-begin
+ local comment_begin=${ret::1}
+ local text=
+ if [[ $arg ]] && ble/widget/insert-comment/.remove-comment "$comment_begin"; then
+ text=$ret
+ else
+ text=$comment_begin${_ble_edit_str//$'\n'/$'\n'"$comment_begin"}
+ fi
+ ble-edit/content/reset-and-check-dirty "$text"
+}
+function ble/widget/insert-comment {
+ local arg; ble-edit/content/get-arg ''
+ ble/widget/insert-comment/.insert "$arg"
+ ble/widget/accept-line
+}
+function ble/widget/alias-expand-line.proc {
+ if ((tchild>=0)); then
+ ble/syntax/tree-enumerate-children \
+ ble/widget/alias-expand-line.proc
+ elif [[ $wtype && ! ${wtype//[0-9]} ]] && ((wtype==_ble_ctx_CMDI)); then
+ local word=${_ble_edit_str:wbegin:wlen}
+ local ret; ble/alias#expand "$word"
+ [[ $word == "$ret" ]] && return 0
+ changed=1
+ ble/widget/.replace-range "$wbegin" $((wbegin+wlen)) "$ret"
+ fi
+}
+function ble/widget/alias-expand-line {
+ ble-edit/content/clear-arg
+ ble-edit/content/update-syntax
+ local iN= changed=
+ ble/syntax/tree-enumerate ble/widget/alias-expand-line.proc
+ [[ $changed ]] && _ble_edit_mark_active=
+}
+function ble/widget/tilde-expand {
+ ble-edit/content/clear-arg
+ ble-edit/content/update-syntax
+ local len=${#_ble_edit_str}
+ local i=$len j=$len
+ while ((--i>=0)); do
+ ((_ble_syntax_attr[i])) || continue
+ if ((_ble_syntax_attr[i]==_ble_attr_TILDE)); then
+ local word=${_ble_edit_str:i:j-i}
+ builtin eval "local path=$word"
+ [[ $path != "$word" ]] &&
+ ble/widget/.replace-range "$i" "$j" "$path"
+ fi
+ j=$i
+ done
+}
+_ble_edit_shell_expand_ExpandWtype=()
+function ble/widget/shell-expand-line.initialize {
+ function ble/widget/shell-expand-line.initialize { :; }
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_CMDI]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_ARGI]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_ARGEI]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_ARGVI]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_RDRF]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_RDRD]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_RDRS]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_VALI]=1
+ _ble_edit_shell_expand_ExpandWtype[_ble_ctx_CONDI]=1
+}
+function ble/widget/shell-expand-line.expand-word {
+ local word=$1
+ ble/widget/shell-expand-line.initialize
+ if [[ ! ${_ble_edit_shell_expand_ExpandWtype[wtype]} ]]; then
+ ret=$word
+ return 0
+ fi
+ ret=$word; [[ $ret == '~'* ]] && ret='\'$word
+ ble/syntax:bash/simple-word/eval "$ret" noglob
+ if [[ $word != $ret || ${#ret[@]} -ne 1 ]]; then
+ [[ $opts == *:quote:* ]] && flags=${flags}q
+ return 0
+ fi
+ if ((wtype==_ble_ctx_CMDI)); then
+ ble/alias#expand "$word"
+ [[ $word != $ret ]] && return 0
+ fi
+ ret=$word
+}
+function ble/widget/shell-expand-line.proc {
+ [[ $wtype ]] || return 0
+ if [[ ${wtype//[0-9]} ]]; then
+ ble/syntax/tree-enumerate-children ble/widget/shell-expand-line.proc
+ return 0
+ fi
+ local word=${_ble_edit_str:wbegin:wlen}
+ local rex='^[_a-zA-Z][_a-zA-Z0-9]*=+?\('
+ if ((wtype==_ble_attr_VAR)) && [[ $word =~ $rex ]]; then
+ ble/syntax/tree-enumerate-children ble/widget/shell-expand-line.proc
+ return 0
+ fi
+ local flags=
+ local -a ret=() words=()
+ ble/widget/shell-expand-line.expand-word "$word"
+ words=("${ret[@]}")
+ [[ ${#words[@]} -eq 1 && $word == "$ret" ]] && return 0
+ if ((wtype==_ble_ctx_RDRF||wtype==_ble_ctx_RDRD||wtype==_ble_ctx_RDRS)); then
+ local IFS=$_ble_term_IFS
+ words=("${words[*]}")
+ fi
+ local q=\' Q="'\''" specialchars='\ ["'\''`$|&;<>()*?!^{,}'
+ local w index=0 out=
+ for w in "${words[@]}"; do
+ ((index++)) && out=$out' '
+ [[ $flags == *q* && $w == *["$specialchars"]* ]] && w=$q${w//$q/$Q}$q
+ out=$out$w
+ done
+ changed=1
+ ble/widget/.replace-range "$wbegin" $((wbegin+wlen)) "$out"
+}
+function ble/widget/shell-expand-line {
+ local opts=:$1:
+ ble-edit/content/clear-arg
+ ble/widget/history-expand-line
+ ble-edit/content/update-syntax
+ local iN= changed=
+ ble/syntax/tree-enumerate ble/widget/shell-expand-line.proc
+ [[ $changed ]] && _ble_edit_mark_active=
+}
+_ble_edit_undo=()
+_ble_edit_undo_index=0
+_ble_edit_undo_history=()
+_ble_edit_undo_hindex=
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_edit_undo \
+ _ble_edit_undo_index \
+ _ble_edit_undo_history \
+ _ble_edit_undo_hindex
+function ble-edit/undo/.check-hindex {
+ local hindex; ble/history/get-index -v hindex
+ [[ $_ble_edit_undo_hindex == "$hindex" ]] && return 0
+ if [[ $_ble_edit_undo_hindex ]]; then
+ local uindex=${_ble_edit_undo_index:-${#_ble_edit_undo[@]}}
+ local ret; ble/string#quote-words "$uindex" "${_ble_edit_undo[@]}"
+ _ble_edit_undo_history[_ble_edit_undo_hindex]=$ret
+ fi
+ if [[ ${_ble_edit_undo_history[hindex]} ]]; then
+ local data; builtin eval -- "data=(${_ble_edit_undo_history[hindex]})"
+ _ble_edit_undo=("${data[@]:1}")
+ _ble_edit_undo_index=${data[0]}
+ else
+ _ble_edit_undo=()
+ _ble_edit_undo_index=0
+ fi
+ _ble_edit_undo_hindex=$hindex
+}
+function ble-edit/undo/clear-all {
+ _ble_edit_undo=()
+ _ble_edit_undo_index=0
+ _ble_edit_undo_history=()
+ _ble_edit_undo_hindex=
+}
+function ble-edit/undo/history-delete.hook {
+ ble/builtin/history/array#delete-hindex _ble_edit_undo_history "$@"
+ _ble_edit_undo_hindex=
+}
+function ble-edit/undo/history-clear.hook {
+ ble-edit/undo/clear-all
+}
+function ble-edit/undo/history-insert.hook {
+ ble/builtin/history/array#insert-range _ble_edit_undo_history "$@"
+ local beg=$1 len=$2
+ [[ $_ble_edit_undo_hindex ]] &&
+ ((_ble_edit_undo_hindex>=beg)) &&
+ ((_ble_edit_undo_hindex+=len))
+}
+blehook history_delete+=ble-edit/undo/history-delete.hook
+blehook history_clear+=ble-edit/undo/history-clear.hook
+blehook history_insert+=ble-edit/undo/history-insert.hook
+function ble-edit/undo/.get-current-state {
+ if ((_ble_edit_undo_index==0)); then
+ str=
+ if [[ $_ble_history_prefix || $_ble_history_load_done ]]; then
+ local index; ble/history/get-index
+ ble/history/get-entry -v str "$index"
+ fi
+ ind=${#entry}
+ else
+ local entry=${_ble_edit_undo[_ble_edit_undo_index-1]}
+ str=${entry#*:} ind=${entry%%:*}
+ fi
+}
+function ble-edit/undo/add {
+ ble-edit/undo/.check-hindex
+ local str ind; ble-edit/undo/.get-current-state
+ [[ $str == "$_ble_edit_str" ]] && return 0
+ _ble_edit_undo[_ble_edit_undo_index++]=$_ble_edit_ind:$_ble_edit_str
+ if ((${#_ble_edit_undo[@]}>_ble_edit_undo_index)); then
+ _ble_edit_undo=("${_ble_edit_undo[@]::_ble_edit_undo_index}")
+ fi
+}
+function ble-edit/undo/.load {
+ local str ind; ble-edit/undo/.get-current-state
+ if [[ $bleopt_undo_point == end || $bleopt_undo_point == beg ]]; then
+ local old=$_ble_edit_str new=$str ret
+ if [[ $bleopt_undo_point == end ]]; then
+ ble/string#common-suffix "${old:_ble_edit_ind}" "$new"; local s1=${#ret}
+ local old=${old::${#old}-s1} new=${new:${#new}-s1}
+ ble/string#common-prefix "${old::_ble_edit_ind}" "$new"; local p1=${#ret}
+ local old=${old:p1} new=${new:p1}
+ ble/string#common-suffix "$old" "$new"; local s2=${#ret}
+ local old=${old::${#old}-s2} new=${new:${#new}-s2}
+ ble/string#common-prefix "$old" "$new"; local p2=${#ret}
+ else
+ ble/string#common-prefix "${old::_ble_edit_ind}" "$new"; local p1=${#ret}
+ local old=${old:p1} new=${new:p1}
+ ble/string#common-suffix "${old:_ble_edit_ind-p1}" "$new"; local s1=${#ret}
+ local old=${old::${#old}-s1} new=${new:${#new}-s1}
+ ble/string#common-prefix "$old" "$new"; local p2=${#ret}
+ local old=${old:p2} new=${new:p2}
+ ble/string#common-suffix "$old" "$new"; local s2=${#ret}
+ fi
+ local beg=$((p1+p2)) end0=$((${#_ble_edit_str}-s1-s2)) end=$((${#str}-s1-s2))
+ ble-edit/content/replace "$beg" "$end0" "${str:beg:end-beg}"
+ if [[ $bleopt_undo_point == end ]]; then
+ ind=$end
+ else
+ ind=$beg
+ fi
+ else
+ ble-edit/content/reset-and-check-dirty "$str"
+ fi
+ _ble_edit_ind=$ind
+ return 0
+}
+function ble-edit/undo/undo {
+ local arg=${1:-1}
+ ble-edit/undo/.check-hindex
+ ble-edit/undo/add # 最後に add/load してから変更があれば記録
+ ((_ble_edit_undo_index)) || return 1
+ ((_ble_edit_undo_index-=arg))
+ ((_ble_edit_undo_index<0&&(_ble_edit_undo_index=0)))
+ ble-edit/undo/.load
+}
+function ble-edit/undo/redo {
+ local arg=${1:-1}
+ ble-edit/undo/.check-hindex
+ ble-edit/undo/add # 最後に add/load してから変更があれば記録
+ local ucount=${#_ble_edit_undo[@]}
+ ((_ble_edit_undo_index<ucount)) || return 1
+ ((_ble_edit_undo_index+=arg))
+ ((_ble_edit_undo_index>=ucount&&(_ble_edit_undo_index=ucount)))
+ ble-edit/undo/.load
+}
+function ble-edit/undo/revert {
+ ble-edit/undo/.check-hindex
+ ble-edit/undo/add # 最後に add/load してから変更があれば記録
+ ((_ble_edit_undo_index)) || return 1
+ ((_ble_edit_undo_index=0))
+ ble-edit/undo/.load
+}
+function ble-edit/undo/revert-toggle {
+ local arg=${1:-1}
+ ((arg%2==0)) && return 0
+ ble-edit/undo/.check-hindex
+ ble-edit/undo/add # 最後に add/load してから変更があれば記録
+ if ((_ble_edit_undo_index)); then
+ ((_ble_edit_undo_index=0))
+ ble-edit/undo/.load
+ elif ((${#_ble_edit_undo[@]})); then
+ ((_ble_edit_undo_index=${#_ble_edit_undo[@]}))
+ ble-edit/undo/.load
+ else
+ return 1
+ fi
+}
+_ble_edit_kbdmacro_record=
+_ble_edit_kbdmacro_last=()
+_ble_edit_kbdmacro_onplay=
+function ble/widget/start-keyboard-macro {
+ ble/keymap:generic/clear-arg
+ [[ $_ble_edit_kbdmacro_onplay ]] && return 0 # 再生中は無視
+ if ! ble/decode/charlog#start kbd-macro; then
+ if [[ $_ble_decode_keylog_chars_enabled == kbd-macro ]]; then
+ ble/widget/.bell 'kbd-macro: recording is already started'
+ else
+ ble/widget/.bell 'kbd-macro: the logging system is currently busy'
+ fi
+ return 1
+ fi
+ _ble_edit_kbdmacro_record=1
+ if [[ $_ble_decode_keymap == emacs ]]; then
+ ble/keymap:emacs/update-mode-name
+ elif [[ $_ble_decode_keymap == vi_nmap ]]; then
+ ble/keymap:vi/adjust-command-mode
+ fi
+ return 0
+}
+function ble/widget/end-keyboard-macro {
+ ble/keymap:generic/clear-arg
+ [[ $_ble_edit_kbdmacro_onplay ]] && return 0 # 再生中は無視
+ if [[ $_ble_decode_keylog_chars_enabled != kbd-macro ]]; then
+ ble/widget/.bell 'kbd-macro: recording is not running'
+ return 1
+ fi
+ _ble_edit_kbdmacro_record=
+ ble/decode/charlog#end-exclusive-depth1
+ _ble_edit_kbdmacro_last=("${ret[@]}")
+ if [[ $_ble_decode_keymap == emacs ]]; then
+ ble/keymap:emacs/update-mode-name
+ elif [[ $_ble_decode_keymap == vi_nmap ]]; then
+ ble/keymap:vi/adjust-command-mode
+ fi
+ return 0
+}
+function ble/widget/call-keyboard-macro {
+ local arg; ble-edit/content/get-arg 1
+ ble/keymap:generic/clear-arg
+ ((arg>0)) || return 1
+ [[ $_ble_edit_kbdmacro_onplay ]] && return 0 # 再生中は無視
+ local _ble_edit_kbdmacro_onplay=1
+ if ((arg==1)); then
+ ble/widget/.MACRO "${_ble_edit_kbdmacro_last[@]}"
+ else
+ local -a chars=()
+ while ((arg-->0)); do
+ ble/array#push chars "${_ble_edit_kbdmacro_last[@]}"
+ done
+ ble/widget/.MACRO "${chars[@]}"
+ fi
+ [[ $_ble_decode_keymap == vi_nmap ]] &&
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/print-keyboard-macro {
+ ble/keymap:generic/clear-arg
+ local ret; ble/decode/charlog#encode "${_ble_edit_kbdmacro_last[@]}"
+ ble/edit/info/show text "kbd-macro: $ret"
+ [[ $_ble_decode_keymap == vi_nmap ]] &&
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+bleopt/declare -v history_preserve_point ''
+function ble-edit/history/goto {
+ ble/history/initialize
+ local histlen=$_ble_history_COUNT
+ local index0=$_ble_history_INDEX
+ local index1=$1
+ ((index0==index1)) && return 0
+ if ((index1>histlen)); then
+ index1=$histlen
+ ble/widget/.bell
+ elif ((index1<0)); then
+ index1=0
+ ble/widget/.bell
+ fi
+ ((index0==index1)) && return 0
+ if [[ $bleopt_history_share && ! $_ble_history_prefix && $_ble_decode_keymap != isearch ]]; then
+ if ((index0==histlen||index1==histlen)); then
+ ble/builtin/history/option:n
+ local histlen2=$_ble_history_COUNT
+ if ((histlen!=histlen2)); then
+ ble/textarea#invalidate
+ ble-edit/history/goto $((index1==histlen?histlen:index1))
+ return "$?"
+ fi
+ fi
+ fi
+ ble/history/set-edited-entry "$index0" "$_ble_edit_str"
+ ble/history/onleave.fire
+ ble/history/set-index "$index1"
+ local entry; ble/history/get-edited-entry -v entry "$index1"
+ ble-edit/content/reset "$entry" history
+ if [[ $bleopt_history_preserve_point ]]; then
+ if ((_ble_edit_ind>${#_ble_edit_str})); then
+ _ble_edit_ind=${#_ble_edit_str}
+ fi
+ else
+ if ((index1<index0)); then
+ _ble_edit_ind=${#_ble_edit_str}
+ else
+ local first_line=${_ble_edit_str%%$'\n'*}
+ _ble_edit_ind=${#first_line}
+ fi
+ fi
+ _ble_edit_mark=0
+ _ble_edit_mark_active=
+}
+function ble-edit/history/history-message.hook {
+ ((_ble_edit_attached)) || return 1
+ local message=$1
+ if [[ $message ]]; then
+ ble/edit/info/immediate-show text "$message"
+ else
+ ble/edit/info/immediate-default
+ fi
+}
+blehook history_message+=ble-edit/history/history-message.hook
+function ble/widget/history-next {
+ if [[ $_ble_history_prefix || $_ble_history_load_done ]]; then
+ local arg; ble-edit/content/get-arg 1
+ ble/history/initialize
+ ble-edit/history/goto $((_ble_history_INDEX+arg))
+ else
+ ble-edit/content/clear-arg
+ ble/widget/.bell
+ fi
+}
+function ble/widget/history-prev {
+ local arg; ble-edit/content/get-arg 1
+ ble/history/initialize
+ ble-edit/history/goto $((_ble_history_INDEX-arg))
+}
+function ble/widget/history-beginning {
+ ble-edit/content/clear-arg
+ ble-edit/history/goto 0
+}
+function ble/widget/history-end {
+ ble-edit/content/clear-arg
+ if [[ $_ble_history_prefix || $_ble_history_load_done ]]; then
+ ble/history/initialize
+ ble-edit/history/goto "$_ble_history_COUNT"
+ else
+ ble/widget/.bell
+ fi
+}
+function ble/widget/history-expand-line {
+ ble-edit/content/clear-arg
+ local hist_expanded
+ ble-edit/hist_expanded.update "$_ble_edit_str" || return 1
+ [[ $_ble_edit_str == "$hist_expanded" ]] && return 1
+ ble-edit/content/reset-and-check-dirty "$hist_expanded"
+ _ble_edit_ind=${#hist_expanded}
+ _ble_edit_mark=0
+ _ble_edit_mark_active=
+ return 0
+}
+function ble/widget/history-and-alias-expand-line {
+ ble/widget/history-expand-line
+ ble/widget/alias-expand-line
+}
+function ble/widget/history-expand-backward-line {
+ ble-edit/content/clear-arg
+ local prevline=${_ble_edit_str::_ble_edit_ind} hist_expanded
+ ble-edit/hist_expanded.update "$prevline" || return 1
+ [[ $prevline == "$hist_expanded" ]] && return 1
+ local ret
+ ble/string#common-prefix "$prevline" "$hist_expanded"; local dmin=${#ret}
+ local insert; ble-edit/content/replace-limited "$dmin" "$_ble_edit_ind" "${hist_expanded:dmin}"
+ ((_ble_edit_ind=dmin+${#insert}))
+ _ble_edit_mark=0
+ _ble_edit_mark_active=
+ return 0
+}
+function ble/widget/magic-space {
+ [[ $_ble_decode_keymap == vi_imap ]] &&
+ local oind=$_ble_edit_ind ostr=$_ble_edit_str
+ local arg; ble-edit/content/get-arg ''
+ ble/widget/history-expand-backward-line ||
+ ble/complete/sabbrev/expand
+ local ext=$?
+ ((ext==147)) && return 147 # sabbrev/expand でメニュー補完に入った時など。
+ [[ $_ble_decode_keymap == vi_imap ]] &&
+ if [[ $ostr != "$_ble_edit_str" ]]; then
+ _ble_edit_ind=$oind _ble_edit_str=$ostr ble/keymap:vi/undo/add more
+ ble/keymap:vi/undo/add more
+ fi
+ local -a KEYS=(32)
+ _ble_edit_arg=$arg
+ ble/widget/self-insert
+}
+function ble/highlight/layer:region/mark:search/get-face { face=region_match; }
+function ble-edit/isearch/search {
+ local needle=$1 opts=$2
+ beg= end=
+ [[ :$opts: != *:regex:* ]]; local has_regex=$?
+ [[ :$opts: != *:extend:* ]]; local has_extend=$?
+ local flag_empty_retry=
+ if [[ :$opts: == *:-:* ]]; then
+ local start=$((has_extend?_ble_edit_mark+1:_ble_edit_ind))
+ if ((has_regex)); then
+ ble-edit/isearch/.shift-backward-references
+ local rex="^.*($needle)" padding=$((${#_ble_edit_str}-start))
+ ((padding)) && rex="$rex.{$padding}"
+ if [[ $_ble_edit_str =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ if [[ $rematch1 || $BASH_REMATCH == "$_ble_edit_str" || :$opts: == *:allow_empty:* ]]; then
+ ((end=${#BASH_REMATCH}-padding,
+ beg=end-${#rematch1}))
+ return 0
+ else
+ flag_empty_retry=1
+ fi
+ fi
+ else
+ if [[ $needle ]]; then
+ local target=${_ble_edit_str::start}
+ local m=${target%"$needle"*}
+ if [[ $target != "$m" ]]; then
+ beg=${#m}
+ end=$((beg+${#needle}))
+ return 0
+ fi
+ else
+ if [[ :$opts: == *:allow_empty:* ]] || ((--start>=0)); then
+ ((beg=end=start))
+ return 0
+ fi
+ fi
+ fi
+ elif [[ :$opts: == *:B:* ]]; then
+ local start=$((has_extend?_ble_edit_ind:_ble_edit_ind-1))
+ ((start<0)) && return 1
+ if ((has_regex)); then
+ ble-edit/isearch/.shift-backward-references
+ local rex="^.{0,$start}($needle)"
+ ((start==0)) && rex="^($needle)"
+ if [[ $_ble_edit_str =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ if [[ $rematch1 || :$opts: == *:allow_empty:* ]]; then
+ ((end=${#BASH_REMATCH},
+ beg=end-${#rematch1}))
+ return 0
+ else
+ flag_empty_retry=1
+ fi
+ fi
+ else
+ if [[ $needle ]]; then
+ local target=${_ble_edit_str::start+${#needle}}
+ local m=${target%"$needle"*}
+ if [[ $target != "$m" ]]; then
+ ((beg=${#m},
+ end=beg+${#needle}))
+ return 0
+ fi
+ else
+ if [[ :$opts: == *:allow_empty:* ]] && ((--start>=0)); then
+ ((beg=end=start))
+ return 0
+ fi
+ fi
+ fi
+ else
+ local start=$((has_extend?_ble_edit_mark:_ble_edit_ind))
+ if ((has_regex)); then
+ ble-edit/isearch/.shift-backward-references
+ local rex="($needle).*\$"
+ ((start)) && rex=".{$start}$rex"
+ if [[ $_ble_edit_str =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ if [[ $rematch1 || :$opts: == *:allow_empty:* ]]; then
+ ((beg=${#_ble_edit_str}-${#BASH_REMATCH}+start))
+ ((end=beg+${#rematch1}))
+ return 0
+ else
+ flag_empty_retry=1
+ fi
+ fi
+ else
+ if [[ $needle ]]; then
+ local target=${_ble_edit_str:start}
+ local m=${target#*"$needle"}
+ if [[ $target != "$m" ]]; then
+ ((end=${#_ble_edit_str}-${#m}))
+ ((beg=end-${#needle}))
+ return 0
+ fi
+ else
+ if [[ :$opts: == *:allow_empty:* ]] || ((++start<=${#_ble_edit_str})); then
+ ((beg=end=start))
+ return 0
+ fi
+ fi
+ fi
+ fi
+ if [[ $flag_empty_retry ]]; then
+ if [[ :$opts: == *:[-B]:* ]]; then
+ if ((--start>=0)); then
+ local mark=$_ble_edit_mark; ((mark&&mark--))
+ local ind=$_ble_edit_ind; ((ind&&ind--))
+ opts=$opts:allow_empty
+ _ble_edit_mark=$mark _ble_edit_ind=$ind ble-edit/isearch/search "$needle" "$opts"
+ return 0
+ fi
+ else
+ if ((++start<=${#_ble_edit_str})); then
+ local mark=$_ble_edit_mark; ((mark<${#_ble_edit_str}&&mark++))
+ local ind=$_ble_edit_ind; ((ind<${#_ble_edit_str}&&ind++))
+ opts=$opts:allow_empty
+ _ble_edit_mark=$mark _ble_edit_ind=$ind ble-edit/isearch/search "$needle" "$opts"
+ return 0
+ fi
+ fi
+ fi
+ return 1
+}
+function ble-edit/isearch/.shift-backward-references {
+ local rex_cc='\[[@][^]@]+[@]\]' # [:space:] [=a=] [.a.] など。
+ local rex_bracket_expr='\[\^?]?('${rex_cc//@/:}'|'${rex_cc//@/=}'|'${rex_cc//@/.}'|[^][]|\[[^]:=.])*\[?\]'
+ local rex='^('$rex_bracket_expr'|\\[^1-8])*\\[1-8]'
+ local buff=
+ while [[ $needle =~ $rex ]]; do
+ local mlen=${#BASH_REMATCH}
+ buff=$buff${BASH_REMATCH::mlen-1}$((10#0${BASH_REMATCH:mlen-1}+1))
+ needle=${needle:mlen}
+ done
+ needle=$buff$needle
+}
+_ble_edit_isearch_str=
+_ble_edit_isearch_dir=-
+_ble_edit_isearch_arr=()
+_ble_edit_isearch_old=
+function ble-edit/isearch/status/append-progress-bar {
+ ble/util/is-unicode-output || return 1
+ local pos=$1 count=$2 dir=$3
+ [[ :$dir: == *:-:* || :$dir: == *:backward:* ]] && ((pos=count-1-pos))
+ local ret; ble/string#create-unicode-progress-bar "$pos" "$count" 5
+ text=$text$' \e[1;38;5;69;48;5;253m'$ret$'\e[m '
+}
+function ble-edit/isearch/.show-status-with-progress.fib {
+ local ll rr
+ if [[ $_ble_edit_isearch_dir == - ]]; then
+ ll=\<\< rr=" "
+ else
+ ll=" " rr=">>"
+ fi
+ local index; ble/history/get-index
+ local histIndex='!'$((index+1))
+ local text="(${#_ble_edit_isearch_arr[@]}: $ll $histIndex $rr) \`$_ble_edit_isearch_str'"
+ if [[ $1 ]]; then
+ local pos=$1
+ local count; ble/history/get-count
+ text=$text' searching...'
+ ble-edit/isearch/status/append-progress-bar "$pos" "$count" "$_ble_edit_isearch_dir"
+ local percentage=$((count?pos*1000/count:1000))
+ text=$text" @$pos ($((percentage/10)).$((percentage%10))%)"
+ fi
+ ((fib_ntask)) && text="$text *$fib_ntask"
+ ble/edit/info/show ansi "$text"
+}
+function ble-edit/isearch/.show-status.fib {
+ ble-edit/isearch/.show-status-with-progress.fib
+}
+function ble-edit/isearch/show-status {
+ local fib_ntask=${#_ble_util_fiberchain[@]}
+ ble-edit/isearch/.show-status.fib
+}
+function ble-edit/isearch/erase-status {
+ ble/edit/info/default
+}
+function ble-edit/isearch/.set-region {
+ local beg=$1 end=$2
+ if ((beg<end)); then
+ if [[ $_ble_edit_isearch_dir == - ]]; then
+ _ble_edit_ind=$beg
+ _ble_edit_mark=$end
+ else
+ _ble_edit_ind=$end
+ _ble_edit_mark=$beg
+ fi
+ _ble_edit_mark_active=search
+ elif ((beg==end)); then
+ _ble_edit_ind=$beg
+ _ble_edit_mark=$beg
+ _ble_edit_mark_active=
+ else
+ _ble_edit_mark_active=
+ fi
+}
+function ble-edit/isearch/.push-isearch-array {
+ local hash=$beg:$end:$needle
+ local ilast=$((${#_ble_edit_isearch_arr[@]}-1))
+ if ((ilast>=0)) && [[ ${_ble_edit_isearch_arr[ilast]} == "$ind:"[-+]":$hash" ]]; then
+ builtin unset -v "_ble_edit_isearch_arr[$ilast]"
+ return 0
+ fi
+ local oind; ble/history/get-index -v oind
+ local obeg=$_ble_edit_ind oend=$_ble_edit_mark
+ [[ $_ble_edit_mark_active ]] || oend=$obeg
+ ((obeg>oend)) && local obeg=$oend oend=$obeg
+ local oneedle=$_ble_edit_isearch_str
+ local ohash=$obeg:$oend:$oneedle
+ [[ $ind == "$oind" && $hash == "$ohash" ]] && return 0
+ ble/array#push _ble_edit_isearch_arr "$oind:$_ble_edit_isearch_dir:$ohash"
+}
+function ble-edit/isearch/.goto-match.fib {
+ local ind=$1 beg=$2 end=$3 needle=$4
+ ble-edit/isearch/.push-isearch-array
+ _ble_edit_isearch_str=$needle
+ [[ $needle ]] && _ble_edit_isearch_old=$needle
+ local oind; ble/history/get-index -v oind
+ ((oind!=ind)) && ble-edit/history/goto "$ind"
+ ble-edit/isearch/.set-region "$beg" "$end"
+ ble-edit/isearch/.show-status.fib
+ ble/textarea#redraw
+}
+function ble-edit/isearch/.next.fib {
+ local opts=$1
+ if [[ ! $fib_suspend ]]; then
+ if [[ :$opts: == *:forward:* || :$opts: == *:backward:* ]]; then
+ if [[ :$opts: == *:forward:* ]]; then
+ _ble_edit_isearch_dir=+
+ else
+ _ble_edit_isearch_dir=-
+ fi
+ fi
+ local needle=${2-$_ble_edit_isearch_str}
+ local beg= end= search_opts=$_ble_edit_isearch_dir
+ if [[ :$opts: == *:append:* ]]; then
+ search_opts=$search_opts:extend
+ ble/path#remove opts append
+ fi
+ if [[ $needle ]] && ble-edit/isearch/search "$needle" "$search_opts"; then
+ local ind; ble/history/get-index -v ind
+ ble-edit/isearch/.goto-match.fib "$ind" "$beg" "$end" "$needle"
+ return 0
+ fi
+ fi
+ ble-edit/isearch/.next-history.fib "$opts" "$needle"
+}
+function ble-edit/isearch/.next-history.fib {
+ local opts=$1
+ if [[ $fib_suspend ]]; then
+ local needle=${fib_suspend#*:} isAdd=
+ local index start; builtin eval -- "${fib_suspend%%:*}"
+ fib_suspend=
+ else
+ local needle=${2-$_ble_edit_isearch_str} isAdd=
+ [[ :$opts: == *:append:* ]] && isAdd=1
+ ble/history/initialize
+ local start=$_ble_history_INDEX
+ local index=$start
+ fi
+ if ((!isAdd)); then
+ if [[ $_ble_edit_isearch_dir == - ]]; then
+ ((index--))
+ else
+ ((index++))
+ fi
+ fi
+ local isearch_progress_callback=ble-edit/isearch/.show-status-with-progress.fib
+ if [[ $_ble_edit_isearch_dir == - ]]; then
+ ble/history/isearch-backward-blockwise stop_check:progress
+ else
+ ble/history/isearch-forward stop_check:progress
+ fi
+ local ext=$?
+ if ((ext==0)); then
+ local str; ble/history/get-edited-entry -v str "$index"
+ if [[ $needle ]]; then
+ if [[ $_ble_edit_isearch_dir == - ]]; then
+ local prefix=${str%"$needle"*}
+ else
+ local prefix=${str%%"$needle"*}
+ fi
+ local beg=${#prefix} end=$((${#prefix}+${#needle}))
+ else
+ local beg=${#str} end=${#str}
+ fi
+ ble-edit/isearch/.goto-match.fib "$index" "$beg" "$end" "$needle"
+ elif ((ext==148)); then
+ fib_suspend="index=$index start=$start:$needle"
+ return 0
+ else
+ ble/widget/.bell "isearch: \`$needle' not found"
+ return 0
+ fi
+}
+function ble-edit/isearch/forward.fib {
+ if [[ ! $_ble_edit_isearch_str ]]; then
+ ble-edit/isearch/.next.fib forward "$_ble_edit_isearch_old"
+ else
+ ble-edit/isearch/.next.fib forward
+ fi
+}
+function ble-edit/isearch/backward.fib {
+ if [[ ! $_ble_edit_isearch_str ]]; then
+ ble-edit/isearch/.next.fib backward "$_ble_edit_isearch_old"
+ else
+ ble-edit/isearch/.next.fib backward
+ fi
+}
+function ble-edit/isearch/self-insert.fib {
+ local needle=
+ if [[ ! $fib_suspend ]]; then
+ local code=$1
+ ((code==0)) && return 0
+ local ret; ble/util/c2s "$code"
+ needle=$_ble_edit_isearch_str$ret
+ fi
+ ble-edit/isearch/.next.fib append "$needle"
+}
+function ble-edit/isearch/insert-string.fib {
+ local needle=
+ [[ ! $fib_suspend ]] &&
+ needle=$_ble_edit_isearch_str$1
+ ble-edit/isearch/.next.fib append "$needle"
+}
+function ble-edit/isearch/history-forward.fib {
+ _ble_edit_isearch_dir=+
+ ble-edit/isearch/.next-history.fib
+}
+function ble-edit/isearch/history-backward.fib {
+ _ble_edit_isearch_dir=-
+ ble-edit/isearch/.next-history.fib
+}
+function ble-edit/isearch/history-self-insert.fib {
+ local needle=
+ if [[ ! $fib_suspend ]]; then
+ local code=$1
+ ((code==0)) && return 0
+ local ret; ble/util/c2s "$code"
+ needle=$_ble_edit_isearch_str$ret
+ fi
+ ble-edit/isearch/.next-history.fib append "$needle"
+}
+function ble-edit/isearch/prev {
+ local sz=${#_ble_edit_isearch_arr[@]}
+ ((sz==0)) && return 0
+ local ilast=$((sz-1))
+ local top=${_ble_edit_isearch_arr[ilast]}
+ builtin unset -v '_ble_edit_isearch_arr[ilast]'
+ local ind dir beg end
+ ind=${top%%:*}; top=${top#*:}
+ dir=${top%%:*}; top=${top#*:}
+ beg=${top%%:*}; top=${top#*:}
+ end=${top%%:*}; top=${top#*:}
+ _ble_edit_isearch_dir=$dir
+ ble-edit/history/goto "$ind"
+ ble-edit/isearch/.set-region "$beg" "$end"
+ _ble_edit_isearch_str=$top
+ [[ $top ]] && _ble_edit_isearch_old=$top
+ ble-edit/isearch/show-status
+}
+function ble-edit/isearch/process {
+ local isearch_time=0
+ ble/util/fiberchain#resume
+ ble-edit/isearch/show-status
+}
+function ble/widget/isearch/forward {
+ ble/util/fiberchain#push forward
+ ble-edit/isearch/process
+}
+function ble/widget/isearch/backward {
+ ble/util/fiberchain#push backward
+ ble-edit/isearch/process
+}
+function ble/widget/isearch/self-insert {
+ local code; ble/widget/self-insert/.get-code
+ ((code==0)) && return 0
+ ble/util/fiberchain#push "self-insert $code"
+ ble-edit/isearch/process
+}
+function ble/widget/isearch/history-forward {
+ ble/util/fiberchain#push history-forward
+ ble-edit/isearch/process
+}
+function ble/widget/isearch/history-backward {
+ ble/util/fiberchain#push history-backward
+ ble-edit/isearch/process
+}
+function ble/widget/isearch/history-self-insert {
+ local code; ble/widget/self-insert/.get-code
+ ((code==0)) && return 0
+ ble/util/fiberchain#push "history-self-insert $code"
+ ble-edit/isearch/process
+}
+function ble/widget/isearch/prev {
+ local nque
+ if ((nque=${#_ble_util_fiberchain[@]})); then
+ local ret; ble/array#pop _ble_util_fiberchain
+ ble-edit/isearch/process
+ else
+ ble-edit/isearch/prev
+ fi
+}
+function ble/widget/isearch/.restore-mark-state {
+ local old_mark_active=${_ble_edit_isearch_save[3]}
+ if [[ $old_mark_active ]]; then
+ local index; ble/history/get-index
+ if ((index==_ble_edit_isearch_save[0])); then
+ _ble_edit_mark=${_ble_edit_isearch_save[2]}
+ if [[ $old_mark_active != S ]] || ((_ble_edit_ind==_ble_edit_isearch_save[1])); then
+ _ble_edit_mark_active=$old_mark_active
+ fi
+ fi
+ fi
+}
+function ble/widget/isearch/exit.impl {
+ ble/decode/keymap/pop
+ _ble_edit_isearch_arr=()
+ _ble_edit_isearch_dir=
+ _ble_edit_isearch_str=
+ ble-edit/isearch/erase-status
+}
+function ble/widget/isearch/exit-with-region {
+ ble/widget/isearch/exit.impl
+ [[ $_ble_edit_mark_active ]] &&
+ _ble_edit_mark_active=S
+}
+function ble/widget/isearch/exit {
+ ble/widget/isearch/exit.impl
+ _ble_edit_mark_active=
+ ble/widget/isearch/.restore-mark-state
+}
+function ble/widget/isearch/cancel {
+ if ((${#_ble_util_fiberchain[@]})); then
+ ble/util/fiberchain#clear
+ ble-edit/isearch/show-status # 進捗状況だけ消去
+ else
+ if ((${#_ble_edit_isearch_arr[@]})); then
+ local step
+ ble/string#split step : "${_ble_edit_isearch_arr[0]}"
+ ble-edit/history/goto "${step[0]}"
+ fi
+ ble/widget/isearch/exit.impl
+ _ble_edit_ind=${_ble_edit_isearch_save[1]}
+ _ble_edit_mark=${_ble_edit_isearch_save[2]}
+ _ble_edit_mark_active=${_ble_edit_isearch_save[3]}
+ fi
+}
+function ble/widget/isearch/exit-default {
+ ble/widget/isearch/exit-with-region
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+}
+function ble/widget/isearch/accept-line {
+ if ((${#_ble_util_fiberchain[@]})); then
+ ble/widget/.bell "isearch: now searching..."
+ else
+ ble/widget/isearch/exit
+ ble-decode-key 13 # RET
+ fi
+}
+function ble/widget/isearch/exit-delete-forward-char {
+ ble/widget/isearch/exit
+ ble/widget/delete-forward-char
+}
+function ble/widget/history-isearch.impl {
+ local opts=$1
+ ble/keymap:generic/clear-arg
+ ble/decode/keymap/push isearch
+ ble/util/fiberchain#initialize ble-edit/isearch
+ local index; ble/history/get-index
+ _ble_edit_isearch_save=("$index" "$_ble_edit_ind" "$_ble_edit_mark" "$_ble_edit_mark_active")
+ if [[ :$opts: == *:forward:* ]]; then
+ _ble_edit_isearch_dir=+
+ else
+ _ble_edit_isearch_dir=-
+ fi
+ _ble_edit_isearch_arr=()
+ _ble_edit_mark=$_ble_edit_ind
+ ble-edit/isearch/show-status
+}
+function ble/widget/history-isearch-backward {
+ ble/widget/history-isearch.impl backward
+}
+function ble/widget/history-isearch-forward {
+ ble/widget/history-isearch.impl forward
+}
+function ble-decode/keymap:isearch/define {
+ ble-bind -f __defchar__ isearch/self-insert
+ ble-bind -f __line_limit__ nop
+ ble-bind -f C-r isearch/backward
+ ble-bind -f C-s isearch/forward
+ ble-bind -f 'C-?' isearch/prev
+ ble-bind -f 'DEL' isearch/prev
+ ble-bind -f 'C-h' isearch/prev
+ ble-bind -f 'BS' isearch/prev
+ ble-bind -f __default__ isearch/exit-default
+ ble-bind -f 'C-g' isearch/cancel
+ ble-bind -f 'C-x C-g' isearch/cancel
+ ble-bind -f 'C-M-g' isearch/cancel
+ ble-bind -f C-m isearch/exit
+ ble-bind -f RET isearch/exit
+ ble-bind -f C-j isearch/accept-line
+ ble-bind -f C-RET isearch/accept-line
+}
+_ble_edit_nsearch_input=
+_ble_edit_nsearch_needle=
+_ble_edit_nsearch_index0=
+_ble_edit_nsearch_opts=
+_ble_edit_nsearch_stack=()
+_ble_edit_nsearch_match=
+_ble_edit_nsearch_index=
+_ble_edit_nsearch_prev=
+function ble/highlight/layer:region/mark:nsearch/get-face {
+ face=region_match
+}
+function ble/highlight/layer:region/mark:nsearch/get-selection {
+ local beg=$_ble_edit_mark
+ local end=$((_ble_edit_mark+${#_ble_edit_nsearch_needle}))
+ selection=("$beg" "$end")
+}
+function ble-edit/nsearch/.show-status.fib {
+ [[ :$_ble_edit_nsearch_opts: == *:hide-status:* ]] && return 0
+ local ll=\<\< rr=">>" # Note: Emacs workaround: '<<' や "<<" と書けない。
+ local match=$_ble_edit_nsearch_match index0=$_ble_edit_nsearch_index0
+ if ((match>index0)); then
+ ll=" "
+ elif ((match<index0)); then
+ rr=" "
+ fi
+ local sindex='!'$((_ble_edit_nsearch_match+1))
+ local nmatch=${#_ble_edit_nsearch_stack[@]}
+ local needle=$_ble_edit_nsearch_needle
+ local text="(nsearch#$nmatch: $ll $sindex $rr) \`$needle'"
+ if [[ $1 ]]; then
+ local pos=$1
+ local count; ble/history/get-count
+ text=$text' searching...'
+ ble-edit/isearch/status/append-progress-bar "$pos" "$count" "$_ble_edit_isearch_opts"
+ local percentage=$((count?pos*1000/count:1000))
+ text=$text" @$pos ($((percentage/10)).$((percentage%10))%)"
+ fi
+ local ntask=$fib_ntask
+ ((ntask)) && text="$text *$ntask"
+ ble/edit/info/show ansi "$text"
+}
+function ble-edit/nsearch/show-status {
+ local fib_ntask=${#_ble_util_fiberchain[@]}
+ ble-edit/nsearch/.show-status.fib
+}
+function ble-edit/nsearch/erase-status {
+ ble/edit/info/default
+}
+function ble-edit/nsearch/.goto-match {
+ local index=$1 opts=$2
+ local direction=backward
+ [[ :$opts: == *:forward:* ]] && direction=forward
+ local needle=$_ble_edit_nsearch_needle
+ local old_match=$_ble_edit_nsearch_match
+ ble/array#push _ble_edit_nsearch_stack "$direction,$old_match,$_ble_edit_ind,$_ble_edit_mark:$_ble_edit_str"
+ if [[ ! $index ]]; then
+ ble/history/get-index
+ elif [[ :$opts: == *:action=load:* ]]; then
+ local old_index; ble/history/get-index -v old_index
+ if ((index!=old_index)); then
+ local line; ble/history/get-edited-entry -v line "$index"
+ ble-edit/content/reset-and-check-dirty "$line"
+ fi
+ else
+ ble-edit/history/goto "$index"
+ fi
+ local prefix=${_ble_edit_str%%"$needle"*}
+ local beg=${#prefix}
+ local end=$((beg+${#needle}))
+ _ble_edit_nsearch_match=$index
+ _ble_edit_nsearch_index=$index
+ _ble_edit_mark=$beg
+ local is_end_marker=
+ local rex=':point=([^:]*):'
+ [[ :$opts: =~ $rex ]]
+ case ${BASH_REMATCH[1]} in
+ (begin) _ble_edit_ind=0 ;;
+ (end) _ble_edit_ind=${#_ble_edit_str} is_end_marker=1 ;;
+ (match-begin) _ble_edit_ind=$beg ;;
+ (match-end|*) _ble_edit_ind=$end is_end_marker=1 ;;
+ esac
+ if [[ $is_end_marker ]] && ((_ble_edit_ind)); then
+ if local ret; ble/decode/keymap/get-parent; [[ $ret == vi_[noxs]map ]]; then
+ ble-edit/content/bolp || ((_ble_edit_ind--))
+ fi
+ fi
+ if ((beg!=end)); then
+ _ble_edit_mark_active=nsearch
+ else
+ _ble_edit_mark_active=
+ fi
+}
+function ble-edit/nsearch/.search.fib {
+ local opts=$1
+ local opt_forward=
+ [[ :$opts: == *:forward:* ]] && opt_forward=1
+ local nstack=${#_ble_edit_nsearch_stack[@]}
+ if ((nstack>=2)); then
+ local record_type=${_ble_edit_nsearch_stack[nstack-1]%%,*}
+ if
+ if [[ $opt_forward ]]; then
+ [[ $record_type == backward ]]
+ else
+ [[ $record_type == forward ]]
+ fi
+ then
+ local ret; ble/array#pop _ble_edit_nsearch_stack
+ local record line=${ret#*:}
+ ble/string#split record , "${ret%%:*}"
+ if [[ :$opts: == *:action=load:* ]]; then
+ ble-edit/content/reset-and-check-dirty "$line"
+ else
+ ble-edit/history/goto "${record[1]}"
+ fi
+ _ble_edit_nsearch_match=${record[1]}
+ _ble_edit_nsearch_index=${record[1]}
+ _ble_edit_ind=${record[2]}
+ _ble_edit_mark=${record[3]}
+ if ((_ble_edit_mark!=_ble_edit_ind)); then
+ _ble_edit_mark_active=nsearch
+ else
+ _ble_edit_mark_active=
+ fi
+ ble-edit/nsearch/.show-status.fib
+ ble/textarea#redraw
+ fib_suspend=
+ return 0
+ fi
+ fi
+ local index start opt_resume=
+ if [[ $fib_suspend ]]; then
+ opt_resume=1
+ builtin eval -- "$fib_suspend"
+ fib_suspend=
+ else
+ local index=$_ble_edit_nsearch_index
+ if ((nstack==1)); then
+ local index0=$_ble_edit_nsearch_index0
+ ((opt_forward?index<index0:index>index0)) &&
+ index=$index0
+ fi
+ local start=$index
+ fi
+ local needle=$_ble_edit_nsearch_needle
+ if
+ if [[ $opt_forward ]]; then
+ local count; ble/history/get-count
+ [[ $opt_resume ]] || ((++index))
+ ((index<=count))
+ else
+ [[ $opt_resume ]] || ((--index))
+ ((index>=0))
+ fi
+ then
+ local isearch_time=$fib_clock
+ local isearch_progress_callback=ble-edit/nsearch/.show-status.fib
+ local isearch_opts=stop_check:progress; [[ :$opts: != *:substr:* ]] && isearch_opts=$isearch_opts:head
+ if [[ $opt_forward ]]; then
+ ble/history/isearch-forward "$isearch_opts"; local ext=$?
+ else
+ ble/history/isearch-backward-blockwise "$isearch_opts"; local ext=$?
+ fi
+ fib_clock=$isearch_time
+ else
+ local ext=1
+ fi
+ if ((ext==0)); then
+ ble-edit/nsearch/.goto-match "$index" "$opts"
+ ble-edit/nsearch/.show-status.fib
+ ble/textarea#redraw
+ elif ((ext==148)); then
+ fib_suspend="index=$index start=$start"
+ return 148
+ else
+ ble/widget/.bell "ble.sh: nsearch: '$needle' not found"
+ ble-edit/nsearch/.show-status.fib
+ if [[ $opt_forward ]]; then
+ local count; ble/history/get-count
+ ((_ble_edit_nsearch_index=count-1))
+ else
+ ((_ble_edit_nsearch_index=0))
+ fi
+ return "$ext"
+ fi
+}
+function ble-edit/nsearch/forward.fib {
+ ble-edit/nsearch/.search.fib "$_ble_edit_nsearch_opts:forward"
+}
+function ble-edit/nsearch/backward.fib {
+ ble-edit/nsearch/.search.fib "$_ble_edit_nsearch_opts:backward"
+}
+function ble/widget/history-search {
+ local opts=$1
+ if [[ :$opts: == *:input:* || :$opts: == *:again:* && ! $_ble_edit_nsearch_input ]]; then
+ ble/builtin/read -ep "nsearch> " _ble_edit_nsearch_needle || return 1
+ _ble_edit_nsearch_input=$_ble_edit_nsearch_needle
+ elif [[ :$opts: == *:again:* ]]; then
+ _ble_edit_nsearch_needle=$_ble_edit_nsearch_input
+ else
+ local len=$_ble_edit_ind
+ if [[ $_ble_decode_keymap == vi_[noxs]map ]]; then
+ ble-edit/content/eolp || ((len++))
+ fi
+ _ble_edit_nsearch_needle=${_ble_edit_str::len}
+ fi
+ if [[ ! $_ble_edit_nsearch_needle ]]; then
+ local empty=empty-search
+ local rex='.*:empty=([^:]*):'
+ [[ :$opts: =~ $rex ]] && empty=${BASH_REMATCH[1]}
+ case $empty in
+ (history-move)
+ if [[ :$opts: == *:forward:* ]]; then
+ ble/widget/history-next
+ else
+ ble/widget/history-prev
+ fi && _ble_edit_ind=0
+ return $? ;;
+ (hide-status)
+ opts=$opts:hide-status ;;
+ (emulate-readline)
+ opts=hide-status:point=end:$opts ;;
+ (previous-search)
+ _ble_edit_nsearch_needle=$_ble_edit_nsearch_prev ;;
+ esac
+ fi
+ _ble_edit_nsearch_prev=$_ble_edit_nsearch_needle
+ ble/keymap:generic/clear-arg
+ _ble_edit_nsearch_stack=()
+ local index; ble/history/get-index
+ _ble_edit_nsearch_index0=$index
+ _ble_edit_nsearch_opts=$opts
+ ble/path#remove _ble_edit_nsearch_opts forward
+ ble/path#remove _ble_edit_nsearch_opts backward
+ _ble_edit_nsearch_match=$index
+ _ble_edit_nsearch_index=$index
+ _ble_edit_mark_active=
+ ble/decode/keymap/push nsearch
+ if
+ if [[ :$opts: == *:substr:* ]]; then
+ [[ $_ble_edit_str == *"$_ble_edit_nsearch_needle"* ]]
+ else
+ [[ $_ble_edit_str == "$_ble_edit_nsearch_needle"* ]]
+ fi
+ then
+ ble-edit/nsearch/.goto-match '' "$opts"
+ fi
+ ble/util/fiberchain#initialize ble-edit/nsearch
+ if [[ :$opts: == *:forward:* ]]; then
+ ble/util/fiberchain#push forward
+ else
+ ble/util/fiberchain#push backward
+ fi
+ ble/util/fiberchain#resume
+}
+function ble/widget/history-nsearch-backward {
+ ble/widget/history-search "input:substr:backward:$1"
+}
+function ble/widget/history-nsearch-forward {
+ ble/widget/history-search "input:substr:forward:$1"
+}
+function ble/widget/history-nsearch-backward-again {
+ ble/widget/history-search "again:substr:backward:$1"
+}
+function ble/widget/history-nsearch-forward-again {
+ ble/widget/history-search "again:substr:forward:$1"
+}
+function ble/widget/history-search-backward {
+ ble/widget/history-search "backward:$1"
+}
+function ble/widget/history-search-forward {
+ ble/widget/history-search "forward:$1"
+}
+function ble/widget/history-substring-search-backward {
+ ble/widget/history-search "substr:backward:$1"
+}
+function ble/widget/history-substring-search-forward {
+ ble/widget/history-search "substr:forward:$1"
+}
+function ble/widget/nsearch/forward {
+ local ntask=${#_ble_util_fiberchain[@]}
+ if ((ntask>=1)) && [[ ${_ble_util_fiberchain[ntask-1]%%:*} == backward ]]; then
+ local ret; ble/array#pop _ble_util_fiberchain
+ else
+ ble/util/fiberchain#push forward
+ fi
+ ble/util/fiberchain#resume
+}
+function ble/widget/nsearch/backward {
+ local ntask=${#_ble_util_fiberchain[@]}
+ if ((ntask>=1)) && [[ ${_ble_util_fiberchain[ntask-1]%%:*} == forward ]]; then
+ local ret; ble/array#pop _ble_util_fiberchain
+ else
+ ble/util/fiberchain#push backward
+ fi
+ ble/util/fiberchain#resume
+}
+function ble/widget/nsearch/.exit {
+ ble/decode/keymap/pop
+ _ble_edit_mark_active=
+ ble-edit/nsearch/erase-status
+}
+function ble/widget/nsearch/exit {
+ if [[ :$_ble_edit_nsearch_opts: == *:immediate-accept:* ]]; then
+ ble/widget/nsearch/accept-line
+ else
+ ble/widget/nsearch/.exit
+ fi
+}
+function ble/widget/nsearch/exit-default {
+ ble/widget/nsearch/.exit
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+}
+function ble/widget/nsearch/cancel {
+ if ((${#_ble_util_fiberchain[@]})); then
+ ble/util/fiberchain#clear
+ ble-edit/nsearch/show-status
+ else
+ ble/widget/nsearch/.exit
+ local record=${_ble_edit_nsearch_stack[0]}
+ if [[ $record ]]; then
+ local line=${record#*:}
+ ble/string#split record , "${record%%:*}"
+ if [[ :$_ble_edit_nsearch_opts: == *:action=load:* ]]; then
+ ble-edit/content/reset-and-check-dirty "$line"
+ else
+ ble-edit/history/goto "$_ble_edit_nsearch_index0"
+ fi
+ _ble_edit_ind=${record[2]}
+ _ble_edit_mark=${record[3]}
+ fi
+ fi
+}
+function ble/widget/nsearch/accept-line {
+ if ((${#_ble_util_fiberchain[@]})); then
+ ble/widget/.bell "nsearch: now searching..."
+ else
+ ble/widget/nsearch/.exit
+ ble-decode-key 13 # RET
+ fi
+}
+function ble-decode/keymap:nsearch/define {
+ ble-bind -f __default__ nsearch/exit-default
+ ble-bind -f __line_limit__ nop
+ ble-bind -f 'C-g' nsearch/cancel
+ ble-bind -f 'C-x C-g' nsearch/cancel
+ ble-bind -f 'C-M-g' nsearch/cancel
+ ble-bind -f C-m nsearch/exit
+ ble-bind -f RET nsearch/exit
+ ble-bind -f C-j nsearch/accept-line
+ ble-bind -f C-RET nsearch/accept-line
+ ble-bind -f C-r nsearch/backward
+ ble-bind -f C-s nsearch/forward
+ ble-bind -f C-p nsearch/backward
+ ble-bind -f C-n nsearch/forward
+ ble-bind -f up nsearch/backward
+ ble-bind -f down nsearch/forward
+ ble-bind -f prior nsearch/backward
+ ble-bind -f next nsearch/forward
+}
+function ble-decode/keymap:safe/.bind {
+ [[ $ble_bind_nometa && $1 == *M-* ]] && return 0
+ ble-bind -f "$1" "$2"
+}
+function ble-decode/keymap:safe/bind-common {
+ ble-decode/keymap:safe/.bind insert 'overwrite-mode'
+ ble-decode/keymap:safe/.bind __batch_char__ 'batch-insert'
+ ble-decode/keymap:safe/.bind __defchar__ 'self-insert'
+ ble-decode/keymap:safe/.bind 'C-q' 'quoted-insert'
+ ble-decode/keymap:safe/.bind 'C-v' 'quoted-insert'
+ ble-decode/keymap:safe/.bind 'M-C-m' 'newline'
+ ble-decode/keymap:safe/.bind 'M-RET' 'newline'
+ ble-decode/keymap:safe/.bind paste_begin 'bracketed-paste'
+ ble-decode/keymap:safe/.bind 'C-@' 'set-mark'
+ ble-decode/keymap:safe/.bind 'C-SP' 'set-mark'
+ ble-decode/keymap:safe/.bind 'NUL' 'set-mark'
+ ble-decode/keymap:safe/.bind 'M-SP' 'set-mark'
+ ble-decode/keymap:safe/.bind 'C-x C-x' 'exchange-point-and-mark'
+ ble-decode/keymap:safe/.bind 'C-w' 'kill-region-or kill-backward-uword'
+ ble-decode/keymap:safe/.bind 'M-w' 'copy-region-or copy-backward-uword'
+ ble-decode/keymap:safe/.bind 'C-y' 'yank'
+ ble-decode/keymap:safe/.bind 'M-y' 'yank-pop'
+ ble-decode/keymap:safe/.bind 'M-S-y' 'yank-pop backward'
+ ble-decode/keymap:safe/.bind 'M-Y' 'yank-pop backward'
+ ble-decode/keymap:safe/.bind 'M-\' 'delete-horizontal-space'
+ ble-decode/keymap:safe/.bind 'C-f' '@nomarked forward-char'
+ ble-decode/keymap:safe/.bind 'C-b' '@nomarked backward-char'
+ ble-decode/keymap:safe/.bind 'right' '@nomarked forward-char'
+ ble-decode/keymap:safe/.bind 'left' '@nomarked backward-char'
+ ble-decode/keymap:safe/.bind 'S-C-f' '@marked forward-char'
+ ble-decode/keymap:safe/.bind 'S-C-b' '@marked backward-char'
+ ble-decode/keymap:safe/.bind 'S-right' '@marked forward-char'
+ ble-decode/keymap:safe/.bind 'S-left' '@marked backward-char'
+ ble-decode/keymap:safe/.bind 'C-d' 'delete-region-or delete-forward-char'
+ ble-decode/keymap:safe/.bind 'delete' 'delete-region-or delete-forward-char'
+ ble-decode/keymap:safe/.bind 'C-?' 'delete-region-or delete-backward-char'
+ ble-decode/keymap:safe/.bind 'DEL' 'delete-region-or delete-backward-char'
+ ble-decode/keymap:safe/.bind 'C-h' 'delete-region-or delete-backward-char'
+ ble-decode/keymap:safe/.bind 'BS' 'delete-region-or delete-backward-char'
+ ble-decode/keymap:safe/.bind 'C-t' 'transpose-chars'
+ ble-decode/keymap:safe/.bind 'C-right' '@nomarked forward-cword'
+ ble-decode/keymap:safe/.bind 'C-left' '@nomarked backward-cword'
+ ble-decode/keymap:safe/.bind 'M-right' '@nomarked forward-sword'
+ ble-decode/keymap:safe/.bind 'M-left' '@nomarked backward-sword'
+ ble-decode/keymap:safe/.bind 'S-C-right' '@marked forward-cword'
+ ble-decode/keymap:safe/.bind 'S-C-left' '@marked backward-cword'
+ ble-decode/keymap:safe/.bind 'M-S-right' '@marked forward-sword'
+ ble-decode/keymap:safe/.bind 'M-S-left' '@marked backward-sword'
+ ble-decode/keymap:safe/.bind 'M-d' 'kill-forward-cword'
+ ble-decode/keymap:safe/.bind 'M-h' 'kill-backward-cword'
+ ble-decode/keymap:safe/.bind 'C-delete' 'delete-forward-cword'
+ ble-decode/keymap:safe/.bind 'C-_' 'delete-backward-cword'
+ ble-decode/keymap:safe/.bind 'C-DEL' 'delete-backward-cword'
+ ble-decode/keymap:safe/.bind 'C-BS' 'delete-backward-cword'
+ ble-decode/keymap:safe/.bind 'M-delete' 'copy-forward-sword'
+ ble-decode/keymap:safe/.bind 'M-C-?' 'copy-backward-sword'
+ ble-decode/keymap:safe/.bind 'M-DEL' 'copy-backward-sword'
+ ble-decode/keymap:safe/.bind 'M-C-h' 'copy-backward-sword'
+ ble-decode/keymap:safe/.bind 'M-BS' 'copy-backward-sword'
+ ble-decode/keymap:safe/.bind 'M-f' '@nomarked forward-cword'
+ ble-decode/keymap:safe/.bind 'M-b' '@nomarked backward-cword'
+ ble-decode/keymap:safe/.bind 'M-F' '@marked forward-cword'
+ ble-decode/keymap:safe/.bind 'M-B' '@marked backward-cword'
+ ble-decode/keymap:safe/.bind 'M-S-f' '@marked forward-cword'
+ ble-decode/keymap:safe/.bind 'M-S-b' '@marked backward-cword'
+ ble-decode/keymap:safe/.bind 'M-c' 'capitalize-eword'
+ ble-decode/keymap:safe/.bind 'M-l' 'downcase-eword'
+ ble-decode/keymap:safe/.bind 'M-u' 'upcase-eword'
+ ble-decode/keymap:safe/.bind 'M-t' 'transpose-ewords'
+ ble-decode/keymap:safe/.bind 'C-a' '@nomarked beginning-of-line'
+ ble-decode/keymap:safe/.bind 'C-e' '@nomarked end-of-line'
+ ble-decode/keymap:safe/.bind 'home' '@nomarked beginning-of-line'
+ ble-decode/keymap:safe/.bind 'end' '@nomarked end-of-line'
+ ble-decode/keymap:safe/.bind 'S-C-a' '@marked beginning-of-line'
+ ble-decode/keymap:safe/.bind 'S-C-e' '@marked end-of-line'
+ ble-decode/keymap:safe/.bind 'S-home' '@marked beginning-of-line'
+ ble-decode/keymap:safe/.bind 'S-end' '@marked end-of-line'
+ ble-decode/keymap:safe/.bind 'M-m' '@nomarked non-space-beginning-of-line'
+ ble-decode/keymap:safe/.bind 'M-S-m' '@marked non-space-beginning-of-line'
+ ble-decode/keymap:safe/.bind 'M-M' '@marked non-space-beginning-of-line'
+ ble-decode/keymap:safe/.bind 'C-p' '@nomarked backward-line' # overwritten by bind-history
+ ble-decode/keymap:safe/.bind 'up' '@nomarked backward-line' # overwritten by bind-history
+ ble-decode/keymap:safe/.bind 'C-n' '@nomarked forward-line' # overwritten by bind-history
+ ble-decode/keymap:safe/.bind 'down' '@nomarked forward-line' # overwritten by bind-history
+ ble-decode/keymap:safe/.bind 'C-k' 'kill-forward-line'
+ ble-decode/keymap:safe/.bind 'C-u' 'kill-backward-line'
+ ble-decode/keymap:safe/.bind 'S-C-p' '@marked backward-line'
+ ble-decode/keymap:safe/.bind 'S-up' '@marked backward-line'
+ ble-decode/keymap:safe/.bind 'S-C-n' '@marked forward-line'
+ ble-decode/keymap:safe/.bind 'S-down' '@marked forward-line'
+ ble-decode/keymap:safe/.bind 'C-home' '@nomarked beginning-of-text'
+ ble-decode/keymap:safe/.bind 'C-end' '@nomarked end-of-text'
+ ble-decode/keymap:safe/.bind 'S-C-home' '@marked beginning-of-text'
+ ble-decode/keymap:safe/.bind 'S-C-end' '@marked end-of-text'
+ ble-decode/keymap:safe/.bind 'C-x (' 'start-keyboard-macro'
+ ble-decode/keymap:safe/.bind 'C-x )' 'end-keyboard-macro'
+ ble-decode/keymap:safe/.bind 'C-x e' 'call-keyboard-macro'
+ ble-decode/keymap:safe/.bind 'C-x P' 'print-keyboard-macro'
+ ble-decode/keymap:safe/.bind 'C-]' 'character-search-forward'
+ ble-decode/keymap:safe/.bind 'M-C-]' 'character-search-backward'
+}
+function ble-decode/keymap:safe/bind-history {
+ ble-decode/keymap:safe/.bind 'C-r' 'history-isearch-backward'
+ ble-decode/keymap:safe/.bind 'C-s' 'history-isearch-forward'
+ ble-decode/keymap:safe/.bind 'M-<' 'history-beginning'
+ ble-decode/keymap:safe/.bind 'M->' 'history-end'
+ ble-decode/keymap:safe/.bind 'C-prior' 'history-beginning'
+ ble-decode/keymap:safe/.bind 'C-next' 'history-end'
+ ble-decode/keymap:safe/.bind 'C-p' '@nomarked backward-line history'
+ ble-decode/keymap:safe/.bind 'up' '@nomarked backward-line history'
+ ble-decode/keymap:safe/.bind 'C-n' '@nomarked forward-line history'
+ ble-decode/keymap:safe/.bind 'down' '@nomarked forward-line history'
+ ble-decode/keymap:safe/.bind 'prior' 'history-search-backward' # bash-5.2
+ ble-decode/keymap:safe/.bind 'next' 'history-search-forward' # bash-5.2
+ ble-decode/keymap:safe/.bind 'C-x C-p' 'history-search-backward'
+ ble-decode/keymap:safe/.bind 'C-x up' 'history-search-backward'
+ ble-decode/keymap:safe/.bind 'C-x C-n' 'history-search-forward'
+ ble-decode/keymap:safe/.bind 'C-x down' 'history-search-forward'
+ ble-decode/keymap:safe/.bind 'C-x p' 'history-substring-search-backward'
+ ble-decode/keymap:safe/.bind 'C-x n' 'history-substring-search-forward'
+ ble-decode/keymap:safe/.bind 'C-x <' 'history-nsearch-backward'
+ ble-decode/keymap:safe/.bind 'C-x >' 'history-nsearch-forward'
+ ble-decode/keymap:safe/.bind 'C-x ,' 'history-nsearch-backward-again'
+ ble-decode/keymap:safe/.bind 'C-x .' 'history-nsearch-forward-again'
+ ble-decode/keymap:safe/.bind 'M-.' 'insert-last-argument'
+ ble-decode/keymap:safe/.bind 'M-_' 'insert-last-argument'
+ ble-decode/keymap:safe/.bind 'M-C-y' 'insert-nth-argument'
+}
+function ble-decode/keymap:safe/bind-complete {
+ ble-decode/keymap:safe/.bind 'C-i' 'complete'
+ ble-decode/keymap:safe/.bind 'TAB' 'complete'
+ ble-decode/keymap:safe/.bind 'M-?' 'complete show_menu'
+ ble-decode/keymap:safe/.bind 'M-*' 'complete insert_all'
+ ble-decode/keymap:safe/.bind 'M-{' 'complete insert_braces'
+ ble-decode/keymap:safe/.bind 'C-TAB' 'menu-complete'
+ ble-decode/keymap:safe/.bind 'S-C-i' 'menu-complete backward'
+ ble-decode/keymap:safe/.bind 'S-TAB' 'menu-complete backward'
+ ble-decode/keymap:safe/.bind 'auto_complete_enter' 'auto-complete-enter'
+ ble-decode/keymap:safe/.bind 'M-/' 'complete context=filename'
+ ble-decode/keymap:safe/.bind 'M-~' 'complete context=username'
+ ble-decode/keymap:safe/.bind 'M-$' 'complete context=variable'
+ ble-decode/keymap:safe/.bind 'M-@' 'complete context=hostname'
+ ble-decode/keymap:safe/.bind 'M-!' 'complete context=command'
+ ble-decode/keymap:safe/.bind 'C-x /' 'complete show_menu:context=filename'
+ ble-decode/keymap:safe/.bind 'C-x ~' 'complete show_menu:context=username'
+ ble-decode/keymap:safe/.bind 'C-x $' 'complete show_menu:context=variable'
+ ble-decode/keymap:safe/.bind 'C-x @' 'complete show_menu:context=hostname'
+ ble-decode/keymap:safe/.bind 'C-x !' 'complete show_menu:context=command'
+ ble-decode/keymap:safe/.bind "M-'" 'sabbrev-expand'
+ ble-decode/keymap:safe/.bind "C-x '" 'sabbrev-expand'
+ ble-decode/keymap:safe/.bind 'C-x C-r' 'dabbrev-expand'
+ ble-decode/keymap:safe/.bind 'M-g' 'complete context=glob'
+ ble-decode/keymap:safe/.bind 'C-x *' 'complete insert_all:context=glob'
+ ble-decode/keymap:safe/.bind 'C-x g' 'complete show_menu:context=glob'
+ ble-decode/keymap:safe/.bind 'M-C-i' 'complete context=dynamic-history'
+ ble-decode/keymap:safe/.bind 'M-TAB' 'complete context=dynamic-history'
+}
+function ble-decode/keymap:safe/bind-arg {
+ local append_arg=append-arg${1:+'-or '}$1
+ ble-decode/keymap:safe/.bind M-C-u 'universal-arg'
+ ble-decode/keymap:safe/.bind M-- "$append_arg"
+ ble-decode/keymap:safe/.bind M-0 "$append_arg"
+ ble-decode/keymap:safe/.bind M-1 "$append_arg"
+ ble-decode/keymap:safe/.bind M-2 "$append_arg"
+ ble-decode/keymap:safe/.bind M-3 "$append_arg"
+ ble-decode/keymap:safe/.bind M-4 "$append_arg"
+ ble-decode/keymap:safe/.bind M-5 "$append_arg"
+ ble-decode/keymap:safe/.bind M-6 "$append_arg"
+ ble-decode/keymap:safe/.bind M-7 "$append_arg"
+ ble-decode/keymap:safe/.bind M-8 "$append_arg"
+ ble-decode/keymap:safe/.bind M-9 "$append_arg"
+ ble-decode/keymap:safe/.bind C-- "$append_arg"
+ ble-decode/keymap:safe/.bind C-0 "$append_arg"
+ ble-decode/keymap:safe/.bind C-1 "$append_arg"
+ ble-decode/keymap:safe/.bind C-2 "$append_arg"
+ ble-decode/keymap:safe/.bind C-3 "$append_arg"
+ ble-decode/keymap:safe/.bind C-4 "$append_arg"
+ ble-decode/keymap:safe/.bind C-5 "$append_arg"
+ ble-decode/keymap:safe/.bind C-6 "$append_arg"
+ ble-decode/keymap:safe/.bind C-7 "$append_arg"
+ ble-decode/keymap:safe/.bind C-8 "$append_arg"
+ ble-decode/keymap:safe/.bind C-9 "$append_arg"
+ ble-decode/keymap:safe/.bind - "$append_arg"
+ ble-decode/keymap:safe/.bind 0 "$append_arg"
+ ble-decode/keymap:safe/.bind 1 "$append_arg"
+ ble-decode/keymap:safe/.bind 2 "$append_arg"
+ ble-decode/keymap:safe/.bind 3 "$append_arg"
+ ble-decode/keymap:safe/.bind 4 "$append_arg"
+ ble-decode/keymap:safe/.bind 5 "$append_arg"
+ ble-decode/keymap:safe/.bind 6 "$append_arg"
+ ble-decode/keymap:safe/.bind 7 "$append_arg"
+ ble-decode/keymap:safe/.bind 8 "$append_arg"
+ ble-decode/keymap:safe/.bind 9 "$append_arg"
+}
+function ble/widget/safe/__attach__ {
+ ble/edit/info/set-default text ''
+}
+function ble-decode/keymap:safe/define {
+ local ble_bind_nometa=
+ ble-decode/keymap:safe/bind-common
+ ble-decode/keymap:safe/bind-history
+ ble-decode/keymap:safe/bind-complete
+ ble-bind -f 'C-d' 'delete-region-or delete-forward-char-or-exit'
+ ble-bind -f 'SP' magic-space
+ ble-bind -f 'M-^' history-expand-line
+ ble-bind -f __attach__ safe/__attach__
+ ble-bind -f __line_limit__ __line_limit__
+ ble-bind -f 'C-c' discard-line
+ ble-bind -f 'C-j' accept-line
+ ble-bind -f 'C-RET' accept-line
+ ble-bind -f 'C-m' accept-single-line-or-newline
+ ble-bind -f 'RET' accept-single-line-or-newline
+ ble-bind -f 'C-o' accept-and-next
+ ble-bind -f 'C-x C-e' edit-and-execute-command
+ ble-bind -f 'M-#' insert-comment
+ ble-bind -f 'M-C-e' shell-expand-line
+ ble-bind -f 'M-&' tilde-expand
+ ble-bind -f 'C-g' bell
+ ble-bind -f 'C-x C-g' bell
+ ble-bind -f 'C-M-g' bell
+ ble-bind -f 'C-l' clear-screen
+ ble-bind -f 'C-M-l' redraw-line
+ ble-bind -f 'f1' command-help
+ ble-bind -f 'C-x C-v' display-shell-version
+ ble-bind -c 'C-z' fg
+ ble-bind -c 'M-z' fg
+}
+function ble-edit/bind/load-editing-mode:safe {
+ ble/decode/keymap#load safe
+}
+ble/util/autoload "keymap/emacs.sh" \
+ ble-decode/keymap:emacs/define
+ble/util/autoload "keymap/vi.sh" \
+ ble-decode/keymap:vi_{i,n,o,x,s,c}map/define
+ble/util/autoload "keymap/vi_digraph.sh" \
+ ble-decode/keymap:vi_digraph/define
+function ble/widget/.change-editing-mode {
+ [[ $_ble_decode_bind_state == none ]] && return 0
+ local mode=$1
+ if [[ $bleopt_default_keymap == auto ]]; then
+ if [[ ! -o $mode ]]; then
+ set -o "$mode"
+ ble/decode/reset-default-keymap
+ ble/decode/detach
+ ble/decode/attach || ble-detach
+ fi
+ else
+ bleopt default_keymap="$mode"
+ fi
+}
+function ble/widget/emacs-editing-mode {
+ ble/widget/.change-editing-mode emacs
+}
+function ble/widget/vi-editing-mode {
+ ble/widget/.change-editing-mode vi
+}
+_ble_edit_read_accept=
+_ble_edit_read_result=
+function ble/widget/read/accept {
+ _ble_edit_read_accept=1
+ _ble_edit_read_result=$_ble_edit_str
+ ble/decode/keymap/pop
+}
+function ble/widget/read/cancel {
+ local _ble_edit_line_disabled=1
+ ble/widget/read/accept
+ _ble_edit_read_accept=2
+}
+function ble/widget/read/delete-forward-char-or-cancel {
+ if [[ $_ble_edit_str ]]; then
+ ble/widget/delete-forward-char
+ else
+ ble/widget/read/cancel
+ fi
+}
+function ble/widget/read/__line_limit__.edit {
+ local content=$1
+ ble/widget/edit-and-execute-command.edit "$content" no-newline; local ext=$?
+ ((ext==127)) && return "$ext"
+ ble-edit/content/reset "$ret"
+ ble/widget/read/accept
+}
+function ble/widget/read/__line_limit__ {
+ ble/widget/__line_limit__ read/__line_limit__.edit
+}
+function ble-decode/keymap:read/define {
+ local ble_bind_nometa=
+ ble-decode/keymap:safe/bind-common
+ ble-decode/keymap:safe/bind-history
+ ble-bind -f __line_limit__ read/__line_limit__
+ ble-bind -f 'C-c' read/cancel
+ ble-bind -f 'C-\' read/cancel
+ ble-bind -f 'C-m' read/accept
+ ble-bind -f 'RET' read/accept
+ ble-bind -f 'C-j' read/accept
+ ble-bind -f 'C-d' 'delete-region-or read/delete-forward-char-or-cancel'
+ ble-bind -f 'C-g' bell
+ ble-bind -f 'C-l' redraw-line
+ ble-bind -f 'C-M-l' redraw-line
+ ble-bind -f 'C-x C-v' display-shell-version
+ ble-bind -f 'C-^' bell
+}
+_ble_edit_read_history=()
+_ble_edit_read_history_edit=()
+_ble_edit_read_history_dirt=()
+_ble_edit_read_history_index=0
+function ble/builtin/read/.process-option {
+ case $1 in
+ (-e) opt_flags=${opt_flags}r ;;
+ (-i) opt_default=$2 ;;
+ (-p) opt_prompt=$2 ;;
+ (-u) opt_fd=$2
+ ble/array#push opts_in "$@" ;;
+ (-t) opt_timeout=$2 ;;
+ (*) ble/array#push opts "$@" ;;
+ esac
+}
+function ble/builtin/read/.read-arguments {
+ local is_normal_args=
+ vars=()
+ opts=()
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $is_normal_args || $arg != -* ]]; then
+ ble/array#push vars "$arg"
+ elif [[ $arg == -- ]]; then
+ is_normal_args=1
+ elif [[ $arg == --* ]]; then
+ case $arg in
+ (--help)
+ opt_flags=${opt_flags}H ;;
+ (*)
+ ble/util/print "read: unrecognized long option '$arg'" >&2
+ opt_flags=${opt_flags}E ;;
+ esac
+ else
+ local i n=${#arg} c
+ for ((i=1;i<n;i++)); do
+ c=${arg:i:1}
+ case ${arg:i} in
+ ([adinNptu])
+ if (($#)); then
+ ble/builtin/read/.process-option -$c "$1"; shift
+ else
+ ble/util/print "read: missing option argument for '-$c'" >&2
+ opt_flags=${opt_flags}E
+ fi
+ break ;;
+ ([adinNptu]*) ble/builtin/read/.process-option -$c "${arg:i+1}"; break ;;
+ ([ers]*) ble/builtin/read/.process-option -$c ;;
+ (*)
+ ble/util/print "read: unrecognized option '-$c'" >&2
+ opt_flags=${opt_flags}E ;;
+ esac
+ done
+ fi
+ done
+}
+function ble/builtin/read/.set-up-textarea {
+ ble/decode/keymap/push read || return 1
+ [[ $_ble_edit_read_context == external ]] &&
+ _ble_canvas_panel_height[0]=0
+ _ble_textarea_panel=1
+ _ble_canvas_panel_focus=1
+ ble/textarea#invalidate
+ ble/edit/info/set-default ansi ''
+ _ble_edit_PS1=$opt_prompt
+ _ble_prompt_ps1_data=(0 '' '' 0 0 0 32 0 "" "")
+ _ble_edit_dirty_observer=()
+ ble/widget/.newline/clear-content
+ _ble_edit_arg=
+ ble-edit/content/reset "$opt_default" newline
+ _ble_edit_ind=${#opt_default}
+ ble-edit/undo/clear-all
+ ble/history/set-prefix _ble_edit_read_
+ _ble_syntax_lang=text
+ _ble_highlight_layer__list=(plain region overwrite_mode disabled)
+ return 0
+}
+function ble/builtin/read/TRAPWINCH {
+ local IFS=$_ble_term_IFS
+ _ble_textmap_pos=()
+ ble/util/buffer "$_ble_term_ed"
+ ble/textarea#redraw
+}
+function ble/builtin/read/.loop {
+ set +m # ジョブ管理を無効にする
+ shopt -u failglob
+ local ret; ble/canvas/panel/save-position; local pos0=$ret
+ ble/builtin/read/.set-up-textarea || return 1
+ ble/builtin/trap/install-hook WINCH readline
+ blehook WINCH=ble/builtin/read/TRAPWINCH
+ local ret= timeout=
+ if [[ $opt_timeout ]]; then
+ ble/util/clock; local start_time=$ret
+ ((start_time&&(start_time-=_ble_util_clock_reso-1)))
+ if [[ $opt_timeout == *.* ]]; then
+ local mantissa=${opt_timeout%%.*}
+ local fraction=${opt_timeout##*.}000
+ ((timeout=mantissa*1000+10#0${fraction::3}))
+ else
+ ((timeout=opt_timeout*1000))
+ fi
+ ((timeout<0)) && timeout=
+ fi
+ ble/application/render
+ local _ble_decode_input_count=0
+ local ble_decode_char_nest=
+ local -a _ble_decode_char_buffer=()
+ local char=
+ local _ble_edit_read_accept=
+ local _ble_edit_read_result=
+ while [[ ! $_ble_edit_read_accept ]]; do
+ local timeout_option=
+ if [[ $timeout ]]; then
+ if ((_ble_bash>=40000)); then
+ local timeout_frac=000$((timeout%1000))
+ timeout_option="-t $((timeout/1000)).${timeout_frac:${#timeout_frac}-3}"
+ else
+ timeout_option="-t $((timeout/1000))"
+ fi
+ fi
+ local TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ IFS= builtin read "${_ble_bash_tmout_wa[@]}" -r -d '' -n 1 $timeout_option char "${opts_in[@]}"; local ext=$?
+ if ((ext>128)); then
+ _ble_edit_read_accept=142
+ break
+ fi
+ if [[ $timeout ]]; then
+ ble/util/clock; local current_time=$ret
+ ((timeout-=current_time-start_time))
+ if ((timeout<=0)); then
+ _ble_edit_read_accept=142
+ break
+ fi
+ start_time=$current_time
+ fi
+ ble/util/s2c "$char"
+ ble-decode-char "$ret"
+ [[ $_ble_edit_read_accept ]] && break
+ ble/util/is-stdin-ready && continue
+ ble-edit/content/check-limit
+ ble-decode/.hook/erase-progress
+ ble/application/render
+ done
+ if [[ $_ble_edit_read_context == internal ]]; then
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#set-height.draw "$_ble_textarea_panel" 0
+ ble/canvas/panel/load-position.draw "$pos0"
+ ble/canvas/bflush.draw
+ else
+ if ((_ble_edit_read_accept==1)); then
+ ble/widget/.insert-newline # #D1800 (既に外部状態なのでOK)
+ else
+ _ble_edit_line_disabled=1 ble/widget/.insert-newline # #D1800 (既に外部状態なのでOK)
+ fi
+ fi
+ ble/util/buffer.flush >&2
+ if ((_ble_edit_read_accept==1)); then
+ local q=\' Q="'\''"
+ printf %s "__ble_input='${_ble_edit_read_result//$q/$Q}'"
+ elif ((_ble_edit_read_accept==142)); then
+ return "$ext"
+ else
+ return 1
+ fi
+}
+function ble/builtin/read/.impl {
+ local -a opts=() vars=() opts_in=()
+ local opt_flags= opt_prompt= opt_default= opt_timeout= opt_fd=0
+ local rex1='^[0-9]+(\.[0-9]*)?$|^\.[0-9]+$' rex2='^[0.]+$'
+ [[ $TMOUT =~ $rex1 && ! ( $TMOUT =~ $rex2 ) ]] && opt_timeout=$TMOUT
+ ble/builtin/read/.read-arguments "$@"
+ if [[ $opt_flags == *[HE]* ]]; then
+ if [[ $opt_flags == *H* ]]; then
+ builtin read --help
+ elif [[ $opt_flags == *E* ]]; then
+ builtin read --usage 2>&1 1>/dev/null | ble/bin/grep ^read >&2
+ fi
+ return 2
+ fi
+ if ! [[ $opt_flags == *r* && -t $opt_fd ]]; then
+ [[ $opt_prompt ]] && ble/array#push opts -p "$opt_prompt"
+ [[ $opt_timeout ]] && ble/array#push opts -t "$opt_timeout"
+ __ble_args=("${opts[@]}" "${opts_in[@]}" -- "${vars[@]}")
+ __ble_command='builtin read "${__ble_args[@]}"'
+ return 0
+ fi
+ ble/decode/keymap#load read
+ local result _ble_edit_read_context=$_ble_term_state
+ ble/util/buffer.flush >&2
+ [[ $_ble_edit_read_context == external ]] && ble/term/enter # 外側にいたら入る
+ result=$(ble/builtin/read/.loop); local ext=$?
+ [[ $_ble_edit_read_context == external ]] && ble/term/leave # 元の状態に戻る
+ [[ $_ble_edit_read_context == internal ]] && ((_ble_canvas_panel_height[1]=0))
+ if ((ext==0)); then
+ builtin eval -- "$result"
+ __ble_args=("${opts[@]}" -- "${vars[@]}")
+ __ble_command='builtin read "${__ble_args[@]}" <<< "$__ble_input"'
+ fi
+ return "$ext"
+}
+function ble/builtin/read {
+ if [[ $_ble_decode_bind_state == none ]]; then
+ builtin read "$@"
+ return "$?"
+ fi
+ local _ble_local_set _ble_local_shopt
+ ble/base/.adjust-bash-options _ble_local_set _ble_local_shopt
+ [[ $_ble_builtin_read_hook ]] &&
+ builtin eval -- "$_ble_builtin_read_hook"
+ local __ble_command= __ble_args= __ble_input=
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] && ble/base/adjust-BASH_REMATCH
+ ble/builtin/read/.impl "$@"; local __ble_ext=$?
+ [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] && ble/base/restore-BASH_REMATCH
+ ble/base/.restore-bash-options _ble_local_set _ble_local_shopt
+ [[ $__ble_command ]] || return "$__ble_ext"
+ builtin eval -- "$__ble_command"
+}
+function read { ble/builtin/read "$@"; }
+function ble/widget/command-help/.read-man {
+ local -x _ble_local_tmpfile; ble/util/assign/.mktmp
+ local pager="sh -c 'cat >| \"\$_ble_local_tmpfile\"'"
+ MANPAGER=$pager PAGER=$pager MANOPT= man "$@" 2>/dev/null; local ext=$? # 668ms
+ ble/util/readfile man_content "$_ble_local_tmpfile" # 80ms
+ return "$ext"
+}
+function ble/widget/command-help/.locate-in-man-bash {
+ local command=$1
+ local ret rex
+ local rex_esc=$'(\e\\[[ -?]*[@-~]||.\b)' cr=$'\r'
+ local pager; ble/util/get-pager pager
+ local pager_cmd=${pager%%["$_ble_term_IFS"]*}
+ [[ ${pager_cmd##*/} == less ]] || return 1
+ local awk=ble/bin/awk; type -t gawk &>/dev/null && awk=gawk
+ local man_content; ble/widget/command-help/.read-man bash || return 1 # 733ms (3 fork: man, sh, cat)
+ local cmd_awk
+ case $command in
+ ('function') cmd_awk='name () compound-command' ;;
+ ('until') cmd_awk=while ;;
+ ('command') cmd_awk='command [' ;;
+ ('source') cmd_awk=. ;;
+ ('typeset') cmd_awk=declare ;;
+ ('readarray') cmd_awk=mapfile ;;
+ ('[') cmd_awk=test ;;
+ (*) cmd_awk=$command ;;
+ esac
+ ble/string#escape-for-awk-regex "$cmd_awk"; local rex_awk=$ret
+ rex='\b$'; [[ $awk == gawk && $cmd_awk =~ $rex ]] && rex_awk=$rex_awk'\y'
+ local awk_script='{
+ gsub(/'"$rex_esc"'/, "");
+ if (!par && $0 ~ /^[[:space:]]*'"$rex_awk"'/) { print NR; exit; }
+ par = !($0 ~ /^[[:space:]]*$/);
+ }'
+ local awk_out; ble/util/assign awk_out '"$awk" "$awk_script" 2>/dev/null <<< "$man_content"' || return 1 # 206ms (1 fork)
+ local iline=${awk_out%$'\n'}; [[ $iline ]] || return 1
+ ble/string#escape-for-extended-regex "$command"; local rex_ext=$ret
+ rex='\b$'; [[ $command =~ $rex ]] && rex_ext=$rex_ext'\b'
+ rex='^\b'; [[ $command =~ $rex ]] && rex_ext="($rex_esc|\b)$rex_ext"
+ local manpager="$pager -r +'/$rex_ext$cr$((iline-1))g'"
+ builtin eval -- "$manpager" <<< "$man_content" # 1 fork
+}
+function ble/widget/command-help/.show-bash-script {
+ local _ble_local_pipeline=$1
+ local -x LESS="${LESS:+$LESS }-r" # Note: Bash のバグで tempenv builtin eval は消滅するので #D1438
+ type -t source-highlight &>/dev/null &&
+ _ble_local_pipeline='source-highlight -s sh -f esc | '$_ble_local_pipeline
+ builtin eval -- "$_ble_local_pipeline"
+}
+function ble/widget/command-help/.locate-function-in-source {
+ local func=$1 source lineno line
+ ble/function#get-source-and-lineno "$func" || return 1
+ [[ -f $source && -s $source ]] || return 1 # pipe 等は読み取らない
+ local pager; ble/util/get-pager pager
+ local pager_cmd=${pager%%["$_ble_term_IFS"]*}
+ [[ ${pager_cmd##*/} == less ]] || return 1
+ ble/util/assign line 'ble/bin/sed -n "${lineno}{p;q;}" "$source"'
+ [[ $line == *"$func"* ]] || return 1
+ ble/widget/command-help/.show-bash-script '"$pager" +"${lineno}g"' < "$source"
+}
+function ble/widget/command-help.core {
+ ble/function#try ble/cmdinfo/help:"$command" && return 0
+ ble/function#try ble/cmdinfo/help "$command" && return 0
+ if [[ $type == builtin || $type == keyword ]]; then
+ ble/widget/command-help/.locate-in-man-bash "$command" && return 0
+ elif [[ $type == function ]]; then
+ ble/widget/command-help/.locate-function-in-source "$command" && return 0
+ local def; ble/function#getdef "$command"
+ ble/widget/command-help/.show-bash-script ble/util/pager <<< "$def" && return 0
+ fi
+ if ble/is-function ble/bin/man; then
+ MANOPT= ble/bin/man "${command##*/}" 2>/dev/null && return 0
+ fi
+ if local content; content=$("$command" --help 2>&1) && [[ $content ]]; then
+ ble/util/print "$content" | ble/util/pager
+ return 0
+ fi
+ ble/util/print "ble: help of \`$command' not found" >&2
+ return 1
+}
+function ble/widget/command-help/.type/.resolve-alias {
+ local literal=$1 command=$2 type=alias
+ local last_literal=$1 last_command=$2
+ while
+ [[ $command == "$literal" ]] || break # Note: type=alias
+ local alias_def
+ ble/util/assign alias_def "alias $command"
+ builtin unalias "$command"
+ builtin eval "alias_def=${alias_def#*=}" # remove quote
+ literal=${alias_def%%["$_ble_term_IFS"]*} command= type=
+ ble/syntax:bash/simple-word/is-simple "$literal" || break # Note: type=
+ local ret; ble/syntax:bash/simple-word/eval "$literal"; command=$ret
+ ble/util/type type "$command"
+ [[ $type ]] || break # Note: type=
+ last_literal=$literal
+ last_command=$command
+ [[ $type == alias ]]
+ do :; done
+ if [[ ! $type || $type == alias ]]; then
+ literal=$last_literal
+ command=$last_command
+ builtin unalias "$command" &>/dev/null
+ ble/util/type type "$command"
+ fi
+ local q="'" Q="'\''"
+ printf "type='%s'\n" "${type//$q/$Q}"
+ printf "literal='%s'\n" "${literal//$q/$Q}"
+ printf "command='%s'\n" "${command//$q/$Q}"
+ return 0
+} 2>/dev/null
+function ble/widget/command-help/.type {
+ local literal=$1
+ type= command=
+ ble/syntax:bash/simple-word/is-simple "$literal" || return 1
+ local ret; ble/syntax:bash/simple-word/eval "$literal"; command=$ret
+ ble/util/type type "$command"
+ if [[ $type == alias ]]; then
+ builtin eval -- "$(ble/widget/command-help/.type/.resolve-alias "$literal" "$command")"
+ fi
+ if [[ $type == keyword && $command != "$literal" ]]; then
+ if [[ $command == %* ]] && jobs -- "$command" &>/dev/null; then
+ type=jobs
+ else
+ type=${type[1]}
+ [[ $type ]] || return 1
+ fi
+ fi
+}
+function ble/widget/command-help.impl {
+ local literal=$1
+ if [[ ! $literal ]]; then
+ ble/widget/.bell
+ return 1
+ fi
+ local type command; ble/widget/command-help/.type "$literal"
+ if [[ ! $type ]]; then
+ ble/widget/.bell "command \`$command' not found"
+ return 1
+ fi
+ ble/widget/external-command ble/widget/command-help.core
+}
+function ble/widget/command-help {
+ ble-edit/content/clear-arg
+ local comp_cword comp_words comp_line comp_point
+ if ble/syntax:bash/extract-command "$_ble_edit_ind"; then
+ local cmd=${comp_words[0]}
+ else
+ local args; ble/string#split-words args "$_ble_edit_str"
+ local cmd=${args[0]}
+ fi
+ ble/widget/command-help.impl "$cmd"
+}
+function ble-edit/bind/stdout.on { :;}
+function ble-edit/bind/stdout.off { ble/util/buffer.flush >&2;}
+function ble-edit/bind/stdout.finalize { :;}
+if [[ $bleopt_internal_suppress_bash_output ]]; then
+ _ble_edit_io_fname2=$_ble_base_run/$$.stderr
+ function ble-edit/bind/stdout.on {
+ exec 2>&$_ble_util_fd_stderr
+ }
+ function ble-edit/bind/stdout.off {
+ ble/util/buffer.flush >&2
+ ble-edit/io/check-stderr
+ exec 2>>$_ble_edit_io_fname2
+ }
+ function ble-edit/bind/stdout.finalize {
+ ble-edit/bind/stdout.on
+ [[ -f $_ble_edit_io_fname2 ]] && : >| "$_ble_edit_io_fname2"
+ }
+ function ble-edit/io/check-stderr {
+ local file=${1:-$_ble_edit_io_fname2}
+ if ble/is-function ble/term/visible-bell; then
+ if [[ -f $file && -s $file ]]; then
+ local message= line TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ while IFS= builtin read "${_ble_bash_tmout_wa[@]}" -r line || [[ $line ]]; do
+ if [[ $line == 'bash: '* || $line == "${BASH##*/}: "* || $line == "ble.sh ("*"): "* ]]; then
+ message="$message${message:+; }$line"
+ fi
+ done < "$file"
+ [[ $message ]] && ble/term/visible-bell "$message"
+ : >| "$file"
+ fi
+ fi
+ }
+ if ((_ble_bash<40000)); then
+ function ble-edit/io/TRAPUSR1 {
+ [[ $_ble_term_state == internal ]] || return 1
+ local FUNCNEST=
+ local IFS=$_ble_term_IFS
+ local file=$_ble_edit_io_fname2.proc
+ if [[ -s $file ]]; then
+ local content cmd
+ ble/util/readfile content "$file"
+ : >| "$file"
+ for cmd in $content; do
+ case "$cmd" in
+ (eof)
+ ble-decode/.hook 4
+ builtin eval -- "$_ble_decode_bind_hook" ;;
+ esac
+ done
+ fi
+ ble/builtin/trap/invoke USR1
+ }
+ blehook/declare USR1
+ blehook USR1+=ble-edit/io/TRAPUSR1
+ ble/builtin/trap/install-hook USR1
+ function ble-edit/io/check-ignoreeof-message {
+ local line=$1
+ [[ ( $bleopt_internal_ignoreeof_trap && $line == *$bleopt_internal_ignoreeof_trap* ) ||
+ $line == *'Use "exit" to leave the shell.'* ||
+ $line == *'ログアウトする為には exit を入力して下さい'* ||
+ $line == *'シェルから脱出するには "exit" を使用してください。'* ||
+ $line == *'シェルから脱出するのに "exit" を使いなさい.'* ||
+ $line == *'Gebruik Kaart na Los Tronk'* ]] && return 0
+ [[ $line == *exit* ]] && ble/bin/grep -q -F "$line" "$_ble_base"/lib/core-edit.ignoreeof-messages.txt
+ }
+ function ble-edit/io/check-ignoreeof-loop {
+ local line opts=:$1: TMOUT= 2>/dev/null # #D1630 WA readonly TMOUT
+ while IFS= builtin read "${_ble_bash_tmout_wa[@]}" -r line; do
+ if [[ $line == *[^$_ble_term_IFS]* ]]; then
+ ble/util/print "$line" >> "$_ble_edit_io_fname2"
+ fi
+ if ble-edit/io/check-ignoreeof-message "$line"; then
+ ble/util/print eof >> "$_ble_edit_io_fname2.proc"
+ kill -USR1 $$
+ ble/util/msleep 100 # 連続で送ると bash が落ちるかも (落ちた事はないが念の為)
+ fi
+ done
+ } &>/dev/null
+ ble/bin/rm -f "$_ble_edit_io_fname2.pipe"
+ if ble/bin/mkfifo "$_ble_edit_io_fname2.pipe" 2>/dev/null; then
+ {
+ ble-edit/io/check-ignoreeof-loop fifo < "$_ble_edit_io_fname2.pipe" & disown
+ } &>/dev/null
+ ble/fd#alloc _ble_edit_io_fd2 '> "$_ble_edit_io_fname2.pipe"'
+ function ble-edit/bind/stdout.off {
+ ble/util/buffer.flush >&2
+ ble-edit/io/check-stderr
+ exec 2>&$_ble_edit_io_fd2
+ }
+ elif . "$_ble_base/lib/init-msys1.sh"; ble-edit/io:msys1/start-background; then
+ function ble-edit/bind/stdout.off {
+ ble/util/buffer.flush >&2
+ ble-edit/io/check-stderr
+ exec 2>/dev/null
+ exec 2>>$_ble_edit_io_fname2.buff
+ }
+ fi
+ fi
+fi
+[[ ${_ble_edit_detach_flag-} != reload ]] &&
+ _ble_edit_detach_flag=
+function ble-edit/bind/.exit-TRAPRTMAX {
+ local FUNCNEST=
+ ble/base/unload
+ builtin exit 0
+}
+function ble-edit/bind/.check-detach {
+ if [[ ! -o emacs && ! -o vi ]]; then
+ ble/util/print "${_ble_term_setaf[9]}[ble: unsupported]$_ble_term_sgr0 Sorry, ble.sh is supported only with some editing mode (set -o emacs/vi)." 1>&2
+ ble-detach
+ fi
+ [[ $_ble_edit_detach_flag == prompt-attach ]] && return 1
+ if [[ $_ble_edit_detach_flag || ! $_ble_attached ]]; then
+ type=$_ble_edit_detach_flag
+ _ble_edit_detach_flag=
+ local attached=$_ble_attached
+ [[ $attached ]] && ble-detach/impl
+ if [[ $type == exit ]]; then
+ ble-detach/message "${_ble_term_setaf[12]}[ble: exit]$_ble_term_sgr0"
+ builtin trap 'ble-edit/bind/.exit-TRAPRTMAX' RTMAX
+ kill -RTMAX $$
+ else
+ ble-detach/message \
+ "${_ble_term_setaf[12]}[ble: detached]$_ble_term_sgr0" \
+ "Please run \`stty sane' to recover the correct TTY state."
+ if ((_ble_bash>=40000)); then
+ READLINE_LINE=' stty sane;' READLINE_POINT=11 READLINE_MARK=0
+ printf %s "$READLINE_LINE"
+ fi
+ fi
+ if [[ $attached ]]; then
+ ble/base/restore-BASH_REMATCH
+ ble/base/restore-bash-options
+ ble/base/restore-POSIXLY_CORRECT
+ ble/base/restore-builtin-wrappers
+ builtin eval -- "$_ble_bash_FUNCNEST_restore" # これ以降関数は呼び出せない
+ else
+ ble-edit/exec:"$bleopt_internal_exec_type"/.prologue
+ _ble_edit_exec_inside_prologue=
+ fi
+ return 0
+ else
+ local state=$_ble_decode_bind_state
+ if [[ ( $state == emacs || $state == vi ) && ! -o $state ]]; then
+ ble/decode/reset-default-keymap
+ ble/decode/detach
+ if ! ble/decode/attach; then
+ ble-detach
+ ble-edit/bind/.check-detach # 改めて終了処理
+ return $?
+ fi
+ fi
+ return 1
+ fi
+}
+if ((_ble_bash>=40100)); then
+ function ble-edit/bind/.head/adjust-bash-rendering {
+ ble/textarea#redraw-cache
+ ble/util/buffer.flush >&2
+ }
+else
+ function ble-edit/bind/.head/adjust-bash-rendering {
+ ((_ble_canvas_y++,_ble_canvas_x=0))
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" "${_ble_textarea_cur[0]}" "${_ble_textarea_cur[1]}"
+ ble/canvas/flush.draw
+ }
+fi
+function ble-edit/bind/.head {
+ ble-edit/bind/stdout.on
+ ble/base/recover-bash-options
+ [[ $bleopt_internal_suppress_bash_output ]] ||
+ ble-edit/bind/.head/adjust-bash-rendering
+}
+function ble-edit/bind/.tail-without-draw {
+ ble-edit/bind/stdout.off
+}
+if ((_ble_bash>=40000)); then
+ function ble-edit/bind/.tail {
+ ble/application/render
+ ble/util/idle.do && ble/application/render
+ ble/textarea#adjust-for-bash-bind # bash-4.0+
+ ble-edit/bind/stdout.off
+ }
+else
+ function ble-edit/bind/.tail {
+ ble/application/render
+ ble/util/idle.do && ble/application/render
+ ble-edit/bind/stdout.off
+ }
+fi
+function ble-decode/PROLOGUE {
+ ble-edit/exec:gexec/restore-state
+ ble-edit/bind/.head
+ ble/decode/bind/adjust-uvw
+ ble/term/enter
+}
+function ble-decode/EPILOGUE {
+ if ((_ble_bash>=40000)); then
+ if ble/decode/has-input && ! ble-edit/exec/has-pending-commands; then
+ ble-edit/bind/.tail-without-draw
+ return 0
+ fi
+ fi
+ ble-edit/content/check-limit
+ ble-edit/exec:"$bleopt_internal_exec_type"/process && return 0
+ ble-edit/bind/.tail
+ return 0
+}
+function ble/widget/.internal-print-command {
+ local command=$1 opts=$2
+ _ble_edit_line_disabled=1 ble/widget/.insert-newline # #D1800 pair=leave-command-layout
+ [[ :$opts: != *:pre-flush:* ]] || ble/util/buffer.flush >&2
+ BASH_COMMAND=$command builtin eval -- "$command"
+ ble/edit/leave-command-layout # #D1800 pair=.insert-newline
+ [[ :$opts: != *:post-flush:* ]] || ble/util/buffer.flush >&2
+}
+function ble/widget/print {
+ ble-edit/content/clear-arg
+ local message="$*" lines
+ [[ ${message//["$_ble_term_IFS"]} ]] || return 1
+ lines=("$@")
+ ble/widget/.internal-print-command \
+ 'ble/util/print-lines "${lines[@]}" >&2' pre-flush
+}
+function ble/widget/internal-command {
+ ble-edit/content/clear-arg
+ local command=$1
+ [[ ${command//[$_ble_term_IFS]} ]] || return 1
+ ble/widget/.internal-print-command "$command"
+}
+function ble/widget/external-command {
+ ble-edit/content/clear-arg
+ local _ble_local_command=$1
+ [[ ${_ble_local_command//[$_ble_term_IFS]} ]] || return 1
+ ble/edit/enter-command-layout # #D1800 pair=leave-command-layout
+ ble/textarea#invalidate
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#set-height.draw "$_ble_textarea_panel" 0
+ ble/canvas/panel#goto.draw "$_ble_textarea_panel" 0 0 sgr0
+ ble/canvas/bflush.draw
+ ble/term/leave
+ ble/util/buffer.flush >&2
+ BASH_COMMAND=$_ble_local_command builtin eval -- "$_ble_local_command"; local ext=$?
+ ble/term/enter
+ ble/edit/leave-command-layout # #D1800 pair=enter-command-layout
+ return "$ext"
+}
+function ble/widget/execute-command {
+ ble-edit/content/clear-arg
+ local command=$1
+ if [[ $command != *[!"$_ble_term_IFS"]* ]]; then
+ _ble_edit_line_disabled=1 ble/widget/.insert-newline keep-info
+ return 1
+ fi
+ _ble_edit_line_disabled=1 ble/widget/.insert-newline # #D1800 pair=exec/register
+ ble-edit/exec/register "$command"
+}
+function ble/widget/.SHELL_COMMAND { ble/widget/execute-command "$@"; }
+function ble/widget/.EDIT_COMMAND {
+ local command=$1
+ local -x READLINE_LINE=$_ble_edit_str
+ local -x READLINE_POINT=$_ble_edit_ind
+ local -x READLINE_MARK=$_ble_edit_mark
+ [[ $_ble_edit_arg ]] &&
+ local -x READLINE_ARGUMENT=$_ble_edit_arg
+ ble/edit/enter-command-layout # #D1800 pair=leave-command-layout
+ ble/widget/.hide-current-line keep-header
+ ble/util/buffer.flush >&2
+ builtin eval -- "$command"; local ext=$?
+ ble-edit/content/clear-arg
+ ble/edit/leave-command-layout # #D1800 pair=enter-command-layout
+ [[ $READLINE_LINE != "$_ble_edit_str" ]] &&
+ ble-edit/content/reset-and-check-dirty "$READLINE_LINE"
+ ((_ble_edit_ind=READLINE_POINT))
+ ((_ble_edit_mark=READLINE_MARK))
+ local N=${#_ble_edit_str}
+ ((_ble_edit_ind<0?_ble_edit_ind=0:(_ble_edit_ind>N&&(_ble_edit_ind=N))))
+ ((_ble_edit_mark<0?_ble_edit_mark=0:(_ble_edit_mark>N&&(_ble_edit_mark=N))))
+ return "$ext"
+}
+function ble-decode/INITIALIZE_DEFMAP {
+ local ret
+ bleopt/get:default_keymap; local defmap=$ret
+ if ble-edit/bind/load-editing-mode "$defmap"; then
+ local base_keymap=$defmap
+ [[ $defmap == vi ]] && base_keymap=vi_imap
+ builtin eval -- "$2=\$base_keymap"
+ ble/decode/is-keymap "$base_keymap" && return 0
+ fi
+ ble/edit/enter-command-layout # #D1800 pair=leave-command-layout
+ ble/widget/.hide-current-line
+ local -a DRAW_BUFF=()
+ ble/canvas/put.draw "$_ble_term_cr$_ble_term_el${_ble_term_setaf[9]}"
+ ble/canvas/put.draw "[ble.sh: The definition of the default keymap \"$defmap\" is not found. ble.sh uses \"safe\" keymap instead.]"
+ ble/canvas/put.draw "$_ble_term_sgr0$_ble_term_nl"
+ ble/canvas/bflush.draw
+ ble/util/buffer.flush >&2
+ ble/edit/leave-command-layout # #D1800 pair=enter-command-layout
+ ble-edit/bind/load-editing-mode safe &&
+ ble/decode/keymap#load safe &&
+ builtin eval -- "$2=safe" &&
+ bleopt_default_keymap=safe
+}
+function ble-edit/bind/load-editing-mode {
+ local name=$1
+ if ble/is-function ble-edit/bind/load-editing-mode:"$name"; then
+ ble-edit/bind/load-editing-mode:"$name"
+ else
+ ble/util/import "$_ble_base/keymap/$name.sh"
+ fi
+}
+function ble-edit/bind/clear-keymap-definition-loader {
+ builtin unset -f ble-edit/bind/load-editing-mode:safe
+ builtin unset -f ble-edit/bind/load-editing-mode:emacs
+ builtin unset -f ble-edit/bind/load-editing-mode:vi
+}
+function ble-edit/initialize {
+ ble/prompt/initialize
+}
+function ble-edit/attach {
+ _ble_builtin_trap_DEBUG__initialize
+ [[ $_ble_builtin_trap_DEBUG_userTrapInitialized ]] &&
+ _ble_edit_exec_gexec__TRAPDEBUG_adjust
+ ble-edit/attach/.attach
+ _ble_canvas_x=0 _ble_canvas_y=0
+ ble/util/buffer "$_ble_term_cr"
+}
+function ble-edit/detach {
+ ble-edit/bind/stdout.finalize
+ ble-edit/attach/.detach
+ ble-edit/exec:gexec/.TRAPDEBUG/restore
+}
+ble/function#trace ble-edit/attach
+function ble/cmdspec/initialize { ble-import "$_ble_base/lib/core-cmdspec.sh"; }
+ble/is-function ble/util/idle.push && ble-import -d "$_ble_base/lib/core-cmdspec.sh"
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_cmdspec_opts}"
+function ble/cmdspec/opts {
+ local spec=$1 command; shift
+ for command; do
+ ble/gdict#set _ble_cmdspec_opts "$command" "$spec"
+ done
+}
+function ble/cmdspec/opts#load {
+ cmdspec_opts=$2
+ local ret=
+ if ble/gdict#get _ble_cmdspec_opts "$1" ||
+ { [[ $1 == */*[!/] ]] && ble/gdict#get _ble_cmdspec_opts "${1##*/}"; }
+ then
+ cmdspec_opts=$ret
+ fi
+}
+_ble_syntax_VARNAMES=(
+ _ble_syntax_text
+ _ble_syntax_lang
+ _ble_syntax_stat
+ _ble_syntax_nest
+ _ble_syntax_tree
+ _ble_syntax_attr
+ _ble_syntax_attr_umin
+ _ble_syntax_attr_umax
+ _ble_syntax_word_umin
+ _ble_syntax_word_umax
+ _ble_syntax_vanishing_word_umin
+ _ble_syntax_vanishing_word_umax
+ _ble_syntax_dbeg
+ _ble_syntax_dend)
+_ble_syntax_lang=bash
+function ble/syntax/initialize-vars {
+ _ble_syntax_text=
+ _ble_syntax_lang=bash
+ _ble_syntax_stat=()
+ _ble_syntax_nest=()
+ _ble_syntax_tree=()
+ _ble_syntax_attr=()
+ _ble_syntax_attr_umin=-1 _ble_syntax_attr_umax=-1
+ _ble_syntax_word_umin=-1 _ble_syntax_word_umax=-1
+ _ble_syntax_vanishing_word_umin=-1
+ _ble_syntax_vanishing_word_umax=-1
+ _ble_syntax_dbeg=-1 _ble_syntax_dend=-1
+}
+function ble/highlight/layer:syntax/update { true; }
+function ble/highlight/layer:syntax/getg { true; }
+function ble/syntax:bash/is-complete { true; }
+ble/util/autoload "$_ble_base/lib/core-syntax.sh" \
+ ble/syntax/parse \
+ ble/syntax/highlight \
+ ble/syntax/tree-enumerate \
+ ble/syntax/tree-enumerate-children \
+ ble/syntax/completion-context/generate \
+ ble/syntax/highlight/cmdtype \
+ ble/syntax/highlight/cmdtype1 \
+ ble/syntax/highlight/filetype \
+ ble/syntax/highlight/getg-from-filename \
+ ble/syntax:bash/extract-command \
+ ble/syntax:bash/simple-word/eval \
+ ble/syntax:bash/simple-word/evaluate-path-spec \
+ ble/syntax:bash/simple-word/is-never-word \
+ ble/syntax:bash/simple-word/is-simple \
+ ble/syntax:bash/simple-word/is-simple-or-open-simple \
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word
+bleopt/declare -v syntax_debug ''
+bleopt/declare -v filename_ls_colors ''
+bleopt/declare -v highlight_syntax 1
+bleopt/declare -v highlight_filename 1
+bleopt/declare -v highlight_variable 1
+bleopt/declare -v highlight_timeout_sync 50
+bleopt/declare -v highlight_timeout_async 5000
+bleopt/declare -v syntax_eval_polling_interval 50
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_syntax_highlight_filetype}"
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_syntax_highlight_lscolors_ext}"
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_syntax_bash_simple_eval}"
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_syntax_bash_simple_eval_full}"
+function ble/syntax/attr2g { ble/color/initialize-faces && ble/syntax/attr2g "$@"; }
+function ble/syntax/defface.onload {
+ function ble/syntax/attr2g {
+ local iface=${_ble_syntax_attr2iface[$1]:-_ble_faces__syntax_default}
+ g=${_ble_faces[iface]}
+ }
+ ble/color/defface syntax_default none
+ ble/color/defface syntax_command fg=brown
+ ble/color/defface syntax_quoted fg=green
+ ble/color/defface syntax_quotation fg=green,bold
+ ble/color/defface syntax_escape fg=magenta
+ ble/color/defface syntax_expr fg=26
+ ble/color/defface syntax_error bg=203,fg=231 # bg=224
+ ble/color/defface syntax_varname fg=202
+ ble/color/defface syntax_delimiter bold
+ ble/color/defface syntax_param_expansion fg=purple
+ ble/color/defface syntax_history_expansion bg=94,fg=231
+ ble/color/defface syntax_function_name fg=92,bold # fg=purple
+ ble/color/defface syntax_comment fg=242
+ ble/color/defface syntax_glob fg=198,bold
+ ble/color/defface syntax_brace fg=37,bold
+ ble/color/defface syntax_tilde fg=navy,bold
+ ble/color/defface syntax_document fg=94
+ ble/color/defface syntax_document_begin fg=94,bold
+ ble/color/defface command_builtin_dot fg=red,bold
+ ble/color/defface command_builtin fg=red
+ ble/color/defface command_alias fg=teal
+ ble/color/defface command_function fg=92 # fg=purple
+ ble/color/defface command_file fg=green
+ ble/color/defface command_keyword fg=blue
+ ble/color/defface command_jobs fg=red,bold
+ ble/color/defface command_directory fg=26,underline
+ ble/color/defface filename_directory underline,fg=26
+ ble/color/defface filename_directory_sticky underline,fg=white,bg=26
+ ble/color/defface filename_link underline,fg=teal
+ ble/color/defface filename_orphan underline,fg=teal,bg=224
+ ble/color/defface filename_setuid underline,fg=black,bg=220
+ ble/color/defface filename_setgid underline,fg=black,bg=191
+ ble/color/defface filename_executable underline,fg=green
+ ble/color/defface filename_other underline
+ ble/color/defface filename_socket underline,fg=cyan,bg=black
+ ble/color/defface filename_pipe underline,fg=lime,bg=black
+ ble/color/defface filename_character underline,fg=white,bg=black
+ ble/color/defface filename_block underline,fg=yellow,bg=black
+ ble/color/defface filename_warning underline,fg=red
+ ble/color/defface filename_url underline,fg=blue
+ ble/color/defface filename_ls_colors underline
+ ble/color/defface varname_unset fg=124
+ ble/color/defface varname_empty fg=31
+ ble/color/defface varname_number fg=64
+ ble/color/defface varname_expr fg=92,bold
+ ble/color/defface varname_array fg=orange,bold
+ ble/color/defface varname_hash fg=70,bold
+ ble/color/defface varname_readonly fg=200
+ ble/color/defface varname_transform fg=29,bold
+ ble/color/defface varname_export fg=200,bold
+ ble/color/defface argument_option fg=teal
+ ble/color/defface argument_error fg=black,bg=225
+}
+blehook/eval-after-load color_defface ble/syntax/defface.onload
+function ble/syntax/import {
+ ble/util/import "$_ble_base/lib/core-syntax.sh"
+}
+ble-import -d lib/core-syntax
+ble/is-function ble/util/idle.push && ble-import -d "$_ble_base/lib/core-complete.sh"
+ble/util/autoload "$_ble_base/lib/core-complete.sh" \
+ ble/widget/complete \
+ ble/widget/menu-complete \
+ ble/widget/auto-complete-enter \
+ ble/widget/sabbrev-expand \
+ ble/widget/dabbrev-expand
+function ble-sabbrev {
+ local arg print=
+ for arg; do
+ if [[ $arg != -* && $arg != *=* ]]; then
+ print=1
+ break
+ fi
+ done
+ if (($#==0)) || [[ $print ]]; then
+ ble-import lib/core-complete && ble-sabbrev "$@"
+ return $?
+ fi
+ local ret; ble/string#quote-command "$FUNCNAME" "$@"
+ blehook/eval-after-load complete "$ret"
+}
+if ! declare -p _ble_complete_sabbrev &>/dev/null; then # reload #D0875
+ builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_complete_sabbrev}"
+fi
+bleopt/declare -n complete_polling_cycle 50
+bleopt/declare -o complete_stdin_frequency complete_polling_cycle
+bleopt/declare -v complete_limit ''
+bleopt/declare -v complete_limit_auto 2000
+bleopt/declare -v complete_limit_auto_menu 100
+bleopt/declare -v complete_timeout_auto 5000
+bleopt/declare -v complete_timeout_compvar 200
+bleopt/declare -v complete_ambiguous 1
+bleopt/declare -v complete_contract_function_names 1
+bleopt/declare -v complete_auto_complete 1
+bleopt/declare -v complete_auto_history 1
+bleopt/declare -n complete_auto_delay 1
+bleopt/declare -v complete_auto_wordbreaks "$_ble_term_IFS"
+bleopt/declare -v complete_auto_menu ''
+bleopt/declare -v complete_allow_reduction ''
+bleopt/declare -n complete_menu_style align-nowrap
+function bleopt/check:complete_menu_style {
+ [[ $value == desc-raw ]] && value=desc
+ if ! ble/is-function "ble/complete/menu-style:$value/construct-page"; then
+ ble/util/print-lines \
+ "bleopt: Invalid value complete_menu_style='$value'." \
+ " A function 'ble/complete/menu-style:$value/construct-page' is not defined." >&2
+ return 1
+ fi
+ return 0
+}
+ble/util/autoload "$_ble_base/lib/core-complete.sh" \
+ ble/complete/menu-style:{align,dense}{,-nowrap}/construct-page \
+ ble/complete/menu-style:linewise/construct-page \
+ ble/complete/menu-style:desc{,-raw}/construct-page
+bleopt/declare -v menu_linewise_prefix ''
+bleopt/declare -v menu_desc_multicolumn_width 65
+bleopt/declare -v complete_menu_complete 1
+bleopt/declare -v complete_menu_filter 1
+bleopt/declare -v complete_menu_maxlines '-1'
+bleopt/declare -n menu_align_min 4
+bleopt/declare -n menu_align_max 20
+bleopt/declare -o complete_menu_align menu_align_max
+ble/util/autoload "$_ble_base/lib/core-complete.sh" \
+ ble/complete/menu#start \
+ ble-decode/keymap:menu/define \
+ ble-decode/keymap:auto_complete/define \
+ ble-decode/keymap:menu_complete/define \
+ ble-decode/keymap:dabbrev/define \
+ ble/complete/sabbrev/expand
+ble/color/defface auto_complete bg=254,fg=238
+ble/color/defface cmdinfo_cd_cdpath fg=26,bg=155
+function ble/contrib/bash-preexec/loader {
+ if [[ ${bp_imported-${__bp_imported}} ]]; then
+ blehook ATTACH-=ble/contrib/bash-preexec/loader
+ blehook POSTEXEC-=ble/contrib/bash-preexec/loader
+ if ble/util/import/is-loaded contrib/bash-preexec; then
+ ble/contrib/bash-preexec/attach.hook
+ else
+ ble-import contrib/bash-preexec
+ fi
+ fi
+}
+if [[ ${bp_imported-${__bp_imported}} ]]; then
+ ble-import contrib/bash-preexec
+else
+ blehook ATTACH+=ble/contrib/bash-preexec/loader
+ blehook POSTEXEC+=ble/contrib/bash-preexec/loader
+fi
+bleopt -I
+ble/bin/.freeze-utility-path ble
+function ble/dispatch/.help {
+ ble/util/print-lines \
+ 'usage: ble [SUBCOMMAND [ARGS...]]' \
+ '' \
+ 'SUBCOMMAND' \
+ ' # Manage ble.sh' \
+ ' attach ... alias of ble-attach' \
+ ' detach ... alias of ble-detach' \
+ ' update ... alias of ble-update' \
+ ' reload ... alias of ble-reload' \
+ ' help ... Show this help' \
+ ' version ... Show version' \
+ ' check ... Run unit tests' \
+ '' \
+ ' # Configuration' \
+ ' opt ... alias of bleopt' \
+ ' bind ... alias of ble-bind' \
+ ' face ... alias of ble-face' \
+ ' hook ... alias of blehook' \
+ ' sabbrev ... alias of ble-sabbrev' \
+ ' palette ... alias of ble-color-show' \
+ ''
+}
+function ble/dispatch {
+ if (($#==0)); then
+ [[ $_ble_attached && ! $_ble_edit_exec_inside_userspace ]]
+ return $?
+ fi
+ local cmd=$1; shift
+ case $cmd in
+ (attach) ble-attach "$@" ;;
+ (detach) ble-detach "$@" ;;
+ (update) ble-update "$@" ;;
+ (reload) ble-reload "$@" ;;
+ (face) ble-face "$@" ;;
+ (bind) ble-bind "$@" ;;
+ (opt) bleopt "$@" ;;
+ (hook) blehook "$@" ;;
+ (sabbrev) ble-sabbrev "$@" ;;
+ (palette) ble-color-show "$@" ;;
+ (help|--help) ble/dispatch/.help "$@" ;;
+ (version|--version) ble/util/print "ble.sh, version $BLE_VERSION (noarch)" ;;
+ (check|--test) ble/base/sub:test "$@" ;;
+ (*)
+ if ble/is-function ble/bin/ble; then
+ ble/bin/ble "$cmd" "$@"
+ else
+ ble/util/print "ble (ble.sh): unrecognized subcommand '$cmd'." >&2
+ return 2
+ fi
+ esac
+}
+function ble { ble/dispatch "$@"; }
+_ble_base_rcfile=
+_ble_base_rcfile_initialized=
+function ble/base/load-rcfile {
+ [[ $_ble_base_rcfile_initialized ]] && return 0
+ _ble_base_rcfile_initialized=1
+ if [[ ! $_ble_base_rcfile ]]; then
+ { _ble_base_rcfile=$HOME/.blerc; [[ -f $_ble_base_rcfile ]]; } ||
+ { _ble_base_rcfile=${XDG_CONFIG_HOME:-$HOME/.config}/blesh/init.sh; [[ -f $_ble_base_rcfile ]]; } ||
+ _ble_base_rcfile=$HOME/.blerc
+ fi
+ if [[ -s $_ble_base_rcfile ]]; then
+ source "$_ble_base_rcfile"
+ blehook/.compatibility-ble-0.3/check
+ fi
+}
+function ble-attach {
+ if (($# >= 2)); then
+ ble/util/print-lines \
+ 'usage: ble-attach [opts]' \
+ 'Attach to ble.sh.' >&2
+ [[ $1 != --help ]] && return 2
+ return 0
+ fi
+ if [[ $_ble_edit_detach_flag ]]; then
+ case $_ble_edit_detach_flag in
+ (exit) return 0 ;;
+ (*) _ble_edit_detach_flag= ;; # cancel "detach"
+ esac
+ fi
+ [[ ! $_ble_attached ]] || return 0
+ _ble_attached=1
+ BLE_ATTACHED=1
+ builtin eval -- "$_ble_bash_FUNCNEST_adjust"
+ ble/base/adjust-builtin-wrappers-1
+ ble/base/adjust-bash-options
+ ble/base/adjust-POSIXLY_CORRECT
+ ble/base/adjust-builtin-wrappers-2
+ ble/base/adjust-BASH_REMATCH
+ if [[ ${IN_NIX_SHELL-} ]]; then
+ if [[ "${BASH_SOURCE[*]}" == */rc && $1 != *:force:* ]]; then
+ ble/base/install-prompt-attach
+ _ble_attached=
+ BLE_ATTACHED=
+ ble/base/restore-BASH_REMATCH
+ ble/base/restore-bash-options
+ ble/base/restore-POSIXLY_CORRECT
+ ble/base/restore-builtin-wrappers
+ builtin eval -- "$_ble_bash_FUNCNEST_restore"
+ return 0
+ fi
+ local ret
+ ble/util/readlink "/proc/$$/exe"
+ [[ -x $ret ]] && BASH=$ret
+ fi
+ ble/canvas/attach
+ ble/term/enter # 3ms (起動時のずれ防止の為 stty)
+ ble-edit/initialize # 3ms
+ ble-edit/attach # 0ms (_ble_edit_PS1 他の初期化)
+ ble/canvas/panel/render # 37ms
+ ble/util/buffer.flush >&2
+ local IFS=$_ble_term_IFS
+ ble/decode/initialize # 7ms
+ ble/decode/reset-default-keymap # 264ms (keymap/vi.sh)
+ if ! ble/decode/attach; then # 53ms
+ _ble_attached=
+ BLE_ATTACHED=
+ ble-edit/detach
+ ble/term/leave
+ ble/base/restore-BASH_REMATCH
+ ble/base/restore-bash-options
+ ble/base/restore-POSIXLY_CORRECT
+ ble/base/restore-builtin-wrappers
+ builtin eval -- "$_ble_bash_FUNCNEST_restore"
+ return 1
+ fi
+ ble/history:bash/reset # 27s for bash-3.0
+ blehook/invoke ATTACH
+ ble/textarea#redraw
+ ble/edit/info/default
+ ble-edit/bind/.tail
+}
+function ble-detach {
+ if (($#)); then
+ ble/base/print-usage-for-no-argument-command 'Detach from ble.sh.' "$@"
+ return "$?"
+ fi
+ [[ $_ble_attached && ! $_ble_edit_detach_flag ]] || return 1
+ _ble_edit_detach_flag=${1:-detach} # schedule detach
+}
+function ble-detach/impl {
+ [[ $_ble_attached ]] || return 1
+ _ble_attached=
+ BLE_ATTACHED=
+ blehook/invoke DETACH
+ ble-edit/detach
+ ble/decode/detach
+ READLINE_LINE='' READLINE_POINT=0
+}
+function ble-detach/message {
+ ble/util/buffer.flush >&2
+ printf '%s\n' "$@" 1>&2
+ ble/edit/info/clear
+ ble/textarea#render
+ ble/util/buffer.flush >&2
+}
+function ble/base/unload-for-reload {
+ if [[ $_ble_attached ]]; then
+ ble-detach/impl
+ ble/util/print "${_ble_term_setaf[12]}[ble: reload]$_ble_term_sgr0" 1>&2
+ [[ $_ble_edit_detach_flag ]] ||
+ _ble_edit_detach_flag=reload
+ fi
+ ble/base/unload
+ return 0
+}
+function ble/base/unload {
+ ble/util/is-running-in-subshell && return 1
+ local IFS=$_ble_term_IFS
+ builtin unset -v _ble_bash BLE_VERSION BLE_VERSINFO
+ ble/term/stty/TRAPEXIT
+ ble/term/leave
+ ble/util/buffer.flush >&2
+ blehook/invoke unload
+ ble/decode/keymap#unload
+ ble-edit/bind/clear-keymap-definition-loader
+ ble/builtin/trap/finalize
+ ble/util/import/finalize
+ ble/fd#finalize
+ ble/bin/rm -rf "$_ble_base_run/$$".* 2>/dev/null
+ return 0
+}
+_ble_base_attach_from_prompt=
+_ble_base_attach_PROMPT_COMMAND=()
+function ble/base/install-prompt-attach {
+ [[ ! $_ble_base_attach_from_prompt ]] || return 0
+ _ble_base_attach_from_prompt=1
+ if ((_ble_bash>=50100)); then
+ ((${#PROMPT_COMMAND[@]})) || PROMPT_COMMAND[0]=
+ ble/array#push PROMPT_COMMAND ble/base/attach-from-PROMPT_COMMAND
+ if [[ $_ble_edit_detach_flag == reload ]]; then
+ _ble_edit_detach_flag=prompt-attach
+ blehook PRECMD+=ble/base/attach-from-PROMPT_COMMAND
+ fi
+ else
+ local save_index=${#_ble_base_attach_PROMPT_COMMAND[@]}
+ _ble_base_attach_PROMPT_COMMAND[save_index]=${PROMPT_COMMAND-}
+ ble/function#lambda PROMPT_COMMAND \
+ "ble/base/attach-from-PROMPT_COMMAND $save_index \"\$FUNCNAME\""
+ ble/function#trace "$PROMPT_COMMAND"
+ if [[ $_ble_edit_detach_flag == reload ]]; then
+ _ble_edit_detach_flag=prompt-attach
+ blehook PRECMD+="$PROMPT_COMMAND"
+ fi
+ fi
+}
+_ble_base_attach_from_prompt_lastexit=
+_ble_base_attach_from_prompt_lastarg=
+_ble_base_attach_from_prompt_PIPESTATUS=()
+function ble/base/attach-from-PROMPT_COMMAND {
+ {
+ _ble_base_attach_from_prompt_lastexit=$? \
+ _ble_base_attach_from_prompt_lastarg=$_ \
+ _ble_base_attach_from_prompt_PIPESTATUS=("${PIPESTATUS[@]}")
+ if ((BASH_LINENO[${#BASH_LINENO[@]}-1]>=1)); then
+ _ble_edit_exec_lastexit=$_ble_base_attach_from_prompt_lastexit
+ _ble_edit_exec_lastarg=$_ble_base_attach_from_prompt_lastarg
+ _ble_edit_exec_PIPESTATUS=("${_ble_base_attach_from_prompt_PIPESTATUS[@]}")
+ _ble_edit_exec_BASH_COMMAND=$FUNCNAME
+ fi
+ local is_last_PROMPT_COMMAND=1
+ if (($#==0)); then
+ if local ret; ble/array#index PROMPT_COMMAND ble/base/attach-from-PROMPT_COMMAND; then
+ local keys; keys=("${!PROMPT_COMMAND[@]}")
+ ((ret==keys[${#keys[@]}-1])) || is_last_PROMPT_COMMAND=
+ ble/idict#replace PROMPT_COMMAND ble/base/attach-from-PROMPT_COMMAND
+ fi
+ blehook PRECMD-=ble/base/attach-from-PROMPT_COMMAND || ((1)) # set -e 対策
+ else
+ local save_index=$1 lambda=$2
+ local PROMPT_COMMAND_local=
+ [[ $PROMPT_COMMAND == "$lambda" ]] || local PROMPT_COMMAND is_last_PROMPT_COMMAND=
+ PROMPT_COMMAND=${_ble_base_attach_PROMPT_COMMAND[save_index]}
+ local ble_base_attach_from_prompt_command=processing
+ ble/prompt/update/.eval-prompt_command 2>&3
+ ble/util/unlocal ble_base_attach_from_prompt_command
+ _ble_base_attach_PROMPT_COMMAND[save_index]=$PROMPT_COMMAND
+ [[ $is_last_PROMPT_COMMAND ]] || ble/util/unlocal PROMPT_COMMAND
+ blehook PRECMD-="$lambda" || ((1)) # set -e 対策
+ [[ ${ble_base_attach_from_prompt_command-} != processing ]] || return
+ fi
+ [[ $_ble_base_attach_from_prompt ]] || return 0
+ _ble_base_attach_from_prompt=
+ if [[ $is_last_PROMPT_COMMAND ]]; then
+ ble-edit/exec:gexec/invoke-hook-with-setexit PRECMD
+ _ble_prompt_hash=$COLUMNS:$_ble_edit_lineno:prompt_attach
+ fi
+ } 3>&2 2>/dev/null # set -x 対策 #D0930
+ ble-attach force
+ ble/util/joblist.flush &>/dev/null
+ ble/util/joblist.check
+}
+function ble/base/process-blesh-arguments {
+ local opts=$_ble_base_arguments_opts
+ local attach=$_ble_base_arguments_attach
+ if [[ :$opts: == *:noinputrc:* ]]; then
+ _ble_builtin_bind_user_settings_loaded=noinputrc
+ _ble_builtin_bind_inputrc_done=noinputrc
+ fi
+ if [[ :$opts: != *:keep-rlvar:* ]]; then
+ ((_ble_bash>=40100)) && builtin bind 'set skip-completed-text on'
+ ((_ble_bash>=40300)) && builtin bind 'set colored-stats on'
+ ((_ble_bash>=40400)) && builtin bind 'set colored-completion-prefix on'
+ fi
+ _ble_base_rcfile=$_ble_base_arguments_rcfile
+ ble/base/load-rcfile # blerc
+ ble/util/invoke-hook BLE_ONLOAD
+ case $attach in
+ (attach) ble-attach ;;
+ (prompt) ble/base/install-prompt-attach ;;
+ (none) ;;
+ (*) ble/util/print "ble.sh: unrecognized attach method --attach='$attach'." ;;
+ esac
+}
+function ble/base/sub:test {
+ local error= logfile=
+ ble-import lib/core-test
+ if (($#==0)); then
+ set -- main util canvas decode edit syntax complete
+ logfile=$_ble_base_cache/test.$(date +'%Y%m%d.%H%M%S').log
+ : >| "$logfile"
+ ble/test/log#open "$logfile"
+ fi
+ if ((!_ble_make_command_check_count)); then
+ ble/test/log "MACHTYPE: $MACHTYPE"
+ ble/test/log "BLE_VERSION: $BLE_VERSION"
+ fi
+ ble/test/log "BASH_VERSION: $BASH_VERSION"
+ local section
+ for section; do
+ local file=$_ble_base/lib/test-$section.sh
+ if [[ -f $file ]]; then
+ source "$file" || error=1
+ else
+ ble/test/log "ERROR: Test '$section' is not defined."
+ error=1
+ fi
+ done
+ if [[ $logfile ]]; then
+ ble/test/log#close
+ ble/util/print "ble: The test log was saved to '${_ble_term_setaf[4]}$logfile$_ble_term_sgr0'."
+ fi
+ [[ ! $error ]]
+}
+function ble/base/sub:update { ble-update; }
+function ble/base/sub:clear-cache {
+ (shopt -u failglob; ble/bin/rm -rf "$_ble_base_cache"/*)
+}
+ble/function#trace ble-attach
+ble/function#trace ble
+ble/function#trace ble/dispatch
+ble/function#trace ble/base/attach-from-PROMPT_COMMAND
+ble/function#trace ble/base/unload
+ble/function#trace ble/builtin/trap/finalize
+ble-import -f lib/_package
+if [[ $_ble_init_command ]]; then
+ ble/base/sub:"$_ble_init_command"; _ble_init_exit=$?
+ [[ $_ble_init_attached ]] && ble-attach
+ ble/util/setexit "$_ble_init_exit"
+else
+ ble/base/process-blesh-arguments "$@"
+fi
+ble/init/clean-up check-attach 2>/dev/null # set -x 対策 #D0930
+{ builtin eval "return $? || exit $?"; } 2>/dev/null # set -x 対策 #D0930
diff --git a/.local/src/blesh/contrib/airline/atomic.bash b/.local/src/blesh/contrib/airline/atomic.bash
new file mode 100644
index 0000000..2a05808
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/atomic.bash
@@ -0,0 +1,42 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/atomic.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+#----------------------------------------------------------------
+# ___ __ _
+# / | / /_____ ____ ___ (_)____
+# / /| |/ __/ __ \/ __ `__ \/ / ___/
+# / ___ / /_/ /_/ / / / / / / / /__
+# /_/ |_\__/\____/_/ /_/ /_/_/\___/
+#
+#----------------------------------------------------------------
+# Theme : Atomic
+# Version : 2.1.0
+# License : MIT
+# Author : Gerard Bajona
+# URL : https://github.com/gerardbm/atomic
+# ----------------------------------------------------------------
+# Colors will be adapted to the current colorscheme. For better
+# contrast use the atomic colorscheme: it has ten color palettes
+# with sixteen colors selected procedurally (algorithms).
+#
+# Atomic colorscheme: https://github.com/gerardbm/vim-atomic
+# ----------------------------------------------------------------
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:atomic/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_a_inactive fg=124,bg=-1 # fg=#a52a2a,bg=-1
+ ble-face -s vim_airline_a_insert fg=-1,bg=29 # fg=-1,bg=#2e8b57
+ ble-face -s vim_airline_a_replace fg=-1,bg=231 # fg=-1,bg=#ffffff
+ ble-face -s vim_airline_a_visual fg=-1,bg=196 # fg=-1,bg=#ff0000
+ ble-face -s vim_airline_b fg=-1,bg=124 # fg=-1,bg=#a52a2a
+ ble-face -s vim_airline_b_inactive fg=124,bg=-1 # fg=#a52a2a,bg=-1
+ ble-face -s vim_airline_c fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_c_inactive fg=124,bg=-1 # fg=#a52a2a,bg=-1
+ ble-face -s vim_airline_c_insert fg=29,bg=-1 # fg=#2e8b57,bg=-1
+ ble-face -s vim_airline_c_replace fg=231,bg=-1 # fg=#ffffff,bg=-1
+ ble-face -s vim_airline_c_visual fg=196,bg=-1 # fg=#ff0000,bg=-1
+}
diff --git a/.local/src/blesh/contrib/airline/dark.bash b/.local/src/blesh/contrib/airline/dark.bash
new file mode 100644
index 0000000..47bf5a6
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/dark.bash
@@ -0,0 +1,30 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/dark.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:dark/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=17,bg=190 # fg=#00005f,bg=#dfff00
+ ble-face -s vim_airline_a_commandline fg=17,bg=40 # fg=#00005f,bg=#00d700
+ ble-face -s vim_airline_a_inactive fg=239,bg=234 # fg=#4e4e4e,bg=#1c1c1c
+ ble-face -s vim_airline_a_insert fg=17,bg=45 # fg=#00005f,bg=#00dfff
+ ble-face -s vim_airline_a_replace fg=231,bg=124 # fg=#ffffff,bg=#af0000
+ ble-face -s vim_airline_a_visual fg=16,bg=214 # fg=#000000,bg=#ffaf00
+ ble-face -s vim_airline_b fg=231,bg=238 # fg=#ffffff,bg=#444444
+ ble-face -s vim_airline_b_inactive fg=239,bg=235 # fg=#4e4e4e,bg=#262626
+ ble-face -s vim_airline_b_insert fg=231,bg=27 # fg=#ffffff,bg=#005fff
+ ble-face -s vim_airline_b_visual fg=16,bg=202 # fg=#000000,bg=#ff5f00
+ ble-face -s vim_airline_c fg=158,bg=234 # fg=#9cffd3,bg=#202020
+ ble-face -s vim_airline_c_inactive fg=239,bg=236 # fg=#4e4e4e,bg=#303030
+ ble-face -s vim_airline_c_inactive_modified fg=97,bg=0 # fg=#875faf,bg=0
+ ble-face -s vim_airline_c_insert fg=231,bg=18 # fg=#ffffff,bg=#000080
+ ble-face -s vim_airline_c_insert_modified fg=231,bg=53 # fg=#ffffff,bg=#5f005f
+ ble-face -s vim_airline_c_normal_modified fg=231,bg=53 # fg=#ffffff,bg=#5f005f
+ ble-face -s vim_airline_c_replace_modified fg=231,bg=53 # fg=#ffffff,bg=#5f005f
+ ble-face -s vim_airline_c_visual fg=231,bg=52 # fg=#ffffff,bg=#5f0000
+ ble-face -s vim_airline_c_visual_modified fg=231,bg=53 # fg=#ffffff,bg=#5f005f
+ ble-face -s vim_airline_z_replace fg=17,bg=45 # fg=#00005f,bg=#00dfff
+}
diff --git a/.local/src/blesh/contrib/airline/dark_minimal.bash b/.local/src/blesh/contrib/airline/dark_minimal.bash
new file mode 100644
index 0000000..2285147
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/dark_minimal.bash
@@ -0,0 +1,13 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/dark_minimal.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:dark_minimal/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=17,bg=190 # fg=#00005f,bg=#dfff00
+ ble-face -s vim_airline_b fg=231,bg=238 # fg=#ffffff,bg=#444444
+ ble-face -s vim_airline_c fg=158,bg=234 # fg=#9cffd3,bg=#202020
+}
diff --git a/.local/src/blesh/contrib/airline/google_dark.bash b/.local/src/blesh/contrib/airline/google_dark.bash
new file mode 100644
index 0000000..6a6c47f
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/google_dark.bash
@@ -0,0 +1,28 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/google_dark.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+# vim-airline template by danrneal (http://github.com/danrneal)
+# Google Scheme by Lisie Michel (https://github.com/google/vim-colorscheme-primary/)
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:google_dark/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=16,bg=71 # fg=#202124,bg=#34a853
+ ble-face -s vim_airline_a_inactive fg=16,bg=59 # fg=#202124,bg=#5f6368
+ ble-face -s vim_airline_a_insert fg=16,bg=69 # fg=#202124,bg=#4285f4
+ ble-face -s vim_airline_a_replace fg=16,bg=167 # fg=#202124,bg=#ea4335
+ ble-face -s vim_airline_a_visual fg=16,bg=214 # fg=#202124,bg=#fbbc04
+ ble-face -s vim_airline_b fg=189,bg=59 # fg=#e8eaed,bg=#5f6368
+ ble-face -s vim_airline_c fg=71,bg=16 # fg=#34a853,bg=#202124
+ ble-face -s vim_airline_c_inactive fg=59,bg=16 # fg=#5f6368,bg=#202124
+ ble-face -s vim_airline_c_inactive_modified fg=231,bg=16 # fg=#ffffff,bg=#202124
+ ble-face -s vim_airline_c_insert fg=69,bg=16 # fg=#4285f4,bg=#202124
+ ble-face -s vim_airline_c_insert_modified fg=231,bg=16 # fg=#ffffff,bg=#202124
+ ble-face -s vim_airline_c_normal_modified fg=231,bg=16 # fg=#ffffff,bg=#202124
+ ble-face -s vim_airline_c_replace fg=167,bg=16 # fg=#ea4335,bg=#202124
+ ble-face -s vim_airline_c_replace_modified fg=231,bg=16 # fg=#ffffff,bg=#202124
+ ble-face -s vim_airline_c_visual fg=214,bg=16 # fg=#fbbc04,bg=#202124
+ ble-face -s vim_airline_c_visual_modified fg=231,bg=16 # fg=#ffffff,bg=#202124
+}
diff --git a/.local/src/blesh/contrib/airline/google_light.bash b/.local/src/blesh/contrib/airline/google_light.bash
new file mode 100644
index 0000000..1bef3d9
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/google_light.bash
@@ -0,0 +1,28 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/google_light.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+# vim-airline template by danrneal (http://github.com/danrneal)
+# Google Scheme by Lisie Michel (https://github.com/google/vim-colorscheme-primary/)
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:google_light/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=231,bg=71 # fg=#ffffff,bg=#34a853
+ ble-face -s vim_airline_a_inactive fg=231,bg=189 # fg=#ffffff,bg=#e8eaed
+ ble-face -s vim_airline_a_insert fg=231,bg=69 # fg=#ffffff,bg=#4285f4
+ ble-face -s vim_airline_a_replace fg=231,bg=167 # fg=#ffffff,bg=#ea4335
+ ble-face -s vim_airline_a_visual fg=231,bg=214 # fg=#ffffff,bg=#fbbc04
+ ble-face -s vim_airline_b fg=59,bg=189 # fg=#5f6368,bg=#e8eaed
+ ble-face -s vim_airline_c fg=71,bg=231 # fg=#34a853,bg=#ffffff
+ ble-face -s vim_airline_c_inactive fg=189,bg=231 # fg=#e8eaed,bg=#ffffff
+ ble-face -s vim_airline_c_inactive_modified fg=16,bg=231 # fg=#202124,bg=#ffffff
+ ble-face -s vim_airline_c_insert fg=69,bg=231 # fg=#4285f4,bg=#ffffff
+ ble-face -s vim_airline_c_insert_modified fg=16,bg=231 # fg=#202124,bg=#ffffff
+ ble-face -s vim_airline_c_normal_modified fg=16,bg=231 # fg=#202124,bg=#ffffff
+ ble-face -s vim_airline_c_replace fg=167,bg=231 # fg=#ea4335,bg=#ffffff
+ ble-face -s vim_airline_c_replace_modified fg=16,bg=231 # fg=#202124,bg=#ffffff
+ ble-face -s vim_airline_c_visual fg=214,bg=231 # fg=#fbbc04,bg=#ffffff
+ ble-face -s vim_airline_c_visual_modified fg=16,bg=231 # fg=#202124,bg=#ffffff
+}
diff --git a/.local/src/blesh/contrib/airline/landscape.bash b/.local/src/blesh/contrib/airline/landscape.bash
new file mode 100644
index 0000000..d3154ac
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/landscape.bash
@@ -0,0 +1,34 @@
+# From github:itchyny/landscape.vim/autoload/airline/themes/landscape.vim
+# The MIT License (MIT)
+# Copyright (c) 2012-2015 itchyny.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:landscape/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=21,bg=231 # fg=#0000ff,bg=#ffffff
+ ble-face -s vim_airline_a_inactive fg=236,bg=233 # fg=#303030,bg=#121212
+ ble-face -s vim_airline_a_insert fg=22,bg=231 # fg=#005f00,bg=#ffffff
+ ble-face -s vim_airline_a_replace fg=124,bg=231 # fg=#af0000,bg=#ffffff
+ ble-face -s vim_airline_a_visual fg=57,bg=231 # fg=#5f00ff,bg=#ffffff
+ ble-face -s vim_airline_b fg=231,bg=21 # fg=#ffffff,bg=#0000ff
+ ble-face -s vim_airline_b_inactive fg=236,bg=233 # fg=#303030,bg=#121212
+ ble-face -s vim_airline_b_insert fg=231,bg=22 # fg=#ffffff,bg=#005f00
+ ble-face -s vim_airline_b_replace fg=231,bg=124 # fg=#ffffff,bg=#af0000
+ ble-face -s vim_airline_b_visual fg=231,bg=57 # fg=#ffffff,bg=#5f00ff
+ ble-face -s vim_airline_c fg=231,bg=236 # fg=#ffffff,bg=#303030
+ ble-face -s vim_airline_c_inactive fg=236,bg=233 # fg=#303030,bg=#121212
+ ble-face -s vim_airline_x_insert fg=250,bg=240 # fg=#bcbcbc,bg=#585858
+ ble-face -s vim_airline_x_normal fg=250,bg=240 # fg=#bcbcbc,bg=#585858
+ ble-face -s vim_airline_x_replace fg=250,bg=240 # fg=#bcbcbc,bg=#585858
+ ble-face -s vim_airline_x_visual fg=250,bg=240 # fg=#bcbcbc,bg=#585858
+ ble-face -s vim_airline_y_insert fg=236,bg=245 # fg=#303030,bg=#8a8a8a
+ ble-face -s vim_airline_y_normal fg=236,bg=245 # fg=#303030,bg=#8a8a8a
+ ble-face -s vim_airline_y_replace fg=236,bg=245 # fg=#303030,bg=#8a8a8a
+ ble-face -s vim_airline_y_visual fg=236,bg=245 # fg=#303030,bg=#8a8a8a
+ ble-face -s vim_airline_z_insert fg=236,bg=252 # fg=#303030,bg=#d0d0d0
+ ble-face -s vim_airline_z_normal fg=236,bg=252 # fg=#303030,bg=#d0d0d0
+ ble-face -s vim_airline_z_replace fg=236,bg=252 # fg=#303030,bg=#d0d0d0
+ ble-face -s vim_airline_z_visual fg=236,bg=252 # fg=#303030,bg=#d0d0d0
+}
diff --git a/.local/src/blesh/contrib/airline/light.bash b/.local/src/blesh/contrib/airline/light.bash
new file mode 100644
index 0000000..26362f4
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/light.bash
@@ -0,0 +1,29 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/light.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:light/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=231,bg=27 # fg=#ffffff,bg=#005fff
+ ble-face -s vim_airline_a_inactive fg=241,bg=249 # fg=#666666,bg=#b2b2b2
+ ble-face -s vim_airline_a_insert fg=231,bg=29 # fg=#ffffff,bg=#00875f
+ ble-face -s vim_airline_a_replace fg=22,bg=196 # fg=#005f00,bg=#ff0000
+ ble-face -s vim_airline_a_visual fg=231,bg=202 # fg=#ffffff,bg=#ff5f00
+ ble-face -s vim_airline_b fg=18,bg=45 # fg=#000087,bg=#00dfff
+ ble-face -s vim_airline_b_inactive fg=245,bg=252 # fg=#8a8a8a,bg=#d0d0d0
+ ble-face -s vim_airline_b_insert fg=22,bg=42 # fg=#005f00,bg=#00df87
+ ble-face -s vim_airline_b_visual fg=52,bg=214 # fg=#5f0000,bg=#ffaf00
+ ble-face -s vim_airline_c fg=27,bg=159 # fg=#005fff,bg=#afffff
+ ble-face -s vim_airline_c_inactive fg=248,bg=231 # fg=#a8a8a8,bg=#ffffff
+ ble-face -s vim_airline_c_inactive_modified fg=160,bg=0 # fg=#df0000,bg=0
+ ble-face -s vim_airline_c_insert fg=23,bg=156 # fg=#005f5f,bg=#afff87
+ ble-face -s vim_airline_c_insert_modified fg=160,bg=224 # fg=#df0000,bg=#ffdfdf
+ ble-face -s vim_airline_c_normal_modified fg=160,bg=224 # fg=#df0000,bg=#ffdfdf
+ ble-face -s vim_airline_c_replace_modified fg=160,bg=224 # fg=#df0000,bg=#ffdfdf
+ ble-face -s vim_airline_c_visual fg=166,bg=228 # fg=#df5f00,bg=#ffff87
+ ble-face -s vim_airline_c_visual_modified fg=160,bg=224 # fg=#df0000,bg=#ffdfdf
+ ble-face -s vim_airline_z_replace fg=231,bg=29 # fg=#ffffff,bg=#00875f
+}
diff --git a/.local/src/blesh/contrib/airline/minimalist.bash b/.local/src/blesh/contrib/airline/minimalist.bash
new file mode 100644
index 0000000..ecefcd3
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/minimalist.bash
@@ -0,0 +1,31 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/minimalist.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+# Minimalist Airline - A Material Color Scheme
+#
+# Author: Diki Ananta <diki1aap@gmail.com>
+# Repository: https://github.com/dikiaap/minimalist
+# Version: 2.0
+# License: MIT
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:minimalist/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=239,bg=249 # fg=#4d4d4d,bg=#b3b3b3
+ ble-face -s vim_airline_a_inactive fg=235,bg=252 # fg=#262626,bg=#cccccc
+ ble-face -s vim_airline_b fg=236,bg=247 # fg=#333333,bg=#999999
+ ble-face -s vim_airline_b_inactive fg=235,bg=252 # fg=#262626,bg=#cccccc
+ ble-face -s vim_airline_c fg=236,bg=252 # fg=#333333,bg=#cccccc
+ ble-face -s vim_airline_c_inactive fg=235,bg=252 # fg=#262626,bg=#cccccc
+ ble-face -s vim_airline_error fg=234,bg=167 # fg=#1c1c1c,bg=#d75f5f
+ ble-face -s vim_airline_error_default fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_error_inactive fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_term fg=234,bg=249 # fg=#1c1c1c,bg=#b3b3b3
+ ble-face -s vim_airline_term_default fg=158,bg=234 # fg=#9cffd3,bg=#202020
+ ble-face -s vim_airline_term_inactive fg=158,bg=234 # fg=#9cffd3,bg=#202020
+ ble-face -s vim_airline_warning fg=234,bg=215 # fg=#1c1c1c,bg=#ffaf5f
+ ble-face -s vim_airline_warning_default fg=16,bg=166 # fg=#000000,bg=#df5f00
+ ble-face -s vim_airline_warning_inactive fg=16,bg=166 # fg=#000000,bg=#df5f00
+}
diff --git a/.local/src/blesh/contrib/airline/monochrome.bash b/.local/src/blesh/contrib/airline/monochrome.bash
new file mode 100644
index 0000000..95daf85
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/monochrome.bash
@@ -0,0 +1,22 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/monochrome.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:monochrome/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_b fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_c fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_error fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_error_default fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_error_inactive fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_term fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_term_default fg=158,bg=234 # fg=#9cffd3,bg=#202020
+ ble-face -s vim_airline_term_inactive fg=158,bg=234 # fg=#9cffd3,bg=#202020
+ ble-face -s vim_airline_warning fg=-1,bg=-1 # fg=-1,bg=-1
+ ble-face -s vim_airline_warning_default fg=16,bg=166 # fg=#000000,bg=#df5f00
+ ble-face -s vim_airline_warning_inactive fg=16,bg=166 # fg=#000000,bg=#df5f00
+}
diff --git a/.local/src/blesh/contrib/airline/solarized.bash b/.local/src/blesh/contrib/airline/solarized.bash
new file mode 100644
index 0000000..8cb0dab
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/solarized.bash
@@ -0,0 +1,33 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/solarized.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:solarized/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=224,bg=66 # fg=#eee8d5,bg=#657b83
+ ble-face -s vim_airline_a_inactive fg=224,bg=102 # fg=#eee8d5,bg=#839496
+ ble-face -s vim_airline_a_insert fg=224,bg=136 # fg=#eee8d5,bg=#b58900
+ ble-face -s vim_airline_a_replace fg=224,bg=166 # fg=#eee8d5,bg=#dc322f
+ ble-face -s vim_airline_a_visual fg=224,bg=168 # fg=#eee8d5,bg=#d33682
+ ble-face -s vim_airline_b fg=224,bg=109 # fg=#eee8d5,bg=#93a1a1
+ ble-face -s vim_airline_b_inactive fg=224,bg=102 # fg=#eee8d5,bg=#839496
+ ble-face -s vim_airline_c fg=109,bg=224 # fg=#93a1a1,bg=#eee8d5
+ ble-face -s vim_airline_c_inactive fg=224,bg=102 # fg=#eee8d5,bg=#839496
+ ble-face -s vim_airline_c_inactive_modified fg=23,bg=0 # fg=#073642,bg=0
+ ble-face -s vim_airline_c_insert_modified fg=60,bg=224 # fg=#586e75,bg=#eee8d5
+ ble-face -s vim_airline_c_normal_modified fg=60,bg=224 # fg=#586e75,bg=#eee8d5
+ ble-face -s vim_airline_c_replace_modified fg=60,bg=224 # fg=#586e75,bg=#eee8d5
+ ble-face -s vim_airline_c_visual_modified fg=60,bg=224 # fg=#586e75,bg=#eee8d5
+ ble-face -s vim_airline_error fg=230,bg=166 # fg=#fdf6e3,bg=#cb4b16
+ ble-face -s vim_airline_error_default fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_error_inactive fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_error_insert fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_error_normal_modified fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_error_visual fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_warning fg=230,bg=166 # fg=#fdf6e3,bg=#cb4b16
+ ble-face -s vim_airline_warning_default fg=16,bg=166 # fg=#000000,bg=#df5f00
+ ble-face -s vim_airline_warning_inactive fg=16,bg=166 # fg=#000000,bg=#df5f00
+}
diff --git a/.local/src/blesh/contrib/airline/solarized_flood.bash b/.local/src/blesh/contrib/airline/solarized_flood.bash
new file mode 100644
index 0000000..2726fe9
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/solarized_flood.bash
@@ -0,0 +1,49 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/solarized_flood.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+# Name: Solarized Flood
+# Changed: June 3 2018
+# Maintainer: https://github.com/Neur1n
+# Description:
+# A vim-airline theme made based on and tested with the Solarized colorscheme
+# (https://github.com/frankier/neovim-colors-solarized-truecolor-only) in
+# Windows 10 OS and GVim 8.1.
+#
+# This script is based on the 'dark' theme. The 'inactive' and 'ctrlp' parts
+# were not changed.
+#
+# It is call 'flood' since the statusline and the tabline will be highlighted
+# with the 'base03' color in Solarized (dark). If you use the dark Solarized
+# colorscheme for Vim and, in Windows, set 'Personalization-Colors-Choose
+# your color - Custom color' to be '#002B36' (*), then most parts of the GVim
+# window will be 'flooded' with the color.
+# NOTE: This will make some components of the airline less distinguishable
+# from the others. If anyone has better ideas, I will be happy to take
+# a conversation with you. :)
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:solarized_flood/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=17,bg=100 # fg=#002b36,bg=#859900
+ ble-face -s vim_airline_a_inactive fg=239,bg=234 # fg=#4e4e4e,bg=#1c1c1c
+ ble-face -s vim_airline_a_insert fg=17,bg=36 # fg=#002b36,bg=#2aa198
+ ble-face -s vim_airline_a_replace fg=17,bg=166 # fg=#002b36,bg=#dc322f
+ ble-face -s vim_airline_a_visual fg=17,bg=136 # fg=#002b36,bg=#b58900
+ ble-face -s vim_airline_b fg=109,bg=17 # fg=#93a1a1,bg=#002b36
+ ble-face -s vim_airline_b_inactive fg=239,bg=235 # fg=#4e4e4e,bg=#262626
+ ble-face -s vim_airline_c fg=36,bg=17 # fg=#2aa198,bg=#002b36
+ ble-face -s vim_airline_c_inactive fg=239,bg=236 # fg=#4e4e4e,bg=#303030
+ ble-face -s vim_airline_c_inactive_modified fg=97,bg=0 # fg=#875faf,bg=0
+ ble-face -s vim_airline_c_insert fg=32,bg=17 # fg=#268bd2,bg=#002b36
+ ble-face -s vim_airline_c_insert_modified fg=168,bg=17 # fg=#d33682,bg=#002b36
+ ble-face -s vim_airline_c_normal_modified fg=168,bg=17 # fg=#d33682,bg=#002b36
+ ble-face -s vim_airline_c_replace_modified fg=168,bg=17 # fg=#d33682,bg=#002b36
+ ble-face -s vim_airline_c_visual fg=166,bg=17 # fg=#dc322f,bg=#002b36
+ ble-face -s vim_airline_c_visual_modified fg=168,bg=17 # fg=#d33682,bg=#002b36
+ ble-face -s vim_airline_z_insert fg=36,bg=17 # fg=#2aa198,bg=#002b36
+ ble-face -s vim_airline_z_normal fg=100,bg=17 # fg=#859900,bg=#002b36
+ ble-face -s vim_airline_z_replace fg=36,bg=17 # fg=#2aa198,bg=#002b36
+ ble-face -s vim_airline_z_visual fg=136,bg=17 # fg=#b58900,bg=#002b36
+}
diff --git a/.local/src/blesh/contrib/airline/term.bash b/.local/src/blesh/contrib/airline/term.bash
new file mode 100644
index 0000000..eebdec5
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/term.bash
@@ -0,0 +1,38 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/term.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:term/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=16,bg=186 # fg=#141413,bg=#cae682
+ ble-face -s vim_airline_a_inactive fg=243,bg=235 # fg=#767676,bg=#242424
+ ble-face -s vim_airline_a_insert fg=16,bg=221 # fg=#141413,bg=#fde76e
+ ble-face -s vim_airline_a_insert_modified fg=16,bg=221 # fg=#141413,bg=#fade3e
+ ble-face -s vim_airline_a_normal_modified fg=16,bg=114 # fg=#141413,bg=#86cd74
+ ble-face -s vim_airline_a_replace fg=16,bg=173 # fg=#141413,bg=#e5786d
+ ble-face -s vim_airline_a_replace_modified fg=16,bg=167 # fg=#141413,bg=#e55345
+ ble-face -s vim_airline_a_visual fg=16,bg=153 # fg=#141413,bg=#b5d3f3
+ ble-face -s vim_airline_a_visual_modified fg=16,bg=110 # fg=#141413,bg=#7cb0e6
+ ble-face -s vim_airline_b fg=186,bg=58 # fg=#cae682,bg=#32322f
+ ble-face -s vim_airline_b_inactive fg=243,bg=235 # fg=#767676,bg=#242424
+ ble-face -s vim_airline_b_insert fg=221,bg=58 # fg=#fde76e,bg=#32322f
+ ble-face -s vim_airline_b_insert_modified fg=221,bg=59 # fg=#fade3e,bg=#40403c
+ ble-face -s vim_airline_b_normal_modified fg=114,bg=59 # fg=#86cd74,bg=#40403c
+ ble-face -s vim_airline_b_replace fg=173,bg=58 # fg=#e5786d,bg=#32322f
+ ble-face -s vim_airline_b_replace_modified fg=167,bg=59 # fg=#e55345,bg=#40403c
+ ble-face -s vim_airline_b_visual fg=153,bg=58 # fg=#b5d3f3,bg=#32322f
+ ble-face -s vim_airline_b_visual_modified fg=110,bg=59 # fg=#7cb0e6,bg=#40403c
+ ble-face -s vim_airline_c fg=186,bg=235 # fg=#cae682,bg=#242424
+ ble-face -s vim_airline_c_inactive fg=243,bg=235 # fg=#767676,bg=#242424
+ ble-face -s vim_airline_c_inactive_modified fg=114,bg=0 # fg=#86cd74,bg=0
+ ble-face -s vim_airline_c_insert fg=221,bg=235 # fg=#fde76e,bg=#242424
+ ble-face -s vim_airline_c_insert_modified fg=221,bg=235 # fg=#fade3e,bg=#242424
+ ble-face -s vim_airline_c_normal_modified fg=114,bg=235 # fg=#86cd74,bg=#242424
+ ble-face -s vim_airline_c_replace fg=173,bg=235 # fg=#e5786d,bg=#242424
+ ble-face -s vim_airline_c_replace_modified fg=167,bg=235 # fg=#e55345,bg=#242424
+ ble-face -s vim_airline_c_visual fg=153,bg=235 # fg=#b5d3f3,bg=#242424
+ ble-face -s vim_airline_c_visual_modified fg=110,bg=235 # fg=#7cb0e6,bg=#242424
+}
diff --git a/.local/src/blesh/contrib/airline/term_light.bash b/.local/src/blesh/contrib/airline/term_light.bash
new file mode 100644
index 0000000..e0ffd22
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/term_light.bash
@@ -0,0 +1,38 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/term_light.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:term_light/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=255,bg=114 # fg=#f0f0f0,bg=#86cd74
+ ble-face -s vim_airline_a_inactive fg=243,bg=102 # fg=#767676,bg=#888a85
+ ble-face -s vim_airline_a_insert fg=255,bg=221 # fg=#f0f0f0,bg=#fade3e
+ ble-face -s vim_airline_a_insert_modified fg=16,bg=221 # fg=#141413,bg=#fde76e
+ ble-face -s vim_airline_a_normal_modified fg=16,bg=186 # fg=#141413,bg=#cae682
+ ble-face -s vim_airline_a_replace fg=255,bg=167 # fg=#f0f0f0,bg=#e55345
+ ble-face -s vim_airline_a_replace_modified fg=16,bg=173 # fg=#141413,bg=#e5786d
+ ble-face -s vim_airline_a_visual fg=255,bg=110 # fg=#f0f0f0,bg=#7cb0e6
+ ble-face -s vim_airline_a_visual_modified fg=16,bg=153 # fg=#141413,bg=#b5d3f3
+ ble-face -s vim_airline_b fg=114,bg=188 # fg=#86cd74,bg=#deded9
+ ble-face -s vim_airline_b_inactive fg=243,bg=102 # fg=#767676,bg=#888a85
+ ble-face -s vim_airline_b_insert fg=221,bg=188 # fg=#fade3e,bg=#deded9
+ ble-face -s vim_airline_b_insert_modified fg=221,bg=59 # fg=#fde76e,bg=#40403c
+ ble-face -s vim_airline_b_normal_modified fg=186,bg=59 # fg=#cae682,bg=#40403c
+ ble-face -s vim_airline_b_replace fg=167,bg=188 # fg=#e55345,bg=#deded9
+ ble-face -s vim_airline_b_replace_modified fg=173,bg=59 # fg=#e5786d,bg=#40403c
+ ble-face -s vim_airline_b_visual fg=110,bg=188 # fg=#7cb0e6,bg=#deded9
+ ble-face -s vim_airline_b_visual_modified fg=153,bg=59 # fg=#b5d3f3,bg=#40403c
+ ble-face -s vim_airline_c fg=114,bg=102 # fg=#86cd74,bg=#888a85
+ ble-face -s vim_airline_c_inactive fg=243,bg=102 # fg=#767676,bg=#888a85
+ ble-face -s vim_airline_c_inactive_modified fg=186,bg=0 # fg=#cae682,bg=0
+ ble-face -s vim_airline_c_insert fg=221,bg=102 # fg=#fade3e,bg=#888a85
+ ble-face -s vim_airline_c_insert_modified fg=221,bg=102 # fg=#fde76e,bg=#888a85
+ ble-face -s vim_airline_c_normal_modified fg=186,bg=102 # fg=#cae682,bg=#888a85
+ ble-face -s vim_airline_c_replace fg=167,bg=102 # fg=#e55345,bg=#888a85
+ ble-face -s vim_airline_c_replace_modified fg=173,bg=102 # fg=#e5786d,bg=#888a85
+ ble-face -s vim_airline_c_visual fg=110,bg=102 # fg=#7cb0e6,bg=#888a85
+ ble-face -s vim_airline_c_visual_modified fg=153,bg=102 # fg=#b5d3f3,bg=#888a85
+}
diff --git a/.local/src/blesh/contrib/airline/transparent.bash b/.local/src/blesh/contrib/airline/transparent.bash
new file mode 100644
index 0000000..30d94b6
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/transparent.bash
@@ -0,0 +1,33 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/transparent.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+#FROM https://github.com/khatiba
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:transparent/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=103,bg=-1 # fg=#8d96a1,bg=-1
+ ble-face -s vim_airline_a_inactive fg=16,bg=-1 # fg=#1d1f21,bg=-1
+ ble-face -s vim_airline_a_insert fg=16,bg=150 # fg=#1d1f21,bg=#bbe67e
+ ble-face -s vim_airline_a_normal_modified fg=16,bg=215 # fg=#1d1f21,bg=#ffae57
+ ble-face -s vim_airline_a_replace fg=16,bg=183 # fg=#1d1f21,bg=#d4bfff
+ ble-face -s vim_airline_a_visual fg=16,bg=204 # fg=#1d1f21,bg=#f07178
+ ble-face -s vim_airline_b fg=59,bg=-1 # fg=#3f4b59,bg=-1
+ ble-face -s vim_airline_b_inactive fg=16,bg=-1 # fg=#1d1f21,bg=-1
+ ble-face -s vim_airline_c fg=59,bg=-1 # fg=#3f4b59,bg=-1
+ ble-face -s vim_airline_c_inactive_modified fg=215,bg=-1 # fg=#ffae57,bg=-1
+ ble-face -s vim_airline_error fg=16,bg=204 # fg=#1d1f21,bg=#f07178
+ ble-face -s vim_airline_error_default fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_error_inactive fg=16,bg=88 # fg=#000000,bg=#990000
+ ble-face -s vim_airline_warning fg=16,bg=215 # fg=#1d1f21,bg=#ffae57
+ ble-face -s vim_airline_warning_default fg=16,bg=166 # fg=#000000,bg=#df5f00
+ ble-face -s vim_airline_warning_inactive fg=16,bg=166 # fg=#000000,bg=#df5f00
+ ble-face -s vim_airline_x_inactive fg=16,bg=-1 # fg=#1d1f21,bg=-1
+ ble-face -s vim_airline_z_insert fg=150,bg=-1 # fg=#bbe67e,bg=-1
+ ble-face -s vim_airline_z_normal fg=59,bg=-1 # fg=#3f4b59,bg=-1
+ ble-face -s vim_airline_z_normal_modified fg=215,bg=-1 # fg=#ffae57,bg=-1
+ ble-face -s vim_airline_z_replace fg=183,bg=-1 # fg=#d4bfff,bg=-1
+ ble-face -s vim_airline_z_visual fg=204,bg=-1 # fg=#f07178,bg=-1
+}
diff --git a/.local/src/blesh/contrib/airline/xtermlight.bash b/.local/src/blesh/contrib/airline/xtermlight.bash
new file mode 100644
index 0000000..f8d23c1
--- /dev/null
+++ b/.local/src/blesh/contrib/airline/xtermlight.bash
@@ -0,0 +1,29 @@
+# From github:vim-airline/vim-airline-themes/autoload/airline/themes/xtermlight.vim
+# The MIT License (MIT)
+# Copyright (C) 2013-2021 Bailey Ling & Contributors.
+#
+
+ble-import lib/vim-airline
+
+function ble/lib/vim-airline/theme:xtermlight/initialize {
+ ble-face -r vim_airline_@
+ ble-face -s vim_airline_a fg=255,bg=27 # fg=#eeeeee,bg=#005fff
+ ble-face -s vim_airline_a_inactive fg=242,bg=249 # fg=#6c6c6c,bg=#b2b2b2
+ ble-face -s vim_airline_a_insert fg=255,bg=29 # fg=#eeeeee,bg=#00875f
+ ble-face -s vim_airline_a_replace fg=22,bg=196 # fg=#005f00,bg=#ff0000
+ ble-face -s vim_airline_a_visual fg=255,bg=202 # fg=#eeeeee,bg=#ff5f00
+ ble-face -s vim_airline_b fg=18,bg=45 # fg=#000087,bg=#00d7ff
+ ble-face -s vim_airline_b_inactive fg=245,bg=252 # fg=#8a8a8a,bg=#d0d0d0
+ ble-face -s vim_airline_b_insert fg=22,bg=42 # fg=#005f00,bg=#00d787
+ ble-face -s vim_airline_b_visual fg=52,bg=214 # fg=#5f0000,bg=#ffaf00
+ ble-face -s vim_airline_c fg=27,bg=159 # fg=#005fff,bg=#afffff
+ ble-face -s vim_airline_c_inactive fg=248,bg=255 # fg=#a8a8a8,bg=#eeeeee
+ ble-face -s vim_airline_c_inactive_modified fg=160,bg=0 # fg=#d70000,bg=0
+ ble-face -s vim_airline_c_insert fg=23,bg=156 # fg=#005f5f,bg=#afff87
+ ble-face -s vim_airline_c_insert_modified fg=160,bg=224 # fg=#d70000,bg=#ffdfdf
+ ble-face -s vim_airline_c_normal_modified fg=160,bg=224 # fg=#d70000,bg=#ffdfdf
+ ble-face -s vim_airline_c_replace_modified fg=160,bg=224 # fg=#d70000,bg=#ffdfdf
+ ble-face -s vim_airline_c_visual fg=166,bg=228 # fg=#d75f00,bg=#ffff87
+ ble-face -s vim_airline_c_visual_modified fg=160,bg=224 # fg=#d70000,bg=#ffdfdf
+ ble-face -s vim_airline_z_replace fg=255,bg=29 # fg=#eeeeee,bg=#00875f
+}
diff --git a/.local/src/blesh/contrib/bash-preexec.bash b/.local/src/blesh/contrib/bash-preexec.bash
new file mode 100644
index 0000000..668aabe
--- /dev/null
+++ b/.local/src/blesh/contrib/bash-preexec.bash
@@ -0,0 +1,154 @@
+# ble/contrib/bash-preexec.bash (C) 2022, akinomyoga
+
+## @arr[in] precmd_functions
+## @arr[in] preexec_functions
+## The functions registered to these arrays are executed on PRECMD and
+## PREEXEC hooks, respectively.
+##
+## @fn[in] precmd
+## @fn[in] preexec
+## If these functions are defined, they are executed on PRECMD and PREEXEC
+## hooks, respectively, through "precmd_functions" and "preexec_functions".
+##
+##
+## * Integration with bash-preexec.sh (https://github.com/rcaloras/bash-preexec)
+##
+## Although this script works without bash-preexec, it provides a better
+## integration with bash-preexec when bash-preexec is loaded. The
+## integration relies on the following public API of bash-preexec.
+##
+## @fn __bp_precmd_invoke_functions lastexit lastarg
+## @fn __bp_preexec_invoke_functions lastexit lastarg this_command
+## @fn __bp_uninstall
+## @var __bp_trapdebug_string
+## @var __bp_install_string
+
+function ble/contrib/bash-preexec/add-convenience-functions {
+ ble/array#remove precmd_functions precmd
+ ble/array#remove preexec_functions preexec
+ ble/array#unshift precmd_functions precmd
+ ble/array#unshift preexec_functions preexec
+}
+
+function ble/contrib/bash-preexec/precmd.hook {
+ local __lastexit=$? __lastarg=$_
+
+ # Emulate bash-preexec variables
+ __bp_last_ret_value=$__lastexit
+ BP_PIPESTATUS=("${BLE_PIPESTATUS[@]}")
+
+ # local __bp_blesh_invoking_through_blesh=1 # XXX
+ if ble/is-function __bp_precmd_invoke_functions; then
+ __bp_precmd_invoke_functions "$__lastexit" "$__lastarg"
+ else
+ # For older bash-preexec.sh / without bash-preexec.sh
+ local __hook
+ for __hook in "${precmd_functions[@]}"; do
+ if builtin type -t "$__hook" &>/dev/null; then
+ ble/util/setexit "$__lastexit" "$__lastarg"
+ "$__hook"
+ fi
+ done
+ fi
+}
+
+function ble/contrib/bash-preexec/preexec.hook {
+ local __lastexit=$? __lastarg=$_ __this_command=$1
+ __bp_last_argument_prev_command=$__lastarg
+
+ # local __bp_blesh_invoking_through_blesh=1 # XXX
+ if ble/is-function __bp_preexec_invoke_functions; then
+ __bp_preexec_invoke_functions "$__lastexit" "$__lastarg"
+ else
+ # For older bash-preexec.sh / without bash-preexec.sh
+ local __hook
+ for __hook in "${preexec_functions[@]}"; do
+ if builtin type -t "$__hook" &>/dev/null; then
+ ble/util/setexit "$__lastexit" "$__lastarg"
+ "$__hook" "$__this_command"
+ fi
+ done
+ fi
+}
+
+## @fn ble/contrib/bash-preexec/attach.hook
+## Remove bash-preexec hooks
+function ble/contrib/bash-preexec/attach.hook {
+ local BP_TRAPDEBUG_STRING=${__bp_trapdebug_string:-'__bp_preexec_invoke_exec "$_"'}
+
+ # Remove bash-preexec preexec hook in builtin DEBUG trap.
+ local trap_string q="'" Q="'\''"
+ ble/util/assign trap_string 'builtin trap -p DEBUG'
+ if [[ $trap_string == "trap -- '${BP_TRAPDEBUG_STRING//$q/$Q}' DEBUG" ]]; then
+ if [[ ${__bp_trap_string-} ]]; then
+ builtin eval -- "builtin $__bp_trap_string"
+ else
+ builtin trap - DEBUG
+ fi
+ fi
+
+ if ble/is-function __bp_uninstall; then
+ __bp_uninstall
+ else
+ # For older bash-preexec.sh
+
+ local BP_INSTALL_STRING=${__bp_install_string:-$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install'}
+ local BP_PROMPT_COMMAND_PREFIX=__bp_precmd_invoke_cmd
+ local BP_PROMPT_COMMAND_SUFFIX=__bp_interactive_mode
+
+ # Remove __bp_install hook from PROMPT_COMMAND
+ if [[ ${PROMPT_COMMAND-} == *"$__bp_install_string"* ]]; then
+ PROMPT_COMMAND="${PROMPT_COMMAND//$BP_INSTALL_STRING[;$'\n']}" # Edge case of appending to PROMPT_COMMAND
+ PROMPT_COMMAND="${PROMPT_COMMAND//$BP_INSTALL_STRING}"
+ fi
+
+ # Remove precmd hook from PROMPT_COMMAND
+ PROMPT_COMMAND=${PROMPT_COMMAND/#$BP_PROMPT_COMMAND_PREFIX$'\n'/$'\n'}
+ PROMPT_COMMAND=${PROMPT_COMMAND%$'\n'$BP_PROMPT_COMMAND_SUFFIX}
+ PROMPT_COMMAND=${PROMPT_COMMAND#$'\n'}
+
+ # Remove preexec hook in the DEBUG trap
+ local q="'" Q="'\''" trap_string
+ ble/util/assign trap_string 'trap -p DEBUG'
+ if [[ $trap_string == "trap -- '${__bp_trapdebug_string//$q/$Q}' DEBUG" ]]; then
+ if [[ ${__bp_trap_string-} ]]; then
+ eval -- "$__bp_trap_string"
+ else
+ trap - DEBUG
+ fi
+ fi
+ fi
+}
+
+## @fn ble/contrib/bash-preexec/detach.hook
+function ble/contrib/bash-preexec/detach.hook {
+ # Reinstall bash-preexec hooks
+ local BP_INSTALL_STRING=${__bp_install_string-}
+ [[ ! $BP_INSTALL_STRING ]] && ble/is-function __bp_install &&
+ BP_INSTALL_STRING=$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install'
+
+ builtin eval -- "$__bp_install_string"
+
+ # Note: 重複して登録される (古い bash-preexec.sh) かもしれないし、全
+ # く登録されない (bash-preexec.sh をロードしていない時) かもしれない
+ # ので、ble.sh 側で末尾で一回呼び出す形に修正する。
+ ble/contrib/bash-preexec/add-convenience-functions
+}
+
+ble/contrib/bash-preexec/add-convenience-functions
+blehook PRECMD-+=ble/contrib/bash-preexec/precmd.hook
+blehook PREEXEC-+=ble/contrib/bash-preexec/preexec.hook
+blehook ATTACH-+=ble/contrib/bash-preexec/attach.hook
+blehook DETACH-+=ble/contrib/bash-preexec/detach.hook
+if [[ ${bp_imported-${__bp_imported-}} ]]; then
+ ble/contrib/bash-preexec/attach.hook
+fi
+
+# XXX: 以下は uninstall で削除しきれなかった時の為の保険。今の所不要に思われる。
+# __bp_blesh_check() {
+# if [[ $BLE_ATTACHED && ! ${__bp_blesh_invoking_through_blesh-} ]]; then
+# ble/contrib/bash-preexec/attach.hook
+# fi
+# }
+# precmd_function+=(__bp_blesh_check)
+# preexec_function+=(__bp_blesh_check)
diff --git a/.local/src/blesh/contrib/config/execmark.bash b/.local/src/blesh/contrib/config/execmark.bash
new file mode 100644
index 0000000..d8da0ce
--- /dev/null
+++ b/.local/src/blesh/contrib/config/execmark.bash
@@ -0,0 +1,111 @@
+# blesh/contrib/config/execmark.bash (C) 2022, Koichi Murase <myoga.murase@gmail.com>
+#
+# Example setup
+#
+# ```bash
+# # blerc
+# ble-import -d contrib/config/execmark
+# bleopt exec_elapsed_enabled='_ble_exec_time_tot>=1000'
+# ```
+#
+
+function ble/contrib/config:execmark/.getsec {
+ local msec=$1 sec
+ if ((msec==0)); then
+ ret=0
+ elif ((msec<1000)); then
+ ret=${msec}ms
+ else
+ ((sec=msec/1000,msec%=1000))
+ msec=000$msec msec=${msec:${#msec}-3}
+ ret=$sec.$msec
+ fi
+}
+
+function ble/contrib/config:execmark/postexec.hook {
+ local command=$_ble_edit_exec_BASH_COMMAND
+
+ if ((_ble_edit_exec_lastexit)) || ble/exec/time#mark-enabled; then
+ local ret
+ local sgr=$'\e[;94m' sgrC=$'\e[38:5:244m' sgr0=$'\e[m'
+ ((_ble_edit_exec_lastexit)) && sgr=$'\e[;91m'
+ ble/color/face2sgr-ansi syntax_varname; local sgrV=$ret
+ ble/color/face2sgr-ansi command_function; local sgrS=$ret
+ ble/color/face2sgr-ansi varname_number; local sgrN=$ret
+
+ # exit
+ local exit=$_ble_edit_exec_lastexit name=
+ if ((exit>=128)) && [[ ${name:=${_ble_builtin_trap_signames[exit&127]}} ]]; then
+ exit=$'\e[1m'"$name"$'\e[22m'" ($sgrN$exit$sgr)"
+ else
+ exit="exit $sgrN$exit$sgr"
+ fi
+
+ # ata
+ local ata=$_ble_exec_time_ata
+ local d=${#ata} sec min hour
+ if ((d<=3)); then
+ ata=${ata}us
+ elif ((d<=5)); then
+ ata=${ata::d-3}.${ata:d-3:6-d}ms
+ elif ((d<=6)); then
+ ata=${ata::3}ms
+ elif ((d<=9)); then
+ ata=${ata::${#ata}-6}.${ata:${#ata}-6:3}s
+ elif ((sec=ata/(1000*1000),min=sec/60,sec%=60,min<100)); then
+ ata="${min}m${sec}s"
+ elif ((hour=min/60,min%=60,hour<100)); then
+ ata="${hour}h${min}m${ata}s"
+ else
+ ata="$((hour/24))d$((hour%24))h${min}m"
+ fi
+ ata="${sgrV}elapsed$sgr $sgrN$ata$sgr"
+
+ # cpu
+ local cpu='--.-%'
+ if ((_ble_exec_time_tot)); then
+ cpu=$(((_ble_exec_time_usr+_ble_exec_time_sys)*1000/_ble_exec_time_tot))
+ cpu=$((cpu/10)).$((cpu%10))%
+ fi
+ cpu="${sgrV}CPU$sgr $sgrN$cpu$sgr"
+ if [[ $_ble_exec_time_usr_self && $_ble_exec_time_sys_self ]]; then
+ local usr0=$_ble_exec_time_usr_self
+ local sys0=$_ble_exec_time_sys_self
+ local usr1=$((_ble_exec_time_usr-_ble_exec_time_usr_self))
+ local sys1=$((_ble_exec_time_sys-_ble_exec_time_sys_self))
+
+ local ret max=0
+ ble/contrib/config:execmark/.getsec "$usr0"; local usr0s=$ret
+ ble/contrib/config:execmark/.getsec "$sys0"; local sys0s=$ret
+ ((usr0>max)) && max=$usr0
+ ((sys0>max)) && max=$sys0
+ if ((usr1||sys1)); then
+ ble/contrib/config:execmark/.getsec "$usr1"; local usr1s=$ret
+ ble/contrib/config:execmark/.getsec "$sys1"; local sys1s=$ret
+ ((usr1>max)) && max=$usr1
+ ((sys1>max)) && max=$sys1
+ fi
+
+ ((usr0==max)) && usr0s=$'\e[1m'$usr0s$'\e[22m'
+ ((sys0==max)) && sys0s=$'\e[1m'$sys0s$'\e[22m'
+ cpu="$cpu $sgrS(self)${sgrV}usr$sgrN$usr0s$sgr/${sgrV}sys$sgrN$sys0s$sgr"
+ if ((usr1||sys1)); then
+ ((usr1==max)) && usr1s=$'\e[1m'$usr1s$'\e[22m'
+ ((sys1==max)) && sys1s=$'\e[1m'$sys1s$'\e[22m'
+ cpu="$cpu+$sgrS(child)${sgrV}usr$sgrN${usr1s}$sgr/${sgrV}sys$sgrN${sys1s}$sgr"
+ fi
+ else
+ local ret
+ ble/contrib/config:execmark/.getsec "$_ble_exec_time_usr"; local usr=$ret
+ ble/contrib/config:execmark/.getsec "$_ble_exec_time_sys"; local sys=$ret
+ cpu="$cpu ${usr}usr/${sys}sys"
+ fi
+
+ local msg=$sgr'[ble: '$exit', '$ata', '$cpu']'$sgr0
+ local ret; ble/string#ltrim "$command"; msg="$msg${ret:+ $sgrC$ret$sgr0}"
+ x=0 y=0 g=0 LINES=1 ble/canvas/trace "$msg" confine:truncate
+ ble/util/buffer.print "$ret"
+ fi
+}
+bleopt exec_@_mark=
+blehook POSTEXEC-+=ble/contrib/config:execmark/postexec.hook
diff --git a/.local/src/blesh/contrib/fzf-completion.bash b/.local/src/blesh/contrib/fzf-completion.bash
new file mode 100644
index 0000000..f6a4876
--- /dev/null
+++ b/.local/src/blesh/contrib/fzf-completion.bash
@@ -0,0 +1,49 @@
+# ble/contrib/fzf-completion.bash (C) 2020-2021, akinomyoga
+
+ble-import contrib/fzf-initialize
+
+[[ $- == *i* ]] || return 0
+
+# fzf/shell/completion.bash を未ロードの時のみロードする
+if ! ble/is-function _fzf_complete; then
+ if [[ -f $_ble_contrib_fzf_base/completion.bash ]]; then
+ source "$_ble_contrib_fzf_base/completion.bash"
+ elif [[ -f $_ble_contrib_fzf_base/shell/completion.bash ]]; then
+ source "$_ble_contrib_fzf_base/shell/completion.bash"
+ elif [[ $_ble_contrib_fzf_base == */share/fzf && -f /etc/bash_completion.d/fzf ]]; then
+ source /etc/bash_completion.d/fzf
+ fi
+fi
+
+# clear blesh completer for cd
+blehook/eval-after-load complete 'unset -f ble/cmdinfo/complete:cd'
+
+# patch fzf functions
+ble/function#advice around __fzf_generic_path_completion _fzf_complete.advice
+ble/function#advice around _fzf_complete _fzf_complete.advice
+ble/function#advice around _fzf_complete_kill _fzf_complete.advice
+function _fzf_complete.advice {
+ if [[ ! $_ble_attached ]]; then
+ ble/function#advice/do
+ return
+ fi
+
+ [[ :$comp_type: == *:auto:* || :$comp_type: == *:[maA]:* ]] && return
+ compopt -o noquote -o ble/syntax-raw
+ COMP_WORDS=("${comp_words[@]}") COMP_CWORD=$comp_cword
+ COMP_LINE=$comp_line COMP_POINT=$comp_point
+ ble/function#push printf '[[ $1 == "\e[5n" ]] || builtin printf "$@"'
+ ble/term/leave-for-widget
+ ble/function#advice/do <> /dev/tty >&0 2>&0
+ ble/term/enter-for-widget
+ ble/function#pop printf
+ ble/textarea#invalidate
+
+ # 単一候補生成の場合は他の候補 (sabbrev 等) を消去して単一確定させる
+ if ((ADVICE_EXIT==0&&${#COMPREPLY[@]}==1)); then
+ ble/complete/candidates/clear
+ [[ $old_cand_count ]] &&
+ ! ble/variable#is-global old_cand_count &&
+ old_cand_count=0
+ fi
+}
diff --git a/.local/src/blesh/contrib/fzf-git.bash b/.local/src/blesh/contrib/fzf-git.bash
new file mode 100644
index 0000000..156fa70
--- /dev/null
+++ b/.local/src/blesh/contrib/fzf-git.bash
@@ -0,0 +1,110 @@
+# ble/contrib/fzf-git.bash (C) 2020, akinomyoga
+# Ported from https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236
+
+ble-import contrib/fzf-initialize
+
+[[ $- == *i* ]] || return 0
+
+# GIT heart FZF
+# -------------
+
+is_in_git_repo() {
+ git rev-parse HEAD > /dev/null 2>&1
+}
+
+fzf-down() {
+ fzf --height 50% "$@" --border
+}
+
+gf() {
+ is_in_git_repo || return
+ git -c color.status=always status --short |
+ fzf-down -m --ansi --nth 2..,.. \
+ --preview '(git diff --color=always -- {-1} | sed 1,4d; cat {-1}) | head -500' |
+ cut -c4- | sed 's/.* -> //'
+}
+
+gb() {
+ is_in_git_repo || return
+ git branch -a --color=always | grep -v '/HEAD\s' | sort |
+ fzf-down --ansi --multi --tac --preview-window right:70% \
+ --preview 'git log --oneline --graph --date=short --color=always --pretty="format:%C(auto)%cd %h%d %s" $(sed s/^..// <<< {} | cut -d" " -f1) | head -'$LINES |
+ sed 's/^..//' | cut -d' ' -f1 |
+ sed 's#^remotes/##'
+}
+
+gt() {
+ is_in_git_repo || return
+ git tag --sort -version:refname |
+ fzf-down --multi --preview-window right:70% \
+ --preview 'git show --color=always {} | head -'$LINES
+}
+
+gh() {
+ is_in_git_repo || return
+ git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=always |
+ fzf-down --ansi --no-sort --reverse --multi --bind 'ctrl-s:toggle-sort' \
+ --header 'Press CTRL-S to toggle sort' \
+ --preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | xargs git show --color=always | head -'$LINES |
+ grep -o "[a-f0-9]\{7,\}"
+}
+
+gr() {
+ is_in_git_repo || return
+ git remote -v | awk '{print $1 "\t" $2}' | uniq |
+ fzf-down --tac \
+ --preview 'git log --oneline --graph --date=short --pretty="format:%C(auto)%cd %h%d %s" {1} | head -200' |
+ cut -d$'\t' -f1
+}
+
+# export FZF_DEFAULT_OPTS=--no-unicode
+
+: "${_ble_contrib_fzf_git_config=key-binding}"
+
+if [[ :$_ble_contrib_fzf_git_config: == *:original:* ]]; then
+ bind '"\er": redraw-current-line'
+ bind '"\C-g\C-f": "$(gf)\e\C-e\er"'
+ bind '"\C-g\C-b": "$(gb)\e\C-e\er"'
+ bind '"\C-g\C-t": "$(gt)\e\C-e\er"'
+ bind '"\C-g\C-h": "$(gh)\e\C-e\er"'
+ bind '"\C-g\C-r": "$(gr)\e\C-e\er"'
+
+ # bind '"\C-g\C-f": "$(gf)\M-\C-e\M-\C-l"'
+ # bind '"\C-g\C-b": "$(gb)\M-\C-e\M-\C-l"'
+ # bind '"\C-g\C-t": "$(gt)\M-\C-e\M-\C-l"'
+ # bind '"\C-g\C-h": "$(gh)\M-\C-e\M-\C-l"'
+ # bind '"\C-g\C-r": "$(gr)\M-\C-e\M-\C-l"'
+fi
+
+if [[ :$_ble_contrib_fzf_git_config: == *:key-binding:* ]]; then
+ function ble/widget/fzf-git {
+ ble/widget/insert-string "$($1)"
+ ble/textarea#invalidate
+ }
+ ble-bind -f 'C-g C-f' 'fzf-git gf'
+ ble-bind -f 'C-g C-b' 'fzf-git gb'
+ ble-bind -f 'C-g C-t' 'fzf-git gt'
+ ble-bind -f 'C-g C-h' 'fzf-git gh'
+ ble-bind -f 'C-g C-r' 'fzf-git gr'
+fi
+
+if [[ :$_ble_contrib_fzf_git_config: == *:sabbrev:* ]]; then
+ function fzf-git.sabbrev {
+ COMPREPLY=$($1)
+ ble/textarea#invalidate
+ }
+ ble-sabbrev -m gf='fzf-git.sabbrev gf'
+ ble-sabbrev -m gb='fzf-git.sabbrev gb'
+ ble-sabbrev -m gt='fzf-git.sabbrev gt'
+ ble-sabbrev -m gh='fzf-git.sabbrev gh'
+ ble-sabbrev -m gr='fzf-git.sabbrev gr'
+fi
+
+if [[ :$_ble_contrib_fzf_git_config: == *:arpeggio:* ]]; then
+ ble-import 'lib/vim-arpeggio.sh'
+ ble/lib/vim-arpeggio.sh/bind -f 'gf' 'fzf-git gf'
+ ble/lib/vim-arpeggio.sh/bind -f 'gb' 'fzf-git gb'
+ ble/lib/vim-arpeggio.sh/bind -f 'gt' 'fzf-git gt'
+ ble/lib/vim-arpeggio.sh/bind -f 'gh' 'fzf-git gh'
+ ble/lib/vim-arpeggio.sh/bind -f 'gr' 'fzf-git gr'
+fi
diff --git a/.local/src/blesh/contrib/fzf-initialize.bash b/.local/src/blesh/contrib/fzf-initialize.bash
new file mode 100644
index 0000000..327c3fe
--- /dev/null
+++ b/.local/src/blesh/contrib/fzf-initialize.bash
@@ -0,0 +1,52 @@
+# ble/contrib/fzf-initialize.bash (C) 2020-2021, akinomyoga
+
+# Usage: Please write the following lines in blerc
+#
+# ```bash
+# _ble_contrib_fzf_base=/path/to/fzf-base-directory
+# ble-import -d contrib/fzf-initialize
+# ```
+
+function ble/contrib/fzf-completion/initialize {
+ if [[ $_ble_contrib_fzf_base ]]; then
+ if [[ :$PATH: != *:"$_ble_contrib_fzf_base/bin":* ]]; then
+ export PATH="${PATH:+${PATH}:}$_ble_contrib_fzf_base/bin"
+ fi
+ if ! type fzf &>/dev/null; then
+ echo 'ble/contrib/fzf-initialize: "fzf" not found.' >&2
+ return 1
+ fi
+ else
+ local ret
+ if ! ble/util/assign ret 'type -p fzf 2>/dev/null'; then
+ echo 'ble/contrib/fzf: "fzf" not found.' >&2
+ return 1
+ fi
+ ble/util/readlink "$ret"
+ ret=${ret%/*} # fzf, fzf-linux_amd64, etc.
+ ret=${ret%/bin} # repo/bin/
+ ret=${ret%/target} # repo/target (compile directory)
+ if [[ -s $ret/shell/key-bindings.bash ]]; then
+ _ble_contrib_fzf_base=$ret
+ elif [[ -d $ret/share/fzf/shell ]]; then
+ _ble_contrib_fzf_base=$ret/share/fzf
+ elif [[ -s $ret/share/fzf/key-bindings.bash ]]; then
+ # NixOS package (https://github.com/akinomyoga/blesh-contrib/pull/5#issuecomment-1019394821)
+ _ble_contrib_fzf_base=$ret/share/fzf
+ elif [[ -s $ret/share/doc/fzf/examples/key-bindings.bash ]]; then
+ # Ubuntu fzf package (https://github.com/akinomyoga/blesh-contrib/pull/5#issuecomment-1019394821)
+ _ble_contrib_fzf_base=$ret/share/doc/fzf/examples
+ elif [[ -d /usr/share/fzf/shell ]]; then
+ _ble_contrib_fzf_base=/usr/share/fzf
+ elif [[ -d /usr/share/doc/fzf/examples/key-bindings.bash ]]; then
+ # Ubuntu fzf package (https://github.com/akinomyoga/blesh-contrib/pull/5#issuecomment-1019394821)
+ _ble_contrib_fzf_base=/usr/share/doc/fzf/examples
+ else
+ echo 'ble/contrib/fzf: failed to find "fzf" base directory' >&2
+ return 1
+ fi
+ fi
+ return 0
+}
+
+ble/contrib/fzf-completion/initialize || return 1
diff --git a/.local/src/blesh/contrib/fzf-key-bindings.bash b/.local/src/blesh/contrib/fzf-key-bindings.bash
new file mode 100644
index 0000000..9ef2774
--- /dev/null
+++ b/.local/src/blesh/contrib/fzf-key-bindings.bash
@@ -0,0 +1,54 @@
+# ble/contrib/fzf-key-bindings.bash (C) 2020, akinomyoga
+
+ble-import contrib/fzf-initialize
+
+[[ $- == *i* ]] || return 0
+
+ble/function#push bind :
+if [[ -f $_ble_contrib_fzf_base/key-bindings.bash ]]; then
+ source "$_ble_contrib_fzf_base/key-bindings.bash"
+elif [[ -f $_ble_contrib_fzf_base/shell/key-bindings.bash ]]; then
+ source "$_ble_contrib_fzf_base/shell/key-bindings.bash"
+fi
+ble/function#pop bind
+
+function ble/contrib/fzf-key-bindings/is-fzf-above-7c447bbd {
+ local def; ble/function#getdef __fzf_history__
+ [[ $def == *READLINE_LINE=* ]]
+}
+
+# CTRL-T - Paste the selected file path into the command line
+ble-bind -m emacs -x C-t fzf-file-widget
+ble-bind -m vi_imap -x C-t fzf-file-widget
+ble-bind -m vi_nmap -s C-t 'i\C-t'
+
+# CTRL-R - Paste the selected command from history into the command line
+ble-bind -m emacs -x C-r fzf-history-widget
+ble-bind -m vi_imap -x C-r fzf-history-widget
+ble-bind -m vi_nmap -s C-r 'i\C-r'
+function fzf-history-widget {
+ READLINE_LINE=$(history -p "$(__fzf_history__)")
+ READLINE_POINT=${#READLINE_LINE}
+}
+((_ble_bash>=40000)) &&
+ ble/contrib/fzf-key-bindings/is-fzf-above-7c447bbd &&
+ function fzf-history-widget { __fzf_history__; }
+
+# ALT-C - cd into the selected directory
+ble-bind -m emacs -c M-c 'eval "$(__fzf_cd__)"'
+ble-bind -m vi_imap -c M-c 'eval "$(__fzf_cd__)"'
+ble-bind -m vi_nmap -c M-c 'eval "$(__fzf_cd__)"'
+
+# patch fzf functions
+ble/function#advice around fzf-file-widget ble/contrib/fzf-key-bindings.advice
+ble/function#advice around __fzf_history__ ble/contrib/fzf-key-bindings.advice
+ble/function#advice around __fzf_cd__ ble/contrib/fzf-key-bindings.advice
+function ble/contrib/fzf-key-bindings.advice {
+ if [[ ! $_ble_attached ]]; then
+ ble/function#advice/do
+ return
+ fi
+ ble/term/leave-for-widget
+ ble/function#advice/do
+ ble/term/enter-for-widget
+}
diff --git a/.local/src/blesh/contrib/prompt-defer.bash b/.local/src/blesh/contrib/prompt-defer.bash
new file mode 100644
index 0000000..ea289ff
--- /dev/null
+++ b/.local/src/blesh/contrib/prompt-defer.bash
@@ -0,0 +1,150 @@
+# blesh/contrib/prompt-defer.bash (C) 2021, akinomyoga
+
+function ble/contrib/prompt-defer/.worker {
+ local prefix=$1
+ local tmpfile=$_ble_base_run/$$.prompt.defer.$prefix
+ ble/contrib/prompt-defer:"$prefix"/worker
+ ble/util/put "$?" >| "$tmpfile"
+}
+
+function ble/contrib/prompt-defer/.finalize {
+ local prefix=$1
+ local tmpfile=$_ble_base_run/$$.prompt.defer.$prefix
+ ble/util/set "${prefix}_DEFER_bgpid" ''
+
+ local ext
+ ble/util/readfile ext "$tmpfile"
+ ble/util/setexit "$ext"
+ ble/contrib/prompt-defer:"$prefix"/callback
+
+ local ret; ble/util/clock
+ ble/util/set "${prefix}_DEFER_clock" "$ret"
+}
+
+function ble/contrib/prompt-defer/clear {
+ local prefix=$1 script='
+ [[ $PREFIX_DEFER_bgpid ]] &&
+ builtin kill -9 "$PREFIX_DEFER_bgpid" &>/dev/null
+ PREFIX_DEFER_index=
+ PREFIX_DEFER_hash1=
+ PREFIX_DEFER_hash2=
+ PREFIX_DEFER_clock=
+ PREFIX_DEFER_bgpid='
+ builtin eval -- "${script//PREFIX/$prefix}"
+}
+
+## @fn ble/contrib/prompt-defer/submit prefix [hash1] [hash2] [opts]
+## @param[in] prefix
+## 関連変数の接頭辞を指定します。
+##
+## @fn ble/comtrib/prompt-defer:$prefix/clear
+## これまでに取得した情報を初期化します。後述の hash1 が前回の呼
+## び出しと異なる際に親シェルで呼び出されます。
+##
+## @fn ble/comtrib/prompt-defer:$prefix/worker
+## バックグラウンドの別プロセスで実行する処理を記述します。bash
+## 4.0 以降ではサブシェルで呼び出されます。bash 4.0 未満では非同
+## 期に処理できない為、親シェルで実行されます。
+##
+## @fn ble/comtrib/prompt-defer:$prefix/callback
+## バックグラウンドの処理が完了した時に親シェルで呼び出される関
+## 数です。$? に worker の終了ステータスが設定された状態で呼び出
+## されます。
+##
+## @var[internal] ${prefix}_DEFER_index
+## @var[internal] ${prefix}_DEFER_hash1
+## @var[internal] ${prefix}_DEFER_hash2
+## @var[internal] ${prefix}_DEFER_clock
+## @var[internal] ${prefix}_DEFER_bgpid
+## 内部で使用する変数です。
+##
+## @param[in] hash1
+## この値が前回の呼び出しと異なる時に強制的に情報の更新を行います。
+##
+## @param[in] hash2
+## この値が前回の呼び出しと異なりかつ前回の呼び出しから十分時間が
+## 経っている時に情報の更新を行います。
+##
+## @param[in,opt] opts
+## コロン区切りのオプションです。
+##
+## cooling=NUM
+## ミリ秒(整数)で情報のタイムアウトを指定します。プロンプト番号
+## または hash2 が前回と異なりかつ此処で指定した時間経過している
+## 場合に再度情報更新を行います。
+##
+## cooling-lines=NUM
+## プロンプト更新回数を指定します。プロンプト番号が此処で指定し
+## た回数以上変化している場合に再度情報更新を行います。
+##
+## expires[=NUM]
+## ミリ秒(整数)で情報のタイムアウトを指定します。プロンプト更新
+## の際に指定した時間経過している場合、強制的に情報更新を行いま
+## す。既定値は 60000 (1分) です。
+##
+## sync=NUM
+## ミリ秒(整数)で同期的な情報取得のタイムアウトを指定します。
+##
+function ble/contrib/prompt-defer/submit {
+ local prefix=$1 opts=$4
+ local tmpfile=$_ble_base_run/$$.prompt.defer.$prefix
+ local rbgpid=${prefix}_DEFER_bgpid
+
+ local opt_cooling=1000 opt_expires=none opt_nprompt=10 opt_sync=5 ret
+ ble/opts#extract-last-optarg "$opts" cooling && opt_cooling=$ret
+ ble/opts#extract-last-optarg "$opts" cooling-lines && opt_nprompt=$ret
+ ble/opts#extract-last-optarg "$opts" expires 60000 && opt_expires=$ret
+ ble/opts#extract-last-optarg "$opts" sync 60000 && opt_sync=$ret
+
+ local oindex=${prefix}_DEFER_index; oindex=${!oindex-}
+ local ohash1=${prefix}_DEFER_hash1; ohash1=${!ohash1-}
+ local ohash2=${prefix}_DEFER_hash2; ohash2=${!ohash2-}
+ local oclock=${prefix}_DEFER_clock; oclock=${!oclock-}
+
+ local nindex=$_ble_prompt_version
+ local nhash1=${2-done} # 強制 update を誘起する hashref
+ local nhash2=${3-done} #
+
+ local update=
+ if [[ $nhash1 != "$ohash1" ]]; then
+ update=1
+ ble/contrib/prompt-defer:"$prefix"/clear
+ elif [[ ! ${!rbgpid} ]]; then
+ if [[ $nindex:$nhash2 != "$oindex:$ohash2" ]]; then
+ if ((nindex<=oindex-opt_nprompt||oindex+opt_nprompt<=nindex)) || { local ret; ble/util/clock; ((ret>=oclock+opt_cooling)); }; then
+ update=1
+ fi
+ elif [[ $opt_expires && $opt_expires != none ]]; then
+ if local ret; ble/util/clock; ((ret>=oclock+opt_expires)); then
+ update=1
+ fi
+ fi
+ fi
+
+ if [[ $update ]]; then
+ ble/util/set "${prefix}_DEFER_index" "$nindex"
+ ble/util/set "${prefix}_DEFER_hash1" "$nhash1"
+ ble/util/set "${prefix}_DEFER_hash2" "$nhash2"
+
+ if ble/is-function ble/util/idle.push; then
+ if [[ ${!rbgpid} ]]; then
+ builtin kill -9 "${!rbgpid}" &>/dev/null
+ ble/util/idle.cancel "ble/contrib/prompt-defer/.finalize $prefix"
+ ble/util/set "$rbgpid" ''
+ fi
+
+ : >| "$tmpfile"
+ ble/util/set "$rbgpid" "$(shopt -u huponexit; ble/contrib/prompt-defer/.worker $prefix < /dev/null &> /dev/null & ble/util/print $!)"
+ ((opt_sync>0)) && ble/util/msleep "$opt_sync"
+ if [[ -s $tmpfile ]]; then
+ ble/contrib/prompt-defer/.finalize "$prefix"
+ else
+ ble/util/idle.push -F "$tmpfile" "ble/contrib/prompt-defer/.finalize $prefix"
+ fi
+
+ else
+ ble/contrib/prompt-defer:"$prefix"/worker
+ ble/contrib/prompt-defer:"$prefix"/callback
+ fi
+ fi
+}
diff --git a/.local/src/blesh/contrib/prompt-elapsed.bash b/.local/src/blesh/contrib/prompt-elapsed.bash
new file mode 100644
index 0000000..b6b79ee
--- /dev/null
+++ b/.local/src/blesh/contrib/prompt-elapsed.bash
@@ -0,0 +1,91 @@
+# blesh/contrib/prompt-elapsed.bash (C) 2022, Koichi Murase <myoga.murase@gmail.com>
+
+function ble/contrib/prompt-elapsed/output-sec.ps {
+ local sec=$1 min
+ ((min=sec/60,sec%=60))
+ if ((min<100)); then
+ ble/prompt/print "${min}m${sec}s"
+ return 0
+ fi
+
+ local hour; ((hour=min/60,min%=60))
+ if ((hour<100)); then
+ ble/prompt/print "${hour}h${min}m${sec}s"
+ return 0
+ fi
+
+ local day; ((day=hour/24,hour%=24))
+ if ((day<365)); then
+ ble/prompt/print "${day}d${hour}h${min}m"
+ return 0
+ fi
+
+ local year; ((year=day/365,day%=365))
+ ble/prompt/print "${year}y${day}d${hour}h"
+ return 0
+}
+
+function ble/contrib/prompt-elapsed/output-time-format.ps {
+ local msec=$1
+ local d=${#msec}
+ if ((d<=3)); then
+ ble/prompt/print "${msec}msec"
+ return 0
+ elif ((d<=5)); then
+ ble/prompt/print "${msec::d-3}.${msec:d-36-d}sec"
+ return 0
+ fi
+
+ local sec=$((msec/1000)) min
+ ((msec%=1000,min=sec/60,sec%=60))
+ msec=000${msec}; msec=${msec:${#msec}-3}
+ if ((min<100)); then
+ ble/prompt/print "${min}m${sec}.${msec}s"
+ return 0
+ fi
+
+ ble/contrib/prompt-elapsed/output-sec.ps $((min*60+sec))
+}
+
+function ble/prompt/backslash:contrib/elapsed {
+ [[ $_ble_exec_time_ata ]] || return 1
+
+ local ata=$_ble_exec_time_ata
+ local d=${#ata}
+ if ((d<=3)); then
+ ble/prompt/print "${ata}usec"
+ return 0
+ elif ((d<=6)); then
+ if ((d<=5)); then
+ ble/prompt/print "${ata::d-3}.${ata:d-3:6-d}msec"
+ else
+ ble/prompt/print "${ata::3}msec"
+ fi
+ return 0
+ elif ((d<=8)); then
+ ble/prompt/print "${ata::d-6}.${ata:d-6:3}sec"
+ return 0
+ fi
+
+ ble/contrib/prompt-elapsed/output-sec.ps $((ata/1000000))
+}
+
+function ble/prompt/backslash:contrib/elapsed-real {
+ [[ $_ble_exec_time_ata ]] || return 1
+ ble/contrib/prompt-elapsed/output-time-format.ps "$_ble_exec_time_tot"
+}
+function ble/prompt/backslash:contrib/elapsed-user {
+ [[ $_ble_exec_time_ata ]] || return 1
+ ble/contrib/prompt-elapsed/output-time-format.ps "$_ble_exec_time_usr"
+}
+function ble/prompt/backslash:contrib/elapsed-sys {
+ [[ $_ble_exec_time_ata ]] || return 1
+ ble/contrib/prompt-elapsed/output-time-format.ps "$_ble_exec_time_sys"
+}
+function ble/prompt/backslash:contrib/elapsed-cpu {
+ ((_ble_exec_time_tot)) || return 1
+
+ local pk=$(((_ble_exec_time_usr+_ble_exec_time_sys)*1000/_ble_exec_time_tot))
+ ble/prompt/print "$((pk/10)).$((pk%10))%"
+ return 0
+}
diff --git a/.local/src/blesh/contrib/prompt-git.bash b/.local/src/blesh/contrib/prompt-git.bash
new file mode 100644
index 0000000..941905a
--- /dev/null
+++ b/.local/src/blesh/contrib/prompt-git.bash
@@ -0,0 +1,250 @@
+# blesh/contrib/prompt-git.bash (C) 2020-2021, akinomyoga
+
+# bleopt prompt_rps1='\q{contrib/git-info}'
+# bleopt prompt_rps1='\q{contrib/git-name}'
+# bleopt prompt_rps1='\q{contrib/git-hash}'
+# bleopt prompt_rps1='\q{contrib/git-branch}'
+# bleopt prompt_rps1='\q{contrib/git-path}'
+
+ble-import contrib/prompt-defer
+
+#------------------------------------------------------------------------------
+
+_ble_contrib_prompt_git_data=()
+_ble_contrib_prompt_git_base=
+_ble_contrib_prompt_git_base_dir=
+_ble_contrib_prompt_git_vars=(git_base git_base_dir)
+
+## @fn ble/contrib/prompt-git/.check-gitdir path
+## @var[out] git_base git_base_dir
+function ble/contrib/prompt-git/.check-gitdir {
+ local path=$1
+ [[ -f $path/.git/HEAD ]] || return 1
+ ble/prompt/unit/assign _ble_contrib_prompt_git_base "$path"
+ ble/prompt/unit/assign _ble_contrib_prompt_git_base_dir "$path/.git"
+ return 0
+}
+## @fn ble/contrib/prompt-git/.check-submodule path
+## @var[out] git_base git_base_dir
+function ble/contrib/prompt-git/.check-submodule {
+ local path=$1 content
+ [[ -f $path/.git ]] || return 1
+ ble/util/mapfile content < "$path/.git"
+ [[ $content == 'gitdir:'* ]] || return 1
+ local git_base=$path
+ local git_base_dir=${content#'gitdir:'}
+ git_base_dir=${git_base_dir#' '}
+ [[ $git_base_dir == /* ]] ||
+ git_base_dir=$path/$git_base_dir
+ [[ -f $git_base_dir/HEAD ]]
+ ble/prompt/unit/assign _ble_contrib_prompt_git_base "$git_base"
+ ble/prompt/unit/assign _ble_contrib_prompt_git_base_dir "$git_base_dir"
+ return 0
+}
+function ble/prompt/unit:_ble_contrib_prompt_git/update {
+ ble/prompt/unit/add-hash '$PWD'
+
+ type git &>/dev/null || return 1
+ # [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) ]]
+ local path=$PWD found=
+ while
+ if ble/contrib/prompt-git/.check-gitdir "$path"; then
+ [[ $prompt_unit_changed ]]
+ return $?
+ elif ble/contrib/prompt-git/.check-submodule "$path"; then
+ [[ $prompt_unit_changed ]]
+ return $?
+ fi
+ [[ $path == */* ]]
+ do path=${path%/*}; done
+
+ ble/prompt/unit/assign _ble_contrib_prompt_git_base ''
+ [[ $prompt_unit_changed ]]
+}
+
+## @fn ble/contrib/prompt-git/initialize
+## @var[out] git_base git_base_dir
+function ble/contrib/prompt-git/initialize {
+ ble/prompt/unit#update _ble_contrib_prompt_git
+ ble/util/restore-vars _ble_contrib_prompt_ "${_ble_contrib_prompt_git_vars[@]}"
+ [[ $git_base ]]
+}
+
+## @fn ble/contrib/prompt-git/check-dirty
+## 現在の working tree に編輯があるかどうかを非同期で取得します。
+## @var[in] git_base
+_ble_contrib_prompt_git_dirty=0
+ble/contrib/prompt-defer/clear _ble_contrib_prompt_git_dirty
+function ble/contrib/prompt-defer:_ble_contrib_prompt_git_dirty/clear { _ble_contrib_prompt_git_dirty=0; }
+function ble/contrib/prompt-defer:_ble_contrib_prompt_git_dirty/worker {
+ #git diff --quiet
+ git status --porcelain | ble/bin/awk '
+ /^[^ ?]./ { staged = 1;}
+ /^.[^ ?]/ { unstaged = 1;}
+ /^\?\?/ { untracked = 1; }
+ END {
+ if (unstaged) exit 1;
+ if (staged) exit 2;
+ if (untracked) exit 3;
+ exit 0
+ }
+ '
+}
+function ble/contrib/prompt-defer:_ble_contrib_prompt_git_dirty/callback { _ble_contrib_prompt_git_dirty=$?; }
+function ble/contrib/prompt-git/check-dirty {
+ [[ $_ble_contrib_prompt_git_base ]] || return 0
+ ble/contrib/prompt-defer/submit _ble_contrib_prompt_git_dirty "$_ble_contrib_prompt_git_base" ''
+ ble/prompt/unit/add-hash '$_ble_contrib_prompt_git_dirty'
+ return "$_ble_contrib_prompt_git_dirty"
+}
+function ble/contrib/prompt-git/is-dirty { ble/contrib/prompt-git/check-dirty; (($?!=0&&$?!=3)); }
+
+## @fn ble/contrib/prompt-git/get-head-information
+## @var[out] hash branch
+function ble/contrib/prompt-git/get-head-information {
+ branch= hash=
+
+ local head_file=$git_base_dir/HEAD
+ [[ -s $head_file ]] || return
+ local content; ble/util/mapfile content < "$head_file"
+
+ if [[ $content == *'ref: refs/heads/'* ]]; then
+ branch=${content#*refs/heads/}
+
+ local branch_file=$git_base_dir/refs/heads/$branch
+ [[ -s $branch_file ]] || return
+ local content; ble/util/mapfile content < "$branch_file"
+ fi
+
+ [[ ! ${content//[0-9a-fA-F]} ]] && hash=$content
+ return 0
+}
+## @fn ble/contrib/prompt-git/get-tag-name hash
+## @var[out] tag
+function ble/contrib/prompt-git/get-tag-name {
+ # ble/util/assign-array tag 'git describe --tags --exact-match 2>/dev/null'
+ tag=
+ local hash=$1; [[ $hash ]] || return 1
+
+ local file tagsdir=$git_base_dir/refs/tags hash1
+ local files ret; ble/util/eval-pathname-expansion '"$tagsdir"/*'; files=("${ret[@]}")
+ for file in "${files[@]}"; do
+ local tag1=${file#$tagsdir/}
+ [[ -s $file ]] || continue
+ ble/util/mapfile hash1 < "$file"
+ if [[ $hash1 == "$hash" ]]; then
+ tag=$tag1
+ return
+ fi
+ done
+}
+
+function ble/contrib/prompt-git/describe-head {
+ local opts=:$1:
+ ret=
+
+ local dirty_mark=
+ [[ $opts == *:check-dirty:* ]] &&
+ { ble/contrib/prompt-git/check-dirty;
+ case $? in
+ (1) dirty_mark=$'\e[1;38:5:202m*\e[m' ;;
+ (2) dirty_mark=$'\e[1;32m*\e[m' ;;
+ (3) dirty_mark=$'\e[1;94m+\e[m' ;;
+ esac }
+
+ local hash branch
+ ble/contrib/prompt-git/get-head-information
+ if [[ $branch ]]; then
+ local sgr=$'\e[1;34m' sgr0=$'\e[m'
+ ret=$sgr$branch$sgr0
+ if [[ $opts == *:add-hash:* && $hash ]]; then
+ ret="$ret (${hash::7}$dirty_mark)"
+ else
+ ret=$ret$dirty_mark
+ fi
+ return
+ fi
+
+ local DETACHED=$'\e[91mDETACHED\e[m'
+
+ local tag
+ ble/contrib/prompt-git/get-tag-name "$hash"
+ if [[ $tag ]]; then
+ local sgr=$'\e[1;32m' sgr0=$'\e[m'
+ ret=$sgr$tag$sgr0
+ [[ $opts == *:add-hash:* && $hash ]] &&
+ ret="$ret ${hash::7}"
+ ret=$ret$dirty_mark
+ [[ $opts == *:check-detached:* ]] &&
+ ret="$DETACHED ($ret)"
+ return
+ fi
+
+ # "master~23" 等の分かりにくい説明なのでこれは使わない
+ # ble/util/assign-array ret 'git describe --contains --all 2>/dev/null'
+ # if [[ $ret ]]; then
+ # local sgr=$'\e[32m' sgr0=$'\e[m'
+ # ret="($DETACHED at $sgr$ret$sgr0)"
+ # return
+ # fi
+
+ if [[ $hash ]]; then
+ ret=${hash::7}$dirty_mark
+ [[ $opts == *:check-detached:* ]] &&
+ ret="$DETACHED ($ret)"
+ return
+ fi
+
+ ret=$'\e[91mUNKNOWN\e[m'
+}
+
+#------------------------------------------------------------------------------
+
+function ble/prompt/backslash:contrib/git-info {
+ local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked
+ if ble/contrib/prompt-git/initialize; then
+ local sgr=$'\e[1m' sgr0=$'\e[m'
+ local name=$sgr${git_base##*?/}$sgr0
+ local ret; ble/contrib/prompt-git/describe-head add-hash:check-dirty:check-detached; local branch=$ret
+ ble/prompt/print "$name $branch"
+ [[ $PWD == "$git_base"/?* ]] &&
+ ble/prompt/print " /${PWD#$git_base/}"
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/prompt/backslash:contrib/git-name {
+ local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked
+ if ble/contrib/prompt-git/initialize; then
+ local name=${git_base%.git}
+ name=${name%/}
+ name=${name##*?/}
+ ble/prompt/print "${git_base##*?/}"
+ fi
+}
+function ble/prompt/backslash:contrib/git-hash {
+ local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked
+ if ble/contrib/prompt-git/initialize; then
+ local hash branch
+ ble/contrib/prompt-git/get-head-information
+ ble/prompt/print "${hash::${1:-7}}"
+ fi
+}
+function ble/prompt/backslash:contrib/git-branch {
+ local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked
+ if ble/contrib/prompt-git/initialize; then
+ local ret; ble/contrib/prompt-git/describe-head check-dirty
+ ble/prompt/print "$ret"
+ fi
+}
+function ble/prompt/backslash:contrib/git-path {
+ local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked
+ if ble/contrib/prompt-git/initialize; then
+ if [[ $PWD == "$git_base"/?* ]]; then
+ ble/prompt/print "/${PWD#$git_base/}"
+ elif [[ $PWD == "$git_base" ]]; then
+ ble/prompt/print /
+ fi
+ fi
+}
diff --git a/.local/src/blesh/contrib/prompt-vim-mode.bash b/.local/src/blesh/contrib/prompt-vim-mode.bash
new file mode 100644
index 0000000..f1574f3
--- /dev/null
+++ b/.local/src/blesh/contrib/prompt-vim-mode.bash
@@ -0,0 +1,20 @@
+# ble/contrib/prompt-vim-mode.bash (C) 2020-2021, akinomyoga
+
+# \q{contrib/vim-mode} (Prompt escape sequence)
+#
+# Example:
+#
+# ble-import contrib/prompt-vim-mode
+# PS1='[\u@\h \W]\q{contrib/vim-mode}\$ '
+# bleopt keymap_vi_mode_show:=
+#
+
+function ble/prompt/backslash:contrib/vim-mode {
+ local mode; ble/keymap:vi/script/get-mode
+ case $mode in
+ ([iR]*) ble/prompt/print '(ins)' ;;
+ (*n) ble/prompt/print '(cmd)' ;;
+ (*x) ble/prompt/print '(vis)' ;;
+ (*s) ble/prompt/print '(sel)' ;;
+ esac
+}
diff --git a/.local/src/blesh/doc/CONTRIBUTING.md b/.local/src/blesh/doc/CONTRIBUTING.md
new file mode 100644
index 0000000..03d44ae
--- /dev/null
+++ b/.local/src/blesh/doc/CONTRIBUTING.md
@@ -0,0 +1,119 @@
+# Contribution Guide
+
+## How to contribute
+
+### Issues
+
+You can freely create an issue using the following links:
+
+- Report and fixes for bugs and performance issues [[Here]](https://github.com/akinomyoga/ble.sh/issues/new?template=bug_report.md)
+- Questions on usage [[Here]](https://github.com/akinomyoga/ble.sh/issues/new?template=feature_request.md)
+- Feature request [[Here]](https://github.com/akinomyoga/ble.sh/issues/new?template=help.md)
+- Others (suggestions, projects, discussion, complaints, news, information or anything) [[Here]](https://github.com/akinomyoga/ble.sh/issues/new?template=free_style.md)
+
+### Pull requests
+
+We always welcome following types of pull requests. Any changes will be considered to be provided under the BSD 3-Clause License.
+If you do not know whether your changes would be appropriate for merge, please feel free to create a pull request and let us talk with each other!
+
+- Better translation to English, typo fixes
+- Fixes, optimization, test cases
+- New features
+- New color themes ... We accept new themes in [`contrib`](https://github.com/akinomyoga/blesh-contrib/pulls) repository.
+- Others
+
+### Wiki
+
+You can freely edit [wiki pages](https://github.com/akinomyoga/ble.sh/wiki).
+
+- Translations
+- Typo fixes
+- Create new pages
+
+## For package maintainers
+
+If you are a package maintainer for a repository of Linux distribution, etc.
+you may provide a package-specific setting by preparing
+a file `/path/to/blesh/lib/_package.sh` (e.g. `/usr/share/blesh/lib/_package.sh`)
+which will be sourced after the load of `ble.sh` just before sourcing user's configuration (`~/.blerc`).
+
+- In the file, the shell variable `_ble_base_package_type=TYPE` should be
+ set up to have a repository-specific name (such as `AUR`).
+
+- The function named `ble/base/package:TYPE/update` (where `TYPE`
+ matches with a value assigned to `_ble_base_package_type`) may be
+ provided to define a custom updating procedure. The exit status of the function can be
+ - `0` ... when the update successed
+ - `6` ... when the update was skipped because the package was up to date.
+ - `125` ... when it wants to fallback to the built-in updating procedure of `ble.sh`.
+ - Other ... when the update failed
+
+An example `lib/_package.sh` might be
+
+```bash
+_ble_base_package_type=apt
+
+function ble/base/package:apt/update {
+ sudo apt upgrade blesh
+}
+```
+
+You can also find a real example for AUR (Arch User Repository) [here](https://aur.archlinux.org/cgit/aur.git/tree/blesh-update.sh?h=blesh-git).
+
+## Summary of codebase
+
+The core script file `ble.sh` is generated by combining the following files:
+
+- `ble.pp` ... Basic initialiation
+- `src/def.sh` ... Prototype definitions
+- `src/util.sh` ... Basic utility functions
+- `src/decode.sh` ... User-input decoder and keybindings
+- `src/color.sh` ... Terminal graphic attributes
+- `src/canvas.sh` ... Terminal layout engine
+ - `src/canvas.emoji.sh` ... Emoji database
+- `src/history.sh` ... Command history management
+- `src/edit.sh` ... Line editor
+- `src/benchmark.sh` ... Measure processing time
+- `lib/core-completion.sh` ... Prototype definition for completions
+- `lib/core-syntax.sh` ... Prototype definitions for syntax analyzer
+
+Useful features are implemented in separate modules:
+
+- `keymap/vi.sh` ... Vim mode
+ - `lib/vim-arpeggio.sh` ... `vim-arpeggio`-like plugin
+ - `lib/vim-surround.sh` ... `vim-surround`-like plugin
+- `keymap/emacs.sh` ... Emacs mode
+- `lib/core-syntax.sh` ... Shell parser and syntax highlighting
+ - `lib/core-syntax-ctx.def` ... Definition of parser states
+- `lib/core-complete.sh` ... Completions including `menu-complete`, `auto-complete`, `menu-filter`, `dabbrev`, `sabbrev`, etc.
+
+The following files are initialization scripts:
+
+- `lib/init-term.sh` ... Initialize terminal escape sequences (host-to-terminal, i.e. control sequences)
+- `lib/init-cmap.sh` ... Initialize terminal escape sequences (terminal-to-host, i.e. key sequences)
+- `lib/init-bind.sh` ... Initialize readline attacher
+- `lib/init-msys1.sh` ... Workaround for MSYS1 with broken pipes
+ - `lib/init-msys1-helper.c` ... Helper C program for the workaround of broken pipes
+
+## Tests
+
+Tests can be run by one of the following commands:
+
+```bash
+$ make check
+$ make check-all
+$ bash out/ble.sh --test
+
+```
+
+Currently test coverage is very small
+partly because the testing for interactive behavior and terminal rendering results is hard.
+Nevertheless, the tests are defined in the following files:
+
+- `lib/core-test.sh` ... Library for tests
+- `lib/test-main.sh`
+- `lib/test-util.sh`
+- `lib/test-canvas.sh`
+- `lib/test-edit.sh`
+- `lib/test-complete.sh`
+- `lib/test-syntax.sh`
diff --git a/.local/src/blesh/doc/ChangeLog.md b/.local/src/blesh/doc/ChangeLog.md
new file mode 100644
index 0000000..5f11a1f
--- /dev/null
+++ b/.local/src/blesh/doc/ChangeLog.md
@@ -0,0 +1,2702 @@
+<!---------------------------------------------------------------------------->
+# ble-0.4.0-devel3
+
+2020-12-02 -- (`#D1427`...) 276baf2...
+
+## New features
+
+- decode (`ble-decode-kbd`): support various specifications of key sequences `#D1439` 0f01cab
+- edit: support new options `bleopt edit_line_type={logical,graphical}` (motivated by 3ximus) `#D1442` 40ae242
+- complete: support new options `bleopt complete_limit{,_auto}` (contributed by timjrd) `#D1445` b13f114 5504bbc
+ - complete: update the default value of `bleopt complete_limit{,auto}` `#D1500` aae553c
+ - complete: inject user interruption and complete limits into `bash-completion` through `read` (motivated by timjrd) `#D1504` 856cec2 `#D1507` 4fc51ae
+- edit (kill/copy): combine multiple kills and copies (suggested by 3ximus) `#D1443` 66564e1
+ - edit (`{kill,copy}-region-or`): fix unconditionally combined kills/copies (reported by 3ximus) `#D1447` 1631751
+- canvas: update emoji database and support `bleopt emoji_version` (motivated by endorfina) `#D1454` d1f8c27
+ - emoji: unify emoji tables of different versions `#D1671` af82662
+- canvas, edit: support `bleopt info_display` (suggested by 0neGuyDev) `#D1458` 69228fa
+ - canvas (panel): always call `panel::render` to update height `#D1472` 51d2c05
+ - util (visible-bell): work around coordinate mismatches in subshells `#D1495` 01cfb10
+ - canvas: work around Kitty's quirk not recognizing <kbd>DECSTBM</kbd> (<kbd>CSI ; r</kbd>) `#D1503` eca2976
+- prompt: support `bleopt prompt_status_{line,align}` and `face prompt_status_line` `#D1462` cca1cbc
+ - prompt: fix missing height allocation for status line `#D1487` b424fa5
+ - prompt: support `bleopt prompt_status_align=justify` `#D1494` c30a0db
+- syntax: properly support case patterns `#D1474` `#D1475` `#D1476` 64b55b7
+- keymap/vi: add `ble/keymap:vi/script/get-mode` for user-defined mode strings `#D1488` f25a6e8 462918d
+- prompt: support multiline `prompt_rps1` `#D1502` 4fa139a
+ - canvas: fix wrong coordinate calculation on linefolding (reported by telometto) `#D1602` 9badb5f
+- syntax: support tilde expansions in parameter expansions `#D1513` 0506df2
+- decode: support `ble-bind -m KEYMAP --cursor DECSCUSR` (motivated by jmederosalvarado) `#D1514` `#D1515` `#D1516` 79d671d
+- edit: support `nsearch` options (motivated by Alyetama, rashil2000, carv-silva) `#D1517` 9125795
+ - edit: support `nsearch` opts `empty=emulate-readline` (motivated by jainpratik163) `#D1661` d68ba61
+ - edit: support bash-5.2 binding of `prior/next` to `history-search-{for,back}ward` `#D1661` d26a6e1
+- syntax: support the deprecated redirection `>& file` `#D1539` b9b0de4
+- complete: complete file descriptors and heredoc words after redirections `#D1539` b9b0de4
+- main: support `blehook ATTACH DETACH`, `BLE_ONLOAD`, `BLE_ATTACHED` `#D1543` 750ca38
+- main: support `ble` `#D1544` 750ca38
+- main (`ble-update`): support package updates and `sudo` updates (motivated by huresche, oc1024) `#D1548` 0bc2660
+ - main (`ble-update`): fix help message (contributed by NoahGorny) 50288bf
+- syntax: support undocumented `${a~}` and `${a~~}` `#D1561` 4df29a6
+- lib: support `lib/vim-airline` (motivated by huresche) `#D1565` da1d0ff
+ - util (`ble/gdict`): refactor `#D1569` 7732eed
+ - vim-airline: support `bleopt vim_airline_theme` `#D1589` 73b037f
+ - prompt: track dependencies and detect changes `#D1590` `#D1591` cf8d949
+ - prompt: preserve `LINES` and `COLUMNS` for custom sequences `#D1592` 040016d
+ - color: fix the face initialiation order for uses in prompts (motivated by jmederosalvarado) `#D1593` 321371f
+ - prompt (`contrib/prompt-git`): support dirty checking `#D1601` b2713d9
+ - prompt (`contrib/prompt-git`): do not use `ble/util/idle` in Bash 3 `#D1606` 959cf27
+ - util (`bleopt`): add new option `-I` to reinitialize user settings on reload `#D1607` 959cf27
+ - vi (vi_cmap): fix wrong prompt calculations by the outdated initial values `#D1653` 2710b23
+- util, color: refactor configuration interfaces (`bleopt`, `blehook`, `ble-face`) `#D1568` c94d292
+ - color: support new face setting function `ble-face`
+ - util (`bleopt`): support option `-r` and `-u` and wildcards in option names
+ - util (`blehook`): hide internal hooks by default and support option `-a`
+ - util, color: fix argument analysis of `bleopt`, `blehook`, and `ble-face` (fixup c94d292) `#D1571` bb53271
+ - util (`blehook`): show explicitly specified internal hooks `#D1594` f4312df
+ - util (`bleopt`): do no select obsoleted options by wildcards `#D1595` f4312df
+ - util (`bleopt`): fix error messages for unknown options `#D1610` 66df3e2
+ - util (`bleopt`, `bind`): fix error message and exit status, respectively `#D1640` b663cee
+- progcomp: support quoted commands and better `progcomp_alias` `#D1581` `#D1583` dbe87c3
+ - progcomp: fix a bug that command names may stray into completer function names `#D1611` 1f2d45f
+- syntax: highlight quotes of the `\?` form `#D1584` 5076a03
+ - syntax: recognize escape \" in double-quoted strings `#D1641` 4b71449
+- prompt: support a new backslash sequence `\g{...}` `#D1609` be31391
+- complete: add a new option `bleopt complete_limit_auto_menu` `#D1618` 1829d80
+- canvas: support grapheme clusters (motivated by huresche) `#D1619` c0d997b
+ - canvas (`ble/util/c2w`): use `EastAsianWidth` and `GeneralCategory` to mimic `wcwidth` `#D1645` 9a132b7
+ - canvas (c2w:auto): work around combining chars applied to the previous line `#D1649` 1cbbecb
+ - canvas (c2w:auto): avoid duplicate requests `#D1649` 1cbbecb a3047f56
+ - canvas (c2w:auto): send <kbd>DSR(6)</kbd> in the internal state `#D1664` a3047f5
+ - canvas (c2w): support `bleopt char_width_mode=musl` `#D1668` 05b258f `#D1672` af82662
+ - canvas (c2w:auto): detect `emacs` and `musl` `#D1668` 05b258f
+- rlfunc: support vi word operations in `emacs` keymap (requested by SolarAquarion) `#D1624` 21d636a
+- edit: support `TMOUT` for the session timeout `#D1631` 0e16dbd
+- edit: support bash-5.2 `READLINE_ARGUMENT` `#D1638` d347fb3
+- complete: support `complete [-DI]` in old versions of Bash through `_DefaultCmD_` and `_InitialWorD_` `#D1639` 925b2cd
+- rlfunc: support nsearch widgets in `vi_nmap` keymap (requested by cornfeedhobo) `#D1651` 9a7c8b1
+- prompt: support `bleopt prompt_ruler` (motivated by Barbarossa93) `#D1666` 05cf638
+ - prompt: fix hanging by a zero-width `prompt_ruler` `#D1673` 9033f29
+- edit: support `bleopt canvas_winch_action` (requested by Johann-Goncalves-Pereira, guptapriyanshu7) `#D1679` 2243e91
+ - blerc: fix the name of the option `bleopt canvas_winch_action` (reported by Knusper) b1be640
+- menu (menu-style:desc): improve descriptions (motivated by Shahabaz-Bagwan) `#D1685` 4de1b45
+- menu (menu-style:desc): support multicolumns (motivated by Shahabaz-Bagwan) `#D1686` 231dc39
+ - menu (menu-style:desc): fix not working `bleopt menu_desc_multicolumn_width=` `#D1727` 2140d1e
+- term: let <kbd>DECSCUSR</kbd> pass through terminal multiplexers (motivated by cmplstofB) `#D1697` a3349e4
+ - util: refactor `_ble_term_TERM` `#D1746` 63fba6b
+- complete: requote for more compact representations on full completions `#D1700` a1859b6
+ - complete (requote): requote from optarg/rhs starting point `#D1786` 93c2786
+- complete: improve support for `declare` and `[[ ... ]]` `#D1701` da38404
+ - syntax: fix completion and highlighting of `declare` with assignment arguments `#D1704` `#D1705` e12bae4
+ - cmdspec: refactor `{mandb => cmdspec}_opts` `#D1706` `#D1707` 0786e92
+- complete (menu-style:align): refactor `complete_menu_align => menu_align_{min,max}` (motivated by banoris) `#D1717` 22a2449
+- prompt: support `bleopt prompt_command_changes_layout` `#D1750` e199bee
+- exec: measure execution times `#D1756` 2b28bec
+ - edit: work around a bash-4.4..5.1 bug of `exit` outputting time to stderr of exit context `#D1765` 3de751e e61dbaa
+ - edit (`exec_elapsed_mark`): show hours and days `#D1793` 699dabb
+- util: preserve original traps and restore them on unload `#D1775` `#D1776` `#D1777` 398e404
+- progcomp: support `compopt -o ble/no-default` to suppress default completions `#D1789` 7b70a0e
+- sabbrev: support options `-r` and `--reset` to remove entries `#D1790` 29b8be3
+- util (blehook): support `hook!=handler` and `hook+-=handler` `#D1791` 0b8c097
+- prompt: escape control characters in `\w` and `\W` `#D1798` 8940434 a9551e5
+ - prompt: fix wrongly escaped UTF-8 chars in `\w` and `\W` `#D1806` XXXXXXX
+
+## Changes
+
+- syntax: exclude <code>\\ + LF</code> at the word beginning from words (motivated by cmplstofB) `#D1431` 67e62d6
+- complete: do not quote `:` and `=` in non-filename completions generated by progcomp (reported by 3ximus) `#D1434` d82535e
+- edit: preserve the state of `READLINE_{LINE,POINT,MARK}` `#D1437` 8379d4a
+- edit: change default behavior of <kbd>C-w</kbd> and <kbd>M-w</kbd> to operate on backward words `#D1448` 47a3301
+- prompt: rename `bleopt prompt_{status_line => term_status}` `#D1462` cca1cbc
+- edit (`ble/builtin/read`): cancel by <kbd>C-d</kbd> on an empty line `#D1473` ecb8888
+- syntax: change syntax context after `time ;` and `! ;` for Bash 4.4 `#D1477` 4628370
+- decode (rlfunc): update mapping `vi-replace` in `imap` and `vi-editing-mode` in `nmap` (reported by onelittlehope) `#D1484` f2ca811
+- prompt: invalidate prompt and textarea on prompt setting changes `#D1492` 1f55913
+- README: update informations on stable versions `#D1509` c8e658e
+- README: update the description of how to uninstall `#D1510` c8e658e
+- util (`bleopt`): validate initial user settings `#D1511` 82c5ece
+ - util (`bleopt`): fix a bug that old values are double-expanded on init (fixup 82c5ece) `#D1521` f795c07
+ - util (`bleopt`): do not validate obsoleted initial settings `#D1527` 032f6b2
+- main: preserve user-space overridden builtins `#D1519` 0860be0
+ - util (`ble/util/type`): fix a bug that aliases are not properly highlighted (reported by 3ximus) `#D1526` 45b30a7
+ - main: preserve user's `expand_aliases` and allow aliases in internal space (fixup 0860be0) `#D1574` afc4112
+ - main: main: fix expand_aliases unset on ble-reload (fixup afc4112) `#D1577` 3417388
+- main: accept non-regular files as `blerc` and add option `--norc` `#D1530` 7244e2f
+- prompt: let `stderr` pass through to tty in evaluating `PS0` (reported by tycho-kirchner) `#D1541` 24a88ce
+- prompt: adjust behavior of `LINENO` and prompt sequence `\#` (reported by tycho-kirchner) `#D1542` 8b0257e
+ - prompt: update `PS0` between multiple commands (motivated by tycho-kirchner) `#D1560` 8f29203
+- edit (`widget:display-shell-version`): include `ble.sh` version `#D1545` 750ca38
+- complete (`ble-sabbrev`): support colored output `#D1546` 750ca38
+- decode (`ble-bind`): support colored output `#D1547` 750ca38
+ - decode (`ble-bind`): output bindings of the specified keymaps with `ble-bind -m KEYMAP` (fixup 750ca38) `#D1559` 6e0245a
+- keymap/vi: update mode names on change of `bleopt keymap_vi_mode_name_*` (motivated by huresche) `#D1565` 11ac106
+- main: show notifications against debug versions of Bash `#D1612` 8f974aa
+- term: update `vte` identification `#D1620` 00e74d8
+- edit: suppress only `stderr` with `internal_suppress_bash_output` (motivated by rashil2000) `#D1646` a30887f
+- prompt: do not evaluate `PROMPT_COMMAND` for subprompts `#D1654` 08e903e
+- Makefile: work around the case the repository is cloned without `--recursive` `#D1655` 22ace5f
+- repo: add subdirectories `make` and `docs` `#D1657` 75bd04c
+- util: time out <kbd>CPR</kbd> requests `#D1669` 1481d48
+ - util (CPR): fix the problem of always timing out (fixup 1481d48) `#D1792` 9b331c4
+- main: suppress non-interactive warnings from manually sourced startup files (reported by andreclerigo) `#D1676` 0525528 88e2df5
+- mandb: integrate `mandb` with `bash-completion` (motivated by Shahabaz-Bagwan, bbyfacekiller and EmilySeville7cfg) `#D1688` c1cd666
+- syntax: do not start argument completions immediately after previous word (reported by EmilySeville7cfg) `#D1690` 371a5a4
+ - syntax: revert 371a5a4 and generate empty completion source on syntax error `#D1609` e09fcab
+- syntax: strictly check variable names of `for`-statements `#D1692` d056547
+- widget `self-insert`: untranslate control chars and insert the last character `#D1696` 5ff3021
+- complete (`source:command`): exclude inactive aliases `#D1715` d6242a7
+- complete (`source:command`): not quote aliases and keywords `#D1715` d6242a7
+- highlight (`wtype=CTX_CMDI`): check alias names before shell expansions `#D1715` d6242a7
+ - util (`ble/is-alias`): fix a bug of unredirected error messages for bash-3.2 (fixup d6242a7) `#D1730` 31372cb
+- edit (`history_share`): update history on `discard-line` (reported by SuperSandro2000) `#D1742` 8dbefe0
+- canvas: do not insert explicit newlines on line folding if possible (reported by banoris) `#D1745` 02b9da6 dc3827b
+ - edit: fix layout with `prompt_rps1` caused by missing `opts=relative` for `ble/textmap#update` `#D1769` f6af802
+- edit (`ble-bind -x`): preserve multiline prompts on execution of `bind -x` commands (requested by SuperSandro2000) `#D1755` 7d05a28
+- util (`ble/util/buffer`): hide cursor in rendering `#D1758` e332dc5
+- complete (`action:file`): always suffix `/` to complete symlinked directory names (reported by SuperSandro2000) `#D1759` 397ac1f
+- edit (command-help): show source files for functions `#D1779` 7683ab9
+- edit (`ble/builtin/exit`): defer exit in trap handlers (motivated by SuperSandro2000) `#D1782` f62fc04 6fdabf3
+ - util (`blehook`): fix a bug that the the hook arguments are lost (reported by SuperSandro2000) `#D1804` 479795d
+- complete (`source:command/get-desc`): show function location and body `#D1788` 496e798
+- edit (`ble-detach`): prepend a space to `stty sane` for `HISTIGNORE=' *'` `#D1796` 26b532e
+
+## Fixes
+
+- term: fix a bug that VTE based terminals are not recognized `#D1427` 7e16d9d
+- complete: fix a problem that candidates are not updated after menu-filter (reported by 3ximus) `#D1428` 98fbc1c
+- complete/mandb-related fixes
+ - mandb: support mandb in FreeBSD `#D1432` 6c54f79
+ - mandb: fix BS contamination used by nroff to represent bold (reported by rlnore) `#D1429` b5c875a
+ - mandb: fix an encoding prpblem of utf8 manuals `#D1446` 7a4a480
+ - mandb: improve extraction and cache for each locale `#D1480` 3588158
+ - mandb: fix an infinite loop by a leak variable (reported by rlanore, riblo) `#D1550` 0efcb65
+ - mandb: work around old groff in macOS (reported by killermoehre) `#D1551` d4f816b
+ - mandb: use `manpath` and `man -w`, and read `/etc/man_db.conf` and `~/.manpath` `#D1637` 2365e09
+ - mandb: support the formats of the man pages of `awk` and `sed` (reported by bbyfacekiller) `#D1687` 6932018
+ - mandb: generate completions of options also for the empty word `#D1689` b90ac78
+ - mandb: support the man-page formats of `wget`, `fish`, and `ping` (reported by bbyfacekiller) `#D1687` a79280e
+ - mandb: carry optarg for e.g. `-a, --accept=LIST` `#D1687` 23d5657
+ - mandb: parse `--help` for specified commands `#D1693` e1ad2f1
+ - mandb: fix small issues of man-page analysis `#D1708` caa77bc
+ - mandb: insert a comma in brace expansions instead of a space `#D1719` 0ac7f03
+ - mandb: support man-page format of `rsync` `#D1733` 7900144
+ - mandb: fix a bug that the description is inserted for `--no-OPTION` `#D1761` 88614b8
+ - mandb: fix a bug that the man page is not correctly searched (fixup 2365e09) `#D1794` 65ffe70
+- edit: work around the wrong job information of Bash in trap handlers (reported by 3ximus) `#D1435` `#D1436` bc4735e
+- edit (command-help): work around the Bash bug that tempenv vanishes with `builtin eval` `#D1438` 8379d4a
+- global: suppress missing locale errors (reported by 3ximus) `#D1440` 4d3c595
+- edit (sword): fix definition of `sword` (shell words) `#D1441` f923388
+- edit (`kill-forward-logical-line`): fix a bug not deleting newline at the end of the line `#D1443` 09cf7f1
+- util (`ble/util/msleep`): fix hang in Cygwin by swithing from `/dev/udp/0.0.0.0/80` to `/dev/zero` `#D1452` d4d718a
+ - util (`ble/util/msleep`): work around the bash-4.3 bug of `read -t` (reported by 3ximus) `#D1468` `#D1469` 4ca9b2e
+- syntax: fix broken AST with `[[` keyword `#D1454` 69658ef
+- benchmark (`ble-measure`): work around a locale-dependent decimal point of `EPOCHREALTIME` (reported by 3ximus) `#D1460` 1aa471b
+- global: work around bash-4.2 bug of `declare -gA` (reported by 0xC0ncord) `#D1470` 8856a04
+ - global: fix declaration of associative arrays for `ble-reload` (reported by 0xC0ncord) `#D1471` 3cae6e4
+ - global: use a better workaround of bash-4.2 `declare -gA` by separating assignment `#D1567` 2408a20
+- bind: work around broken `cmd_xmap` after switching the editing mode `#D1478` 8d354c1
+- edit: clear graphic rendition on newlines and external commands `#D1479` 18bb2d5
+- decode (rlfunc): work around incomplete bytes in keyseq (reported by onelittlehope) `#D1483` 3559658 beb0383 37363be
+- main: fix a bug that unset `IFS` is not correctly restored `#D1489` 808f6f7
+ - edit: fix error messages on accessing undo records in emacs mode (reported by rux616) `#D1497` 61a57c0 e9be69e
+- canvas: fix a glitch that SGR at the end of command line is applied to new lines `#D1498` 4bdfdbf
+- syntax: fix a bug that `eval() { :; }`, `declare() { :; }` are not treated as function definition `#D1529` b429095
+- decode: fix a hang on attach failure by cache corruption `#D1531` 24ea379
+- edit, etc: add workarounds for `localvar_inherit` `#D1532` 7b63c60
+ - edit: fix a bug that `command-help` doesn't work `#D1635` 0f6a083
+- progcomp: fix non-working `complete -C prog` (reported by Archehandoro) `#D1535` 026432d
+- bind: fix a problem that `bind '"seq":"key"'` causes a loop macro `bind -s key key` (reported by thanosz) `#D1536` ea05fc5
+ - bind: fix errors on readline macros (reported by RakibFiha) `#D1537` c257299
+- main: work around sourcing `ble.sh` inside subshells `#D1554` bbc2a90
+ - main: fix exit status for `bash ble.sh --test` (fixup bbc2a90) `#D1558` 641238a
+ - main: fix reloading after ble-update (fixup bbc2a90) (fixed by oc1024) `#D1558` 9372670
+- main: work around `. ble.sh --{test,update,clear-cache}` in intereactive sessions `#D1555` bbc2a90
+- Makefile: create `run` directory instead of `tmp` `#D1557` 9bdb37d
+- main: fix the workaround for `set -e` `#D1564` ab2f70b
+ - main: fix the workaround for `set -u` `#D1575` 76073a9
+ - main: fix the workaround for `set -eu` and refactor `#D1743` 6a946f0
+- util: work around bash-3.0 bug `"${scal[@]/xxx}"` `#D1570` 24f79da
+- sabbrev (`ble-sabbrev`): fix delayed output before the initialization `#D1573` 5d85238
+- history: fix the workaround for bash-3.0 bug of reducing histories `#D1576` 15c9133
+- syntax: fix a bug that argument completion is attempted in nested commands (reported by huresche) `#D1579` 301d40f
+- edit (brackated-paste): fix incomplete `CR => LF` conversion (reported by alborotogarcia) `#D1587` 8d6da16
+- main (adjust-bash-options): adjust `LC_COLLATE=C` `#D1588` e87ac21
+- highlight (`layer:region`): fix blocked lower-layer changes without selection changes `#D1596` 5ede3c6
+- complete (`auto-menu`): fix sleep loops by clock/sclock difference `#D1597` 53dd018
+- history: fix a bug that history data is cleared on `history -r` `#D1605` 72c274e
+- util (`ble/string#quote-command`): remove redundant trailing spaces for single word command `#D1613` 94556b4
+- util: work around the Bash 3 bug of array assignments with `^A` and `^?` in Bash 3.2 `#D1614` b9f7611
+- benchmark (`ble-measure`): fix a bug that the result is always 0 in Bash 3 and 4 (fixup bbc2a904) `#D1615` a034c91
+- complete: fix a bug that the shopt settings are not restored correctly (reported by Lun4m) `#D1623` 899c114
+- decode, canvas, etc.: explicitly treat CSI arguments as decimal numbers (reported by GorrillaRibs) `#D1625` c6473b7 2ea48d7
+- history: fix the vanishing history entry used for `ble-attach` `#D1629` eb34061
+- global: work around readonly `TMOUT` (reported by farmerbobathan) `#D1630` 44e6ec1
+- complete: fix a task scheduling bug of referencing two different clocks (reported by rashil2000) `#D1636` fea5f5b
+- canvas: update prompt trace on `char_width_mode` change (reported by Barbarossa93) `#D1642` 68ee111
+- decode (`cmap/initialize`): fix unquoted special chars in the cmap cache `#D1647` 7434d2d
+- decode: fix a bug that the characters input while initialization are delayed `#D1670` 430f449
+- util (`ble/util/readfile`): fix a bug of always exiting with 1 in `bash <= 3.2` (reported by laoshaw) `#D1678` 61705bf
+- trace: fix wrong positioning of the ellipses on overflow `#D1684` b90ac78
+- complete: do not generate keywords for quoted command names `#D1691` 60d244f
+- menu (menu-style:align): fix the failure of delaying `ble/canvas/trace` on items (motivated by banoris) `#D1710` acc9661
+- complete: fix empty completions with `FIGNORE` (reported by seanfarley) `#D1711` 144ea5d
+- main: fix the message of owner errors of cache directories (reported by zim0369) `#D1712` b547a41
+- util (`ble/string#escape-for-bash-specialchars`): fix escaping of TAB `#D1713` 7db3d2b
+- complete: fix failglob messages while progcomp for commands containing globchars `#D1716` e26a3a8
+ - complete: fix a bug that the default progcomp does not work properly `#D1722` 01643fa
+- highlight: fix a bug that arrays without the element `0` is not highlighted `#D1721` b0a0b6f
+- util (visible-bell): erase visible-bell before running external commands `#D1723` 0da0c1c
+- util (`ble/function`): work around `shopt -u extglob` `#D1725` 952c388
+- syntax: fix uninitialized syntax-highlighting in bash-3.2 `#D1731` e3f5bf7
+- make: fix a bug that config update messages are removed on install `#D1736` 72d968f
+- util: fix bugs in conversions from `'` to `\''` `#D1739` 6d15782
+- canvas: fix unupdated prompt on async wcwidth resolution `#D1740` e14fa5d
+- progcomp: retry completions on `$? == 124` also for non-default completions (reported by SuperSandro2000) `#D1759` 82b9c01
+- app: work around data corruption by WINCH on intermediate state `#D1762` 5065fda
+- util (`ble/util/import`): work around filenames with bash special characters `#D1763` b27f758
+- edit: fix the restore failure of `PS1` and `PROMPT_COMMAND` on `ble-detach` `#D1784` b9fdaab
+- complete: do not attempt an independent rhs completion for arguments (reported by rsteube) `#D1787` f8bbe2c
+- history: fix the unsaved history in the detached state `#D1795` 344168e
+- edit: fix an unexpected leave from the command layout on `read` `#D1800` 4dbf16f
+
+## Documentation
+
+- blerc: add all the missing options `#D1667` 0228d76
+- blerc: add missing faces `argument_option` and `cmdinfo_cd_cdpath` (reported by Prikalel) `#D1675` 26aaf87
+- README: describe how to invoke multiple widgets with a keybinding (motivated by michaelmob) `#D1699` 6123551
+- README: add links to `bash-it` and `oh-my-bash` `#D1724` 4a2575f
+
+## Optimization
+
+- syntax (`layer:syntax/word`): perform pathname expansions in background subshells (motivated by 3ximus) `#D1449` 13e7bdd
+ - syntax (`simple-word/is-simple-noglob`): suppress error messages on expansions `#D1461` a56873f
+ - syntax (`simple-word/eval`): fix unperformed tilde expansions in the background (reported by 3ximus) `#D1463` 6ebec48
+ - syntax (`simple-word/eval`): propagate timeouts in sync highlighting (reported by 3ximus) `#D1465` c2555e2
+ - edit: change the priority of `render-defer` and `menu-filter` `#D1501` aae553c
+- complete: perform pathname expansions in subshells (motivated by 3ximus) `#D1450` d511896
+- complete: support `bleopt complete_timeout_compvar` to time out pathname expansions for `COMP_WORDS` / `COMP_LINE` `#D1457` cc2881a
+- complete (`ble/complete/source:file`): remove slow old codes (reported by timjrd) `#D1512` e5be0c1
+- syntax (`ble/syntax:bash/simple-word/eval`): optimize large array passing (motivated by timjrd) `#D1522` c89aa23
+ - syntax (`ble/syntax:bash/simple-word/eval`): use `mapfile -d ''` for Bash 5.2 `#D1604` 72c274e
+- main: prefer `nawk` over `mawk` and `gawk` `#D1523` `#D1524` c89aa23
+ - main (`ble/bin/.freeze-utility-path`): fix unupdated temporary implementations `#D1528` c70a3b4
+ - util (`ble/util/assign`): work around subshell conflicts `#D1578` 6e4bb12
+- history: use `mapfile -d ''` to load history in Bash 5.2 `#D1603` 72c274e
+- prompt: use `${PS1@P}` when the prompt contains only safe prompt sequences `#D1617` 8b5da08
+ - prompt: fix not properly set `$?` in `${PS1@P}` evaluation (reported by nihilismus) `#D1644` 521aff9
+ - prompt: fix a bug that the special treatment of `\$` in Cygwin/MSYS is disabled `#D1741` 4782a33
+- decode: cache `inputrc` translations `#D1652` 994e2a5
+- complete: use `awk` for batch `quote-insert` (motivated by banoris) `#D1714` a0b2ad2 92d9734
+ - complete (quote-insert.batch): fix regex escaping in bracket expr of awk (reported by telometto) `#D1729` 8039b77
+- prompt: reduce redundant evaluation of `PROMPT_COMMAND` on the startup `#D1778` 042376b
+- main: run `ble/base/unload` directly at the end of `EXIT` handler `#D1797` 115baec
+
+## Compatibility
+
+- term: work around quirks of Solaris xpg4 awk `#D1481` 6ca0b8c
+- term: support key sequences and control sequences of Solaris console `#D1481` 6ca0b8c
+- term: work around Cygwin-console bug of bottom `IL`/`DL` `#D1482` 5dce0b8
+- term: work around leaked <kbd>DA2R</kbd> in screen from outside terminal `#D1485` e130619
+- complete: work around `fzf` completion settings loaded automatically `#D1508` 4fc51ae
+- complete: work around `bash-completion` bugs (reported by oc1024) `#D1533` 9d4ad56
+- main: work around MSYS2 .inputrc (reported by n1kk) `#D1534` 9e786ae
+- util (`modifyOtherKeys`): work around a quirk of Kitty (reported by NoahGorny) `#D1549` f599525
+ - util (`modifyOtherKeys`): update the workaround for a new quiark of kitty `#D1627` 3e4ecf5
+ - util (`modifyOtherKeys`): use the kitty protocol for kitty 0.23+ which removes the support of `modifyOtherKeys` (reported by kovidgoyal) `#D1681` ec91574
+- global: work around empty `vi_imap` cache by `tmux-resurrect` `#D1562` 560160b
+- decode: identify `kitty` and treat `\e[27u` as isolated ESC (reported by lyiriyah) `#D1585` c2a84a2
+- complete: suppress known error messages of `bash-completion` (reported by oc1024, Lun4m) `#D1622` d117973
+- decode: work around kitty keypad keys in modifyOtherKeys (reported by Nudin) `#D1626` 27c80f9
+- main: work around `set -B` and `set -k` `#D1628` a860769
+- term: disable `modifyOtherKeys` and do not send `DA2` for `st` (requested by Shahabaz-Bagwan) `#D1632` 92c7b26
+- cmap: add `st`-specific escape sequences for cursor keys `#D1633` acfb879
+- cmap: distinguish <kbd>find</kbd>/<kbd>select</kbd> from <kbd>home</kbd>/<kbd>end</kbd> for openSUSE `inputrc.keys` (reported by cornfeedhobo) `#D1648` c4d28f4
+ - cmap: freeze the internal codes of <kbd>find</kbd>/<kbd>select</kbd> and kitty special keys `#D1674` fdfe62a
+- main: work around self-modifying `PROMPT_COMMAND` by `bash-preexec` (reported by cornfeedhobo) `#D1650` 39ebf53
+- decode: work around openSUSE broken `/etc/inputrc` `#D1662` e5b0c86
+- decode: work around the overwritten builtin `set` (reported by eadmaster) `#D1680` a6b4e2c
+- complete: work around the variable leaks by `virsh` completion from `libvirt` (reported by telometto) `#D1682` f985b9a
+- stty: do not remove keydefs for <kbd>C-u</kbd>, <kbd>C-v</kbd>, <kbd>C-w</kbd>, and <kbd>C-?</kbd> (reported by laoshaw) `#D1683` 82f74f0
+- builtin: print usages of emulated builtins on option errors `#D1694` 6f74021
+- decode (`ble/builtin/bind`): improve compatibility of the deprecated form `bind key:rlfunc` (motivated by cmplstofB) `#D1698` b6fc4f0
+ - decode (`ble/builtin/bind`): fix a bug that only lowercase is accepted for deprecated form `bind key:rlfunc` (reported by returntrip) `#D1726` a67458e e363f1b
+- complete: work around a false warning messages of gawk-4.0.2 `#D1709` 9771693
+- main: work around `XDG_RUNTIME_DIR` of a different user by `su` (reported by zim0369) `#D1712` 8d37048
+- main (`ble/util/readlink`): work around non-standard or missing `readlink` (motivated by peterzky) `#D1720` a41279e
+- menu (`menu-style:desc`): work around xenl quirks for relative cursor movements (reported by telometto) `#D1728` 3e136a6
+- global: work around the arithmetic syntax error of `10#` in Bash-5.1 `#D1734` 7545ea3
+- global: adjust implementations for Bash 5.2 `patsub_replacement` `#D1738` 4590997
+ - global: work around `compat42` quoting of `"${v/pat/"$rep"}"` `#D1751` a75bb25
+ - prompt: fix a bug of `ble/prompt/print` redundantly quoting `$` `#D1752` a75bb25
+ - global: identify bash-4.2 bug that internal quoting of `${v/%$empty/"$rep"}` remains `#D1753` a75bb25
+ - global: work around `shopt -s compat42` `#D1754` a75bb25
+- global (`ble/builtin/*`): work around `set -eu` in NixOS initialization (reported by SuperSandro2000) `#D1743` 001c595
+- util, edit, contrib: add support for `bash-preexec` (motivated by SuperSandro2000) `#D1744` e85f52c
+ - util (`ble/builtin/trap`): fix resetting `$?` and `$_` (reported by SuperSandro2000) `#D1757` dfc6221
+ - util (`ble/builtin/trap`): fix a failure of setting the trap-handler exit status (reported by SuperSandro2000) `#D1771` c513ed4
+- main: check `IN_NIX_SHELL` to inactivate ble.sh in nix-shell (suggested by SuperSandro2000) `#D1747` b4bd955
+ - main: force prompt-attach inside the nix-shell `rc` `#D1766` ceb2e7c
+- canvas: test the terminal for the sequence of clearing `DECSTBM` `#D1748` 4b1601d
+- main: check `/dev/tty` on startup (reported by andychu) `#D1749` 711c69f
+- util: add identification of Windows Terminal `wt` `#D1758` e332dc5
+- complete: evaluate words for `noquote` (motivated by SuperSandro2000) `#D1767` 0a42299
+- edit (TRAPDEBUG): preserve original `DEBUG` trap and enabled it in `PROMPT_COMMAND` (motivated by ammarooo) `#D1772` `#D1773` ec2a67a
+ - main, trap: fix initialization order of `{save,restore}-BASH_REMATCH` (reported by SuperSandro2000) `#D1780` 689534d
+- global: work around bash-3.0 bug that single quotas remains for `"${v-$''}"` `#D1774` 9b96578
+- util: work around old `vte` not supporting `DECSCUSR` yet setting `TERM=xterm` (reported by dongxi8) `#D1785` 70277d0
+- progcomp: work around the cobra V2 description hack (reported by SuperSandro2000) `#D1803` 71d0736
+- complete: work around blocking `_scp_remote_files` and `_dnf` (reported by iantra) `#D1807` XXXXXXX
+
+## Internal changes and fixes
+
+- main: include hostname in local runtime directory `#D1444` 6494836
+- global: update the style of document comments ff4c4e7
+- util: add function `ble/string#quote-words` `#D1451` f03b87b
+- syntax (`ble/syntax:bash/simple-word/eval`): cache `#D1453` 6d8311e
+ - syntax (`simple-word/eval`): support `opts=single` for a better cache performance (motivated by 3ximus) `#D1464` 10caaa4
+- global: refactor `setup => set up / set-up` `#D1456` c37a9dd
+- global: clean up helps of user functions `#D1459` 33c283e
+- benchmark (`ble-measure`): support `-T TIME` and `-B TIME` option `#D1460` 1aa471b
+- util, color (`bleopt`, `blehook`, `ble-color-setface`): support `--color` and fix `sgr0` contamination in non-color output `#D1466` 69248ff
+- global: fix status check for read timeout `#D1467` e886883
+- decode: move `{keymap/*. => lib/core-decode.*-}rlfunc.txt` and clean up files `#D1486` f7323b4
+ - Makefile: fix up f7323b4: restore rule for `keymap/*.txt` `#D1496` 054e5c1
+- util, etc: ensure each function to work with arbitrary `IFS` `#D1490` `#D1491` 5f9adfe
+- tui, canvas (`ble/canvas/trace`): support `opts=clip` `#D1493` 61ce90c
+- tui, edit: add a new render mode for full-screen applications 817889d
+- test (`test-canvas`): fix dependency on `ext/contra` `#D1525` c89aa23
+- util: inherit special file descriptors `#D1552` 98835b5
+ - util: fix a bug that old tty is used in new sessions `#D1586` 0e55b8e
+- global: use `_ble_term_IFS` `#D1557` d23ad3c
+- global: work around `localvar_inherit` for varname-list init `#D1566` 5c2edfc
+- util: fix `ble/util/dense-array#fill-range` a46fdaf
+- util: fix leak variables `buff`, `trap`, `{x,y}{1,2}` `#D1572` 5967d6c
+- util: fix leak variables `#D1643` fcf634b
+- edit (`command-help`): use `ble/util/assign/.mktmp` to determine the temporary filename `#D1663` 1af0800
+- make: update lint check `#D1709` 7e26dcd
+- test: save the test log to a file `#D1735` d8e6ea7
+- benchmark: improve determination of the base time `#D1737` ad866c1
+
+## Contrib
+
+- prompt-git: detect staged changes `#D1718` 2b48e31
+- prompt-git: fix a bug that information is not updated on reload `#D1732` 361e9c5
+
+<!---------------------------------------------------------------------------->
+# ble-0.4.0-devel2
+
+2020-01-12 -- 2020-12-02 (`#D1215`...`#D1426`) c74abc5...276baf2
+
+## New features
+
+- complete: support `bleopt complete_auto_wordbreaks` (suggestion by dylankb) `#D1219` c294e31
+- main: check `~/.config/blesh/init.sh` `#D1224` a82f961
+- progcolor: support programmable highlighting `#D1218` 0770234 `#D1244` 9cb3583 `#D1245` 8e8a296 `#D1247` 154f638 `#D1269` fa0036c
+- decode/kbd: support <kbd>U+XXXX</kbd>, <kbd>@ESC</kbd> and <kbd>@NUL</kbd> for keynames `#D1251` 441117c ef23ad1
+- syntax: support `coproc` `#D1252` 7ff68d2
+- vi/nmap: support readline widgets for <kbd>M-left</kbd>, <kbd>M-right</kbd>, <kbd>C-delete</kbd>, <kbd>#</kbd> and <kbd>&</kbd> `#D1258` 846e0be
+- complete: add `compopt -o quote/default` for `fzf` (motivated by dylankb) `#D1275` 58e1be4
+- util (`ble-import`): support an option `-d` (`--delay`) `#D1285` 9673e4e
+- syntax: support parameter expansion of the form `${var/#pat}`, `${var/%pat}` `#D1286` e2f4809
+- edit: support `bleopt editor line_limit_{type,length} history_limit_length` `#D1295` 2f9a000
+- edit: support widgets `{vi,emacs}-editing-mode` `#D1301` 0c6c76e
+- syntax: allow unquoted `[!` and `[^` in `simple-word` (reported by cmplstofB) `#D1303` 1efe833
+- util (`ble/util/print-global-definitions`): support arrays and unset variables (test-util) 6e85f1c
+- util (`ble/util/cat`): support NUL and multiple files (test-util) d19a9af
+- edit: support Bash 5.1 `READLINE_MARK` and `PROMPT_COMMANDS` `#D1328` e97a858 `#D1338` 657bea5
+ - edit, main: support array PROMPT_COMMAND in bash-5.1 `#D1380` b852a4f
+- syntax: support confusing parameter expansions like `${#@}`, etc. `#D1330` b7b42eb
+- contrib: add contrib for user settings `#D1335` f290115
+- syntax: support `${var@UuLK}` in Bash 5.1 `#D1336` 04da4dd
+- main: add an option `--test` `#D1340` 1410c72
+- util (`ble/builtin/trap`): support `return` in `INT`/`EXIT`/`WINCH` `#D1347` `#D1348` 3865488
+- history: support timestamp (reported by rux616) `#D1351` 4bcbd71 `#D1356` 350bb15 `#D1364` 1d8adf9
+- edit: support Bash 4.4 `PS0` `#D1357` 23a1ac5
+- vi: support `bleopt keymap_vi_mode_{update_prompt,show,name_*}` (suggested by Dave-Elec) `#D1365` 76be6f1
+- prompt: support prompt sequence `\q{...}` `#D1365` 76be6f1
+- edit: support `bind 'set show-mode-in-prompt'` `#D1365` 76be6f1
+ - prompt: fix a bug that mode string is not shown in `auto_complete` and other sub-modes (reported by tigger04) `#D1371` f6fc7ff
+ - prompt: redraw prompts on the prompt content change (reported by tigger04) `#D1371` 1954a1e
+- prompt: support `bleopt prompt_{{ps1,rps1}{_final,_transient}}` (suggested by Dave-Elec) `#D1366` 06381c9
+ - prompt: fix a bug that prompt are always re-insntiated for every rendering `#D1374` 0770cda
+ - prompt: fix a bug that rprompt is not cleared when `bleopt prompt_rps1` is reset `#D1377` 1904b1d
+ - prompt: fix a bug that prompts updated by `PROMPT_COMMAND` are not reflected immediately (reported by 3ximus) `#D1426` bbda197
+- edit: support Bash 5.1 widgets `#D1368` e747ee3
+- color: support `TERM=*-direct` `#D1369` 0d38897 `#D1370` f7dc477
+- complete: support `bleopt complete_auto_menu` `#D1373` 77bfabd
+ - complete: fix a problem of frequent bells with auto-menu activated `#D1381` 3b1d8ac
+- complete: support `bleopt complete_menu_maxlines` `#D1375` 8e81cd7
+- prompt: support `_ble_prompt_update` `#D1376` 0fa8739
+- prompt: support `bleopt prompt_{xterm_title,screen_title,status_line}` `#D1378` 5c3f6fe
+ - prompt: check `TERM` for prompt window titles when `_ble_term_TERM` is unavailable `#D1388` 3c88869
+- syntax: support options `bleopt highlight_{syntax,filename,vartype}` to turn off highlighting (requested by pjmp) `#D1379` 0116f8b
+- complete: support `shopt progcomp_alias` `#D1397` d68afa5
+- complete: generate completions of options based on man pages `#D1405` 8183455
+ - complete (mandb): fix a bug that `bleopt complete_menu_style` is globally changed `#D1412` b91fd10
+- highlight: support colon separated lists of paths `#D1409` 2f40422
+ - highlight: fix a bug that non-simple words are always highlighted as `syntax_error` (reported by cmplstofB) `#D1411` 46e2ac6
+ - highlight: fix a bug that words are sometimes unhighlighted `#D1418` 4395484
+ - highlight: fix a bug that non-existent directories are not highlighted in the command name context `#D1419` 4395484
+- highlight: support options `#D1410` 2f40422
+ - highlight: support highlighting of `declare` command options `#D1420` f0df481
+ - highlight: fix unhighlighted tilde expansions `~+` (reported by cmplstofB) `#D1424` a32962e
+
+## Changes
+
+- highlight: highlight symlink directories as symlinks `#D1249` 25e8a72
+- auto-complete: bind `insert-on-end` to `C-e` `#D1250` 90b45eb
+- edit (`widget/shell-expand-line`): not quote expanded results by default `#D1255` a9b7810
+- decode: refactor
+ - decode: delay bind until keymap initialization `#D1258` 0beac33
+ - decode: read user settings from `bind -Xsp` `#D1259` eef14d0
+ - decode: fix a bug of `ble-bind` with uninitialized cmap `#D1260` 5d98210
+ - decode: fix error messages of BSD `sed` rejecting unencoded bytes from `bind -p` (reported by dylankb) `#D1277` 0cc9160
+- edit: provide proper `$BASH_COMMAND` and `$_` for PS1, PROMPT_COMMAND, PRECMD, etc. `#D1276` 7db48dc
+- edit (quoted-insert): insert literal key sequence `#D1291` 420c933
+- decode: support `decode_abort_char` for `modifyOtherKeys` `#D1293` ad98416
+- edit (edit-and-execute): disable highlighting of old command line content `#D1295` 2f9a000
+- util (`bleopt`): fail when a specified bleopt variable does not exist (test-util) 5966f22
+- builtin: let redefined builtins return 2 for `--help` `#D1323` 731896c
+- edit: preserve `PS1` when `internal_suppress_bash_output` is set `#D1344` 6ede0c7
+- complete: complete param expan in additional contexts `#D1358` 3683305
+- main: reload on ble-update when ble.sh is already updated `#D1359` a441d4d
+- main (`ble-update`): clone github repository if the original repository is not found `#D1363` 6e3b3b5
+- util (bleopt): change output format d4b12cd
+- syntax: allow `time -- command` for Bash 5.1 `#D1367` 00d0e93
+- menu: preserve columns with `{forward,backward}-line` `#D1396` 3d5a341
+- syntax: rename `ble_debug` to `bleopt syntax_debug` `#D1398` 3cda58b
+- syntax: change a style of buffer contents in `bleopt syntax_debug` `#D1399` 3cda58b
+- complete: change to generate filenames starting from `.` by default (motivated by cmplstofB) `#D1425` 987436d
+
+## Fix
+
+- util (ble/builtin/trap): fix argument analysis for the form `trap INT` (reported by dylankb) `#D1221` db8b0c2
+- main: fix an error message on ristricted shells `#D1220` b726225
+- edit: fix a bug that the shell hangs with `source ble.sh --noattach && ble-attach` (reported by dylankb) `#D1223` 59c1ce4 3031007
+- edit: fix a bug that the textarea state is not properly saved (reported by cmplstofB) `#D1227` 06ae2b1
+- syntax: support hexadecimal literals for arithmetic expression (reported by cmplstofB) `#D1228` 90e4f35
+- history: fix a bug that history append does not work with `set -C` (reported by cmplstofB) `#D1229` 604bb8b
+- decode (`ble/builtin/bind`): fix widget mapping for `default_keymap=safe` `#D1234` 750a9f5
+- main (ble-update): fix a bug that the check of `make` does not work in Bash 3.2 `#D1236` 08ced81
+- syntax: fix a infinite loop for variable assignments and parameter expansions `#D1239` 327661f
+- complete: clear menu on history move `#D1248` 06cc7de
+- syntax: fix a bug that arguments of `eval` are not highlighted `#D1254` 5046d14
+- decode: fix error message `command=${[key]-}` for mouse input `#D1263` 09bb274
+- [ble-0.3] reload: fix a bug that the state is broken by `ble-reload` `#D1266` f2f30d1
+- decode (`ble/builtin/bind`): remove comment from bind argument `#D1267` 880bb2c
+- decode: use `BRE` instead of `ERE` for `POSIX sed` (reported by dylankb) `#D1283` 2184739
+- decode: fix strange behaviors after `fzf` (convert <kbd>DEL</kbd> to <kbd>C-?</kbd>) `#D1281` 744c8e8
+- edit: work around Bash rebinding on `TERM` change `#D1287` ac7ab55 7a99bf3
+- term: work around terminfo/termcap entry collisions in `tput` (reported by killermoehre) `#D1289` f8c54ef
+- complete: clear menu on discard-line (reported by animecyc) `#D1290` fb794b3 `#D1315` 99880ef
+- vi (vi-command/nth-column): fix a bug in arithmetic expansion (reported by andychu) `#D1292` da6cc47
+- complete: fix a bug that insert-word does not for with ambiguous candidates `#D1295` 2f9a000
+- complete: fix a bug that menu-filter is only partially turned off by `complete_menu_filter` `#D1298` b3654e2
+- decode: fix error messages for unsupported readline functions `#D1301` 91bdb64
+- global: work around `shopt -s assoc_expand_once` `#D1305` 31908e1
+- global: work around `TMOUT` for `builtin read` `#D1306` 1c22a9d
+- syntax: fix failglob errors of heredocs of the form `<<$(echo A)` `#D1308` 3212fd2
+- decode (`ble-bind`): fix an error message `#D1311` c868b6d
+- util (`bleopt`): fix a bug that a new setting is not defined with `name:=` (test-util) `#D1312` c757b92
+- util (`ble/util/{save,restore}-vars`): fix a bug that `name` and `prefix` cannot be saved/restored (test-util) 5f2480c
+- util: fix `ble/is-{inttype,readonly,transformed}` (test-util) 485e1ac
+- util (`ble/path#remove{,-glob}`): fix corner cases (test-util) ccbc9f8
+- history: fix a problem that the history is doubled by `history -a` in `bashrc` `#D1314` 34821fe
+- util (`ble/variable#get-attr`): fix an error message with special variable names such as `?` and `*` `#D1321` 557b774
+- util (has-glob-pattern): fix abort in subshells (test-util) `#D1326` dc292a2
+- edit: fix a bug that `set +H` is cancelled on command execution `#D1332` 02bdf4e
+- syntax (`ble/syntax/parse/shift`): fix a bug of shift skip in nested words `#D1333` 65fbba0
+- global: work around Bash-4.4 `return` in trap handlers `#D1334` aa09d15
+- util (`ble-stackdump`): fix a shift of line numbers `#D1337` a14b72f d785b64
+- edit (`ble-bind -x`): check range of `READLINE_{POINT,MARK}` `#D1339` efe1e81
+- main: fix a bug that `~/.config/blesh/init.sh` is not detected (GitHub #53 by rux616) 61f9e10
+- util (`ble/string#to{upper,lower}`): work around `LC_COLLATE=en_US.utf8` (test-util) `#D1341` 1f6b44e `#D1355` 4da6103 5f0d49f
+- util (encoding, keyseq): fix miscelleneous encoding bugs (test-util) 435bd16
+ - `ble/util/c2keyseq`: work around bash ambiguous keyseq `\M-\C-\\`
+ - `ble/util/c2keyseq`: fix a bug that `C1` characters are not properly encoded
+ - `ble/util/keyseq2chars`: fix a bug that `\xHH` is not properly processed
+ - `ble/encoding:UTF-8/b2c`: work around Bash-4.2 arithmetic crash
+ - `ble/encoding:UTF-8/b2c`: fix a bug that `G0` characters lose its seventh bit
+ - `ble/encoding:UTF-8/c2b`: fix a bug that the first byte gets redundant bits
+- edit: work around `WINCH` not updating `COLUMNS`/`LINES` after `ble-reload` `#D1345` a190455
+- complete: initialize `bleopt complete_menu_style` options before `complete_load` hook (reported by rux616) `#D1352` 8a9a386
+- main: fix problems caused by multiple `source ble.sh` in bashrc `#D1354` 5476933
+- syntax: allow single-character variable name in named redirections `{a}<>` `#D1360` 4760409
+- complete: quote `#` and `~` at the beginning of word `#D1362` f62fe54
+- decode (`bind`): work around `shopt -s nocasematch` (reported by tigger04) `#D1372` 855cacf
+- syntax (tree-enumerate): fix unmodified `wtype` of reconstructed words at the end `#D1385` 98576c7
+- complete: fix a bug that progcomp retry by 124 caused the default completion again `#D1386` 98576c7
+- complete: fix bugs that quotation disappears on ambiguous completion `#D1387` 98576c7
+- complete: fix a bug of duplicated completions of filenames with spaces `#D1390` 98576c7
+- complete: fix superlinear performace of ambiguous matching globpat `#D1389` 71afaba
+- prompt: fix extra spaces on line folding before double width character `#D1400` d84bcd8
+- prompt: fix a bug that lonig rps1 is not correctly turned off `#D1401` d84bcd8
+- syntax (glob bracket expression): fix a bug of unsupported POSIX brackets `#D1402` 6fd9e22
+- syntax (`ble/syntax:bash/simple-word/evaluate-path-spec`): fix a bug of unrecognized `[!...]` and `[^...]` `#D1403` 0b842f5
+- complete (`cd`): fix duplicate candidates by `CDPATH` (reported by Lennart00 at `oh-my-bash`) `#D1415` 5777d7f
+- complete (`source:file`): fix a bug that tilde expansion candidates are always filtered out `#D1416` 5777d7f
+- complete: fix a problem of redundant unmatched ambiguous part with tilde expansions in the common prefix `#D1417` 5777d7f
+- highlight: fix remaininig highlighting of vanishing words `#D1421` `#D1422` 1066653
+- complete: fix a problem that the user setting `dotglob` is changed `#D1425` 987436d
+
+## Compatibility
+
+- main: work around cygwin uninitialized environment `#D1225` `#D1226` b9278bc
+- global: work around Bash 3.2 bug of array initialization with <kbd>SOH</kbd>/<kbd>DEL</kbd> `#D1238` defdbd4 `#D1241` 1720ec0
+- term: support `TERM=minix` `#D1262` ae0b80f
+- msys2: support2 MSYS (motivated by SUCHMOKUO) `#D1264` 47e2863
+ - edit: support `\$` in `PS1` for MSYS2 `#D1265` f6f8956
+ - msys2: work around MSYS2 Bash bug of missing <kbd>CR</kbd> `#D1270` 71f3498
+ - cygwin, msys2: support widget `paste-from-clipboard` `#D1271` cd26c65
+- msys1: support MSYS1 `#D1272` 630d659
+ - msys1: work around missing named pipes in MSYS1 `#D1273` 6f6c2e5
+- term: support contra `SPD` `#D1288` 1e65f2c
+- decode: work around Bash-4.1 bug that locale not applied with `LC_CTYPE=C eval command` (test-util) b2c7d1c
+- util (`ble/variable#get-attr`): fix a bug that attributes are not obtained in Bash <= 4.3 (test-util) b2c7d1c
+- decode: work around Bash-3.1 bug of `declare -f` rejecting special characters in function names (test-util) b2c7d1c
+- edit (`ble/widget/bracketed-paste`): fix error messages on `paste_end` in older version of Bash (test-util) b2c7d1c
+- decode: work around Bash-4.1 arithmetic bug of array subscripts evaluated in discarded branches `#D1320` 557b774
+- complete: follow Bash-5.1 change of arithmetic literal `10#` `#D1322` 557b774
+- decode: fix a bug of broken cmap cache found in ble-0.3 `#D1327` 16b56bf
+- util (strftime): fix a bug not working with `-v var` option in Bash <= 4.1 (test-util) f1a2818
+- complete: work around slow `compgen -c` in Cygwin `#D1329` 5327f5d
+- edit: work around problems with `mc` (reported by onelittlehope) `#D1392` e97aa07
+ - highlight: fix a problem that the attribute of the last character is applied till EOL `#D1393` 2ddb1ba `#D1395` ef09932
+
+## Internal changes and fixes
+
+- util: merge `ble/util/{save,restore}-{arrs => vars}` `#D1217` 6acb9a3
+- internal: merge subdir `test` into `memo` `#D1230` f0c38b6
+- ble-measure: improve calibration `DD1231` d3a7a52
+- vi_test: fix a bug that test fails to restore the original state `#D1232` 4b882fb
+- decode (ble/builtin/bind): skip checking stdin in parsing the keyseq `#D1235` 5f949e8
+- syntax: delay load of `ble/syntax/parse` for syntax highlighting `#D1237` bb31b11
+- memo: split `memo.txt` -> `note.txt`, `done.txt` and `ChangeLog.md` `#D1243` 31bc9aa 8b0fe34 419155e
+- global: check isolated identifiers and leak variables `#D1246` 19cc99d 2e74b6d
+- util: add `ble/function#{advice,push,pop}` to patch functions (motivated by dylankb) `#D1275` fbe531a
+- util (`ble/util/stackdump`): output to `stdout` instead of `stderr` `#D1279` 9d3c50d
+- complete (`ble-sabbrev`): delay initialization `#D1282` dfc4f66
+- test: update `lib/test-{core => util}.sh` (reported by andychu) `#D1294` e835b0d
+- edit: improve performance of bracketed-paste `#D1296` 0a45596 `#D1300` 3f33dab `#D1302` 5ee06c8 10ad274
+- decode: improve performance of `ble-decode-char` `#D1297` 0d9d867
+- ext: update `mwg_pp.awk` (for branch osh) 978ea32
+- test: add `lib/core-test.sh` `#D1309` 68f8077
+- global: do not use `local -i` `#D1310` f9f0f9b
+- global: normalize calls of builtins `#D1313` b3b06f7
+- test: refactor test `#D1316` `#D1317` 6c2f863
+- util (`ble/util/openat`): change to open unused fds `#D1318` 6c2f863
+- util: rename `ble/{util/openat => fd#alloc}` `#D1319` 6c2f863
+- util (`ble/function#advice remove`): restore original command 149a640
+- edit: rename `ble-edit/prompt/*` -> `ble/prompt/*` `#D1365` 76be6f1
+- main: use `PROMPT_COMMAND` in bash-5.1 for prompt attach `#D1380` b852a4f
+- main: unset `BLE_VERSION`, `_ble_bash`, etc. on `ble-unload` `#D1382` 6b615b6
+- util: revisit `ble/variable#is-global` implementation `#D1383` 6b5468f
+- cmap: recognize <kbd>SS3 O</kbd> as <kbd>blur</kbd> `#D1384` 445a5ad
+- edit (`ble/widget/{accept-line,newline}`): automatically switch widgets by the keymap `#D1391` 5bed6e6
+- complete: perform filter in `ble/complete/cand/yield` `#D1404` 7c6b67b 83fa830
+ - complete: fix a bug that `ble/cmdinfo/complete:cd` candidates are unfiltered (reported by cmplstofB) `#D1413` 5c17a31
+ - complete: fix unfiltered tilde expansions `#D1414` 5777d7f
+ - complete: fix candidate filter failure in dynamic sabbrev expansion (reported by darrSonik) `#D1423` dabc515
+- syntax, edit: use `type -a -t -- cmd` to get command types hidden by keywords `#D1406` ef2d912
+- edit, complete: replace some external commands with Bash builtin `#D1407` 5386e93
+
+<!---------------------------------------------------------------------------->
+# ble-0.4.0-devel1
+
+2019-03-21 -- 2020-01-12 (#D1015...#D1215) df4feaa...c74abc5
+
+## New features
+
+- emacs: support widgets `forward-byte` and `backward-byte` `#D1017` b2951ef
+- emacs: support arguments of word wise operations `#D1020` 719092c
+- emacs: support widgets `{capitalize,downcase,upcase}-xword` `#D1019` 719092c
+- emacs: support widgets `alias-expand-line` and `history-and-alias-expand-line` `#D1024` fdaf579
+- emacs: support keyboard macros `#D1028` 284668a
+ - decode: workaround recursive charlog/keylog `#D1030` ea421a3
+- complete: define `menu` keymap `#D1033` abfd060
+- emacs: support widgets `kill{,-graphical,-logical}-line` `#D1037` 3bb3d33
+- emacs: support a widget `re-read-init-file` `#D1038` ebe2928
+- emacs: support widgets `readline-dump-{functions,macros,variables}` `#D1039` 49256a9
+- emacs: support widgets `character-search-{for,back}ward` and `delete-forward-char-or-list` `#D1040` 2b20c88
+- emacs: support widgets `insert-comment` and `do-lowercase-version` `#D1041` 7aae37b
+- main: support options `--version` and `--help` `#D1042` b5ab789
+- main: read `.inputrc` as `ble.sh` settings `#D1042` b5ab789
+ - decode: fix a bug of error messages on reading `.inputrc` `#D1062` e163b9a
+- complete: support widget `menu-complete insert_braces` `#D1043` 3d29c8d
+ - complete (insert_braces): reimplement range contraction `#D1044` dc586da
+ - complete (insert_braces): remove empty quotations `#D1045` `#D1046` dc586da
+ - complete (insert_braces): fix support of replacement of existing part `#D1047` dc586da
+- complete: support `complete context=dynamic-history` `#D1048` 4f7b284
+- emacs: support a widget `edit-and-execute-command` `#D1050` ca5fe08
+- emacs: support widgets `insert-{last,nth}-argument` `#D1051` 24458be
+- complete: support `menu-complete backward` `#D1052` 2b0c7e8
+- emacs: `history-nsearch-{for,back}ward-again` `#D1053` 60dde2c
+- emacs: support widgets `tab-insert`, `tilde-expand` and `shell-expand-line` `#D1054` 156b76e
+- emacs: support a widget `transpose-{c,u,s,f,e}words` `#D1055` d72c2d4
+- emacs: support `bleopt decode_error_cseq_{abell,vbell,discard}` `#D1056` ab1b8b0
+ - decode: fix a bug that cmap cache update is not triggered for `#D1073` f1e7674
+- emacs: support a widget `universal-arg` `#D1057` 8b1dd07
+- emacs: support kill ring and a widget `yank-pop` `#D1059` 8c9b6e8
+- highlight: support job names by `auto_resume` `#D1065` ce46024
+- decode: add support for `S8C1T` key sequences `#D1083` 9b7939b
+- history: support `bleopt history_share` `#D1100` `#D1099` 305b89f `#D1193` 4838a46
+- history: support full multiline history `#D1120` 8cf17f7
+ - history: do not synchronize multiline resolution on "history -p" `#D1121` 9e56b7b
+ - history.mlfix: suppress errors on Bash 3 `#D1122` 4fe7a0c
+ - history: suppress error messages trying to kill background worker on reattach `#D1125` f045fec
+- highlight: support dirname colors with pathname expansion, failglob and command names `#D1134` edaf495
+- util: introduce `blehook` `#D1139` d1a78fb
+ - blehook: support `blehook PRECMD PREEXEC POSTEXEC CHPWD ADDHISTORY` `#D1142` bedc2ba
+ - blehook: add `blehook/eval-after-load` `#D1145` c1f7aa9
+ - blehook: fix a bug that the definition of specified hooks are not printed `#D1146` a4a7cbc
+- highlight: highlight word with the form of URL `#D1150` f48f2d7
+- syntax: support syntax/globpat in param expansions `#D1157` `#D1158` 051222e `#D1160` 57b42ba
+ - syntax: fix attr of nested extglob in param expansions `#D1159` 2d019f0
+- decode: support `ble-bind -T kspecs timeout` for timeout and `lib/vim-arpeggio.sh` (request by divramod) `#D1174` 272344e
+- complete: use `WORD*` pathname expansion for candidates on failglob with `WORD` `#D1177` c1b0532
+- edit: support `bleopt accept_line_threshold` `#D1178` a3385f6 82a1e0b
+- complete: support `bleopt complete_allow_reduction` `#D1181` 03040b7
+- edit: support `bleopt exec_errexit_mark` `#D1182` 6adc2df
+- color: support true colors `#D1184` bd631ce 5dd6b03
+- color (`ble-color-setface`): support reference to another face (reported by cmplstofB) `#D1188` 1885b54 `#D1206` 7e31ad3
+- edit: support `shopt -u promptvars` `#D1189` 269ba09
+- highlight: highlight variable names and numbers according to its state `#D1210` `#D1211` 93dab7b
+- highlight: support `${var@op}` (for bash 4.4) `#D1212` a85bdb8
+
+## Changes
+
+- edit: erase in page on `SIGWINCH` `#D1016` 7625ebe
+- edit: the widgets `{kill,copy,delete}-region-or` now receives widgets as arguments `#D1021` bbbd155
+- edit: disable aliases for builtins and keywords `#D1023` 61da093
+- edit: disable `rps1` in secondary textareas `#D1027` b86709a
+- edit: support `$?` in `PROMPT_COMMAND` and `PS1` evaluation `#D1074` 43f2967
+- main: change default attach strategy to `--attach=prompt` `#D1076` 197f752
+- main: change exit status of `ble-update` when it is already up to date `#D1081` d94f691
+- progcomp: improve treatment of `COMP_WORDBREAKS` `#D1094` f6740b5 `#D1098` 6c6bae5
+- history: replace builtin `history` `#D1101` 655d73e
+ - history: synchronize undo/mark/dirty data with history changes `#D1102` `#D1103` `#D1104` 5367360
+ - history: improve performance of `history -r` `#D1105` `#D1106` f204bc7
+ - history: fix a problem that history file is doubled with `history -cr` in `PROMPT_COMMAND` `#D1110` e64edb7
+ - history: suppress errors on new history file `#D1111` e64edb7 `#D1113` 91f07b6
+ - history: fix a problem that `_ble_edit_history` is not synchronized with `history -r` `#D1112` e64edb7
+ - history: do not process `_ble_edit_history` in detached state `#D1115` bf3b014
+ - history: move history item on delete of current item with `history -d` `#D1114` bf3b014
+ - history: fix a problem that history before load of ble.sh is lost `#D1126` 37cd154
+ - history: fix problems of history output after `ble-reload` `#D1129` 9c8d858
+- history: improve performance of `erasedups` `#D1107` 518e2ee
+- history: correctly handle `HISTSIZE` overflow `#D1108` 7be255c
+- sabbrev: support sabbrev expansion in wider contexts (reported by cmplstofB) `#D1117` ca6e03d
+- main: change loading point of `.inputrc` `#D1127` af758e5
+- highlight: do not split command names with `:` and `=` `#D1133` 8a1bd8f
+- decode: support DA1 responses sent by some terminals (reported by miba072) `#D1135` 362ab05
+- highlight: make brace expansions active for RHS of variable-assignment-form arguments `#D1138` 93cc8da
+- main: adjust readline variables for `ble.sh` `#D1148` 36312f7
+- edit: update prompt after execution of command through `ble-bind` `#D1151` 27208ea
+- blehook: replace builtin `trap` `#D1152` d6c555e 7d4fd03
+ - blehook: suppress extra `DEBUG` trap calls `#D1155` 25c3e19
+- syntax: allow `},fi,done,esac,then,...` after subshell `()` `#D1165` fdb49f3
+- edit: support options `--help` for `read` and `exit` `#D1173` faccc6b
+- color (`ble-color-{set,def}face`): list faces without arguments `#D1180` 50327c3
+- complete: search completion settings through alias expansion `#D1187` c472809
+- history (`ble/builtin/history`): support an option `--help` `#D1192` d4c26c5
+
+## Fixes
+
+- decode: workaround Poderosa that returns `DSR` instead of `CPR` in reply to `DSR(6)` `#D1018` 8e22c17
+- isearch: fix a bug to match with the old content of the current line `#D1025` 605dcd0
+- vi: fix a bug that quoted-insert is not properly recorded with `qx...q` `#D1026` 06698a4
+- decode: fix a bug that chars from nested widgets are not processed immediately `#D1028` c79d89b
+- menu: fix a bug that fails to retrieve menu item description `#D1031` c936db8
+- menu: fix a bug that menu item color is disabled `#D1032` c936db8
+- vbell: fix a bug that persistent vbell is not erased before next vbell `#D1034` a3af6c0
+- menu-complete: fix a bug that candidates from menu only contained visible ones `#D1036` 275779f
+- menu-complete: fix a bug that original texts were lost on cancel `#D1049` 3bbfef6
+- edit: fix a bug that rendering is caused twice `#D1053` c7599a2
+- color (layer:region): fix a bug that highlighting is cleared without dirty ranges `#D1053` 23796bc
+- edit (nsearch): fix a bug that the search range is narrowed after fail `#D1053` 3b2237e
+- edit (nsearch): fix a bug of messages on search fail `#D1053` 3b2237e
+- util: fix a bug that SGR of visible-bell remains 799f6d3
+- decode: fix a bug of infinite loops on `ble-reload` `#D1077` 0f01bcf `#D1079` fee22b1
+- decode: workaround a bash-5.0 bug of `bind -p` `#D1078` b52da28
+- complete: workaround slow command candidates generation in Cygwin `#D1080` 376bfe7
+- syntax: fix false error highlighting of commands after `}`, `fi`, `done` or `esac` `#D1082` 4ce2753
+- decode: fix a bug that modifyOtherKeys did not work at all 1666ec2
+- edit: fix a problem that status line vanishes on window resize `#D1085` 467b7a4
+ - edit: recalculate prompts after resize `#D1088` b29f248
+ - edit: fix the position of cursor after resize `#D1089` b29f248
+- decode: fix a bug that `ble-update` breaks keymap cache `#D1086` ab8dad2
+- edit (`ble/builtin/read`): suppress noisy job messages and delay caused by vbell `#D1087` 309b9e4
+- edit (`ble/builtin/read`): workaround failglob crash on vbell inside `read` `#D1090` 2e6f44c
+- edit: workaround a bash bug that history entries are removed by `history -p` `#D1091` 146f9e7
+- edit (self-insert): workaround Bash-3.0 bug that ^? cannot be handled properly `#D1093` e09c7b5
+- highlight: fix a bug that quoted tilde expansions are processed for filename highlighting `#D1095` 3f1f472
+- menu-complete: fix a bug that word is expanded on cancel `#D1097` 001b914
+- highlight: fix a problem that empty arguments are highlighted as errors `#D1116` 64ae8ce
+- sabbrev: fix a bug that menu-filter is not canceled on some sabbrev expansion `#D1118` 30cc31c
+- main: fix a bug that `source ble.sh --noattach` in `ble.sh` sessions hangs `#D1130` d35682a caa46c2 `#D1199`
+- syntax: workaround bashbug 3.1/3.2 that `eval` ending with <kbd>\ + LF</kbd> causes error messages `#D1132` a4b7e00
+- term: workaround `cygwin` console glitches `#D1143` b79c35f `#D1144` ef19d17
+- main: fix a bug that error messages for unsupported shells are not printed `#D1149` 34bd6f8
+- main: workaround `set -ex` `#D1153` 06ebf9f
+- main: workaround shell variable `FUNCNEST` `#D1154` fa2aa47
+- highlight: fix error messages on the command line `a=[` `#D1156` b159ea2
+- util: fix a bug of "ble/builtin/trap" not recognizing "-" `#D1161` 11fddba
+- init-bind: workaround a bash-5.0 bug that `bind '"\C-\\": ...'` does not work `#D1162` 80edf44
+- init-bind: do not use workaround of `C-x` in vi mode `#D1163` e6a3d33
+- vi_test: fix test for the macro playing `#D1164` 636517c
+- exec: fix a problem that the shell hangs with failglob in pipe `#D1166` ac8ba6e
+- complete: fix a problem of delay with path `//` in Cygwin `#D1168` 2cf8cc7
+- prompt: fix the expansion of `\w` and `\W` in `PS1` for working directories with double slashes `#D1169` d1288dd
+- exec: workaround termination of command execution on syntax error in array subscripts `#D1170` 4f442d0
+- history: fix a bug that garbage `__ble_edt__` is added in front of history entries 61f4bd1
+- decode: remove debug messages for `ble-bind -s` 64a17c3
+- syntax: fix highlighting of `${!var@}` `#D1176` 161ed80
+- term: fix `Ss` (`DECSCUSR`) 0c773da
+- term: workaround linux console <kbd>CSI \></kbd>, <kbd>CSI M</kbd>, <kbd>CSI L</kbd> `#D1213` `#D1214` 0ec6f0c
+- edit: fix exit status of Bash by key binding <kbd>C-d</kbd> `#D1215` a9756e9
+
+## Support macOS, FreeBSD, Arch Linux, Solaris, Haiku, Minix
+
+- util: fix the error message "usage: sleep seconds" on macOS bash 3.2 `#D1194` (reported by dylankb) 6ff4d2b
+- decode: recover the terminal states after failing the default keymap initialization `#D1195` (reported by dylankb) 846f284
+- main (`ble-update`): use shallow clone `#D1196` 2a20d9c
+- main (`$_ble_base_cache`): use different directories for different ble versions `#D1197` 55951d1
+- edit (`ble/builtin/read`): fix argument analysis with user-provided `IFS` in Bash 3.2 (reported by dylankb) `#D1198` 7411f06
+- global: fix subshell detection in Bash 3.2 `#D1200` ca8df8a
+- syntax: workaround Bash-4.1 arithmetic bug `#D1201` f248c52
+- Makefile: fix "install" for BSD sed `#D1202` 32c2e1a
+- term: support "tput" based on termcap `#D1203` `#D1204` 161af07
+- global: adjust for FreeBSD and Arch Linux `#D1205` 6ac5b8c
+- global: workaround Solaris awk `#D1207` 74d438d
+- util: support Haiku `#D1208` e3de373
+ - ble/util/msleep: do not use `read -t time` for Haiku
+ - ble/term/stty: check available character settings
+ - init-cmap: check termcap settings for <kbd>home</kbd>
+- util: support Minix `#D1209` 49e6457
+ - ble/util/msleep: do not use `read -t time -u FD` in Minix
+ - ble-edit/prompt: does not abbreviate IPv4 address for `\h`
+ - Makefile: create directory `dist` for `make dist`
+
+## Internal changes
+
+- complete: isolate menu related codes `#D1029` 43bb074
+- global: use `builtin echo` explicitly `#D1035` a6232c2
+- decode: re-implement rlfunc2widget without fork `#D1063` d2e7dbe
+- blerc: add descriptions `#D1064` d61b6af
+- decode: decode mouse events `#D1084` 51fae67
+- history: move history related codes to `src/history.sh` `#D1119` 1bfc8eb e5b1980
+ - history: move codes related to history prefixes and history searches to `history.sh` `#D1136` 1cda6ff 20024d2
+ - history: use common "_ble_history_onleave" for different histories `#D1137` ec19d51
+- keymap/vi: deal with textarea local data properly `#D1123` 2ea7cfd
+- edit: remove `ble-edit/exec:exec` `#D1131` 0cb9c6d
+- global: distinguish exit status 147 and 148 `#D1141` d1a78fb
+- global: follow bash syntactic changes on arithmetic command 16e0f0e
+- decode: check `bind -X` first to store the original bindings `#D1179` 4057ff0
+- complete: resolve collision of flag chars with `shopt -s nocaseglob` `#D1186` 550fb14
+- color: change return variable of `ble/color/{,i}face2{g,sgr}` to `ret` `#D1188` 1885b54
+- global: workaround `shopt -s xpg_echo` `#D1191` e46f9a3
+
+<!---------------------------------------------------------------------------->
+# 2019-03-21
+
+2019-02-09..2019-03-21 (#D0915...#D1015) 949e9a8...df4feaa
+
+## New features
+
+- auto-complete: support <kbd>end</kbd> at the end of line a374635
+- decode: replace builtin `bind` for `ble.sh` settings `#D0915` 90ca3be `#D0918` e0cdd15
+ - decode: update mapping of rl-functions and widgets for vi_imap and vi_nmap `#D1012` 7fec4b6
+ - decode: support `bind [-psPSX] [-quf arg]` `#D1013` 9265f8a
+- edit: support <kbd>C-x C-g</kbd>, <kbd>C-M-g</kbd> for `bell` and `cancel` `#D0919` 2e83120
+- syntax: support `set +B` `#D0931` 12f80dd
+- syntax: support aliased keywords `#D0936` 7054e28
+- complete: support `ble-sabbrev -m key=function` `#D0942` bcdf843
+- complete: support description of candidates `#D0945` `#D0946` 0fa73bf `#D0977` 96fe498
+ - canvas: use ... instead of … when unicode is not available `#D0979` 51e600a
+ - canvas (`ble/canvas/trace`): support `opts=truncate:confine` `#D0981` 79916d2
+- complete: support insertion of ambiguous common part `#D0947` 3644a8e
+- complete: support three levels of ambiguous matching `#D0948` 3644a8e
+- complete: support menu item highlight of ambiguous matching `#D0949` 3644a8e
+- complete: support menu pages `#D0958` ff43e01 a488e01 `#D0990` 32aeef0
+ - menu-complete: show page numbers with `visible-bell` `#D0980` 6297e65
+ - menu-complete: fix a bug that height of `menu` is too large (<= bash-4.1) `#D0983` 129a1f0
+- edit: support `bleopt rps1=` for the right prompt `#D0959` 90a8915 `#D0964` fa2a874 `#D0970` 87c8348
+ - rps1: fix coordinate calculations for rps1 `#D0982` 129a1f0
+ - canvas (`ble/canvas/trace`): fix a bug that `measure-bbox` does not work (<= bash-3.1) `#D0988` 7f880de
+ - canvas (`ble/canvas/trace`): fix a bug that `x1` and `y1` is not properly updated `#D0988` 7f880de
+ - edit: support `bleopt rps1_transient` `#D0993` 44edd38
+ - edit: fix a bug that `rps1` is cleared on execution of the command `#D1003` 5780154
+ - edit: erase trailing spaces after newlines when `rps1_transient` is enabled `#D1004` 5780154
+ - edit: support multiline `rps1` (Note: still restricted to fit in lines of `PS1`) `#D1005` 5780154
+- complete: support "bleopt complete_menu_style=desc-raw" `#D0965` 1fd7a3e
+- complete: support <kbd>prior</kbd>, <kbd>next</kbd>, <kbd>home</kbd>, <kbd>end</kbd> in `menu_complete` keymap `#D0966` b729d23
+- edit: support `bleopt prompt_eol_mark=$'\e[94m[ble: EOF]\e[m'` `#D0968` 6c8b52a
+- complete: highlight active ranges of `menu-filter` `#D0969` 500f702 `#D0971` aae8b26
+ - menu-filter: cancel `menu-filter` when the word ends `#D0974` 6ce2ad2
+ - menu-filter: improve highlight `#D0975` b89f39f
+- isearch: show progress bar using unicode chars `#D0978` 51e600a
+- main: support `ble-reload` ef51490
+- complete: support `source:sabbrev` `#D0994` 5c9e579
+- complete: clear menu on <kbd>C-g</kbd> `#D0995` e0f93a2
+- vi_imap: support `bleopt keymap_vi_imap_undo=more` `#D0996` 50f8ad2
+- util: support `bleopt vbell_align` and `ble-color-setface vbell{,_flash,_erase}` for vbell `#D0997` 325883e
+ - vbell: fix a bug that garbages remain on short messages just after longer messages `#D1010` 3e9ff85
+- decode: support "bleopt decode_abort_char=28" `#D0998` b110cb9
+- complete: support `visible-stats` and `mark-directories` `#D1006` b389b3b
+- complete: support `mark-symlinked-directories`, `match-hidden-files` and `menu-complete-display-prefix` `#D1007` fd66194
+- canvas: support `bleopt char_width_mode=auto` `#D1011` 3978df3
+
+## Changes
+
+- prompt: support correct handling of escapes `#D0923` 22f9b56
+- util (`ble/util/sleep`): adjust delay `#D0934` `#D0935` 5fd5cd6 ad1208b 188cd98
+- complete: use candidates in menu if present `#D0939` 52eaf01
+ - complete: fix a bug that menu-complete is disabled after `menu-filter` `#D0951` 08cba07
+ - complete: fix a bug that wrong action is performed after `menu-filter` `#D0952` 08cba07
+ - complete: fix a bug that extra <kbd>TAB</kbd> is needed to enter `menu-complete` `#D0956` aa6bd73
+ - complete: fix a bug that candidates are not regenerated on function name completions `#D0961` bbea72e
+ - complete: fix a problem that the menu style is reset on `menu-complete` `#D0972` 47c28ff
+ - menu-filter: explicitly call `ble/complete/menu-filter` (<= bash-3.2) `#D0986` 1b14b11
+- syntax: allow variable assignment in arguments of `eval` `#D0941` 2f2f0eb
+- highlight: do not highlight overwrite modes when mark is active `#D0950` 4efe1a9
+ - highlight: disable `layer:menu_filter` (<= bash-3.2) `#D0987` 1b14b11
+- complete: disable `auto-complete` inside the active range of `menu-filter` `#D0957`
+- util (visible-bell): truncate long messages to fit into a line `#D0973` e55ff86
+- edit: render prompt immediately on newline `#D0991` cdb8acb `#D1003` 5780154
+- syntax: detect syntax errors of `CTX_CMDX1` immediately followed by terminating keywords `#D1001` 7ea02b7
+- complete: improve support of `bind 'completion-ignore-case on'` `#D1002` 25ebc55
+- complete: preserve original path specifications on ambiguous completion `#D1014` a39d1ac
+- complete: append `,` instead of ` ` after completion in brace expansions `#D1015` df4feaa
+
+## Fixes
+
+- main: workaround `set -evx` `#D0930` 698517d
+- edit (widget `delete-horizontal-space`): fix a bug that spaces before the cursor is not removed `#D0932` 9290adb
+- bleopt: fix a bug that false error messages are output on reload when `failglob` is set `#D0933` 64cdcba c62db26
+- decode: fix a bug that <kbd>\\</kbd> cannot be input after reattach `#D0937` a46ada0
+- reload: fix a bug that `PS1` is lost on reload with `--attach=prompt` `#D0938` 1107ca8
+- main (`--attach=prompt`): workaround rewrite of `PROMPT_COMMAND` `#D0940` 863fd7b
+- vi_nmap (`/`, `?`, `n`, `N`): fix search progress `#D0944` f20f840
+- complete: fix a problem of slow ambiguous filename matching in nested directories `#D0960` 7b3ee55
+- util: improve performance of `ble/{util/{mapfile,assign-array},string#split-lines}` (<= bash-3.2) `#D0985` ae176b2 `#D0989` 36b9a8f f199215
+- sabbrev: fix a bug that sabbrev is disabled (<= bash-3.2) `#D0985` 840af29
+- util (ble/util/msleep): suppress warnings from `usleep` `#D0984` 8e4180c
+- util: fix a problem that <kbd>C-d</kbd> cannot be input in nested Bash 3.1 `#D0992` 88a1b0f
+- edit: fix a bug of a redundant newline on `read -e` `#D0999` 700bc91
+
+## Internal changes
+
+- [refactor] info: rename info type `raw` -> `esc` `#D0954` ac86f10
+- [refactor] do not use brace expansions for `VARNAMES` `#D0955` 711e7df
+- [refactor] `ble-{highlight,complete,syntax}` -> `ble/*` 7aaa660 ae6be66 8ea903c
+- [refactor] `ble-edit/info/.construct-text` -> `ble/canvas/trace-text` `#D0973` e55ff86
+- rename `ble/complete/action:*/getg` -> `ble/complete/action:*/init-menu-item` `#D1006` b389b3b
+
+<!---------------------------------------------------------------------------->
+# 2019-02-09
+
+2018-10-05 -- 2019-02-09 (#D0858..#D0914) 6ed51e7..949e9a8
+
+## New features
+
+- color (`ble-color-setface`): support various spec such as SGR params `#D0860` 82fe96d `#D0861` 257c16d `#D0864` 2eaf2a9
+- syntax: `bleopt filename_ls_colors` に対応 `#D0862` c7ff302 `#D0863` 3c5bacf ec31aab
+- vi_omap: support <kbd>v</kbd>, <kbd>V</kbd>, <kbd>C-v</kbd> `#D0865` 54942e0 `#D0866` a9a1638 `#D0867` d3d8ea3 `#D0868` eb848dc
+- main: improve support of `[[ -o posix ]]` `#D0871` 07ae3cc `#D0872` 513c543
+- main: do not load ble.sh when bash is started by `bash -i -c command` `#D0873` fc23a6d
+- main: support `ble-update` `#D0874` fc45be6 `#D0875` 0b50974 `#D0891` d010300 `#D0910` 4743c00 2dc3a3f
+- vi_nmap: support <kbd>C-d</kbd>, <kbd>C-u</kbd>, <kbd>C-e</kbd>, <kbd>C-y</kbd>, <kbd>C-f</kbd>, <kbd>next</kbd>, <kbd>C-b</kbd>, <kbd>prior</kbd> `#D0886`
+- isearch: use previous needle for empty string search `#D0889` 362fce3
+- vi_imap: add a function `ble-decode/keymap:vi_imap/define-meta-bindings` `#D0892` a21d22f
+- progcomp: support `complete -I` for Bash 5.0 `#D0895` `#D0896`
+- progcomp: support candidates which replace the original text before the cursor `#D0897` 41b8cbb
+- progcomp: support `compopt -o nosort|noquote|plusdirs` `#D0898` cc48539
+- edit: support <kbd>M-*</kbd> `#D0899` 3fd7d6e
+- edit: support <kbd>M-g</kbd>, <kbd>C-x *</kbd>, <kbd>C-x g</kbd> `#D0902` 41797c6
+- progcomp: support `COMP_WORDBREAKS` `#D0903` 7cfe425
+- complete: support completion of tilde expansion `#D0907` b4fc40c `#D0908` 9fafdb3
+- main: support `BLE_VERSION` and `BLE_VERSINFO` (suggested by cmplstofB) `#D0909`
+- global: support `--help` for public functions `ble-*` (suggested by cmplstofB) `#D0911` 77d459d f4d03f6 1d191c7 1209ac6 `#D0913` 92d9038
+
+## Changes
+
+- edit: change cursor position after <kbd>u</kbd> `#D0877` 9d5c945
+- edit: handle panel layouts `#D0878`--`D0882` 6a26894 `#D0888` c8e0d28
+- vi_nmap: support <kbd>z z</kbd>, <kbd>z t</kbd>, <kbd>z b</kbd>, <kbd>z .</kbd>, <kbd>z RET</kbd>, <kbd>z C-m</kbd>, <kbd>z +</kbd>, <kbd>z -</kbd> `#D0886`
+- emacs: change M-m M-S-m from `beginning-of-line` to `non-space-beginning-of-line` f77f1aa
+- bleopt: rename internal settings to `internal_{ignore_trap,suppress_bash_output,exec_type,stackdump_enabled}` fd042d8
+- vi_nmap: change the behavior of <kbd>C-home</kbd>, <kbd>C-end</kbd> to match with those of vim 8682f98
+- util (`ble/util/unlocal`): add workaround for Bash-5.0 `localvar_unset` `#D0904` 8677a71
+- sabbrev: quote key in printing definitions by `ble-sabbrev` `#D0912` 2994d80
+
+### Fixes
+
+- info: fix a bug that coordinates calculation breaks with Japanese text `#D0858` 67c77dc
+- syntax (`extract-command`): fix a bug that extraction of nested commands always fails `#D0859` c3270f6
+- complete: fix a bug that the settings `complete -c` does not work `#D0870` 1ca5386 82bb154
+- main: fix a bug that the determination of `_ble_base` fails when loaded as `source ble.sh` without specifying the directory of `ble.sh` 201deae
+- util: `ble/util/assign` が正しい戻り値を返さないバグの修正 bd14982
+- util: `ble/util/assign-array` の入れ子の呼び出しで内容が混ざり合う問題の修正 bd14982
+- progcomp: fix a bug that bash-completion does not work properly due to wrong `COMP_POINT` `#D0897` 41b8cbb
+- global: fix leak variables `#D0900` 244f965 `#D0906` b8dcbfe 9892d63
+- progcomp: fix a problem that completion functions can consume stdin `#D0903` 7cfe425
+
+## Internal changes
+
+- global: properly quote rhs of `[[ lhs == rhs ]]` f1c56ab
+- syntax: rename variables `BLE_{ATTR,CTX,SYNTAX}_*` -> `_ble_{attr,ctx,syntax}_*` 1fbcd8b (ref #D0909)
+
+<!---------------------------------------------------------------------------->
+# 2018-10-05
+
+2018-09-24 -- 2018-10-05 (#D0825..#D0857 6ed51e7)
+
+## 新機能
+ - highlight: 変数代入の右辺及び配列要素の着色に対応 `#D0839` 854c3b4
+ - nsearch: (非インクリメンタル)履歴検索に対応 <kbd>C-x {C-,}{p,n}</kbd> `history-{,substring-,n}search-{for,back}ward` `#D0843` e3b7d8b 0d31cd9 253b52e
+ - isearch: 検索前に選択状態でがあれば検索後に復元する `#D0845` 93f3a0f
+ - decode: 貼り付け時など大量の入力があった時に処理の進行状況を表示 `#D0848` c2d6100
+ - decode: 貼り付け時などの高速化の為に一括の文字列挿入に対応 (`batch-insert`) `#D0849` 48eeb03
+ - decode: `bleopt decode_isolated_esc=auto` でキーマップに応じて単独 <kbd>ESC</kbd> の取扱を切り替え `#D0852` 9b20b45 edd481c
+ - complete: `bleopt complete_{auto_complete,menu_filter}=` で自動補完・候補絞り込みの無効化に対応 `#D0852` 4425d12
+ - vi: テキストオブジェクト単語の再実装 (reported by cmplstofB) `#D0855` 9f2a973 ad308ae 3a5c456 6ebcb35
+ - vi: オペレータ `d` の特殊ルールに対応 `#D0855` fa0d3d3
+
+## バグ・問題修正
+ - decode: `ble-bind -d` に於いて `-c` 及び `-x` の引数の引用符が二重になっている問題の修正 `#D0850`
+ - auto-complete: 構文エラーが自動補完により解決される時 <kbd>RET</kbd> でコマンド実行が抑止されない問題の修正 `#D0827` daf360e
+ - highlight: `shopt -s failglob` で配列の指示初期化子がエラー着色される問題の修正 (reported by cmplstofB) `#D0838` d6fe413
+ - complete: プログラム補完に対して曖昧補完が効かない時の対策 `#D0841` 713e95d
+ - isearch: ユーザ入力による割り込みで検索位置の記録に失敗していたバグの修正 `#D0843`
+ - isearch: キャンセル時に位置とマークが正確に復元されない問題の修正 `#D0847`
+ - isearch, dabbrev: 検索処理中にユーザが何か入力するまで現在行が更新されない問題の修正 `#D0847`
+ - decode: 未ロードのキーマップに対して `ble-bind -m -P` `ble-bind -m kmap -f kspecs -` が使えない問題の修正 66e202a
+ - auto-complete: <kbd>C-j</kbd> が単なる "確定" になっていたのを "確定して実行" に修正 `#D0852` 01476a7
+ - edit: <kbd>M-S-f</kbd>, <kbd>M-S-b</kbd> を束縛するべきところ <kbd>M-C-f</kbd>, <kbd>M-C-b</kbd> を束縛している箇所を修正 `#D0852` c68e7d7
+ - color: Bash 3.0 で算術式内の `<()` がプロセス置換と解釈される問題の対策 `#D0853` 520184d
+ - syntax: コメント上の単語が何故か除去されないバグの修正 (reported by cmplstofB) `#D0854` 641583f
+ - vi: Bash 3.1 及び 3.2 で <kbd>C-d</kbd> 受信の為のリダイレクトに失敗する問題の修正 `#D0857` d4b39b3
+
+## 動作変更
+ - sabbrev, vi_imap: `sabbrev-expand` を <kbd>C-x '</kbd> ではなく <kbd>C-]</kbd> から束縛 `#D0825` e5969b7
+ - core: `bleopt` に設定名を指定子て設定内容を表示させる時、設定名の存在を確認する `#D0850` 725d09c
+ - isearch: <kbd>C-d</kbd> で現在の選択範囲を削除する様に変更 `#D0826` c3bb69e `#D0852` db28f74
+ - isearch: <kbd>C-m</kbd> (<kbd>RET</kbd>) で確定した時は選択範囲を解除する様に変更 `#D0826` c3bb69e
+ - decode: `ble-bind` のオプションを再構成 `#D0850` f7f1ec8 64ad962
+ - decode: 組み込みコマンド `bind` を上書きして `ble.sh` の動作が阻害されない様に引数をチェックして実行 `#D0850`
+ - complete: autoload `ble-sabbrev` (`core-complete.sh`), `ble-syntax:bash/is-complete` (`core-syntax.sh`) `#D0842` df0b769
+ - isearch: 編集関数 `isearch/accept-line` が <kbd>RET</kbd> 以外から束縛されていても <kbd>RET</kbd> を実行する様に変更 `#D0843`
+ - vi, [in]search: mark 名を整理 (`char`/`line`/`block`/`search` に接頭辞 `vi_` 付加し、新しい mark 名を `search` とする) `#D0843`
+ - edit: 関数名変更 `ble/widget/accept-single-line-or/accepts` → `ble-edit/is-single-complete-line` `#D0844`
+ - isearch: 空文字列で検索した時の振る舞いを再考 `#D0847` d05705e
+ - decode: 入力のキー復号の各種調整 `#D0850` dc013ad
+ - dabbrev: <kbd>C-m</kbd>, <kbd>RET</kbd> で展開終了、<kbd>C-j</kbd>, <kbd>C-RET</kbd> でコマンド実行 `#D0852` 01476a7
+
+## 内部的変更
+ - isearch, dabbrev: `ble/util/fiberchain` による再実装 `#D0843`, `#D0846` 2c695cf bdf8072 95268c1
+ - edit, vi: 選択範囲の種類を表す mark 名を整理 a1a6272
+ - edit: 関数名変更 `ble/widget/accept-single-line-or/accepts` → `ble-edit/is-single-complete-line` `#D0844` 63ec9fe
+ - refactor: ファイルの整理 5e07e7f 1a03da2 673bd1d 55c4224 9ce944c 9a47c57 25487a7 5679ffc b7291a7
+ - refactor: 関数名・変数名の整理 `#D0851` d1b780c 9129c47 4d1181a
+
+<!---------------------------------------------------------------------------->
+# 2018-09-23
+
+2018-09-03 -- 2018-09-23 (#D0766..#D0824 8584e82)
+
+### 補完: 新機能
+ - complete: 自動補完において履歴からの検索に対応 `#D0766`, `#D0769` `#D0784` (fix)
+ - complete: 自動補完時の <kbd>M-f</kbd> <kbd>C-f</kbd> 等に対応 `#D0767`
+ - complete: `"$hello"` などの引用符中のパラメータ展開がある場合でも補完に対応 `#D0768`
+ - complete: 配列要素代入の右辺での補完に対応 `#D0773`
+ - complete: ブレース展開の途中での補完に対応 `#D0774`
+ - auto-complete: `ble/widget/auto_complete/accept-and-execute` 対応 `#D0811`
+ - complete: 補完関係の設定をする為の load hook の追加 `#D0812`
+ - complete: 種類を指定した補完に対応 `#D0820` `#D0819` (fix)
+ - complete: 静的略語展開に対応 (`ble-sabbrev key=value` で設定) `#D0820`
+ - complete: 動的略語展開に対応 `#D0820`
+
+## 補完: バグ・問題点修正
+ - complete: 一意確定した直後の補完ですぐにメニュー補完に入るバグの修正 `#D0771`
+ - complete: `function fun [` 直後の補完で `[\[` が挿入される問題の修正 `#D0772`
+ - complete: 曖昧補完で補完を実行しようとすると入力済みの部分が削除されるバグの修正 `#D0775`
+ - complete: 自動補完が起動しなくなっているバグの修正 `#D0776`
+ - complete: プログラム補完関数が `failglob` で失敗するとシェルが終了する問題の対策 (reported by cmplstofB) `#D0781`
+ - complete: `failglob` の時コマンド補完候補に `*` が含まれてしまう問題の修正 (reported by cmplstofB) `#D0783`
+ - complete: 候補一覧にて入力済み範囲の強調が絞り込みにより無効化されるバグの修正 `#D0790`
+ - complete: 自動補完を抜けた後のマーク位置が誤っているバグの修正 `#D0798`
+ - complete: `for a in @` や `do @` の位置の補完でエラーメッセージが表示されるバグの修正 `#D0810`
+
+## 補完: 動作変更
+ - complete: 入力済み部分の評価方法の内部変更 `#D0777`
+ - complete: 自動補完の着色の変更 `#D0780` `#D0792`
+ - complete: プログラム補完で提供するコマンドライン (`COMP_*`) にて、補完開始点に単語の切れ目を入れる様に変更 `#D0793`
+ - auto-complete: <kbd>C-RET</kbd> で補完を確定してコマンド実行 `#D0822`
+
+## 他: 新機能
+ - edit: `IGNOREEOF` に対応 `#D0787`
+ - edit: コマンド `exit` にて、ジョブが残っている場合はユーザに尋ねて終了 `#D0789`, `#D0805` (bugfix)
+ - term: 256色対応のない端末での減色の実装 `#D0824`
+
+## 他: バグ・問題点修正
+ - isearch: 非同期検索ができなくなっていたバグの修正
+ - color: `ble-color-setface` の遅延初期化順序のバグを修正 (reported by cmplstofB) `#D0779`
+ - decode: CentOS 7 で `LC_ALL=C.UTF-8` に対してエラーメッセージが出る問題の対策 `#D0785`
+ - edit: ジョブがある時の終了 <kbd>C-d</kbd> について `bleopt allow_exit_with_jobs` 対応 (request by cmplstofB) `#D0786`
+ - edit: Bash 3.* で <kbd>C-d</kbd> によるプログラム実行 (`ble-edit/exec:gexec`) が遅延するバグの修正
+ - syntax: Bash 3.2--4.1 の算術式バグによる関数定義の構文解析に失敗する問題の対策 `#D0788`
+ - highlight: `region` レイヤーの着色範囲が改行を跨ぐ場合に既定の着色になるバグの修正 `#D0791`
+ - isearch: 空の検索文字列による一致に <kbd>C-h</kbd> で戻った時に全体が選択されるバグの修正 `#D0794`
+ - decode: `failglob` の時 `ble-bind -d` に失敗する問題の修正 `#D0795`
+ - edit: `command-help` のコマンド名抽出に失敗するバグの修正 (reported by cmplstofB) `#D0799`
+ - syntax: 履歴展開の置換指示子の解析が正確でない問題の修正 (report by cmplstofB) `#D0800`
+ - edit: Bash 3.0 で履歴展開 `:&` が使えない問題の修正 `#D0801`
+ - idle: 負の `sleep` を試みてエラーメッセージが出る問題の修正 `#D0802`
+ - bind: `ble-detach` 時に、Bash 3.0 の <kbd>"</kbd> のバインディングを破壊するバグの修正 `#D0803`
+ - edit: `ble-detach` 直後にコマンドラインに設定される `stty sane` が表示されない問題の対策 `#D0804`
+ - core: Bash-3.0 で補完候補がない場合にエラーメッセージが表示されるバグの修正 `#D0807`
+ - edit: コマンド実行中にウィンドウサイズが変更された時にプロンプトが表示されてしまう問題の解消 `#D0809`
+ - edit: widget 内で `read -e` を使用した時・`read -e` がタイムアウトした時に表示が乱れる問題の解消 `#D0809`
+ - edit: `read -e` でタイムアウトが効かないバグの修正 `#D0809`
+ - term: 16色の端末で色が化けるバグの修正 `#D0823`
+
+## 他: 動作変更
+ - edit: `read -e` がキャンセル・タイムアウトによって終了した時に入力文字列を灰色で再表示 `#D0809`
+ - decode: キーマップの既定の初期化を最初の `ble-bind` 時に確認する様に変更 `#D0813`
+ - core: `ble/util/clock` 導入 `#D0814`
+ - edit: `ble-edit/read -e -t timeout` において、タイムアウトをより高精度で処理 (`ble/util/clock`) `#D0814`
+ - color: `face` が定義されていない時のエラーメッセージの表示方法を変更 `#D0815`
+ - edit: コマンド実行時に現在のカーソル位置より下に表示されている端末の内容を上書きする様に変更 `#D0816`
+ - edit: `accept-line` において、ちらつき防止の為、実際のコマンド実行が伴わない時は info の再描画を行わない `#D0816`
+ - edit: `ble/widget/history-expand-line` は <kbd>C-RET</kbd> ではなく <kbd>M-^</kbd> から束縛される様に変更 `#D0820`
+ - edit: `ble/widget/magic-space` で履歴展開が行われなかった時、現在位置で静的略語展開を試みる様に変更 `#D0820`
+ - isearch: <kbd>RET</kbd> でコマンド実行ではなく検索を終了するだけに変更。<kbd>C-RET</kbd> でコマンド実行 `#D0822`
+
+## 他
+ - Makefile: 依存ファイルを `.PHONY` target として出力 `#D0778`
+ - core: `ble/util/assign` をリエントラントに修正 `#D0782`
+ - 議論 complete: `#D0770` edit: `#D0796` vi: `#D0796`
+ - `blerc` の更新
+
+## 以下は widget 名変更の一覧
+ - `menu_complete/accept` → `menu_complete/exit`
+ - `auto_complete/accept` → `auto_complete/insert`
+ - `auto_complete/accept-on-end` → `auto_complete/insert-on-end`
+ - `auto_complete/accept-word` → `auto_complete/insert-word`
+ - `auto_complete/accept-and-execute` → `auto_complete/accept-line`
+ - `isearch/accept` → `isearch/accept-line`
+
+<!---------------------------------------------------------------------------->
+# 2018-09-02
+
+2018-07-29 - 2018-09-02 (#D0684..#D0765 0c28ed9)
+
+## 補完: 新機能
+ - complete: 曖昧補完 `#D0707` `#D0708` `#D0710` `#D0713` `#D0743` (fix)
+ - complete: Readline 設定 `completion-ignore-case` に対応 `#D0709` `#D0710`
+ - complete: `ble/cmdinfo/complete:$command_name` 対応 `#D0711`
+ - complete: `path:...` などと入力した時の続きの補完に対応 `#D0715`
+ - complete: 引用符内のエスケープなどを適切に処理する `#D0717`
+ - complete: 自動補完に対応 `#D0724`, `#D0728`, `#D0734` & `#D0735` (vim-mode), `#D0766` (history)
+ - complete: カーソルの右側に補完結果の一部が含まれる時にスキップする機能 (`bind set skip-completed-text`) `#D0736`
+ - complete: 引用符の中で補完した時に引用符を閉じる機能 `#D0738`
+ - complete: 算術式内部での変数名の補完に対応 `#D0742`
+ - complete: 候補一覧表示の整列と着色 `#D0746` `#D0747` `#D0762` `#D0765`
+ - complete: menu-completion (メニュー補完) 対応 `#D0749` `#D0757` `#D0764`
+ - complete: menu-filter (候補絞り込み) 対応 `#D0751`
+ - complete: vi_cmap に於ける補完 `#D0761`
+
+## 補完: バグ修正・対策
+ - complete: Cygwin でのコマンド名補完に於いて `.exe` の途中まで入力した時に正しく補完できない問題の修正 `#D0703`
+ - complete: `complete` によって登録されたプログラム補完に対して変数 `COMP_*` が正しく設定されない問題の修正 `#D0711`
+ - complete: `"` や `'` を含むファイル名の補完が正しくできない問題の修正 `#D0712` `#D0714`
+ - complete: 補完中に特殊キーを入力しても中断しない問題の解消 `#D0729`
+ - complete: クォートを認識しないプログラム補完関数に対する対策 `#D0739`
+ - complete: 引数の途中からのプログラム補完の不整合の修正 `#D0742` `#D0744`
+ - complete: パラメータ展開 `${var}` 直後からの補完が正しく実行できる様に修正 `#D0742`
+
+## 補完: 動作変更
+ - complete: 補完候補生成直前の `shopt -s force_fignore` を参照して候補を制限する様に変更 `#D0704`
+ - complete: `FIGNORE` はエスケープされた挿入文字列に対してではなくて、候補文字列に対して判定する様に変更 `#D0704`
+ - complete: 関数名補完を `/` で区切られた単位で行う `#D0706` `#D0724` (曖昧一致の時は抑制)
+ - complete: パラメータ展開で厳密一致で一意確定の時は他の補完文脈を使うように変更 `#D0740`
+ - complete: パラメータ展開の補完後に挿入する文字を文脈に依存して変更 `#D0741`
+ - complete: パラメータ展開の直後に補完で挿入する際のエスケープを文脈に依存して変更
+ - complete: プログラム補完による生成候補でディレクトリ名を省略 `#D0755`
+
+## 他: 新機能
+ - edit (`RET`): 文法的に不完全のときに改行を挿入 `#D0684`
+ - core (`ble/util/idle`): 簡易タスクスケジューラの実装 `#D0721`
+ - core: add a function `ble/function#try` `#D0725`
+ - idle: `ble/util/idle` でバックグラウンドジョブ待ち機能を実装 `#D0731` `#D0745` (history bugfix)
+ - base: `--attach=prompt` 対応 `#D0737`
+ - base: 初回初期化時の順序の変更と過程の info による表示
+ - decode: modifyOtherKeys 対応の改善 `#D0752` `#D0756` `#D0758` `#D0759`
+ - core (`ble/util/assing`): 第3引数以降にコマンドに対する引数を指定できるように変更 `#D763`
+
+## 他: バグ修正・対策
+ - highlight: 単語着色が乱れるバグの修正 `#D0686`
+ - syntax: bash-3.2 以下で `_ble_syntax_attr: bad array subscript` のエラーが出るバグの修正 `#D0687`
+ - prompt: PS1 で \v が空文字列になるバグの修正 `#D0688`
+ - highlight: 上書きモードにおいてコマンドをキャンセルしても `disabled` レイヤーの着色が無視されるバグの修正 `#D0689`
+ - core (ble/term/visible-bell): 横幅の計算を誤っているバグの修正 `#D0690`
+ - decode: "set -o vi/emacs" で編集モードを切り替えた直後に "stty" が変になる問題の修正 `D0691`
+ - core: LANG=C とすると動かなくなる問題の対処 `#D0698` `#D0699` `#D0700`
+ - history: Cygwin で履歴の初期化に時間がかかる問題の対策 `#D0701`
+ - history: bashrc 読み込み直後に謎の待ち時間が発生する問題の対策 `#D0702`
+ - emacs: 貼り付け (bracketed paste) で文字列が二重に挿入されるバグの修正 `#D0720`
+ - main: POSIXLY_CORRECT が設定されている時の対策 `#D0722` `#D0726` `#D0727`
+ - edit: POSIXLY_CORRECT を用いた組み込みコマンド上書き対策 `#D0722`
+ - decode: 連想配列に依る実装のバグを修正し bash-4.0, 4.1 においても連想配列を使用 '#D0730'
+ - decode: `ble-bind -c` でシェルの特殊文字を含むコマンドが正しく実行できないバグの修正
+ - edit: 履歴項目の数が倍増するバグの修正 `#D0732`
+ - vi: キーボードマクロで特殊キーが再生されないバグの修正 `#D0733`
+ - isearch: 現在位置の表示時の 0 除算のバグの修正
+ - vi: `!!` をキャンセルしても操作範囲を示す着色が消えないバグの修正 `#D0760`
+
+## 他
+ - refactor: `#D0725` `#D0750` `#D0753` `#D0754`
+ - bash-bug: Bash に対するバグ報告 `#D0692` `D0695` `D0697`
+
+<!---------------------------------------------------------------------------->
+# 2018-03-15
+
+2018-03-15 (#D0644..#D0683 7d365d5)
+
+## 新機能
+ - undo: vi-mode `u` `<C-r>` `U` (`#D0644` `#D0648`); emacs `#D0649`; `#D0662`
+ - vi-mode (nmap/xmap): `f1` で `command-help` 呼び出し
+ - vi-mode (nmap): `C-a` `C-x` 対応 (nmap `#D0650`, xmap `#D0661`)
+ - vi-mode (operator): 各種オペレータ対応 `#D0655` (`gq`, `gw` `#D0652`; `!` `#D0653`; `g@` `#D0654`)
+ - vi-mode (operator): 追加入力のあるオペレータで作用対象を着色 `#D0656`
+ - vi-mode (registers): registers `"[0-9%:-]` `#D0666` `#D0668`, `:reg` `#D0665`
+ - vi-mode (smap): 選択モード `#D0672`
+ - emacs: 主要なコマンドで引数に対応 `#D0646`
+ - emacs: 複数行モードの時にモード名を表示。引数も表示。 `#D0683`
+ - edit: `safe` keymap
+ - edit: 絵文字の文字幅 `bleopt emoji_width=2` `#D0645`
+ - core: 誤った `PATH` に対する対策 `#D0651`
+
+## 動作修正
+ - vi-mode (nmap/xmap/omap `<paste>`): 引数を無視するように変更
+ - vi-mode (map `/` `?` `n` `N`): 検索の一致の仕方を vim と同様のものに変更 `#D0658`
+ - vi-mode (omap): `g~?` で検索して一致した範囲まで大文字・小文字を切り替えるように変更 `#D0659`
+ - vi-mode (map): 最終行付近で `+` `_` `g_` などを呼び出したときの振る舞いを vim と同様のものに変更 `#D0663`
+ - vi-mode (xmap): テキストオブジェクト `[ia]['"]` の xmap での正しい振る舞い `#D0670`
+ - vi-mode (nmap): `Y` で行頭に動かないように変更 `#D0673`
+ - vi-mode (xmap): 矩形範囲抽出の効率化 `#D0677`
+ - core: `ble.sh` ロード時間の改善 `#D0675`, `#D0682`, (遅延読込 `#D0678` `#D0679` `#D0680`, 裏で履歴読込 `#D0681`)
+
+## バグ修正
+ - vi-mode (omap): `cw` や `y?` が動かなくなっていたバグの修正
+ - vi-mode: マクロで記録される内容に空白が挿入されるバグの修正 `#D0667` (テスト追加 `#D0669`)
+ - vi-mode: 行指向の貼り付けが動かなくなっていたバグの修正 `#D0674`
+ - complete: コマンド名によって第一引数の補完が正しく実行されないことがあるバグの修正 `#D0664`
+ - syntax: ヒアストリングで $ret を指定するとエラーメッセージが現れたバグの修正 `#D0660`
+ - syntax: bash-3.0 でコマンドの着色が常にエラーになっていたバグの修正 `#D0676`
+ - decode: ble-decode-unkbd があらゆる文字について ESC を返す様になっていたバグの修正 `#D0657`
+ - Makefile: 削除したファイル isearch.sh が要求されるバグの修正
+ - Makefile: 最新の gawk で動かないバグの修正
+
+<!---------------------------------------------------------------------------->
+# 2017-12-03
+
+## 新機能
+ - edit, vi-mode: bracketed paste mode に対応 `#D0639`
+
+## 動作修正
+ - core: 端末の状態設定・復元とカーソル形状の内部管理 `#D0638`
+ - 外部コマンドを呼び出すときに既定のカーソル形状にする
+ - 外部コマンドから戻ったときにカーソル形状を復元する
+ - syntax (extract-command): より下の構文階層にいてもコマンドを見つけられるように修正 `#D0635`
+ これによりリダイレクトの単語などの上でも `command-help` (nmap `K`, emacs `f1`) が動くように。
+ - syntax (チルダ展開): 変数代入の形式を持つ通常単語内部でのチルダ展開に対応 `#D0636`
+ - syntax: [...] 内部でチルダ展開が起こったとき [...] は意味を失う `#D0637`
+ - vi-mode (cmap `<C-w>`): imap `<C-w>` と同様に vim の動きに変更
+
+## バグ修正
+ - complete: 補完候補がない時に空文字列で確定するバグの修正 `#D0631`
+ - complete, highlight: `failglob` 周りのバグの修正 (3) `#D0633` `#D0634`
+ - vi-mode: `ret` グローバル変数が汚染されていたバグの修正 `#D0632`
+ - highlight: 読み取り専用の変数名を入力するとエラーメッセージが出るバグの修正
+ - decode: `__defchar__` から呼び出された widget が 125 を返したとき
+ `__default__` から呼び出された widget にキー列が渡されないバグの修正
+ - core: set -u にすると全く動かないバグの修正 `#D0642`
+ - edit: ble.sh ロード中に `read -e` が動かないバグの修正 `#D0643`
+
+<!---------------------------------------------------------------------------->
+# 2017-11-26
+
+## バグ修正
+ - general: failglob で問題が生じるバグの修正 `#D0630`
+ - keymap/vi (nmap q): bash-3.0 で動かなかったバグの修正
+ - keymap/vi (cmap): C-d で終了してしまうバグを修正 `#D0629`
+ - edit (ble/widget/command-help): エイリアスの上でヘルプを実行しようとすると無限ループになるバグを修正
+ - edit (ble/util/type): "-" で始まる名前のコマンドの種類の判定に失敗し着色されなかったバグの修正
+ - complete: 変数代入の右辺やリダイレクト先で補完できないことがあるバグの修正 `#D0627`
+ - complete: 補完する単語にパラメータ展開が含まれるとき ble.sh のローカル変数の値を参照している問題の修正 `#D0628`
+
+## 動作変更
+ - bind/decode: 孤立 ESC の読み取り方法を変更。<C-q><C-[> で単体 <C-[> が入力されるように修正
+ - bind/decode: input_encoding=C の時の孤立 ESC および C-@ の読み取りに対応
+ - complete: 重複して列挙される候補を統合する `#D0606`
+ - complete: 厳密一致するディレクトリ名が何故かコマンド候補に現れる問題の修正 `#D0608`
+ - edit (command-help): 幾つかの組み込みコマンド・予約語について man bash の正しい位置に移動するように修正 `#D0609`
+ - edit (command-help): クォートなどを除去してからコマンドのヘルプを探索するように変更 `#D0610`
+ - core: 条件コマンドの比較で右辺をクォートし忘れていた箇所を修正 `#D0618`
+ - highlight: `shopt -s failglob` の時、失敗する単語にエラー着色をする `#D0630`
+
+## 構文解析変更
+ - syntax: `> a.txt; echo` は構文エラーではないことに対応 `#D0591`
+ - syntax: 変数代入・リダイレクトの後では予約語は意味を失いコマンドとして扱われることに対応 `#D0592`
+ - syntax: `time` や `time -p` は構文的に正しいことに対応 `#D0593`
+ - syntax: `echo $(echo > )` などの `>` の引数がない構文エラーにより `$()` が閉じず別の構文エラーを引き起こしていたのを抑制 `#D0601`
+ - syntax: `function hello (())` は bash-4.2 未満では構文エラーとして扱うように変更 `#D0603`
+ - syntax: `time -p -- command` を独立した文脈で解析するように変更 `#D0604`
+ - complete: これにより `time` の引数のコマンド補完ができなかった問題は解消した `#D0605`
+ - syntax: extglob 内部のプロセス置換 `@(<(echo))` に対応 `#D0611`
+ - syntax: `[...]` によるパターンの解析に対応 `#D0612`
+ - syntax: 変数代入の右辺にある不活性になった extglob の入れ子 `@(@())` も不活性にする `#D0613`
+ - syntax: `shopt -u extglob` の時でも `*` や `?` を着色する `#D0616`
+ - syntax: ブレース展開の着色に対応 `#D0622`
+ - syntax: チルダ展開の着色に対応 `#D0626`
+ - syntax: `for var in args...` の `args` におけるリダイレクトの禁止 `#D0623`
+ - highlight: ヒアストリングの場合はパス名展開・ブレース展開を行わない `#D0624`
+ - highlight: リダイレクト先ファイル名が複数語に展開されたらエラー着色 `#D0625`
+
+## 構文解析修正
+ - syntax: `$({ echo; })` や `$(while false; do :; done)` において `}`, `done` 等の後にコマンドがないと構文エラーになっていたバグの修正 `#D0593`
+ - syntax: `-` で始まる名前のコマンド・関数名が正しく着色されないバグの修正 `#D0595`
+ - syntax: `if :; then :; fi $(echo)` などの構文エラー着色が実行されないバグの修正 `#D0597`
+ - syntax: 先読みによる不整合が起こるバグの修正・先読みの枠組みの整備 `#D0601`
+ - プロセス置換周りで部分更新により不整合が生じるバグを修正
+ - `function hello (())` としておいて `) (` を挿入して `function hello () (())` にすると不整合が生じるバグを修正 `#D0602`
+ - syntax: 途中で `shopt -u extglob` にしても `_ble_syntax_bashc` が更新されないバグの修正 `#D0615`
+
+<!---------------------------------------------------------------------------->
+# 2017-11-09
+
+## 新機能
+ - vi-mode (nmap): `*` `#` `qx...q` `@x`
+ - vi-mode (cmap): 履歴
+ - core: bleopt 変数 `pager` (既定値 `''`) に対応。`ble.sh` の使うページャとして `${bleopt_pager:-${PAGER:-適当に探索}}` を使用する。
+ - vi-mode (nmap `K`): `ble/cmdinfo/help:$cmd`, `ble/cmdinfo/help` に対応。
+
+## バグ修正
+ - vi-mode (cmap `<C-[>`): コマンドラインモードをキャンセルするキーマップが `bell` で上書きされていたバグの修正
+ - decode: `shopt -s failglob`, `shopt -s nullglob` で `unset` が正しく動かないバグの修正
+ - vi-mode (nmap `K`): `MANOPT=-a` で操作できなくなるバグの修正
+
+## 動作変更
+ - edit (`ble/widget/command-help`), vi-mode (nmap `K`): カーソル位置のコマンドの `man` を表示するように変更
+ - base: キャッシュディレクトリ・一時ディレクトリの決定で、それぞれ `XDG_CACHE_HOME`, `XDG_RUNTIME_DIR` を参照するように変更
+ - Makefile: インストール先ディレクトリで、`XDG_DATA_DIR` を参照するように変更
+ - isearch: 実際に必要になるまでコマンド履歴のロードを遅延するように変更
+ - vi-mode (nmap `K`): 組み込みコマンド・キーワードは `man bash` を表示する。
+ - vi-mode (nmap `K`): シェル関数は関数定義を表示する。
+
+<!---------------------------------------------------------------------------->
+# 2017-11-05
+
+## 新機能
+ - vi-mode (exclusive motion): `:help exclusive-linewise` 特別規則 (exclusive -> inclusive, exclusive -> linewise) に対応
+ - vi-mode (omap): `C-c` `C-[` で明示的にキャンセル
+ - vi-mode: keymap/vi_test.sh 追加。regression が酷いので vi-mode の動作テストを自動化
+ - complete: bleopt 変数 `complete_stdin_frequency` (既定値 `50`) 追加
+
+## 動作変更
+ - vi-mode (nmap `e`, `E`): 移動先が最終行の最後の文字の空白のとき、omap なら bell を鳴らさないように変更
+ - vi-mode (omap/xmap `<space>`, `<back>`, `<C-h>`): 改行の数え方を変更
+ - vi-mode (nmap `cw`, `cW`): 単語の最後の文字、および空白の上にいるときの振る舞いの変更
+ - decode (ble-bind): `ble-bind -D` でキーマップの内部状態も出力するように変更
+ - term: `_ble_term_SS` の既定値を空文字列に変更
+ - complete: `shopt -s no_empty_cmd_completion` では補完を (コマンドの補完以外も) 全く行わないように変更
+ - edit (ble/widget/exit): 編集中の文字列が残っているとき、灰色で再描画してから exit するように変更
+
+<!---------------------------------------------------------------------------->
+# 2017-11-03
+
+## 破壊的変更
+ - vi-mode (widget): 名称変更 blw/widget/vi-insert/* → ble/widget/vi_imap/*
+ - vi-mode (bleopt 変数): 名称変更 bleopt keymap_vi_normal_mode_name → keymap_vi_nmap_name
+ - vi-mode (imap): vi-insert/magic-space 廃止。代わりに magic-space を直接用いる。
+
+## 新機能
+ - vi-mode (xmap): `o` `O`
+ - vi-mode (nmap): `.` 取り敢えず完成?
+ - vi-mode (xmap/nmap): `gv`
+
+## バグ修正
+ - vi-mode (mark `` `x `` `'x`): オペレータが呼び出されないバグの修正
+ - vi-mode (txtobj `[ia]w`): 英数字と _ の連続ではなく英字と _ だけの連続を単語としていたバグの修正
+ - vi-mode (imap): `{count}i...<C-[>` において `<C-q>x` `<C-v>x` が正しく繰り返されなかったバグの修正
+ - vi-mode (imap): `{count}i...<C-c>` において繰り返しが有効になっていたバグの修正
+ - vi-mode (nmap `{N}%`): 目的の行に移動しなくなっていたバグの修正
+ - vi-mode (nmap `_`): `d_` 及び `d1_` が linewise になっていないバグの修正
+ - vi-mode (xmap `I` `A`): 動かなくなっていたバグの修正
+ - vi-mode (xmap `I` `A`): 実行後のカーソル位置がずれていたバグの修正
+ - vi-mode (xmap `I` `A` `c` `s` `C`): 矩形挿入の後の編集範囲 `` `[`] `` から1行目が抜けているバグの修正
+ - vi-mode (xmap `?`): 検索 `?` が operator `g?` になっているバグの修正
+ - vi-mode (xmap `/` `?` `n` `N`): ビジュアルモードの選択範囲が検索の一致範囲で上書きされるバグの修正
+ - vi-mode (xmap `/` `?` `n` `N`): 現在の履歴項目の中で一致しない時、別の履歴項目にビジュアルモードのまま移動するバグの修正
+ - lib/vim-surround (nmap `cs` `cS`): nmap `.` 対応時に引数とレジスタが効かなくなっていたバグの修正
+ - lib/vim-surround (xmap `S`): `v` によるビジュアルモードで改行が前後に挿入されていたバグの修正
+
+## 動作変更
+ - vi-mode (imap `<C-w>`): vim の単語区切り (`w`) による削除に変更
+ - vi-mode (nmap `[rRfFtT]x`): `<C-[>` でキャンセルするように変更
+ - vi-mode (nmap `w` `b` `e` `ge`): 非英数字 ASCII の連続と、Unicode 文字の連続 をそれぞれ別の単語と扱うように変更
+ - vi-mode (xmap `c` `s` `C`): `I`, `A` と同様の矩形挿入に対応
+
+<!---------------------------------------------------------------------------->
+# 2017-10-30
+
+## 破壊的変更
+ - vi-mode: キーマップの名称変更 vi_command -> vi_nmap, vi_insert -> vi_imap
+ - vi-mode: 一部の widget の名称変更
+ - ble/widget/{no,}marked -> ble/widget/@{no,}marked
+ - ble/widget/vi-command/* (一部) -> ble/widget/vi_nmap/*
+ - vi-mode: ble/widget/vi-insert/@norepeat 廃止。別の方法 (_ble_keymap_vi_imap_white_list) を用いる。
+
+## 新しい機能
+ - vi-mode (nmap): . は実装途中 (現状 nmap/omap におけるオペレータ経由の変更のみ記録)
+ - vi-mode (mode): bleopt 変数 `term_vi_[inoxc]map`
+ - decode: 孤立 ESC のタイムアウトに対応
+ - edit: shopt -s histverify, shopt -s histreedit に対応 #D0548
+
+## バグ修正
+ - vi-mode (xmap): `p`, `P` が正しく動作しないバグを修正
+ - vi-mode (imap): 挿入モードに入るときに指定した引数 (繰り返し回数) が常にキャンセルされていたバグの修正
+ - vi-mode (txtobj; nmap `gg`, `G`): レジスター指定が消失していたバグの修正
+ - lib/vim-surround (nmap ds): 引数が内部使用のオペレータ `y`, `d` に正しく渡っていなかったバグの修正
+ - prompt: `PROMPT_COMMAND` で設定された `PS1` が永続化されていなかったバグの修正
+ - decode: bind -x で曖昧な登録があって bash_execute_unix_command エラーになっていた問題の修正 #D0545
+ - decode: `vi.sh`, `emacs.sh` において `default.sh` が多重に呼び出されていた無駄の修正 #D0546
+ - core: bash-3.0 において ble/util/assign が壊れていたバグの修正
+
+## 動作変更
+ - vi-mode (nmap `x`, `<delete>`, `s`, `X`, `C`, `D`): support registers
+ - source ble.sh において無事にロードされたときに終了ステータス 0 を返すことを保証
+ - widget marked, nomarked を @marked, @nomarked に改名。元の widget は非推奨 (削除予定)
+ - ble.sh: Linux 以外でも (`readlink -f` が動かないときも) シンボリックリンクを通したロードに対応 #D0544
+
+<!---------------------------------------------------------------------------->
+# 2017-10-22
+
+## 新機能
+ - vi-mode (mark): `mx` <code>`x</code> <code>'x</code> (`x` = <code>[][<>`'a-zA-Z"^.]</code>)
+ - vi-mode (nmap): `gi` `<C-d>` (空文字列のとき exit) `"x` (registers)
+ - vi-mode (xmap): `I` `A` `p` `P` `J` `gJ` `aw` `iw`
+ - lib/vim-surround.sh: nmap `yS` `ySS` `ySs` `cS`, xmap `S` `gS`
+ - タブ・インデントの制御
+ - bleopt tab_width= (タブの表示幅)
+ - bleopt indent_offset=4 (`>` や `<` のインデントの幅)
+ - bleopt indent_tabs=1 (`>` や `<` のインデントにタブを用いるかどうか)
+ - 既定のインデントの幅は 8 から 4 に変更
+
+## バグ修正
+ - vi-mode: 挿入モードに繰り返し回数を指定したとき `ESC ?` も一緒に繰り返されていたバグの修正
+ - vi-mode: オペレータ `g?` が動かなくなっていたのを修正
+ - vi-mode (nmap `/` `?`): 検索対象の入力中に `C-c` してもキャンセルされないバグの修正
+ - vi-mode (xmap `r` (visual char/line)): 全体を置換したものが選択範囲に挿入されていたバグの修正
+ - vi-mode (xmap `$`): 行末で `$` をしたときに表示が更新されないバグの修正
+ - vi-mode (motion `0`): オペレータを認識していなかったバグを修正
+ - isearch: 一度一致したら同じものに一致し続けるバグを前回の `/` `?` `n` `N` 対応の際に埋め込んでいたので修正
+ - complete: `complete -F something -D` で登録されている補完関数が正しく実行されていなかったのを修正
+ - prompt: PROMPT_COMMAND によって設定された PS1 を拾っていなかったバグを修正
+ - textarea: 端末の下部で複数行編集時に `C-z` (`fz`) すると描画高さを正しく確保できていないバグの修正
+
+## 動作変更
+ - vi-mode (operator `<` `>`): Visual block での正しい振る舞い
+ - vi-mode (nmap `:` `/` `?`): 文字列入力中に空文字列で DEL or C-h することでキャンセルできるように修正
+ - vi-mode (nmap `J`, `gJ`): 引数に対応
+ - vi-mode (nmap `p`): 最後の行で挿入するときに余分な行が入らないように修正
+ - vi-mode (xmap `Y` `D` `R`): 記録するビジュアルモードの種類を修正
+ - lib/vim-surround.sh: タグ名入力中に '>' で確定するように修正
+ - widget (.SHELL_COMMAND): 実行しないコマンドに色がついているのはややこしいのでグレーアウトする様に変更
+
+## 他の変更
+ - magic-space: 空白を挿入してから履歴展開していた順番を逆転
+
+----
+
+# 2015-03-06..2017-10-09 (Git Commit Log)
+
+## 2017-10-09
+* keymap/vi: support specialized handling of keys for cmap
+ - vi (nmap / ?): treatment of C-h and DEL on input of search targets
+ - vim-surround.sh (nmap ys cs): treatment of > on input of tag names
+
+## 2017-10-07
+* keymap/vi_xmap: add tentative text object implementation
+* lib/vim-surround: accept user input of tag names with the replacement being t, T, <
+* keymap/vi_command: support search / ? n N
+
+## 2017-10-05
+* keymap/vi_command: fix behavior of yy, dd, D, etc. on the last line with count arg
+* keymap/vi_xmap: support x <delete> C D X R Y
+* keymap/vi_xmap: support r s
+* keymap/vi-command: support : and few commands
+* ble-core: fix a bug that conditions for assotiative arrays are inverted
+
+## 2017-10-04
+* [refactor] ble-edit (ble-edit/render -> ble/textarea): support "ble/textarea#{save,restore,clear}-state"
+* [refactor] ble-edit (text/update/positions -> ble/textmap): support any time updates of text positions
+* keymap/vi_command: support _ g0 g<home> g^ g$ g<end> gm go g_ ge gE
+* check: fix "local lines=()" in vi_digraph.sh and update "check"
+* (ble-highlight-layer:region): fix a bug that the "region" face is sometimes applied to intervals between selections
+
+## 2017-10-03
+* keymap/vi (visual mode): support previous selections
+* keymap/vi (nmap p, P for block): convert HTs under inserting points to spaces
+* (ble-decode-key/dump): fix a bug that pathname expansions internally occurred
+* ble-core: add ble/string#split-lines
+* keymap/vi (visual block): improve performance of block extraction
+* keymap/vi_command (linewise operator d): go to the previous line on deleting the last line
+* keymap/vi (operator d c g~ gu gU g?): support block
+* keymap/vi (nmap p, operator y): support block
+
+## 2017-10-02
+* keymap/vi_xmap: support count arg for operators
+* keymap/vi_command: fix a bug that linewise < > operators produce an error
+* keymap/vi_command: perform EOL fix on history traveling with normal mode
+* keymap/vi_xmap: support block selection
+
+## 2017-10-01
+* keymap/vi_xmap: support visual mode swithing
+* keymap/vi: support visual mode
+
+## 2017-09-28
+* ble-edit: add a condition to accept-single-line-or
+* keymap/vi_command: support gj gk
+
+## 2017-09-27
+* ble-edit: restore BASH_REMATCH
+* ble-edit: do not execute pasted multiline texts
+* ble-edit: support scrolling
+* bleopt: implement value checking on assignment
+
+## 2017-09-24
+* ilb/vim-surround.sh: do not refer bleopt "vim_surruond_{char}" for digit replacement char
+* keymap/vi: show configurable string (defaulted to be ~) on the normal mode
+* keymap/vi_command: support % N%
+* keymap/vi_command: support indentation for o O
+* keymap/vi_command: reimplement text object is as
+* keymap/vi (linewise-range.impl): fix a bug that the line ranges are reverted, fix behavior to go to nol
+
+## 2017-09-23
+* keymap/vi_command: support text object ip ap
+* keymap/vi_command: support text object is as
+* keymap/vi_insert: support indentation for C-m, C-h, DEL
+* ble-edit: erase garbage input echo during initialization of ble.sh
+* ble-edit (bleopt char_width=emacs): fix a bug that U+2000 - U+2600 are always treated as width 1
+* keymap/vi: fix a bug that selection is not cleared on entering the normal mode during isearch
+
+## 2017-09-22
+* keymap/vi_command (r, gr): highlight on waiting replacement
+* keymap/vi_command: support text object it at
+
+## 2017-09-20
+* ble-edit/exec: fix handling of $? and $_ and add a workaround for "set -o verbose"
+
+## 2017-09-18
+* lib/vim-surround: support configurable replacements with bleopt vi_surround_45:=tmpl vi_surround_q:=tmpl
+* (bleopt): support the form "var:=value" which skips existence checks of variables
+* lib/vim-surround: support ds cs
+* ble-decode: fix stty settings for command execution
+* keymap/vi_omap: fix mode transition from vi_omap to vi_insert
+* [m] lib/vim-surround: remove redundant codes
+
+## 2017-09-17
+* keymap/vi (text object i[bB]): exclude newlines around the range and transform to linewise
+* [m] keymap/vi (text object i"): behave the same as a" with arg >= 2 specified
+* [m] keymap/vi: rename functions
+* keymap/vi_insert: change the default of C-k to kill-forward-line
+* keymap/vi_command: support digraphs for arg of f, F, t, T, r, gr
+* keymap/vi: support digraph
+* (ble-bind): support "ble-bind -@f kspec command"
+* (ble-decode-kbd): fix a bug that keys "*" and "?" cannot be properly encoded
+
+## 2017-09-16
+* keymap/vi_command (operators): fix a bug that arg is cleared before the use
+* lib/vim-surround: support b B r a C-] C-} as replacements
+* keymap/vi: rename operator flag for < and >
+* (ble/widget/self-insert): explicitly return 0
+* ble-decode (ble-decode-key/.invoke-command): propagate exit status of widgets
+* keymap/vi_omap: decompose M-*
+* add ilb/vim-surround.sh, support operator "ys" and "yss"
+* keymap/vi: add new keymap "vi_omap"
+
+## 2017-09-15
+* keymap/vi_command: support operators < >
+* keymap/vi_command: support g~~ guu gUU g??
+* keymap/vi_command: handle meta flags of input keys
+* keymap/vi_command: support ~
+* keymap/vi_command: fix the text object "aw"
+* keymap/vi_command: rename widgets
+
+## 2017-09-13
+* ble-edit/info: fix cursor position calculations in rendering
+* (ble-form/panel#set-height-and-clear.draw): fix to add lines on an increased height
+* keymap/vi_command: support text objects [ia][][{}()<>bBwW'"`]
+
+## 2017-09-12
+* add ble-form.sh and introduce ble-form/panel
+* ble-edit: rename functions
+* keymap/vi_command: support text object iw
+* ble-edit/info: show default contents at the end of bind
+* ble.pp: fix PATH if standard utilities are not found on load
+* keymap/vi_command: add operators g~ gu gU g?
+* keymap/vi_command: refactor ydc operators
+* ble-decode (ble-bind): fix check of redundant "ble/widget" prefix
+
+## 2017-09-11
+* ble-edit (ble/widget/clear-screen): show info after the clear
+* keymap/vi_command (C-o): fix cusor positions after first-non-space commands
+* keymap/vi: fix the initial position of "-- INSERT --"
+* keymap/vi_command: support C-o
+* ble-core: add string functions
+* keymap/vi_insert: change mode names on "insert"
+* keymap/vi: show current modes in the info area
+* ble-edit: support ble-edit/info/set-default
+* ble-edit: clear info on exit
+* memo.txt: add comments from @B-bar
+* ble-decode: check existence of keymaps
+
+## 2017-09-10
+* keymap/vi_command: fix C D
+* keymap/vi_command: support arg for insert modes
+* ble-decode: fix ble-decode-key and support __before_command__ and __after_command__
+* keymap/vi_command: update bindings and support z{char} clear screens
+
+## 2017-09-09
+* keymap/vi_command: fix R and support gR
+* keymap/vi_command: support f F t T ; ,
+* ble-edit: suppress unnecessary history loads on history-next
+* ble.pp: support loading ble.sh from inside of functions
+* keymap/vi_command: support J gJ o O
+* fix leak variables
+* keymap/vi_command: support r gr
+
+## 2017-09-08
+* keymap/vi_command: fix mode change widgets and support gI
+* keymap/vi_command: support G H L gg
+* keymap/vi_command: fix behavior of [dcy][-+jk]
+* keymap/vi_command: update memo.txt and support K
+* keymap/vi_command (RET, C-m): fix to behave as + if the line contains LF
+* keymap/vi_command: support w W b B e E
+
+## 2017-09-07
+* keymap/vi_command: support s S
+* ble-edit: rename ble-edit/text/getxy -> ble-edit/text/getxy.out
+* keymap/vi_command: support C-h DEL SP
+* (ble/widget/vi-command/{forward,backward}-line): fix
+* keymap/vi_command: return to insert mode on accept-line
+* keymap/vi_command: support |
+* keymap/vi_command: clear arg on mode changes
+* keymap/vi_command: support I
+* keymap/vi_command: support Y D C
+* keymap/vi_command: support x X
+* keymap/vi_command: support p P
+* keymap/vi_command: check unknown flags
+* keymap/vi_command: support A
+* keymap/vi_command: add basic bash operations
+* keymap/vi_command (+ -): travel history
+* keymap/vi_command: support ^ + - $
+* keymap/vi_command: fix behavior of "yh" and "yl"
+* keymap/vi_command: support dd yy cc 0
+* ble-edit: partial revert 35098f0 where necessary ble-edit/history/load calls were removed
+* ble-edit (ble/widget/{for,back}ward-line, etc): fix a bug that the destination cursor pos was based on possible old layout
+* keymap/vi.sh: support hjkl
+* ble-edit: remove redundant ble-edit/history/load calls
+* (ble/widget/.bell): fix exit status
+
+## 2017-09-06
+* check: add check codes for bashbug workarounds
+* (ble-edit/text/get*): check if the cached text positions are up to date
+
+## 2017-09-05
+* keymap/vi: support mode switching
+* (ble/widget/.goto-char): simplify
+* (ble-edit/load-keymap-definition): workaround for bash-3.0
+* (ble-decode-key): accept multiple keys
+* ble-edit: support the value bleopt_default_keymap=vi
+
+## 2017-09-04
+* add keymap/vi.sh and switch keymap on editing mode change
+* ble-decode: split and refactor external settings
+* ble-decode: support bleopt_default_keymap=auto
+
+## 2017-09-03
+* ble.pp: remove the check enforcing "set -o emacs"
+* ble-decode (ble-decode-{attach,detach}): support attached editing modes
+* ble-decode: update spacing of an awk script
+* ble.pp: fix "set -o emacs" checks
+* ble-syntax: fix a bug that here strings are interpreted as here documents
+* complete.sh: suppress error messages on internal compgen calls
+
+## 2017-08-30
+* ble-edit: check editing mode
+
+## 2017-08-19
+* cmap/default.sh: disable modifier keys "CAN @ ?" which is ambiguous with "C-x C-x"
+* ble-edit: support "bleopt delete_selection_mode=1"
+
+## 2017-06-09
+* ble-syntax: workaround for the bash-4.2 arithmetic bug resulting in segfaults
+
+## 2017-05-20
+* ble.pp: guard double ble-attach
+
+## 2017-04-21
+* bind.sh: bash-4.4 workaroud: fix a bug C-x ? is not bound
+
+## 2017-03-17
+* README: update color settings and translate tips
+* README: add a hint on editing multiline commands
+
+## 2017-03-16
+* (ble-color-gspec2g): change to recognize 0 padded color indices as decimal numbers
+* README: bump release 0.1.7
+
+## 2017-03-15
+* README: update heading syntax of GitHub flavored markdown
+
+## 2017-03-13
+* suppress error messages caused by incorrect user LC_*/LANG values
+
+## 2017-03-06
+* complete: fix a bug that backquotes, newlines and tabs in completed words were not escaped
+
+## 2017-03-05
+* ble.pp ($_ble_init_original_IFS): \minor, fix unset
+* ble-core.sh ($ble_util_upvar_setup): add "local ret" declartion
+* (ble-syntax:bash/ctx-heredoc-word): use ctx-redirect to read keyword of here documents
+* ble-color: move deprecated "ble-highlight-layer:adapter" codes to layer/adapter.sh as a sample
+* save/restore IFS to protect ble functions from user's IFS
+* memo.txt: assign numbers of the form "#D????" to old items
+* (ble-syntax:bash): :new: support "select var in ..."
+* (ble-syntax:bash): fix a recent bug that semicolons after "for (())" was not allowed
+* (ble-syntax:bash): :new: support here documents
+
+## 2017-03-04
+* (ble-syntax:bash): fix a bug that semicolons are not allowed after "}", "fi", "done", etc.
+* (ble-syntax:bash): support the construct with the form "for name do ...; done"
+* (ble-syntax:bash): accept "do" immediately after "for (())" without semicolons
+* Makefile: add a prerequisite "install"
+* (ble-edit-attach): output CR before showing prompt
+
+## 2017-03-02
+* (ble-syntax:bash): allow `then, elif, else, do' after `}, etc.'
+* (ble-syntax:bash): improve checks of quotes in parameter expansion and arithmetic expansion
+ - change so that quotes are processed always in the syntax level
+ - introduce new nest-types, ntype='$((' and ntype='$[', for CTX_EXPR (arithmetic expressions)
+ - introduce a new nest-type ntype='NQ(' to support nesting in quote-removal-less contexts
+ - fix so that quotes '...' in parameter expansions such as `${var#text}' are always enabled
+* \clean: format memo.txt and document comments, etc.
+* (ble-syntax:bash): add a work around of a bash-4.2 bug in arithmetic expressions
+
+## 2017-03-01
+* (ble-edit/info/draw-text): change to truncate overflow contents
+* ble-edit: fix bugs that line representation is broken at the last line of terminals
+ - \fix, use IND to ensure size of the edit area
+ - \fix, clear _ble_line_{beg,end}{x,y} on newline
+ - ble-edit.sh: add a function ble-edit/draw/put.ind
+ - ble-edit.sh: add a function ble/widget/.insert-newline
+ - (ble/widget/redraw-line): \clean, 無駄な _ble_line_cur 初期化を削除。ble-edit/render/invalidate を呼び出すだけで充分。
+ - (ble-edit/exec/.adjust-eol): \clean, 無駄な _ble_line_x=0 _ble_line_y=0 を消去。元からそうなっている前提である。
+ - (ble-edit/exec/.adjust-eol): \fix, 直接 stderr に出力していたのを ble/util/buffer に出す様に変更。
+* (ble-syntax:bash): support `} }', etc.
+* (ble-syntax:bash): :new: support `for ((;;)) { ... }'
+* (ble-syntax:bash): support `((echo)>/dev/null)' and `$((echo)>/dev/null)'
+* complete: support completion of "in" keywords for "for var in"/"case arg in"
+* (ble-syntax:bash): :new: support `for var in ...' and `case arg in'
+* (ble-syntax:bash/ctx-command): [refactor] split into functions, use arrays for ctx settings
+* (ble-syntax:bash): fix a bug that redirection accepted comments
+* (ble-highlight-layer:syntax): fix a bug that causes error on a word beginning with #
+ - Note: words beginning with '#' can be formed when `shopt -u interactive_comments'
+* (ble-syntax:bash): fix a bug that beginning of process substitutions splitted words
+
+## 2017-02-28
+* ble-edit: [refact] rename ble/edit/prompt/update/update-cache_wd -> ble-edit/prompt/update/update-cache_wd
+* ble-edit: [refact] rename ble/widget functions
+* ble-edit: [refact] rename ble-edit functions
+* ble-edit: use ble/util/buffer to suppress flicker
+* ble-core: add variable "ble_util_upvar{,_setup}"
+
+## 2017-02-25
+* (ble-syntax/parse/shift): fix a bug that caused duplicated shifts
+* (ble-syntax/print-status/.dump-arrays): add consistency checks
+
+## 2017-02-14
+* ble-syntax.sh: fix a bug that attempts "continue" out side of loop
+
+## 2017-02-13
+* ble-edit (ble/widget/isearch): fix a bug that isearch does not work in bash-4.4
+
+## 2016-12-21
+* ble-edit (exec): default value of the parameter "$_" is "$BASH"
+* ble-edit (exec): support parameter "$_"
+
+## 2016-12-06
+* ble-core (ble/string#split): add a work around for "shopt -s nullglob"
+
+## 2016-11-08
+* Makefile: detect correct path of gawk for mwg_pp.awk
+
+## 2016-11-07
+* ble-core.sh: add a work around of bashbug to accept inputs of hankaku kana
+
+## 2016-09-20
+* (ble/util/sleep in Cygwin): check parent processes of blocking process substitutions
+
+## 2016-09-16
+* README: update
+* (ble/util/upvar): fixed a bug that array elements cannot be exported
+
+## 2016-09-14
+* ble-core: add a function ble/util/upvar
+* _ble_edit_str.replace: improve error correction of _ble_edit_ind and _ble_edit_mark
+
+## 2016-09-11
+* (ble/widget/isearch/cancel): return to the original position, i.e. restore _ble_edit_{ind,mark}
+* (ble-syntax:bash/check-dollar): fixed a bug that isolated dollars generate syntax errors
+* (ble/widget/accept-and-next): fixed a bug that the next line is not loaded on accepting the last histentry
+* ble.sh (ble-edit/history/add): fixed a bug that erasedups is performed even if a new entry is rejected by ignorespace
+* isearch: fixed a bug that words in the current line is not matched incrementally
+
+## 2016-08-24
+* complete.sh: recognize dangling symbolic links in completion and syntax-highlighting
+
+## 2016-08-08
+* term.sh: fixed a bug that xenl cap was always disabled.
+
+## 2016-08-07
+* ble-edit/prompt: improved admin privileges checks on Cygwin
+
+## 2016-08-05
+* (ble-edit/history/add): fixed a bug that history entries are not registered after certain operations.
+* syntax: fixed a bug that causes an fatal error for param expansions with offset in quotes like "${v:1}"
+* (ble/util/sleep): do not use /dev/tcp which generates error messages on Win10 Cygwin.
+
+## 2016-07-16
+* (ble/util/array-push): \refactor, rename, support multiple elements to append.
+ - rename ble/util/array-push -> ble/array#push
+ - rename ble/util/array-reverse -> ble/array#reverse
+
+## 2016-07-15
+* complete: enable completion of variable names in "..." and ${...}.
+* complete.sh: insert '=' after the completion of variable name of assignment.
+ - (ble/widget/complete):
+ completion-context にて source の引数をコロン区切で指定できるように拡張する。
+ - ble-complete/source/variable:
+ 引数に応じて確定時に挿入する接尾辞を選択する様に変更する。
+ - ble-syntax.sh (ble-syntax/completion-context):
+ 文脈に応じて variable 候補源に引数 '=' を指定して、補完確定時に何を挿入するべきか指定する。
+* complete.sh: fixes and clean up; a new fn ble/string#split.
+ - ble-core.sh: a new function ble/string#split to replace "GLOBIGNORE=* IFS=... eval 'arr=(...)'".
+ - complete.sh: (ble-complete/.fignore/filter): fixed a bug that local variable pat was leaked.
+ - complete.sh: (ble/widget/complete): fixed a bug that "shopt -s force_fignore" was ineffective.
+
+## 2016-07-14
+* (ble/util/sleep): add fallbacks to sleepenh and usleep for bash-3.*.
+* isearch: fixed a bug that a new range overlapped with the current match cannot be matched incrementally.
+* (bleopt): fixed a bug in printing variables.
+
+## 2016-07-09
+* (ble/history/add): work around for bash-3.0 to add history entries to bash command history.
+* (ble/history/add): fixed a bug that command history was always disabled under bash-3.2.
+
+## 2016-07-08
+* ble-syntax.sh, complete.sh (shopt -q autocd): fixed a bug that error messages were output to stderr on completions in bash-3.*.
+* ble-edit (prompt): :new: support shell variable PROMPT_DIRTRIM for PS1 instantiation.
+* ble-edit: Now, the history index \! in PS1 is the index of the editted line.
+ - isearch: also, the position shown while isearch is changed to the history index.
+
+## 2016-07-07
+* README: move language options to the top. add icons of the languages.
+* update README and LICENSE
+* ble-edit.sh (ble-edit/isearch/backward): improve the performance (work around for slow bash arrays).
+
+## 2016-07-06
+* ble-edit.sh (_ble_edit_history_edit): changed to hold the whole editted history data.
+* ble-syntax: glob patterns are not active in variable assignments.
+* ble-edit.sh: 修正: ジョブ状態の変更を標準出力に確実に出力
+ - fixed a bug that job state changes are not output when PS1 contains '\j'.
+ - fixed a bug that the changes are not output immediately.
+* minor fixes in visible-bell and check-stderr.
+ - ble-core.sh (ble-term/visible-bell): fixed a bug in subsecond treatment.
+ - ble-edit.sh (.ble-edit/stdout/check-stderr): fixed a bug that lines without LF were not processed.
+
+* (ble/util/joblist): use ble/util/joblist for internal usage of jobs.
+ - ble-core.sh (ble/util/joblist): bugfix:
+ 誤って _ble_util_joblist_jobs を _ble_util_joblist_list として使用している箇所が 4 箇所。
+ - ble-core.sh (ble/util/joblist): bugfix:
+ - (直前のジョブ) や - (一つ前のジョブ) の変化も変化として検知していた。
+ - これはジョブ状態の本質的な変化とは言いがたいので無視する。
+ - ble-core.sh (ble/util/joblist): bugfix: add ble/util/joblist.clear
+ bash 自身によってジョブ状態の変化が報告された後に、
+ 二重に状態変化が報告される場合があるので、その様な場合にはキャッシュを消去する。
+ - ble-edit.sh の各 jobs を呼び出すところで、ble/util/joblist を代わりに呼び出す。
+ - ble-syntax.sh, ble-color.sh で jobs を使用してジョブの存在確認している箇所では、
+ 先に ble/util/joblist を呼び出してジョブの状態変更を確認してから目的の jobs 呼び出しを行う。
+* ble-core.sh: add a new function ble/util/joblist.
+
+## 2016-07-05
+* ble-core: add option bleopt_stackdump_enabled
+ - bleopt_stackdump_enabled が非零の値に設定されている時にだけ
+ stackdump を出力する様にする。既定では 0 (出力しない) とする。
+
+## 2016-07-04
+* ble-decode.sh (ble-decode-attach): fixed a bug that makes C-{u,v,w,?} ineffective after the second ble-attach.
+ - 2回目以降の ble-attach でも ble-decode-bind/uvw が動作する様に
+ ble-decode-attach で source "~.bind" した直後に _ble_decode_bind__uvwflag をクリアする。
+
+## 2016-06-27
+* ble-core.sh ($_ble_base/cache): move to _ble_base_cache="$_ble_base/cache.d/$UID" for user separation.
+* ble-core.sh ($_ble_base_tmp): change to use /tmp/blesh/$UID if it is available.
+ - 今迄は ble.sh と同じディレクトリに一時ファイルを配置していた。
+ しかし、ble_util_assign.tmp などのファイルは速度を考えれば tmpfs (RAM上) に配置したい。
+ 従って、一時ファイルは /tmp の上に配置するように変更する。
+* ble-core.sh: add ble/util/sleep to provide subsecond sleep.
+
+## 2016-06-25
+* ble-edit.sh (_ble_edit_str.replace debug codes): resume from wrong state.
+
+## 2016-06-23
+* ble-core.sh (ble/util/array-reverse): improve performance.
+
+## 2016-06-22
+* ble-edit/isearch: show progress of search.
+
+## 2016-06-19
+* ble-edit/isearch: ble/widget/isearch/prev cancel a task in que, ble/widget/isearch/accept is not effective while a search.
+ - ble/widget/isearch/prev: 現在実行中のタスク (_ble_edit_isearch_que) がある場合には一つずつキャンセルする。
+ - ble/widget/isearch/accept: 現在実行中のタスクがある場合には bell を鳴らすだけで動作をスキップする。
+ - ble-edit/isearch/.goto-match: 一致があった場合には is-stdin-ready でも強制的に描画を実行する。
+* ble-edit/isearch: check is-stdin-ready on history search to suspend.
+
+## 2016-05-21
+* update README.md for v0.1.5
+* ble-edit.sh: bugfix, incorrect _ble_edit_ind caused by the inconsistensy of history/isearch targets.
+ - _ble_edit_history を履歴検索して _ble_edit_history_edit をロードしていた事による _ble_edit_ind 不整合
+ これにより、dirty-range の不整合が生じエラーが発生していた。長年の謎のバグがこれで潰れたと思われる。
+
+## 2016-04-07
+* ble-syntax.sh (ble-syntax/parse/shift.impl2): bugfix 制御構造の欠陥による shift 漏れ。
+
+## 2016-01-24
+* ble-syntax.sh: \debug add debug codes for dirty-range bug
+ - ble-edit.sh: dirty range checks
+ - ble-syntax.sh (ble-syntax/parse): remove readonly flag of `beg' and `end' for dirty-range bug
+
+## 2015-12-30
+* modify README: use -O option for curl; release v0.1.4.
+
+## 2015-12-26
+* (ble-color/faces): preserve orders of addhook-onload, and ble-color-{def,set}face.
+ - ble-color/faces 初期化前に呼び出した ble-color/faces/addhook-onload,
+ ble-color-defface, ble-color-setface を独立に記録していた為、
+ 実際に呼び出された順序と異なる順序で処理が実行されてしまっていた。
+ 記録を一つの配列 _ble_faces_lazy_loader にまとめ、順序が保存される様にした。
+
+## 2015-12-25
+* (ble-color) \change ble-color-{def,set}face の処理も遅延する。
+* functions/getopt.sh: \add description.
+
+## 2015-12-24
+* (ble-syntax:bash): :new:, support option `-p` for keyword `time`.
+* (ble-syntax:bash): \new, support `a=([key]=value)` and `a+=([key]+=delta)`.
+ * (ble-syntax): \new local variable `parse_suppressNextStat` in ble-syntax/parse.
+ * (ble-syntax:bash): \bugfix, correct resume for `var+`, `arr[...]+` -> `var+=`, `arr[...]+=`.
+ * (ble-syntax:bash): \new, support `a=([key]=value)` and `a+=([key]+=delta)`.
+* (ble-syntax:bash): \new context CTX_CASE.
+* (ble-syntax:bash): \new CTX_COND{X,I}; \change unexpected '(' is treated as extglob '@(' instead of sub-shell '(';
+ * ble-syntax.sh: `CTX_VAL{X,I}` から `CTX_COND{X,I}` を分離。
+ * ble-syntax.sh: コマンド中に現れる '(' を extglob の括弧として取り扱う事にする。
+ 今迄は暫定的に sub-shell として取り扱っていたが、
+ エラーが多く出てうるさいのでエラーの少ない extglob 括弧として取り扱う事にする。
+* ble-edit.sh: \bugfix histexpand condition [[ -o histexpand ]] inverted.
+ * \bugfix 履歴展開が効かなくなっていた。
+ 条件判定の誤りだった: [[ -o histexpand ]] → [[ ! -o histexpand ]]
+ * \bugfix 履歴展開に失敗した時に : が実行される。
+ 履歴展開が失敗すると history -p は標準出力に何も出力しないためであった。
+ 失敗した時は echo "$BASH_COMMAND" により手動で出力する。
+* (ble-syntax:bash): \support shopt -s extglob; \bugfix error on {delimiter after redirect,'<' redirect};
+ * extglob 対応: `CTX_GLOB`, `ATTR_GLOB`, `ctx-glob`, `check-glob` 追加。
+ * \bugfix redirect 直後に redirect/delimiter があった時に解析データ書き込み違反。
+ * \cleanup: 共通の正規表現の整理:
+ `$_ble_syntax_bash_rex_spaces`,
+ `$_ble_syntax_bash_rex_IFSs`,
+ `$_ble_syntax_bash_rex_delimiters`.
+ * \bugfix `$_ble_syntax_bash_rex_redirect`: < が抜けていた。
+
+## 2015-12-23
+* (ble-syntax:bash): special treatment of arguments of `declare`.
+ * (ble-syntax:bash): declare, typeset, local, export, alias コマンドの引数を文法的に特別に扱う。特に配列構文 =() を許容する。
+ その為に新しい文脈値 `CTX_ARGVX`, `CTX_ARGVI` を追加する。
+ * (ble-syntax:bash): `CTX_ARGVI` に対する補完候補は変数名。等号 '=' 以降の部分についてはファイル名の補完候補を列挙する。
+ * (ble-syntax:bash): 通常の代入構文における配列構文の動作を変更。
+ 今迄は a=(1 2 3)echo などとすると a=(1 2 3) を配列代入と解釈し echo の部分をコマンドと解釈する様にしていた。
+ その為に配列構文の nest-pop 時にすぐに単語を抜けて cxt==CTX_CMDXV になる様に構成していた。
+ しかし、実際の bash の動作を確認してみると、a=(1 2 3)echo は a='(1 2 3)echo' の様に、全体が代入文の右辺と解釈される様である。
+ 実際の bash の動作に合わせて、nest-pop 時に特別な動作を特にしない様に変更した。
+
+## 2015-12-21
+* (ble-syntax:bash): 算術式終了条件修正、bash-3.0 で += 無効; (completion-context): a+= 直後の補完候補生成。
+ * ble-syntax.sh (ble-syntax:bash): 算術式の終了条件を修正する。
+ $((...)) ((...)) の中では '(', ')' を数えて終了判定を行う。
+ $[...]、${arr[...]} arr[...]= の中では '[', ']' を数えて終了判定を行う。
+ ${var:...:...} では '}' が来たらすぐに終了する。
+ * ble-syntax.sh (completion-context): a+= の直後でも補完候補生成を行う。
+ * ble-syntax.sh (ble-syntax:bash): disable += under bash-3.1.
+* ble-edit.sh: bugfix failure of catch C-d in bash-3.0.
+
+## 2015-12-20
+* (ble-highlight-layer:syntax): color of special files, permission of files in redirection.
+ - ble-syntax.sh: bugfix of assertion test in ble-syntax/parse/tree-append.
+ - ble-syntax.sh (ble-highlight-layer:syntax): color filenames of block device, character device, pipe, and socket.
+ - ble-syntax.sh (ble-highlight-layer:syntax): redirection: check permissions.
+* (ble-syntax:bash): bugfix, tree-structure corruption on edit of array subscripts in array-element assignment.
+ - ble-syntax.sh: 配列添字の書き換え時に解析木の破壊が起こる。
+ 配列添字の終了 ']=' において nest-pop を先頭位置で行っていた。
+ これが為に、過去の解析結果を書き換えている事になっていた為に、
+ shift の際に設置した情報が消滅したりしていた。
+* ble-edit.sh: add support `set +o history`; ble-syntax.sh: check file existence on '<' redirection.
+ - ble-edit.sh: add support `set +o history`
+ - ble-syntax.sh (ble-highlight-layer:syntax): check filename of `<` redirections.
+ - ble-syntax.sh (constants): refact,
+ definition of `local rex_redirect` -> global `_ble_syntax_bash_rex_redirect`.
+ rename `_BLE_SYNTAX_CSPACE` -> `_ble_syntax_bash_cspace`.
+ - ble-edit.sh: refact, rename functions `.ble-edit[./]history[./]*` -> `ble-edit/history/*`.
+* complete: 候補生成箇所の追加・修正、コマンド補完候補としてサブディレクトリも列挙
+ - ble-syntax.sh (complete): bugfix, 単語の間の空白で complete を実行しようとしても候補が生成されなかった。
+ - ble-syntax.sh (complete): generate filenames after `VAR='.
+ - ble-syntax.sh (complete): generate filenames just after the redirection.
+ - complete.sh: コマンドの補完候補として現在のディレクトリのサブディレクトリも列挙する様に修正する。
+ サブディレクトリにある実行属性のファイルを実行したい場合がある為である。
+
+## 2015-12-19
+* complete.sh: support `FIGNORE`, `shopt -s force_fignore`.
+ - Makefile: bugfix, remove `ble-getopt.sh` from the required files to generate ble.sh.
+ - complete.sh: support `FIGNORE` and `shopt -s force_fignore`.
+* functions/*: move unused file ble-getopt.sh to `functions/`. Add new impl of getopt.
+* ble-syntax.sh (ble-syntax:bash): redirections: bugfix '<<<', support '>|', overwrite check of files, etc.
+ - ble-syntax.sh (ble-highlight-layer:syntax): Support `set -o noclobber`; Check overwrites of target files of redirections for '>', '&>', and '<>' redirect.
+ - ble-{core,decode,edit}.sh, bind.sh, term.sh, emacs.sh: change redirection '>' -> '>|' for the case of the noclobber option on.
+ - ble-syntax.sh (ble-syntax:bash): support the redirect using `>|`.
+ - ble-syntax.sh (ble-syntax:bash): bugfix false syntax error of `<<<`.
+ - ble-syntax.sh (ble-syntax:bash): bugfix redundant skip on unexpected termination of redirect by an end of command or another redirection.
+ - ble-syntax.sh (ble-syntax:bash): bugfix, do not allow newline after the redirection introducers.
+* ble.pp, ble-core.sh: Check and modify dependencies on external commands.
+ - ble.pp (ble/.check-environment): Remove tput (POSIX UP option) which is not necessarily required.
+ - ble-core.sh (ble-term/visible-bell): Add a function `ble/util/getmtime` to get modified time of files in a compatible way.
+ - ble-edit.sh (ble/widget/command-help): Select available pager from any of $PAGER, less, more, and cat.
+* ble-syntax.sh: syntax: quotations in words in parameter expansion (shopt -u extquote, etc.).
+ - ble-syntax.sh: support single quotation in parameter expansion.
+ - ble-syntax.sh: support shopt -u extquote.
+* clean up & minor behavior change: Check bash opts --{posix,noediting,restricted}, Unset mark on accept-line.
+ * bug fix
+ - ble-syntax.sh (ble-syntax:bash/extract-command/.construct-proc): remove a debug code which prints the message "clear words".
+ * minor behavior change
+ - ble-edit.sh (ble/widget/accept-line): redraw without mark.
+ - ble.pp (startup check): do not load ble.sh for bash --posix, --noediting, or --restricted.
+ * clean up
+ - ble-decode.sh (ble-decode-byte:bind/EPILOGUE): use ble/util/is-stdin-ready instead of the direct use of `read`.
+ - ble-core.sh (ble/util/is-stdin-ready): use LANG instead of LC_ALL.
+ - ble-edit.sh, ble-syntax.sh: use [[ -o histexpand ]] rather than [[ $- == *H* ]].
+ - ble-syntax.sh (test): remove unused functions `.ble-shopt-extglob-push`, and `.ble-shopt-extglob-pop` for test.
+ - ble-edit.sh: remove old complete functions:
+ - .ble-edit-comp.initialize-vars
+ - .ble-edit-comp.common-part
+ - .ble-edit-comp.complete-filename
+ - ble/widget/complete
+ - ble/widget/complete-F
+ - ble-syntax.sh, complete.sh: no need of redirection for `shopt -q optname`.
+
+## 2015-12-09
+* Refactoring ble-edit.sh/ble-line-prompt.
+ * .ble-line-prompt -> ble-edit/prompt.
+ * `_ble_cursor_prompt`, `_ble_line_prompt` -> `_ble_edit_prompt`.
+* Refactoring ble-core.sh, ble-color.sh, cmap/xterm.sh.
+ * ble-core.sh: .ble-text.* -> ble/util/*.
+ * ble-color.sh: .ble-color.* -> ble-color/.*.
+ * cmap/xterm.sh: .ble-bind.function-key.* -> ble-bind/cmap:xterm/*.
+* Refactoring ble-decode.sh.
+ * ble-core.sh: .ble-term.{visible,audible}-bell -> ble-term/{visible,audible}-bell.
+ * ble-decode.sh: .ble-stty.* -> ble-stty/*.
+ * ble-decode.sh: .ble-decode-* -> 適切な名称に変更。
+* Refactoring and clean up.
+ * ble-edit.sh, etc: 'ble-edit+' -> 'ble/widget/.
+ * 'ble-edit.sh: ble-edit/exec 関数名整理。
+ * ble-decode.sh: ble-decode-byte 関数名整理、ble-edit 依存性分離。
+ * README-ja_JP.md: 日本語説明修正。
+ * README.md: 英語修正。
+ * ble-syntax.sh: コードコメント @fn -> 関数 に統一。
+
+## 2015-12-06
+* ble-core.sh: Add function ble/util/cat to replace /bin/cat.
+ - ble-core.sh: 関数 ble/util/cat。command cat の単純な呼出と同じ機能を builtin read で実装。
+ - ble-decode.sh (ble-bind --help): 外部コマンドの cat を呼び出していたが、bash の組込コマンドで実現できるので置き換え。
+ - README.md: gmake/make について説明を追加。
+* Update README-ja_JP.md
+* ble-bind: New option `-L, --list-functions`, ble-color.sh bugfix initialization of faces:region,disabled,overwrite_mode.
+ - ble-color.sh: bugfix, 色初期化 (region disabled overwrite_mode) 遅延ロードに登録していなかった。
+ - ble-decode.sh (ble-bind): New option `-L, --list-functions` to list edit functions.
+
+## 2015-12-03
+* Changed default value of bleopt_char_width_mode from `emacs` to `east`.
+* Update README-ja_JP.md.
+* Add README-ja_JP.md. 日本語の説明。
+* optimization: lazy init of faces (ble-{syntax,color}.sh), removal of temporary files (ble-core.sh).
+ * ble-syntax.sh, ble-core.sh: lazy initialization of `_ble_faces_*`.
+ * minor: modify messgese: initialization message, the header of the script ble.sh.
+ * ble.pp: Add pp switch `measure_load_time` to identify the initialization bottle neck.
+ * ble-core.sh (`_ble_base_tmp.wipe`): optimization, use parameter expansion instead of regex captures.
+* Support here string, shopt -q progcomp; Bugfix ble-syntax/parse/nest-equals.
+ * ble-syntax.sh: support here string.
+ * ble.htm: comment out outdated descriptions.
+ * ble-syntax.sh (ble-syntax/parse/nest-equals): bugfix, 前回の bugfix で onest[3]<0 の場合を考えていなかった。
+ * complete.sh: shopt -q progcomp によるプログラム補完の有効・無効の切り替え。
+* update version numbers.
+* ble-syntax.sh (ble-syntax/parse/nest-equals): fatal bugfix, misjudge on nest equality test causing nest structure corruption.
+ * Note: _ble_syntax_nest の要素に含まれている nest 開始位置は相対位置で記録されているにも拘わらず、絶対位置の変数に直接代入していた事が原因であった。
+ * 他 ble-syntax.sh, ble-color.sh: compatibility fix., fgrep to command grep -F.
+* README.md: correct download links.
+* `*.sh`: Add `command` for external command execution.
+* (ble-edit/stderr for bash-3.0): Add ignoreeof-message.txt for C-d message i18n.
+* `*.sh`: New marker `__ENCODING__` for 文字コード依存部分
+
+## 2015-11-30
+* complete.sh (ble-complete/source/argument): minor bugfix, default behavior using comp_opts exported by func .../.compgen.
+ * 他 ble.pp: check chmod.
+* Makefile: a phony target `dist`.
+* memo.txt: todo 整理.
+* complete.sh: bugfix, completion doesn't work on an argument without complete -D spec.
+* ble-edit.sh (ble-edit+isearch/next): bugfix, didn't match locally on self-insert of forward isearch.
+* ble-decode.sh (generate-source-to-unbind-default): bugfix, need of LANG=C.
+ * LANG=C を設定しないと bind -sp の出力に変なバイトが含まれている為に解釈に失敗する。
+ (utf-8 の様な ASCII 文字を含まない様な文字コード体系の場合にはこれで問題ないが。
+ memo.txt に Note(2015-11-30) として追加する。)
+* Update README.md
+* ble-edit.sh: remove dependency on GNU awk.
+ * ble.pp: 念の為 gawk に戻す事ができる様に use_gawk (PP変数) を用意する。
+ * ble.pp (ble/.check-environment): check awk.
+ * ble-core.sh (ble/util/array-reverse):(awk scripts):
+ + uninitialized variable `decl` を初期化する。
+ + locale dependent な /[a-z]/ の類を POSIX 括弧 (/[[:alpha:]]/, /[[:alnum:]]/) に置き換え。
+ * ble-edit.sh (.ble-edit/history/generate-source-to-load-history):(awk scripts): uninitialized variable `n`.
+ * ble-decode.sh (.ble-decode-bind/generate-source-to-unbind-default):(awk scripts):
+ + 引数名と大域変数が被らない様にする。
+ + gawk 特有の機能 (/\y/, match 第三引数) を使わない。
+ + bugfix, gsub の対象の変数が指定されていない箇所があった。
+ * それぞれ gawk --lint 及び nawk でも動作を確認した。
+
+## 2015-11-29
+* ble-edit/isearch: 現在のコマンド内も検索対象に。
+ * 旧来の履歴項目検索機能を改名:
+ - ble-edit+isearch/forward -> ble-edit+isearch/history-forward,
+ - ble-edit+isearch/backward -> ble-edit+isearch/history-backward,
+ - ble-edit+isearch/self-insert -> ble-edit+isearch/history-self-insert.
+ * 検索履歴 (_ble_edit_isearch_arr) に一致範囲も記録する様に変更
+ * 現在の位置からコマンド内を検索する関数を追加・旧関数を置換:
+ - ble-edit+isearch/forward,
+ - ble-edit+isearch/backward,
+ - ble-edit+isearch/self-insert.
+* ble-edit.sh (+isearch/next): 一致範囲を囲む。
+ * ble-edit.sh (+isearch/next), set region to matched range.
+ * ble-edit.sh: pattern matching using [[ text == pattern ]] instead of case statement.
+ * ble-color.sh (ble-syntax-layer:region/update): bugfix, PREV_UMIN/PREV_UMAX out of range due to the shift failure of omin/omax.
+* ble-core.sh: full support for bleopt_input_encoding=C
+ * ble-core.sh: Add functions: ble-text-b2c+C, and ble-text-c2b+C.
+ * ble-core.sh (.ble-text.c2bc): rename .ble-text.c2bc -> ble-text-c2bc.
+ * .gitignore: 古い物を整理。/wiki 追加。
+
+## 2015-11-28
+* Update README.md
+* ble-decode.sh, ble-edit.sh: support `bind -xf`.
+ * ble-core.sh: Add functions ble/string#common-{prefix,suffix}.
+ * ble-decode.sh, ble-edit.sh: support `bind -xf COMMAND`.
+ * ble-edit.sh:714: ^M が直接埋め込まれていると GitHub が改行位置を勘違いする様なので $'\r' に修正する。
+ * complete.sh: embedded sed scripts, POSIX compliance.
+* ble-color.sh: Add a function ble-color-show.
+* README.md: Add animation gif.
+* README.md: settings for syntax highlighting.
+* README.md: Add some description of settings.
+
+## 2015-11-27
+* Create LICENSE.md
+* Update README.md
+
+## 2015-11-24
+* ble-edit.sh (+magic-space): bugfix, 現在のカーソル位置よりも前の部分に対して履歴展開する。
+* complete.sh: behavior of source/argument, compopt -o/+o, bugfix.
+ - complete.sh (ble-complete/source/argument): complete -o ..., compopt -o option +o option の読み取り。
+ - complete.sh (ble-complete/util/escape-regexchars): bugfix.
+ - complete.sh: Add action/plain, action/argument, action/argument-nospace.
+ - complete.sh: Add source/dir.
+ - complete.sh (ble-complete/source/argument): support -o nospace, -o dirnames.
+* complete.sh (ble-complete/source/argument): bugfixes.
+ * ble-complete/source/argument/.compgen-helper-prog: Export `COMP_LINE` `COMP_POINT` `COMP_KEY` `COMP_TYPE`
+ * ble-complete/source/argument/.compgen-helper-{prog,func}: Pass arguments `command`, `cur`, and `prev` for program/function.
+ * ble-complete/source/argument: Fix option -F, -C interruption failure.
+ * ble-complete/source/argument: Fix -F <-> -C miss arrangement.
+ * ble-complete/source/argument: Correct IFS when compgen is called.
+ * ble-complete/source/argument: `return 1` if no candidates are generated.
+ * ble-complete/source/argument: Evaluate `compgen` in the original shell (i.e., not in a sub-shell).
+ * ble-complete/source/argument: Filter and modify candidates generated by `compgen` using `sed`.
+
+## 2015-11-23
+* ble-edit.sh (ble-decode): show the message to run "stty sane" after "ble-detach".
+* ble-syntax (ble-syntax:bash/extract-command): bugfix, 出力用の変数が local 指定になっていたのを削除。
+ - 他: complete.sh: compgen -F prog -C cmd の際に compgen が警告を出すので compgen 2>/dev/null とする。
+* complete.sh: complete -p による補完の基本実装。
+ * ble-core.sh: Create function ble/util/array-reverse.
+ * ble-decode.sh (.ble-decode-keys, .ble-decode-key/invoke-command): bash-3.0 workaround, local -a keys=(), local -a KEYS=() を2行に分ける。
+ * ble-syntax.sh: complete 用の整備。
+ * 関数追加 ble-syntax/tree-enumerate-break: "((tprev=-1))" は意図が分かりにくいので。
+ * 関数追加 ble-syntax:bash/extract-command:
+ * ble-syntax/tree-enumerate: シェル変数 iN の既定値を _ble_syntax_text の末端に。
+ * ble-syntax/completion-context: CTX_VALI, CTX_VALX に対応。
+ * ble-syntax/completion-context: 一部の補完文脈を file から argument に変更。
+ * complete.sh: complete -p 設定に基づく補完。
+ * ble-complete/source/argument: 追加
+
+## 2015-11-22
+* ble-syntax.sh: bash 文法関連の関数名整理。
+ * ble-decode.sh (ble-bind): error message に . を追加。古いコメントを削除。
+ * ble-syntax.sh (ble-syntax/parse/{check,ctx}-*): bash 文法特有の関数の名称を整理。
+
+## 2015-11-21
+* cmap/cmap+*.sh: Update for current ble-decode.sh.
+* ble-edit.sh (ble-edit+magic-space): Add edit function magic-space.
+
+## 2015-11-19
+* Support of PROMPT_COMMAND, and function bleopt.
+ * ble-edit.sh: easy support of PROMT_COMMAND.
+ * ble-core.sh: bleopt 関数追加。
+ * ble-decode.sh (.ble-decode-initialize-cmap): POSIX sed BRE does not support the quantifiers: \+, \?.
+* ble-syntax.sh: 履歴展開をより正確に。
+ * histchars に応じた履歴展開の解析
+ * extglob が設定されている時は !( は履歴展開と解釈しない
+ * 文字列 "~" 中の履歴展開は " の直前で終わる
+* ble-core.sh: workaround for bash-3.0 regex in _ble_base_tmp.wipe.
+
+## 2015-11-17
+* `ext/mwg_pp.awk`: Include mwg_pp.awk in ext; Makefile (listf): renamed to list-functions and modified.
+* ble-syntax.sh (ble-syntax/parse/nest-equals): bugfix (operater associativity), incorrect break of loops.
+
+## 2015-11-09
+* ble-core.sh (_ble_base_tmp.wipe): bugfix, correct iteration of old tmp files.
+
+## 2015-11-08
+* complete.sh: ユーザ入力があった時の候補列挙の中断に対応 (bash-4.0 以降); ble-syntax.sh: コメント判定の修正。
+ * ble-core.sh (ble/util/is-stdin-ready): 関数追加。標準入力に未処理の文字が残っているかどうかを判定。ユーザの入力が待ち状態になっているかどうかを判定する為の物。
+ * ble-syntax.sh (ble-syntax/parse/check-comment): コマンドライン解析時 shopt -u interactive_comments の時にはコメントは無効とする。
+ * ble-syntax.sh (ble-syntax/parse/check-comment): bugfix コメント開始判定(単語頭)。単語開始の判定が単語頭ではなく「単語頭または単語内部の解析開始点の位置」という事になっていた。
+ * complete.sh (ble-complete/source/command/gen, ble-edit+complete): コマンド候補の列挙・一致判定には時間が掛かるので ble/util/is-stdin-ready を用いて中断の判定を実行する。
+
+## 2015-11-07
+* Update README.md
+* ble.pp: check environment for required commands, ble-edit.sh: 'M-\'.
+ * ble.pp: check required commands.
+ * ble-core.sh: remove dependencies on `touch' command.
+ * ble-edit.sh, keymap/emacs.sh: Add edit function: delete-horizontal-space ('M-\').
+
+## 2015-11-06
+* ble-syntax.sh: cleanup debug codes.
+* ble-syntax.sh (ble-syntax/parse/shift.nest): bugfix, parse error by shift failure of _ble_syntax_nest.
+
+## 2015-11-25
+* Create README.md
+
+## 2015-08-25
+* m, bugfixes.
+ * PS1 の '!' の処理、
+ * PS1 の \w の処理、
+ * (bash-3.0) history '!1' &>/dev/null によるチェックでエラーメッセージが漏れていた。
+* bugfix, specify explicit collation order for regs and globs.
+ * Character ranges in regular expressions and glob patterns are dependent on collation order.
+ * To obtain the desired results for ascii characters, `local LC_COLLATE=C' should be explicitly specified.
+
+## 2015-08-24
+* ble-edit.sh (.ble-edit.history-add): bugfix, handling of HISTCONTROL.
+
+## 2015-08-19
+* bin/ble-edit.sh: bugfix for bash-3.0, history -s が正しく動作しないので修正。
+
+## 2015-08-18
+* bugfix and cleanups.
+ * ble-core.sh (ble-assert): bugfix, correct return value.
+ * ble-edit.sh, ble-synta.sh: bash-3.0 bugfix, `local arr=(...)' form cannot be used in bash-3.0.
+ * ble-edit.sh (hist_expanded.initialize): renamed to `ble-edit/hist_expanded.initialize'.
+
+## 2015-08-16
+* 消滅単語に対する色解除の対策(暫定)。
+ * ble-syntax.sh (ble-syntax/parse): 消滅単語の範囲集計。
+ * ble-syntax.sh: 範囲更新・並進の整理。関数 ble/util/[uw]range#{update,shift} の追加。
+* 表示系統 bug fixes.
+ * ble-edit.sh (ble-edit/dirty-range/update): bugfix, endA0 の読み出しに誤り、変数名 delta/del に誤り。
+ * ble-syntax.sh (ble-highlight-layer:syntax/update-attribute-table): bugfix in umin/umax update, umax の更新に使う変数名を誤っていた。
+* 組込コマンド上書き対策。ble-syntax shift bufgix for bash-4.2 算術式。
+ * ble-syntax.sh (bash-4.2): bugfix, ble-syntax/parse/shift.{tree1,nest} の算術式で bash-4.2 をクラッシュされる形式の物が見付かった。
+ * ble-core.sh: ble/util/set 関数を追加。
+ * ble-edit.sh: builtin 上書きを防ぐ為に unset -f builtin を実行 (builtin, unset 両方上書きされると駄目だが)。
+ * ble-edit.sh: return/break/continue も上書きを禁止する。
+ * ble-*.sh: test の代わりに [[ ]] を使用。
+* 貼付時の再描画抑制 (read -t 0 による判定)。\x80-\x9F を M-^? で表示。
+ * ble-edit.sh: 編集文字列内の \x80-\x9F の表示を M-^? に。表示が乱れていた。
+ * ble-edit.sh (ble-decode-byte:bind): 次の文字が来ている時に再描画を抑制。
+ * ble-edit.sh: exec/gexec 周りの関数名を整理。
+ * ble-edit.sh: 関数削除 .ble-edit-isearch.create-visible-text
+
+## 2015-08-14
+* 構文 function ... に対応、履歴展開 bugfix.
+ * ble/src: .srcoption 追加。
+ * ble-syntax.sh: defface 関数の色の変更。
+ * ble-syntax.sh: 構文 `function ...` に対応。
+ * ble-syntax.sh: `function ...`, `hoge ()` の直後に来るコマンドを compound-commands に制限。
+ * ble-edit.sh: bugfix, set +H の時も履歴展開が有効になっていた。history -p は set +H と関係なく展開を行う。
+ * ble-edit.sh: bugfix, 関数 echo を定義するとコマンドがそれ以上実行できなくなる。echo/printf を builtin を介して呼び出す様に変更。
+* ble/util/assign cleanup, ble/util/type add, .ble-line-prompt/update bugfix.
+ * ble-core.sh (ble/util/assign): cleanup, ble/util/sprintf, ble/util/type, ble/util/isfunction でも仕様,
+ * ble-core.sh: ble/util/type 追加。$(type -t) はこれを用いて処理する様に変更,
+ * ble-edit.sh (.ble-line-prompt/update): bugfix, 地の文の '$' や '`' が escape されてしまい展開されない.
+* ble-edit.sh: プロンプト更新最適化。
+* ble-core.sh (ble/util/assign): $(...) 高速化用関数。
+* shift 高速化、入れ子構造を考慮に入れた単語着色に対応。
+ * ble-syntax.sh (ble-syntax/parse/shift): 入れ子構造を考慮に入れた shift,
+ * ble-syntax.sh (_ble_syntax_tree): 単語毎の着色情報をデータ配列内に保持するように変更,
+ * ble-syntax.sh (ble-highlight-layer:syntax/update-word-table): 入れ子構造を考慮に入れた着色.
+* leak variables: g cs
+* cleanup, leak variables 処置.
+* ble-syntax.sh: 終端していない節も列挙対象に含める。他整理。
+ * ble-syntax.sh (ble-syntax/print-status): prints unterminated nodes.
+ * ble-syntax.sh: add new functions ble-syntax/tree-enumerate, ble-syntax/tree-enumerate-children.
+ * ble-syntax.sh: rename shell variable: _ble_syntax_word -> _ble_syntax_tree.
+ * ble-syntax.sh: cleanup.
+
+## 2015-08-13
+* ble-syntax.sh: clenup, print-status/dump-tree.
+* ble-sytanx.sh (_ble_syntax_stat): 解析状態に tchild, tprev (兄・子へのoffset情報) を追加。
+* ble-sytanx.sh (_ble_syntax_word): 形式変更。兄・子へのoffset情報はその場で計算する暫定方式。
+
+## 2015-08-12
+* memo.txt: _ble_syntax_word 形式変更の計画, ble-syntax.sh: clean up
+
+## 2015-08-11
+* ble-syntax.sh (`_ble_syntax_nest[]`): 形式変更 → "ctx wlen wtype nlen type"
+* ble-syntax.sh (`_ble_syntax_stat[]`): 形式の変更 → "ctx wlen wtype nlen"
+* ble-syntax.sh (`_ble_syntax_word[i]`): 要素の形式を wtype wbegin から wtype wlen に変更
+* ble-edit.sh (.ble-line-info.draw): 制御文字も入れられる様に,
+* ble-syntax.sh (ble-syntax/print-status): Added,
+* ble.pp: 二重起動対策,
+* ble-edit.sh: history load.
+
+## 2015-08-08
+* ble-syntex.sh (ble-syntax/completion-context/check-prefix): completion at redirect filenames.
+
+## 2015-07-10
+* memo.txt: Added todos.
+
+## 2015-06-15
+* modified complete.sh
+
+## 2015-03-22
+* ble-decode.sh: bugfix, bash-4.1 でも ESC [ を翻訳しないと駄目
+* ble-decode.sh: bugfix, bash-4.1 でも ESC * に登録しないと駄目
+* ble-core.sh, etc.: 一時ファイルを tmp/$UID に置く事にする。
+
+## 2015-03-12
+* ble-syntax.sh (ble-syntax/parse): stat の設定されていない箇所に word があり、shift されていなかった。
+
+## 2015-03-08
+* ble-edit.sh (ble-edit/draw/trace): bugfix, LC_COLLATE を設定して正規表現を使用する様に修正。
+* bashbug related bugfix: 幾つかの bugfix, 全て bash のバグが関係していた…。
+ - `<bug>` bash-4.1 以下でカーソルの表示位置がずれている。
+ - `<bug>` bash-4.2, 4.0, 3.2, 不完全な編集内容に対してエラーが出る
+ - `<bug>` bash-4.0, 4.1 でプロンプトが表示されない
+ - `<bug>` bash-4.1 以下でプロンプトの色が着かない
+* ble-decode.sh (.ble-decode-char): control/alter/meta/shift/super/hyper prefix が、
+ その場で自身に適用されて出力されていた。
+* ble-core.sh (ble/util/declare-print-definitions): 連想配列に対応
+* ble-decode.sh, 他: オプション名 ble_opt を bleopt に統一
+* ble-decode.sh: .ble-decode-char 再実装
+ - 修飾機能を send-modified-key (旧 sendkey-mod) に合流
+ - C-x @ S 等、ESC 以外の修飾にも対応
+ - .ble-decode-char/csi/* による CSI sequence の解釈
+ - 新実装に対応する様に cmap/default.sh を書き直し
+
+## 2015-03-06
+* ble-decode.sh (stty): -icanon の設定。
+* ble-edit.sh (PS1): bugfix, job count, 時刻その他の更新。
+* ble-edit.sh (.ble-line-text/update/postion)
+ - bugfix: ascii printable characters の行末で \n を付加した時 ichg に登録していなかった。
+ - bugfix: _ble_util_string_prototype の長さ指定に 0 を指定していた
+ - bugfix, 行末付近での tab の取り扱い
+ - 制御文字も追い出しの対象に。
+ - xenl の時、行末で必ず \n を追加する (追い出しの場合なども含め)。
+ - 追い出しがあった場合にそれを記録する。
+* ble-edit.sh (.ble-line-text/getxy.cur): カーソル位置を取得する為の getxy を新規作成。
+* ble-edit.sh (ble-edit/draw/trace): 描画属性
+ - term.sh: 描画属性について terminfo から読み取る様に。
+ - ble-color.sh: 描画属性の点滅、不可視、イタリック、打ち消し線に対応。
+ - ble-color.sh: sgr 構築で term.sh の結果を利用する様に変更。
+ - ble-edit.sh (.ble-line-prompt): ble-color-g2sgr で端末に依存しない PS1 を書ける様に変更。
+* ble-decode.sh (ble-decode-kbd): bugfix, 複数キーがある場合に正しく処理できていなかった
+* overwrite-mode に対応
+* ble-syntax.sh, ble-color.sh: layer:syntax による色付けを face を介した物に変更。
+* ble-decode.sh, ble-edit.sh: 条件コマンドの統一。test や [ 等を [[ に統一。
+
+----
+
+<!---------------------------------------------------------------------------->
+# Old ChangeLog
+
+## 2015-03-03
+
+ * ble-edit.sh, ble-edit.color: discard-line の際に着色
+ * ble-edit.sh, ble-core.sh, etc: echo を builtin echo に。
+ * ble-edit.sh: bugfix, 複数行で上に行けない
+ * ble-edit.sh: bugfix, 複数行なのに空行の accept-line でのずれ量が1行になっている
+ * プロンプト再実装
+ - ble-edit.sh (ble-edit/draw/trace): escape sequences が含まれている文字列の位置追跡。
+ - ble-edit.sh (.ble-line-prompt/update): プロンプトの構築を再実装。$() がある場合なども正しい計算。
+ * ble-complete.sh (source/command): shopt -s autocd の時にディレクトリ名も候補として列挙。
+ * ble-complete.sh: 補完候補の選択の方法を変更。より近くの開始点の物を優先。
+
+## 2015-03-01
+
+ * ble-edit.sh: .ble-edit-draw.goto-xy, .ble-edit-draw.put 廃止
+ * complete.sh: 関数名に / が入っていると compgen -c で列挙されないので、別に列挙する。
+
+## 2015-02-28
+
+ * 初期化の最適化
+ - ble-decode.sh: ble-decode-kbd 書き直し、ble-bind 書き直し
+ - ble-getopt.sh: 多少最適化
+ - ble-decode.sh: bash-4.3 でも ESC [ を utf-8 2-byte code で受信する様に変更。
+ - ble-decode.sh (.ble-decode-bind/generate-source-to-unbind-default): awk 呼出を一回に統合。
+ - ble-decode.sh (.ble-decode-key.bind/unbind): [[ ]] による書き換え、bugfix。
+ - ble-decode.sh, bind.sh: bind -x を生成する為のコードを bind.sh に分離。
+ - ble-edit.sh, keymap.emacs.sh: keymap 初期化部分の分離、キャッシュ化。
+ - ble-edit.sh: history 遅延ロード対応
+ * ble-core.sh, ble-color.sh: .ble-shopt-extglob-push/pop/pop-all 廃止
+ * ble-edit.sh: bugfix, .ble-line-info.clear で位置がずれる
+ * ble-edit.sh: ble-edit/draw/put.il, ble-edit/draw/put.dl
+ * ble-color.sh (ble-highlight-layer/update/shift): 長さが変わらない場合でも shift する。
+ * ble.pp (include ble-getopt.sh): 現在使っている所がないので取り敢えず外す。
+ * ble-syntax.sh (completion-context): 簡単なパラメータ展開に対する対応。
+
+## 2015-02-27
+
+ * [bug] TAB 等の変更文字があった場合に文字列が表示されなくなる
+ * bash-3.0, 3.1 対応
+ "[bug] bash-3.1 日本語の色付け・描画が変だ"
+ - ble-edit.sh, 他: @bash-3.1 bashbug workaround, ${param//%d/x} などは効かないので %d を '' で囲む。
+ - ble-syntax.sh, 他: @bash-3.1 bashbug workaround, x${#arr[n]} はバイト数を返す様なので一旦通常変数に入れて ${#var} とする。
+ - *.sh: @bash-3.0: += 演算子の置き換え、配列宣言の修正。
+ - term.sh: @bash-3.0: bashbug workaround, declare -p で出力すると誤った物になる。
+ * ble-edit.sh (.ble-line-text/update/slice): bugfix, 変更文字がある時にもう存在しないローカル変数を参照していた。
+ * ble-core.sh: ble-load, ble-autoload
+ * complete.sh:, ble-syntax.sh, ble-edit.sh: 文脈依存補完の実装
+
+## 2015-02-26
+
+ * ble-syntax.sh: a+=( a=( に対応
+
+## 2015-02-25
+
+ * ble/term.sh: TERM 依存の部分を分離。キャッシュ化。完全移行ではないが徐々に。
+ * ble-decode.sh:
+ - [bug] $_ble_base/cache の代わりに $_ble_bash/cache を作成していた
+ - [bug] accept-single-line-or-newline が二回目以降常に accept
+ * ble-edit.sh:
+ - [bug] 複数行の編集時に履歴移動をすると表示が乱れる
+ - printf %()T を用いた実装の導入、PS1 \D{...} に対応
+ - [bug] 表示の属性の更新がうまく行かない事がある。
+ - [bug] 編集文字列の行数が変わった時に info.draw の内容がずれる
+ * カーソル移動
+ - ble-edit: 複数行編集と項目内でのカーソル移動に対応
+ - ble-edit.sh: 複数行コマンドの履歴に対応。
+ * ble-syntax.sh: ble-syntax-highlight+syntax を ble-highlight-layer:syntax に書き換え
+ * ble-syntax.sh:
+ - 関数定義 func() の形式に対応、
+ - 条件式 [[ ... ]] と配列初期化子内の文脈に対応。
+ - コメントに対応。
+ - $[...] の形式に対応 (何故か bash の説明には一切載っていないが使える)。
+ - [bug] invalid nest " $()" の先頭に for を挿入した時
+
+## 2015-02-24
+
+ * ble-edit.sh 出力の部分更新に対応 (描画ちらつき対策)
+ * ble-syntax.sh: _ble_syntax_word, _ble_syntax_stat の形式の変更
+ * ble-syntax.sh: 今迄行っていた dirty-range 拡大の方法を止めて、単に stat の削除を行う。
+ * ble-syntax.sh: 及び上記の変更に伴う数々の bugfix
+ - [bug] 文字削除時 invalid nest の assertion に引っかかる。
+ - [bug] 編集内容が零文字になった瞬間に改行が起こって表示が消える。
+ - [bug] 改行しても先頭がコマンドになっていない
+ - [bug] _ble_region_highlight_table で空欄になっている箇所がある。
+ - [bug] 単語の属性適用が後ろに続く単語にも続いている。
+ - [bug] _ble_syntax_attr の中に "BLE_ATTR_ERR" の文字列が混入している。
+ - 残っている dirty 拡大と _ble_syntax_word[] の廃止された形式に対する処理の
+ コメントアウトされた部分を削除。dirty 拡大の変更に伴う効率化の確認と、
+ shift が遅いという事の ToDo 項目の追加。
+ * ble-decode.sh: [bug] $_ble_base/cache の代わりに $_ble_bash/cache を作成していた
+ * ble-edit.sh: ble-edit+delete-backward-xword の類の動作を変更。
+
+## 2015-02-23
+
+ * ble-core.sh: ble-stackdump, ble-assert
+ * [bug] update-positions で dend-dbeg が負になると警告が出る
+ * [bug] info.draw で特殊文字が改行に跨っている時の座標計算
+
+## 2015-02-22
+
+ * ble-edit.sh: [bug] .ble-line-info.draw を使った時行がずれる
+ * ble-syntax.sh: [bug] for や do に色が着かない?
+ * レイヤー化
+ - ble-color.sh: レイヤーの仕組み、レイヤ region, adapter, plain + RandomColor
+ - ble-edit.sh: レイヤーに対応した表示文字列構築関数。古い構築関数の削除。出力関数の変更。
+ - ble-syntax.sh: 多少の変更。
+
+## 2015-02-21
+
+ * 描画の高速化
+ - ble-syntax.sh: 属性値の変更範囲に応じて適用を行い、変更範囲を LAYER_MIN, LAYER_MAX に返す様に。
+ - ble-edit.sh: 表示用の文字列の構築部分を書き直して部分更新に対応。
+ - ble-syntax.sh: 内容に変化のあった word の範囲も記録する様に変更。
+ - ble-syntax.sh (parse): _ble_syntax_attr_umin (属性値の変更範囲),
+ _ble_syntax_word_umin (word の変更範囲) の累積に対応する為に、これらについても shift を実行する。
+
+## 2015-02-20
+
+ * ble-decode.sh: bind 周り
+ - bash-4.3 C-@ を utf-8 2-byte code で受信する様に変更
+ - bash-3.1 ESC [ を utf-8 2-byte code で受信する様に変更
+ - bugfix, \C-\\ \C-_ \C-^ \C-] に bind できなくなっていた。
+ - bind の version 分岐について整理。
+ - 既存の bind を ESC に関係なく bind -r する。
+ * ble-decode.sh: .ble-decode-key 部分一致探索の処理の再実装。変な動作だった。
+ * ble-decode.sh: bugfix, 8bit 文字を正しく bind できていない。c2s で8bit文字が符号化されていた。
+ * ble-syntax.sh: 履歴展開は $- に H がある時のみ有効に。
+ * ble-syntax.sh: bugfix, bash-4.2 のバグの work around。配列を参照する算術式の書き換え。
+ * ble-core.sh: c2s を bash の機能だけで実装できたので fallback を replace。
+ * ble-core.sh: bash-4.0 で .ble-text.s2c を連想配列でメモ化
+ * ble-edit.sh: bugfix, bash-4.0 で ret に予め特定の値が入っていると c2w に失敗する。
+ * ble-edit.sh: bugfix, bind -x 直前のプロンプトの取り扱いは bash-4.0 では bash-3 系と同じ。
+ * ble-edit.sh (.ble-line-text.construct 周り): lc lg を後で計算する様に変更。一区切り。一旦 commit する。
+
+## 2015-02-19
+ * ble-syntax.sh: 履歴展開に対応。
+ * ble-decode.sh: bugfix, bind -X から bind -x を生成するコード。
+ bind -X の出力する形式は再利用不可能な形式でエスケープされているのでこれを変換。
+ * ble.pp, etc: noattach 引数に対応。ble-attach/ble-detach 関数の定義。detach の bugfix。
+ * ble-edit.sh: bug, bleopt_suppress_bash_output= にした時にプロンプトが二重になる
+
+## 2015-02-18
+
+ * ble.pp, ...: ディレクトリの構成を変更
+ * ble-syntax.sh: 文法の対応
+ - プロセス置換を単語として扱う様に変更
+ - リダイレクトの後の引数に対応
+ - リダイレクトの前の fd 部分に対応
+ * bash-3.1 対応
+ - ble-edit.sh: bash-3.1 で C-d を捕捉できる様に(結構無理のある方法だが)。
+ - ble-edit.sh, ble-decode.sh: bugfix, bash-3 でカーソルキーの類が動かない。履歴が読み込まれていない。
+ - ble-edis.sh: bash-3.1, bleopt_suppress_bash_output=1 の方が安定して動いているのでこちらで行く。
+ - ble-edit.sh: bash-3.1, カーソルキーが効かない。例によって ESC [ ... に関係するコマンドで
+ keymap が見付からないエラーになっている。これは ESC [ を CSI (utf-8) に変換してから読み取る事にした。
+ - ble-syntax.sh: bash-3.2.48 のバグの work-around, (()) 内で配列要素を参照すると制御が無条件に其処に跳ぶ。
+
+## 2015-02-17
+ * ble-edit.sh (ble-edit/dirty-range): 範囲更新の仕組みを追加。
+ _ble_edit_dirty はプロンプト再描画の判定も兼ねているので取り敢えず残す。
+ * ble-edit.sh: 変数リーク (グローバル変数の汚染) の修正。line i
+ * ble-syntax.sh (ctx-command/check-word-end): 単語終了判定の処理タイミングを変更。
+ * ble-syntax.sh: context の追加。CTX_CMDXF CTX_CMDX1 CTX_CMDXV CTX_ARGX0
+ より正確な文脈判定・エラー検知。
+ * ble-syntax.sh: 他にも多くの修正がある。未だ修正が続きそうなので一旦 commit する。
+
+ * ble-edit.sh (accept-line): bug, - で始まるコマンドを実行できない。
+ * ble-color.sh: [bug] bg=black を設定しても反映されない。
+ "未設定" と "黒" を区別する様に修正。
+ * ble-syntax (ble-syntax-highlight+syntax): 入れ子エラーの色の範囲
+ * ble-syntax: m, ;& は ;; ;;& 等と同じ取り扱い
+ * ble-syntax, etc: bash-3 正規表現対策。bash-3/4 の正規表現の違いに依存しない書き方に変更。
+
+## 2015-02-16
+ * ble-syntax.sh: bugfix, incremental に更新した時に word の長さが更新されない。
+ _ble_syntax_word への格納の際に失敗していた。
+
+## 2015-02-15
+ * ble-synatax.sh: bash の文法に従った incremental な解析と色付け。
+
+## 2015-02-14
+ * ble-edit.sh (.ble-line-info.draw): 表示が遅いので修正。
+ ASCII 文字は特別扱いする様に改良。劇的に速くなった。
+
+## 2015-02-13
+ * ble-edit.sh (keymap emacs): 既定の keymap に emacs の名を付与。
+ * ble-edit.sh (accept-line.exec): bugfix, C-c で再帰呼び出しのループから抜けられない。
+ trap DEBUG を用いて再帰呼び出しから抜けられる様に exec 周りを整理・実装し直し。
+ * ble-edit.sh: オプション名の変更、各オプションの整理・説明の追加。
+ * ble-edit.sh (.ble-edit/gexec): グローバルな文脈でコマンドを実行する仕組み。
+ 再帰呼出に対する C-c にも対応。bleopt_exec_type で実行の方法を切り替えられる様に。
+ exec が従来の方法で gexec がこの新しい方法。
+
+## 2015-02-12
+ * ble-decode.sh: bugfix, exit 後に stty が壊れているのを修正
+ これに伴って ble の detach 機能の実装も行った。
+ * ble-decode.sh: bugfix, bash-4.3 で三文字以上のシーケンスが悉く聞かない。
+ keymap が見付からないエラーになってしまうので全てのシーケンスについて bind -x する事にした。
+ * ble-core.sh: bugfix, builtin printf \U.... の使えない環境で command printf fallback が働かない。
+ printf のパスを修正。また ASCII に対しては printf は使わない様に変更。
+ * ble-color.sh (ble-syntax-highlight+default):
+ 追加・修正。また選択範囲の反転を ble-syntax-highlight+region として実装し、それを呼び出す形に。
+ * ble.pp: 起動時に interactive モードかどうかのチェックを行う様に。
+
+## 2015-02-11
+ * ble-edit.sh (_ble_edit_io_*): ちらつきを抑える為に stdout/stderr を切り替える事にした。
+ ちらつくのは bash の既定の出力によって ble の表示がクリアされ、bash の表示したい物が表示されるから。
+ これに対抗して ble は bash の出力の直後に上書き再描画して何とか表示していた。
+ bash の既定の出力を抑える為に、exec で出力先を切り替える事にした。
+ bash の出力はファイルに書き込まれる様にし向ける。出力先ファイルを逐次確認して、
+ エラーが出力されていれば visible-bell で表示する事にした。
+ `bleopt_suppress_bash_output=1` の時にこの新しい方法を実験的に用いる。
+ `bleopt_suppress_bash_output=` の時は従来のちらつく方法。
+
+## 2015-02-10
+ * ble-edit.sh (accept-line.exec): bash-4.3 で内部からグローバル変数を定義できる様に
+ declare 及び typeset を上書きして -g オプションを指定する様に変更。
+ また、これに関係する注意点を ble.htm に記述。
+ * ble-edit.sh (history): ロードに時間が掛かるので最適化。
+ * 全般: bugfix, 文字列分割で GLOBIGNORE='*' を設定していないとパス名展開されて危険
+ * ble-color.sh (ble-syntax-highlight+default): より良い色づけ。
+ * ble-edit.sh (accept-line.exec): ble-bind -cf で bind されたコマンドの実行コンテキストを変更。
+ accept-line で実行されるのと同じコンテキストで実行する。
+ * ble-edit.sh (keymap default): C-z M-z を fg に bind。
+
+## 2015-02-09
+ * git repos
+ * ble-edit: bugfix, locate-xword マクロが展開されていなかった
+ * ble-decode: bash-4.3 に対応する為に色々変更
+ - bind 指定の場合分けを整理
+ - bugfix, ESC ?, ESC [ ? に対して全て bind
+ - bugfix, 場合によって全く bind -r できていない
+ →"bind -sp | fgrep" が "バイナリ" という結果になる事がある様だ。
+ fgrep に -a を指定する。
+ - bugfix, 日本語が入力できない。8bit 文字が認識されない。
+ →8bit 文字はエスケープシーケンスで bind に指定する様に変更。
+
+## 2013-06-12
+ * ble-edit: history-beginning, history-end, accept-and-next
+
+## 2013-06-12
+ * ble-edit:
+ kill-forward-fword, kill-backward-fword, kill-fword,
+ copy-forward-fword, copy-backward-fword, copy-fword,
+ delete-forward-fword, delete-backward-fword, delete-fword,
+ forward-fword, backward-fword
+ * ble-edit: history-expand-line, display-shell-version
+
+## 2013-06-10
+ * ble-edit:
+ kill-forward-uword, kill-backward-uword, kill-uword, kill-region-or-uword,
+ copy-forward-uword, copy-backward-uword, copy-uword, copy-region-or-uword,
+ forward-uword, backward-uword
+
+ * ble-edit:
+ delete-forward-uword, delete-backward-uword, delete-uword, delete-region-or-uword,
+ delete-forward-sword, delete-backward-sword, delete-sword, delete-region-or-sword,
+ delete-forward-cword, delete-backward-cword, delete-cword, delete-region-or-cword
+
+ * ble-edit:
+ 以下の編集関数を廃止:
+ delete-region-or-uword, kill-region-or-uword, copy-region-or-uword,
+ delete-region-or-sword, kill-region-or-sword, copy-region-or-sword,
+ delete-region-or-cword, kill-region-or-cword, copy-region-or-cword.
+ 代わりに以下の編集関数を用いる:
+ delete-region-or type, kill-region-or type, copy-region-or type.
+
+## 2013-06-09
+ * ble-edit: kill-region, copy-region
+ * ble-edit:
+ kill-forward-sword, kill-backward-sword, kill-sword, kill-region-or-sword,
+ copy-forward-sword, copy-backward-sword, copy-sword, copy-region-or-sword
+ * ble-edit:
+ kill-forward-cword, kill-backward-cword, kill-cword, kill-region-or-cword,
+ copy-forward-cword, copy-backward-cword, copy-cword, copy-region-or-cword
+ * ble-edit: forward-sword, backward-sword, forward-cword, backward-cword
+
+## 2013-06-06
+ * ble-edit-bind: 全ての文字・キーが入力可能に。
+ * complete: 候補一覧の表示 (簡易版)
+ * ble-color.sh: 色付け機能を highlight.sh から移植
+
+## 2013-06-05
+ * ble-edit: history-isearch-backward, history-isearch-forward,
+ isearch/self-insert,
+ isearch/next, isearch/forward, isearch/backward,
+ isearch/exit, isearch/cancel, isearch/default,
+ isearch/prev, isearch/accept
+ * ble-edit: yank
+ * ble-bind -d で今迄に bind した物を表示できる様に。
+ * ble-edit: complete, 取り敢えずファイル名補完だけ
+ * ble-edit: command-help
+
+## 2013-06-04
+ * ble-edit: discard-line, accept-line
+ * ble-edit: history-prev, history-next
+ * ble-edit: set-mark, kill-line, kill-backward-line, exchange-point-and-mark
+ * ble-edit: clear-screen
+ * ble-edit: transpose-chars
+ * ble-edit: insert-string
+
+## 2013-06-03
+ * ble-edit: bell, self-insert, redraw-line,
+ * ble-edit: delete-char, delete-backward-char, delete-char-or-exit,
+ delete-forward-backward-char
+ * ble-edit: forward-char, backward-char, end-of-line, beginning-of-line
+ * ble-edit: quoted-insert
+ * ble.sh: 取り敢えず簡単に文字列を入力できる程度までは完成
+
+## 2013-06-02
+ * ble-getopt.sh: bugfixes
+ * ble-getopt.sh: 無事に完了した場合に OPTARGS を unset する様に変更
+ * ble-decode-kbd, ble-decode-unkbd
+
+## 2013-05-31
+ * ble-getopt.sh: created
+ * ble-decode: 大枠が完成
+
+## 2013-05-30
+ * highlight.sh: 取り敢えず簡単な色付け
+ * ble.sh:
+
+ -- 経緯 --
+ highlight.sh の方針だと bash が表示する編集中の内容を消す事が出来ないし、
+ カーソルの位置も bash が表示する物の場所を指している。
+ 色を付けて表示した物は、補助的に bash が表示する物の下に並べて表示する
+ ぐらいしか方法がない。
+
+ また readline 関数をスクリプトから呼び出す事が出来ないので、
+ 結局、色付けを更新したいタイミングで READLINE_LINE や READLINE_POINT の動作を
+ スクリプトの側で全て模倣して再現しなければならない。
+ READLINE_LINE, READLINE_POINT の bash の仕様が変な所為で、日本語など
+ のマルチバイトで正しく処理する為に、色々と汚い事をしなければならない。
+
+ 以上の事から、文字列の編集などの操作からスクリプトの実行まで
+ 全部自分で好きな様に実装して bash readline の機能を全て上書きする事にした。
+ その為に、スクリプトを新しく書き直す。zle を真似て ble (bash line editor)
+ と名付ける。
+
+ -- 方針としては --
+ a. read -n 1 を用いて 1 文字ずつ標準入力から文字を取り出してそれを処理していく
+ b. bash の bind で全ての文字に ble のバイト受信関数を繋げて、
+ バイト列を受信しながら処理する。
+
+ highlight.sh の延長線上で b. の方針にしたが、
+ もしかすると a. の方針も可能かも知れない。
+
+## 2013-05-29
+ * highlight.sh: 作成
diff --git a/.local/src/blesh/doc/LICENSE.md b/.local/src/blesh/doc/LICENSE.md
new file mode 100644
index 0000000..fe71660
--- /dev/null
+++ b/.local/src/blesh/doc/LICENSE.md
@@ -0,0 +1,12 @@
+Copyright (c) 2013, 2015-2020, K. Murase @akinomyoga <myoga.murase@gmail.com>,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/.local/src/blesh/doc/README-ja_JP.md b/.local/src/blesh/doc/README-ja_JP.md
new file mode 100644
index 0000000..9ea591c
--- /dev/null
+++ b/.local/src/blesh/doc/README-ja_JP.md
@@ -0,0 +1,563 @@
+[ Languages: [English](README.md) (英語) | **日本語** ]
+
+<h1 align="center"><ruby>ble.sh<rp> (</rp><rt>/blɛʃ/</rt><rp>)</rp></ruby> ―Bash Line Editor―</h1>
+<p align="center">
+[ <b>README</b> | <a href="https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A71-%E5%9F%BA%E6%9C%AC">説明書</a> |
+<a href="https://github.com/akinomyoga/ble.sh/wiki/%E8%B3%AA%E5%95%8F%E3%81%A8%E5%9B%9E%E7%AD%94">Q&A</a> |
+<a href="https://github.com/akinomyoga/blesh-contrib"><code>contrib</code></a> |
+<a href="https://github.com/akinomyoga/ble.sh/wiki/%E9%80%86%E5%BC%95%E3%81%8D%E3%83%AC%E3%82%B7%E3%83%94">逆引き</a> ]
+</p>
+
+`ble.sh` (*Bash Line Editor*) はピュア Bash スクリプトで書かれたコマンドラインエディタで、標準の GNU Readline を置き換える形で動作します。
+
+現在の開発バージョンは 0.4 です。
+このスクリプトは Bash 3.0 以降で利用できますが、速度・機能などの観点から 4.0 以降ののリリース版 Bash でお使い頂くことがお薦めです。
+現時点では、文字コードとして `UTF-8` のみの対応です。
+このスクリプトは [**BSD License**](LICENSE.md) (3条項 BSD ライセンス) の下で提供されます。
+
+免責: ラインエディタ本体は **ピュア Bash** で書かれていますが、
+ユーザーコマンド実行時には TTY 設定の為に `stty` (POSIX) を呼び出します。
+他にも処理の高速化の為に、初期化・終了処理、
+巨大なデータの処理 (補完、貼り付けなど) の局面でPOSIX 標準コマンドを利用しています。
+
+呼称: `ble.sh` はお好きな様に読んでいただいて問題ありませんが、一番短いのは標記の /blɛʃ/ になりましょう。
+しかし個人的には脳裡で /biːɛliː dɑt ɛseɪtʃ/ と読んでいるものですから、標記の読み方は飽くまで参考と受け止めていただければ幸いです。
+
+## 簡単設定
+
+`ble.sh` インストールには `git`, `make` (GNU make), and `gawk` が必要です。
+詳細は、試用またはインストールに関しては [節1.1](#get-from-source) と [節1.2](#get-from-tarball) を、
+`~/.bashrc` の設定に関しては [節1.3](#set-up-bashrc) を御覧ください。
+以下、GNU make が `gmake` として提供されているシステム (BSD など) では `make` を `gmake` に置き換えて実行してください。
+
+```bash
+# 簡単お試し (インストールせずにお試しいただけます)
+
+git clone --recursive https://github.com/akinomyoga/ble.sh.git
+make -C ble.sh
+source ble.sh/out/ble.sh
+
+# インストール & .bashrc 簡単設定 (動かない場合は節1.3を御参照下さい)
+
+git clone --recursive https://github.com/akinomyoga/ble.sh.git
+make -C ble.sh install PREFIX=~/.local
+echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc
+
+# 更新 (ble.sh をロードした状態で)
+
+ble-update
+
+# 更新 (ble.sh 外部から)
+
+bash /path/to/ble.sh --update
+
+# パッケージ作成用コマンド
+
+git clone --recursive https://github.com/akinomyoga/ble.sh.git
+make -C ble.sh install DESTDIR=/tmp/blesh-package PREFIX=/usr/local
+```
+
+パッケージ管理システムを通じて `ble.sh` をインストールする事もできます (現在 AUR のみ)。
+
+- [AUR (Arch Linux)](https://github.com/akinomyoga/ble.sh/wiki/Manual-A1-Installation#user-content-AUR) `blesh-git` (devel), `blesh` (stable 0.3.3)
+
+## 機能概要
+
+- **構文着色**: `fish` や `zsh-syntax-highlighting` のような文法構造に従った着色を行います。
+ `zsh-syntax-highlighting` のような単純な着色ではなく、構文の入れ子構造や複数のヒアドキュメントなども正しく解析して着色します。
+ 着色は[全て設定可能](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A72-%E6%8F%8F%E7%94%BB)です。
+- **補完増強**: [補完](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A77-%E8%A3%9C%E5%AE%8C)を大幅に増強します。
+ **文法構造に応じた補完**、クォートやパラメータ展開を展開した上でのプログラム補完、**曖昧補完**に対応しています。
+ また、候補をカーソルキーや <kbd>TAB</kbd>, <kbd>S-TAB</kbd> で選択できる
+ [**メニュー補完**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A77-%E8%A3%9C%E5%AE%8C#user-content-sec-menu-complete)、
+ `fish` や `zsh-autosuggestions` のような
+ [**自動補完**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A77-%E8%A3%9C%E5%AE%8C#user-content-sec-auto-complete)
+ (Bash 4.0 以上) の機能もあります。
+ 更に、従来 `peco` や `fzf` を呼び出さなければならなかった補完候補の絞り込みも
+ [**メニュー絞り込み**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A77-%E8%A3%9C%E5%AE%8C#user-content-sec-menu-filter)
+ (Bash 4.0 以上) として自然な形で組み込んでいます。
+ 他に、[**動的略語展開**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A77-%E8%A3%9C%E5%AE%8C#user-content-sec-dabbrev)
+ や、[*zsh abbreviations*](https://unix.stackexchange.com/questions/6152/zsh-alias-expansion)・[`zsh-abbr`](https://github.com/olets/zsh-abbr) のような
+ [**静的略語展開**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A77-%E8%A3%9C%E5%AE%8C#user-content-sec-sabbrev)
+ にも対応しています。
+- **Vim編集モード**: `set -o vi` による編集モードを増強します。
+ 挿入・ノーマルモードの他に(行・矩形)ビジュアルモード、置換モードなどの各種モードに対応しています。
+ テキストオブジェクト・各種レジスタ・オペレータ・キーボードマクロなどにも対応しています。
+ 拡張として `vim-surround` も提供しています。
+- 他にも
+ [**ステータス行**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A74-%E7%B7%A8%E9%9B%86#user-content-bleopt-prompt_status_line),
+ [**コマンド履歴共有**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A74-%E7%B7%A8%E9%9B%86#user-content-bleopt-history_share),
+ [**右プロンプト**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A74-%E7%B7%A8%E9%9B%86#user-content-bleopt-prompt_rps1),
+ [**過渡的プロンプト**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A74-%E7%B7%A8%E9%9B%86#user-content-bleopt-prompt_ps1_transient),
+ [**xterm タイトル**](https://github.com/akinomyoga/ble.sh/wiki/%E8%AA%AC%E6%98%8E%E6%9B%B8-%C2%A74-%E7%B7%A8%E9%9B%86#user-content-bleopt-prompt_xterm_title),
+ など様々な機能に対応しています。
+
+注意: `ble.sh` は、(プロンプト (`PS1`)、エイリアス、関数などを提供する) 典型的な Bash 設定集と異なります。
+`ble.sh` はより低層の基盤を提供するもので、ユーザは自分でプロンプトやエイリアスを設定する必要があります。
+勿論 [`bash-it`](https://github.com/Bash-it/bash-it) や [`oh-my-bash`](https://github.com/ohmybash/oh-my-bash) の様な他の Bash 設定と一緒に使っていただくことも可能です。
+
+> デモ
+>
+> ![ble.sh demo gif](https://github.com/akinomyoga/ble.sh/wiki/images/trial1.gif)
+
+## これまでとこれから
+
+このプロジェクトは初めは `.bashrc` の片隅で行われた小さな実験からスタートしました。
+2013年5月に `zsh-syntax-highlighting` のとある記事に触発されたのがきっかけでした。
+初めは数百行のコードを書けば構文着色が簡単に実現できるのではないかと思って始めた実験ですが、
+すぐに行エディタを根本から書き直さなければ実現できないのではないかということが分かり、
+独立したファイルにコードを移動した後に `ble.sh` という名前を与えました。
+この名前は Zsh の行エディタ (*ZLE* (*Zsh Line Editor*)) を真似て、
+但しシェルで書かれているという事を意識して `.sh` という拡張子にしたように記憶しています。
+`ble.sh` の読み方について屡々訊かれるのですが、最初に書いたように特に定まった読み方はありません。
+最初の実験は2週間程コードを弄って原理的に行エディタを作れるという事を結論づけて終わりました。
+本格的な実装が始まったのは2015年2月の事で12月には公開しました。
+その時点で行エディタとしては普段遣いに堪える程度に完成していました。
+Vimモードの実装は2017年9月に始まり2018年3月に一先ず完成としました。
+続いて補完の拡張は2018年8月に始まり2019年2月には一通り完成しました。
+現在は漫然とメンテナンスしている所でいつになるかは分かりませんが、以下に挙げるような機能も加えたいと何となく考えています。
+
+- 2013-06 v0.0 -- 実験
+- 2015-12 v0.1 -- 構文着色 [[v0.1.14](https://github.com/akinomyoga/ble.sh/releases/tag/v0.1.14)]
+- 2018-03 v0.2 -- Vim モード [[v0.2.6](https://github.com/akinomyoga/ble.sh/releases/tag/v0.2.6)]
+- 2019-02 v0.3 -- 拡張補完 [[v0.3.3](https://github.com/akinomyoga/ble.sh/releases/tag/v0.3.3)]
+- 20xx-xx v0.4 (plan) -- プログラム着色 [`master`]
+- 20xx-xx v0.5 (plan) -- TUI設定画面
+- 20xx-xx v0.6 (plan) -- エラー診断?
+
+# 1 使い方
+
+## 1.1 最新の git repository のソースから生成して試す (バージョン ble-0.4)<sup><a id="get-from-source" href="#get-from-source">†</a></sup>
+
+### ble.sh 生成
+
+`ble.sh` を生成する為には `gawk` (GNU awk) と `gmake` (GNU make) が必要です。
+以下のコマンドで生成できます。
+GNU make が `gmake` という名前でインストールされている場合は、`make` の代わりに `gmake` として下さい。
+```console
+$ git clone --recursive https://github.com/akinomyoga/ble.sh.git
+$ cd ble.sh
+$ make
+```
+スクリプトファイル `ble.sh` がサブディレクトリ `ble.sh/out` 内に生成されます。
+
+### 試用
+
+生成された `ble.sh` は `source` コマンドを用いてお試しいただけます。
+
+```console
+$ source out/ble.sh
+```
+
+### インストール
+
+指定したディレクトリにインストールするには `make install` コマンドを使用します。
+
+```bash
+# ~/.local/share/blesh にインストール
+make install
+
+# 指定したディレクトリにインストール
+make install INSDIR=/path/to/blesh
+
+# パッケージ作成用 (パッケージ管理者用)
+make install DESTDIR=/tmp/blesh-package PREFIX=/usr/local
+```
+
+Make 変数 `DESTDIR` または `PREFIX` が指定されている時、`ble.sh` は `$DESTDIR/$PREFIX/share/blesh` にコピーされます。
+それ以外で Make 変数 `INSDIR` が指定されている時、直接 `$INSDIR` にインストールされます。
+更にそれ以外で環境変数 `$XDG_DATA_HOME` が指定されている時、`$XDG_DATA_HOME/blesh` にインストールされます。
+以上の変数が何れも指定されていない時の既定のインストール先は `~/.local/share/blesh` です。
+
+`.bashrc` の設定に関しては[節1.3](#set-up-bashrc)を御覧ください。
+
+## 1.2 GitHub Releases から tar をダウンロードして使う<sup><a id="get-from-tarball" href="#get-from-tarball">†</a></sup>
+
+ダウンロード・試用・インストールの方法については各リリースページの説明を御覧ください。
+現在、安定版は開発版に比べてかなり古いので様々な機能が欠けている事にご注意下さい。
+
+- 開発版 [v0.4.0-devel2](https://github.com/akinomyoga/ble.sh/releases/tag/v0.4.0-devel2) (2020-12)
+- 安定版 [v0.3.3](https://github.com/akinomyoga/ble.sh/releases/tag/v0.3.3) (2019-02 fork) 拡張補完
+- 安定版 [v0.2.6](https://github.com/akinomyoga/ble.sh/releases/tag/v0.2.6) (2018-03 fork) Vim モード
+- 安定版 [v0.1.14](https://github.com/akinomyoga/ble.sh/releases/tag/v0.1.14) (2015-12 fork) 構文着色
+
+## 1.2 `ble.sh` をダウンロードして試す (旧バージョン ble-0.3 201902版)<sup><a id="get-from-tarball" href="#get-from-tarball">†</a></sup>
+
+`wget` を使う場合:
+```console
+$ wget https://github.com/akinomyoga/ble.sh/releases/download/v0.3.3/ble-0.3.3.tar.xz
+$ tar xJf ble-0.3.3.tar.xz
+$ source ble-0.3.3/ble.sh
+```
+`curl` を使う場合:
+```console
+$ curl -LO https://github.com/akinomyoga/ble.sh/releases/download/v0.3.3/ble-0.3.3.tar.xz
+$ tar xJf ble-0.3.3.tar.xz
+$ source ble-0.3.3/ble.sh
+```
+
+指定したディレクトリに `ble.sh` を配置するには単に `ble-0.1.7` ディレクトリをコピーします。
+```console
+$ cp -r ble-0.3.3 /path/to/blesh
+```
+
+## 1.3 `.bashrc` に設定する<sup><a id="set-up-bashrc" href="#set-up-bashrc">†</a></sup>
+
+対話シェルで常用する場合には `.bashrc` に設定を行います。
+単に `ble.sh` を `source` して頂くだけでも大抵の場合動作しますが、
+より確実に動作させる為には以下の様にコードを記述します。
+```bash
+# bashrc
+
+# .bashrc の先頭近くに以下を追加して下さい。
+[[ $- == *i* ]] && source /path/to/blesh/ble.sh --noattach
+
+# 間に通常の bashrc の内容を既述します。
+
+# .bashrc の末端近くに以下を追加して下さい。
+[[ ${BLE_VERSION-} ]] && ble-attach
+```
+
+## 1.4 初期化スクリプト `~/.blerc` について
+
+ユーザー設定は初期化スクリプト `~/.blerc` (またはもし `~/.blerc` が見つからなければ `${XDG_CONFIG_HOME:-$HOME/.config}/blesh/init.sh`) に記述します。
+テンプレートとしてリポジトリの [`blerc`](https://github.com/akinomyoga/ble.sh/blob/master/blerc) というファイルを利用できます。
+初期化スクリプトは `ble.sh` ロード時に自動で読み込まれる Bash スクリプトなので、Bash で使えるコマンドを初期化スクリプトの中で利用できます。
+初期化スクリプトの位置を変更する場合には、`source ble.sh` 時に `--rcfile INITFILE` を指定します。以下に例を挙げます。
+
+```bash
+# in bashrc
+
+# Example 1: ~/.blerc will be used by default
+[[ $- == *i* ]] && source /path/to/blesh/ble.sh --noattach
+
+# Example 2: /path/to/your/blerc will be used
+[[ $- == *i* ]] && source /path/to/blesh/ble.sh --noattach --rcfile /path/to/your/blerc
+```
+
+## 1.5 アップデート
+
+Git (`git'), GNU awk (`gawk`), 及び GNU make (`make`) が必要になります。
+`ble-0.3` 以上をお使いの場合は `ble.sh` をロードした状態で `ble-update` を実行して下さい。
+
+```bash
+$ ble-update
+```
+
+`ble-0.4` 以上をお使いの場合は `ble.sh` をロードしなくても以下のコマンドで更新可能です。
+
+```bash
+$ bash /path/to/ble.sh --update
+```
+
+それ以外の場合には、以下のように `git pull` で最新版を入手・インストールできます。
+
+```bash
+cd ble.sh # ※既に持っている git リポジトリに入る
+git pull
+git submodule update --recursive --remote
+make
+make INSDIR="$HOME/.local/share/blesh" install
+```
+
+## 1.6 アンインストール
+
+基本的に `ble.sh` ディレクトリとユーザの追加した設定を単に削除していただければ問題ありません。
+
+- 全ての `ble.sh` セッション (`ble.sh` をロードしている Bash 対話セッション) を終了します。
+- `.bashrc` に追加した行があれば削除します。
+- `blerc` 設定ファイル (`~/.blerc` または `~/.config/blesh/init.sh`) があれば削除します。
+- `ble.sh` をインストールしたディレクトリを削除します。
+- キャッシュディレクトリ `~/.cache/blesh` が生成されていればそれを削除します。
+- 一時ディレクトリ `/tmp/blesh` が生成されていればそれを削除します。これは `/tmp` の内容が自動的にクリアされないシステムで必要です。
+
+# 2 基本設定
+
+ここでは `~/.blerc` に記述する基本的な設定を幾つか紹介します。
+[質問と回答](https://github.com/akinomyoga/ble.sh/wiki/%E8%B3%AA%E5%95%8F%E3%81%A8%E5%9B%9E%E7%AD%94)、
+[逆引きレシピ](https://github.com/akinomyoga/ble.sh/wiki/%E9%80%86%E5%BC%95%E3%81%8D%E3%83%AC%E3%82%B7%E3%83%94)、
+[`contrib` リポジトリ](https://github.com/akinomyoga/blesh-contrib/blob/master/README-ja.md) にも便利な設定があります。
+その他の全ての設定項目はテンプレート [`blerc`](https://github.com/akinomyoga/ble.sh/blob/master/blerc) に含まれています。
+詳細な説明に関しては[説明書](https://github.com/akinomyoga/ble.sh/wiki/%E7%9B%AE%E6%AC%A1)を参照して下さい。
+
+## 2.1 Vim モード
+
+Vim モードについては [Wiki の説明ページ](https://github.com/akinomyoga/ble.sh/wiki/Vi-(Vim)-editing-mode) を御覧ください。
+
+## 2.2 各機能の無効化
+
+よくお尋ね頂くご質問の一つにそれぞれの機能をどのように無効化すれば良いのかというものが御座います。
+各機能の無効化方法を以下にまとめます。
+
+```bash
+# 構文着色を無効化
+bleopt highlight_syntax=
+
+# ファイル名に基づく構文着色を無効化
+bleopt highlight_filename=
+
+# 変数の種類に基づく構文着色の無効化
+bleopt highlight_variable=
+
+# 自動補完の無効化 (自動補完は Bash 4.0 以降にて既定で有効です)
+bleopt complete_auto_complete=
+# Tip: 代わりに自動補完の起動遅延をミリ秒単位でご指定いただくこともできます。
+bleopt complete_auto_delay=300
+
+# コマンド履歴に基づく自動補完の無効化
+bleopt complete_auto_history=
+
+# 曖昧補完の無効化
+bleopt complete_ambiguous=
+
+# TAB によるメニュー補完の無効化
+bleopt complete_menu_complete=
+
+# メニュー自動絞り込みの無効化 (Bash 4.0 以降にて既定で有効化されます)
+bleopt complete_menu_filter=
+
+# 行末マーカー "[ble: EOF]" の無効化
+bleopt prompt_eol_mark=''
+# Tip: 代わりに他の文字列をご指定頂くこともできます。
+bleopt prompt_eol_mark='⏎'
+
+# 終了ステータスマーカー "[ble: exit %d]" の無効化
+bleopt exec_errexit_mark=
+# Tip: 代わりに他の文字列をご指定頂くこともできます。
+bleopt exec_errexit_mark=$'\e[91m[error %d]\e[m'
+
+# コマンド実行時間マーカー "[ble: elapsed 1.203s (CPU 0.4%)]" の無効化
+bleopt exec_elapsed_mark=
+# Tip: 代わりに別の文字列をご指定いただくこともできます。
+bleopt exec_elapsed_mark=$'\e[94m[%ss (%s %%)]\e[m'
+# Tip: マーカーを表示する条件を変更することも可能です。
+bleopt exec_elapsed_enabled='sys+usr>=10*60*1000' # 例: 合計CPU時間が 10 分以上の時に表示
+```
+
+## 2.3 曖昧文字幅
+
+設定 `char_width_mode` を用いて、曖昧文字幅を持つ文字 (Unicode 参考特性 `East_Asian_Width` が `A` (Ambiguous) の文字) の幅を制御できます。
+現在は 4 つの選択肢 `emacs`, `west`, `east`, `auto` が用意されています。
+設定値 `emacs` を指定した場合、GNU Emacs における既定の文字幅と同じ物を使います。
+設定値 `west` を指定した場合、全ての曖昧文字幅を 1 (半角) と解釈します。
+設定値 `east` を指定した場合、全ての曖昧文字幅を 2 (全角) と解釈します。
+設定値 `auto` を指定した場合、`west` か `east` かを端末とのやり取りに基づいて自動判定します。
+既定値は `auto` です。この設定項目は、利用している端末の振る舞いに応じて適切に設定する必要があります。
+例えば `west` に設定する場合は以下の様にします:
+
+```bash
+bleopt char_width_mode='west'
+```
+
+## 2.4 文字コード
+
+設定 `input_encoding` は入力の文字コードを制御するのに使います。現在 `UTF-8` と `C` のみに対応しています。
+設定値 `C` を指定した場合は、受信したバイト値が直接文字コードであると解釈されます。
+既定値は `UTF-8` です。`C` に設定を変更する場合には以下の様にします:
+
+```bash
+bleopt input_encoding='C'
+```
+
+## 2.5 ベル
+
+設定 `edit_abell` と設定 `edit_vbell` は、編集関数 `bell` の振る舞いを制御します。
+`edit_abell` が非空白の文字列の場合、音による通知が有効になります (つまり、制御文字の `BEL` (0x07) が `stderr` に出力されます)。
+`edit_vbell` が非空白の文字列の場合、画面での通知が有効になります。既定では音による通知が有効で、画面での通知が無効になっています。
+
+設定 `vbell_default_message` は画面での通知で使用するメッセージ文字列を指定します。既定値は `' Wuff, -- Wuff!! '` です。
+設定 `vbell_duration` は画面での通知を表示する時間の長さを指定します。単位はミリ秒です。既定値は `2000` です。
+
+例えば、画面での通知は以下のように設定・有効化できます:
+```bash
+bleopt edit_vbell=1 vbell_default_message=' BEL ' vbell_duration=3000
+```
+
+もう一つの例として、音による通知は以下の様にして無効化できます。
+```bash
+bleopt edit_abell=
+```
+
+## 2.6 着色の設定
+
+構文に従った着色で使用される、各文法要素の色と属性は `ble-face` シェル関数で設定します。
+既定の設定は以下のコードに対応します:
+```bash
+# 編集に関連する着色の設定
+ble-face -s region bg=60,fg=white
+ble-face -s region_target bg=153,fg=black
+ble-face -s region_match bg=55,fg=white
+ble-face -s region_insert fg=12,bg=252
+ble-face -s disabled fg=242
+ble-face -s overwrite_mode fg=black,bg=51
+ble-face -s auto_complete fg=238,bg=254
+ble-face -s menu_filter_fixed bold
+ble-face -s menu_filter_input fg=16,bg=229
+ble-face -s vbell reverse
+ble-face -s vbell_erase bg=252
+ble-face -s vbell_flash fg=green,reverse
+ble-face -s prompt_status_line fg=231,bg=240
+
+# 構文着色の設定
+ble-face -s syntax_default none
+ble-face -s syntax_command fg=brown
+ble-face -s syntax_quoted fg=green
+ble-face -s syntax_quotation fg=green,bold
+ble-face -s syntax_escape fg=magenta
+ble-face -s syntax_expr fg=26
+ble-face -s syntax_error bg=203,fg=231
+ble-face -s syntax_varname fg=202
+ble-face -s syntax_delimiter bold
+ble-face -s syntax_param_expansion fg=purple
+ble-face -s syntax_history_expansion bg=94,fg=231
+ble-face -s syntax_function_name fg=92,bold
+ble-face -s syntax_comment fg=242
+ble-face -s syntax_glob fg=198,bold
+ble-face -s syntax_brace fg=37,bold
+ble-face -s syntax_tilde fg=navy,bold
+ble-face -s syntax_document fg=94
+ble-face -s syntax_document_begin fg=94,bold
+ble-face -s command_builtin_dot fg=red,bold
+ble-face -s command_builtin fg=red
+ble-face -s command_alias fg=teal
+ble-face -s command_function fg=92
+ble-face -s command_file fg=green
+ble-face -s command_keyword fg=blue
+ble-face -s command_jobs fg=red
+ble-face -s command_directory fg=26,underline
+ble-face -s filename_directory underline,fg=26
+ble-face -s filename_directory_sticky underline,fg=white,bg=26
+ble-face -s filename_link underline,fg=teal
+ble-face -s filename_orphan underline,fg=teal,bg=224
+ble-face -s filename_executable underline,fg=green
+ble-face -s filename_setuid underline,fg=black,bg=220
+ble-face -s filename_setgid underline,fg=black,bg=191
+ble-face -s filename_other underline
+ble-face -s filename_socket underline,fg=cyan,bg=black
+ble-face -s filename_pipe underline,fg=lime,bg=black
+ble-face -s filename_character underline,fg=white,bg=black
+ble-face -s filename_block underline,fg=yellow,bg=black
+ble-face -s filename_warning underline,fg=red
+ble-face -s filename_url underline,fg=blue
+ble-face -s filename_ls_colors underline
+ble-face -s varname_array fg=orange,bold
+ble-face -s varname_empty fg=31
+ble-face -s varname_export fg=200,bold
+ble-face -s varname_expr fg=92,bold
+ble-face -s varname_hash fg=70,bold
+ble-face -s varname_number fg=64
+ble-face -s varname_readonly fg=200
+ble-face -s varname_transform fg=29,bold
+ble-face -s varname_unset fg=124
+ble-face -s argument_option fg=teal
+ble-face -s argument_error fg=black,bg=225
+```
+
+現在の描画設定の一覧は以下のコマンドでも確認できます (`ble-face` を無引数で呼び出す)。
+```console
+$ ble-face
+```
+
+色コードはシェル関数 `ble-color-show` (`ble.sh` 内で定義) で確認できます。
+```console
+$ ble-color-show
+```
+
+## 2.7 キーバインディング
+
+キーバインディングはシェル関数 `ble-bind` を使って変更できます。
+例えば <kbd>C-x h</kbd> を入力した時に "Hello, world!" と挿入させたければ以下のようにします。
+```bash
+ble-bind -f 'C-x h' 'insert-string "Hello, world!"'
+```
+
+<kbd>M-c</kbd> を入力した時にコマンドを実行するには以下のようにします。
+
+```bash
+ble-bind -c 'M-c' 'my-command'
+```
+
+<kbd>C-r</kbd> を入力した時に、ユーザー定義編集関数 (Bash の `bind -x` で指定するのと同様の物) を実行するには以下のようにします。
+
+```bash
+ble-bind -x 'C-r' 'my-edit-function'
+```
+
+既存のキーバインディングは以下のコマンドで確認できます。
+```console
+$ ble-bind -P
+```
+
+以下のコマンドでキーバインディングに使える編集関数一覧を確認できます。
+```console
+$ ble-bind -L
+```
+
+一つのキーで複数の編集関数を呼び出したい場合は、以下の例の様に、
+`ble/widget/編集関数の名前` という名前のシェル関数を通して新しい編集関数を定義できます。
+既存の標準の編集関数と名前が重複しない様に、
+編集関数の名前は `ユーザー名/`, `my/`, `blerc/`, `dotfiles/` などで始める事が強く推奨されます。
+
+```bash
+# C-t で複数の操作を行う例
+function ble/widget/my/example1 {
+ ble/widget/beginning-of-logical-line
+ ble/widget/insert-string 'echo $('
+ ble/widget/end-of-logical-line
+ ble/widget/insert-string ')'
+}
+ble-bind -f C-t my/example1
+```
+
+# 3 ヒント
+
+## 3.1 複数行モード
+
+コマンドラインに改行が含まれている場合、複数行モード (MULTILINE モード) になります。
+
+<kbd>C-v C-j</kbd> または <kbd>C-q C-j</kbd> とすると改行をコマンドラインの一部として入力できます。
+複数行モードでは、<kbd>RET</kbd> (<kbd>C-m</kbd>) はコマンドの実行ではなく新しい改行の挿入になります。
+複数行モードでは、<kbd>C-j</kbd> を用いてコマンドを実行して下さい。
+
+`shopt -s cmdhist` が設定されているとき (既定)、もし <kbd>RET</kbd> (<kbd>C-m</kbd>) を押した時にコマンドラインが構文的に閉じていなければ、コマンドの実行ではなく改行の挿入を行います。
+
+## 3.2 Vim モード
+
+`.bashrc` に `set -o vi` が設定されているとき、または `.inputrc` に `set editing-mode vi` が設定されているとき、vim モードが有効になります。
+Vim モードの詳細な設定については [Wiki のページ (英語)](https://github.com/akinomyoga/ble.sh/wiki/Vi-(Vim)-editing-mode) を御覧ください。
+
+## 3.3 自動補完
+
+Bash 4.0 以降では自動補完が有効になり、予測候補が表示されます。
+候補を確定するには <kbd>S-RET</kbd> を入力します (編集文字列の末尾にいる時は <kbd>right</kbd>, <kbd>C-f</kbd> または <kbd>end</kbd> でも確定できます)。
+表示されている候補の初めの単語だけ部分的に確定する時は <kbd>M-f</kbd> または <kbd>M-right</kbd> を入力します。
+現在の候補で確定しそのままコマンドを実行する場合には <kbd>C-RET</kbd> (※お使いの端末が対応している時) を入力します。
+
+## 3.4 静的略語展開
+
+特定の単語を静的略語展開に登録することで好きな文字列に展開することができます。
+登録済み単語に一致する単語の直後で <kbd>SP</kbd> を入力した時に静的略語展開が起きます。
+例えば、以下の設定をしておくと `command L` まで入力した状態で <kbd>SP</kbd> を押した時に、コマンドラインが `command | less` に展開されます。
+
+```bash
+# blerc
+ble-sabbrev L='| less'
+```
+
+実際に実行したいコマンドに含まれる可能性の低い単語として、`\` で始まる単語を静的略語展開に登録することもお薦めです。
+
+```bash
+# blerc
+ble-sabbrev '\L'='| less'
+```
+
+# 4 謝辞
+
+GitHub の Issue/PR を通して多くの方からフィードバックを頂き、皆様に本当に感謝しております。
+特に以下の方には大きな寄与を受けたので言及させていただきます。
+
+- [`@cmplstofB`](https://github.com/cmplstofB) 様には vim モードの実装において初期よりテスト及び様々な提案をしていただきました。
+- [`@dylankb`](https://github.com/dylankb) 様には `fzf` との互換性や `ble.sh` 初期化に関連して様々な問題報告をいただきました。
+- [`@rux616`](https://github.com/rux616) 様には幾つかの問題報告および `.blerc` の既定パス解決のバグ修正をいただきました。
+- [`@timjrd`](https://github.com/timjrd) 様には補完の枠組みの高速化に関する PR をいただきました。
+- [`@3ximus`](https://github.com/3ximus) 様には広範囲に渡る様々な問題について報告いただきました。
diff --git a/.local/src/blesh/doc/README.md b/.local/src/blesh/doc/README.md
new file mode 100644
index 0000000..1a6001f
--- /dev/null
+++ b/.local/src/blesh/doc/README.md
@@ -0,0 +1,538 @@
+[ Languages: **English** | [日本語](README-ja_JP.md) (Japanese) ]
+
+<h1 align="center"><ruby>ble.sh<rp> (</rp><rt>/blɛʃ/</rt><rp>)</rp></ruby> ―Bash Line Editor―</h1>
+<p align="center">
+[ <b>README</b> | <a href="https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A71-Introduction">Manual</a> |
+<a href="https://github.com/akinomyoga/ble.sh/wiki/Q&A">Q&A</a> |
+<a href="https://github.com/akinomyoga/blesh-contrib"><code>contrib</code></a> |
+<a href="https://github.com/akinomyoga/ble.sh/wiki/Recipes">Recipes</a> ]
+</p>
+
+*Bash Line Editor* (`ble.sh`) is a command line editor written in pure Bash which replaces the default GNU Readline.
+
+Current devel version is 0.4.
+This script supports Bash 3.0 or higher although we recommend to use `ble.sh` with release versions of Bash 4.0 or higher.
+Currently, only `UTF-8` encoding is supported for non-ASCII characters.
+This script is provided under the [**BSD License**](LICENSE.md) (3-clause BSD license).
+
+Disclaimer: The core part of the line editor is written in **pure Bash**, but
+`ble.sh` relies on POSIX `stty` to set up TTY states before and after the execution of user commands.
+It also uses other POSIX utilities for acceleration
+in some part of initialization and cleanup code,
+processing of large data in completions, paste of large data, etc.
+
+Pronunciation: The easiest pronunciation of `ble.sh` that users use is /blɛʃ/, but you can actually pronounce it as you like.
+I do not specify the canonical way of pronoucing `ble.sh`.
+In fact, I personally read it verbosely as /biːɛliː dɑt ɛseɪtʃ/ in my head.
+
+## Quick instructions
+
+Installation requires the commands `git`, `make` (GNU make), and `gawk` (in addition to `bash` and POSIX standard utilities).
+For detailed descriptions, see [Sec 1.1](#get-from-source) and [Sec 1.2](#get-from-tarball) for trial/installation,
+[Sec 1.3](#set-up-bashrc) for the setup of your `~/.bashrc`.
+Please replace `make` with `gmake` if your system provides GNU make as `gmake` (such as in BSD).
+
+```bash
+# TRIAL without installation
+
+git clone --recursive https://github.com/akinomyoga/ble.sh.git
+make -C ble.sh
+source ble.sh/out/ble.sh
+
+# Quick INSTALL to BASHRC (If this doesn't work, please follow Sec 1.3)
+
+git clone --recursive https://github.com/akinomyoga/ble.sh.git
+make -C ble.sh install PREFIX=~/.local
+echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc
+
+# UPDATE (in a ble.sh session)
+
+ble-update
+
+# UPDATE (outside ble.sh sessions)
+
+bash /path/to/ble.sh --update
+
+# PACKAGE (for package maintainers)
+
+git clone --recursive https://github.com/akinomyoga/ble.sh.git
+make -C ble.sh install DESTDIR=/tmp/blesh-package PREFIX=/usr/local
+```
+
+You may also install `ble.sh` through package-management systems (currently only AUR):
+
+- [AUR (Arch Linux)](https://github.com/akinomyoga/ble.sh/wiki/Manual-A1-Installation#user-content-AUR) `blesh-git` (devel), `blesh` (stable 0.3.3)
+
+## Features
+
+- **Syntax highlighting**: Highlight command lines input by users as in `fish` and `zsh-syntax-highlighting`.
+ Unlike the simple highlighting in `zsh-syntax-highlighting`, `ble.sh` performs syntactic analysis
+ to enable the correct highlighting of complex structures such as nested command substitutions, multiple here documents, etc.
+ Highlighting colors and styles are [fully configurable](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A72-Graphics).
+- **Enhanced completion**:
+ Extend [completion](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A77-Completion)
+ by **syntax-aware completion**, completion with quotes and parameter expansions in prefix texts, **ambiguous candidate generation**, etc.
+ Also, [**menu-complete**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A77-Completion#user-content-sec-menu-complete)
+ supports selection of candidates in menu (candidate list) by cursor keys, <kbd>TAB</kbd> and <kbd>S-TAB</kbd>.
+ The feature [**auto-complete**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A77-Completion#user-content-sec-auto-complete)
+ supports the automatic suggestion of completed texts as in `fish` and `zsh-autosuggestions` (with Bash 4.0+).
+ The feature [**menu-filter**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A77-Completion#user-content-sec-menu-filter)
+ integrates automatic filtering of candidates into menu completion (with Bash 4.0+).
+ There are other functionalities such as
+ [**dabbrev**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A77-Completion#user-content-sec-dabbrev) and
+ [**sabbrev**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A77-Completion#user-content-sec-sabbrev) like
+ [*zsh abbreviations*](https://unix.stackexchange.com/questions/6152/zsh-alias-expansion) or [`zsh-abbr`](https://github.com/olets/zsh-abbr).
+- **Vim editing mode**: Enhance `readline`'s vi editing mode available with `set -o vi`.
+ Vim editing mode supports various vim modes such as char/line/block visual/select mode, replace mode,
+ command mode, operator pending mode as well as insert mode and normal mode.
+ Vim editing mode supports various operators, text objects, registers, keyboard macros, marks, etc.
+ It also provides `vim-surround` as an option.
+- Other interesting features include
+ [**status line**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A74-Editing#user-content-bleopt-prompt_status_line),
+ [**history share**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A74-Editing#user-content-bleopt-history_share),
+ [**right prompt**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A74-Editing#user-content-bleopt-prompt_rps1),
+ [**transient prompt**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A74-Editing#user-content-bleopt-prompt_ps1_transient),
+ [**xterm title**](https://github.com/akinomyoga/ble.sh/wiki/Manual-%C2%A74-Editing#user-content-bleopt-prompt_xterm_title), etc.
+
+Note: ble.sh does not provide specific settings of the prompt, aliases, functions, etc.
+ble.sh provides a more fundamental infrastructure so that users can set up their own prompt, aliases, functions, etc.
+Of course ble.sh can be used in combination with other Bash configurations such as [`bash-it`](https://github.com/Bash-it/bash-it) and [`oh-my-bash`](https://github.com/ohmybash/oh-my-bash).
+
+> Demo (version 0.2)
+>
+> ![ble.sh demo gif](https://github.com/akinomyoga/ble.sh/wiki/images/trial1.gif)
+
+## History and roadmap
+
+My little experiment has took place in one corner of my `bashrc` in the end of May, 2013 after I enjoyed some article on `zsh-syntax-highlighting`.
+I initially thought something can be achieved by writing a few hundred of lines of codes
+but soon realized that everything needs to be re-implemented for the authentic support of syntax highlighting in Bash.
+I decided to make it as an independent script `ble.sh`.
+The name stemmed from that of Zsh's line editor, *ZLE* (*Zsh Line Editor*), but suffixed with `.sh` for the implication of being written in shell script.
+I'm occasinally asked about the pronunciation of `ble.sh`, but you can actually pronounce it as you like.
+After the two-week experiment, I was satisfied with my conclusion that it is *possible* to implement a full-featured line editor in Bash that satisfies the actual daily uses.
+The real efforts of improving the prototype implementation for the real uses was started in Feburuary, 2015.
+I released the initial version in the next December. Until then, the basic part of the line editor was completed.
+The implementation of vim mode has been started in September, 2017 and completed in the next March.
+I started working on the enhancement of the completion in August, 2018 and released it in the next February.
+
+- 2013-06 v0.0 -- prototype
+- 2015-12 v0.1 -- Syntax highlighting [[v0.1.14](https://github.com/akinomyoga/ble.sh/releases/tag/v0.1.14)]
+- 2018-03 v0.2 -- Vim mode [[v0.2.6](https://github.com/akinomyoga/ble.sh/releases/tag/v0.2.6)]
+- 2019-02 v0.3 -- Enhanced completion [[v0.3.3](https://github.com/akinomyoga/ble.sh/releases/tag/v0.3.3)]
+- 20xx-xx v0.4 (plan) -- programmable highlighting [`master`]
+- 20xx-xx v0.5 (plan) -- TUI configuration
+- 20xx-xx v0.6 (plan) -- error diagnostics?
+
+# 1 Usage
+
+## 1.1 Try `ble.sh` generated from source (version ble-0.4 devel)<sup><a id="get-from-source" href="#get-from-source">†</a></sup>
+
+### Generate
+
+To generate `ble.sh`, `gawk` (GNU awk) and `gmake` (GNU make) (in addition to Bash and POSIX standard utilities) is required.
+The file `ble.sh` can be generated using the following commands.
+If you have GNU make installed on `gmake`, please use `gmake` instead of `make`.
+```bash
+git clone --recursive https://github.com/akinomyoga/ble.sh.git
+cd ble.sh
+make
+```
+
+A script file `ble.sh` will be generated in the directory `ble.sh/out`.
+
+### Try
+
+Then, you can load `ble.sh` in the Bash session using the `source` command:
+```bash
+source out/ble.sh
+```
+
+### Install
+
+To install `ble.sh` in a specified directory, use `make install`.
+
+```bash
+# INSTALL to ~/.local/share/blesh
+make install
+
+# INSTALL to a specified directory
+make install INSDIR=/path/to/blesh
+
+# PACKAGE (for package maintainers)
+make install DESTDIR=/tmp/blesh-package PREFIX=/usr/local
+```
+
+If either the make variables `DESTDIR` or `PREFIX` is supplied, `ble.sh` will be copied to `$DESTDIR/$PREFIX/share/blesh`.
+Otherwise, if the make variables `INSDIR` is specified, it will be installed directly on `$INSDIR`.
+Otherwise, if the environment variable `$XDG_DATA_HOME` is defined, the install location will be `$XDG_DATA_HOME/blesh`.
+If none of these variables are specified, the default install location is `~/.local/share/blesh`.
+
+To set up `.bashrc` see [Sec. 1.3](#set-up-bashrc).
+
+## 1.2 Or, use a tar ball of `ble.sh` obtained from GitHub releases<sup><a id="get-from-tarball" href="#get-from-tarball">†</a></sup>
+
+For download, trial and install, see the description at each release page.
+The stable versions are significantly old compared to the devel version, so many features are unavailable.
+
+- Devel [v0.4.0-devel2](https://github.com/akinomyoga/ble.sh/releases/tag/v0.4.0-devel2) (2020-12)
+- Stable [v0.3.3](https://github.com/akinomyoga/ble.sh/releases/tag/v0.3.3) (2019-02 fork) Enhanced completions
+- Stable [v0.2.6](https://github.com/akinomyoga/ble.sh/releases/tag/v0.2.6) (2018-03 fork) Vim mode
+- Stable [v0.1.14](https://github.com/akinomyoga/ble.sh/releases/tag/v0.1.14) (2015-12 fork) Syntax highlighting
+
+## 1.3 Set up `.bashrc`<sup><a id="set-up-bashrc" href="#set-up-bashrc">†</a></sup>
+
+If you want to load `ble.sh` by default in interactive sessions of `bash`, usually one can just source `ble.sh` in `~/.bashrc`,
+but more reliable way is to add the following codes to your `.bashrc` file:
+```bash
+# bashrc
+
+# Add this lines at the top of .bashrc:
+[[ $- == *i* ]] && source /path/to/blesh/ble.sh --noattach
+
+# your bashrc settings come here...
+
+# Add this line at the end of .bashrc:
+[[ ${BLE_VERSION-} ]] && ble-attach
+```
+
+## 1.4 User settings `~/.blerc`
+
+User settings can be placed in the init script `~/.blerc` (or `${XDG_CONFIG_HOME:-$HOME/.config}/blesh/init.sh` if `~/.blerc` is not available)
+whose template is available as the file [`blerc`](https://github.com/akinomyoga/ble.sh/blob/master/blerc) in the repository.
+The init script is a Bash script which will be sourced during the load of `ble.sh`, so any shell commands can be used in `~/.blerc`.
+If you want to change the default path of the init script, you can add the option `--rcfile INITFILE` to `source ble.sh` as the following example:
+
+```bash
+# in bashrc
+
+# Example 1: ~/.blerc will be used by default
+[[ $- == *i* ]] && source /path/to/blesh/ble.sh --noattach
+
+# Example 2: /path/to/your/blerc will be used
+[[ $- == *i* ]] && source /path/to/blesh/ble.sh --noattach --rcfile /path/to/your/blerc
+```
+
+## 1.5 Update
+
+You need Git (`git`), GNU awk (`gawk`) and GNU make (`make`).
+For `ble-0.3+`, you can run `ble-update` in the session with `ble.sh` loaded:
+
+```bash
+$ ble-update
+```
+
+For `ble.0.4+`, you can also update it outside the `ble.sh` session using
+
+```bash
+$ bash /path/to/ble.sh --update
+```
+
+You can instead download the latest version by `git pull` and install it:
+
+```bash
+cd ble.sh # <-- enter the git repository you already have
+git pull
+git submodule update --recursive --remote
+make
+make INSDIR="$HOME/.local/share/blesh" install
+```
+
+## 1.6 Uninstall
+
+Basically you can simply delete the installed directory and the settings that user added.
+
+- Close all the `ble.sh` sessions (the Bash interactive sessions with `ble.sh`)
+- Remove the added lines in `.bashrc`.
+- Remove `blerc` files (`~/.blerc` or `~/.config/blesh/init.sh`) if any.
+- Remove the installed directory.
+- Remove the cache directory `~/.cache/blesh` if any.
+- Remove the temporary directory `/tmp/blesh` if any [ Only needed when your system does not automatically clears `/tmp` ].
+
+# 2 Basic settings
+
+Here some of the settings for `~/.blerc` are picked up.
+You can find useful settings also in [Q\&A](https://github.com/akinomyoga/ble.sh/wiki/Q&A),
+[Recipes](https://github.com/akinomyoga/ble.sh/wiki/Recipes)
+and [`contrib` repository](https://github.com/akinomyoga/blesh-contrib).
+The complete list of setting items can be found in the template [`blerc`](https://github.com/akinomyoga/ble.sh/blob/master/blerc).
+For detailed explanations please refer to [Manual](https://github.com/akinomyoga/ble.sh/wiki).
+
+## 2.1 Vim mode
+
+For the vi/vim mode, check [the wiki page](https://github.com/akinomyoga/ble.sh/wiki/Vi-(Vim)-editing-mode).
+
+## 2.2 Disable features
+
+One of frequently asked questions is the way to disable a specific feature that `ble.sh` adds.
+Here the settings for disabling features are summarized.
+
+```bash
+# Disable syntax highlighting
+bleopt highlight_syntax=
+
+# Disable highlighting based on filenames
+bleopt highlight_filename=
+
+# Disable highlighting based on variable types
+bleopt highlight_variable=
+
+# Disable auto-complete (Note: auto-complete is enabled by default in bash-4.0+)
+bleopt complete_auto_complete=
+# Tip: you may instead specify the delay of auto-complete in millisecond
+bleopt complete_auto_delay=300
+
+# Disable auto-complete based on the command history
+bleopt complete_auto_history=
+
+# Disable ambiguous completion
+bleopt complete_ambiguous=
+
+# Disable menu-complete by TAB
+bleopt complete_menu_complete=
+
+# Disable menu filtering (Note: auto-complete is enabled by default in bash-4.0+)
+bleopt complete_menu_filter=
+
+# Disable EOF marker like "[ble: EOF]"
+bleopt prompt_eol_mark=''
+# Tip: you may instead specify another string:
+bleopt prompt_eol_mark='⏎'
+
+# Disable error exit marker like "[ble: exit %d]"
+bleopt exec_errexit_mark=
+# Tip: you may instead specify another string:
+bleopt exec_errexit_mark=$'\e[91m[error %d]\e[m'
+
+# Disable elapsed-time marker like "[ble: elapsed 1.203s (CPU 0.4%)]"
+bleopt exec_elapsed_mark=
+# Tip: you may instead specify another string
+bleopt exec_elapsed_mark=$'\e[94m[%ss (%s %%)]\e[m'
+# Tip: you may instead change the threshold of showing the mark
+bleopt exec_elapsed_enabled='sys+usr>=10*60*1000' # e.g. ten minutes for total CPU usage
+```
+
+## 2.3 CJK Width
+
+The option `char_width_mode` controls the width of the Unicode characters with `East_Asian_Width=A` (Ambiguous characters).
+Currently four values `emacs`, `west`, `east`, and `auto` are supported. With the value `emacs`, the default width in emacs is used.
+With `west` all the ambiguous characters have width 1 (Hankaku). With `east` all the ambiguous characters have width 2 (Zenkaku).
+With `auto` the width mode `west` or `east` is automatically chosen based on the terminal behavior.
+The default value is `auto`. Appropriate value should be chosen in accordance with your terminal behavior.
+For example, the value can be changed to `west` as:
+
+```bash
+bleopt char_width_mode='west'
+```
+
+## 2.4 Input Encoding
+
+The option `input_encoding` controls the encoding scheme used in the decode of input. Currently `UTF-8` and `C` are available. With the value `C`, byte values are directly interpreted as character codes. The default value is `UTF-8`. For example, the value can be changed to `C` as:
+
+```bash
+bleopt input_encoding='C'
+```
+
+## 2.5 Bell
+
+The options `edit_abell` and `edit_vbell` control the behavior of the edit function `bell`. If `edit_abell` is a non-empty string, audible bell is enabled, i.e. ASCII Control Character `BEL` (0x07) will be written to `stderr`. If `edit_vbell` is a non-empty string, visual bell is enabled. By default, the audible bell is enabled while the visual bell is disabled.
+
+The option `vbell_default_message` specifies the message shown as the visual bell. The default value is `' Wuff, -- Wuff!! '`. The option `vbell_duration` specifies the display duration of the visual-bell message. The unit is millisecond. The default value is `2000`.
+
+For example, the visual bell can be enabled as:
+```
+bleopt edit_vbell=1 vbell_default_message=' BEL ' vbell_duration=3000
+```
+
+For another instance, the audible bell is disabled as:
+```
+bleopt edit_abell=
+```
+
+## 2.6 Highlight Colors
+
+The colors and attributes used in the syntax highlighting are controlled by `ble-face` function. The following code reproduces the default configuration:
+```bash
+# highlighting related to editing
+ble-face -s region bg=60,fg=white
+ble-face -s region_target bg=153,fg=black
+ble-face -s region_match bg=55,fg=white
+ble-face -s region_insert fg=12,bg=252
+ble-face -s disabled fg=242
+ble-face -s overwrite_mode fg=black,bg=51
+ble-face -s auto_complete fg=238,bg=254
+ble-face -s menu_filter_fixed bold
+ble-face -s menu_filter_input fg=16,bg=229
+ble-face -s vbell reverse
+ble-face -s vbell_erase bg=252
+ble-face -s vbell_flash fg=green,reverse
+ble-face -s prompt_status_line fg=231,bg=240
+
+# syntax highlighting
+ble-face -s syntax_default none
+ble-face -s syntax_command fg=brown
+ble-face -s syntax_quoted fg=green
+ble-face -s syntax_quotation fg=green,bold
+ble-face -s syntax_escape fg=magenta
+ble-face -s syntax_expr fg=26
+ble-face -s syntax_error bg=203,fg=231
+ble-face -s syntax_varname fg=202
+ble-face -s syntax_delimiter bold
+ble-face -s syntax_param_expansion fg=purple
+ble-face -s syntax_history_expansion bg=94,fg=231
+ble-face -s syntax_function_name fg=92,bold
+ble-face -s syntax_comment fg=242
+ble-face -s syntax_glob fg=198,bold
+ble-face -s syntax_brace fg=37,bold
+ble-face -s syntax_tilde fg=navy,bold
+ble-face -s syntax_document fg=94
+ble-face -s syntax_document_begin fg=94,bold
+ble-face -s command_builtin_dot fg=red,bold
+ble-face -s command_builtin fg=red
+ble-face -s command_alias fg=teal
+ble-face -s command_function fg=92
+ble-face -s command_file fg=green
+ble-face -s command_keyword fg=blue
+ble-face -s command_jobs fg=red
+ble-face -s command_directory fg=26,underline
+ble-face -s filename_directory underline,fg=26
+ble-face -s filename_directory_sticky underline,fg=white,bg=26
+ble-face -s filename_link underline,fg=teal
+ble-face -s filename_orphan underline,fg=teal,bg=224
+ble-face -s filename_executable underline,fg=green
+ble-face -s filename_setuid underline,fg=black,bg=220
+ble-face -s filename_setgid underline,fg=black,bg=191
+ble-face -s filename_other underline
+ble-face -s filename_socket underline,fg=cyan,bg=black
+ble-face -s filename_pipe underline,fg=lime,bg=black
+ble-face -s filename_character underline,fg=white,bg=black
+ble-face -s filename_block underline,fg=yellow,bg=black
+ble-face -s filename_warning underline,fg=red
+ble-face -s filename_url underline,fg=blue
+ble-face -s filename_ls_colors underline
+ble-face -s varname_array fg=orange,bold
+ble-face -s varname_empty fg=31
+ble-face -s varname_export fg=200,bold
+ble-face -s varname_expr fg=92,bold
+ble-face -s varname_hash fg=70,bold
+ble-face -s varname_number fg=64
+ble-face -s varname_readonly fg=200
+ble-face -s varname_transform fg=29,bold
+ble-face -s varname_unset fg=124
+ble-face -s argument_option fg=teal
+ble-face -s argument_error fg=black,bg=225
+
+```
+
+The current list of faces can be obtained by the following command (`ble-face` without arguments):
+```console
+$ ble-face
+```
+
+The color codes can be checked in output of the function `ble-color-show` (defined in `ble.sh`):
+```console
+$ ble-color-show
+```
+
+## 2.7 Key Bindings
+
+Key bindings can be controlled with the shell function, `ble-bind`.
+For example, with the following setting, "Hello, world!" will be inserted on typing <kbd>C-x h</kbd>
+```bash
+ble-bind -f 'C-x h' 'insert-string "Hello, world!"'
+```
+
+For another example, if you want to invoke a command on typing <kbd>M-c</kbd>, you can write as follows:
+
+```bash
+ble-bind -c 'M-c' 'my-command'
+```
+
+Or, if you want to invoke a edit function (designed for Bash `bind -x`) on typing <kbd>C-r</kbd>, you can write as follows:
+
+```bash
+ble-bind -x 'C-r' 'my-edit-function'
+```
+
+The existing key bindings are shown by the following command:
+```console
+$ ble-bind -P
+```
+
+The list of widgets is shown by the following command:
+```console
+$ ble-bind -L
+```
+
+If you want to run multiple widgets with a key, you can define your own widget by creating a function of the name `ble/widget/YOUR_WIDGET_NAME`
+as illustrated in the following example.
+It is highly recommended to prefix the widget name with `YOUR_NAME/`, `my/`, `blerc/`, `dotfiles/`, etc.
+in order not to conflict with the names of the existing standard widgets.
+
+```bash
+# Example of calling multiple widgets with the key C-t
+function ble/widget/my/example1 {
+ ble/widget/beginning-of-logical-line
+ ble/widget/insert-string 'echo $('
+ ble/widget/end-of-logical-line
+ ble/widget/insert-string ')'
+}
+ble-bind -f C-t my/example1
+```
+
+# 3 Tips
+
+## 3.1 Use multiline mode
+
+When the command line string contains a newline character, `ble.sh` enters the MULTILINE mode.
+
+By typing <kbd>C-v C-j</kbd> or <kbd>C-q C-j</kbd>, you can insert a newline character in the command line string.
+In the MULTILINE mode, <kbd>RET</kbd> (<kbd>C-m</kbd>) causes insertion of a new newline character.
+In the MULTILINE mode, the command can be executed by typing <kbd>C-j</kbd>.
+
+When the shell option `shopt -s cmdhist` is set (which is the default),
+<kbd>RET</kbd> (<kbd>C-m</kbd>) inserts a newline if the current command line string is syntactically incomplete.
+
+## 3.2 Use vim editing mode
+
+If `set -o vi` is specified in `.bashrc` or `set editing-mode vi` is specified in `.inputrc`, the vim mode is enabled.
+For details, please check [the wiki page](https://github.com/akinomyoga/ble.sh/wiki/Vi-(Vim)-editing-mode).
+
+## 3.3 Use `auto-complete`
+
+The feature `auto-complete` is available in Bash 4.0 or later. `auto-complete` automatically suggests a possible completion on user input.
+The suggested contents can be inserted by typing <kbd>S-RET</kbd>
+(when the cursor is at the end of the command line, you can also use <kbd>right</kbd>, <kbd>C-f</kbd> or <kbd>end</kbd> to insert the suggestion).
+If you want to insert only first word of the suggested contents, you can use <kbd>M-right</kbd> or <kbd>M-f</kbd>.
+If you want to accept the suggestion and immediately run the command, you can use <kbd>C-RET</kbd> (if your terminal supports this special key combination).
+
+## 3.4 Use `sabbrev` (static abbrev expansions)
+
+By registering words to `sabbrev`, the words can be expanded to predefined strings.
+When the cursor is just after a registered word, typing <kbd>SP</kbd> causes `sabbrev` expansion.
+For example, with the following settings, when you type <kbd>SP</kbd> after the string `command L`, the command line will be expanded to `command | less`.
+
+```bash
+# blerc
+ble-sabbrev L='| less'
+```
+
+The sabbrev names that starts from `\` are also recommended since it is unlikely to conflict with the real words that is a part of the executed command.
+
+```bash
+# blerc
+ble-sabbrev '\L'='| less'
+```
+
+
+# 4 Contributors
+
+I received many feedbacks from many people in GitHub Issues/PRs.
+I thank all such people for supporting the project.
+Among them, the following people have made particularly significant contributions.
+
+- [`@cmplstofB`](https://github.com/cmplstofB) helped me implementing vim-mode by testing it and giving me a lot of suggestions.
+- [`@dylankb`](https://github.com/dylankb) reported many issues for fzf-integration, initialization, etc.
+- [`@rux616`](https://github.com/rux616) reported several issues and created a PR for fixing the default path of `.blerc`
+- [`@timjrd`](https://github.com/timjrd) suggested and contributed to performance improvements in completion.
+- [`@3ximus`](https://github.com/3ximus) reported many issues for a wide variety of problems.
diff --git a/.local/src/blesh/doc/Release.md b/.local/src/blesh/doc/Release.md
new file mode 100644
index 0000000..e950d82
--- /dev/null
+++ b/.local/src/blesh/doc/Release.md
@@ -0,0 +1,238 @@
+# ble-0.4.0-devel2
+
+## Usage
+
+**Prerequisites**
+
+Bash 3.0+ and basic POSIX utilities are required.
+
+**Download ble-0.4.0-devel2.tar.xz**
+
+https://github.com/akinomyoga/ble.sh/releases/download/v0.4.0-devel2/ble-0.4.0-devel2.tar.xz
+
+```bash
+# DOWNLOAD with wget
+wget https://github.com/akinomyoga/ble.sh/releases/download/v0.4.0-devel2/ble-0.4.0-devel2.tar.xz
+
+# DOWNLOAD with curl
+curl -LO https://github.com/akinomyoga/ble.sh/releases/download/v0.4.0-devel2/ble-0.4.0-devel2.tar.xz
+```
+
+**Trial & Install**
+
+```bash
+# TRIAL
+tar xJf ble-0.4.0-devel2.tar.xz
+source ble-0.4.0-devel2/ble.sh
+
+# INSTALL (quick)
+tar xJf ble-0.4.0-devel2.tar.xz -C ~/.local/share/blesh
+echo 'source ~/.local/share/blesh' >> ~/.bashrc
+
+# INSTALL (more robust)
+tar xJf ble-0.4.0-devel2.tar.xz -C ~/.local/share/blesh
+# Add the following line near the top of ~/.bashrc
+[[ $- == *i* ]] && source ~/.local/share/blesh/ble.sh --attach=none
+# Add the following line at the end of ~/.bashrc
+[[ ${BLE_VERSION-} ]] && ble-attach
+```
+
+--------------------------------------------------------------------------------
+
+# ble-0.3.3
+
+## Usage
+
+**Prerequisites**
+
+Bash 3.0+ and basic POSIX utilities are required.
+
+**Download ble-0.3.3.tar.xz**
+
+https://github.com/akinomyoga/ble.sh/releases/download/v0.3.3/ble-0.3.3.tar.xz
+
+```bash
+# DOWNLOAD with wget
+wget https://github.com/akinomyoga/ble.sh/releases/download/v0.3.3/ble-0.3.3.tar.xz
+
+# DOWNLOAD with curl
+curl -LO https://github.com/akinomyoga/ble.sh/releases/download/v0.3.3/ble-0.3.3.tar.xz
+```
+
+**Trial & Install**
+
+```bash
+# TRIAL
+tar xJf ble-0.3.3.tar.xz
+source ble-0.3.3/ble.sh
+
+# INSTALL
+tar xJf ble-0.3.3.tar.xz -C ~/.local/share/blesh
+# Add the following line near the top of ~/.bashrc
+[[ $- == *i* ]] && source ~/.local/share/blesh/ble.sh --attach=none
+# Add the following line at the end of ~/.bashrc
+[[ ${BLE_VERSION-} ]] && ble-attach
+```
+
+## New features
+
+- syntax: allow unquoted `[!` and `[^` in `simple-word` (reported by cmplstofB) `#D1303` 4bf8b86 (master: 1efe833)
+
+## Changes
+
+- auto-complete: bind `insert-on-end` to `C-e` `#D1250` 1070aba (master: 90b45eb)
+- util (`bleopt`): fail when a specified bleopt variable does not exist (test-util) 0a51044 (master: 5966f22)
+- edit: preserve `PS1` when `internal_suppress_bash_output` is set `#D1344` 537acf2 (master: 6ede0c7)
+- complete: change to generate filenames starting from `.` by default `#D1425` e26867d (master: 987436d)
+
+## Fix
+
+- [ble-0.3] reload: fix a bug that the state is broken by `ble-reload` `#D1266` f2f30d1 (master: N/A)
+- decode (`ble/builtin/bind`): remove comment from bind argument `#D1267` 82f4aaa (master: 880bb2c)
+- complete: clear menu on history move `#D1248` 04fddd6 (master: 06cc7de)
+- syntax: fix a bug that arguments of `eval` are not highlighted `#D1254` 38a7fc7 (master: 5046d14)
+- decode: use `BRE` instead of `ERE` for `POSIX sed` (reported by dylankb) `#D1283` a577ec4 (master: 2184739)
+- vi (vi-command/nth-column): fix a bug in arithmetic expansion (reported by andychu) `#D1292` ea2fa8e (master: da6cc47)
+- complete: fix a bug that menu-filter is only partially turned off by `complete_menu_filter` `#D1298` 7278e27 (master: b3654e2)
+- syntax: fix failglob errors of heredocs of the form `<<$(echo A)` `#D1308` 5ba9400 (master: 3212fd2)
+- util (`bleopt`): fix a bug that a new setting is not defined with `name:=` (test-util) `#D1312` f2dbad0 (master: c757b92)
+- util (`ble/util/{save,restore}-vars`): fix a bug that `name` and `prefix` cannot be saved/restored (test-util) f91f7ed (master: 5f2480c)
+- util (`ble/path#remove{,-glob}`): fix corner cases (test-util) 2ba1d42 (master: ccbc9f8)
+- util (`ble/variable#get-attr`): fix an error message with special variable names such as `?` and `*` `#D1321` b58f006 (master: 557b774)
+- edit: fix a bug that `set +H` is cancelled on command execution `#D1332` bc454a2 (master: 02bdf4e)
+- syntax (`ble/syntax/parse/shift`): fix a bug of shift skip in nested words `#D1333` 78e2170 (master: 65fbba0)
+- util (`ble-stackdump`): fix a shift of line numbers `#D1337` 1505a5b (master: a14b72f)
+- edit (`ble-bind -x`): check range of `READLINE_{POINT,MARK}` `#D1339` 1bc1ff6 (master: efe1e81)
+- main: fix a bug that `~/.config/blesh/init.sh` is not detected (GitHub #53 by rux616) 9f74da6 (master: 61f9e10)
+- util (`ble/string#to{upper,lower}`): work around `LC_COLLATE=en_US.utf8` (test-util) `#D1341` 5d9aa64 (master: 1f6b44e) `#D1355` 4e67719 (master: 4da6103)
+ - fixup 5d9aa64 fef40eb (master: N/A)
+- util (encoding, keyseq): fix miscelleneous encoding bugs (test-util) 6d72d2a (master: 435bd16)
+- edit: work around `WINCH` not updating `COLUMNS`/`LINES` after `ble-reload` `#D1345` e2d54a2 (master: a190455)
+- complete: initialize `bleopt complete_menu_style` options before `complete_load` hook (reported by rux616) `#D1352` 15ba24f (master: 8a9a386)
+- main: fix problems caused by multiple `source ble.sh` in bashrc `#D1354` 983e8a9 (master: 5476933)
+- syntax: allow single-character variable name in named redirections `{a}<>` `#D1360` 52de342 (master: 4760409)
+- decode (`bind`): work around `shopt -s nocasematch` (reported by tigger04) `#D1372` b34ad58 (master: 855cacf)
+- prompt: fix a bug that rprompt is not cleared when `bleopt prompt_rps1` is reset `#D1377` c736bd5 (master: 1904b1d)
+- complete: fix a bug of duplicated completions of filenames with spaces `#D1390` 048f17e (master: 98576c7)
+- complete: fix bugs that quotation disappears on ambiguous completion `#D1387` 048f17e (master: 98576c7)
+- complete: fix a bug that progcomp retry by 124 caused the default completion again `#D1386` 048f17e (master: 98576c7)
+- syntax (tree-enumerate): fix unmodified `wtype` of reconstructed words at the end `#D1385` 048f17e (master: 98576c7)
+- complete: fix superlinear performace of ambiguous matching globpat `#D1389` bd4657a (master: 71afaba)
+- prompt: fix a bug that lonig rps1 is not correctly turned off `#D1401` 9266961 (master: d84bcd8)
+- prompt: fix extra spaces on line folding before double width character `#D1400` 9266961 (master: d84bcd8)
+- syntax (glob bracket expression): fix a bug of unsupported POSIX brackets `#D1402` e1eca65 (master: 6fd9e22)
+- syntax (`ble/syntax:bash/simple-word/evaluate-path-spec`): fix a bug of unrecognized `[!...]` and `[^...]` `#D1403` 50fcd03 (master: 0b842f5)
+- highlight: fix remaininig highlighting of vanishing words `#D1421` `#D1422` 0f85719 (master: 1066653)
+- highlight: fix unhighlighted tilde expansions `~+` (reported by cmplstofB) `#D1424` 1f9abf6 (master: a32962e)
+- complete: fix a problem that the user setting `dotglob` is changed `#D1425` e26867d (master: 987436d)
+- complete: fix a problem of redundant unmatched ambiguous part with tilde expansions in the common prefix `#D1417` 20cb6af (master: 5777d7f)
+- complete (`source:file`): fix a bug that tilde expansion candidates are always filtered out `#D1416` 20cb6af (master: 5777d7f)
+- complete (`cd`): fix duplicate candidates by `CDPATH` (reported by Lennart00 at `oh-my-bash`) `#D1415` 20cb6af (master: 5777d7f)
+
+## Compatibility
+
+- msys2: support2 MSYS (motivated by SUCHMOKUO) `#D1264` 500e051 (master: 47e2863)
+ - edit: support `\$` in `PS1` for MSYS2 `#D1265` b8c2ca6 (master: f6f8956)
+ - edit: fixup b8c2ca6 fe78bd6 (master: N/A)
+ - msys2: work around MSYS2 Bash bug of missing <kbd>CR</kbd> `#D1270` 8c09190 (master: 71f3498)
+- edit (`ble/widget/bracketed-paste`): fix error messages on `paste_end` in older version of Bash (test-util) 1631069 (master: b2c7d1c)
+- decode: work around Bash-3.1 bug of `declare -f` rejecting special characters in function names (test-util) 1631069 (master: b2c7d1c)
+- util (`ble/variable#get-attr`): fix a bug that attributes are not obtained in Bash <= 4.3 (test-util) 1631069 (master: b2c7d1c)
+- decode: work around Bash-4.1 bug that locale not applied with `LC_CTYPE=C eval command` (test-util) 1631069 (master: b2c7d1c)
+- complete: follow Bash-5.1 change of arithmetic literal `10#` `#D1322` b58f006 (master: 557b774)
+- decode: work around Bash-4.1 arithmetic bug of array subscripts evaluated in discarded branches `#D1320` b58f006 (master: 557b774)
+- decode: fix a bug of broken cmap cache found in ble-0.3 `#D1327` 4b15993 (master: 16b56bf)
+- util (strftime): fix a bug not working with `-v var` option in Bash <= 4.1 (test-util) 360211c (master: f1a2818)
+- complete: work around slow `compgen -c` in Cygwin `#D1329` 185a443 (master: 5327f5d)
+- edit: work around problems with `mc` (reported by onelittlehope) `#D1392` 4d534b4 (master: e97aa07)
+ - highlight: fix a problem that the attribute of the last character is applied till EOL `#D1393` f47a5b8 (master: 2ddb1ba) `#D1395` 8c1e17c (master: ef09932)
+
+## Internal
+
+- global: check isolated identifiers and leak variables `#D1246` f92ba5c (master: 19cc99d) 9461953 (master: 2e74b6d)
+- main: unset `BLE_VERSION`, `_ble_bash`, etc. on `ble-unload` `#D1382` 2bbd0fb (master: 6b615b6)
+ - complete: fix unfiltered tilde expansions `#D1414` 20cb6af (master: 5777d7f)
+
+-------------------------------------------------------------------------------
+# ble-0.2.6
+
+## New features
+
+- syntax: allow unquoted `[!` and `[^` in `simple-word` (reported by cmplstofB) `#D1303` 5cff40f (master: 1efe833)
+
+## Changes
+
+- edit: preserve `PS1` when `internal_suppress_bash_output` is set `#D1344` 72ae9c6 (master: 6ede0c7)
+
+## Fix
+
+- decode: use `BRE` instead of `ERE` for `POSIX sed` (reported by dylankb) `#D1283` bca4598 (master: 2184739)
+- vi (vi-command/nth-column): fix a bug in arithmetic expansion (reported by andychu) `#D1292` 4260bc2 (master: da6cc47)
+- syntax: fix failglob errors of heredocs of the form `<<$(echo A)` `#D1308` 1f874ba (master: 3212fd2)
+- util (`bleopt`): fix a bug that a new setting is not defined with `name:=` (test-util) `#D1312` a9eb0e9 (master: c757b92)
+- util (`ble/util/{save,restore}-vars`): fix a bug that `name` and `prefix` cannot be saved/restored (test-util) 49841db (master: 5f2480c)
+- edit: fix a bug that `set +H` is cancelled on command execution `#D1332` 2ff6d06 (master: 02bdf4e)
+- syntax (`ble/syntax/parse/shift`): fix a bug of shift skip in nested words `#D1333` bc935bd (master: 65fbba0)
+- util (`ble-stackdump`): fix a shift of line numbers `#D1337` b597e90 (master: a14b72f)
+- edit (`ble-bind -x`): check range of `READLINE_{POINT,MARK}` `#D1339` 47a93e8 (master: efe1e81)
+- util (`ble/string#to{upper,lower}`): work around `LC_COLLATE=en_US.utf8` (test-util) `#D1341` 5b32621 (master: 1f6b44e) `#D1355` b38ef10 (master: 4da6103)
+- util (encoding, keyseq): fix miscelleneous encoding bugs (test-util) 03c0b44 (master: 435bd16)
+- edit: work around `WINCH` not updating `COLUMNS`/`LINES` after `ble-reload` `#D1345` 50af6a5 (master: a190455)
+- syntax: allow single-character variable name in named redirections `{a}<>` `#D1360` f81734f (master: 4760409)
+- syntax (glob bracket expression): fix a bug of unsupported POSIX brackets `#D1402` b7ea892 (master: 6fd9e22)
+- highlight: fix remaininig highlighting of vanishing words `#D1421` `#D1422` cc5e4d1 (master: 1066653)
+- highlight: fix unhighlighted tilde expansions `~+` (reported by cmplstofB) `#D1424` 3f7f044 (master: a32962e)
+
+## Compatibility
+
+- msys2: support2 MSYS (motivated by SUCHMOKUO) `#D1264` 7cf81c0 (master: 47e2863)
+ - edit: support `\$` in `PS1` for MSYS2 `#D1265` 8f44624 (master: f6f8956)
+ - msys2: work around MSYS2 Bash bug of missing <kbd>CR</kbd> `#D1270` bbe1b61 (master: 71f3498)
+- edit (`ble/widget/bracketed-paste`): fix error messages on `paste_end` in older version of Bash (test-util) a80f1d1 (master: b2c7d1c)
+- decode: work around Bash-3.1 bug of `declare -f` rejecting special characters in function names (test-util) a80f1d1 (master: b2c7d1c)
+- util (`ble/variable#get-attr`): fix a bug that attributes are not obtained in Bash <= 4.3 (test-util) a80f1d1 (master: b2c7d1c)
+- decode: work around Bash-4.1 bug that locale not applied with `LC_CTYPE=C eval command` (test-util) a80f1d1 (master: b2c7d1c)
+- decode: fix a bug of broken cmap cache found in ble-0.3 `#D1327` 366e8c1 (master: 16b56bf)
+- util (strftime): fix a bug not working with `-v var` option in Bash <= 4.1 (test-util) 4f11463 (master: f1a2818)
+- complete: work around slow `compgen -c` in Cygwin `#D1329` 887be6e (master: 5327f5d)
+- edit: work around problems with `mc` (reported by onelittlehope) `#D1392` a2d6099 (master: e97aa07)
+
+## Internal
+
+- global: check isolated identifiers and leak variables `#D1246` 146c98b (master: 19cc99d)
+
+-------------------------------------------------------------------------------
+# ble-0.1.14
+
+## Change
+
+- edit: preserve `PS1` when `internal_suppress_bash_output` is set `#D1344` 549f8f5 (master: 6ede0c7)
+
+## Fix
+
+- fixup ab01ceb 8129816 (v0.2: 51bde60)
+- decode: use `BRE` instead of `ERE` for `POSIX sed` (reported by dylankb) `#D1283` 1244d86 (master: 2184739)
+- edit: fix a bug that `set +H` is cancelled on command execution `#D1332` ba3687a (master: 02bdf4e)
+- syntax (`ble/syntax/parse/shift`): fix a bug of shift skip in nested words `#D1333` 16fb351 (master: 65fbba0)
+- util (`ble-stackdump`): fix a shift of line numbers `#D1337` 5d5b86b (master: a14b72f)
+- edit (`ble-bind -x`): check range of `READLINE_{POINT,MARK}` `#D1339` 6909cc0 (master: efe1e81)
+- util (`ble/string#to{upper,lower}`): work around `LC_COLLATE=en_US.utf8` (test-util) `#D1341` 31476cc (master: 1f6b44e) `#D1355` 65cab5c (master: 4da6103)
+- util (encoding, keyseq): fix miscelleneous encoding bugs (test-util) 11d8db7 (master: 435bd16)
+- edit: work around `WINCH` not updating `COLUMNS`/`LINES` after `ble-reload` `#D1345` e15c5a6 (master: a190455)
+- syntax: allow single-character variable name in named redirections `{a}<>` `#D1360` 6bbed24 (master: 4760409)
+- highlight: fix remaininig highlighting of vanishing words `#D1421` `#D1422` bf8fdc8 (master: 1066653)
+
+## Compatibility
+
+- global: work around Bash 3.2 bug of array initialization with <kbd>SOH</kbd>/<kbd>DEL</kbd> `#D1238` 566f53e (master: defdbd4) `#D1241`
+- msys2: support2 MSYS (motivated by SUCHMOKUO) `#D1264` 19a36ea (master: 47e2863)
+ - edit: support `\$` in `PS1` for MSYS2 `#D1265` 8658738 (master: f6f8956)
+ - msys2: work around MSYS2 Bash bug of missing <kbd>CR</kbd> `#D1270` b72c063 (master: 71f3498)
+- decode: fix a bug of broken cmap cache found in ble-0.3 `#D1327` fc6ded3 (master: 16b56bf)
+- util (strftime): fix a bug not working with `-v var` option in Bash <= 4.1 (test-util) cb2389c (master: f1a2818)
+- complete: work around slow `compgen -c` in Cygwin `#D1329` d6d49cc (master: 5327f5d)
+- edit: work around problems with `mc` (reported by onelittlehope) `#D1392` 15111cf (master: e97aa07)
+
+## Internal
+
+- global: check isolated identifiers and leak variables `#D1246` 03b3204 (master: 19cc99d) 2e74b6d
diff --git a/.local/src/blesh/doc/contrib/LICENSE b/.local/src/blesh/doc/contrib/LICENSE
new file mode 100644
index 0000000..074fea0
--- /dev/null
+++ b/.local/src/blesh/doc/contrib/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2020-2021, K. Murase @akinomyoga <myoga.murase@gmail.com>,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/.local/src/blesh/doc/contrib/README-ja.md b/.local/src/blesh/doc/contrib/README-ja.md
new file mode 100644
index 0000000..fb6b492
--- /dev/null
+++ b/.local/src/blesh/doc/contrib/README-ja.md
@@ -0,0 +1,97 @@
+\[ Language: [English](README.md) | **日本語** ]
+
+# blesh-contrib
+[akinomyoga/ble.sh](https://github.com/akinomyoga/ble.sh)向けの設定
+
+特に指定のない限りこのリポジトリのファイルは [3条項 BSD ライセンス](LICENSE) で提供されます。
+サブディレクトリ `airline` 以下のファイルは MIT ライセンスで提供されます。
+
+<sup>〔訳註: これは[2020年5月20日(日本標準時)時点のREADME.md](https://github.com/akinomyoga/blesh-contrib/blob/8d89d469bd46d9d1158ab5295cd48a3df6942074/README.md) (8d89d46)の,技術的内容を変更しない日本語訳です〕</sup>
+
+## :pencil: fzfとの統合
+
+### 選択肢その1: `~/.fzf.bash`内で設定する
+
+fzfを`ble.sh`と共に用いたい場合,`.fzf.bash`を次のように書き直します(`/path/to/fzf`は fzf ディレクトリへのパスに置き換えてください。※fzf バイナリではなくて **fzf ディレクトリ**へのパスです)。
+
+```bash
+# fzf.bash
+
+# fzfの設定
+# ---------
+
+_ble_contrib_fzf_base=/path/to/fzf
+if [[ ! "$PATH" == *"$_ble_contrib_fzf_base/bin"* ]]; then
+ export PATH="${PATH:+${PATH}:}/path/to/fzf/bin"
+fi
+
+# 自動補完
+# ---------------
+if [[ ${BLE_VERSION-} ]]; then
+ ble-import -d contrib/fzf-completion
+else
+ [[ $- == *i* ]] && source "$_ble_contrib_fzf_base/shell/completion.bash" 2> /dev/null
+fi
+
+# キー束縛
+# ------------
+if [[ ${BLE_VERSION-} ]]; then
+ ble-import -d contrib/fzf-key-bindings
+else
+ source "$_ble_contrib_fzf_base/shell/key-bindings.bash"
+fi
+```
+
+### 選択肢その2: `~/.blerc`内で設定する
+
+別の方法として,`blerc`において次のように直接設定を書くこともできます(`/path/to/fzf`は各人のfzfへのパスに置き換えてください)。
+この場合,`.fzf.bash`を`.bashrc`の中で呼び出さ(`source`コマンドを用い)ないでください。
+
+```bash
+# blerc
+
+# fzfの設定
+_ble_contrib_fzf_base=/path/to/fzf
+ble-import -d contrib/fzf-completion
+ble-import -d contrib/fzf-key-bindings
+```
+
+## :pencil: fzf-git
+
+[fzf-git](https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236)での設定を`ble.sh`と共に用いるには,次のように設定してください。
+
+```bash
+# bashrc / fzf.bash
+if [[ ${BLE_VERSION-} ]]; then
+ _ble_contrib_fzf_base=/path/to/fzf
+ _ble_contrib_fzf_git_config=key-binding:sabbrev:arpeggio
+ ble-import -d contrib/fzf-git
+fi
+```
+
+または,`~/.blerc`内でも構成できます:
+
+```bash
+# blerc
+_ble_contrib_fzf_base=/path/to/fzf
+_ble_contrib_fzf_git_config=key-binding:sabbrev:arpeggio
+ble-import -d contrib/fzf-git
+```
+
+シェル変数`$_ble_contrib_fzf_git_config`には,有効にする束縛の種別をコロン区切りで列挙します。
+`key-binding`という値で,次の形式のキー束縛を有効にします: <kbd>C-g C-f</kbd>, <kbd>C-g C-b</kbd>, <kbd>C-g C-t</kbd>, <kbd>C-g C-h</kbd>及び<kbd>C-g C-r</kbd>。
+`sabbrev`という値で,次の語に対する静的略語展開を有効にします: `gf`, `gb`, `gt`, `gh`及び`gr`。
+`arpeggio`という値で,次のキーの組み合わせを同時に押下できるようにします: <kbd>g f</kbd>, <kbd>g b</kbd>, <kbd>g t</kbd>, <kbd>g h</kbd>及び<kbd>g r</kbd>。
+
+## :pencil: プロンプトにおける特殊指定
+
+### `\q{contrib/vim-mode}`
+
+この指定はVimのモード名に展開されます。
+
+```bash
+# blerc(例)
+ble-import contrib/prompt-vim-mode
+PS1='[\u@\h \W]\q{contrib/vim-mode}\$ ' # PS1にモード名を表示
+bleopt keymap_vi_mode_show:= # モード行を表示しない
+```
diff --git a/.local/src/blesh/doc/contrib/README.md b/.local/src/blesh/doc/contrib/README.md
new file mode 100644
index 0000000..dc1bc80
--- /dev/null
+++ b/.local/src/blesh/doc/contrib/README.md
@@ -0,0 +1,172 @@
+[ Languages: **English** | [日本語](README-ja.md) (Japanese) ]
+
+# blesh-contrib
+Settings for [akinomyoga/ble.sh](https://github.com/akinomyoga/ble.sh)
+
+Unless otherwise specified, files in this repository is licensed by [BSD 3-clause license](LICENSE).
+The files in `airline` are licensed by the MIT License.
+
+## :pencil: fzf integration
+
+Source: [`fzf-completion.bash`](https://github.com/akinomyoga/blesh-contrib/blob/master/fzf-completion.bash),
+ [`fzf-key-bindings.bash`](https://github.com/akinomyoga/blesh-contrib/blob/master/fzf-key-bindings.bash)
+
+Note: If you would like to integrate `fzf-completion` with `bash-completion`, `bash-completion` needs to be loaded before `fzf-completion` is loaded.
+
+### Option 1: Setup in `~/.fzf.bash`
+
+If you would like to use fzf with `ble.sh`, you can rewrite your `.fzf.bash` in the following way (please replace `/path/to/fzf` by your fzf path, the path to the **fzf directory** but not the fzf binary):
+
+```bash
+# fzf.bash
+
+# Setup fzf
+# ---------
+_ble_contrib_fzf_base=/path/to/fzf
+if [[ ! "$PATH" == *"$_ble_contrib_fzf_base/bin"* ]]; then
+ export PATH="${PATH:+${PATH}:}/path/to/fzf/bin"
+fi
+
+# Auto-completion
+# ---------------
+if [[ ${BLE_VERSION-} ]]; then
+ ble-import -d contrib/fzf-completion
+else
+ [[ $- == *i* ]] && source "$_ble_contrib_fzf_base/shell/completion.bash" 2> /dev/null
+fi
+
+# Key bindings
+# ------------
+if [[ ${BLE_VERSION-} ]]; then
+ ble-import -d contrib/fzf-key-bindings
+else
+ source "$_ble_contrib_fzf_base/shell/key-bindings.bash"
+fi
+```
+
+### Option 2: Setup in `~/.blerc`
+
+Or, you can directly write settings in your `blerc` as follows (please replace `/path/to/fzf` by your fzf path).
+In this case do not source `.fzf.bash` in your `.bashrc`.
+
+```bash
+# blerc
+
+# Setup fzf
+_ble_contrib_fzf_base=/path/to/fzf
+ble-import -d contrib/fzf-completion
+ble-import -d contrib/fzf-key-bindings
+```
+
+## :pencil: `contrib/fzf-git`
+
+Source: [`fzf-git.bash`](https://github.com/akinomyoga/blesh-contrib/blob/master/fzf-git.bash)
+
+You can use [fzf-git](https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236) settings for `ble.sh` with the following settings.
+
+```bash
+# bashrc / fzf.bash
+if [[ ${BLE_VERSION-} ]]; then
+ _ble_contrib_fzf_base=/path/to/fzf
+ _ble_contrib_fzf_git_config=key-binding:sabbrev:arpeggio
+ ble-import -d contrib/fzf-git
+fi
+```
+
+Or you can configure it in `~/.blerc`:
+
+```bash
+# blerc
+_ble_contrib_fzf_base=/path/to/fzf
+_ble_contrib_fzf_git_config=key-binding:sabbrev:arpeggio
+ble-import -d contrib/fzf-git
+```
+
+The shell variable `_ble_contrib_fzf_git_config` is a colon-separated list of the enabled types of bindings.
+The value `key-binding` enables the key bindings of the form <kbd>C-g C-f</kbd>, <kbd>C-g C-b</kbd>, <kbd>C-g C-t</kbd>, <kbd>C-g C-h</kbd> and <kbd>C-g C-r</kbd>.
+The value `sabbrev` enables the sabbrev expansion for the words `gf`, `gb`, `gt`, `gh` and `gr`.
+The value `arpeggio` enables the simultaneous key combinations of <kbd>g f</kbd>, <kbd>g b</kbd>, <kbd>g t</kbd>, <kbd>g h</kbd> and <kbd>g r</kbd>.
+
+# &#x2699; Prompt sequences
+
+## :pencil: `contrib/prompt-vim-mode`
+
+Source: [`prompt-vim-mode.bash`](https://github.com/akinomyoga/blesh-contrib/blob/master/prompt-vim-mode.bash)
+
+### `\q{contrib/vim-mode}`
+
+This prompt sequence expands to the vim mode name.
+
+```bash
+# blerc (example)
+
+ble-import contrib/prompt-vim-mode
+PS1='[\u@\h \W]\q{contrib/vim-mode}\$ ' # show mode name in PS1
+bleopt keymap_vi_mode_show:= # hide mode line
+```
+
+## :pencil: `contrib/prompt-git`
+
+Source: [`prompt-git.bash`](https://github.com/akinomyoga/blesh-contrib/blob/master/prompt-git.bash)
+
+```bash
+# blerc (example)
+
+ble-import contrib/prompt-git
+bleopt prompt_rps1='\q{contrib/git-info}'
+```
+
+### `\q{contrib/git-info}`
+
+This expands to a string that explains the current git status.
+
+### `\q{contrib/git-name}`
+
+This expands to the directory name of the repository.
+
+### `\q{contrib/git-hash N}`
+
+This expands to the commit hash.
+The hash is truncated to the length `N`.
+The default value for `N` is `7`.
+
+### `\q{contrib/git-branch}`
+
+This expands to the branch name (or tag name or hash) of `HEAD`.
+
+### `\q{contrib/git-path}`
+
+This expands to the current path relative to the root directory of the repository.
+
+## :pencil: `contrib/prompt-elapsed`
+
+Source: [`prompt-elapsed.bash`](https://github.com/akinomyoga/blesh-contrib/blob/master/prompt-elapsed.bash)
+
+Measures the time of the previous command execution.
+
+```bash
+# blerc (example)
+
+ble-import contrib/prompt-elapsed
+bleopt prompt_rps1='\g{fg=69,italic}\q{contrib/elapsed}'
+```
+
+### `\q{contrib/elapsed}`
+
+This expands to the high-resolution elapsed time for the command execution.
+
+### `\q{contrib/elapsed-real}`
+
+This expands to the `real` time of `time`.
+
+### `\q{contrib/elapsed-user}`
+
+This expands to the `user` time of `time`.
+
+### `\q{contrib/elapsed-sys}`
+
+This expands to the `sys` time of `time`.
+
+### `\q{contrib/elapsed-cpu}`
+
+This expands to the average cpu usage.
diff --git a/.local/src/blesh/keymap/emacs.sh b/.local/src/blesh/keymap/emacs.sh
new file mode 100644
index 0000000..430e213
--- /dev/null
+++ b/.local/src/blesh/keymap/emacs.sh
@@ -0,0 +1,163 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble/is-function ble-edit/bind/load-editing-mode:emacs && return 0
+function ble-edit/bind/load-editing-mode:emacs { :; }
+ble/util/autoload "$_ble_base/keymap/vi.sh" \
+ ble/widget/vi-rlfunc/{prev,end,next}-word \
+ ble/widget/vi-command/{forward,backward}-{v,u}word \
+ ble/widget/vi-command/forward-{v,u}word-end
+_ble_keymap_emacs_white_list=(
+ self-insert
+ batch-insert
+ nop
+ magic-space
+ copy{,-forward,-backward}-{c,f,s,u}word
+ copy-region{,-or}
+ clear-screen
+ command-help
+ display-shell-version
+ redraw-line
+)
+function ble/keymap:emacs/is-command-white {
+ if [[ $1 == ble/widget/self-insert ]]; then
+ return 0
+ elif [[ $1 == ble/widget/* ]]; then
+ local IFS=$_ble_term_IFS
+ local cmd=${1#ble/widget/}; cmd=${cmd%%["$_ble_term_IFS"]*}
+ [[ $cmd == emacs/* || " ${_ble_keymap_emacs_white_list[*]} " == *" $cmd "* ]] && return 0
+ fi
+ return 1
+}
+function ble/widget/emacs/__before_widget__ {
+ if ! ble/keymap:emacs/is-command-white "$WIDGET"; then
+ ble-edit/undo/add
+ fi
+}
+function ble/widget/emacs/undo {
+ local arg; ble-edit/content/get-arg 1
+ ble-edit/undo/undo "$arg" || ble/widget/.bell 'no more older undo history'
+}
+function ble/widget/emacs/redo {
+ local arg; ble-edit/content/get-arg 1
+ ble-edit/undo/redo "$arg" || ble/widget/.bell 'no more recent undo history'
+}
+function ble/widget/emacs/revert {
+ local arg; ble-edit/content/clear-arg
+ ble-edit/undo/revert
+}
+_ble_keymap_emacs_modeline=::
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_emacs_modeline
+function ble/keymap:emacs/update-mode-name {
+ local opt_multiline=; [[ $_ble_edit_str == *$'\n'* ]] && opt_multiline=1
+ local footprint=$opt_multiline:$_ble_edit_arg:$_ble_edit_kbdmacro_record
+ [[ $footprint == "$_ble_keymap_emacs_modeline" ]] && return 0
+ _ble_keymap_emacs_modeline=$footprint
+ local name=
+ [[ $opt_multiline ]] && name=$'\e[1m-- MULTILINE --\e[m'
+ local info=
+ [[ $_ble_edit_arg ]] &&
+ info=$info$' (arg: \e[1;34m'$_ble_edit_arg$'\e[m)'
+ [[ $_ble_edit_kbdmacro_record ]] &&
+ info=$info$' \e[1;31mREC\e[m'
+ [[ ! $info && $opt_multiline ]] &&
+ info=$' (\e[35mRET\e[m or \e[35mC-m\e[m: insert a newline, \e[35mC-j\e[m: run)'
+ [[ $name ]] || info=${info#' '}
+ name=$name$info
+ ble/edit/info/default ansi "$name"
+}
+function ble/widget/emacs/__after_widget__ {
+ ble/keymap:emacs/update-mode-name
+}
+function ble/widget/emacs/quoted-insert-char {
+ _ble_edit_mark_active=
+ _ble_decode_char__hook=ble/widget/emacs/quoted-insert-char.hook
+ return 147
+}
+function ble/widget/emacs/quoted-insert-char.hook {
+ ble/widget/quoted-insert-char.hook
+ ble/keymap:emacs/update-mode-name
+}
+function ble/widget/emacs/quoted-insert {
+ _ble_edit_mark_active=
+ _ble_decode_key__hook=ble/widget/emacs/quoted-insert.hook
+ return 147
+}
+function ble/widget/emacs/quoted-insert.hook {
+ ble/widget/quoted-insert.hook
+ ble/keymap:emacs/update-mode-name
+}
+function ble/widget/emacs/bracketed-paste {
+ ble/widget/bracketed-paste
+ _ble_edit_bracketed_paste_proc=ble/widget/emacs/bracketed-paste.proc
+ return 147
+}
+function ble/widget/emacs/bracketed-paste.proc {
+ ble/widget/bracketed-paste.proc "$@"
+ ble/keymap:emacs/update-mode-name
+}
+function ble-decode/keymap:emacs/define {
+ local ble_bind_nometa=
+ ble-decode/keymap:safe/bind-common
+ ble-decode/keymap:safe/bind-history
+ ble-decode/keymap:safe/bind-complete
+ ble-decode/keymap:safe/bind-arg
+ ble-bind -f 'C-d' 'delete-region-or delete-forward-char-or-exit'
+ ble-bind -f 'M-^' history-expand-line
+ ble-bind -f 'SP' magic-space
+ ble-bind -f __attach__ safe/__attach__
+ ble-bind -f __before_widget__ emacs/__before_widget__
+ ble-bind -f __after_widget__ emacs/__after_widget__
+ ble-bind -f __line_limit__ __line_limit__
+ ble-bind -f 'C-c' discard-line
+ ble-bind -f 'C-j' accept-line
+ ble-bind -f 'C-RET' accept-line
+ ble-bind -f 'C-m' accept-single-line-or-newline
+ ble-bind -f 'RET' accept-single-line-or-newline
+ ble-bind -f 'C-o' accept-and-next
+ ble-bind -f 'C-x C-e' edit-and-execute-command
+ ble-bind -f 'M-#' insert-comment
+ ble-bind -f 'M-C-e' shell-expand-line
+ ble-bind -f 'M-&' tilde-expand
+ ble-bind -f 'C-g' bell
+ ble-bind -f 'C-x C-g' bell
+ ble-bind -f 'C-M-g' bell
+ ble-bind -f 'C-l' clear-screen
+ ble-bind -f 'C-M-l' redraw-line
+ ble-bind -f 'f1' command-help
+ ble-bind -f 'C-x C-v' display-shell-version
+ ble-bind -c 'C-z' fg
+ ble-bind -c 'M-z' fg
+ ble-bind -f 'C-\' bell
+ ble-bind -f 'C-^' bell
+ ble-bind -f 'C-_' emacs/undo
+ ble-bind -f 'C-DEL' emacs/undo
+ ble-bind -f 'C-BS' emacs/undo
+ ble-bind -f 'C-/' emacs/undo
+ ble-bind -f 'C-x u' emacs/undo
+ ble-bind -f 'C-x C-u' emacs/undo
+ ble-bind -f 'C-x U' emacs/redo
+ ble-bind -f 'C-x C-S-u' emacs/redo
+ ble-bind -f 'M-r' emacs/revert
+ ble-bind -f 'C-q' emacs/quoted-insert
+ ble-bind -f 'C-v' emacs/quoted-insert
+ ble-bind -f paste_begin emacs/bracketed-paste
+}
+function ble-decode/keymap:emacs/initialize {
+ local fname_keymap_cache=$_ble_base_cache/keymap.emacs
+ if [[ -s $fname_keymap_cache &&
+ $fname_keymap_cache -nt $_ble_base/keymap/emacs.sh &&
+ $fname_keymap_cache -nt $_ble_base/lib/init-cmap.sh ]]; then
+ source "$fname_keymap_cache" && return 0
+ fi
+ ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.emacs..."
+ {
+ ble/decode/keymap#load isearch dump
+ ble/decode/keymap#load nsearch dump
+ ble/decode/keymap#load emacs dump
+ } 3>| "$fname_keymap_cache"
+ ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.emacs... done"
+}
+ble-decode/keymap:emacs/initialize
+blehook/invoke keymap_load
+blehook/invoke keymap_emacs_load
+return 0
diff --git a/.local/src/blesh/keymap/vi.sh b/.local/src/blesh/keymap/vi.sh
new file mode 100644
index 0000000..ccf8b84
--- /dev/null
+++ b/.local/src/blesh/keymap/vi.sh
@@ -0,0 +1,6171 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble/is-function ble-edit/bind/load-editing-mode:vi && return 0
+function ble-edit/bind/load-editing-mode:vi { :; }
+source "$_ble_base/keymap/vi_digraph.sh"
+bleopt/declare -n keymap_vi_macro_depth 64
+function ble/keymap:vi/k2c {
+ local key=$1
+ local flag=$((key&_ble_decode_MaskFlag)) char=$((key&_ble_decode_MaskChar))
+ if ((flag==0&&(32<=char&&char<_ble_decode_FunctionKeyBase))); then
+ ret=$char
+ return 0
+ elif ((flag==_ble_decode_Ctrl&&63<=char&&char<128&&(char&0x1F)!=0)); then
+ ((char=char==63?127:char&0x1F))
+ ret=$char
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/string#index-of-chars {
+ local chars=$2 index=${3:-0}
+ local text=${1:index}
+ local cut=${text%%["$chars"]*}
+ if ((${#cut}<${#text})); then
+ ((ret=index+${#cut}))
+ return 0
+ else
+ ret=-1
+ return 1
+ fi
+}
+function ble/string#last-index-of-chars {
+ local text=$1 chars=$2 index=$3
+ [[ $index ]] && text=${text::index}
+ local cut=${text%["$chars"]*}
+ if ((${#cut}<${#text})); then
+ ((ret=${#cut}))
+ return 0
+ else
+ ret=-1
+ return 1
+ fi
+}
+function ble-edit/content/nonbol-eolp {
+ local pos=${1:-$_ble_edit_ind}
+ ! ble-edit/content/bolp "$pos" && ble-edit/content/eolp "$pos"
+}
+function ble/keymap:vi/string#encode-rot13 {
+ local text=$1
+ local -a buff=() ch
+ for ((i=0;i<${#text};i++)); do
+ ch=${text:i:1}
+ if [[ $ch == [A-Z] ]]; then
+ ch=${_ble_util_string_upper_list%%"$ch"*}
+ ch=${_ble_util_string_upper_list:(${#ch}+13)%26:1}
+ elif [[ $ch == [a-z] ]]; then
+ ch=${_ble_util_string_lower_list%%"$ch"*}
+ ch=${_ble_util_string_lower_list:(${#ch}+13)%26:1}
+ fi
+ ble/array#push buff "$ch"
+ done
+ IFS= builtin eval 'ret="${buff[*]-}"'
+}
+_ble_keymap_vi_REX_WORD=$'[a-zA-Z0-9_]+|[!-/:-@[-`{-~]+|[^ \t\na-zA-Z0-9!-/:-@[-`{-~]+'
+function ble/widget/vi_imap/__default__ {
+ local flag=$((KEYS[0]&_ble_decode_MaskFlag)) code=$((KEYS[0]&_ble_decode_MaskChar))
+ if ((flag&_ble_decode_Meta)); then
+ ble/keymap:vi/imap-repeat/pop
+ local esc=27 # ESC
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "$esc" $((KEYS[0]&~_ble_decode_Meta)) "${KEYS[@]:1}"
+ return 0
+ fi
+ if local ret; ble/keymap:vi/k2c "${KEYS[0]}"; then
+ local -a KEYS; KEYS=("$ret")
+ ble/widget/self-insert
+ return 0
+ fi
+ return 125
+}
+function ble/widget/vi-command/decompose-meta {
+ local flag=$((KEYS[0]&_ble_decode_MaskFlag)) code=$((KEYS[0]&_ble_decode_MaskChar))
+ if ((flag&_ble_decode_Meta)); then
+ local esc=$((_ble_decode_Ctrl|0x5b)) # C-[ (もしくは esc=27 ESC?)
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "$esc" $((KEYS[0]&~_ble_decode_Meta)) "${KEYS[@]:1}"
+ return 0
+ fi
+ return 125
+}
+function ble/widget/vi_omap/__default__ {
+ ble/widget/vi-command/decompose-meta || ble/widget/vi-command/bell
+ return 0
+}
+function ble/widget/vi_omap/cancel {
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+_ble_keymap_vi_irepeat_count=
+_ble_keymap_vi_irepeat=()
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_irepeat_count \
+ _ble_keymap_vi_irepeat
+function ble/keymap:vi/imap-repeat/pop {
+ local top_index=$((${#_ble_keymap_vi_irepeat[*]}-1))
+ ((top_index>=0)) && builtin unset -v '_ble_keymap_vi_irepeat[top_index]'
+}
+function ble/keymap:vi/imap-repeat/push {
+ local IFS=$_ble_term_IFS
+ ble/array#push _ble_keymap_vi_irepeat "${KEYS[*]-}:$WIDGET"
+}
+function ble/keymap:vi/imap-repeat/reset {
+ local count=${1-}
+ _ble_keymap_vi_irepeat_count=
+ _ble_keymap_vi_irepeat=()
+ ((count>1)) && _ble_keymap_vi_irepeat_count=$count
+}
+function ble/keymap:vi/imap-repeat/process {
+ if ((_ble_keymap_vi_irepeat_count>1)); then
+ local repeat=$_ble_keymap_vi_irepeat_count
+ local -a widgets; widgets=("${_ble_keymap_vi_irepeat[@]}")
+ local i widget
+ for ((i=1;i<repeat;i++)); do
+ for widget in "${widgets[@]}"; do
+ ble/decode/widget/call "${widget#*:}" ${widget%%:*}
+ done
+ done
+ fi
+}
+function ble/keymap:vi/imap/invoke-widget {
+ local WIDGET=$1
+ local -a KEYS; KEYS=("${@:2}")
+ ble/keymap:vi/imap-repeat/push
+ builtin eval -- "$WIDGET"
+}
+_ble_keymap_vi_imap_white_list=(
+ self-insert
+ batch-insert
+ nop
+ magic-space
+ delete-backward-{c,f,s,u}word
+ copy{,-forward,-backward}-{c,f,s,u}word
+ copy-region{,-or}
+ clear-screen
+ command-help
+ display-shell-version
+ redraw-line
+)
+function ble/keymap:vi/imap/is-command-white {
+ if [[ $1 == ble/widget/self-insert ]]; then
+ return 0
+ elif [[ $1 == ble/widget/* ]]; then
+ local IFS=$_ble_term_IFS
+ local cmd=${1#ble/widget/}; cmd=${cmd%%["$_ble_term_IFS"]*}
+ [[ $cmd == vi_imap/* || " ${_ble_keymap_vi_imap_white_list[*]} " == *" $cmd "* ]] && return 0
+ fi
+ return 1
+}
+function ble/widget/vi_imap/__before_widget__ {
+ if ble/keymap:vi/imap/is-command-white "$WIDGET"; then
+ ble/keymap:vi/imap-repeat/push
+ else
+ if ((_ble_keymap_vi_mark_edit_dbeg>=0)); then
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/repeat/record-insert
+ ble/keymap:vi/mark/start-edit-area
+ fi
+ ble/keymap:vi/imap-repeat/reset
+ fi
+}
+function ble/widget/vi_imap/complete {
+ ble/keymap:vi/imap-repeat/pop
+ ble/keymap:vi/undo/add more
+ ble/widget/complete "$@"
+}
+function ble/keymap:vi/complete/insert.hook {
+ [[ $_ble_decode_keymap == vi_imap ||
+ $_ble_decode_keymap == auto_complete ]] || return 1
+ local original=${comp_text:insert_beg:insert_end-insert_beg}
+ local q="'" Q="'\''"
+ local WIDGET="ble/widget/complete-insert '${original//$q/$Q}' '${insert//$q/$Q}' '${suffix//$q/$Q}'"
+ ble/keymap:vi/imap-repeat/push
+ [[ $_ble_decode_keymap == vi_imap ]] &&
+ ble/keymap:vi/undo/add more
+}
+blehook complete_insert+=ble/keymap:vi/complete/insert.hook
+function ble-decode/keymap:vi_imap/bind-complete {
+ ble-bind -f 'C-i' 'vi_imap/complete'
+ ble-bind -f 'TAB' 'vi_imap/complete'
+ ble-bind -f 'C-TAB' 'menu-complete'
+ ble-bind -f 'S-C-i' 'menu-complete backward'
+ ble-bind -f 'S-TAB' 'menu-complete backward'
+ ble-bind -f 'auto_complete_enter' 'auto-complete-enter'
+ ble-bind -f 'C-x /' 'menu-complete context=filename'
+ ble-bind -f 'C-x ~' 'menu-complete context=username'
+ ble-bind -f 'C-x $' 'menu-complete context=variable'
+ ble-bind -f 'C-x @' 'menu-complete context=hostname'
+ ble-bind -f 'C-x !' 'menu-complete context=command'
+ ble-bind -f 'C-]' 'sabbrev-expand'
+ ble-bind -f 'C-x C-r' 'dabbrev-expand'
+ ble-bind -f 'C-x *' 'complete insert_all:context=glob'
+ ble-bind -f 'C-x g' 'complete show_menu:context=glob'
+}
+_ble_keymap_vi_insert_overwrite=
+_ble_keymap_vi_insert_leave=
+_ble_keymap_vi_single_command=
+_ble_keymap_vi_single_command_overwrite=
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_insert_overwrite \
+ _ble_keymap_vi_insert_leave \
+ _ble_keymap_vi_single_command \
+ _ble_keymap_vi_single_command_overwrite
+bleopt/declare -n keymap_vi_mode_string_nmap $'\e[1m~\e[m'
+bleopt/declare -o keymap_vi_nmap_name keymap_vi_mode_string_nmap
+bleopt/declare -v term_vi_imap ''
+bleopt/declare -v term_vi_nmap ''
+bleopt/declare -v term_vi_omap ''
+bleopt/declare -v term_vi_xmap ''
+bleopt/declare -v term_vi_smap ''
+bleopt/declare -v term_vi_cmap ''
+bleopt/declare -v keymap_vi_imap_cursor ''
+bleopt/declare -v keymap_vi_nmap_cursor ''
+bleopt/declare -v keymap_vi_omap_cursor ''
+bleopt/declare -v keymap_vi_xmap_cursor ''
+bleopt/declare -v keymap_vi_smap_cursor ''
+bleopt/declare -v keymap_vi_cmap_cursor ''
+function ble/keymap:vi/.process-cursor-options {
+ local keymap=${FUNCNAME[1]#bleopt/check:keymap_}; keymap=${keymap%_cursor}
+ ble-bind -m "$keymap" --cursor "$value"
+ local locate=$'\e[32m'$bleopt_source:$bleopt_lineno$'\e[m'
+ ble/util/print-lines \
+ "bleopt ($locate): The option 'keymap_${keymap}_cursor' has been removed." \
+ " Please use 'ble-bind -m $keymap --cursor $value' instead." >&2
+}
+function bleopt/check:keymap_vi_imap_cursor { ble/keymap:vi/.process-cursor-options; }
+function bleopt/check:keymap_vi_nmap_cursor { ble/keymap:vi/.process-cursor-options; }
+function bleopt/check:keymap_vi_omap_cursor { ble/keymap:vi/.process-cursor-options; }
+function bleopt/check:keymap_vi_xmap_cursor { ble/keymap:vi/.process-cursor-options; }
+function bleopt/check:keymap_vi_smap_cursor { ble/keymap:vi/.process-cursor-options; }
+function bleopt/check:keymap_vi_cmap_cursor { ble/keymap:vi/.process-cursor-options; }
+function bleopt/obsolete:keymap_vi_imap_cursor { :; }
+function bleopt/obsolete:keymap_vi_nmap_cursor { :; }
+function bleopt/obsolete:keymap_vi_omap_cursor { :; }
+function bleopt/obsolete:keymap_vi_xmap_cursor { :; }
+function bleopt/obsolete:keymap_vi_smap_cursor { :; }
+function bleopt/obsolete:keymap_vi_cmap_cursor { :; }
+bleopt/declare -v keymap_vi_mode_show 1
+function bleopt/check:keymap_vi_mode_show {
+ local bleopt_keymap_vi_mode_show=$value
+ [[ $_ble_attached ]] &&
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+bleopt/declare -v keymap_vi_mode_update_prompt ''
+bleopt/declare -v keymap_vi_mode_name_insert 'INSERT'
+bleopt/declare -v keymap_vi_mode_name_replace 'REPLACE'
+bleopt/declare -v keymap_vi_mode_name_vreplace 'VREPLACE'
+bleopt/declare -v keymap_vi_mode_name_visual 'VISUAL'
+bleopt/declare -v keymap_vi_mode_name_select 'SELECT'
+bleopt/declare -v keymap_vi_mode_name_linewise 'LINE'
+bleopt/declare -v keymap_vi_mode_name_blockwise 'BLOCK'
+function bleopt/check:keymap_vi_mode_name_insert { ble/keymap:vi/update-mode-name; }
+function bleopt/check:keymap_vi_mode_name_replace { ble/keymap:vi/update-mode-name; }
+function bleopt/check:keymap_vi_mode_name_vreplace { ble/keymap:vi/update-mode-name; }
+function bleopt/check:keymap_vi_mode_name_visual { ble/keymap:vi/update-mode-name; }
+function bleopt/check:keymap_vi_mode_name_select { ble/keymap:vi/update-mode-name; }
+function bleopt/check:keymap_vi_mode_name_linewise { ble/keymap:vi/update-mode-name; }
+function bleopt/check:keymap_vi_mode_name_blockwise { ble/keymap:vi/update-mode-name; }
+function ble/keymap:vi/script/get-vi-keymap {
+ ble/prompt/unit/add-hash '$_ble_decode_keymap,${_ble_decode_keymap_stack[*]}'
+ local i=${#_ble_decode_keymap_stack[@]}
+ keymap=$_ble_decode_keymap
+ while [[ $keymap != vi_?map || $keymap == emacs ]]; do
+ ((i--)) || return 1
+ keymap=${_ble_decode_keymap_stack[i]}
+ done
+ [[ $keymap == vi_?map ]]
+}
+function ble/keymap:vi/script/get-mode {
+ ble/prompt/unit/add-hash '$_ble_decode_keymap,${_ble_decode_keymap_stack[*]}'
+ ble/prompt/unit/add-hash '$_ble_keymap_vi_single_command,$_ble_edit_mark_active'
+ mode=
+ local keymap; ble/keymap:vi/script/get-vi-keymap
+ if [[ $_ble_keymap_vi_single_command || $keymap == vi_imap ]]; then
+ local overwrite=
+ if [[ $keymap == vi_imap ]]; then
+ overwrite=$_ble_edit_overwrite_mode
+ elif [[ $keymap == vi_[noxs]map ]]; then
+ overwrite=$_ble_keymap_vi_single_command_overwrite
+ fi
+ case $overwrite in
+ ('') mode=i ;;
+ (R) mode=R ;;
+ (*) mode=$'\x12' ;; # C-r
+ esac
+ fi
+ case $keymap:${_ble_edit_mark_active%+} in
+ (vi_xmap:vi_line) mode=$mode'V' ;;
+ (vi_xmap:vi_block)mode=$mode$'\x16' ;; # C-v
+ (vi_xmap:*) mode=$mode'v' ;;
+ (vi_smap:vi_line) mode=$mode'S' ;;
+ (vi_smap:vi_block)mode=$mode$'\x13' ;; # C-s
+ (vi_smap:*) mode=$mode's' ;;
+ (vi_[no]map:*) mode=$mode'n' ;;
+ (vi_cmap:*) mode=$mode'c' ;;
+ (vi_imap:*) ;;
+ (*:*) mode=$mode'?' ;;
+ esac
+}
+_ble_keymap_vi_mode_name_dirty=
+function ble/keymap:vi/info_reveal.hook {
+ [[ $_ble_keymap_vi_mode_name_dirty ]] || return 0
+ _ble_keymap_vi_mode_name_dirty=
+ ble/keymap:vi/update-mode-name
+}
+blehook info_reveal+=ble/keymap:vi/info_reveal.hook
+function ble/keymap:vi/update-mode-name {
+ if [[ ! $_ble_attached ]] || ble/edit/is-command-layout; then
+ _ble_keymap_vi_mode_name_dirty=1
+ return 0
+ fi
+ local keymap
+ ble/keymap:vi/script/get-vi-keymap || return 0
+ if [[ $keymap == vi_imap ]]; then
+ ble/util/buffer "$bleopt_term_vi_imap"
+ elif [[ $keymap == vi_nmap ]]; then
+ ble/util/buffer "$bleopt_term_vi_nmap"
+ elif [[ $keymap == vi_xmap ]]; then
+ ble/util/buffer "$bleopt_term_vi_xmap"
+ elif [[ $keymap == vi_smap ]]; then
+ ble/util/buffer "$bleopt_term_vi_smap"
+ elif [[ $keymap == vi_omap ]]; then
+ ble/util/buffer "$bleopt_term_vi_omap"
+ elif [[ $keymap == vi_cmap ]]; then
+ ble/edit/info/default text ''
+ ble/util/buffer "$bleopt_term_vi_cmap"
+ return 0
+ fi
+ [[ $bleopt_keymap_vi_mode_update_prompt ]] && ble/prompt/clear
+ local name=
+ if [[ $bleopt_keymap_vi_mode_show ]]; then
+ local show= overwrite=
+ if [[ $keymap == vi_imap ]]; then
+ show=1 overwrite=$_ble_edit_overwrite_mode
+ elif [[ $_ble_keymap_vi_single_command && ( $keymap == vi_nmap || $keymap == vi_omap ) ]]; then
+ show=1 overwrite=$_ble_keymap_vi_single_command_overwrite
+ elif [[ $keymap == vi_[xs]map ]]; then
+ show=x overwrite=$_ble_keymap_vi_single_command_overwrite
+ else
+ name=$bleopt_keymap_vi_mode_string_nmap
+ fi
+ fi
+ if [[ $show ]]; then
+ if [[ $overwrite == R ]]; then
+ name=$bleopt_keymap_vi_mode_name_replace
+ elif [[ $overwrite ]]; then
+ name=$bleopt_keymap_vi_mode_name_vreplace
+ else
+ name=$bleopt_keymap_vi_mode_name_insert
+ fi
+ if [[ $_ble_keymap_vi_single_command ]]; then
+ local ret; ble/string#tolower "$name"; name="($ret)"
+ fi
+ if [[ $show == x ]]; then
+ local mark_type=${_ble_edit_mark_active%+}
+ local visual_name=$bleopt_keymap_vi_mode_name_visual
+ [[ $keymap == vi_smap ]] && visual_name=$bleopt_keymap_vi_mode_name_select
+ if [[ $mark_type == vi_line ]]; then
+ visual_name=$visual_name' '$bleopt_keymap_vi_mode_name_linewise
+ elif [[ $mark_type == vi_block ]]; then
+ visual_name=$visual_name' '$bleopt_keymap_vi_mode_name_blockwise
+ fi
+ if [[ $_ble_keymap_vi_single_command ]]; then
+ name="$name $visual_name"
+ else
+ name=$visual_name
+ fi
+ fi
+ name=$'\e[1m-- '$name$' --\e[m'
+ fi
+ if [[ $_ble_keymap_vi_reg_record ]]; then
+ name=$name${name:+' '}$'\e[1;31mREC @'$_ble_keymap_vi_reg_record_char$'\e[m'
+ elif [[ $_ble_edit_kbdmacro_record ]]; then
+ name=$name${name:+' '}$'\e[1;31mREC\e[m'
+ fi
+ ble/edit/info/default ansi "$name" # 6ms
+}
+function ble/widget/vi_imap/normal-mode.impl {
+ local opts=$1
+ ble/keymap:vi/mark/set-local-mark 94 "$_ble_edit_ind" # `^
+ ble/keymap:vi/mark/end-edit-area
+ [[ :$opts: == *:InsertLeave:* ]] && builtin eval -- "$_ble_keymap_vi_insert_leave"
+ _ble_edit_mark_active=
+ _ble_edit_overwrite_mode=
+ _ble_keymap_vi_insert_leave=
+ _ble_keymap_vi_single_command=
+ _ble_keymap_vi_single_command_overwrite=
+ ble-edit/content/bolp || ((_ble_edit_ind--))
+ ble/decode/keymap/push vi_nmap
+}
+function ble/widget/vi_imap/normal-mode {
+ ble-edit/content/clear-arg
+ ble/keymap:vi/imap-repeat/pop
+ ble/keymap:vi/imap-repeat/process
+ ble/keymap:vi/repeat/record-insert
+ ble/widget/vi_imap/normal-mode.impl InsertLeave
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+function ble/widget/vi_imap/normal-mode-without-insert-leave {
+ ble-edit/content/clear-arg
+ ble/keymap:vi/imap-repeat/pop
+ ble/keymap:vi/repeat/record-insert
+ ble/widget/vi_imap/normal-mode.impl
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+function ble/widget/vi_imap/single-command-mode {
+ ble-edit/content/clear-arg
+ local single_command=1
+ local single_command_overwrite=$_ble_edit_overwrite_mode
+ ble-edit/content/eolp && _ble_keymap_vi_single_command=2
+ ble/keymap:vi/imap-repeat/pop
+ ble/widget/vi_imap/normal-mode.impl
+ _ble_keymap_vi_single_command=$single_command
+ _ble_keymap_vi_single_command_overwrite=$single_command_overwrite
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+function ble/keymap:vi/needs-eol-fix {
+ [[ $_ble_decode_keymap == vi_nmap || $_ble_decode_keymap == vi_omap ]] || return 1
+ [[ $_ble_keymap_vi_single_command ]] && return 1
+ local index=${1:-$_ble_edit_ind}
+ ble-edit/content/nonbol-eolp "$index"
+}
+function ble/keymap:vi/adjust-command-mode {
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ ble/keymap:vi/xmap/remove-eol-extension
+ fi
+ local kmap_popped=
+ if [[ $_ble_decode_keymap == vi_omap ]]; then
+ ble/decode/keymap/pop
+ kmap_popped=1
+ fi
+ if [[ $_ble_keymap_vi_search_activate ]]; then
+ if [[ $_ble_decode_keymap != vi_[xs]map ]]; then
+ _ble_edit_mark_active=$_ble_keymap_vi_search_activate
+ fi
+ _ble_keymap_vi_search_matched=1
+ _ble_keymap_vi_search_activate=
+ else
+ [[ $_ble_edit_mark_active == vi_search ]] && _ble_edit_mark_active=
+ ((_ble_keymap_vi_search_matched)) && _ble_keymap_vi_search_matched=
+ fi
+ if [[ $_ble_decode_keymap == vi_nmap && $_ble_keymap_vi_single_command ]]; then
+ if ((_ble_keymap_vi_single_command==2)); then
+ local index=$((_ble_edit_ind+1))
+ ble-edit/content/nonbol-eolp "$index" && _ble_edit_ind=$index
+ fi
+ ble/widget/vi_nmap/.insert-mode 1 "$_ble_keymap_vi_single_command_overwrite" resume
+ ble/keymap:vi/repeat/clear-insert
+ elif [[ $kmap_popped ]]; then
+ ble/keymap:vi/update-mode-name
+ fi
+ return 0
+}
+function ble/widget/vi-command/bell {
+ ble/widget/.bell "$1"
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi_nmap/.insert-mode {
+ [[ $_ble_decode_keymap == vi_[xs]map ]] && ble/decode/keymap/pop
+ [[ $_ble_decode_keymap == vi_omap ]] && ble/decode/keymap/pop
+ local arg=$1 overwrite=$2
+ ble/keymap:vi/imap-repeat/reset "$arg"
+ _ble_edit_mark_active=
+ _ble_edit_overwrite_mode=$overwrite
+ _ble_keymap_vi_insert_leave=
+ _ble_keymap_vi_insert_overwrite=$overwrite
+ _ble_keymap_vi_single_command=
+ _ble_keymap_vi_single_command_overwrite=
+ ble/keymap:vi/search/clear-matched
+ ble/decode/keymap/pop
+ ble/keymap:vi/update-mode-name
+ ble/keymap:vi/mark/start-edit-area
+ if [[ :$opts: != *:resume:* ]]; then
+ ble/keymap:vi/mark/commit-edit-area "$_ble_edit_ind" "$_ble_edit_ind"
+ fi
+}
+function ble/widget/vi_nmap/insert-mode {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/append-mode {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ if ! ble-edit/content/eolp; then
+ ((_ble_edit_ind++))
+ fi
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/append-mode-at-end-of-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret; ble-edit/content/find-logical-eol
+ _ble_edit_ind=$ret
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/insert-mode-at-beginning-of-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret; ble-edit/content/find-logical-bol
+ _ble_edit_ind=$ret
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/insert-mode-at-first-non-space {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/first-non-space
+ [[ ${_ble_edit_str:_ble_edit_ind:1} == [$' \t'] ]] &&
+ ((_ble_edit_ind++)) # 逆eol補正
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/insert-mode-at-previous-point {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ ble/keymap:vi/mark/get-local-mark 94 && _ble_edit_ind=$ret
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/replace-mode {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi_nmap/.insert-mode "$ARG" R
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/virtual-replace-mode {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi_nmap/.insert-mode "$ARG" 1
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/accept-line {
+ ble/keymap:vi/clear-arg
+ ble/widget/vi_nmap/.insert-mode
+ ble/keymap:vi/repeat/clear-insert
+ [[ $_ble_keymap_vi_reg_record ]] &&
+ ble/widget/vi_nmap/record-register
+ ble/widget/default/accept-line
+}
+function ble/widget/vi-command/edit-and-execute-command {
+ ble/keymap:vi/clear-arg
+ ble/widget/vi_nmap/.insert-mode
+ ble/keymap:vi/repeat/clear-insert
+ [[ $_ble_keymap_vi_reg_record ]] &&
+ ble/widget/vi_nmap/record-register
+ ble/widget/edit-and-execute-command
+}
+_ble_keymap_vi_oparg=
+_ble_keymap_vi_opfunc=
+_ble_keymap_vi_reg=
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_oparg \
+ _ble_keymap_vi_opfunc \
+ _ble_keymap_vi_reg
+_ble_keymap_vi_register=()
+_ble_keymap_vi_register_onplay=
+function ble/keymap:vi/clear-arg {
+ _ble_edit_arg=
+ _ble_keymap_vi_oparg=
+ _ble_keymap_vi_opfunc=
+ _ble_keymap_vi_reg=
+}
+function ble/keymap:vi/get-arg {
+ local default_value=$1
+ REG=$_ble_keymap_vi_reg
+ FLAG=$_ble_keymap_vi_opfunc
+ if [[ ! $_ble_edit_arg && ! $_ble_keymap_vi_oparg ]]; then
+ ARG=$default_value
+ else
+ ARG=$((10#0${_ble_edit_arg:-1}*10#0${_ble_keymap_vi_oparg:-1}))
+ fi
+ ble/keymap:vi/clear-arg
+}
+function ble/keymap:vi/register#load {
+ local reg=$1
+ if [[ $reg ]] && ((reg!=34)); then
+ if [[ $reg == 37 ]]; then # "%
+ ble-edit/content/push-kill-ring "$HISTFILE" ''
+ return 0
+ fi
+ local value=${_ble_keymap_vi_register[reg]}
+ if [[ $value == */* ]]; then
+ ble-edit/content/push-kill-ring "${value#*/}" "${value%%/*}"
+ return 0
+ else
+ ble-edit/content/push-kill-ring
+ return 1
+ fi
+ fi
+}
+function ble/keymap:vi/register#set {
+ local reg=$1 type=$2 content=$3
+ if [[ $reg == +* ]]; then
+ local value=${_ble_keymap_vi_register[reg]}
+ if [[ $value == */* ]]; then
+ local otype=${value%%/*}
+ local oring=${value#*/}
+ if [[ $otype == L ]]; then
+ if [[ $type == q ]]; then
+ type=L content=${oring%$'\n'}$content # V + * → V
+ else
+ type=L content=$oring$content # V + * → V
+ fi
+ elif [[ $type == L ]]; then
+ type=L content=$oring$'\n'$content # C-v + V, v + V → V
+ elif [[ $otype == B:* ]]; then
+ if [[ $type == B:* ]]; then
+ type=$otype' '${type#B:}
+ content=$oring$'\n'$content # C-v + C-v → C-v
+ elif [[ $type == q ]]; then
+ local ret; ble/string#count-char "$content" $'\n'
+ ble/string#repeat ' 0' "$ret"
+ type=$otype$ret
+ content=$oring$$content # C-v + q → C-v
+ else
+ local ret; ble/string#count-char "$content" $'\n'
+ ble/string#repeat ' 0' $((ret+1))
+ type=$otype$ret
+ content=$oring$'\n'$content # C-v + v → C-v
+ fi
+ else
+ type= content=$oring$content # v + C-v, v + v, v + q → v
+ fi
+ fi
+ fi
+ [[ $type == L && $content != *$'\n' ]] && content=$content$'\n'
+ local suppress_default=
+ [[ $type == q ]] && type= suppress_default=1
+ if [[ ! $reg ]] || ((reg==34)); then # ""
+ ble-edit/content/push-kill-ring "$content" "$type"
+ return 0
+ elif ((reg==58||reg==46||reg==37||reg==126)); then # ": ". "% "~
+ ble/widget/.bell "attempted to write on a read-only register #$reg"
+ return 1
+ elif ((reg==95)); then # "_
+ return 0
+ else
+ if [[ ! $suppress_default ]]; then
+ ble-edit/content/push-kill-ring "$content" "$type"
+ fi
+ _ble_keymap_vi_register[reg]=$type/$content
+ return 0
+ fi
+}
+function ble/keymap:vi/register#set-yank {
+ ble/keymap:vi/register#set "$@" || return 1
+ local reg=$1 type=$2 content=$3
+ if [[ $reg == '' || $reg == 34 ]]; then
+ ble/keymap:vi/register#set 48 "$type" "$content" # "0
+ fi
+}
+_ble_keymap_vi_register_49_widget_list=(
+ ble/widget/vi-command/search-matchpair-or
+ ble/widget/vi-command/percentage-line
+ ble/widget/vi-command/goto-mark
+ ble/widget/vi-command/search-forward
+ ble/widget/vi-command/search-backward
+ ble/widget/vi-command/search-repeat
+ ble/widget/vi-command/search-reverse-repeat
+)
+function ble/keymap:vi/register#set-edit {
+ ble/keymap:vi/register#set "$@" || return 1
+ local reg=$1 type=$2 content=$3
+ if [[ $reg == '' || $reg == 34 ]]; then
+ local IFS=$_ble_term_IFS
+ local widget=${WIDGET%%["$_ble_term_IFS"]*}
+ if [[ $content == *$'\n'* || " $widget " == " ${_ble_keymap_vi_register_49_widget_list[*]} " ]]; then
+ local n
+ for ((n=9;n>=2;n--)); do
+ _ble_keymap_vi_register[48+n]=${_ble_keymap_vi_register[48+n-1]}
+ done
+ ble/keymap:vi/register#set 49 "$type" "$content" # "1
+ else
+ ble/keymap:vi/register#set 45 "$type" "$content" # "-
+ fi
+ fi
+}
+function ble/keymap:vi/register#play {
+ local reg=$1 value
+ if [[ $reg ]] && ((reg!=34)); then
+ value=${_ble_keymap_vi_register[reg]}
+ if [[ $value == */* ]]; then
+ value=${value#*/}
+ else
+ value=
+ return 1
+ fi
+ else
+ value=$_ble_edit_kill_ring
+ fi
+ local _ble_keymap_vi_register_onplay=1
+ local ret; ble/decode/charlog#decode "$value"
+ ble/widget/.MACRO "${ret[@]}"
+ return 0
+}
+function ble/keymap:vi/register#dump/escape {
+ local text=$1
+ local out= i=0 iN=${#text}
+ while ((i<iN)); do
+ local tail=${text:i}
+ if ble/util/isprint+ "$tail"; then
+ out=$out$BASH_REMATCH
+ ((i+=${#BASH_REMATCH}))
+ else
+ ble/util/s2c "$tail"
+ local code=$ret
+ if ((code<32)); then
+ ble/util/c2s $((code+64))
+ out=$out$_ble_term_rev^$ret$_ble_term_sgr0
+ elif ((code==127)); then
+ out=$out$_ble_term_rev^?$_ble_term_sgr0
+ elif ((128<=code&&code<160)); then
+ ble/util/c2s $((code-64))
+ out=$out${_ble_term_rev}M-^$ret$_ble_term_sgr0
+ else
+ out=$out${tail::1}
+ fi
+ ((i++))
+ fi
+ done
+ ret=$out
+}
+function ble/keymap:vi/register#dump {
+ local k ret out=
+ local value type content
+ for k in 34 "${!_ble_keymap_vi_register[@]}"; do
+ if ((k==34)); then
+ type=$_ble_edit_kill_type
+ content=$_ble_edit_kill_ring
+ else
+ value=${_ble_keymap_vi_register[k]}
+ type=${value%%/*} content=${value#*/}
+ fi
+ ble/util/c2s "$k"; k=$ret
+ case $type in
+ (L) type=line ;;
+ (B:*) type=block ;;
+ (*) type=char ;;
+ esac
+ ble/keymap:vi/register#dump/escape "$content"; content=$ret
+ out=$out'"'$k' ('$type') '$content$'\n'
+ done
+ ble/edit/info/show ansi "$out"
+ return 0
+}
+function ble/widget/vi-command:reg { ble/keymap:vi/register#dump; }
+function ble/widget/vi-command:regi { ble/keymap:vi/register#dump; }
+function ble/widget/vi-command:regis { ble/keymap:vi/register#dump; }
+function ble/widget/vi-command:regist { ble/keymap:vi/register#dump; }
+function ble/widget/vi-command:registe { ble/keymap:vi/register#dump; }
+function ble/widget/vi-command:register { ble/keymap:vi/register#dump; }
+function ble/widget/vi-command:registers { ble/keymap:vi/register#dump; }
+function ble/widget/vi-command/append-arg {
+ local ret ch=$1
+ if [[ ! $ch ]]; then
+ local n=${#KEYS[@]}
+ local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar))
+ ((code==0)) && return 1
+ ble/util/c2s "$code"; ch=$ret
+ fi
+ ble/util/assert '[[ ! ${ch//[0-9]} ]]'
+ if [[ $ch == 0 && ! $_ble_edit_arg ]]; then
+ ble/widget/vi-command/beginning-of-line
+ return "$?"
+ fi
+ _ble_edit_arg="$_ble_edit_arg$ch"
+ return 0
+}
+function ble/widget/vi-command/register {
+ _ble_decode_key__hook="ble/widget/vi-command/register.hook"
+}
+function ble/widget/vi-command/register.hook {
+ local key=$1
+ ble/keymap:vi/clear-arg
+ local ret
+ if ble/keymap:vi/k2c "$key" && local c=$ret; then
+ if ((65<=c&&c<91)); then # A-Z
+ _ble_keymap_vi_reg=+$((c+32))
+ return 0
+ elif ((97<=c&&c<123||48<=c&&c<58||c==45||c==58||c==46||c==37||c==35||c==61||c==42||c==43||c==126||c==95||c==47)); then # a-z 0-9 - : . % # = * + ~ _ /
+ _ble_keymap_vi_reg=$c
+ return 0
+ elif ((c==34)); then # ""
+ _ble_keymap_vi_reg=$c
+ return 0
+ fi
+ fi
+ ble/widget/vi-command/bell
+ return 1
+}
+_ble_keymap_vi_reg_record=
+_ble_keymap_vi_reg_record_char=
+_ble_keymap_vi_reg_record_play=0
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_reg_record \
+ _ble_keymap_vi_reg_record_char \
+ _ble_keymap_vi_reg_record_play
+function ble/widget/vi_nmap/record-register {
+ if [[ $_ble_keymap_vi_register_onplay ]]; then
+ ble/keymap:vi/clear-arg
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ if [[ $_ble_keymap_vi_reg_record ]]; then
+ ble/keymap:vi/clear-arg
+ local -a ret
+ ble/decode/charlog#end-exclusive-depth1
+ ble/decode/charlog#encode "${ret[@]}"
+ ble/keymap:vi/register#set "$_ble_keymap_vi_reg_record" q "$ret"
+ _ble_keymap_vi_reg_record=
+ ble/keymap:vi/update-mode-name
+ else
+ _ble_decode_key__hook="ble/widget/vi_nmap/record-register.hook"
+ fi
+}
+function ble/widget/vi_nmap/record-register.hook {
+ local key=$1 ret
+ ble/keymap:vi/clear-arg
+ local reg= c=
+ if ble/keymap:vi/k2c "$key" && c=$ret; then
+ if ((65<=c&&c<91)); then # q{A-Z}
+ reg=+$((c+32))
+ elif ((48<=c&&c<58||97<=c&&c<123)); then # q{0-9a-z}
+ reg=$c
+ elif ((c==34)); then # q"
+ reg=$c
+ fi
+ fi
+ if [[ ! $reg ]]; then
+ ble/widget/vi-command/bell "invalid register key=$key"
+ return 1
+ fi
+ if ! ble/decode/charlog#start vi-macro; then
+ ble/widget/.bell 'vi-macro: the logging system is currently busy'
+ return 1
+ fi
+ ble/util/c2s "$c"
+ _ble_keymap_vi_reg_record=$reg
+ _ble_keymap_vi_reg_record_char=$ret
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+function ble/widget/vi_nmap/play-register {
+ _ble_decode_key__hook="ble/widget/vi_nmap/play-register.hook"
+}
+function ble/widget/vi_nmap/play-register.hook {
+ ble/keymap:vi/clear-arg
+ local depth=$_ble_keymap_vi_reg_record_play
+ if ((depth>=bleopt_keymap_vi_macro_depth)) || ble/util/is-stdin-ready; then
+ return 1 # 無限ループを防ぐため
+ fi
+ local _ble_keymap_vi_reg_record_play=$((depth+1))
+ local key=$1
+ local ret
+ if ble/keymap:vi/k2c "$key" && local c=$ret; then
+ ((65<=c&&c<91)) && ((c+=32)) # A-Z -> a-z
+ if ((48<=c&&c<58||97<=c&&c<123)); then # 0-9a-z
+ ble/keymap:vi/register#play "$c" && return 0
+ fi
+ fi
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vi-command/operator {
+ local ret opname=$1
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ local ARG FLAG REG; ble/keymap:vi/get-arg ''
+ local a=$_ble_edit_ind b=$_ble_edit_mark
+ ((a<=b||(a=_ble_edit_mark,b=_ble_edit_ind)))
+ ble/widget/vi_xmap/.save-visual-state
+ local ble_keymap_vi_mark_active=$_ble_edit_mark_active # used in call-operator-blockwise
+ local mark_type=${_ble_edit_mark_active%+}
+ ble/widget/vi_xmap/exit
+ local ble_keymap_vi_opmode=$mark_type
+ if [[ $mark_type == vi_line ]]; then
+ ble/keymap:vi/call-operator-linewise "$opname" "$a" "$b" "$ARG" "$REG"
+ elif [[ $mark_type == vi_block ]]; then
+ ble/keymap:vi/call-operator-blockwise "$opname" "$a" "$b" "$ARG" "$REG"
+ else
+ local end=$b
+ ((end<${#_ble_edit_str}&&end++))
+ ble/keymap:vi/call-operator-charwise "$opname" "$a" "$end" "$ARG" "$REG"
+ fi; local ext=$?
+ ((ext==147)) && return 147
+ ((ext)) && ble/widget/.bell
+ ble/keymap:vi/adjust-command-mode
+ return "$ext"
+ elif [[ $_ble_decode_keymap == vi_nmap ]]; then
+ ble/decode/keymap/push vi_omap
+ _ble_keymap_vi_oparg=$_ble_edit_arg
+ _ble_keymap_vi_opfunc=$opname
+ _ble_edit_arg=
+ ble/keymap:vi/update-mode-name
+ elif [[ $_ble_decode_keymap == vi_omap ]]; then
+ local opname1=${_ble_keymap_vi_opfunc%%:*}
+ if [[ $opname == "$opname1" ]]; then
+ ble/widget/vi_nmap/linewise-operator "$_ble_keymap_vi_opfunc"
+ else
+ ble/keymap:vi/clear-arg
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ fi
+ return 0
+}
+function ble/widget/vi_nmap/linewise-operator {
+ local opname=${1%%:*} opflags=${1#*:}
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1 # _ble_edit_arg is consumed here
+ if ((ARG==1)) || [[ ${_ble_edit_str:_ble_edit_ind} == *$'\n'* ]]; then
+ if [[ :$opflags: == *:vi_char:* || :$opflags: == *:vi_block:* ]]; then
+ local beg=$_ble_edit_ind
+ local ret; ble-edit/content/find-logical-bol "$beg" $((ARG-1)); local end=$ret
+ ((beg<=end)) || local beg=$end end=$beg
+ if [[ :$opflags: == *:vi_block:* ]]; then
+ ble/keymap:vi/call-operator-blockwise "$opname" "$beg" "$end" '' "$REG"
+ else
+ ble/keymap:vi/call-operator-charwise "$opname" "$beg" "$end" '' "$REG"
+ fi
+ else
+ ble/keymap:vi/call-operator-linewise "$opname" "$_ble_edit_ind" "$_ble_edit_ind:$((ARG-1))" '' "$REG"; local ext=$?
+ fi
+ if ((ext==0)); then
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ elif ((ext==147)); then
+ return 147
+ fi
+ fi
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vi_nmap/copy-current-line {
+ ble/widget/vi_nmap/linewise-operator y
+}
+function ble/widget/vi_nmap/kill-current-line {
+ ble/widget/vi_nmap/linewise-operator d
+}
+function ble/widget/vi_nmap/kill-current-line-and-insert {
+ ble/widget/vi_nmap/linewise-operator c
+}
+function ble/widget/vi-command/beginning-of-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret; ble-edit/content/find-logical-bol; local beg=$ret
+ ble/widget/vi-command/exclusive-goto.impl "$beg" "$FLAG" "$REG" nobell
+}
+function ble/keymap:vi/call-operator {
+ ble/keymap:vi/mark/start-edit-area
+ local _ble_keymap_vi_mark_suppress_edit=1
+ ble/keymap:vi/operator:"$@"; local ext=$?
+ ble/util/unlocal _ble_keymap_vi_mark_suppress_edit
+ ble/keymap:vi/mark/end-edit-area
+ if ((ext==0)); then
+ if ble/is-function ble/keymap:vi/operator:"$1".record; then
+ ble/keymap:vi/operator:"$1".record
+ else
+ ble/keymap:vi/repeat/record
+ fi
+ fi
+ return "$ext"
+}
+function ble/keymap:vi/call-operator-charwise {
+ local ch=$1 beg=$2 end=$3 arg=$4 reg=$5
+ ((beg<=end||(beg=$3,end=$2)))
+ if ble/is-function ble/keymap:vi/operator:"$ch"; then
+ local ble_keymap_vi_operator_index=
+ ble/keymap:vi/call-operator "$ch" "$beg" "$end" char "$arg" "$reg"; local ext=$?
+ ((ext==147)) && return 147
+ local index=${ble_keymap_vi_operator_index:-$beg}
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ _ble_edit_ind=$index
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/keymap:vi/call-operator-linewise {
+ local ch=$1 a=$2 b=$3 arg=$4 reg=$5 ia=0 ib=0
+ [[ $a == *:* ]] && local a=${a%%:*} ia=${a#*:}
+ [[ $b == *:* ]] && local b=${b%%:*} ib=${b#*:}
+ local ret
+ ble-edit/content/find-logical-bol "$a" "$ia"; local beg=$ret
+ ble-edit/content/find-logical-eol "$b" "$ib"; local end=$ret
+ if ble/is-function ble/keymap:vi/operator:"$ch"; then
+ local ble_keymap_vi_operator_index=
+ ((end<${#_ble_edit_str}&&end++))
+ ble/keymap:vi/call-operator "$ch" "$beg" "$end" line "$arg" "$reg"; local ext=$?
+ ((ext==147)) && return 147
+ if [[ $ble_keymap_vi_operator_index ]]; then
+ local index=$ble_keymap_vi_operator_index
+ else
+ ble-edit/content/find-logical-bol "$beg"; beg=$ret # operator 中で beg が変更されているかも
+ ble-edit/content/find-non-space "$beg"; local index=$ret
+ fi
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ _ble_edit_ind=$index
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/keymap:vi/call-operator-blockwise {
+ local ch=$1 beg=$2 end=$3 arg=$4 reg=$5
+ if ble/is-function ble/keymap:vi/operator:"$ch"; then
+ local mark_active=${ble_keymap_vi_mark_active:-vi_block}
+ local sub_ranges sub_x1 sub_x2
+ _ble_edit_mark_active=$mark_active ble/keymap:vi/extract-block "$beg" "$end"
+ local nrange=${#sub_ranges[@]}
+ ((nrange)) || return 1
+ local ble_keymap_vi_operator_index=
+ local beg=${sub_ranges[0]}; beg=${beg%%:*}
+ local end=${sub_ranges[nrange-1]}; end=${end#*:}; end=${end%%:*}
+ ble/keymap:vi/call-operator "$ch" "$beg" "$end" block "$arg" "$reg"
+ ((ext==147)) && return 147
+ local index=${ble_keymap_vi_operator_index:-$beg}
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ _ble_edit_ind=$index
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/keymap:vi/operator:d {
+ local context=$3 arg=$4 reg=$5 # beg end は上書きする
+ if [[ $context == line ]]; then
+ ble/keymap:vi/register#set-edit "$reg" L "${_ble_edit_str:beg:end-beg}" || return 1
+ if ((end==${#_ble_edit_str}&&beg>0)); then
+ local ret
+ ((beg--))
+ ble-edit/content/find-logical-bol "$beg"
+ ble-edit/content/find-non-space "$ret"
+ ble_keymap_vi_operator_index=$ret
+ fi
+ ble/widget/.delete-range "$beg" "$end"
+ elif [[ $context == block ]]; then
+ local -a afill=() atext=() arep=()
+ local sub shift=0 slpad0=
+ local smin smax slpad srpad sfill stext
+ for sub in "${sub_ranges[@]}"; do
+ stext=${sub#*:*:*:*:*:}
+ ble/string#split sub : "$sub"
+ smin=${sub[0]} smax=${sub[1]}
+ slpad=${sub[2]} srpad=${sub[3]}
+ sfill=${sub[4]}
+ [[ $slpad0 ]] || slpad0=$slpad # 最初の slpad
+ ble/array#push afill "$sfill"
+ ble/array#push atext "$stext"
+ local ret; ble/string#repeat ' ' $((slpad+srpad))
+ ble/array#push arep $((smin+shift)):$((smax+shift)):"$ret"
+ ((shift+=(slpad+srpad)-(smax-smin)))
+ done
+ IFS=$'\n' builtin eval 'local yank_content="${atext[*]-}"'
+ local IFS=$_ble_term_IFS
+ local yank_type=B:"${afill[*]-}"
+ ble/keymap:vi/register#set-edit "$reg" "$yank_type" "$yank_content" || return 1
+ local rep
+ for rep in "${arep[@]}"; do
+ smin=${rep%%:*}; rep=${rep:${#smin}+1}
+ smax=${rep%%:*}; rep=${rep:${#smax}+1}
+ ble/widget/.replace-range "$smin" "$smax" "$rep"
+ done
+ ((beg+=slpad)) # fix start position
+ else
+ if ((beg<end)); then
+ if [[ $ble_keymap_vi_opmode != vi_char && ${_ble_edit_str:beg:end-beg} == *$'\n'* ]]; then
+ if local rex=$'(^|\n)([ \t]*)$'; [[ ${_ble_edit_str::beg} =~ $rex ]]; then
+ local prefix=${BASH_REMATCH[2]}
+ if rex=$'^[ \t]*(\n|$)'; [[ ${_ble_edit_str:end} =~ $rex ]]; then
+ local suffix=$BASH_REMATCH
+ ((beg-=${#prefix},end+=${#suffix}))
+ ble/keymap:vi/operator:d "$beg" "$end" line "$arg" "$reg"
+ return "$?"
+ fi
+ fi
+ fi
+ ble/keymap:vi/register#set-edit "$reg" '' "${_ble_edit_str:beg:end-beg}" || return 1
+ ble/widget/.delete-range "$beg" "$end"
+ fi
+ fi
+ return 0
+}
+function ble/keymap:vi/operator:c {
+ local context=$3 arg=$4 reg=$5 # beg は上書き対象
+ if [[ $context == line ]]; then
+ ble/keymap:vi/register#set-edit "$reg" L "${_ble_edit_str:beg:end-beg}" || return 1
+ local end2=$end
+ ((end2)) && [[ ${_ble_edit_str:end2-1:1} == $'\n' ]] && ((end2--))
+ local indent= ret
+ ble-edit/content/find-non-space "$beg"; local nol=$ret
+ ((beg<nol)) && indent=${_ble_edit_str:beg:nol-beg}
+ ble/widget/.replace-range "$beg" "$end2" "$indent"
+ ble/widget/vi_nmap/.insert-mode
+ elif [[ $context == block ]]; then
+ ble/keymap:vi/operator:d "$@" || return 1 # @var beg will be overwritten here
+ local sub=${sub_ranges[0]}
+ local smin=${sub%%:*} sub=${sub#*:}
+ local smax=${sub%%:*} sub=${sub#*:}
+ local slpad=${sub%%:*} sub=${sub#*:}
+ ((smin+=slpad,smax=smin,slpad=0))
+ sub_ranges[0]=$smin:$smax:$slpad:$sub
+ ble/widget/vi_xmap/block-insert-mode.impl insert
+ else
+ local ble_keymap_vi_opmode=vi_char
+ ble/keymap:vi/operator:d "$@" || return 1
+ ble/widget/vi_nmap/.insert-mode
+ fi
+ return 0
+}
+function ble/keymap:vi/operator:y.record { :; }
+function ble/keymap:vi/operator:y {
+ local beg=$1 end=$2 context=$3 arg=$4 reg=$5
+ local yank_type= yank_content=
+ if [[ $context == line ]]; then
+ ble_keymap_vi_operator_index=$_ble_edit_ind # operator:y では現在位置を動かさない
+ yank_type=L
+ yank_content=${_ble_edit_str:beg:end-beg}
+ elif [[ $context == block ]]; then
+ local sub
+ local -a afill=() atext=()
+ for sub in "${sub_ranges[@]}"; do
+ local sub4=${sub#*:*:*:*:}
+ local sfill=${sub4%%:*} stext=${sub4#*:}
+ ble/array#push afill "$sfill"
+ ble/array#push atext "$stext"
+ done
+ IFS=$'\n' builtin eval 'local yank_content="${atext[*]-}"'
+ local IFS=$_ble_term_IFS
+ yank_type=B:"${afill[*]-}"
+ else
+ yank_type=
+ yank_content=${_ble_edit_str:beg:end-beg}
+ fi
+ ble/keymap:vi/register#set-yank "$reg" "$yank_type" "$yank_content" || return 1
+ ble/keymap:vi/mark/commit-edit-area "$beg" "$end"
+ return 0
+}
+function ble/keymap:vi/operator:tr.impl {
+ local beg=$1 end=$2 context=$3 filter=$4
+ if [[ $context == block ]]; then
+ local isub=${#sub_ranges[@]}
+ while ((isub--)); do
+ ble/string#split sub : "${sub_ranges[isub]}"
+ local smin=${sub[0]} smax=${sub[1]}
+ local ret; "$filter" "${_ble_edit_str:smin:smax-smin}"
+ ble/widget/.replace-range "$smin" "$smax" "$ret"
+ done
+ else
+ local ret; "$filter" "${_ble_edit_str:beg:end-beg}"
+ ble/widget/.replace-range "$beg" "$end" "$ret"
+ fi
+ return 0
+}
+function ble/keymap:vi/operator:u {
+ ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/string#tolower
+}
+function ble/keymap:vi/operator:U {
+ ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/string#toupper
+}
+function ble/keymap:vi/operator:toggle_case {
+ ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/string#toggle-case
+}
+function ble/keymap:vi/operator:rot13 {
+ ble/keymap:vi/operator:tr.impl "$1" "$2" "$3" ble/keymap:vi/string#encode-rot13
+}
+function ble/keymap:vi/expand-range-for-linewise-operator {
+ local ret
+ ble-edit/content/find-logical-bol "$beg"; beg=$ret
+ ble-edit/content/find-logical-bol "$end"; local bol2=$ret
+ ble-edit/content/find-non-space "$bol2"; local nol2=$ret
+ if ((beg<bol2&&_ble_edit_ind<=bol2&&end<=nol2)); then
+ end=$bol2
+ else
+ ble-edit/content/find-logical-eol "$end"; local end=$ret
+ [[ ${_ble_edit_str:end:1} == $'\n' ]] && ((end++))
+ fi
+}
+function ble/keymap:vi/string#increase-indent {
+ local text=$1 delta=$2
+ local space=$' \t' it=${bleopt_tab_width:-$_ble_term_it}
+ local arr; ble/string#split-lines arr "$text"
+ local -a arr2=()
+ local line indent i len x r
+ for line in "${arr[@]}"; do
+ indent=${line%%[!$space]*}
+ line=${line:${#indent}}
+ ((x=0))
+ if [[ $indent ]]; then
+ ((len=${#indent}))
+ for ((i=0;i<len;i++)); do
+ if [[ ${indent:i:1} == ' ' ]]; then
+ ((x++))
+ else
+ ((x=(x+it)/it*it))
+ fi
+ done
+ fi
+ ((x+=delta,x<0&&(x=0)))
+ indent=
+ if ((x)); then
+ if ((bleopt_indent_tabs&&(r=x/it))); then
+ ble/string#repeat $'\t' "$r"
+ indent=$ret
+ ((x%=it))
+ fi
+ if ((x)); then
+ ble/string#repeat ' ' "$x"
+ indent=$indent$ret
+ fi
+ fi
+ ble/array#push arr2 "$indent$line"
+ done
+ IFS=$'\n' builtin eval 'ret="${arr2[*]-}"'
+}
+function ble/keymap:vi/operator:indent.impl/increase-block-indent {
+ local width=$1
+ local isub=${#sub_ranges[@]}
+ local sub smin slpad ret
+ while ((isub--)); do
+ ble/string#split sub : "${sub_ranges[isub]}"
+ smin=${sub[0]} slpad=${sub[2]}
+ ble/string#repeat ' ' $((slpad+width))
+ ble/widget/.replace-range "$smin" "$smin" "$ret"
+ done
+}
+function ble/keymap:vi/operator:indent.impl/decrease-graphical-block-indent {
+ local width=$1
+ local it=${bleopt_tab_width:-$_ble_term_it} cols=$_ble_textmap_cols
+ local sub smin slpad ret
+ local -a replaces=()
+ local isub=${#sub_ranges[@]}
+ while ((isub--)); do
+ ble/string#split sub : "${sub_ranges[isub]}"
+ smin=${sub[0]} slpad=${sub[2]}
+ ble-edit/content/find-non-space "$smin"; local nsp=$ret
+ ((smin<nsp)) || continue
+ local ax ay bx by
+ ble/textmap#getxy.out --prefix=a "$smin"
+ ble/textmap#getxy.out --prefix=b "$nsp"
+ local w=$(((bx-ax)-(by-ay)*cols-width))
+ ((w<slpad)) && w=$slpad
+ local ins=
+ if ((w)); then
+ local r
+ if ((bleopt_indent_tabs&&(r=(ax+w)/it-ax/it))); then
+ ble/string#repeat $'\t' "$r"; ins=$ret
+ ((w=(ax+w)%it))
+ fi
+ if ((w)); then
+ ble/string#repeat ' ' "$w"
+ ins=$ins$ret
+ fi
+ fi
+ ble/array#push replaces "$smin:$nsp:$ins"
+ done
+ local rep
+ for rep in "${replaces[@]}"; do
+ ble/string#split rep : "$rep"
+ ble/widget/.replace-range "${rep[@]::3}"
+ done
+}
+function ble/keymap:vi/operator:indent.impl/decrease-logical-block-indent {
+ local width=$1
+ local it=${bleopt_tab_width:-$_ble_term_it}
+ local sub smin ret nsp
+ local isub=${#sub_ranges[@]}
+ while ((isub--)); do
+ ble/string#split sub : "${sub_ranges[isub]}"
+ smin=${sub[0]}
+ ble-edit/content/find-non-space "$smin"; nsp=$ret
+ ((smin<nsp)) || continue
+ local stext=${_ble_edit_str:smin:nsp-smin}
+ local i=0 n=${#stext} c=0 pad=0
+ for ((i=0;i<n;i++)); do
+ if [[ ${stext:i:1} == $'\t' ]]; then
+ ((c+=it))
+ else
+ ((c++))
+ fi
+ if ((c>=width)); then
+ pad=$((c-width))
+ nsp=$((smin+i+1))
+ break
+ fi
+ done
+ local padding=
+ ((pad)) && { ble/string#repeat ' ' "$pad"; padding=$ret; }
+ ble/widget/.replace-range "$smin" "$nsp" "$padding"
+ done
+}
+function ble/keymap:vi/operator:indent.impl {
+ local delta=$1 context=$2
+ ((delta)) || return 0
+ if [[ $context == block ]]; then
+ if ((delta>=0)); then
+ ble/keymap:vi/operator:indent.impl/increase-block-indent "$delta"
+ elif ble/edit/use-textmap; then
+ ble/keymap:vi/operator:indent.impl/decrease-graphical-block-indent $((-delta))
+ else
+ ble/keymap:vi/operator:indent.impl/decrease-logical-block-indent $((-delta))
+ fi
+ else
+ [[ $context == char ]] && ble/keymap:vi/expand-range-for-linewise-operator
+ ((beg<end)) && [[ ${_ble_edit_str:end-1:1} == $'\n' ]] && ((end--))
+ local ret
+ ble/keymap:vi/string#increase-indent "${_ble_edit_str:beg:end-beg}" "$delta"; local content=$ret
+ ble/widget/.replace-range "$beg" "$end" "$content"
+ if [[ $context == char ]]; then
+ ble-edit/content/find-non-space "$beg"
+ ble_keymap_vi_operator_index=$ret
+ fi
+ fi
+ return 0
+}
+function ble/keymap:vi/operator:indent-left {
+ local context=$3 arg=${4:-1}
+ ble/keymap:vi/operator:indent.impl $((-bleopt_indent_offset*arg)) "$context"
+}
+function ble/keymap:vi/operator:indent-right {
+ local context=$3 arg=${4:-1}
+ ble/keymap:vi/operator:indent.impl $((bleopt_indent_offset*arg)) "$context"
+}
+function ble/keymap:vi/string#measure-width {
+ local text=$1 iN=${#1} i=0 s=0
+ while ((i<iN)); do
+ if ble/util/isprint+ "${text:i}"; then
+ ((s+=${#BASH_REMATCH},
+ i+=${#BASH_REMATCH}))
+ else
+ ble/util/s2c "${text:i:1}"
+ ble/util/c2w-edit "$ret"
+ ((s+=ret,i++))
+ fi
+ done
+ ret=$s
+}
+function ble/keymap:vi/string#fold/.get-interval {
+ local text=$1 x=$2
+ local it=${bleopt_tab_width:-${_ble_term_it:-8}}
+ local i=0 iN=${#text}
+ for ((i=0;i<iN;i++)); do
+ if [[ ${text:i:1} == $'\t' ]]; then
+ ((x=(x/it+1)*it))
+ else
+ ((x++))
+ fi
+ done
+ ret=$((x-$2))
+}
+function ble/keymap:vi/string#fold {
+ local text=$1
+ local cols=${2:-${COLUMNS-80}}
+ local sp=$' \t' nl=$'\n'
+ local i=0 out= otmp= x=0 xtmp=0
+ local isfirst=1 indent= xindent=0
+ local rex='^([^'$nl$sp']+)|^(['$sp']+)|^.'
+ while [[ ${text:i} =~ $rex ]]; do
+ ((i+=${#BASH_REMATCH}))
+ if [[ ${BASH_REMATCH[1]} ]]; then
+ local word=${BASH_REMATCH[1]}
+ ble/keymap:vi/string#measure-width "$word"
+ if ((xtmp+ret<cols||xtmp<=xindent)); then
+ out=$out$otmp$word
+ ((x=xtmp+=ret))
+ else
+ out=$out$'\n'$indent$word
+ ((x=xtmp=xindent+ret))
+ fi
+ otmp=
+ else
+ local w=1
+ if [[ ${BASH_REMATCH[2]} ]]; then
+ [[ $otmp ]] && continue # 改行直後の空白は無視
+ otmp=${BASH_REMATCH[2]}
+ ble/keymap:vi/string#fold/.get-interval "$otmp" "$x"; w=$ret
+ [[ $isfirst ]] && indent=$otmp xindent=$ret # インデント記録
+ else
+ otmp=' ' w=1
+ fi
+ if ((x+w<cols)); then
+ ((xtmp=x+w))
+ else
+ ((xtmp=xindent))
+ otmp=$'\n'$indent
+ fi
+ fi
+ isfirst=
+ done
+ ret=$out
+}
+function ble/keymap:vi/operator:fold/.fold-paragraphwise {
+ local text=$1
+ local cols=${2:-${COLUMNS:-80}}
+ local nl=$'\n' sp=$' \t'
+ local rex_paragraph='^((['$sp']*'$nl')*)(['$sp']*[^'$sp$nl'][^'$nl']*('$nl'|$))+'
+ local i=0 out=
+ while [[ ${text:i} =~ $rex_paragraph ]]; do
+ ((i+=${#BASH_REMATCH}))
+ local rematch1=${BASH_REMATCH[1]}
+ local len1=${#rematch1}
+ local paragraph=${BASH_REMATCH:len1}
+ ble/keymap:vi/string#fold "$paragraph" "$cols"
+ paragraph=${ret%$'\n'}$'\n'
+ out=$out$rematch1$paragraph
+ done
+ ret=$out${text:i}
+}
+function ble/keymap:vi/operator:fold.impl {
+ local context=$1 opts=$2
+ local ret
+ [[ $context != line ]] && ble/keymap:vi/expand-range-for-linewise-operator
+ local old=${_ble_edit_str:beg:end-beg} oind=$_ble_edit_ind
+ local cols=${COLUMNS:-80}; ((cols>80&&(cols=80)))
+ ble/keymap:vi/operator:fold/.fold-paragraphwise "$old" "$cols"; local new=$ret
+ ble/widget/.replace-range "$beg" "$end" "$new"
+ if [[ :$opts: == *:preserve_point:* ]]; then
+ if ((end<=oind)); then
+ ble_keymap_vi_operator_index=$((beg+${#new}))
+ elif ((beg<oind)); then
+ ble/keymap:vi/operator:fold/.fold-paragraphwise "${old::oind-beg}" "$cols"
+ ble_keymap_vi_operator_index=$((beg+${#ret}))
+ fi
+ else
+ if [[ $new ]]; then
+ ble-edit/content/find-logical-bol $((beg+${#new}-1))
+ ble-edit/content/find-non-space "$ret"
+ ble_keymap_vi_operator_index=$ret
+ fi
+ fi
+ return 0
+}
+function ble/keymap:vi/operator:fold {
+ local context=$3
+ ble/keymap:vi/operator:fold.impl "$context"
+}
+function ble/keymap:vi/operator:fold-preserve-point {
+ local context=$3
+ ble/keymap:vi/operator:fold.impl "$context" preserve_point
+}
+_ble_keymap_vi_filter_args=()
+_ble_keymap_vi_filter_repeat=()
+_ble_keymap_vi_filter_history=()
+_ble_keymap_vi_filter_history_edit=()
+_ble_keymap_vi_filter_history_dirt=()
+_ble_keymap_vi_filter_history_index=0
+function ble/highlight/layer:region/mark:vi_filter/get-face {
+ face=region_target
+}
+function ble/keymap:vi/operator:filter/.cache-repeat {
+ local -a _ble_keymap_vi_repeat _ble_keymap_vi_repeat_irepeat
+ ble/keymap:vi/repeat/record-normal
+ _ble_keymap_vi_filter_repeat=("${_ble_keymap_vi_repeat[@]}")
+}
+function ble/keymap:vi/operator:filter/.record-repeat {
+ ble/keymap:vi/repeat/record-special && return 0
+ local command=$1
+ _ble_keymap_vi_repeat=("${_ble_keymap_vi_filter_repeat[@]}")
+ _ble_keymap_vi_repeat_irepeat=()
+ _ble_keymap_vi_repeat[10]=$command
+}
+function ble/keymap:vi/operator:filter {
+ local context=$3
+ [[ $context != line ]] && ble/keymap:vi/expand-range-for-linewise-operator
+ _ble_keymap_vi_filter_args=("$beg" "$end" "${@:3}")
+ if [[ $_ble_keymap_vi_repeat_invoke ]]; then
+ local command=${_ble_keymap_vi_repeat[10]}
+ ble/keymap:vi/operator:filter/.hook "$command"
+ return "$?"
+ else
+ ble/keymap:vi/operator:filter/.cache-repeat
+ _ble_edit_ind=$beg
+ _ble_edit_mark=$end
+ _ble_edit_mark_active=vi_filter
+ ble/keymap:vi/async-commandline-mode 'ble/keymap:vi/operator:filter/.hook'
+ _ble_edit_PS1='!'
+ ble/history/set-prefix _ble_keymap_vi_filter
+ _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook
+ _ble_keymap_vi_cmap_cancel_hook=ble/keymap:vi/operator:filter/cancel.hook
+ _ble_syntax_lang=bash
+ _ble_highlight_layer__list=(plain syntax region overwrite_mode)
+ return 147
+ fi
+}
+function ble/keymap:vi/operator:filter/cancel.hook {
+ _ble_edit_mark_active= # clear mark:vi_filter
+}
+function ble/keymap:vi/operator:filter/.hook {
+ local command=$1 # 入力されたコマンド
+ if [[ ! $command ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local beg=${_ble_keymap_vi_filter_args[0]}
+ local end=${_ble_keymap_vi_filter_args[1]}
+ local context=${_ble_keymap_vi_filter_args[2]}
+ _ble_edit_mark_active= # clear mark:vi_filter
+ local old=${_ble_edit_str:beg:end-beg} new
+ old=${old%$'\n'}
+ if ! ble/util/assign new 'builtin eval -- "$command" <<< "$old" 2>/dev/null'; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ new=${new%$'\n'}$'\n'
+ ble/widget/.replace-range "$beg" "$end" "$new"
+ _ble_edit_ind=$beg
+ if [[ $context == line ]]; then
+ ble/widget/vi-command/first-non-space
+ else
+ ble/keymap:vi/adjust-command-mode
+ fi
+ ble/keymap:vi/mark/set-previous-edit-area "$beg" $((beg+${#new}))
+ ble/keymap:vi/operator:filter/.record-repeat "$command"
+ return 0
+}
+bleopt/declare -v keymap_vi_operatorfunc ''
+function ble/keymap:vi/operator:map {
+ local context=$3
+ if [[ $bleopt_keymap_vi_operatorfunc ]]; then
+ local opfunc=ble/keymap:vi/operator:$bleopt_keymap_vi_operatorfunc
+ if ble/is-function "$opfunc"; then
+ "$opfunc" "$@"
+ return "$?"
+ fi
+ fi
+ return 1
+}
+function ble/widget/vi-command/exclusive-range.impl {
+ local src=$1 dst=$2 flag=$3 reg=$4 opts=$5
+ if [[ $flag ]]; then
+ local opname=${flag%%:*} opflags=${flag#*:}
+ if [[ :$opflags: == *:vi_line:* ]]; then
+ local ble_keymap_vi_opmode=vi_line
+ ble/keymap:vi/call-operator-linewise "$opname" "$src" "$dst" '' "$reg"; local ext=$?
+ elif [[ :$opflags: == *:vi_block:* ]]; then
+ local ble_keymap_vi_opmode=vi_line
+ ble/keymap:vi/call-operator-blockwise "$opname" "$src" "$dst" '' "$reg"; local ext=$?
+ elif [[ :$opflags: == *:vi_char:* ]]; then
+ local ble_keymap_vi_opmode=vi_char
+ if [[ :$opts: == *:inclusive:* ]]; then
+ ((src<dst?dst--:(dst<src&&src--)))
+ else
+ if ((src<=dst)); then
+ ((dst<${#_ble_edit_str})) &&
+ [[ ${_ble_edit_str:dst:1} != $'\n' ]] &&
+ ((dst++))
+ else
+ ((src<${#_ble_edit_str})) &&
+ [[ ${_ble_edit_str:src:1} != $'\n' ]] &&
+ ((src++))
+ fi
+ fi
+ ble/keymap:vi/call-operator-charwise "$opname" "$src" "$dst" '' "$reg"; local ext=$?
+ else
+ local ble_keymap_vi_opmode=
+ ble/keymap:vi/call-operator-charwise "$opname" "$src" "$dst" '' "$reg"; local ext=$?
+ fi
+ ((ext==147)) && return 147
+ ((ext)) && ble/widget/.bell
+ ble/keymap:vi/adjust-command-mode
+ return "$ext"
+ else
+ ble/keymap:vi/needs-eol-fix "$dst" && ((dst--))
+ if ((dst!=_ble_edit_ind)); then
+ _ble_edit_ind=$dst
+ elif [[ :$opts: != *:nobell:* ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+}
+function ble/widget/vi-command/exclusive-goto.impl {
+ local index=$1 flag=$2 reg=$3 opts=$4
+ if [[ $flag ]]; then
+ if ble-edit/content/bolp "$index"; then
+ local is_linewise=
+ if ((_ble_edit_ind<index)); then
+ ((index--))
+ rex=$'(^|\n)[ \t]*$'
+ [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]] &&
+ is_linewise=1
+ elif ((index<_ble_edit_ind)); then
+ ble-edit/content/bolp &&
+ is_linewise=1
+ fi
+ if [[ $is_linewise ]]; then
+ ble/widget/vi-command/linewise-goto.impl "$index" "$flag" "$reg"
+ return "$?"
+ fi
+ fi
+ fi
+ ble/widget/vi-command/exclusive-range.impl "$_ble_edit_ind" "$index" "$flag" "$reg" "$opts"
+}
+function ble/widget/vi-command/inclusive-goto.impl {
+ local index=$1 flag=$2 reg=$3 opts=$4
+ if [[ $flag ]]; then
+ if ((_ble_edit_ind<=index)); then
+ ble-edit/content/eolp "$index" || ((index++))
+ else
+ ble-edit/content/eolp || ((_ble_edit_ind++))
+ fi
+ fi
+ ble/widget/vi-command/exclusive-range.impl "$_ble_edit_ind" "$index" "$flag" "$reg" "$opts:inclusive"
+}
+function ble/widget/vi-command/linewise-range.impl {
+ local p=$1 q=$2 flag=$3 reg=$4 opts=$5
+ local ret
+ if [[ $q == *:* ]]; then
+ local qbase=${q%%:*} qline=${q#*:}
+ else
+ local qbase=$q qline=0
+ fi
+ local bolx=; local rex=':bolx=([0-9]+):'; [[ :$opts: =~ $rex ]] && bolx=${BASH_REMATCH[1]}
+ local nolx=; local rex=':nolx=([0-9]+):'; [[ :$opts: =~ $rex ]] && nolx=${BASH_REMATCH[1]}
+ if [[ ! $flag ]]; then
+ if [[ ! $nolx ]]; then
+ if [[ ! $bolx ]]; then
+ ble-edit/content/find-logical-bol "$qbase" "$qline"; bolx=$ret
+ fi
+ ble-edit/content/find-non-space "$bolx"; nolx=$ret
+ fi
+ ble-edit/content/nonbol-eolp "$nolx" && ((nolx--))
+ _ble_edit_ind=$nolx
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ local opname=${flag%%:*} opflags=${flag#*:}
+ if ! ble/is-function ble/keymap:vi/operator:"$opname"; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local bolp bolq=$bolx nolq=$nolx
+ ble-edit/content/find-logical-bol "$p"; bolp=$ret
+ [[ $bolq ]] || { ble-edit/content/find-logical-bol "$qbase" "$qline"; bolq=$ret; }
+ if [[ :$opts: == *:require_multiline:* ]]; then
+ if ((bolq==bolp)); then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ fi
+ if [[ :$opflags: == *:vi_char:* || :$opflags: == *:vi_block:* ]]; then
+ local beg=$p end
+ if [[ :$opts: == *:preserve_column:* ]]; then
+ local index
+ ble/keymap:vi/get-index-of-relative-line "$qbase" "$qline"; end=$index
+ elif [[ :$opts: == *:goto_bol:* ]]; then
+ end=$bolq
+ else
+ [[ $nolq ]] || { ble-edit/content/find-non-space "$bolq"; nolq=$ret; }
+ end=$nolq
+ fi
+ ((beg<=end)) || local beg=$end end=$beg
+ if [[ :$opflags: == *:vi_block:* ]]; then
+ local ble_keymap_vi_opmode=vi_block
+ ble/keymap:vi/call-operator "$opname" "$beg" "$end" block '' "$reg"; local ext=$?
+ else
+ local ble_keymap_vi_opmode=vi_char
+ ble/keymap:vi/call-operator "$opname" "$beg" "$end" char '' "$reg"; local ext=$?
+ fi
+ if ((ext)); then
+ ((ext==147)) && return 147
+ ble/widget/vi-command/bell
+ return "$ext"
+ fi
+ else
+ local beg end
+ if ((bolp<=bolq)); then
+ ble-edit/content/find-logical-eol "$bolq"; beg=$bolp end=$ret
+ else
+ ble-edit/content/find-logical-eol "$bolp"; beg=$bolq end=$ret
+ fi
+ ((end<${#_ble_edit_str}&&end++))
+ local ble_keymap_vi_opmode=
+ [[ :$opflags: == *:vi_line:* ]] && ble_keymap_vi_opmode=vi_line
+ ble/keymap:vi/call-operator "$opname" "$beg" "$end" line '' "$reg"; local ext=$?
+ if ((ext)); then
+ ((ext==147)) && return 147
+ ble/widget/vi-command/bell
+ return "$ext"
+ fi
+ local ind=$_ble_edit_ind
+ if [[ $opname == [cd] ]]; then
+ _ble_edit_ind=$beg
+ ble/widget/vi-command/first-non-space
+ elif [[ :$opts: == *:preserve_column:* ]]; then # j k
+ if ((beg<ind)); then
+ ble/string#count-char "${_ble_edit_str:beg:ind-beg}" $'\n'
+ ((ret=-ret))
+ elif ((ind<beg)); then
+ ble/string#count-char "${_ble_edit_str:ind:beg-ind}" $'\n'
+ else
+ ret=0
+ fi
+ if ((ret)); then
+ local index; ble/keymap:vi/get-index-of-relative-line "$_ble_edit_ind" "$ret"
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ _ble_edit_ind=$index
+ fi
+ elif [[ :$opts: == *:goto_bol:* ]]; then # 行指向 yis
+ _ble_edit_ind=$beg
+ else # + - gg G L H
+ if ((beg==bolq||ind<beg)) || [[ ${_ble_edit_str:beg:ind-beg} == *$'\n'* ]] ; then
+ if ((bolq<=bolp)) && [[ $nolq ]]; then
+ local nolb=$nolq
+ else
+ ble-edit/content/find-non-space "$beg"; local nolb=$ret
+ fi
+ ble-edit/content/nonbol-eolp "$nolb" && ((nolb--))
+ ((ind<beg||nolb<ind)) && _ble_edit_ind=$nolb
+ fi
+ fi
+ fi
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-command/linewise-goto.impl {
+ ble/widget/vi-command/linewise-range.impl "$_ble_edit_ind" "$@"
+}
+function ble/keymap:vi/async-read-char.hook {
+ local IFS=$_ble_term_IFS
+ local command="${*:1:$#-1}" key="${*:$#}"
+ if ((key==(_ble_decode_Ctrl|0x6B))); then # C-k
+ ble/decode/keymap/push vi_digraph
+ _ble_keymap_vi_digraph__hook="$command"
+ else
+ builtin eval -- "$command $key"
+ fi
+}
+function ble/keymap:vi/async-read-char {
+ local IFS=$_ble_term_IFS
+ _ble_decode_key__hook="ble/keymap:vi/async-read-char.hook $*"
+ return 147
+}
+_ble_keymap_vi_mark_Offset=32
+_ble_keymap_vi_mark_hindex=
+_ble_keymap_vi_mark_local=()
+_ble_keymap_vi_mark_global=()
+_ble_keymap_vi_mark_history=()
+_ble_keymap_vi_mark_edit_dbeg=-1
+_ble_keymap_vi_mark_edit_dend=-1
+_ble_keymap_vi_mark_edit_dend0=-1
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_mark_hindex \
+ _ble_keymap_vi_mark_local \
+ _ble_keymap_vi_mark_global \
+ _ble_keymap_vi_mark_history \
+ _ble_keymap_vi_mark_edit_dbeg \
+ _ble_keymap_vi_mark_edit_dend \
+ _ble_keymap_vi_mark_edit_dend0
+ble/array#push _ble_edit_dirty_observer ble/keymap:vi/mark/shift-by-dirty-range
+blehook history_onleave+=ble/keymap:vi/mark/history-onleave.hook
+function ble/keymap:vi/mark/history-onleave.hook {
+ if [[ $_ble_decode_keymap == vi_[inoxs]map ]]; then
+ ble/keymap:vi/mark/set-local-mark 34 "$_ble_edit_ind" # `"
+ fi
+}
+function ble/keymap:vi/mark/update-mark-history {
+ local h; ble/history/get-index -v h
+ if [[ ! $_ble_keymap_vi_mark_hindex ]]; then
+ _ble_keymap_vi_mark_hindex=$h
+ elif ((_ble_keymap_vi_mark_hindex!=h)); then
+ local imark value
+ local -a save=()
+ for imark in "${!_ble_keymap_vi_mark_local[@]}"; do
+ local value=${_ble_keymap_vi_mark_local[imark]}
+ ble/array#push save "$imark:$value"
+ done
+ local IFS=$_ble_term_IFS
+ _ble_keymap_vi_mark_history[_ble_keymap_vi_mark_hindex]="${save[*]-}"
+ _ble_keymap_vi_mark_local=()
+ local entry
+ for entry in ${_ble_keymap_vi_mark_history[h]-}; do
+ imark=${entry%%:*} value=${entry#*:}
+ _ble_keymap_vi_mark_local[imark]=$value
+ done
+ _ble_keymap_vi_mark_hindex=$h
+ fi
+}
+blehook history_clear+=ble/keymap:vi/mark/history-clear.hook
+blehook history_delete+=ble/keymap:vi/mark/history-delete.hook
+blehook history_insert+=ble/keymap:vi/mark/history-insert.hook
+function ble/keymap:vi/mark/history-clear.hook {
+ _ble_keymap_vi_mark_global=()
+ _ble_keymap_vi_mark_history=()
+ _ble_keymap_vi_mark_hindex=
+}
+function ble/keymap:vi/mark/history-delete.hook {
+ for imark in "${!_ble_keymap_vi_mark_global[@]}"; do
+ local value=${_ble_keymap_vi_mark_global[imark]}
+ local h=${value%%:*} v=${value#*:}
+ local idel shift=0
+ for idel; do
+ if [[ $idel == *-* ]]; then
+ local b=${idel%-*} e=${idel#*-}
+ ((b<=h&&h<e)) && shift= # delete
+ ((h<e)) && break
+ ((shift+=e-b))
+ else
+ ((idel==h)) && shift= # delete
+ ((idel>=h)) && break
+ ((shift++))
+ fi
+ done
+ [[ $shift ]] &&
+ _ble_keymap_vi_mark_global[imark]=$((h-shift)):$v
+ done
+ ble/builtin/history/array#delete-hindex _ble_keymap_vi_mark_history "$@"
+ _ble_keymap_vi_mark_hindex=
+}
+function ble/keymap:vi/mark/history-insert.hook {
+ local beg=$1 len=$2
+ for imark in "${!_ble_keymap_vi_mark_global[@]}"; do
+ local value=${_ble_keymap_vi_mark_global[imark]}
+ local h=${value%%:*} v=${value#*:}
+ ((h>=beg)) && _ble_keymap_vi_mark_global[imark]=$((h+len)):$v
+ done
+ ble/builtin/history/array#insert-range _ble_keymap_vi_mark_history "$@"
+ _ble_keymap_vi_mark_hindex=
+}
+function ble/keymap:vi/mark/shift-by-dirty-range {
+ local beg=$1 end=$2 end0=$3 reason=$4
+ if [[ $4 == edit ]]; then
+ ble/dirty-range#update --prefix=_ble_keymap_vi_mark_edit_d "${@:1:3}"
+ ble/keymap:vi/xmap/update-dirty-range "$@"
+ ble/keymap:vi/mark/update-mark-history
+ local shift=$((end-end0))
+ local imark
+ for imark in "${!_ble_keymap_vi_mark_local[@]}"; do
+ local value=${_ble_keymap_vi_mark_local[imark]}
+ local index=${value%%:*} rest=${value#*:}
+ ((index<beg)) || _ble_keymap_vi_mark_local[imark]=$((index<end0?beg:index+shift)):$rest
+ done
+ local h; ble/history/get-index -v h
+ for imark in "${!_ble_keymap_vi_mark_global[@]}"; do
+ local value=${_ble_keymap_vi_mark_global[imark]}
+ [[ $value == "$h":* ]] || continue
+ local h=${value%%:*}; value=${value:${#h}+1}
+ local index=${value%%:*}; value=${value:${#index}+1}
+ ((index<beg)) || _ble_keymap_vi_mark_global[imark]=$h:$((index<end0?beg:index+shift)):$value
+ done
+ ble/keymap:vi/mark/set-local-mark 46 "$beg" # `.
+ else
+ ble/dirty-range#clear --prefix=_ble_keymap_vi_mark_edit_d
+ if [[ $4 == newline && $_ble_decode_keymap != vi_cmap ]]; then
+ ble/keymap:vi/mark/set-local-mark 96 0 # ``
+ fi
+ fi
+}
+function ble/keymap:vi/mark/set-global-mark {
+ local c=$1 index=$2 ret
+ ble/keymap:vi/mark/update-mark-history
+ ble-edit/content/find-logical-bol "$index"; local bol=$ret
+ local h; ble/history/get-index -v h
+ _ble_keymap_vi_mark_global[c]=$h:$bol:$((index-bol))
+}
+function ble/keymap:vi/mark/set-local-mark {
+ local c=$1 index=$2 ret
+ ble/keymap:vi/mark/update-mark-history
+ ble-edit/content/find-logical-bol "$index"; local bol=$ret
+ _ble_keymap_vi_mark_local[c]=$bol:$((index-bol))
+}
+function ble/keymap:vi/mark/get-mark.impl {
+ local index=$1 bytes=$2
+ local len=${#_ble_edit_str}
+ ((index>len&&(index=len)))
+ ble-edit/content/find-logical-bol "$index"; index=$ret
+ ble-edit/content/find-logical-eol "$index"; local eol=$ret
+ ((index+=bytes,index>eol&&(index=eol))) # ToDo: calculate by byte offset
+ ret=$index
+ return 0
+}
+function ble/keymap:vi/mark/get-local-mark {
+ local c=$1
+ ble/keymap:vi/mark/update-mark-history
+ local value=${_ble_keymap_vi_mark_local[c]}
+ [[ $value ]] || return 1
+ local data
+ ble/string#split data : "$value"
+ ble/keymap:vi/mark/get-mark.impl "${data[0]}" "${data[1]}" # -> ret
+}
+_ble_keymap_vi_mark_suppress_edit=
+function ble/keymap:vi/mark/set-previous-edit-area {
+ [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0
+ local beg=$1 end=$2
+ ((beg<end)) && ! ble-edit/content/bolp "$end" && ((end--))
+ ble/keymap:vi/mark/set-local-mark 91 "$beg" # `[
+ ble/keymap:vi/mark/set-local-mark 93 "$end" # `]
+ ble/keymap:vi/undo/add
+}
+function ble/keymap:vi/mark/start-edit-area {
+ [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0
+ ble/dirty-range#clear --prefix=_ble_keymap_vi_mark_edit_d
+}
+function ble/keymap:vi/mark/commit-edit-area {
+ local beg=$1 end=$2
+ ble/dirty-range#update --prefix=_ble_keymap_vi_mark_edit_d "$beg" "$end" "$end"
+}
+function ble/keymap:vi/mark/end-edit-area {
+ [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0
+ local beg=$_ble_keymap_vi_mark_edit_dbeg
+ local end=$_ble_keymap_vi_mark_edit_dend
+ ((beg>=0)) && ble/keymap:vi/mark/set-previous-edit-area "$beg" "$end"
+}
+function ble/keymap:vi/mark/set-jump {
+ ble/keymap:vi/mark/set-local-mark 96 "$_ble_edit_ind"
+}
+function ble/widget/vi-command/set-mark {
+ _ble_decode_key__hook="ble/widget/vi-command/set-mark.hook"
+ return 147
+}
+function ble/widget/vi-command/set-mark.hook {
+ local key=$1
+ ble/keymap:vi/clear-arg
+ local ret
+ if ble/keymap:vi/k2c "$key" && local c=$ret; then
+ if ((65<=c&&c<91)); then # A-Z
+ ble/keymap:vi/mark/set-global-mark "$c" "$_ble_edit_ind"
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ elif ((97<=c&&c<123||c==91||c==93||c==60||c==62||c==96||c==39)); then # a-z [ ] < > ` '
+ ((c==39)) && c=96 # m' は m` に読み替える
+ ble/keymap:vi/mark/set-local-mark "$c" "$_ble_edit_ind"
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ fi
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vi-command/goto-mark.impl {
+ local index=$1 flag=$2 reg=$3 opts=$4
+ [[ $flag ]] || ble/keymap:vi/mark/set-jump # ``
+ if [[ :$opts: == *:line:* ]]; then
+ ble/widget/vi-command/linewise-goto.impl "$index" "$flag" "$reg"
+ else
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg" nobell
+ fi
+}
+function ble/widget/vi-command/goto-local-mark.impl {
+ local c=$1 opts=$2 ret
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ if ble/keymap:vi/mark/get-local-mark "$c" && local index=$ret; then
+ ble/widget/vi-command/goto-mark.impl "$index" "$FLAG" "$REG" "$opts"
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi-command/goto-global-mark.impl {
+ local c=$1 opts=$2
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/keymap:vi/mark/update-mark-history
+ local value=${_ble_keymap_vi_mark_global[c]}
+ if [[ ! $value ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local data
+ ble/string#split data : "$value"
+ local index; ble/history/get-index
+ if ((index!=data[0])); then
+ if [[ $FLAG ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ ble-edit/history/goto "${data[0]}"
+ fi
+ local ret
+ ble/keymap:vi/mark/get-mark.impl "${data[1]}" "${data[2]}"
+ ble/widget/vi-command/goto-mark.impl "$ret" "$FLAG" "$REG" "$opts"
+}
+function ble/widget/vi-command/goto-mark {
+ _ble_decode_key__hook="ble/widget/vi-command/goto-mark.hook ${1:-char}"
+ return 147
+}
+function ble/widget/vi-command/goto-mark.hook {
+ local opts=$1 key=$2
+ local ret
+ if ble/keymap:vi/k2c "$key" && local c=$ret; then
+ if ((65<=c&&c<91)); then # A-Z
+ ble/widget/vi-command/goto-global-mark.impl "$c" "$opts"
+ return "$?"
+ elif ((_ble_keymap_vi_mark_Offset<=c)); then
+ ((c==39)) && c=96 # `' は `` に読み替える
+ ble/widget/vi-command/goto-local-mark.impl "$c" "$opts"
+ return "$?"
+ fi
+ fi
+ ble/keymap:vi/clear-arg
+ ble/widget/vi-command/bell
+ return 1
+}
+_ble_keymap_vi_repeat=()
+_ble_keymap_vi_repeat_insert=()
+_ble_keymap_vi_repeat_irepeat=()
+_ble_keymap_vi_repeat_invoke=
+function ble/keymap:vi/repeat/record-special {
+ [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0
+ if [[ $_ble_keymap_vi_repeat_invoke ]]; then
+ [[ $repeat_arg ]] && _ble_keymap_vi_repeat[3]=$repeat_arg
+ [[ ! ${_ble_keymap_vi_repeat[5]} ]] && _ble_keymap_vi_repeat[5]=$repeat_reg
+ return 0
+ fi
+ return 1
+}
+function ble/keymap:vi/repeat/record-normal {
+ local IFS=$_ble_term_IFS
+ local -a repeat; repeat=("$KEYMAP" "${KEYS[*]-}" "$WIDGET" "$ARG" "$FLAG" "$REG" '')
+ if [[ $KEYMAP == vi_[xs]map ]]; then
+ repeat[6]=$_ble_keymap_vi_xmap_prev_edit
+ fi
+ if [[ $_ble_decode_keymap == vi_imap ]]; then
+ _ble_keymap_vi_repeat_insert=("${repeat[@]}")
+ else
+ _ble_keymap_vi_repeat=("${repeat[@]}")
+ _ble_keymap_vi_repeat_irepeat=()
+ fi
+}
+function ble/keymap:vi/repeat/record {
+ ble/keymap:vi/repeat/record-special && return 0
+ ble/keymap:vi/repeat/record-normal
+}
+function ble/keymap:vi/repeat/record-insert {
+ ble/keymap:vi/repeat/record-special && return 0
+ if [[ ${_ble_keymap_vi_repeat_insert-} ]]; then
+ _ble_keymap_vi_repeat=("${_ble_keymap_vi_repeat_insert[@]}")
+ _ble_keymap_vi_repeat_irepeat=("${_ble_keymap_vi_irepeat[@]}")
+ elif ((${#_ble_keymap_vi_irepeat[@]})); then
+ local IFS=$_ble_term_IFS
+ _ble_keymap_vi_repeat=(vi_nmap "${KEYS[*]-}" ble/widget/vi_nmap/insert-mode 1 '' '')
+ _ble_keymap_vi_repeat_irepeat=("${_ble_keymap_vi_irepeat[@]}")
+ fi
+ ble/keymap:vi/repeat/clear-insert
+}
+function ble/keymap:vi/repeat/clear-insert {
+ _ble_keymap_vi_repeat_insert=()
+}
+function ble/keymap:vi/repeat/invoke {
+ local repeat_arg=$_ble_edit_arg
+ local repeat_reg=$_ble_keymap_vi_reg
+ local KEYMAP=${_ble_keymap_vi_repeat[0]}
+ local -a KEYS; ble/string#split-words KEYS "${_ble_keymap_vi_repeat[1]}"
+ local WIDGET=${_ble_keymap_vi_repeat[2]}
+ if [[ $KEYMAP != vi_[onxs]map ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ elif [[ $KEYMAP == vi_omap ]]; then
+ ble/decode/keymap/push vi_omap
+ elif [[ $KEYMAP == vi_[xs]map ]]; then
+ local _ble_keymap_vi_xmap_prev_edit=${_ble_keymap_vi_repeat[6]}
+ ble/widget/vi_xmap/.restore-visual-state
+ ble/decode/keymap/push "$KEYMAP"
+ fi
+ _ble_edit_arg=
+ _ble_keymap_vi_oparg=${_ble_keymap_vi_repeat[3]}
+ _ble_keymap_vi_opfunc=${_ble_keymap_vi_repeat[4]}
+ [[ $repeat_arg ]] && _ble_keymap_vi_oparg=$repeat_arg
+ local REG=${_ble_keymap_vi_repeat[5]}
+ [[ $REG ]] && _ble_keymap_vi_reg=$REG
+ local _ble_keymap_vi_single_command{,_overwrite}= # single-command-mode は持続させる。
+ local _ble_keymap_vi_repeat_invoke=1
+ local LASTWIDGET=$_ble_decode_widget_last
+ _ble_decode_widget_last=$WIDGET
+ builtin eval -- "$WIDGET"
+ if [[ $_ble_decode_keymap == vi_imap ]]; then
+ ((_ble_keymap_vi_irepeat_count<=1?(_ble_keymap_vi_irepeat_count=2):_ble_keymap_vi_irepeat_count++))
+ local -a _ble_keymap_vi_irepeat
+ _ble_keymap_vi_irepeat=("${_ble_keymap_vi_repeat_irepeat[@]}")
+ ble/array#push _ble_keymap_vi_irepeat '0:ble/widget/dummy' # Note: normal-mode が自分自身を pop しようとするので。
+ ble/widget/vi_imap/normal-mode
+ fi
+ ble/util/unlocal _ble_keymap_vi_single_command{,_overwrite}
+}
+function ble/widget/vi_nmap/repeat {
+ ble/keymap:vi/repeat/invoke
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/vi-command/forward-char {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local index
+ if [[ $1 == wrap ]]; then
+ if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then
+ ((index=_ble_edit_ind+ARG,
+ index>${#_ble_edit_str}&&(index=${#_ble_edit_str})))
+ else
+ local nl=$'\n'
+ local rex="^([^$nl]$nl?|$nl){0,$ARG}"
+ [[ ${_ble_edit_str:_ble_edit_ind} =~ $rex ]]
+ ((index=_ble_edit_ind+${#BASH_REMATCH}))
+ fi
+ else
+ local line=${_ble_edit_str:_ble_edit_ind:ARG}
+ line=${line%%$'\n'*}
+ ((index=_ble_edit_ind+${#line}))
+ fi
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG"
+}
+function ble/widget/vi-command/backward-char {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local index
+ ((ARG>_ble_edit_ind&&(ARG=_ble_edit_ind)))
+ if [[ $1 == wrap ]]; then
+ if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then
+ ((index=_ble_edit_ind-ARG,index<0&&(index=0)))
+ else
+ local width=$ARG line
+ while ((width<=_ble_edit_ind)); do
+ line=${_ble_edit_str:_ble_edit_ind-width:width}
+ line=${line//[!$'\n']$'\n'/x}
+ ((${#line}>=ARG)) && break
+ ((width+=ARG-${#line}))
+ done
+ ((index=_ble_edit_ind-width,index<0&&(index=0)))
+ fi
+ else
+ local line=${_ble_edit_str:_ble_edit_ind-ARG:ARG}
+ line=${line##*$'\n'}
+ ((index=_ble_edit_ind-${#line}))
+ fi
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG"
+}
+function ble/widget/vi_nmap/forward-char-toggle-case {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local line=${_ble_edit_str:_ble_edit_ind:ARG}
+ line=${line%%$'\n'*}
+ local len=${#line}
+ if ((len==0)); then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local index=$((_ble_edit_ind+len))
+ local ret; ble/string#toggle-case "${_ble_edit_str:_ble_edit_ind:len}"
+ ble/widget/.replace-range "$_ble_edit_ind" "$index" "$ret"
+ ble/keymap:vi/mark/set-previous-edit-area "$_ble_edit_ind" "$index"
+ ble/keymap:vi/repeat/record
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ _ble_edit_ind=$index
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-command/.history-relative-line {
+ local offset=$1
+ ((offset)) || return 0
+ if [[ ! $_ble_history_prefix && ! $_ble_history_load_done ]]; then
+ ((offset<0)) || return 1
+ ble/history/initialize # to use ble/history/get-index
+ fi
+ local index histsize
+ ble/history/get-index
+ ble/history/get-count -v histsize
+ local ret count=$((offset<0?-offset:offset)) exit=1
+ ((count--))
+ while ((count>=0)); do
+ if ((offset<0)); then
+ ((index>0)) || return "$exit"
+ ble/widget/history-prev
+ ret=${#_ble_edit_str}
+ ble/keymap:vi/needs-eol-fix "$ret" && ((ret--))
+ _ble_edit_ind=$ret
+ else
+ ((index<histsize)) || return "$exit"
+ ble/widget/history-next
+ _ble_edit_ind=0
+ fi
+ exit=0
+ ble/string#count-char "$_ble_edit_str" $'\n'; local nline=$((ret+1))
+ ((count<nline)) && break
+ ((count-=nline))
+ done
+ if ((count)); then
+ if ((offset<0)); then
+ ble-edit/content/find-logical-eol 0 $((nline-count-1))
+ ble/keymap:vi/needs-eol-fix "$ret" && ((ret--))
+ else
+ ble-edit/content/find-logical-bol 0 "$count"
+ fi
+ _ble_edit_ind=$ret
+ fi
+ return 0
+}
+function ble/keymap:vi/get-index-of-relative-line {
+ local ind=${1:-$_ble_edit_ind} offset=$2
+ if ((offset==0)); then
+ index=$ind
+ return 0
+ fi
+ local count=$((offset<0?-offset:offset))
+ local ret
+ ble-edit/content/find-logical-bol "$ind" 0; local bol1=$ret
+ ble-edit/content/find-logical-bol "$ind" "$offset"; local bol2=$ret
+ if ble/edit/use-textmap; then
+ local b1x b1y; ble/textmap#getxy.cur --prefix=b1 "$bol1"
+ local b2x b2y; ble/textmap#getxy.cur --prefix=b2 "$bol2"
+ ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret
+ local c1x c1y; ble/textmap#getxy.cur --prefix=c1 "$ind"
+ local e2x e2y; ble/textmap#getxy.cur --prefix=e2 "$eol2"
+ local x=$c1x y=$((b2y+c1y-b1y))
+ ((y>e2y&&(x=e2x,y=e2y)))
+ ble/textmap#get-index-at "$x" "$y" # local variable "index" is set here
+ else
+ ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret
+ ((index=bol2+ind-bol1,index>eol2&&(index=eol2)))
+ fi
+}
+function ble/widget/vi-command/relative-line.impl {
+ local offset=$1 flag=$2 reg=$3 opts=$4
+ ((offset==0)) && return 0
+ if [[ $flag ]]; then
+ ble/widget/vi-command/linewise-goto.impl "$_ble_edit_ind:$offset" "$flag" "$reg" preserve_column:require_multiline
+ return "$?"
+ fi
+ local count=$((offset<0?-offset:offset)) ret
+ if ((offset<0)); then
+ ble/string#count-char "${_ble_edit_str::_ble_edit_ind}" $'\n'
+ else
+ ble/string#count-char "${_ble_edit_str:_ble_edit_ind}" $'\n'
+ fi
+ ((count-=count<ret?count:ret))
+ if ((count==0)); then
+ local index; ble/keymap:vi/get-index-of-relative-line "$_ble_edit_ind" "$offset"
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ _ble_edit_ind=$index
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ if [[ $_ble_decode_keymap == vi_nmap && :$opts: == *:history:* ]]; then
+ if ble/widget/vi-command/.history-relative-line $((offset>=0?count:-count)) || ((nmove)); then
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ fi
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vi-command/forward-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/relative-line.impl "$ARG" "$FLAG" "$REG" history
+}
+function ble/widget/vi-command/backward-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/relative-line.impl $((-ARG)) "$FLAG" "$REG" history
+}
+function ble/widget/vi-command/graphical-relative-line.impl {
+ local offset=$1 flag=$2 reg=$3 opts=$4
+ local index move
+ if ble/edit/use-textmap; then
+ local x y ax ay
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ((ax=x,ay=y+offset,
+ ay<_ble_textmap_begy?(ay=_ble_textmap_begy):
+ (ay>_ble_textmap_endy?(ay=_ble_textmap_endy):0)))
+ ble/textmap#get-index-at "$ax" "$ay"
+ ble/textmap#getxy.cur --prefix=a "$index"
+ ((offset-=move=ay-y))
+ else
+ local ret ind=$_ble_edit_ind
+ ble-edit/content/find-logical-bol "$ind" 0; local bol1=$ret
+ ble-edit/content/find-logical-bol "$ind" "$offset"; local bol2=$ret
+ ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret
+ ((index=bol2+ind-bol1,index>eol2&&(index=eol2)))
+ if ((index>ind)); then
+ ble/string#count-char "${_ble_edit_str:ind:index-ind}" $'\n'
+ ((offset+=move=-ret))
+ elif ((index<ind)); then
+ ble/string#count-char "${_ble_edit_str:index:ind-index}" $'\n'
+ ((offset+=move=ret))
+ fi
+ fi
+ if ((offset==0)); then
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg"
+ return "$?"
+ fi
+ if [[ ! $flag && $_ble_decode_keymap == vi_nmap && :$opts: == *:history:* ]]; then
+ if ble/widget/vi-command/.history-relative-line "$offset"; then
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ fi
+ ((move)) && ble/widget/vi-command/exclusive-goto.impl "$index"
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vi-command/graphical-forward-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/graphical-relative-line.impl "$ARG" "$FLAG" "$REG"
+}
+function ble/widget/vi-command/graphical-backward-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/graphical-relative-line.impl $((-ARG)) "$FLAG" "$REG"
+}
+function ble/widget/vi-command/relative-first-non-space.impl {
+ local arg=$1 flag=$2 reg=$3 opts=$4
+ local ret ind=$_ble_edit_ind
+ ble-edit/content/find-logical-bol "$ind" "$arg"; local bolx=$ret
+ ble-edit/content/find-non-space "$bolx"; local nolx=$ret
+ ((_ble_keymap_vi_single_command==2&&_ble_keymap_vi_single_command--))
+ if [[ $flag ]]; then
+ if [[ :$opts: == *:charwise:* ]]; then
+ ble-edit/content/nonbol-eolp "$nolx" && ((nolx--))
+ ble/widget/vi-command/exclusive-goto.impl "$nolx" "$flag" "$reg" nobell
+ elif [[ :$opts: == *:multiline:* ]]; then
+ ble/widget/vi-command/linewise-goto.impl "$nolx" "$flag" "$reg" require_multiline:bolx="$bolx":nolx="$nolx"
+ else
+ ble/widget/vi-command/linewise-goto.impl "$nolx" "$flag" "$reg" bolx="$bolx":nolx="$nolx"
+ fi
+ return "$?"
+ fi
+ local count=$((arg<0?-arg:arg)) nmove=0
+ if ((count)); then
+ local beg end; ((nolx<ind?(beg=nolx,end=ind):(beg=ind,end=nolx)))
+ ble/string#count-char "${_ble_edit_str:beg:end-beg}" $'\n'; nmove=$ret
+ ((count-=nmove))
+ fi
+ if ((count==0)); then
+ ble/keymap:vi/needs-eol-fix "$nolx" && ((nolx--))
+ _ble_edit_ind=$nolx
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ if [[ $_ble_decode_keymap == vi_nmap && :$opts: == *:history:* ]] && ble/widget/vi-command/.history-relative-line $((arg>=0?count:-count)); then
+ ble/widget/vi-command/first-non-space
+ elif ((nmove)); then
+ ble/keymap:vi/needs-eol-fix "$nolx" && ((nolx--))
+ _ble_edit_ind=$nolx
+ ble/keymap:vi/adjust-command-mode
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi-command/first-non-space {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/relative-first-non-space.impl 0 "$FLAG" "$REG" charwise:history
+}
+function ble/widget/vi-command/forward-first-non-space {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/relative-first-non-space.impl "$ARG" "$FLAG" "$REG" multiline:history
+}
+function ble/widget/vi-command/backward-first-non-space {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/relative-first-non-space.impl $((-ARG)) "$FLAG" "$REG" multiline:history
+}
+function ble/widget/vi-command/first-non-space-forward {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/relative-first-non-space.impl $((ARG-1)) "$FLAG" "$REG" history
+}
+function ble/widget/vi-command/forward-eol {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ if ((ARG>1)) && [[ ${_ble_edit_str:_ble_edit_ind} != *$'\n'* ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local ret index
+ ble-edit/content/find-logical-eol "$_ble_edit_ind" $((ARG-1)); index=$ret
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+ [[ $_ble_decode_keymap == vi_[xs]map ]] &&
+ ble/keymap:vi/xmap/add-eol-extension # 末尾拡張
+}
+function ble/widget/vi-command/beginning-of-graphical-line {
+ if ble/edit/use-textmap; then
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local x y index
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at 0 "$y"
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+ else
+ ble/widget/vi-command/beginning-of-line
+ fi
+}
+function ble/widget/vi-command/graphical-first-non-space {
+ if ble/edit/use-textmap; then
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local x y index ret
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at 0 "$y"
+ ble-edit/content/find-non-space "$index"
+ ble/keymap:vi/needs-eol-fix "$ret" && ((ret--))
+ ble/widget/vi-command/exclusive-goto.impl "$ret" "$FLAG" "$REG" nobell
+ else
+ ble/widget/vi-command/first-non-space
+ fi
+}
+function ble/widget/vi-command/graphical-forward-eol {
+ if ble/edit/use-textmap; then
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local x y index
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at $((_ble_textmap_cols-1)) $((y+ARG-1))
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+ else
+ ble/widget/vi-command/forward-eol
+ fi
+}
+function ble/widget/vi-command/middle-of-graphical-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local index
+ if ble/edit/use-textmap; then
+ local x y
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at $((_ble_textmap_cols/2)) "$y"
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ else
+ local ret
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-logical-eol; local eol=$ret
+ ((index=(bol+${COLUMNS:-eol})/2,
+ index>eol&&(index=eol),
+ bol<eol&&index==eol&&(index--)))
+ fi
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+}
+function ble/widget/vi-command/last-non-space {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ ble-edit/content/find-logical-eol "$_ble_edit_ind" $((ARG-1)); local index=$ret
+ if ((ARG>1)) && [[ ${_ble_edit_str:_ble_edit_ind:index-_ble_edit_ind} != *$'\n'* ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local rex=$'([^ \t\n]?[ \t]+|[^ \t\n])$'
+ [[ ${_ble_edit_str::index} =~ $rex ]] && ((index-=${#BASH_REMATCH}))
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+}
+_ble_keymap_vi_previous_scroll=
+function ble/widget/vi_nmap/scroll.impl {
+ local opts=$1
+ local height=${_ble_canvas_panel_height[_ble_textarea_panel]}
+ local ARG FLAG REG; ble/keymap:vi/get-arg "$_ble_keymap_vi_previous_scroll"
+ _ble_keymap_vi_previous_scroll=$ARG
+ [[ $ARG ]] || ((ARG=height/2))
+ [[ :$opts: == *:backward:* ]] && ((ARG=-ARG))
+ ble/widget/.update-textmap
+ if [[ :$opts: == *:cursor:* ]]; then
+ local x y index ret
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ble/textmap#get-index-at 0 $((y+ARG))
+ ble-edit/content/find-non-space "$index"
+ ble/keymap:vi/needs-eol-fix "$ret" && ((ret--))
+ _ble_edit_ind=$ret
+ ble/keymap:vi/adjust-command-mode
+ ((_ble_textmap_endy<height)) && return 0
+ local ax ay
+ ble/textmap#getxy.cur --prefix=a "$_ble_edit_ind"
+ local max_scroll=$((_ble_textmap_endy+1-height))
+ ((_ble_textarea_scroll_new+=ay-y))
+ if ((_ble_textarea_scroll_new<0)); then
+ _ble_textarea_scroll_new=0
+ elif ((_ble_textarea_scroll_new>max_scroll)); then
+ _ble_textarea_scroll_new=$max_scroll
+ fi
+ else
+ ((_ble_textmap_endy<height)) && return 0
+ local max_scroll=$((_ble_textmap_endy+1-height))
+ ((_ble_textarea_scroll_new+=ARG))
+ if ((_ble_textarea_scroll_new<0)); then
+ _ble_textarea_scroll_new=0
+ elif ((_ble_textarea_scroll_new>max_scroll)); then
+ _ble_textarea_scroll_new=$max_scroll
+ fi
+ local ay=$((_ble_textarea_scroll_new+_ble_textmap_begy))
+ local by=$((_ble_textarea_scroll_new+height-1))
+ ((_ble_textarea_scroll_new&&ay++))
+ ((_ble_textarea_scroll_new!=0&&ay<by&&ay++,
+ _ble_textarea_scroll_new!=max_scroll&&ay<by&&by--))
+ local x y
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ if ((y<ay?(y=ay,1):(y>by?(y=by,1):0))); then
+ local index
+ ble/textmap#get-index-at "$x" "$y"
+ _ble_edit_ind=$index
+ fi
+ ble/keymap:vi/adjust-command-mode
+ fi
+}
+function ble/widget/vi_nmap/forward-line-scroll {
+ ble/widget/vi_nmap/scroll.impl forward:cursor
+}
+function ble/widget/vi_nmap/backward-line-scroll {
+ ble/widget/vi_nmap/scroll.impl backward:cursor
+}
+function ble/widget/vi_nmap/forward-scroll {
+ ble/widget/vi_nmap/scroll.impl forward
+}
+function ble/widget/vi_nmap/backward-scroll {
+ ble/widget/vi_nmap/scroll.impl backward
+}
+function ble/widget/vi_nmap/pagedown {
+ local height=${_ble_canvas_panel_height[_ble_textarea_panel]}
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/.update-textmap
+ local x y
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ if ((y==_ble_textmap_endy)); then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local vheight=$((height-_ble_textmap_begy-1))
+ local ybase=$((_ble_textarea_scroll_new+height-1))
+ local y1=$((ybase+(ARG-1)*(vheight-2)))
+ local index ret
+ ble/textmap#get-index-at 0 "$y1"
+ ble-edit/content/bolp "$index" &&
+ ble-edit/content/find-non-space "$index"; index=$ret
+ _ble_edit_ind=$index
+ local max_scroll=$((_ble_textmap_endy+1-height))
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ local scroll=$((y<=_ble_textmap_begy+1?0:(y-_ble_textmap_begy-1)))
+ ((scroll>max_scroll&&(scroll=max_scroll)))
+ _ble_textarea_scroll_new=$scroll
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/vi_nmap/pageup {
+ local height=${_ble_canvas_panel_height[_ble_textarea_panel]}
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/.update-textmap
+ if ((!_ble_textarea_scroll_new)); then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local vheight=$((height-_ble_textmap_begy-1))
+ local ybase=$((_ble_textarea_scroll_new+_ble_textmap_begy+1))
+ local y1=$((ybase-(ARG-1)*(vheight-2)))
+ ((y1<_ble_textmap_begy&&(y1=_ble_textmap_begy)))
+ local index ret
+ ble/textmap#get-index-at 0 "$y1"
+ ble-edit/content/bolp "$index" &&
+ ble-edit/content/find-non-space "$index"; index=$ret
+ _ble_edit_ind=$index
+ local x y
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ local scroll=$((y-height+2))
+ ((scroll<0&&(scroll=0)))
+ _ble_textarea_scroll_new=$scroll
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/vi_nmap/scroll-to-center.impl {
+ local opts=$1
+ ble/widget/.update-textmap
+ local height=${_ble_canvas_panel_height[_ble_textarea_panel]}
+ local ARG FLAG REG; ble/keymap:vi/get-arg ''
+ if [[ ! $ARG && :$opts: == *:pagedown:* ]]; then
+ local y1=$((_ble_textarea_scroll_new+height))
+ local index
+ ble/textmap#get-index-at 0 "$y1"
+ ((_ble_edit_ind=index))
+ fi
+ local ret
+ ble-edit/content/find-logical-bol "$_ble_edit_ind"; local bol1=$ret
+ if [[ $ARG || :$opts: == *:nol:* ]]; then
+ if [[ $ARG ]]; then
+ ble-edit/content/find-logical-bol 0 $((ARG-1)); local bol2=$ret
+ else
+ local bol2=$bol1
+ fi
+ if [[ :$opts: == *:nol:* ]]; then
+ ble-edit/content/find-non-space "$bol2"
+ _ble_edit_ind=$ret
+ elif ((bol1!=bol2)); then
+ local b1x b1y p1x p1y dx dy
+ ble/textmap#getxy.cur --prefix=b1 "$bol1"
+ ble/textmap#getxy.cur --prefix=p1 "$_ble_edit_ind"
+ ((dx=p1x,dy=p1y-b1y))
+ local b2x b2y p2x p2y index
+ ble/textmap#getxy.cur --prefix=b2 "$bol2"
+ ((p2x=b2x,p2y=b2y+dy))
+ ble/textmap#get-index-at "$p2x" "$p2y"
+ if ble-edit/content/find-logical-bol "$index"; ((ret==bol2)); then
+ _ble_edit_ind=$index
+ else
+ ble-edit/content/find-logical-eol "$bol2"
+ _ble_edit_ind=$ret
+ fi
+ fi
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ fi
+ if ((_ble_textmap_endy+1>height)); then
+ local max_scroll=$((_ble_textmap_endy+1-height))
+ local b1x b1y
+ ble/textmap#getxy.cur --prefix=b1 "$bol1"
+ local scroll=
+ if [[ :$opts: == *:top:* ]]; then
+ ((scroll=b1y-(_ble_textmap_begy+2)))
+ elif [[ :$opts: == *:bottom:* ]]; then
+ ((scroll=b1y-(height-2)))
+ else
+ local vheight=$((height-_ble_textmap_begy-1))
+ ((scroll=b1y-(_ble_textmap_begy+1+vheight/2)))
+ fi
+ if ((scroll<0)); then
+ scroll=0
+ elif ((scroll>max_scroll)); then
+ scroll=$max_scroll
+ fi
+ _ble_textarea_scroll_new=$scroll
+ fi
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/vi_nmap/scroll-to-center-and-redraw {
+ ble/widget/vi_nmap/scroll-to-center.impl
+ ble/widget/redraw-line
+}
+function ble/widget/vi_nmap/scroll-to-top-and-redraw {
+ ble/widget/vi_nmap/scroll-to-center.impl top
+ ble/widget/redraw-line
+}
+function ble/widget/vi_nmap/scroll-to-bottom-and-redraw {
+ ble/widget/vi_nmap/scroll-to-center.impl bottom
+ ble/widget/redraw-line
+}
+function ble/widget/vi_nmap/scroll-to-center-non-space-and-redraw {
+ ble/widget/vi_nmap/scroll-to-center.impl nol
+ ble/widget/redraw-line
+}
+function ble/widget/vi_nmap/scroll-to-top-non-space-and-redraw {
+ ble/widget/vi_nmap/scroll-to-center.impl top:nol
+ ble/widget/redraw-line
+}
+function ble/widget/vi_nmap/scroll-to-bottom-non-space-and-redraw {
+ ble/widget/vi_nmap/scroll-to-center.impl bottom:nol
+ ble/widget/redraw-line
+}
+function ble/widget/vi_nmap/scroll-or-pagedown-and-redraw {
+ ble/widget/vi_nmap/scroll-to-center.impl top:nol:pagedown
+ ble/widget/redraw-line
+}
+function ble/widget/vi_nmap/paste.impl/block {
+ local arg=${1:-1} type=$2
+ local graphical=
+ if [[ $type ]]; then
+ [[ $type == graphical ]] && graphical=1
+ else
+ ble/edit/use-textmap && graphical=1
+ fi
+ local ret cols=$_ble_textmap_cols
+ local -a afill; ble/string#split-words afill "${_ble_edit_kill_type:2}"
+ local atext; ble/string#split-lines atext "$_ble_edit_kill_ring"
+ local ntext=${#atext[@]}
+ if [[ $graphical ]]; then
+ ble-edit/content/find-logical-bol; local bol=$ret
+ local bx by x y c
+ ble/textmap#getxy.cur --prefix=b "$bol"
+ ble/textmap#getxy.cur "$_ble_edit_ind"
+ ((y-=by,c=y*cols+x))
+ else
+ ble-edit/content/find-logical-bol; local bol=$ret
+ local c=$((_ble_edit_ind-bol))
+ fi
+ local -a ins_beg=() ins_end=() ins_text=()
+ local i is_newline=
+ for ((i=0;i<ntext;i++)); do
+ if ((i>0)); then
+ ble-edit/content/find-logical-bol "$bol" 1
+ if ((bol==ret)); then
+ is_newline=1
+ else
+ bol=$ret
+ [[ $graphical ]] && ble/textmap#getxy.cur --prefix=b "$bol"
+ fi
+ fi
+ local text=${atext[i]}
+ local fill=$((afill[i]))
+ if ((arg>1)); then
+ ret=
+ ((fill)) && ble/string#repeat ' ' "$fill"
+ ble/string#repeat "$text$ret" "$arg"
+ text=${ret::${#ret}-fill}
+ fi
+ local index iend=
+ if [[ $is_newline ]]; then
+ index=${#_ble_edit_str}
+ ble/string#repeat ' ' "$c"
+ text=$'\n'$ret$text
+ elif [[ $graphical ]]; then
+ ble-edit/content/find-logical-eol "$bol"; local eol=$ret
+ ble/textmap#get-index-at "$x" $((by+y)); ((index>eol&&(index=eol)))
+ local ax ay ac; ble/textmap#getxy.out --prefix=a "$index"
+ ((ay-=by,ac=ay*cols+ax))
+ if ((ac<c)); then
+ ble/string#repeat ' ' $((c-ac))
+ text=$ret$text
+ if ((index<eol)) && [[ ${_ble_edit_str:index:1} == $'\t' ]]; then
+ local rx ry rc; ble/textmap#getxy.out --prefix=r $((index+1))
+ ((rc=(ry-by)*cols+rx))
+ ble/string#repeat ' ' $((rc-c))
+ text=$text$ret
+ iend=$((index+1))
+ fi
+ fi
+ if ((index<eol&&fill)); then
+ ble/string#repeat ' ' "$fill"
+ text=$text$ret
+ fi
+ else
+ ble-edit/content/find-logical-eol "$bol"; local eol=$ret
+ local index=$((bol+c))
+ if ((index<eol)); then
+ if ((fill)); then
+ ble/string#repeat ' ' "$fill"
+ text=$text$ret
+ fi
+ elif ((index>eol)); then
+ ble/string#repeat ' ' $((index-eol))
+ text=$ret$text
+ index=$eol
+ fi
+ fi
+ ble/array#push ins_beg "$index"
+ ble/array#push ins_end "${iend:-$index}"
+ ble/array#push ins_text "$text"
+ done
+ ble/keymap:vi/mark/start-edit-area
+ local i=${#ins_beg[@]}
+ while ((i--)); do
+ local ibeg=${ins_beg[i]} iend=${ins_end[i]} text=${ins_text[i]}
+ ble/widget/.replace-range "$ibeg" "$iend" "$text"
+ done
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/repeat/record
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/vi_nmap/paste.impl {
+ local arg=$1 reg=$2 is_after=$3
+ if [[ $reg ]]; then
+ local _ble_edit_kill_ring _ble_edit_kill_type
+ ble/keymap:vi/register#load "$reg"
+ fi
+ [[ $_ble_edit_kill_ring ]] || return 0
+ local ret
+ if [[ $_ble_edit_kill_type == L ]]; then
+ ble/string#repeat "$_ble_edit_kill_ring" "$arg"
+ local content=$ret
+ local index dbeg dend
+ if ((is_after)); then
+ ble-edit/content/find-logical-eol; index=$ret
+ if ((index==${#_ble_edit_str})); then
+ content=$'\n'${content%$'\n'}
+ ((dbeg=index+1,dend=index+${#content}))
+ else
+ ((index++,dbeg=index,dend=index+${#content}-1))
+ fi
+ else
+ ble-edit/content/find-logical-bol
+ ((index=ret,dbeg=index,dend=index+${#content}-1))
+ fi
+ ble/widget/.replace-range "$index" "$index" "$content"
+ _ble_edit_ind=$dbeg
+ ble/keymap:vi/mark/set-previous-edit-area "$dbeg" "$dend"
+ ble/keymap:vi/repeat/record
+ ble/widget/vi-command/first-non-space
+ elif [[ $_ble_edit_kill_type == B:* ]]; then
+ if ((is_after)) && ! ble-edit/content/eolp; then
+ ((_ble_edit_ind++))
+ fi
+ ble/widget/vi_nmap/paste.impl/block "$arg"
+ else
+ if ((is_after)) && ! ble-edit/content/eolp; then
+ ((_ble_edit_ind++))
+ fi
+ ble/string#repeat "$_ble_edit_kill_ring" "$arg"
+ local beg=$_ble_edit_ind
+ ble/widget/.insert-string "$ret"
+ local end=$_ble_edit_ind
+ ble/keymap:vi/mark/set-previous-edit-area "$beg" "$end"
+ ble/keymap:vi/repeat/record
+ [[ $_ble_keymap_vi_single_command ]] || ((_ble_edit_ind--))
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ ble/keymap:vi/adjust-command-mode
+ fi
+ return 0
+}
+function ble/widget/vi_nmap/paste-after {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi_nmap/paste.impl "$ARG" "$REG" 1
+}
+function ble/widget/vi_nmap/paste-before {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi_nmap/paste.impl "$ARG" "$REG" 0
+}
+function ble/widget/vi_nmap/kill-forward-char {
+ _ble_keymap_vi_opfunc=d
+ ble/widget/vi-command/forward-char
+}
+function ble/widget/vi_nmap/kill-forward-char-and-insert {
+ _ble_keymap_vi_opfunc=c
+ ble/widget/vi-command/forward-char
+}
+function ble/widget/vi_nmap/kill-backward-char {
+ _ble_keymap_vi_opfunc=d
+ ble/widget/vi-command/backward-char
+}
+function ble/widget/vi_nmap/kill-forward-line {
+ _ble_keymap_vi_opfunc=d
+ ble/widget/vi-command/forward-eol
+}
+function ble/widget/vi_nmap/kill-forward-line-and-insert {
+ _ble_keymap_vi_opfunc=c
+ ble/widget/vi-command/forward-eol
+}
+function ble/widget/vi-command/forward-word.impl {
+ local arg=$1 flag=$2 reg=$3 rex_word=$4
+ local ifs=$_ble_term_IFS
+ if [[ $flag == c && ${_ble_edit_str:_ble_edit_ind:1} != [$ifs] ]]; then
+ ble/widget/vi-command/forward-word-end.impl "$arg" "$flag" "$reg" "$rex_word" allow_here
+ return "$?"
+ fi
+ local b=$'[ \t]' n=$'\n'
+ local rex="^((($rex_word)$n?|$b+$n?|$n)($b+$n)*$b*){0,$arg}" # 単語先頭または空行に止まる
+ [[ ${_ble_edit_str:_ble_edit_ind} =~ $rex ]]
+ local index=$((_ble_edit_ind+${#BASH_REMATCH}))
+ if [[ $flag ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ if local rex="$n$b*\$"; [[ $rematch1 =~ $rex ]]; then
+ local suffix_len=${#BASH_REMATCH}
+ ((suffix_len<${#rematch1})) &&
+ ((index-=suffix_len))
+ fi
+ fi
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg"
+}
+function ble/widget/vi-command/forward-word-end.impl {
+ local arg=$1 flag=$2 reg=$3 rex_word=$4 opts=$5
+ local IFS=$_ble_term_IFS
+ local rex="^([$IFS]*($rex_word)?){0,$arg}" # 単語末端に止まる。空行には止まらない
+ local offset=1; [[ :$opts: == *:allow_here:* ]] && offset=0
+ [[ ${_ble_edit_str:_ble_edit_ind+offset} =~ $rex ]]
+ local index=$((_ble_edit_ind+offset+${#BASH_REMATCH}-1))
+ ((index<_ble_edit_ind&&(index=_ble_edit_ind)))
+ [[ ! $flag && $BASH_REMATCH && ${_ble_edit_str:index:1} == [$IFS] ]] && ble/widget/.bell
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$flag" "$reg"
+}
+function ble/widget/vi-command/backward-word.impl {
+ local arg=$1 flag=$2 reg=$3 rex_word=$4
+ local b=$'[ \t]' n=$'\n'
+ local rex="((($rex_word)$n?|$b+$n?|$n)($b+$n)*$b*){0,$arg}\$" # 単語先頭または空行に止まる
+ [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]]
+ local index=$((_ble_edit_ind-${#BASH_REMATCH}))
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg"
+}
+function ble/widget/vi-command/backward-word-end.impl {
+ local arg=$1 flag=$2 reg=$3 rex_word=$4
+ local i=$'[ \t\n]' b=$'[ \t]' n=$'\n' w="($rex_word)"
+ local rex1="(^|$w$n?|$n)($b+$n)*$b*"
+ local rex="($rex1)($rex1){$((arg-1))}($rex_word|$i)\$" # 単語末端または空行に止まる
+ [[ ${_ble_edit_str::_ble_edit_ind+1} =~ $rex ]]
+ local index=$((_ble_edit_ind+1-${#BASH_REMATCH}))
+ local rematch3=${BASH_REMATCH[3]} # 最初の ($rex_word)
+ [[ $rematch3 ]] && ((index+=${#rematch3}-1))
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$flag" "$reg"
+}
+function ble/widget/vi-command/forward-vword {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/forward-word.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD"
+}
+function ble/widget/vi-command/forward-vword-end {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/forward-word-end.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD"
+}
+function ble/widget/vi-command/backward-vword {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/backward-word.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD"
+}
+function ble/widget/vi-command/backward-vword-end {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/backward-word-end.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD"
+}
+function ble/widget/vi-command/forward-uword {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/forward-word.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+'
+}
+function ble/widget/vi-command/forward-uword-end {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/forward-word-end.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+'
+}
+function ble/widget/vi-command/backward-uword {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/backward-word.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+'
+}
+function ble/widget/vi-command/backward-uword-end {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/backward-word-end.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+'
+}
+function ble/widget/vi-command/nth-column {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret index
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-logical-eol; local eol=$ret
+ if ble/edit/use-textmap; then
+ local bx by; ble/textmap#getxy.cur --prefix=b "$bol" # Note: 先頭行はプロンプトにより bx!=0
+ local ex ey; ble/textmap#getxy.cur --prefix=e "$eol"
+ local dstx=$((bx+ARG-1)) dsty=$by cols=${COLUMNS:-80}
+ ((dsty+=dstx/cols,dstx%=cols))
+ ((dsty>ey&&(dsty=ey,dstx=ex)))
+ ble/textmap#get-index-at "$dstx" "$dsty" # local variable "index" is set here
+ [[ $_ble_decode_keymap != vi_[xs]map ]] &&
+ ble-edit/content/nonbol-eolp "$index" && ((index--))
+ else
+ [[ $_ble_decode_keymap != vi_[xs]map ]] &&
+ ble-edit/content/nonbol-eolp "$eol" && ((eol--))
+ ((index=bol+ARG-1,index>eol&&(index=eol)))
+ fi
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+}
+function ble/widget/vi-command/nth-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
+ ble/widget/vi-command/linewise-goto.impl 0:$((ARG-1)) "$FLAG" "$REG"
+}
+function ble/widget/vi-command/nth-last-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
+ ble/widget/vi-command/linewise-goto.impl ${#_ble_edit_str}:$((-(ARG-1))) "$FLAG" "$REG"
+}
+function ble/widget/vi-command/history-beginning {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 0
+ if [[ $FLAG ]]; then
+ if ((ARG)); then
+ _ble_keymap_vi_oparg=$ARG
+ else
+ _ble_keymap_vi_oparg=
+ fi
+ _ble_keymap_vi_opfunc=$FLAG
+ _ble_keymap_vi_reg=$REG
+ ble/widget/vi-command/nth-line
+ return "$?"
+ fi
+ if ((ARG)); then
+ ble-edit/history/goto $((ARG-1))
+ else
+ ble/widget/history-beginning
+ fi
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-command/history-end {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 0
+ if [[ $FLAG ]]; then
+ _ble_keymap_vi_opfunc=$FLAG
+ _ble_keymap_vi_reg=$REG
+ if ((ARG)); then
+ _ble_keymap_vi_oparg=$ARG
+ ble/widget/vi-command/nth-line
+ else
+ _ble_keymap_vi_oparg=
+ ble/widget/vi-command/nth-last-line
+ fi
+ return "$?"
+ fi
+ if ((ARG)); then
+ ble-edit/history/goto $((ARG-1))
+ else
+ ble/widget/history-end
+ fi
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-command/last-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 0
+ [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
+ if ((ARG)); then
+ ble/widget/vi-command/linewise-goto.impl 0:$((ARG-1)) "$FLAG" "$REG"
+ else
+ ble/widget/vi-command/linewise-goto.impl ${#_ble_edit_str}:0 "$FLAG" "$REG"
+ fi
+}
+function ble/widget/vi-command/first-nol {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi-command/linewise-goto.impl 0:$((ARG-1)) "$FLAG" "$REG"
+}
+function ble/widget/vi-command/last-eol {
+ local ARG FLAG REG; ble/keymap:vi/get-arg ''
+ local ret index
+ if [[ $ARG ]]; then
+ ble-edit/content/find-logical-eol 0 $((ARG-1)); index=$ret
+ else
+ ble-edit/content/find-logical-eol ${#_ble_edit_str}; index=$ret
+ fi
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+}
+function ble/widget/vi_nmap/replace-char.impl {
+ local key=$1 overwrite_mode=${2:-R}
+ _ble_edit_overwrite_mode=
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ if ((key==(_ble_decode_Ctrl|91))); then # C-[
+ ble/keymap:vi/adjust-command-mode
+ return 27
+ elif ! ble/keymap:vi/k2c "$key"; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local pos=$_ble_edit_ind
+ ble/keymap:vi/mark/start-edit-area
+ {
+ local -a KEYS; KEYS=("$ret")
+ local _ble_edit_arg=$ARG
+ local _ble_edit_overwrite_mode=$overwrite_mode
+ local ble_widget_self_insert_opts=nolineext
+ ble/widget/self-insert
+ ble/util/unlocal KEYS
+ }
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/repeat/record
+ ((pos<_ble_edit_ind&&_ble_edit_ind--))
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi_nmap/replace-char.hook {
+ ble/widget/vi_nmap/replace-char.impl "$1" R
+}
+function ble/widget/vi_nmap/replace-char {
+ _ble_edit_overwrite_mode=R
+ ble/keymap:vi/async-read-char ble/widget/vi_nmap/replace-char.hook
+}
+function ble/widget/vi_nmap/virtual-replace-char.hook {
+ ble/widget/vi_nmap/replace-char.impl "$1" 1
+}
+function ble/widget/vi_nmap/virtual-replace-char {
+ _ble_edit_overwrite_mode=1
+ ble/keymap:vi/async-read-char ble/widget/vi_nmap/virtual-replace-char.hook
+}
+function ble/widget/vi_nmap/connect-line-with-space {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ ble-edit/content/find-logical-eol; local eol1=$ret
+ ble-edit/content/find-logical-eol "$_ble_edit_ind" $((ARG<=1?1:ARG-1)); local eol2=$ret
+ ble-edit/content/find-logical-bol "$eol2"; local bol2=$ret
+ if ((eol1<eol2)); then
+ local text=${_ble_edit_str:eol1:eol2-eol1}
+ text=${text//$'\n'/' '}
+ ble/widget/.replace-range "$eol1" "$eol2" "$text"
+ ble/keymap:vi/mark/set-previous-edit-area "$eol1" "$eol2"
+ ble/keymap:vi/repeat/record
+ _ble_edit_ind=$((bol2-1))
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi_nmap/connect-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ ble-edit/content/find-logical-eol; local eol1=$ret
+ ble-edit/content/find-logical-eol "$_ble_edit_ind" $((ARG<=1?1:ARG-1)); local eol2=$ret
+ ble-edit/content/find-logical-bol "$eol2"; local bol2=$ret
+ if ((eol1<eol2)); then
+ local text=${_ble_edit_str:eol1:bol2-eol1}
+ text=${text//$'\n'}
+ ble/widget/.replace-range "$eol1" "$bol2" "$text"
+ local delta=$((${#text}-(bol2-eol1)))
+ ble/keymap:vi/mark/set-previous-edit-area "$eol1" $((eol2+delta))
+ ble/keymap:vi/repeat/record
+ _ble_edit_ind=$((bol2+delta))
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi_nmap/insert-mode-at-forward-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-logical-eol; local eol=$ret
+ ble-edit/content/find-non-space "$bol"; local indent=${_ble_edit_str:bol:ret-bol}
+ _ble_edit_ind=$eol
+ ble/widget/.insert-string $'\n'"$indent"
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_nmap/insert-mode-at-backward-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-non-space "$bol"; local indent=${_ble_edit_str:bol:ret-bol}
+ _ble_edit_ind=$bol
+ ble/widget/.insert-string "$indent"$'\n'
+ _ble_edit_ind=$((bol+${#indent}))
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+_ble_keymap_vi_char_search=
+function ble/widget/vi-command/search-char.impl/core {
+ local opts=$1 key=$2
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret c
+ [[ $opts != *p* ]]; local isprev=$?
+ [[ $opts != *r* ]]; local isrepeat=$?
+ if ((isrepeat)); then
+ c=$key
+ elif ((key==(_ble_decode_Ctrl|91))); then # C-[ -> cancel
+ return 27
+ else
+ ble/keymap:vi/k2c "$key" || return 1
+ ble/util/c2s "$ret"; local c=$ret
+ fi
+ [[ $c ]] || return 1
+ ((isrepeat)) || _ble_keymap_vi_char_search=$c$opts
+ local index
+ if [[ $opts == *b* ]]; then
+ ble-edit/content/find-logical-bol; local bol=$ret
+ local base=$_ble_edit_ind
+ ((isrepeat&&isprev&&base--,base>bol)) || return 1
+ local line=${_ble_edit_str:bol:base-bol}
+ ble/string#last-index-of "$line" "$c" "$ARG"
+ ((ret>=0)) || return 1
+ ((index=bol+ret,isprev&&index++))
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+ return "$?"
+ else
+ ble-edit/content/find-logical-eol; local eol=$ret
+ local base=$((_ble_edit_ind+1))
+ ((isrepeat&&isprev&&base++,base<eol)) || return 1
+ local line=${_ble_edit_str:base:eol-base}
+ ble/string#index-of "$line" "$c" "$ARG"
+ ((ret>=0)) || return 1
+ ((index=base+ret,isprev&&index--))
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+ return "$?"
+ fi
+}
+function ble/widget/vi-command/search-char.impl {
+ if ble/widget/vi-command/search-char.impl/core "$1" "$2"; then
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi-command/search-forward-char {
+ ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl f
+}
+function ble/widget/vi-command/search-forward-char-prev {
+ ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl fp
+}
+function ble/widget/vi-command/search-backward-char {
+ ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl b
+}
+function ble/widget/vi-command/search-backward-char-prev {
+ ble/keymap:vi/async-read-char ble/widget/vi-command/search-char.impl bp
+}
+function ble/widget/vi-command/search-char-repeat {
+ [[ $_ble_keymap_vi_char_search ]] || ble/widget/.bell
+ local c=${_ble_keymap_vi_char_search::1} opts=${_ble_keymap_vi_char_search:1}
+ ble/widget/vi-command/search-char.impl "r$opts" "$c"
+}
+function ble/widget/vi-command/search-char-reverse-repeat {
+ [[ $_ble_keymap_vi_char_search ]] || ble/widget/.bell
+ local c=${_ble_keymap_vi_char_search::1} opts=${_ble_keymap_vi_char_search:1}
+ if [[ $opts == *b* ]]; then
+ opts=f${opts//b}
+ else
+ opts=b${opts//f}
+ fi
+ ble/widget/vi-command/search-char.impl "r$opts" "$c"
+}
+function ble/widget/vi-command/search-matchpair/.search-forward {
+ ble/string#index-of-chars "$_ble_edit_str" "$ch1$ch2" $((index+1))
+}
+function ble/widget/vi-command/search-matchpair/.search-backward {
+ ble/string#last-index-of-chars "$_ble_edit_str" "$ch1$ch2" "$index"
+}
+function ble/widget/vi-command/search-matchpair-or {
+ local ARG FLAG REG; ble/keymap:vi/get-arg -1
+ if ((ARG>=0)); then
+ _ble_keymap_vi_oparg=$ARG
+ _ble_keymap_vi_opfunc=$FLAG
+ _ble_keymap_vi_reg=$REG
+ ble/widget/"$@"
+ return "$?"
+ fi
+ local open='({[' close=')}]'
+ local ret
+ ble-edit/content/find-logical-eol; local eol=$ret
+ if ! ble/string#index-of-chars "${_ble_edit_str::eol}" '(){}[]' "$_ble_edit_ind"; then
+ ble/keymap:vi/adjust-command-mode
+ return 1
+ fi
+ local index1=$ret ch1=${_ble_edit_str:ret:1}
+ if [[ $ch1 == ["$open"] ]]; then
+ local i=${open%%"$ch"*}; i=${#i}
+ local ch2=${close:i:1}
+ local searcher=ble/widget/vi-command/search-matchpair/.search-forward
+ else
+ local i=${close%%"$ch"*}; i=${#i}
+ local ch2=${open:i:1}
+ local searcher=ble/widget/vi-command/search-matchpair/.search-backward
+ fi
+ local index=$index1 count=1
+ while "$searcher"; do
+ index=$ret
+ if [[ ${_ble_edit_str:ret:1} == "$ch1" ]]; then
+ ((++count))
+ else
+ ((--count==0)) && break
+ fi
+ done
+ if ((count)); then
+ ble/keymap:vi/adjust-command-mode
+ return 1
+ fi
+ [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
+ ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+}
+function ble/widget/vi-command/percentage-line {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 0
+ local ret; ble/string#count-char "$_ble_edit_str" $'\n'; local nline=$((ret+1))
+ local iline=$(((ARG*nline+99)/100))
+ ble/widget/vi-command/linewise-goto.impl 0:$((iline-1)) "$FLAG" "$REG"
+}
+function ble/widget/vi-command/nth-byte {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ((ARG--))
+ local offset=0 text=$_ble_edit_str len=${#_ble_edit_str}
+ local left nleft ret
+ while ((ARG>0&&len>1)); do
+ left=${text::len/2}
+ ble/util/strlen "$left"; nleft=$ret
+ if ((ARG<nleft)); then
+ text=$left
+ ((len/=2))
+ else
+ text=${text:len/2}
+ ((offset+=len/2,
+ ARG-=nleft,
+ len-=len/2))
+ fi
+ done
+ ble/keymap:vi/needs-eol-fix "$offset" && ((offset--))
+ ble/widget/vi-command/exclusive-goto.impl "$offset" "$FLAG" "$REG" nobell
+}
+_ble_keymap_vi_text_object=
+function ble/keymap:vi/text-object/word.extend-forward {
+ local rex
+ flags=
+ [[ ${_ble_edit_str:beg:1} == ["$ifs"] ]] && flags=${flags}A
+ if [[ $_ble_decode_keymap != vi_[xs]map ]]; then
+ flags=${flags}I
+ elif ((_ble_edit_mark==_ble_edit_ind)); then
+ flags=${flags}I
+ fi
+ local rex_unit
+ local W='('$rex_word')' b='['$space']' n=$nl
+ if [[ $type == i* ]]; then
+ rex_unit='^'$W'|^'$b'+|^'$n
+ elif [[ $type == a* ]]; then
+ rex_unit='^'$W$b'*|^'$b'+'$W'|^'$b'*'$n'('$b'+'$n')*('$n'|'$b'*'$W')'
+ else
+ return 1
+ fi
+ local i rematch=
+ for ((i=0;i<arg;i++)); do
+ if ((i==0)) && [[ $flags == *I* ]]; then
+ rex='('$rex_word')$|['$space']*['$ifs']$'
+ [[ ${_ble_edit_str::beg+1} =~ $rex ]] &&
+ ((beg-=${#BASH_REMATCH}-1,end=beg))
+ else
+ [[ ${_ble_edit_str:end:1} == $'\n' ]] && ((end++))
+ fi
+ [[ ${_ble_edit_str:end} =~ $rex_unit ]] || return 1
+ rematch=$BASH_REMATCH
+ ((end+=${#rematch}))
+ [[ $type == a* && $rematch == *$'\n\n' ]] && ((end--))
+ if ((i==0)) && [[ $flags == *I* ]] || ((i==arg-1)); then
+ [[ $type == i* && $rematch == *"$nl" ]] && ((end--))
+ fi
+ done
+ [[ ${_ble_edit_str:end-1:1} == *["$ifs"] ]] && flags=${flags}Z
+ if [[ $type == a* && $flags != *[AZ]* ]]; then
+ if rex='['$space']+$'; [[ ${_ble_edit_str::beg} =~ $rex ]]; then
+ local p=$((beg-${#BASH_REMATCH}))
+ ble-edit/content/bolp "$p" || beg=$p
+ fi
+ fi
+ return 0
+}
+function ble/keymap:vi/text-object/word.extend-backward {
+ local rex_unit=
+ local W='('$rex_word')' b='['$space']' n=$nl
+ if [[ $type == i* ]]; then
+ rex_unit='('$W'|'$b'+)'$n'?$|'$n'$'
+ elif [[ $type == a* ]]; then
+ rex_unit=$b'*'$W$n'?$|'$W'?'$b'*('$n'('$b'+'$n')*'$b'*)?('$b$n'?|'$n')$'
+ else
+ return 1
+ fi
+ local count=$arg
+ while ((count--)); do
+ [[ ${_ble_edit_str::beg} =~ $rex_unit ]] || return 1
+ ((beg-=${#BASH_REMATCH}))
+ local match=${BASH_REMATCH%"$nl"}
+ if ((beg==0&&${#match}>=2)); then
+ if [[ $type == i* ]]; then
+ [[ $match == ["$space"]* ]] && beg=1
+ elif [[ $type == a* ]]; then
+ [[ $match == *[!"$ifs"] ]] && beg=1
+ fi
+ fi
+ done
+ return 0
+}
+function ble/keymap:vi/text-object/word.impl {
+ local arg=$1 flag=$2 reg=$3 type=$4
+ local space=$' \t' nl=$'\n' ifs=$_ble_term_IFS
+ ((arg==0)) && return 0
+ local rex_word
+ if [[ $type == ?W ]]; then
+ rex_word="[^$ifs]+"
+ else
+ rex_word=$_ble_keymap_vi_REX_WORD
+ fi
+ local index=$_ble_edit_ind
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ if ((index<_ble_edit_mark)); then
+ local beg=$index
+ if ble/keymap:vi/text-object/word.extend-backward; then
+ _ble_edit_ind=$beg
+ else
+ _ble_edit_ind=0
+ ble/widget/.bell
+ fi
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ fi
+ local beg=$index end=$index flags=
+ if ! ble/keymap:vi/text-object/word.extend-forward; then
+ index=${#_ble_edit_str}
+ ble-edit/content/nonbol-eolp "$index" && ((index--))
+ _ble_edit_ind=$index
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ ((end--))
+ ble-edit/content/nonbol-eolp "$end" && ((end--))
+ ((beg<_ble_edit_mark)) && _ble_edit_mark=$beg
+ [[ $_ble_edit_mark_active == vi_line ]] &&
+ _ble_edit_mark_active=vi_char
+ _ble_edit_ind=$end
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ else
+ ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg"
+ fi
+}
+function ble/keymap:vi/text-object:quote/.next {
+ local index=${1:-$((_ble_edit_ind+1))} nl=$'\n'
+ local rex="^[^$nl$quote]*$quote"
+ [[ ${_ble_edit_str:index} =~ $rex ]] || return 1
+ ((ret=index+${#BASH_REMATCH}-1))
+ return 0
+}
+function ble/keymap:vi/text-object:quote/.prev {
+ local index=${1:-_ble_edit_ind} nl=$'\n'
+ local rex="$quote[^$nl$quote]*\$"
+ [[ ${_ble_edit_str::index} =~ $rex ]] || return 1
+ ((ret=index-${#BASH_REMATCH}))
+ return 0
+}
+function ble/keymap:vi/text-object/quote.impl {
+ local arg=$1 flag=$2 reg=$3 type=$4
+ local ret quote=${type:1}
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ if ble/keymap:vi/text-object:quote/.xmap; then
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ fi
+ local beg= end=
+ if [[ ${_ble_edit_str:_ble_edit_ind:1} == "$quote" ]]; then
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble/string#count-char "${_ble_edit_str:bol:_ble_edit_ind-bol}" "$quote"
+ if ((ret%2==1)); then
+ ((end=_ble_edit_ind+1))
+ ble/keymap:vi/text-object:quote/.prev && beg=$ret
+ else
+ ((beg=_ble_edit_ind))
+ ble/keymap:vi/text-object:quote/.next && end=$((ret+1))
+ fi
+ elif ble/keymap:vi/text-object:quote/.prev && beg=$ret; then
+ ble/keymap:vi/text-object:quote/.next && end=$((ret+1))
+ elif ble/keymap:vi/text-object:quote/.next && beg=$ret; then
+ ble/keymap:vi/text-object:quote/.next $((beg+1)) && end=$((ret+1))
+ fi
+ if [[ $beg && $end ]]; then
+ [[ $type == i* || arg -gt 1 ]] && ((beg++,end--))
+ ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg"
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/keymap:vi/text-object:quote/.expand-xmap-range {
+ local inclusive=$1
+ ((end++))
+ if ((inclusive==2)); then
+ local rex
+ rex=$'^[ \t]+'; [[ ${_ble_edit_str:end} =~ $rex ]] && ((end+=${#BASH_REMATCH}))
+ elif ((inclusive==0&&end-beg>2)); then
+ ((beg++,end--))
+ fi
+}
+function ble/keymap:vi/text-object:quote/.xmap {
+ local min=$_ble_edit_ind max=$_ble_edit_mark
+ ((min>max)) && local min=$max max=$min
+ [[ ${_ble_edit_str:min:max+1-min} == *$'\n'* ]] && return 1
+ local inclusive=0
+ if [[ $type == a* ]]; then
+ inclusive=2
+ elif ((arg>1)); then
+ inclusive=1
+ fi
+ local ret
+ if ((_ble_edit_ind==_ble_edit_mark)); then
+ ble/keymap:vi/text-object:quote/.prev $((_ble_edit_ind+1)) ||
+ ble/keymap:vi/text-object:quote/.next $((_ble_edit_ind+1)) || return 1
+ local beg=$ret
+ ble/keymap:vi/text-object:quote/.next $((beg+1)) || return 1
+ local end=$ret
+ ble/keymap:vi/text-object:quote/.expand-xmap-range "$inclusive"
+ _ble_edit_mark=$beg
+ _ble_edit_ind=$((end-1))
+ return 0
+ elif ((_ble_edit_ind>_ble_edit_mark)); then
+ local updates_mark=
+ if [[ ${_ble_edit_str:_ble_edit_ind:1} == "$quote" ]]; then
+ ble/keymap:vi/text-object:quote/.next $((_ble_edit_ind+1)) || return 1; local beg=$ret
+ if ble/keymap:vi/text-object:quote/.next $((beg+1)); then
+ local end=$ret
+ else
+ local end=$beg beg=$_ble_edit_ind
+ fi
+ else
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble/string#count-char "${_ble_edit_str:bol:_ble_edit_ind-bol}" "$quote"
+ if ((ret%2==0)); then
+ ble/keymap:vi/text-object:quote/.next $((_ble_edit_ind+1)) || return 1; local beg=$ret
+ ble/keymap:vi/text-object:quote/.next $((beg+1)) || return 1; local end=$ret
+ else
+ ble/keymap:vi/text-object:quote/.prev "$_ble_edit_ind" || return 1; local beg=$ret
+ ble/keymap:vi/text-object:quote/.next $((_ble_edit_ind+1)) || return 1; local end=$ret
+ fi
+ local i1=$((_ble_edit_mark?_ble_edit_mark-1:0))
+ [[ ${_ble_edit_str:i1:_ble_edit_ind-i1} != *"$quote"* ]] && updates_mark=1
+ fi
+ ble/keymap:vi/text-object:quote/.expand-xmap-range "$inclusive"
+ [[ $updates_mark ]] && _ble_edit_mark=$beg
+ _ble_edit_ind=$((end-1))
+ return 0
+ else
+ ble-edit/content/find-logical-bol; local bol=$ret nl=$'\n'
+ local rex="^([^$nl$quote]*$quote[^$nl$quote]*$quote)*[^$nl$quote]*$quote"
+ [[ ${_ble_edit_str:bol:_ble_edit_ind-bol} =~ $rex ]] || return 1
+ local beg=$((bol+${#BASH_REMATCH}-1))
+ ble/keymap:vi/text-object:quote/.next $((beg+1)) || return 1
+ local end=$ret
+ ble/keymap:vi/text-object:quote/.expand-xmap-range "$inclusive"
+ [[ ${_ble_edit_str:_ble_edit_ind:_ble_edit_mark+2-_ble_edit_ind} != *"$quote"* ]] && _ble_edit_mark=$((end-1))
+ _ble_edit_ind=$beg
+ return 0
+ fi
+}
+function ble/keymap:vi/text-object/block.impl {
+ local arg=$1 flag=$2 reg=$3 type=$4
+ local ret paren=${type:1} lparen=${type:1:1} rparen=${type:2:1}
+ local axis=$_ble_edit_ind
+ [[ ${_ble_edit_str:axis:1} == "$lparen" ]] && ((axis++))
+ local count=$arg beg=$axis
+ while ble/string#last-index-of-chars "$_ble_edit_str" "$paren" "$beg"; do
+ beg=$ret
+ if [[ ${_ble_edit_str:beg:1} == "$lparen" ]]; then
+ ((--count==0)) && break
+ else
+ ((++count))
+ fi
+ done
+ if ((count)); then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local count=$arg end=$axis
+ while ble/string#index-of-chars "$_ble_edit_str" "$paren" "$end"; do
+ end=$((ret+1))
+ if [[ ${_ble_edit_str:end-1:1} == "$rparen" ]]; then
+ ((--count==0)) && break
+ else
+ ((++count))
+ fi
+ done
+ if ((count)); then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local linewise=
+ if [[ $type == *i* ]]; then
+ ((beg++,end--))
+ [[ ${_ble_edit_str:beg:1} == $'\n' ]] && ((beg++))
+ ((beg<end)) && ble-edit/content/bolp "$end" && ((end--))
+ ((beg<end)) && ble-edit/content/bolp "$beg" && ble-edit/content/eolp "$end" && linewise=1
+ fi
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ _ble_edit_mark=$beg
+ ble/widget/vi-command/exclusive-goto.impl "$end"
+ elif [[ $linewise ]]; then
+ ble/widget/vi-command/linewise-range.impl "$beg" "$end" "$flag" "$reg" goto_bol
+ else
+ ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg"
+ fi
+}
+function ble/keymap:vi/text-object:tag/.find-end-tag {
+ local ifs=$_ble_term_IFS ret rex
+ rex="^<([^$ifs/>!]+)"; [[ ${_ble_edit_str:beg} =~ $rex ]] || return 1
+ ble/string#escape-for-extended-regex "${BASH_REMATCH[1]}"; local tagname=$ret
+ rex="^</?$tagname([$ifs]+([^>]*[^/])?)?>"
+ end=$beg
+ local count=0
+ while ble/string#index-of-chars "$_ble_edit_str" '<' "$end" && end=$((ret+1)); do
+ [[ ${_ble_edit_str:end-1} =~ $rex ]] || continue
+ ((end+=${#BASH_REMATCH}-1))
+ if [[ ${BASH_REMATCH::2} == '</' ]]; then
+ ((--count==0)) && return 0
+ else
+ ((++count))
+ fi
+ done
+ return 1
+}
+function ble/keymap:vi/text-object/tag.impl {
+ local arg=$1 flag=$2 reg=$3 type=$4
+ local ret rex
+ local pivot=$_ble_edit_ind ret=$_ble_edit_ind
+ if [[ ${_ble_edit_str:ret:1} == '<' ]] || ble/string#last-index-of-chars "${_ble_edit_str::_ble_edit_ind}" '<>'; then
+ if rex='^<[^/][^>]*>' && [[ ${_ble_edit_str:ret} =~ $rex ]]; then
+ ((pivot=ret+${#BASH_REMATCH}))
+ else
+ ((pivot=ret+1))
+ fi
+ fi
+ local ifs=$_ble_term_IFS
+ local beg=$pivot count=$arg
+ rex="<([^$ifs/>!]+([$ifs]+([^>]*[^/])?)?|/[^>]*)>\$"
+ while ble/string#last-index-of-chars "${_ble_edit_str::beg}" '>' && beg=$ret; do
+ [[ ${_ble_edit_str::beg+1} =~ $rex ]] || continue
+ ((beg-=${#BASH_REMATCH}-1))
+ if [[ ${BASH_REMATCH::2} == '</' ]]; then
+ ((++count))
+ else
+ if ((--count==0)); then
+ if ble/keymap:vi/text-object:tag/.find-end-tag "$beg" && ((_ble_edit_ind<end)); then
+ break
+ else
+ ((count++))
+ fi
+ fi
+ fi
+ done
+ if ((count)); then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ if [[ $type == i* ]]; then
+ rex='^<[^>]*>'; [[ ${_ble_edit_str:beg:end-beg} =~ $rex ]] && ((beg+=${#BASH_REMATCH}))
+ rex='<[^>]*>$'; [[ ${_ble_edit_str:beg:end-beg} =~ $rex ]] && ((end-=${#BASH_REMATCH}))
+ fi
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ _ble_edit_mark=$beg
+ ble/widget/vi-command/exclusive-goto.impl "$end"
+ else
+ ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg"
+ fi
+}
+function ble/keymap:vi/text-object:sentence/.beg {
+ beg= is_interval=
+ local pivot=$_ble_edit_ind rex=
+ if ble-edit/content/bolp && ble-edit/content/eolp; then
+ if rex=$'^\n+[^\n]'; [[ ${_ble_edit_str:pivot} =~ $rex ]]; then
+ beg=$((pivot+${#BASH_REMATCH}-2))
+ else
+ if rex=$'\n+$'; [[ ${_ble_edit_str::pivot} =~ $rex ]]; then
+ ((pivot-=${#BASH_REMATCH}))
+ fi
+ fi
+ fi
+ if [[ ! $beg ]]; then
+ rex="^.*((^$LF?|$LF$LF)([ $HT]*)|[.!?][])'\"]*([ $HT$LF]+))"
+ if [[ ${_ble_edit_str::pivot+1} =~ $rex ]]; then
+ beg=${#BASH_REMATCH}
+ if ((pivot<beg)); then
+ local rematch34=${BASH_REMATCH[3]}${BASH_REMATCH[4]}
+ if [[ $rematch34 ]]; then
+ beg=$((pivot+1-${#rematch34})) is_interval=1
+ else
+ beg=$pivot
+ fi
+ fi
+ else
+ beg=0
+ fi
+ fi
+}
+function ble/keymap:vi/text-object:sentence/.next {
+ if [[ $is_interval ]]; then
+ is_interval=
+ local rex=$'[ \t]*((\n[ \t]+)*\n[ \t]*)?'
+ [[ ${_ble_edit_str:end} =~ $rex ]]
+ local index=$((end+${#BASH_REMATCH}))
+ ((end<index)) && [[ ${_ble_edit_str:index-1:1} == $'\n' ]] && ((index--))
+ ((end=index))
+ else
+ is_interval=1
+ if local rex=$'^\n+'; [[ ${_ble_edit_str:end} =~ $rex ]]; then
+ ((end+=${#BASH_REMATCH}))
+ elif rex="(([.!?][])\"']*)[ $HT$LF]|$LF$LF).*\$"; [[ ${_ble_edit_str:end} =~ $rex ]]; then
+ local rematch2=${BASH_REMATCH[2]}
+ end=$((${#_ble_edit_str}-${#BASH_REMATCH}+${#rematch2}))
+ else
+ local index=${#_ble_edit_str}
+ ((end<index)) && [[ ${_ble_edit_str:index-1:1} == $'\n' ]] && ((index--))
+ ((end=index))
+ fi
+ fi
+}
+function ble/keymap:vi/text-object/sentence.impl {
+ local arg=$1 flag=$2 reg=$3 type=$4
+ local LF=$'\n' HT=$'\t'
+ local rex
+ local beg is_interval
+ ble/keymap:vi/text-object:sentence/.beg
+ local end=$beg i n=$arg
+ [[ $type != i* ]] && ((n*=2))
+ for ((i=0;i<n;i++)); do
+ ble/keymap:vi/text-object:sentence/.next
+ done
+ ((beg<end)) && [[ ${_ble_edit_str:end-1:1} == $'\n' ]] && ((end--))
+ if [[ $type != i* && ! $is_interval ]]; then
+ local ifs=$_ble_term_IFS
+ if ((end)) && [[ ${_ble_edit_str:end-1:1} != ["$ifs"] ]]; then
+ rex="^.*(^$LF?|$LF$LF|[.!?][])'\"]*([ $HT$LF]))([ $HT$LF]*)\$"
+ if [[ ${_ble_edit_str::beg} =~ $rex ]]; then
+ local rematch2=${BASH_REMATCH[2]}
+ local rematch3=${BASH_REMATCH[3]}
+ ((beg-=${#rematch2}+${#rematch3}))
+ [[ ${_ble_edit_str:beg:1} == $'\n' ]] && ((beg++))
+ fi
+ fi
+ fi
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ _ble_edit_mark=$beg
+ ble/widget/vi-command/exclusive-goto.impl "$end"
+ elif ble-edit/content/bolp "$beg" && [[ ${_ble_edit_str:end:1} == $'\n' ]]; then
+ ble/widget/vi-command/linewise-range.impl "$beg" "$end" "$flag" "$reg" goto_bol
+ else
+ ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg"
+ fi
+}
+function ble/keymap:vi/text-object/paragraph.impl {
+ local arg=$1 flag=$2 reg=$3 type=$4
+ local rex ret
+ local beg= empty_start=
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-non-space "$bol"; local nol=$ret
+ if rex=$'[ \t]*(\n|$)' ble-edit/content/eolp "$nol"; then
+ empty_start=1
+ rex=$'(^|\n)([ \t]*\n)*$'
+ [[ ${_ble_edit_str::bol} =~ $rex ]]
+ local rematch1=${BASH_REMATCH[1]} # Note: for bash-3.1 ${#arr[n]} bug
+ ((beg=bol-(${#BASH_REMATCH}-${#rematch1})))
+ else
+ if rex=$'^(.*\n)?[ \t]*\n'; [[ ${_ble_edit_str::bol} =~ $rex ]]; then
+ ((beg=${#BASH_REMATCH}))
+ else
+ ((beg=0))
+ fi
+ fi
+ local end=$beg
+ local rex_empty_line=$'([ \t]*\n|[ \t]+$)' rex_paragraph_line=$'([ \t]*[^ \t\n][^\n]*(\n|$))'
+ if [[ $type == i* ]]; then
+ rex="$rex_empty_line+|$rex_paragraph_line+"
+ elif [[ $empty_start ]]; then
+ rex="$rex_empty_line*$rex_paragraph_line+"
+ else
+ rex="$rex_paragraph_line+$rex_empty_line*"
+ fi
+ local i
+ for ((i=0;i<arg;i++)); do
+ if [[ ${_ble_edit_str:end} =~ $rex ]]; then
+ ((end+=${#BASH_REMATCH}))
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ done
+ if [[ $type != i* && ! $empty_start ]]; then
+ if rex=$'(^|\n)[ \t]*\n$'; ! [[ ${_ble_edit_str::end} =~ $rex ]]; then
+ if rex=$'(^|\n)([ \t]*\n)*$'; [[ ${_ble_edit_str::beg} =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ ((beg-=${#BASH_REMATCH}-${#rematch1}))
+ fi
+ fi
+ fi
+ ((beg<end)) && [[ ${_ble_edit_str:end-1:1} == $'\n' ]] && ((end--))
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ _ble_edit_mark=$beg
+ ble/widget/vi-command/exclusive-goto.impl "$end"
+ else
+ ble/widget/vi-command/linewise-range.impl "$beg" "$end" "$flag" "$reg"
+ fi
+}
+function ble/keymap:vi/text-object.impl {
+ local arg=$1 flag=$2 reg=$3 type=$4
+ case "$type" in
+ ([ia][wW]) ble/keymap:vi/text-object/word.impl "$arg" "$flag" "$reg" "$type" ;;
+ ([ia][\"\'\`]) ble/keymap:vi/text-object/quote.impl "$arg" "$flag" "$reg" "$type" ;;
+ ([ia]['b()']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}()" ;;
+ ([ia]['B{}']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}{}" ;;
+ ([ia]['<>']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}<>" ;;
+ ([ia]['][']) ble/keymap:vi/text-object/block.impl "$arg" "$flag" "$reg" "${type::1}[]" ;;
+ ([ia]t) ble/keymap:vi/text-object/tag.impl "$arg" "$flag" "$reg" "$type" ;;
+ ([ia]s) ble/keymap:vi/text-object/sentence.impl "$arg" "$flag" "$reg" "$type" ;;
+ ([ia]p) ble/keymap:vi/text-object/paragraph.impl "$arg" "$flag" "$reg" "$type" ;;
+ (*)
+ ble/widget/vi-command/bell
+ return 1;;
+ esac
+}
+function ble/keymap:vi/text-object.hook {
+ local key=$1
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ if ! ble-decode-key/ischar "$key"; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local ret; ble/util/c2s "$key"
+ local type=$_ble_keymap_vi_text_object$ret
+ ble/keymap:vi/text-object.impl "$ARG" "$FLAG" "$REG" "$type"
+ return 0
+}
+function ble/keymap:vi/.check-text-object {
+ local n=${#KEYS[@]}; ((n&&n--))
+ ble-decode-key/ischar "${KEYS[n]}" || return 1
+ local ret; ble/util/c2s "${KEYS[n]}"; local c=$ret
+ [[ $c == [ia] ]] || return 1
+ [[ $_ble_keymap_vi_opfunc || $_ble_decode_keymap == vi_[xs]map ]] || return 1
+ _ble_keymap_vi_text_object=$c
+ _ble_decode_key__hook=ble/keymap:vi/text-object.hook
+ return 0
+}
+function ble/widget/vi-command/text-object {
+ ble/keymap:vi/.check-text-object && return 0
+ ble/widget/vi-command/bell
+ return 1
+}
+_ble_keymap_vi_commandline_history=()
+_ble_keymap_vi_commandline_history_edit=()
+_ble_keymap_vi_commandline_history_dirt=()
+_ble_keymap_vi_commandline_history_index=0
+_ble_keymap_vi_cmap_is_cancel_key[63|_ble_decode_Ctrl]=1 # C-?
+_ble_keymap_vi_cmap_is_cancel_key[127]=1 # DEL
+_ble_keymap_vi_cmap_is_cancel_key[104|_ble_decode_Ctrl]=1 # C-h
+_ble_keymap_vi_cmap_is_cancel_key[8]=1 # BS
+function ble/keymap:vi/commandline/before-command.hook {
+ if [[ ! $_ble_edit_str ]] && ((_ble_keymap_vi_cmap_is_cancel_key[KEYS[0]])); then
+ ble/widget/vi_cmap/cancel
+ ble/decode/widget/suppress-widget
+ fi
+}
+function ble/widget/vi-command/commandline {
+ ble/keymap:vi/clear-arg
+ ble/keymap:vi/async-commandline-mode ble/widget/vi-command/commandline.hook
+ _ble_edit_PS1=:
+ ble/history/set-prefix _ble_keymap_vi_commandline
+ _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook
+ return 147
+}
+function ble/widget/vi-command/commandline.hook {
+ local command
+ ble/string#split-words command "$1"
+ local cmd="ble/widget/vi-command:${command[0]}"
+ if ble/is-function "$cmd"; then
+ "$cmd" "${command[@]:1}"; local ext=$?
+ else
+ ble/widget/vi-command/bell "unknown command $1"; local ext=1
+ fi
+ [[ $1 ]] && _ble_keymap_vi_register[58]=/$result # ":
+ return "$ext"
+}
+function ble/widget/vi-command:w {
+ if [[ $1 ]]; then
+ ble/builtin/history -a "$1"
+ local file=$1
+ else
+ ble/builtin/history -a
+ local file=${HISTFILE:-'~/.bash_history'}
+ fi
+ local wc
+ ble/util/assign wc 'ble/bin/wc "$file"'
+ ble/string#split-words wc "$wc"
+ ble/edit/info/show text "\"$file\" ${wc[0]}L, ${wc[2]}C written"
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-command:q! {
+ ble/widget/exit force
+ return 1
+}
+function ble/widget/vi-command:q {
+ ble/widget/exit
+ ble/keymap:vi/adjust-command-mode # ジョブがあるときは終了しないので。
+ return 1
+}
+function ble/widget/vi-command:wq {
+ ble/widget/vi-command:w "$@"
+ ble/widget/exit
+ ble/keymap:vi/adjust-command-mode
+ return 1
+}
+_ble_keymap_vi_search_obackward=
+_ble_keymap_vi_search_ohistory=
+_ble_keymap_vi_search_needle=
+_ble_keymap_vi_search_activate=
+_ble_keymap_vi_search_matched=
+_ble_keymap_vi_search_history=()
+_ble_keymap_vi_search_history_edit=()
+_ble_keymap_vi_search_history_dirt=()
+_ble_keymap_vi_search_history_index=0
+bleopt/declare -v keymap_vi_search_match_current ''
+function ble/highlight/layer:region/mark:vi_search/get-selection {
+ ble/highlight/layer:region/mark:vi_char/get-selection
+}
+function ble/keymap:vi/search/matched {
+ [[ $_ble_keymap_vi_search_matched || $_ble_edit_mark_active == vi_search || $_ble_keymap_vi_search_activate ]]
+}
+function ble/keymap:vi/search/clear-matched {
+ _ble_keymap_vi_search_activate=
+ _ble_keymap_vi_search_matched=
+ [[ $_ble_edit_mark_active == vi_search ]] && _ble_edit_mark_active=
+}
+function ble/keymap:vi/search/invoke-search {
+ local needle=$1
+ local dir=+; ((opt_backward)) && dir=B
+ local ind=$_ble_edit_ind
+ if ((opt_optional_next)); then
+ if ((!opt_backward)); then
+ ((_ble_edit_ind<${#_ble_edit_str}&&_ble_edit_ind++))
+ fi
+ elif ((opt_locate)) || ! ble/keymap:vi/search/matched; then
+ if ((opt_locate)) || [[ $bleopt_keymap_vi_search_match_current ]]; then
+ if ((opt_backward)); then
+ ble-edit/content/eolp || ((_ble_edit_ind++))
+ fi
+ else
+ if ((!opt_backward)); then
+ ble-edit/content/eolp || ((_ble_edit_ind++))
+ fi
+ fi
+ else
+ if ((!opt_backward)); then
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ if ble-edit/isearch/search "$@" && ((beg==_ble_edit_ind)); then
+ _ble_edit_ind=$end
+ else
+ ((_ble_edit_ind<${#_ble_edit_str}&&_ble_edit_ind++))
+ fi
+ else
+ ((_ble_edit_ind=_ble_edit_mark))
+ ble-edit/content/eolp || ((_ble_edit_ind++))
+ fi
+ else
+ dir=-
+ fi
+ fi
+ ble-edit/isearch/search "$needle" "$dir":regex; local ret=$?
+ _ble_edit_ind=$ind
+ return "$ret"
+}
+function ble/widget/vi-command/search.core {
+ local beg= end= is_empty_match=
+ if ble/keymap:vi/search/invoke-search "$needle"; then
+ if ((beg<end)); then
+ ble-edit/content/bolp "$end" || ((end--))
+ _ble_edit_ind=$beg # eol 補正は search.impl 側で最後に行う
+ [[ $_ble_decode_keymap != vi_[xs]map ]] && _ble_edit_mark=$end
+ _ble_keymap_vi_search_activate=vi_search
+ return 0
+ else
+ opt_history=
+ is_empty_match=1
+ fi
+ fi
+ if ((opt_history)) && [[ $_ble_history_load_done || opt_backward -ne 0 ]]; then
+ ble/history/initialize
+ local index; ble/history/get-index
+ [[ $start ]] || start=$index
+ if ((opt_backward)); then
+ ((index--))
+ else
+ ((index++))
+ fi
+ local _ble_edit_isearch_dir=+; ((opt_backward)) && _ble_edit_isearch_dir=-
+ local _ble_edit_isearch_str=$needle
+ local isearch_ntask=$ntask
+ local isearch_time=0
+ local isearch_progress_callback=ble-edit/isearch/.show-status-with-progress.fib
+ if ((opt_backward)); then
+ ble/history/isearch-backward-blockwise regex:progress
+ else
+ ble/history/isearch-forward regex:progress
+ fi; local r=$?
+ ble/edit/info/default
+ if ((r==0)); then
+ local new_index; ble/history/get-index -v new_index
+ [[ $index != "$new_index" ]] &&
+ ble-edit/history/goto "$index"
+ if ((opt_backward)); then
+ local i=${#_ble_edit_str}
+ ble/keymap:vi/needs-eol-fix "$i" && ((i--))
+ _ble_edit_ind=$i
+ else
+ _ble_edit_ind=0
+ fi
+ opt_locate=1 opt_history=0 ble/widget/vi-command/search.core
+ return "$?"
+ fi
+ fi
+ if ((!opt_optional_next)); then
+ if [[ $is_empty_match ]]; then
+ ble/widget/.bell "search: empty match"
+ else
+ ble/widget/.bell "search: not found"
+ fi
+ if [[ $_ble_edit_mark_active == vi_search ]]; then
+ _ble_keymap_vi_search_activate=vi_search
+ fi
+ fi
+ return 1
+}
+function ble/widget/vi-command/search.impl {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local opts=$1 needle=$2
+ [[ :$opts: != *:repeat:* ]]; local opt_repeat=$? # 再検索 n N
+ [[ :$opts: != *:history:* ]]; local opt_history=$? # 履歴検索が有効か
+ [[ :$opts: != *:-:* ]]; local opt_backward=$? # 逆方向
+ local opt_locate=0
+ local opt_optional_next=0
+ if ((opt_repeat)); then
+ if [[ $_ble_keymap_vi_search_needle ]]; then
+ needle=$_ble_keymap_vi_search_needle
+ ((opt_backward^=_ble_keymap_vi_search_obackward,
+ opt_history=_ble_keymap_vi_search_ohistory))
+ else
+ ble/widget/vi-command/bell 'no previous search'
+ return 1
+ fi
+ else
+ ble/keymap:vi/search/clear-matched
+ if [[ $needle ]]; then
+ _ble_keymap_vi_search_needle=$needle
+ _ble_keymap_vi_search_obackward=$opt_backward
+ _ble_keymap_vi_search_ohistory=$opt_history
+ elif [[ $_ble_keymap_vi_search_needle ]]; then
+ needle=$_ble_keymap_vi_search_needle
+ _ble_keymap_vi_search_obackward=$opt_backward
+ _ble_keymap_vi_search_ohistory=$opt_history
+ else
+ ble/widget/vi-command/bell 'no previous search'
+ return 1
+ fi
+ fi
+ local original_ind=$_ble_edit_ind
+ if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then
+ opt_history=0
+ else
+ local old_hindex; ble/history/get-index -v old_hindex
+ fi
+ local start= # 初めの履歴番号。search.core 内で最初に履歴を読み込んだあとで設定される。
+ local ntask=$ARG
+ while ((ntask)); do
+ ble/widget/vi-command/search.core || break
+ ((ntask--))
+ done
+ if [[ $FLAG ]]; then
+ if ((ntask)); then
+ _ble_keymap_vi_search_activate=
+ _ble_edit_ind=$original_ind
+ ble/keymap:vi/adjust-command-mode
+ return 1
+ else
+ if ((_ble_edit_ind==original_index)); then
+ opt_optional_next=1 ble/widget/vi-command/search.core
+ fi
+ local index=$_ble_edit_ind
+ _ble_keymap_vi_search_activate=
+ _ble_edit_ind=$original_ind
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+ fi
+ else
+ if ((ntask<ARG)); then
+ if ((opt_history)); then
+ local new_hindex; ble/history/get-index -v new_hindex
+ ((new_hindex==old_hindex))
+ fi && ble/keymap:vi/mark/set-local-mark 96 "$original_index" # ``
+ if ble/keymap:vi/needs-eol-fix; then
+ if ((!opt_backward&&_ble_edit_ind<_ble_edit_mark)); then
+ ((_ble_edit_ind++))
+ else
+ ((_ble_edit_ind--))
+ fi
+ fi
+ fi
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+}
+function ble/widget/vi-command/search-forward {
+ ble/keymap:vi/async-commandline-mode 'ble/widget/vi-command/search.impl +:history'
+ _ble_edit_PS1='/'
+ ble/history/set-prefix _ble_keymap_vi_search
+ _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook
+ return 147
+}
+function ble/widget/vi-command/search-backward {
+ ble/keymap:vi/async-commandline-mode 'ble/widget/vi-command/search.impl -:history'
+ _ble_edit_PS1='?'
+ ble/history/set-prefix _ble_keymap_vi_search
+ _ble_keymap_vi_cmap_before_command=ble/keymap:vi/commandline/before-command.hook
+ return 147
+}
+function ble/widget/vi-command/search-repeat {
+ ble/widget/vi-command/search.impl repeat:+
+}
+function ble/widget/vi-command/search-reverse-repeat {
+ ble/widget/vi-command/search.impl repeat:-
+}
+function ble/widget/vi-command/search-word.impl {
+ local opts=$1
+ local rex=$'^([^[:alnum:]_\n]*)([[:alnum:]_]*)'
+ if ! [[ ${_ble_edit_str:_ble_edit_ind} =~ $rex ]]; then
+ ble/keymap:vi/clear-arg
+ ble/widget/vi-command/bell 'word is not found'
+ return 1
+ fi
+ local end=$((_ble_edit_ind+${#BASH_REMATCH}))
+ local word=${BASH_REMATCH[2]}
+ if [[ ! ${BASH_REMATCH[1]} ]]; then
+ rex=$'[[:alnum:]_]+$'
+ [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]] &&
+ word=$BASH_REMATCH$word
+ fi
+ local needle=$word
+ rex='\<'$needle; [[ $word =~ $rex ]] && needle=$rex
+ rex=$needle'\>'; [[ $word =~ $rex ]] && needle=$rex
+ if [[ $opts == backward ]]; then
+ ble/widget/vi-command/search.impl -:history "$needle"
+ else
+ local original_ind=$_ble_edit_ind
+ _ble_edit_ind=$((end-1))
+ ble/widget/vi-command/search.impl +:history "$needle" && return 0
+ _ble_edit_ind=$original_ind
+ return 1
+ fi
+}
+function ble/widget/vi-command/search-word-forward {
+ ble/widget/vi-command/search-word.impl forward
+}
+function ble/widget/vi-command/search-word-backward {
+ ble/widget/vi-command/search-word.impl backward
+}
+function ble/widget/vi_nmap/command-help {
+ ble/keymap:vi/clear-arg
+ ble/widget/command-help; local ext=$?
+ ble/keymap:vi/adjust-command-mode
+ return "$ext"
+}
+function ble/widget/vi_xmap/command-help.core {
+ ble/keymap:vi/clear-arg
+ local get_selection=ble/highlight/layer:region/mark:$_ble_edit_mark_active/get-selection
+ ble/is-function "$get_selection" || return 1
+ local selection
+ "$get_selection" || return 1
+ ((${#selection[*]}==2)) || return 1
+ local comp_cword=0 comp_line=$_ble_edit_str comp_point=$_ble_edit_ind
+ local -a comp_words; comp_words=("$cmd")
+ local cmd=${_ble_edit_str:selection[0]:selection[1]-selection[0]}
+ ble/widget/command-help.impl "$cmd"; local ext=$?
+ ble/keymap:vi/adjust-command-mode
+ return "$ext"
+}
+function ble/widget/vi_xmap/command-help {
+ if ! ble/widget/vi_xmap/command-help.core; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/keymap:vi/set-up-command-map {
+ ble-bind -f 0 vi-command/append-arg
+ ble-bind -f 1 vi-command/append-arg
+ ble-bind -f 2 vi-command/append-arg
+ ble-bind -f 3 vi-command/append-arg
+ ble-bind -f 4 vi-command/append-arg
+ ble-bind -f 5 vi-command/append-arg
+ ble-bind -f 6 vi-command/append-arg
+ ble-bind -f 7 vi-command/append-arg
+ ble-bind -f 8 vi-command/append-arg
+ ble-bind -f 9 vi-command/append-arg
+ ble-bind -f y 'vi-command/operator y'
+ ble-bind -f d 'vi-command/operator d'
+ ble-bind -f c 'vi-command/operator c'
+ ble-bind -f '<' 'vi-command/operator indent-left'
+ ble-bind -f '>' 'vi-command/operator indent-right'
+ ble-bind -f '!' 'vi-command/operator filter'
+ ble-bind -f 'g ~' 'vi-command/operator toggle_case'
+ ble-bind -f 'g u' 'vi-command/operator u'
+ ble-bind -f 'g U' 'vi-command/operator U'
+ ble-bind -f 'g ?' 'vi-command/operator rot13'
+ ble-bind -f 'g q' 'vi-command/operator fold'
+ ble-bind -f 'g w' 'vi-command/operator fold-preserve-point'
+ ble-bind -f 'g @' 'vi-command/operator map'
+ ble-bind -f paste_begin vi-command/bracketed-paste
+ ble-bind -f 'home' vi-command/beginning-of-line
+ ble-bind -f '$' vi-command/forward-eol
+ ble-bind -f 'end' vi-command/forward-eol
+ ble-bind -f '^' vi-command/first-non-space
+ ble-bind -f '_' vi-command/first-non-space-forward
+ ble-bind -f '+' vi-command/forward-first-non-space
+ ble-bind -f 'C-m' vi-command/forward-first-non-space
+ ble-bind -f 'RET' vi-command/forward-first-non-space
+ ble-bind -f '-' vi-command/backward-first-non-space
+ ble-bind -f 'g 0' vi-command/beginning-of-graphical-line
+ ble-bind -f 'g home' vi-command/beginning-of-graphical-line
+ ble-bind -f 'g ^' vi-command/graphical-first-non-space
+ ble-bind -f 'g $' vi-command/graphical-forward-eol
+ ble-bind -f 'g end' vi-command/graphical-forward-eol
+ ble-bind -f 'g m' vi-command/middle-of-graphical-line
+ ble-bind -f 'g _' vi-command/last-non-space
+ ble-bind -f h vi-command/backward-char
+ ble-bind -f l vi-command/forward-char
+ ble-bind -f left vi-command/backward-char
+ ble-bind -f right vi-command/forward-char
+ ble-bind -f 'C-?' 'vi-command/backward-char wrap'
+ ble-bind -f 'DEL' 'vi-command/backward-char wrap'
+ ble-bind -f 'C-h' 'vi-command/backward-char wrap'
+ ble-bind -f 'BS' 'vi-command/backward-char wrap'
+ ble-bind -f SP 'vi-command/forward-char wrap'
+ ble-bind -f j vi-command/forward-line
+ ble-bind -f down vi-command/forward-line
+ ble-bind -f C-n vi-command/forward-line
+ ble-bind -f C-j vi-command/forward-line
+ ble-bind -f k vi-command/backward-line
+ ble-bind -f up vi-command/backward-line
+ ble-bind -f C-p vi-command/backward-line
+ ble-bind -f 'g j' vi-command/graphical-forward-line
+ ble-bind -f 'g down' vi-command/graphical-forward-line
+ ble-bind -f 'g k' vi-command/graphical-backward-line
+ ble-bind -f 'g up' vi-command/graphical-backward-line
+ ble-bind -f w vi-command/forward-vword
+ ble-bind -f W vi-command/forward-uword
+ ble-bind -f b vi-command/backward-vword
+ ble-bind -f B vi-command/backward-uword
+ ble-bind -f e vi-command/forward-vword-end
+ ble-bind -f E vi-command/forward-uword-end
+ ble-bind -f 'g e' vi-command/backward-vword-end
+ ble-bind -f 'g E' vi-command/backward-uword-end
+ ble-bind -f C-right vi-command/forward-vword
+ ble-bind -f S-right vi-command/forward-vword
+ ble-bind -f C-left vi-command/backward-vword
+ ble-bind -f S-left vi-command/backward-vword
+ ble-bind -f 'g o' vi-command/nth-byte
+ ble-bind -f '|' vi-command/nth-column
+ ble-bind -f H vi-command/nth-line
+ ble-bind -f L vi-command/nth-last-line
+ ble-bind -f 'g g' vi-command/history-beginning
+ ble-bind -f G vi-command/history-end
+ ble-bind -f C-home vi-command/first-nol
+ ble-bind -f C-end vi-command/last-eol
+ ble-bind -f 'f' vi-command/search-forward-char
+ ble-bind -f 'F' vi-command/search-backward-char
+ ble-bind -f 't' vi-command/search-forward-char-prev
+ ble-bind -f 'T' vi-command/search-backward-char-prev
+ ble-bind -f ';' vi-command/search-char-repeat
+ ble-bind -f ',' vi-command/search-char-reverse-repeat
+ ble-bind -f '%' 'vi-command/search-matchpair-or vi-command/percentage-line'
+ ble-bind -f 'C-\ C-n' nop
+ ble-bind -f ':' vi-command/commandline
+ ble-bind -f '/' vi-command/search-forward
+ ble-bind -f '?' vi-command/search-backward
+ ble-bind -f 'n' vi-command/search-repeat
+ ble-bind -f 'N' vi-command/search-reverse-repeat
+ ble-bind -f '*' vi-command/search-word-forward
+ ble-bind -f '#' vi-command/search-word-backward
+ ble-bind -f '`' 'vi-command/goto-mark'
+ ble-bind -f \' 'vi-command/goto-mark line'
+ ble-bind -c 'C-z' fg
+}
+function ble/widget/vi_omap/operator-rot13-or-search-backward {
+ if [[ $_ble_keymap_vi_opfunc == rot13 ]]; then
+ ble/widget/vi-command/operator rot13
+ else
+ ble/widget/vi-command/search-backward
+ fi
+}
+function ble/widget/vi_omap/switch-visual-mode.impl {
+ local new_mode=$1
+ local old=$_ble_keymap_vi_opfunc
+ [[ $old ]] || return 1
+ local new=$old:
+ new=${new/:vi_char:/:}
+ new=${new/:vi_line:/:}
+ new=${new/:vi_block:/:}
+ [[ $new_mode ]] && new=$new:$new_mode
+ _ble_keymap_vi_opfunc=$new
+}
+function ble/widget/vi_omap/switch-to-charwise {
+ ble/widget/vi_omap/switch-visual-mode.impl vi_char
+}
+function ble/widget/vi_omap/switch-to-linewise {
+ ble/widget/vi_omap/switch-visual-mode.impl vi_line
+}
+function ble/widget/vi_omap/switch-to-blockwise {
+ ble/widget/vi_omap/switch-visual-mode.impl vi_block
+}
+function ble-decode/keymap:vi_omap/define {
+ ble/keymap:vi/set-up-command-map
+ ble-bind -f __default__ vi_omap/__default__
+ ble-bind -f __line_limit__ nop
+ ble-bind -f 'ESC' vi_omap/cancel
+ ble-bind -f 'C-[' vi_omap/cancel
+ ble-bind -f 'C-c' vi_omap/cancel
+ ble-bind -f a vi-command/text-object
+ ble-bind -f i vi-command/text-object
+ ble-bind -f v vi_omap/switch-to-charwise
+ ble-bind -f V vi_omap/switch-to-linewise
+ ble-bind -f C-v vi_omap/switch-to-blockwise
+ ble-bind -f C-q vi_omap/switch-to-blockwise
+ ble-bind -f '~' 'vi-command/operator toggle_case'
+ ble-bind -f 'u' 'vi-command/operator u'
+ ble-bind -f 'U' 'vi-command/operator U'
+ ble-bind -f '?' 'vi_omap/operator-rot13-or-search-backward'
+ ble-bind -f 'q' 'vi-command/operator fold'
+}
+function ble/widget/vi-command/exit-on-empty-line {
+ if [[ $_ble_edit_str ]]; then
+ ble/widget/vi_nmap/forward-scroll
+ return "$?"
+ else
+ ble/widget/exit
+ ble/keymap:vi/adjust-command-mode # ジョブがあるときは終了しないので。
+ return 1
+ fi
+}
+function ble/widget/vi-command/show-line-info {
+ local index count
+ ble/history/get-index -v index
+ ble/history/get-count -v count
+ local hist_ratio=$(((100*index+count-1)/count))%
+ local hist_stat=$'!\e[32m'$index$'\e[m / \e[32m'$count$'\e[m (\e[32m'$hist_ratio$'\e[m)'
+ local ret
+ ble/string#count-char "$_ble_edit_str" $'\n'; local nline=$((ret+1))
+ ble/string#count-char "${_ble_edit_str::_ble_edit_ind}" $'\n'; local iline=$((ret+1))
+ local line_ratio=$(((100*iline+nline-1)/nline))%
+ local line_stat=$'line \e[34m'$iline$'\e[m / \e[34m'$nline$'\e[m --\e[34m'$line_ratio$'\e[m--'
+ ble/edit/info/show ansi "\"$hist_stat\" $line_stat"
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-command/cancel {
+ if [[ $_ble_keymap_vi_single_command ]]; then
+ _ble_keymap_vi_single_command=
+ _ble_keymap_vi_single_command_overwrite=
+ ble/keymap:vi/update-mode-name
+ else
+ local joblist; ble/util/joblist
+ if ((${#joblist[*]})); then
+ ble/array#push joblist $'Type \e[35m:q!\e[m and press \e[35m<Enter>\e[m to abandon all \e[31mjobs\e[m and exit Bash'
+ IFS=$'\n' builtin eval 'ble/edit/info/show ansi "${joblist[*]}"'
+ else
+ ble/edit/info/show ansi $'Type \e[35m:q\e[m and press \e[35m<Enter>\e[m to exit Bash'
+ fi
+ fi
+ ble/widget/vi-command/bell
+ return 0
+}
+bleopt/declare -v keymap_vi_imap_undo ''
+_ble_keymap_vi_undo_suppress=
+function ble/keymap:vi/undo/add {
+ [[ $_ble_keymap_vi_undo_suppress ]] && return 0
+ [[ $1 == more && $bleopt_keymap_vi_imap_undo != more ]] && return 0
+ ble-edit/undo/add
+}
+function ble/widget/vi_nmap/undo {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local _ble_keymap_vi_undo_suppress=1
+ ble/keymap:vi/mark/start-edit-area
+ if ble-edit/undo/undo "$ARG"; then
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/adjust-command-mode
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi_nmap/redo {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local _ble_keymap_vi_undo_suppress=1
+ ble/keymap:vi/mark/start-edit-area
+ if ble-edit/undo/redo "$ARG"; then
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/adjust-command-mode
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi_nmap/revert {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local _ble_keymap_vi_undo_suppress=1
+ ble/keymap:vi/mark/start-edit-area
+ if ble-edit/undo/revert-toggle "$ARG"; then
+ ble/keymap:vi/needs-eol-fix && ((_ble_edit_ind--))
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/adjust-command-mode
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+}
+function ble/widget/vi_nmap/increment.impl {
+ local delta=$1
+ ((delta==0)) && return 0
+ local line=${_ble_edit_str:_ble_edit_ind}
+ line=${line%%$'\n'*}
+ local rex='^([^0-9]*)[0-9]+'
+ if ! [[ $line =~ $rex ]]; then
+ [[ $line ]] && ble/widget/.bell 'number not found'
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+ local rematch1=${BASH_REMATCH[1]}
+ local beg=$((_ble_edit_ind+${#rematch1}))
+ local end=$((_ble_edit_ind+${#BASH_REMATCH}))
+ rex='-?[0-9]*$'; [[ ${_ble_edit_str::beg} =~ $rex ]]
+ ((beg-=${#BASH_REMATCH}))
+ local number=${_ble_edit_str:beg:end-beg}
+ local abs=${number#-}
+ if [[ $abs == 0?* ]]; then
+ if [[ $number == -* ]]; then
+ number=-$((10#0$abs))
+ else
+ number=$((10#0$abs))
+ fi
+ fi
+ ((number+=delta))
+ if [[ $abs == 0?* ]]; then
+ local wsign=$((number<0?1:0))
+ local zpad=$((wsign+${#abs}-${#number}))
+ if ((zpad>0)); then
+ local ret; ble/string#repeat 0 "$zpad"
+ number=${number::wsign}$ret${number:wsign}
+ fi
+ fi
+ ble/widget/.replace-range "$beg" "$end" "$number"
+ ble/keymap:vi/mark/set-previous-edit-area "$beg" $((beg+${#number}))
+ ble/keymap:vi/repeat/record
+ _ble_edit_ind=$((beg+${#number}-1))
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi_nmap/increment {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi_nmap/increment.impl "$ARG"
+}
+function ble/widget/vi_nmap/decrement {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vi_nmap/increment.impl $((-ARG))
+}
+function ble/widget/vi_nmap/__line_limit__.edit {
+ ble/keymap:vi/clear-arg
+ ble/widget/vi_nmap/.insert-mode
+ ble/keymap:vi/repeat/clear-insert
+ ble/widget/edit-and-execute-command.impl "$1"
+}
+function ble/widget/vi_nmap/__line_limit__ {
+ ble/widget/__line_limit__ vi_nmap/__line_limit__.edit
+}
+function ble-decode/keymap:vi_nmap/define {
+ ble/keymap:vi/set-up-command-map
+ ble-bind -f __default__ vi-command/decompose-meta
+ ble-bind -f __line_limit__ vi_nmap/__line_limit__
+ ble-bind -f 'ESC' vi-command/bell
+ ble-bind -f 'C-[' vi-command/bell
+ ble-bind -f 'C-c' vi-command/cancel
+ ble-bind -f a vi_nmap/append-mode
+ ble-bind -f A vi_nmap/append-mode-at-end-of-line
+ ble-bind -f i vi_nmap/insert-mode
+ ble-bind -f insert vi_nmap/insert-mode
+ ble-bind -f I vi_nmap/insert-mode-at-first-non-space
+ ble-bind -f 'g I' vi_nmap/insert-mode-at-beginning-of-line
+ ble-bind -f o vi_nmap/insert-mode-at-forward-line
+ ble-bind -f O vi_nmap/insert-mode-at-backward-line
+ ble-bind -f R vi_nmap/replace-mode
+ ble-bind -f 'g R' vi_nmap/virtual-replace-mode
+ ble-bind -f 'g i' vi_nmap/insert-mode-at-previous-point
+ ble-bind -f '~' vi_nmap/forward-char-toggle-case
+ ble-bind -f Y vi_nmap/copy-current-line
+ ble-bind -f S vi_nmap/kill-current-line-and-insert
+ ble-bind -f D vi_nmap/kill-forward-line
+ ble-bind -f C vi_nmap/kill-forward-line-and-insert
+ ble-bind -f p vi_nmap/paste-after
+ ble-bind -f P vi_nmap/paste-before
+ ble-bind -f x vi_nmap/kill-forward-char
+ ble-bind -f s vi_nmap/kill-forward-char-and-insert
+ ble-bind -f X vi_nmap/kill-backward-char
+ ble-bind -f delete vi_nmap/kill-forward-char
+ ble-bind -f 'r' vi_nmap/replace-char
+ ble-bind -f 'g r' vi_nmap/virtual-replace-char # vim で実際に試すとこの機能はない
+ ble-bind -f J vi_nmap/connect-line-with-space
+ ble-bind -f 'g J' vi_nmap/connect-line
+ ble-bind -f v vi_nmap/charwise-visual-mode
+ ble-bind -f V vi_nmap/linewise-visual-mode
+ ble-bind -f C-v vi_nmap/blockwise-visual-mode
+ ble-bind -f C-q vi_nmap/blockwise-visual-mode
+ ble-bind -f 'g v' vi-command/previous-visual-area
+ ble-bind -f 'g h' vi_nmap/charwise-select-mode
+ ble-bind -f 'g H' vi_nmap/linewise-select-mode
+ ble-bind -f 'g C-h' vi_nmap/blockwise-select-mode
+ ble-bind -f . vi_nmap/repeat
+ ble-bind -f K vi_nmap/command-help
+ ble-bind -f f1 vi_nmap/command-help
+ ble-bind -f 'C-d' vi_nmap/forward-line-scroll
+ ble-bind -f 'C-u' vi_nmap/backward-line-scroll
+ ble-bind -f 'C-e' vi_nmap/forward-scroll
+ ble-bind -f 'C-y' vi_nmap/backward-scroll
+ ble-bind -f 'C-f' vi_nmap/pagedown
+ ble-bind -f 'next' vi_nmap/pagedown
+ ble-bind -f 'C-b' vi_nmap/pageup
+ ble-bind -f 'prior' vi_nmap/pageup
+ ble-bind -f 'z t' vi_nmap/scroll-to-top-and-redraw
+ ble-bind -f 'z z' vi_nmap/scroll-to-center-and-redraw
+ ble-bind -f 'z b' vi_nmap/scroll-to-bottom-and-redraw
+ ble-bind -f 'z RET' vi_nmap/scroll-to-top-non-space-and-redraw
+ ble-bind -f 'z C-m' vi_nmap/scroll-to-top-non-space-and-redraw
+ ble-bind -f 'z +' vi_nmap/scroll-or-pagedown-and-redraw
+ ble-bind -f 'z -' vi_nmap/scroll-to-bottom-non-space-and-redraw
+ ble-bind -f 'z .' vi_nmap/scroll-to-center-non-space-and-redraw
+ ble-bind -f m vi-command/set-mark
+ ble-bind -f '"' vi-command/register
+ ble-bind -f 'C-g' vi-command/show-line-info
+ ble-bind -f 'q' vi_nmap/record-register
+ ble-bind -f '@' vi_nmap/play-register
+ ble-bind -f u vi_nmap/undo
+ ble-bind -f C-r vi_nmap/redo
+ ble-bind -f U vi_nmap/revert
+ ble-bind -f C-a vi_nmap/increment
+ ble-bind -f C-x vi_nmap/decrement
+ ble-bind -f 'Z Z' 'vi-command:q'
+ ble-bind -f 'Z Q' 'vi-command:q'
+ ble-bind -f 'C-j' 'accept-line'
+ ble-bind -f 'C-RET' 'accept-line'
+ ble-bind -f 'C-m' 'accept-single-line-or vi-command/forward-first-non-space'
+ ble-bind -f 'RET' 'accept-single-line-or vi-command/forward-first-non-space'
+ ble-bind -f 'C-l' 'clear-screen'
+ ble-bind -f 'C-d' 'vi-command/exit-on-empty-line' # overwrites vi_nmap/forward-scroll
+ ble-bind -f 'auto_complete_enter' auto-complete-enter
+ ble-bind -f M-left 'vi-command/backward-vword'
+ ble-bind -f M-right 'vi-command/forward-vword'
+ ble-bind -f C-delete 'vi-rlfunc/kill-word'
+ ble-bind -f '#' 'vi-rlfunc/insert-comment'
+ ble-bind -f '&' 'vi_nmap/@edit tilde-expand'
+}
+function ble/widget/vi-rlfunc/.is-uppercase {
+ local n=${#KEYS[@]}
+ local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar))
+ ((0x41<=code&&code<=0x5a))
+}
+function ble/widget/vi-rlfunc/delete-to {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi_nmap/kill-forward-line
+ else
+ ble/widget/vi-command/operator d
+ fi
+}
+function ble/widget/vi-rlfunc/change-to {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi_nmap/kill-forward-line-and-insert
+ else
+ ble/widget/vi-command/operator c
+ fi
+}
+function ble/widget/vi-rlfunc/yank-to {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi_nmap/copy-current-line
+ else
+ ble/widget/vi-command/operator y
+ fi
+}
+function ble/widget/vi-rlfunc/char-search {
+ local n=${#KEYS[@]}
+ local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar))
+ ((code==0)) && return 1
+ ble/util/c2s "$code"
+ case $ret in
+ ('f') ble/widget/vi-command/search-forward-char ;;
+ ('F') ble/widget/vi-command/search-backward-char ;;
+ ('t') ble/widget/vi-command/search-forward-char-prev ;;
+ ('T') ble/widget/vi-command/search-backward-char-prev ;;
+ (';') ble/widget/vi-command/search-char-repeat ;;
+ (',') ble/widget/vi-command/search-char-reverse-repeat ;;
+ (*) return 1 ;;
+ esac
+}
+function ble/widget/vi-rlfunc/next-word {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi-command/forward-uword
+ else
+ ble/widget/vi-command/forward-vword
+ fi
+}
+function ble/widget/vi-rlfunc/prev-word {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi-command/backward-uword
+ else
+ ble/widget/vi-command/backward-vword
+ fi
+}
+function ble/widget/vi-rlfunc/end-word {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi-command/forward-uword-end
+ else
+ ble/widget/vi-command/forward-vword-end
+ fi
+}
+function ble/widget/vi-rlfunc/put {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi_nmap/paste-before
+ else
+ ble/widget/vi_nmap/paste-after
+ fi
+}
+function ble/widget/vi-rlfunc/search {
+ local n=${#KEYS[@]}
+ local code=$((KEYS[n?n-1:0]&_ble_decode_MaskChar))
+ if ((code==63)); then
+ ble/widget/vi-command/search-backward
+ else
+ ble/widget/vi-command/search-forward
+ fi
+}
+function ble/widget/vi-rlfunc/search-again {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi-command/search-reverse-repeat
+ else
+ ble/widget/vi-command/search-repeat
+ fi
+}
+function ble/widget/vi-rlfunc/subst {
+ if ble/widget/vi-rlfunc/.is-uppercase; then
+ ble/widget/vi_nmap/kill-current-line-and-insert
+ else
+ ble/widget/vi_nmap/kill-forward-char-and-insert
+ fi
+}
+function ble/widget/vi-rlfunc/kill-word {
+ _ble_keymap_vi_opfunc=d
+ ble/widget/vi-command/forward-vword-end
+}
+function ble/widget/vi-rlfunc/unix-line-discard {
+ _ble_keymap_vi_opfunc=d
+ ble/widget/vi-command/beginning-of-line
+}
+function ble/widget/vi-rlfunc/insert-comment {
+ local ARG FLAG REG; ble/keymap:vi/get-arg ''
+ ble/keymap:vi/mark/start-edit-area
+ ble/widget/insert-comment/.insert "$ARG"
+ ble/keymap:vi/mark/end-edit-area
+ ble/widget/vi_nmap/accept-line
+}
+function ble/widget/vi-rlfunc/quoted-insert-char.hook {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/keymap:vi/mark/start-edit-area
+ _ble_edit_arg=$ARG ble/widget/quoted-insert-char.hook
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/repeat/record
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-rlfunc/quoted-insert-char {
+ _ble_edit_mark_active=
+ _ble_decode_char__hook=ble/widget/vi-rlfunc/quoted-insert-char.hook
+ return 147
+}
+function ble/widget/vi-rlfunc/quoted-insert.hook {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/keymap:vi/mark/start-edit-area
+ _ble_edit_arg=$ARG ble/widget/quoted-insert.hook
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/repeat/record
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vi-rlfunc/quoted-insert {
+ _ble_edit_mark_active=
+ _ble_decode_key__hook=ble/widget/vi-rlfunc/quoted-insert.hook
+ return 147
+}
+function ble/widget/vi-rlfunc/eof-maybe {
+ if [[ ! $_ble_edit_str ]]; then
+ ble/widget/exit
+ ble/keymap:vi/adjust-command-mode # ジョブがあるときは終了しないので。
+ return 1
+ elif ble-edit/is-single-complete-line; then
+ ble/widget/vi_nmap/accept-line
+ else
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/keymap:vi/mark/start-edit-area
+ _ble_edit_ind=${#_ble_edit_str}
+ _ble_edit_arg=$ARG
+ ble/widget/self-insert
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/adjust-command-mode
+ fi
+}
+function ble/widget/vi-rlfunc/yank-arg {
+ ble/widget/vi_nmap/append-mode
+ ble/keymap:vi/imap-repeat/reset
+ local -a KEYS; KEYS=(32)
+ ble/widget/self-insert
+ ble/util/unlocal KEYS
+ ble/widget/insert-last-argument
+ return "$?"
+}
+function ble/widget/vi-command/forward-byte {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local index=$_ble_edit_ind
+ ble/widget/.locate-forward-byte "$ARG" || [[ $FLAG ]] || ble/widget/.bell
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG"
+}
+function ble/widget/vi-command/backward-byte {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local index=$_ble_edit_ind
+ ble/widget/.locate-forward-byte $((-ARG)) || [[ $FLAG ]] || ble/widget/.bell
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG"
+}
+function ble/widget/vi_nmap/capitalize-XWORD { ble/widget/filter-word.impl XWORD ble/string#capitalize; }
+function ble/widget/vi_nmap/downcase-XWORD { ble/widget/filter-word.impl XWORD ble/string#tolower; }
+function ble/widget/vi_nmap/upcase-XWORD { ble/widget/filter-word.impl XWORD ble/string#toupper; }
+function ble/widget/vi_nmap/@edit {
+ ble/keymap:vi/clear-arg
+ ble/keymap:vi/repeat/record
+ ble/keymap:vi/mark/start-edit-area
+ ble/widget/"$@"
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/vi_nmap/@adjust {
+ ble/keymap:vi/clear-arg
+ ble/widget/"$@"
+ ble/keymap:vi/adjust-command-mode
+}
+function ble/widget/vi_nmap/@motion {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local _ble_edit_ind=$_ble_edit_ind _ble_edit_arg=$ARG
+ if ble/widget/"$@"; then
+ local index=$_ble_edit_ind
+ ble/util/unlocal _ble_edit_ind
+ ble/widget/vi-command/exclusive-goto.impl "$index" "$FLAG" "$REG" nobell
+ else
+ ble/keymap:vi/adjust-command-mode
+ fi
+}
+function ble/keymap:vi/xmap/has-eol-extension {
+ [[ $_ble_edit_mark_active == *+ ]]
+}
+function ble/keymap:vi/xmap/add-eol-extension {
+ [[ $_ble_edit_mark_active ]] &&
+ _ble_edit_mark_active=${_ble_edit_mark_active%+}+
+}
+function ble/keymap:vi/xmap/remove-eol-extension {
+ [[ $_ble_edit_mark_active ]] &&
+ _ble_edit_mark_active=${_ble_edit_mark_active%+}
+}
+function ble/keymap:vi/xmap/switch-type {
+ local suffix; [[ $_ble_edit_mark_active == *+ ]] && suffix=+
+ _ble_edit_mark_active=$1$suffix
+}
+function ble/keymap:vi/get-graphical-rectangle {
+ local p=${1:-$_ble_edit_mark} q=${2:-$_ble_edit_ind}
+ local ret
+ ble-edit/content/find-logical-bol "$p"; p0=$ret
+ ble-edit/content/find-logical-bol "$q"; q0=$ret
+ local p0x p0y q0x q0y
+ ble/textmap#getxy.out --prefix=p0 "$p0"
+ ble/textmap#getxy.out --prefix=q0 "$q0"
+ local plx ply qlx qly
+ ble/textmap#getxy.cur --prefix=pl "$p"
+ ble/textmap#getxy.cur --prefix=ql "$q"
+ local prx=$plx pry=$ply qrx=$qlx qry=$qly
+ ble-edit/content/eolp "$p" && ((prx++)) || ble/textmap#getxy.out --prefix=pr $((p+1))
+ ble-edit/content/eolp "$q" && ((qrx++)) || ble/textmap#getxy.out --prefix=qr $((q+1))
+ ((ply-=p0y,qly-=q0y,pry-=p0y,qry-=q0y,
+ (ply<qly||ply==qly&&plx<qlx)?(lx=plx,ly=ply):(lx=qlx,ly=qly),
+ (pry>qry||pry==qry&&prx>qrx)?(rx=prx,ry=pry):(rx=qrx,ry=qry)))
+}
+function ble/keymap:vi/get-logical-rectangle {
+ local p=${1:-$_ble_edit_mark} q=${2:-$_ble_edit_ind}
+ local ret
+ ble-edit/content/find-logical-bol "$p"; p0=$ret
+ ble-edit/content/find-logical-bol "$q"; q0=$ret
+ ((p-=p0,q-=q0,p<=q)) || local p=$q q=$p
+ lx=$p rx=$((q+1)) ly=0 ry=0
+}
+function ble/keymap:vi/get-rectangle {
+ if ble/edit/use-textmap; then
+ ble/keymap:vi/get-graphical-rectangle "$@"
+ else
+ ble/keymap:vi/get-logical-rectangle "$@"
+ fi
+}
+function ble/keymap:vi/get-rectangle-height {
+ local p0 q0 lx ly rx ry
+ ble/keymap:vi/get-rectangle "$@"
+ ble/string#count-char "${_ble_edit_str:p0:q0-p0}" $'\n'
+ ((ret++))
+ return 0
+}
+function ble/keymap:vi/extract-graphical-block-by-geometry {
+ local bol1=$1 bol2=$2 x1=$3 x2=$4 y1=0 y2=0 opts=$5
+ ((bol1<=bol2||(bol1=$2,bol2=$1)))
+ [[ $x1 == *:* ]] && local x1=${x1%%:*} y1=${x1#*:}
+ [[ $x2 == *:* ]] && local x2=${x2%%:*} y2=${x2#*:}
+ local cols=$_ble_textmap_cols
+ local c1=$((cols*y1+x1)) c2=$((cols*y2+x2))
+ sub_x1=$c1 sub_x2=$c2
+ local ret index lx ly rx ly
+ ble-edit/content/find-logical-eol "$bol2"; local eol2=$ret
+ local lines; ble/string#split-lines lines "${_ble_edit_str:bol1:eol2-bol1}"
+ sub_ranges=()
+ local min_sfill=0
+ local line bol=$bol1 eol bolx boly
+ local c1l c1r c2l c2r
+ for line in "${lines[@]}"; do
+ ((eol=bol+${#line}))
+ if [[ :$opts: == *:first_line:* ]] && ((${#sub_ranges[@]})); then
+ ble/array#push sub_ranges :::::
+ elif [[ :$opts: == *:skip_middle:* ]] && ((0<${#sub_ranges[@]}&&${#sub_ranges[@]}<${#lines[@]}-1)); then
+ ble/array#push sub_ranges :::::
+ else
+ ble/textmap#getxy.out --prefix=bol "$bol"
+ ble/textmap#hit out "$x1" $((boly+y1)) "$bol" "$eol"
+ local smin=$index x1l=$lx y1l=$ly x1r=$rx y1r=$ry
+ if ble/keymap:vi/xmap/has-eol-extension; then
+ local eolx eoly; ble/textmap#getxy.out --prefix=eol "$eol"
+ local smax=$eol x2l=$eolx y2l=$eoly x2r=$eolx y2r=$eoly
+ else
+ ble/textmap#hit out "$x2" $((boly+y2)) "$bol" "$eol"
+ local smax=$index x2l=$lx y2l=$ly x2r=$rx y2r=$ry
+ fi
+ local sfill=0 slpad=0 srpad=0
+ local stext=${_ble_edit_str:smin:smax-smin}
+ if ((smin<smax)); then
+ ((c1l=(y1l-boly)*cols+x1l))
+ if ((c1l<c1)); then
+ ((slpad=c1-c1l))
+ ble/util/assert '! ble-edit/content/eolp "$smin"'
+ ((c1r=(y1r-boly)*cols+x1r))
+ ble/util/assert '((c1r>c1))' || ((c1r=c1))
+ ble/string#repeat ' ' $((c1r-c1))
+ stext=$ret${stext:1}
+ fi
+ ((c2l=(y2l-boly)*cols+x2l))
+ if ((c2l<c2)); then
+ if ((smax==eol)); then
+ ((sfill=c2-c2l))
+ else
+ ble/string#repeat ' ' $((c2-c2l))
+ stext=$stext$ret
+ ((smax++))
+ ((c2r=(y2r-boly)*cols+x2r))
+ ble/util/assert '((c2r>c2))' || ((c2r=c2))
+ ((srpad=c2r-c2))
+ fi
+ elif ((c2l>c2)); then
+ ((sfill=c2-c2l,
+ sfill<min_sfill&&(min_sfill=sfill)))
+ fi
+ else
+ if ((smin==eol)); then
+ ((sfill=c2-c1))
+ elif ((c2>c1)); then
+ ble/string#repeat ' ' $((c2-c1))
+ stext=$ret${stext:1}
+ ((smax++))
+ ((c1l=(y1l-boly)*cols+x1l,slpad=c1-c1l))
+ ((c1r=(y1r-boly)*cols+x1r,srpad=c1r-c1))
+ fi
+ fi
+ ble/array#push sub_ranges "$smin:$smax:$slpad:$srpad:$sfill:$stext"
+ fi
+ ((bol=eol+1))
+ done
+ if ((min_sfill<0)); then
+ local isub=${#sub_ranges[@]}
+ while ((isub--)); do
+ local sub=${sub_ranges[isub]}
+ local sub45=${sub#*:*:*:*:}
+ local sfill=${sub45%%:*}
+ sub_ranges[isub]=${sub::${#sub}-${#sub45}}$((sfill-min_sfill))${sub45:${#sfill}}
+ done
+ fi
+}
+function ble/keymap:vi/extract-graphical-block {
+ local opts=$3
+ local p0 q0 lx ly rx ry
+ ble/keymap:vi/get-graphical-rectangle "$@"
+ ble/keymap:vi/extract-graphical-block-by-geometry "$p0" "$q0" "$lx:$ly" "$rx:$ry" "$opts"
+}
+function ble/keymap:vi/extract-logical-block-by-geometry {
+ local bol1=$1 bol2=$2 x1=$3 x2=$4 opts=$5
+ ((bol1<=bol2||(bol1=$2,bol2=$1)))
+ sub_x1=$c1 sub_x2=$c2
+ local ret min_sfill=0
+ local bol=$bol1 eol smin smax slpad srpad sfill
+ sub_ranges=()
+ while :; do
+ ble-edit/content/find-logical-eol "$bol"; eol=$ret
+ slpad=0 srpad=0 sfill=0
+ ((smin=bol+x1,smin>eol&&(smin=eol)))
+ if ble/keymap:vi/xmap/has-eol-extension; then
+ ((smax=eol,
+ sfill=bol+x2-eol,
+ sfill<min_sfill&&(min_sfill=sfill)))
+ else
+ ((smax=bol+x2,smax>eol&&(sfill=smax-eol,smax=eol)))
+ fi
+ local stext=${_ble_edit_str:smin:smax-smin}
+ ble/array#push sub_ranges "$smin:$smax:$slpad:$srpad:$sfill:$stext"
+ ((bol>=bol2)) && break
+ ble-edit/content/find-logical-bol "$bol" 1; bol=$ret
+ done
+ if ((min_sfill<0)); then
+ local isub=${#sub_ranges[@]}
+ while ((isub--)); do
+ local sub=${sub_ranges[isub]}
+ local sub45=${sub#*:*:*:*:}
+ local sfill=${sub45%%:*}
+ sub_ranges[isub]=${sub::${#sub}-${#sub45}}$((sfill-min_sfill))${sub45:${#sfill}}
+ done
+ fi
+}
+function ble/keymap:vi/extract-logical-block {
+ local opts=$3
+ local p0 q0 lx ly rx ry
+ ble/keymap:vi/get-logical-rectangle "$@"
+ ble/keymap:vi/extract-logical-block-by-geometry "$p0" "$q0" "$lx" "$rx" "$opts"
+}
+function ble/keymap:vi/extract-block {
+ if ble/edit/use-textmap; then
+ ble/keymap:vi/extract-graphical-block "$@"
+ else
+ ble/keymap:vi/extract-logical-block "$@"
+ fi
+}
+function ble/highlight/layer:region/mark:vi_char/get-selection {
+ local rmin rmax
+ if ((_ble_edit_mark<_ble_edit_ind)); then
+ rmin=$_ble_edit_mark rmax=$_ble_edit_ind
+ else
+ rmin=$_ble_edit_ind rmax=$_ble_edit_mark
+ fi
+ ble-edit/content/eolp "$rmax" || ((rmax++))
+ selection=("$rmin" "$rmax")
+}
+function ble/highlight/layer:region/mark:vi_line/get-selection {
+ local rmin rmax
+ if ((_ble_edit_mark<_ble_edit_ind)); then
+ rmin=$_ble_edit_mark rmax=$_ble_edit_ind
+ else
+ rmin=$_ble_edit_ind rmax=$_ble_edit_mark
+ fi
+ local ret
+ ble-edit/content/find-logical-bol "$rmin"; rmin=$ret
+ ble-edit/content/find-logical-eol "$rmax"; rmax=$ret
+ selection=("$rmin" "$rmax")
+}
+function ble/highlight/layer:region/mark:vi_block/get-selection {
+ local sub_ranges sub_x1 sub_x2
+ ble/keymap:vi/extract-block
+ selection=()
+ local sub
+ for sub in "${sub_ranges[@]}"; do
+ ble/string#split sub : "$sub"
+ ((sub[0]<sub[1])) || continue
+ ble/array#push selection "${sub[0]}" "${sub[1]}"
+ done
+}
+function ble/highlight/layer:region/mark:vi_char+/get-selection {
+ ble/highlight/layer:region/mark:vi_char/get-selection
+}
+function ble/highlight/layer:region/mark:vi_line+/get-selection {
+ ble/highlight/layer:region/mark:vi_line/get-selection
+}
+function ble/highlight/layer:region/mark:vi_block+/get-selection {
+ ble/highlight/layer:region/mark:vi_block/get-selection
+}
+function ble/highlight/layer:region/mark:vi_char/get-face { [[ $_ble_edit_overwrite_mode ]] && face=region_target; }
+function ble/highlight/layer:region/mark:vi_char+/get-face { ble/highlight/layer:region/mark:vi_char/get-face; }
+function ble/highlight/layer:region/mark:vi_line/get-face { ble/highlight/layer:region/mark:vi_char/get-face; }
+function ble/highlight/layer:region/mark:vi_line+/get-face { ble/highlight/layer:region/mark:vi_char/get-face; }
+function ble/highlight/layer:region/mark:vi_block/get-face { ble/highlight/layer:region/mark:vi_char/get-face; }
+function ble/highlight/layer:region/mark:vi_block+/get-face { ble/highlight/layer:region/mark:vi_char/get-face; }
+_ble_keymap_vi_xmap_prev_edit=vi_char:1:1
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_xmap_prev_edit
+function ble/widget/vi_xmap/.save-visual-state {
+ local nline nchar mark_type=${_ble_edit_mark_active%+}
+ if [[ $mark_type == vi_block ]]; then
+ local p0 q0 lx rx ly ry
+ if ble/edit/use-textmap; then
+ local cols=$_ble_textmap_cols
+ ble/keymap:vi/get-graphical-rectangle
+ ((lx+=ly*cols,rx+=ry*cols))
+ else
+ ble/keymap:vi/get-logical-rectangle
+ fi
+ nchar=$((rx-lx))
+ local ret
+ ((p0<=q0)) || local p0=$q0 q0=$p0
+ ble/string#count-char "${_ble_edit_str:p0:q0-p0}" $'\n'
+ nline=$((ret+1))
+ else
+ local ret
+ local p=$_ble_edit_mark q=$_ble_edit_ind
+ ((p<=q)) || local p=$q q=$p
+ ble/string#count-char "${_ble_edit_str:p:q-p}" $'\n'
+ nline=$((ret+1))
+ local base
+ if ((nline==1)) && [[ $mark_type != vi_line ]]; then
+ base=$p
+ else
+ ble-edit/content/find-logical-bol "$q"; base=$ret
+ fi
+ if ble/edit/use-textmap; then
+ local cols=$_ble_textmap_cols
+ local bx by x y
+ ble/textmap#getxy.cur --prefix=b "$base"
+ ble/textmap#getxy.cur "$q"
+ nchar=$((x-bx+(y-by)*cols+1))
+ else
+ nchar=$((q-base+1))
+ fi
+ fi
+ _ble_keymap_vi_xmap_prev_edit=$_ble_edit_mark_active:$nchar:$nline
+}
+function ble/widget/vi_xmap/.restore-visual-state {
+ local arg=$1; ((arg>0)) || arg=1
+ local prev; ble/string#split prev : "$_ble_keymap_vi_xmap_prev_edit"
+ _ble_edit_mark_active=${prev[0]:-vi_char}
+ local nchar=${prev[1]:-1}
+ local nline=${prev[2]:-1}
+ ((nchar<1&&(nchar=1),nline<1&&(nline=1)))
+ local is_x_relative=0
+ if [[ ${_ble_edit_mark_active%+} == vi_block ]]; then
+ ((is_x_relative=1,nchar*=arg,nline*=arg))
+ elif [[ ${_ble_edit_mark_active%+} == vi_line ]]; then
+ ((nline*=arg,is_x_relative=1,nchar=1))
+ else
+ ((nline==1?(is_x_relative=1,nchar*=arg):(nline*=arg)))
+ fi
+ ((nchar--,nline--))
+ local index ret
+ ble-edit/content/find-logical-bol "$_ble_edit_ind" 0; local b1=$ret
+ ble-edit/content/find-logical-bol "$_ble_edit_ind" "$nline"; local b2=$ret
+ ble-edit/content/find-logical-eol "$b2"; local e2=$ret
+ if ble/keymap:vi/xmap/has-eol-extension; then
+ index=$e2
+ elif ble/edit/use-textmap; then
+ local cols=$_ble_textmap_cols
+ local b1x b1y b2x b2y x y
+ ble/textmap#getxy.out --prefix=b1 "$b1"
+ ble/textmap#getxy.out --prefix=b2 "$b2"
+ if ((is_x_relative)); then
+ ble/textmap#getxy.out "$_ble_edit_ind"
+ local c=$((x+(y-b1y)*cols+nchar))
+ else
+ local c=$nchar
+ fi
+ ((y=c/cols,x=c%cols))
+ local lx ly rx ry
+ ble/textmap#hit out "$x" $((b2y+y)) "$b2" "$e2"
+ else
+ local c=$((is_x_relative?_ble_edit_ind-b1+nchar:nchar))
+ ((index=b2+c,index>e2&&(index=e2)))
+ fi
+ _ble_edit_mark=$_ble_edit_ind
+ _ble_edit_ind=$index
+}
+_ble_keymap_vi_xmap_prev_visual=
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_xmap_prev_visual
+function ble/keymap:vi/xmap/set-previous-visual-area {
+ local beg end
+ local mark_type=${_ble_edit_mark_active%+}
+ if [[ $mark_type == vi_block ]]; then
+ local sub_ranges sub_x1 sub_x2
+ ble/keymap:vi/extract-block
+ local nrange=${#sub_ranges[*]}
+ ((nrange)) || return 1
+ local beg=${sub_ranges[0]%%:*}
+ local sub2_slice1=${sub_ranges[nrange-1]#*:}
+ local end=${sub2_slice1%%:*}
+ ((beg<end)) && ! ble-edit/content/bolp "$end" && ((end--))
+ else
+ local beg=$_ble_edit_mark end=$_ble_edit_ind
+ ((beg<=end)) || local beg=$end end=$beg
+ if [[ $mark_type == vi_line ]]; then
+ local ret
+ ble-edit/content/find-logical-bol "$beg"; beg=$ret
+ ble-edit/content/find-logical-eol "$end"; end=$ret
+ ble-edit/content/bolp "$end" || ((end--))
+ fi
+ fi
+ _ble_keymap_vi_xmap_prev_visual=$_ble_edit_mark_active
+ ble/keymap:vi/mark/set-local-mark 60 "$beg" # `<
+ ble/keymap:vi/mark/set-local-mark 62 "$end" # `>
+}
+function ble/widget/vi-command/previous-visual-area {
+ local mark=$_ble_keymap_vi_xmap_prev_visual
+ local ret beg= end=
+ ble/keymap:vi/mark/get-local-mark 60 && beg=$ret # `<
+ ble/keymap:vi/mark/get-local-mark 62 && end=$ret # `>
+ [[ $beg && $end ]] || return 1
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ ble/keymap:vi/clear-arg
+ ble/keymap:vi/xmap/set-previous-visual-area
+ _ble_edit_ind=$end
+ _ble_edit_mark=$beg
+ _ble_edit_mark_active=$mark
+ ble/keymap:vi/update-mode-name
+ else
+ ble/keymap:vi/clear-arg
+ ble/widget/vi-command/visual-mode.impl vi_xmap "$mark"
+ _ble_edit_ind=$end
+ _ble_edit_mark=$beg
+ fi
+ return 0
+}
+function ble/widget/vi-command/visual-mode.impl {
+ local keymap=$1 visual_type=$2
+ local ARG FLAG REG; ble/keymap:vi/get-arg 0
+ if [[ $FLAG ]]; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ _ble_edit_overwrite_mode=
+ _ble_edit_mark=$_ble_edit_ind
+ _ble_edit_mark_active=$visual_type
+ _ble_keymap_vi_xmap_insert_data= # ※矩形挿入の途中で更に xmap に入ったときはキャンセル
+ ((ARG)) && ble/widget/vi_xmap/.restore-visual-state "$ARG"
+ ble/decode/keymap/push "$keymap"
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+function ble/widget/vi_nmap/charwise-visual-mode {
+ ble/widget/vi-command/visual-mode.impl vi_xmap vi_char
+}
+function ble/widget/vi_nmap/linewise-visual-mode {
+ ble/widget/vi-command/visual-mode.impl vi_xmap vi_line
+}
+function ble/widget/vi_nmap/blockwise-visual-mode {
+ ble/widget/vi-command/visual-mode.impl vi_xmap vi_block
+}
+function ble/widget/vi_nmap/charwise-select-mode {
+ ble/widget/vi-command/visual-mode.impl vi_smap vi_char
+}
+function ble/widget/vi_nmap/linewise-select-mode {
+ ble/widget/vi-command/visual-mode.impl vi_smap vi_line
+}
+function ble/widget/vi_nmap/blockwise-select-mode {
+ ble/widget/vi-command/visual-mode.impl vi_smap vi_block
+}
+function ble/widget/vi_xmap/exit {
+ if [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ ble/keymap:vi/xmap/set-previous-visual-area
+ _ble_edit_mark_active=
+ ble/decode/keymap/pop
+ ble/keymap:vi/update-mode-name
+ ble/keymap:vi/adjust-command-mode
+ fi
+ return 0
+}
+function ble/widget/vi_xmap/cancel {
+ _ble_keymap_vi_single_command=
+ _ble_keymap_vi_single_command_overwrite=
+ ble-edit/content/nonbol-eolp && ((_ble_edit_ind--))
+ ble/widget/vi_xmap/exit
+}
+function ble/widget/vi_xmap/switch-visual-mode.impl {
+ local visual_type=$1
+ local ARG FLAG REG; ble/keymap:vi/get-arg 0
+ if [[ $FLAG ]]; then
+ ble/widget/.bell
+ return 1
+ fi
+ if [[ ${_ble_edit_mark_active%+} == "$visual_type" ]]; then
+ ble/widget/vi_xmap/cancel
+ else
+ ble/keymap:vi/xmap/switch-type "$visual_type"
+ ble/keymap:vi/update-mode-name
+ return 0
+ fi
+}
+function ble/widget/vi_xmap/switch-to-charwise {
+ ble/widget/vi_xmap/switch-visual-mode.impl vi_char
+}
+function ble/widget/vi_xmap/switch-to-linewise {
+ ble/widget/vi_xmap/switch-visual-mode.impl vi_line
+}
+function ble/widget/vi_xmap/switch-to-blockwise {
+ ble/widget/vi_xmap/switch-visual-mode.impl vi_block
+}
+function ble/widget/vi_xmap/switch-to-select {
+ if [[ $_ble_decode_keymap == vi_xmap ]]; then
+ ble/decode/keymap/pop
+ ble/decode/keymap/push vi_smap
+ ble/keymap:vi/update-mode-name
+ fi
+}
+function ble/widget/vi_xmap/switch-to-visual {
+ if [[ $_ble_decode_keymap == vi_smap ]]; then
+ ble/decode/keymap/pop
+ ble/decode/keymap/push vi_xmap
+ ble/keymap:vi/update-mode-name
+ fi
+}
+function ble/widget/vi_xmap/switch-to-visual-blockwise {
+ if [[ $_ble_decode_keymap == vi_smap ]]; then
+ ble/decode/keymap/pop
+ ble/decode/keymap/push vi_xmap
+ fi
+ if [[ ${_ble_edit_mark_active%+} != vi_block ]]; then
+ ble/widget/vi_xmap/switch-to-blockwise
+ else
+ xble/keymap:vi/update-mode-name
+ fi
+}
+bleopt/declare -v keymap_vi_keymodel ''
+function ble/widget/vi_smap/@nomarked {
+ [[ ,$bleopt_keymap_vi_keymodel, == *,stopsel,* ]] &&
+ ble/widget/vi_xmap/exit
+ ble/widget/"$@"
+}
+function ble/widget/vi_smap/self-insert {
+ ble/widget/vi-command/operator c
+ ble/widget/self-insert
+}
+function ble/widget/vi_xmap/exchange-points {
+ ble/keymap:vi/xmap/remove-eol-extension
+ ble/widget/exchange-point-and-mark
+ return 0
+}
+function ble/widget/vi_xmap/exchange-boundaries {
+ if [[ ${_ble_edit_mark_active%+} == vi_block ]]; then
+ ble/keymap:vi/xmap/remove-eol-extension
+ local sub_ranges sub_x1 sub_x2
+ ble/keymap:vi/extract-block '' '' skip_middle
+ local nline=${#sub_ranges[@]}
+ ble/util/assert '((nline))'
+ local data1; ble/string#split data1 : "${sub_ranges[0]}"
+ local lpos1=${data1[0]} rpos1=$((data1[4]?data1[1]:data1[1]-1))
+ if ((nline==1)); then
+ local lpos2=$lpos1 rpos2=$rpos1
+ else
+ local data2; ble/string#split data2 : "${sub_ranges[nline-1]}"
+ local lpos2=${data2[0]} rpos2=$((data2[4]?data2[1]:data2[1]-1))
+ fi
+ if ! ((lpos2<=_ble_edit_ind&&_ble_edit_ind<=rpos2)); then
+ local lpos1=$lpos2 lpos2=$lpos1
+ local rpos1=$rpos2 rpos2=$rpos1
+ fi
+ _ble_edit_mark=$((_ble_edit_mark==lpos1?rpos1:lpos1))
+ _ble_edit_ind=$((_ble_edit_ind==lpos2?rpos2:lpos2))
+ return 0
+ else
+ ble/widget/vi_xmap/exchange-points
+ fi
+}
+function ble/widget/vi_xmap/visual-replace-char.hook {
+ local key=$1
+ _ble_edit_overwrite_mode=
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local ret
+ if [[ $FLAG ]]; then
+ ble/widget/.bell
+ return 1
+ elif ((key==(_ble_decode_Ctrl|91))); then # C-[ -> cancel
+ return 27
+ elif ! ble/keymap:vi/k2c "$key"; then
+ ble/widget/.bell
+ return 1
+ fi
+ local c=$ret
+ ble/util/c2s "$c"; local s=$ret
+ local old_mark_active=$_ble_edit_mark_active # save
+ local mark_type=${_ble_edit_mark_active%+}
+ ble/widget/vi_xmap/.save-visual-state
+ ble/widget/vi_xmap/exit # Note: _ble_edit_mark_active will be cleared here
+ if [[ $mark_type == vi_block ]]; then
+ ble/util/c2w "$c"; local w=$ret
+ ((w<=0)) && w=1
+ local sub_ranges sub_x1 sub_x2
+ _ble_edit_mark_active=$old_mark_active ble/keymap:vi/extract-block
+ local n=${#sub_ranges[@]}
+ if ((n==0)); then
+ ble/widget/.bell
+ return 1
+ fi
+ local width=$((sub_x2-sub_x1))
+ local count=$((width/w))
+ ble/string#repeat "$s" "$count"; local ins=$ret
+ local pad=$((width-count*w))
+ if ((pad)); then
+ ble/string#repeat ' ' "$pad"; ins=$ins$ret
+ fi
+ local i=$n sub smin=0
+ ble/keymap:vi/mark/start-edit-area
+ while ((i--)); do
+ ble/string#split sub : "${sub_ranges[i]}"
+ local smin=${sub[0]} smax=${sub[1]}
+ local slpad=${sub[2]} srpad=${sub[3]} sfill=${sub[4]}
+ local ins1=$ins
+ ((sfill)) && ins1=${ins1::(width-sfill)/w}
+ ((slpad)) && { ble/string#repeat ' ' "$slpad"; ins1=$ret$ins1; }
+ ((srpad)) && { ble/string#repeat ' ' "$srpad"; ins1=$ins1$ret; }
+ ble/widget/.replace-range "$smin" "$smax" "$ins1"
+ done
+ local beg=$smin
+ ble/keymap:vi/needs-eol-fix "$beg" && ((beg--))
+ _ble_edit_ind=$beg
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/repeat/record
+ else
+ local beg=$_ble_edit_mark end=$_ble_edit_ind
+ ((beg<=end)) || local beg=$end end=$beg
+ if [[ $mark_type == vi_line ]]; then
+ ble-edit/content/find-logical-bol "$beg"; local beg=$ret
+ ble-edit/content/find-logical-eol "$end"; local end=$ret
+ else
+ ble-edit/content/eolp "$end" || ((end++))
+ fi
+ local ins=${_ble_edit_str:beg:end-beg}
+ ins=${ins//[!$'\n']/"$s"}
+ ble/widget/.replace-range "$beg" "$end" "$ins"
+ ble/keymap:vi/needs-eol-fix "$beg" && ((beg--))
+ _ble_edit_ind=$beg
+ ble/keymap:vi/mark/set-previous-edit-area "$beg" "$end"
+ ble/keymap:vi/repeat/record
+ fi
+ return 0
+}
+function ble/widget/vi_xmap/visual-replace-char {
+ _ble_edit_overwrite_mode=R
+ ble/keymap:vi/async-read-char ble/widget/vi_xmap/visual-replace-char.hook
+}
+function ble/widget/vi_xmap/linewise-operator.impl {
+ local op=$1 opts=$2
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ if [[ $FLAG ]]; then
+ ble/widget/.bell 'wrong keymap: xmap ではオペレータは設定されないはず'
+ return 1
+ fi
+ local mark_type=${_ble_edit_mark_active%+}
+ local beg=$_ble_edit_mark end=$_ble_edit_ind
+ ((beg<=end)) || local beg=$end end=$beg
+ local call_operator=
+ if [[ :$opts: != *:force_line:* && $mark_type == vi_block ]]; then
+ call_operator=ble/keymap:vi/call-operator-blockwise
+ _ble_edit_mark_active=vi_block
+ [[ :$opts: == *:extend:* ]] && _ble_edit_mark_active=vi_block+
+ else
+ call_operator=ble/keymap:vi/call-operator-linewise
+ _ble_edit_mark_active=vi_line
+ fi
+ local ble_keymap_vi_mark_active=$_ble_edit_mark_active
+ ble/widget/vi_xmap/.save-visual-state
+ ble/widget/vi_xmap/exit
+ "$call_operator" "$op" "$beg" "$end" "$ARG" "$REG"; local ext=$?
+ ((ext==147)) && return 147
+ ((ext)) && ble/widget/.bell
+ ble/keymap:vi/adjust-command-mode
+ return "$ext"
+}
+function ble/widget/vi_xmap/replace-block-lines { ble/widget/vi_xmap/linewise-operator.impl c extend; }
+function ble/widget/vi_xmap/delete-block-lines { ble/widget/vi_xmap/linewise-operator.impl d extend; }
+function ble/widget/vi_xmap/delete-lines { ble/widget/vi_xmap/linewise-operator.impl d force_line; }
+function ble/widget/vi_xmap/copy-block-or-lines { ble/widget/vi_xmap/linewise-operator.impl y; }
+function ble/widget/vi_xmap/connect-line.impl {
+ local name=$1
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1 # ignored
+ local beg=$_ble_edit_mark end=$_ble_edit_ind
+ ((beg<=end)) || local beg=$end end=$beg
+ local ret; ble/string#count-char "${_ble_edit_str:beg:end-beg}" $'\n'; local nline=$((ret+1))
+ ble/widget/vi_xmap/.save-visual-state
+ ble/widget/vi_xmap/exit # Note: _ble_edit_mark_active will be cleared here
+ _ble_edit_ind=$beg
+ _ble_edit_arg=$nline
+ _ble_keymap_vi_oparg=
+ _ble_keymap_vi_opfunc=
+ _ble_keymap_vi_reg=
+ "ble/widget/$name"
+}
+function ble/widget/vi_xmap/connect-line-with-space {
+ ble/widget/vi_xmap/connect-line.impl vi_nmap/connect-line-with-space
+}
+function ble/widget/vi_xmap/connect-line {
+ ble/widget/vi_xmap/connect-line.impl vi_nmap/connect-line
+}
+_ble_keymap_vi_xmap_insert_data=
+_ble_keymap_vi_xmap_insert_dbeg=-1
+ble/array#push _ble_textarea_local_VARNAMES \
+ _ble_keymap_vi_xmap_insert_data \
+ _ble_keymap_vi_xmap_insert_dbeg
+function ble/keymap:vi/xmap/update-dirty-range {
+ [[ $_ble_keymap_vi_insert_leave == ble/widget/vi_xmap/block-insert-mode.onleave ]] &&
+ ((_ble_keymap_vi_xmap_insert_dbeg<0||beg<_ble_keymap_vi_xmap_insert_dbeg)) &&
+ _ble_keymap_vi_xmap_insert_dbeg=$beg
+}
+function ble/widget/vi_xmap/block-insert-mode.impl {
+ local type=$1
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local nline=${#sub_ranges[@]}
+ ble/util/assert '((nline))'
+ local index ins_x
+ if [[ $type == append ]]; then
+ local sub=${sub_ranges[0]#*:}
+ local smax=${sub%%:*}
+ index=$smax
+ if ble/keymap:vi/xmap/has-eol-extension; then
+ ins_x='$'
+ else
+ ins_x=$sub_x2
+ fi
+ else
+ local sub=${sub_ranges[0]}
+ local smin=${sub%%:*}
+ index=$smin
+ ins_x=$sub_x1
+ fi
+ ble/widget/vi_xmap/cancel
+ _ble_edit_ind=$index
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ ble/keymap:vi/mark/set-local-mark 1 "$_ble_edit_ind"
+ _ble_keymap_vi_xmap_insert_dbeg=-1
+ local ret display_width
+ ble/string#count-char "${_ble_edit_str::_ble_edit_ind}" $'\n'; local iline=$ret
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-logical-eol; local eol=$ret
+ if ble/edit/use-textmap; then
+ local bx by ex ey
+ ble/textmap#getxy.out --prefix=b "$bol"
+ ble/textmap#getxy.out --prefix=e "$eol"
+ ((display_width=ex+_ble_textmap_cols*(ey-by)))
+ else
+ ((display_width=eol-bol))
+ fi
+ _ble_keymap_vi_xmap_insert_data=$iline:$ins_x:$display_width:$nline
+ _ble_keymap_vi_insert_leave=ble/widget/vi_xmap/block-insert-mode.onleave
+ return 0
+}
+function ble/widget/vi_xmap/block-insert-mode.onleave {
+ local data=$_ble_keymap_vi_xmap_insert_data
+ [[ $data ]] || continue
+ _ble_keymap_vi_xmap_insert_data=
+ ble/string#split data : "$data"
+ local ret
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble/string#count-char "${_ble_edit_str::bol}" $'\n'; ((ret==data[0])) || return 1 # 行番号
+ ble/keymap:vi/mark/get-local-mark 1 || return 1; local mark=$ret # `[
+ ble-edit/content/find-logical-bol "$mark"; ((bol==ret)) || return 1 # 記録行 `[ と同じか
+ local has_textmap=
+ if ble/edit/use-textmap; then
+ local cols=$_ble_textmap_cols
+ has_textmap=1
+ fi
+ local new_width delta
+ ble-edit/content/find-logical-eol; local eol=$ret
+ if [[ $has_textmap ]]; then
+ local bx by ex ey
+ ble/textmap#getxy.out --prefix=b "$bol"
+ ble/textmap#getxy.out --prefix=e "$eol"
+ ((new_width=ex+cols*(ey-by)))
+ else
+ ((new_width=eol-bol))
+ fi
+ ((delta=new_width-data[2]))
+ ((delta>0)) || return 1 # 縮んだ場合は処理しない
+ local x1=${data[1]}
+ [[ $x1 == '$' ]] && ((x1=data[2]))
+ ((x1>new_width&&(x1=new_width)))
+ if ((bol<=_ble_keymap_vi_xmap_insert_dbeg&&_ble_keymap_vi_xmap_insert_dbeg<=eol)); then
+ local px py
+ if [[ $has_textmap ]]; then
+ ble/textmap#getxy.out --prefix=p "$_ble_keymap_vi_xmap_insert_dbeg"
+ ((px+=cols*(py-by)))
+ else
+ ((px=_ble_keymap_vi_xmap_insert_dbeg-bol))
+ fi
+ ((px>x1&&(x1=px)))
+ fi
+ local x2=$((x1+delta))
+ local ins= p1 p2
+ if [[ $has_textmap ]]; then
+ local index lx ly rx ry
+ ble/textmap#hit out $((x1%cols)) $((by+x1/cols)) "$bol" "$eol"; p1=$index
+ ble/textmap#hit out $((x2%cols)) $((by+x2/cols)) "$bol" "$eol"; p2=$index
+ ((lx+=(ly-by)*cols,rx+=(ry-by)*cols,lx!=rx&&p2++))
+ else
+ ((p1=bol+x1,p2=bol+x2))
+ fi
+ ins=${_ble_edit_str:p1:p2-p1}
+ local -a ins_beg=() ins_text=()
+ local iline=1 nline=${data[3]} strlen=${#_ble_edit_str}
+ for ((iline=1;iline<nline;iline++)); do
+ local index= lpad=
+ if ((eol<strlen)); then
+ bol=$((eol+1))
+ ble-edit/content/find-logical-eol "$bol"; eol=$ret
+ else
+ bol=$eol lpad=$'\n'
+ fi
+ if [[ ${data[1]} == '$' ]]; then
+ index=$eol
+ elif [[ $has_textmap ]]; then
+ ble/textmap#getxy.out --prefix=b "$bol"
+ ble/textmap#hit out $((x1%cols)) $((by+x1/cols)) "$bol" "$eol" # -> index
+ local nfill
+ if ((index==eol&&(nfill=x1-lx+(ly-by)*cols)>0)); then
+ ble/string#repeat ' ' "$nfill"; lpad=$lpad$ret
+ fi
+ else
+ index=$((bol+x1))
+ if ((index>eol)); then
+ ble/string#repeat ' ' $((index-eol)); lpad=$lpad$ret
+ ((index=eol))
+ fi
+ fi
+ ble/array#push ins_beg "$index"
+ ble/array#push ins_text "$lpad$ins"
+ done
+ local i=${#ins_beg[@]}
+ ble/keymap:vi/mark/start-edit-area
+ ble/keymap:vi/mark/commit-edit-area "$p1" "$p2"
+ while ((i--)); do
+ local index=${ins_beg[i]} text=${ins_text[i]}
+ ble/widget/.replace-range "$index" "$index" "$text"
+ done
+ ble/keymap:vi/mark/end-edit-area
+ local index
+ if ble/keymap:vi/mark/get-local-mark 60 && index=$ret; then
+ ble/widget/vi-command/goto-mark.impl "$index"
+ else
+ ble-edit/content/find-logical-bol; index=$ret
+ fi
+ ble-edit/content/eolp || ((index++))
+ _ble_edit_ind=$index
+ return 0
+}
+function ble/widget/vi_xmap/insert-mode {
+ local mark_type=${_ble_edit_mark_active%+}
+ if [[ $mark_type == vi_block ]]; then
+ local sub_ranges sub_x1 sub_x2
+ ble/keymap:vi/extract-block '' '' first_line
+ ble/widget/vi_xmap/block-insert-mode.impl insert
+ else
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local beg=$_ble_edit_mark end=$_ble_edit_ind
+ ((beg<=end)) || local beg=$end end=$beg
+ if [[ $mark_type == vi_line ]]; then
+ local ret
+ ble-edit/content/find-logical-bol "$beg"; beg=$ret
+ fi
+ ble/widget/vi_xmap/cancel
+ _ble_edit_ind=$beg
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+ fi
+}
+function ble/widget/vi_xmap/append-mode {
+ local mark_type=${_ble_edit_mark_active%+}
+ if [[ $mark_type == vi_block ]]; then
+ local sub_ranges sub_x1 sub_x2
+ ble/keymap:vi/extract-block '' '' first_line
+ ble/widget/vi_xmap/block-insert-mode.impl append
+ else
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local beg=$_ble_edit_mark end=$_ble_edit_ind
+ ((beg<=end)) || local beg=$end end=$beg
+ if [[ $mark_type == vi_line ]]; then
+ if ((_ble_edit_mark>_ble_edit_ind)); then
+ local ret
+ ble-edit/content/find-logical-bol "$end"; end=$ret
+ fi
+ fi
+ ble-edit/content/eolp "$end" || ((end++))
+ ble/widget/vi_xmap/cancel
+ _ble_edit_ind=$end
+ ble/widget/vi_nmap/.insert-mode "$ARG"
+ ble/keymap:vi/repeat/record
+ return 0
+ fi
+}
+function ble/widget/vi_xmap/paste.impl {
+ local opts=$1
+ [[ :$opts: != *:after:* ]]; local is_after=$?
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ [[ $REG ]] && ble/keymap:vi/register#load "$REG"
+ local mark_type=${_ble_edit_mark_active%+}
+ local kill_ring=$_ble_edit_kill_ring
+ local kill_type=$_ble_edit_kill_type
+ local adjustment=
+ if [[ $mark_type == vi_block ]]; then
+ if [[ $kill_type == L ]]; then
+ if ((is_after)); then
+ local ret; ble/keymap:vi/get-rectangle-height; local nline=$ret
+ adjustment=lastline:$nline
+ fi
+ elif [[ $kill_type == B:* ]]; then
+ is_after=0
+ else
+ is_after=0
+ if [[ $kill_ring != *$'\n'* ]]; then
+ ((${#kill_ring}>=2)) && adjustment=index:$((${#kill_ring}*ARG-1))
+ local ret; ble/keymap:vi/get-rectangle-height; local nline=$ret
+ ble/string#repeat "$kill_ring"$'\n' "$nline"; kill_ring=${ret%$'\n'}
+ ble/string#repeat '0 ' "$nline"; kill_type=B:${ret% }
+ fi
+ fi
+ elif [[ $mark_type == vi_line ]]; then
+ if [[ $kill_type == L ]]; then
+ is_after=0
+ elif [[ $kill_type == B:* ]]; then
+ is_after=0 kill_type=L kill_ring=$kill_ring$'\n'
+ else
+ is_after=0 kill_type=L
+ [[ $kill_ring == *$'\n' ]] && kill_ring=$kill_ring$'\n'
+ fi
+ else
+ is_after=0
+ [[ $kill_type == L ]] && adjustment=newline
+ fi
+ ble/keymap:vi/mark/start-edit-area
+ local _ble_keymap_vi_mark_suppress_edit=1
+ {
+ ble/widget/vi-command/operator d; local ext=$? # _ble_edit_kill_{ring,type} is set here
+ if [[ $adjustment == newline ]]; then
+ local -a KEYS=(10)
+ ble/widget/self-insert
+ elif [[ $adjustment == lastline:* ]]; then
+ local ret
+ ble-edit/content/find-logical-bol "$_ble_edit_ind" $((${adjustment#*:}-1))
+ _ble_edit_ind=$ret
+ fi
+ local _ble_edit_kill_ring=$kill_ring
+ local _ble_edit_kill_type=$kill_type
+ ble/widget/vi_nmap/paste.impl "$ARG" '' "$is_after"
+ if [[ $adjustment == index:* ]]; then
+ local index=$((_ble_edit_ind+${adjustment#*:}))
+ ((index>${#_ble_edit_str}&&(index=${#_ble_edit_str})))
+ ble/keymap:vi/needs-eol-fix "$index" && ((index--))
+ _ble_edit_ind=$index
+ fi
+ }
+ ble/util/unlocal _ble_keymap_vi_mark_suppress_edit
+ ble/keymap:vi/mark/end-edit-area
+ ble/keymap:vi/repeat/record
+ return "$ext"
+}
+function ble/widget/vi_xmap/paste-after {
+ ble/widget/vi_xmap/paste.impl after
+}
+function ble/widget/vi_xmap/paste-before {
+ ble/widget/vi_xmap/paste.impl before
+}
+function ble/widget/vi_xmap/increment.impl {
+ local opts=$1
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ if [[ $FLAG ]]; then
+ ble/widget/.bell
+ return 1
+ fi
+ local delta=$ARG
+ [[ :$opts: == *:decrease:* ]] && ((delta=-delta))
+ local progress=0
+ [[ :$opts: == *:progressive:* ]] && progress=$delta
+ local old_mark_active=$_ble_edit_mark_active # save
+ local mark_type=${_ble_edit_mark_active%+}
+ ble/widget/vi_xmap/.save-visual-state
+ ble/widget/vi_xmap/exit # Note: _ble_edit_mark_active will be cleared here
+ if [[ $mark_type == vi_block ]]; then
+ local sub_ranges sub_x1 sub_x2
+ _ble_edit_mark_active=$old_mark_active ble/keymap:vi/extract-block
+ if ((${#sub_ranges[@]}==0)); then
+ ble/widget/.bell
+ return 1
+ fi
+ else
+ local beg=$_ble_edit_mark end=$_ble_edit_ind
+ ((beg<=end)) || local beg=$end end=$beg
+ if [[ $mark_type == vi_line ]]; then
+ local ret
+ ble-edit/content/find-logical-bol "$beg"; local beg=$ret
+ ble-edit/content/find-logical-eol "$end"; local end=$ret
+ else
+ ble-edit/content/eolp "$end" || ((end++))
+ fi
+ local -a lines
+ ble/string#split-lines lines "${_ble_edit_str:beg:end-beg}"
+ local line index=$beg
+ local -a sub_ranges
+ for line in "${lines[@]}"; do
+ [[ $line ]] && ble/array#push sub_ranges "$index:::::$line"
+ ((index+=${#line}+1))
+ done
+ ((${#sub_ranges[@]})) || return 0
+ fi
+ local sub rex_number='^([^0-9]*)([0-9]+)' shift=0 dmin=-1 dmax=-1
+ for sub in "${sub_ranges[@]}"; do
+ local stext=${sub#*:*:*:*:*:}
+ [[ $stext =~ $rex_number ]] || continue
+ local rematch1=${BASH_REMATCH[1]}
+ local rematch2=${BASH_REMATCH[2]}
+ local offset=${#rematch1} length=${#rematch2}
+ local number=$((10#0$rematch2))
+ [[ $rematch1 == *- ]] && ((number=-number,offset--,length++))
+ ((number+=delta,delta+=progress))
+ if [[ $rematch2 == 0?* ]]; then
+ local wsign=$((number<0?1:0))
+ local zpad=$((wsign+${#rematch2}-${#number}))
+ if ((zpad>0)); then
+ local ret; ble/string#repeat 0 "$zpad"
+ number=${number::wsign}$ret${number:wsign}
+ fi
+ fi
+ local smin=${sub%%:*}
+ local beg=$((shift+smin+offset))
+ local end=$((beg+length))
+ ble/widget/.replace-range "$beg" "$end" "$number"
+ ((shift+=${#number}-length,
+ dmin<0&&(dmin=beg),
+ dmax=beg+${#number}))
+ done
+ local beg=${sub_ranges[0]%%:*}
+ ble/keymap:vi/needs-eol-fix "$beg" && ((beg--))
+ _ble_edit_ind=$beg
+ ((dmin>=0)) && ble/keymap:vi/mark/set-previous-edit-area "$dmin" "$dmax"
+ ble/keymap:vi/repeat/record
+ return 0
+}
+function ble/widget/vi_xmap/increment { ble/widget/vi_xmap/increment.impl increase; }
+function ble/widget/vi_xmap/decrement { ble/widget/vi_xmap/increment.impl decrease; }
+function ble/widget/vi_xmap/progressive-increment { ble/widget/vi_xmap/increment.impl progressive:increase; }
+function ble/widget/vi_xmap/progressive-decrement { ble/widget/vi_xmap/increment.impl progressive:decrease; }
+function ble-decode/keymap:vi_xmap/define {
+ ble/keymap:vi/set-up-command-map
+ ble-bind -f __default__ vi-command/decompose-meta
+ ble-bind -f 'ESC' vi_xmap/exit
+ ble-bind -f 'C-[' vi_xmap/exit
+ ble-bind -f 'C-c' vi_xmap/cancel
+ ble-bind -f '"' vi-command/register
+ ble-bind -f a vi-command/text-object
+ ble-bind -f i vi-command/text-object
+ ble-bind -f 'C-\ C-n' vi_xmap/cancel
+ ble-bind -f 'C-\ C-g' vi_xmap/cancel
+ ble-bind -f v vi_xmap/switch-to-charwise
+ ble-bind -f V vi_xmap/switch-to-linewise
+ ble-bind -f C-v vi_xmap/switch-to-blockwise
+ ble-bind -f C-q vi_xmap/switch-to-blockwise
+ ble-bind -f 'g v' vi-command/previous-visual-area
+ ble-bind -f C-g vi_xmap/switch-to-select
+ ble-bind -f o vi_xmap/exchange-points
+ ble-bind -f O vi_xmap/exchange-boundaries
+ ble-bind -f '~' 'vi-command/operator toggle_case'
+ ble-bind -f 'u' 'vi-command/operator u'
+ ble-bind -f 'U' 'vi-command/operator U'
+ ble-bind -f 's' 'vi-command/operator c'
+ ble-bind -f 'x' 'vi-command/operator d'
+ ble-bind -f delete 'vi-command/operator d'
+ ble-bind -f r vi_xmap/visual-replace-char
+ ble-bind -f C vi_xmap/replace-block-lines
+ ble-bind -f D vi_xmap/delete-block-lines
+ ble-bind -f X vi_xmap/delete-block-lines
+ ble-bind -f S vi_xmap/delete-lines
+ ble-bind -f R vi_xmap/delete-lines
+ ble-bind -f Y vi_xmap/copy-block-or-lines
+ ble-bind -f J vi_xmap/connect-line-with-space
+ ble-bind -f 'g J' vi_xmap/connect-line
+ ble-bind -f I vi_xmap/insert-mode
+ ble-bind -f A vi_xmap/append-mode
+ ble-bind -f p vi_xmap/paste-after
+ ble-bind -f P vi_xmap/paste-before
+ ble-bind -f 'C-a' vi_xmap/increment
+ ble-bind -f 'C-x' vi_xmap/decrement
+ ble-bind -f 'g C-a' vi_xmap/progressive-increment
+ ble-bind -f 'g C-x' vi_xmap/progressive-decrement
+ ble-bind -f f1 vi_xmap/command-help
+ ble-bind -f K vi_xmap/command-help
+}
+function ble-decode/keymap:vi_smap/define {
+ ble-bind -f __default__ vi-command/decompose-meta
+ ble-bind -f 'ESC' vi_xmap/exit
+ ble-bind -f 'C-[' vi_xmap/exit
+ ble-bind -f 'C-c' vi_xmap/cancel
+ ble-bind -f 'C-\ C-n' nop
+ ble-bind -f 'C-\ C-n' vi_xmap/cancel
+ ble-bind -f 'C-\ C-g' vi_xmap/cancel
+ ble-bind -f C-v vi_xmap/switch-to-visual-blockwise
+ ble-bind -f C-q vi_xmap/switch-to-visual-blockwise
+ ble-bind -f C-g vi_xmap/switch-to-visual
+ ble-bind -f delete 'vi-command/operator d'
+ ble-bind -f 'C-?' 'vi-command/operator d'
+ ble-bind -f 'DEL' 'vi-command/operator d'
+ ble-bind -f 'C-h' 'vi-command/operator d'
+ ble-bind -f 'BS' 'vi-command/operator d'
+ ble-bind -f __defchar__ vi_smap/self-insert
+ ble-bind -f paste_begin vi-command/bracketed-paste
+ ble-bind -f 'C-a' vi_xmap/increment
+ ble-bind -f 'C-x' vi_xmap/decrement
+ ble-bind -f f1 vi_xmap/command-help
+ ble-bind -c 'C-z' fg
+ ble-bind -f home 'vi_smap/@nomarked vi-command/beginning-of-line'
+ ble-bind -f end 'vi_smap/@nomarked vi-command/forward-eol'
+ ble-bind -f C-m 'vi_smap/@nomarked vi-command/forward-first-non-space'
+ ble-bind -f RET 'vi_smap/@nomarked vi-command/forward-first-non-space'
+ ble-bind -f S-home 'vi-command/beginning-of-line'
+ ble-bind -f S-end 'vi-command/forward-eol'
+ ble-bind -f S-C-m 'vi-command/forward-first-non-space'
+ ble-bind -f S-RET 'vi-command/forward-first-non-space'
+ ble-bind -f C-right 'vi_smap/@nomarked vi-command/forward-vword'
+ ble-bind -f C-left 'vi_smap/@nomarked vi-command/backward-vword'
+ ble-bind -f S-C-right 'vi-command/forward-vword'
+ ble-bind -f S-C-left 'vi-command/backward-vword'
+ ble-bind -f left 'vi_smap/@nomarked vi-command/backward-char'
+ ble-bind -f right 'vi_smap/@nomarked vi-command/forward-char'
+ ble-bind -f 'C-?' 'vi_smap/@nomarked vi-command/backward-char wrap'
+ ble-bind -f 'DEL' 'vi_smap/@nomarked vi-command/backward-char wrap'
+ ble-bind -f 'C-h' 'vi_smap/@nomarked vi-command/backward-char wrap'
+ ble-bind -f 'BS' 'vi_smap/@nomarked vi-command/backward-char wrap'
+ ble-bind -f SP 'vi_smap/@nomarked vi-command/forward-char wrap'
+ ble-bind -f S-left 'vi-command/backward-char'
+ ble-bind -f S-right 'vi-command/forward-char'
+ ble-bind -f 'S-C-?' 'vi-command/backward-char wrap'
+ ble-bind -f 'S-DEL' 'vi-command/backward-char wrap'
+ ble-bind -f 'S-C-h' 'vi-command/backward-char wrap'
+ ble-bind -f 'S-BS' 'vi-command/backward-char wrap'
+ ble-bind -f S-SP 'vi-command/forward-char wrap'
+ ble-bind -f down 'vi_smap/@nomarked vi-command/forward-line'
+ ble-bind -f C-n 'vi_smap/@nomarked vi-command/forward-line'
+ ble-bind -f C-j 'vi_smap/@nomarked vi-command/forward-line'
+ ble-bind -f up 'vi_smap/@nomarked vi-command/backward-line'
+ ble-bind -f C-p 'vi_smap/@nomarked vi-command/backward-line'
+ ble-bind -f C-home 'vi_smap/@nomarked vi-command/first-nol'
+ ble-bind -f C-end 'vi_smap/@nomarked vi-command/last-eol'
+ ble-bind -f S-down 'vi-command/forward-line'
+ ble-bind -f S-C-n 'vi-command/forward-line'
+ ble-bind -f S-C-j 'vi-command/forward-line'
+ ble-bind -f S-up 'vi-command/backward-line'
+ ble-bind -f S-C-p 'vi-command/backward-line'
+ ble-bind -f S-C-home 'vi-command/first-nol'
+ ble-bind -f S-C-end 'vi-command/last-eol'
+}
+function ble/widget/vi_imap/__attach__ {
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+function ble/widget/vi_imap/__detach__ {
+ ble/edit/info/default clear
+ ble/keymap:vi/clear-arg
+ ble/keymap:vi/search/clear-matched
+ return 0
+}
+function ble/widget/vi_imap/accept-single-line-or {
+ if ble-edit/is-single-complete-line; then
+ ble/keymap:vi/imap-repeat/reset
+ ble/widget/accept-line
+ else
+ ble/widget/"$@"
+ fi
+}
+function ble/widget/vi_imap/delete-region-or {
+ if [[ $_ble_edit_mark_active ]]; then
+ ble/keymap:vi/imap-repeat/reset
+ if ((_ble_edit_ind!=_ble_edit_mark)); then
+ ble/keymap:vi/undo/add more
+ ble/widget/delete-region
+ ble/keymap:vi/undo/add more
+ fi
+ else
+ ble/widget/"$@"
+ fi
+}
+function ble/widget/vi_imap/overwrite-mode {
+ ble-edit/content/clear-arg
+ if [[ $_ble_edit_overwrite_mode ]]; then
+ _ble_edit_overwrite_mode=
+ else
+ _ble_edit_overwrite_mode=${_ble_keymap_vi_insert_overwrite:-R}
+ fi
+ ble/keymap:vi/update-mode-name
+ return 0
+}
+function ble/widget/vi_imap/delete-backward-word {
+ local space=$' \t' nl=$'\n'
+ local rex="($_ble_keymap_vi_REX_WORD)[$space]*\$|[$space]+\$|$nl\$"
+ if [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]]; then
+ local index=$((_ble_edit_ind-${#BASH_REMATCH}))
+ if ((index!=_ble_edit_ind)); then
+ ble/keymap:vi/undo/add more
+ ble/widget/.delete-range "$index" "$_ble_edit_ind"
+ ble/keymap:vi/undo/add more
+ fi
+ return 0
+ else
+ ble/widget/.bell
+ return 1
+ fi
+}
+function ble/widget/vi_imap/quoted-insert-char {
+ ble/keymap:vi/imap-repeat/pop
+ _ble_edit_mark_active=
+ _ble_decode_char__hook=ble/widget/vi_imap/quoted-insert-char.hook
+ return 147
+}
+function ble/widget/vi_imap/quoted-insert-char.hook {
+ ble/keymap:vi/imap/invoke-widget ble/widget/self-insert "$1"
+}
+function ble/widget/vi_imap/quoted-insert {
+ ble/keymap:vi/imap-repeat/pop
+ _ble_edit_mark_active=
+ _ble_decode_key__hook=ble/widget/vi_imap/quoted-insert.hook
+ return 147
+}
+function ble/widget/vi_imap/quoted-insert.hook {
+ ble/keymap:vi/imap/invoke-widget ble/widget/quoted-insert.hook "$1"
+}
+function ble/widget/vi_imap/bracketed-paste {
+ ble/keymap:vi/imap-repeat/pop
+ ble/widget/bracketed-paste
+ _ble_edit_bracketed_paste_proc=ble/widget/vi_imap/bracketed-paste.proc
+ return 147
+}
+function ble/widget/vi_imap/bracketed-paste.proc {
+ local WIDGET=ble/widget/batch-insert
+ local -a KEYS; KEYS=("$@")
+ ble/keymap:vi/imap-repeat/push
+ builtin eval -- "$WIDGET"
+}
+_ble_keymap_vi_brackated_paste_mark_active=
+function ble/widget/vi-command/bracketed-paste {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1 # discard args
+ _ble_keymap_vi_brackated_paste_mark_active=$_ble_edit_mark_active
+ _ble_edit_mark_active=
+ ble/widget/bracketed-paste
+ _ble_edit_bracketed_paste_proc=ble/widget/vi-command/bracketed-paste.proc
+ return 147
+}
+function ble/widget/vi-command/bracketed-paste.proc {
+ if [[ $_ble_decode_keymap == vi_nmap ]]; then
+ local isbol index=$_ble_edit_ind
+ ble-edit/content/bolp && isbol=1
+ ble/decode/widget/call-interactively 'ble/widget/vi_nmap/append-mode' 97
+ [[ $isbol ]] && ((_ble_edit_ind=index)) # 行頭にいたときは戻る
+ ble/widget/vi_imap/bracketed-paste.proc "$@"
+ ble/keymap:vi/imap/invoke-widget \
+ ble/widget/vi_imap/normal-mode $((_ble_decode_Ctrl|0x5b))
+ elif [[ $_ble_decode_keymap == vi_[xs]map ]]; then
+ local _ble_edit_mark_active=$_ble_keymap_vi_brackated_paste_mark_active
+ ble/decode/widget/call-interactively 'ble/widget/vi-command/operator c' 99 || return 1
+ ble/widget/vi_imap/bracketed-paste.proc "$@"
+ ble/keymap:vi/imap/invoke-widget \
+ ble/widget/vi_imap/normal-mode $((_ble_decode_Ctrl|0x5b))
+ elif [[ $_ble_decode_keymap == vi_omap ]]; then
+ ble/widget/vi_omap/cancel
+ ble/widget/.bell
+ return 1
+ else # vi_omap
+ ble/widget/.bell
+ return 1
+ fi
+}
+function ble/widget/vi_imap/insert-digraph.hook {
+ local -a KEYS; KEYS=("$1")
+ ble/widget/self-insert
+}
+function ble/widget/vi_imap/insert-digraph {
+ ble/decode/keymap/push vi_digraph
+ _ble_keymap_vi_digraph__hook=ble/widget/vi_imap/insert-digraph.hook
+ return 0
+}
+function ble/widget/vi_imap/newline {
+ local ret
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-non-space "$bol"; local nol=$ret
+ ble/widget/default/newline
+ ((bol<nol)) && ble/widget/.insert-string "${_ble_edit_str:bol:nol-bol}"
+ return 0
+}
+function ble/widget/vi_imap/delete-backward-indent-or {
+ local rex=$'(^|\n)([ \t]+)$'
+ if [[ ${_ble_edit_str::_ble_edit_ind} =~ $rex ]]; then
+ local rematch2=${BASH_REMATCH[2]} # Note: for bash-3.1 ${#arr[n]} bug
+ if [[ $rematch2 ]]; then
+ ble/keymap:vi/undo/add more
+ ble/widget/.delete-range $((_ble_edit_ind-${#rematch2})) "$_ble_edit_ind"
+ ble/keymap:vi/undo/add more
+ fi
+ return 0
+ else
+ ble/widget/"$@"
+ fi
+}
+function ble-decode/keymap:vi_imap/define {
+ local ble_bind_nometa=1
+ ble-decode/keymap:safe/bind-common
+ ble-decode/keymap:safe/bind-history
+ ble-bind -f 'C-d' 'delete-region-or delete-forward-char-or-exit'
+ ble-bind -f 'SP' 'magic-space'
+ ble-bind -f 'C-j' 'accept-line'
+ ble-bind -f 'C-RET' 'accept-line'
+ ble-bind -f 'C-m' 'accept-single-line-or-newline'
+ ble-bind -f 'RET' 'accept-single-line-or-newline'
+ ble-bind -f 'C-x C-e' 'edit-and-execute-command'
+ ble-bind -f 'C-g' 'bell'
+ ble-bind -f 'C-x C-g' 'bell'
+ ble-bind -f 'C-l' 'clear-screen'
+ ble-bind -f 'f1' 'command-help'
+ ble-bind -f 'C-x C-v' 'display-shell-version'
+ ble-bind -c 'C-z' 'fg'
+ ble-bind -f insert 'vi_imap/overwrite-mode'
+ ble-bind -f 'C-q' 'vi_imap/quoted-insert'
+ ble-bind -f 'C-v' 'vi_imap/quoted-insert'
+ ble-bind -f 'C-RET' 'newline'
+ ble-bind -f paste_begin 'vi_imap/bracketed-paste'
+ ble-bind -f 'C-?' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char'
+ ble-bind -f 'DEL' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char'
+ ble-bind -f 'C-h' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char'
+ ble-bind -f 'BS' 'vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char'
+ ble-bind -f 'C-w' 'vi_imap/delete-backward-word'
+ ble-decode/keymap:vi_imap/bind-complete
+ ble-bind -f 'C-\' bell
+ ble-bind -f 'C-^' bell
+ ble-bind -f __attach__ vi_imap/__attach__
+ ble-bind -f __detach__ vi_imap/__detach__
+ ble-bind -f __default__ vi_imap/__default__
+ ble-bind -f __before_widget__ vi_imap/__before_widget__
+ ble-bind -f __line_limit__ __line_limit__
+ ble-bind -f 'ESC' 'vi_imap/normal-mode'
+ ble-bind -f 'C-[' 'vi_imap/normal-mode'
+ ble-bind -f 'C-c' 'vi_imap/normal-mode-without-insert-leave'
+ ble-bind -f 'C-o' 'vi_imap/single-command-mode'
+}
+function ble-decode/keymap:vi_imap/define-meta-bindings {
+ local ble_bind_keymap=vi_imap
+ ble-bind -f 'M-^' 'history-expand-line'
+ ble-bind -f 'C-M-l' 'redraw-line'
+ ble-bind -f 'M-#' 'insert-comment'
+ ble-bind -f 'M-C-e' 'shell-expand-line'
+ ble-bind -f 'M-&' 'tilde-expand'
+ ble-bind -f 'C-M-g' 'bell'
+ ble-bind -c 'M-z' 'fg'
+ ble-bind -f 'M-C-m' 'newline'
+ ble-bind -f 'M-RET' 'newline'
+ ble-bind -f 'M-SP' 'set-mark'
+ ble-bind -f 'M-w' 'copy-region-or copy-uword'
+ ble-bind -f 'M-y' 'yank-pop'
+ ble-bind -f 'M-S-y' 'yank-pop backward'
+ ble-bind -f 'M-Y' 'yank-pop backward'
+ ble-bind -f 'M-\' 'delete-horizontal-space'
+ ble-bind -f 'M-right' '@nomarked forward-sword'
+ ble-bind -f 'M-left' '@nomarked backward-sword'
+ ble-bind -f 'S-M-right' '@marked forward-sword'
+ ble-bind -f 'S-M-left' '@marked backward-sword'
+ ble-bind -f 'M-d' 'kill-forward-cword'
+ ble-bind -f 'M-h' 'kill-backward-cword'
+ ble-bind -f 'M-delete' 'copy-forward-sword'
+ ble-bind -f 'M-C-?' 'copy-backward-sword'
+ ble-bind -f 'M-DEL' 'copy-backward-sword'
+ ble-bind -f 'M-C-h' 'copy-backward-sword'
+ ble-bind -f 'M-BS' 'copy-backward-sword'
+ ble-bind -f 'M-f' '@nomarked forward-cword'
+ ble-bind -f 'M-b' '@nomarked backward-cword'
+ ble-bind -f 'M-F' '@marked forward-cword'
+ ble-bind -f 'M-B' '@marked backward-cword'
+ ble-bind -f 'M-S-f' '@marked forward-cword'
+ ble-bind -f 'M-S-b' '@marked backward-cword'
+ ble-bind -f 'M-c' 'capitalize-eword'
+ ble-bind -f 'M-l' 'downcase-eword'
+ ble-bind -f 'M-u' 'upcase-eword'
+ ble-bind -f 'M-t' 'transpose-ewords'
+ ble-bind -f 'M-m' '@nomarked non-space-beginning-of-line'
+ ble-bind -f 'S-M-m' '@marked non-space-beginning-of-line'
+ ble-bind -f 'M-M' '@marked non-space-beginning-of-line'
+ ble-bind -f 'M-<' 'history-beginning'
+ ble-bind -f 'M->' 'history-end'
+ ble-bind -f 'M-.' 'insert-last-argument'
+ ble-bind -f 'M-_' 'insert-last-argument'
+ ble-bind -f 'M-C-y' 'insert-nth-argument'
+ ble-bind -f 'M-?' 'complete show_menu'
+ ble-bind -f 'M-*' 'complete insert_all'
+ ble-bind -f 'M-{' 'complete insert_braces'
+ ble-bind -f 'M-/' 'complete context=filename'
+ ble-bind -f 'M-~' 'complete context=username'
+ ble-bind -f 'M-$' 'complete context=variable'
+ ble-bind -f 'M-@' 'complete context=hostname'
+ ble-bind -f 'M-!' 'complete context=command'
+ ble-bind -f "M-'" 'sabbrev-expand'
+ ble-bind -f 'M-g' 'complete context=glob'
+ ble-bind -f 'M-C-i' 'complete context=dynamic-history'
+ ble-bind -f 'M-TAB' 'complete context=dynamic-history'
+}
+_ble_keymap_vi_cmap_hook=
+_ble_keymap_vi_cmap_cancel_hook=
+_ble_keymap_vi_cmap_before_command=
+_ble_keymap_vi_cmap_history=()
+_ble_keymap_vi_cmap_history_edit=()
+_ble_keymap_vi_cmap_history_dirt=()
+_ble_keymap_vi_cmap_history_index=0
+function ble/keymap:vi/async-commandline-mode {
+ local hook=$1
+ _ble_keymap_vi_cmap_hook=$hook
+ _ble_keymap_vi_cmap_cancel_hook=
+ _ble_keymap_vi_cmap_before_command=
+ ble/textarea#render
+ ble/textarea#save-state _ble_keymap_vi_cmap
+ ble/util/save-vars _ble_keymap_vi_cmap _ble_canvas_panel_focus
+ _ble_keymap_vi_cmap_history_prefix=$_ble_history_prefix
+ ble/decode/keymap/push vi_cmap
+ ble/keymap:vi/update-mode-name
+ _ble_textarea_panel=1
+ _ble_canvas_panel_focus=1
+ ble/textarea#invalidate
+ _ble_edit_PS1=$PS2
+ _ble_prompt_ps1_data=(0 '' '' 0 0 0 32 0 '' '')
+ _ble_edit_dirty_observer=()
+ ble/widget/.newline/clear-content
+ _ble_edit_arg=
+ ble-edit/undo/clear-all
+ ble/history/set-prefix _ble_keymap_vi_cmap
+ _ble_syntax_lang=text
+ _ble_highlight_layer__list=(plain region overwrite_mode)
+}
+function ble/widget/vi_cmap/accept {
+ local hook=${_ble_keymap_vi_cmap_hook}
+ _ble_keymap_vi_cmap_hook=
+ local result=$_ble_edit_str
+ [[ $result ]] && ble/history/add "$result" # Note: cancel でも登録する
+ local -a DRAW_BUFF=()
+ ble/canvas/panel#set-height.draw "$_ble_textarea_panel" 0
+ ble/canvas/bflush.draw
+ ble/textarea#restore-state _ble_keymap_vi_cmap
+ ble/textarea#clear-state _ble_keymap_vi_cmap
+ ble/util/restore-vars _ble_keymap_vi_cmap _ble_canvas_panel_focus
+ [[ $_ble_edit_overwrite_mode ]] && ble/util/buffer "$_ble_term_civis"
+ ble/history/set-prefix "$_ble_keymap_vi_cmap_history_prefix"
+ ble/decode/keymap/pop
+ ble/keymap:vi/update-mode-name
+ if [[ $hook ]]; then
+ builtin eval -- "$hook \"\$result\""
+ else
+ ble/keymap:vi/adjust-command-mode
+ return 0
+ fi
+}
+function ble/widget/vi_cmap/cancel {
+ _ble_keymap_vi_cmap_hook=$_ble_keymap_vi_cmap_cancel_hook
+ ble/widget/vi_cmap/accept
+}
+function ble/widget/vi_cmap/__before_widget__ {
+ if [[ $_ble_keymap_vi_cmap_before_command ]]; then
+ builtin eval -- "$_ble_keymap_vi_cmap_before_command"
+ fi
+}
+function ble/widget/vi_cmap/__line_limit__.edit {
+ local content=$1
+ ble/widget/edit-and-execute-command.edit "$content" no-newline; local ext=$?
+ ((ext==127)) && return "$ext"
+ ble-edit/content/reset "$ret"
+ ble/widget/vi_cmap/accept
+}
+function ble/widget/vi_cmap/__line_limit__ {
+ ble/widget/__line_limit__ vi_cmap/__line_limit__.edit
+}
+function ble-decode/keymap:vi_cmap/define {
+ local ble_bind_nometa=
+ ble-decode/keymap:safe/bind-common
+ ble-decode/keymap:safe/bind-history
+ ble-decode/keymap:safe/bind-complete
+ ble-bind -f __before_widget__ vi_cmap/__before_widget__
+ ble-bind -f __line_limit__ vi_cmap/__line_limit__
+ ble-bind -f 'ESC' vi_cmap/cancel
+ ble-bind -f 'C-[' vi_cmap/cancel
+ ble-bind -f 'C-c' vi_cmap/cancel
+ ble-bind -f 'C-m' vi_cmap/accept
+ ble-bind -f 'RET' vi_cmap/accept
+ ble-bind -f 'C-j' vi_cmap/accept
+ ble-bind -f 'C-g' bell
+ ble-bind -f 'C-x C-g' bell
+ ble-bind -f 'C-M-g' bell
+ ble-bind -f 'C-l' redraw-line
+ ble-bind -f 'C-M-l' redraw-line
+ ble-bind -f 'C-x C-v' display-shell-version
+ ble-bind -f 'C-\' bell
+ ble-bind -f 'C-^' bell
+}
+function ble-decode/keymap:vi/initialize {
+ local fname_keymap_cache=$_ble_base_cache/keymap.vi
+ if [[ -s $fname_keymap_cache &&
+ $fname_keymap_cache -nt $_ble_base/keymap/vi.sh &&
+ $fname_keymap_cache -nt $_ble_base/lib/init-cmap.sh ]]; then
+ source "$fname_keymap_cache" && return 0
+ fi
+ ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi..."
+ {
+ ble/decode/keymap#load isearch dump
+ ble/decode/keymap#load nsearch dump
+ ble/decode/keymap#load vi_imap dump
+ ble/decode/keymap#load vi_nmap dump
+ ble/decode/keymap#load vi_omap dump
+ ble/decode/keymap#load vi_xmap dump
+ ble/decode/keymap#load vi_cmap dump
+ } 3>| "$fname_keymap_cache"
+ ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi... done"
+}
+ble-decode/keymap:vi/initialize
+blehook/invoke keymap_load
+blehook/invoke keymap_vi_load
+return 0
diff --git a/.local/src/blesh/keymap/vi_digraph.sh b/.local/src/blesh/keymap/vi_digraph.sh
new file mode 100644
index 0000000..dce0bf4
--- /dev/null
+++ b/.local/src/blesh/keymap/vi_digraph.sh
@@ -0,0 +1,51 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+_ble_keymap_vi_digraph__hook=
+function ble/widget/vi_digraph/.proc {
+ local code=$1
+ local hook=${_ble_keymap_vi_digraph__hook:-ble-decode-key}
+ _ble_keymap_vi_digraph__hook=
+ ble/decode/keymap/pop
+ builtin eval -- "$hook $code"
+}
+function ble/widget/vi_digraph/defchar {
+ ble/widget/vi_digraph/.proc "${KEYS[0]}"
+}
+function ble/widget/vi_digraph/default {
+ local key=${KEYS[0]}
+ local flag=$((key&_ble_decode_MaskFlag)) char=$((key&_ble_decode_MaskChar))
+ if ((flag==_ble_decode_Ctrl&&63<=char&&char<128&&(char&0x1F)!=0)); then
+ ((char=char==63?127:char&0x1F))
+ ble/widget/vi_digraph/.proc "$char"
+ return 0
+ fi
+ ble/widget/.bell
+ return 0
+}
+function ble-decode/keymap:vi_digraph/define {
+ ble-bind -f __defchar__ vi_digraph/defchar
+ ble-bind -f __default__ vi_digraph/default
+ ble-bind -f __line_limit__ nop
+ local lines; ble/util/mapfile lines < "$_ble_base/keymap/vi_digraph.txt"
+ local line field ch1 ch2 code
+ for line in "${lines[@]}"; do
+ [[ $line == ??' '* ]] || continue
+ ch1=${line::1}
+ ch2=${line:1:1}
+ code=${line:3}
+ ble-bind -f "$ch1 $ch2" "vi_digraph/.proc $code"
+ done
+}
+function ble-decode/keymap:vi_digraph/initialize {
+ local fname_keymap_cache=$_ble_base_cache/keymap.vi_digraph
+ if [[ -s $fname_keymap_cache &&
+ $fname_keymap_cache -nt $_ble_base/keymap/vi_digraph.sh &&
+ $fname_keymap_cache -nt $_ble_base/keymap/vi_digraph.txt ]]; then
+ source "$fname_keymap_cache"
+ return 0
+ fi
+ ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi_digraph..."
+ : >| "$fname_keymap_cache"
+ ble/decode/keymap#load vi_digraph dump 3>> "$fname_keymap_cache"
+ ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi_digraph... done"
+}
+ble-decode/keymap:vi_digraph/initialize
diff --git a/.local/src/blesh/keymap/vi_digraph.txt b/.local/src/blesh/keymap/vi_digraph.txt
new file mode 100644
index 0000000..9086f91
--- /dev/null
+++ b/.local/src/blesh/keymap/vi_digraph.txt
@@ -0,0 +1,1304 @@
+NU 0
+SH 1
+SX 2
+EX 3
+ET 4
+EQ 5
+AK 6
+BL 7
+BS 8
+HT 9
+LF 10
+VT 11
+FF 12
+CR 13
+SO 14
+SI 15
+DL 16
+D1 17
+D2 18
+D3 19
+D4 20
+NK 21
+SY 22
+EB 23
+CN 24
+EM 25
+SB 26
+EC 27
+FS 28
+GS 29
+RS 30
+US 31
+SP 32
+Nb 35
+DO 36
+At 64
+<( 91
+// 92
+)> 93
+'> 94
+'! 96
+(! 123
+!! 124
+!) 125
+'? 126
+DT 127
+PA 128
+HO 129
+BH 130
+NH 131
+IN 132
+NL 133
+SA 134
+ES 135
+HS 136
+HJ 137
+VS 138
+PD 139
+PU 140
+RI 141
+S2 142
+S3 143
+DC 144
+P1 145
+P2 146
+TS 147
+CC 148
+MW 149
+SG 150
+EG 151
+SS 152
+GC 153
+SC 154
+CI 155
+ST 156
+OC 157
+PM 158
+AC 159
+NS 160
+!I 161
+Ct 162
+Pd 163
+Cu 164
+Ye 165
+BB 166
+SE 167
+': 168
+Co 169
+-a 170
+<< 171
+NO 172
+-- 173
+Rg 174
+'m 175
+DG 176
++- 177
+2S 178
+3S 179
+'' 180
+My 181
+PI 182
+.M 183
+', 184
+1S 185
+-o 186
+>> 187
+14 188
+12 189
+34 190
+?I 191
+A! 192
+A' 193
+A> 194
+A? 195
+A: 196
+AA 197
+AE 198
+C, 199
+E! 200
+E' 201
+E> 202
+E: 203
+I! 204
+I' 205
+I> 206
+I: 207
+D- 208
+N? 209
+O! 210
+O' 211
+O> 212
+O? 213
+O: 214
+*X 215
+O/ 216
+U! 217
+U' 218
+U> 219
+U: 220
+Y' 221
+TH 222
+ss 223
+a! 224
+a' 225
+a> 226
+a? 227
+a: 228
+aa 229
+ae 230
+c, 231
+e! 232
+e' 233
+e> 234
+e: 235
+i! 236
+i' 237
+i> 238
+i: 239
+d- 240
+n? 241
+o! 242
+o' 243
+o> 244
+o? 245
+o: 246
+-: 247
+o/ 248
+u! 249
+u' 250
+u> 251
+u: 252
+y' 253
+th 254
+y: 255
+A- 256
+a- 257
+A( 258
+a( 259
+A; 260
+a; 261
+C' 262
+c' 263
+C> 264
+c> 265
+C. 266
+c. 267
+C< 268
+c< 269
+D< 270
+d< 271
+D/ 272
+d/ 273
+E- 274
+e- 275
+E( 276
+e( 277
+E. 278
+e. 279
+E; 280
+e; 281
+E< 282
+e< 283
+G> 284
+g> 285
+G( 286
+g( 287
+G. 288
+g. 289
+G, 290
+g, 291
+H> 292
+h> 293
+H/ 294
+h/ 295
+I? 296
+i? 297
+I- 298
+i- 299
+I( 300
+i( 301
+I; 302
+i; 303
+I. 304
+i. 305
+IJ 306
+ij 307
+J> 308
+j> 309
+K, 310
+k, 311
+kk 312
+L' 313
+l' 314
+L, 315
+l, 316
+L< 317
+l< 318
+L. 319
+l. 320
+L/ 321
+l/ 322
+N' 323
+n' 324
+N, 325
+n, 326
+N< 327
+n< 328
+'n 329
+NG 330
+ng 331
+O- 332
+o- 333
+O( 334
+o( 335
+O" 336
+o" 337
+OE 338
+oe 339
+R' 340
+r' 341
+R, 342
+r, 343
+R< 344
+r< 345
+S' 346
+s' 347
+S> 348
+s> 349
+S, 350
+s, 351
+S< 352
+s< 353
+T, 354
+t, 355
+T< 356
+t< 357
+T/ 358
+t/ 359
+U? 360
+u? 361
+U- 362
+u- 363
+U( 364
+u( 365
+U0 366
+u0 367
+U" 368
+u" 369
+U; 370
+u; 371
+W> 372
+w> 373
+Y> 374
+y> 375
+Y: 376
+Z' 377
+z' 378
+Z. 379
+z. 380
+Z< 381
+z< 382
+O9 416
+o9 417
+OI 418
+oi 419
+yr 422
+U9 431
+u9 432
+Z/ 437
+z/ 438
+ED 439
+A< 461
+a< 462
+I< 463
+i< 464
+O< 465
+o< 466
+U< 467
+u< 468
+A1 478
+a1 479
+A7 480
+a7 481
+A3 482
+a3 483
+G/ 484
+g/ 485
+G< 486
+g< 487
+K< 488
+k< 489
+O; 490
+o; 491
+O1 492
+o1 493
+EZ 494
+ez 495
+j< 496
+G' 500
+g' 501
+;S 703
+'< 711
+'( 728
+'. 729
+'0 730
+'; 731
+'" 733
+A% 902
+E% 904
+Y% 905
+I% 906
+O% 908
+U% 910
+W% 911
+i3 912
+A* 913
+B* 914
+G* 915
+D* 916
+E* 917
+Z* 918
+Y* 919
+H* 920
+I* 921
+K* 922
+L* 923
+M* 924
+N* 925
+C* 926
+O* 927
+P* 928
+R* 929
+S* 931
+T* 932
+U* 933
+F* 934
+X* 935
+Q* 936
+W* 937
+J* 938
+V* 939
+a% 940
+e% 941
+y% 942
+i% 943
+u3 944
+a* 945
+b* 946
+g* 947
+d* 948
+e* 949
+z* 950
+y* 951
+h* 952
+i* 953
+k* 954
+l* 955
+m* 956
+n* 957
+c* 958
+o* 959
+p* 960
+r* 961
+*s 962
+s* 963
+t* 964
+u* 965
+f* 966
+x* 967
+q* 968
+w* 969
+j* 970
+v* 971
+o% 972
+u% 973
+w% 974
+'G 984
+,G 985
+T3 986
+t3 987
+M3 988
+m3 989
+K3 990
+k3 991
+P3 992
+p3 993
+'% 1012
+j3 1013
+IO 1025
+D% 1026
+G% 1027
+IE 1028
+DS 1029
+II 1030
+YI 1031
+J% 1032
+LJ 1033
+NJ 1034
+Ts 1035
+KJ 1036
+V% 1038
+DZ 1039
+A= 1040
+B= 1041
+V= 1042
+G= 1043
+D= 1044
+E= 1045
+Z% 1046
+Z= 1047
+I= 1048
+J= 1049
+K= 1050
+L= 1051
+M= 1052
+N= 1053
+O= 1054
+P= 1055
+R= 1056
+S= 1057
+T= 1058
+U= 1059
+F= 1060
+H= 1061
+C= 1062
+C% 1063
+S% 1064
+Sc 1065
+=" 1066
+Y= 1067
+%" 1068
+JE 1069
+JU 1070
+JA 1071
+a= 1072
+b= 1073
+v= 1074
+g= 1075
+d= 1076
+e= 1077
+z% 1078
+z= 1079
+i= 1080
+j= 1081
+k= 1082
+l= 1083
+m= 1084
+n= 1085
+o= 1086
+p= 1087
+r= 1088
+s= 1089
+t= 1090
+u= 1091
+f= 1092
+h= 1093
+c= 1094
+c% 1095
+s% 1096
+sc 1097
+=' 1098
+y= 1099
+%' 1100
+je 1101
+ju 1102
+ja 1103
+io 1105
+d% 1106
+g% 1107
+ie 1108
+ds 1109
+ii 1110
+yi 1111
+j% 1112
+lj 1113
+nj 1114
+ts 1115
+kj 1116
+v% 1118
+dz 1119
+Y3 1122
+y3 1123
+O3 1130
+o3 1131
+F3 1138
+f3 1139
+V3 1140
+v3 1141
+C3 1152
+c3 1153
+G3 1168
+g3 1169
+A+ 1488
+B+ 1489
+G+ 1490
+D+ 1491
+H+ 1492
+W+ 1493
+Z+ 1494
+X+ 1495
+Tj 1496
+J+ 1497
+K% 1498
+K+ 1499
+L+ 1500
+M% 1501
+M+ 1502
+N% 1503
+N+ 1504
+S+ 1505
+E+ 1506
+P% 1507
+P+ 1508
+Zj 1509
+ZJ 1510
+Q+ 1511
+R+ 1512
+Sh 1513
+T+ 1514
+,+ 1548
+;+ 1563
+?+ 1567
+H' 1569
+aM 1570
+aH 1571
+wH 1572
+ah 1573
+yH 1574
+a+ 1575
+b+ 1576
+tm 1577
+t+ 1578
+tk 1579
+g+ 1580
+hk 1581
+x+ 1582
+d+ 1583
+dk 1584
+r+ 1585
+z+ 1586
+s+ 1587
+sn 1588
+c+ 1589
+dd 1590
+tj 1591
+zH 1592
+e+ 1593
+i+ 1594
+++ 1600
+f+ 1601
+q+ 1602
+k+ 1603
+l+ 1604
+m+ 1605
+n+ 1606
+h+ 1607
+w+ 1608
+j+ 1609
+y+ 1610
+:+ 1611
+"+ 1612
+=+ 1613
+/+ 1614
+'+ 1615
+1+ 1616
+3+ 1617
+0+ 1618
+aS 1648
+p+ 1662
+v+ 1700
+gf 1711
+0a 1776
+1a 1777
+2a 1778
+3a 1779
+4a 1780
+5a 1781
+6a 1782
+7a 1783
+8a 1784
+9a 1785
+B. 7682
+b. 7683
+B_ 7686
+b_ 7687
+D. 7690
+d. 7691
+D_ 7694
+d_ 7695
+D, 7696
+d, 7697
+F. 7710
+f. 7711
+G- 7712
+g- 7713
+H. 7714
+h. 7715
+H: 7718
+h: 7719
+H, 7720
+h, 7721
+K' 7728
+k' 7729
+K_ 7732
+k_ 7733
+L_ 7738
+l_ 7739
+M' 7742
+m' 7743
+M. 7744
+m. 7745
+N. 7748
+n. 7749
+N_ 7752
+n_ 7753
+P' 7764
+p' 7765
+P. 7766
+p. 7767
+R. 7768
+r. 7769
+R_ 7774
+r_ 7775
+S. 7776
+s. 7777
+T. 7786
+t. 7787
+T_ 7790
+t_ 7791
+V? 7804
+v? 7805
+W! 7808
+w! 7809
+W' 7810
+w' 7811
+W: 7812
+w: 7813
+W. 7814
+w. 7815
+X. 7818
+x. 7819
+X: 7820
+x: 7821
+Y. 7822
+y. 7823
+Z> 7824
+z> 7825
+Z_ 7828
+z_ 7829
+h_ 7830
+t: 7831
+w0 7832
+y0 7833
+A2 7842
+a2 7843
+E2 7866
+e2 7867
+E? 7868
+e? 7869
+I2 7880
+i2 7881
+O2 7886
+o2 7887
+U2 7910
+u2 7911
+Y! 7922
+y! 7923
+Y2 7926
+y2 7927
+Y? 7928
+y? 7929
+;' 7936
+,' 7937
+;! 7938
+,! 7939
+?; 7940
+?, 7941
+!: 7942
+?: 7943
+1N 8194
+1M 8195
+3M 8196
+4M 8197
+6M 8198
+1T 8201
+1H 8202
+-1 8208
+-N 8211
+-M 8212
+-3 8213
+!2 8214
+=2 8215
+'6 8216
+'9 8217
+.9 8218
+9' 8219
+"6 8220
+"9 8221
+:9 8222
+9" 8223
+/- 8224
+/= 8225
+.. 8229
+,. 8230
+%0 8240
+1' 8242
+2' 8243
+3' 8244
+1" 8245
+2" 8246
+3" 8247
+Ca 8248
+<1 8249
+>1 8250
+:X 8251
+'- 8254
+/f 8260
+0S 8304
+4S 8308
+5S 8309
+6S 8310
+7S 8311
+8S 8312
+9S 8313
++S 8314
+-S 8315
+=S 8316
+(S 8317
+)S 8318
+nS 8319
+0s 8320
+1s 8321
+2s 8322
+3s 8323
+4s 8324
+5s 8325
+6s 8326
+7s 8327
+8s 8328
+9s 8329
++s 8330
+-s 8331
+=s 8332
+(s 8333
+)s 8334
+Li 8356
+Pt 8359
+W= 8361
+Eu 8364
+=R 8381
+=P 8381
+oC 8451
+co 8453
+oF 8457
+N0 8470
+PO 8471
+Rx 8478
+SM 8480
+TM 8482
+Om 8486
+AO 8491
+13 8531
+23 8532
+15 8533
+25 8534
+35 8535
+45 8536
+16 8537
+56 8538
+18 8539
+38 8540
+58 8541
+78 8542
+1R 8544
+2R 8545
+3R 8546
+4R 8547
+5R 8548
+6R 8549
+7R 8550
+8R 8551
+9R 8552
+aR 8553
+bR 8554
+cR 8555
+1r 8560
+2r 8561
+3r 8562
+4r 8563
+5r 8564
+6r 8565
+7r 8566
+8r 8567
+9r 8568
+ar 8569
+br 8570
+cr 8571
+<- 8592
+-! 8593
+-> 8594
+-v 8595
+<> 8596
+UD 8597
+<= 8656
+=> 8658
+== 8660
+FA 8704
+dP 8706
+TE 8707
+/0 8709
+DE 8710
+NB 8711
+(- 8712
+-) 8715
+*P 8719
++Z 8721
+-2 8722
+-+ 8723
+*- 8727
+Ob 8728
+Sb 8729
+RT 8730
+0( 8733
+00 8734
+-L 8735
+-V 8736
+PP 8741
+AN 8743
+OR 8744
+(U 8745
+)U 8746
+In 8747
+DI 8748
+Io 8750
+.: 8756
+:. 8757
+:R 8758
+:: 8759
+?1 8764
+CG 8766
+?- 8771
+?= 8773
+?2 8776
+=? 8780
+HI 8787
+!= 8800
+=3 8801
+=< 8804
+>= 8805
+<* 8810
+*> 8811
+!< 8814
+!> 8815
+(C 8834
+)C 8835
+(_ 8838
+)_ 8839
+0. 8857
+02 8858
+-T 8869
+.P 8901
+:3 8942
+.3 8943
+Eh 8962
+<7 8968
+>7 8969
+7< 8970
+7> 8971
+NI 8976
+(A 8978
+TR 8981
+Iu 8992
+Il 8993
+</ 9001
+/> 9002
+Vs 9251
+1h 9280
+3h 9281
+2h 9282
+4h 9283
+1j 9286
+2j 9287
+3j 9288
+4j 9289
+1. 9352
+2. 9353
+3. 9354
+4. 9355
+5. 9356
+6. 9357
+7. 9358
+8. 9359
+9. 9360
+hh 9472
+HH 9473
+vv 9474
+VV 9475
+3- 9476
+3_ 9477
+3! 9478
+3/ 9479
+4- 9480
+4_ 9481
+4! 9482
+4/ 9483
+dr 9484
+dR 9485
+Dr 9486
+DR 9487
+dl 9488
+dL 9489
+Dl 9490
+LD 9491
+ur 9492
+uR 9493
+Ur 9494
+UR 9495
+ul 9496
+uL 9497
+Ul 9498
+UL 9499
+vr 9500
+vR 9501
+Vr 9504
+VR 9507
+vl 9508
+vL 9509
+Vl 9512
+VL 9515
+dh 9516
+dH 9519
+Dh 9520
+DH 9523
+uh 9524
+uH 9527
+Uh 9528
+UH 9531
+vh 9532
+vH 9535
+Vh 9538
+VH 9547
+FD 9585
+BD 9586
+TB 9600
+LB 9604
+FB 9608
+lB 9612
+RB 9616
+.S 9617
+:S 9618
+?S 9619
+fS 9632
+OS 9633
+RO 9634
+Rr 9635
+RF 9636
+RY 9637
+RH 9638
+RZ 9639
+RK 9640
+RX 9641
+sB 9642
+SR 9644
+Or 9645
+UT 9650
+uT 9651
+PR 9654
+Tr 9655
+Dt 9660
+dT 9661
+PL 9664
+Tl 9665
+Db 9670
+Dw 9671
+LZ 9674
+0m 9675
+0o 9678
+0M 9679
+0L 9680
+0R 9681
+Sn 9688
+Ic 9689
+Fd 9698
+Bd 9699
+*2 9733
+*1 9734
+<H 9756
+>H 9758
+0u 9786
+0U 9787
+SU 9788
+Fm 9792
+Ml 9794
+cS 9824
+cH 9825
+cD 9826
+cC 9827
+Md 9833
+M8 9834
+M2 9835
+Mb 9837
+Mx 9838
+MX 9839
+OK 10003
+XX 10007
+-X 10016
+IS 12288
+,_ 12289
+._ 12290
++" 12291
++_ 12292
+*_ 12293
+;_ 12294
+0_ 12295
+<+ 12298
+>+ 12299
+<' 12300
+>' 12301
+<" 12302
+>" 12303
+(" 12304
+)" 12305
+=T 12306
+=_ 12307
+(' 12308
+)' 12309
+(I 12310
+)I 12311
+-? 12316
+A5 12353
+a5 12354
+I5 12355
+i5 12356
+U5 12357
+u5 12358
+E5 12359
+e5 12360
+O5 12361
+o5 12362
+ka 12363
+ga 12364
+ki 12365
+gi 12366
+ku 12367
+gu 12368
+ke 12369
+ge 12370
+ko 12371
+go 12372
+sa 12373
+za 12374
+si 12375
+zi 12376
+su 12377
+zu 12378
+se 12379
+ze 12380
+so 12381
+zo 12382
+ta 12383
+da 12384
+ti 12385
+di 12386
+tU 12387
+tu 12388
+du 12389
+te 12390
+de 12391
+to 12392
+do 12393
+na 12394
+ni 12395
+nu 12396
+ne 12397
+no 12398
+ha 12399
+ba 12400
+pa 12401
+hi 12402
+bi 12403
+pi 12404
+hu 12405
+bu 12406
+pu 12407
+he 12408
+be 12409
+pe 12410
+ho 12411
+bo 12412
+po 12413
+ma 12414
+mi 12415
+mu 12416
+me 12417
+mo 12418
+yA 12419
+ya 12420
+yU 12421
+yu 12422
+yO 12423
+yo 12424
+ra 12425
+ri 12426
+ru 12427
+re 12428
+ro 12429
+wA 12430
+wa 12431
+wi 12432
+we 12433
+wo 12434
+n5 12435
+vu 12436
+"5 12443
+05 12444
+*5 12445
++5 12446
+a6 12449
+A6 12450
+i6 12451
+I6 12452
+u6 12453
+U6 12454
+e6 12455
+E6 12456
+o6 12457
+O6 12458
+Ka 12459
+Ga 12460
+Ki 12461
+Gi 12462
+Ku 12463
+Gu 12464
+Ke 12465
+Ge 12466
+Ko 12467
+Go 12468
+Sa 12469
+Za 12470
+Si 12471
+Zi 12472
+Su 12473
+Zu 12474
+Se 12475
+Ze 12476
+So 12477
+Zo 12478
+Ta 12479
+Da 12480
+Ti 12481
+Di 12482
+TU 12483
+Tu 12484
+Du 12485
+Te 12486
+De 12487
+To 12488
+Do 12489
+Na 12490
+Ni 12491
+Nu 12492
+Ne 12493
+No 12494
+Ha 12495
+Ba 12496
+Pa 12497
+Hi 12498
+Bi 12499
+Pi 12500
+Hu 12501
+Bu 12502
+Pu 12503
+He 12504
+Be 12505
+Pe 12506
+Ho 12507
+Bo 12508
+Po 12509
+Ma 12510
+Mi 12511
+Mu 12512
+Me 12513
+Mo 12514
+YA 12515
+Ya 12516
+YU 12517
+Yu 12518
+YO 12519
+Yo 12520
+Ra 12521
+Ri 12522
+Ru 12523
+Re 12524
+Ro 12525
+WA 12526
+Wa 12527
+Wi 12528
+We 12529
+Wo 12530
+N6 12531
+Vu 12532
+KA 12533
+KE 12534
+Va 12535
+Vi 12536
+Ve 12537
+Vo 12538
+.6 12539
+-6 12540
+*6 12541
++6 12542
+b4 12549
+p4 12550
+m4 12551
+f4 12552
+d4 12553
+t4 12554
+n4 12555
+l4 12556
+g4 12557
+k4 12558
+h4 12559
+j4 12560
+q4 12561
+x4 12562
+zh 12563
+ch 12564
+sh 12565
+r4 12566
+z4 12567
+c4 12568
+s4 12569
+a4 12570
+o4 12571
+e4 12572
+ai 12574
+ei 12575
+au 12576
+ou 12577
+an 12578
+en 12579
+aN 12580
+eN 12581
+er 12582
+i4 12583
+u4 12584
+iu 12585
+v4 12586
+nG 12587
+gn 12588
+1c 12832
+2c 12833
+3c 12834
+4c 12835
+5c 12836
+6c 12837
+7c 12838
+8c 12839
+9c 12840
+ff 64256
+fi 64257
+fl 64258
+ft 64261
+st 64262
diff --git a/.local/src/blesh/keymap/vi_test.sh b/.local/src/blesh/keymap/vi_test.sh
new file mode 100644
index 0000000..2821515
--- /dev/null
+++ b/.local/src/blesh/keymap/vi_test.sh
@@ -0,0 +1,363 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+function ble/keymap:vi_test/decompose-state {
+ local spec=$1
+ ind=${spec%%:*} str=${spec#*:}
+ if ((${#ind}==1)) && [[ $ind == [!0-9a-zA-Z] ]]; then
+ ind=${str%%"$ind"*} ind=${#ind} str=${str::ind}${str:ind+1}
+ mark=
+ elif ((${#ind}==2)) && [[ ${ind::1} == [!0-9a-zA-Z] && ${ind:1:1} == [!0-9a-zA-Z] ]]; then
+ local ind1=${ind::1} ind2=${ind:1:1} text
+ text=${str//"$ind2"} text=${text%%"$ind1"*} ind=${#text}
+ text=${str//"$ind1"} text=${text%%"$ind2"*} mark=${#text}
+ str=${str//["$ind"]*}
+ fi
+}
+function ble/keymap:vi_test/start-section {
+ section=$1 nsuccess=0 ntest=0
+}
+function ble/keymap:vi_test/check {
+ local id=$1 initial=$2 kspecs=$3 final=$4
+ local str ind mark
+ ble/keymap:vi_test/decompose-state "$initial"; local i=$ind in=$str ima=$mark
+ ble/keymap:vi_test/decompose-state "$final"; local f=$ind fin=$str fma=$mark
+ local nl=$'\n' NL=$'\e[7m^J\e[m'
+ ble-edit/content/reset "$in" edit
+ _ble_edit_ind=$i
+ [[ $ima ]] && _ble_edit_mark=$ima
+ local ret
+ ble-decode-kbd "$kspecs"
+ local ble_decode=${_ble_keymap_vi_test_ble_decode:-ble-decode-key}
+ "$ble_decode" $ret &>/dev/null
+ [[ $_ble_edit_ind == "$f" && $_ble_edit_str == "$fin" && ( ! $fma || $_ble_edit_mark == "$fma" ) ]]; local ext=$?
+ if ((ext==0)); then
+ ((ntest++,nsuccess++))
+ else
+ ((ntest++))
+ local esc_in=${in//$nl/"$NL"}
+ local esc_fin=${fin//$nl/"$NL"}
+ local esc_str=${_ble_edit_str//$nl/"$NL"}
+ ble/util/print "test($section/$id): keys = ($kspecs)"
+ ble/util/print " initial = \"$i:$esc_in\""
+ ble/util/print " expected = \"$f:$esc_fin\""
+ ble/util/print " result = \"$_ble_edit_ind:$esc_str\""
+ fi >&2
+ case $_ble_decode_keymap in
+ (vi_[ixo]map)
+ ble-decode-key $((_ble_decode_Ctrl|99)) &>/dev/null ;;
+ esac
+ return "$ext"
+}
+function ble/keymap:vi_test/show-summary {
+ local title=$section
+ if ((nsuccess==ntest)); then
+ local tip=$'\e[32mpassed\e[m'
+ else
+ local tip=$'\e[31mfailed\e[m'
+ fi
+ ble/util/print "# $title test: result $((nsuccess))/$((ntest)) $tip"
+}
+function ble/widget/vi-command:check-vi-mode/space {
+ ble/keymap:vi_test/start-section '<space>'
+ local str=$' 1234\n567890ab\n'
+ ble/keymap:vi_test/check 1 "4:$str" '4 SP' "9:$str"
+ ble/keymap:vi_test/check 2 "4:$str" 'd 4 SP' $'3: \n567890ab\n'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/cw {
+ ble/keymap:vi_test/start-section 'cw'
+ ble/keymap:vi_test/check A1 '@:cp ./foo.txt @ /tmp/' 'c w' '@:cp ./foo.txt @/tmp/'
+ ble/keymap:vi_test/check A2 '@:cp ./foo.tx@t /tmp/' 'c w' '@:cp ./foo.tx@ /tmp/'
+ ble/keymap:vi_test/check A3 '@:cp ./fo@o.txt /tmp/' 'c w' '@:cp ./fo@.txt /tmp/'
+ ble/keymap:vi_test/check A4 '@:cp ./foo.t@xt /tmp/' 'c w' '@:cp ./foo.t@ /tmp/'
+ ble/keymap:vi_test/check A5 '@:cp ./fo@o.txt /tmp/' 'c W' '@:cp ./fo@ /tmp/'
+ ble/keymap:vi_test/check B1a '@:123@ 456 789' 'c w' '@:123@456 789'
+ ble/keymap:vi_test/check B1b '@:123@ 456 789' '1 c w' '@:123@456 789'
+ ble/keymap:vi_test/check B1c '@:123@ 456 789' '2 c w' '@:123@789'
+ ble/keymap:vi_test/check B2a '@:12@3 456 789' 'c w' '@:12@ 456 789'
+ ble/keymap:vi_test/check B2b '@:12@3 456 789' '1 c w' '@:12@ 456 789'
+ ble/keymap:vi_test/check B2c '@:12@3 456 789' '2 c w' '@:12@ 789'
+ ble/keymap:vi_test/check B3a '@:@123 456 789' 'c w' '@:@ 456 789'
+ ble/keymap:vi_test/check B3b '@:@123 456 789' '1 c w' '@:@ 456 789'
+ ble/keymap:vi_test/check B3c '@:@123 456 789' '2 c w' '@:@ 789'
+ ble/keymap:vi_test/check B4a '@:ab@c///漢字' 'c w' '@:ab@///漢字'
+ ble/keymap:vi_test/check B4b '@:ab@c///漢字' '1 c w' '@:ab@///漢字'
+ ble/keymap:vi_test/check B4c '@:ab@c///漢字' '2 c w' '@:ab@漢字'
+ ble/keymap:vi_test/check B5a '@:@abc///漢字' 'c w' '@:@///漢字'
+ ble/keymap:vi_test/check B5b '@:@abc///漢字' '1 c w' '@:@///漢字'
+ ble/keymap:vi_test/check B5c '@:@abc///漢字' '2 c w' '@:@漢字'
+ ble/keymap:vi_test/check C1 $'@:123 456 @ \n\n789' 'c w' $'@:123 456 @\n\n789'
+ ble/keymap:vi_test/check C2 $'@:123 456 \n@\n789' 'c w' $'@:123 456 \n@\n789'
+ ble/keymap:vi_test/check C3 $'@:123 45@6 \n\n789' 'c w' $'@:123 45@ \n\n789'
+ ble/keymap:vi_test/check C4 $'@:123 456@ \n\n789\nabc' '2 c w' $'@:123 456@\n789\nabc'
+ ble/keymap:vi_test/check C5 $'@:123 45@6 \n\n789\nabc' '2 c w' $'@:123 45@\nabc'
+ ble/keymap:vi_test/check C6 $'@:123 4@56 \n\n789\nabc' '2 c w' $'@:123 4@\nabc'
+ ble/keymap:vi_test/check C7 $'@:123 456@ \n\n\n789\nabc' '2 c w' $'@:123 456@\n\n789\nabc'
+ ble/keymap:vi_test/check C8 $'@:123 45@6 \n\n\n789\nabc' '2 c w' $'@:123 45@\nabc'
+ ble/keymap:vi_test/check C9 $'@:123 4@56 \n\n\n789\nabc' '2 c w' $'@:123 4@\nabc'
+ ble/keymap:vi_test/check C9 $'@:123 456 \n\n@' '2 c w' $'@:123 456 \n\n@'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/search {
+ ble/keymap:vi_test/start-section '/ ? n N'
+ ble/keymap:vi_test/check A1a '@:ech@o abc abc abc' '/ a b c RET' '@:echo @abc abc abc'
+ ble/keymap:vi_test/check A1b '@:ech@o abc abc abc' '/ a b c RET n' '@:echo abc @abc abc'
+ ble/keymap:vi_test/check A1c '@:ech@o abc abc abc' '/ a b c RET 2 n' '@:echo abc abc @abc'
+ ble/keymap:vi_test/check A1d '@:ech@o abc abc abc' '/ a b c RET 2 n N' '@:echo abc @abc abc'
+ ble/keymap:vi_test/check A2a '@:echo@ abc abc abc' '/ a b c RET' '@:echo @abc abc abc'
+ ble/keymap:vi_test/check A2b '@:echo @abc abc abc' '/ a b c RET' '@:echo abc @abc abc'
+ ble/keymap:vi_test/check A2c '@:echo a@bc abc abc' '/ a b c RET' '@:echo abc @abc abc'
+ ble/keymap:vi_test/check A3a '@:echo abc@ abc abc' '? a b c RET' '@:echo @abc abc abc'
+ ble/keymap:vi_test/check A3b '@:echo abc @abc abc' '? a b c RET' '@:echo @abc abc abc'
+ ble/keymap:vi_test/check A3c '@:echo abc a@bc abc' '? a b c RET' '@:echo abc @abc abc'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/increment {
+ ble/keymap:vi_test/start-section '<C-a>, <C-x>'
+ ble/keymap:vi_test/check A1a '@:@123' 'C-a' '@:12@4'
+ ble/keymap:vi_test/check A1b '@:@123' 'C-x' '@:12@2'
+ ble/keymap:vi_test/check A1c '@:@-123' 'C-a' '@:-12@2'
+ ble/keymap:vi_test/check A1d '@:@-123' 'C-x' '@:-12@4'
+ ble/keymap:vi_test/check A2a '@:@ -123 0' 'C-a' '@: -12@2 0'
+ ble/keymap:vi_test/check A2b '@: @-123 0' 'C-a' '@: -12@2 0'
+ ble/keymap:vi_test/check A2c '@: -@123 0' 'C-a' '@: -12@2 0'
+ ble/keymap:vi_test/check A2d '@: -1@23 0' 'C-a' '@: -12@2 0'
+ ble/keymap:vi_test/check A2e '@: -12@3 0' 'C-a' '@: -12@2 0'
+ ble/keymap:vi_test/check A2f '@: -123@ 0' 'C-a' '@: -123 @1'
+ ble/keymap:vi_test/check A3a '@:@000' 'C-a' '@:00@1'
+ ble/keymap:vi_test/check A3b '@:@000' '1 0 C-a' '@:01@0'
+ ble/keymap:vi_test/check A3c '@:@000' '1 0 0 C-a' '@:10@0'
+ ble/keymap:vi_test/check A3d '@:@000' 'C-x' '@:-00@1'
+ ble/keymap:vi_test/check A3e '@:@000' '1 0 C-x' '@:-01@0'
+ ble/keymap:vi_test/check A3f '@:@000' '1 0 0 C-x' '@:-10@0'
+ ble/keymap:vi_test/check A3g '@:@099' '1 0 0 C-x' '@:-00@1'
+ ble/keymap:vi_test/check A3h '@:@099' '9 9 C-x' '@:00@0'
+ ble/keymap:vi_test/check A4a '@:-@0' 'C-a' '@:@1'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/macro {
+ local _ble_decode_keylog_depth=0
+ local _ble_keymap_vi_test_ble_decode=ble-decode-char
+ local ble_decode_char_sync=1
+ ble/keymap:vi_test/start-section 'qx..q'
+ ble/keymap:vi_test/check A1 '@:@123' 'q a A SP h e l l o @ESC q @ a' '@:123 hello hell@o'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/surround {
+ ble/keymap:vi_test/start-section 'surround'
+ ble/keymap:vi_test/check A1a '@:abcd @fghi jklm nopq' 'y s e a' '@:abcd @<fghi> jklm nopq'
+ ble/keymap:vi_test/check A1b '@:abcd @fghi jklm nopq' 'y s w a' '@:abcd @<fghi> jklm nopq'
+ ble/keymap:vi_test/check A1c '@:abcd @fghi jklm nopq' 'y s a w a' '@:abcd @<fghi> jklm nopq'
+ ble/keymap:vi_test/check A1d '@:abcd @ jklm nopq' 'y s 3 l a' '@:abcd @<> jklm nopq'
+ ble/keymap:vi_test/check A2a '@:abcd @fghi jklm nopq' 'v 3 l S a' '@:abcd @<fghi> jklm nopq'
+ ble/keymap:vi_test/check A2b '@:abcd @fghi jklm nopq' 'v 4 l S a' '@:abcd @<fghi >jklm nopq'
+ ble/keymap:vi_test/check A2c '@:abcd @fghi jklm nopq' 'h v 5 l S a' '@:abcd@< fghi >jklm nopq'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/xmap_txtobj_quote {
+ ble/keymap:vi_test/start-section 'xmap text object i" a"'
+ ble/keymap:vi_test/check A1a '@:ab@cd " fghi " jklm " nopq " rstu " vwxyz' 'v i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A1b '@:abcd @" fghi " jklm " nopq " rstu " vwxyz' 'v i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A1c '@:abcd " fghi@ " jklm " nopq " rstu " vwxyz' 'v i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A1d '@:abcd " fghi @" jklm " nopq " rstu " vwxyz' 'v i " S a' '@:abcd " fghi "@< jklm >" nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A2a '@:ab@cd " fghi " jklm " nopq " rstu " vwxyz' 'v 2 i " S a' '@:abcd @<" fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A2b '@:ab@cd " fghi " jklm " nopq " rstu " vwxyz' 'v a " S a' '@:abcd @<" fghi " >jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A2c '@:ab@cd " fghi " jklm " nopq " rstu " vwxyz' 'v 2 a " S a' '@:abcd @<" fghi " >jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A3a '@:ab@cd "" jklm " nopq " rstu " vwxyz' 'v i " S a' '@:abcd @<""> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check A3b '@:ab@cd "" jklm " nopq " rstu " vwxyz' 'v 2 i " S a' '@:abcd @<""> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B1a '@:abcd@ " fghi " jklm " nopq " rstu " vwxyz' 'v l i " S a' '@:abcd@< " fghi " jklm >" nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B1b '@:abcd " fghi " jklm " nopq@ " rstu " vwxyz' 'v l i " S a' '@:abcd " fghi " jklm " nopq@< " rstu >" vwxyz'
+ ble/keymap:vi_test/check B1c '@:abc@d " fghi " jklm " nopq " rstu " vwxyz' 'v l i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B1d '@:abcd " fgh@i " jklm " nopq " rstu " vwxyz' 'v l i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B1e '@:abcd " fghi " @jklm " nopq " rstu " vwxyz' 'v l i " S a' '@:abcd " fghi " jklm "@< nopq >" rstu " vwxyz'
+ ble/keymap:vi_test/check B1f '@:abcd " fghi "@ jklm " nopq " rstu " vwxyz' 'v l i " S a' '@:abcd " fghi "@< jklm " nopq >" rstu " vwxyz'
+ ble/keymap:vi_test/check B2a '@:abcd@ " fghi " jklm " nopq " rstu " vwxyz' 'v l 2 i " S a' '@:abcd@< " fghi " jklm "> nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B2b '@:abcd " fghi " jklm " nopq@ " rstu " vwxyz' 'v l 2 i " S a' '@:abcd " fghi " jklm " nopq@< " rstu "> vwxyz'
+ ble/keymap:vi_test/check B2c '@:abc@d " fghi " jklm " nopq " rstu " vwxyz' 'v l 2 i " S a' '@:abcd @<" fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B2d '@:abcd " fgh@i " jklm " nopq " rstu " vwxyz' 'v l 2 i " S a' '@:abcd @<" fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B2e '@:abcd " fghi " @jklm " nopq " rstu " vwxyz' 'v l 2 i " S a' '@:abcd " fghi " jklm @<" nopq "> rstu " vwxyz'
+ ble/keymap:vi_test/check B2f '@:abcd " fghi "@ jklm " nopq " rstu " vwxyz' 'v l 2 i " S a' '@:abcd " fghi "@< jklm " nopq "> rstu " vwxyz'
+ ble/keymap:vi_test/check B3a '@:abcd@ " fghi " jklm " nopq " rstu " vwxyz' 'v l a " S a' '@:abcd@< " fghi " jklm " >nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B3b '@:abcd " fghi " jklm " nopq@ " rstu " vwxyz' 'v l a " S a' '@:abcd " fghi " jklm " nopq@< " rstu " >vwxyz'
+ ble/keymap:vi_test/check B3c '@:abc@d " fghi " jklm " nopq " rstu " vwxyz' 'v l a " S a' '@:abcd @<" fghi " >jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B3d '@:abcd " fgh@i " jklm " nopq " rstu " vwxyz' 'v l a " S a' '@:abcd @<" fghi " >jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check B3e '@:abcd " fghi " @jklm " nopq " rstu " vwxyz' 'v l a " S a' '@:abcd " fghi " jklm @<" nopq " >rstu " vwxyz'
+ ble/keymap:vi_test/check B3f '@:abcd " fghi "@ jklm " nopq " rstu " vwxyz' 'v l a " S a' '@:abcd " fghi "@< jklm " nopq " >rstu " vwxyz'
+ ble/keymap:vi_test/check C1a '@:abc@d " fghi " jklm " nopq " rstu " vwxyz' 'v h i " S a' '@:ab@<cd> " fghi " jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C1b '@:abcd " @fghi " jklm " nopq " rstu " vwxyz' 'v h i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C1c '@:abcd " fghi@ " jklm " nopq " rstu " vwxyz' 'v h i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C1d '@:abcd " fghi @" jklm " nopq " rstu " vwxyz' 'v h i " S a' '@:abcd "@< fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C1e '@:abcd " fghi " jkl@m " nopq " rstu " vwxyz' 'v h i " S a' '@:abcd "@< fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C1f '@:abcd " fghi " jkl@m " nopq " rstu " vwxyz' 'v 5 h i " S a' '@:abcd "@< fghi " jklm> " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C2a '@:abc@d " fghi " jklm " nopq " rstu " vwxyz' 'v h 2 i " S a' '@:ab@<cd> " fghi " jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C2b '@:abcd " @fghi " jklm " nopq " rstu " vwxyz' 'v h 2 i " S a' '@:abcd @<" fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C2c '@:abcd " fghi@ " jklm " nopq " rstu " vwxyz' 'v h 2 i " S a' '@:abcd @<" fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C2d '@:abcd " fghi @" jklm " nopq " rstu " vwxyz' 'v h 2 i " S a' '@:abcd @<" fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C2e '@:abcd " fghi " jkl@m " nopq " rstu " vwxyz' 'v h 2 i " S a' '@:abcd @<" fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C2f '@:abcd " fghi " jkl@m " nopq " rstu " vwxyz' 'v 5 h 2 i " S a' '@:abcd @<" fghi " jklm> " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C3a '@:abc@d " fghi " jklm " nopq " rstu " vwxyz' 'v h a " S a' '@:ab@<cd> " fghi " jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C3b '@:abcd " @fghi " jklm " nopq " rstu " vwxyz' 'v h a " S a' '@:abcd @<" fghi " >jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C3c '@:abcd " fghi@ " jklm " nopq " rstu " vwxyz' 'v h a " S a' '@:abcd @<" fghi >" jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C3d '@:abcd " fghi @" jklm " nopq " rstu " vwxyz' 'v h a " S a' '@:abcd @<" fghi "> jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C3e '@:abcd " fghi " jkl@m " nopq " rstu " vwxyz' 'v h a " S a' '@:abcd @<" fghi " >jklm " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/check C3f '@:abcd " fghi " jkl@m " nopq " rstu " vwxyz' 'v 5 h a " S a' '@:abcd @<" fghi " jklm> " nopq " rstu " vwxyz'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/txtobj_word {
+ ble/keymap:vi_test/start-section 'txtobj word omap'
+ ble/keymap:vi_test/check A1/iw '@:echo he@llo world "hello" "world"' 'd i w' '@:echo @ world "hello" "world"'
+ ble/keymap:vi_test/check A1/aw '@:echo he@llo world "hello" "world"' 'd a w' '@:echo @world "hello" "world"'
+ ble/keymap:vi_test/check A2/iw '@:echo hello@ world "hello" "world"' 'd i w' '@:echo hello@world "hello" "world"'
+ ble/keymap:vi_test/check A2/aw '@:echo hello@ world "hello" "world"' 'd a w' '@:echo hello@ "hello" "world"'
+ ble/keymap:vi_test/check A3/iw '@:echo hello world "he@llo" "world"' 'd i w' '@:echo hello world "@" "world"'
+ ble/keymap:vi_test/check A3/aw '@:echo hello world "he@llo" "world"' 'd a w' '@:echo hello world "@" "world"'
+ ble/keymap:vi_test/check A4/iw '@:echo hello world @"hello" "world"' 'd i w' '@:echo hello world @hello" "world"'
+ ble/keymap:vi_test/check A4/aw '@:echo hello world @"hello" "world"' 'd a w' '@:echo hello world@hello" "world"'
+ ble/keymap:vi_test/check A5/iw '@:echo hello world "hello@" "world"' 'd i w' '@:echo hello world "hello@ "world"'
+ ble/keymap:vi_test/check A5/aw '@:echo hello world "hello@" "world"' 'd a w' '@:echo hello world "hello@"world"'
+ ble/keymap:vi_test/check A1/2iw '@:echo he@llo world "hello" "world"' 'd 2 i w' '@:echo @world "hello" "world"'
+ ble/keymap:vi_test/check A1/2aw '@:echo he@llo world "hello" "world"' 'd 2 a w' '@:echo @"hello" "world"'
+ ble/keymap:vi_test/check A2/2iw '@:echo hello@ world "hello" "world"' 'd 2 i w' '@:echo hello@ "hello" "world"'
+ ble/keymap:vi_test/check A2/2aw '@:echo hello@ world "hello" "world"' 'd 2 a w' '@:echo hello@hello" "world"'
+ ble/keymap:vi_test/check A3/2iw '@:echo hello world "he@llo" "world"' 'd 2 i w' '@:echo hello world "@ "world"'
+ ble/keymap:vi_test/check A3/2aw '@:echo hello world "he@llo" "world"' 'd 2 a w' '@:echo hello world "@"world"'
+ ble/keymap:vi_test/check A4/2iw '@:echo hello world @"hello" "world"' 'd 2 i w' '@:echo hello world @" "world"'
+ ble/keymap:vi_test/check A4/2aw '@:echo hello world @"hello" "world"' 'd 2 a w' '@:echo hello world@" "world"'
+ ble/keymap:vi_test/check A5/2iw '@:echo hello world "hello@" "world"' 'd 2 i w' '@:echo hello world "hello@"world"'
+ ble/keymap:vi_test/check A5/2aw '@:echo hello world "hello@" "world"' 'd 2 a w' '@:echo hello world "hello@world"'
+ ble/keymap:vi_test/check A6/iw $'@:echo@ \n hello world' 'd i w' $'@:ech@o\n hello world'
+ ble/keymap:vi_test/check A6/aw $'@:echo@ \n hello world' 'd a w' $'@:echo@ world'
+ ble/keymap:vi_test/check A7.2/iw $'@:echo\n@\nhello\n\nworld\nZ' 'd i w' $'@:echo\n@\nhello\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.2/aw $'@:echo\n@\nhello\n\nworld\nZ' 'd a w' $'@:echo\n@\nworld\nZ'
+ ble/keymap:vi_test/check A7.2/2iw $'@:echo\n@\nhello\n\nworld\nZ' 'd 2 i w' $'@:echo\n@\nworld\nZ'
+ ble/keymap:vi_test/check A7.2/2aw $'@:echo\n@\nhello\n\nworld\nZ' 'd 2 a w' $'@:echo\n@Z'
+ ble/keymap:vi_test/check A7.1/1diw $'@:echo\n@\nhello\nworld\nZ' 'd 1 i w' $'@:echo\n@\nhello\nworld\nZ'
+ ble/keymap:vi_test/check A7.1/2diw $'@:echo\n@\nhello\nworld\nZ' 'd 2 i w' $'@:echo\n@world\nZ'
+ ble/keymap:vi_test/check A7.1/3diw $'@:echo\n@\nhello\nworld\nZ' 'd 3 i w' $'@:echo\n@Z'
+ ble/keymap:vi_test/check A7.2/1diw $'@:echo\n@\nhello\n\nworld\nZ' 'd 1 i w' $'@:echo\n@\nhello\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.2/2diw $'@:echo\n@\nhello\n\nworld\nZ' 'd 2 i w' $'@:echo\n@\nworld\nZ'
+ ble/keymap:vi_test/check A7.2/3diw $'@:echo\n@\nhello\n\nworld\nZ' 'd 3 i w' $'@:echo\n@world\nZ'
+ ble/keymap:vi_test/check A7.2/4diw $'@:echo\n@\nhello\n\nworld\nZ' 'd 4 i w' $'@:echo\n@Z'
+ ble/keymap:vi_test/check A7.3/1diw $'@:echo\n@\nhello\n\n\nworld\nZ' 'd 1 i w' $'@:echo\n@\nhello\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.3/2diw $'@:echo\n@\nhello\n\n\nworld\nZ' 'd 2 i w' $'@:echo\n@\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.3/3diw $'@:echo\n@\nhello\n\n\nworld\nZ' 'd 3 i w' $'@:echo\n@\nworld\nZ'
+ ble/keymap:vi_test/check A7.3/4diw $'@:echo\n@\nhello\n\n\nworld\nZ' 'd 4 i w' $'@:echo\n@Z'
+ ble/keymap:vi_test/check A7.4/1diw $'@:echo\n@\nhello\n\n\n\nworld\nZ' 'd 1 i w' $'@:echo\n@\nhello\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.4/2diw $'@:echo\n@\nhello\n\n\n\nworld\nZ' 'd 2 i w' $'@:echo\n@\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.4/3diw $'@:echo\n@\nhello\n\n\n\nworld\nZ' 'd 3 i w' $'@:echo\n@\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.4/4diw $'@:echo\n@\nhello\n\n\n\nworld\nZ' 'd 4 i w' $'@:echo\n@world\nZ'
+ ble/keymap:vi_test/check A7.4/5diw $'@:echo\n@\nhello\n\n\n\nworld\nZ' 'd 5 i w' $'@:echo\n@Z'
+ ble/keymap:vi_test/check A7.5/1diw $'@:echo\n@\nhello\n\n\n\n\nworld\nZ' 'd 1 i w' $'@:echo\n@\nhello\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.5/2diw $'@:echo\n@\nhello\n\n\n\n\nworld\nZ' 'd 2 i w' $'@:echo\n@\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.5/3diw $'@:echo\n@\nhello\n\n\n\n\nworld\nZ' 'd 3 i w' $'@:echo\n@\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.5/4diw $'@:echo\n@\nhello\n\n\n\n\nworld\nZ' 'd 4 i w' $'@:echo\n@\nworld\nZ'
+ ble/keymap:vi_test/check A7.5/5diw $'@:echo\n@\nhello\n\n\n\n\nworld\nZ' 'd 5 i w' $'@:echo\n@Z'
+ local A7_a=$'@:echo\n@\nhello\n\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/1ciw "$A7_a" 'c 1 i w' $'@:echo\n@\nhello\n\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/2ciw "$A7_a" 'c 2 i w' $'@:echo\n@\n\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/3ciw "$A7_a" 'c 3 i w' $'@:echo\n@\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/4ciw "$A7_a" 'c 4 i w' $'@:echo\n@\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/5ciw "$A7_a" 'c 5 i w' $'@:echo\n@\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/6ciw "$A7_a" 'c 6 i w' $'@:echo\n@\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/7ciw "$A7_a" 'c 7 i w' $'@:echo\n@\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/8ciw "$A7_a" 'c 8 i w' $'@:echo\n@\nZ'
+ ble/keymap:vi_test/check A7.a/1diw "$A7_a" 'd 1 i w' $'@:echo\n@\nhello\n\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/2diw "$A7_a" 'd 2 i w' $'@:echo\n@\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/3diw "$A7_a" 'd 3 i w' $'@:echo\n@\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/4diw "$A7_a" 'd 4 i w' $'@:echo\n@\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/5diw "$A7_a" 'd 5 i w' $'@:echo\n@\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/6diw "$A7_a" 'd 6 i w' $'@:echo\n@\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/7diw "$A7_a" 'd 7 i w' $'@:echo\n@world\nZ'
+ ble/keymap:vi_test/check A7.a/8diw "$A7_a" 'd 8 i w' $'@:echo\n@Z'
+ ble/keymap:vi_test/check A7.a/1caw "$A7_a" 'c 1 a w' $'@:echo\n@\n\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/2caw "$A7_a" 'c 2 a w' $'@:echo\n@\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/3caw "$A7_a" 'c 3 a w' $'@:echo\n@\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/4caw "$A7_a" 'c 4 a w' $'@:echo\n@\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/5caw "$A7_a" 'c 5 a w' $'@:echo\n@\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/6caw "$A7_a" 'c 6 a w' $'@:echo\n@\nZ'
+ ble/keymap:vi_test/check A7.a/1daw "$A7_a" 'd 1 a w' $'@:echo\n@\n\n\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/2daw "$A7_a" 'd 2 a w' $'@:echo\n@\n\n\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/3daw "$A7_a" 'd 3 a w' $'@:echo\n@\n\n\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/4daw "$A7_a" 'd 4 a w' $'@:echo\n@\n\n\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/5daw "$A7_a" 'd 5 a w' $'@:echo\n@\nworld\nZ'
+ ble/keymap:vi_test/check A7.a/6daw "$A7_a" 'd 6 a w' $'@:echo\n@Z'
+ ble/keymap:vi_test/check A8.0/2aw $'@:echo\n@\nhello\n\nworld\n' 'd 2 a w' $'@:@echo'
+ ble/keymap:vi_test/check A8.2/2aw $'@: echo\n@\nhello\n\nworld\n' 'd 2 a w' $'@: @echo'
+ ble/keymap:vi_test/check A9.1/ciw $'@:@ \necho' 'c i w' $'@:@\necho'
+ ble/keymap:vi_test/check A9.2/ciw $'@:@\n echo' 'c i w' $'@:@\n echo'
+ ble/keymap:vi_test/show-summary
+ ble/keymap:vi_test/start-section 'txtobj word xmap'
+ ble/keymap:vi_test/check B1/viw.1 '@:echo he@llo world "hello" "world"' 'v i w S a' '@:echo @<hello> world "hello" "world"'
+ ble/keymap:vi_test/check B1/vaw.1 '@:echo he@llo world "hello" "world"' 'v a w S a' '@:echo @<hello >world "hello" "world"'
+ ble/keymap:vi_test/check B2/viw.2 '@:echo hello@ world "hello" "world"' 'v i w S a' '@:echo hello@< >world "hello" "world"'
+ ble/keymap:vi_test/check B2/vaw.2 '@:echo hello@ world "hello" "world"' 'v a w S a' '@:echo hello@< world> "hello" "world"'
+ ble/keymap:vi_test/check B3/viw.3 '@:echo hello world "he@llo" "world"' 'v i w S a' '@:echo hello world "@<hello>" "world"'
+ ble/keymap:vi_test/check B3/vaw.3 '@:echo hello world "he@llo" "world"' 'v a w S a' '@:echo hello world "@<hello>" "world"'
+ ble/keymap:vi_test/check B4/viw.4 '@:echo hello world @"hello" "world"' 'v i w S a' '@:echo hello world @<">hello" "world"'
+ ble/keymap:vi_test/check B4/vaw.4 '@:echo hello world @"hello" "world"' 'v a w S a' '@:echo hello world@< ">hello" "world"'
+ ble/keymap:vi_test/check B5/viw.5 '@:echo hello world "hello@" "world"' 'v i w S a' '@:echo hello world "hello@<"> "world"'
+ ble/keymap:vi_test/check B5/vaw.5 '@:echo hello world "hello@" "world"' 'v a w S a' '@:echo hello world "hello@<" >"world"'
+ ble/keymap:vi_test/check B1/v2iw.1 '@:echo he@llo world "hello" "world"' 'v 2 i w S a' '@:echo @<hello >world "hello" "world"'
+ ble/keymap:vi_test/check B1/v2aw.1 '@:echo he@llo world "hello" "world"' 'v 2 a w S a' '@:echo @<hello world >"hello" "world"'
+ ble/keymap:vi_test/check B2/v2iw.2 '@:echo hello@ world "hello" "world"' 'v 2 i w S a' '@:echo hello@< world> "hello" "world"'
+ ble/keymap:vi_test/check B2/v2aw.2 '@:echo hello@ world "hello" "world"' 'v 2 a w S a' '@:echo hello@< world ">hello" "world"'
+ ble/keymap:vi_test/check B3/v2iw.3 '@:echo hello world "he@llo" "world"' 'v 2 i w S a' '@:echo hello world "@<hello"> "world"'
+ ble/keymap:vi_test/check B3/v2aw.3 '@:echo hello world "he@llo" "world"' 'v 2 a w S a' '@:echo hello world "@<hello" >"world"'
+ ble/keymap:vi_test/check B4/v2iw.4 '@:echo hello world @"hello" "world"' 'v 2 i w S a' '@:echo hello world @<"hello>" "world"'
+ ble/keymap:vi_test/check B4/v2aw.4 '@:echo hello world @"hello" "world"' 'v 2 a w S a' '@:echo hello world@< "hello>" "world"'
+ ble/keymap:vi_test/check B5/v2iw.5 '@:echo hello world "hello@" "world"' 'v 2 i w S a' '@:echo hello world "hello@<" >"world"'
+ ble/keymap:vi_test/check B5/v2aw.5 '@:echo hello world "hello@" "world"' 'v 2 a w S a' '@:echo hello world "hello@<" ">world"'
+ ble/keymap:vi_test/check B2/v1hiw '@:echo hello wo@rld' 'v 1 h i w S a' '@:echo hello @<wor>ld'
+ ble/keymap:vi_test/check B2/v2hiw '@:echo hello wo@rld' 'v 2 h i w S a' '@:echo hello@< wor>ld'
+ ble/keymap:vi_test/check B2/v3hiw '@:echo hello wo@rld' 'v 3 h i w S a' '@:echo hello@< wor>ld'
+ ble/keymap:vi_test/check B2/v4hiw '@:echo hello wo@rld' 'v 4 h i w S a' '@:echo @<hello wor>ld'
+ ble/keymap:vi_test/check B2/v1haw '@:echo hello wo@rld' 'v 1 h a w S a' '@:echo hello@< wor>ld'
+ ble/keymap:vi_test/check B2/v2haw '@:echo hello wo@rld' 'v 2 h a w S a' '@:echo @<hello wor>ld'
+ ble/keymap:vi_test/check B2/v3haw '@:echo hello wo@rld' 'v 3 h a w S a' '@:echo @<hello wor>ld'
+ ble/keymap:vi_test/check B2/v4haw '@:echo hello wo@rld' 'v 4 h a w S a' '@:echo@< hello wor>ld'
+ ble/keymap:vi_test/check B1/v1haw '@:echo he@llo' 'v 1 h a w S a' '@:echo@< hel>lo'
+ ble/keymap:vi_test/check B1/v2haw '@:echo he@llo' 'v 2 h a w S a' '@:@<echo hel>lo'
+ ble/keymap:vi_test/check B1/v3haw '@:echo he@llo' 'v 3 h a w S a' '@:e@<cho hel>lo'
+ ble/keymap:vi_test/check B1/v4haw '@:echo he@llo' 'v 4 h a w S a' '@:e@<cho hel>lo'
+ ble/keymap:vi_test/check Bn/viw $'@:@echo hello\necho world' 'v $ o $ i w c' $'@:echo hell@echo world'
+ ble/keymap:vi_test/check Bn/viw $'@:@echo hello \necho world' 'v $ o $ i w c' $'@:echo hello@\necho world'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode/op.2018-02-22 {
+ ble/keymap:vi_test/start-section 'op.2018-02-22'
+ ble/keymap:vi_test/check A0 $'@:12@345\n67890\n' 'y y p' $'@:12345\n@12345\n67890\n'
+ ble/keymap:vi_test/check B1 $'@:12@345\n67890\n' 'Y' $'@:12@345\n67890\n'
+ ble/keymap:vi_test/check B2 $'@:12@345\n67890\n' 'y y' $'@:12@345\n67890\n'
+ ble/keymap:vi_test/check C $'@:\n12@34567\n1あ2345\n12い345\n123う45\n1234え5\n' 'C-v 4 j l d' $'@:\n12@567\n1 345\n12345\n12 45\n12え5\n'
+ ble/keymap:vi_test/show-summary
+}
+function ble/widget/vi-command:check-vi-mode {
+ local original_str=$_ble_edit_str
+ local original_ind=$_ble_edit_ind
+ local original_mark=$_ble_edit_mark
+ local original_mark_active=$_ble_edit_mark_active
+ _ble_edit_line_disabled=1 ble/widget/.insert-newline # #D1800 pair=leave-command-layout
+ ble/util/buffer.flush >&2
+ local section ntest nsuccess
+ ble/widget/vi-command:check-vi-mode/space
+ ble/widget/vi-command:check-vi-mode/cw
+ ble/widget/vi-command:check-vi-mode/search
+ ble/widget/vi-command:check-vi-mode/increment
+ ble/widget/vi-command:check-vi-mode/macro
+ ble/widget/vi-command:check-vi-mode/surround
+ ble/widget/vi-command:check-vi-mode/xmap_txtobj_quote
+ ble/widget/vi-command:check-vi-mode/op.2018-02-22
+ ble/widget/vi-command:check-vi-mode/txtobj_word
+ ble-edit/content/reset "$original_str" edit
+ _ble_edit_ind=$original_ind
+ _ble_edit_mark=$original_mark
+ _ble_edit_mark_active=$original_mark_active
+ ble/edit/leave-command-layout # #D1800 pair=.insert-newline
+ return 0
+}
+function ble/widget/vi_imap/check-vi-mode {
+ ble/widget/vi_imap/normal-mode
+ ble/widget/vi-command:check-vi-mode
+ return 0
+}
+ble-bind -m vi_imap -f 'C-\ C-\' vi_imap/check-vi-mode
+ble-bind -m vi_nmap -f 'C-\ C-\' vi-command:check-vi-mode
diff --git a/.local/src/blesh/lib/core-cmdspec.sh b/.local/src/blesh/lib/core-cmdspec.sh
new file mode 100644
index 0000000..9da62a8
--- /dev/null
+++ b/.local/src/blesh/lib/core-cmdspec.sh
@@ -0,0 +1,66 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+function ble/cmdspec/initialize { return 0; }
+function ble/complete/opts/initialize {
+ ble/cmdspec/opts mandb-help printf
+ ble/cmdspec/opts mandb-disable-man:mandb-help bind
+ ble/cmdspec/opts mandb-disable-man:mandb-help:mandb-help-usage complete
+ ble/cmdspec/opts mandb-disable-man:no-options : true false
+ ble/cmdspec/opts mandb-help=%'help echo':stop-options-unless='^-[neE]+$' echo
+ local conditional_operators='
+ -eq (NUM1 -eq NUM2) Arithmetic comparison ==.
+ -ne (NUM1 -ne NUM2) Arithmetic comparison !=.
+ -lt (NUM1 -lt NUM2) Arithmetic comparison < .
+ -le (NUM1 -le NUM2) Arithmetic comparison <=.
+ -gt (NUM1 -gt NUM2) Arithmetic comparison > .
+ -ge (NUM1 -ge NUM2) Arithmetic comparison >=.
+ -nt (FILE1 -nt FILE2) True if file1 is newer than file2 (according to modification date).
+ -ot (FILE1 -ot FILE2) True if file1 is older than file2.
+ -ef (FILE1 -ef FILE2) True if file1 is a hard link to file2.'
+ ble/cmdspec/opts disable-double-hyphen:mandb-help=%'help test':mandb-help=@"$conditional_operators" '[['
+ local test_operators=$conditional_operators'
+ -a (EXPR1 -a EXPR2) True if both expr1 AND expr2 are true.
+ -a (EXPR1 -o EXPR2) True if either expr1 OR expr2 is true.'
+ ble/cmdspec/opts disable-double-hyphen:mandb-help=%'help test':mandb-help=@"$test_operators" 'test' '['
+ ble/cmdspec/opts mandb-disable-man:mandb-help:stop-options-postarg:plus-options=aAilnrtux declare typeset local
+ ble/cmdspec/opts mandb-disable-man:mandb-help:stop-options-postarg local export readonly
+ ble/cmdspec/opts mandb-disable-man:mandb-help:stop-options-postarg alias
+ ble/cmdspec/opts mandb-help rsync
+}
+ble/complete/opts/initialize
+function ble/cmdinfo/cmd:declare/chroma.wattr {
+ local ret
+ if ((wtype==_ble_attr_VAR)); then
+ ble/syntax:bash/find-rhs "$wtype" "$wbeg" "$wlen" element-assignment &&
+ ble/progcolor/highlight-filename.wattr "$ret" "$wend"
+ else
+ ble/progcolor/eval-word || return "$?"
+ local wval=$ret
+ if ble/string#match "$wval" '^([_a-zA-Z][_a-zA-Z0-9]*)(\[.+\])?$'; then
+ local varname=${BASH_REMATCH[1]}
+ ble/syntax/highlight/vartype "$varname"
+ ble/progcolor/wattr#setattr "$wbeg" "$ret"
+ ble/progcolor/wattr#setattr $((wbeg+${#varname})) d
+ elif ble/string#match "$wval" '^[-+]' && ble/progcolor/is-option-context; then
+ local ret; ble/color/face2g argument_option
+ ble/progcolor/wattr#setg "$wbeg" "$ret"
+ else
+ local ret; ble/color/face2g argument_error
+ ble/progcolor/wattr#setg "$wbeg" "$ret"
+ fi
+ fi
+ return 0
+}
+function ble/cmdinfo/cmd:declare/chroma {
+ local i "${_ble_syntax_progcolor_vars[@]/%/=}" # WA #D1570 checked
+ for ((i=1;i<${#comp_words[@]};i++)); do
+ local ref=${tree_words[i]}
+ [[ $ref ]] || continue
+ local progcolor_iword=$i
+ ble/progcolor/load-word-data "$ref"
+ ble/progcolor/@wattr ble/cmdinfo/cmd:declare/chroma.wattr
+ done
+}
+function ble/cmdinfo/cmd:typeset/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; }
+function ble/cmdinfo/cmd:local/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; }
+function ble/cmdinfo/cmd:readonly/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; }
+function ble/cmdinfo/cmd:export/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; }
diff --git a/.local/src/blesh/lib/core-complete.sh b/.local/src/blesh/lib/core-complete.sh
new file mode 100644
index 0000000..9d7c4c1
--- /dev/null
+++ b/.local/src/blesh/lib/core-complete.sh
@@ -0,0 +1,6327 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble/util/import "$_ble_base/lib/core-syntax.sh"
+function ble/complete/string#search-longest-suffix-in {
+ local needle=$1 haystack=$2
+ local l=0 u=${#needle}
+ while ((l<u)); do
+ local m=$(((l+u)/2))
+ if [[ $haystack == *"${needle:m}"* ]]; then
+ u=$m
+ else
+ l=$((m+1))
+ fi
+ done
+ ret=${needle:l}
+}
+function ble/complete/string#common-suffix-prefix {
+ local lhs=$1 rhs=$2
+ if ((${#lhs}<${#rhs})); then
+ local i n=${#lhs}
+ for ((i=0;i<n;i++)); do
+ ret=${lhs:i}
+ [[ $rhs == "$ret"* ]] && return 0
+ done
+ ret=
+ else
+ local j m=${#rhs}
+ for ((j=m;j>0;j--)); do
+ ret=${rhs::j}
+ [[ $lhs == *"$ret" ]] && return 0
+ done
+ ret=
+ fi
+}
+function ble/complete/get-wordbreaks {
+ wordbreaks=$_ble_term_IFS$COMP_WORDBREAKS
+ [[ $wordbreaks == *'('* ]] && wordbreaks=${wordbreaks//['()']}'()'
+ [[ $wordbreaks == *']'* ]] && wordbreaks=']'${wordbreaks//']'}
+ [[ $wordbreaks == *'-'* ]] && wordbreaks=${wordbreaks//'-'}'-'
+}
+_ble_complete_menu_items=()
+_ble_complete_menu_class=
+_ble_complete_menu_param=
+_ble_complete_menu_version=
+_ble_complete_menu_page_style=
+_ble_complete_menu_ipage=
+_ble_complete_menu_offset=
+_ble_complete_menu_icons=()
+_ble_complete_menu_info_data=()
+_ble_complete_menu_selected=-1
+function ble/complete/menu#check-cancel {
+ ((menu_iloop++%menu_interval==0)) &&
+ [[ :$comp_type: != *:sync:* ]] &&
+ ble/decode/has-input
+}
+_ble_complete_menu_style_measure=()
+_ble_complete_menu_style_icons=()
+_ble_complete_menu_style_pages=()
+function ble/complete/menu#render-item {
+ if ble/is-function "$menu_class"/render-item; then
+ "$menu_class"/render-item "$@"
+ return "$?"
+ fi
+ local item=$1 opts=$2
+ local sgr0=$_ble_term_sgr0 sgr1=$_ble_term_rev
+ [[ :$opts: == *:selected:* ]] && local sgr0=$sgr1 sgr1=$sgr0
+ ble/canvas/trace-text "$item" nonewline:external-sgr
+ ret=$sgr0$ret$_ble_term_sgr0
+}
+function ble/complete/menu-style:align/construct/.measure-candidates-in-page {
+ local max_wcell=$bleopt_menu_align_max; ((max_wcell>cols&&(max_wcell=cols)))
+ ((wcell=bleopt_menu_align_min,wcell<2&&(wcell=2)))
+ local ncell=0 index=$begin
+ local item ret esc1 w
+ for item in "${menu_items[@]:begin}"; do
+ ble/complete/menu#check-cancel && return 148
+ local wcell_old=$wcell
+ local w=${_ble_complete_menu_style_measure[index]%%:*}
+ if [[ ! $w ]]; then
+ local x=0 y=0
+ ble/complete/menu#render-item "$item"; esc1=$ret
+ local w=$((y*cols+x))
+ _ble_complete_menu_style_measure[index]=$w:${#item}:$item$esc1
+ fi
+ local wcell_request=$((w++,w<=max_wcell?w:max_wcell))
+ ((wcell<wcell_request)) && wcell=$wcell_request
+ local line_ncell=$((cols/wcell))
+ local cand_ncell=$(((w+wcell-1)/wcell))
+ if [[ $menu_style == align-nowrap ]]; then
+ local x1=$((ncell%line_ncell*wcell))
+ local ncell_eol=$(((ncell/line_ncell+1)*line_ncell))
+ if ((x1>0&&x1+w>=cols)); then
+ ((ncell=ncell_eol+cand_ncell))
+ elif ((x1+w<cols)); then
+ ((ncell+=cand_ncell))
+ ((ncell>ncell_eol&&(ncell=ncell_eol)))
+ else
+ ((ncell+=cand_ncell))
+ fi
+ else
+ ((ncell+=cand_ncell))
+ fi
+ local max_ncell=$((line_ncell*lines))
+ ((index&&ncell>max_ncell)) && { wcell=$wcell_old; break; }
+ ((index++))
+ done
+ end=$index
+}
+function ble/complete/menu-style:align/construct-page {
+ x=0 y=0 esc=
+ local wcell=2
+ ble/complete/menu-style:align/construct/.measure-candidates-in-page
+ (($?==148)) && return 148
+ local ncell=$((cols/wcell))
+ local index=$begin entry
+ for entry in "${_ble_complete_menu_style_measure[@]:begin:end-begin}"; do
+ ble/complete/menu#check-cancel && return 148
+ local w=${entry%%:*}; entry=${entry#*:}
+ local s=${entry%%:*}; entry=${entry#*:}
+ local item=${entry::s} esc1=${entry:s}
+ local x0=$x y0=$y
+ if ((x==0||x+w<cols)); then
+ ((x+=w%cols,y+=w/cols))
+ ((y>=lines&&(x=x0,y=y0,1))) && break
+ else
+ if [[ $menu_style == align-nowrap ]]; then
+ ((y+1>=lines)) && break
+ esc=$esc$'\n'
+ ((x0=x=0,y0=++y))
+ ((x=w%cols,y+=w/cols))
+ ((y>=lines&&(x=x0,y=y0,1))) && break
+ else
+ ble/complete/menu#render-item "$item" ||
+ ((begin==index)) || # [Note: 少なくとも1個ははみ出ても表示する]
+ { x=$x0 y=$y0; break; }; esc1=$ret
+ fi
+ fi
+ _ble_complete_menu_style_icons[index]=$x0,$y0,$x,$y,${#item},${#esc1}:$item$esc1
+ esc=$esc$esc1
+ if ((++index<end)); then
+ local icell=$((x==0?0:(x+wcell)/wcell))
+ if ((icell<ncell)); then
+ local pad=$((icell*wcell-x))
+ ble/string#reserve-prototype "$pad"
+ esc=$esc${_ble_string_prototype::pad}
+ ((x=icell*wcell))
+ else
+ ((y+1>=lines)) && break
+ esc=$esc$'\n'
+ ((x=0,++y))
+ fi
+ fi
+ done
+ end=$index
+}
+function ble/complete/menu-style:align-nowrap/construct-page {
+ ble/complete/menu-style:align/construct-page "$@"
+}
+function ble/complete/menu-style:dense/construct-page {
+ x=0 y=0 esc=
+ local item index=$begin N=${#menu_items[@]}
+ for item in "${menu_items[@]:begin}"; do
+ ble/complete/menu#check-cancel && return 148
+ local x0=$x y0=$y esc1
+ ble/complete/menu#render-item "$item" ||
+ ((index==begin)) ||
+ { x=$x0 y=$y0; break; }; esc1=$ret
+ if [[ $menu_style == dense-nowrap ]]; then
+ if ((y>y0&&x>0||y>y0+1)); then
+ ((++y0>=lines)) && break
+ esc=$esc$'\n'
+ ((y=y0,x=x0=0))
+ ble/complete/menu#render-item "$item" ||
+ ((begin==index)) ||
+ { x=$x0 y=$y0; break; }; esc1=$ret
+ fi
+ fi
+ _ble_complete_menu_style_icons[index]=$x0,$y0,$x,$y,${#item},${#esc1}:$item$esc1
+ esc=$esc$esc1
+ if ((++index<N)); then
+ if [[ $menu_style == dense-nowrap ]] && ((x==0)); then
+ : skip
+ elif ((x+1<cols)); then
+ esc=$esc' '
+ ((x++))
+ else
+ ((y+1>=lines)) && break
+ esc=$esc$'\n'
+ ((x=0,++y))
+ fi
+ fi
+ done
+ end=$index
+}
+function ble/complete/menu-style:dense-nowrap/construct-page {
+ ble/complete/menu-style:dense/construct-page "$@"
+}
+function ble/complete/menu-style:linewise/construct-page {
+ local opts=$1 ret
+ local max_icon_width=$((cols-1))
+ local prefix_format=$bleopt_menu_linewise_prefix prefix_width=0
+ if [[ $prefix_format ]]; then
+ local prefix1
+ ble/util/sprintf prefix1 "$prefix_format" ${#menu_items[@]}
+ local x1 y1 x2 y2
+ LINES=1 COLUMNS=$max_icon_width x=0 y=0 ble/canvas/trace "$prefix1" truncate:measure-bbox
+ if ((x2<=max_icon_width/2)); then
+ prefix_width=$x2
+ ble/string#reserve-prototype "$prefix_width"
+ fi
+ fi
+ local item x0 y0 esc1 index=$begin
+ end=$begin x=0 y=0 esc=
+ for item in "${menu_items[@]:begin:lines}"; do
+ ble/complete/menu#check-cancel && return 148
+ if ((prefix_width)); then
+ local prefix1; ble/util/sprintf prefix1 "$prefix_format" $((index+1))
+ LINES=1 COLUMNS=$max_icon_width y=0 ble/canvas/trace "$prefix1" truncate:relative:measure-bbox; esc1=$ret
+ if ((x<prefix_width)); then
+ x=$prefix_width
+ esc=$esc${_ble_string_prototype::prefix_width-x}$esc1
+ else
+ esc=$esc$esc1
+ fi
+ fi
+ ((x0=x,y0=y))
+ lines=1 cols=$max_icon_width y=0 ble/complete/menu#render-item "$item"; esc1=$ret
+ _ble_complete_menu_style_icons[index]=$x0,$y0,$x,$y,${#item},${#esc1}:$item$esc1
+ ((index++))
+ esc=$esc$esc1
+ ((y+1>=lines)) && break
+ ((x=0,++y))
+ esc=$esc$'\n'
+ done
+ end=$index
+}
+function ble/complete/menu-style:linewise/guess {
+ ((ipage=scroll/lines,
+ begin=ipage*lines,
+ end=begin))
+}
+_ble_complete_menu_desc_pageheight=()
+function ble/complete/menu-style:desc/construct-page {
+ local opts=$1 ret
+ local opt_raw=; [[ $menu_style != desc-text ]] && opt_raw=1
+ end=$begin esc= x=0 y=0
+ local colsep=' | '
+ local desc_sgr0=$'\e[m'
+ ble/color/face2sgr-ansi syntax_quoted; local desc_sgrq=$ret
+ ble/color/face2sgr-ansi syntax_delimiter; local desc_sgrt=$ret
+ local ncolumn=1 nline=$lines
+ local nrest_item=$((${#menu_items[@]}-begin))
+ if [[ $bleopt_menu_desc_multicolumn_width ]]; then
+ ncolumn=$((cols/bleopt_menu_desc_multicolumn_width))
+ if ((ncolumn<1)); then
+ ncolumn=1
+ elif ((ncolumn>nrest_item)); then
+ ncolumn=$nrest_item
+ fi
+ fi
+ ((nline=(${#menu_items[@]}-begin+ncolumn-1)/ncolumn,
+ nline>lines&&(nline=lines)))
+ local ncolumn_max=$(((nrest_item+nline-1)/nline))
+ ((ncolumn>ncolumn_max&&(ncolumn=ncolumn_max)))
+ local available_width=$cols
+ case $_ble_term_TERM in
+ (screen:*|tmux:*|kitty:*|contra:*) ;;
+ (*) ((available_width--)) ;;
+ esac
+ local wcolumn=$(((available_width-${#colsep}*(ncolumn-1))/ncolumn))
+ local wcand_limit=$(((wcolumn+1)*2/3))
+ ((wcand_limit<10&&(wcand_limit=wcolumn)))
+ local -a DRAW_BUFF=()
+ local index=$begin icolumn ymax=0
+ for ((icolumn=0;icolumn<ncolumn;icolumn++)); do
+ local measure; measure=()
+ local pack w esc1 max_width=0
+ for pack in "${menu_items[@]:index:nline}"; do
+ ble/complete/menu#check-cancel && return 148
+ x=0 y=0
+ lines=1 cols=$wcand_limit ble/complete/menu#render-item "$pack"; esc1=$ret
+ ((w=y*wcolumn+x,w>max_width&&(max_width=w)))
+ ble/array#push measure "$w:${#pack}:$pack$esc1"
+ done
+ local cand_width=$max_width
+ local desc_x=$((cand_width+1)); ((desc_x>wcolumn&&(desc_x=wcolumn)))
+ local desc_prefix=; ((wcolumn-desc_x>30)) && desc_prefix=': '
+ local xcolumn=$((icolumn*(wcolumn+${#colsep})))
+ x=0 y=0
+ local entry w s pack esc1 x0 y0 pad
+ for entry in "${measure[@]}"; do
+ ble/complete/menu#check-cancel && return 148
+ w=${entry%%:*} entry=${entry#*:}
+ s=${entry%%:*} entry=${entry#*:}
+ pack=${entry::s} esc1=${entry:s}
+ ((x0=x,y0=y,x+=w))
+ _ble_complete_menu_style_icons[index]=$((xcolumn+x0)),$y0,$((xcolumn+x)),$y,${#pack},${#esc1},"0 0 $wcand_limit 1":$pack$esc1
+ ((index++))
+ ble/canvas/put.draw "$esc1"
+ ble/canvas/put-spaces.draw $((pad=desc_x-x))
+ ble/canvas/put.draw "$desc_prefix"
+ ((x+=pad+${#desc_prefix}))
+ local desc=$desc_sgrt'(no description)'$desc_sgr0
+ ble/function#try "$menu_class"/get-desc "$pack"
+ if [[ $opt_raw ]]; then
+ y=0 g=0 lc=0 lg=0 LINES=1 COLUMNS=$wcolumn ble/canvas/trace.draw "$desc" truncate:relative:ellipsis
+ else
+ y=0 lines=1 cols=$wcolumn ble/canvas/trace-text "$desc" nonewline
+ ble/canvas/put.draw "$ret"
+ fi
+ ble/canvas/put.draw "$_ble_term_sgr0"
+ ((y+1>=nline)) && break
+ ble/canvas/put-move.draw $((-x)) 1
+ ((x=0,++y))
+ done
+ ((y>ymax)) && ymax=$y
+ if ((icolumn+1<ncolumn)); then
+ ble/canvas/put-move.draw $((wcolumn-x)) $((-y))
+ for ((y=0;y<=ymax;y++)); do
+ ble/canvas/put.draw "$colsep"
+ if ((y<ymax)); then
+ ble/canvas/put-move.draw -${#colsep} 1
+ else
+ ble/canvas/put-move-y.draw $((-y))
+ fi
+ done
+ else
+ ((y<ymax)) && ble/canvas/put-move-y.draw $((ymax-y))
+ ((x+=xcolumn,y=ymax))
+ fi
+ done
+ _ble_complete_menu_desc_pageheight[ipage]=$nline
+ end=$index
+ ble/canvas/sflush.draw -v esc
+}
+function ble/complete/menu-style:desc/guess {
+ local ncolumn=1
+ if [[ $bleopt_menu_desc_multicolumn_width ]]; then
+ ncolumn=$((cols/bleopt_menu_desc_multicolumn_width))
+ ((ncolumn<1)) && ncolumn=1
+ fi
+ local nitem_per_page=$((ncolumn*lines))
+ ((ipage=scroll/nitem_per_page,
+ begin=ipage*nitem_per_page,
+ end=begin))
+}
+function ble/complete/menu-style:desc/locate {
+ local type=$1 osel=$2
+ local ipage=$_ble_complete_menu_ipage
+ local nline=${_ble_complete_menu_desc_pageheight[ipage]:-1}
+ case $type in
+ (right) ((ret=osel+nline)) ;;
+ (left) ((ret=osel-nline)) ;;
+ (down) ((ret=osel+1)) ;;
+ (up) ((ret=osel-1)) ;;
+ (*) return 1 ;;
+ esac
+ local beg=$_ble_complete_menu_offset
+ local end=$((beg+${#_ble_complete_menu_icons[@]}))
+ if ((ret<beg)); then
+ ((ret=beg-1))
+ elif ((ret>end)); then
+ ((ret=end))
+ fi
+ return 0
+}
+function ble/complete/menu-style:desc-text/construct-page { ble/complete/menu-style:desc/construct-page "$@"; }
+function ble/complete/menu-style:desc-text/guess { ble/complete/menu-style:desc/guess; }
+function ble/complete/menu-style:desc-text/locate { ble/complete/menu-style:desc/locate "$@"; }
+function ble/complete/menu-style:desc-raw/construct-page { ble/complete/menu-style:desc/construct-page "$@"; }
+function ble/complete/menu-style:desc-raw/guess { ble/complete/menu-style:desc/guess; }
+function ble/complete/menu-style:desc-raw/locate { ble/complete/menu-style:desc/locate "$@"; }
+function ble/complete/menu#construct/.initialize-size {
+ ble/edit/info/.initialize-size
+ local maxlines=$((bleopt_complete_menu_maxlines))
+ ((maxlines>0&&lines>maxlines)) && lines=$maxlines
+}
+function ble/complete/menu#construct {
+ local menu_opts=$1
+ local menu_iloop=0
+ local menu_interval=$bleopt_complete_polling_cycle
+ local cols lines
+ ble/complete/menu#construct/.initialize-size
+ local nitem=${#menu_items[@]}
+ local version=$nitem:$lines:$cols
+ if ((nitem==0)); then
+ _ble_complete_menu_version=$version
+ _ble_complete_menu_items=()
+ _ble_complete_menu_page_style=
+ _ble_complete_menu_ipage=0
+ _ble_complete_menu_offset=0
+ _ble_complete_menu_icons=()
+ _ble_complete_menu_info_data=(ansi $'\e[38;5;242m(no items)\e[m')
+ _ble_complete_menu_selected=-1
+ return 0
+ fi
+ local scroll=0 rex=':scroll=([0-9]+):' use_cache=
+ if [[ :$menu_opts: =~ $rex ]]; then
+ scroll=${BASH_REMATCH[1]}
+ ((nitem&&(scroll%=nitem)))
+ [[ $_ble_complete_menu_version == $version ]] && use_cache=1
+ fi
+ if [[ ! $use_cache ]]; then
+ _ble_complete_menu_style_measure=()
+ _ble_complete_menu_style_icons=()
+ _ble_complete_menu_style_pages=()
+ fi
+ local begin=0 end=0 ipage=0 x y esc
+ ble/function#try ble/complete/menu-style:"$menu_style"/guess
+ while ((end<nitem)); do
+ ((scroll<begin)) && return 1
+ local page_data=${_ble_complete_menu_style_pages[ipage]}
+ if [[ $page_data ]]; then
+ local fields; ble/string#split fields , "${page_data%%:*}"
+ begin=${fields[0]} end=${fields[1]}
+ if ((begin<=scroll&&scroll<end)); then
+ x=${fields[2]} y=${fields[3]} esc=${page_data#*:}
+ break
+ fi
+ else
+ ble/complete/menu-style:"$menu_style"/construct-page "$menu_opts" || return "$?"
+ _ble_complete_menu_style_pages[ipage]=$begin,$end,$x,$y:$esc
+ ((begin<=scroll&&scroll<end)) && break
+ fi
+ begin=$end
+ ((ipage++))
+ done
+ _ble_complete_menu_version=$version
+ _ble_complete_menu_items=("${menu_items[@]}")
+ _ble_complete_menu_class=$menu_class
+ _ble_complete_menu_param=$menu_param
+ _ble_complete_menu_page_style=$menu_style
+ _ble_complete_menu_ipage=$ipage
+ _ble_complete_menu_offset=$begin
+ _ble_complete_menu_icons=("${_ble_complete_menu_style_icons[@]:begin:end-begin}")
+ _ble_complete_menu_info_data=(store "$x" "$y" "$esc")
+ _ble_complete_menu_selected=-1
+ return 0
+}
+function ble/complete/menu#show {
+ ble/edit/info/immediate-show "${_ble_complete_menu_info_data[@]}"
+}
+function ble/complete/menu#clear {
+ ble/edit/info/default
+}
+function ble/complete/menu#select {
+ local menu_class=$_ble_complete_menu_class
+ local menu_param=$_ble_complete_menu_param
+ local osel=$_ble_complete_menu_selected nsel=$1 opts=$2
+ local ncand=${#_ble_complete_menu_items[@]}
+ ((0<=osel&&osel<ncand)) || osel=-1
+ ((0<=nsel&&nsel<ncand)) || nsel=-1
+ ((osel==nsel)) && return 0
+ local infox infoy
+ ble/canvas/panel#get-origin "$_ble_edit_info_panel" --prefix=info
+ local visible_beg=$_ble_complete_menu_offset
+ local visible_end=$((visible_beg+${#_ble_complete_menu_icons[@]}))
+ if ((nsel>=0&&!(visible_beg<=nsel&&nsel<visible_end))); then
+ ble/complete/menu/show filter:load-filtered-data:scroll="$nsel"; local ext=$?
+ ((ext)) && return "$ext"
+ if [[ $_ble_complete_menu_ipage ]]; then
+ local ipage=$_ble_complete_menu_ipage
+ ble/term/visible-bell "menu: Page $((ipage+1))" persistent
+ else
+ ble/term/visible-bell "menu: Offset $_ble_complete_menu_offset/$ncand" persistent
+ fi
+ visible_beg=$_ble_complete_menu_offset
+ visible_end=$((visible_beg+${#_ble_complete_menu_icons[@]}))
+ ((visible_end<=nsel&&(nsel=visible_end-1)))
+ ((nsel<=visible_beg&&(nsel=visible_beg)))
+ ((visible_beg<=osel&&osel<visible_end)) || osel=-1
+ fi
+ local -a DRAW_BUFF=()
+ local ret; ble/canvas/panel/save-position; local pos0=$ret
+ if ((osel>=0)); then
+ local entry=${_ble_complete_menu_icons[osel-visible_beg]}
+ local fields text=${entry#*:}
+ ble/string#split fields , "${entry%%:*}"
+ if ((fields[3]<_ble_canvas_panel_height[_ble_edit_info_panel])); then
+ ble/canvas/panel#goto.draw "$_ble_edit_info_panel" "${fields[@]::2}"
+ ble/canvas/put.draw "${text:fields[4]}"
+ _ble_canvas_x=${fields[2]} _ble_canvas_y=$((infoy+fields[3]))
+ fi
+ fi
+ local value=
+ if ((nsel>=0)); then
+ [[ :$opts: == *:goto-page-top:* ]] && nsel=$visible_beg
+ local entry=${_ble_complete_menu_icons[nsel-visible_beg]}
+ local fields text=${entry#*:}
+ ble/string#split fields , "${entry%%:*}"
+ local x=${fields[0]} y=${fields[1]}
+ local item=${text::fields[4]}
+ local ret
+ if [[ ${fields[6]} ]]; then
+ local box cols lines
+ ble/string#split-words box "${fields[6]}"
+ x=${box[0]} y=${box[1]} cols=${box[2]} lines=${box[3]}
+ ble/complete/menu#render-item "$item" selected
+ ((x+=fields[0]-box[0]))
+ ((y+=fields[1]-box[1]))
+ else
+ local cols lines
+ ble/complete/menu#construct/.initialize-size
+ ble/complete/menu#render-item "$item" selected
+ fi
+ if ((y<_ble_canvas_panel_height[_ble_edit_info_panel])); then
+ ble/canvas/panel#goto.draw "$_ble_edit_info_panel" "${fields[@]::2}"
+ ble/canvas/put.draw "$ret"
+ _ble_canvas_x=$x _ble_canvas_y=$((infoy+y))
+ fi
+ _ble_complete_menu_selected=$nsel
+ else
+ _ble_complete_menu_selected=-1
+ value=$_ble_complete_menu_original
+ fi
+ ble/canvas/panel/load-position.draw "$pos0"
+ ble/canvas/bflush.draw
+ ble/function#try "$menu_class"/onselect "$nsel" "$osel"
+ return 0
+}
+function ble/widget/menu/forward {
+ local opts=$1
+ local nsel=$((_ble_complete_menu_selected+1))
+ local ncand=${#_ble_complete_menu_items[@]}
+ if ((nsel>=ncand)); then
+ if [[ :$opts: == *:cyclic:* ]] && ((ncand>=2)); then
+ nsel=0
+ else
+ ble/widget/.bell "menu: no more candidates"
+ return 1
+ fi
+ fi
+ ble/complete/menu#select "$nsel"
+}
+function ble/widget/menu/backward {
+ local opts=$1
+ local nsel=$((_ble_complete_menu_selected-1))
+ if ((nsel<0)); then
+ local ncand=${#_ble_complete_menu_items[@]}
+ if [[ :$opts: == *:cyclic:* ]] && ((ncand>=2)); then
+ ((nsel=ncand-1))
+ else
+ ble/widget/.bell "menu: no more candidates"
+ return 1
+ fi
+ fi
+ ble/complete/menu#select "$nsel"
+}
+function ble/widget/menu/forward-column {
+ local osel=$((_ble_complete_menu_selected))
+ if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate right "$osel"; then
+ local nsel=$ret ncand=${#_ble_complete_menu_items[@]}
+ if ((0<=nsel&&nsel<ncand&&nsel!=osel)); then
+ ble/complete/menu#select "$nsel"
+ else
+ ble/widget/.bell "menu: no more candidates"
+ fi
+ else
+ ble/widget/menu/forward
+ fi
+}
+function ble/widget/menu/backward-column {
+ local osel=$((_ble_complete_menu_selected))
+ if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate left "$osel"; then
+ local nsel=$ret ncand=${#_ble_complete_menu_items[@]}
+ if ((0<=nsel&&nsel<ncand&&nsel!=osel)); then
+ ble/complete/menu#select "$nsel"
+ else
+ ble/widget/.bell "menu: no more candidates"
+ fi
+ else
+ ble/widget/menu/backward
+ fi
+}
+_ble_complete_menu_lastcolumn=
+function ble/widget/menu/.check-last-column {
+ if [[ $_ble_complete_menu_lastcolumn ]]; then
+ local lastwidget=${LASTWIDGET%%' '*}
+ if [[ $lastwidget == ble/widget/menu/forward-line ||
+ $lastwidget == ble/widget/menu/backward-line ]]
+ then
+ ox=$_ble_complete_menu_lastcolumn
+ return 0
+ fi
+ fi
+ _ble_complete_menu_lastcolumn=$ox
+}
+function ble/widget/menu/.goto-column {
+ local column=$1
+ local offset=$_ble_complete_menu_offset
+ local osel=$_ble_complete_menu_selected
+ ((osel>=0)) || return 1
+ local entry=${_ble_complete_menu_icons[osel-offset]}
+ local fields; ble/string#split fields , "${entry%%:*}"
+ local ox=${fields[0]} oy=${fields[1]}
+ local nsel=-1
+ if ((ox<column)); then
+ nsel=$osel
+ for entry in "${_ble_complete_menu_icons[@]:osel+1-offset}"; do
+ ble/string#split fields , "${entry%%:*}"
+ local x=${fields[0]} y=${fields[1]}
+ ((y==oy&&x<=column)) || break
+ ((nsel++))
+ done
+ elif ((ox>column)); then
+ local i=$osel
+ while ((--i>=offset)); do
+ entry=${_ble_complete_menu_icons[i-offset]}
+ ble/string#split fields , "${entry%%:*}"
+ local x=${fields[0]} y=${fields[1]}
+ ((y<oy||x<=column&&(nsel=i,1))) && break
+ done
+ fi
+ ((nsel>=0&&nsel!=osel)) &&
+ ble/complete/menu#select "$nsel"
+}
+function ble/widget/menu/forward-line {
+ local offset=$_ble_complete_menu_offset
+ local osel=$_ble_complete_menu_selected
+ ((osel>=0)) || return 1
+ local nsel=-1 goto_column=
+ if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate down "$osel"; then
+ nsel=$ret
+ else
+ local entry=${_ble_complete_menu_icons[osel-offset]}
+ local fields; ble/string#split fields , "${entry%%:*}"
+ local ox=${fields[0]} oy=${fields[1]}
+ ble/widget/menu/.check-last-column
+ local i=$osel nsel=-1 is_next_page=
+ for entry in "${_ble_complete_menu_icons[@]:osel+1-offset}"; do
+ ble/string#split fields , "${entry%%:*}"
+ local x=${fields[0]} y=${fields[1]}
+ ((y<=oy||y==oy+1&&x<=ox||nsel<0)) || break
+ ((++i,y>oy&&(nsel=i)))
+ done
+ ((nsel<0&&(is_next_page=1,nsel=offset+${#_ble_complete_menu_icons[@]})))
+ ((is_next_page)) && goto_column=$ox
+ fi
+ local ncand=${#_ble_complete_menu_items[@]}
+ if ((0<=nsel&&nsel<ncand)); then
+ ble/complete/menu#select "$nsel"
+ [[ $goto_column ]] && ble/widget/menu/.goto-column "$goto_column"
+ return 0
+ else
+ ble/widget/.bell 'menu: no more candidates'
+ return 1
+ fi
+}
+function ble/widget/menu/backward-line {
+ local offset=$_ble_complete_menu_offset
+ local osel=$_ble_complete_menu_selected
+ ((osel>=0)) || return 1
+ local nsel=-1 goto_column=
+ if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate up "$osel"; then
+ nsel=$ret
+ else
+ local entry=${_ble_complete_menu_icons[osel-offset]}
+ local fields; ble/string#split fields , "${entry%%:*}"
+ local ox=${fields[0]} oy=${fields[1]}
+ ble/widget/menu/.check-last-column
+ local nsel=$osel
+ while ((--nsel>=offset)); do
+ entry=${_ble_complete_menu_icons[nsel-offset]}
+ ble/string#split fields , "${entry%%:*}"
+ local x=${fields[0]} y=${fields[1]}
+ ((y<oy-1||y==oy-1&&x<=ox)) && break
+ done
+ ((0<=nsel&&nsel<offset)) && goto_column=$ox
+ fi
+ local ncand=${#_ble_complete_menu_items[@]}
+ if ((0<=nsel&&nsel<ncand)); then
+ ble/complete/menu#select "$nsel"
+ [[ $goto_column ]] && ble/widget/menu/.goto-column "$goto_column"
+ else
+ ble/widget/.bell 'menu: no more candidates'
+ return 1
+ fi
+}
+function ble/widget/menu/backward-page {
+ if ((_ble_complete_menu_offset>0)); then
+ ble/complete/menu#select $((_ble_complete_menu_offset-1)) goto-page-top
+ else
+ ble/widget/.bell "menu: this is the first page."
+ return 1
+ fi
+}
+function ble/widget/menu/forward-page {
+ local next=$((_ble_complete_menu_offset+${#_ble_complete_menu_icons[@]}))
+ if ((next<${#_ble_complete_menu_items[@]})); then
+ ble/complete/menu#select "$next"
+ else
+ ble/widget/.bell "menu: this is the last page."
+ return 1
+ fi
+}
+function ble/widget/menu/beginning-of-page {
+ ble/complete/menu#select "$_ble_complete_menu_offset"
+}
+function ble/widget/menu/end-of-page {
+ local nicon=${#_ble_complete_menu_icons[@]}
+ ((nicon)) && ble/complete/menu#select $((_ble_complete_menu_offset+nicon-1))
+}
+function ble/widget/menu/cancel {
+ ble/decode/keymap/pop
+ ble/complete/menu#clear
+ "$_ble_complete_menu_class"/oncancel
+}
+function ble/widget/menu/accept {
+ ble/decode/keymap/pop
+ ble/complete/menu#clear
+ local nsel=$_ble_complete_menu_selected
+ local hook=$_ble_complete_menu_accept_hook
+ _ble_complete_menu_accept_hook=
+ if ((nsel>=0)); then
+ "$_ble_complete_menu_class"/onaccept "$nsel" "${_ble_complete_menu_items[nsel]}"
+ else
+ "$_ble_complete_menu_class"/onaccept "$nsel"
+ fi
+}
+function ble-decode/keymap:menu/define {
+ ble-bind -f __default__ 'bell'
+ ble-bind -f __line_limit__ nop
+ ble-bind -f C-m 'menu/accept'
+ ble-bind -f RET 'menu/accept'
+ ble-bind -f C-g 'menu/cancel'
+ ble-bind -f 'C-x C-g' 'menu/cancel'
+ ble-bind -f 'C-M-g' 'menu/cancel'
+ ble-bind -f C-f 'menu/forward-column'
+ ble-bind -f right 'menu/forward-column'
+ ble-bind -f C-i 'menu/forward cyclic'
+ ble-bind -f TAB 'menu/forward cyclic'
+ ble-bind -f C-b 'menu/backward-column'
+ ble-bind -f left 'menu/backward-column'
+ ble-bind -f C-S-i 'menu/backward cyclic'
+ ble-bind -f S-TAB 'menu/backward cyclic'
+ ble-bind -f C-n 'menu/forward-line'
+ ble-bind -f down 'menu/forward-line'
+ ble-bind -f C-p 'menu/backward-line'
+ ble-bind -f up 'menu/backward-line'
+ ble-bind -f prior 'menu/backward-page'
+ ble-bind -f next 'menu/forward-page'
+ ble-bind -f home 'menu/beginning-of-page'
+ ble-bind -f end 'menu/end-of-page'
+}
+function ble/complete/menu.class/onaccept {
+ local hook=$_ble_complete_menu_accept_hook
+ _ble_complete_menu_accept_hook=
+ "$hook" "$@"
+}
+function ble/complete/menu.class/oncancel {
+ local hook=$_ble_complete_menu_cancel_hook
+ _ble_complete_menu_cancel_hook=
+ "$hook" "$@"
+}
+function ble/complete/menu#start {
+ _ble_complete_menu_accept_hook=$1; shift
+ _ble_complete_menu_cancel_hook=
+ local menu_style=linewise
+ local menu_items; menu_items=("$@")
+ local menu_class=ble/complete/menu.class menu_param=
+ ble/complete/menu#construct sync || return "$?"
+ ble/complete/menu#show
+ ble/complete/menu#select 0
+ ble/decode/keymap/push menu
+ return 147
+}
+function ble/complete/check-cancel {
+ [[ :$comp_type: != *:sync:* ]] && ble/decode/has-input
+}
+function ble/complete/string#escape-for-completion-context {
+ local str=$1 escape_flags=$2
+ case $comps_flags in
+ (*S*) ble/string#escape-for-bash-single-quote "$str" ;;
+ (*E*) ble/string#escape-for-bash-escape-string "$str" ;;
+ (*[DI]*) ble/string#escape-for-bash-double-quote "$str" ;;
+ (*)
+ if [[ $comps_fixed ]]; then
+ ble/string#escape-for-bash-specialchars "$str" "b$escape_flags"
+ else
+ ble/string#escape-for-bash-specialchars "$str" "$escape_flags"
+ fi ;;
+ esac
+}
+function ble/complete/action/complete.addtail {
+ suffix=$suffix$1
+}
+function ble/complete/action/complete.mark-directory {
+ [[ :$comp_type: == *:markdir:* && $CAND != */ ]] &&
+ [[ ! -h $CAND || ( $insert == "$COMPS" || :$comp_type: == *:marksymdir:* ) ]] &&
+ ble/complete/action/complete.addtail /
+}
+function ble/complete/action/complete.close-quotation {
+ case $comps_flags in
+ (*[SE]*) ble/complete/action/complete.addtail \' ;;
+ (*[DI]*) ble/complete/action/complete.addtail \" ;;
+ esac
+}
+_ble_complete_quote_insert_varnames=(
+ quote_action
+ quote_escape_flags
+ quote_cont_cutbackslash
+ quote_paramx_comps
+ quote_trav_prefix
+ quote_fixed_comps
+ quote_fixed_compv
+ quote_fixed_comps_len
+ quote_fixed_compv_len)
+function ble/complete/action/quote-insert.initialize {
+ quote_action=$1
+ quote_escape_flags=c
+ if [[ $quote_action == command ]]; then
+ quote_escape_flags=
+ elif [[ $quote_action == progcomp ]]; then
+ [[ $comp_opts != *:filenames:* ]] &&
+ quote_escape_flags=${quote_escape_flags//c}
+ fi
+ [[ $comps_fixed ]] && quote_escape_flags=b$quote_escape_flags
+ quote_cont_cutbackslash=
+ [[ $comps_flags == *B* && $COMPS == *'\' ]] &&
+ quote_cont_cutbackslash=1
+ quote_paramx_comps=$COMPS
+ if [[ $comps_flags == *p* ]]; then
+ [[ $comps_flags == *B* && $quote_paramx_comps == *'\' ]] &&
+ quote_paramx_comps=${quote_paramx_comps%'\'}
+ case $comps_flags in
+ (*[DI]*)
+ if [[ $COMPS =~ $rex_raw_paramx ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ quote_paramx_comps=$rematch1'${'${COMPS:${#rematch1}+1}'}'
+ else
+ quote_paramx_comps=$quote_paramx_comps'""'
+ fi ;;
+ (*)
+ quote_paramx_comps=$quote_paramx_comps'\' ;;
+ esac
+ fi
+ quote_trav_prefix=
+ case $comps_flags in
+ (*S*) quote_trav_prefix=\' ;;
+ (*E*) quote_trav_prefix=\$\' ;;
+ (*D*) quote_trav_prefix=\" ;;
+ (*I*) quote_trav_prefix=\$\" ;;
+ esac
+ quote_fixed_comps=
+ quote_fixed_compv=
+ quote_fixed_comps_len=
+ quote_fixed_compv_len=
+ if [[ $comps_fixed ]]; then
+ quote_fixed_compv=${comps_fixed#*:}
+ quote_fixed_compv_len=${#quote_fixed_compv}
+ quote_fixed_comps_len=${comps_fixed%%:*}
+ quote_fixed_comps=${COMPS::quote_fixed_comps_len}
+ fi
+}
+function ble/complete/action/quote-insert {
+ if [[ ! $quote_action ]]; then
+ local "${_ble_complete_quote_insert_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/action/quote-insert.initialize "${1:-plain}"
+ fi
+ local escape_flags=$quote_escape_flags
+ if [[ $quote_action == command ]]; then
+ [[ $DATA == *:noquote:* || $COMPS == "$COMPV" && ( $CAND == '[[' || $CAND == '!' ) ]] && return 0
+ elif [[ $quote_action == progcomp ]]; then
+ [[ $comp_opts == *:noquote:* ]] && return 0
+ [[ $comp_opts == *:nospace:* && $CAND == *' ' && ! -f $CAND ]] && return 0
+ [[ $CAND == '~'* && ! ( $comp_opts == *:filenames:* && -e $CAND ) ]] &&
+ escape_flags=T$escape_flags
+ fi
+ if [[ $comps_flags == *v* && $CAND == "$COMPV"* ]]; then
+ local ins ret
+ ble/complete/string#escape-for-completion-context "${CAND:${#COMPV}}" "$escape_flags"; ins=$ret
+ if [[ $comps_flags == *p* && $ins == [_a-zA-Z0-9]* ]]; then
+ INSERT=$quote_paramx_comps$ins
+ else
+ [[ $quote_cont_cutbackslash ]] && ins=${ins#'\'}
+ INSERT=$COMPS$ins;
+ fi
+ elif [[ $quote_fixed_comps && $CAND == "$quote_fixed_compv"* ]]; then
+ local ret; ble/complete/string#escape-for-completion-context "${CAND:quote_fixed_compv_len}" "$escape_flags"
+ INSERT=$quote_fixed_comps$quote_trav_prefix$ret
+ else
+ local ret; ble/complete/string#escape-for-completion-context "$CAND" "$escape_flags"
+ INSERT=$quote_trav_prefix$ret
+ fi
+}
+function ble/complete/action/quote-insert.batch/awk {
+ local q=\'
+ local -x comp_opts=$comp_opts
+ local -x comps=$COMPS
+ local -x compv=$COMPV
+ local -x comps_flags=$comps_flags
+ local -x quote_action=$quote_action
+ local -x quote_escape_flags=$quote_escape_flags
+ local -x quote_paramx_comps=$quote_paramx_comps
+ local -x quote_cont_cutbackslash=$quote_cont_cutbackslash
+ local -x quote_trav_prefix=$quote_trav_prefix
+ local -x quote_fixed_comps=$quote_fixed_comps
+ local -x quote_fixed_compv=$quote_fixed_compv
+ "$quote_batch_awk" -v quote_batch_nulsep="$quote_batch_nulsep" -v q="$q" '
+ function exists(filename) { return substr($0, 1, 1) == "1"; }
+ function is_file(filename) { return substr($0, 2, 1) == "1"; }
+ function initialize(_, flags, comp_opts, tmp) {
+ IS_XPG4 = AWKTYPE == "xpg4";
+ REP_SL = "\\";
+ if (IS_XPG4) REP_SL = "\\\\";
+ REP_DBL_SL = "\\\\"; # gawk, nawk
+ sub(/.*/, REP_DBL_SL, tmp);
+ if (tmp == "\\") REP_DBL_SL = "\\\\\\\\"; # mawk, xpg4
+ Q = q "\\" q q;
+ DELIM = 10;
+ if (quote_batch_nulsep != "") {
+ RS = "\0";
+ DELIM = 0;
+ }
+ quote_action = ENVIRON["quote_action"];
+ comps = ENVIRON["comps"];
+ compv = ENVIRON["compv"];
+ compv_len = length(compv);
+ comps_flags = ENVIRON["comps_flags"];
+ escape_type = 0;
+ if (comps_flags ~ /S/)
+ escape_type = 1;
+ else if (comps_flags ~ /E/)
+ escape_type = 2;
+ else if (comps_flags ~ /[DI]/)
+ escape_type = 3;
+ else
+ escape_type = 4;
+ comps_v = (comps_flags ~ /v/);
+ comps_p = (comps_flags ~ /p/);
+ comp_opts = ENVIRON["comp_opts"];
+ is_noquote = comp_opts ~ /:noquote:/;
+ is_nospace = comp_opts ~ /:nospace:/;
+ flags = ENVIRON["quote_escape_flags"];
+ escape_c = (flags ~ /c/);
+ escape_b = (flags ~ /b/);
+ escape_tilde_always = 1;
+ escape_tilde_exists = 0;
+ if (quote_action == "progcomp") {
+ escape_tilde_always = 0;
+ escape_tilde_exists = (comp_opts ~ /:filenames:/);
+ }
+ quote_cont_cutbackslash = ENVIRON["quote_cont_cutbackslash"] != "";
+ quote_paramx_comps = ENVIRON["quote_paramx_comps"];
+ quote_trav_prefix = ENVIRON["quote_trav_prefix"];
+ quote_fixed_comps = ENVIRON["quote_fixed_comps"];
+ quote_fixed_compv = ENVIRON["quote_fixed_compv"];
+ quote_fixed_comps_len = length(quote_fixed_comps);
+ quote_fixed_compv_len = length(quote_fixed_compv);
+ }
+ BEGIN { initialize(); }
+ function escape_for_completion_context(text) {
+ if (escape_type == 1) {
+ gsub(/'$q'/, Q, text);
+ } else if (escape_type == 2) {
+ if (text ~ /[\\'$q'\a\b\t\n\v\f\r\033]/) {
+ gsub(/\\/ , REP_DBL_SL, text);
+ gsub(/'$q'/, REP_SL q , text);
+ gsub(/\007/, REP_SL "a", text);
+ gsub(/\010/, REP_SL "b", text);
+ gsub(/\011/, REP_SL "t", text);
+ gsub(/\012/, REP_SL "n", text);
+ gsub(/\013/, REP_SL "v", text);
+ gsub(/\014/, REP_SL "f", text);
+ gsub(/\015/, REP_SL "r", text);
+ gsub(/\033/, REP_SL "e", text);
+ }
+ } else if (escape_type == 3) {
+ gsub(/[\\"$`]/, "\\\\&", text); # Note: All awks behaves the same for "\\\\&"
+ } else if (escape_type == 4) {
+ gsub(/[]\\ "'$q'`$|&;<>()!^*?[]/, "\\\\&", text);
+ if (escape_c) gsub(/[=:]/, "\\\\&", text);
+ if (escape_b) gsub(/[{,}]/, "\\\\&", text);
+ if (ret ~ /^~/ && (escape_tilde_always || escape_tilde_exists && exists(cand)))
+ text = "\\" text;
+ gsub(/\n/, "$" q REP_SL "n" q, text);
+ gsub(/\t/, "$" q REP_SL "t" q, text);
+ }
+ return text;
+ }
+ function quote_insert(cand) {
+ if (quote_action == "command") {
+ if (comps == compv && cand ~ /^(\[\[|]]|!)$/) return cand;
+ } else if (quote_action == "progcomp") {
+ if (is_noquote) return cand;
+ if (is_nospace && cand ~ / $/ && !is_file(cand)) return cand;
+ }
+ if (comps_v && substr(cand, 1, compv_len) == compv) {
+ ins = escape_for_completion_context(substr(cand, compv_len + 1));
+ if (comps_p && ins ~ /^[_a-zA-Z0-9]/) {
+ return quote_paramx_comps ins;
+ } else {
+ if (quote_cont_cutbackslash) sub(/^\\/, "", ins);
+ return comps ins;
+ }
+ } else if (quote_fixed_comps_len && substr(cand, 1, quote_fixed_compv_len) == quote_fixed_compv) {
+ ins = substr(cand, quote_fixed_compv_len + 1);
+ return quote_fixed_comps quote_trav_prefix escape_for_completion_context(ins);
+ } else {
+ return quote_trav_prefix escape_for_completion_context(cand);
+ }
+ }
+ {
+ cand = substr($0, 3);
+ insert = quote_insert(cand);
+ printf("%s%c", insert, DELIM);
+ }
+ '
+}
+function ble/complete/action/quote-insert.batch/proc {
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ local delim='\n'
+ [[ $quote_batch_nulsep ]] && delim='\0'
+ if [[ $quote_action == progcomp ]]; then
+ local cand file exist
+ for cand in "${cands[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ f=0 e=0
+ [[ -e $cand ]] && e=1
+ [[ -f $cand ]] && f=1
+ printf "$e$f%s$delim" "$cand"
+ done
+ else
+ printf "00%s$delim" "${cands[@]}"
+ fi >| "$_ble_local_tmpfile"
+ local fname_cands=$_ble_local_tmpfile
+ ble/util/conditional-sync \
+ 'ble/complete/action/quote-insert.batch/awk < "$fname_cands"' \
+ '! ble/complete/check-cancel < /dev/tty' '' progressive-weight
+ local ext=$?
+ ble/util/assign/.rmtmp
+ return "$ext"
+}
+function ble/complete/action/quote-insert.batch {
+ local opts=$1
+ local quote_batch_nulsep=
+ local quote_batch_awk=ble/bin/awk
+ if [[ :$opts: != *:newline:* ]]; then
+ if ((_ble_bash>=40400)); then
+ if [[ $_ble_bin_awk_type == [mg]awk ]]; then
+ quote_batch_nulsep=1
+ elif ble/bin#has mawk; then
+ quote_batch_nulsep=1
+ quote_batch_awk=mawk
+ elif ble/bin#has gawk; then
+ quote_batch_nulsep=1
+ quote_batch_awk=gawk
+ fi
+ fi
+ [[ ! $quote_batch_nulsep ]] &&
+ [[ "${cands[*]}" == *$'\n'* ]] &&
+ return 1
+ fi
+ if [[ $quote_batch_nulsep ]]; then
+ ble/util/assign-array0 inserts ble/complete/action/quote-insert.batch/proc
+ else
+ ble/util/assign-array inserts ble/complete/action/quote-insert.batch/proc
+ fi
+ return $?
+}
+function ble/complete/action/requote-final-insert {
+ local comps_prefix= check_optarg=
+ if [[ $insert == "$COMPS"* ]]; then
+ [[ $comps_flags == *[SEDI]* ]] && return 0
+ [[ $COMPS != *[!':/={,'] ]] && comps_prefix=$COMPS
+ check_optarg=$COMPS
+ else
+ check_optarg=$insert
+ fi
+ if [[ $check_optarg ]]; then
+ if ble/string#match "$check_optarg" '^([_a-zA-Z][_a-zA-Z0-9]*|-[-a-zA-Z0-9.]+)=(([^\'\''"`${}]*|\\.)*:)?'; then
+ comps_prefix=$BASH_REMATCH
+ elif [[ $COMP_PREFIX == -[!'-=:/\'\''"$`{};&|<>!^{}'] && $check_optarg == "$COMP_PREFIX"* ]]; then
+ comps_prefix=${check_optarg::2}
+ fi
+ fi
+ if [[ $comps_fixed ]]; then
+ local comps_fixed_part=${COMPS::${comps_fixed%%:*}}
+ [[ $comps_prefix == "$comps_fixed_part"* ]] ||
+ comps_prefix=$comps_fixed_part
+ fi
+ if [[ $insert == "$comps_prefix"* && $comps_prefix != *[!':/={,'] ]]; then
+ local ret ins=${insert:${#comps_prefix}}
+ if ! ble/syntax:bash/simple-word/is-literal "$ins" &&
+ ble/syntax:bash/simple-word/is-simple "$ins" &&
+ ble/syntax:bash/simple-word/eval "$ins" &&
+ ((${#ret[@]}==1))
+ then
+ ble/string#quote-word "$ret" quote-empty
+ ((${#ret}<=${#ins})) || return 0
+ insert=$comps_prefix$ret
+ [[ $insert == "$COMPS"* ]] || insert_flags=r$insert_flags # 遡って書き換えた
+ fi
+ fi
+ return 0
+}
+function ble/complete/action#inherit-from {
+ local dst=$1 src=$2
+ local member srcfunc dstfunc
+ for member in initialize{,.batch} complete getg get-desc; do
+ srcfunc=ble/complete/action:$src/$member
+ dstfunc=ble/complete/action:$dst/$member
+ ble/is-function "$srcfunc" && builtin eval "function $dstfunc { $srcfunc; }"
+ done
+}
+function ble/complete/action:plain/initialize {
+ ble/complete/action/quote-insert
+}
+function ble/complete/action:plain/initialize.batch {
+ ble/complete/action/quote-insert.batch
+}
+function ble/complete/action:plain/complete {
+ ble/complete/action/requote-final-insert
+}
+function ble/complete/action:literal-substr/initialize { :; }
+function ble/complete/action:literal-substr/initialize.batch { inserts=("${cands[@]}"); }
+function ble/complete/action:literal-substr/complete { :; }
+function ble/complete/action:substr/initialize {
+ ble/complete/action/quote-insert
+}
+function ble/complete/action:substr/initialize.batch {
+ ble/complete/action/quote-insert.batch
+}
+function ble/complete/action:substr/complete {
+ ble/complete/action/requote-final-insert
+}
+function ble/complete/action:literal-word/initialize { :; }
+function ble/complete/action:literal-word/initialize.batch { inserts=("${cands[@]}"); }
+function ble/complete/action:literal-word/complete {
+ if [[ $comps_flags == *x* ]]; then
+ ble/complete/action/complete.addtail ','
+ else
+ ble/complete/action/complete.addtail ' '
+ fi
+}
+function ble/complete/action:word/initialize {
+ ble/complete/action/quote-insert
+}
+function ble/complete/action:word/initialize.batch {
+ ble/complete/action/quote-insert.batch
+}
+function ble/complete/action:word/complete {
+ ble/complete/action/requote-final-insert
+ ble/complete/action/complete.close-quotation
+ ble/complete/action:literal-word/complete
+}
+function ble/complete/action:word/get-desc {
+ [[ $DATA ]] && desc=$DATA
+}
+function ble/complete/action:file/initialize {
+ ble/complete/action/quote-insert
+}
+function ble/complete/action:file/initialize.batch {
+ ble/complete/action/quote-insert.batch
+}
+function ble/complete/action:file/complete {
+ ble/complete/action/requote-final-insert
+ if [[ -e $CAND || -h $CAND ]]; then
+ if [[ -d $CAND ]]; then
+ ble/complete/action/complete.mark-directory
+ else
+ ble/complete/action:word/complete
+ fi
+ fi
+}
+function ble/complete/action:file/init-menu-item {
+ ble/syntax/highlight/getg-from-filename "$CAND"
+ [[ $g ]] || { local ret; ble/color/face2g filename_warning; g=$ret; }
+ if [[ :$comp_type: == *:vstat:* ]]; then
+ if [[ -h $CAND ]]; then
+ suffix='@'
+ elif [[ -d $CAND ]]; then
+ suffix='/'
+ elif [[ -x $CAND ]]; then
+ suffix='*'
+ fi
+ fi
+}
+function ble/complete/action:file_rhs/initialize {
+ ble/complete/action:file/initialize
+}
+function ble/complete/action:file_rhs/initialize.batch {
+ ble/complete/action:file/initialize.batch
+}
+function ble/complete/action:file_rhs/complete {
+ CAND=${CAND:${#DATA}} ble/complete/action:file/complete
+}
+function ble/complete/action:file_rhs/init-menu-item {
+ CAND=${CAND:${#DATA}} ble/complete/action:file/init-menu-item
+}
+_ble_complete_action_file_desc[_ble_attr_FILE_LINK]='symbolic link'
+_ble_complete_action_file_desc[_ble_attr_FILE_ORPHAN]='symbolic link (orphan)'
+_ble_complete_action_file_desc[_ble_attr_FILE_DIR]='directory'
+_ble_complete_action_file_desc[_ble_attr_FILE_STICKY]='directory (sticky)'
+_ble_complete_action_file_desc[_ble_attr_FILE_SETUID]='file (setuid)'
+_ble_complete_action_file_desc[_ble_attr_FILE_SETGID]='file (setgid)'
+_ble_complete_action_file_desc[_ble_attr_FILE_EXEC]='file (executable)'
+_ble_complete_action_file_desc[_ble_attr_FILE_FILE]='file'
+_ble_complete_action_file_desc[_ble_attr_FILE_CHR]='character device'
+_ble_complete_action_file_desc[_ble_attr_FILE_FIFO]='named pipe'
+_ble_complete_action_file_desc[_ble_attr_FILE_SOCK]='socket'
+_ble_complete_action_file_desc[_ble_attr_FILE_BLK]='block device'
+_ble_complete_action_file_desc[_ble_attr_FILE_URL]='URL'
+function ble/complete/action:file/get-desc {
+ local type; ble/syntax/highlight/filetype "$CAND"
+ desc=${_ble_complete_action_file_desc[type]:-'file (???)'}
+}
+function ble/complete/action:progcomp/initialize/.reconstruct-from-noquote {
+ local simple_flags simple_ibrace ret count
+ ble/syntax:bash/simple-word/is-simple-or-open-simple "$INSERT" &&
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$INSERT" &&
+ ble/complete/source/eval-simple-word "$ret" single:count &&
+ ((count==1)) || return 0
+ CAND=$ret
+ if [[ $quote_fixed_comps && $CAND == "$quote_fixed_compv"* ]]; then
+ local ret; ble/complete/string#escape-for-completion-context "${CAND:quote_fixed_compv_len}" "$escape_flags"
+ INSERT=$quote_fixed_comps$quote_trav_prefix$ret
+ return 3
+ fi
+ return 0
+}
+function ble/complete/action:progcomp/initialize {
+ if [[ :$DATA: == *:noquote:* ]]; then
+ local progcomp_resolve_brace=$quote_fixed_comps
+ [[ :$DATA: == *:ble/syntax-raw:* ]] && progcomp_resolve_brace=
+ ble/complete/action:progcomp/initialize/.reconstruct-from-noquote
+ return 0
+ else
+ ble/complete/action/quote-insert progcomp
+ fi
+}
+function ble/complete/action:progcomp/initialize.batch {
+ if [[ :$DATA: == *:noquote:* ]]; then
+ inserts=("${cands[@]}")
+ local progcomp_resolve_brace=$quote_fixed_comps
+ [[ :$DATA: == *:ble/syntax-raw:* ]] && progcomp_resolve_brace=
+ cands=()
+ local INSERT simple_flags simple_ibrace ret count icand=0
+ for INSERT in "${inserts[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ local CAND=$INSERT
+ ble/complete/action:progcomp/initialize/.reconstruct-from-noquote ||
+ inserts[icand]=$INSERT # INSERT を上書きした時 ($?==3)
+ cands[icand++]=$CAND
+ done
+ else
+ ble/complete/action/quote-insert.batch newline
+ fi
+}
+function ble/complete/action:progcomp/complete {
+ if [[ $DATA == *:filenames:* ]]; then
+ ble/complete/action:file/complete
+ else
+ if [[ $DATA != *:ble/no-mark-directories:* && -d $CAND ]]; then
+ ble/complete/action/requote-final-insert
+ ble/complete/action/complete.mark-directory
+ else
+ ble/complete/action:word/complete
+ fi
+ fi
+ [[ $DATA == *:nospace:* ]] && suffix=${suffix%' '}
+ [[ $DATA == *:ble/no-mark-directories:* && -d $CAND ]] && suffix=${suffix%/}
+}
+function ble/complete/action:progcomp/init-menu-item {
+ if [[ $DATA == *:filenames:* ]]; then
+ ble/complete/action:file/init-menu-item
+ fi
+}
+function ble/complete/action:progcomp/get-desc {
+ if [[ $DATA == *:filenames:* ]]; then
+ ble/complete/action:file/get-desc
+ fi
+}
+function ble/complete/action:command/initialize {
+ ble/complete/action/quote-insert command
+}
+function ble/complete/action:command/initialize.batch {
+ ble/complete/action/quote-insert.batch newline
+}
+function ble/complete/action:command/complete {
+ if [[ -d $CAND ]]; then
+ ble/complete/action/complete.mark-directory
+ elif ! type "$CAND" &>/dev/null; then
+ if [[ $CAND == */ ]]; then
+ insert_flags=${insert_flags}n
+ fi
+ else
+ ble/complete/action:word/complete
+ fi
+}
+function ble/complete/action:command/init-menu-item {
+ if [[ -d $CAND ]]; then
+ local ret; ble/color/face2g filename_directory; g=$ret
+ else
+ local type
+ if [[ $CAND != "$INSERT" ]]; then
+ ble/syntax/highlight/cmdtype "$CAND" "$INSERT"
+ else
+ local type; ble/util/type type "$CAND"
+ ble/syntax/highlight/cmdtype1 "$type" "$CAND"
+ fi
+ if [[ $CAND == */ ]] && ((type==_ble_attr_ERR)); then
+ type=_ble_attr_CMD_FUNCTION
+ fi
+ ble/syntax/attr2g "$type"
+ fi
+}
+_ble_complete_action_command_desc[_ble_attr_CMD_BOLD]=builtin
+_ble_complete_action_command_desc[_ble_attr_CMD_BUILTIN]=builtin
+_ble_complete_action_command_desc[_ble_attr_CMD_ALIAS]=alias
+_ble_complete_action_command_desc[_ble_attr_CMD_FUNCTION]=function
+_ble_complete_action_command_desc[_ble_attr_CMD_FILE]=file
+_ble_complete_action_command_desc[_ble_attr_KEYWORD]=command
+_ble_complete_action_command_desc[_ble_attr_CMD_JOBS]=job
+_ble_complete_action_command_desc[_ble_attr_ERR]='command ???'
+_ble_complete_action_command_desc[_ble_attr_CMD_DIR]=directory
+function ble/complete/action:command/get-desc {
+ local title= value=
+ if [[ -d $CAND ]]; then
+ title=directory
+ else
+ local type; ble/util/type type "$CAND"
+ ble/syntax/highlight/cmdtype1 "$type" "$CAND"
+ case $type in
+ ($_ble_attr_CMD_ALIAS)
+ local ret
+ ble/alias#expand "$CAND"
+ title=alias value=$ret ;;
+ ($_ble_attr_CMD_FILE)
+ local path; ble/util/assign path 'type -p -- "$CAND"'
+ [[ $path == ?*/"$CAND" ]] && path="from ${path%/"$CAND"}"
+ title=file value=$path ;;
+ ($_ble_attr_CMD_FUNCTION)
+ local source lineno
+ ble/function#get-source-and-lineno "$CAND"
+ local def; ble/function#getdef "$CAND"
+ ble/string#match "$def" '^[^()]*\(\)[[:space:]]*\{[[:space:]]+(.*[^[:space:]])[[:space:]]+\}[[:space:]]*$' &&
+ def=${BASH_REMATCH[1]} # 関数の中身を抽出する
+ local ret sgr0=$'\e[27m' sgr1=$'\e[7m' # Note: sgr-ansi で生成
+ lines=1 cols=${COLUMNS:-80} x=0 y=0 ble/canvas/trace-text "$def" external-sgr
+ title=function value="${source##*/}:$lineno $desc_sgrq$ret" ;;
+ ($_ble_attr_CMD_JOBS)
+ ble/util/joblist.check
+ local job; ble/util/assign job 'jobs -- "$CAND" 2>/dev/null' || job='???'
+ title=job value=${job:-(ambiguous)} ;;
+ ($_ble_attr_ERR)
+ if [[ $CAND == */ ]]; then
+ title='function namespace'
+ else
+ title=${_ble_complete_action_command_desc[_ble_attr_ERR]}
+ fi ;;
+ (*)
+ title=${_ble_complete_action_command_desc[type]:-'???'} ;;
+ esac
+ fi
+ desc=${title:+$desc_sgrt($title)$desc_sgr0}${value:+ $value}
+}
+function ble/complete/action:variable/initialize { ble/complete/action/quote-insert; }
+function ble/complete/action:variable/initialize.batch { ble/complete/action/quote-insert.batch newline; }
+function ble/complete/action:variable/complete {
+ case $DATA in
+ (assignment)
+ ble/complete/action/complete.addtail '=' ;;
+ (braced)
+ ble/complete/action/complete.addtail '}' ;;
+ (word) ble/complete/action:word/complete ;;
+ (arithmetic|nosuffix) ;; # do nothing
+ esac
+}
+function ble/complete/action:variable/init-menu-item {
+ local ret; ble/color/face2g syntax_varname; g=$ret
+}
+function ble/complete/action:variable/get-desc {
+ local _ble_local_title=variable
+ if ble/is-array "$CAND"; then
+ _ble_local_title=array
+ elif ble/is-assoc "$CAND"; then
+ _ble_local_title=assoc
+ fi
+ local _ble_local_value=
+ if [[ $_ble_local_title == array || $_ble_local_title == assoc ]]; then
+ builtin eval "local count=\${#$CAND[@]}"
+ if ((count==0)); then
+ count=empty
+ else
+ count="$count items"
+ fi
+ _ble_local_value=$'\e[94m['$count$']\e[m'
+ else
+ local ret; ble/string#quote-word "${!CAND}" ansi:sgrq="$desc_sgrq":quote-empty
+ _ble_local_value=$ret
+ fi
+ desc="$desc_sgrt($_ble_local_title)$desc_sgr0 $_ble_local_value"
+}
+function ble/complete/source/test-limit {
+ local value=$1 limit=
+ if [[ :$comp_type: == *:auto_menu:* && $bleopt_complete_limit_auto_menu ]]; then
+ limit=$bleopt_complete_limit_auto_menu
+ elif [[ :$comp_type: == *:auto:* && $bleopt_complete_limit_auto ]]; then
+ limit=$bleopt_complete_limit_auto
+ else
+ limit=$bleopt_complete_limit
+ fi
+ if [[ $limit && value -gt limit ]]; then
+ cand_limit_reached=1
+ [[ :$comp_type: == *:auto_menu: ]] && cand_limit_reached=cancel
+ return 1
+ else
+ return 0
+ fi
+}
+function ble/complete/source/eval-simple-word {
+ local word=$1 opts=$2
+ if [[ :$comp_type: != *:sync:* && :$opts: != *:noglob:* ]]; then
+ opts=$opts:stopcheck:cached
+ [[ :$comp_type: == *:auto:* && $bleopt_complete_timeout_auto ]] &&
+ opts=$opts:timeout=$((bleopt_complete_timeout_auto))
+ fi
+ ble/syntax:bash/simple-word/eval "$word" "$opts"; local ext=$?
+ ((ext==142)) && return 148
+ return "$ext"
+}
+function ble/complete/source/evaluate-path-spec {
+ local word=$1 sep=$2 opts=$3
+ if [[ :$comp_type: != *:sync:* && :$opts: != *:noglob:* ]]; then
+ opts=$opts:stopcheck:cached:single
+ [[ :$comp_type: == *:auto:* && $bleopt_complete_timeout_auto ]] &&
+ opts=$opts:timeout=$((bleopt_complete_timeout_auto))
+ fi
+ ble/syntax:bash/simple-word/evaluate-path-spec "$word" "$sep" "$opts"; local ext=$?
+ ((ext==142)) && return 148
+ return "$ext"
+}
+function ble/complete/source/reduce-compv-for-ambiguous-match {
+ [[ :$comp_type: == *:[maA]:* ]] || return 0
+ local comps=$COMPS compv=$COMPV
+ local comps_prefix= compv_prefix=
+ if [[ $comps_fixed ]]; then
+ comps_prefix=${comps::${comps_fixed%%:*}}
+ compv_prefix=${comps_fixed#*:}
+ compv=${COMPV:${#compv_prefix}}
+ fi
+ case $comps_flags in
+ (*S*) comps_prefix=$comps_prefix\' ;;
+ (*E*) comps_prefix=$comps_prefix\$\' ;;
+ (*D*) comps_prefix=$comps_prefix\" ;;
+ (*I*) comps_prefix=$comps_prefix\$\" ;;
+ esac
+ if [[ $compv && :$comp_type: == *:a:* ]]; then
+ compv=${compv::1}
+ ble/complete/string#escape-for-completion-context "$compv"
+ comps=$ret
+ else
+ compv= comps=
+ fi
+ COMPV=$compv_prefix$compv
+ COMPS=$comps_prefix$comps
+}
+_ble_complete_yield_varnames=("${_ble_complete_quote_insert_varnames[@]}")
+function ble/complete/cand/yield.initialize {
+ ble/complete/action/quote-insert.initialize "$1"
+}
+function ble/complete/cand/yield {
+ local ACTION=$1 CAND=$2 DATA=$3
+ [[ $flag_force_fignore ]] && ! ble/complete/.fignore/filter "$CAND" && return 0
+ [[ $flag_source_filter ]] || ble/complete/candidates/filter#test "$CAND" || return 0
+ local INSERT=$CAND
+ ble/complete/action:"$ACTION"/initialize || return "$?"
+ local PREFIX_LEN=0
+ [[ $CAND == "$COMP_PREFIX"* ]] && PREFIX_LEN=${#COMP_PREFIX}
+ local icand
+ ((icand=cand_count++))
+ cand_cand[icand]=$CAND
+ cand_word[icand]=$INSERT
+ cand_pack[icand]=$ACTION:${#CAND},${#INSERT},$PREFIX_LEN:$CAND$INSERT$DATA
+}
+function ble/complete/cand/yield.batch {
+ local ACTION=$1 DATA=$2
+ local inserts threshold=500
+ [[ $OSTYPE == cygwin* || $OSTYPE == msys* ]] && threshold=2000
+ if ((${#cands[@]}>=threshold)) && ble/function#try ble/complete/action:"$ACTION"/initialize.batch; then
+ local i n=${#cands[@]}
+ for ((i=0;i<n;i++)); do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ local CAND=${cands[i]} INSERT=${inserts[i]}
+ [[ $flag_force_fignore ]] && ! ble/complete/.fignore/filter "$CAND" && continue
+ [[ $flag_source_filter ]] || ble/complete/candidates/filter#test "$CAND" || continue
+ local PREFIX_LEN=0
+ [[ $CAND == "$COMP_PREFIX"* ]] && PREFIX_LEN=${#COMP_PREFIX}
+ local icand
+ ((icand=cand_count++))
+ cand_cand[icand]=$CAND
+ cand_word[icand]=$INSERT
+ cand_pack[icand]=$ACTION:${#CAND},${#INSERT},$PREFIX_LEN:$CAND$INSERT$DATA
+ done
+ else
+ local cand
+ for cand in "${cands[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ ble/complete/cand/yield "$ACTION" "$cand" "$DATA"
+ done
+ fi
+}
+function ble/complete/cand/yield-filenames {
+ local action=$1; shift
+ local rex_hidden=
+ [[ :$comp_type: != *:match-hidden:* ]] &&
+ rex_hidden=${COMPV:+'.{'${#COMPV}'}'}'(^|/)\.[^/]*$'
+ local -a cands=()
+ local cand icand=0
+ for cand; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ [[ $rex_hidden && $cand =~ $rex_hidden ]] && continue
+ cands[icand++]=$cand
+ done
+ [[ $FIGNORE ]] && local flag_force_fignore=1
+ local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ ble/complete/cand/yield.batch "$action"
+}
+_ble_complete_cand_varnames=(ACTION CAND INSERT DATA PREFIX_LEN)
+function ble/complete/cand/unpack {
+ local pack=$1
+ ACTION=${pack%%:*} pack=${pack#*:}
+ local text=${pack#*:}
+ IFS=, builtin eval 'pack=(${pack%%:*})'
+ CAND=${text::pack[0]}
+ INSERT=${text:pack[0]:pack[1]}
+ DATA=${text:pack[0]+pack[1]}
+ PREFIX_LEN=${pack[2]}
+}
+function ble/complete/source:none { return 0; }
+function ble/complete/source:wordlist {
+ [[ $comps_flags == *v* ]] || return 1
+ local COMPS=$COMPS COMPV=$COMPV
+ ble/complete/source/reduce-compv-for-ambiguous-match
+ [[ $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]}
+ local opt_raw= opt_noword= opt_sabbrev=
+ while (($#)) && [[ $1 == -* ]]; do
+ local arg=$1; shift
+ case $arg in
+ (--) break ;;
+ (--*) ;; # ignore
+ (-*)
+ local i iN=${#arg}
+ for ((i=1;i<iN;i++)); do
+ case ${arg:i:1} in
+ (r) opt_raw=1 ;;
+ (W) opt_noword=1 ;;
+ (s) opt_sabbrev=1 ;;
+ (*) ;; # ignore
+ esac
+ done ;;
+ esac
+ done
+ [[ $opt_sabbrev ]] &&
+ ble/complete/source:sabbrev
+ local action=word
+ [[ $opt_noword ]] && action=substr
+ [[ $opt_raw ]] && action=literal-$action
+ local cand "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ for cand; do
+ [[ $cand == "$COMPV"* ]] && ble/complete/cand/yield "$action" "$cand"
+ done
+}
+function ble/complete/source:command/.contract-by-slashes {
+ local slashes=${COMPV//[!'/']}
+ ble/bin/awk -F / -v baseNF=${#slashes} '
+ function initialize_common() {
+ common_NF = NF;
+ for (i = 1; i <= NF; i++) common[i] = $i;
+ common_degeneracy = 1;
+ common0_NF = NF;
+ common0_str = $0;
+ }
+ function print_common(_, output) {
+ if (!common_NF) return;
+ if (common_degeneracy == 1) {
+ print common0_str;
+ common_NF = 0;
+ return;
+ }
+ output = common[1];
+ for (i = 2; i <= common_NF; i++)
+ output = output "/" common[i];
+ if (common_NF == common0_NF) print output;
+ print output "/";
+ common_NF = 0;
+ }
+ {
+ if (NF <= baseNF + 1) {
+ print_common();
+ print $0;
+ } else if (!common_NF) {
+ initialize_common();
+ } else {
+ n = common_NF < NF ? common_NF : NF;
+ for (i = baseNF + 1; i <= n; i++)
+ if (common[i] != $i) break;
+ matched_length = i - 1;
+ if (matched_length <= baseNF) {
+ print_common();
+ initialize_common();
+ } else {
+ common_NF = matched_length;
+ common_degeneracy++;
+ }
+ }
+ }
+ END { print_common(); }
+ '
+}
+function ble/complete/source:command/gen.1 {
+ local COMPS=$COMPS COMPV=$COMPV
+ ble/complete/source/reduce-compv-for-ambiguous-match
+ local slow_compgen=
+ if [[ ! $COMPV ]]; then
+ slow_compgen=1
+ elif [[ $OSTYPE == cygwin* ]]; then
+ case $COMPV in
+ (?|cy*|x8*|i6*)
+ slow_compgen=1 ;;
+ esac
+ fi
+ if [[ $slow_compgen ]]; then
+ shopt -q no_empty_cmd_completion && return 0
+ ble/util/conditional-sync \
+ 'builtin compgen -c -- "$COMPV"' \
+ '! ble/complete/check-cancel' 128 progressive-weight
+ else
+ builtin compgen -c -- "$COMPV"
+ fi
+ if [[ $COMPV == */* ]]; then
+ local q="'" Q="'\''"
+ local compv_quoted="'${COMPV//$q/$Q}'"
+ builtin compgen -A function -- "$compv_quoted"
+ fi
+}
+function ble/complete/source:command/gen {
+ if [[ :$comp_type: != *:[maA]:* && $bleopt_complete_contract_function_names ]]; then
+ ble/complete/source:command/gen.1 |
+ ble/complete/source:command/.contract-by-slashes
+ else
+ ble/complete/source:command/gen.1
+ fi
+ if [[ $arg != *D* ]]; then
+ local ret
+ ble/complete/source:file/.construct-pathname-pattern "$COMPV"
+ ble/complete/util/eval-pathname-expansion "$ret/"; (($?==148)) && return 148
+ ble/complete/source/test-limit ${#ret[@]} || return 1
+ ((${#ret[@]})) && printf '%s\n' "${ret[@]}"
+ fi
+ if [[ ! $COMPV || $COMPV == %* ]]; then
+ local q="'" Q="'\''"
+ local compv_quoted=${COMPV#'%'}
+ compv_quoted="'${compv_quoted//$q/$Q}'"
+ builtin compgen -j -P % -- "$compv_quoted"
+ local i joblist; ble/util/joblist
+ local job_count=${#joblist[@]}
+ for i in "${!joblist[@]}"; do
+ if local rex='^\[([0-9]+)\]'; [[ ${joblist[i]} =~ $rex ]]; then
+ joblist[i]=%${BASH_REMATCH[1]}
+ else
+ builtin unset -v 'joblist[i]'
+ fi
+ done
+ joblist=("${joblist[@]}")
+ if ((job_count>0)); then
+ ble/array#push joblist %% %+
+ ((job_count>=2)) &&
+ ble/array#push joblist %-
+ fi
+ builtin compgen -W '"${joblist[@]}"' -- "$compv_quoted"
+ fi
+}
+function ble/complete/source:command {
+ [[ $comps_flags == *v* ]] || return 1
+ [[ ! $COMPV ]] && shopt -q no_empty_cmd_completion && return 1
+ [[ $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]}
+ local arg=$1
+ {
+ local old_cand_count=$cand_count
+ local comp_opts=:
+ ble/complete/source:argument/.generate-user-defined-completion initial; local ext=$?
+ ((ext==148)) && return "$ext"
+ if ((ext==0)); then
+ ((cand_count>old_cand_count)) && return "$ext"
+ fi
+ }
+ ble/complete/source:sabbrev
+ local arr
+ local compgen
+ ble/util/assign compgen 'ble/complete/source:command/gen "$arg"'
+ [[ $compgen ]] || return 1
+ ble/util/assign-array arr 'ble/bin/sort -u <<< "$compgen"' # 1 fork/exec
+ ble/complete/source/test-limit ${#arr[@]} || return 1
+ local action=command "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ local is_quoted=
+ [[ $COMPS != "$COMPV" ]] && is_quoted=1
+ local rex_keyword='^(if|then|else|elif|fi|case|esac|for|select|while|until|do|done|function|time|[!{}]|\[\[|coproc|\]\]|in)$'
+ local expand_aliases=
+ shopt -q expand_aliases && expand_aliases=1
+ local cand icand=0 cands
+ for cand in "${arr[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ [[ $cand != */ && -d $cand ]] && ! type "$cand" &>/dev/null && continue
+ if [[ $is_quoted ]]; then
+ local disable_count=
+ [[ $cand =~ $rex_keyword ]] && ((disable_count++))
+ [[ $expand_aliases ]] && ble/is-alias "$cand" && ((disable_count++))
+ if [[ $disable_count ]]; then
+ local type; ble/util/type type "$cand"
+ ((${#type[@]}>disable_count)) || continue
+ fi
+ else
+ [[ $cand == ']]' || $cand == in ]] &&
+ ! { [[ $expand_aliases ]] && ble/is-alias "$cand"; } &&
+ continue
+ if [[ ! $expand_aliases ]]; then
+ ble/is-alias "$cand" && ! type "$cand" &>/dev/null && continue
+ fi
+ if ble/string#match "$cand" '[][*?{,}!^~#]' && ble/is-alias "$cand"; then
+ ble/complete/cand/yield "$action" "$cand" :noquote:
+ continue
+ fi
+ fi
+ cands[icand++]=$cand
+ done
+ ble/complete/cand/yield.batch "$action"
+}
+function ble/complete/util/eval-pathname-expansion/.print-def {
+ local pattern=$1 ret
+ IFS= builtin eval "ret=($pattern)" 2>/dev/null
+ ble/string#quote-words "${ret[@]}"
+ ble/util/print "ret=($ret)"
+}
+function ble/complete/util/eval-pathname-expansion {
+ local pattern=$1
+ local -a dtor=()
+ if [[ -o noglob ]]; then
+ set +f
+ ble/array#push dtor 'set -f'
+ fi
+ if ! shopt -q nullglob; then
+ shopt -s nullglob
+ ble/array#push dtor 'shopt -u nullglob'
+ fi
+ if ! shopt -q dotglob; then
+ shopt -s dotglob
+ ble/array#push dtor 'shopt -u dotglob'
+ else
+ ble/array#push dtor 'shopt -s dotglob'
+ fi
+ if ! shopt -q extglob; then
+ shopt -s extglob
+ ble/array#push dtor 'shopt -u extglob'
+ fi
+ if [[ :$comp_type: == *:i:* ]]; then
+ if ! shopt -q nocaseglob; then
+ shopt -s nocaseglob
+ ble/array#push dtor 'shopt -u nocaseglob'
+ fi
+ else
+ if shopt -q nocaseglob; then
+ shopt -u nocaseglob
+ ble/array#push dtor 'shopt -s nocaseglob'
+ fi
+ fi
+ if ble/util/is-cygwin-slow-glob "$pattern"; then # Note: #D1168
+ if shopt -q failglob &>/dev/null || shopt -q nullglob &>/dev/null; then
+ pattern=
+ else
+ set -f
+ ble/array#push dtor 'set +f'
+ fi
+ fi
+ if [[ $GLOBIGNORE ]]; then
+ local GLOBIGNORE_save=$GLOBIGNORE
+ GLOBIGNORE=
+ ble/array#push dtor 'GLOBIGNORE=$GLOBIGNORE_save'
+ fi
+ ble/array#reverse dtor
+ ret=()
+ if [[ :$comp_type: == *:sync:* ]]; then
+ IFS= builtin eval "ret=($pattern)" 2>/dev/null
+ else
+ local sync_command='ble/complete/util/eval-pathname-expansion/.print-def "$pattern"'
+ local sync_opts=progressive-weight
+ [[ :$comp_type: == *:auto:* && $bleopt_complete_timeout_auto ]] &&
+ sync_opts=$sync_opts:timeout=$((bleopt_complete_timeout_auto))
+ local def
+ ble/util/assign def 'ble/util/conditional-sync "$sync_command" "" "" "$sync_opts"' &>/dev/null; local ext=$?
+ if ((ext==148)) || ble/complete/check-cancel; then
+ ble/util/invoke-hook dtor
+ return 148
+ fi
+ builtin eval -- "$def"
+ fi 2>&$_ble_util_fd_stderr
+ ble/util/invoke-hook dtor
+ return 0
+}
+function ble/complete/source:file/.construct-ambiguous-pathname-pattern {
+ local path=$1 fixlen=${2:-1}
+ local pattern= i=0 j
+ local names; ble/string#split names / "$1"
+ local name
+ for name in "${names[@]}"; do
+ ((i++)) && pattern=$pattern/
+ if [[ $name ]]; then
+ ble/string#quote-word "${name::fixlen}"
+ pattern=$pattern$ret*
+ for ((j=fixlen;j<${#name};j++)); do
+ ble/string#quote-word "${name:j:1}"
+ if [[ $_ble_bash -lt 50000 && $pattern == *\* ]]; then
+ pattern=$pattern'([!'$ret'])'
+ fi
+ pattern=$pattern$ret*
+ done
+ fi
+ done
+ [[ $pattern == *'*' ]] || pattern=$pattern*
+ ret=$pattern
+}
+function ble/complete/source:file/.construct-pathname-pattern {
+ local path=$1 pattern
+ case :$comp_type: in
+ (*:a:*) ble/complete/source:file/.construct-ambiguous-pathname-pattern "$path"; pattern=$ret ;;
+ (*:A:*) ble/complete/source:file/.construct-ambiguous-pathname-pattern "$path" 0; pattern=$ret ;;
+ (*:m:*) ble/string#quote-word "$path"; pattern=*$ret* ;;
+ (*) ble/string#quote-word "$path"; pattern=$ret*
+ esac
+ ret=$pattern
+}
+function ble/complete/source:file/.impl {
+ local opts=$1
+ [[ $comps_flags == *v* ]] || return 1
+ [[ :$comp_type: != *:[maA]:* && $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]}
+ [[ :$comp_type: == *:[maA]:* && ! $COMPV ]] && return 1
+ ble/complete/source:tilde; local ext=$?
+ ((ext==148||ext==0)) && return "$ext"
+ local -a candidates=()
+ local ret
+ ble/complete/source:file/.construct-pathname-pattern "$COMPV"
+ [[ :$opts: == *:directory:* ]] && ret=$ret/
+ ble/complete/util/eval-pathname-expansion "$ret"; (($?==148)) && return 148
+ ble/complete/source/test-limit ${#ret[@]} || return 1
+ if [[ :$opts: == *:directory:* ]]; then
+ candidates=("${ret[@]%/}")
+ else
+ candidates=("${ret[@]}")
+ fi
+ [[ :$opts: == *:no-fd:* ]] &&
+ ble/array#remove-by-regex candidates '^[0-9]+-?$|^-$'
+ local flag_source_filter=1
+ ble/complete/cand/yield-filenames file "${candidates[@]}"
+}
+function ble/complete/source:file {
+ ble/complete/source:file/.impl "$1"
+}
+function ble/complete/source:dir {
+ ble/complete/source:file/.impl "directory:$1"
+}
+function ble/complete/source:rhs { ble/complete/source:file; }
+function ble/complete/action:tilde/initialize {
+ CAND=${CAND#\~} ble/complete/action/quote-insert
+ INSERT=\~$INSERT
+ local rex='^~[^/'\''"$`\!:]*$'; [[ $INSERT =~ $rex ]]
+}
+function ble/complete/action:tilde/complete {
+ ble/complete/action/complete.mark-directory
+}
+function ble/complete/action:tilde/init-menu-item {
+ local ret
+ ble/color/face2g filename_directory; g=$ret
+}
+function ble/complete/action:tilde/get-desc {
+ if [[ $CAND == '~+' ]]; then
+ desc='current directory (tilde expansion)'
+ elif [[ $CAND == '~-' ]]; then
+ desc='previous directory (tilde expansion)'
+ elif local rex='^~[0-9]$'; [[ $CAND =~ $rex ]]; then
+ desc='DIRSTACK directory (tilde expansion)'
+ else
+ desc='user directory (tilde expansion)'
+ fi
+}
+function ble/complete/source:tilde/.generate {
+ local pattern=${COMPS#\~}
+ [[ :$comp_type: == *:[maA]:* ]] && pattern=
+ builtin compgen -P \~ -u -- "$pattern"
+ printf '%s\n' '~' '~+' '~-'
+ local dirstack_max=$((${#DIRSTACK[@]}-1))
+ ((dirstack_max>=0)) &&
+ builtin eval "printf '%s\n' '~'{0..$dirstack_max}"
+}
+function ble/complete/source:tilde {
+ local rex='^~[^/'\''"$`\!:]*$'; [[ $COMPS =~ $rex ]] || return 1
+ local compgen candidates
+ ble/util/assign compgen ble/complete/source:tilde/.generate
+ [[ $compgen ]] || return 1
+ ble/util/assign-array candidates 'ble/bin/sort -u <<< "$compgen"'
+ local flag_source_filter=1
+ if [[ $COMPS == '~'?* ]]; then
+ local filter_type=$comp_filter_type
+ [[ $filter_type == none ]] && filter_type=head
+ local comp_filter_type
+ local comp_filter_pattern
+ ble/complete/candidates/filter#init "$filter_type" "$COMPS"
+ ble/array#filter candidates ble/complete/candidates/filter#test
+ fi
+ ((${#candidates[@]})) || return 1
+ local old_cand_count=$cand_count
+ ble/complete/cand/yield-filenames tilde "${candidates[@]}"; local ext=$?
+ return $((ext?ext:cand_count>old_cand_count))
+}
+function ble/complete/source:fd {
+ IFS=: builtin eval 'local fdlist=":${_ble_util_openat_fdlist[*]}:"'
+ [[ $comp_filter_type == none ]] &&
+ local comp_filter_type=head
+ local old_cand_count=$cand_count
+ local action=word "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ ble/complete/cand/yield "$action" -
+ if [[ -d /proc/self/fd ]]; then
+ local ret
+ ble/complete/util/eval-pathname-expansion '/proc/self/fd/*'
+ local fd
+ for fd in "${ret[@]}"; do
+ fd=${fd#/proc/self/fd/}
+ [[ ${fd//[0-9]} ]] && continue
+ [[ $fdlist == *:"$fd":* ]] && continue
+ ble/complete/cand/yield "$action" "$fd"
+ ble/complete/cand/yield "$action" "$fd-"
+ done
+ else
+ local fd
+ for ((fd=0;fd<10;fd++)); do
+ ble/fd#is-open "$fd" || continue
+ ble/complete/cand/yield "$action" "$fd"
+ ble/complete/cand/yield "$action" "$fd-"
+ done
+ fi
+ return $((cand_count>old_cand_count))
+}
+function ble/complete/progcomp/.compvar-initialize-wordbreaks {
+ local ifs=$_ble_term_IFS q=\'\" delim=';&|<>()' glob='[*?' hist='!^{' esc='`$\'
+ local escaped=$ifs$q$delim$glob$hist$esc
+ wordbreaks=${COMP_WORDBREAKS//[$escaped]} # =:
+}
+function ble/complete/progcomp/.compvar-perform-wordbreaks {
+ local word=$1
+ if [[ ! $word ]]; then
+ ret=('')
+ return 0
+ fi
+ ret=()
+ while local head=${word%%["$wordbreaks"]*}; [[ $head != $word ]]; do
+ ble/array#push ret "$head"
+ word=${word:${#head}}
+ head=${word%%[!"$wordbreaks"]*}
+ ble/array#push ret "$head"
+ word=${word:${#head}}
+ done
+ ble/array#push ret "$word"
+}
+function ble/complete/progcomp/.compvar-eval-word {
+ local opts=$2:single
+ if [[ :$opts: == *:noglob:* ]]; then
+ ble/syntax:bash/simple-word/eval "$1" "$opts"
+ else
+ [[ $bleopt_complete_timeout_compvar ]] &&
+ opts=timeout=$((bleopt_complete_timeout_compvar)):retry-noglob-on-timeout:$opts
+ ble/complete/source/eval-simple-word "$1" "$opts"
+ fi
+}
+function ble/complete/progcomp/.compvar-generate-subwords/impl1 {
+ local word=$1 ret simple_flags simple_ibrace
+ if [[ $point ]]; then
+ local left=${word::point} right=${word:point}
+ else
+ local left=$word right=
+ local point= # hide
+ fi
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$left" || return 1
+ left=$ret
+ if [[ $right ]]; then
+ case $simple_flags in
+ (*I*) right=\$\"$right ;;
+ (*D*) right=\"$right ;;
+ (*E*) right=\$\'$right ;;
+ (*S*) right=\'$right ;;
+ (*B*) right=\\$right ;;
+ esac
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$right" || return 1
+ right=$ret
+ fi
+ point=0 words=()
+ local eval_opts=noglob
+ ((${#ret[@]}==1)) && eval_opts=
+ ble/syntax:bash/simple-word#break-word "$left"
+ local subword
+ for subword in "${ret[@]}"; do
+ ble/complete/progcomp/.compvar-eval-word "$subword" "$eval_opts"
+ ble/array#push words "$ret"
+ ((point+=${#ret}))
+ done
+ if [[ $right ]]; then
+ ble/syntax:bash/simple-word#break-word "$right"
+ local subword isfirst=1
+ for subword in "${ret[@]}"; do
+ ble/complete/progcomp/.compvar-eval-word "$subword" noglob
+ if [[ $isfirst ]]; then
+ isfirst=
+ local iword=${#words[@]}; ((iword&&iword--))
+ words[iword]=${words[iword]}$ret
+ else
+ ble/array#push words "$ret"
+ fi
+ done
+ fi
+ return 0
+}
+function ble/complete/progcomp/.compvar-generate-subwords/impl2 {
+ local word=$1
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$word" || return 1
+ ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148; local value1=$ret
+ if [[ $point ]]; then
+ if ((point==${#word})); then
+ point=${#value1}
+ elif ble/syntax:bash/simple-word/reconstruct-incomplete-word "${word::point}"; then
+ ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148
+ point=${#ret}
+ fi
+ fi
+ ble/complete/progcomp/.compvar-perform-wordbreaks "$value1"; words=("${ret[@]}")
+ return 0
+}
+function ble/complete/progcomp/.compvar-generate-subwords {
+ local word1=$1 ret simple_flags simple_ibrace
+ if [[ ! $word1 ]]; then
+ subword_flags=E
+ words=('')
+ elif [[ $word1 == '~' ]]; then
+ subword_flags=Q
+ words=('~')
+ elif ble/complete/progcomp/.compvar-generate-subwords/impl1 "$word1"; then
+ subword_flags=E
+ elif ble/complete/progcomp/.compvar-generate-subwords/impl2 "$word1"; then
+ subword_flags=E
+ else
+ ble/complete/progcomp/.compvar-perform-wordbreaks "$word1"; words=("${ret[@]}")
+ fi
+}
+function ble/complete/progcomp/.compvar-quote-subword {
+ local word=$1 to_quote= is_evaluated= is_quoted=
+ if [[ $subword_flags == *[EQ]* ]]; then
+ [[ $subword_flags == *E* ]] && to_quote=1
+ elif ble/syntax:bash/simple-word/reconstruct-incomplete-word "$word"; then
+ is_evaluated=1
+ ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148; word=$ret
+ to_quote=1
+ fi
+ if [[ $to_quote ]]; then
+ local shell_specialchars=']\ ["'\''`$|&;<>()*?{}!^'$'\n\t' q="'" Q="'\''" qq="''"
+ if ((index>0)) && [[ $word == *["$shell_specialchars"]* || $word == [#~]* ]]; then
+ is_quoted=1
+ word="'${w//$q/$Q}'" word=${word#"$qq"} word=${word%"$qq"}
+ fi
+ fi
+ if [[ $p && $word != "$1" ]]; then
+ if ((p==${#1})); then
+ p=${#word}
+ else
+ local left=${word::p}
+ if [[ $is_evaluated ]]; then
+ if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$left"; then
+ ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148; left=$ret
+ fi
+ fi
+ if [[ $is_quoted ]]; then
+ left="'${left//$q/$Q}" left=${left#"$qq"}
+ fi
+ p=${#left}
+ fi
+ fi
+ ret=$word
+}
+function ble/complete/progcomp/.compvar-initialize {
+ COMP_TYPE=9
+ COMP_KEY=9
+ ((${#KEYS[@]})) && COMP_KEY=${KEYS[${#KEYS[@]}-1]:-9} # KEYS defined in ble-decode/widget/.call-keyseq
+ local wordbreaks
+ ble/complete/progcomp/.compvar-initialize-wordbreaks
+ progcomp_prefix=
+ COMP_CWORD=
+ COMP_POINT=
+ COMP_LINE=
+ COMP_WORDS=()
+ local ret simple_flags simple_ibrace
+ local word1 index=0 offset=0 sep=
+ for word1 in "${comp_words[@]}"; do
+ local point=$((comp_point-offset))
+ ((0<=point&&point<=${#word1})) || point=
+ ((offset+=${#word1}))
+ local words subword_flags=
+ ble/complete/progcomp/.compvar-generate-subwords "$word1"
+ local w wq i=0 o=0 p
+ for w in "${words[@]}"; do
+ p=
+ if [[ $point ]]; then
+ ((p=point-o))
+ ((i%2==0?p<=${#w}:p<${#w})) || p=
+ ((o+=${#w},i++))
+ fi
+ [[ $p ]] && point=
+ [[ $point ]] && progcomp_prefix=$progcomp_prefix$w
+ ble/complete/progcomp/.compvar-quote-subword "$w"; local wq=$ret
+ if [[ $p ]]; then
+ COMP_CWORD=${#COMP_WORDS[*]}
+ ((COMP_POINT=${#COMP_LINE}+${#sep}+p))
+ fi
+ ble/array#push COMP_WORDS "$wq"
+ COMP_LINE=$COMP_LINE$sep$wq
+ sep=
+ done
+ sep=' '
+ ((offset++))
+ ((index++))
+ done
+}
+function ble/complete/progcomp/.compgen-helper-prog {
+ if [[ $comp_prog ]]; then
+ local COMP_WORDS COMP_CWORD
+ local -x COMP_LINE COMP_POINT COMP_TYPE COMP_KEY
+ ble/complete/progcomp/.compvar-initialize
+ local cmd=${COMP_WORDS[0]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+ if [[ $comp_opts == *:ble/prog-trim:* ]]; then
+ local compreply
+ ble/util/assign compreply '"$comp_prog" "$cmd" "$cur" "$prev" < /dev/null'
+ ble/bin/sed "s/[[:space:]]\{1,\}\$//" <<< "$compreply"
+ else
+ "$comp_prog" "$cmd" "$cur" "$prev" < /dev/null
+ fi
+ fi
+}
+function ble/complete/progcomp/compopt {
+ local ext=0
+ local -a ospec
+ while (($#)); do
+ local arg=$1; shift
+ case "$arg" in
+ (-*)
+ local ic c
+ for ((ic=1;ic<${#arg};ic++)); do
+ c=${arg:ic:1}
+ case "$c" in
+ (o) ospec[${#ospec[@]}]="-$1"; shift ;;
+ ([DE]) fDefault=1; break 2 ;;
+ (*) ((ext==0&&(ext=1))) ;;
+ esac
+ done ;;
+ (+o) ospec[${#ospec[@]}]="+$1"; shift ;;
+ (*)
+ return "$ext" ;;
+ esac
+ done
+ local s
+ for s in "${ospec[@]}"; do
+ case "$s" in
+ (-*) comp_opts=${comp_opts//:"${s:1}":/:}${s:1}: ;;
+ (+*) comp_opts=${comp_opts//:"${s:1}":/:} ;;
+ esac
+ done
+ return "$ext"
+}
+function ble/complete/progcomp/.check-limits {
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) &&
+ [[ ! -t 0 ]] && ble/complete/check-cancel <&$_ble_util_fd_stdin &&
+ return 148
+ ble/complete/source/test-limit $((progcomp_read_count++))
+ return "$?"
+}
+function ble/complete/progcomp/.compgen-helper-func {
+ [[ $comp_func ]] || return 1
+ local -a COMP_WORDS
+ local COMP_LINE COMP_POINT COMP_CWORD COMP_TYPE COMP_KEY
+ ble/complete/progcomp/.compvar-initialize
+ local progcomp_read_count=0
+ local _ble_builtin_read_hook='ble/complete/progcomp/.check-limits || { builtin read "$@" < /dev/null; return 148; }'
+ local fDefault=
+ local cmd=${COMP_WORDS[0]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+ ble/function#push compopt 'ble/complete/progcomp/compopt "$@"'
+ ble/function#push ssh '
+ local IFS=$_ble_term_IFS
+ if [[ " ${FUNCNAME[*]} " == *" ble/complete/progcomp/.compgen "* ]]; then
+ local -a args; args=("$@")
+ ble/util/conditional-sync "exec ssh \"\${args[@]}\"" \
+ "! ble/complete/check-cancel <&$_ble_util_fd_stdin" 128 progressive-weight:killall
+ else
+ ble/function#push/call-top "$@"
+ fi'
+ builtin eval '"$comp_func" "$cmd" "$cur" "$prev"' < /dev/null >&$_ble_util_fd_stdout 2>&$_ble_util_fd_stderr; local ret=$?
+ ble/function#pop ssh
+ ble/function#pop compopt
+ [[ $ret == 124 ]] && progcomp_retry=1
+ return 0
+}
+function ble/complete/progcomp/.parse-complete/next {
+ if [[ $compdef =~ $rex ]]; then
+ builtin eval "arg=$BASH_REMATCH"
+ compdef=${compdef:${#BASH_REMATCH}}
+ return 0
+ elif [[ ${compdef%%' '*} ]]; then
+ arg=${compdef%%' '*}
+ compdef=${compdef#*' '}
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/complete/progcomp/.parse-complete/optarg {
+ optarg=
+ if ((ic+1<${#arg})); then
+ optarg=${arg:ic+1}
+ ic=${#arg}
+ return 0
+ elif [[ $compdef =~ $rex ]]; then
+ builtin eval "optarg=$BASH_REMATCH"
+ compdef=${compdef:${#BASH_REMATCH}}
+ return 0
+ else
+ return 2
+ fi
+}
+function ble/complete/progcomp/.parse-complete {
+ compoptions=()
+ comp_prog=
+ comp_func=
+ flag_noquote=
+ local compdef=${1#'complete '}
+ local arg optarg rex='^([^][*?;&|[:space:]<>()\`$"'\''{}#^!]|\\.|'\''[^'\'']*'\'')+[[:space:]]+' # #D1709 safe (WA gawk 4.0.2)
+ while ble/complete/progcomp/.parse-complete/next; do
+ case $arg in
+ (-*)
+ local ic c
+ for ((ic=1;ic<${#arg};ic++)); do
+ c=${arg:ic:1}
+ case "$c" in
+ ([abcdefgjksuvE])
+ case $c in
+ (c) flag_noquote=1 ;;
+ (d) ((_ble_bash>=40300)) && flag_noquote=1 ;;
+ (f) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;;
+ esac
+ ble/array#push compoptions "-$c" ;;
+ ([pr])
+ ;; # 無視 (-p 表示 -r 削除)
+ ([AGWXPS])
+ ble/complete/progcomp/.parse-complete/optarg || break 2
+ if [[ $c == A ]]; then
+ case $optarg in
+ (command) flag_noquote=1 ;;
+ (directory) ((_ble_bash>=40300)) && flag_noquote=1 ;;
+ (file) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;;
+ esac
+ fi
+ ble/array#push compoptions "-$c" "$optarg" ;;
+ (o)
+ ble/complete/progcomp/.parse-complete/optarg || break 2
+ comp_opts=${comp_opts//:"$optarg":/:}$optarg:
+ ble/array#push compoptions "-$c" "$optarg" ;;
+ (C)
+ if ((_ble_bash<40000)); then
+ comp_prog=${compdef%' '}
+ compdef=
+ else
+ ble/complete/progcomp/.parse-complete/optarg || break 2
+ comp_prog=$optarg
+ fi
+ ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-prog ;;
+ (F)
+ if ((_ble_bash<40000)) && [[ $compdef == *' -C '* ]]; then
+ comp_prog=${compdef#*' -C '}
+ comp_prog=${comp_prog%' '}
+ ble/array#push compoptions '-C' ble/complete/progcomp/.compgen-helper-prog
+ comp_func=${compdef%%' -C '*}
+ else
+ comp_func=${compdef%' '}
+ fi
+ compdef=
+ ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-func ;;
+ (*)
+ esac
+ done ;;
+ (*)
+ ;; # 無視
+ esac
+ done
+}
+function ble/complete/progcomp/.filter-and-split-compgen {
+ flag_mandb=
+ local sed_script=
+ {
+ if [[ $comp_opts == *:ble/filter-by-prefix:* ]]; then
+ local ret; ble/string#escape-for-sed-regex "$COMPV"; local rex_compv=$ret
+ sed_script='!/^'$rex_compv'/d'
+ fi
+ [[ $use_workaround_for_git ]] &&
+ sed_script=${sed_script:+$sed_script;}'s/[[:space:]]\{1,\}$//'
+ }
+ local out=
+ [[ $sed_script ]] && ble/util/assign out 'ble/bin/sed "$sed_script;/^\$/d" <<< "$compgen"'
+ [[ $out ]] || out=$compgen
+ local require_awk=
+ if [[ $comp_opts != *:nosort:* ]]; then
+ ble/util/assign out 'ble/bin/sort -u <<< "$out"'
+ else
+ require_awk=1 # for uniq
+ fi
+ local -a args_mandb=()
+ if [[ $compcmd == "${comp_words[0]}" && $COMPV != [!-]* ]]; then
+ if local ret; ble/complete/mandb/generate-cache "$compcmd"; then
+ require_awk=1
+ args_mandb=(mode=mandb "$ret")
+ fi
+ fi
+ if [[ $require_awk ]]; then
+ local awk_script='
+ BEGIN { mandb_count = 0; }
+ mode == "mandb" {
+ name = $0
+ sub(/'"$_ble_term_FS"'.*/, "", name);
+ if (!mandb[name]) mandb[name] = $0;
+ next;
+ }
+ !hash[$0]++ {
+ if (/^$/) next;
+ name = $0
+ sub(/=$/, "", name);
+ if (mandb[name]) {
+ mandb_count++;
+ print mandb[name];
+ next;
+ } else if (sub(/^--no-/, "--", name)) {
+ if ((entry = mandb[name]) || (entry = mandb[substr(name, 2)])) {
+ split(entry, record, FS);
+ if ((desc = record[4])) {
+ desc = "\033[1mReverse[\033[m " desc " \033[;1m]\033[m";
+ if (match($0, /[[:space:]]*[:=[]/)) {
+ option = substr($0, 1, RSTART - 1);
+ optarg = substr($0, RSTART);
+ suffix = substr($0, RSTART, 1);
+ if (suffix == "[") suffix = "";
+ } else {
+ option = $0;
+ optarg = "";
+ suffix = " ";
+ }
+ mandb_count++;
+ print option FS optarg FS suffix FS desc;
+ }
+ next;
+ }
+ }
+ print $0;
+ }
+ END { if (mandb_count) exit 10; }
+ '
+ ble/util/assign-array "$1" 'ble/bin/awk -F "$_ble_term_FS" "$awk_script" "${args_mandb[@]}" mode=compgen - <<< "$out"'
+ (($?==10)) && flag_mandb=1
+ else
+ ble/string#split-lines "$1" "$out"
+ fi
+ return 0
+} 2>/dev/null
+function ble/complete/progcomp/.cobraV2.patch {
+ local prefix=$cur
+ [[ $comps_flags == *v* ]] && prefix=$COMPV
+ local unprocessed has_desc=
+ unprocessed=()
+ local lines line cand desc
+ for lines in "${out[@]}"; do
+ ble/string#split-lines lines "$lines"
+ for line in "${lines[@]}"; do
+ if [[ $line == *$'\t'* ]]; then
+ cand=${line%%$'\t'*}
+ desc=${line#*$'\t'}
+ [[ $cand == "$prefix"* ]] || continue
+ ble/complete/cand/yield word "$cand" "$desc"
+ has_desc=1
+ else
+ ble/array#push unprocessed "$line"
+ fi
+ done
+ done
+ [[ $has_desc ]] && bleopt complete_menu_style=desc
+ if ((${#unprocessed[@]})); then
+ out=("${unprocessed[@]}")
+ ble/function#advice/do
+ fi
+}
+function ble/complete/progcomp/.compgen {
+ local opts=$1
+ local compcmd= is_special_completion=
+ local -a alias_args=()
+ if [[ :$opts: == *:initial:* ]]; then
+ if ((_ble_bash>=50000)); then
+ is_special_completion=1
+ compcmd='-I'
+ else
+ compcmd=_InitialWorD_
+ fi
+ elif [[ :$opts: == *:default:* ]]; then
+ if ((_ble_bash>=40100)); then
+ builtin complete -p -D &>/dev/null || return 1
+ is_special_completion=1
+ compcmd='-D'
+ else
+ builtin complete -p _DefaultCmD_ &>/dev/null || return 1
+ compcmd=_DefaultCmD_
+ fi
+ else
+ compcmd=${comp_words[0]}
+ fi
+ local compdef
+ if [[ $is_special_completion ]]; then
+ ble/util/assign compdef 'builtin complete -p "$compcmd" 2>/dev/null'
+ elif ble/syntax:bash/simple-word/is-simple "$compcmd"; then
+ ble/util/assign compdef "builtin complete -p -- $compcmd 2>/dev/null"
+ local ret; ble/syntax:bash/simple-word/eval "$compcmd"; compcmd=$ret
+ else
+ ble/util/assign compdef 'builtin complete -p -- "$compcmd" 2>/dev/null'
+ fi
+ compdef=${compdef%"${compcmd:-''}"}
+ compdef=${compdef%' '}' '
+ local comp_prog comp_func compoptions flag_noquote
+ ble/complete/progcomp/.parse-complete "$compdef"
+ if [[ $comp_func ]]; then
+ [[ $comp_func == _fzf_* ]] &&
+ ble-import -f contrib/fzf-completion
+ if ble/is-function _quote_readline_by_ref; then
+ function _quote_readline_by_ref {
+ if [[ $1 == \'* ]]; then
+ printf -v "$2" %s "${1:1}"
+ else
+ printf -v "$2" %q "$1"
+ [[ ${!2} == \$* ]] && builtin eval "$2=${!2}"
+ fi
+ }
+ ble/function#suppress-stderr _filedir 2>/dev/null
+ ble/function#suppress-stderr _find 2>/dev/null
+ ble/function#suppress-stderr _scp_remote_files 2>/dev/null
+ ble/complete/mandb:_parse_help/inject
+ fi
+ if [[ $comp_func == __start_* ]]; then
+ local target=__${comp_func#__start_}_handle_completion_types
+ ble/is-function "$target" &&
+ ble/function#advice around "$target" ble/complete/progcomp/.cobraV2.patch
+ fi
+ ble/function#advice around _dnf_commands_helper '
+ ble/util/conditional-sync \
+ ble/function#advice/do \
+ "! ble/complete/check-cancel <&$_ble_util_fd_stdin" 128 progressive-weight:killall' 2>/dev/null
+ fi
+ if [[ $comp_prog ]]; then
+ if [[ $comp_prog == aws_completer ]]; then
+ comp_opts=${comp_opts}ble/no-mark-directories:ble/prog-trim:
+ fi
+ fi
+ ble/complete/check-cancel && return 148
+ local compgen compgen_compv=$COMPV
+ if [[ ! $flag_noquote && :$comp_opts: != *:noquote:* ]]; then
+ local q="'" Q="'\''"
+ compgen_compv="'${compgen_compv//$q/$Q}'"
+ fi
+ local progcomp_prefix= progcomp_retry=
+ IFS=$IFS word= ble/util/assign compgen 'builtin compgen "${compoptions[@]}" -- "$compgen_compv" 2>/dev/null'
+ if [[ $progcomp_retry && ! $_ble_complete_retry_guard ]]; then
+ local _ble_complete_retry_guard=1
+ opts=:$opts:
+ opts=${opts//:default:/:}
+ ble/complete/progcomp/.compgen "$opts"
+ return "$?"
+ fi
+ [[ $compgen ]] || return 1
+ local use_workaround_for_git=
+ if [[ $comp_func == __git* && $comp_opts == *:nospace:* ]]; then
+ use_workaround_for_git=1
+ comp_opts=${comp_opts//:nospace:/:}
+ fi
+ local cands flag_mandb=
+ ble/complete/progcomp/.filter-and-split-compgen cands # compgen (comp_opts, etc) -> cands, flag_mandb
+ ble/complete/source/test-limit ${#cands[@]} || return 1
+ [[ $comp_opts == *:filenames:* && $COMPV == */* ]] && COMP_PREFIX=${COMPV%/*}/
+ local old_cand_count=$cand_count
+ local action=progcomp "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ if [[ $flag_mandb ]]; then
+ local -a entries; entries=("${cands[@]}")
+ cands=()
+ local fs=$_ble_term_FS has_desc= icand=0 entry
+ for entry in "${entries[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ if [[ $entry == -*"$fs"*"$fs"*"$fs"* ]]; then
+ local cand=${entry%%"$fs"*}
+ ble/complete/cand/yield mandb "$cand" "$entry"
+ [[ $entry == *"$fs"*"$fs"*"$fs"?* ]] && has_desc=1
+ else
+ cands[icand++]=$progcomp_prefix$entry
+ fi
+ done
+ [[ $has_desc ]] && bleopt complete_menu_style=desc
+ else
+ [[ $progcomp_prefix ]] &&
+ if ((_ble_bash>=40300)) && ! shopt -q compat42; then
+ cands=("${cands[@]/#/"$progcomp_prefix"}") # WA #D1570 #D1751 safe
+ else
+ cands=("${cands[@]/#/$progcomp_prefix}") # WA #D1570 #D1738 safe
+ fi
+ fi
+ ble/complete/cand/yield.batch "$action" "$comp_opts"
+ [[ $comp_opts == *:plusdirs:* ]] && ble/complete/source:dir
+ ((cand_count>old_cand_count))
+}
+function ble/complete/progcomp/.compline-rewrite-command {
+ local ocmd=${comp_words[0]}
+ [[ $1 != "$ocmd" ]] || (($#>=2)) || return 1
+ local IFS=$_ble_term_IFS
+ local ins="$*"
+ if (($#==0)); then
+ local ret; ble/string#ltrim "${comp_line:${#ocmd}}"
+ ((comp_point-=${#comp_line}-${#ret}))
+ comp_line=$ret
+ else
+ comp_line=$ins${comp_line:${#ocmd}}
+ ((comp_point-=${#ocmd}))
+ fi
+ ((comp_point<0&&(comp_point=0),comp_point+=${#ins}))
+ comp_words=("$@" "${comp_words[@]:1}")
+ ((comp_cword&&(comp_cword+=$#-1)))
+}
+function ble/complete/progcomp/.split-alias-words {
+ local tail=$1
+ local rex_redir='^'$_ble_syntax_bash_RexRedirect
+ local rex_word='^'$_ble_syntax_bash_simple_rex_element'+'
+ local rex_delim=$'^[\n;|&]'
+ local rex_spaces=$'^[ \t]+'
+ local rex_misc='^[<>()]+'
+ local -a words=()
+ while [[ $tail ]]; do
+ if [[ $tail =~ $rex_redir && $tail != ['<>']'('* ]]; then
+ ble/array#push words "$BASH_REMATCH"
+ tail=${tail:${#BASH_REMATCH}}
+ elif [[ $tail =~ $rex_word ]]; then
+ local w=$BASH_REMATCH
+ tail=${tail:${#w}}
+ if [[ $tail && $tail != ["$_ble_term_IFS;|&<>()"]* ]]; then
+ local s=${tail%%["$_ble_term_IFS"]*}
+ tail=${tail:${#s}}
+ w=$w$s
+ fi
+ ble/array#push words "$w"
+ elif [[ $tail =~ $rex_delim ]]; then
+ words=()
+ tail=${tail:${#BASH_REMATCH}}
+ elif [[ $tail =~ $rex_spaces ]]; then
+ tail=${tail:${#BASH_REMATCH}}
+ elif [[ $tail =~ $rex_misc ]]; then
+ ble/array#push words "$BASH_REMATCH"
+ tail=${tail:${#BASH_REMATCH}}
+ else
+ local w=${tail%%["$_ble_term_IFS"]*}
+ ble/array#push words "$w"
+ tail=${tail:${#w}}
+ fi
+ done
+ local i=0 rex_assign='^[a-zA-Z_0-9]+(\['$_ble_syntax_bash_simple_rex_element'*\])?\+?='
+ while ((i<${#words[@]})); do
+ if [[ ${words[i]} =~ $rex_assign ]]; then
+ ((i++))
+ elif [[ ${words[i]} =~ $rex_redir && ${words[i]} != ['<>']'('* ]]; then
+ ((i+=2))
+ else
+ break
+ fi
+ done
+ ret=("${words[@]:i}")
+}
+function ble/complete/progcomp {
+ local cmd=${1-${comp_words[0]}} opts=$2
+ local -a orig_comp_words; orig_comp_words=("${comp_words[@]}")
+ local comp_words comp_line=$comp_line comp_point=$comp_point comp_cword=$comp_cword
+ comp_words=("$cmd" "${orig_comp_words[@]:1}")
+ local orig_qcmds_set=
+ local -a orig_qcmds=()
+ local -a alias_args=()
+ [[ :$opts: == *:__recursive__:* ]] ||
+ local alias_checked=' '
+ while :; do
+ local ret ucmd qcmds
+ ucmd=$cmd qcmds=("$cmd")
+ if ble/syntax:bash/simple-word/is-simple "$cmd"; then
+ if ble/syntax:bash/simple-word/eval "$cmd" noglob &&
+ [[ $ret != "$cmd" || ${#ret[@]} -ne 1 ]]; then
+ ucmd=${ret[0]} qcmds=()
+ local word
+ for word in "${ret[@]}"; do
+ ble/string#quote-word "$word" quote-empty
+ ble/array#push qcmds "$ret"
+ done
+ else
+ ble/string#quote-word "$cmd" quote-empty
+ qcmds=("$ret")
+ fi
+ [[ $cmd == "${orig_comp_words[0]}" ]] &&
+ orig_qcmds_set=1 orig_qcmds=("${qcmds[@]}")
+ fi
+ if ble/is-function "ble/cmdinfo/complete:$ucmd"; then
+ ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}"
+ "ble/cmdinfo/complete:$ucmd" "$opts"
+ return "$?"
+ elif [[ $ucmd == */?* ]] && ble/is-function "ble/cmdinfo/complete:${ucmd##*/}"; then
+ ble/string#quote-word "${ucmd##*/}"; qcmds[0]=$ret
+ ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}"
+ "ble/cmdinfo/complete:${ucmd##*/}" "$opts"
+ return "$?"
+ elif builtin complete -p -- "$ucmd" &>/dev/null; then
+ ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}"
+ ble/complete/progcomp/.compgen "$opts"
+ return "$?"
+ elif [[ $ucmd == */?* ]] && builtin complete -p -- "${ucmd##*/}" &>/dev/null; then
+ ble/string#quote-word "${ucmd##*/}"; qcmds[0]=$ret
+ ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}"
+ ble/complete/progcomp/.compgen "$opts"
+ return "$?"
+ elif
+ ble/function#try __load_completion "${ucmd##*/}" &>/dev/null &&
+ builtin complete -p -- "${ucmd##*/}" &>/dev/null
+ then
+ ble/string#quote-word "${ucmd##*/}"; qcmds[0]=$ret
+ ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}"
+ ble/complete/progcomp/.compgen "$opts"
+ return "$?"
+ fi
+ alias_checked=$alias_checked$cmd' '
+ ((_ble_bash<50000)) || shopt -q progcomp_alias || break
+ local ret
+ ble/alias#expand "$cmd"
+ [[ $ret == "$cmd" ]] && break
+ ble/complete/progcomp/.split-alias-words "$ret"
+ if ((${#ret[@]}==0)); then
+ ble/complete/progcomp/.compline-rewrite-command "${alias_args[@]}"
+ if ((${#comp_words[@]})); then
+ if ((comp_cword==0)); then
+ ble/complete/source:command
+ else
+ ble/complete/progcomp "${comp_words[0]}" "__recursive__:$opts"
+ fi
+ fi
+ return $?
+ fi
+ [[ $alias_checked != *" $ret "* ]] || break
+ cmd=$ret
+ ((${#ret[@]}>=2)) &&
+ alias_args=("${ret[@]:1}" "${alias_args[@]}")
+ done
+ comp_words=("${orig_comp_words[@]}")
+ [[ $orig_qcmds_set ]] &&
+ ble/complete/progcomp/.compline-rewrite-command "${orig_qcmds[@]}"
+ ble/complete/progcomp/.compgen "default:$opts"
+}
+_ble_complete_option_chars='_!#$%&:;.,^~|\\?\/*a-zA-Z0-9'
+function ble/complete/action:mandb/initialize {
+ ble/complete/action/quote-insert
+}
+function ble/complete/action:mandb/initialize.batch {
+ ble/complete/action/quote-insert.batch newline
+}
+function ble/complete/action:mandb/complete {
+ ble/complete/action/complete.close-quotation
+ local fields
+ ble/string#split fields "$_ble_term_FS" "$DATA"
+ local tail=${fields[2]}
+ [[ $tail == ' ' && $comps_flags == *x* ]] && tail=','
+ ble/complete/action/complete.addtail "$tail"
+}
+function ble/complete/action:mandb/init-menu-item {
+ local ret; ble/color/face2g argument_option; g=$ret
+ local fields
+ ble/string#split fields "$_ble_term_FS" "$DATA"
+ suffix=${fields[1]}
+}
+function ble/complete/action:mandb/get-desc {
+ local fields
+ ble/string#split fields "$_ble_term_FS" "$DATA"
+ desc=${fields[3]}
+}
+function ble/complete/mandb/load-mandb-conf {
+ [[ -s $1 ]] || return 0
+ local line words
+ while builtin read "${_ble_bash_tmout_wa[@]}" -r line || [[ $line ]]; do
+ ble/string#split-words words "${line%%'#'*}"
+ case ${words[0]} in
+ (MANDATORY_MANPATH)
+ [[ -d ${words[1]} ]] &&
+ ble/array#push manpath_mandatory "${words[1]}" ;;
+ (MANPATH_MAP)
+ ble/dict#set manpath_map "${words[1]}" "${words[2]}" ;;
+ esac
+ done < "$1"
+}
+_ble_complete_mandb_default_manpath=()
+function ble/complete/mandb/initialize-manpath {
+ ((${#_ble_complete_mandb_default_manpath[@]})) && return 0
+ local manpath
+ MANPATH= ble/util/assign manpath 'manpath || ble/bin/man -w' 2>/dev/null
+ ble/string#split manpath : "$manpath"
+ if ((${#manpath[@]}==0)); then
+ local -a manpath_mandatory=()
+ builtin eval -- "${_ble_util_dict_declare//NAME/manpath_map}"
+ ble/complete/mandb/load-mandb-conf /etc/man_db.conf
+ ble/complete/mandb/load-mandb-conf ~/.manpath
+ if ((${#manpath_mandatory[@]}==0)); then
+ local ret
+ ble/complete/util/eval-pathname-expansion '~/*/share/man'
+ ble/array#push manpath_mandatory "${ret[@]}"
+ ble/complete/util/eval-pathname-expansion '~/@(opt|.opt)/*/share/man'
+ ble/array#push manpath_mandatory "${ret[@]}"
+ for ret in /usr/local/share/man /usr/local/man /usr/share/man; do
+ [[ -d $ret ]] && ble/array#push manpath_mandatory "$ret"
+ done
+ fi
+ builtin eval -- "${_ble_util_dict_declare//NAME/mark}"
+ local paths path ret
+ ble/string#split paths : "$PATH"
+ for path in "${paths[@]}"; do
+ [[ -d $path ]] || continue
+ [[ $path == *?/ ]] && path=${path%/}
+ if ble/dict#get manpath_map "$path"; then
+ path=$ret
+ else
+ path=${path%/bin}/share/man
+ fi
+ if [[ -d $path ]] && ! ble/set#contains mark "$path"; then
+ ble/set#add mark "$path"
+ ble/array#push manpath "$path"
+ fi
+ done
+ for path in "${manpath_mandatory[@]}"; do
+ if [[ -d $path ]] && ! ble/set#contains mark "$path"; then
+ ble/set#add mark "$path"
+ ble/array#push manpath "$path"
+ fi
+ done
+ fi
+ _ble_complete_mandb_default_manpath=("${manpath[@]}")
+}
+function ble/complete/mandb/search-file/.extract-path {
+ local command=$1
+ [[ $_ble_complete_mandb_lang ]] &&
+ local LC_ALL=$$_ble_complete_mandb_lang
+ ble/util/assign path 'ble/bin/man -w "$command"' 2>/dev/null
+}
+ble/function#suppress-stderr ble/complete/mandb/search-file/.extract-path
+function ble/complete/mandb/search-file/.check {
+ local path=$1
+ if [[ $path && -s $path ]]; then
+ ret=$path
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/complete/mandb/search-file {
+ local command=$1
+ local path
+ ble/complete/mandb/search-file/.extract-path "$command"
+ ble/complete/mandb/search-file/.check "$path" && return
+ ble/string#split ret : "$MANPATH"
+ ((${#ret[@]})) || ret=('')
+ local -a manpath=()
+ for path in "${ret[@]}"; do
+ if [[ $path ]]; then
+ ble/array#push manpath "$path"
+ else
+ ble/complete/mandb/initialize-manpath
+ ble/array#push manpath "${_ble_complete_mandb_default_manpath[@]}"
+ fi
+ done
+ local path
+ for path in "${manpath[@]}"; do
+ [[ -d $path ]] || continue
+ ble/complete/mandb/search-file/.check "$path/man1/$command.1" && return 0
+ ble/complete/mandb/search-file/.check "$path/man1/$command.8" && return 0
+ if ble/is-function ble/bin/gzip; then
+ ble/complete/mandb/search-file/.check "$path/man1/$command.1.gz" && return 0
+ ble/complete/mandb/search-file/.check "$path/man1/$command.8.gz" && return 0
+ fi
+ if ble/is-function ble/bin/bzcat; then
+ ble/complete/mandb/search-file/.check "$path/man1/$command.1.bz" && return 0
+ ble/complete/mandb/search-file/.check "$path/man1/$command.1.bz2" && return 0
+ ble/complete/mandb/search-file/.check "$path/man1/$command.8.bz" && return 0
+ ble/complete/mandb/search-file/.check "$path/man1/$command.8.bz2" && return 0
+ fi
+ if ble/is-function ble/bin/xzcat; then
+ ble/complete/mandb/search-file/.check "$path/man1/$command.1.xz" && return 0
+ ble/complete/mandb/search-file/.check "$path/man1/$command.8.xz" && return 0
+ fi
+ if ble/is-function ble/bin/lzcat; then
+ ble/complete/mandb/search-file/.check "$path/man1/$command.1.lzma" && return 0
+ ble/complete/mandb/search-file/.check "$path/man1/$command.8.lzma" && return 0
+ fi
+ done
+ return 1
+}
+if ble/bin/.freeze-utility-path preconv; then
+ function ble/complete/mandb/.preconv { ble/bin/preconv; }
+else
+ function ble/complete/mandb/.preconv {
+ ble/bin/od -A n -t u1 -v | ble/bin/awk '
+ BEGIN {
+ ECHAR = 65533; # U+FFFD
+ byte = 0;
+ for (i = 0; byte < 128; byte++) { mtable[byte] = 0; vtable[byte] = i++; }
+ for (i = 0; byte < 192; byte++) { mtable[byte] = 0; vtable[byte] = ECHAR; }
+ for (i = 0; byte < 224; byte++) { mtable[byte] = 1; vtable[byte] = i++; }
+ for (i = 0; byte < 240; byte++) { mtable[byte] = 2; vtable[byte] = i++; }
+ for (i = 0; byte < 248; byte++) { mtable[byte] = 3; vtable[byte] = i++; }
+ for (i = 0; byte < 252; byte++) { mtable[byte] = 4; vtable[byte] = i++; }
+ for (i = 0; byte < 254; byte++) { mtable[byte] = 5; vtable[byte] = i++; }
+ for (i = 0; byte < 256; byte++) { mtable[byte] = 0; vtable[byte] = ECHAR; }
+ M = 0; C = 0;
+ }
+ function put_uchar(uchar) {
+ if (uchar < 128)
+ printf("%c", uchar);
+ else
+ printf("\\[u%04X]", uchar);
+ }
+ function process_byte(byte) {
+ if (M) {
+ if (128 <= byte && byte < 192) {
+ C = C * 64 + byte % 64;
+ if (--M == 0) put_uchar(C);
+ return;
+ } else {
+ put_uchar(ECHAR);
+ M = 0;
+ }
+ }
+ M = mtable[byte];
+ C = vtable[byte];
+ if (M == 0) put_uchar(C);
+ }
+ { for (i = 1; i <= NF; i++) process_byte($i); }
+ '
+ }
+fi
+_ble_complete_mandb_lang=
+if ble/is-function ble/bin/groff; then
+ _ble_complete_mandb_convert_type=man
+ function ble/complete/mandb/convert-mandoc {
+ if [[ $_ble_util_locale_encoding == UTF-8 ]]; then
+ ble/bin/groff -k -Tutf8 -man
+ else
+ ble/bin/groff -Tascii -man
+ fi
+ }
+ if [[ $OSTYPE == darwin* ]] && ! ble/bin/groff -k -Tutf8 -man &>/dev/null <<< 'α'; then
+ if ble/bin/groff -T utf8 -m man &>/dev/null <<< '\[u03B1]'; then
+ function ble/complete/mandb/convert-mandoc {
+ if [[ $_ble_util_locale_encoding == UTF-8 ]]; then
+ ble/complete/mandb/.preconv | ble/bin/groff -T utf8 -m man
+ else
+ ble/bin/groff -T ascii -m man
+ fi
+ }
+ else
+ _ble_complete_mandb_lang=C
+ function ble/complete/mandb/convert-mandoc {
+ ble/bin/groff -T ascii -m man
+ }
+ fi
+ fi
+elif ble/is-function ble/bin/nroff; then
+ _ble_complete_mandb_convert_type=man
+ function ble/complete/mandb/convert-mandoc {
+ if [[ $_ble_util_locale_encoding == UTF-8 ]]; then
+ ble/bin/nroff -Tutf8 -man
+ else
+ ble/bin/groff -Tascii -man
+ fi
+ }
+elif ble/is-function ble/bin/mandoc; then
+ _ble_complete_mandb_convert_type=mdoc
+ function ble/complete/mandb/convert-mandoc {
+ ble/bin/mandoc -mdoc
+ }
+fi
+function ble/complete/mandb/.generate-cache-from-man {
+ ble/is-function ble/bin/man &&
+ ble/is-function ble/complete/mandb/convert-mandoc || return 1
+ local command=$1
+ local ret
+ ble/complete/mandb/search-file "$command" || return 1
+ local path=$ret
+ case $ret in
+ (*.gz) ble/bin/gzip -cd "$path" ;;
+ (*.bz|*.bz2) ble/bin/bzcat "$path" ;;
+ (*.lzma) ble/bin/lzcat "$path" ;;
+ (*.xz) ble/bin/xzcat "$path" ;;
+ (*) ble/bin/cat "$path" ;;
+ esac | ble/bin/awk -v type="$_ble_complete_mandb_convert_type" '
+ BEGIN {
+ g_keys_count = 0;
+ g_desc = "";
+ if (type == "man") {
+ print ".TH __ble_ignore__ 1 __ble_ignore__ __ble_ignore__";
+ print ".ll 9999"
+ topic_start = ".TP";
+ }
+ mode = "begin";
+ fmt3_state = "";
+ fmt5_state = "";
+ fmt6_state = "";
+ }
+ function output_pair(key, desc) {
+ print "";
+ print "__ble_key__";
+ if (topic_start != "") print topic_start;
+ print key;
+ print "";
+ print "__ble_desc__";
+ print "";
+ print desc;
+ }
+ function flush_topic(_, i) {
+ if (g_keys_count != 0) {
+ for (i = 0; i < g_keys_count; i++)
+ output_pair(g_keys[i], g_desc);
+ }
+ g_keys_count = 0;
+ g_desc = "";
+ fmt3_flush();
+ fmt5_state = "";
+ fmt6_flush();
+ }
+ mode == "begin" && /^\.(Dd|Nm)[[:space:]]/ {
+ if (type == "man" && /^\.Dd[[:space:]]+\$Mdoc/) topic_start = "";
+ print $0;
+ }
+ function register_key(key) {
+ g_keys[g_keys_count++] = key;
+ g_desc = "";
+ }
+ /^\.ig/ { mode = "ignore"; next; }
+ mode == "ignore" {
+ if (/^\.\.[[:space:]]*/) mode = "none";
+ next;
+ }
+ {
+ sub(/[[:space:]]+$/, "");
+ REQ = match($0, /^\.[_[:alnum:]]+/) ? substr($0, 2, RLENGTH - 1) : "";
+ }
+ REQ ~ /^(S[Ss]|S[Hh]|Pp)$/ { flush_topic(); next; }
+ REQ == "PP" {
+ flush_topic();
+ fmt5_state = "key";
+ fmt5_key = "";
+ fmt5_desc = "";
+ next;
+ }
+ fmt5_state {
+ if (fmt5_state == "key") {
+ if (/^\.RS([^_[:alnum:]]|$)/)
+ fmt5_state = "desc";
+ else if (/^\.RE([^_[:alnum:]]|$)/)
+ fmt5_state = "none";
+ else
+ fmt5_key = (fmt5_key ? "\n" : "") $0;
+ } else if (fmt5_state == "desc") {
+ if (/^\.RE([^_[:alnum:]]|$)/) {
+ register_key(fmt5_key);
+ g_desc = fmt5_desc;
+ flush_topic();
+ fmt5_state = "";
+ } else
+ fmt5_desc = (fmt5_desc ? "\n" : "") $0;
+ }
+ }
+ REQ == "HP" {
+ flush_topic();
+ fmt3_state = "key";
+ fmt3_key_count = 0;
+ fmt3_desc = "";
+ next;
+ }
+ function fmt3_process(_, key) {
+ if (REQ == "TP") { fmt3_flush(); return; }
+ if (REQ == "PD") return;
+ if (fmt3_state == "key") {
+ if (REQ == "IP") { fmt3_state = "desc"; return; }
+ if (match($0, /( | )[[:space:]]*/)) {
+ fmt3_keys[fmt3_key_count++] = substr($0, 1, RSTART - 1);
+ fmt3_desc = substr($0, RSTART + RLENGTH);
+ fmt3_state = "desc";
+ } else {
+ fmt3_keys[fmt3_key_count++] = $0;
+ }
+ } else if (fmt3_state == "desc") {
+ if (fmt3_desc != "") fmt3_desc = fmt3_desc "\n";
+ fmt3_desc = fmt3_desc $0;
+ }
+ }
+ function fmt3_flush(_, i) {
+ if (fmt3_state == "desc" && fmt3_key_count > 0) {
+ for (i = 0; i < fmt3_key_count; i++)
+ register_key(fmt3_keys[i]);
+ g_desc = fmt3_desc;
+ }
+ fmt3_state = "";
+ fmt3_key_count = 0;
+ fmt3_desc = "";
+ }
+ fmt3_state { fmt3_process(); }
+ /^\.IP[[:space:]]+".*"([[:space:]]+[0-9]+)?$/ && fmt3_state != "key" {
+ fmt6_init();
+ fmt4_init();
+ next;
+ }
+ function fmt4_init() {
+ if (mode != "fmt4_desc")
+ if (!(g_keys_count && g_desc == "")) flush_topic();
+ gsub(/^\.IP[[:space:]]+"|"([[:space:]]+[0-9]+)?$/, "");
+ register_key($0);
+ mode = "fmt4_desc";
+ }
+ mode == "fmt4_desc" {
+ if ($0 == "") { flush_topic(); mode = "none"; next; }
+ if (g_keys_count == 1 && g_keys[0] == "\\(bu" && match($0, /^\\fC[^\\]+\\fP( or \\fC[^\\]+\\fP)?/) > 0) {
+ _key = substr($0, 1, RLENGTH);
+ _desc = substr($0, RLENGTH + 1);
+ if (match(_key, / or \\fC[^\\]+\\fP/) > 0)
+ _key = substr(_key, 1, RSTART - 1) ", " substr(_key, RSTART + 4);
+ g_keys[0] = _key;
+ g_desc = _desc;
+ next;
+ }
+ if (REQ == "PD") next;
+ if (/^\.IX[[:space:]]+Item[[:space:]]+/) next;
+ if (g_desc != "") g_desc = g_desc "\n";
+ g_desc = g_desc $0;
+ }
+ function fmt6_init() {
+ fmt6_flush();
+ fmt6_state = "desc"
+ fmt6_key = $0;
+ fmt6_desc = "";
+ }
+ fmt6_state {
+ if (REQ == "IX") {
+ fmt6_state = "";
+ } else if (REQ == "IP") {
+ fmt6_flush();
+ } else {
+ fmt6_desc = fmt6_desc $0 "\n";
+ }
+ }
+ function fmt6_flush() {
+ if (!fmt6_state) return;
+ fmt6_state = "";
+ if (fmt6_desc)
+ output_pair(fmt6_key, fmt6_desc);
+ }
+ /^\.It Fl([^_[:alnum:]]|$)/ {
+ if (g_keys_count && g_desc != "") flush_topic();
+ sub(/^\.It Fl/, ".Fl");
+ if ($0 ~ / Xo$/) {
+ g_current_key = $0;
+ mode = "fmt2_keyc"
+ } else {
+ register_key($0);
+ mode = "desc";
+ }
+ next;
+ }
+ mode == "fmt2_keyc" {
+ if (/^\.PD[[:space:]]*([0-9]+[[:space:]]*)?$/) next;
+ g_current_key = g_current_key "\n" $0;
+ if (REQ == "Xc") {
+ register_key(g_current_key);
+ mode = "desc";
+ }
+ next;
+ }
+ type == "man" && REQ == "TP" {
+ if (g_keys_count && g_desc != "") flush_topic();
+ mode = "key1";
+ next;
+ }
+ mode == "key1" {
+ if (/^\.PD[[:space:]]*([0-9]+[[:space:]]*)?$/) next;
+ register_key($0);
+ mode = "desc";
+ next;
+ }
+ mode == "desc" {
+ if (REQ == "PD") next;
+ if (g_desc != "") g_desc = g_desc "\n";
+ g_desc = g_desc $0;
+ }
+ END { flush_topic(); }
+ ' | ble/complete/mandb/convert-mandoc 2>/dev/null | ble/bin/awk -F "$_ble_term_FS" '
+ function flush_pair(_, i) {
+ if (g_option_count) {
+ gsub(/\034/, "\x1b[7m^\\\x1b[27m", g_desc);
+ sub(/(\. |; ).*/, ".", g_desc); # Long descriptions are truncated.
+ for (i = 0; i < g_option_count; i++)
+ print g_options[i] FS g_desc;
+ }
+ g_option_count = 0;
+ g_desc = "";
+ }
+ function process_key(line, _, n, specs, i, spec, option, optarg, suffix) {
+ gsub(/\x1b\[[ -?]*[@-~]/, "", line); # CSI seq
+ gsub(/\x1b[ -\/]*[0-~]/, "", line); # ESC seq
+ gsub(/.\x08/, "", line); # CHAR BS
+ gsub(/\x0E/, "", line); # SO
+ gsub(/\x0F/, "", line); # SI
+ gsub(/[\x00-\x1F]/, "", line); # Give up all the other control chars
+ gsub(/^[[:space:]]*|[[:space:]]*$/, "", line);
+ gsub(/[[:space:]]+/, " ", line);
+ if (line !~ /^[-+]./) return;
+ n = split(line, specs, /,([[:space:]]+|$)| or /);
+ prev_optarg = "";
+ for (i = n; i > 0; i--) {
+ spec = specs[i];
+ sub(/,[[:space:]]+$/, "", spec);
+ if (spec !~ /^[-+]/ || spec ~ /\034/) { specs[i] = ""; continue; }
+ if (match(spec, /\[[:=]?|[:=[:space:]]/)) {
+ option = substr(spec, 1, RSTART - 1);
+ optarg = substr(spec, RSTART);
+ suffix = substr(spec, RSTART + RLENGTH - 1, 1);
+ if (suffix == "[") suffix = "";
+ prev_optarg = optarg;
+ } else {
+ option = spec;
+ optarg = "";
+ suffix = " ";
+ if (prev_optarg ~ /[A-Z]|<.+>/) {
+ optarg = prev_optarg;
+ if (option ~ /^[-+].$/) {
+ sub(/^\[=/, "[", optarg);
+ sub(/^=/, "", optarg);
+ sub(/^[^[:space:][]/, " &", optarg);
+ } else {
+ if (optarg ~ /^\[[^:=]/)
+ sub(/^\[/, "[=", optarg);
+ else if (optarg ~ /^[^:=[:space:][]/)
+ optarg = " " optarg;
+ }
+ if (match(optarg, /^\[[:=]?|^[:=[:space:]]/)) {
+ suffix = substr(optarg, RSTART + RLENGTH - 1, 1);
+ if (suffix == "[") suffix = "";
+ }
+ }
+ }
+ specs[i] = option FS optarg FS suffix;
+ }
+ for (i = 1; i <= n; i++) {
+ if (specs[i] == "") continue;
+ option = substr(specs[i], 1, index(specs[i], FS) - 1);
+ if (!g_hash[option]++)
+ g_options[g_option_count++] = specs[i];
+ }
+ }
+ function process_desc(line) {
+ gsub(/^[[:space:]]*|[[:space:]]*$/, "", line);
+ gsub(/[[:space:]][[:space:]]+/, " ", line);
+ if (line == "") {
+ if (g_desc != "") return 0;
+ return 1;
+ }
+ if (g_desc != "") g_desc = g_desc " ";
+ g_desc = g_desc line;
+ return 1;
+ }
+ sub(/^[[:space:]]*__ble_key__/, "", $0) {
+ flush_pair();
+ mode = "key";
+ if (match($0, /__ble_desc__/) > 0) {
+ s_key = substr($0, 1, RSTART - 1);
+ s_desc = substr($0, RSTART + RLENGTH);
+ process_key(s_key);
+ mode = "desc";
+ if (!process_desc(s_desc)) mode = "";
+ next;
+ }
+ }
+ sub(/^[[:space:]]*__ble_desc__/, "", $0) {
+ mode = "desc";
+ }
+ mode == "key" { process_key($0); }
+ mode == "desc" { if (!process_desc($0)) mode = ""; }
+ END { flush_pair(); }
+ ' | ble/bin/sort -t "$_ble_term_FS" -k 1
+}
+function ble/complete/mandb:help/generate-cache {
+ local opts=$1
+ local -x cfg_usage= cfg_help=1 cfg_plus= cfg_plus_generate=
+ [[ :$opts: == *:mandb-help-usage:* ]] && cfg_usage=1
+ [[ :$opts: == *:mandb-usage:* ]] && cfg_usage=1 cfg_help=
+ ble/string#match ":$opts:" ':plus-options(=[^:]+)?:' &&
+ cfg_plus=1 cfg_plus_generate=${BASH_REMATCH[1]:1}
+ local space=$' \t' # for #D1709 (WA gawk 4.0.2)
+ local rex_argsep='(\[?[:=]| ?|\[)'
+ local rex_option='[-+](,|[^]:='$space',[]+)('$rex_argsep'(<[^<>]+>|\([^()]+\)|[^-[:space:]])[^[:space:]]*)?'
+ ble/bin/awk -F "$_ble_term_FS" '
+ BEGIN {
+ cfg_help = ENVIRON["cfg_help"];
+ g_indent = -1;
+ g_keys_count = 0;
+ g_desc = "";
+ cfg_usage = ENVIRON["cfg_usage"];
+ g_usage_count = 0;
+ cfg_plus_generate = ENVIRON["cfg_plus_generate"];
+ cfg_plus = ENVIRON["cfg_plus"] cfg_plus_generate;
+ }
+ function split_option_optarg_suffix(optspec, _, key, suffix, optarg) {
+ if (index(optspec, FS) != 0) return "";
+ if ((pos = match(optspec, /'"$rex_argsep"'/)) > 0) {
+ key = substr(optspec, 1, pos - 1);
+ suffix = substr(optspec, pos + RLENGTH - 1, 1);
+ if (suffix == "[") suffix = "";
+ optarg = substr(optspec, pos);
+ } else {
+ key = optspec;
+ optarg = "";
+ suffix = " ";
+ }
+ if (key ~ /[^-+'"$_ble_complete_option_chars"']/) return "";
+ return key FS optarg FS suffix;
+ }
+ function print_entry(entry, _, name) {
+ name = entry;
+ sub(/'"$_ble_term_FS"'.*$/, "", name);
+ if (name ~ /^\+/ && !cfg_plus) return;
+ if (!g_hash[name]++) # uniq
+ print entry;
+ }
+ {
+ gsub(/\x1b\[[ -?]*[@-~]/, ""); # CSI seq
+ gsub(/\x1b[ -\/]*[0-~]/, ""); # ESC seq
+ gsub(/[\x00-\x1F]/, ""); # Remove all the other C0 chars
+ }
+ function generate_plus(_, i, n) {
+ if (!cfg_plus_generate) return;
+ n = length(cfg_plus_generate);
+ for (i = 1; i <= n; i++)
+ print_entry("+" substr(cfg_plus_generate, i, 1) FS FS FS);
+ }
+ function parse_usage(line, _, optspec, optspec1, option, optarg, n, i, o) {
+ while (match(line, /\[[[:space:]]*([^][]|\[[^][]*\])+[[:space:]]*\]/)) {
+ optspec = substr(line, RSTART + 1, RLENGTH - 2);
+ line = substr(line, RSTART + RLENGTH);
+ while (match(optspec, /([^][|]|\[[^][]*\])+/)) {
+ optspec1 = substr(optspec, RSTART, RLENGTH);
+ optspec = substr(optspec, RSTART + RLENGTH);
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", optspec1);
+ if (match(optspec1, /^[-+][^]:='"$space"'[]+/)) {
+ option = substr(optspec1, RSTART, RLENGTH);
+ optarg = substr(optspec1, RSTART + RLENGTH);
+ n = RLENGTH;
+ if (option ~ /^-.*-/) {
+ if ((keyinfo = split_option_optarg_suffix(optspec1)) != "")
+ g_usage[g_usage_count++] = keyinfo;
+ } else {
+ o = substr(option, 1, 1);
+ for (i = 2; i <= n; i++)
+ if ((keyinfo = split_option_optarg_suffix(o substr(option, i, 1) optarg)) != "")
+ g_usage[g_usage_count++] = keyinfo;
+ }
+ }
+ }
+ }
+ }
+ function print_usage(_, i) {
+ for (i = 0; i < g_usage_count; i++)
+ print_entry(g_usage[i] FS);
+ }
+ cfg_usage {
+ if (NR <= 20 && (g_usage_start || $0 ~ /^[a-zA-Z_0-9]|^[^-[:space:]][^[:space:]]*(: |:)/) ) {
+ g_usage_start = 1;
+ parse_usage($0);
+ } else if (/^[[:space:]]*$/)
+ cfg_usage = 0;
+ }
+ function get_indent(text, _, i, n, ret) {
+ ret = 0;
+ n = length(text);
+ for (i = 1; i <= n; i++) {
+ c = substr(text, i, 1);
+ if (c == " ")
+ ret++;
+ else if (c == "\t")
+ ret = (int(ret / 8) + 1) * 8;
+ else
+ break;
+ }
+ return ret;
+ }
+ function flush_data(_, i) {
+ if (g_indent < 0) return;
+ for (i = 0; i < g_keys_count; i++)
+ print_entry(g_keys[i] FS g_desc);
+ g_indent = -1;
+ g_keys_count = 0;
+ g_desc = "";
+ }
+ function register_key(keydef, _, key, keyinfo, keys, nkey, i, optarg) {
+ if (g_desc != "") flush_data();
+ g_indent = get_indent(keydef);
+ nkey = 0;
+ for (;;) {
+ sub(/^,?[[:space:]]+/, "", keydef);
+ if (match(keydef, /^'"$rex_option"'/) <= 0) break;
+ key = substr(keydef, 1, RLENGTH);
+ keydef = substr(keydef, RLENGTH + 1);
+ sub(/,$/, "", key);
+ keys[nkey++] = key;
+ }
+ if (nkey >= 2) {
+ optarg = "";
+ for (i = nkey; --i >= 0; ) {
+ if (match(keys[i], /'"$rex_argsep"'/) > 0) {
+ optarg = substr(keys[i], RSTART);
+ sub(/^[[:space:]]+/, "", optarg);
+ if (optarg !~ /[A-Z]|<.+>/) optarg = "";
+ } else if (optarg != ""){
+ if (keys[i] ~ /^[-+].$/) {
+ optarg2 = optarg;
+ sub(/^\[=/, "[", optarg2);
+ sub(/^=/, "", optarg2);
+ sub(/^[^[:space:][]/, " &", optarg2);
+ keys[i] = keys[i] optarg2;
+ } else {
+ optarg2 = optarg;
+ if (optarg2 ~ /^\[[^:=]/)
+ sub(/^\[/, "[=", optarg2);
+ else if (optarg2 ~ /^[^:=[:space:][]/)
+ optarg2 = " " optarg2;
+ keys[i] = keys[i] optarg2;
+ }
+ }
+ }
+ }
+ for (i = 0; i < nkey; i++)
+ if ((keyinfo = split_option_optarg_suffix(keys[i])) != "")
+ g_keys[g_keys_count++] = keyinfo;
+ }
+ function append_desc(desc) {
+ gsub(/^[[:space:]]+|[[:space:]]$/, "", desc);
+ if (desc == "") return;
+ if (g_desc == "")
+ g_desc = desc;
+ else
+ g_desc = g_desc " " desc;
+ }
+ cfg_help && match($0, /^[[:space:]]*'"$rex_option"'(,?[[:space:]]+'"$rex_option"')*/) {
+ key = substr($0, 1, RLENGTH);
+ desc = substr($0, RLENGTH + 1);
+ if (desc ~ /^,/) next;
+ register_key(key);
+ append_desc(desc);
+ next;
+ }
+ g_indent >= 0 {
+ sub(/[[:space:]]+$/, "");
+ indent = get_indent($0);
+ if (indent <= g_indent)
+ flush_data();
+ else
+ append_desc($0);
+ }
+ END {
+ flush_data();
+ print_usage();
+ generate_plus();
+ }
+ ' | ble/bin/sort -t "$_ble_term_FS" -k 1
+}
+function ble/complete/mandb:_parse_help/inject {
+ ble/is-function _parse_help || return 0
+ ble/function#advice before _parse_help 'ble/complete/mandb:_parse_help/generate-cache "${ADVICE_WORDS[1]}" "${ADVICE_WORDS[2]}"'
+ ble/function#advice before _longopt 'ble/complete/mandb:_parse_help/generate-cache "${ADVICE_WORDS[1]}"'
+ ble/function#advice before _parse_usage 'ble/complete/mandb:_parse_help/generate-cache "${ADVICE_WORDS[1]}" "${ADVICE_WORDS[2]}" usage'
+ function ble/complete/mandb:_parse_help/inject { return 0; }
+}
+function ble/string#hash-pjw {
+ local size=${2:-32}
+ local S=${3:-$(((size+7)/8))} # shift 4
+ local C=$((size-2*S)) # co-shift 24
+ local M=$(((1<<size-S)-1)) # mask 0x0FFFFFFF
+ local N=$(((1<<S)-1<<S)) # mask2 0x000000F0
+ ble/util/s2bytes "$1"
+ local c h=0
+ for c in "${ret[@]}"; do
+ ((h=(h<<S)+c,h=(h^h>>C&N)&M))
+ done
+ ret=$h
+}
+function ble/complete/mandb:_parse_help/generate-cache {
+ [[ $_ble_attached ]] || return 0
+ local command=$1; [[ $1 == ble*/* ]] || command=${1##*/}
+ local ret; ble/string#hash-pjw "${*:2}" 64; local hash=$ret
+ local lc_messages=${LC_ALL:-${LC_MESSAGES:-${LANG:-C}}}
+ local mandb_cache_dir=$_ble_base_cache/complete.mandb/${lc_messages//'/'/%}
+ local subcache; ble/util/sprintf subcache '%s.%014x' "$mandb_cache_dir/_parse_help.d/$command" "$hash"
+ [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]] && return 0
+ ble/util/mkd "${subcache%/*}"
+ if [[ $1 == - ]]; then
+ ble/complete/mandb:help/generate-cache "$3"
+ else
+ local args default_option=--help
+ [[ :$3: == *:usage:* ]] && default_option=--usage
+ ble/string#split-words args "${2:-$default_option}"
+ "$1" "${args[@]}" 2>&1 | ble/complete/mandb:help/generate-cache "$3"
+ fi >| "$subcache"
+}
+function ble/complete/mandb/generate-cache {
+ local command=${1##*/}
+ local lc_messages=${LC_ALL:-${LC_MESSAGES:-${LANG:-C}}}
+ local mandb_cache_dir=$_ble_base_cache/complete.mandb/${lc_messages//'/'/%}
+ local fcache=$mandb_cache_dir/$command
+ local cmdspec_opts; ble/cmdspec/opts#load "$command"
+ [[ :$cmdspec_opts: == *:no-options:* ]] && return 1
+ if ble/opts#extract-all-optargs "$cmdspec_opts" mandb-help --help; then
+ local -a helpspecs; helpspecs=("${ret[@]}")
+ local subcache=$mandb_cache_dir/help.d/$command
+ if ! [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]]; then
+ ble/util/mkd "${subcache%/*}"
+ local helpspec
+ for helpspec in "${helpspecs[@]}"; do
+ if [[ $helpspec == %* ]]; then
+ builtin eval -- "${helpspec:1}"
+ elif [[ $helpspec == @* ]]; then
+ ble/util/print "${helpspec:1}"
+ else
+ ble/string#split-words helpspec "${helpspec#+}"
+ "$command" "${helpspec[@]}" 2>&1
+ fi
+ done | ble/complete/mandb:help/generate-cache "$cmdspec_opts" >| "$subcache"
+ fi
+ fi
+ if [[ :$cmdspec_opts: != *:mandb-disable-man:* ]] && ble/bin#has "$1"; then
+ local subcache=$mandb_cache_dir/man.d/$command
+ if ! [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]]; then
+ ble/util/mkd "${subcache%/*}"
+ ble/complete/mandb/.generate-cache-from-man "$command" >| "$subcache"
+ fi
+ fi
+ local -a subcaches=()
+ local subcache update=
+ ble/complete/util/eval-pathname-expansion '"$mandb_cache_dir"/_parse_help.d/"$command".??????????????'
+ for subcache in "${ret[@]}" "$mandb_cache_dir"/{help,man}.d/"$command"; do
+ if [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]]; then
+ ble/array#push subcaches "$subcache"
+ [[ $fcache -nt $subcache ]] || update=1
+ fi
+ done
+ if [[ $update ]]; then
+ local fs=$_ble_term_FS
+ ble/bin/awk -F "$_ble_term_FS" '
+ BEGIN { plus_count = 0; nodesc_count = 0; }
+ $4 == "" {
+ if ($1 ~ /^\+/) {
+ plus_name[plus_count] = $1;
+ plus_entry[plus_count] = $0;
+ plus_count++;
+ } else {
+ nodesc_name[nodesc_count] = $1;
+ nodesc_entry[nodesc_count] = $0;
+ nodesc_count++;
+ }
+ next;
+ }
+ !hash[$1] { hash[$1] = $0; print; }
+ END {
+ for (i = 0; i < nodesc_count; i++) {
+ if (!hash[nodesc_name[i]]) {
+ hash[nodesc_name[i]] = nodesc_entry[i];
+ print nodesc_entry[i];
+ }
+ }
+ for (i = 0; i < plus_count; i++) {
+ name = plus_name[i];
+ if (hash[name]) continue;
+ split(plus_entry[i], record, FS);
+ optarg = record[2];
+ suffix = record[3];
+ desc = "";
+ mname = name;
+ sub(/^\+/, "-", mname);
+ if (hash[mname]) {
+ if (!optarg) {
+ split(hash[mname], record, FS);
+ optarg = record[2];
+ suffix = record[3];
+ }
+ desc = hash[mname];
+ sub(/^[^'$fs']*'$fs'[^'$fs']*'$fs'[^'$fs']*'$fs'/, "", desc);
+ if (desc) desc = "\033[1mReverse[\033[m " desc " \033[;1m]\033[m";
+ }
+ if (!desc) desc = "reverse of \033[4m" mname "\033[m";
+ hash[name] = name FS optarg FS suffix FS desc;
+ print hash[name];
+ }
+ }
+ ' "${subcaches[@]}" >| "$fcache"
+ fi
+ ret=$fcache
+ [[ -s $fcache ]]
+}
+function ble/complete/mandb/load-cache {
+ ret=()
+ ble/complete/mandb/generate-cache "$@" &&
+ ble/util/mapfile ret < "$ret"
+}
+function ble/complete/source:option/.is-option-context {
+ local rexrej rexreq stopat
+ ble/progcolor/stop-option#init "$cmdspec_opts"
+ if [[ $stopat ]] && ((stopat<=$#)); then
+ return 1
+ elif [[ ! $rexrej$rexreq ]]; then
+ return 0
+ fi
+ local word ret
+ for word; do
+ ble/syntax:bash/simple-word/is-simple "$word" &&
+ ble/syntax:bash/simple-word/eval "$word" noglob &&
+ ble/progcolor/stop-option#test "$ret" &&
+ return 1
+ done
+ return 0
+}
+function ble/complete/source:option {
+ local rex='^-[-+'$_ble_complete_option_chars']*$|^\+[_'$_ble_complete_option_chars']*$'
+ [[ ! $COMPV || $COMPV =~ $rex ]] || return 0
+ local COMPS=$COMPS COMPV=$COMPV
+ ble/complete/source/reduce-compv-for-ambiguous-match
+ [[ :$comp_type: == *:[maA]:* ]] && local COMP2=$COMP1
+ local comp_words comp_line comp_point comp_cword
+ ble/syntax:bash/extract-command "$COMP2" || return 1
+ local -a prev_args=()
+ ((comp_cword>=1)) && prev_args=("${comp_words[@]:1:comp_cword-1}")
+ local cmd=${comp_words[0]}
+ local alias_checked=' '
+ while local ret; ! ble/complete/mandb/load-cache "$cmd"; do
+ alias_checked=$alias_checked$cmd' '
+ ble/alias#expand "$cmd" || return 1
+ local words; ble/string#split-words ret "$ret"; words=("${ret[@]}")
+ local iword=0 rex='^[_a-zA-Z][_a-zA-Z0-9]*\+?='
+ while [[ ${words[iword]} =~ $rex ]]; do ((iword++)); done
+ [[ ${words[iword]} && $alias_checked != *" ${words[iword]} "* ]] || return 1
+ prev_args=("${words[@]:iword+1}" "${prev_args[@]}")
+ cmd=${words[iret]}
+ done
+ local -a entries; entries=("${ret[@]}")
+ local ret cmdspec_opts=
+ ble/syntax:bash/simple-word/is-simple "$cmd" &&
+ ble/syntax:bash/simple-word/eval "$cmd" noglob &&
+ ble/cmdspec/opts#load "$ret"
+ ble/complete/source:option/.is-option-context "${prev_args[@]}" || return 1
+ local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize mandb
+ local entry fs=$_ble_term_FS has_desc=
+ for entry in "${entries[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) &&
+ ble/complete/check-cancel && return 148
+ local CAND=${entry%%$_ble_term_FS*}
+ [[ $CAND == "$COMPV"* ]] || continue
+ ble/complete/cand/yield mandb "$CAND" "$entry"
+ [[ $entry == *"$fs"*"$fs"*"$fs"?* ]] && has_desc=1
+ done
+ [[ $has_desc ]] && bleopt complete_menu_style=desc
+}
+function ble/complete/source:argument/.generate-user-defined-completion {
+ shopt -q progcomp || return 1
+ [[ :$comp_type: == *:[maA]:* ]] && local COMP2=$COMP1
+ local comp_words comp_line comp_point comp_cword
+ ble/syntax:bash/extract-command "$COMP2" || return 1
+ local forward_words=
+ ((comp_cword)) && IFS=' ' builtin eval 'forward_words="${comp_words[*]::comp_cword} "'
+ local comp2_in_word=$((comp_point-${#forward_words}))
+ local comp1_in_word=$((comp2_in_word-(COMP2-COMP1)))
+ if ((comp1_in_word>0)); then
+ local w=${comp_words[comp_cword]}
+ comp_words=("${comp_words[@]::comp_cword}" "${w::comp1_in_word}" "${w:comp1_in_word}" "${comp_words[@]:comp_cword+1}")
+ IFS=' ' builtin eval 'comp_line="${comp_words[*]}"'
+ ((comp_cword++,comp_point++))
+ ((comp2_in_word=COMP2-COMP1,comp1_in_word=0))
+ fi
+ if [[ $COMPV && :$comp_type: == *:[maA]:* ]]; then
+ local oword=${comp_words[comp_cword]::comp2_in_word} ins
+ local ins=; [[ :$comp_type: == *:a:* ]] && ins=${COMPV::1}
+ local ret comps_flags= comps_fixed= # referenced in ble/complete/string#escape-for-completion-context
+ if [[ $oword ]]; then
+ local simple_flags simple_ibrace
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$oword" || return 1
+ comps_flags=v$simple_flags
+ ((${simple_ibrace%:*})) && comps_fixed=1
+ fi
+ ble/complete/string#escape-for-completion-context "$ins" c; ins=$ret
+ ble/util/unlocal comps_flags comps_fixed
+ ((comp_point+=${#ins}))
+ comp_words=("${comp_words[@]::comp_cword}" "$oword$ins" "${comp_words[@]:comp_cword+1}")
+ IFS=' ' builtin eval 'comp_line="${comp_words[*]}"'
+ ((comp2_in_word+=${#ins}))
+ fi
+ local opts=$1
+ if [[ :$opts: == *:initial:* ]]; then
+ ble/complete/progcomp/.compgen initial
+ else
+ ble/complete/progcomp "${comp_words[0]}"
+ fi
+}
+function ble/complete/source:argument {
+ local comp_opts=:
+ ble/complete/source:sabbrev
+ if [[ $comps_flags == *f* && $COMPS != *\* && :$comp_type: != *:[maA]:* ]]; then
+ local ret simple_flags simple_ibrace
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$COMPS"
+ ble/complete/source/eval-simple-word "$ret*" && ((${#ret[*]})) &&
+ ble/complete/cand/yield-filenames file "${ret[@]}"
+ (($?==148)) && return 148
+ fi
+ local old_cand_count=$cand_count
+ ble/complete/source:argument/.generate-user-defined-completion; local ext=$?
+ ((ext==148||cand_count>old_cand_count)) && return "$ext"
+ [[ $comp_opts == *:ble/no-default:* ]] && return "$ext"
+ ble/complete/source:option; local ext=$?
+ ((ext==148||cand_count>old_cand_count&&${#COMPV})) && return "$ext"
+ if [[ $comp_opts == *:dirnames:* ]]; then
+ ble/complete/source:dir
+ else
+ ble/complete/source:file
+ fi; local ext=$?
+ ((ext==148||cand_count>old_cand_count)) && return "$ext"
+ if local rex='^/?[-_a-zA-Z0-9.]+[:=]|^-[^-/=:]'; [[ $COMPV =~ $rex ]]; then
+ local prefix=$BASH_REMATCH value=${COMPV:${#BASH_REMATCH}}
+ local COMP_PREFIX=$prefix
+ [[ :$comp_type: != *:[maA]:* && $value =~ ^.+/ ]] &&
+ COMP_PREFIX=$prefix${BASH_REMATCH[0]}
+ local ret cand "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/source:file/.construct-pathname-pattern "$value"
+ ble/complete/util/eval-pathname-expansion "$ret"; (($?==148)) && return 148
+ ble/complete/source/test-limit ${#ret[@]} || return 1
+ ble/complete/cand/yield.initialize file_rhs
+ for cand in "${ret[@]}"; do
+ [[ -e $cand || -h $cand ]] || continue
+ [[ $FIGNORE ]] && ! ble/complete/.fignore/filter "$cand" && continue
+ ble/complete/cand/yield file_rhs "$prefix$cand" "$prefix"
+ done
+ fi
+}
+function ble/complete/source/compgen {
+ [[ $comps_flags == *v* ]] || return 1
+ local COMPS=$COMPS COMPV=$COMPV
+ ble/complete/source/reduce-compv-for-ambiguous-match
+ local compgen_action=$1
+ local action=$2
+ local data=$3
+ local q="'" Q="'\''"
+ local compv_quoted="'${COMPV//$q/$Q}'"
+ local arr
+ ble/util/assign-array arr 'builtin compgen -A "$compgen_action" -- "$compv_quoted"'
+ ble/complete/source/test-limit ${#arr[@]} || return 1
+ [[ $1 != '=' && ${#arr[@]} == 1 && $arr == "$COMPV" ]] && return 0
+ local cand "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ for cand in "${arr[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ ble/complete/cand/yield "$action" "$cand" "$data"
+ done
+}
+function ble/complete/source:variable {
+ local data=
+ case $1 in
+ ('=') data=assignment ;;
+ ('b') data=braced ;;
+ ('a') data=arithmetic ;;
+ ('n') data=nosuffix ;;
+ ('w'|*) data=word ;;
+ esac
+ ble/complete/source/compgen variable variable "$data"
+}
+function ble/complete/source:user {
+ ble/complete/source/compgen user word
+}
+function ble/complete/source:hostname {
+ ble/complete/source/compgen hostname word
+}
+function ble/complete/complete/determine-context-from-opts {
+ local opts=$1
+ context=syntax
+ if local rex=':context=([^:]+):'; [[ :$opts: =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ if ble/is-function ble/complete/context:"$rematch1"/generate-sources; then
+ context=$rematch1
+ else
+ ble/util/print "ble/widget/complete: unknown context '$rematch1'" >&2
+ fi
+ fi
+}
+function ble/complete/context/filter-prefix-sources {
+ local -a filtered_sources=()
+ local src asrc
+ for src in "${sources[@]}"; do
+ ble/string#split-words asrc "$src"
+ local comp1=${asrc[1]}
+ ((comp1<comp_index)) &&
+ ble/array#push filtered_sources "$src"
+ done
+ sources=("${filtered_sources[@]}")
+ ((${#sources[@]}))
+}
+function ble/complete/context/overwrite-sources {
+ local source_name=$1
+ local -a new_sources=()
+ local src asrc mark
+ for src in "${sources[@]}"; do
+ ble/string#split-words asrc "$src"
+ [[ ${mark[asrc[1]]} ]] && continue
+ ble/array#push new_sources "$source_name ${asrc[1]}"
+ mark[asrc[1]]=1
+ done
+ ((${#new_sources[@]})) ||
+ ble/array#push new_sources "$source_name $comp_index"
+ sources=("${new_sources[@]}")
+}
+function ble/complete/context:syntax/generate-sources {
+ ble/syntax/import
+ ble-edit/content/update-syntax
+ ble/cmdspec/initialize # load user configruation
+ ble/syntax/completion-context/generate "$comp_text" "$comp_index"
+ ((${#sources[@]}))
+}
+function ble/complete/context:filename/generate-sources {
+ ble/complete/context:syntax/generate-sources || return "$?"
+ ble/complete/context/overwrite-sources file
+}
+function ble/complete/context:command/generate-sources {
+ ble/complete/context:syntax/generate-sources || return "$?"
+ ble/complete/context/overwrite-sources command
+}
+function ble/complete/context:variable/generate-sources {
+ ble/complete/context:syntax/generate-sources || return "$?"
+ ble/complete/context/overwrite-sources variable
+}
+function ble/complete/context:username/generate-sources {
+ ble/complete/context:syntax/generate-sources || return "$?"
+ ble/complete/context/overwrite-sources user
+}
+function ble/complete/context:hostname/generate-sources {
+ ble/complete/context:syntax/generate-sources || return "$?"
+ ble/complete/context/overwrite-sources hostname
+}
+function ble/complete/context:glob/generate-sources {
+ comp_type=$comp_type:raw
+ ble/complete/context:syntax/generate-sources || return "$?"
+ ble/complete/context/overwrite-sources glob
+}
+function ble/complete/source:glob {
+ [[ $comps_flags == *v* ]] || return 1
+ [[ :$comp_type: == *:[maA]:* ]] && return 1
+ local pattern=$COMPV
+ ble/complete/source/eval-simple-word "$pattern"; (($?==148)) && return 148
+ if ((!${#ret[@]})) && [[ $pattern != *'*' ]]; then
+ ble/complete/source/eval-simple-word "$pattern*"; (($?==148)) && return 148
+ fi
+ local cand action=file "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ for cand in "${ret[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ ble/complete/cand/yield "$action" "$cand"
+ done
+}
+function ble/complete/context:dynamic-history/generate-sources {
+ comp_type=$comp_type:raw
+ ble/complete/context:syntax/generate-sources || return "$?"
+ ble/complete/context/overwrite-sources dynamic-history
+}
+function ble/complete/source:dynamic-history {
+ [[ $comps_flags == *v* ]] || return 1
+ [[ :$comp_type: == *:[maA]:* ]] && return 1
+ [[ $COMPV ]] || return 1
+ local wordbreaks; ble/complete/get-wordbreaks
+ wordbreaks=${wordbreaks//$'\n'}
+ local ret; ble/string#escape-for-extended-regex "$COMPV"
+ local rex_needle='(^|['$wordbreaks'])'$ret'[^'$wordbreaks']+'
+ local rex_wordbreaks='['$wordbreaks']'
+ ble/util/assign-array ret 'HISTTIMEFORMAT= builtin history | ble/bin/grep -Eo "$rex_needle" | ble/bin/sed "s/^$rex_wordbreaks//" | ble/bin/sort -u'
+ local cand action=literal-word "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ for cand in "${ret[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ ble/complete/cand/yield "$action" "$cand"
+ done
+}
+function ble/complete/util/construct-ambiguous-regex {
+ local text=$1 fixlen=${2:-1}
+ local opt_icase=; [[ :$comp_type: == *:i:* ]] && opt_icase=1
+ local -a buff=()
+ local i=0 n=${#text} ch=
+ for ((i=0;i<n;i++)); do
+ ((i>=fixlen)) && ble/array#push buff '.*'
+ ch=${text:i:1}
+ if [[ $ch == [a-zA-Z] ]]; then
+ if [[ $opt_icase ]]; then
+ ble/string#toggle-case "$ch"
+ ch=[$ch$ret]
+ fi
+ else
+ ble/string#escape-for-extended-regex "$ch"; ch=$ret
+ fi
+ ble/array#push buff "$ch"
+ done
+ IFS= builtin eval 'ret="${buff[*]}"'
+}
+function ble/complete/util/construct-glob-pattern {
+ local text=$1
+ if [[ :$comp_type: == *:i:* ]]; then
+ local i n=${#text} c
+ local -a buff=()
+ for ((i=0;i<n;i++)); do
+ c=${text:i:1}
+ if [[ $c == [a-zA-Z] ]]; then
+ ble/string#toggle-case "$c"
+ c=[$c$ret]
+ else
+ ble/string#escape-for-bash-glob "$c"; c=$ret
+ fi
+ ble/array#push buff "$c"
+ done
+ IFS= builtin eval 'ret="${buff[*]}"'
+ else
+ ble/string#escape-for-bash-glob "$1"
+ fi
+}
+function ble/complete/.fignore/prepare {
+ _fignore=()
+ local i=0 leaf tmp
+ ble/string#split tmp ':' "$FIGNORE"
+ for leaf in "${tmp[@]}"; do
+ [[ $leaf ]] && _fignore[i++]="$leaf"
+ done
+}
+function ble/complete/.fignore/filter {
+ local pat
+ for pat in "${_fignore[@]}"; do
+ [[ $1 == *"$pat" ]] && return 1
+ done
+ return 0
+}
+function ble/complete/candidates/.pick-nearest-sources {
+ COMP1= COMP2=$comp_index
+ nearest_sources=()
+ local -a unused_sources=()
+ local src asrc
+ for src in "${remaining_sources[@]}"; do
+ ble/string#split-words asrc "$src"
+ if ((COMP1<asrc[1])); then
+ COMP1=${asrc[1]}
+ ble/array#push unused_sources "${nearest_sources[@]}"
+ nearest_sources=("$src")
+ elif ((COMP1==asrc[1])); then
+ ble/array#push nearest_sources "$src"
+ else
+ ble/array#push unused_sources "$src"
+ fi
+ done
+ remaining_sources=("${unused_sources[@]}")
+ COMPS=${comp_text:COMP1:COMP2-COMP1}
+ comps_flags=
+ comps_fixed=
+ if [[ ! $COMPS ]]; then
+ comps_flags=${comps_flags}v COMPV=
+ elif local ret simple_flags simple_ibrace; ble/syntax:bash/simple-word/reconstruct-incomplete-word "$COMPS"; then
+ local reconstructed=$ret
+ if [[ :$comp_type: == *:raw:* ]]; then
+ if ((${simple_ibrace%:*})); then
+ COMPV=
+ else
+ comps_flags=$comps_flags${simple_flags}v
+ COMPV=$reconstructed
+ fi
+ elif ble/complete/source/eval-simple-word "$reconstructed"; local ext=$?; ((ext==148)) && return 148; ((ext==0)); then
+ COMPV=("${ret[@]}")
+ comps_flags=$comps_flags${simple_flags}v
+ if ((${simple_ibrace%:*})); then
+ ble/complete/source/eval-simple-word "${reconstructed::${simple_ibrace#*:}}" single; (($?==148)) && return 148
+ comps_fixed=${simple_ibrace%:*}:$ret
+ comps_flags=${comps_flags}x
+ fi
+ else
+ COMPV=
+ comps_flags=$comps_flags${simple_flags}f
+ fi
+ [[ $COMPS =~ $rex_raw_paramx ]] && comps_flags=${comps_flags}p
+ else
+ COMPV=
+ fi
+}
+function ble/complete/candidates/clear {
+ cand_count=0
+ cand_cand=()
+ cand_word=()
+ cand_pack=()
+}
+function ble/complete/candidates/.filter-by-command {
+ local command=$1
+ local i j=0
+ local -a prop=() cand=() word=() show=() data=()
+ for ((i=0;i<cand_count;i++)); do
+ ((i%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ builtin eval -- "$command" || continue
+ cand[j]=${cand_cand[i]}
+ word[j]=${cand_word[i]}
+ data[j]=${cand_pack[i]}
+ ((j++))
+ done
+ cand_count=$j
+ cand_cand=("${cand[@]}")
+ cand_word=("${word[@]}")
+ cand_pack=("${data[@]}")
+}
+function ble/complete/candidates/.filter-by-regex {
+ local rex_filter=$1
+ ble/complete/candidates/.filter-by-command '[[ ${cand_cand[i]} =~ $rex_filter ]]'
+}
+function ble/complete/candidates/.filter-by-glob {
+ local globpat=$1
+ ble/complete/candidates/.filter-by-command '[[ ${cand_cand[i]} == $globpat ]]'
+}
+function ble/complete/candidates/.filter-word-by-prefix {
+ local prefix=$1
+ ble/complete/candidates/.filter-by-command '[[ ${cand_word[i]} == "$prefix"* ]]'
+}
+function ble/complete/candidates/.initialize-rex_raw_paramx {
+ local element=$_ble_syntax_bash_simple_rex_element
+ local open_dquot=$_ble_syntax_bash_simple_rex_open_dquot
+ rex_raw_paramx='^('$element'*('$open_dquot')?)\$[a-zA-Z_][a-zA-Z_0-9]*$'
+}
+function ble/complete/candidates/filter#init {
+ comp_filter_type=$1
+ comp_filter_pattern=
+ ble/complete/candidates/filter:"$comp_filter_type"/init "$2"
+}
+function ble/complete/candidates/filter#test {
+ ble/complete/candidates/filter:"$comp_filter_type"/test "$1"
+}
+function ble/complete/candidates/filter:none/init { ble/complete/candidates/filter:head/init "$@"; }
+function ble/complete/candidates/filter:none/test { true; }
+function ble/complete/candidates/filter:none/count-match-chars { ble/complete/candidates/filter:head/count-match-chars "$@"; }
+function ble/complete/candidates/filter:none/match { ble/complete/candidates/filter:head/match "$@"; }
+function ble/complete/candidates/filter:head/init {
+ local ret; ble/complete/util/construct-glob-pattern "$1"
+ comp_filter_pattern=$ret*
+}
+function ble/complete/candidates/filter:head/count-match-chars { # unused but for completeness
+ local value=$1 compv=$COMPV
+ if [[ :$comp_type: == *:i:* ]]; then
+ ble/string#tolower "$value"; value=$ret
+ ble/string#tolower "$compv"; compv=$ret
+ fi
+ if [[ $value == "$compv"* ]]; then
+ ret=${#compv}
+ elif [[ $compv == "$value"* ]]; then
+ ret=${#value}
+ else
+ ret=0
+ fi
+}
+function ble/complete/candidates/filter:head/test { [[ $1 == $comp_filter_pattern ]]; }
+function ble/complete/candidates/filter:head/match {
+ local needle=$1 text=$2
+ if [[ :$comp_type: == *:i:* ]]; then
+ ble/string#tolower "$needle"; needle=$ret
+ ble/string#tolower "$text"; text=$ret
+ fi
+ if [[ ! $needle || ! $text ]]; then
+ ret=()
+ elif [[ $text == "$needle"* ]]; then
+ ret=(0 ${#needle})
+ return 0
+ elif [[ $text == "${needle::${#text}}" ]]; then
+ ret=(0 ${#text})
+ return 0
+ else
+ ret=()
+ return 1
+ fi
+}
+function ble/complete/candidates/filter:substr/init {
+ local ret; ble/complete/util/construct-glob-pattern "$1"
+ comp_filter_pattern=*$ret*
+}
+function ble/complete/candidates/filter:substr/count-match-chars {
+ local value=$1 compv=$COMPV
+ if [[ :$comp_type: == *:i:* ]]; then
+ ble/string#tolower "$value"; value=$ret
+ ble/string#tolower "$compv"; compv=$ret
+ fi
+ if [[ $value == *"$compv"* ]]; then
+ ret=${#compv}
+ return 0
+ fi
+ ble/complete/string#common-suffix-prefix "$value" "$compv"
+ ret=${#ret}
+}
+function ble/complete/candidates/filter:substr/test { [[ $1 == $comp_filter_pattern ]]; }
+function ble/complete/candidates/filter:substr/match {
+ local needle=$1 text=$2
+ if [[ :$comp_type: == *:i:* ]]; then
+ ble/string#tolower "$needle"; needle=$ret
+ ble/string#tolower "$text"; text=$ret
+ fi
+ if [[ ! $needle ]]; then
+ ret=()
+ elif [[ $text == *"$needle"* ]]; then
+ text=${text%%"$needle"*}
+ local beg=${#text}
+ local end=$((beg+${#needle}))
+ ret=("$beg" "$end")
+ elif ble/complete/string#common-suffix-prefix "$text" "$needle"; ((${#ret})); then
+ local end=${#text}
+ local beg=$((end-${#ret}))
+ ret=("$beg" "$end")
+ else
+ ret=()
+ fi
+}
+function ble/complete/candidates/filter:hsubseq/.determine-fixlen {
+ fixlen=${1:-1}
+ if [[ $comps_fixed ]]; then
+ local compv_fixed_part=${comps_fixed#*:}
+ [[ $compv_fixed_part ]] && fixlen=${#compv_fixed_part}
+ fi
+}
+function ble/complete/candidates/filter:hsubseq/init {
+ local fixlen; ble/complete/candidates/filter:hsubseq/.determine-fixlen "$2"
+ local ret; ble/complete/util/construct-ambiguous-regex "$1" "$fixlen"
+ comp_filter_pattern=^$ret
+}
+function ble/complete/candidates/filter:hsubseq/count-match-chars {
+ local value=$1 compv=$COMPV
+ if [[ :$comp_type: == *:i:* ]]; then
+ ble/string#tolower "$value"; value=$ret
+ ble/string#tolower "$compv"; compv=$ret
+ fi
+ local fixlen
+ ble/complete/candidates/filter:hsubseq/.determine-fixlen "$2"
+ [[ $value == "${compv::fixlen}"* ]] || return 1
+ value=${value:fixlen}
+ local i n=${#COMPV}
+ for ((i=fixlen;i<n;i++)); do
+ local a=${value%%"${compv:i:1}"*}
+ [[ $a == "$value" ]] && { ret=$i; return 0; }
+ value=${value:${#a}+1}
+ done
+ ret=$n
+}
+function ble/complete/candidates/filter:hsubseq/test { [[ $1 =~ $comp_filter_pattern ]]; }
+function ble/complete/candidates/filter:hsubseq/match {
+ local needle=$1 text=$2
+ if [[ :$comp_type: == *:i:* ]]; then
+ ble/string#tolower "$needle"; needle=$ret
+ ble/string#tolower "$text"; text=$ret
+ fi
+ local fixlen; ble/complete/candidates/filter:hsubseq/.determine-fixlen "$3"
+ local prefix=${needle::fixlen}
+ if [[ $text != "$prefix"* ]]; then
+ if [[ $text && $text == "${prefix::${#text}}" ]]; then
+ ret=(0 ${#text})
+ else
+ ret=()
+ fi
+ return 0
+ fi
+ local pN=${#text} iN=${#needle}
+ local first=1
+ ret=()
+ while :; do
+ if [[ $first ]]; then
+ first=
+ local p0=0 p=${#prefix} i=${#prefix}
+ else
+ ((i<iN)) || return 0
+ while ((p<pN)) && [[ ${text:p:1} != "${needle:i:1}" ]]; do
+ ((p++))
+ done
+ ((p<pN)) || return 1
+ p0=$p
+ fi
+ while ((i<iN&&p<pN)) && [[ ${text:p:1} == "${needle:i:1}" ]]; do
+ ((p++,i++))
+ done
+ ((p0<p)) && ble/array#push ret "$p0" "$p"
+ done
+}
+function ble/complete/candidates/filter:subseq/init {
+ [[ $comps_fixed ]] && return 1
+ ble/complete/candidates/filter:hsubseq/init "$1" 0
+}
+function ble/complete/candidates/filter:subseq/count-match-chars {
+ ble/complete/candidates/filter:hsubseq/count-match-chars "$1" 0
+}
+function ble/complete/candidates/filter:subseq/test { [[ $1 =~ $comp_filter_pattern ]]; }
+function ble/complete/candidates/filter:subseq/match {
+ ble/complete/candidates/filter:hsubseq/match "$1" "$2" 0
+}
+function ble/complete/candidates/generate-with-filter {
+ local filter_type=$1 opts=$2
+ local -a remaining_sources nearest_sources
+ remaining_sources=("${sources[@]}")
+ local src asrc source
+ while ((${#remaining_sources[@]})); do
+ nearest_sources=()
+ ble/complete/candidates/.pick-nearest-sources; (($?==148)) && return 148
+ [[ ! $COMPV && :$opts: == *:no-empty:* ]] && continue
+ local comp_filter_type
+ local comp_filter_pattern
+ ble/complete/candidates/filter#init "$filter_type" "$COMPV" || continue
+ for src in "${nearest_sources[@]}"; do
+ ble/string#split-words asrc "$src"
+ ble/string#split source : "${asrc[0]}"
+ local COMP_PREFIX= # 既定値 (yield-candidate で参照)
+ ble/complete/source:"${source[@]}"
+ ble/complete/check-cancel && return 148
+ done
+ [[ $comps_fixed ]] &&
+ ble/complete/candidates/.filter-word-by-prefix "${COMPS::${comps_fixed%%:*}}"
+ ((cand_count)) && return 0
+ done
+ return 0
+}
+function ble/complete/candidates/comp_type#read-rl-variables {
+ ble/util/test-rl-variable completion-ignore-case 0 && comp_type=${comp_type}:i
+ ble/util/test-rl-variable visible-stats 0 && comp_type=${comp_type}:vstat
+ ble/util/test-rl-variable mark-directories 1 && comp_type=${comp_type}:markdir
+ ble/util/test-rl-variable mark-symlinked-directories 1 && comp_type=${comp_type}:marksymdir
+ ble/util/test-rl-variable match-hidden-files 1 && comp_type=${comp_type}:match-hidden
+ ble/util/test-rl-variable menu-complete-display-prefix 0 && comp_type=${comp_type}:menu-show-prefix
+ comp_type=$comp_type:menu-color:menu-color-match
+}
+function ble/complete/candidates/generate {
+ local opts=$1
+ local flag_force_fignore=
+ local flag_source_filter=
+ local -a _fignore=()
+ if [[ $FIGNORE ]]; then
+ ble/complete/.fignore/prepare
+ ((${#_fignore[@]})) && shopt -q force_fignore && flag_force_fignore=1
+ fi
+ local rex_raw_paramx
+ ble/complete/candidates/.initialize-rex_raw_paramx
+ ble/complete/candidates/comp_type#read-rl-variables
+ local cand_iloop=0
+ ble/complete/candidates/clear
+ ble/complete/candidates/generate-with-filter none "$opts" || return "$?"
+ ((cand_count)) && return 0
+ if [[ $bleopt_complete_ambiguous && $COMPV ]]; then
+ local original_comp_type=$comp_type
+ comp_type=${original_comp_type}:m
+ ble/complete/candidates/generate-with-filter substr "$opts" || return "$?"
+ ((cand_count)) && return 0
+ comp_type=${original_comp_type}:a
+ ble/complete/candidates/generate-with-filter hsubseq "$opts" || return "$?"
+ ((cand_count)) && return 0
+ comp_type=${original_comp_type}:A
+ ble/complete/candidates/generate-with-filter subseq "$opts" || return "$?"
+ ((cand_count)) && return 0
+ comp_type=$original_comp_type
+ fi
+ return 0
+}
+function ble/complete/candidates/determine-common-prefix/.apply-partial-comps {
+ local word0=$COMPS word1=$common fixed=
+ if [[ $comps_fixed ]]; then
+ local fixlen=${comps_fixed%%:*}
+ fixed=${word0::fixlen}
+ word0=${word0:fixlen}
+ word1=${word1:fixlen}
+ fi
+ local ret spec path spec0 path0 spec1 path1
+ ble/complete/source/evaluate-path-spec "$word0"; (($?==148)) && return 148; spec0=("${spec[@]}") path0=("${path[@]}")
+ ble/complete/source/evaluate-path-spec "$word1"; (($?==148)) && return 148; spec1=("${spec[@]}") path1=("${path[@]}")
+ local i=${#path1[@]}
+ while ((i--)); do
+ if ble/array#last-index path0 "${path1[i]}"; then
+ local elem=${spec1[i]} # workaround bash-3.1 ${#arr[i]} bug
+ word1=${spec0[ret]}${word1:${#elem}}
+ break
+ fi
+ done
+ common=$fixed$word1
+}
+function ble/complete/candidates/determine-common-prefix {
+ local common=${cand_word[0]}
+ local clen=${#common}
+ if ((cand_count>1)); then
+ local unset_nocasematch= flag_tolower=
+ if [[ :$comp_type: == *:i:* ]]; then
+ if ((_ble_bash<30100)); then
+ flag_tolower=1
+ ble/string#tolower "$common"; common=$ret
+ else
+ unset_nocasematch=1
+ shopt -s nocasematch
+ fi
+ fi
+ local word loop=0
+ for word in "${cand_word[@]:1}"; do
+ ((loop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && break
+ if [[ $flag_tolower ]]; then
+ ble/string#tolower "$word"; word=$ret
+ fi
+ ((clen>${#word}&&(clen=${#word})))
+ while [[ ${word::clen} != "${common::clen}" ]]; do
+ ((clen--))
+ done
+ common=${common::clen}
+ done
+ [[ $unset_nocasematch ]] && shopt -u nocasematch
+ ble/complete/check-cancel && return 148
+ [[ $flag_tolower ]] && common=${cand_word[0]::${#common}}
+ fi
+ if [[ $common != "$COMPS"* && ! ( $cand_count -eq 1 && $comp_type == *:i:* ) ]]; then
+ ble/complete/candidates/determine-common-prefix/.apply-partial-comps
+ fi
+ if ((cand_count>1)) && [[ $common != "$COMPS"* ]]; then
+ local common0=$common
+ common=$COMPS # 取り敢えず補完挿入をキャンセル
+ if [[ :$comp_type: == *:[maAi]:* ]]; then
+ local simple_flags simple_ibrace
+ if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$common0"; then
+ local common_reconstructed=$ret
+ local value=$ret filter_type=head
+ case :$comp_type: in
+ (*:m:*) filter_type=substr ;;
+ (*:a:*) filter_type=hsubseq ;;
+ (*:A:*) filter_type=subseq ;;
+ esac
+ local is_processed=
+ ble/complete/source/eval-simple-word "$common_reconstructed" single; local ext=$?
+ ((ext==148)) && return 148
+ if ((ext==0)) && ble/complete/candidates/filter:"$filter_type"/count-match-chars "$ret"; then
+ if [[ $filter_type == head ]] && ((ret<${#COMPV})); then
+ is_processed=1
+ [[ $bleopt_complete_allow_reduction ]] && common=$common0
+ elif ((ret)); then
+ is_processed=1
+ ble/string#escape-for-bash-specialchars "${COMPV:ret}" c
+ common=$common0$ret
+ fi
+ fi
+ if [[ ! $is_processed ]] &&
+ local notilde=\'\' &&
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$COMPS" &&
+ ble/syntax:bash/simple-word/eval "$notilde$ret" noglob &&
+ local compv_notilde=$ret &&
+ ble/syntax:bash/simple-word/eval "$notilde$common_reconstructed" noglob &&
+ local commonv_notilde=$ret &&
+ COMPV=$compv_notilde ble/complete/candidates/filter:"$filter_type"/count-match-chars "$commonv_notilde"
+ then
+ if [[ $filter_type == head ]] && ((ret<${#COMPV})); then
+ is_processed=1
+ [[ $bleopt_complete_allow_reduction ]] && common=$common0
+ elif ((ret)); then
+ is_processed=1
+ ble/string#escape-for-bash-specialchars "${compv_notilde:ret}" TG
+ common=$common0$ret
+ fi
+ fi
+ [[ $is_processed ]] || common=$common0$COMPS
+ fi
+ else
+ if ble/syntax:bash/simple-word/is-simple-or-open-simple "$common"; then
+ local flag_reduction=
+ if [[ $bleopt_complete_allow_reduction ]]; then
+ flag_reduction=1
+ else
+ local simple_flags simple_ibrace
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$common0" &&
+ ble/complete/source/eval-simple-word "$ret" single &&
+ [[ $ret == "$COMPV"* ]] &&
+ flag_reduction=1
+ (($?==148)) && return 148
+ fi
+ [[ $flag_reduction ]] && common=$common0
+ fi
+ fi
+ fi
+ ret=$common
+}
+_ble_complete_menu_active=
+_ble_complete_menu_style=
+_ble_complete_menu0_beg=
+_ble_complete_menu0_end=
+_ble_complete_menu0_str=
+_ble_complete_menu_common_part=
+_ble_complete_menu0_comp=()
+_ble_complete_menu0_pack=()
+_ble_complete_menu_comp=()
+function ble/complete/menu-complete.class/render-item {
+ local opts=$2
+ if [[ :$opts: == *:selected:* ]]; then
+ local COMP1=${_ble_complete_menu_comp[0]}
+ local COMP2=${_ble_complete_menu_comp[1]}
+ local COMPS=${_ble_complete_menu_comp[2]}
+ local COMPV=${_ble_complete_menu_comp[3]}
+ local comp_type=${_ble_complete_menu_comp[4]}
+ local comps_flags=${_ble_complete_menu0_comp[5]}
+ local comps_fixed=${_ble_complete_menu0_comp[6]}
+ local menu_common_part=$_ble_complete_menu_common_part
+ fi
+ local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
+ ble/complete/cand/unpack "$1"
+ local prefix_len=$PREFIX_LEN
+ [[ :$comp_type: == *:menu-show-prefix:* ]] && prefix_len=0
+ local filter_target=${CAND:prefix_len}
+ if [[ ! $filter_target ]]; then
+ ret=
+ return 0
+ fi
+ local g=0 show=$filter_target suffix= prefix=
+ ble/function#try ble/complete/action:"$ACTION"/init-menu-item
+ local g0=$g; [[ :$comp_type: == *:menu-color:* ]] || g0=0
+ local m
+ if [[ :$comp_type: == *:menu-color-match:* && $_ble_complete_menu_common_part && $show == *"$filter_target"* ]]; then
+ local filter_type=head
+ case :$comp_type: in
+ (*:m:*) filter_type=substr ;;
+ (*:a:*) filter_type=hsubseq ;;
+ (*:A:*) filter_type=subseq ;;
+ esac
+ local needle=${_ble_complete_menu_common_part:prefix_len}
+ ble/complete/candidates/filter:"$filter_type"/match "$needle" "$filter_target"; m=("${ret[@]}")
+ if [[ $show != "$filter_target" ]]; then
+ local show_prefix=${show%%"$filter_target"*}
+ local offset=${#show_prefix}
+ local i n=${#m[@]}
+ for ((i=0;i<n;i++)); do ((m[i]+=offset)); done
+ fi
+ else
+ m=()
+ fi
+ local sgrN0= sgrN1= sgrB0= sgrB1=
+ [[ :$opts: == *:selected:* ]] && ((g0^=_ble_color_gflags_Revert))
+ ret=${_ble_color_g2sgr[g=g0]}
+ [[ $ret ]] || ble/color/g2sgr "$g"; sgrN0=$ret
+ ret=${_ble_color_g2sgr[g=g0^_ble_color_gflags_Revert]}
+ [[ $ret ]] || ble/color/g2sgr "$g"; sgrN1=$ret
+ if ((${#m[@]})); then
+ ret=${_ble_color_g2sgr[g=g0|_ble_color_gflags_Bold]}
+ [[ $ret ]] || ble/color/g2sgr "$g"; sgrB0=$ret
+ ret=${_ble_color_g2sgr[g=(g0|_ble_color_gflags_Bold)^_ble_color_gflags_Revert]}
+ [[ $ret ]] || ble/color/g2sgr "$g"; sgrB1=$ret
+ fi
+ local out= flag_overflow= p0=0
+ if [[ $prefix ]]; then
+ ble/canvas/trace-text "$prefix" nonewline || flag_overflow=1
+ out=$out$_ble_term_sgr0$ret
+ fi
+ if ((${#m[@]})); then
+ local i iN=${#m[@]} p p0=0 out=
+ for ((i=0;i<iN;i++)); do
+ ((p=m[i]))
+ if ((p0<p)); then
+ if ((i%2==0)); then
+ local sgr0=$sgrN0 sgr1=$sgrN1
+ else
+ local sgr0=$sgrB0 sgr1=$sgrB1
+ fi
+ ble/canvas/trace-text "${show:p0:p-p0}" nonewline:external-sgr || flag_overflow=1
+ out=$out$sgr0$ret
+ fi
+ p0=$p
+ done
+ fi
+ if ((p0<${#show})); then
+ local sgr0=$sgrN0 sgr1=$sgrN1
+ ble/canvas/trace-text "${show:p0}" nonewline:external-sgr || flag_overflow=1
+ out=$out$sgr0$ret
+ fi
+ if [[ $suffix ]]; then
+ ble/canvas/trace-text "$suffix" nonewline || flag_overflow=1
+ out=$out$_ble_term_sgr0$ret
+ fi
+ ret=$out$_ble_term_sgr0
+ [[ ! $flag_overflow ]]
+}
+function ble/complete/menu-complete.class/get-desc {
+ local item=$1
+ local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
+ ble/complete/cand/unpack "$item"
+ desc="$desc_sgrt(action:$ACTION)$desc_sgr0"
+ ble/function#try ble/complete/action:"$ACTION"/get-desc
+}
+function ble/complete/menu-complete.class/onselect {
+ local nsel=$1 osel=$2
+ local insert=${_ble_complete_menu_original:-${_ble_complete_menu_comp[2]}}
+ if ((nsel>=0)); then
+ local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
+ ble/complete/cand/unpack "${_ble_complete_menu_items[nsel]}"
+ insert=$INSERT
+ fi
+ ble-edit/content/replace-limited "$_ble_complete_menu0_beg" "$_ble_edit_ind" "$insert"
+ ((_ble_edit_ind=_ble_complete_menu0_beg+${#insert}))
+}
+function ble/complete/menu/clear {
+ if [[ $_ble_complete_menu_active ]]; then
+ _ble_complete_menu_active=
+ ble/complete/menu#clear
+ [[ $_ble_highlight_layer_menu_filter_beg ]] &&
+ ble/textarea#invalidate str # layer:menu_filter 解除 (#D0995)
+ fi
+ return 0
+}
+blehook widget_bell+=ble/complete/menu/clear
+blehook history_onleave+=ble/complete/menu/clear
+function ble/complete/menu/get-footprint {
+ footprint=$_ble_edit_ind:$_ble_edit_mark_active:${_ble_edit_mark_active:+$_ble_edit_mark}:$_ble_edit_overwrite_mode:$_ble_edit_str
+}
+function ble/complete/menu/show {
+ local opts=$1
+ if [[ :$opts: == *:load-filtered-data:* ]]; then
+ local COMP1=${_ble_complete_menu_comp[0]}
+ local COMP2=${_ble_complete_menu_comp[1]}
+ local COMPS=${_ble_complete_menu_comp[2]}
+ local COMPV=${_ble_complete_menu_comp[3]}
+ local comp_type=${_ble_complete_menu_comp[4]}
+ local comps_flags=${_ble_complete_menu0_comp[5]}
+ local comps_fixed=${_ble_complete_menu0_comp[6]}
+ local cand_pack; cand_pack=("${_ble_complete_menu_items[@]}")
+ local menu_common_part=$_ble_complete_menu_common_part
+ fi
+ local menu_style=$bleopt_complete_menu_style
+ [[ :$opts: == *:filter:* && $_ble_complete_menu_style ]] &&
+ menu_style=$_ble_complete_menu_style
+ local menu_items; menu_items=("${cand_pack[@]}")
+ _ble_complete_menu_common_part=$menu_common_part
+ local menu_class=ble/complete/menu-complete.class menu_param=
+ local menu_opts=$opts
+ [[ :$comp_type: == *:sync:* ]] && menu_opts=$menu_opts:sync
+ ble/complete/menu#construct "$menu_opts" || return "$?"
+ ble/complete/menu#show
+ if [[ :$opts: == *:menu-source:* ]]; then
+ local left0=${_ble_complete_menu0_str::_ble_complete_menu0_end}
+ local left1=${_ble_edit_str::_ble_edit_ind}
+ local ret; ble/string#common-prefix "$left0" "$left1"; left0=$ret
+ local right0=${_ble_complete_menu0_str:_ble_complete_menu0_end}
+ local right1=${_ble_edit_str:_ble_edit_ind}
+ local ret; ble/string#common-suffix "$right0" "$right1"; right0=$ret
+ local footprint; ble/complete/menu/get-footprint
+ _ble_complete_menu0_str=$left0$right0
+ _ble_complete_menu0_end=${#left0}
+ _ble_complete_menu_footprint=$footprint
+ elif [[ :$opts: != *:filter:* ]]; then
+ local beg=$COMP1 end=$_ble_edit_ind # COMP2 でなく補完挿入後の位置
+ local str=$_ble_edit_str
+ [[ $_ble_decode_keymap == auto_complete ]] &&
+ str=${str::_ble_edit_ind}${str:_ble_edit_mark}
+ local footprint; ble/complete/menu/get-footprint
+ _ble_complete_menu_active=1
+ _ble_complete_menu_style=$menu_style
+ _ble_complete_menu0_beg=$beg
+ _ble_complete_menu0_end=$end
+ _ble_complete_menu0_str=$str
+ _ble_complete_menu0_comp=("$COMP1" "$COMP2" "$COMPS" "$COMPV" "$comp_type" "$comps_flags" "$comps_fixed")
+ _ble_complete_menu0_pack=("${cand_pack[@]}")
+ _ble_complete_menu_selected=-1
+ _ble_complete_menu_comp=("$COMP1" "$COMP2" "$COMPS" "$COMPV" "$comp_type")
+ _ble_complete_menu_footprint=$footprint
+ fi
+ return 0
+}
+function ble/complete/menu/redraw {
+ if [[ $_ble_complete_menu_active ]]; then
+ ble/complete/menu#show
+ fi
+}
+function ble/complete/menu/get-active-range {
+ [[ $_ble_complete_menu_active ]] || return 1
+ local str=${1-$_ble_edit_str} ind=${2-$_ble_edit_ind}
+ local mbeg=$_ble_complete_menu0_beg
+ local mend=$_ble_complete_menu0_end
+ local left=${_ble_complete_menu0_str::mend}
+ local right=${_ble_complete_menu0_str:mend}
+ if [[ ${str::_ble_edit_ind} == "$left"* && ${str:_ble_edit_ind} == *"$right" ]]; then
+ ((beg=mbeg,end=${#str}-${#right}))
+ return 0
+ else
+ ble/complete/menu/clear
+ return 1
+ fi
+}
+function ble/complete/menu/generate-candidates-from-menu {
+ COMP1=${_ble_complete_menu_comp[0]}
+ COMP2=${_ble_complete_menu_comp[1]}
+ COMPS=${_ble_complete_menu_comp[2]}
+ COMPV=${_ble_complete_menu_comp[3]}
+ comp_type=${_ble_complete_menu_comp[4]}
+ comps_flags=${_ble_complete_menu0_comp[5]}
+ comps_fixed=${_ble_complete_menu0_comp[6]}
+ cand_count=${#_ble_complete_menu_items[@]}
+ cand_cand=() cand_word=() cand_pack=()
+ local pack "${_ble_complete_cand_varnames[@]/%/=}" # #D1570 WA checked
+ for pack in "${_ble_complete_menu_items[@]}"; do
+ ble/complete/cand/unpack "$pack"
+ ble/array#push cand_cand "$CAND"
+ ble/array#push cand_word "$INSERT"
+ ble/array#push cand_pack "$pack"
+ done
+ ((cand_count))
+}
+function ble/complete/generate-candidates-from-opts {
+ local opts=$1
+ local context; ble/complete/complete/determine-context-from-opts "$opts"
+ comp_type=
+ [[ :$opts: == *:auto_menu:* ]] && comp_type=auto_menu
+ local comp_text=$_ble_edit_str comp_index=$_ble_edit_ind
+ local sources
+ ble/complete/context:"$context"/generate-sources "$comp_text" "$comp_index" || return "$?"
+ ble/complete/candidates/generate "$opts"
+}
+function ble/complete/insert {
+ local insert_beg=$1 insert_end=$2
+ local insert=$3 suffix=$4
+ local original_text=${_ble_edit_str:insert_beg:insert_end-insert_beg}
+ local ret
+ local insert_replace=
+ if [[ $insert == "$original_text"* ]]; then
+ insert=${insert:insert_end-insert_beg}
+ ((insert_beg=insert_end))
+ else
+ ble/string#common-prefix "$insert" "$original_text"
+ if [[ $ret ]]; then
+ insert=${insert:${#ret}}
+ ((insert_beg+=${#ret}))
+ fi
+ fi
+ if ble/util/test-rl-variable skip-completed-text; then
+ if [[ $insert ]]; then
+ local right_text=${_ble_edit_str:insert_end}
+ right_text=${right_text%%[$IFS]*}
+ if ble/string#common-prefix "$insert" "$right_text"; [[ $ret ]]; then
+ ((insert_end+=${#ret}))
+ elif ble/complete/string#common-suffix-prefix "$insert" "$right_text"; [[ $ret ]]; then
+ ((insert_end+=${#ret}))
+ fi
+ fi
+ if [[ $suffix ]]; then
+ local right_text=${_ble_edit_str:insert_end}
+ if ble/string#common-prefix "$suffix" "$right_text"; [[ $ret ]]; then
+ ((insert_end+=${#ret}))
+ elif ble/complete/string#common-suffix-prefix "$suffix" "$right_text"; [[ $ret ]]; then
+ ((insert_end+=${#ret}))
+ fi
+ fi
+ fi
+ local ins=$insert$suffix
+ ble/widget/.replace-range "$insert_beg" "$insert_end" "$ins"
+ ((_ble_edit_ind=insert_beg+${#ins},
+ _ble_edit_ind>${#_ble_edit_str}&&
+ (_ble_edit_ind=${#_ble_edit_str})))
+}
+function ble/complete/insert-common {
+ local ret
+ ble/complete/candidates/determine-common-prefix; (($?==148)) && return 148
+ local insert=$ret suffix=
+ local insert_beg=$COMP1 insert_end=$COMP2
+ local insert_flags=
+ [[ $insert == "$COMPS"* ]] || insert_flags=r
+ if ((cand_count==1)); then
+ local ACTION=${cand_pack[0]%%:*}
+ if ble/is-function ble/complete/action:"$ACTION"/complete; then
+ local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
+ ble/complete/cand/unpack "${cand_pack[0]}"
+ ble/complete/action:"$ACTION"/complete
+ (($?==148)) && return 148
+ fi
+ else
+ insert_flags=${insert_flags}m
+ fi
+ local do_insert=1
+ if ((cand_count>1)) && [[ $insert_flags == *r* ]]; then
+ if [[ :$comp_type: != *:[maAi]:* ]]; then
+ do_insert=
+ fi
+ elif [[ $insert$suffix == "$COMPS" ]]; then
+ do_insert=
+ fi
+ if [[ $do_insert ]]; then
+ ble/complete/insert "$insert_beg" "$insert_end" "$insert" "$suffix"
+ blehook/invoke complete_insert
+ fi
+ if [[ $insert_flags == *m* ]]; then
+ local menu_common_part=$COMPV
+ local ret simple_flags simple_ibrace
+ if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$insert"; then
+ ble/complete/source/eval-simple-word "$ret" single
+ (($?==148)) && return 148
+ menu_common_part=$ret
+ fi
+ ble/complete/menu/show "$menu_show_opts" || return "$?"
+ elif [[ $insert_flags == *n* ]]; then
+ ble/widget/complete show_menu:regenerate || return "$?"
+ else
+ _ble_complete_state=complete
+ ble/complete/menu/clear
+ fi
+ return 0
+}
+function ble/complete/insert-all {
+ local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
+ local pack beg=$COMP1 end=$COMP2 insert= suffix= insert_flags= index=0
+ for pack in "${cand_pack[@]}"; do
+ ble/complete/cand/unpack "$pack"
+ insert=$INSERT suffix= insert_flags=
+ if ble/is-function ble/complete/action:"$ACTION"/complete; then
+ ble/complete/action:"$ACTION"/complete
+ (($?==148)) && return 148
+ fi
+ [[ $suffix != *' ' ]] && suffix="$suffix "
+ ble/complete/insert "$beg" "$end" "$insert" "$suffix"
+ blehook/invoke complete_insert
+ beg=$_ble_edit_ind end=$_ble_edit_ind
+ ((index++))
+ done
+ _ble_complete_state=complete
+ ble/complete/menu/clear
+ return 0
+}
+function ble/complete/insert-braces/.compose {
+ if ble/bin/awk.supports-null-record-separator; then
+ local printf_format='%s\0' RS='"\0"'
+ else
+ local printf_format='%s\x1E' RS='"\x1E"'
+ fi
+ local q=\'
+ local -x rex_atom='^(\\.|[0-9]+|.)' del_close= del_open= quote_type=
+ local -x COMPS=$COMPS
+ if [[ :$comp_type: != *:[maAi]:* ]]; then
+ local rex_brace='[,{}]|\{[-a-zA-Z0-9]+\.\.[-a-zA-Z0-9]+\}'
+ case $comps_flags in
+ (*S*) rex_atom='^('$q'(\\'$q'|'$rex_brace')'$q'|[0-9]+|.)' # '...'
+ del_close=\' del_open=\' quote_type=S ;;
+ (*E*) rex_atom='^(\\.|'$q'('$rex_brace')\$'$q'|[0-9]+|.)' # $'...'
+ del_close=\' del_open=\$\' quote_type=E ;;
+ (*[DI]*) rex_atom='^(\\[\"$`]|"('$rex_brace')"|[0-9]+|.)' # "...", $"..."
+ del_close=\" del_open=\" quote_type=D ;;
+ esac
+ fi
+ printf "$printf_format" "$@" | ble/bin/awk '
+ function starts_with(str, head) {
+ return substr(str, 1, length(head)) == head;
+ }
+ BEGIN {
+ RS = '"$RS"';
+ rex_atom = ENVIRON["rex_atom"];
+ del_close = ENVIRON["del_close"];
+ del_open = ENVIRON["del_open"];
+ quote_type = ENVIRON["quote_type"];
+ COMPS = ENVIRON["COMPS"];
+ BRACE_OPEN = del_close "{" del_open;
+ BRACE_CLOS = del_close "}" del_open;
+ }
+ function to_atoms(str, arr, _, chr, atom, level, count, rex) {
+ count = 0;
+ while (match(str, rex_atom) > 0) {
+ chr = substr(str, 1, RLENGTH);
+ str = substr(str, RLENGTH + 1);
+ if (chr == BRACE_OPEN) {
+ atom = chr;
+ level = 1;
+ while (match(str, rex_atom) > 0) {
+ chr = substr(str, 1, RLENGTH);
+ str = substr(str, RLENGTH + 1);
+ atom = atom chr;
+ if (chr == BRACE_OPEN)
+ level++;
+ else if (chr == BRACE_CLOS && --level==0)
+ break;
+ }
+ } else {
+ atom = chr;
+ }
+ arr[count++] = atom;
+ }
+ return count;
+ }
+ function remove_empty_quote(str, _, rex_quote_first, rex_quote, out, empty, m) {
+ if (quote_type == "S" || quote_type == "E") {
+ rex_quote_first = "^[^'$q']*'$q'";
+ rex_quote = "'$q'[^'$q']*'$q'|(\\\\.|[^'$q'])+";
+ } else if (quote_type == "D") {
+ rex_quote_first = "^[^\"]*\"";
+ rex_quote = "\"([^\\\"]|\\\\.)*\"|(\\\\.|[^\"])+";
+ } else return str;
+ empty = del_open del_close;
+ out = "";
+ if (starts_with(str, COMPS)) {
+ out = COMPS;
+ str = substr(str, length(COMPS) + 1);
+ if (match(str, rex_quote_first) > 0) {
+ out = out substr(str, 1, RLENGTH);
+ str = substr(str, RLENGTH + 1);
+ }
+ }
+ while (match(str, rex_quote) > 0) {
+ m = substr(str, 1, RLENGTH);
+ if (m != empty) out = out m;
+ str = substr(str, RLENGTH + 1);
+ }
+ if (str == del_open)
+ return out;
+ else
+ return out str del_close;
+ }
+ function zpad(value, width, _, wpad, i, pad) {
+ wpad = width - length(value);
+ pad = "";
+ for (i = 0; i < wpad; i++) pad = "0" pad;
+ if (value < 0)
+ return "-" pad (-value);
+ else
+ return pad value;
+ }
+ function zpad_remove(value) {
+ if (value ~ /^0+$/)
+ value = "0";
+ else if (value ~ /^-/)
+ sub(/^-0+/, "-", value);
+ else
+ sub(/^0+/, "", value);
+ return value;
+ }
+ function zpad_a2i(text) {
+ sub(/^-0+/, "-", text) || sub(/^0+/, "", text);
+ return 0 + text;
+ }
+ function range_contract(arr, len, _, i, value, alpha, lower, upper, keys, ikey, dict, b, e, beg, end, tmp) {
+ lower = "abcdefghijklmnopqrstuvwxyz";
+ upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ for (i = 0; i < len; i++) {
+ value = arr[i];
+ if (dict[value]) {
+ dict[value]++;
+ } else {
+ keys[ikey++] = value;
+ dict[value] = 1;
+ }
+ }
+ len = 0;
+ for (i = 0; i < ikey; i++) {
+ while (dict[value = keys[i]]--) {
+ if (value ~ /^([a-zA-Z])$/) {
+ alpha = (value ~ /^[a-z]$/) ? lower : upper;
+ beg = end = value;
+ b = e = index(alpha, value);
+ while (b > 1 && dict[tmp = substr(alpha, b - 1, 1)]) {
+ dict[beg = tmp]--;
+ b--;
+ }
+ while (e < 26 && dict[tmp = substr(alpha, e + 1, 1)]) {
+ dict[end = tmp]--;
+ e++;
+ }
+ if (e == b) {
+ arr[len++] = beg;
+ } else if (e == b + 1) {
+ arr[len++] = beg;
+ arr[len++] = end;
+ } else {
+ arr[len++] = del_close "{" beg ".." end "}" del_open;
+ }
+ } else if (value ~ /^(0+|-?0*[1-9][0-9]*)$/) {
+ beg = end = value;
+ b = e = zpad_a2i(value);
+ wmax = wmin = length(value);
+ if (value ~ /^(0|-?[1-9][0-9]*)$/) {
+ while (dict[b - 1]) dict[--b]--;
+ while (dict[e + 1]) dict[++e]--;
+ tmp = length(beg = "" b);
+ if (tmp < wmin) wmin = tmp;
+ else if (tmp > wmax) wmax = tmp;
+ tmp = length(end = "" e);
+ if (tmp < wmin) wmin = tmp;
+ else if (tmp > wmax) wmax = tmp;
+ }
+ if (wmax == wmin) {
+ while (length(tmp = zpad(b - 1, wmin)) == wmin && dict[tmp]) { dict[tmp]--; --b; }
+ while (length(tmp = zpad(e + 1, wmin)) == wmin && dict[tmp]) { dict[tmp]--; ++e; }
+ beg = zpad(b, wmin);
+ end = zpad(e, wmin);
+ }
+ if (e == b) {
+ arr[len++] = beg;
+ } else if (e == b + 1) {
+ arr[len++] = beg;
+ arr[len++] = end;
+ } else if (b < 0 && e < 0) {
+ arr[len++] = del_close "-{" substr(end, 2) ".." substr(beg, 2) "}" del_open;
+ } else {
+ arr[len++] = del_close "{" beg ".." end "}" del_open;
+ }
+ } else {
+ arr[len++] = value;
+ }
+ }
+ }
+ return len;
+ }
+ function simple_brace(arr, len, _, ret, i) {
+ if (len == 0) return "";
+ len = range_contract(arr, len);
+ if (len == 1) return arr[0];
+ ret = BRACE_OPEN arr[0];
+ for (i = 1; i < len; i++)
+ ret = ret del_close "," del_open arr[i];
+ return ret BRACE_CLOS;
+ }
+ function rfrag_strlen_common(a, b, _, la, lb, tmp, i, n) {
+ ret = 0;
+ alen = to_atoms(a, abuf);
+ blen = to_atoms(b, bbuf);
+ while (alen > 0 && blen > 0) {
+ if (abuf[alen - 1] != bbuf[blen - 1]) break;
+ ret += length(abuf[alen - 1]);
+ alen--;
+ blen--;
+ }
+ return ret;
+ }
+ function rfrag_get_level(str, _, len, i, rfrag0, rfrag0len, rfrag1) {
+ len = length(str);
+ rfrag_matching_offset = len;
+ for (i = 0; i < rfrag_depth - 1; i++) {
+ rfrag0 = rfrag[i];
+ rfrag0len = length(rfrag0);
+ rfrag1 = substr(str, len - rfrag0len + 1);
+ str = substr(str, 1, len -= rfrag0len);
+ if (rfrag0 != rfrag1) break;
+ rfrag_matching_offset -= rfrag0len;
+ }
+ while (i && rfrag[i - 1] == "") i--; # empty fragment
+ return i;
+ }
+ function rfrag_reduce(new_depth, _, c, i, brace, frags) {
+ while (rfrag_depth > new_depth) {
+ rfrag_depth--;
+ c = rfrag_count[rfrag_depth];
+ for (i = 0; i < c; i++)
+ frags[i] = rfrag[rfrag_depth, i];
+ frags[c] = rfrag[rfrag_depth];
+ brace = simple_brace(frags, c + 1);
+ if (rfrag_depth == 0)
+ return brace;
+ else
+ rfrag[rfrag_depth - 1] = brace rfrag[rfrag_depth - 1];
+ }
+ }
+ function rfrag_register(str, level, _, rfrag0, rfrag1, len) {
+ if (level == rfrag_depth) {
+ rfrag_depth = level + 1;
+ rfrag[level] = "";
+ rfrag_count[level] = 0;
+ } else if (rfrag_depth != level + 1) {
+ print "ERR(rfrag)";
+ }
+ rfrag0 = rfrag[level];
+ rfrag1 = substr(str, 1, rfrag_matching_offset);
+ len = rfrag_strlen_common(rfrag0, rfrag1);
+ if (len == 0) {
+ rfrag[level, rfrag_count[level]++] = rfrag0;
+ rfrag[level] = rfrag1;
+ } else {
+ rfrag[level] = substr(rfrag0, length(rfrag0) - len + 1);
+ rfrag[level + 1, 0] = substr(rfrag0, 1, length(rfrag0) - len);
+ rfrag[level + 1] = substr(rfrag1, 1, length(rfrag1) - len);
+ rfrag_count[level + 1] = 1;
+ rfrag_depth++;
+ }
+ }
+ function rfrag_dump(_, i, j, prefix) {
+ print "depth = " rfrag_depth;
+ for (i = 0; i < rfrag_depth; i++) {
+ prefix = "";
+ for (j = 0; j < i; j++) prefix = prefix " ";
+ for (j = 0; j < rfrag_count[i]; j++)
+ print prefix "rfrag[" i "," j "] = " rfrag[i,j];
+ print prefix "rfrag[" i "] = " rfrag[i];
+ }
+ }
+ function rfrag_brace(arr, len, _, i, level) {
+ if (len == 0) return "";
+ if (len == 1) return arr[0];
+ rfrag_depth = 1;
+ rfrag[0] = arr[0];
+ rfrag_count[0] = 0;
+ for (i = 1; i < len; i++) {
+ level = rfrag_get_level(arr[i]);
+ rfrag_reduce(level + 1);
+ rfrag_register(arr[i], level);
+ }
+ return rfrag_reduce(0);
+ }
+ function lfrag_strlen_common(a, b, _, ret, abuf, bbuf, alen, blen, ia, ib) {
+ ret = 0;
+ alen = to_atoms(a, abuf);
+ blen = to_atoms(b, bbuf);
+ for (ia = ib = 0; ia < alen && ib < blen; ia++ + ib++) {
+ if (abuf[ia] != bbuf[ib]) break;
+ ret += length(abuf[ia]);
+ }
+ return ret;
+ }
+ function lfrag_get_level(str, _, i, frag0, frag0len, frag1) {
+ lfrag_matching_offset = 0;
+ for (i = 0; i < lfrag_depth - 1; i++) {
+ frag0 = frag[i]
+ frag0len = length(frag0);
+ frag1 = substr(str, lfrag_matching_offset + 1, frag0len);
+ if (frag0 != frag1) break;
+ lfrag_matching_offset += frag0len;
+ }
+ while (i && frag[i - 1] == "") i--; # empty fragment
+ return i;
+ }
+ function lfrag_reduce(new_depth, _, c, i, brace, frags) {
+ while (lfrag_depth > new_depth) {
+ lfrag_depth--;
+ c = frag_count[lfrag_depth];
+ for (i = 0; i < c; i++)
+ frags[i] = frag[lfrag_depth, i];
+ frags[c] = frag[lfrag_depth];
+ brace = rfrag_brace(frags, c + 1);
+ if (lfrag_depth == 0)
+ return brace;
+ else
+ frag[lfrag_depth - 1] = frag[lfrag_depth - 1] brace;
+ }
+ }
+ function lfrag_register(str, level, _, frag0, frag1, len) {
+ if (lfrag_depth == level) {
+ lfrag_depth = level + 1;
+ frag[level] = "";
+ frag_count[level] = 0;
+ } else if (lfrag_depth != level + 1) {
+ print "ERR";
+ }
+ frag0 = frag[level];
+ frag1 = substr(str, lfrag_matching_offset + 1);
+ len = lfrag_strlen_common(frag0, frag1);
+ if (len == 0) {
+ frag[level, frag_count[level]++] = frag0;
+ frag[level] = frag1;
+ } else {
+ frag[level] = substr(frag0, 1, len);
+ frag[level + 1, 0] = substr(frag0, len + 1);
+ frag[level + 1] = substr(frag1, len + 1);
+ frag_count[level + 1] = 1;
+ lfrag_depth++;
+ }
+ }
+ function lfrag_dump(_, i, j, prefix) {
+ print "depth = " lfrag_depth;
+ for (i = 0; i < lfrag_depth; i++) {
+ prefix = "";
+ for (j = 0; j < i; j++) prefix = prefix " ";
+ for (j = 0; j < frag_count[i]; j++)
+ print prefix "frag[" i "," j "] = " frag[i,j];
+ print prefix "frag[" i "] = " frag[i];
+ }
+ }
+ NR == 1 {
+ lfrag_depth = 1;
+ frag[0] = $0;
+ frag_count[0] = 0;
+ next
+ }
+ {
+ level = lfrag_get_level($0);
+ lfrag_reduce(level + 1);
+ lfrag_register($0, level);
+ }
+ END {
+ result = lfrag_reduce(0);
+ result = remove_empty_quote(result);
+ print result;
+ }
+ '
+}
+function ble/complete/insert-braces {
+ if ((cand_count==1)); then
+ ble/complete/insert-common; return "$?"
+ fi
+ local comps_len=${#COMPS} loop=0
+ local -a tails=()
+ local common=${cand_word[0]}
+ ble/array#push tails "${common:comps_len}"
+ local word clen=${#common}
+ for word in "${cand_word[@]:1}"; do
+ ((loop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ ((clen>${#word}&&(clen=${#word})))
+ while [[ ${word::clen} != "${common::clen}" ]]; do
+ ((clen--))
+ done
+ common=${common::clen}
+ ble/array#push tails "${word:comps_len}"
+ done
+ local fixed=$COMPS
+ if [[ $common != "$COMPS"* ]]; then
+ tails=()
+ local fixed= fixval=
+ {
+ [[ $comps_fixed ]] &&
+ fixed=${COMPS::${comps_fixed%%:*}} fixval=${comps_fixed#*:}
+ local ret simple_flags simple_ibrace
+ ble/complete/candidates/determine-common-prefix/.apply-partial-comps # var[in,out] common
+ if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$common"; then
+ ble/complete/source/eval-simple-word "$ret" single
+ (($?==148)) && return 148
+ fixed=$common fixval=$ret
+ fi
+ }
+ local cand ret fixval_len=${#fixval}
+ for cand in "${cand_cand[@]}"; do
+ ((loop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
+ [[ $cand == "$fixval"* ]] || continue
+ ble/complete/string#escape-for-completion-context "${cand:fixval_len}"
+ case $comps in
+ (*S*) cand=\'$ret\' ;;
+ (*E*) cand=\$\'$ret\' ;;
+ (*D*) cand=\"$ret\" ;;
+ (*I*) cand=\$\"$ret\" ;;
+ (*) cand=$ret ;;
+ esac
+ ble/array#push tails "$cand"
+ done
+ fi
+ local tail; ble/util/assign tail 'ble/complete/insert-braces/.compose "${tails[@]}"'
+ local beg=$COMP1 end=$COMP2 insert=$fixed$tail suffix=
+ if [[ $comps_flags == *x* ]]; then
+ ble/complete/action/complete.addtail ','
+ else
+ ble/complete/action/complete.addtail ' '
+ fi
+ ble/complete/insert "$beg" "$end" "$insert" "$suffix"
+ blehook/invoke complete_insert
+ _ble_complete_state=complete
+ ble/complete/menu/clear
+ return 0
+}
+_ble_complete_state=
+function ble/widget/complete {
+ local opts=$1
+ ble-edit/content/clear-arg
+ local state=$_ble_complete_state
+ _ble_complete_state=start
+ local menu_show_opts=
+ if [[ :$opts: != *:insert_*:* && :$opts: != *:show_menu:* ]]; then
+ if [[ :$opts: == *:enter_menu:* ]]; then
+ [[ $_ble_complete_menu_active && :$opts: != *:context=*:* ]] &&
+ ble/complete/menu-complete/enter "$opts" && return 0
+ elif [[ $bleopt_complete_menu_complete ]]; then
+ if [[ $_ble_complete_menu_active && :$opts: != *:context=*:* ]]; then
+ local footprint; ble/complete/menu/get-footprint
+ [[ $footprint == "$_ble_complete_menu_footprint" ]] &&
+ ble/complete/menu-complete/enter && return 0
+ fi
+ [[ $WIDGET == "$LASTWIDGET" && $state != complete ]] && opts=$opts:enter_menu
+ fi
+ fi
+ local COMP1 COMP2 COMPS COMPV
+ local comp_type comps_flags comps_fixed
+ local cand_count cand_cand cand_word cand_pack
+ ble/complete/candidates/clear
+ local cand_limit_reached=
+ if [[ $_ble_complete_menu_active && :$opts: != *:regenerate:* &&
+ :$opts: != *:context=*:* && ${#_ble_complete_menu_icons[@]} -gt 0 ]]
+ then
+ if [[ $_ble_complete_menu_filter_enabled && $bleopt_complete_menu_filter ]] || {
+ ble/complete/menu-filter; local ext=$?
+ ((ext==148)) && return 148
+ ((ext==0)); }; then
+ ble/complete/menu/generate-candidates-from-menu; local ext=$?
+ ((ext==148)) && return 148
+ if ((ext==0&&cand_count)); then
+ local bleopt_complete_menu_style=$_ble_complete_menu_style
+ menu_show_opts=$menu_show_opts:menu-source # 既存の filter 前候補を保持する
+ fi
+ fi
+ fi
+ if ((cand_count==0)); then
+ local bleopt_complete_menu_style=$bleopt_complete_menu_style # source 等に一次変更を認める。
+ ble/complete/generate-candidates-from-opts "$opts"; local ext=$?
+ if ((ext==148)); then
+ return 148
+ fi
+ if [[ $cand_limit_reached ]]; then
+ [[ :$opts: != *:no-bell:* ]] &&
+ ble/widget/.bell 'complete: limit reached'
+ if [[ $cand_limit_reached == cancel ]]; then
+ ble/edit/info/default
+ return 1
+ fi
+ fi
+ if ((ext!=0||cand_count==0)); then
+ [[ :$opts: != *:no-bell:* && ! $cand_limit_reached ]] &&
+ ble/widget/.bell 'complete: no completions'
+ ble/edit/info/default
+ return 1
+ fi
+ fi
+ if [[ :$opts: == *:insert_common:* ]]; then
+ ble/complete/insert-common; return "$?"
+ elif [[ :$opts: == *:insert_braces:* ]]; then
+ ble/complete/insert-braces; return "$?"
+ elif [[ :$opts: == *:insert_all:* ]]; then
+ ble/complete/insert-all; return "$?"
+ elif [[ :$opts: == *:enter_menu:* ]]; then
+ local menu_common_part=$COMPV
+ ble/complete/menu/show "$menu_show_opts" || return "$?"
+ ble/complete/menu-complete/enter "$opts"; local ext=$?
+ ((ext==148)) && return 148
+ ((ext)) && [[ :$opts: != *:no-bell:* ]] &&
+ ble/widget/.bell 'menu-complete: no completions'
+ return 0
+ elif [[ :$opts: == *:show_menu:* ]]; then
+ local menu_common_part=$COMPV
+ ble/complete/menu/show "$menu_show_opts"
+ return "$?" # exit status of ble/complete/menu/show
+ fi
+ ble/complete/insert-common; return "$?"
+}
+function ble/widget/complete-insert {
+ local original=$1 insert=$2 suffix=$3
+ [[ ${_ble_edit_str::_ble_edit_ind} == *"$original" ]] || return 1
+ local insert_beg=$((_ble_edit_ind-${#original}))
+ local insert_end=$_ble_edit_ind
+ ble/complete/insert "$insert_beg" "$insert_end" "$insert" "$suffix"
+}
+function ble/widget/menu-complete {
+ local opts=$1
+ ble/widget/complete enter_menu:$opts
+}
+function ble/complete/menu-filter/.filter-candidates {
+ cand_pack=()
+ local iloop=0 interval=$bleopt_complete_polling_cycle
+ local filter_type pack "${_ble_complete_cand_varnames[@]/%/=}" # #D1570 WA checked
+ for filter_type in head substr hsubseq subseq; do
+ ble/path#remove-glob comp_type '[maA]'
+ case $filter_type in
+ (substr) comp_type=${comp_type}:m ;;
+ (hsubseq) comp_type=${comp_type}:a ;;
+ (subseq) comp_type=${comp_type}:A ;;
+ esac
+ local comp_filter_type
+ local comp_filter_pattern
+ ble/complete/candidates/filter#init "$filter_type" "$COMPV"
+ for pack in "${_ble_complete_menu0_pack[@]}"; do
+ ((iloop++%interval==0)) && ble/complete/check-cancel && return 148
+ ble/complete/cand/unpack "$pack"
+ ble/complete/candidates/filter#test "$CAND" &&
+ ble/array#push cand_pack "$pack"
+ done
+ ((${#cand_pack[@]}!=0)) && return 0
+ done
+}
+function ble/complete/menu-filter/.get-filter-target {
+ if [[ $_ble_decode_keymap == emacs || $_ble_decode_keymap == vi_[ic]map ]]; then
+ ret=$_ble_edit_str
+ elif [[ $_ble_decode_keymap == auto_complete ]]; then
+ ret=${_ble_edit_str::_ble_edit_ind}${_ble_edit_str:_ble_edit_mark}
+ else
+ return 1
+ fi
+}
+function ble/complete/menu-filter {
+ [[ $_ble_decode_keymap == menu_complete ]] && return 0
+ local ret; ble/complete/menu-filter/.get-filter-target || return 1; local str=$ret
+ local beg end; ble/complete/menu/get-active-range "$str" "$_ble_edit_ind" || return 1
+ local input=${str:beg:end-beg}
+ [[ $input == "${_ble_complete_menu_comp[2]}" ]] && return 0
+ local simple_flags simple_ibrace
+ if ! ble/syntax:bash/simple-word/reconstruct-incomplete-word "$input"; then
+ ble/syntax:bash/simple-word/is-never-word "$input" && return 1
+ return 0
+ fi
+ [[ $simple_ibrace ]] && ((${simple_ibrace%%:*}>10#0${_ble_complete_menu0_comp[6]%%:*})) && return 1 # 別のブレース展開要素に入った時
+ ble/syntax:bash/simple-word/eval "$ret" single; (($?==148)) && return 148
+ local COMPV=$ret
+ local comp_type=${_ble_complete_menu0_comp[4]} cand_pack
+ ble/complete/menu-filter/.filter-candidates; (($?==148)) && return 148
+ local menu_common_part=$COMPV
+ ble/complete/menu/show filter || return "$?"
+ _ble_complete_menu_comp=("$beg" "$end" "$input" "$COMPV" "$comp_type")
+ return 0
+}
+function ble/complete/menu-filter.idle {
+ ble/util/idle.wait-user-input
+ [[ $bleopt_complete_menu_filter ]] || return 1
+ [[ $_ble_complete_menu_active ]] || return 1
+ ble/complete/menu-filter; local ext=$?
+ ((ext==148)) && return 148
+ ((ext)) && ble/complete/menu/clear
+ return 0
+}
+function ble/highlight/layer/buff#operate-gflags {
+ local BUFF=$1 beg=$2 end=$3 mask=$4 gflags=$5
+ ((beg<end)) || return 1
+ if [[ $mask == auto ]]; then
+ mask=0
+ ((gflags&(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask))) &&
+ ((mask|=_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask))
+ ((gflags&(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask))) &&
+ ((mask|=_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask))
+ fi
+ local i g ret
+ for ((i=beg;i<end;i++)); do
+ ble/highlight/layer/update/getg "$i"
+ ((g=g&~mask|gflags))
+ ble/color/g2sgr "$g"
+ builtin eval -- "$BUFF[$i]=\$ret\${_ble_highlight_layer_plain_buff[$i]}"
+ done
+}
+function ble/highlight/layer/buff#set-explicit-sgr {
+ local BUFF=$1 index=$2
+ builtin eval "((index<\${#$BUFF[@]}))" || return 1
+ local g; ble/highlight/layer/update/getg "$index"
+ local ret; ble/color/g2sgr "$g"
+ builtin eval "$BUFF[index]=\$ret\${_ble_highlight_layer_plain_buff[index]}"
+}
+ble/color/defface menu_filter_fixed bold
+ble/color/defface menu_filter_input fg=16,bg=229
+_ble_highlight_layer_menu_filter_buff=()
+_ble_highlight_layer_menu_filter_beg=
+_ble_highlight_layer_menu_filter_end=
+function ble/highlight/layer:menu_filter/update {
+ local text=$1 player=$2
+ local obeg=$_ble_highlight_layer_menu_filter_beg
+ local oend=$_ble_highlight_layer_menu_filter_end
+ if [[ $obeg ]] && ((DMIN>=0)); then
+ ((DMAX0<=obeg?(obeg+=DMAX-DMAX0):(DMIN<obeg&&(obeg=DMIN)),
+ DMAX0<=oend?(oend+=DMAX-DMAX0):(DMIN<oend&&(oend=DMIN))))
+ fi
+ _ble_highlight_layer_menu_filter_beg=$obeg
+ _ble_highlight_layer_menu_filter_end=$oend
+ local beg= end= ret
+ if [[ $bleopt_complete_menu_filter && $_ble_complete_menu_active && ${#_ble_complete_menu_icons[@]} -gt 0 ]]; then
+ ble/complete/menu-filter/.get-filter-target && local str=$ret &&
+ ble/complete/menu/get-active-range "$str" "$_ble_edit_ind" &&
+ [[ ${str:beg:end-beg} != "${_ble_complete_menu0_comp[2]}" ]] || beg= end=
+ fi
+ [[ ! $obeg && ! $beg ]] && return 0
+ ((PREV_UMIN<0)) && [[ $beg == "$obeg" && $end == "$oend" ]] &&
+ PREV_BUFF=_ble_highlight_layer_menu_filter_buff && return 0
+ local umin=$PREV_UMIN umax=$PREV_UMAX
+ if [[ $beg ]]; then
+ ble/color/face2g menu_filter_fixed; local gF=$ret
+ ble/color/face2g menu_filter_input; local gI=$ret
+ local mid=$_ble_complete_menu0_end
+ ((mid<beg?(mid=beg):(end<mid&&(mid=end))))
+ local buff_name=_ble_highlight_layer_menu_filter_buff
+ builtin eval "$buff_name=(\"\${$PREV_BUFF[@]}\")"
+ ble/highlight/layer/buff#operate-gflags "$buff_name" "$beg" "$mid" auto "$gF"
+ ble/highlight/layer/buff#operate-gflags "$buff_name" "$mid" "$end" auto "$gI"
+ ble/highlight/layer/buff#set-explicit-sgr "$buff_name" "$end"
+ PREV_BUFF=$buff_name
+ if [[ $obeg ]]; then :
+ ble/highlight/layer:region/.update-dirty-range "$beg" "$obeg"
+ ble/highlight/layer:region/.update-dirty-range "$end" "$oend"
+ else
+ ble/highlight/layer:region/.update-dirty-range "$beg" "$end"
+ fi
+ else
+ if [[ $obeg ]]; then
+ ble/highlight/layer:region/.update-dirty-range "$obeg" "$oend"
+ fi
+ fi
+ _ble_highlight_layer_menu_filter_beg=$beg
+ _ble_highlight_layer_menu_filter_end=$end
+ ((PREV_UMIN=umin,PREV_UMAX=umax))
+}
+function ble/highlight/layer:menu_filter/getg {
+ local index=$1
+ local obeg=$_ble_highlight_layer_menu_filter_beg
+ local oend=$_ble_highlight_layer_menu_filter_end
+ local mid=$_ble_complete_menu0_end
+ if [[ $obeg ]] && ((obeg<=index&&index<oend)); then
+ local ret
+ if ((index<mid)); then
+ ble/color/face2g menu_filter_fixed; local g0=$ret
+ else
+ ble/color/face2g menu_filter_input; local g0=$ret
+ fi
+ ble/highlight/layer/update/getg "$index"
+ ble/color/g.append "$g0"
+ fi
+}
+_ble_complete_menu_filter_enabled=
+if ble/is-function ble/util/idle.push-background; then
+ _ble_complete_menu_filter_enabled=1
+ ble/util/idle.push -n 9999 ble/complete/menu-filter.idle
+ ble/array#insert-before _ble_highlight_layer__list region menu_filter
+fi
+_ble_complete_menu_original=
+function ble/complete/menu-complete/select {
+ ble/complete/menu#select "$@"
+}
+function ble/complete/menu-complete/enter {
+ ((${#_ble_complete_menu_icons[@]}>=1)) || return 1
+ local beg end; ble/complete/menu/get-active-range || return 1
+ local opts=$1
+ _ble_edit_mark=$beg
+ _ble_edit_ind=$end
+ local comps_fixed=${_ble_complete_menu0_comp[6]}
+ if [[ $comps_fixed ]]; then
+ local comps_fixed_length=${comps_fixed%%:*}
+ ((_ble_edit_mark+=comps_fixed_length))
+ fi
+ _ble_complete_menu_original=${_ble_edit_str:beg:end-beg}
+ ble/complete/menu/redraw
+ if [[ :$opts: == *:backward:* ]]; then
+ ble/complete/menu#select $((${#_ble_complete_menu_items[@]}-1))
+ else
+ ble/complete/menu#select 0
+ fi
+ _ble_edit_mark_active=insert
+ ble/decode/keymap/push menu_complete
+ return 0
+}
+function ble/widget/menu_complete/exit {
+ local opts=$1
+ ble/decode/keymap/pop
+ if ((_ble_complete_menu_selected>=0)); then
+ local new=${_ble_edit_str:_ble_complete_menu0_beg:_ble_edit_ind-_ble_complete_menu0_beg}
+ local old=$_ble_complete_menu_original
+ local comp_text=${_ble_edit_str::_ble_complete_menu0_beg}$old${_ble_edit_str:_ble_edit_ind}
+ local insert_beg=$_ble_complete_menu0_beg
+ local insert_end=$((_ble_complete_menu0_beg+${#old}))
+ local insert=$new
+ local insert_flags=
+ local suffix=
+ if [[ :$opts: == *:complete:* ]]; then
+ local icon=${_ble_complete_menu_icons[_ble_complete_menu_selected-_ble_complete_menu_offset]}
+ local icon_data=${icon#*:} icon_fields
+ ble/string#split icon_fields , "${icon%%:*}"
+ local pack=${icon_data::icon_fields[4]}
+ local ACTION=${pack%%:*}
+ if ble/is-function ble/complete/action:"$ACTION"/complete; then
+ local COMP1=${_ble_complete_menu0_comp[0]}
+ local COMP2=${_ble_complete_menu0_comp[1]}
+ local COMPS=${_ble_complete_menu0_comp[2]}
+ local COMPV=${_ble_complete_menu0_comp[3]}
+ local comp_type=${_ble_complete_menu0_comp[4]}
+ local comps_flags=${_ble_complete_menu0_comp[5]}
+ local comps_fixed=${_ble_complete_menu0_comp[6]}
+ local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
+ ble/complete/cand/unpack "$pack"
+ ble/complete/action:"$ACTION"/complete
+ fi
+ ble/complete/insert "$_ble_complete_menu0_beg" "$_ble_edit_ind" "$insert" "$suffix"
+ fi
+ blehook/invoke complete_insert
+ fi
+ ble/complete/menu/clear
+ _ble_edit_mark_active=
+ _ble_complete_menu_original=
+}
+function ble/widget/menu_complete/cancel {
+ ble/decode/keymap/pop
+ ble/complete/menu#select -1
+ _ble_edit_mark_active=
+ _ble_complete_menu_original=
+}
+function ble/widget/menu_complete/accept {
+ ble/widget/menu_complete/exit complete
+}
+function ble/widget/menu_complete/exit-default {
+ ble/widget/menu_complete/exit
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+}
+function ble-decode/keymap:menu_complete/define {
+ ble-bind -f __default__ 'menu_complete/exit-default'
+ ble-bind -f __line_limit__ nop
+ ble-bind -f C-m 'menu_complete/accept'
+ ble-bind -f RET 'menu_complete/accept'
+ ble-bind -f C-g 'menu_complete/cancel'
+ ble-bind -f 'C-x C-g' 'menu_complete/cancel'
+ ble-bind -f 'C-M-g' 'menu_complete/cancel'
+ ble-bind -f C-f 'menu/forward-column'
+ ble-bind -f right 'menu/forward-column'
+ ble-bind -f C-i 'menu/forward cyclic'
+ ble-bind -f TAB 'menu/forward cyclic'
+ ble-bind -f C-b 'menu/backward-column'
+ ble-bind -f left 'menu/backward-column'
+ ble-bind -f C-S-i 'menu/backward cyclic'
+ ble-bind -f S-TAB 'menu/backward cyclic'
+ ble-bind -f C-n 'menu/forward-line'
+ ble-bind -f down 'menu/forward-line'
+ ble-bind -f C-p 'menu/backward-line'
+ ble-bind -f up 'menu/backward-line'
+ ble-bind -f prior 'menu/backward-page'
+ ble-bind -f next 'menu/forward-page'
+ ble-bind -f home 'menu/beginning-of-page'
+ ble-bind -f end 'menu/end-of-page'
+}
+function ble/complete/auto-complete/initialize {
+ local ret
+ ble-decode-kbd/generate-keycode auto_complete_enter
+ _ble_complete_KCODE_ENTER=$ret
+}
+ble/complete/auto-complete/initialize
+function ble/highlight/layer:region/mark:auto_complete/get-face {
+ face=auto_complete
+}
+_ble_complete_ac_type=
+_ble_complete_ac_comp1=
+_ble_complete_ac_cand=
+_ble_complete_ac_word=
+_ble_complete_ac_insert=
+_ble_complete_ac_suffix=
+function ble/complete/auto-complete/.search-history-light {
+ [[ $_ble_history_prefix ]] && return 1
+ local text=$1
+ [[ ! $text ]] && return 1
+ local wordbreaks="<>();&|:$_ble_term_IFS"
+ local word= expand
+ if [[ $text != [-0-9#?!]* ]]; then
+ word=${text%%[$wordbreaks]*}
+ command='!'$word ble/util/assign expand 'ble/edit/hist_expanded/.core' &>/dev/null || return 1
+ if [[ $expand == "$text"* ]]; then
+ ret=$expand
+ return 0
+ fi
+ fi
+ if [[ $word != "$text" ]]; then
+ local fragments; ble/string#split fragments '?' "$text"
+ local frag longest_fragments len=0; longest_fragments=('')
+ for frag in "${fragments[@]}"; do
+ local len1=${#frag}
+ ((len1>len&&(len=len1))) && longest_fragments=()
+ ((len1==len)) && ble/array#push longest_fragments "$frag"
+ done
+ for frag in "${longest_fragments[@]}"; do
+ command='!?'$frag ble/util/assign expand 'ble/edit/hist_expanded/.core' &>/dev/null || return 1
+ [[ $expand == "$text"* ]] || continue
+ ret=$expand
+ return 0
+ done
+ fi
+ return 1
+}
+_ble_complete_ac_history_needle=
+_ble_complete_ac_history_index=
+_ble_complete_ac_history_start=
+function ble/complete/auto-complete/.search-history-heavy {
+ local text=$1
+ local count; ble/history/get-count -v count
+ local start=$((count-1))
+ local index=$((count-1))
+ local needle=$text
+ ((start==_ble_complete_ac_history_start)) &&
+ [[ $needle == "$_ble_complete_ac_history_needle"* ]] &&
+ index=$_ble_complete_ac_history_index
+ local isearch_time=0 isearch_ntask=1
+ local isearch_opts=head
+ [[ :$comp_type: == *:sync:* ]] || isearch_opts=$isearch_opts:stop_check
+ ble/history/isearch-backward-blockwise "$isearch_opts"; local ext=$?
+ _ble_complete_ac_history_start=$start
+ _ble_complete_ac_history_index=$index
+ _ble_complete_ac_history_needle=$needle
+ ((ext)) && return "$ext"
+ ble/history/get-edited-entry -v ret "$index"
+ return 0
+}
+function ble/complete/auto-complete/.enter-auto-complete-mode {
+ _ble_complete_ac_type=$type
+ _ble_complete_ac_comp1=$COMP1
+ _ble_complete_ac_cand=$cand
+ _ble_complete_ac_word=$word
+ _ble_complete_ac_insert=$insert
+ _ble_complete_ac_suffix=$suffix
+ _ble_edit_mark_active=auto_complete
+ ble/decode/keymap/push auto_complete
+ ble-decode-key "$_ble_complete_KCODE_ENTER" # dummy key input to record keyboard macros
+}
+function ble/complete/auto-complete/.insert {
+ local insert=$1
+ ble-edit/content/replace-limited "$_ble_edit_ind" "$_ble_edit_ind" "$insert" nobell
+ ((_ble_edit_mark=_ble_edit_ind+${#insert}))
+}
+function ble/complete/auto-complete/.check-history {
+ local opts=$1
+ local searcher=.search-history-heavy
+ [[ :$opts: == *:light:* ]] && searcher=.search-history-light
+ local ret
+ ((_ble_edit_ind==${#_ble_edit_str})) || return 1
+ ble/complete/auto-complete/"$searcher" "$_ble_edit_str" || return "$?" # 0, 1 or 148
+ local word=$ret cand=
+ local COMP1=0 COMPS=$_ble_edit_str
+ [[ $word == "$COMPS" ]] && return 1
+ local insert=$word suffix=
+ local type=h
+ ble/complete/auto-complete/.insert "${insert:${#COMPS}}"
+ ble/complete/auto-complete/.enter-auto-complete-mode
+ return 0
+}
+function ble/complete/auto-complete/.check-context {
+ local sources
+ ble/complete/context:syntax/generate-sources "$comp_text" "$comp_index" &&
+ ble/complete/context/filter-prefix-sources || return 1
+ local bleopt_complete_contract_function_names=
+ local bleopt_complete_menu_style=$bleopt_complete_menu_style # source local settings
+ ((bleopt_complete_polling_cycle>25)) &&
+ local bleopt_complete_polling_cycle=25
+ local COMP1 COMP2 COMPS COMPV
+ local comps_flags comps_fixed
+ local cand_count cand_cand cand_word cand_pack
+ local cand_limit_reached=
+ ble/complete/candidates/generate; local ext=$?
+ [[ $COMPV ]] || return 1
+ ((ext)) && return "$ext"
+ ((cand_count)) || return 1
+ local word=${cand_word[0]} cand=${cand_cand[0]}
+ [[ $word == "$COMPS" ]] && return 1
+ local insert=$word suffix=
+ local ACTION=${cand_pack[0]%%:*}
+ if ble/is-function ble/complete/action:"$ACTION"/complete; then
+ local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
+ ble/complete/cand/unpack "${cand_pack[0]}"
+ ble/complete/action:"$ACTION"/complete
+ fi
+ local type=
+ if [[ $insert == "$COMPS"* ]]; then
+ [[ ${comp_text:COMP1} == "$insert"* ]] && return 1
+ type=c
+ ble/complete/auto-complete/.insert "${insert:${#COMPS}}"
+ else
+ case :$comp_type: in
+ (*:a:*) type=a ;;
+ (*:m:*) type=m ;;
+ (*:A:*) type=A ;;
+ (*) type=r ;;
+ esac
+ ble/complete/auto-complete/.insert " [$insert] "
+ fi
+ ble/complete/auto-complete/.enter-auto-complete-mode
+ return 0
+}
+function ble/complete/auto-complete.impl {
+ local opts=$1
+ local comp_type=auto
+ [[ :$opts: == *:sync:* ]] && comp_type=${comp_type}:sync
+ local comp_text=$_ble_edit_str comp_index=$_ble_edit_ind
+ [[ $comp_text ]] || return 0
+ if local beg end; ble/complete/menu/get-active-range "$_ble_edit_str" "$_ble_edit_ind"; then
+ ((_ble_edit_ind<end)) && return 0
+ fi
+ if [[ $bleopt_complete_auto_history ]]; then
+ ble/complete/auto-complete/.check-history light; local ext=$?
+ ((ext==0||ext==148)) && return "$ext"
+ [[ $_ble_history_prefix || $_ble_history_load_done ]] &&
+ ble/complete/auto-complete/.check-history; local ext=$?
+ ((ext==0||ext==148)) && return "$ext"
+ fi
+ ble/complete/auto-complete/.check-context
+}
+function ble/complete/auto-complete.idle {
+ ble/util/idle.wait-user-input
+ [[ $bleopt_complete_auto_complete ]] || return 1
+ [[ $_ble_decode_keymap == emacs || $_ble_decode_keymap == vi_[ic]map ]] || return 0
+ case $_ble_decode_widget_last in
+ (ble/widget/self-insert) ;;
+ (ble/widget/complete) ;;
+ (ble/widget/vi_imap/complete) ;;
+ (*) return 0 ;;
+ esac
+ [[ $_ble_edit_str ]] || return 0
+ ble/util/idle.sleep-until $((_idle_clock_start+bleopt_complete_auto_delay)) checked && return 0
+ ble/complete/auto-complete.impl
+}
+function ble/complete/auto-menu.idle {
+ ble/util/idle.wait-user-input
+ [[ $_ble_complete_menu_active ]] && return 0
+ ((bleopt_complete_auto_menu>0)) || return 1
+ case $_ble_decode_widget_last in
+ (ble/widget/self-insert) ;;
+ (ble/widget/complete) ;;
+ (ble/widget/vi_imap/complete) ;;
+ (ble/widget/auto_complete/self-insert) ;;
+ (*) return 0 ;;
+ esac
+ [[ $_ble_edit_str ]] || return 0
+ local until=$((_idle_clock_start+bleopt_complete_auto_menu))
+ ble/util/idle.sleep-until "$until" checked && return 0
+ ble/widget/complete auto_menu:show_menu:no-empty:no-bell
+}
+ble/function#try ble/util/idle.push-background ble/complete/auto-complete.idle
+ble/function#try ble/util/idle.push-background ble/complete/auto-menu.idle
+function ble/widget/auto-complete-enter {
+ ble/complete/auto-complete.impl sync
+}
+function ble/widget/auto_complete/cancel {
+ ble/decode/keymap/pop
+ ble-edit/content/replace "$_ble_edit_ind" "$_ble_edit_mark" ''
+ _ble_edit_mark=$_ble_edit_ind
+ _ble_edit_mark_active=
+ _ble_complete_ac_insert=
+ _ble_complete_ac_suffix=
+}
+function ble/widget/auto_complete/insert {
+ ble/decode/keymap/pop
+ ble-edit/content/replace "$_ble_edit_ind" "$_ble_edit_mark" ''
+ _ble_edit_mark=$_ble_edit_ind
+ local comp_text=$_ble_edit_str
+ local insert_beg=$_ble_complete_ac_comp1
+ local insert_end=$_ble_edit_ind
+ local insert=$_ble_complete_ac_insert
+ local suffix=$_ble_complete_ac_suffix
+ ble/complete/insert "$insert_beg" "$insert_end" "$insert" "$suffix"
+ blehook/invoke complete_insert
+ _ble_edit_mark_active=
+ _ble_complete_ac_insert=
+ _ble_complete_ac_suffix=
+ ble/complete/menu/clear
+ ble-edit/content/clear-arg
+ return 0
+}
+function ble/widget/auto_complete/cancel-default {
+ ble/widget/auto_complete/cancel
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+}
+function ble/widget/auto_complete/self-insert {
+ local code; ble/widget/self-insert/.get-code
+ ((code==0)) && return 0
+ local ret
+ ble/util/c2s "$code"; local ins=$ret
+ local comps_cur=${_ble_edit_str:_ble_complete_ac_comp1:_ble_edit_ind-_ble_complete_ac_comp1}
+ local comps_new=$comps_cur$ins
+ local processed=
+ if [[ $_ble_complete_ac_type == [ch] ]]; then
+ if [[ $_ble_complete_ac_word == "$comps_new"* ]]; then
+ ((_ble_edit_ind+=${#ins}))
+ [[ ! $_ble_complete_ac_word ]] && ble/widget/auto_complete/cancel
+ processed=1
+ fi
+ elif [[ $_ble_complete_ac_type == [rmaA] && $ins != [{,}] ]]; then
+ if local ret simple_flags simple_ibrace; ble/syntax:bash/simple-word/reconstruct-incomplete-word "$comps_new"; then
+ if ble/complete/source/eval-simple-word "$ret" single && local compv_new=$ret; then
+ local filter_type=head
+ case $_ble_complete_ac_type in
+ (*m*) filter_type=substr ;;
+ (*a*) filter_type=hsubseq ;;
+ (*A*) filter_type=subseq ;;
+ esac
+ local comps_fixed=
+ local comp_filter_type
+ local comp_filter_pattern
+ ble/complete/candidates/filter#init "$filter_type" "$compv_new"
+ if ble/complete/candidates/filter#test "$_ble_complete_ac_cand"; then
+ local insert; ble-edit/content/replace-limited "$_ble_edit_ind" "$_ble_edit_ind" "$ins"
+ ((_ble_edit_ind+=${#insert},_ble_edit_mark+=${#insert}))
+ [[ $_ble_complete_ac_cand == "$compv_new" ]] &&
+ ble/widget/auto_complete/cancel
+ processed=1
+ fi
+ fi
+ fi
+ fi
+ if [[ $processed ]]; then
+ local comp_text= insert_beg=0 insert_end=0 insert=$ins suffix=
+ blehook/invoke complete_insert
+ return 0
+ else
+ ble/widget/auto_complete/cancel
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+ fi
+}
+function ble/widget/auto_complete/insert-on-end {
+ if ((_ble_edit_mark==${#_ble_edit_str})); then
+ ble/widget/auto_complete/insert
+ else
+ ble/widget/auto_complete/cancel-default
+ fi
+}
+function ble/widget/auto_complete/insert-word {
+ local breaks=${bleopt_complete_auto_wordbreaks:-$_ble_term_IFS}
+ local rex='^['$breaks']*([^'$breaks']+['$breaks']*)?'
+ if [[ $_ble_complete_ac_type == [ch] ]]; then
+ local ins=${_ble_edit_str:_ble_edit_ind:_ble_edit_mark-_ble_edit_ind}
+ [[ $ins =~ $rex ]]
+ if [[ $BASH_REMATCH == "$ins" ]]; then
+ ble/widget/auto_complete/insert
+ return 0
+ else
+ local ins=$BASH_REMATCH
+ ((_ble_edit_ind+=${#ins}))
+ local comp_text=$_ble_edit_str
+ local insert_beg=$_ble_complete_ac_comp1
+ local insert_end=$_ble_edit_ind
+ local insert=${_ble_edit_str:insert_beg:insert_end-insert_beg}$ins
+ local suffix=
+ blehook/invoke complete_insert
+ return 0
+ fi
+ elif [[ $_ble_complete_ac_type == [rmaA] ]]; then
+ local ins=$_ble_complete_ac_insert
+ [[ $ins =~ $rex ]]
+ if [[ $BASH_REMATCH == "$ins" ]]; then
+ ble/widget/auto_complete/insert
+ return 0
+ else
+ local ins=$BASH_REMATCH
+ _ble_complete_ac_type=c
+ ble-edit/content/replace "$_ble_complete_ac_comp1" "$_ble_edit_mark" "$_ble_complete_ac_insert"
+ ((_ble_edit_ind=_ble_complete_ac_comp1+${#ins},
+ _ble_edit_mark=_ble_complete_ac_comp1+${#_ble_complete_ac_insert}))
+ local comp_text=$_ble_edit_str
+ local insert_beg=$_ble_complete_ac_comp1
+ local insert_end=$_ble_edit_ind
+ local insert=$ins
+ local suffix=
+ blehook/invoke complete_insert
+ return 0
+ fi
+ fi
+ return 1
+}
+function ble/widget/auto_complete/accept-line {
+ ble/widget/auto_complete/insert
+ ble-decode-key 13
+}
+function ble/widget/auto_complete/notify-enter {
+ ble/decode/widget/skip-lastwidget
+}
+function ble-decode/keymap:auto_complete/define {
+ ble-bind -f __defchar__ auto_complete/self-insert
+ ble-bind -f __default__ auto_complete/cancel-default
+ ble-bind -f __line_limit__ nop
+ ble-bind -f 'C-g' auto_complete/cancel
+ ble-bind -f 'C-x C-g' auto_complete/cancel
+ ble-bind -f 'C-M-g' auto_complete/cancel
+ ble-bind -f S-RET auto_complete/insert
+ ble-bind -f S-C-m auto_complete/insert
+ ble-bind -f C-f auto_complete/insert-on-end
+ ble-bind -f right auto_complete/insert-on-end
+ ble-bind -f C-e auto_complete/insert-on-end
+ ble-bind -f end auto_complete/insert-on-end
+ ble-bind -f M-f auto_complete/insert-word
+ ble-bind -f M-right auto_complete/insert-word
+ ble-bind -f C-j auto_complete/accept-line
+ ble-bind -f C-RET auto_complete/accept-line
+ ble-bind -f auto_complete_enter auto_complete/notify-enter
+}
+function ble/complete/sabbrev/.initialize-print {
+ sgr0= sgr1= sgr2= sgr3= sgro=
+ if [[ $flags == *c* || $flags != *n* && -t 1 ]]; then
+ local ret
+ ble/color/face2sgr command_function; sgr1=$ret
+ ble/color/face2sgr syntax_varname; sgr2=$ret
+ ble/color/face2sgr syntax_quoted; sgr3=$ret
+ ble/color/face2sgr argument_option; sgro=$ret
+ sgr0=$_ble_term_sgr0
+ fi
+}
+function ble/complete/sabbrev/.print-definition {
+ local key=$1 type=${2%%:*} value=${2#*:}
+ local option=
+ [[ $type == m ]] && option=$sgro'-m'$sgr0' '
+ local ret
+ ble/string#quote-word "$key" quote-empty:sgrq="$sgr3":sgr0="$sgr2"
+ key=$sgr2$ret$sgr0
+ ble/string#quote-word "$value" sgrq="$sgr3":sgr0="$sgr0"
+ value=$ret
+ ble/util/print "${sgr1}ble-sabbrev$sgr0 $option$key=$value"
+}
+function ble/complete/sabbrev/register {
+ local key=$1 value=$2
+ ble/gdict#set _ble_complete_sabbrev "$key" "$value"
+}
+function ble/complete/sabbrev/list {
+ local keys ret; keys=("$@")
+ if ((${#keys[@]}==0)); then
+ ble/gdict#keys _ble_complete_sabbrev
+ keys=("${ret[@]}")
+ ((${#keys[@]})) || return 0
+ fi
+ local sgr0 sgr1 sgr2 sgr3 sgro
+ ble/complete/sabbrev/.initialize-print
+ local key ext=0
+ for key in "${keys[@]}"; do
+ if ble/gdict#get _ble_complete_sabbrev "$key"; then
+ ble/complete/sabbrev/.print-definition "$key" "$ret"
+ else
+ ble/util/print "ble-sabbrev: $key: not found." >&2
+ ext=1
+ fi
+ done
+ return "$ext"
+}
+function ble/complete/sabbrev/reset {
+ if (($#)); then
+ local key
+ for key; do
+ ble/gdict#unset _ble_complete_sabbrev "$key"
+ done
+ else
+ ble/gdict#clear _ble_complete_sabbrev
+ fi
+ return 0
+}
+function ble/complete/sabbrev/get {
+ local key=$1
+ ble/gdict#get _ble_complete_sabbrev "$key"
+}
+function ble/complete/sabbrev/get-keys {
+ local ret
+ ble/gdict#keys _ble_complete_sabbrev
+ keys=("${ret[@]}")
+}
+function ble/complete/sabbrev/read-arguments {
+ while (($#)); do
+ local arg=$1; shift
+ if [[ $arg == ?*=* ]]; then
+ ble/array#push specs "s:$arg"
+ else
+ case $arg in
+ (--help)
+ flags=H$flags ;;
+ (--reset)
+ flags=r$flags
+ (--color|--color=always)
+ flags=c${flags//[cn]} ;;
+ (--color=never)
+ flags=n${flags//[cn]} ;;
+ (--color=auto)
+ flags=${flags//[cn]} ;;
+ (-*)
+ local i n=${#arg} c
+ for ((i=1;i<n;i++)); do
+ c=${arg:i:1}
+ case $c in
+ (m)
+ if ((!$#)); then
+ ble/util/print "ble-sabbrev: option argument for '-$c' is missing" >&2
+ flags=E$flags
+ elif [[ $1 != ?*=* ]]; then
+ ble/util/print "ble-sabbrev: invalid option argument '-$c $1' (expected form: '-$c key=value')" >&2
+ flags=E$flags
+ else
+ ble/array#push specs "$c:$1"; shift
+ fi ;;
+ (r)
+ flags=r$flags ;;
+ (*)
+ ble/util/print "ble-sabbrev: unknown option '-$c'." >&2
+ flags=E$flags ;;
+ esac
+ done ;;
+ (*)
+ ble/array#push print "$arg" ;;
+ esac
+ fi
+ done
+}
+function ble-sabbrev {
+ local -a specs=() print=()
+ local flags=
+ ble/complete/sabbrev/read-arguments "$@"
+ if [[ $flags == *H* || $flags == *E* ]]; then
+ [[ $flags == *E* ]] && ble/util/print
+ ble/util/print-lines \
+ 'usage: ble-sabbrev [KEY=VALUE|-m KEY=FUNCTION]...' \
+ 'usage: ble-sabbrev [-r|--reset] [KEY...]' \
+ 'usage: ble-sabbrev --help' \
+ ' Register sabbrev expansion.'
+ [[ ! $flags == *E* ]]; return "$?"
+ fi
+ local ext=0
+ if ((${#specs[@]}==0||${#print[@]})); then
+ if [[ $flags == *r* ]]; then
+ ble/complete/sabbrev/reset "${print[@]}"
+ else
+ ble/complete/sabbrev/list "${print[@]}"
+ fi || ext=$?
+ fi
+ local spec key type value
+ for spec in "${specs[@]}"; do
+ type=${spec::1} spec=${spec:2}
+ key=${spec%%=*} value=${spec#*=}
+ ble/complete/sabbrev/register "$key" "$type:$value"
+ done
+ return "$ext"
+}
+function ble/complete/sabbrev/expand {
+ local sources comp_index=$_ble_edit_ind comp_text=$_ble_edit_str
+ ble/complete/context:syntax/generate-sources
+ local src asrc pos=$comp_index
+ for src in "${sources[@]}"; do
+ ble/string#split-words asrc "$src"
+ case ${asrc[0]} in
+ (file|command|argument|variable:w|wordlist:*|sabbrev)
+ ((asrc[1]<pos)) && pos=${asrc[1]} ;;
+ esac
+ done
+ ((pos<comp_index)) || return 1
+ local key=${_ble_edit_str:pos:comp_index-pos}
+ local ret; ble/complete/sabbrev/get "$key" || return 1
+ local type=${ret%%:*} value=${ret#*:}
+ case $type in
+ (s)
+ ble/widget/.replace-range "$pos" "$comp_index" "$value"
+ ((_ble_edit_ind=pos+${#value})) ;;
+ (m)
+ local comp_type= comps_flags= comps_fixed=
+ local COMP1=$pos COMP2=$pos COMPS=$key COMPV=
+ ble/complete/candidates/comp_type#read-rl-variables
+ local flag_force_fignore=
+ local flag_source_filter=1
+ local cand_count cand_cand cand_word cand_pack
+ ble/complete/candidates/clear
+ local COMP_PREFIX=
+ local bleopt_sabbrev_menu_style=$bleopt_complete_menu_style
+ local bleopt_sabbrev_menu_opts=
+ local -a COMPREPLY=()
+ builtin eval -- "$value"
+ local cand action=word "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ for cand in "${COMPREPLY[@]}"; do
+ ble/complete/cand/yield "$action" "$cand" ""
+ done
+ if ((cand_count==0)); then
+ return 1
+ elif ((cand_count==1)); then
+ local value=${cand_word[0]}
+ ble/widget/.replace-range "$pos" "$comp_index" "$value"
+ ((_ble_edit_ind=pos+${#value}))
+ return 0
+ fi
+ ble/widget/.replace-range "$pos" "$comp_index" ''
+ local bleopt_complete_menu_style=$bleopt_sabbrev_menu_style
+ local menu_common_part=
+ ble/complete/menu/show || return "$?"
+ [[ :$bleopt_sabbrev_menu_opts: == *:enter_menu:* ]] &&
+ ble/complete/menu-complete/enter
+ return 147 ;;
+ (*) return 1 ;;
+ esac
+ return 0
+}
+function ble/widget/sabbrev-expand {
+ if ! ble/complete/sabbrev/expand; then
+ ble/widget/.bell
+ return 1
+ fi
+}
+function ble/complete/action:sabbrev/initialize { CAND=$value; }
+function ble/complete/action:sabbrev/complete { :; }
+function ble/complete/action:sabbrev/init-menu-item {
+ local ret; ble/color/face2g command_alias; g=$ret
+ show=$INSERT
+}
+function ble/complete/action:sabbrev/get-desc {
+ local ret; ble/complete/sabbrev/get "$INSERT"
+ desc="$desc_sgrt(sabbrev)$desc_sgr0 $ret"
+}
+function ble/complete/source:sabbrev {
+ local keys; ble/complete/sabbrev/get-keys
+ local filter_type=$comp_filter_type
+ [[ $filter_type == none ]] && filter_type=head
+ local comps_fixed=
+ local comp_filter_type
+ local comp_filter_pattern
+ ble/complete/candidates/filter#init "$filter_type" "$COMPS"
+ local cand action=sabbrev "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ for cand in "${keys[@]}"; do
+ ble/complete/candidates/filter#test "$cand" || continue
+ local ret simple_flags simple_ibrace
+ ble/syntax:bash/simple-word/reconstruct-incomplete-word "$cand" &&
+ ble/complete/source/eval-simple-word "$ret" single || continue
+ local value=$ret # referenced in "ble/complete/action:sabbrev/initialize"
+ local flag_source_filter=1
+ ble/complete/cand/yield "$action" "$cand"
+ done
+}
+_ble_complete_dabbrev_original=
+_ble_complete_dabbrev_regex1=
+_ble_complete_dabbrev_regex2=
+_ble_complete_dabbrev_index=
+_ble_complete_dabbrev_pos=
+_ble_complete_dabbrev_stack=()
+function ble/complete/dabbrev/.show-status.fib {
+ local index='!'$((_ble_complete_dabbrev_index+1))
+ local nmatch=${#_ble_complete_dabbrev_stack[@]}
+ local needle=$_ble_complete_dabbrev_original
+ local text="(dabbrev#$nmatch: << $index) \`$needle'"
+ local pos=$1
+ if [[ $pos ]]; then
+ local count; ble/history/get-count
+ local percentage=$((count?pos*1000/count:1000))
+ text="$text searching... @$pos ($((percentage/10)).$((percentage%10))%)"
+ fi
+ ((fib_ntask)) && text="$text *$fib_ntask"
+ ble/edit/info/show text "$text"
+}
+function ble/complete/dabbrev/show-status {
+ local fib_ntask=${#_ble_util_fiberchain[@]}
+ ble/complete/dabbrev/.show-status.fib
+}
+function ble/complete/dabbrev/erase-status {
+ ble/edit/info/default
+}
+function ble/complete/dabbrev/initialize-variables {
+ local wordbreaks; ble/complete/get-wordbreaks
+ _ble_complete_dabbrev_wordbreaks=$wordbreaks
+ local left=${_ble_edit_str::_ble_edit_ind}
+ local original=${left##*[$wordbreaks]}
+ local p1=$((_ble_edit_ind-${#original})) p2=$_ble_edit_ind
+ _ble_edit_mark=$p1
+ _ble_edit_ind=$p2
+ _ble_complete_dabbrev_original=$original
+ local ret; ble/string#escape-for-extended-regex "$original"
+ local needle='(^|['$wordbreaks'])'$ret
+ _ble_complete_dabbrev_regex1=$needle
+ _ble_complete_dabbrev_regex2='('$needle'[^'$wordbreaks']*).*'
+ local index; ble/history/get-index
+ _ble_complete_dabbrev_index=$index
+ _ble_complete_dabbrev_pos=${#_ble_edit_str}
+ _ble_complete_dabbrev_stack=()
+}
+function ble/complete/dabbrev/reset {
+ local original=$_ble_complete_dabbrev_original
+ ble-edit/content/replace "$_ble_edit_mark" "$_ble_edit_ind" "$original"
+ ((_ble_edit_ind=_ble_edit_mark+${#original}))
+ _ble_edit_mark_active=
+}
+function ble/complete/dabbrev/search-in-history-entry {
+ local line=$1 index=$2
+ local index_editing; ble/history/get-index -v index_editing
+ if ((index!=index_editing)); then
+ local pos=$dabbrev_pos
+ while [[ ${line:pos} && ${line:pos} =~ $_ble_complete_dabbrev_regex2 ]]; do
+ local rematch1=${BASH_REMATCH[1]} rematch2=${BASH_REMATCH[2]}
+ local match=${rematch1:${#rematch2}}
+ if [[ $match && $match != "$dabbrev_current_match" ]]; then
+ dabbrev_match=$match
+ dabbrev_match_pos=$((${#line}-${#BASH_REMATCH}+${#match}))
+ return 0
+ else
+ ((pos++))
+ fi
+ done
+ fi
+ return 1
+}
+function ble/complete/dabbrev/.search.fib {
+ if [[ ! $fib_suspend ]]; then
+ local start=$_ble_complete_dabbrev_index
+ local index=$_ble_complete_dabbrev_index
+ local pos=$_ble_complete_dabbrev_pos
+ ((--start>=0)) || ble/history/get-count -v start
+ else
+ local start index pos; builtin eval -- "$fib_suspend"
+ fib_suspend=
+ fi
+ local dabbrev_match=
+ local dabbrev_pos=$pos
+ local dabbrev_current_match=${_ble_edit_str:_ble_edit_mark:_ble_edit_ind-_ble_edit_mark}
+ local line; ble/history/get-edited-entry -v line "$index"
+ if ! ble/complete/dabbrev/search-in-history-entry "$line" "$index"; then
+ ((index--,dabbrev_pos=0))
+ local isearch_time=0
+ local isearch_opts=stop_check:cyclic
+ isearch_opts=$isearch_opts:condition
+ local dabbrev_original=$_ble_complete_dabbrev_original
+ local dabbrev_regex1=$_ble_complete_dabbrev_regex1
+ local needle='[[ $LINE =~ $dabbrev_regex1 ]] && ble/complete/dabbrev/search-in-history-entry "$LINE" "$INDEX"'
+ [[ $dabbrev_original ]] && needle='[[ $LINE == *"$dabbrev_original"* ]] && '$needle
+ isearch_opts=$isearch_opts:progress
+ local isearch_progress_callback=ble/complete/dabbrev/.show-status.fib
+ ble/history/isearch-backward-blockwise "$isearch_opts"; local ext=$?
+ ((ext==148)) && fib_suspend="start=$start index=$index pos=$pos"
+ if ((ext)); then
+ if ((${#_ble_complete_dabbrev_stack[@]})); then
+ ble/widget/.bell # 周回したので鳴らす
+ return 0
+ else
+ return "$ext"
+ fi
+ fi
+ fi
+ local rec=$_ble_complete_dabbrev_index,$_ble_complete_dabbrev_pos,$_ble_edit_ind,$_ble_edit_mark
+ ble/array#push _ble_complete_dabbrev_stack "$rec:$_ble_edit_str"
+ local insert; ble-edit/content/replace-limited "$_ble_edit_mark" "$_ble_edit_ind" "$dabbrev_match"
+ ((_ble_edit_ind=_ble_edit_mark+${#insert}))
+ ((index>_ble_complete_dabbrev_index)) &&
+ ble/widget/.bell # 周回
+ _ble_complete_dabbrev_index=$index
+ _ble_complete_dabbrev_pos=$dabbrev_match_pos
+ ble/textarea#redraw
+}
+function ble/complete/dabbrev/next.fib {
+ ble/complete/dabbrev/.search.fib; local ext=$?
+ if ((ext==0)); then
+ _ble_edit_mark_active=insert
+ ble/complete/dabbrev/.show-status.fib
+ elif ((ext==148)); then
+ ble/complete/dabbrev/.show-status.fib
+ else
+ ble/widget/.bell
+ ble/widget/dabbrev/exit
+ ble/complete/dabbrev/reset
+ fib_kill=1
+ fi
+ return "$ext"
+}
+function ble/widget/dabbrev-expand {
+ ble/complete/dabbrev/initialize-variables
+ ble/decode/keymap/push dabbrev
+ ble/util/fiberchain#initialize ble/complete/dabbrev
+ ble/util/fiberchain#push next
+ ble/util/fiberchain#resume
+}
+function ble/widget/dabbrev/next {
+ ble/util/fiberchain#push next
+ ble/util/fiberchain#resume
+}
+function ble/widget/dabbrev/prev {
+ if ((${#_ble_util_fiberchain[@]})); then
+ local ret; ble/array#pop _ble_util_fiberchain
+ if ((${#_ble_util_fiberchain[@]})); then
+ ble/util/fiberchain#resume
+ else
+ ble/complete/dabbrev/show-status
+ fi
+ elif ((${#_ble_complete_dabbrev_stack[@]})); then
+ local ret; ble/array#pop _ble_complete_dabbrev_stack
+ local rec str=${ret#*:}
+ ble/string#split rec , "${ret%%:*}"
+ ble-edit/content/reset-and-check-dirty "$str"
+ _ble_edit_ind=${rec[2]}
+ _ble_edit_mark=${rec[3]}
+ _ble_complete_dabbrev_index=${rec[0]}
+ _ble_complete_dabbrev_pos=${rec[1]}
+ ble/complete/dabbrev/show-status
+ else
+ ble/widget/.bell
+ return 1
+ fi
+}
+function ble/widget/dabbrev/cancel {
+ if ((${#_ble_util_fiberchain[@]})); then
+ ble/util/fiberchain#clear
+ ble/complete/dabbrev/show-status
+ else
+ ble/widget/dabbrev/exit
+ ble/complete/dabbrev/reset
+ fi
+}
+function ble/widget/dabbrev/exit {
+ ble/decode/keymap/pop
+ _ble_edit_mark_active=
+ ble/complete/dabbrev/erase-status
+}
+function ble/widget/dabbrev/exit-default {
+ ble/widget/dabbrev/exit
+ ble/decode/widget/skip-lastwidget
+ ble/decode/widget/redispatch-by-keys "${KEYS[@]}"
+}
+function ble/widget/dabbrev/accept-line {
+ ble/widget/dabbrev/exit
+ ble-decode-key 13
+}
+function ble-decode/keymap:dabbrev/define {
+ ble-bind -f __default__ 'dabbrev/exit-default'
+ ble-bind -f __line_limit__ nop
+ ble-bind -f 'C-g' 'dabbrev/cancel'
+ ble-bind -f 'C-x C-g' 'dabbrev/cancel'
+ ble-bind -f 'C-M-g' 'dabbrev/cancel'
+ ble-bind -f C-r 'dabbrev/next'
+ ble-bind -f C-s 'dabbrev/prev'
+ ble-bind -f RET 'dabbrev/exit'
+ ble-bind -f C-m 'dabbrev/exit'
+ ble-bind -f C-RET 'dabbrev/accept-line'
+ ble-bind -f C-j 'dabbrev/accept-line'
+}
+function ble/complete/action:cdpath/initialize {
+ DATA=$cdpath_basedir
+ ble/complete/action:file/initialize
+}
+function ble/complete/action:cdpath/complete {
+ CAND=$DATA$CAND ble/complete/action:file/complete
+}
+function ble/complete/action:cdpath/init-menu-item {
+ ble/color/face2g cmdinfo_cd_cdpath; g=$ret
+ if [[ :$comp_type: == *:vstat:* ]]; then
+ if [[ -h $CAND ]]; then
+ suffix='@'
+ elif [[ -d $CAND ]]; then
+ suffix='/'
+ fi
+ fi
+}
+function ble/complete/action:cdpath/get-desc {
+ local sgr0=$_ble_term_sgr0 sgr1= sgr2=
+ local g ret g1 g2
+ ble/syntax/highlight/getg-from-filename "$DATA$CAND"; g1=$g
+ [[ $g1 ]] || { ble/color/face2g filename_warning; g1=$ret; }
+ ((g2=g1^_ble_color_gflags_Revert))
+ ble/color/g2sgr "$g1"; sgr1=$ret
+ ble/color/g2sgr "$g2"; sgr2=$ret
+ ble/string#escape-for-display "$DATA$CAND" sgr1="$sgr2":sgr0="$sgr1"
+ local filename=$sgr1$ret$sgr0
+ CAND=$DATA$CAND ble/complete/action:file/get-desc
+ desc="CDPATH $filename ($desc)"
+}
+function ble/cmdinfo/complete:cd/.impl {
+ local type=$1
+ [[ $comps_flags == *v* ]] || return 1
+ if [[ $COMPV == -* ]]; then
+ local action=word
+ case $type in
+ (pushd)
+ if [[ $COMPV == - || $COMPV == -n ]]; then
+ local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ ble/complete/cand/yield "$action" -n
+ fi ;;
+ (*)
+ COMP_PREFIX=$COMPV
+ local -a list=()
+ local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe
+ ble/complete/cand/yield.initialize "$action"
+ [[ $COMPV == -* ]] && ble/complete/cand/yield "$action" "${COMPV}"
+ [[ $COMPV != *L* ]] && ble/complete/cand/yield "$action" "${COMPV}L"
+ [[ $COMPV != *P* ]] && ble/complete/cand/yield "$action" "${COMPV}P"
+ ((_ble_bash>=40200)) && [[ $COMPV != *e* ]] && ble/complete/cand/yield "$action" "${COMPV}e"
+ ((_ble_bash>=40300)) && [[ $COMPV != *@* ]] && ble/complete/cand/yield "$action" "${COMPV}@" ;;
+ esac
+ return 0
+ fi
+ [[ :$comp_type: != *:[maA]:* && $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]}
+ [[ :$comp_type: == *:[maA]:* && ! $COMPV ]] && return 1
+ if [[ ! $CDPATH ]]; then
+ ble/complete/source:dir
+ return "$?"
+ fi
+ ble/complete/source:tilde; local ext=$?
+ ((ext==148||ext==0)) && return "$ext"
+ local is_pwd_visited= is_cdpath_generated=
+ "${_ble_util_set_declare[@]//NAME/visited}" # WA #D1570 checked
+ local name names; ble/string#split names : "$CDPATH"
+ for name in "${names[@]}"; do
+ [[ $name ]] || continue
+ name=${name%/}/
+ local action=cdpath
+ [[ ${name%/} == . || ${name%/} == "${PWD%/}" ]] &&
+ is_pwd_visited=1 action=file
+ local -a candidates=()
+ local ret cand
+ ble/complete/source:file/.construct-pathname-pattern "$COMPV"
+ ble/complete/util/eval-pathname-expansion "$name$ret"; (($?==148)) && return 148
+ ble/complete/source/test-limit ${#ret[@]} || return 1
+ for cand in "${ret[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) &&
+ ble/complete/check-cancel && return 148
+ [[ $cand && -d $cand ]] || continue
+ [[ $cand == / ]] || cand=${cand%/}
+ cand=${cand#"$name"}
+ ble/set#contains visited "$cand" && continue
+ ble/set#add visited "$cand"
+ ble/array#push candidates "$cand"
+ done
+ ((${#candidates[@]})) || continue
+ local flag_source_filter=1
+ local cdpath_basedir=$name
+ ble/complete/cand/yield-filenames "$action" "${candidates[@]}"
+ [[ $action == cdpath ]] && is_cdpath_generated=1
+ done
+ [[ $is_cdpath_generated ]] &&
+ bleopt complete_menu_style=desc
+ if [[ ! $is_pwd_visited ]]; then
+ local -a candidates=()
+ local ret cand
+ ble/complete/source:file/.construct-pathname-pattern "$COMPV"
+ ble/complete/util/eval-pathname-expansion "${ret%/}/"; (($?==148)) && return 148
+ ble/complete/source/test-limit ${#ret[@]} || return 1
+ for cand in "${ret[@]}"; do
+ ((cand_iloop++%bleopt_complete_polling_cycle==0)) &&
+ ble/complete/check-cancel && return 148
+ [[ -d $cand ]] || continue
+ [[ $cand == / ]] || cand=${cand%/}
+ ble/set#contains visited "$cand" && continue
+ ble/array#push candidates "$cand"
+ done
+ local flag_source_filter=1
+ ble/complete/cand/yield-filenames file "${candidates[@]}"
+ fi
+}
+function ble/cmdinfo/complete:cd {
+ ble/cmdinfo/complete:cd/.impl cd
+}
+function ble/cmdinfo/complete:pushd {
+ ble/cmdinfo/complete:cd/.impl pushd
+}
+blehook/invoke complete_load
+blehook complete_load=
+return 0
diff --git a/.local/src/blesh/lib/core-decode.emacs-rlfunc.txt b/.local/src/blesh/lib/core-decode.emacs-rlfunc.txt
new file mode 100644
index 0000000..e0dbffd
--- /dev/null
+++ b/.local/src/blesh/lib/core-decode.emacs-rlfunc.txt
@@ -0,0 +1,170 @@
+abort bell
+accept-line accept-line
+alias-expand-line alias-expand-line
+arrow-key-prefix -
+backward-byte @nomarked backward-byte
+backward-char @nomarked backward-char
+backward-delete-char delete-region-or delete-backward-char
+backward-kill-line kill-backward-line
+backward-kill-word kill-backward-cword
+backward-word @nomarked backward-cword
+beginning-of-history history-beginning
+beginning-of-line @nomarked beginning-of-line
+bracketed-paste-begin bracketed-paste
+call-last-kbd-macro call-keyboard-macro
+capitalize-word capitalize-eword
+character-search character-search-forward
+character-search-backward character-search-backward
+clear-display clear-display
+clear-screen clear-screen
+complete complete
+complete-command complete context=command
+complete-filename complete context=filename
+complete-hostname complete context=hostname
+complete-into-braces complete insert_braces
+complete-username complete context=username
+complete-variable complete context=variable
+copy-backward-word copy-backward-cword
+copy-forward-word copy-forward-cword
+copy-region-as-kill copy-region
+dabbrev-expand dabbrev-expand
+delete-char delete-forward-char
+delete-char-or-list delete-forward-char-or-list
+delete-horizontal-space delete-horizontal-space
+digit-argument append-arg
+display-shell-version display-shell-version
+do-lowercase-version do-lowercase-version
+downcase-word downcase-eword
+dump-functions readline-dump-functions
+dump-macros readline-dump-macros
+dump-variables readline-dump-variables
+dynamic-complete-history complete context=dynamic-history
+edit-and-execute-command edit-and-execute-command
+emacs-editing-mode nop
+end-kbd-macro end-keyboard-macro
+end-of-history history-end
+end-of-line end-of-line
+exchange-point-and-mark exchange-point-and-mark
+forward-backward-delete-char delete-forward-backward-char
+forward-byte @nomarked forward-byte
+forward-char @nomarked forward-char
+forward-search-history history-isearch-forward
+forward-word @nomarked forward-cword
+glob-complete-word complete context=glob
+glob-expand-word complete context=glob:insert-all
+glob-list-expansions complete context=glob:show_menu
+history-and-alias-expand-line history-and-alias-expand-line
+history-expand-line history-expand-line
+history-search-backward history-search-backward empty=emulate-readline
+history-search-forward history-search-forward empty=emulate-readline
+history-substring-search-backward history-substring-search-backward
+history-substring-search-forward history-substring-search-forward
+insert-comment insert-comment
+insert-completions complete insert_all
+insert-last-argument insert-last-argument
+kill-line kill-forward-line
+kill-region kill-region-or kill-uword
+kill-whole-line kill-line
+kill-word kill-forward-cword
+magic-space magic-space
+menu-complete menu-complete
+menu-complete-backward menu-complete backward
+next-history history-next
+next-screen-line @nomarked forward-graphical-line
+non-incremental-forward-search-history history-nsearch-forward
+non-incremental-forward-search-history-again history-nsearch-forward-again
+non-incremental-reverse-search-history history-nsearch-backward
+non-incremental-reverse-search-history-again history-nsearch-backward-again
+old-menu-complete menu-complete
+operate-and-get-next accept-and-next
+overwrite-mode overwrite-mode
+possible-command-completions complete show_menu:context=command
+possible-completions complete show_menu
+possible-filename-completions complete show_menu:context=filename
+possible-hostname-completions complete show_menu:context=hostname
+possible-username-completions complete show_menu:context=username
+possible-variable-completions complete show_menu:context=variable
+previous-history history-prev
+previous-screen-line @nomarked backward-graphical-line
+print-last-kbd-macro print-keyboard-macro
+quoted-insert quoted-insert
+re-read-init-file re-read-init-file
+redraw-current-line redraw-line
+reverse-search-history history-isearch-backward
+revert-line emacs/revert
+self-insert self-insert
+set-mark set-mark
+shell-backward-kill-word kill-backward-sword
+shell-backward-word @nomarked backward-sword
+shell-expand-line shell-expand-line
+shell-forward-word @nomarked forward-sword
+shell-kill-word kill-forward-sword
+shell-transpose-words transpose-swords
+skip-csi-sequence <IGNORE>
+start-kbd-macro start-keyboard-macro
+tab-insert tab-insert
+tilde-expand tilde-expand
+transpose-chars transpose-chars
+transpose-words transpose-ewords
+tty-status -
+undo emacs/undo
+universal-argument universal-arg
+unix-filename-rubout kill-backward-fword
+unix-line-discard kill-backward-line
+unix-word-rubout kill-backward-uword
+upcase-word upcase-eword
+vi-append-eol -
+vi-append-mode -
+vi-arg-digit -
+vi-prev-word vi-rlfunc/prev-word
+vi-backward-word vi-command/backward-vword
+vi-backward-bigword vi-command/backward-uword
+vi-bword vi-command/backward-vword
+vi-bWord vi-command/backward-uword
+vi-end-word vi-rlfunc/end-word
+vi-end-bigword vi-command/forward-uword-end
+vi-eword vi-command/forward-vword-end
+vi-eWord vi-command/forward-uword-end
+vi-next-word vi-rlfunc/next-word
+vi-forward-word vi-command/forward-vword
+vi-forward-bigword vi-command/forward-uword
+vi-fword vi-command/forward-vword
+vi-fWord vi-command/forward-uword
+vi-back-to-indent -
+vi-change-case -
+vi-change-char -
+vi-change-to -
+vi-char-search -
+vi-column -
+vi-complete -
+vi-delete -
+vi-delete-to -
+vi-editing-mode vi-editing-mode
+vi-eof-maybe -
+vi-fetch-history -
+vi-first-print -
+vi-goto-mark -
+vi-insert-beg -
+vi-insertion-mode -
+vi-match -
+vi-movement-mode -
+vi-overstrike -
+vi-overstrike-delete -
+vi-put -
+vi-redo -
+vi-replace -
+vi-rubout -
+vi-search -
+vi-search-again -
+vi-set-mark -
+vi-subst -
+vi-tilde-expand -
+vi-unix-word-rubout -
+vi-yank-arg -
+vi-yank-pop -
+vi-yank-to -
+yank yank
+yank-last-arg insert-last-argument
+yank-nth-arg insert-nth-argument
+yank-pop yank-pop
+paste-from-clipboard paste-from-clipboard
diff --git a/.local/src/blesh/lib/core-decode.vi_imap-rlfunc.txt b/.local/src/blesh/lib/core-decode.vi_imap-rlfunc.txt
new file mode 100644
index 0000000..8b4dfac
--- /dev/null
+++ b/.local/src/blesh/lib/core-decode.vi_imap-rlfunc.txt
@@ -0,0 +1,169 @@
+abort bell
+accept-line accept-single-line-or-newline
+alias-expand-line alias-expand-line
+arrow-key-prefix -
+backward-byte @nomarked backward-byte
+backward-char @nomarked backward-char
+backward-delete-char vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char
+backward-kill-line kill-backward-line
+backward-kill-word kill-backward-uword
+backward-word @nomarked backward-sword
+beginning-of-history history-beginning
+beginning-of-line @nomarked beginning-of-line
+bracketed-paste-begin vi_imap/bracketed-paste
+call-last-kbd-macro call-keyboard-macro
+capitalize-word capitalize-eword
+character-search character-search-forward
+character-search-backward character-search-backward
+clear-display clear-display
+clear-screen clear-screen
+complete complete
+complete-command complete context=command
+complete-filename complete context=filename
+complete-hostname complete context=hostname
+complete-into-braces complete insert_braces
+complete-username complete context=username
+complete-variable complete context=variable
+copy-backward-word copy-backward-sword
+copy-forward-word copy-forward-sword
+copy-region-as-kill copy-region-or copy-uword
+dabbrev-expand dabbrev-expand
+delete-char vi_imap/delete-region-or delete-forward-char
+delete-char-or-list delete-forward-char-or-list
+delete-horizontal-space delete-horizontal-space
+digit-argument append-arg
+display-shell-version display-shell-version
+do-lowercase-version do-lowercase-version
+downcase-word downcase-eword
+dump-functions readline-dump-functions
+dump-macros readline-dump-macros
+dump-variables readline-dump-variables
+dynamic-complete-history complete context=dynamic-history
+edit-and-execute-command edit-and-execute-command
+emacs-editing-mode emacs-editing-mode
+end-kbd-macro end-keyboard-macro
+end-of-history history-end
+end-of-line @nomarked end-of-line
+exchange-point-and-mark exchange-point-and-mark
+forward-backward-delete-char delete-forward-backward-char
+forward-byte @nomarked forward-byte
+forward-char @nomarked forward-char
+forward-search-history history-isearch-forward
+forward-word @nomarked forward-uword
+glob-complete-word complete context=glob
+glob-expand-word complete context=glob:insert-all
+glob-list-expansions complete context=glob:show_menu
+history-and-alias-expand-line history-and-alias-expand-line
+history-expand-line history-expand-line
+history-search-backward history-search-backward empty=emulate-readline
+history-search-forward history-search-forward empty=emulate-readline
+history-substring-search-backward history-substring-search-backward
+history-substring-search-forward history-substring-search-forward
+insert-comment insert-comment
+insert-completions complete insert_all
+insert-last-argument insert-last-argument
+kill-line kill-forward-line
+kill-region kill-region-or kill-uword
+kill-whole-line kill-line
+kill-word kill-forward-uword
+magic-space magic-space
+menu-complete menu-complete
+menu-complete-backward menu-complete backward
+next-history history-next
+next-screen-line @nomarked forward-graphical-line
+non-incremental-forward-search-history history-nsearch-forward
+non-incremental-forward-search-history-again history-nsearch-forward-again
+non-incremental-reverse-search-history history-nsearch-backward
+non-incremental-reverse-search-history-again history-nsearch-backward-again
+old-menu-complete menu-complete
+operate-and-get-next accept-and-next
+overwrite-mode vi_imap/overwrite-mode
+possible-command-completions complete show_menu:context=command
+possible-completions complete show_menu
+possible-filename-completions complete show_menu:context=filename
+possible-hostname-completions complete show_menu:context=hostname
+possible-username-completions complete show_menu:context=username
+possible-variable-completions complete show_menu:context=variable
+previous-history history-prev
+previous-screen-line @nomarked backward-graphical-line
+print-last-kbd-macro print-keyboard-macro
+quoted-insert vi_imap/quoted-insert
+re-read-init-file re-read-init-file
+redraw-current-line redraw-line
+reverse-search-history history-isearch-backward
+revert-line -
+self-insert self-insert
+set-mark set-mark
+shell-backward-kill-word kill-backward-sword
+shell-backward-word @nomarked backward-sword
+shell-expand-line shell-expand-line
+shell-forward-word @nomarked forward-sword
+shell-kill-word kill-forward-sword
+shell-transpose-words transpose-swords
+skip-csi-sequence <IGNORE>
+start-kbd-macro start-keyboard-macro
+tab-insert tab-insert
+tilde-expand tilde-expand
+transpose-chars transpose-chars
+transpose-words transpose-ewords
+tty-status -
+undo -
+universal-argument universal-arg
+unix-filename-rubout kill-backward-fword
+unix-line-discard kill-backward-line
+unix-word-rubout kill-backward-uword
+upcase-word upcase-eword
+vi-append-eol -
+vi-append-mode -
+vi-arg-digit -
+vi-back-to-indent -
+vi-prev-word vi-rlfunc/prev-word
+vi-backward-word vi-command/backward-vword
+vi-backward-bigword vi-command/backward-uword
+vi-bword vi-command/backward-vword
+vi-bWord vi-command/backward-uword
+vi-end-word vi-rlfunc/end-word
+vi-end-bigword vi-command/forward-uword-end
+vi-eword vi-command/forward-vword-end
+vi-eWord vi-command/forward-uword-end
+vi-next-word vi-rlfunc/next-word
+vi-forward-word vi-command/forward-vword
+vi-forward-bigword vi-command/forward-uword
+vi-fword vi-command/forward-vword
+vi-fWord vi-command/forward-uword
+vi-change-case -
+vi-change-char -
+vi-change-to -
+vi-char-search -
+vi-column -
+vi-complete -
+vi-delete -
+vi-delete-to -
+vi-editing-mode nop
+vi-eof-maybe -
+vi-fetch-history -
+vi-first-print -
+vi-goto-mark -
+vi-insert-beg -
+vi-insertion-mode nop
+vi-match -
+vi-movement-mode vi_imap/normal-mode
+vi-overstrike -
+vi-overstrike-delete -
+vi-put -
+vi-redo -
+vi-replace vi_imap/overwrite-mode
+vi-rubout -
+vi-search -
+vi-search-again -
+vi-set-mark -
+vi-subst -
+vi-tilde-expand -
+vi-unix-word-rubout vi_imap/delete-backward-word
+vi-yank-arg -
+vi-yank-pop -
+vi-yank-to -
+yank yank
+yank-last-arg insert-last-argument
+yank-nth-arg insert-nth-argument
+yank-pop yank-pop
diff --git a/.local/src/blesh/lib/core-decode.vi_nmap-rlfunc.txt b/.local/src/blesh/lib/core-decode.vi_nmap-rlfunc.txt
new file mode 100644
index 0000000..a3db96d
--- /dev/null
+++ b/.local/src/blesh/lib/core-decode.vi_nmap-rlfunc.txt
@@ -0,0 +1,170 @@
+abort bell
+accept-line accept-single-line-or vi-command/forward-first-non-space
+alias-expand-line vi_nmap/@edit alias-expand-line
+arrow-key-prefix -
+backward-byte vi-command/backward-byte
+backward-char vi-command/backward-char
+backward-delete-char -
+backward-kill-line -
+backward-kill-word -
+backward-word vi-command/backward-vword
+beginning-of-history -
+beginning-of-line vi-command/beginning-of-line
+bracketed-paste-begin vi-command/bracketed-paste
+call-last-kbd-macro call-keyboard-macro
+capitalize-word vi_nmap/capitalize-eword
+character-search vi_nmap/@motion character-search-forward
+character-search-backward vi_nmap/@motion character-search-backward
+clear-display clear-display
+clear-screen clear-screen
+complete -
+complete-command -
+complete-filename -
+complete-hostname -
+complete-into-braces -
+complete-username -
+complete-variable -
+copy-backward-word -
+copy-forward-word -
+copy-region-as-kill -
+dabbrev-expand -
+delete-char vi_nmap/kill-forward-char
+delete-char-or-list -
+delete-horizontal-space -
+digit-argument vi-command/append-arg
+display-shell-version vi_nmap/@adjust display-shell-version
+do-lowercase-version do-lowercase-version
+downcase-word vi_nmap/downcase-eword
+dump-functions vi_nmap/@adjust readline-dump-functions
+dump-macros vi_nmap/@adjust readline-dump-macros
+dump-variables vi_nmap/@adjust readline-dump-variables
+dynamic-complete-history -
+edit-and-execute-command vi-command/edit-and-execute-line
+emacs-editing-mode emacs-editing-mode
+end-kbd-macro end-keyboard-macro
+end-of-history -
+end-of-line vi-command/forward-eol
+exchange-point-and-mark -
+forward-backward-delete-char -
+forward-byte vi-command/forward-byte
+forward-char vi-command/forward-char
+forward-search-history history-isearch-forward
+forward-word vi-command/forward-vword
+glob-complete-word -
+glob-expand-word -
+glob-list-expansions -
+history-and-alias-expand-line vi_nmap/@edit history-and-alias-expand-line
+history-expand-line vi_nmap/@edit history-expand-line
+history-search-backward history-search-backward empty=emulate-readline
+history-search-forward history-search-forward empty=emulate-readline
+history-substring-search-backward history-substring-search-backward
+history-substring-search-forward history-substring-search-forward
+insert-comment vi-rlfunc/insert-comment
+insert-completions -
+insert-last-argument -
+kill-line vi_nmap/kill-forward-line
+kill-region -
+kill-whole-line -
+kill-word vi-rlfunc/kill-word
+magic-space -
+menu-complete -
+menu-complete-backward -
+next-history history-next
+next-screen-line -
+non-incremental-forward-search-history history-nsearch-forward
+non-incremental-forward-search-history-again history-nsearch-forward-again
+non-incremental-reverse-search-history history-nsearch-backward
+non-incremental-reverse-search-history-again history-nsearch-backward-again
+old-menu-complete -
+operate-and-get-next -
+overwrite-mode vi_nmap/replace-mode
+possible-command-completions complete show_menu:context=command
+possible-completions complete show_menu
+possible-filename-completions complete show_menu:context=filename
+possible-hostname-completions complete show_menu:context=hostname
+possible-username-completions complete show_menu:context=username
+possible-variable-completions complete show_menu:context=variable
+previous-history history-prev
+previous-screen-line -
+print-last-kbd-macro print-keyboard-macro
+quoted-insert vi-rlfunc/quoted-insert
+re-read-init-file vi_nmap/@adjust re-read-init-file
+redraw-current-line redraw-line
+reverse-search-history history-isearch-backward
+revert-line vi_nmap/revert
+self-insert -
+set-mark vi_nmap/charwise-visual-mode
+shell-backward-kill-word -
+shell-backward-word -
+shell-expand-line -
+shell-forward-word -
+shell-kill-word -
+shell-transpose-words -
+skip-csi-sequence <IGNORE>
+start-kbd-macro start-keyboard-macro
+tab-insert -
+tilde-expand vi_nmap/@edit tilde-expand
+transpose-chars transpose-chars
+transpose-words -
+tty-status -
+undo vi_nmap/undo
+universal-argument -
+unix-filename-rubout -
+unix-line-discard vi-rlfunc/unix-line-discard
+unix-word-rubout -
+upcase-word vi_nmap/upcase-eword
+vi-append-eol vi_nmap/append-mode-at-end-of-line
+vi-append-mode vi_nmap/append-mode
+vi-arg-digit vi-command/append-arg
+vi-prev-word vi-rlfunc/prev-word
+vi-backward-word vi-command/backward-vword
+vi-backward-bigword vi-command/backward-uword
+vi-bword vi-command/backward-vword
+vi-bWord vi-command/backward-uword
+vi-end-word vi-rlfunc/end-word
+vi-end-bigword vi-command/forward-uword-end
+vi-eword vi-command/forward-vword-end
+vi-eWord vi-command/forward-uword-end
+vi-next-word vi-rlfunc/next-word
+vi-forward-word vi-command/forward-vword
+vi-forward-bigword vi-command/forward-uword
+vi-fword vi-command/forward-vword
+vi-fWord vi-command/forward-uword
+vi-back-to-indent -
+vi-change-case vi-command/operator toggle_case
+vi-change-char vi_nmap/replace-char
+vi-change-to vi-rlfunc/change-to
+vi-char-search vi-rlfunc/char-search
+vi-column vi-command/nth-column
+vi-complete -
+vi-delete vi_nmap/kill-forward-char
+vi-delete-to vi-rlfunc/delete-to
+vi-editing-mode vi_nmap/insert-mode
+vi-eof-maybe vi-rlfunc/eof-maybe
+vi-fetch-history vi-command/history-end
+vi-first-print vi-command/first-non-space
+vi-goto-mark vi-command/goto-mark
+vi-insert-beg vi_nmap/insert-mode-at-first-non-space
+vi-insertion-mode vi_nmap/insert-mode
+vi-match vi-command/search-matchpair-or vi-command/percentage-line
+vi-movement-mode nop
+vi-overstrike -
+vi-overstrike-delete -
+vi-put vi-rlfunc/put
+vi-redo vi_nmap/repeat
+vi-replace vi_nmap/replace-mode
+vi-rubout vi_nmap/kill-backward-char
+vi-search vi-rlfunc/search
+vi-search-again vi-rlfunc/search-again
+vi-set-mark vi-command/set-mark
+vi-subst vi-rlfunc/subst
+vi-tilde-expand -
+vi-undo vi_nmap/undo
+vi-unix-word-rubout -
+vi-yank-arg vi-rlfunc/yank-arg
+vi-yank-pop -
+vi-yank-to vi-rlfunc/yank-to
+yank yank
+yank-last-arg -
+yank-nth-arg -
+yank-pop -
diff --git a/.local/src/blesh/lib/core-edit.ignoreeof-messages.txt b/.local/src/blesh/lib/core-edit.ignoreeof-messages.txt
new file mode 100644
index 0000000..6588f87
--- /dev/null
+++ b/.local/src/blesh/lib/core-edit.ignoreeof-messages.txt
@@ -0,0 +1,32 @@
+Gebruik Kaart na Los Tronk
+Използвайте „exit“, за да излезете от обвивката.
+Utilitzeu ?exit? per a eixir de l'int?rpret d'ordres.
+Shell lze ukončit příkazem „exit“.
+Brug "exit" for at forlade skallen.
+Benutze "exit" um die Shell zu verlassen.
+Χρήση «exit» για έξοδο από το κέλυφος.
+Use “exit” to leave the shell.
+Use “exit” to leave the shell.
+Uzu «exit» por eliri el la ŝelo.
+Use "exit" para dejar el shell.
+Kirjoita ”exit” poistuaksesi komentotulkista.
+Utilisez « exit » pour quitter le shell.
+Úsáid "exit" le scoir den mblaosc.
+Use «exit» para deixar o shell.
+Koristite „exit” za napuštanje ljuske.
+„exit” használatával lehet elhagyni a parancsértelmezőt.
+Gunakan "exit" untuk meninggalkan shell.
+Usare "exit" per uscire dalla shell.
+シェルから脱出するには "exit" を使用してください。
+Naudokite „exit“, jei norite išeiti iš ap.
+Gebruik "exit" om de shell te verlaten.
+Użyj "exit", aby opuścić tę powłokę.
+Use "exit" para sair da `shell'.
+Na opustenie shellu použite „exit“.
+Uporabite "exit", če želite zapustiti lupino.
+Користите „exit“ да напустите шкољку.
+Använd "exit" fär att lämna skalet.
+Kabuğu bırakmak için "exit" kullanın.
+Використовуйте "exit", щоб вийти з оболонки.
+Dùng "exit" để rời hệ vỏ.
+使用 "exit" 退出 shell 。
diff --git a/.local/src/blesh/lib/core-syntax.sh b/.local/src/blesh/lib/core-syntax.sh
new file mode 100644
index 0000000..bd566f9
--- /dev/null
+++ b/.local/src/blesh/lib/core-syntax.sh
@@ -0,0 +1,5355 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+function ble/syntax/util/is-directory {
+ local path=$1
+ if [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $path == //* ]]; then
+ [[ $path == // ]]
+ else
+ [[ -d $path ]]
+ fi
+}
+function ble/syntax/urange#update {
+ local prefix=$1
+ local p1=$2 p2=${3:-$2}
+ ((0<=p1&&p1<p2)) || return 1
+ (((${prefix}umin<0||${prefix}umin>p1)&&(${prefix}umin=p1),
+ (${prefix}umax<0||${prefix}umax<p2)&&(${prefix}umax=p2)))
+}
+function ble/syntax/wrange#update {
+ local prefix=$1
+ local p1=$2 p2=${3:-$2}
+ ((0<=p1&&p1<=p2)) || return 1
+ (((${prefix}umin<0||${prefix}umin>p1)&&(${prefix}umin=p1),
+ (${prefix}umax<0||${prefix}umax<p2)&&(${prefix}umax=p2)))
+}
+function ble/syntax/urange#shift {
+ local prefix=$1
+ ((${prefix}umin>=end0?(${prefix}umin+=shift):(
+ ${prefix}umin>=beg&&(${prefix}umin=end)),
+ ${prefix}umax>end0?(${prefix}umax+=shift):(
+ ${prefix}umax>beg&&(${prefix}umax=beg)),
+ ${prefix}umin>=${prefix}umax&&
+ (${prefix}umin=${prefix}umax=-1)))
+}
+function ble/syntax/wrange#shift {
+ local prefix=$1
+ ((${prefix}umin>=end0?(${prefix}umin+=shift):(
+ ${prefix}umin>beg&&(${prefix}umin=end)),
+ ${prefix}umax>=end0?(${prefix}umax+=shift):(
+ ${prefix}umax>=beg&&(${prefix}umax=beg)),
+ ${prefix}umin==0&&++${prefix}umin,
+ ${prefix}umin>${prefix}umax&&
+ (${prefix}umin=${prefix}umax=-1)))
+}
+_ble_syntax_text=
+_ble_syntax_lang=bash
+_ble_syntax_stat=()
+_ble_syntax_nest=()
+_ble_syntax_tree=()
+_ble_syntax_attr=()
+_ble_syntax_TREE_WIDTH=5
+function ble/syntax/tree-enumerate/.add-root-element {
+ local wtype=$1 wlen=$2 tclen=$3 tplen=$4
+ [[ ! ${wtype//[0-9]} && ${_ble_syntax_bash_command_EndWtype[wtype]} ]] &&
+ wtype=${_ble_syntax_bash_command_EndWtype[wtype]}
+ TE_root="$wtype $wlen $tclen $tplen -- $TE_root"
+}
+function ble/syntax/tree-enumerate/.initialize {
+ if [[ ! ${_ble_syntax_stat[iN]} ]]; then
+ TE_root= TE_i=-1 TE_nofs=0
+ return 0
+ fi
+ local -a stat nest
+ ble/string#split-words stat "${_ble_syntax_stat[iN]}"
+ local wtype=${stat[2]}
+ local wlen=${stat[1]}
+ local nlen=${stat[3]} inest
+ ((inest=nlen<0?nlen:iN-nlen))
+ local tclen=${stat[4]}
+ local tplen=${stat[5]}
+ TE_root=
+ ((iN>0)) && TE_root=${_ble_syntax_tree[iN-1]}
+ while
+ if ((wlen>=0)); then
+ ble/syntax/tree-enumerate/.add-root-element "$wtype" "$wlen" "$tclen" "$tplen"
+ tclen=0
+ fi
+ ((inest>=0))
+ do
+ ble/util/assert '[[ ${_ble_syntax_nest[inest]} ]]' "$FUNCNAME/FATAL1" || break
+ ble/string#split-words nest "${_ble_syntax_nest[inest]}"
+ local olen=$((iN-inest))
+ tplen=${nest[4]}
+ ((tplen>=0&&(tplen+=olen)))
+ ble/syntax/tree-enumerate/.add-root-element "${nest[7]}" "$olen" "$tclen" "$tplen"
+ wtype=${nest[2]} wlen=${nest[1]} nlen=${nest[3]} tclen=0 tplen=${nest[5]}
+ ((wlen>=0&&(wlen+=olen),
+ tplen>=0&&(tplen+=olen),
+ nlen>=0&&(nlen+=olen),
+ inest=nlen<0?nlen:iN-nlen))
+ ble/util/assert '((nlen<0||nlen>olen))' "$FUNCNAME/FATAL2" || break
+ done
+ if [[ $TE_root ]]; then
+ ((TE_i=iN))
+ else
+ ((TE_i=tclen>=0?iN-tclen:tclen))
+ fi
+ ((TE_nofs=0))
+}
+function ble/syntax/tree-enumerate/.impl {
+ local islast=1
+ while ((TE_i>0)); do
+ local -a node
+ if ((TE_i<iN)); then
+ ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}"
+ else
+ ble/string#split-words node "${TE_root:-${_ble_syntax_tree[iN-1]}}"
+ fi
+ ble/util/assert '((TE_nofs<${#node[@]}))' "$FUNCNAME(i=$TE_i,iN=$iN,TE_nofs=$TE_nofs,node=${node[*]},command=$@)/FATAL1" || break
+ local wtype=${node[TE_nofs]} wlen=${node[TE_nofs+1]} tclen=${node[TE_nofs+2]} tplen=${node[TE_nofs+3]} attr=${node[TE_nofs+4]}
+ local wbegin=$((wlen<0?wlen:TE_i-wlen))
+ local tchild=$((tclen<0?tclen:TE_i-tclen))
+ local tprev=$((tplen<0?tplen:TE_i-tplen))
+ "$@"
+ ble/util/assert '((tprev<TE_i))' "$FUNCNAME/FATAL2" || break
+ ((TE_i=tprev,TE_nofs=0,islast=0))
+ done
+}
+function ble/syntax/tree-enumerate-children {
+ ((0<tchild&&tchild<=TE_i)) || return 1
+ local TE_nofs=$((TE_i==tchild?TE_nofs+_ble_syntax_TREE_WIDTH:0))
+ local TE_i=$tchild
+ ble/syntax/tree-enumerate/.impl "$@"
+}
+function ble/syntax/tree-enumerate-break () ((tprev=-1))
+function ble/syntax/tree-enumerate {
+ local TE_root TE_i TE_nofs
+ [[ ${iN:+set} ]] || local iN=${#_ble_syntax_text}
+ ble/syntax/tree-enumerate/.initialize
+ ble/syntax/tree-enumerate/.impl "$@"
+}
+function ble/syntax/tree-enumerate-in-range {
+ local beg=$1 end=$2
+ local proc=$3
+ local -a node
+ local TE_i TE_nofs
+ for ((TE_i=end;TE_i>=beg;TE_i--)); do
+ ((TE_i>0)) && [[ ${_ble_syntax_tree[TE_i-1]} ]] || continue
+ ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}"
+ local flagUpdateNode=
+ for ((TE_nofs=0;TE_nofs<${#node[@]};TE_nofs+=_ble_syntax_TREE_WIDTH)); do
+ local wtype=${node[TE_nofs]} wlen=${node[TE_nofs+1]} wattr=${node[TE_nofs+4]}
+ local wbeg=$((wlen<0?wlen:TE_i-wlen)) wend=$TE_i
+ "${@:3}"
+ done
+ done
+}
+function ble/syntax/print-status/.graph {
+ local char=$1
+ if ble/util/isprint+ "$char"; then
+ graph="'$char'"
+ return 0
+ else
+ local ret
+ ble/util/s2c "$char"
+ local code=$ret
+ if ((code<32)); then
+ ble/util/c2s $((code+64))
+ graph="$_ble_term_rev^$ret$_ble_term_sgr0"
+ elif ((code==127)); then
+ graph="$_ble_term_rev^?$_ble_term_sgr0"
+ elif ((128<=code&&code<160)); then
+ ble/util/c2s $((code-64))
+ graph="${_ble_term_rev}M-^$ret$_ble_term_sgr0"
+ else
+ graph="'$char' ($code)"
+ fi
+ fi
+}
+function ble/syntax/print-status/.tree-prepend {
+ local j=$1
+ local value=$2${tree[j]}
+ tree[j]=$value
+ ((max_tree_width<${#value}&&(max_tree_width=${#value})))
+}
+function ble/syntax/print-status/.dump-arrays/.append-attr-char {
+ if (($?==0)); then
+ attr="${attr}$1"
+ else
+ attr="${attr} "
+ fi
+}
+function ble/syntax/print-status/ctx#get-text {
+ local sgr
+ ble/syntax/ctx#get-name "$1"
+ ret=${ret#BLE_}
+ if [[ ! $ret ]]; then
+ ble/color/face2sgr syntax_error
+ ret="${ret}CTX$1$_ble_term_sgr0"
+ fi
+}
+function ble/syntax/print-status/word.get-text {
+ local index=$1
+ ble/string#split-words word "${_ble_syntax_tree[index]}"
+ local out= ret
+ if [[ $word ]]; then
+ local nofs=$((${#word[@]}/_ble_syntax_TREE_WIDTH*_ble_syntax_TREE_WIDTH))
+ while (((nofs-=_ble_syntax_TREE_WIDTH)>=0)); do
+ local axis=$((index+1))
+ local wtype=${word[nofs]}
+ if [[ $wtype =~ ^[0-9]+$ ]]; then
+ ble/syntax/print-status/ctx#get-text "$wtype"; wtype=$ret
+ elif [[ $wtype =~ ^n* ]]; then
+ wtype=$sgr_quoted\"${wtype:1}\"$_ble_term_sgr0
+ else
+ wtype=$sgr_error${wtype}$_ble_term_sgr0
+ fi
+ local b=$((axis-word[nofs+1])) e=$axis
+ local _prev=${word[nofs+3]} _child=${word[nofs+2]}
+ if ((_prev>=0)); then
+ _prev="@$((axis-_prev-1))>"
+ else
+ _prev=
+ fi
+ if ((_child>=0)); then
+ _child=">@$((axis-_child-1))"
+ else
+ _child=
+ fi
+ local wattr=${word[nofs+4]} _wattr=
+ if [[ $wattr != - ]]; then
+ wattr="/(wattr=$wattr)"
+ else
+ wattr=
+ fi
+ out=" word=$wtype:$_prev$b-$e$_child$wattr$out"
+ for ((;b<index;b++)); do
+ ble/syntax/print-status/.tree-prepend "$b" '|'
+ done
+ ble/syntax/print-status/.tree-prepend "$index" '+'
+ done
+ word=$out
+ fi
+}
+function ble/syntax/print-status/nest.get-text {
+ local index=$1
+ ble/string#split-words nest "${_ble_syntax_nest[index]}"
+ if [[ $nest ]]; then
+ local ret
+ ble/syntax/print-status/ctx#get-text "${nest[0]}"; local nctx=$ret
+ local nword=-
+ if ((nest[1]>=0)); then
+ ble/syntax/print-status/ctx#get-text "${nest[2]}"; local swtype=$ret
+ local wbegin=$((index-nest[1]))
+ nword="$swtype:$wbegin-"
+ fi
+ local nnest=-
+ ((nest[3]>=0)) && nnest="'${nest[7]}':$((index-nest[3]))-"
+ local nchild=-
+ if ((nest[4]>=0)); then
+ local tchild=$((index-nest[4]))
+ nchild='$'$tchild
+ if ! ((0<tchild&&tchild<=index)) || [[ ! ${_ble_syntax_tree[tchild-1]} ]]; then
+ nchild=$sgr_error$nchild$_ble_term_sgr0
+ fi
+ fi
+ local nprev=-
+ if ((nest[5]>=0)); then
+ local tprev=$((index-nest[5]))
+ nprev='$'$tprev
+ if ! ((0<tprev&&tprev<=index)) || [[ ! ${_ble_syntax_tree[tprev-1]} ]]; then
+ nprev=$sgr_error$nprev$_ble_term_sgr0
+ fi
+ fi
+ local nparam=${nest[6]}
+ if [[ $nparam == none ]]; then
+ nparam=
+ else
+ nparam=${nparam//$_ble_term_FS/$'\e[7m^\\\e[m'}
+ nparam=" nparam=$nparam"
+ fi
+ nest=" nest=($nctx w=$nword n=$nnest t=$nchild:$nprev$nparam)"
+ fi
+}
+function ble/syntax/print-status/stat.get-text {
+ local index=$1
+ ble/string#split-words stat "${_ble_syntax_stat[index]}"
+ if [[ $stat ]]; then
+ local ret
+ ble/syntax/print-status/ctx#get-text "${stat[0]}"; local stat_ctx=$ret
+ local stat_word=-
+ if ((stat[1]>=0)); then
+ ble/syntax/print-status/ctx#get-text "${stat[2]}"; local stat_wtype=$ret
+ stat_word="$stat_wtype:$((index-stat[1]))-"
+ fi
+ local stat_inest=-
+ if ((stat[3]>=0)); then
+ local inest=$((index-stat[3]))
+ stat_inest="@$inest"
+ if ((inest<0)) || [[ ! ${_ble_syntax_nest[inest]} ]]; then
+ stat_inest=$sgr_error$stat_inest$_ble_term_sgr0
+ fi
+ fi
+ local stat_child=-
+ if ((stat[4]>=0)); then
+ local tchild=$((index-stat[4]))
+ stat_child='$'$tchild
+ if ! ((0<tchild&&tchild<=index)) || [[ ! ${_ble_syntax_tree[tchild-1]} ]]; then
+ stat_child=$sgr_error$stat_child$_ble_term_sgr0
+ fi
+ fi
+ local stat_prev=-
+ if ((stat[5]>=0)); then
+ local tprev=$((index-stat[5]))
+ stat_prev='$'$tprev
+ if ! ((0<tprev&&tprev<=index)) || [[ ! ${_ble_syntax_tree[tprev-1]} ]]; then
+ stat_prev=$sgr_error$stat_prev$_ble_term_sgr0
+ fi
+ fi
+ local snparam=${stat[6]}
+ if [[ $snparam == none ]]; then
+ snparam=
+ else
+ snparam=${snparam//"$_ble_term_FS"/$'\e[7m^\\\e[m'}
+ snparam=" nparam=$snparam"
+ fi
+ local stat_lookahead=
+ ((stat[7]!=1)) && stat_lookahead=" >>${stat[7]}"
+ stat=" stat=($stat_ctx w=$stat_word n=$stat_inest t=$stat_child:$stat_prev$snparam$stat_lookahead)"
+ fi
+}
+function ble/syntax/print-status/.dump-arrays {
+ local -a tree char line
+ tree=()
+ char=()
+ line=()
+ local ret
+ ble/color/face2sgr syntax_error; local sgr_error=$ret
+ ble/color/face2sgr syntax_quoted; local sgr_quoted=$ret
+ local i max_tree_width=0
+ for ((i=0;i<=iN;i++)); do
+ local attr=" ${_ble_syntax_attr[i]:-|}"
+ if ((_ble_syntax_attr_umin<=i&&i<_ble_syntax_attr_umax)); then
+ attr="${attr:${#attr}-2:2}*"
+ else
+ attr="${attr:${#attr}-2:2} "
+ fi
+ [[ ${_ble_highlight_layer_syntax1_table[i]} ]] && ble/color/g2sgr "${_ble_highlight_layer_syntax1_table[i]}"
+ ble/syntax/print-status/.dump-arrays/.append-attr-char "${ret}a${_ble_term_sgr0}"
+ [[ ${_ble_highlight_layer_syntax2_table[i]} ]] && ble/color/g2sgr "${_ble_highlight_layer_syntax2_table[i]}"
+ ble/syntax/print-status/.dump-arrays/.append-attr-char "${ret}w${_ble_term_sgr0}"
+ [[ ${_ble_highlight_layer_syntax3_table[i]} ]] && ble/color/g2sgr "${_ble_highlight_layer_syntax3_table[i]}"
+ ble/syntax/print-status/.dump-arrays/.append-attr-char "${ret}e${_ble_term_sgr0}"
+ [[ ${_ble_syntax_stat_shift[i]} ]]
+ ble/syntax/print-status/.dump-arrays/.append-attr-char s
+ local index=000$i
+ index=${index:${#index}-3:3}
+ local word nest stat
+ ble/syntax/print-status/word.get-text "$i"
+ ble/syntax/print-status/nest.get-text "$i"
+ ble/syntax/print-status/stat.get-text "$i"
+ local graph=
+ ble/syntax/print-status/.graph "${_ble_syntax_text:i:1}"
+ char[i]="$attr $index $graph"
+ line[i]=$word$nest$stat
+ done
+ resultA='_ble_syntax_attr/tree/nest/stat?'$'\n'
+ ble/string#reserve-prototype "$max_tree_width"
+ for ((i=0;i<=iN;i++)); do
+ local t=${tree[i]}${_ble_string_prototype::max_tree_width}
+ resultA="$resultA${char[i]} ${t::max_tree_width}${line[i]}"$'\n'
+ done
+}
+function ble/syntax/print-status/.dump-tree/proc1 {
+ local tip="| "; tip=${tip:islast:1}
+ prefix="$prefix$tip " ble/syntax/tree-enumerate-children ble/syntax/print-status/.dump-tree/proc1
+ resultB="$prefix\_ '${_ble_syntax_text:wbegin:wlen}'$nl$resultB"
+}
+function ble/syntax/print-status/.dump-tree {
+ resultB=
+ local nl=$_ble_term_nl
+ local prefix=
+ ble/syntax/tree-enumerate ble/syntax/print-status/.dump-tree/proc1
+}
+function ble/syntax/print-status {
+ local iN=${#_ble_syntax_text}
+ local resultA
+ ble/syntax/print-status/.dump-arrays
+ local resultB
+ ble/syntax/print-status/.dump-tree
+ local result=$resultA$resultB
+ if [[ $1 == -v && $2 ]]; then
+ local "${2%%\[*\]}" && ble/util/upvar "$2" "$result"
+ else
+ ble/util/print "$result"
+ fi
+}
+function ble/syntax/print-layer-buffer.draw {
+ local layer_name=$1
+ local -a keys vals
+ builtin eval "keys=(\"\${!_ble_highlight_layer_${layer_name}_buff[@]}\")"
+ builtin eval "vals=(\"\${_ble_highlight_layer_${layer_name}_buff[@]}\")"
+ local ret sgr0=$_ble_term_sgr0
+ ble/color/face2sgr command_builtin; local sgr1=$ret
+ ble/color/face2sgr syntax_varname; local sgr2=$ret
+ ble/color/face2sgr syntax_quoted; local sgr3=$ret
+ ble/canvas/put.draw "${sgr1}buffer${sgr0} ${sgr2}$layer_name${sgr0}=("
+ local i count=0
+ for ((i=0;i<${#keys[@]};i++)); do
+ local key=${keys[i]} val=${vals[i]}
+ while ((count++<key)); do
+ ((count==1)) || ble/canvas/put.draw ' '
+ ble/canvas/put.draw $'\e[91munset\e[m'
+ done
+ ((count==1)) || ble/canvas/put.draw ' '
+ ble/string#quote-word "$val" quote-empty:sgrq="$sgr3"
+ ble/canvas/put.draw "$ret"
+ done
+ ble/canvas/put.draw ")$_ble_term_nl"
+}
+function ble/syntax/parse/generate-stat {
+ ((ilook<=i&&(ilook=i+1)))
+ _stat="$ctx $((wbegin<0?wbegin:i-wbegin)) $wtype $((inest<0?inest:i-inest)) $((tchild<0?tchild:i-tchild)) $((tprev<0?tprev:i-tprev)) ${nparam:-none} $((ilook-i))"
+}
+function ble/syntax/parse/set-lookahead {
+ ((i+$1>ilook&&(ilook=i+$1)))
+}
+function ble/syntax/parse/tree-append {
+ [[ $debug_p1 ]] && ble/util/assert '((i-1>=debug_p1))' "Wrong call of tree-append: Condition violation (p1=$debug_p1 i=$i iN=$iN)."
+ local type=$1
+ local beg=$2 end=$i
+ local len=$((end-beg))
+ ((len==0)) && return 0
+ local tchild=$3 tprev=$4
+ local ochild=-1 oprev=-1
+ ((tchild>=0&&(ochild=i-tchild)))
+ ((tprev>=0&&(oprev=i-tprev)))
+ [[ $type =~ ^[0-9]+$ ]] && ble/syntax/parse/touch-updated-word "$i"
+ _ble_syntax_tree[i-1]="$type $len $ochild $oprev - ${_ble_syntax_tree[i-1]}"
+}
+function ble/syntax/parse/word-push {
+ wtype=$1 wbegin=$2 tprev=$tchild tchild=-1
+}
+function ble/syntax/parse/word-pop {
+ ble/syntax/parse/tree-append "$wtype" "$wbegin" "$tchild" "$tprev"
+ ((wbegin=-1,wtype=-1,tchild=i))
+ ble/syntax/parse/nest-reset-tprev
+}
+function ble/syntax/parse/word-cancel {
+ local -a word
+ ble/string#split-words word "${_ble_syntax_tree[i-1]}"
+ local wlen=${word[1]} tplen=${word[3]}
+ local wbegin=$((i-wlen))
+ tchild=$((tplen<0?tplen:i-tplen))
+ ble/array#fill-range _ble_syntax_tree "$wbegin" "$i" ''
+}
+function ble/syntax/parse/nest-push {
+ local wlen=$((wbegin<0?wbegin:i-wbegin))
+ local nlen=$((inest<0?inest:i-inest))
+ local tclen=$((tchild<0?tchild:i-tchild))
+ local tplen=$((tprev<0?tprev:i-tprev))
+ _ble_syntax_nest[i]="$ctx $wlen $wtype $nlen $tclen $tplen ${nparam:-none} ${2:-none}"
+ ((ctx=$1,inest=i,wbegin=-1,wtype=-1,tprev=tchild,tchild=-1))
+ nparam=
+}
+function ble/syntax/parse/nest-pop {
+ ((inest<0)) && return 1
+ local -a parentNest
+ ble/string#split-words parentNest "${_ble_syntax_nest[inest]}"
+ local ntype=${parentNest[7]} nbeg=$inest
+ ble/syntax/parse/tree-append "n$ntype" "$nbeg" "$tchild" "$tprev"
+ local wlen=${parentNest[1]} nlen=${parentNest[3]} tplen=${parentNest[5]}
+ ((ctx=parentNest[0]))
+ ((wtype=parentNest[2]))
+ ((wbegin=wlen<0?wlen:nbeg-wlen,
+ inest=nlen<0?nlen:nbeg-nlen,
+ tchild=i,
+ tprev=tplen<0?tplen:nbeg-tplen))
+ nparam=${parentNest[6]}
+ [[ $nparam == none ]] && nparam=
+}
+function ble/syntax/parse/nest-type {
+ local _var=ntype
+ [[ $1 == -v ]] && _var=$2
+ if ((inest<0)); then
+ builtin eval "$_var="
+ return 1
+ else
+ builtin eval "$_var=\"\${_ble_syntax_nest[inest]##* }\""
+ fi
+}
+function ble/syntax/parse/nest-ctx {
+ nctx=
+ ((inest>=0)) || return 1
+ nctx=${_ble_syntax_nest[inest]%% *}
+}
+function ble/syntax/parse/nest-reset-tprev {
+ if ((inest<0)); then
+ tprev=-1
+ else
+ local -a nest
+ ble/string#split-words nest "${_ble_syntax_nest[inest]}"
+ local tclen=${nest[4]}
+ ((tprev=tclen<0?tclen:inest-tclen))
+ fi
+}
+function ble/syntax/parse/nest-equals {
+ local parent_inest=$1
+ while :; do
+ ((parent_inest<i1)) && return 0 # 変更していない範囲 または -1
+ ((parent_inest<i2)) && return 1 # 変更によって消えた範囲
+ local _onest=${_tail_syntax_nest[parent_inest-i2]}
+ local _nnest=${_ble_syntax_nest[parent_inest]}
+ [[ $_onest != "$_nnest" ]] && return 1
+ local -a onest; ble/string#split-words onest "$_onest"
+ ble/util/assert \
+ '((onest[3]!=0&&onest[3]<=parent_inest))' \
+ "invalid nest onest[3]=${onest[3]} parent_inest=$parent_inest text=$text" || return 0
+ ((parent_inest=onest[3]<0?onest[3]:(parent_inest-onest[3])))
+ done
+}
+_ble_syntax_attr_umin=-1 _ble_syntax_attr_umax=-1
+_ble_syntax_word_umin=-1 _ble_syntax_word_umax=-1
+_ble_syntax_word_defer_umin=-1 _ble_syntax_word_defer_umax=-1
+function ble/syntax/parse/touch-updated-attr {
+ ble/syntax/urange#update _ble_syntax_attr_ "$1" $(($1+1))
+}
+function ble/syntax/parse/touch-updated-word {
+ ble/util/assert "(($1>0))" "invalid word position $1"
+ ble/syntax/wrange#update _ble_syntax_word_ "$1"
+}
+_ble_ctx_UNSPECIFIED=0
+_ble_ctx_ARGX=3
+_ble_ctx_ARGX0=18
+_ble_ctx_ARGI=4
+_ble_ctx_ARGQ=61
+_ble_ctx_CMDX=1
+_ble_ctx_CMDX1=17
+_ble_ctx_CMDXT=49
+_ble_ctx_CMDXC=26
+_ble_ctx_CMDXE=43
+_ble_ctx_CMDXD0=38
+_ble_ctx_CMDXD=68
+_ble_ctx_CMDXV=13
+_ble_ctx_CMDI=2
+_ble_ctx_VRHS=11
+_ble_ctx_QUOT=5
+_ble_ctx_EXPR=8
+_ble_attr_ERR=6
+_ble_attr_VAR=7
+_ble_attr_QDEL=9
+_ble_attr_QESC=81
+_ble_attr_DEF=10
+_ble_attr_DEL=12
+_ble_attr_HISTX=21
+_ble_attr_FUNCDEF=22
+_ble_ctx_PARAM=14
+_ble_ctx_PWORD=15
+_ble_ctx_PWORDE=73
+_ble_ctx_PWORDR=72
+_ble_ctx_RDRF=19
+_ble_ctx_RDRD=20
+_ble_ctx_RDRD2=80
+_ble_ctx_RDRS=27
+_ble_ctx_VALX=23
+_ble_ctx_VALI=24
+_ble_ctx_VALR=65
+_ble_ctx_VALQ=66
+_ble_attr_COMMENT=25
+_ble_ctx_ARGVX=28
+_ble_ctx_ARGVI=29
+_ble_ctx_ARGVR=62
+_ble_ctx_CONDX=32
+_ble_ctx_CONDI=33
+_ble_ctx_CONDQ=67
+_ble_ctx_CASE=34
+_ble_ctx_CPATX=76
+_ble_ctx_CPATI=77
+_ble_ctx_CPATQ=79
+_ble_ctx_CPATX0=78
+_ble_ctx_PATN=30
+_ble_attr_GLOB=31
+_ble_ctx_BRAX=54
+_ble_attr_BRACE=55
+_ble_ctx_BRACE1=56
+_ble_ctx_BRACE2=57
+_ble_attr_TILDE=60
+_ble_ctx_FARGX1=16
+_ble_ctx_FARGI1=35
+_ble_ctx_FARGX2=36
+_ble_ctx_FARGI2=37
+_ble_ctx_FARGX3=58
+_ble_ctx_FARGI3=59
+_ble_ctx_FARGQ3=63
+_ble_ctx_SARGX1=48
+_ble_ctx_CARGX1=39
+_ble_ctx_CARGI1=40
+_ble_ctx_CARGQ1=64
+_ble_ctx_CARGX2=41
+_ble_ctx_CARGI2=42
+_ble_ctx_TARGX1=50
+_ble_ctx_TARGI1=51
+_ble_ctx_TARGX2=52
+_ble_ctx_TARGI2=53
+_ble_ctx_RDRH=44
+_ble_ctx_RDRI=45
+_ble_ctx_HERE0=46
+_ble_ctx_HERE1=47
+_ble_ctx_ARGEX=69
+_ble_ctx_ARGEI=70
+_ble_ctx_ARGER=71
+_ble_ctx_COARGX=74
+_ble_ctx_COARGI=75
+_ble_attr_CMD_BOLD=101
+_ble_attr_CMD_BUILTIN=102
+_ble_attr_CMD_ALIAS=103
+_ble_attr_CMD_FUNCTION=104
+_ble_attr_CMD_FILE=105
+_ble_attr_KEYWORD=106
+_ble_attr_KEYWORD_BEGIN=118
+_ble_attr_KEYWORD_END=119
+_ble_attr_KEYWORD_MID=120
+_ble_attr_CMD_JOBS=107
+_ble_attr_CMD_DIR=112
+_ble_attr_FILE_DIR=108
+_ble_attr_FILE_STICKY=124
+_ble_attr_FILE_LINK=109
+_ble_attr_FILE_ORPHAN=121
+_ble_attr_FILE_FILE=111
+_ble_attr_FILE_SETUID=122
+_ble_attr_FILE_SETGID=123
+_ble_attr_FILE_EXEC=110
+_ble_attr_FILE_FIFO=114
+_ble_attr_FILE_CHR=115
+_ble_attr_FILE_BLK=116
+_ble_attr_FILE_SOCK=117
+_ble_attr_FILE_WARN=113
+_ble_attr_FILE_URL=125
+_ble_attr_VAR_UNSET=126
+_ble_attr_VAR_EMPTY=127
+_ble_attr_VAR_NUMBER=128
+_ble_attr_VAR_EXPR=129
+_ble_attr_VAR_ARRAY=130
+_ble_attr_VAR_HASH=132
+_ble_attr_VAR_READONLY=131
+_ble_attr_VAR_TRANSFORM=133
+_ble_attr_VAR_EXPORT=134
+_ble_syntax_bash_ctx_names=(
+ [0]=_ble_ctx_UNSPECIFIED
+ [3]=_ble_ctx_ARGX
+ [18]=_ble_ctx_ARGX0
+ [4]=_ble_ctx_ARGI
+ [61]=_ble_ctx_ARGQ
+ [1]=_ble_ctx_CMDX
+ [17]=_ble_ctx_CMDX1
+ [49]=_ble_ctx_CMDXT
+ [26]=_ble_ctx_CMDXC
+ [43]=_ble_ctx_CMDXE
+ [38]=_ble_ctx_CMDXD0
+ [68]=_ble_ctx_CMDXD
+ [13]=_ble_ctx_CMDXV
+ [2]=_ble_ctx_CMDI
+ [11]=_ble_ctx_VRHS
+ [5]=_ble_ctx_QUOT
+ [8]=_ble_ctx_EXPR
+ [6]=_ble_attr_ERR
+ [7]=_ble_attr_VAR
+ [9]=_ble_attr_QDEL
+ [81]=_ble_attr_QESC
+ [10]=_ble_attr_DEF
+ [12]=_ble_attr_DEL
+ [21]=_ble_attr_HISTX
+ [22]=_ble_attr_FUNCDEF
+ [14]=_ble_ctx_PARAM
+ [15]=_ble_ctx_PWORD
+ [73]=_ble_ctx_PWORDE
+ [72]=_ble_ctx_PWORDR
+ [19]=_ble_ctx_RDRF
+ [20]=_ble_ctx_RDRD
+ [80]=_ble_ctx_RDRD2
+ [27]=_ble_ctx_RDRS
+ [23]=_ble_ctx_VALX
+ [24]=_ble_ctx_VALI
+ [65]=_ble_ctx_VALR
+ [66]=_ble_ctx_VALQ
+ [25]=_ble_attr_COMMENT
+ [28]=_ble_ctx_ARGVX
+ [29]=_ble_ctx_ARGVI
+ [62]=_ble_ctx_ARGVR
+ [32]=_ble_ctx_CONDX
+ [33]=_ble_ctx_CONDI
+ [67]=_ble_ctx_CONDQ
+ [34]=_ble_ctx_CASE
+ [76]=_ble_ctx_CPATX
+ [77]=_ble_ctx_CPATI
+ [79]=_ble_ctx_CPATQ
+ [78]=_ble_ctx_CPATX0
+ [30]=_ble_ctx_PATN
+ [31]=_ble_attr_GLOB
+ [54]=_ble_ctx_BRAX
+ [55]=_ble_attr_BRACE
+ [56]=_ble_ctx_BRACE1
+ [57]=_ble_ctx_BRACE2
+ [60]=_ble_attr_TILDE
+ [16]=_ble_ctx_FARGX1
+ [35]=_ble_ctx_FARGI1
+ [36]=_ble_ctx_FARGX2
+ [37]=_ble_ctx_FARGI2
+ [58]=_ble_ctx_FARGX3
+ [59]=_ble_ctx_FARGI3
+ [63]=_ble_ctx_FARGQ3
+ [48]=_ble_ctx_SARGX1
+ [39]=_ble_ctx_CARGX1
+ [40]=_ble_ctx_CARGI1
+ [64]=_ble_ctx_CARGQ1
+ [41]=_ble_ctx_CARGX2
+ [42]=_ble_ctx_CARGI2
+ [50]=_ble_ctx_TARGX1
+ [51]=_ble_ctx_TARGI1
+ [52]=_ble_ctx_TARGX2
+ [53]=_ble_ctx_TARGI2
+ [44]=_ble_ctx_RDRH
+ [45]=_ble_ctx_RDRI
+ [46]=_ble_ctx_HERE0
+ [47]=_ble_ctx_HERE1
+ [69]=_ble_ctx_ARGEX
+ [70]=_ble_ctx_ARGEI
+ [71]=_ble_ctx_ARGER
+ [74]=_ble_ctx_COARGX
+ [75]=_ble_ctx_COARGI
+ [101]=_ble_attr_CMD_BOLD
+ [102]=_ble_attr_CMD_BUILTIN
+ [103]=_ble_attr_CMD_ALIAS
+ [104]=_ble_attr_CMD_FUNCTION
+ [105]=_ble_attr_CMD_FILE
+ [106]=_ble_attr_KEYWORD
+ [118]=_ble_attr_KEYWORD_BEGIN
+ [119]=_ble_attr_KEYWORD_END
+ [120]=_ble_attr_KEYWORD_MID
+ [107]=_ble_attr_CMD_JOBS
+ [112]=_ble_attr_CMD_DIR
+ [108]=_ble_attr_FILE_DIR
+ [124]=_ble_attr_FILE_STICKY
+ [109]=_ble_attr_FILE_LINK
+ [121]=_ble_attr_FILE_ORPHAN
+ [111]=_ble_attr_FILE_FILE
+ [122]=_ble_attr_FILE_SETUID
+ [123]=_ble_attr_FILE_SETGID
+ [110]=_ble_attr_FILE_EXEC
+ [114]=_ble_attr_FILE_FIFO
+ [115]=_ble_attr_FILE_CHR
+ [116]=_ble_attr_FILE_BLK
+ [117]=_ble_attr_FILE_SOCK
+ [113]=_ble_attr_FILE_WARN
+ [125]=_ble_attr_FILE_URL
+ [126]=_ble_attr_VAR_UNSET
+ [127]=_ble_attr_VAR_EMPTY
+ [128]=_ble_attr_VAR_NUMBER
+ [129]=_ble_attr_VAR_EXPR
+ [130]=_ble_attr_VAR_ARRAY
+ [132]=_ble_attr_VAR_HASH
+ [131]=_ble_attr_VAR_READONLY
+ [133]=_ble_attr_VAR_TRANSFORM
+ [134]=_ble_attr_VAR_EXPORT
+)
+function ble/syntax/ctx#get-name {
+ ret=${_ble_syntax_bash_ctx_names[$1]#_ble_ctx_}
+}
+_BLE_SYNTAX_FCTX=()
+_BLE_SYNTAX_FEND=()
+function ble/syntax:text/ctx-unspecified {
+ ((i+=${#tail}))
+ return 0
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_UNSPECIFIED]=ble/syntax:text/ctx-unspecified
+function ble/syntax:text/initialize-ctx { ctx=$_ble_ctx_UNSPECIFIED; }
+function ble/syntax:text/initialize-vars { :; }
+_ble_syntax_bash_RexSpaces=$'[ \t]+'
+_ble_syntax_bash_RexIFSs="[$_ble_term_IFS]+"
+_ble_syntax_bash_RexDelimiter="[$_ble_term_IFS;|&<>()]"
+_ble_syntax_bash_RexRedirect='((\{[a-zA-Z_][a-zA-Z_0-9]*\}|[0-9]+)?(&?>>?|>[|&]|<[>&]?|<<[-<]?))[ ]*'
+_ble_syntax_bash_chars=()
+_ble_syntax_bashc_seed=
+function ble/syntax:bash/cclass/update/reorder {
+ builtin eval "local a=\"\${$1}\""
+ [[ $a == *']'* ]] && a="]${a//]}"
+ [[ $a == *'-'* ]] && a="${a//-}-"
+ builtin eval "$1=\$a"
+}
+function ble/syntax:bash/cclass/update {
+ local seed=$_ble_syntax_bash_histc12
+ shopt -q extglob && seed=${seed}x
+ [[ $seed == "$_ble_syntax_bashc_seed" ]] && return 1
+ _ble_syntax_bashc_seed=$seed
+ local key modified=
+ if [[ $_ble_syntax_bash_histc12 == '!^' ]]; then
+ for key in "${!_ble_syntax_bash_charsDef[@]}"; do
+ _ble_syntax_bash_chars[key]=${_ble_syntax_bash_charsDef[key]}
+ done
+ _ble_syntax_bashc_simple=$_ble_syntax_bash_chars_simpleDef
+ else
+ modified=1
+ local histc1=${_ble_syntax_bash_histc12:0:1}
+ local histc2=${_ble_syntax_bash_histc12:1:1}
+ for key in "${!_ble_syntax_bash_charsFmt[@]}"; do
+ local a=${_ble_syntax_bash_charsFmt[key]}
+ a=${a//@h/"$histc1"}
+ a=${a//@q/"$histc2"}
+ _ble_syntax_bash_chars[key]=$a
+ done
+ local a=$_ble_syntax_bash_chars_simpleFmt
+ a=${a//@h/"$histc1"}
+ a=${a//@q/"$histc2"}
+ _ble_syntax_bashc_simple=$a
+ fi
+ if [[ $seed == *x ]]; then
+ local extglob='@+!' # *? は既に登録されている筈
+ _ble_syntax_bash_chars[_ble_ctx_ARGI]=${_ble_syntax_bash_chars[_ble_ctx_ARGI]}$extglob
+ _ble_syntax_bash_chars[_ble_ctx_PATN]=${_ble_syntax_bash_chars[_ble_ctx_PATN]}$extglob
+ _ble_syntax_bash_chars[_ble_ctx_PWORD]=${_ble_syntax_bash_chars[_ble_ctx_PWORD]}$extglob
+ _ble_syntax_bash_chars[_ble_ctx_PWORDE]=${_ble_syntax_bash_chars[_ble_ctx_PWORDE]}$extglob
+ _ble_syntax_bash_chars[_ble_ctx_PWORDR]=${_ble_syntax_bash_chars[_ble_ctx_PWORDR]}$extglob
+ fi
+ if [[ $modified ]]; then
+ for key in "${!_ble_syntax_bash_chars[@]}"; do
+ ble/syntax:bash/cclass/update/reorder _ble_syntax_bash_chars[key]
+ done
+ ble/syntax:bash/cclass/update/reorder _ble_syntax_bashc_simple
+ fi
+ return 0
+}
+_ble_syntax_bash_charsDef=()
+_ble_syntax_bash_charsFmt=()
+_ble_syntax_bash_chars_simpleDef=
+_ble_syntax_bash_chars_simpleFmt=
+function ble/syntax:bash/cclass/initialize {
+ local delimiters="$_ble_term_IFS;|&()<>"
+ local expansions="\$\"\`\\'"
+ local glob='[*?'
+ local tilde='~:'
+ _ble_syntax_bash_charsDef[_ble_ctx_ARGI]="$delimiters$expansions$glob{$tilde^!"
+ _ble_syntax_bash_charsDef[_ble_ctx_PATN]="$expansions$glob(|)<>{!" # <> はプロセス置換のため。
+ _ble_syntax_bash_charsDef[_ble_ctx_QUOT]="\$\"\`\\!" # 文字列 "~" で特別な意味を持つのは $ ` \ " のみ。+履歴展開の ! も。
+ _ble_syntax_bash_charsDef[_ble_ctx_EXPR]="][}()$expansions!" # ()[] は入れ子を数える為。} は ${var:ofs:len} の為。
+ _ble_syntax_bash_charsDef[_ble_ctx_PWORD]="}$expansions$glob!" # パラメータ展開 ${~}
+ _ble_syntax_bash_charsDef[_ble_ctx_PWORDE]="}$expansions$glob!" # パラメータ展開 ${~} エラー
+ _ble_syntax_bash_charsDef[_ble_ctx_PWORDR]="}/$expansions$glob!" # パラメータ展開 ${~} 置換前
+ _ble_syntax_bash_charsDef[_ble_ctx_RDRH]="$delimiters$expansions"
+ _ble_syntax_bash_charsFmt[_ble_ctx_ARGI]="$delimiters$expansions$glob{$tilde@q@h"
+ _ble_syntax_bash_charsFmt[_ble_ctx_PATN]="$expansions$glob(|)<>{@h"
+ _ble_syntax_bash_charsFmt[_ble_ctx_QUOT]="\$\"\`\\@h"
+ _ble_syntax_bash_charsFmt[_ble_ctx_EXPR]="][}()$expansions@h"
+ _ble_syntax_bash_charsFmt[_ble_ctx_PWORD]="}$expansions$glob@h"
+ _ble_syntax_bash_charsFmt[_ble_ctx_PWORDE]="}$expansions$glob@h"
+ _ble_syntax_bash_charsFmt[_ble_ctx_PWORDR]="}/$expansions$glob@h"
+ _ble_syntax_bash_charsFmt[_ble_ctx_RDRH]=${_ble_syntax_bash_charsDef[_ble_ctx_RDRH]}
+ _ble_syntax_bash_chars_simpleDef="$delimiters$expansions^!"
+ _ble_syntax_bash_chars_simpleFmt="$delimiters$expansions@q@h"
+ _ble_syntax_bash_histc12='!^'
+ ble/syntax:bash/cclass/update
+}
+ble/syntax:bash/cclass/initialize
+_ble_syntax_bash_simple_rex_letter=
+_ble_syntax_bash_simple_rex_param=
+_ble_syntax_bash_simple_rex_bquot=
+_ble_syntax_bash_simple_rex_squot=
+_ble_syntax_bash_simple_rex_dquot=
+_ble_syntax_bash_simple_rex_literal=
+_ble_syntax_bash_simple_rex_element=
+_ble_syntax_bash_simple_rex_word=
+_ble_syntax_bash_simple_rex_open_word=
+_ble_syntax_bash_simple_rex_open_dquot=
+_ble_syntax_bash_simple_rex_open_squot=
+_ble_syntax_bash_simple_rex_incomplete_word1=
+_ble_syntax_bash_simple_rex_incomplete_word2=
+_ble_syntax_bash_simple_rex_noglob_word1=
+_ble_syntax_bash_simple_rex_noglob_word2=
+function ble/syntax:bash/simple-word/update {
+ local q="'"
+ local letter='\[[!^]|[^'${_ble_syntax_bashc_simple}']'
+ local param1='\$([-*@#?$!0_]|[1-9][0-9]*|[a-zA-Z_][a-zA-Z_0-9]*)'
+ local param2='\$\{(#?[-*@#?$!0]|[#!]?([1-9][0-9]*|[a-zA-Z_][a-zA-Z_0-9]*))\}' # ${!!} ${!$} はエラーになる。履歴展開の所為?
+ local param=$param1'|'$param2
+ local bquot='\\.'
+ local squot=$q'[^'$q']*'$q'|\$'$q'([^'$q'\]|\\.)*'$q
+ local dquot='\$?"([^'${_ble_syntax_bash_chars[_ble_ctx_QUOT]}']|\\.|'$param')*"'
+ _ble_syntax_bash_simple_rex_letter=$letter # 0 groups
+ _ble_syntax_bash_simple_rex_param=$param # 3 groups
+ _ble_syntax_bash_simple_rex_bquot=$bquot # 0 groups
+ _ble_syntax_bash_simple_rex_squot=$squot # 1 groups
+ _ble_syntax_bash_simple_rex_dquot=$dquot # 4 groups
+ _ble_syntax_bash_simple_rex_literal='^('$letter')+$'
+ _ble_syntax_bash_simple_rex_element='('$bquot'|'$squot'|'$dquot'|'$param'|'$letter')'
+ _ble_syntax_bash_simple_rex_word='^'$_ble_syntax_bash_simple_rex_element'+$'
+ local open_squot=$q'[^'$q']*|\$'$q'([^'$q'\]|\\.)*'
+ local open_dquot='\$?"([^'${_ble_syntax_bash_chars[_ble_ctx_QUOT]}']|\\.|'$param')*'
+ _ble_syntax_bash_simple_rex_open_word='^('$_ble_syntax_bash_simple_rex_element'*)(\\|'$open_squot'|'$open_dquot')$'
+ _ble_syntax_bash_simple_rex_open_squot=$open_squot
+ _ble_syntax_bash_simple_rex_open_dquot=$open_dquot
+ local letter1='\[[!^]|[^{'${_ble_syntax_bashc_simple}']'
+ local letter2='\[[!^]|[^'${_ble_syntax_bashc_simple}']'
+ _ble_syntax_bash_simple_rex_incomplete_word1='^('$bquot'|'$squot'|'$dquot'|'$param'|'$letter1')+'
+ _ble_syntax_bash_simple_rex_incomplete_word2='^(('$bquot'|'$squot'|'$dquot'|'$param'|'$letter2')*)(\\|'$open_squot'|'$open_dquot')?$'
+ local noglob_letter='[^[?*'${_ble_syntax_bashc_simple}']'
+ _ble_syntax_bash_simple_rex_noglob_word1='^('$bquot'|'$squot'|'$dquot'|'$noglob_letter')+$'
+ _ble_syntax_bash_simple_rex_noglob_word2='^('$bquot'|'$squot'|'$dquot'|'$param'|'$noglob_letter')+$'
+}
+ble/syntax:bash/simple-word/update
+function ble/syntax:bash/simple-word/is-literal {
+ [[ $1 =~ $_ble_syntax_bash_simple_rex_literal ]]
+}
+function ble/syntax:bash/simple-word/is-simple {
+ [[ $1 =~ $_ble_syntax_bash_simple_rex_word ]]
+}
+function ble/syntax:bash/simple-word/is-simple-or-open-simple {
+ [[ $1 =~ $_ble_syntax_bash_simple_rex_word || $1 =~ $_ble_syntax_bash_simple_rex_open_word ]]
+}
+function ble/syntax:bash/simple-word/is-never-word {
+ ble/syntax:bash/simple-word/is-simple-or-open-simple && return 1
+ local rex=${_ble_syntax_bash_simple_rex_word%'$'}'[ |&;<>()]|^[ |&;<>()]'
+ [[ $1 =~ $rex ]]
+}
+function ble/syntax:bash/simple-word/is-simple-noglob {
+ [[ $1 =~ $_ble_syntax_bash_simple_rex_noglob_word1 ]] && return 0
+ if [[ $1 =~ $_ble_syntax_bash_simple_rex_noglob_word2 ]]; then
+ builtin eval -- "local expanded=$1" 2>/dev/null
+ local rex='[*?]|\[.+\]|[*?@+!]\(.*\)'
+ [[ $expanded =~ $rex ]] || return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/simple-word/evaluate-last-brace-expansion {
+ local value=$1
+ local bquot=$_ble_syntax_bash_simple_rex_bquot
+ local squot=$_ble_syntax_bash_simple_rex_squot
+ local dquot=$_ble_syntax_bash_simple_rex_dquot
+ local param=$_ble_syntax_bash_simple_rex_param
+ local letter='\[[!^]|[^{,}'${_ble_syntax_bashc_simple}']'
+ local symbol='[{,}]'
+ local rex_range_expansion='^(([-+]?[0-9]+)\.\.\.[-+]?[0-9]+|([a-zA-Z])\.\.[a-zA-Z])(\.\.[-+]?[0-9]+)?$'
+ local rex0='^('$bquot'|'$squot'|'$dquot'|'$param'|'$letter')+'
+ local stack; stack=()
+ local out= comma= index=0 iopen=0 no_brace_length=0
+ while [[ $value ]]; do
+ if [[ $value =~ $rex0 ]]; then
+ local len=${#BASH_REMATCH}
+ ((index+=len,no_brace_length+=len))
+ out=$out${value::len}
+ value=${value:len}
+ elif [[ $value == '{'* ]]; then
+ ((iopen=++index,no_brace_length=0))
+ value=${value:1}
+ ble/array#push stack "$comma:$out"
+ out= comma=
+ elif ((${#stack[@]})) && [[ $value == '}'* ]]; then
+ ((++index))
+ value=${value:1}
+ ble/array#pop stack
+ local out0=${ret#*:} comma0=${ret%%:*}
+ if [[ $comma ]]; then
+ ((iopen=index,no_brace_length=0))
+ out=$out0$out
+ comma=$comma0
+ elif [[ $out =~ $rex_range_expansion ]]; then
+ ((iopen=index,no_brace_length=0))
+ out=$out0${2#+}$3
+ comma=$comma0
+ else
+ ((++no_brace_length))
+ ble/array#push stack "$comma0:$out0" # cancel pop
+ out=$out'}'
+ fi
+ elif ((${#stack[@]})) && [[ $value == ','* ]]; then
+ ((iopen=++index,no_brace_length=0))
+ value=${value:1}
+ out= comma=1
+ else
+ ((++index,++no_brace_length))
+ out=$out${value::1}
+ value=${value:1}
+ fi
+ done
+ while ((${#stack[@]})); do
+ ble/array#pop stack
+ local out0=${ret#*:} comma0=${ret%%:*}
+ out=$out0$out
+ done
+ ret=$out simple_ibrace=$iopen:$((${#out}-no_brace_length))
+}
+function ble/syntax:bash/simple-word/reconstruct-incomplete-word {
+ local word=$1
+ ret= simple_flags= simple_ibrace=0:0
+ [[ $word ]] || return 0
+ if [[ $word =~ $_ble_syntax_bash_simple_rex_incomplete_word1 ]]; then
+ ret=${word::${#BASH_REMATCH}}
+ word=${word:${#BASH_REMATCH}}
+ [[ $word ]] || return 0
+ fi
+ if [[ $word =~ $_ble_syntax_bash_simple_rex_incomplete_word2 ]]; then
+ local out=$ret
+ local m_brace=${BASH_REMATCH[1]}
+ local m_quote=${word:${#m_brace}}
+ if [[ $m_brace ]]; then
+ ble/syntax:bash/simple-word/evaluate-last-brace-expansion "$m_brace"
+ simple_ibrace=$((${#out}+${simple_ibrace%:*})):$((${#out}+${simple_ibrace#*:}))
+ out=$out$ret
+ fi
+ if [[ $m_quote ]]; then
+ case $m_quote in
+ ('$"'*) out=$out$m_quote\" simple_flags=I ;;
+ ('"'*) out=$out$m_quote\" simple_flags=D ;;
+ ("$'"*) out=$out$m_quote\' simple_flags=E ;;
+ ("'"*) out=$out$m_quote\' simple_flags=S ;;
+ ('\') simple_flags=B ;;
+ (*) return 1 ;;
+ esac
+ fi
+ ret=$out
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/simple-word/extract-parameter-names {
+ ret=()
+ local letter=$_ble_syntax_bash_simple_rex_letter
+ local bquot=$_ble_syntax_bash_simple_rex_bquot
+ local squot=$_ble_syntax_bash_simple_rex_squot
+ local dquot=$_ble_syntax_bash_simple_rex_dquot
+ local param=$_ble_syntax_bash_simple_rex_param
+ local value=$1
+ local rex0='^('$letter'|'$bquot'|'$squot')+'
+ local rex1='^('$dquot')'
+ local rex2='^('$param')'
+ while [[ $value ]]; do
+ [[ $value =~ $rex0 ]] && value=${value:${#BASH_REMATCH}}
+ if [[ $value =~ $rex1 ]]; then
+ value=${value:${#BASH_REMATCH}}
+ ble/syntax:bash/simple-word/extract-parameter-names/.process-dquot "$BASH_REMATCH"
+ fi
+ [[ $value =~ $rex2 ]] || break
+ value=${value:${#BASH_REMATCH}}
+ local var=${BASH_REMATCH[2]}${BASH_REMATCH[3]}
+ [[ $var == [_a-zA-Z]* ]] && ble/array#push ret "$var"
+ done
+}
+function ble/syntax:bash/simple-word/extract-parameter-names/.process-dquot {
+ local value=$1
+ if [[ $value == '$"'*'"' ]]; then
+ value=${value:2:${#value}-3}
+ elif [[ $value == '"'*'"' ]]; then
+ value=${value:1:${#value}-2}
+ else
+ return 0
+ fi
+ local rex0='^([^'${_ble_syntax_bash_chars[_ble_ctx_QUOT]}']|\\.)+'
+ local rex2='^('$param')'
+ while [[ $value ]]; do
+ [[ $value =~ $rex0 ]] && value=${value:${#BASH_REMATCH}}
+ [[ $value =~ $rex2 ]] || break
+ value=${value:${#BASH_REMATCH}}
+ local var=${BASH_REMATCH[2]}${BASH_REMATCH[3]}
+ [[ $var == [_a-zA-Z]* ]] && ble/array#push ret "$var"
+ done
+}
+function ble/syntax:bash/simple-word/eval/.set-result { __ble_ret=("$@"); }
+function ble/syntax:bash/simple-word/eval/.print-result {
+ if (($#>=1000)) && [[ $OSTYPE != cygwin ]]; then
+ if ((_ble_bash>=50200)); then
+ printf '%s\0' "$@" >| "$__ble_simple_word_tmpfile"
+ ble/util/print 'ble/util/readarray -d "" __ble_ret < "$__ble_simple_word_tmpfile"'
+ return 0
+ elif ((_ble_bash>=40000)); then
+ ret=("$@")
+ ble/util/writearray --nlfix ret >| "$__ble_simple_word_tmpfile"
+ ble/util/print 'ble/util/readarray --nlfix __ble_ret < "$__ble_simple_word_tmpfile"'
+ return 0
+ fi
+ fi
+ local ret; ble/string#quote-words "$@"
+ ble/util/print "__ble_ret=($ret)"
+}
+function ble/syntax:bash/simple-word/eval/.impl {
+ local __ble_word=$1 __ble_opts=$2 __ble_flags=
+ local -a ret=()
+ ble/syntax:bash/simple-word/extract-parameter-names "$__ble_word"
+ if ((${#ret[@]})); then
+ local __ble_defs
+ ble/util/assign __ble_defs 'ble/util/print-global-definitions --hidden-only "${ret[@]}"'
+ builtin eval -- "$__ble_defs" &>/dev/null # 読み取り専用の変数のこともある
+ fi
+ if [[ $- != *f* ]] && ! ble/syntax:bash/simple-word/is-simple-noglob "$1"; then
+ if [[ :$__ble_opts: == *:noglob:* ]]; then
+ set -f
+ __ble_flags=f
+ elif ble/util/is-cygwin-slow-glob "$1"; then # Note: #D1168
+ if shopt -q failglob &>/dev/null; then
+ __ble_ret=()
+ return 1
+ elif shopt -q nullglob &>/dev/null; then
+ __ble_ret=()
+ return 0
+ else
+ set -f
+ __ble_flags=f
+ fi
+ elif [[ :$__ble_opts: == *:stopcheck:* ]]; then
+ ble/decode/has-input && return 148
+ if ((_ble_bash>=40000)); then
+ __ble_flags=s
+ elif shopt -q globstar &>/dev/null; then
+ if builtin eval "[[ $__ble_word == *'**'* ]]"; then
+ [[ :$__ble_opts: == *:timeout=*:* ]] && return 142
+ return 148
+ fi
+ fi
+ fi
+ fi
+ __ble_ret=()
+ if [[ $__ble_flags == *s* ]]; then
+ local __ble_sync_command="ble/syntax:bash/simple-word/eval/.print-result $__ble_word"
+ local __ble_sync_opts=progressive-weight
+ local __ble_sync_weight=$bleopt_syntax_eval_polling_interval
+ local __ble_sync_timeout=$_ble_syntax_bash_simple_eval_timeout
+ if [[ $_ble_syntax_bash_simple_eval_timeout_carry ]]; then
+ __ble_sync_timeout=0
+ elif local __ble_rex=':timeout=([^:]*):'; [[ :$__ble_opts: =~ $__ble_rex ]]; then
+ __ble_sync_timeout=${BASH_REMATCH[1]}
+ fi
+ [[ $__ble_sync_timeout ]] &&
+ __ble_sync_opts=$__ble_sync_opts:timeout=$((__ble_sync_timeout))
+ local _ble_local_tmpfile; ble/util/assign/.mktmp
+ local __ble_simple_word_tmpfile=$_ble_local_tmpfile
+ local __ble_script
+ ble/util/assign __ble_script 'ble/util/conditional-sync "$__ble_sync_command" "" "$__ble_sync_weight" "$__ble_sync_opts"' &>/dev/null; local ext=$?
+ builtin eval -- "$__ble_script"
+ ble/util/assign/.rmtmp
+ else
+ builtin eval "ble/syntax:bash/simple-word/eval/.set-result $__ble_word" &>/dev/null; local ext=$?
+ builtin eval : # Note: bash 3.1/3.2 eval バグ対策 (#D1132)
+ fi
+ [[ $__ble_flags == *f* ]] && set +f
+ return "$ext"
+}
+_ble_syntax_bash_simple_eval_hash=
+function ble/syntax:bash/simple-word/eval/.cache-clear {
+ ble/gdict#clear _ble_syntax_bash_simple_eval
+ ble/gdict#clear _ble_syntax_bash_simple_eval_full
+}
+function ble/syntax:bash/simple-word/eval/.cache-update {
+ local hash=$-:$BASHOPTS:$_ble_edit_lineno:$_ble_textarea_version:$PWD
+ if [[ $hash != "$_ble_syntax_bash_simple_eval_hash" ]]; then
+ _ble_syntax_bash_simple_eval_hash=$hash
+ ble/syntax:bash/simple-word/eval/.cache-clear
+ fi
+}
+function ble/syntax:bash/simple-word/eval/.cache-save {
+ ((ext==148||ext==142)) && return 0
+ local ret; ble/string#quote-words "$3"
+ ble/gdict#set _ble_syntax_bash_simple_eval "$1" "ext=$2 count=$(($#-2)) ret=$ret"
+ local ret; ble/string#quote-words "${@:3}"
+ ble/gdict#set _ble_syntax_bash_simple_eval_full "$1" "ext=$2 count=$(($#-2)) ret=($ret)"
+}
+function ble/syntax:bash/simple-word/eval/.cache-load {
+ ext= ret=
+ if [[ :$2: == *:single:* ]]; then
+ ble/gdict#get _ble_syntax_bash_simple_eval "$1" || return 1
+ else
+ ble/gdict#get _ble_syntax_bash_simple_eval_full "$1" || return 1
+ fi
+ builtin eval -- "$ret"
+ return 0
+}
+_ble_syntax_bash_simple_eval_timeout=
+_ble_syntax_bash_simple_eval_timeout_carry=
+function ble/syntax:bash/simple-word/eval {
+ [[ :$2: != *:count:* ]] && local count
+ if [[ :$2: == *:cached:* && :$2: != *:noglob:* ]]; then
+ ble/syntax:bash/simple-word/eval/.cache-update
+ local ext; ble/syntax:bash/simple-word/eval/.cache-load "$1" "$2" && return "$ext"
+ fi
+ local __ble_ret
+ ble/syntax:bash/simple-word/eval/.impl "$1" "$2"; local ext=$?
+ ret=("${__ble_ret[@]}")
+ count=${#ret[@]}
+ if [[ :$2: == *:cached:* && :$2: != *:noglob:* ]]; then
+ ble/syntax:bash/simple-word/eval/.cache-save "$1" "$ext" "${ret[@]}"
+ fi
+ if ((ext==142)); then
+ [[ :$2: == *:timeout-carry:* ]] &&
+ _ble_syntax_bash_simple_eval_timeout_carry=1
+ if [[ :$2: == *:retry-noglob-on-timeout:* ]]; then
+ ble/syntax:bash/simple-word/eval "$1" "$2:noglob"
+ return "$?"
+ fi
+ fi
+ return "$ext"
+}
+function ble/syntax:bash/simple-word/.get-rex_element {
+ local sep=$1
+ local param=$_ble_syntax_bash_simple_rex_param
+ local bquot=$_ble_syntax_bash_simple_rex_bquot
+ local squot=$_ble_syntax_bash_simple_rex_squot
+ local dquot=$_ble_syntax_bash_simple_rex_dquot
+ local letter1='\[[!^]|[^'$sep$_ble_syntax_bashc_simple']'
+ rex_element='('$bquot'|'$squot'|'$dquot'|'$param'|'$letter1')+'
+}
+function ble/syntax:bash/simple-word/evaluate-path-spec {
+ local word=$1 sep=${2:-'/:='} opts=$3
+ ret=() spec=() path=()
+ [[ $word ]] || return 0
+ local eval_opts=$opts notilde=
+ [[ :$opts: == *:notilde:* ]] && notilde=\'\' # チルダ展開の抑制
+ local rex_element; ble/syntax:bash/simple-word/.get-rex_element "$sep"
+ local rex='^['$sep']?'$rex_element'|^['$sep']'
+ [[ :$opts: == *:after-sep:* ]] &&
+ local rex='^'$rex_element'['$sep']?|^['$sep']'
+ local tail=$word s= p= ext=0
+ while [[ $tail =~ $rex ]]; do
+ local rematch=$BASH_REMATCH
+ s=$s$rematch
+ ble/syntax:bash/simple-word/eval "$notilde$s" "$eval_opts"; ext=$?
+ ((ext==148||ext==142)) && return "$ext"
+ p=$ret
+ tail=${tail:${#rematch}}
+ ble/array#push spec "$s"
+ ble/array#push path "$p"
+ done
+ [[ $tail ]] && return 1
+ ((ext)) && return "$ext"
+ return 0
+}
+function ble/syntax:bash/simple-word/detect-separated-path {
+ local word=$1 sep=${2:-':'} opts=$3
+ [[ $word ]] || return 1
+ local rex_url='^[a-z]+://'
+ [[ :$opts: == *:url:* && $word =~ $rex_url ]] && return 1
+ local eval_opts=$opts notilde=
+ [[ :$opts: == *:notilde:* ]] && notilde=\'\' # チルダ展開の抑制
+ local rex_element
+ ble/syntax:bash/simple-word/.get-rex_element /
+ local rex='^'$rex_element'/?|^/'
+ local tail=$word head=
+ while [[ $tail =~ $rex ]]; do
+ local rematch=$BASH_REMATCH
+ ble/syntax:bash/simple-word/locate-filename/.exists "$notilde$head$rematch"; local ext=$?
+ ((ext==148)) && return 148
+ ((ext==0)) || break
+ head=$head$rematch
+ tail=${tail:${#rematch}}
+ done
+ ret=
+ local i
+ for ((i=0;i<${#sep};i++)); do
+ local sep1=${sep:i:1}
+ ble/syntax:bash/simple-word/.get-rex_element "$sep1"
+ local rex_nocolon='^('$rex_element')?$'
+ local rex_hascolon='^('$rex_element')?['$sep1']'
+ [[ $head =~ $rex_nocolon && $tail =~ $rex_hascolon ]] && ret=$ret$sep1
+ done
+ [[ $ret ]]
+}
+function ble/syntax:bash/simple-word/locate-filename/.exists {
+ local word=$1 ret
+ ble/syntax:bash/simple-word/eval "$word" "$eval_opts" || return "$?"
+ local path=$ret
+ if [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $path == //* ]]; then
+ [[ $path == // ]]
+ else
+ [[ -e $path || -h $path ]]
+ fi || [[ :$opts: == *:url:* && $path =~ $rex_url ]]
+}
+function ble/syntax:bash/simple-word/locate-filename {
+ local word=$1 sep=${2:-':='} opts=$3
+ ret=0
+ [[ $word ]] || return 0
+ local eval_opts=$opts
+ local rex_element; ble/syntax:bash/simple-word/.get-rex_element "$sep"
+ local rex='^'$rex_element'['$sep']|^['$sep']'
+ local rex_url='^[a-z]+://'
+ local -a seppos=()
+ local tail=$word p=0
+ while [[ $tail =~ $rex ]]; do
+ ((p+=${#BASH_REMATCH}))
+ tail=${tail:${#BASH_REMATCH}}
+ ble/array#push seppos $((p-1))
+ done
+ ble/syntax:bash/simple-word/is-simple "$tail" &&
+ ble/array#push seppos $((p+${#tail}))
+ local -a out=()
+ for ((i=0;i<${#seppos[@]};i++)); do
+ local j0=$i
+ [[ :$opts: == *:greedy:* ]] && j0=${#seppos[@]}-1
+ for ((j=j0;j>=i;j--)); do
+ local f1=0 f2=${seppos[j]}
+ ((i)) && ((f1=seppos[i-1]+1))
+ if ((j>i)); then
+ ble/syntax:bash/simple-word/locate-filename/.exists "${word:f1:f2-f1}" "$opts"; local ext=$?
+ ((ext==148)) && return 148
+ if ((ext==0)); then
+ ble/array#push out "$f1" "$f2"
+ ((i=j))
+ fi
+ else
+ if [[ :$opts: != *:exists:* ]] ||
+ { ble/syntax:bash/simple-word/locate-filename/.exists "${word:f1:f2-f1}" "$opts"
+ local ext=$?; ((ext==148)) && return 148; ((ext==0)); }; then
+ ble/array#push out "$f1" "$f2"
+ fi
+ fi
+ done
+ done
+ ret=("${out[@]}")
+ return 0
+}
+function ble/syntax:bash/simple-word#break-word {
+ local word=$1 sep=${2:-':='}
+ if [[ ! $word ]]; then
+ ret=('')
+ return 0
+ fi
+ sep=${sep//[\"\'\$\`]}
+ local rex_element; ble/syntax:bash/simple-word/.get-rex_element "$sep"
+ local rex='^('$rex_element')?['$sep']+'
+ local -a out=()
+ local tail=$word p=0
+ while [[ $tail =~ $rex ]]; do
+ local rematch1=${BASH_REMATCH[1]}
+ ble/array#push out "$rematch1"
+ ble/array#push out "${BASH_REMATCH:${#rematch1}}"
+ tail=${tail:${#BASH_REMATCH}}
+ done
+ ble/array#push out "$tail"
+ ret=("${out[@]}")
+ return 0
+}
+function ble/syntax:bash/initialize-ctx {
+ ctx=$_ble_ctx_CMDX # _ble_ctx_CMDX が ble/syntax:bash の最初の文脈
+}
+function ble/syntax:bash/initialize-vars {
+ local histc12
+ if [[ ${histchars+set} ]]; then
+ histc12=${histchars::2}
+ else
+ histc12='!^'
+ fi
+ _ble_syntax_bash_histc12=$histc12
+ if ble/syntax:bash/cclass/update; then
+ ble/syntax:bash/simple-word/update
+ fi
+ local histstop=$' \t\n='
+ shopt -q extglob && histstop="$histstop("
+ _ble_syntax_bash_histstop=$histstop
+}
+function ble/syntax/highlight/vartype {
+ if [[ ! $bleopt_highlight_variable ]]; then
+ ret=$_ble_attr_VAR
+ return 0
+ fi
+ local name=$1 opts=$2 tail=$3 rex='^-?[0-9]+(#[0-9a-zA-Z@_]*)?$'
+ local attr; ble/variable#get-attr "$name"
+ if [[ ${!name+set} || $attr == *[aA]* ]]; then
+ if [[ ${!name-} && :$opts: == *:expr:* && ! ( ${!name} =~ $rex ) ]]; then
+ ret=$_ble_attr_VAR_EXPR
+ elif [[ ${!name+set} && $attr == *x* ]]; then
+ ret=$_ble_attr_VAR_EXPORT
+ elif [[ $attr == *a* ]]; then
+ ret=$_ble_attr_VAR_ARRAY
+ elif [[ $attr == *A* ]]; then
+ ret=$_ble_attr_VAR_HASH
+ elif [[ $attr == *r* ]]; then
+ ret=$_ble_attr_VAR_READONLY
+ elif [[ $attr == *i* ]]; then
+ ret=$_ble_attr_VAR_NUMBER
+ elif [[ $attr == *[luc]* ]]; then
+ ret=$_ble_attr_VAR_TRANSFORM
+ elif [[ ! ${!name} ]]; then
+ ret=$_ble_attr_VAR_EMPTY
+ else
+ ret=$_ble_attr_VAR
+ fi
+ else
+ if [[ :$opts: == *:readvar:* && $_ble_bash_set == *u* ]]; then
+ if [[ ! $tail ]] || {
+ local rex='^:?[-+?=]'
+ [[ $tail == :* ]] && lookahead=2
+ ! [[ $tail =~ $rex ]]; }
+ then
+ ret=$_ble_attr_ERR
+ return 0
+ fi
+ fi
+ ret=$_ble_attr_VAR_UNSET
+ fi
+}
+function ble/syntax:bash/check-plain-with-escape {
+ local rex='^('$1'|\\.)' is_quote=$2
+ [[ $tail =~ $rex ]] || return 1
+ if [[ $BASH_REMATCH == '\'? &&
+ ( ! $is_quote || $BASH_REMATCH == '\'[$'\\`$\n"'] ) ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_QESC))
+ else
+ ((_ble_syntax_attr[i]=ctx))
+ fi
+ ((i+=${#BASH_REMATCH}))
+ return 0
+}
+function ble/syntax:bash/check-dollar {
+ [[ $tail == '$'* ]] || return 1
+ local rex
+ if [[ $tail == '${'* ]]; then
+ local rex1='^(\$\{#)([-*@#?$!0]\}?|[1-9][0-9]*\}?|[a-zA-Z_][a-zA-Z_0-9]*[[}]?)'
+ local rex2='^(\$\{!?)([-*@#?$!0]|[1-9][0-9]*|[a-zA-Z_][a-zA-Z_0-9]*\[?)'
+ if
+ [[ $tail =~ $rex1 ]] && {
+ [[ ${BASH_REMATCH[2]} == *['[}'] || $BASH_REMATCH == "$tail" ]] ||
+ { ble/syntax/parse/set-lookahead $((${#BASH_REMATCH}+1)); false; } } ||
+ [[ $tail =~ $rex2 ]]
+ then
+ local rematch1=${BASH_REMATCH[1]}
+ local rematch2=${BASH_REMATCH[2]}
+ local varname=${rematch2%['[}']}
+ local ntype='${'
+ if ((ctx==_ble_ctx_QUOT)); then
+ ntype='"${'
+ elif ((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR||ctx==_ble_ctx_EXPR)); then
+ local ntype2; ble/syntax/parse/nest-type -v ntype2
+ [[ $ntype2 == '"${' ]] && ntype='"${'
+ fi
+ local ret lookahead= tail2=${tail:${#rematch1}+${#varname}}
+ ble/syntax/highlight/vartype "$varname" readvar "$tail2"; local attr=$ret
+ ble/syntax/parse/nest-push "$_ble_ctx_PARAM" "$ntype"
+ ((_ble_syntax_attr[i]=ctx,
+ i+=${#rematch1},
+ _ble_syntax_attr[i]=attr,
+ i+=${#varname}))
+ [[ $lookahead ]] && ble/syntax/parse/set-lookahead "$lookahead"
+ if rex='^\$\{![a-zA-Z_][a-zA-Z_0-9]*[*@]\}?'; [[ $tail =~ $rex ]]; then
+ ble/syntax/parse/set-lookahead 2
+ if [[ $BASH_REMATCH == *'}' ]]; then
+ ((i++,ctx=_ble_ctx_PWORDE))
+ fi
+ elif [[ $rematch2 == *'[' ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_EXPR" 'v['
+ ((_ble_syntax_attr[i++]=_ble_ctx_EXPR))
+ fi
+ return 0
+ else
+ ((_ble_syntax_attr[i]=_ble_attr_ERR,i+=2))
+ return 0
+ fi
+ elif [[ $tail == '$(('* ]]; then
+ ((_ble_syntax_attr[i]=_ble_ctx_PARAM))
+ ble/syntax/parse/nest-push "$_ble_ctx_EXPR" '$(('
+ ((i+=3))
+ return 0
+ elif [[ $tail == '$['* ]]; then
+ ((_ble_syntax_attr[i]=_ble_ctx_PARAM))
+ ble/syntax/parse/nest-push "$_ble_ctx_EXPR" '$['
+ ((i+=2))
+ return 0
+ elif [[ $tail == '$('* ]]; then
+ ((_ble_syntax_attr[i]=_ble_ctx_PARAM))
+ ble/syntax/parse/nest-push "$_ble_ctx_CMDX" '$('
+ ((i+=2))
+ return 0
+ elif rex='^\$([-*@#?$!0_]|[1-9]|[a-zA-Z_][a-zA-Z_0-9]*)' && [[ $tail =~ $rex ]]; then
+ local rematch=$BASH_REMATCH rematch1=${BASH_REMATCH[1]}
+ local ret; ble/syntax/highlight/vartype "$rematch1" readvar
+ ((_ble_syntax_attr[i]=_ble_ctx_PARAM,
+ _ble_syntax_attr[i+1]=ret,
+ i+=${#rematch}))
+ return 0
+ else
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ fi
+}
+function ble/syntax:bash/check-quotes {
+ local rex aqdel=$_ble_attr_QDEL aquot=$_ble_ctx_QUOT
+ if ((ctx==_ble_ctx_EXPR)); then
+ local ntype
+ ble/syntax/parse/nest-type
+ if [[ $ntype == '${' || $ntype == '$[' || $ntype == '$((' || $ntype == 'NQ(' ]]; then
+ ((aqdel=_ble_attr_ERR,aquot=_ble_ctx_EXPR))
+ elif [[ $ntype == '"${' ]] && ! { [[ $tail == '$'[\'\"]* ]] && shopt -q extquote; }; then
+ ((aqdel=_ble_attr_ERR,aquot=_ble_ctx_EXPR))
+ fi
+ elif ((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR)); then
+ if [[ $tail == '$'[\'\"]* ]] && ! shopt -q extquote; then
+ local ntype
+ ble/syntax/parse/nest-type
+ if [[ $ntype == '"${' ]]; then
+ ((aqdel=ctx,aquot=ctx))
+ fi
+ fi
+ fi
+ if rex='^`([^`\]|\\(.|$))*(`?)|^'\''[^'\'']*('\''?)' && [[ $tail =~ $rex ]]; then
+ ((_ble_syntax_attr[i]=aqdel,
+ _ble_syntax_attr[i+1]=aquot,
+ i+=${#BASH_REMATCH},
+ _ble_syntax_attr[i-1]=${#BASH_REMATCH[3]}||${#BASH_REMATCH[4]}?aqdel:_ble_attr_ERR))
+ return 0
+ fi
+ if ((ctx!=_ble_ctx_QUOT)); then
+ if rex='^(\$?")([^'"${_ble_syntax_bash_chars[_ble_ctx_QUOT]}"']*)("?)' && [[ $tail =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]} # for bash-3.1 ${#arr[n]} bug
+ if [[ ${BASH_REMATCH[3]} ]]; then
+ ((_ble_syntax_attr[i]=aqdel,
+ _ble_syntax_attr[i+${#rematch1}]=aquot,
+ i+=${#BASH_REMATCH},
+ _ble_syntax_attr[i-1]=aqdel))
+ else
+ ble/syntax/parse/nest-push "$_ble_ctx_QUOT"
+ if (((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR)&&aqdel!=_ble_attr_QDEL)); then
+ ((_ble_syntax_attr[i]=aqdel,
+ _ble_syntax_attr[i+${#rematch1}-1]=_ble_attr_QDEL,
+ _ble_syntax_attr[i+${#rematch1}]=_ble_ctx_QUOT,
+ i+=${#BASH_REMATCH}))
+ else
+ ((_ble_syntax_attr[i]=aqdel,
+ _ble_syntax_attr[i+${#rematch1}]=_ble_ctx_QUOT,
+ i+=${#BASH_REMATCH}))
+ fi
+ fi
+ return 0
+ elif rex='^\$'\''(([^'\''\]|\\(.|$))*)('\''?)' && [[ $tail =~ $rex ]]; then
+ ((_ble_syntax_attr[i]=aqdel,i+=2))
+ local t=${BASH_REMATCH[1]} rematch4=${BASH_REMATCH[4]}
+ local rex='\\[abefnrtvE"'\''\?]|\\[0-7]{1,3}|\\c.|\\x[0-9a-fA-F]{1,2}'
+ ((_ble_bash>=40200)) && rex=$rex'|\\u[0-9a-fA-F]{1,4}|\\U[0-9a-fA-F]{1,8}'
+ local rex='^([^'\''\]*)('$rex'|(\\.))'
+ while [[ $t =~ $rex ]]; do
+ local m1=${BASH_REMATCH[1]} m2=${BASH_REMATCH[2]}
+ [[ $m1 ]] && ((_ble_syntax_attr[i]=aquot,i+=${#m1}))
+ if [[ ${BASH_REMATCH[3]} ]]; then
+ ((_ble_syntax_attr[i]=aquot))
+ else
+ ((_ble_syntax_attr[i]=_ble_attr_QESC))
+ fi
+ ((i+=${#m2}))
+ t=${t:${#BASH_REMATCH}}
+ done
+ [[ $t ]] && ((_ble_syntax_attr[i]=aquot,i+=${#t}))
+ if [[ $rematch4 ]]; then
+ ((_ble_syntax_attr[i++]=aqdel))
+ else
+ ((_ble_syntax_attr[i-1]=_ble_attr_ERR))
+ fi
+ return 0
+ fi
+ fi
+ return 1
+}
+function ble/syntax:bash/check-process-subst {
+ if [[ $tail == ['<>']'('* ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_CMDX" '('
+ ((_ble_syntax_attr[i]=_ble_attr_DEL,i+=2))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/check-comment {
+ if shopt -q interactive_comments; then
+ if ((wbegin<0||wbegin==i)) && local rex=$'^#[^\n]*' && [[ $tail =~ $rex ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_COMMENT,
+ i+=${#BASH_REMATCH}))
+ return 0
+ fi
+ fi
+ return 1
+}
+function ble/syntax:bash/check-glob {
+ [[ $tail == ['[?*@+!()|']* ]] || return 1
+ local ntype= force_attr=
+ if ((ctx==_ble_ctx_VRHS||ctx==_ble_ctx_ARGVR||ctx==_ble_ctx_ARGER||ctx==_ble_ctx_VALR||ctx==_ble_ctx_RDRS)); then
+ force_attr=$ctx
+ ntype="glob_attr=$force_attr"
+ elif ((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_FARGI1)); then
+ force_attr=$_ble_attr_ERR
+ ntype="glob_attr=$force_attr"
+ elif ((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR)); then
+ ntype="glob_ctx=$ctx"
+ elif ((ctx==_ble_ctx_PATN||ctx==_ble_ctx_BRAX)); then
+ ble/syntax/parse/nest-type
+ local exit_attr=
+ if [[ $ntype == glob_attr=* ]]; then
+ force_attr=${ntype#*=}
+ exit_attr=$force_attr
+ elif ((ctx==_ble_ctx_BRAX)); then
+ force_attr=$ctx
+ ntype="glob_attr=$force_attr"
+ elif ((ctx==_ble_ctx_PATN)); then
+ ((exit_attr=_ble_syntax_attr[inest]))
+ [[ $ntype != glob_ctx=* ]] && ntype=
+ else
+ ntype=
+ fi
+ elif [[ $1 == assign ]]; then
+ ntype='a['
+ fi
+ if [[ $tail == ['?*@+!']'('* ]] && shopt -q extglob; then
+ ble/syntax/parse/nest-push "$_ble_ctx_PATN" "$ntype"
+ ((_ble_syntax_attr[i]=${force_attr:-_ble_attr_GLOB},i+=2))
+ return 0
+ fi
+ local histc1=${_ble_syntax_bash_histc12::1}
+ [[ $histc1 && $tail == "$histc1"* ]] && return 1
+ if [[ $tail == '['* ]]; then
+ if ((ctx==_ble_ctx_BRAX)); then
+ ((_ble_syntax_attr[i++]=force_attr))
+ [[ $tail == '[!'* ]] && ((i++))
+ return 0
+ fi
+ ble/syntax/parse/nest-push "$_ble_ctx_BRAX" "$ntype"
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB}))
+ [[ $tail == '[!'* ]] && ((i++))
+ if [[ ${text:i:1} == ']' ]]; then
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_ctx_BRAX}))
+ elif [[ ${text:i:1} == '[' ]]; then
+ if [[ ${text:i+1:1} == [:=.] ]]; then
+ ble/syntax/parse/set-lookahead 2
+ else
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_ctx_BRAX}))
+ [[ ${text:i:1} == '!'* ]] && ((i++))
+ fi
+ fi
+ return 0
+ elif [[ $tail == ['?*']* ]]; then
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB}))
+ return 0
+ elif [[ $tail == ['@+!']* ]]; then
+ ((_ble_syntax_attr[i++]=${force_attr:-ctx}))
+ return 0
+ elif ((ctx==_ble_ctx_PATN||ctx==_ble_ctx_BRAX)); then
+ if [[ $tail == '('* ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_PATN" "$ntype"
+ ((_ble_syntax_attr[i++]=${force_attr:-ctx}))
+ return 0
+ elif [[ $tail == ')'* ]]; then
+ if ((ctx==_ble_ctx_PATN)); then
+ ((_ble_syntax_attr[i++]=exit_attr))
+ ble/syntax/parse/nest-pop
+ else
+ ((_ble_syntax_attr[i++]=${force_attr:-ctx}))
+ fi
+ return 0
+ elif [[ $tail == '|'* ]]; then
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB}))
+ return 0
+ fi
+ fi
+ return 1
+}
+_ble_syntax_bash_histexpand_RexWord=
+_ble_syntax_bash_histexpand_RexMods=
+_ble_syntax_bash_histexpand_RexEventDef=
+_ble_syntax_bash_histexpand_RexQuicksubDef=
+_ble_syntax_bash_histexpand_RexEventFmt=
+_ble_syntax_bash_histexpand_RexQuicksubFmt=
+function ble/syntax:bash/check-history-expansion/.initialize {
+ local spaces=$_ble_term_IFS nl=$'\n'
+ local rex_event='-?[0-9]+|[!#]|[^-$^*%:'$spaces'=?!#;&|<>()]+|\?[^?'$nl']*\??'
+ _ble_syntax_bash_histexpand_RexEventDef='^!('$rex_event')'
+ local rex_word1='([0-9]+|[$%^])'
+ local rex_wordsA=':('$rex_word1'?-'$rex_word1'?|\*|'$rex_word1'\*?)'
+ local rex_wordsB='([$%^]?-'$rex_word1'?|\*|[$^%][*-]?)'
+ _ble_syntax_bash_histexpand_RexWord='('$rex_wordsA'|'$rex_wordsB')?'
+ local rex_modifier=':[htrepqx]|:[gGa]?&|:[gGa]?s(/([^\/]|\\.)*){0,2}(/|$)'
+ _ble_syntax_bash_histexpand_RexMods='('$rex_modifier')*'
+ _ble_syntax_bash_histexpand_RexQuicksubDef='\^([^^\]|\\.)*\^([^^\]|\\.)*\^'
+ _ble_syntax_bash_histexpand_RexQuicksubFmt='@A([^@C\]|\\.)*@A([^@C\]|\\.)*@A'
+ _ble_syntax_bash_histexpand_RexEventFmt='^@A('$rex_event'|@A)'
+}
+ble/syntax:bash/check-history-expansion/.initialize
+function ble/syntax:bash/check-history-expansion/.initialize-event {
+ local histc1=${_ble_syntax_bash_histc12::1}
+ if [[ $histc1 == '!' ]]; then
+ rex_event=$_ble_syntax_bash_histexpand_RexEventDef
+ else
+ local A="[$histc1]"
+ [[ $histc1 == '^' ]] && A='\^'
+ rex_event=$_ble_syntax_bash_histexpand_RexEventFmt
+ rex_event=${rex_event//@A/"$A"}
+ fi
+}
+function ble/syntax:bash/check-history-expansion/.initialize-quicksub {
+ local histc2=${_ble_syntax_bash_histc12:1:1}
+ if [[ $histc2 == '^' ]]; then
+ rex_quicksub=$_ble_syntax_bash_histexpand_RexQuicksubDef
+ else
+ rex_quicksub=$_ble_syntax_bash_histexpand_RexQuicksubFmt
+ rex_quicksub=${rex_quicksub//@A/"[$histc2]"}
+ rex_quicksub=${rex_quicksub//@C/"$histc2"}
+ fi
+}
+function ble/syntax:bash/check-history-expansion/.check-modifiers {
+ [[ ${text:i} =~ $_ble_syntax_bash_histexpand_RexMods ]] &&
+ ((i+=${#BASH_REMATCH}))
+ if local rex='^:[gGa]?s(.)'; [[ ${text:i} =~ $rex ]]; then
+ local del=${BASH_REMATCH[1]}
+ local A="[$del]" B="[^$del]"
+ [[ $del == '^' || $del == ']' ]] && A='\'$del
+ [[ $del != '\' ]] && B=$B'|\\.'
+ local rex_substitute='^:[gGa]?s('$A'('$B')*){0,2}('$A'|$)'
+ if [[ ${text:i} =~ $rex_substitute ]]; then
+ ((i+=${#BASH_REMATCH}))
+ ble/syntax:bash/check-history-expansion/.check-modifiers
+ return 0
+ fi
+ fi
+ if [[ ${text:i} == ':'[gGa]* ]]; then
+ ((_ble_syntax_attr[i+1]=_ble_attr_ERR,i+=2))
+ elif [[ ${text:i} == ':'* ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_ERR,i++))
+ fi
+}
+function ble/syntax:bash/check-history-expansion {
+ [[ -o histexpand ]] || return 1
+ local histc1=${_ble_syntax_bash_histc12:0:1}
+ local histc2=${_ble_syntax_bash_histc12:1:1}
+ if [[ $histc1 && $tail == "$histc1"[^"$_ble_syntax_bash_histstop"]* ]]; then
+ if ((ctx==_ble_ctx_QUOT)); then
+ local tail=${tail%%'"'*}
+ [[ $tail == '!' ]] && return 1
+ fi
+ ((_ble_syntax_attr[i]=_ble_attr_HISTX))
+ local rex_event
+ ble/syntax:bash/check-history-expansion/.initialize-event
+ if [[ $tail =~ $rex_event ]]; then
+ ((i+=${#BASH_REMATCH}))
+ elif [[ $tail == "$histc1"['-:0-9^$%*']* ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_HISTX,i++))
+ else
+ ((_ble_syntax_attr[i+1]=_ble_attr_ERR,i+=2))
+ return 0
+ fi
+ [[ ${text:i} =~ $_ble_syntax_bash_histexpand_RexWord ]] &&
+ ((i+=${#BASH_REMATCH}))
+ ble/syntax:bash/check-history-expansion/.check-modifiers
+ return 0
+ elif ((i==0)) && [[ $histc2 && $tail == "$histc2"* ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_HISTX))
+ local rex_quicksub
+ ble/syntax:bash/check-history-expansion/.initialize-quicksub
+ if [[ $tail =~ $rex_quicksub ]]; then
+ ((i+=${#BASH_REMATCH}))
+ ble/syntax:bash/check-history-expansion/.check-modifiers
+ return 0
+ else
+ ((i+=${#tail}))
+ return 0
+ fi
+ fi
+ return 1
+}
+function ble/syntax:bash/starts-with-histchars {
+ [[ $_ble_syntax_bash_histc12 && $tail == ["$_ble_syntax_bash_histc12"]* ]]
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_QUOT]=ble/syntax:bash/ctx-quot
+function ble/syntax:bash/ctx-quot {
+ if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_QUOT]}]+" 1; then
+ return 0
+ elif [[ $tail == '"'* ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_QDEL,
+ i+=1))
+ ble/syntax/parse/nest-pop
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i]=ctx,i++))
+ return 0
+ fi
+ return 1
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_CASE]=ble/syntax:bash/ctx-case
+function ble/syntax:bash/ctx-case {
+ if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs ]]; then
+ ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH}))
+ return 0
+ elif [[ $tail == '('* ]]; then
+ ((_ble_syntax_attr[i++]=_ble_attr_GLOB,ctx=_ble_ctx_CPATX))
+ return 0
+ elif [[ $tail == 'esac'$_ble_syntax_bash_RexDelimiter* || $tail == 'esac' ]]; then
+ ((ctx=_ble_ctx_CMDX))
+ ble/syntax:bash/ctx-command
+ else
+ ((ctx=_ble_ctx_CPATX))
+ ble/syntax:bash/ctx-command-case-pattern-expect
+ fi
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_PATN]=ble/syntax:bash/ctx-globpat
+_BLE_SYNTAX_FEND[_ble_ctx_PATN]=ble/syntax:bash/ctx-globpat.end
+function ble/syntax:bash/ctx-globpat/get-stop-chars {
+ chars=${_ble_syntax_bash_chars[_ble_ctx_PATN]}
+ local ntype; ble/syntax/parse/nest-type
+ if [[ $ntype == glob_ctx=* ]]; then
+ local gctx=${ntype#glob_ctx=}
+ if ((gctx==_ble_ctx_PWORD||gctx==_ble_ctx_PWORDE)); then
+ chars=}$chars
+ elif ((gctx==_ble_ctx_PWORDR)); then
+ chars=}/$chars
+ fi
+ fi
+}
+function ble/syntax:bash/ctx-globpat {
+ local chars; ble/syntax:bash/ctx-globpat/get-stop-chars
+ if ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then
+ return 0
+ elif ble/syntax:bash/check-process-subst; then
+ return 0
+ elif [[ $tail == ['<>']* ]]; then
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/check-glob; then
+ return 0
+ elif ble/syntax:bash/check-brace-expansion; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i]=ctx,i++))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-globpat.end {
+ local is_end= tail=${text:i}
+ local ntype; ble/syntax/parse/nest-type
+ if [[ $ntype == glob_ctx=* ]]; then
+ local gctx=${ntype#glob_ctx=}
+ if ((gctx==_ble_ctx_PWORD||gctx==_ble_ctx_PWORDE)); then
+ [[ ! $tail || $tail == '}'* ]] && is_end=1
+ elif ((gctx==_ble_ctx_PWORDR)); then
+ [[ ! $tail || $tail == ['/}']* ]] && is_end=1
+ fi
+ fi
+ if [[ $is_end ]]; then
+ ble/syntax/parse/nest-pop
+ ble/syntax/parse/check-end
+ return 0
+ fi
+ return 0
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_BRAX]=ble/syntax:bash/ctx-bracket-expression
+_BLE_SYNTAX_FEND[_ble_ctx_BRAX]=ble/syntax:bash/ctx-bracket-expression.end
+function ble/syntax:bash/ctx-bracket-expression {
+ local nctx; ble/syntax/parse/nest-ctx
+ if ((nctx==_ble_ctx_PATN)); then
+ local chars; ble/syntax:bash/ctx-globpat/get-stop-chars
+ elif ((nctx==_ble_ctx_PWORD||nctx==_ble_ctx_PWORDE||nctx==_ble_ctx_PWORDR)); then
+ local chars=${_ble_syntax_bash_chars[nctx]}
+ else
+ local chars=${_ble_syntax_bash_chars[_ble_ctx_ARGI]//'~'}
+ fi
+ chars="][${chars#']'}"
+ local ntype; ble/syntax/parse/nest-type
+ local force_attr=; [[ $ntype == glob_attr=* ]] && force_attr=${ntype#*=}
+ local rex
+ if [[ $tail == ']'* ]]; then
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB}))
+ ble/syntax/parse/nest-pop
+ if [[ $ntype == 'a[' ]]; then
+ local is_assign=
+ if [[ $tail == ']='* ]]; then
+ ((_ble_syntax_attr[i++]=ctx,is_assign=1))
+ elif [[ $tail == ']+'* ]]; then
+ ble/syntax/parse/set-lookahead 2
+ [[ $tail == ']+=' ]] && ((_ble_syntax_attr[i]=ctx,i+=2,is_assign=1))
+ fi
+ if [[ $is_assign ]]; then
+ ble/util/assert '[[ ${_ble_syntax_bash_command_CtxAssign[ctx]} ]]'
+ ((ctx=_ble_syntax_bash_command_CtxAssign[ctx]))
+ if local tail=${text:i}; [[ $tail == '~'* ]]; then
+ ble/syntax:bash/check-tilde-expansion rhs
+ fi
+ fi
+ fi
+ return 0
+ elif [[ $tail == '['* ]]; then
+ rex='^\[@([^'$chars']+(@\]?)?)?'
+ rex=${rex//@/:}'|'${rex//@/'\.'}'|'${rex//@/=}'|^\['
+ [[ $tail =~ $rex ]]
+ ((_ble_syntax_attr[i]=${force_attr:-ctx},
+ i+=${#BASH_REMATCH}))
+ return 0
+ elif ctx=${force_attr:-$ctx} ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then
+ return 0
+ elif ble/syntax:bash/check-process-subst; then
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/check-glob; then
+ return 0
+ elif ble/syntax:bash/check-brace-expansion; then
+ return 0
+ elif ble/syntax:bash/check-tilde-expansion; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i++]=${force_attr:-ctx}))
+ return 0
+ elif ((nctx==_ble_ctx_PATN)) && [[ $tail == ['<>']* ]]; then
+ ((_ble_syntax_attr[i++]=${force_attr:-ctx}))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-bracket-expression.end {
+ local is_end=
+ local tail=${text:i}
+ if [[ ! $tail ]]; then
+ is_end=1
+ else
+ local nctx; ble/syntax/parse/nest-ctx
+ local external_ctx=$nctx
+ if ((nctx==_ble_ctx_PATN)); then
+ local ntype; ble/syntax/parse/nest-type
+ [[ $ntype == glob_ctx=* ]] &&
+ external_ctx=${ntype#glob_ctx=}
+ fi
+ if ((external_ctx==_ble_ctx_PATN)); then
+ [[ $tail == ')'* ]] && is_end=1
+ elif ((external_ctx==_ble_ctx_PWORD||external_ctx==_ble_ctx_PWORDE)); then
+ [[ $tail == '}'* ]] && is_end=1
+ elif ((external_ctx==_ble_ctx_PWORDR)); then
+ [[ $tail == ['}/']* ]] && is_end=1
+ else
+ if ble/syntax:bash/check-word-end/is-delimiter; then
+ is_end=1
+ elif [[ $tail == ':'* && ${_ble_syntax_bash_command_IsAssign[ctx]} ]]; then
+ is_end=1
+ fi
+ fi
+ fi
+ if [[ $is_end ]]; then
+ ble/syntax/parse/nest-pop
+ ble/syntax/parse/check-end
+ return "$?"
+ fi
+ return 0
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_PARAM]=ble/syntax:bash/ctx-param
+_BLE_SYNTAX_FCTX[_ble_ctx_PWORD]=ble/syntax:bash/ctx-pword
+_BLE_SYNTAX_FCTX[_ble_ctx_PWORDR]=ble/syntax:bash/ctx-pword
+_BLE_SYNTAX_FCTX[_ble_ctx_PWORDE]=ble/syntax:bash/ctx-pword-error
+function ble/syntax:bash/ctx-param {
+ if [[ $tail == '}'* ]]; then
+ ((_ble_syntax_attr[i]=_ble_syntax_attr[inest]))
+ ((i+=1))
+ ble/syntax/parse/nest-pop
+ return 0
+ fi
+ local rex='##?|%%?|:?[-?=+]|:|/[/#%]?'
+ ((_ble_bash>=40000)) && rex=$rex'|,,?|\^\^?|~~?'
+ if ((_ble_bash>=50100)); then
+ rex=$rex'|@[QEPAaUuLK]?'
+ elif ((_ble_bash>=40400)); then
+ rex=$rex'|@[QEPAa]?'
+ fi
+ rex='^('$rex')'
+ if [[ $tail =~ $rex ]]; then
+ ((_ble_syntax_attr[i]=_ble_ctx_PARAM,
+ i+=${#BASH_REMATCH}))
+ if [[ $BASH_REMATCH == '/'* ]]; then
+ ((ctx=_ble_ctx_PWORDR))
+ elif [[ $BASH_REMATCH == : ]]; then
+ ((ctx=_ble_ctx_EXPR,_ble_syntax_attr[i-1]=_ble_ctx_EXPR))
+ elif [[ $BASH_REMATCH == @* ]]; then
+ ((ctx=_ble_ctx_PWORDE))
+ else
+ ((ctx=_ble_ctx_PWORD))
+ [[ $BASH_REMATCH == [':-+=?#%']* ]] &&
+ tail=${text:i} ble/syntax:bash/check-tilde-expansion pword
+ fi
+ return 0
+ else
+ local i0=$i
+ ((ctx=_ble_ctx_PWORD))
+ ble/syntax:bash/ctx-pword || return 1
+ if ((i0+2<=i)); then
+ ((_ble_syntax_attr[i0+1])) ||
+ ((_ble_syntax_attr[i0+1]=_ble_syntax_attr[i0]))
+ fi
+ ((_ble_syntax_attr[i0]=_ble_attr_ERR))
+ return 0
+ fi
+}
+function ble/syntax:bash/ctx-pword {
+ if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}]+"; then
+ return 0
+ elif ((ctx==_ble_ctx_PWORDR)) && [[ $tail == '/'* ]]; then
+ ((_ble_syntax_attr[i++]=_ble_ctx_PARAM,ctx=_ble_ctx_PWORD))
+ return 0
+ elif [[ $tail == '}'* ]]; then
+ ((_ble_syntax_attr[i]=_ble_syntax_attr[inest]))
+ ((i+=1))
+ ble/syntax/parse/nest-pop
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/check-glob; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i]=ctx,i++))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-pword-error {
+ local i0=$i
+ if ble/syntax:bash/ctx-pword; then
+ [[ $tail == '}'* ]] ||
+ ((_ble_syntax_attr[i0]=_ble_attr_ERR))
+ return 0
+ else
+ return 1
+ fi
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_EXPR]=ble/syntax:bash/ctx-expr
+function ble/syntax:bash/ctx-expr/.count-paren {
+ if [[ $char == ')' ]]; then
+ if [[ $ntype == '((' || $ntype == '$((' ]]; then
+ if [[ $tail == '))'* ]]; then
+ ((_ble_syntax_attr[i]=_ble_syntax_attr[inest]))
+ ((i+=2))
+ ble/syntax/parse/nest-pop
+ else
+ ((ctx=_ble_ctx_ARGX0,
+ _ble_syntax_attr[i++]=_ble_syntax_attr[inest]))
+ fi
+ return 0
+ elif [[ $ntype == '(' || $ntype == 'NQ(' ]]; then
+ ((_ble_syntax_attr[i++]=ctx))
+ ble/syntax/parse/nest-pop
+ return 0
+ fi
+ elif [[ $char == '(' ]]; then
+ local ntype2='('
+ [[ $ntype == '$((' || $ntype == 'NQ(' ]] && ntype2='NQ('
+ ble/syntax/parse/nest-push "$_ble_ctx_EXPR" "$ntype2"
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-expr/.count-bracket {
+ if [[ $char == ']' ]]; then
+ if [[ $ntype == '[' || $ntype == '$[' ]]; then
+ ((_ble_syntax_attr[i]=_ble_syntax_attr[inest]))
+ ((i++))
+ ble/syntax/parse/nest-pop
+ return 0
+ elif [[ $ntype == [ad]'[' ]]; then
+ ((_ble_syntax_attr[i++]=_ble_ctx_EXPR))
+ ble/syntax/parse/nest-pop
+ if [[ $tail == ']='* ]]; then
+ ((i++))
+ tail=${text:i} ble/syntax:bash/check-tilde-expansion rhs
+ elif ((_ble_bash>=30100)) && [[ $tail == ']+'* ]]; then
+ ble/syntax/parse/set-lookahead 2
+ if [[ $tail == ']+='* ]]; then
+ ((i+=2))
+ tail=${text:i} ble/syntax:bash/check-tilde-expansion rhs
+ fi
+ else
+ if [[ $ntype == 'a[' ]]; then
+ if ((ctx==_ble_ctx_VRHS)); then
+ ((ctx=_ble_ctx_CMDI,wtype=_ble_ctx_CMDI))
+ elif ((ctx==_ble_ctx_ARGVR)); then
+ ((ctx=_ble_ctx_ARGVI,wtype=_ble_ctx_ARGVI))
+ elif ((ctx==_ble_ctx_ARGER)); then
+ ((ctx=_ble_ctx_ARGEI,wtype=_ble_ctx_ARGEI))
+ fi
+ else # ntype == 'd['
+ ((ctx=_ble_ctx_VALI,wtype=_ble_ctx_VALI))
+ fi
+ fi
+ return 0
+ elif [[ $ntype == 'v[' ]]; then
+ ((_ble_syntax_attr[i++]=_ble_ctx_EXPR))
+ ble/syntax/parse/nest-pop
+ return 0
+ fi
+ elif [[ $char == '[' ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_EXPR" '['
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-expr/.count-brace {
+ if [[ $char == '}' ]]; then
+ ((_ble_syntax_attr[i]=_ble_syntax_attr[inest]))
+ ((i++))
+ ble/syntax/parse/nest-pop
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-expr {
+ local rex
+ if rex='^[a-zA-Z_][a-zA-Z_0-9]*'; [[ $tail =~ $rex ]]; then
+ local rematch=$BASH_REMATCH
+ local ret; ble/syntax/highlight/vartype "$BASH_REMATCH" readvar:expr
+ ((_ble_syntax_attr[i]=ret,i+=${#rematch}))
+ return 0
+ elif rex='^0[xX][0-9a-fA-F]*|^[0-9]+(#[0-9a-zA-Z@_]*)?'; [[ $tail =~ $rex ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_VAR_NUMBER,i+=${#BASH_REMATCH}))
+ return 0
+ elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}a-zA-Z_0-9]+" 1; then
+ return 0
+ elif [[ $tail == ['][()}']* ]]; then
+ local char=${tail::1} ntype
+ ble/syntax/parse/nest-type
+ if [[ $ntype == *'(' ]]; then
+ ble/syntax:bash/ctx-expr/.count-paren && return 0
+ elif [[ $ntype == *'[' ]]; then
+ ble/syntax:bash/ctx-expr/.count-bracket && return 0
+ elif [[ $ntype == '${' || $ntype == '"${' ]]; then
+ ble/syntax:bash/ctx-expr/.count-brace && return 0
+ else
+ ble/util/assert 'false' "unexpected ntype=$ntype for arithmetic expression"
+ fi
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i]=ctx,i++))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/check-brace-expansion {
+ [[ $tail == '{'* ]] || return 1
+ local rex='^\{[-+0-9a-zA-Z.]*(\}?)'
+ [[ $tail =~ $rex ]]
+ local str=$BASH_REMATCH
+ local force_attr= inactive=
+ if [[ $- != *B* ]]; then
+ inactive=1
+ elif ((ctx==_ble_ctx_CONDI||ctx==_ble_ctx_CONDQ||ctx==_ble_ctx_RDRS||ctx==_ble_ctx_VRHS)); then
+ inactive=1
+ elif ((ctx==_ble_ctx_PATN||ctx==_ble_ctx_BRAX)); then
+ local ntype; ble/syntax/parse/nest-type
+ if [[ $ntype == glob_attr=* ]]; then
+ force_attr=${ntype#*=}
+ (((force_attr==_ble_ctx_RDRS||force_attr==_ble_ctx_VRHS||force_attr==_ble_ctx_ARGVR||force_attr==_ble_ctx_ARGER||force_attr==_ble_ctx_VALR)&&(inactive=1)))
+ elif ((ctx==_ble_ctx_BRAX)); then
+ local nctx; ble/syntax/parse/nest-ctx
+ (((nctx==_ble_ctx_CONDI||octx==_ble_ctx_CONDQ)&&(inactive=1)))
+ fi
+ elif ((ctx==_ble_ctx_BRACE1||ctx==_ble_ctx_BRACE2)); then
+ local ntype; ble/syntax/parse/nest-type
+ if [[ $ntype == glob_attr=* ]]; then
+ force_attr=${ntype#*=}
+ fi
+ fi
+ if [[ $inactive ]]; then
+ ((_ble_syntax_attr[i]=${force_attr:-ctx},i+=${#str}))
+ return 0
+ fi
+ [[ ${_ble_syntax_bash_command_IsAssign[ctx]} ]] &&
+ ctx=${_ble_syntax_bash_command_IsAssign[ctx]}
+ if rex='^\{(([-+]?[0-9]+)\.\.[-+]?[0-9]+|[a-zA-Z]\.\.[a-zA-Z])(\.\.[-+]?[0-9]+)?\}$'; [[ $str =~ $rex ]]; then
+ if [[ $force_attr ]]; then
+ ((_ble_syntax_attr[i]=force_attr,i+=${#str}))
+ else
+ local rematch1=${BASH_REMATCH[1]}
+ local rematch2=${BASH_REMATCH[2]}
+ local rematch3=${BASH_REMATCH[3]}
+ local len2=${#rematch2}; ((len2||(len2=1)))
+ local attr=$_ble_attr_BRACE
+ if ((ctx==_ble_ctx_RDRF||ctx==_ble_ctx_RDRD||ctx==_ble_ctx_RDRD2)); then
+ local lhs=${rematch1::len2} rhs=${rematch1:len2+2}
+ if [[ $rematch2 ]]; then
+ local lhs1=$((10#0${lhs#[-+]})); [[ $lhs == -* ]] && ((lhs1=-lhs1))
+ local rhs1=$((10#0${rhs#[-+]})); [[ $rhs == -* ]] && ((rhs1=-rhs1))
+ lhs=$lhs1 rhs=$rhs1
+ fi
+ [[ $lhs != "$rhs" ]] && ((attr=_ble_attr_ERR))
+ fi
+ ((_ble_syntax_attr[i++]=attr))
+ ((_ble_syntax_attr[i]=ctx,i+=len2,
+ _ble_syntax_attr[i]=_ble_attr_BRACE,i+=2,
+ _ble_syntax_attr[i]=ctx,i+=${#rematch1}-len2-2))
+ if [[ $rematch3 ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_BRACE,i+=2,
+ _ble_syntax_attr[i]=ctx,i+=${#rematch3}-2))
+ fi
+ ((_ble_syntax_attr[i++]=attr))
+ fi
+ return 0
+ fi
+ local ntype=
+ ((ctx==_ble_ctx_RDRF||ctx==_ble_ctx_RDRD||ctx==_ble_ctx_RDRD2)) && force_attr=$ctx
+ [[ $force_attr ]] && ntype="glob_attr=$force_attr"
+ ble/syntax/parse/nest-push "$_ble_ctx_BRACE1" "$ntype"
+ local len=$((${#str}-1))
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_BRACE},
+ len&&(_ble_syntax_attr[i]=${force_attr:-ctx},i+=len)))
+ return 0
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_BRACE1]=ble/syntax:bash/ctx-brace-expansion
+_BLE_SYNTAX_FCTX[_ble_ctx_BRACE2]=ble/syntax:bash/ctx-brace-expansion
+_BLE_SYNTAX_FEND[_ble_ctx_BRACE1]=ble/syntax:bash/ctx-brace-expansion.end
+_BLE_SYNTAX_FEND[_ble_ctx_BRACE2]=ble/syntax:bash/ctx-brace-expansion.end
+function ble/syntax:bash/ctx-brace-expansion {
+ if [[ $tail == '}'* ]] && ((ctx==_ble_ctx_BRACE2)); then
+ local force_attr=
+ local ntype; ble/syntax/parse/nest-type
+ [[ $ntype == glob_attr=* ]] && force_attr=$_ble_attr_ERR # ※${ntype#*=} ではなくエラー
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_BRACE}))
+ ble/syntax/parse/nest-pop
+ return 0
+ elif [[ $tail == ','* ]]; then
+ local force_attr=
+ local ntype; ble/syntax/parse/nest-type
+ [[ $ntype == glob_attr=* ]] && force_attr=${ntype#*=}
+ ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_BRACE}))
+ ((ctx=_ble_ctx_BRACE2))
+ return 0
+ fi
+ local chars=",${_ble_syntax_bash_chars[_ble_ctx_ARGI]//'~:'}"
+ ((ctx==_ble_ctx_BRACE2)) && chars="}$chars"
+ ble/syntax:bash/cclass/update/reorder chars
+ if ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then
+ return 0
+ elif ble/syntax:bash/check-process-subst; then
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/check-glob; then
+ return 0
+ elif ble/syntax:bash/check-brace-expansion; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-brace-expansion.end {
+ if ((i==${#text})) || ble/syntax:bash/check-word-end/is-delimiter; then
+ ble/syntax/parse/nest-pop
+ ble/syntax/parse/check-end
+ return "$?"
+ fi
+ return 0
+}
+function ble/syntax:bash/check-tilde-expansion {
+ [[ $tail == ['~:']* ]] || return 1
+ local rhs_enabled=
+ { ((ctx==_ble_ctx_VRHS||ctx==_ble_ctx_ARGVR||ctx==_ble_ctx_VALR||ctx==_ble_ctx_ARGER)) ||
+ ! ble/base/is-POSIXLY_CORRECT; } && rhs_enabled=1
+ local tilde_enabled=$((i==wbegin||ctx==_ble_ctx_PWORD))
+ [[ $1 == rhs && $rhs_enabled ]] && tilde_enabled=1 # = の直後
+ if [[ $tail == ':'* ]]; then
+ _ble_syntax_attr[i++]=$ctx
+ if [[ $rhs_enabled ]]; then
+ if ! ((tilde_enabled=_ble_syntax_bash_command_IsAssign[ctx])); then
+ if ((ctx==_ble_ctx_BRAX)); then
+ local nctx; ble/syntax/parse/nest-ctx
+ ((tilde_enabled=_ble_syntax_bash_command_IsAssign[nctx]))
+ fi
+ fi
+ fi
+ local tail=${text:i}
+ [[ $tail == '~'* ]] || return 0
+ fi
+ if ((tilde_enabled)); then
+ local chars="${_ble_syntax_bash_chars[_ble_ctx_ARGI]}/:"
+ ((ctx==_ble_ctx_PWORD)) && chars=${chars/'{'/'{}'}
+ ble/syntax:bash/cclass/update/reorder chars
+ local delimiters="$_ble_term_IFS;|&)<>"
+ local rex='^(~\+|~[^'$chars']*)([^'$delimiters'/:]?)'; [[ $tail =~ $rex ]]
+ local str=${BASH_REMATCH[1]}
+ local path attr=$ctx
+ builtin eval "path=$str"
+ if [[ ! ${BASH_REMATCH[2]} && $path != "$str" ]]; then
+ ((attr=_ble_attr_TILDE))
+ if ((ctx==_ble_ctx_BRAX)); then
+ ble/util/assert 'ble/util/unlocal tail; [[ $tail == ":~"* ]]'
+ ble/syntax/parse/nest-pop
+ fi
+ else
+ if [[ $str == '~+' ]]; then
+ ble/syntax/parse/set-lookahead 3
+ str='~'
+ fi
+ fi
+ ((_ble_syntax_attr[i]=attr,i+=${#str}))
+ else
+ ((_ble_syntax_attr[i]=ctx,i++)) # skip tilde
+ local chars=${_ble_syntax_bash_chars[_ble_ctx_ARGI]}
+ ble/syntax:bash/check-plain-with-escape "[^$chars]+" # 追加(失敗してもOK)
+ fi
+ return 0
+}
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_CMDI]=$_ble_ctx_VRHS
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_COARGI]=$_ble_ctx_VRHS
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_ARGVI]=$_ble_ctx_ARGVR
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_ARGEI]=$_ble_ctx_ARGER
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_ARGI]=$_ble_ctx_ARGQ
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_FARGI3]=$_ble_ctx_FARGQ3
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_CARGI1]=$_ble_ctx_CARGQ1
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_CPATI]=$_ble_ctx_CPATQ
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_VALI]=$_ble_ctx_VALQ
+_ble_syntax_bash_command_CtxAssign[_ble_ctx_CONDI]=$_ble_ctx_CONDQ
+_ble_syntax_bash_command_IsAssign[_ble_ctx_VRHS]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_IsAssign[_ble_ctx_ARGVR]=$_ble_ctx_ARGVI
+_ble_syntax_bash_command_IsAssign[_ble_ctx_ARGER]=$_ble_ctx_ARGEI
+_ble_syntax_bash_command_IsAssign[_ble_ctx_ARGQ]=$_ble_ctx_ARGI
+_ble_syntax_bash_command_IsAssign[_ble_ctx_FARGQ3]=$_ble_ctx_FARGI3
+_ble_syntax_bash_command_IsAssign[_ble_ctx_CARGQ1]=$_ble_ctx_CARGI1
+_ble_syntax_bash_command_IsAssign[_ble_ctx_CPATQ]=$_ble_ctx_CPATI
+_ble_syntax_bash_command_IsAssign[_ble_ctx_VALR]=$_ble_ctx_VALI
+_ble_syntax_bash_command_IsAssign[_ble_ctx_VALQ]=$_ble_ctx_VALI
+_ble_syntax_bash_command_IsAssign[_ble_ctx_CONDQ]=$_ble_ctx_CONDI
+function ble/syntax:bash/check-variable-assignment {
+ ((wbegin==i)) || return 1
+ if ((ctx==_ble_ctx_VALI)) && [[ $tail == '['* ]]; then
+ ((ctx=_ble_ctx_VALR))
+ ble/syntax/parse/nest-push "$_ble_ctx_EXPR" 'd['
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ fi
+ [[ ${_ble_syntax_bash_command_CtxAssign[ctx]} ]] || return 1
+ local suffix='[=[]'
+ ((_ble_bash>=30100)) && suffix=$suffix'|\+=?'
+ local rex_assign="^([a-zA-Z_][a-zA-Z_0-9]*)($suffix)"
+ [[ $tail =~ $rex_assign ]] || return 1
+ local rematch=$BASH_REMATCH
+ local rematch1=${BASH_REMATCH[1]} # for bash-3.1 ${#arr[n]} bug
+ local rematch2=${BASH_REMATCH[2]} # for bash-3.1 ${#arr[n]} bug
+ if [[ $rematch2 == '+' ]]; then
+ ble/syntax/parse/set-lookahead $((${#rematch}+1))
+ return 1
+ fi
+ local variable_assign=
+ if ((ctx==_ble_ctx_CMDI||ctx==_ble_ctx_ARGVI||ctx==_ble_ctx_ARGEI&&${#rematch2})); then
+ local ret; ble/syntax/highlight/vartype "$rematch1"
+ ((wtype=_ble_attr_VAR,
+ _ble_syntax_attr[i]=ret,
+ i+=${#rematch},
+ ${#rematch2}&&(_ble_syntax_attr[i-${#rematch2}]=_ble_ctx_EXPR),
+ variable_assign=1,
+ ctx=_ble_syntax_bash_command_CtxAssign[ctx]))
+ else
+ ((_ble_syntax_attr[i]=ctx,
+ i+=${#rematch}))
+ fi
+ if [[ $rematch2 == '[' ]]; then
+ if [[ $variable_assign ]]; then
+ i=$((i-1)) ble/syntax/parse/nest-push "$_ble_ctx_EXPR" 'a['
+ else
+ ((i--))
+ tail=${text:i} ble/syntax:bash/check-glob assign
+ fi
+ elif [[ $rematch2 == *'=' ]]; then
+ if [[ $variable_assign && ${text:i} == '('* ]]; then
+ ble/syntax:bash/ctx-values/enter
+ ((_ble_syntax_attr[i++]=_ble_attr_DEL))
+ else
+ [[ $variable_assign ]] || ((ctx=_ble_syntax_bash_command_CtxAssign[ctx]))
+ if local tail=${text:i}; [[ $tail == '~'* ]]; then
+ ble/syntax:bash/check-tilde-expansion rhs
+ fi
+ fi
+ fi
+ return 0
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGX]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGX0]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDX]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDX1]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDXT]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDXC]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDXE]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDXD]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDXD0]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDXV]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGI]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGQ]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CMDI]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_VRHS]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGVR]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGER]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FEND[_ble_ctx_CMDI]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_ARGI]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_ARGQ]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_VRHS]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_ARGVR]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_ARGER]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGVX]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGVI]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FEND[_ble_ctx_ARGVI]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGEX]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_ARGEI]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FEND[_ble_ctx_ARGEI]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_SARGX1]=ble/syntax:bash/ctx-command-compound-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_FARGX1]=ble/syntax:bash/ctx-command-compound-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_FARGX2]=ble/syntax:bash/ctx-command-compound-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_FARGX3]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_FARGI1]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_FARGI2]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_FARGI3]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_FARGQ3]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FEND[_ble_ctx_FARGI1]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_FARGI2]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_FARGI3]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_FARGQ3]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_CARGX1]=ble/syntax:bash/ctx-command-compound-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_CARGX2]=ble/syntax:bash/ctx-command-compound-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_CPATX]=ble/syntax:bash/ctx-command-case-pattern-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_CPATX0]=ble/syntax:bash/ctx-command-case-pattern-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_CARGI1]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CARGQ1]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CARGI2]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CPATI]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_CPATQ]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FEND[_ble_ctx_CARGI1]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_CARGQ1]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_CARGI2]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_CPATI]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_CPATQ]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_TARGX1]=ble/syntax:bash/ctx-command-time-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_TARGX2]=ble/syntax:bash/ctx-command-time-expect
+_BLE_SYNTAX_FCTX[_ble_ctx_TARGI1]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FCTX[_ble_ctx_TARGI2]=ble/syntax:bash/ctx-command
+_BLE_SYNTAX_FEND[_ble_ctx_TARGI1]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_TARGI2]=ble/syntax:bash/ctx-command/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_COARGX]=ble/syntax:bash/ctx-command-compound-expect
+_BLE_SYNTAX_FEND[_ble_ctx_COARGI]=ble/syntax:bash/ctx-coproc/check-word-end
+function ble/syntax:bash/starts-with-delimiter-or-redirect {
+ local delimiters=$_ble_syntax_bash_RexDelimiter
+ local redirect=$_ble_syntax_bash_RexRedirect
+ [[ ( $tail =~ ^$delimiters || $wbegin -lt 0 && $tail =~ ^$redirect || $wbegin -lt 0 && $tail == $'\\\n'* ) && $tail != ['<>']'('* ]]
+}
+function ble/syntax:bash/starts-with-delimiter {
+ [[ $tail == ["$_ble_term_IFS;|&<>()"]* && $tail != ['<>']'('* ]]
+}
+function ble/syntax:bash/check-word-end/is-delimiter {
+ local tail=${text:i}
+ if [[ $tail == [!"$_ble_term_IFS;|&<>()"]* ]]; then
+ return 1
+ elif [[ $tail == ['<>']* ]]; then
+ ble/syntax/parse/set-lookahead 2
+ [[ $tail == ['<>']'('* ]] && return 1
+ fi
+ return 0
+}
+function ble/syntax:bash/check-here-document-from {
+ local spaces=$1
+ [[ $nparam && $spaces == *$'\n'* ]] || return 1
+ local rex="$_ble_term_FS@([RI][QH][^$_ble_term_FS]*)(.*$)" && [[ $nparam =~ $rex ]] || return 1
+ local rematch1=${BASH_REMATCH[1]}
+ local rematch2=${BASH_REMATCH[2]}
+ local padding=${spaces%%$'\n'*}
+ ((_ble_syntax_attr[i]=ctx,i+=${#padding}))
+ nparam=${nparam::${#nparam}-${#BASH_REMATCH}}${nparam:${#nparam}-${#rematch2}}
+ ble/syntax/parse/nest-push "$_ble_ctx_HERE0"
+ ((i++))
+ nparam=$rematch1
+ return 0
+}
+function ble/syntax:bash/ctx-coproc/.is-next-compound {
+ local p=$i ahead=1 tail=${text:i}
+ if local rex=$'^[ \t]+'; [[ $tail =~ $rex ]]; then
+ ((p+=${#BASH_REMATCH}))
+ ahead=1 tail=${text:p}
+ fi
+ local is_compound=
+ if [[ $tail == '('* ]]; then
+ is_compound=1
+ elif rex='^[a-z]+|^\[\[?|^[{}!]'; [[ $tail =~ $rex ]]; then
+ local rematch=$BASH_REMATCH
+ ((p+=${#rematch}))
+ [[ $rematch == ['{}!'] || $rematch == '[[' ]]; ahead=$?
+ rex='^(\[\[|for|select|case|if|while|until|fi|done|esac|then|elif|else|do|[{}!]|coproc|function)$'
+ if [[ $rematch =~ $rex ]]; then
+ if rex='^[;|&()'$_ble_term_IFS']|^$|^[<>]\(?' ahead=1; [[ ${text:p} =~ $rex ]]; then
+ local rematch=$BASH_REMATCH
+ ((p+=${#rematch}))
+ [[ $rematch && $rematch != ['<>'] ]]; ahead=$?
+ [[ $rematch != ['<>']'(' ]] && is_compound=1
+ fi
+ fi
+ fi
+ ble/syntax/parse/set-lookahead $((p+ahead-i))
+ [[ $is_compound ]]
+}
+function ble/syntax:bash/ctx-coproc/check-word-end {
+ ble/util/assert '((ctx==_ble_ctx_COARGI))'
+ ((wbegin<0)) && return 1
+ ble/syntax:bash/check-word-end/is-delimiter || return 1
+ local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i
+ local word=${text:wbegin:wlen}
+ local wt=$wtype
+ if local rex='^[_a-zA-Z0-9]+$'; [[ $word =~ $rex ]]; then
+ if ble/syntax:bash/ctx-coproc/.is-next-compound; then
+ ((_ble_syntax_attr[wbegin]=_ble_attr_VAR))
+ ((ctx=_ble_ctx_CMDXC,type=_ble_ctx_ARGVI))
+ ble/syntax/parse/word-pop
+ return 0
+ fi
+ fi
+ ((ctx=_ble_ctx_CMDI,wtype=_ble_ctx_CMDX))
+ ble/syntax:bash/ctx-command/check-word-end
+}
+_ble_syntax_bash_command_EndCtx=()
+_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGI]=$_ble_ctx_ARGX
+_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGQ]=$_ble_ctx_ARGX
+_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGVI]=$_ble_ctx_ARGVX
+_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGVR]=$_ble_ctx_ARGVX
+_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGEI]=$_ble_ctx_ARGEX
+_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGER]=$_ble_ctx_ARGEX
+_ble_syntax_bash_command_EndCtx[_ble_ctx_VRHS]=$_ble_ctx_CMDXV
+_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGI1]=$_ble_ctx_FARGX2
+_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGI2]=$_ble_ctx_FARGX3
+_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGI3]=$_ble_ctx_FARGX3
+_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGQ3]=$_ble_ctx_FARGX3
+_ble_syntax_bash_command_EndCtx[_ble_ctx_CARGI1]=$_ble_ctx_CARGX2
+_ble_syntax_bash_command_EndCtx[_ble_ctx_CARGQ1]=$_ble_ctx_CARGX2
+_ble_syntax_bash_command_EndCtx[_ble_ctx_CARGI2]=$_ble_ctx_CASE
+_ble_syntax_bash_command_EndCtx[_ble_ctx_CPATI]=$_ble_ctx_CPATX0
+_ble_syntax_bash_command_EndCtx[_ble_ctx_CPATQ]=$_ble_ctx_CPATX0
+_ble_syntax_bash_command_EndCtx[_ble_ctx_TARGI1]=$((_ble_bash>=40200?_ble_ctx_TARGX2:_ble_ctx_CMDXT)) #1
+_ble_syntax_bash_command_EndCtx[_ble_ctx_TARGI2]=$_ble_ctx_CMDXT
+_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGX]=$_ble_ctx_ARGI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGX0]=$_ble_ctx_ARGI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGVX]=$_ble_ctx_ARGVI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGEX]=$_ble_ctx_ARGEI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDX]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDX1]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXT]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXC]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXE]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXD]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXD0]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXV]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_FARGX1]=$_ble_ctx_FARGI1 # 変数名
+_ble_syntax_bash_command_EndWtype[_ble_ctx_SARGX1]=$_ble_ctx_ARGI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_FARGX2]=$_ble_ctx_FARGI2 # in
+_ble_syntax_bash_command_EndWtype[_ble_ctx_FARGX3]=$_ble_ctx_ARGI # in
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CARGX1]=$_ble_ctx_ARGI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CARGX2]=$_ble_ctx_CARGI2 # in
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CPATX]=$_ble_ctx_CPATI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_CPATX0]=$_ble_ctx_CPATI
+_ble_syntax_bash_command_EndWtype[_ble_ctx_TARGX1]=$_ble_ctx_ARGI # -p
+_ble_syntax_bash_command_EndWtype[_ble_ctx_TARGX2]=$_ble_ctx_ARGI # --
+_ble_syntax_bash_command_Expect=()
+_ble_syntax_bash_command_Expect[_ble_ctx_CMDXC]='^(\(|\{|\(\(|\[\[|for|select|case|if|while|until)$'
+_ble_syntax_bash_command_Expect[_ble_ctx_CMDXE]='^(\}|fi|done|esac|then|elif|else|do)$'
+_ble_syntax_bash_command_Expect[_ble_ctx_CMDXD]='^(\{|do)$'
+_ble_syntax_bash_command_Expect[_ble_ctx_CMDXD0]='^(\{|do)$'
+function ble/syntax:bash/ctx-command/check-word-end {
+ ((wbegin<0)) && return 1
+ ble/syntax:bash/check-word-end/is-delimiter || return 1
+ local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i
+ local word=${text:wbegin:wlen}
+ local wt=$wtype
+ [[ ${_ble_syntax_bash_command_EndWtype[wt]} ]] &&
+ wtype=${_ble_syntax_bash_command_EndWtype[wt]}
+ local rex_expect_command=${_ble_syntax_bash_command_Expect[wt]}
+ if [[ $rex_expect_command ]]; then
+ [[ $word =~ $rex_expect_command ]] || ((wtype=_ble_attr_ERR))
+ fi
+ if ((wt==_ble_ctx_CMDX1)); then
+ local rex='^(then|elif|else|do|\}|done|fi|esac)$'
+ [[ $word =~ $rex ]] && ((wtype=_ble_attr_ERR))
+ fi
+ ble/syntax/parse/word-pop
+ if ((ctx==_ble_ctx_CMDI)); then
+ local ret
+ ble/alias#expand "$word"; local word_expanded=$ret
+ if ((wt!=_ble_ctx_CMDXV)); then # Note: 変数代入の直後はキーワードは処理しない
+ local processed=
+ case "$word_expanded" in
+ ('[[')
+ ble/syntax/parse/touch-updated-attr "$wbeg"
+ ((_ble_syntax_attr[wbeg]=_ble_attr_DEL,
+ ctx=_ble_ctx_ARGX0))
+ ble/syntax/parse/word-cancel # 単語 "[[" (とその内部のノード全て) を削除
+ if [[ $word == '[[' ]]; then
+ _ble_syntax_attr[wbeg+1]= # 角括弧式として着色されているのを消去
+ fi
+ i=$wbeg ble/syntax/parse/nest-push "$_ble_ctx_CONDX"
+ i=$wbeg ble/syntax/parse/word-push "$_ble_ctx_CMDI" "$wbeg"
+ ble/syntax/parse/word-pop
+ return 0 ;;
+ ('time') ((ctx=_ble_ctx_TARGX1)); processed=keyword ;;
+ ('!') ((ctx=_ble_ctx_CMDXT)) ; processed=keyword ;;
+ ('if'|'while'|'until') ((ctx=_ble_ctx_CMDX1)) ; processed=begin ;;
+ ('for') ((ctx=_ble_ctx_FARGX1)); processed=begin ;;
+ ('select') ((ctx=_ble_ctx_SARGX1)); processed=begin ;;
+ ('case') ((ctx=_ble_ctx_CARGX1)); processed=begin ;;
+ ('{')
+ ((ctx=_ble_ctx_CMDX1))
+ if ((wt==_ble_ctx_CMDXD||wt==_ble_ctx_CMDXD0)); then
+ processed=middle # "for ...; {" などの時
+ else
+ processed=begin
+ fi ;;
+ ('then'|'elif'|'else'|'do') ((ctx=_ble_ctx_CMDX1)) ; processed=middle ;;
+ ('}'|'done'|'fi'|'esac') ((ctx=_ble_ctx_CMDXE)) ; processed=end ;;
+ ('coproc')
+ if ((_ble_bash>=40000)); then
+ if ble/syntax:bash/ctx-coproc/.is-next-compound; then
+ ((ctx=_ble_ctx_CMDXC))
+ else
+ ((ctx=_ble_ctx_COARGX))
+ fi
+ processed=keyword
+ fi ;;
+ ('function')
+ ((ctx=_ble_ctx_ARGX))
+ local isfuncsymx=$'\t\n'' "$&'\''();<>\`|' rex_space=$'[ \t]' rex
+ if rex="^$rex_space+" && [[ ${text:i} =~ $rex ]]; then
+ ((_ble_syntax_attr[i]=_ble_ctx_ARGX,i+=${#BASH_REMATCH},ctx=_ble_ctx_ARGX))
+ if rex="^([^#$isfuncsymx][^$isfuncsymx]*)($rex_space*)(\(\(|\($rex_space*\)?)?" && [[ ${text:i} =~ $rex ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ local rematch2=${BASH_REMATCH[2]}
+ local rematch3=${BASH_REMATCH[3]}
+ ((_ble_syntax_attr[i]=_ble_attr_FUNCDEF,i+=${#rematch1},
+ ${#rematch2}&&(_ble_syntax_attr[i]=_ble_ctx_CMDX1,i+=${#rematch2})))
+ if [[ $rematch3 == '('*')' ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_DEL,i+=${#rematch3},ctx=_ble_ctx_CMDXC))
+ elif ((_ble_bash>=40200)) && [[ $rematch3 == '((' ]]; then
+ ble/syntax/parse/set-lookahead 2
+ ((ctx=_ble_ctx_CMDXC))
+ elif [[ $rematch3 == '('* ]]; then
+ ((_ble_syntax_attr[i]=_ble_attr_ERR,ctx=_ble_ctx_ARGX0))
+ ble/syntax/parse/nest-push "$_ble_ctx_CMDX1" '('
+ ((${#rematch3}>=2&&(_ble_syntax_attr[i+1]=_ble_ctx_CMDX1),i+=${#rematch3}))
+ else
+ ((ctx=_ble_ctx_CMDXC))
+ fi
+ processed=keyword
+ fi
+ fi
+ [[ $processed ]] || ((_ble_syntax_attr[i-1]=_ble_attr_ERR)) ;;
+ esac
+ if [[ $processed ]]; then
+ local attr=
+ case $processed in
+ (keyword) attr=$_ble_attr_KEYWORD ;;
+ (begin) attr=$_ble_attr_KEYWORD_BEGIN ;;
+ (end) attr=$_ble_attr_KEYWORD_END ;;
+ (middle) attr=$_ble_attr_KEYWORD_MID ;;
+ esac
+ if [[ $attr ]]; then
+ ble/syntax/parse/touch-updated-attr "$wbeg"
+ ((_ble_syntax_attr[wbeg]=attr))
+ fi
+ return 0
+ fi
+ fi
+ ((ctx=_ble_ctx_ARGX))
+ if local rex='^([ ]*)(\([ ]*\)?)?'; [[ ${text:i} =~ $rex && $BASH_REMATCH ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ local rematch2=${BASH_REMATCH[2]}
+ if [[ $rematch2 == '('*')' ]]; then
+ _ble_syntax_tree[i-1]="$_ble_attr_FUNCDEF ${_ble_syntax_tree[i-1]#* }"
+ ((_ble_syntax_attr[i]=_ble_ctx_CMDX1,i+=${#rematch1},
+ _ble_syntax_attr[i]=_ble_attr_DEL,i+=${#rematch2},
+ ctx=_ble_ctx_CMDXC))
+ elif [[ $rematch2 == '('* ]]; then
+ ((_ble_syntax_attr[i]=_ble_ctx_ARGX0,i+=${#rematch1},
+ _ble_syntax_attr[i]=_ble_attr_ERR,
+ ctx=_ble_ctx_ARGX0))
+ ble/syntax/parse/nest-push "$_ble_ctx_PATN"
+ ((${#rematch2}>=2&&(_ble_syntax_attr[i+1]=_ble_ctx_CMDXC),
+ i+=${#rematch2}))
+ else
+ ((_ble_syntax_attr[i]=_ble_ctx_ARGX,i+=${#rematch1}))
+ fi
+ fi
+ case $word_expanded in
+ ('declare'|'readonly'|'typeset'|'local'|'export'|'alias')
+ ((ctx=_ble_ctx_ARGVX)) ;;
+ ('eval')
+ ((ctx=_ble_ctx_ARGEX)) ;;
+ esac
+ return 0
+ fi
+ if ((ctx==_ble_ctx_FARGI2)); then
+ if [[ $word == do ]]; then
+ ((ctx=_ble_ctx_CMDX1))
+ return 0
+ fi
+ fi
+ if ((ctx==_ble_ctx_FARGI2||ctx==_ble_ctx_CARGI2)); then
+ if [[ $word != in ]]; then
+ ble/syntax/parse/touch-updated-attr "$wbeg"
+ ((_ble_syntax_attr[wbeg]=_ble_attr_ERR))
+ fi
+ fi
+ if ((_ble_syntax_bash_command_EndCtx[ctx])); then
+ ((ctx=_ble_syntax_bash_command_EndCtx[ctx]))
+ fi
+ return 0
+}
+_ble_syntax_bash_command_Opt=()
+_ble_syntax_bash_command_Opt[_ble_ctx_ARGX]=1
+_ble_syntax_bash_command_Opt[_ble_ctx_ARGX0]=1
+_ble_syntax_bash_command_Opt[_ble_ctx_ARGVX]=1
+_ble_syntax_bash_command_Opt[_ble_ctx_ARGEX]=1
+_ble_syntax_bash_command_Opt[_ble_ctx_CMDXV]=1
+_ble_syntax_bash_command_Opt[_ble_ctx_CMDXE]=1
+_ble_syntax_bash_command_Opt[_ble_ctx_CMDXD0]=1
+_ble_syntax_bash_is_command_form_for=
+function ble/syntax:bash/ctx-command/.check-delimiter-or-redirect {
+ if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs || $wbegin -lt 0 && $tail == $'\\\n'* ]]; then
+ local spaces=$BASH_REMATCH
+ if [[ $tail == $'\\\n'* ]]; then
+ spaces=$'\\\n'
+ elif [[ $spaces == *$'\n'* ]]; then
+ ble/syntax:bash/check-here-document-from "$spaces" && return 0
+ if ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX||ctx==_ble_ctx_CMDXV||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXE)); then
+ ((ctx=_ble_ctx_CMDX))
+ elif ((ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_FARGX3||ctx==_ble_ctx_CMDXD0)); then
+ ((ctx=_ble_ctx_CMDXD))
+ fi
+ fi
+ ((_ble_syntax_attr[i]=ctx,i+=${#spaces}))
+ return 0
+ elif [[ $tail =~ ^$_ble_syntax_bash_RexRedirect ]]; then
+ local len=${#BASH_REMATCH}
+ local rematch1=${BASH_REMATCH[1]}
+ local rematch3=${BASH_REMATCH[3]}
+ ((_ble_syntax_attr[i]=_ble_attr_DEL,
+ ${#rematch1}<len&&(_ble_syntax_attr[i+${#rematch1}]=_ble_ctx_ARGX)))
+ if ((ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT)); then
+ ((ctx=_ble_ctx_CMDXV))
+ elif ((ctx==_ble_ctx_CMDXC||ctx==_ble_ctx_CMDXD||ctx==_ble_ctx_CMDXD0)); then
+ ((ctx=_ble_ctx_CMDXV,
+ _ble_syntax_attr[i]=_ble_attr_ERR))
+ elif ((ctx==_ble_ctx_CMDXE)); then
+ ((ctx=_ble_ctx_ARGX0))
+ elif ((ctx==_ble_ctx_FARGX3)); then
+ ((_ble_syntax_attr[i]=_ble_attr_ERR))
+ fi
+ if [[ ${text:i+len} != [!$'\n|&()']* ]]; then
+ ((_ble_syntax_attr[i+len-1]=_ble_attr_ERR))
+ else
+ if [[ $rematch3 == '>&' ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_RDRD2" "$rematch3"
+ elif [[ $rematch1 == *'&' ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_RDRD" "$rematch3"
+ elif [[ $rematch1 == *'<<<' ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_RDRS" "$rematch3"
+ elif [[ $rematch1 == *\<\< ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_RDRH" "$rematch3"
+ elif [[ $rematch1 == *\<\<- ]]; then
+ ble/syntax/parse/nest-push "$_ble_ctx_RDRI" "$rematch3"
+ else
+ ble/syntax/parse/nest-push "$_ble_ctx_RDRF" "$rematch3"
+ fi
+ fi
+ ((i+=len))
+ return 0
+ elif local rex='^(&&|\|[|&]?)|^;(;&?|&)|^[;&]'
+ ((_ble_bash<40000)) && rex='^(&&|\|\|?)|^;(;)|^[;&]'
+ [[ $tail =~ $rex ]]
+ then
+ if [[ $BASH_REMATCH == ';' ]]; then
+ if ((ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_FARGX3||ctx==_ble_ctx_CMDXD0)); then
+ ((_ble_syntax_attr[i++]=_ble_attr_DEL,ctx=_ble_ctx_CMDXD))
+ return 0
+ elif ((ctx==_ble_ctx_CMDXT)); then
+ ((_ble_syntax_attr[i++]=_ble_attr_DEL,ctx=_ble_bash>=40400?_ble_ctx_CMDX:_ble_ctx_CMDXE))
+ return 0
+ fi
+ fi
+ local rematch1=${BASH_REMATCH[1]} rematch2=${BASH_REMATCH[2]}
+ ((_ble_syntax_attr[i]=_ble_attr_DEL,
+ (_ble_syntax_bash_command_Opt[ctx]||ctx==_ble_ctx_CMDX&&${#rematch2})||
+ (_ble_syntax_attr[i]=_ble_attr_ERR)))
+ ((ctx=${#rematch1}?_ble_ctx_CMDX1:(
+ ${#rematch2}?_ble_ctx_CASE:
+ _ble_ctx_CMDX)))
+ ((i+=${#BASH_REMATCH}))
+ return 0
+ elif local rex='^\(\(?' && [[ $tail =~ $rex ]]; then
+ local m=${BASH_REMATCH[0]}
+ if ((ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXC)); then
+ ((_ble_syntax_attr[i]=_ble_attr_DEL))
+ ((ctx=${#m}==1?_ble_ctx_CMDXE:_ble_ctx_ARGX0))
+ [[ $_ble_syntax_bash_is_command_form_for && $tail == '(('* ]] && ((ctx=_ble_ctx_CMDXD0))
+ ble/syntax/parse/nest-push $((${#m}==1?_ble_ctx_CMDX1:_ble_ctx_EXPR)) "$m"
+ ((i+=${#m}))
+ else
+ ble/syntax/parse/nest-push "$_ble_ctx_PATN"
+ ((_ble_syntax_attr[i++]=_ble_attr_ERR))
+ fi
+ return 0
+ elif [[ $tail == ')'* ]]; then
+ local ntype
+ ble/syntax/parse/nest-type
+ local attr=
+ if [[ $ntype == '(' || $ntype == '$(' || $ntype == '((' || $ntype == '$((' ]]; then
+ ((attr=_ble_syntax_attr[inest]))
+ fi
+ if [[ $attr ]]; then
+ ((_ble_syntax_attr[i]=(ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDXV||ctx==_ble_ctx_CMDXE||ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX)?attr:_ble_attr_ERR,
+ i+=1))
+ ble/syntax/parse/nest-pop
+ return 0
+ fi
+ fi
+ return 1
+}
+_ble_syntax_bash_command_BeginCtx=()
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGX]=$_ble_ctx_ARGI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGX0]=$_ble_ctx_ARGI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGVX]=$_ble_ctx_ARGVI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGEX]=$_ble_ctx_ARGEI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDX]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDX1]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXT]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXC]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXE]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXD]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXD0]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXV]=$_ble_ctx_CMDI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_FARGX1]=$_ble_ctx_FARGI1
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_SARGX1]=$_ble_ctx_FARGI1
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_FARGX2]=$_ble_ctx_FARGI2
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_FARGX3]=$_ble_ctx_FARGI3
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CARGX1]=$_ble_ctx_CARGI1
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CARGX2]=$_ble_ctx_CARGI2
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CPATX]=$_ble_ctx_CPATI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_CPATX0]=$_ble_ctx_CPATI
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_TARGX1]=$_ble_ctx_TARGI1
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_TARGX2]=$_ble_ctx_TARGI2
+_ble_syntax_bash_command_BeginCtx[_ble_ctx_COARGX]=$_ble_ctx_COARGI
+_ble_syntax_bash_command_isARGI[_ble_ctx_CMDI]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_VRHS]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_ARGI]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_ARGQ]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_ARGVI]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_ARGVR]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_ARGEI]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_ARGER]=1
+_ble_syntax_bash_command_isARGI[_ble_ctx_FARGI1]=1 # var
+_ble_syntax_bash_command_isARGI[_ble_ctx_FARGI2]=1 # in
+_ble_syntax_bash_command_isARGI[_ble_ctx_FARGI3]=1 # args...
+_ble_syntax_bash_command_isARGI[_ble_ctx_FARGQ3]=1 # args... (= の後)
+_ble_syntax_bash_command_isARGI[_ble_ctx_CARGI1]=1 # value
+_ble_syntax_bash_command_isARGI[_ble_ctx_CARGQ1]=1 # value (= の後)
+_ble_syntax_bash_command_isARGI[_ble_ctx_CARGI2]=1 # in
+_ble_syntax_bash_command_isARGI[_ble_ctx_CPATI]=1 # pattern
+_ble_syntax_bash_command_isARGI[_ble_ctx_CPATQ]=1 # pattern
+_ble_syntax_bash_command_isARGI[_ble_ctx_TARGI1]=1 # -p
+_ble_syntax_bash_command_isARGI[_ble_ctx_TARGI2]=1 # --
+_ble_syntax_bash_command_isARGI[_ble_ctx_COARGI]=1 # var (coproc の後)
+function ble/syntax:bash/ctx-command/.check-word-begin {
+ if ((wbegin<0)); then
+ local octx
+ ((octx=ctx,
+ wtype=octx,
+ ctx=_ble_syntax_bash_command_BeginCtx[ctx]))
+ ble/util/assert '((ctx!=0))' "invalid ctx=$octx at the beginning of words" ||
+ ((ctx=wtype=_ble_ctx_ARGI))
+ ble/syntax/parse/word-push "$wtype" "$i"
+ ((octx!=_ble_ctx_ARGX0&&octx!=_ble_ctx_CPATX0)); return "$?" # return unexpectedWbegin
+ fi
+ ble/util/assert '((_ble_syntax_bash_command_isARGI[ctx]))' "invalid ctx=$ctx in words"
+ return 0
+}
+function ble/syntax:bash/ctx-command {
+ if ble/syntax:bash/starts-with-delimiter-or-redirect; then
+ ble/util/assert '
+ ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX||
+ ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_FARGX3||ctx==_ble_ctx_COARGX||
+ ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXC||
+ ctx==_ble_ctx_CMDXE||ctx==_ble_ctx_CMDXD||ctx==_ble_ctx_CMDXD0||ctx==_ble_ctx_CMDXV))' "invalid ctx=$ctx @ i=$i"
+ ble/util/assert '((wbegin<0&&wtype<0))' "invalid word-context (wtype=$wtype wbegin=$wbegin) on non-word char."
+ ble/syntax:bash/ctx-command/.check-delimiter-or-redirect; return "$?"
+ fi
+ ble/syntax:bash/check-comment && return 0
+ local unexpectedWbegin=-1
+ ble/syntax:bash/ctx-command/.check-word-begin || ((unexpectedWbegin=i))
+ local wtype0=$wtype i0=$i
+ local flagConsume=0
+ if ble/syntax:bash/check-variable-assignment; then
+ flagConsume=1
+ elif local rex='^([^'${_ble_syntax_bash_chars[_ble_ctx_ARGI]}']+|\\.)'; [[ $tail =~ $rex ]]; then
+ local rematch=$BASH_REMATCH
+ local attr=$ctx
+ [[ $BASH_REMATCH == '\'? ]] && attr=$_ble_attr_QESC
+ ((_ble_syntax_attr[i]=attr,i+=${#rematch}))
+ flagConsume=1
+ elif ble/syntax:bash/check-process-subst; then
+ flagConsume=1
+ elif ble/syntax:bash/check-quotes; then
+ flagConsume=1
+ elif ble/syntax:bash/check-dollar; then
+ flagConsume=1
+ elif ble/syntax:bash/check-glob; then
+ flagConsume=1
+ elif ble/syntax:bash/check-brace-expansion; then
+ flagConsume=1
+ elif ble/syntax:bash/check-tilde-expansion; then
+ flagConsume=1
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i]=ctx,i++))
+ flagConsume=1
+ fi
+ if ((flagConsume)); then
+ ble/util/assert '((wtype0>=0))'
+ if ((ctx==_ble_ctx_FARGI1)); then
+ local rex='^[a-zA-Z_][a-zA-Z_0-9]*$' attr=$_ble_attr_ERR
+ if ((i0==wbegin)) && [[ ${text:i0:i-i0} =~ $rex ]]; then
+ local ret; ble/syntax/highlight/vartype "$BASH_REMATCH"; attr=$ret
+ fi
+ ((_ble_syntax_attr[i0]=attr))
+ fi
+ [[ ${_ble_syntax_bash_command_Expect[wtype0]} ]] &&
+ ((_ble_syntax_attr[i0]=_ble_attr_ERR))
+ if ((unexpectedWbegin>=0)); then
+ ble/syntax/parse/touch-updated-attr "$unexpectedWbegin"
+ ((_ble_syntax_attr[unexpectedWbegin]=_ble_attr_ERR))
+ fi
+ return 0
+ else
+ return 1
+ fi
+}
+function ble/syntax:bash/ctx-command-compound-expect {
+ ble/util/assert '((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_CARGX2||ctx==_ble_ctx_COARGX))'
+ local _ble_syntax_bash_is_command_form_for=
+ if ble/syntax:bash/starts-with-delimiter-or-redirect; then
+ if ((ctx==_ble_ctx_FARGX2)) && [[ $tail == [$';\n']* ]]; then
+ ble/syntax:bash/ctx-command
+ return "$?"
+ elif ((ctx==_ble_ctx_FARGX1)) && [[ $tail == '(('* ]]; then
+ ((ctx=_ble_ctx_CMDX1,_ble_syntax_bash_is_command_form_for=1))
+ elif [[ $tail == $'\n'* ]]; then
+ if ((ctx==_ble_ctx_CARGX2)); then
+ ((_ble_syntax_attr[i++]=_ble_ctx_ARGX))
+ else
+ ((_ble_syntax_attr[i++]=_ble_attr_ERR,ctx=_ble_ctx_ARGX))
+ fi
+ return 0
+ elif [[ $tail =~ ^$_ble_syntax_bash_RexSpaces ]]; then
+ ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH}))
+ return 0
+ elif ((ctx!=_ble_ctx_COARGX)); then
+ local i0=$i
+ ((ctx=_ble_ctx_ARGX))
+ ble/syntax:bash/ctx-command/.check-delimiter-or-redirect || ((i++))
+ ((_ble_syntax_attr[i0]=_ble_attr_ERR))
+ return 0
+ fi
+ fi
+ local i0=$i
+ if ble/syntax:bash/check-comment; then
+ if ((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_COARGX)); then
+ ((_ble_syntax_attr[i0]=_ble_attr_ERR))
+ fi
+ return 0
+ fi
+ ble/syntax:bash/ctx-command
+}
+function ble/syntax:bash/ctx-command-expect/.match-word {
+ local word=$1 len=${#1}
+ if [[ $tail == "$word"* ]]; then
+ ble/syntax/parse/set-lookahead $((len+1))
+ if ((${#tail}==len)) || i=$((i+len)) ble/syntax:bash/check-word-end/is-delimiter; then
+ return 0
+ fi
+ fi
+ return 1
+}
+function ble/syntax:bash/ctx-command-time-expect {
+ ble/util/assert '((ctx==_ble_ctx_TARGX1||ctx==_ble_ctx_TARGX2))'
+ if ble/syntax:bash/starts-with-delimiter-or-redirect; then
+ ble/util/assert '((wbegin<0&&wtype<0))'
+ if [[ $tail =~ ^$_ble_syntax_bash_RexSpaces ]]; then
+ ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH}))
+ return 0
+ else
+ ((ctx=_ble_ctx_CMDXT))
+ ble/syntax:bash/ctx-command/.check-delimiter-or-redirect; return "$?"
+ fi
+ fi
+ if ((ctx==_ble_ctx_TARGX1)); then
+ ble/syntax:bash/ctx-command-expect/.match-word '-p' ||
+ ((ctx=_ble_bash>=50100?_ble_ctx_TARGX2:_ble_ctx_CMDXT))
+ fi
+ if ((ctx==_ble_ctx_TARGX2)); then
+ ble/syntax:bash/ctx-command-expect/.match-word '--' ||
+ ((ctx=_ble_ctx_CMDXT))
+ fi
+ ble/syntax:bash/ctx-command
+}
+function ble/syntax:bash/ctx-command-case-pattern-expect {
+ ble/util/assert '((ctx==_ble_ctx_CPATX||ctx==_ble_ctx_CPATX0))'
+ if ble/syntax:bash/starts-with-delimiter-or-redirect; then
+ local delimiter=$BASH_REMATCH
+ if [[ $tail =~ ^$_ble_syntax_bash_RexSpaces ]]; then
+ ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH}))
+ elif [[ $tail == '|'* ]]; then
+ ((_ble_syntax_attr[i++]=ctx==_ble_ctx_CPATX?_ble_attr_ERR:_ble_attr_GLOB,ctx=_ble_ctx_CPATX))
+ elif [[ $tail == ')'* ]]; then
+ ((_ble_syntax_attr[i++]=ctx==_ble_ctx_CPATX?_ble_attr_ERR:_ble_attr_GLOB,ctx=_ble_ctx_CMDX))
+ elif [[ $tail == '('* ]]; then
+ ble/syntax:bash/ctx-command/.check-delimiter-or-redirect
+ else
+ ((_ble_syntax_attr[i]=_ble_attr_ERR,i+=${#delimiter}))
+ fi
+ return "$?"
+ fi
+ local i0=$i
+ if ble/syntax:bash/check-comment; then
+ ((_ble_syntax_attr[i0]=_ble_attr_ERR))
+ return 0
+ fi
+ ble/syntax:bash/ctx-command
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_VALX]=ble/syntax:bash/ctx-values
+_BLE_SYNTAX_FCTX[_ble_ctx_VALI]=ble/syntax:bash/ctx-values
+_BLE_SYNTAX_FEND[_ble_ctx_VALI]=ble/syntax:bash/ctx-values/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_VALR]=ble/syntax:bash/ctx-values
+_BLE_SYNTAX_FEND[_ble_ctx_VALR]=ble/syntax:bash/ctx-values/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_VALQ]=ble/syntax:bash/ctx-values
+_BLE_SYNTAX_FEND[_ble_ctx_VALQ]=ble/syntax:bash/ctx-values/check-word-end
+function ble/syntax:bash/ctx-values/enter {
+ local outer_nparam=$nparam
+ ble/syntax/parse/nest-push "$_ble_ctx_VALX"
+ nparam=$outer_nparam
+}
+function ble/syntax:bash/ctx-values/leave {
+ local inner_nparam=$nparam
+ ble/syntax/parse/nest-pop
+ nparam=$inner_nparam
+}
+function ble/syntax:bash/ctx-values/check-word-end {
+ ((wbegin<0)) && return 1
+ [[ ${text:i:1} == [!"$_ble_term_IFS;|&<>()"] ]] && return 1
+ local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i
+ local word=${text:wbegin:wlen}
+ ble/syntax/parse/word-pop
+ ble/util/assert '((ctx==_ble_ctx_VALI||ctx==_ble_ctx_VALR||ctx==_ble_ctx_VALQ))' 'invalid context'
+ ((ctx=_ble_ctx_VALX))
+ return 0
+}
+function ble/syntax:bash/ctx-values {
+ if ble/syntax:bash/starts-with-delimiter; then
+ ble/util/assert '((ctx==_ble_ctx_VALX))' "invalid ctx=$ctx @ i=$i"
+ ble/util/assert '((wbegin<0&&wtype<0))' "invalid word-context (wtype=$wtype wbegin=$wbegin) on non-word char."
+ if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs ]]; then
+ local spaces=$BASH_REMATCH
+ ble/syntax:bash/check-here-document-from "$spaces" && return 0
+ ((_ble_syntax_attr[i]=ctx,i+=${#spaces}))
+ return 0
+ elif [[ $tail == ')'* ]]; then
+ ((_ble_syntax_attr[i++]=_ble_attr_DEL))
+ ble/syntax:bash/ctx-values/leave
+ return 0
+ elif [[ $type == ';'* ]]; then
+ ((_ble_syntax_attr[i++]=_ble_attr_ERR))
+ return 0
+ else
+ ((_ble_syntax_attr[i++]=_ble_attr_ERR))
+ return 0
+ fi
+ fi
+ if ble/syntax:bash/check-comment; then
+ return 0
+ fi
+ if ((wbegin<0)); then
+ ((ctx=_ble_ctx_VALI))
+ ble/syntax/parse/word-push "$ctx" "$i"
+ fi
+ ble/util/assert '((ctx==_ble_ctx_VALI||ctx==_ble_ctx_VALR||ctx==_ble_ctx_VALQ))' "invalid context ctx=$ctx"
+ if ble/syntax:bash/check-variable-assignment; then
+ return 0
+ elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_ARGI]}]+"; then
+ return 0
+ elif ble/syntax:bash/check-process-subst; then
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/check-glob; then
+ return 0
+ elif ble/syntax:bash/check-brace-expansion; then
+ return 0
+ elif ble/syntax:bash/check-tilde-expansion; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i]=ctx,i++))
+ return 0
+ fi
+ return 1
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_CONDX]=ble/syntax:bash/ctx-conditions
+_BLE_SYNTAX_FCTX[_ble_ctx_CONDI]=ble/syntax:bash/ctx-conditions
+_BLE_SYNTAX_FEND[_ble_ctx_CONDI]=ble/syntax:bash/ctx-conditions/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_CONDQ]=ble/syntax:bash/ctx-conditions
+_BLE_SYNTAX_FEND[_ble_ctx_CONDQ]=ble/syntax:bash/ctx-conditions/check-word-end
+function ble/syntax:bash/ctx-conditions/check-word-end {
+ ((wbegin<0)) && return 1
+ [[ ${text:i:1} == [!"$_ble_term_IFS;|&<>()"] ]] && return 1
+ local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i
+ local word=${text:wbegin:wlen}
+ ble/syntax/parse/word-pop
+ ble/util/assert '((ctx==_ble_ctx_CONDI||ctx==_ble_ctx_CONDQ))' 'invalid context'
+ if [[ $word == ']]' ]]; then
+ ble/syntax/parse/touch-updated-attr "$wbeg"
+ ((_ble_syntax_attr[wbeg]=_ble_attr_DEL))
+ ble/syntax/parse/nest-pop
+ else
+ ((ctx=_ble_ctx_CONDX))
+ fi
+ return 0
+}
+function ble/syntax:bash/ctx-conditions {
+ if ble/syntax:bash/starts-with-delimiter; then
+ ble/util/assert '((ctx==_ble_ctx_CONDX))' "invalid ctx=$ctx @ i=$i"
+ ble/util/assert '((wbegin<0&&wtype<0))' "invalid word-context (wtype=$wtype wbegin=$wbegin) on non-word char."
+ if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs ]]; then
+ ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH}))
+ return 0
+ else
+ ((_ble_syntax_attr[i++]=_ble_ctx_CONDI))
+ return 0
+ fi
+ fi
+ ble/syntax:bash/check-comment && return 0
+ if ((wbegin<0)); then
+ ((ctx=_ble_ctx_CONDI))
+ ble/syntax/parse/word-push "$ctx" "$i"
+ fi
+ ble/util/assert '((ctx==_ble_ctx_CONDI||ctx==_ble_ctx_CONDQ))' "invalid context ctx=$ctx"
+ if ble/syntax:bash/check-variable-assignment; then
+ return 0
+ elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_ARGI]}]+"; then
+ return 0
+ elif ble/syntax:bash/check-process-subst; then
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/check-glob; then
+ return 0
+ elif ble/syntax:bash/check-brace-expansion; then
+ return 0
+ elif ble/syntax:bash/check-tilde-expansion; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ else
+ ((_ble_syntax_attr[i++]=ctx))
+ return 0
+ fi
+ return 1
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_RDRF]=ble/syntax:bash/ctx-redirect
+_BLE_SYNTAX_FCTX[_ble_ctx_RDRD]=ble/syntax:bash/ctx-redirect
+_BLE_SYNTAX_FCTX[_ble_ctx_RDRD2]=ble/syntax:bash/ctx-redirect
+_BLE_SYNTAX_FCTX[_ble_ctx_RDRS]=ble/syntax:bash/ctx-redirect
+_BLE_SYNTAX_FEND[_ble_ctx_RDRF]=ble/syntax:bash/ctx-redirect/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_RDRD]=ble/syntax:bash/ctx-redirect/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_RDRD2]=ble/syntax:bash/ctx-redirect/check-word-end
+_BLE_SYNTAX_FEND[_ble_ctx_RDRS]=ble/syntax:bash/ctx-redirect/check-word-end
+function ble/syntax:bash/ctx-redirect/check-word-begin {
+ if ((wbegin<0)); then
+ ble/syntax/parse/word-push "$ctx" "$i"
+ ble/syntax/parse/touch-updated-word "$i" #■これは不要では?
+ fi
+}
+function ble/syntax:bash/ctx-redirect/check-word-end {
+ ((wbegin<0)) && return 1
+ ble/syntax:bash/check-word-end/is-delimiter || return 1
+ ble/syntax/parse/word-pop
+ ble/syntax/parse/nest-pop
+ ble/util/assert '((!_ble_syntax_bash_command_isARGI[ctx]))' "invalid ctx=$ctx in words"
+ return 0
+}
+function ble/syntax:bash/ctx-redirect {
+ if ble/syntax:bash/starts-with-delimiter-or-redirect; then
+ ((_ble_syntax_attr[i++]=_ble_attr_ERR))
+ [[ ${tail:1} =~ ^$_ble_syntax_bash_RexSpaces ]] &&
+ ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH}))
+ return 0
+ fi
+ if local i0=$i; ble/syntax:bash/check-comment; then
+ ((_ble_syntax_attr[i0]=_ble_attr_ERR))
+ return 0
+ fi
+ ble/syntax:bash/ctx-redirect/check-word-begin
+ if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_ARGI]}]+"; then
+ return 0
+ elif ble/syntax:bash/check-process-subst; then
+ return 0
+ elif ble/syntax:bash/check-quotes; then
+ return 0
+ elif ble/syntax:bash/check-dollar; then
+ return 0
+ elif ble/syntax:bash/check-glob; then
+ return 0
+ elif ble/syntax:bash/check-brace-expansion; then
+ return 0
+ elif ble/syntax:bash/check-tilde-expansion; then
+ return 0
+ elif ble/syntax:bash/starts-with-histchars; then
+ ble/syntax:bash/check-history-expansion ||
+ ((_ble_syntax_attr[i]=ctx,i++))
+ return 0
+ fi
+ return 1
+}
+_ble_syntax_bash_heredoc_EscSP='\040'
+_ble_syntax_bash_heredoc_EscHT='\011'
+_ble_syntax_bash_heredoc_EscLF='\012'
+_ble_syntax_bash_heredoc_EscFS='\034'
+function ble/syntax:bash/ctx-heredoc-word/initialize {
+ local ret
+ ble/util/s2c ' '
+ ble/util/sprintf _ble_syntax_bash_heredoc_EscSP '\\%03o' "$ret"
+ ble/util/s2c $'\t'
+ ble/util/sprintf _ble_syntax_bash_heredoc_EscHT '\\%03o' "$ret"
+ ble/util/s2c $'\n'
+ ble/util/sprintf _ble_syntax_bash_heredoc_EscLF '\\%03o' "$ret"
+ ble/util/s2c "$_ble_term_FS"
+ ble/util/sprintf _ble_syntax_bash_heredoc_EscFS '\\%03o' "$ret"
+}
+ble/syntax:bash/ctx-heredoc-word/initialize
+function ble/syntax:bash/ctx-heredoc-word/remove-quotes {
+ local text=$1 result=
+ local rex='^[^\$"'\'']+|^\$?["'\'']|^\\.?|^.'
+ while [[ $text && $text =~ $rex ]]; do
+ local rematch=$BASH_REMATCH
+ if [[ $rematch == \" || $rematch == \$\" ]]; then
+ if rex='^\$?"(([^\"]|\\.)*)(\\?$|")'; [[ $text =~ $rex ]]; then
+ local str=${BASH_REMATCH[1]}
+ local a b
+ b='\`' a='`'; str=${str//"$b"/"$a"}
+ b='\"' a='"'; str=${str//"$b"/"$a"} # WA #D1751 safe
+ b='\$' a='$'; str=${str//"$b"/"$a"}
+ b='\\' a='\'; str=${str//"$b"/"$a"}
+ result=$result$str
+ text=${text:${#BASH_REMATCH}}
+ continue
+ fi
+ elif [[ $rematch == \' ]]; then
+ if rex="^('[^']*)'?"; [[ $text =~ $rex ]]; then
+ builtin eval "result=\$result${BASH_REMATCH[1]}'"
+ text=${text:${#BASH_REMATCH}}
+ continue
+ fi
+ elif [[ $rematch == \$\' ]]; then
+ if rex='^(\$'\''([^\'\'']|\\.)*)('\''|\\?$)'; [[ $text =~ $rex ]]; then
+ builtin eval "result=\$result${BASH_REMATCH[1]}'"
+ text=${text:${#BASH_REMATCH}}
+ continue
+ fi
+ elif [[ $rematch == \\* ]]; then
+ result=$result${rematch:1}
+ text=${text:${#rematch}}
+ continue
+ fi
+ result=$result$rematch
+ text=${text:${#rematch}}
+ done
+ delimiter=$result$text
+}
+function ble/syntax:bash/ctx-heredoc-word/escape-delimiter {
+ local ret=$1
+ if [[ $ret == *[\\\'$_ble_term_IFS$_ble_term_FS]* ]]; then
+ local a b fs=$_ble_term_FS
+ a=\\ ; b='\'$a; ret=${ret//"$a"/"$b"}
+ a=\' ; b='\'$a; ret=${ret//"$a"/"$b"}
+ a=' ' ; b=$_ble_syntax_bash_heredoc_EscSP; ret=${ret//"$a"/"$b"}
+ a=$'\t'; b=$_ble_syntax_bash_heredoc_EscHT; ret=${ret//"$a"/"$b"}
+ a=$'\n'; b=$_ble_syntax_bash_heredoc_EscLF; ret=${ret//"$a"/"$b"}
+ a=$fs ; b=$_ble_syntax_bash_heredoc_EscFS; ret=${ret//"$a"/"$b"}
+ fi
+ escaped=$ret
+}
+function ble/syntax:bash/ctx-heredoc-word/unescape-delimiter {
+ builtin eval "delimiter=\$'$1'"
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_RDRH]=ble/syntax:bash/ctx-heredoc-word
+_BLE_SYNTAX_FEND[_ble_ctx_RDRH]=ble/syntax:bash/ctx-heredoc-word/check-word-end
+_BLE_SYNTAX_FCTX[_ble_ctx_RDRI]=ble/syntax:bash/ctx-heredoc-word
+_BLE_SYNTAX_FEND[_ble_ctx_RDRI]=ble/syntax:bash/ctx-heredoc-word/check-word-end
+function ble/syntax:bash/ctx-heredoc-word/check-word-end {
+ ((wbegin<0)) && return 1
+ ble/syntax:bash/check-word-end/is-delimiter || return 1
+ local octx=$ctx word=${text:wbegin:i-wbegin}
+ ble/syntax/parse/word-pop
+ ble/syntax/parse/nest-pop
+ local I
+ if ((octx==_ble_ctx_RDRI)); then I=I; else I=R; fi
+ local Q delimiter
+ if [[ $word == *[\'\"\\]* ]]; then
+ Q=Q; ble/syntax:bash/ctx-heredoc-word/remove-quotes "$word"
+ else
+ Q=H; delimiter=$word
+ fi
+ local escaped; ble/syntax:bash/ctx-heredoc-word/escape-delimiter "$delimiter"
+ nparam=$nparam$_ble_term_FS@$I$Q$escaped
+ return 0
+}
+function ble/syntax:bash/ctx-heredoc-word {
+ ble/syntax:bash/ctx-redirect
+}
+_BLE_SYNTAX_FCTX[_ble_ctx_HERE0]=ble/syntax:bash/ctx-heredoc-content
+_BLE_SYNTAX_FCTX[_ble_ctx_HERE1]=ble/syntax:bash/ctx-heredoc-content
+function ble/syntax:bash/ctx-heredoc-content {
+ local indented= quoted= delimiter=
+ ble/syntax:bash/ctx-heredoc-word/unescape-delimiter "${nparam:2}"
+ [[ ${nparam::1} == I ]] && indented=1
+ [[ ${nparam:1:1} == Q ]] && quoted=1
+ local rex ht=$'\t' lf=$'\n'
+ if ((ctx==_ble_ctx_HERE0)); then
+ rex="^${indented:+$ht*}"$'([^\n]+\n?|\n)'
+ [[ $tail =~ $rex ]] || return 1
+ local line=${BASH_REMATCH%"$lf"}
+ local rematch1=${BASH_REMATCH[1]}
+ if [[ ${rematch1%"$lf"} == "$delimiter" ]]; then
+ local indent
+ ((indent=${#BASH_REMATCH}-${#rematch1},
+ _ble_syntax_attr[i]=_ble_ctx_HERE0,
+ _ble_syntax_attr[i+indent]=_ble_ctx_RDRH,
+ i+=${#line}))
+ ble/syntax/parse/nest-pop
+ return 0
+ fi
+ fi
+ if [[ $quoted ]]; then
+ ble/util/assert '((ctx==_ble_ctx_HERE0))'
+ ((_ble_syntax_attr[i]=_ble_ctx_HERE0,i+=${#BASH_REMATCH}))
+ return 0
+ else
+ ((ctx=_ble_ctx_HERE1))
+ if rex='^([^$`\'"$lf"']|\\.)+'"$lf"'?|^'"$lf" && [[ $tail =~ $rex ]]; then
+ ((_ble_syntax_attr[i]=_ble_ctx_HERE0,
+ i+=${#BASH_REMATCH}))
+ [[ $BASH_REMATCH == *"$lf" ]] && ((ctx=_ble_ctx_HERE0))
+ return 0
+ fi
+ if ble/syntax:bash/check-dollar; then
+ return 0
+ elif [[ $tail == '`'* ]] && ble/syntax:bash/check-quotes; then
+ return 0
+ else
+ ((_ble_syntax_attr[i]=_ble_ctx_HERE0,i++))
+ return 0
+ fi
+ fi
+}
+function ble/syntax:bash/is-complete {
+ local iN=${#_ble_syntax_text}
+ ((iN>0)) && ((_ble_syntax_attr[iN-1]==_ble_attr_ERR)) && return 1
+ local stat=${_ble_syntax_stat[iN]}
+ if [[ $stat ]]; then
+ ble/string#split-words stat "$stat"
+ local nlen=${stat[3]}; ((nlen>=0)) && return 1
+ local nparam=${stat[6]}; [[ $nparam == none ]] && nparam=
+ local rex="$_ble_term_FS@([RI][QH][^$_ble_term_FS]*)(.*$)"
+ [[ $nparam =~ $rex ]] && return 1
+ local ctx=${stat[0]}
+ ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX||
+ ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXE||ctx==_ble_ctx_CMDXV||
+ ctx==_ble_ctx_TARGX1||ctx==_ble_ctx_TARGX2)) || return 1
+ fi
+ local attrs ret
+ IFS= builtin eval 'attrs="::${_ble_syntax_attr[*]/%/::}"' # WA #D1570 checked
+ ble/string#count-string "$attrs" ":$_ble_attr_KEYWORD_BEGIN:"; local nbeg=$ret
+ ble/string#count-string "$attrs" ":$_ble_attr_KEYWORD_END:"; local nend=$ret
+ ((nbeg>nend)) && return 1
+ return 0
+}
+function ble/syntax:bash/find-end-of-array-index {
+ local beg=$1 end=$2
+ ret=
+ local inest0=$beg nest0
+ [[ ${_ble_syntax_nest[inest0]} ]] || return 1
+ local q stat1 nlen1 inest1 r=
+ for ((q=inest0+1;q<end;q++)); do
+ local stat1=${_ble_syntax_stat[q]}
+ [[ $stat1 ]] || continue
+ ble/string#split-words stat1 "$stat1"
+ ((nlen1=stat1[3])) # (workaround Bash-4.2 segfault)
+ ((inest1=nlen1<0?nlen1:q-nlen1))
+ ((inest1<inest0)) && break
+ ((r=q))
+ done
+ [[ ${_ble_syntax_text:r:end-r} == ']'* ]] && ret=$r
+ [[ $ret ]]
+}
+function ble/syntax:bash/find-rhs {
+ local wtype=$1 wbeg=$2 wlen=$3 opts=$4
+ local text=$_ble_syntax_text
+ local word=${text:wbeg:wlen} wend=$((wbeg+wlen))
+ local rex=
+ if ((wtype==_ble_attr_VAR)); then
+ rex='^[a-zA-Z0-9_]+(\+?=|\[)'
+ elif ((wtype==_ble_ctx_VALI)); then
+ if [[ :$opts: == *:element-assignment:* ]]; then
+ rex='^[a-zA-Z0-9_]+(\+?=|\[)|^(\[)'
+ else
+ rex='^(\[)'
+ fi
+ fi
+ if [[ $rex && $word =~ $rex ]]; then
+ local last_char=${BASH_REMATCH:${#BASH_REMATCH}-1}
+ if [[ $last_char == '[' ]]; then
+ local p1=$((wbeg+${#BASH_REMATCH}-1))
+ if ble/syntax:bash/find-end-of-array-index "$p1" "$wend"; then
+ local p2=$ret
+ case ${text:p2:wend-p2} in
+ (']='*) ((ret=p2+2)); return 0 ;;
+ (']+='*) ((ret=p2+3)); return 0 ;;
+ esac
+ fi
+ else
+ ((ret=wbeg+${#BASH_REMATCH}))
+ return 0
+ fi
+ fi
+ ret=$wbeg
+ return 1
+}
+_ble_syntax_vanishing_word_umin=-1
+_ble_syntax_vanishing_word_umax=-1
+function ble/syntax/vanishing-word/register {
+ local tree_array=$1 tofs=$2
+ local beg=$3 end=$4 lbeg=$5 lend=$6
+ (((beg<=0)&&(beg=1)))
+ local node i nofs
+ for ((i=end;i>=beg;i--)); do
+ builtin eval "node=(\${$tree_array[tofs+i-1]})"
+ ((${#node[@]})) || continue
+ for ((nofs=0;nofs<${#node[@]};nofs+=_ble_syntax_TREE_WIDTH)); do
+ local wtype=${node[nofs]} wlen=${node[nofs+1]}
+ local wbeg=$((wlen<0?wlen:i-wlen)) wend=$i
+ ((wbeg<lbeg&&(wbeg=lbeg),
+ wend>lend&&(wend=lend)))
+ ble/syntax/urange#update _ble_syntax_vanishing_word_ "$wbeg" "$wend"
+ done
+ done
+}
+function ble/syntax/parse/shift.stat {
+ if [[ ${_ble_syntax_stat[shift2_j]} ]]; then
+ local -a stat; ble/string#split-words stat "${_ble_syntax_stat[shift2_j]}"
+ local k klen kbeg
+ for k in 1 3 4 5; do # wlen nlen tclen tplen
+ (((klen=stat[k])<0)) && continue
+ ((kbeg=shift2_j-klen))
+ if ((kbeg<beg)); then
+ ((stat[k]+=shift))
+ elif ((kbeg<end0)); then
+ ((stat[k]-=end0-kbeg))
+ fi
+ done
+ _ble_syntax_stat[shift2_j]="${stat[*]}"
+ fi
+}
+function ble/syntax/parse/shift.tree/1 {
+ local k klen kbeg
+ for k in 1 2 3; do # wlen/nlen tclen tplen
+ ((klen=node[nofs+k]))
+ ((klen<0||(kbeg=shift2_j-klen)>end0)) && continue
+ if [[ $k == 1 && ${node[nofs]} =~ ^[0-9]$ ]]; then
+ ble/syntax/parse/touch-updated-word "$shift2_j"
+ node[nofs+4]='-'
+ fi
+ if ((kbeg<beg)); then
+ ((node[nofs+k]+=shift))
+ elif ((kbeg<end0)); then
+ ((node[nofs+k]-=end0-kbeg))
+ fi
+ done
+}
+function ble/syntax/parse/shift.tree {
+ [[ ${_ble_syntax_tree[shift2_j-1]} ]] || return 1
+ local -a node
+ ble/string#split-words node "${_ble_syntax_tree[shift2_j-1]}"
+ local nofs
+ if [[ $1 ]]; then
+ nofs=$1 ble/syntax/parse/shift.tree/1
+ else
+ for ((nofs=0;nofs<${#node[@]};nofs+=_ble_syntax_TREE_WIDTH)); do
+ ble/syntax/parse/shift.tree/1
+ done
+ fi
+ _ble_syntax_tree[shift2_j-1]="${node[*]}"
+}
+function ble/syntax/parse/shift.nest {
+ if [[ ${_ble_syntax_nest[shift2_j]} ]]; then
+ local -a nest
+ ble/string#split-words nest "${_ble_syntax_nest[shift2_j]}"
+ local k klen kbeg
+ for k in 1 3 4 5; do
+ (((klen=nest[k])))
+ ((klen<0||(kbeg=shift2_j-klen)<0)) && continue
+ if ((kbeg<beg)); then
+ ((nest[k]+=shift))
+ elif ((kbeg<end0)); then
+ ((nest[k]-=end0-kbeg))
+ fi
+ done
+ _ble_syntax_nest[shift2_j]="${nest[*]}"
+ fi
+}
+function ble/syntax/parse/shift.impl2/.shift-until {
+ local limit=$1
+ while ((shift2_j>=limit)); do
+ [[ $bleopt_syntax_debug ]] && _ble_syntax_stat_shift[shift2_j+shift]=1
+ ble/syntax/parse/shift.stat
+ ble/syntax/parse/shift.nest
+ ((shift2_j--))
+ done
+}
+function ble/syntax/parse/shift.impl2/.proc1 {
+ if ((TE_i<j2)); then
+ ((tprev=-1)) # 中断
+ return 0
+ fi
+ ble/syntax/parse/shift.impl2/.shift-until $((TE_i+1))
+ ble/syntax/parse/shift.tree "$TE_nofs"
+ if ((tprev>end0&&wbegin>end0)) && [[ ${wtype//[0-9]} ]]; then
+ [[ $bleopt_syntax_debug ]] && _ble_syntax_stat_shift[shift2_j+shift]=1
+ ble/syntax/parse/shift.stat
+ ble/syntax/parse/shift.nest
+ ((shift2_j=wbegin)) # skip
+ elif ((tchild>=0)); then
+ ble/syntax/tree-enumerate-children ble/syntax/parse/shift.impl2/.proc1
+ fi
+}
+function ble/syntax/parse/shift.method1 {
+ local i j
+ for ((i=i2,j=j2;i<=iN;i++,j++)); do
+ local shift2_j=$j
+ ble/syntax/parse/shift.stat
+ ((j>0)) && ble/syntax/parse/shift.tree
+ ((i<iN)) && ble/syntax/parse/shift.nest
+ done
+}
+function ble/syntax/parse/shift.method2 {
+ [[ $bleopt_syntax_debug ]] && _ble_syntax_stat_shift=()
+ local iN=${#_ble_syntax_text} # tree-enumerate 起点は (古い text の長さ) である
+ local shift2_j=$iN # proc1 に渡す変数
+ ble/syntax/tree-enumerate ble/syntax/parse/shift.impl2/.proc1
+ ble/syntax/parse/shift.impl2/.shift-until "$j2" # 未処理部分
+}
+function ble/syntax/parse/shift {
+ ble/syntax/parse/shift.method2 # tree-enumerate による skip
+ if ((shift!=0)); then
+ ble/syntax/urange#shift _ble_syntax_attr_
+ ble/syntax/wrange#shift _ble_syntax_word_
+ ble/syntax/wrange#shift _ble_syntax_word_defer_
+ ble/syntax/urange#shift _ble_syntax_vanishing_word_
+ fi
+}
+_ble_syntax_dbeg=-1 _ble_syntax_dend=-1
+function ble/syntax/parse/determine-parse-range {
+ local flagSeekStat=0
+ ((i1=_ble_syntax_dbeg,i1>=end0&&(i1+=shift),
+ i2=_ble_syntax_dend,i2>=end0&&(i2+=shift),
+ (i1<0||beg<i1)&&(i1=beg,flagSeekStat=1),
+ (i2<0||i2<end)&&(i2=end),
+ (i2>iN)&&(i2=iN),
+ j2=i2-shift))
+ if ((flagSeekStat)); then
+ local lookahead='stat[7]'
+ local -a stat
+ while ((i1>0)); do
+ if [[ ${_ble_syntax_stat[--i1]} ]]; then
+ ble/string#split-words stat "${_ble_syntax_stat[i1]}"
+ ((i1+lookahead<=beg)) && break
+ fi
+ done
+ fi
+ ble/util/assert '((0<=i1&&i1<=beg&&end<=i2&&i2<=iN))' "X2 0 <= $i1 <= $beg <= $end <= $i2 <= $iN"
+}
+function ble/syntax/parse/check-end {
+ [[ ${_BLE_SYNTAX_FEND[ctx]} ]] && "${_BLE_SYNTAX_FEND[ctx]}"
+}
+function ble/syntax/parse {
+ local text=$1 iN=${#1}
+ local opts=$2
+ local beg=${3:-0} end=${4:-$iN} end0=${5:-0}
+ ((end==beg&&end0==beg&&_ble_syntax_dbeg<0)) && return 0
+ local IFS=$_ble_term_IFS
+ local shift=$((end-end0))
+ ble/util/assert \
+ '((0<=beg&&beg<=end&&end<=iN&&beg<=end0))' \
+ "X1 0 <= beg:$beg <= end:$end <= iN:$iN, beg:$beg <= end0:$end0 (shift=$shift text=$text)" ||
+ ((beg=0,end=iN))
+ local i1 i2 j2
+ ble/syntax/parse/determine-parse-range
+ ble/syntax/vanishing-word/register _ble_syntax_tree 0 "$i1" "$j2" 0 "$i2"
+ ble/syntax/parse/shift
+ local ctx wbegin wtype inest tchild tprev nparam ilook
+ if ((i1>0)) && [[ ${_ble_syntax_stat[i1]} ]]; then
+ local -a stat
+ ble/string#split-words stat "${_ble_syntax_stat[i1]}"
+ local wlen=${stat[1]} nlen=${stat[3]} tclen=${stat[4]} tplen=${stat[5]}
+ ctx=${stat[0]}
+ wbegin=$((wlen<0?wlen:i1-wlen))
+ wtype=${stat[2]}
+ inest=$((nlen<0?nlen:i1-nlen))
+ tchild=$((tclen<0?tclen:i1-tclen))
+ tprev=$((tplen<0?tplen:i1-tplen))
+ nparam=${stat[6]}; [[ $nparam == none ]] && nparam=
+ ilook=$((i1+${stat[7]:-1}))
+ else
+ ctx=$_ble_ctx_UNSPECIFIED ##!< 現在の解析の文脈
+ ble/syntax:"$_ble_syntax_lang"/initialize-ctx # ctx 初期化
+ wbegin=-1 ##!< シェル単語内にいる時、シェル単語の開始位置
+ wtype=-1 ##!< シェル単語内にいる時、シェル単語の種類
+ inest=-1 ##!< 入れ子の時、親の開始位置
+ tchild=-1
+ tprev=-1
+ nparam=
+ ilook=1
+ fi
+ local -a _tail_syntax_stat _tail_syntax_tree _tail_syntax_nest _tail_syntax_attr
+ _tail_syntax_stat=("${_ble_syntax_stat[@]:j2:iN-i2+1}")
+ _tail_syntax_tree=("${_ble_syntax_tree[@]:j2:iN-i2}")
+ _tail_syntax_nest=("${_ble_syntax_nest[@]:j2:iN-i2}")
+ _tail_syntax_attr=("${_ble_syntax_attr[@]:j2:iN-i2}")
+ ble/array#reserve-prototype "$iN"
+ _ble_syntax_stat=("${_ble_syntax_stat[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 再開用データ
+ _ble_syntax_tree=("${_ble_syntax_tree[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 単語
+ _ble_syntax_nest=("${_ble_syntax_nest[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 入れ子の親
+ _ble_syntax_attr=("${_ble_syntax_attr[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 文脈・色とか
+ ble/syntax:"$_ble_syntax_lang"/initialize-vars
+ _ble_syntax_text=$text
+ local i _stat tail
+ local debug_p1
+ for ((i=i1;i<iN;)); do
+ ble/syntax/parse/generate-stat
+ if ((i>=i2)) && [[ ${_tail_syntax_stat[i-i2]} == "$_stat" ]]; then
+ if ble/syntax/parse/nest-equals "$inest"; then
+ _ble_syntax_stat=("${_ble_syntax_stat[@]::i}" "${_tail_syntax_stat[@]:i-i2}")
+ _ble_syntax_tree=("${_ble_syntax_tree[@]::i}" "${_tail_syntax_tree[@]:i-i2}")
+ _ble_syntax_nest=("${_ble_syntax_nest[@]::i}" "${_tail_syntax_nest[@]:i-i2}")
+ _ble_syntax_attr=("${_ble_syntax_attr[@]::i}" "${_tail_syntax_attr[@]:i-i2}")
+ break
+ fi
+ fi
+ _ble_syntax_stat[i]=$_stat
+ tail=${text:i}
+ debug_p1=$i
+ "${_BLE_SYNTAX_FCTX[ctx]}" || ((_ble_syntax_attr[i]=_ble_attr_ERR,i++))
+ ble/syntax/parse/check-end
+ done
+ builtin unset -v debug_p1
+ ble/syntax/vanishing-word/register _tail_syntax_tree $((-i2)) $((i2+1)) "$i" 0 "$i"
+ ble/syntax/urange#update _ble_syntax_attr_ "$i1" "$i"
+ (((i>=i2)?(
+ _ble_syntax_dbeg=_ble_syntax_dend=-1
+ ):(
+ _ble_syntax_dbeg=i,_ble_syntax_dend=i2)))
+ if ((i>=iN)); then
+ ((i=iN))
+ ble/syntax/parse/generate-stat
+ _ble_syntax_stat[i]=$_stat
+ if ((inest>0)); then
+ ((_ble_syntax_attr[iN-1]=_ble_attr_ERR))
+ while ((inest>=0)); do
+ ((i=inest))
+ ble/syntax/parse/nest-pop
+ ((inest>=i&&(inest=i-1)))
+ done
+ fi
+ fi
+ ble/util/assert \
+ '((${#_ble_syntax_stat[@]}==iN+1))' \
+ "unexpected array length #arr=${#_ble_syntax_stat[@]} (expected to be $iN), #proto=${#_ble_array_prototype[@]} should be >= $iN"
+}
+function ble/syntax/highlight {
+ local text=$1 lang=${2:-bash} cache_prefix=$3
+ local -a _ble_highlight_layer__list=(plain syntax)
+ local -a vars=()
+ ble/array#push vars "${_ble_syntax_VARNAMES[@]}"
+ ble/array#push vars "${_ble_highlight_layer_plain_VARNAMES[@]}"
+ ble/array#push vars "${_ble_highlight_layer_syntax_VARNAMES[@]}"
+ local "${vars[@]/%/=}" # WA #D1570 checked
+ if [[ $cache_prefix ]] && ((${cache_prefix}_INITIALIZED++)); then
+ ble/util/restore-vars "$cache_prefix" "${vars[@]}"
+ ble/string#common-prefix "$_ble_syntax_text" "$text"
+ local beg=${#ret}
+ ble/string#common-suffix "${_ble_syntax_text:beg}" "${text:beg}"
+ local end=$((${#text}-${#ret})) end0=$((${#_ble_syntax_text}-${#ret}))
+ else
+ ble/syntax/initialize-vars
+ ble/highlight/layer:plain/initialize-vars
+ ble/highlight/layer:syntax/initialize-vars
+ _ble_syntax_lang=$lang
+ local beg=0 end=${#text} end0=0
+ fi
+ ble/syntax/parse "$text" '' "$beg" "$end" "$end0"
+ local HIGHLIGHT_BUFF HIGHLIGHT_UMIN HIGHLIGHT_UMAX
+ ble/highlight/layer/update "$text" '' "$beg" "$end" "$end0"
+ IFS= builtin eval "ret=\"\${$HIGHLIGHT_BUFF[*]}\""
+ [[ $cache_prefix ]] &&
+ ble/util/save-vars "$cache_prefix" "${vars[@]}"
+ return 0
+}
+function ble/syntax/completion-context/.add {
+ local source=$1
+ local comp1=$2
+ ble/util/assert '[[ $source && comp1 -ge 0 ]]'
+ sources[${#sources[*]}]="$source $comp1"
+}
+function ble/syntax/completion-context/.check/parameter-expansion {
+ local rex_paramx='^(\$(\{[!#]?)?)([a-zA-Z_][a-zA-Z_0-9]*)?$'
+ if [[ ${text:istat:index-istat} =~ $rex_paramx ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ local source=variable
+ if [[ $rematch1 == '${'* ]]; then
+ source=variable:b # suffix }
+ elif ((ctx==_ble_ctx_BRACE1||ctx==_ble_ctx_BRACE2)); then
+ source=variable:n # no suffix
+ fi
+ ble/syntax/completion-context/.add "$source" $((istat+${#rematch1}))
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDI]=inside-command
+function ble/syntax/completion-context/.check-prefix/ctx:inside-command {
+ if ((wlen>=0)); then
+ ble/syntax/completion-context/.add command "$wbeg"
+ if [[ ${text:wbeg:index-wbeg} =~ $rex_param ]]; then
+ ble/syntax/completion-context/.add variable:= "$wbeg"
+ fi
+ fi
+ ble/syntax/completion-context/.check/parameter-expansion
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGI]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGQ]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGI1]='inside-argument variable:w'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGI3]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGQ3]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGI1]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGQ1]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATI]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATQ]='inside-argument argument'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_COARGI]='inside-argument variable command'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALI]='inside-argument sabbrev file'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALQ]='inside-argument sabbrev file'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CONDI]='inside-argument sabbrev file option'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CONDQ]='inside-argument sabbrev file'
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGVI]='inside-argument sabbrev variable:='
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGEI]='inside-argument command:D variable:= file'
+function ble/syntax/completion-context/.check-prefix/ctx:inside-argument {
+ if ((wlen>=0)); then
+ local source
+ for source; do
+ ble/syntax/completion-context/.add "$source" "$wbeg"
+ if [[ $source != argument ]]; then
+ local sub=${text:wbeg:index-wbeg}
+ if [[ $sub == *[=:]* ]]; then
+ sub=${sub##*[=:]}
+ ble/syntax/completion-context/.add "$source" $((index-${#sub}))
+ fi
+ fi
+ done
+ fi
+ ble/syntax/completion-context/.check/parameter-expansion
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDX]=next-command
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDX1]=next-command
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXT]=next-command
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXV]=next-command
+function ble/syntax/completion-context/.check-prefix/.test-redirection {
+ local word=$1
+ [[ $word =~ ^$_ble_syntax_bash_RexRedirect$ ]] || return 1
+ ((ctx==_ble_ctx_CMDXC||ctx==_ble_ctx_CMDXD||ctx==_ble_ctx_CMDXD0||ctx==_ble_ctx_FARGX3)) && return 0
+ local rematch3=${BASH_REMATCH[3]}
+ case $rematch3 in
+ ('>&')
+ ble/syntax/completion-context/.add fd "$index"
+ ble/syntax/completion-context/.add file:no-fd "$index" ;;
+ (*'&')
+ ble/syntax/completion-context/.add fd "$index" ;;
+ ('<<'|'<<-')
+ ble/syntax/completion-context/.add wordlist:EOF:END:HERE "$index" ;;
+ ('<<<'|*)
+ ble/syntax/completion-context/.add file "$index" ;;
+ esac
+ return 0
+}
+function ble/syntax/completion-context/.check-prefix/ctx:next-command {
+ local word=${text:istat:index-istat}
+ if ble/syntax:bash/simple-word/is-simple-or-open-simple "$word"; then
+ ble/syntax/completion-context/.add command "$istat"
+ if local rex='^[a-zA-Z_][a-zA-Z_0-9]*(\+?=)?$' && [[ $word =~ $rex ]]; then
+ if [[ $word == *= ]]; then
+ if ((_ble_bash>=30100)) || [[ $word != *+= ]]; then
+ ble/syntax/completion-context/.add argument "$index"
+ fi
+ else
+ ble/syntax/completion-context/.add variable:= "$istat"
+ fi
+ fi
+ elif ble/syntax/completion-context/.check-prefix/.test-redirection; then
+ true
+ elif [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then
+ shopt -q no_empty_cmd_completion ||
+ ble/syntax/completion-context/.add command "$index"
+ fi
+ ble/syntax/completion-context/.check/parameter-expansion
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGX]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGX1]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATX]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGX3]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_COARGX]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGVX]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGEX]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALX]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CONDX]=next-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRS]=next-argument
+function ble/syntax/completion-context/.check-prefix/ctx:next-argument {
+ local source
+ if ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_FARGX3)); then
+ source=(argument)
+ elif ((ctx==_ble_ctx_COARGX)); then
+ source=(command variable)
+ elif ((ctx==_ble_ctx_ARGVX)); then
+ source=(sabbrev variable:= option)
+ elif ((ctx==_ble_ctx_ARGEX)); then
+ source=(command:D variable:= file)
+ elif ((ctx==_ble_ctx_CONDX)); then
+ source=(sabbrev file option)
+ else
+ source=(sabbrev file)
+ fi
+ local word=${text:istat:index-istat}
+ if ble/syntax:bash/simple-word/is-simple-or-open-simple "$word"; then
+ local src
+ for src in "${source[@]}"; do
+ ble/syntax/completion-context/.add "$src" "$istat"
+ done
+ if [[ ${source[0]} != argument ]]; then
+ local rex="^([^='\"\$\\{}]|\\.)*="
+ if [[ $word =~ $rex ]]; then
+ word=${word:${#BASH_REMATCH}}
+ ble/syntax/completion-context/.add rhs $((index-${#word}))
+ fi
+ fi
+ elif ble/syntax/completion-context/.check-prefix/.test-redirection "$word"; then
+ true
+ elif [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then
+ local src
+ for src in "${source[@]}"; do
+ ble/syntax/completion-context/.add "$src" "$index"
+ done
+ fi
+ ble/syntax/completion-context/.check/parameter-expansion
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXC]=next-compound
+function ble/syntax/completion-context/.check-prefix/ctx:next-compound {
+ local rex word=${text:istat:index-istat}
+ if [[ ${text:istat:index-istat} =~ $rex_param ]]; then
+ ble/syntax/completion-context/.add wordlist:-r:'for:select:case:if:while:until' "$istat"
+ elif rex='^[[({]+$'; [[ $word =~ $rex ]]; then
+ ble/syntax/completion-context/.add wordlist:-r:'(:{:((:[[' "$istat"
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGX1]="next-identifier variable:w" # _ble_ctx_FARGX1 → (( でなければ 変数名
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_SARGX1]="next-identifier variable:w"
+function ble/syntax/completion-context/.check-prefix/ctx:next-identifier {
+ local source=$1 word=${text:istat:index-istat}
+ if [[ $word =~ $rex_param ]]; then
+ ble/syntax/completion-context/.add "$source" "$istat"
+ elif [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then
+ ble/syntax/completion-context/.add "$source" "$index"
+ else
+ ble/syntax/completion-context/.add none "$istat"
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGX0]="next-word sabbrev"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATX0]="next-word sabbrev"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXD0]="next-word wordlist:-rs:';:{:do'"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXD]="next-word wordlist:-rs:'{:do'"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXE]="next-word wordlist:-rs:'}:fi:done:esac:then:elif:else:do'"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGX2]="next-word wordlist:-rs:'in'"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGI2]="next-word wordlist:-rs:'in'"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGX2]="next-word wordlist:-rs:'in:do'"
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGI2]="next-word wordlist:-rs:'in:do'"
+function ble/syntax/completion-context/.check-prefix/ctx:next-word {
+ local source=$1 word=${text:istat:index-istat} rex=$'^[^ \t]*$'
+ if [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then
+ ble/syntax/completion-context/.add "$source" "$index"
+ else
+ ble/syntax/completion-context/.add "$source" "$istat"
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGX1]=time-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGI1]=time-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGX2]=time-argument
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGI2]=time-argument
+function ble/syntax/completion-context/.check-prefix/ctx:time-argument {
+ ble/syntax/completion-context/.check/parameter-expansion
+ ble/syntax/completion-context/.add command "$istat"
+ if ((ctx==_ble_ctx_TARGX1)); then
+ local rex='^-p?$' words='-p'
+ ((_ble_bash>=50100)) &&
+ rex='^-[-p]?$' words='-p':'--'
+ [[ ${text:istat:index-istat} =~ $rex ]] &&
+ ble/syntax/completion-context/.add wordlist:--:"$words" "$istat"
+ elif ((ctx==_ble_ctx_TARGX2)); then
+ local rex='^--?$'
+ [[ ${text:istat:index-istat} =~ $rex ]] &&
+ ble/syntax/completion-context/.add wordlist:--:'--' "$istat"
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_QUOT]=quote
+function ble/syntax/completion-context/.check-prefix/ctx:quote {
+ ble/syntax/completion-context/.check/parameter-expansion
+ ble/syntax/completion-context/.check-prefix/ctx:quote/.check-container-word
+}
+function ble/syntax/completion-context/.check-prefix/ctx:quote/.check-container-word {
+ local nlen=${stat[3]}; ((nlen>=0)) || return 1
+ local inest=$((nlen<0?nlen:istat-nlen))
+ local nest; ble/string#split-words nest "${_ble_syntax_nest[inest]}"
+ [[ ${nest[0]} ]] || return 1
+ local wlen2=${nest[1]}; ((wlen2>=0)) || return 1
+ local wbeg2=$((wlen2<0?wlen2:inest-wlen2))
+ if ble/syntax:bash/simple-word/is-simple-or-open-simple "${text:wbeg2:index-wbeg2}"; then
+ local wt=${nest[2]}
+ [[ ${_ble_syntax_bash_command_EndWtype[wt]} ]] &&
+ wt=${_ble_syntax_bash_command_EndWtype[wt]}
+ if ((wt==_ble_ctx_CMDI)); then
+ ble/syntax/completion-context/.add command "$wbeg2"
+ elif ((wt==_ble_ctx_ARGI||wt==_ble_ctx_ARGVI||wt==_ble_ctx_ARGEI||wt==_ble_ctx_FARGI2||wt==_ble_ctx_CARGI2)); then
+ ble/syntax/completion-context/.add argument "$wbeg2"
+ elif ((wt==_ble_ctx_CPATI)); then # case pattern の内部
+ return
+ fi
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRF]=redirection
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRD2]=redirection
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRD]=redirection
+function ble/syntax/completion-context/.check-prefix/ctx:redirection {
+ ble/syntax/completion-context/.check/parameter-expansion
+ local p=$((wlen>=0?wbeg:istat))
+ if ble/syntax:bash/simple-word/is-simple-or-open-simple "${text:p:index-p}"; then
+ if ((ctx==_ble_ctx_RDRF)); then
+ ble/syntax/completion-context/.add file "$p"
+ elif ((ctx==_ble_ctx_RDRD)); then
+ ble/syntax/completion-context/.add fd "$p"
+ elif ((ctx==_ble_ctx_RDRD2)); then
+ ble/syntax/completion-context/.add fd "$p"
+ ble/syntax/completion-context/.add file:no-fd "$p"
+ fi
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRH]=here
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRI]=here
+function ble/syntax/completion-context/.check-prefix/ctx:here {
+ local p=$((wlen>=0?wbeg:istat))
+ ble/syntax/completion-context/.add wordlist:EOF:END:HERE "$p"
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_VRHS]=rhs
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGVR]=rhs
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGER]=rhs
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALR]=rhs
+function ble/syntax/completion-context/.check-prefix/ctx:rhs {
+ ble/syntax/completion-context/.check/parameter-expansion
+ if ((wlen>=0)); then
+ local p=$wbeg
+ local rex='^[a-zA-Z0-9_]+(\+?=|\[)'
+ ((ctx==_ble_ctx_VALR)) && rex='^(\[)'
+ if [[ ${text:p:index-p} =~ $rex ]]; then
+ if [[ ${BASH_REMATCH[1]} == '[' ]]; then
+ local p1=$((wbeg+${#BASH_REMATCH}-1))
+ if local ret; ble/syntax:bash/find-end-of-array-index "$p1" "$index"; then
+ local p2=$ret
+ case ${_ble_syntax_text:p2:index-p2} in
+ (']='*) ((p=p2+2)) ;;
+ (']+='*) ((p=p2+3)) ;;
+ (']+')
+ ble/syntax/completion-context/.add wordlist:-rW:'+=' $((p2+1))
+ p= ;;
+ esac
+ fi
+ else
+ ((p+=${#BASH_REMATCH}))
+ fi
+ fi
+ else
+ local p=$istat
+ fi
+ if [[ $p ]] && ble/syntax:bash/simple-word/is-simple-or-open-simple "${text:p:index-p}"; then
+ ble/syntax/completion-context/.add rhs "$p"
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_PARAM]=param
+function ble/syntax/completion-context/.check-prefix/ctx:param {
+ local tail=${text:istat:index-istat}
+ if [[ $tail == : ]]; then
+ return 0
+ elif [[ $tail == '}'* ]]; then
+ local nlen=${stat[3]}
+ local inest=$((nlen<0?nlen:istat-nlen))
+ ((0<=inest&&inest<istat)) &&
+ ble/syntax/completion-context/.check-prefix "$inest"
+ return "$?"
+ else
+ return 1
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_EXPR]=expr
+function ble/syntax/completion-context/.check-prefix/ctx:expr {
+ local tail=${text:istat:index-istat} rex='[a-zA-Z_]+$'
+ if [[ $tail =~ $rex ]]; then
+ local p=$((index-${#BASH_REMATCH}))
+ ble/syntax/completion-context/.add variable:a "$p"
+ return 0
+ elif [[ $tail == ']'* ]]; then
+ local inest=... ntype
+ local nlen=${stat[3]}; ((nlen>=0)) || return 1
+ local inest=$((istat-nlen))
+ ble/syntax/parse/nest-type # ([in] inest; [out] ntype)
+ if [[ $ntype == [ad]'[' ]]; then
+ if [[ $tail == ']' ]]; then
+ ble/syntax/completion-context/.add wordlist:-rW:'=' $((istat+1))
+ elif ((_ble_bash>=30100)) && [[ $tail == ']+' ]]; then
+ ble/syntax/completion-context/.add wordlist:-rW:'+=' $((istat+1))
+ elif [[ $tail == ']=' || _ble_bash -ge 30100 && $tail == ']+=' ]]; then
+ ble/syntax/completion-context/.add rhs "$index"
+ fi
+ fi
+ fi
+}
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_BRACE1]=brace
+_ble_syntax_bash_complete_check_prefix[_ble_ctx_BRACE2]=brace
+function ble/syntax/completion-context/.check-prefix/ctx:brace {
+ local ctx1=$ctx istat1=$istat nlen1=${stat[3]}
+ ((nlen1>=0)) || return 1
+ local inest1=$((istat1-nlen1))
+ while :; do
+ local nest=${_ble_syntax_nest[inest1]}
+ [[ $nest ]] || return 1
+ ble/string#split-words nest "$nest"
+ ctx1=${nest[0]}
+ ((ctx1==_ble_ctx_BRACE1||ctx1==_ble_ctx_BRACE2)) || break
+ inest1=${nest[3]}
+ ((inest1>=0)) || return 1
+ done
+ for ((istat1=inest1;1;istat1--)); do
+ ((istat1>=0)) || return 1
+ [[ ${_ble_syntax_stat[istat1]} ]] && break
+ done
+ local stat1
+ ble/string#split-words stat1 "${_ble_syntax_stat[istat1]}"
+ local wlen=${stat1[1]}
+ local wbeg=$((wlen>=0?istat1-wlen:istat1))
+ ble/syntax/completion-context/.check/parameter-expansion
+ ble/syntax/completion-context/.add argument "$wbeg"
+}
+function ble/syntax/completion-context/.search-last-istat {
+ local index=$1 istat
+ for ((istat=index;istat>=0;istat--)); do
+ if [[ ${_ble_syntax_stat[istat]} ]]; then
+ ret=$istat
+ return 0
+ fi
+ done
+ ret=
+ return 1
+}
+function ble/syntax/completion-context/.check-prefix {
+ local rex_param='^[a-zA-Z_][a-zA-Z_0-9]*$'
+ local from=${1:-$((index-1))}
+ local ret
+ ble/syntax/completion-context/.search-last-istat "$from" || return 1
+ local istat=$ret stat
+ ble/string#split-words stat "${_ble_syntax_stat[istat]}"
+ [[ ${stat[0]} ]] || return 1
+ local ctx=${stat[0]} wlen=${stat[1]}
+ local wbeg=$((wlen<0?wlen:istat-wlen))
+ local name=${_ble_syntax_bash_complete_check_prefix[ctx]}
+ if [[ $name ]]; then
+ builtin eval "ble/syntax/completion-context/.check-prefix/ctx:$name"
+ fi
+}
+function ble/syntax/completion-context/.check-here {
+ ((${#sources[*]})) && return 0
+ local -a stat
+ ble/string#split-words stat "${_ble_syntax_stat[index]}"
+ if [[ ${stat[0]} ]]; then
+ local ctx=${stat[0]}
+ if ((ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDXV||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT)); then
+ if ! shopt -q no_empty_cmd_completion; then
+ ble/syntax/completion-context/.add command "$index"
+ ble/syntax/completion-context/.add variable:= "$index"
+ fi
+ elif ((ctx==_ble_ctx_CMDXC)); then
+ ble/syntax/completion-context/.add wordlist:-rs:'(:{:((:[[:for:select:case:if:while:until' "$index"
+ elif ((ctx==_ble_ctx_CMDXE)); then
+ ble/syntax/completion-context/.add wordlist:-rs:'}:fi:done:esac:then:elif:else:do' "$index"
+ elif ((ctx==_ble_ctx_CMDXD0)); then
+ ble/syntax/completion-context/.add wordlist:-rs:';:{:do' "$index"
+ elif ((ctx==_ble_ctx_CMDXD)); then
+ ble/syntax/completion-context/.add wordlist:-rs:'{:do' "$index"
+ elif ((ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_CPATX0)); then
+ ble/syntax/completion-context/.add sabbrev "$index"
+ elif ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_FARGX3)); then
+ ble/syntax/completion-context/.add argument "$index"
+ elif ((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1)); then
+ ble/syntax/completion-context/.add variable:w "$index"
+ ble/syntax/completion-context/.add sabbrev "$index"
+ elif ((ctx==_ble_ctx_ARGVX)); then
+ ble/syntax/completion-context/.add variable:= "$index"
+ ble/syntax/completion-context/.add option "$index"
+ ble/syntax/completion-context/.add sabbrev "$index"
+ elif ((ctx==_ble_ctx_ARGEX)); then
+ ble/syntax/completion-context/.add variable:= "$index"
+ ble/syntax/completion-context/.add command:D "$index"
+ ble/syntax/completion-context/.add file "$index"
+ elif ((ctx==_ble_ctx_CARGX2)); then
+ ble/syntax/completion-context/.add wordlist:-rs:'in' "$index"
+ elif ((ctx==_ble_ctx_FARGX2)); then
+ ble/syntax/completion-context/.add wordlist:-rs:'in:do' "$index"
+ elif ((ctx==_ble_ctx_TARGX1)); then
+ local words='-p'
+ ((_ble_bash>=50100)) && words='-p':'--'
+ ble/syntax/completion-context/.add command "$index"
+ ble/syntax/completion-context/.add wordlist:--:"$words" "$index"
+ elif ((ctx==_ble_ctx_TARGX2)); then
+ ble/syntax/completion-context/.add command "$index"
+ ble/syntax/completion-context/.add wordlist:--:'--' "$index"
+ elif ((ctx==_ble_ctx_COARGX)); then
+ ble/syntax/completion-context/.add variable:w "$index"
+ ble/syntax/completion-context/.add command "$index"
+ elif ((ctx==_ble_ctx_CONDX)); then
+ ble/syntax/completion-context/.add sabbrev "$index"
+ ble/syntax/completion-context/.add option "$index"
+ ble/syntax/completion-context/.add file "$index"
+ elif ((ctx==_ble_ctx_CPATI||ctx==_ble_ctx_RDRF||ctx==_ble_ctx_RDRS)); then
+ ble/syntax/completion-context/.add file "$index"
+ elif ((ctx==_ble_ctx_RDRD)); then
+ ble/syntax/completion-context/.add fd "$index"
+ elif ((ctx==_ble_ctx_RDRD2)); then
+ ble/syntax/completion-context/.add fd "$index"
+ ble/syntax/completion-context/.add file:no-fd "$index"
+ elif ((ctx==_ble_ctx_RDRH||ctx==_ble_ctx_RDRI)); then
+ ble/syntax/completion-context/.add wordlist:EOF:END:HERE "$index"
+ elif ((ctx==_ble_ctx_VRHS||ctx==_ble_ctx_ARGVR||ctx==_ble_ctx_ARGER||ctx==_ble_ctx_VALR)); then
+ ble/syntax/completion-context/.add rhs "$index"
+ fi
+ fi
+}
+function ble/syntax/completion-context/generate {
+ local text=$1 index=$2
+ sources=()
+ ((index<0&&(index=0)))
+ ble/syntax/completion-context/.check-prefix
+ ble/syntax/completion-context/.check-here
+}
+function ble/syntax:bash/extract-command/.register-word {
+ local wtxt=${_ble_syntax_text:wbegin:wlen}
+ if [[ ! $comp_cword ]] && ((wbegin<=EC_pos)); then
+ if ((EC_pos<=wbegin+wlen)); then
+ comp_cword=${#comp_words[@]}
+ comp_point=$((${#comp_line}+wbegin+wlen-EC_pos))
+ comp_line="$wtxt$comp_line"
+ ble/array#push comp_words "$wtxt"
+ else
+ comp_cword=${#comp_words[@]}
+ comp_point=${#comp_line}
+ comp_line="$wtxt $comp_line"
+ ble/array#push comp_words "" "$wtxt"
+ fi
+ else
+ comp_line="$wtxt$comp_line"
+ ble/array#push comp_words "$wtxt"
+ fi
+ [[ $EC_opts == *:treeinfo:* ]] &&
+ ble/array#push tree_words "$TE_i:$TE_nofs"
+}
+function ble/syntax:bash/extract-command/.construct-proc {
+ if [[ $wtype =~ ^[0-9]+$ ]]; then
+ if ((wtype==_ble_ctx_CMDI)); then
+ if ((EC_pos<wbegin)); then
+ comp_line= comp_point= comp_cword= comp_words=()
+ else
+ ble/syntax:bash/extract-command/.register-word
+ ble/syntax/tree-enumerate-break
+ EC_found=1
+ return 0
+ fi
+ elif ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGVI||wtype==_ble_ctx_ARGEI||wtype==_ble_attr_VAR)); then
+ ble/syntax:bash/extract-command/.register-word
+ comp_line=" $comp_line"
+ fi
+ fi
+}
+function ble/syntax:bash/extract-command/.construct {
+ comp_line= comp_point= comp_cword= comp_words=()
+ if [[ $1 == nested ]]; then
+ ble/syntax/tree-enumerate-children \
+ ble/syntax:bash/extract-command/.construct-proc
+ else
+ ble/syntax/tree-enumerate \
+ ble/syntax:bash/extract-command/.construct-proc
+ fi
+ ble/array#reverse comp_words
+ ((comp_cword=${#comp_words[@]}-1-comp_cword,
+ comp_point=${#comp_line}-comp_point))
+ [[ $EC_opts == *:treeinfo:* ]] &&
+ ble/array#reverse tree_words
+}
+function ble/syntax:bash/extract-command/.scan {
+ ((EC_pos<wbegin)) && return 0
+ if ((wbegin+wlen<EC_pos)); then
+ ble/syntax/tree-enumerate-break
+ else
+ local EC_has_word=
+ ble/syntax/tree-enumerate-children \
+ ble/syntax:bash/extract-command/.scan
+ local has_word=$EC_has_word
+ ble/util/unlocal EC_has_word
+ if [[ $has_word && ! $EC_found ]]; then
+ ble/syntax:bash/extract-command/.construct nested
+ ble/syntax/tree-enumerate-break
+ fi
+ fi
+ if [[ $wtype =~ ^[0-9]+$ && ! $EC_has_word ]]; then
+ EC_has_word=$wtype
+ return 0
+ fi
+}
+function ble/syntax:bash/extract-command {
+ local EC_pos=$1 EC_opts=:$2:
+ local EC_found=
+ local EC_has_word=
+ ble/syntax/tree-enumerate \
+ ble/syntax:bash/extract-command/.scan
+ if [[ ! $EC_found && $EC_has_word ]]; then
+ ble/syntax:bash/extract-command/.construct
+ fi
+ [[ $EC_found ]]
+}
+function ble/syntax/tree#previous-sibling {
+ local i0=${1%%:*} nofs0=0 opts=:$2:
+ [[ $1 == *:* ]] && nofs0=${1#*:}
+ local node
+ ble/string#split-words node "${_ble_syntax_tree[i0-1]}"
+ ble-assert '((${#node[@]}>nofs0))' "Broken AST: tree-node info missing at $((i0-1))[$nofs0]" || return 1
+ local tplen=${node[nofs0+3]}
+ ((tplen>=0)) || return 1
+ local i=$((i0-tplen)) nofs=0
+ ret=$i:$nofs
+ if [[ $opts == *:wvars:* ]]; then
+ ble/string#split-words node "${_ble_syntax_tree[i-1]}"
+ ble-assert '((${#node[@]}>nofs))' "Broken AST: tree-node info missing at $((i-1))[$nofs]" || return 1
+ wtype=${node[nofs]}
+ wlen=${node[nofs+1]}
+ ((wbeg=i-wlen,wend=i))
+ wattr=${node[nofs+4]}
+ fi
+ return 0
+}
+function ble/syntax/tree#next-sibling {
+ local i0=${1%%:*} nofs0=0 opts=:$2:
+ [[ $1 == *:* ]] && nofs0=${1#*:}
+ ((nofs0)) && return 1
+ local iN=${#_ble_syntax_text} i nofs node
+ for ((i=i0+1;i<=iN;i++)); do
+ [[ ${_ble_syntax_tree[i-1]} ]] || continue
+ ble/string#split-words node "${_ble_syntax_tree[i-1]}"
+ nofs=${#node[@]}
+ while (((nofs-=_ble_syntax_TREE_WIDTH)>=0)); do
+ if ((i0==i-node[nofs+2])); then
+ return 1
+ elif ((i0==i-node[nofs+3])); then
+ ret=$i:$nofs
+ if [[ $opts == *:wvars:* ]]; then
+ wtype=${node[nofs]}
+ wlen=${node[nofs+1]}
+ ((wbeg=i-wlen,wend=i))
+ wattr=${node[nofs+4]}
+ fi
+ return 0
+ fi
+ done
+ done
+ return 1
+}
+function ble/syntax:bash/extract-command-by-noderef {
+ local i=${1%%:*} nofs=0 opts=:$2:
+ [[ $1 == *:* ]] && nofs=${1#*:}
+ comp_words=()
+ tree_words=()
+ comp_line=
+ comp_cword=0
+ comp_point=0
+ local ExprIsArgument='wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGVI||wtype==_ble_ctx_ARGEI||wtype==_ble_attr_VAR'
+ local ret node wtype wlen wbeg wend wattr
+ ble/string#split-words node "${_ble_syntax_tree[i-1]}"
+ wtype=${node[nofs]} wlen=${node[nofs+1]}
+ [[ ! ${wtype//[0-9]} ]] && ((wtype==_ble_ctx_CMDI||ExprIsArgument)) || return 1
+ ble/array#push comp_words "${_ble_syntax_text:i-wlen:wlen}"
+ [[ $opts == *:treeinfo:* ]] &&
+ ble/array#push tree_words "$i:$nofs"
+ ret=$i:$nofs
+ while
+ { [[ ${wtype//[0-9]} ]] || ((wtype!=_ble_ctx_CMDI)); } &&
+ ble/syntax/tree#previous-sibling "$ret" wvars
+ do
+ [[ ! ${wtype//[0-9]} ]] || continue
+ if ((wtype==_ble_ctx_CMDI||ExprIsArgument)); then
+ ble/array#push comp_words "${_ble_syntax_text:wbeg:wlen}"
+ [[ $opts == *:treeinfo:* ]] &&
+ ble/array#push tree_words "$ret"
+ fi
+ done
+ ble/array#reverse comp_words
+ [[ $opts == *:treeinfo:* ]] &&
+ ble/array#reverse tree_words
+ ((comp_cword=${#comp_words[@]}-1))
+ ret=$i:$nofs
+ while ble/syntax/tree#next-sibling "$ret" wvars; do
+ [[ ! ${wtype//[0-9]} ]] || continue
+ ((wtype==_ble_ctx_CMDI)) && break
+ if ((ExprIsArgument)); then
+ ble/array#push comp_words "${_ble_syntax_text:wbeg:wlen}"
+ [[ $opts == *:treeinfo:* ]] &&
+ ble/array#push tree_words "$ret"
+ fi
+ done
+ local IFS=$_ble_term_IFS
+ comp_line="${comp_words[*]}"
+ local tmp="${comp_words[*]::comp_cword+1}"
+ comp_point=${#tmp}
+}
+_ble_syntax_attr2iface=()
+function ble/syntax/attr2iface/color_defface.onload {
+ function ble/syntax/attr2iface/.define {
+ ((_ble_syntax_attr2iface[$1]=_ble_faces__$2))
+ }
+ ble/syntax/attr2iface/.define _ble_ctx_ARGX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGX0 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGI syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGQ syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGVX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGVI syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGVR syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGEX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGEI syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_ARGER syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDX1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDXT syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDXC syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDXE syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDXD syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDXD0 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDXV syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CMDI syntax_command
+ ble/syntax/attr2iface/.define _ble_ctx_VRHS syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_QUOT syntax_quoted
+ ble/syntax/attr2iface/.define _ble_ctx_EXPR syntax_expr
+ ble/syntax/attr2iface/.define _ble_attr_ERR syntax_error
+ ble/syntax/attr2iface/.define _ble_attr_VAR syntax_varname
+ ble/syntax/attr2iface/.define _ble_attr_QDEL syntax_quotation
+ ble/syntax/attr2iface/.define _ble_attr_QESC syntax_escape
+ ble/syntax/attr2iface/.define _ble_attr_DEF syntax_default
+ ble/syntax/attr2iface/.define _ble_attr_DEL syntax_delimiter
+ ble/syntax/attr2iface/.define _ble_ctx_PARAM syntax_param_expansion
+ ble/syntax/attr2iface/.define _ble_ctx_PWORD syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_PWORDE syntax_error
+ ble/syntax/attr2iface/.define _ble_ctx_PWORDR syntax_default
+ ble/syntax/attr2iface/.define _ble_attr_HISTX syntax_history_expansion
+ ble/syntax/attr2iface/.define _ble_attr_FUNCDEF syntax_function_name
+ ble/syntax/attr2iface/.define _ble_ctx_VALX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_VALI syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_VALR syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_VALQ syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CONDX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CONDI syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CONDQ syntax_default
+ ble/syntax/attr2iface/.define _ble_attr_COMMENT syntax_comment
+ ble/syntax/attr2iface/.define _ble_ctx_CASE syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_PATN syntax_default
+ ble/syntax/attr2iface/.define _ble_attr_GLOB syntax_glob
+ ble/syntax/attr2iface/.define _ble_ctx_BRAX syntax_default
+ ble/syntax/attr2iface/.define _ble_attr_BRACE syntax_brace
+ ble/syntax/attr2iface/.define _ble_ctx_BRACE1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_BRACE2 syntax_default
+ ble/syntax/attr2iface/.define _ble_attr_TILDE syntax_tilde
+ ble/syntax/attr2iface/.define _ble_ctx_SARGX1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_FARGX1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_FARGX2 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_FARGX3 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_FARGI1 syntax_varname
+ ble/syntax/attr2iface/.define _ble_ctx_FARGI2 command_keyword
+ ble/syntax/attr2iface/.define _ble_ctx_FARGI3 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_FARGQ3 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CARGX1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CARGX2 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CARGI1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CARGQ1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CARGI2 command_keyword
+ ble/syntax/attr2iface/.define _ble_ctx_CPATX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CPATI syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CPATQ syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_CPATX0 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_TARGX1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_TARGX2 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_TARGI1 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_TARGI2 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_COARGX syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_COARGI syntax_command
+ ble/syntax/attr2iface/.define _ble_ctx_RDRF syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_RDRD syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_RDRD2 syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_RDRS syntax_default
+ ble/syntax/attr2iface/.define _ble_ctx_RDRH syntax_document_begin
+ ble/syntax/attr2iface/.define _ble_ctx_RDRI syntax_document_begin
+ ble/syntax/attr2iface/.define _ble_ctx_HERE0 syntax_document
+ ble/syntax/attr2iface/.define _ble_ctx_HERE1 syntax_document
+ ble/syntax/attr2iface/.define _ble_attr_CMD_BOLD command_builtin_dot
+ ble/syntax/attr2iface/.define _ble_attr_CMD_BUILTIN command_builtin
+ ble/syntax/attr2iface/.define _ble_attr_CMD_ALIAS command_alias
+ ble/syntax/attr2iface/.define _ble_attr_CMD_FUNCTION command_function
+ ble/syntax/attr2iface/.define _ble_attr_CMD_FILE command_file
+ ble/syntax/attr2iface/.define _ble_attr_CMD_JOBS command_jobs
+ ble/syntax/attr2iface/.define _ble_attr_CMD_DIR command_directory
+ ble/syntax/attr2iface/.define _ble_attr_KEYWORD command_keyword
+ ble/syntax/attr2iface/.define _ble_attr_KEYWORD_BEGIN command_keyword
+ ble/syntax/attr2iface/.define _ble_attr_KEYWORD_END command_keyword
+ ble/syntax/attr2iface/.define _ble_attr_KEYWORD_MID command_keyword
+ ble/syntax/attr2iface/.define _ble_attr_FILE_DIR filename_directory
+ ble/syntax/attr2iface/.define _ble_attr_FILE_STICKY filename_directory_sticky
+ ble/syntax/attr2iface/.define _ble_attr_FILE_LINK filename_link
+ ble/syntax/attr2iface/.define _ble_attr_FILE_ORPHAN filename_orphan
+ ble/syntax/attr2iface/.define _ble_attr_FILE_FILE filename_other
+ ble/syntax/attr2iface/.define _ble_attr_FILE_SETUID filename_setuid
+ ble/syntax/attr2iface/.define _ble_attr_FILE_SETGID filename_setgid
+ ble/syntax/attr2iface/.define _ble_attr_FILE_EXEC filename_executable
+ ble/syntax/attr2iface/.define _ble_attr_FILE_WARN filename_warning
+ ble/syntax/attr2iface/.define _ble_attr_FILE_FIFO filename_pipe
+ ble/syntax/attr2iface/.define _ble_attr_FILE_SOCK filename_socket
+ ble/syntax/attr2iface/.define _ble_attr_FILE_BLK filename_block
+ ble/syntax/attr2iface/.define _ble_attr_FILE_CHR filename_character
+ ble/syntax/attr2iface/.define _ble_attr_FILE_URL filename_url
+ ble/syntax/attr2iface/.define _ble_attr_VAR_UNSET varname_unset
+ ble/syntax/attr2iface/.define _ble_attr_VAR_EMPTY varname_empty
+ ble/syntax/attr2iface/.define _ble_attr_VAR_NUMBER varname_number
+ ble/syntax/attr2iface/.define _ble_attr_VAR_EXPR varname_expr
+ ble/syntax/attr2iface/.define _ble_attr_VAR_ARRAY varname_array
+ ble/syntax/attr2iface/.define _ble_attr_VAR_HASH varname_hash
+ ble/syntax/attr2iface/.define _ble_attr_VAR_READONLY varname_readonly
+ ble/syntax/attr2iface/.define _ble_attr_VAR_TRANSFORM varname_transform
+ ble/syntax/attr2iface/.define _ble_attr_VAR_EXPORT varname_export
+}
+blehook/eval-after-load color_defface ble/syntax/attr2iface/color_defface.onload
+function ble/syntax/highlight/cmdtype1 {
+ type=$1
+ local cmd=$2
+ case "$type:$cmd" in
+ (builtin::|builtin:.)
+ ((type=_ble_attr_CMD_BOLD)) ;;
+ (builtin:*)
+ ((type=_ble_attr_CMD_BUILTIN)) ;;
+ (alias:*)
+ ((type=_ble_attr_CMD_ALIAS)) ;;
+ (function:*)
+ ((type=_ble_attr_CMD_FUNCTION)) ;;
+ (file:*)
+ ((type=_ble_attr_CMD_FILE)) ;;
+ (keyword:*)
+ ((type=_ble_attr_KEYWORD)) ;;
+ (*:%*)
+ ble/util/joblist.check
+ if jobs -- "$cmd" &>/dev/null; then
+ ((type=_ble_attr_CMD_JOBS))
+ else
+ ((type=_ble_attr_ERR))
+ fi ;;
+ (*)
+ if [[ -d $cmd ]] && shopt -q autocd &>/dev/null; then
+ ((type=_ble_attr_CMD_DIR))
+ else
+ ((type=_ble_attr_ERR))
+ fi ;;
+ esac
+}
+function ble/syntax/highlight/cmdtype/.jobs { local LC_ALL=C; jobs; }
+ble/function#suppress-stderr ble/syntax/highlight/cmdtype/.jobs
+function ble/syntax/highlight/cmdtype/.is-job-name {
+ ble/util/joblist.check
+ local value=$1 word=$2
+ if [[ $value == '%'* ]] && jobs -- "$value" &>/dev/null; then
+ return 0
+ fi
+ local quote=\'\"\\\`
+ if [[ ${auto_resume+set} && $word != *["$quote"]* ]]; then
+ if [[ $auto_resume == exact ]]; then
+ local jobs job ret
+ ble/util/assign-array jobs 'ble/syntax/highlight/cmdtype/.jobs'
+ for job in "${jobs[@]}"; do
+ ble/string#trim "${job#*' '}"
+ ble/string#trim "${ret#*' '}"
+ [[ $value == "$ret" ]] && return 0
+ done
+ return 1
+ elif [[ $auto_resume == substring ]]; then
+ jobs -- "%?$value" &>/dev/null; return "$?"
+ else
+ jobs -- "%$value" &>/dev/null; return "$?"
+ fi
+ fi
+ return 1
+}
+function ble/syntax/highlight/cmdtype/.impl {
+ local cmd=$1 _0=$2
+ local cmd_type; ble/util/type cmd_type "$cmd"
+ ble/syntax/highlight/cmdtype1 "$cmd_type" "$cmd"
+ if [[ $type == "$_ble_attr_CMD_ALIAS" && $cmd != "$_0" ]]; then
+ type=$(
+ builtin unalias "$cmd"
+ ble/util/type cmd_type "$cmd"
+ ble/syntax/highlight/cmdtype1 "$cmd_type" "$cmd"
+ printf %s "$type")
+ elif ble/syntax/highlight/cmdtype/.is-job-name "$cmd" "$_0"; then
+ ((type=_ble_attr_CMD_JOBS))
+ elif [[ $type == "$_ble_attr_KEYWORD" ]]; then
+ ble/syntax/highlight/cmdtype1 "${cmd_type[1]}" "$cmd"
+ fi
+}
+_ble_syntax_highlight_filetype_version=-1
+function ble/syntax/highlight/cmdtype {
+ local cmd=$1 _0=$2
+ if ((_ble_syntax_highlight_filetype_version!=_ble_edit_LINENO)); then
+ ble/gdict#clear _ble_syntax_highlight_filetype
+ ((_ble_syntax_highlight_filetype_version=_ble_edit_LINENO))
+ fi
+ if local ret; ble/gdict#get _ble_syntax_highlight_filetype "$_0"; then
+ type=$ret
+ return 0
+ fi
+ ble/syntax/highlight/cmdtype/.impl "$cmd" "$_0"
+ ble/gdict#set _ble_syntax_highlight_filetype "$_0" "$type"
+}
+function ble/syntax/highlight/filetype {
+ type=
+ local file=$1
+ if [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $file == //* ]]; then
+ [[ $file == // ]] && ((type=_ble_attr_FILE_DIR))
+ [[ $type ]]; return "$?"
+ fi
+ if [[ -h $file ]]; then
+ if [[ -e $file ]]; then
+ ((type=_ble_attr_FILE_LINK))
+ else
+ ((type=_ble_attr_FILE_ORPHAN))
+ fi
+ elif [[ -e $file ]]; then
+ if [[ -d $file ]]; then
+ if [[ -k $file ]]; then
+ ((type=_ble_attr_FILE_STICKY))
+ elif [[ -h ${file%/} ]]; then
+ ((type=_ble_attr_FILE_LINK))
+ else
+ ((type=_ble_attr_FILE_DIR))
+ fi
+ elif [[ -f $file ]]; then
+ if [[ -u $file ]]; then
+ ((type=_ble_attr_FILE_SETUID))
+ elif [[ -g $file ]]; then
+ ((type=_ble_attr_FILE_SETGID))
+ elif [[ -x $file ]]; then
+ ((type=_ble_attr_FILE_EXEC))
+ else
+ ((type=_ble_attr_FILE_FILE))
+ fi
+ elif [[ -c $file ]]; then
+ ((type=_ble_attr_FILE_CHR))
+ elif [[ -p $file ]]; then
+ ((type=_ble_attr_FILE_FIFO))
+ elif [[ -S $file ]]; then
+ ((type=_ble_attr_FILE_SOCK))
+ elif [[ -b $file ]]; then
+ ((type=_ble_attr_FILE_BLK))
+ fi
+ elif local rex='^https?://[^ ^`"<>\{|}]+$'; [[ $file =~ $rex ]]; then
+ ((type=_ble_attr_FILE_URL))
+ fi
+ [[ $type ]]
+}
+function ble/syntax/highlight/ls_colors/.clear {
+ _ble_syntax_highlight_lscolors=()
+ ble/gdict#clear _ble_syntax_highlight_lscolors_ext
+}
+function ble/syntax/highlight/ls_colors/.register-extension {
+ local key=$1 value=$2
+ ble/gdict#set _ble_syntax_highlight_lscolors_ext "$key" "$value"
+}
+function ble/syntax/highlight/ls_colors/.read-extension {
+ ble/gdict#get _ble_syntax_highlight_lscolors_ext "$1"
+}
+function ble/syntax/highlight/ls_colors/.parse {
+ ble/syntax/highlight/ls_colors/.clear
+ local fields field
+ ble/string#split fields : "$1"
+ for field in "${fields[@]}"; do
+ [[ $field == *=* ]] || continue
+ local lhs=${field%%=*}
+ local ret; ble/color/sgrspec2g "${field#*=}"; local rhs=$ret
+ case $lhs in
+ ('di') _ble_syntax_highlight_lscolors[_ble_attr_FILE_DIR]=$rhs ;;
+ ('st') _ble_syntax_highlight_lscolors[_ble_attr_FILE_STICKY]=$rhs ;;
+ ('ln') _ble_syntax_highlight_lscolors[_ble_attr_FILE_LINK]=$rhs ;;
+ ('or') _ble_syntax_highlight_lscolors[_ble_attr_FILE_ORPHAN]=$rhs ;;
+ ('fi') _ble_syntax_highlight_lscolors[_ble_attr_FILE_FILE]=$rhs ;;
+ ('su') _ble_syntax_highlight_lscolors[_ble_attr_FILE_SETUID]=$rhs ;;
+ ('sg') _ble_syntax_highlight_lscolors[_ble_attr_FILE_SETGID]=$rhs ;;
+ ('ex') _ble_syntax_highlight_lscolors[_ble_attr_FILE_EXEC]=$rhs ;;
+ ('cd') _ble_syntax_highlight_lscolors[_ble_attr_FILE_CHR]=$rhs ;;
+ ('pi') _ble_syntax_highlight_lscolors[_ble_attr_FILE_FIFO]=$rhs ;;
+ ('so') _ble_syntax_highlight_lscolors[_ble_attr_FILE_SOCK]=$rhs ;;
+ ('bd') _ble_syntax_highlight_lscolors[_ble_attr_FILE_BLK]=$rhs ;;
+ (\*.*)
+ ble/syntax/highlight/ls_colors/.register-extension "${lhs:2}" "$rhs" ;;
+ esac
+ done
+}
+function ble/syntax/highlight/ls_colors {
+ local file=$1
+ if ((type==_ble_attr_FILE_FILE)); then
+ local ext=${file##*/} ret=
+ while [[ $ext == *.* ]]; do
+ ext=${ext#*.}
+ [[ $ext ]] || break
+ if ble/syntax/highlight/ls_colors/.read-extension "$ext"; then
+ type=g:$ret
+ return 0
+ fi
+ done
+ fi
+ local g=${_ble_syntax_highlight_lscolors[type]}
+ if [[ $g ]]; then
+ type=g:$g
+ return 0
+ fi
+ return 1
+}
+function ble/syntax/highlight/getg-from-filename {
+ local filename=$1 type=
+ ble/syntax/highlight/filetype "$filename"
+ if [[ $bleopt_filename_ls_colors ]]; then
+ if ble/syntax/highlight/ls_colors "$filename" && [[ $type == g:* ]]; then
+ local ret; ble/color/face2g filename_ls_colors; g=$ret
+ ((g|=${type:2}))
+ return 0
+ fi
+ fi
+ if [[ $type ]]; then
+ ble/syntax/attr2g "$type"
+ else
+ g=
+ fi
+}
+function bleopt/check:filename_ls_colors {
+ ble/syntax/highlight/ls_colors/.parse "$value"
+}
+bleopt -I filename_ls_colors
+_ble_syntax_progcolor_vars=(
+ node TE_i TE_nofs wtype wlen wbeg wend wattr)
+_ble_syntax_progcolor_wattr_vars=(
+ wattr_buff wattr_pos wattr_g)
+function ble/progcolor/load-word-data {
+ TE_i=${1%%:*} TE_nofs=${1#*:}
+ [[ $1 != *:* ]] && TE_nofs=0
+ ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}"
+ wtype=${node[TE_nofs]}
+ wlen=${node[TE_nofs+1]}
+ wattr=${node[TE_nofs+4]}
+ wbeg=$((TE_i-wlen))
+ wend=$TE_i
+}
+function ble/progcolor/set-wattr {
+ ble/syntax/urange#update color_ "$wbeg" "$wend"
+ ble/syntax/wrange#update _ble_syntax_word_ "$TE_i"
+ node[TE_nofs+4]=$1
+ local IFS=$_ble_term_IFS
+ _ble_syntax_tree[TE_i-1]="${node[*]}"
+}
+function ble/progcolor/eval-word {
+ local iword=${1:-progcolor_iword} opts=$2
+ if [[ ${progcolor_stats[iword]+set} ]]; then
+ ret=${progcolor_wvals[iword]}
+ return "${progcolor_stats[iword]}"
+ fi
+ local wtxt=${comp_words[iword]}
+ local simple_flags simple_ibrace
+ if ! ble/syntax:bash/simple-word/reconstruct-incomplete-word "$wtxt"; then
+ ret=
+ progcolor_stats[iword]=2
+ progcolor_wvals[iword]=
+ return 2
+ fi
+ ble/syntax:bash/simple-word/eval "$ret" "$opts"; local ext=$?
+ ((ext==148)) && return 148
+ if ((ext!=0)); then
+ ret=
+ progcolor_stats[iword]=1
+ progcolor_wvals[iword]=
+ return 1
+ fi
+ progcolor_stats[iword]=0
+ progcolor_wvals[iword]=$ret
+ return 0
+}
+function ble/progcolor/load-cmdspec-opts {
+ if [[ $progcolor_cmdspec_opts ]]; then
+ cmdspec_opts=$progcolor_cmdspec_opts
+ else
+ ble/cmdspec/opts#load "${comp_words[0]}"
+ progcolor_cmdspec_opts=${cmdspec_opts:-:}
+ fi
+}
+function ble/progcolor/stop-option#init {
+ rexrej='^--$' rexreq= stopat=
+ local cmdspec_opts=$1
+ if [[ $cmdspec_opts ]]; then
+ if [[ :$cmdspec_opts: == *:no-options:* ]]; then
+ stopat=0
+ return 1
+ elif ble/opts#extract-first-optarg "$cmdspec_opts" stop-options-at && [[ $ret ]]; then
+ ((stopat=ret))
+ return 1
+ fi
+ local ret
+ if ble/opts#extract-first-optarg "$cmdspec_opts" stop-options-on && [[ $ret ]]; then
+ rexrej=$ret
+ elif [[ :$cmdspec_opts: == *:disable-double-hyphen:* ]]; then
+ rexrej=
+ fi
+ if ble/opts#extract-first-optarg "$cmdspec_opts" stop-options-unless && [[ $ret ]]; then
+ rexreq=$ret
+ elif [[ :$cmdspec_opts: == *:stop-options-postarg:* ]]; then
+ rexreq='^-.+'
+ ble/opts#has "$cmdspec_opts" plus-options && rexreq='^[-+].+'
+ fi
+ fi
+}
+function ble/progcolor/stop-option#test {
+ [[ $rexrej && $1 =~ $rexrej || $rexreq && ! ( $1 =~ $rexreq ) ]]
+}
+function ble/progcolor/is-option-context {
+ if [[ ${progcolor_optctx[1]} ]]; then
+ ((progcolor_optctx[1]<0?1:(progcolor_iword<=progcolor_optctx[1])))
+ return $?
+ fi
+ local rexrej rexreq stopat
+ if [[ ! ${progcolor_optctx[0]} ]]; then
+ progcolor_optctx[0]=1
+ local cmdspec_opts
+ ble/progcolor/load-cmdspec-opts
+ ble/progcolor/stop-option#init "$cmdspec_opts"
+ if [[ ! $rexrej$rexreq ]]; then
+ progcolor_optctx[1]=${stopat:--1}
+ ((progcolor_optctx[1]<0?1:(progcolor_iword<=progcolor_optctx[1])))
+ return $?
+ fi
+ progcolor_optctx[2]=$rexrej
+ progcolor_optctx[3]=$rexreq
+ progcolor_optctx[4]=$stopat
+ else
+ rexrej=${progcolor_optctx[2]}
+ rexreq=${progcolor_optctx[3]}
+ stopat=${progcolor_optctx[4]}
+ fi
+ [[ $stopat ]] && ((progcolor_iword>stopat)) && return 1
+ local iword
+ for ((iword=progcolor_optctx[0];iword<progcolor_iword;iword++)); do
+ ble/progcolor/eval-word "$iword" "$highlight_eval_opts"
+ if ble/progcolor/stop-option#test "$ret"; then
+ progcolor_optctx[1]=$iword
+ return 1
+ fi
+ done
+ progcolor_optctx[0]=$iword
+ return 0
+}
+function ble/progcolor/wattr#initialize {
+ wattr_buff=()
+ wattr_pos=$wbeg
+ wattr_g=d
+}
+function ble/progcolor/wattr#setg {
+ local pos=$1 g=$2
+ local len=$((pos-wattr_pos))
+ ((len>0)) && ble/array#push wattr_buff "$len:$wattr_g"
+ wattr_pos=$pos
+ wattr_g=$g
+}
+function ble/progcolor/wattr#setattr {
+ local pos=$1 attr=$2 g
+ ble/syntax/attr2g "$attr"
+ ble/progcolor/wattr#setg "$pos" "$g"
+}
+function ble/progcolor/wattr#finalize {
+ local wattr
+ if ((${#wattr_buff[@]})); then
+ local len=$((wend-wattr_pos))
+ ((len>0)) && ble/array#push wattr_buff \$:"$wattr_g"
+ wattr_pos=$wend
+ wattr_g=d
+ IFS=, builtin eval 'wattr="m${wattr_buff[*]}"'
+ else
+ wattr=$wattr_g
+ fi
+ ble/progcolor/set-wattr "$wattr"
+}
+function ble/progcolor/highlight-filename/.detect-separated-path {
+ local word=$1
+ ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_VALI||wtype==_ble_attr_VAR||wtype==_ble_ctx_RDRS)) || return 1
+ local detect_opts=url:$highlight_eval_opts
+ ((wtype==_ble_ctx_RDRS)) && detect_opts=$detect_opts:noglob
+ [[ $word == '~'* ]] && ((_ble_syntax_attr[p0]!=_ble_attr_TILDE)) && detect_opts=$detect_opts:notilde
+ ble/syntax:bash/simple-word/detect-separated-path "$word" :, "$detect_opts"
+}
+function ble/progcolor/highlight-filename/.pathspec.wattr {
+ local p=$p0 opts=$2
+ if [[ :$opts: != *:no-path-color:* ]]; then
+ local ipath npath=${#path[@]}
+ for ((ipath=0;ipath<npath-1;ipath++)); do
+ local epath=${path[ipath]} espec=${spec[ipath]}
+ local g=d
+ if ble/syntax/util/is-directory "$epath"; then
+ local type
+ ble/syntax/highlight/filetype "$epath" &&
+ ble/syntax/attr2g "$type"
+ elif ((wtype==_ble_ctx_CMDI)); then
+ ble/syntax/attr2g "$_ble_attr_ERR"
+ fi
+ ((wtype==_ble_ctx_CMDI&&(g&=~_ble_color_gflags_Underline)))
+ ble/progcolor/wattr#setg "$p" "$g"
+ ((p=p0+${#espec}))
+ done
+ fi
+ ble/progcolor/wattr#setg "$p" "$1"
+ [[ $1 != d ]] &&
+ ble/progcolor/wattr#setg "$p1" d
+ return 0
+}
+function ble/progcolor/highlight-filename/.pathspec-with-attr.wattr {
+ local g; ble/syntax/attr2g "$1"
+ ble/progcolor/highlight-filename/.pathspec.wattr "$g"
+ return 0
+}
+function ble/progcolor/highlight-filename/.pathspec-by-name.wattr {
+ local value=$1
+ local highlight_opts=
+ local type=; ble/syntax/highlight/filetype "$value"
+ ((type==_ble_attr_FILE_URL)) && highlight_opts=no-path-color
+ if ((wtype==_ble_ctx_RDRF||wtype==_ble_ctx_RDRD2)); then
+ if ((type==_ble_attr_FILE_DIR)); then
+ type=$_ble_attr_ERR
+ elif ((_ble_syntax_TREE_WIDTH<=TE_nofs)); then
+ local redirect_ntype=${node[TE_nofs-_ble_syntax_TREE_WIDTH]:1}
+ if [[ ( $redirect_ntype == *'>' || $redirect_ntype == '>'[\|\&] ) ]]; then
+ if [[ -e $value || -h $value ]]; then
+ if [[ -d $value || ! -w $value ]]; then
+ type=$_ble_attr_ERR
+ elif [[ ( $redirect_ntype == [\<\&]'>' || $redirect_ntype == '>' || $redirect_ntype == '>&' ) && -f $value ]]; then
+ if [[ -o noclobber ]]; then
+ type=$_ble_attr_ERR
+ else
+ type=$_ble_attr_FILE_WARN
+ fi
+ fi
+ elif [[ $value == */* && ! -w ${value%/*}/ || $value != */* && ! -w ./ ]]; then
+ type=$_ble_attr_ERR
+ fi
+ elif [[ $redirect_ntype == '<' && ! -r $value ]]; then
+ type=$_ble_attr_ERR
+ fi
+ fi
+ fi
+ local g=
+ if [[ $bleopt_filename_ls_colors ]]; then
+ if ble/syntax/highlight/ls_colors "$value" && [[ $type == g:* ]]; then
+ local ret; ble/color/face2g filename_ls_colors; g=$ret
+ type=g:$((${type:2}|g))
+ fi
+ fi
+ [[ $type && ! $g ]] && ble/syntax/attr2g "$type"
+ ble/progcolor/highlight-filename/.pathspec.wattr "${g:-d}" "$highlight_opts"
+ return 0
+}
+function ble/progcolor/highlight-filename/.single.wattr {
+ local p0=${1%%:*} p1=${1#*:}
+ local wtxt=${text:p0:p1-p0}
+ if ((wtype==_ble_ctx_CMDI)) && ble/alias#active "$wtxt"; then
+ ble/progcolor/wattr#setattr "$p0" "$_ble_attr_CMD_ALIAS"
+ return 0
+ fi
+ local path_opts=after-sep:$highlight_eval_opts
+ [[ $wtxt == '~'* ]] && ((_ble_syntax_attr[p0]!=_ble_attr_TILDE)) && path_opts=$path_opts:notilde
+ ((wtype==_ble_ctx_RDRS||wtype==_ble_attr_VAR||wtype==_ble_ctx_VALI&&wbeg<p0)) && path_opts=$path_opts:noglob
+ local ret path spec ext value count
+ ble/syntax:bash/simple-word/evaluate-path-spec "$wtxt" / "count:$path_opts"; ext=$? value=("${ret[@]}")
+ ((ext==148)) && return 148
+ if ((ext==142)); then
+ if [[ $ble_textarea_render_defer_running ]]; then
+ ble/progcolor/wattr#setg "$p0" d
+ else
+ return 148
+ fi
+ elif ((ext&&(wtype==_ble_ctx_CMDI||wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_RDRF||wtype==_ble_ctx_RDRS||wtype==_ble_ctx_RDRD||wtype==_ble_ctx_RDRD2||wtype==_ble_ctx_VALI))); then
+ ble/progcolor/highlight-filename/.pathspec-with-attr.wattr "$_ble_attr_ERR"
+ elif (((wtype==_ble_ctx_RDRF||wtype==_ble_ctx_RDRD||wtype==_ble_ctx_RDRD2)&&count>=2)); then
+ ble/progcolor/wattr#setattr "$p0" "$_ble_attr_ERR"
+ elif ((wtype==_ble_ctx_CMDI)); then
+ local attr=${_ble_syntax_attr[wbeg]}
+ if ((attr!=_ble_attr_KEYWORD&&attr!=_ble_attr_KEYWORD_BEGIN&&attr!=_ble_attr_KEYWORD_END&&attr!=_ble_attr_KEYWORD_MID&&attr!=_ble_attr_DEL)); then
+ local type=; ble/syntax/highlight/cmdtype "$value" "$wtxt"
+ if ((type==_ble_attr_CMD_FILE||type==_ble_attr_CMD_FILE||type==_ble_attr_ERR)); then
+ ble/progcolor/highlight-filename/.pathspec-with-attr.wattr "$type"
+ elif [[ $type ]]; then
+ ble/progcolor/wattr#setattr "$p0" "$type"
+ fi
+ fi
+ elif ((wtype==_ble_ctx_RDRD||wtype==_ble_ctx_RDRD2)); then
+ if local rex='^[0-9]+-?$|^-$'; [[ $value =~ $rex ]]; then
+ ble/progcolor/wattr#setattr "$p0" "$_ble_attr_DEL"
+ elif ((wtype==_ble_ctx_RDRD2)); then
+ ble/progcolor/highlight-filename/.pathspec-by-name.wattr "$value"
+ else
+ ble/progcolor/wattr#setattr "$p0" "$_ble_attr_ERR"
+ fi
+ elif ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_VALI||wtype==_ble_attr_VAR||wtype==_ble_ctx_RDRS||wtype==_ble_ctx_RDRF)); then
+ ble/progcolor/highlight-filename/.pathspec-by-name.wattr "$value"
+ fi
+}
+function ble/progcolor/highlight-filename.wattr {
+ local p0=$1 p1=$2
+ if ((p0<p1)) && [[ $bleopt_highlight_filename ]]; then
+ local wtxt=${text:p0:p1-p0}
+ local ret; ble/progcolor/highlight-filename/.detect-separated-path "$wtxt"; local ext=$?
+ ((ext==148)) && return 148
+ if ((ext==0)); then
+ local sep=$ret ranges i
+ ble/syntax:bash/simple-word/locate-filename "$wtxt" "$sep" "url:$highlight_eval_opts"
+ (($?==148)) && return 148; ranges=("${ret[@]}")
+ for ((i=0;i<${#ranges[@]};i+=2)); do
+ ble/progcolor/highlight-filename/.single.wattr $((p0+ranges[i])):$((p0+ranges[i+1]))
+ (($?==148)) && return 148
+ done
+ elif ble/syntax:bash/simple-word/is-simple "$wtxt"; then
+ ble/progcolor/highlight-filename/.single.wattr "$p0":"$p1"
+ (($?==148)) && return 148
+ fi
+ fi
+}
+function ble/progcolor/@wattr {
+ [[ $wtype =~ ^[0-9]+$ ]] || return 1
+ [[ $wattr == - ]] || return 1
+ local "${_ble_syntax_progcolor_wattr_vars[@]/%/=}" # WA #D1570 checked
+ ble/progcolor/wattr#initialize
+ "$@"; local ext=$?
+ if ((ext==148)); then
+ _ble_textarea_render_defer=1
+ ble/syntax/wrange#update _ble_syntax_word_defer_ "$wend"
+ else
+ ble/progcolor/wattr#finalize
+ fi
+ return "$ext"
+}
+function ble/progcolor/word:default/.is-option {
+ ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_ARGVI)) &&
+ ble/string#match "$1" '^(-[-_a-zA-Z0-9]*)=?' && # 高速な判定を先に済ませる
+ ble/progcolor/is-option-context &&
+ ble/string#match "$1" '^(-[-_a-zA-Z0-9]*)=?' # 再実行 for BASH_REMATCH
+}
+function ble/progcolor/word:default/impl.wattr {
+ if ((wtype==_ble_ctx_RDRH||wtype==_ble_ctx_RDRI||wtype==_ble_attr_FUNCDEF||wtype==_ble_attr_ERR)); then
+ ble/progcolor/wattr#setattr "$wbeg" "$wtype"
+ else
+ local p0=$wbeg p1=$wend wtxt=${text:wbeg:wlen}
+ if ((wtype==_ble_attr_VAR||wtype==_ble_ctx_VALI)); then
+ local ret
+ ble/syntax:bash/find-rhs "$wtype" "$wbeg" "$wlen" element-assignment && p0=$ret
+ elif ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_VALI)) && { local rex='^[_a-zA-Z][_a-zA-Z0-9]*='; [[ $wtxt =~ $rex ]]; }; then
+ ((p0+=${#BASH_REMATCH}))
+ elif ble/progcolor/word:default/.is-option "$wtxt"; then
+ local rematch=$BASH_REMATCH rematch1=${BASH_REMATCH[1]}
+ local ret; ble/color/face2g argument_option
+ ble/progcolor/wattr#setg "$p0" "$ret"
+ ble/progcolor/wattr#setg $((p0+${#rematch1})) d
+ ((p0+=${#rematch}))
+ fi
+ ble/progcolor/highlight-filename.wattr "$p0" "$p1"
+ (($?==148)) && return 148
+ fi
+ return 0
+}
+function ble/progcolor/word:default {
+ ble/progcolor/@wattr ble/progcolor/word:default/impl.wattr
+}
+function ble/progcolor/default {
+ local i "${_ble_syntax_progcolor_vars[@]/%/=}" # WA #D1570 checked
+ for ((i=1;i<${#comp_words[@]};i++)); do
+ local ref=${tree_words[i]}
+ [[ $ref ]] || continue
+ local progcolor_iword=$i
+ ble/progcolor/load-word-data "$ref"
+ ble/progcolor/word:default
+ done
+}
+function ble/progcolor/.compline-rewrite-command {
+ local ocmd=${comp_words[0]}
+ [[ $1 != "$ocmd" ]] || (($#>=2)) || return 1
+ local IFS=$_ble_term_IFS
+ local ins="$*"
+ comp_line=$ins${comp_line:${#ocmd}}
+ ((comp_point-=${#ocmd},comp_point<0&&(comp_point=0),comp_point+=${#ins}))
+ comp_words=("$@" "${comp_words[@]:1}")
+ ((comp_cword&&(comp_cword+=$#-1)))
+ ble/array#reserve-prototype $#
+ tree_words=("${tree_words[0]}" "${_ble_array_prototype[@]::$#-1}" "${tree_words[@]:1}")
+}
+function ble/progcolor {
+ local cmd=$1 opts=$2
+ local -a progcolor_stats=()
+ local -a progcolor_wvals=()
+ local progcolor_cmdspec_opts=
+ local -a progcolor_optctx=()
+ local -a alias_args=()
+ local checked=" " processed=
+ while :; do
+ if ble/is-function ble/cmdinfo/cmd:"$cmd"/chroma; then
+ ble/progcolor/.compline-rewrite-command "$cmd" "${alias_args[@]}"
+ ble/cmdinfo/cmd:"$cmd"/chroma "$opts"
+ processed=1
+ break
+ elif [[ $cmd == */?* ]] && ble/is-function ble/cmdinfo/cmd:"${cmd##*/}"/chroma; then
+ ble/progcolor/.compline-rewrite-command "${cmd##*/}" "${alias_args[@]}"
+ ble/cmdinfo/cmd:"${cmd##*/}"/chroma "$opts"
+ processed=1
+ break
+ fi
+ checked="$checked$cmd "
+ local ret
+ ble/alias#expand "$cmd"
+ ble/string#split-words ret "$ret"
+ [[ $checked == *" $ret "* ]] && break
+ cmd=$ret
+ ((${#ret[@]}>=2)) &&
+ alias_args=("${ret[@]:1}" "${alias_args[@]}")
+ done
+ [[ $processed ]] ||
+ ble/progcolor/default
+ if [[ ${tree_words[0]} ]]; then
+ local "${_ble_syntax_progcolor_vars[@]/%/=}" # WA #D1570 checked
+ ble/progcolor/load-word-data "${tree_words[0]}"
+ [[ $wattr == - ]] && ble/progcolor/word:default
+ fi
+}
+function ble/highlight/layer:syntax/touch-range {
+ ble/syntax/urange#update '' "$@"
+}
+function ble/highlight/layer:syntax/fill {
+ local _i _arr=$1 _i1=$2 _i2=$3 _v=$4
+ for ((_i=_i1;_i<_i2;_i++)); do
+ builtin eval "$_arr[_i]=\"\$_v\""
+ done
+}
+_ble_highlight_layer_syntax_VARNAMES=(
+ _ble_highlight_layer_syntax_buff
+ _ble_highlight_layer_syntax_active
+ _ble_highlight_layer_syntax1_table
+ _ble_highlight_layer_syntax2_table
+ _ble_highlight_layer_syntax3_list
+ _ble_highlight_layer_syntax3_table)
+function ble/highlight/layer:syntax/initialize-vars {
+ _ble_highlight_layer_syntax_buff=()
+ _ble_highlight_layer_syntax1_table=()
+ _ble_highlight_layer_syntax2_table=()
+ _ble_highlight_layer_syntax3_list=()
+ _ble_highlight_layer_syntax3_table=() # errors
+}
+ble/highlight/layer:syntax/initialize-vars
+function ble/highlight/layer:syntax/update-attribute-table {
+ ble/highlight/layer/update/shift _ble_highlight_layer_syntax1_table
+ if ((_ble_syntax_attr_umin>=0)); then
+ ble/highlight/layer:syntax/touch-range _ble_syntax_attr_umin _ble_syntax_attr_umax
+ local i g=0
+ ((_ble_syntax_attr_umin>0)) &&
+ ((g=_ble_highlight_layer_syntax1_table[_ble_syntax_attr_umin-1]))
+ for ((i=_ble_syntax_attr_umin;i<_ble_syntax_attr_umax;i++)); do
+ if ((${_ble_syntax_attr[i]})); then
+ ble/syntax/attr2g "${_ble_syntax_attr[i]}"
+ fi
+ _ble_highlight_layer_syntax1_table[i]=$g
+ done
+ _ble_syntax_attr_umin=-1 _ble_syntax_attr_umax=-1
+ fi
+}
+function ble/highlight/layer:syntax/word/.update-attributes/.proc {
+ [[ $wtype =~ ^[0-9]+$ ]] || return 1
+ [[ ${node[TE_nofs+4]} == - ]] || return 1
+ if ((wtype==_ble_ctx_CMDI||wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGVI||wtype==_ble_ctx_ARGEI)); then
+ local comp_line comp_point comp_words comp_cword tree_words
+ if ble/syntax:bash/extract-command-by-noderef "$TE_i:$TE_nofs" treeinfo; then
+ local cmd=${comp_words[0]}
+ ble/progcolor "$cmd"
+ return 0
+ fi
+ fi
+ ble/progcolor/word:default
+}
+function ble/highlight/layer:syntax/word/.update-attributes {
+ ((_ble_syntax_word_umin>=0)) || return 1
+ if [[ ! $ble_textarea_render_defer_running ]]; then
+ local _ble_syntax_bash_simple_eval_timeout=$bleopt_highlight_timeout_sync
+ local _ble_syntax_bash_simple_eval_timeout_carry=
+ local highlight_eval_opts=cached:single:stopcheck:timeout-carry
+ else
+ local _ble_syntax_bash_simple_eval_timeout=$bleopt_highlight_timeout_async
+ local highlight_eval_opts=cached:single:stopcheck
+ fi
+ ble/syntax/tree-enumerate-in-range "$_ble_syntax_word_umin" "$_ble_syntax_word_umax" \
+ ble/highlight/layer:syntax/word/.update-attributes/.proc
+}
+function ble/highlight/layer:syntax/word/.apply-attribute {
+ local wbeg=$1 wend=$2 wattr=$3
+ ((wbeg<color_umin&&(wbeg=color_umin),
+ wend>color_umax&&(wend=color_umax),
+ wbeg<wend)) || return 1
+ if [[ $wattr =~ ^[0-9]+$ ]]; then
+ ble/array#fill-range _ble_highlight_layer_syntax2_table "$wbeg" "$wend" "$wattr"
+ elif [[ $wattr == m* ]]; then
+ local ranges; ble/string#split ranges , "${wattr:1}"
+ local i=$wbeg j range
+ for range in "${ranges[@]}"; do
+ local len=${range%%:*} sub_wattr=${range#*:}
+ if [[ $len == '$' ]]; then
+ j=$wend
+ else
+ ((j=i+len,j>wend&&(j=wend)))
+ fi
+ ble/highlight/layer:syntax/word/.apply-attribute "$i" "$j" "$sub_wattr"
+ (((i=j)<wend)) || break
+ done
+ elif [[ $wattr == d ]]; then
+ ble/array#fill-range _ble_highlight_layer_syntax2_table "$wbeg" "$wend" ''
+ fi
+}
+function ble/highlight/layer:syntax/word/.proc-childnode {
+ if [[ $wtype =~ ^[0-9]+$ ]]; then
+ local wbeg=$wbegin wend=$TE_i
+ ble/highlight/layer:syntax/word/.apply-attribute "$wbeg" "$wend" "$attr"
+ fi
+ ((tchild>=0)) && ble/syntax/tree-enumerate-children "$proc_children"
+}
+function ble/highlight/layer:syntax/update-word-table {
+ local color_umin=-1 color_umax=-1 iN=${#_ble_syntax_text}
+ ble/highlight/layer:syntax/word/.update-attributes
+ ble/highlight/layer/update/shift _ble_highlight_layer_syntax2_table
+ ble/syntax/wrange#update _ble_syntax_word_ "$_ble_syntax_vanishing_word_umin" "$_ble_syntax_vanishing_word_umax"
+ ble/syntax/wrange#update color_ "$_ble_syntax_vanishing_word_umin" "$_ble_syntax_vanishing_word_umax"
+ _ble_syntax_vanishing_word_umin=-1 _ble_syntax_vanishing_word_umax=-1
+ ble/highlight/layer:syntax/word/.apply-attribute 0 "$iN" d # clear word color
+ local TE_i
+ for ((TE_i=_ble_syntax_word_umax;TE_i>=_ble_syntax_word_umin;)); do
+ if ((TE_i>0)) && [[ ${_ble_syntax_tree[TE_i-1]} ]]; then
+ local -a node
+ ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}"
+ local wlen=${node[1]}
+ local wbeg=$((TE_i-wlen)) wend=$TE_i
+ if [[ ${node[0]} =~ ^[0-9]+$ ]]; then
+ local attr=${node[4]}
+ ble/highlight/layer:syntax/word/.apply-attribute "$wbeg" "$wend" "$attr"
+ fi
+ local tclen=${node[2]}
+ if ((tclen>=0)); then
+ local tchild=$((TE_i-tclen))
+ local tree= TE_nofs=0 proc_children=ble/highlight/layer:syntax/word/.proc-childnode
+ ble/syntax/tree-enumerate-children "$proc_children"
+ fi
+ ((TE_i=wbeg))
+ else
+ ((TE_i--))
+ fi
+ done
+ ((color_umin>=0)) && ble/highlight/layer:syntax/touch-range "$color_umin" "$color_umax"
+ _ble_syntax_word_umin=-1 _ble_syntax_word_umax=-1
+}
+function ble/highlight/layer:syntax/update-error-table/set {
+ local i1=$1 i2=$2 g=$3
+ if ((i1<i2)); then
+ ble/highlight/layer:syntax/touch-range "$i1" "$i2"
+ ble/highlight/layer:syntax/fill _ble_highlight_layer_syntax3_table "$i1" "$i2" "$g"
+ _ble_highlight_layer_syntax3_list[${#_ble_highlight_layer_syntax3_list[@]}]="$i1 $i2"
+ fi
+}
+function ble/highlight/layer:syntax/update-error-table {
+ ble/highlight/layer/update/shift _ble_highlight_layer_syntax3_table
+ local j=0 jN=${#_ble_highlight_layer_syntax3_list[*]}
+ if ((jN)); then
+ for ((j=0;j<jN;j++)); do
+ local -a range
+ ble/string#split-words range "${_ble_highlight_layer_syntax3_list[j]}"
+ local a=${range[0]} b=${range[1]}
+ ((a>=DMAX0?(a+=DMAX-DMAX0):(a>=DMIN&&(a=DMIN)),
+ b>=DMAX0?(b+=DMAX-DMAX0):(b>=DMIN&&(b=DMIN))))
+ if ((a<b)); then
+ ble/highlight/layer:syntax/fill _ble_highlight_layer_syntax3_table "$a" "$b" ''
+ ble/highlight/layer:syntax/touch-range "$a" "$b"
+ fi
+ done
+ _ble_highlight_layer_syntax3_list=()
+ fi
+ if ((iN>0)) && [[ ${_ble_syntax_stat[iN]} ]]; then
+ local ret; ble/color/face2g syntax_error; local g=$ret
+ local -a stat
+ ble/string#split-words stat "${_ble_syntax_stat[iN]}"
+ local ctx=${stat[0]} nlen=${stat[3]} nparam=${stat[6]}
+ [[ $nparam == none ]] && nparam=
+ local i inest
+ if ((nlen>0)) || [[ $nparam ]]; then
+ ble/highlight/layer:syntax/update-error-table/set $((iN-1)) "$iN" "$g"
+ if ((nlen>0)); then
+ ((inest=iN-nlen))
+ while ((inest>=0)); do
+ local inest2
+ for((inest2=inest+1;inest2<iN;inest2++)); do
+ [[ ${_ble_syntax_attr[inest2]} ]] && break
+ done
+ ble/highlight/layer:syntax/update-error-table/set "$inest" "$inest2" "$g"
+ ((i=inest))
+ local wtype wbegin tchild tprev
+ ble/syntax/parse/nest-pop
+ ((inest>=i&&(inest=i-1)))
+ done
+ fi
+ fi
+ if ((ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXC||ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1||ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_CARGX2||ctx==_ble_ctx_COARGX)); then
+ ble/highlight/layer:syntax/update-error-table/set $((iN-1)) "$iN" "$g"
+ fi
+ fi
+}
+function ble/highlight/layer:syntax/update {
+ local text=$1 player=$2
+ local i iN=${#text}
+ local umin=-1 umax=-1
+ ((DMIN>=0)) && umin=$DMIN umax=$DMAX
+ if [[ ! $bleopt_highlight_syntax ]]; then
+ if [[ $_ble_highlight_layer_syntax_active ]]; then
+ _ble_highlight_layer_syntax_active=
+ PREV_UMIN=0 PREV_UMAX=${#1}
+ fi
+ return
+ fi
+ if [[ ! $_ble_highlight_layer_syntax_active ]]; then
+ _ble_highlight_layer_syntax_active=1
+ umin=0 umax=${#text}
+ fi
+ if [[ $bleopt_syntax_debug ]]; then
+ local debug_attr_umin=$_ble_syntax_attr_umin
+ local debug_attr_uend=$_ble_syntax_attr_umax
+ fi
+ ble/cmdspec/initialize # load chroma
+ ble/highlight/layer:syntax/update-attribute-table
+ ble/highlight/layer:syntax/update-word-table
+ ble/highlight/layer:syntax/update-error-table
+ if ((DMIN>=0)); then
+ ble/highlight/layer/update/shift _ble_highlight_layer_syntax_buff
+ if ((DMAX>0)); then
+ local g sgr ch ret
+ ble/highlight/layer:syntax/getg "$DMAX"
+ ble/color/g2sgr "$g"; sgr=$ret
+ ch=${_ble_highlight_layer_plain_buff[DMAX]}
+ _ble_highlight_layer_syntax_buff[DMAX]=$sgr$ch
+ fi
+ fi
+ local i j g gprev=0
+ if ((umin>0)); then
+ ble/highlight/layer:syntax/getg $((umin-1))
+ gprev=$g
+ fi
+ if ((umin>=0)); then
+ local ret
+ for ((i=umin;i<=umax;i++)); do
+ local ch=${_ble_highlight_layer_plain_buff[i]}
+ ble/highlight/layer:syntax/getg "$i"
+ [[ $g ]] || ble/highlight/layer/update/getg "$i"
+ if ((gprev!=g)); then
+ ble/color/g2sgr "$g"
+ ch=$ret$ch
+ ((gprev=g))
+ fi
+ _ble_highlight_layer_syntax_buff[i]=$ch
+ done
+ fi
+ PREV_UMIN=$umin PREV_UMAX=$umax
+ PREV_BUFF=_ble_highlight_layer_syntax_buff
+ if [[ $bleopt_syntax_debug ]]; then
+ local status buff= nl=$'\n'
+ _ble_syntax_attr_umin=$debug_attr_umin _ble_syntax_attr_umax=$debug_attr_uend ble/syntax/print-status -v status
+ local -a DRAW_BUFF=()
+ ble/syntax/print-layer-buffer.draw plain
+ ble/syntax/print-layer-buffer.draw syntax
+ ble/syntax/print-layer-buffer.draw disabled
+ ble/syntax/print-layer-buffer.draw region
+ ble/syntax/print-layer-buffer.draw overwrite
+ local ret; ble/canvas/sflush.draw
+ status=$status$ret
+ ble/edit/info/show ansi "$status"
+ fi
+}
+function ble/highlight/layer:syntax/getg {
+ [[ ! $bleopt_highlight_syntax ]] && return
+ local i=$1
+ if [[ ${_ble_highlight_layer_syntax3_table[i]} ]]; then
+ g=${_ble_highlight_layer_syntax3_table[i]}
+ elif [[ ${_ble_highlight_layer_syntax2_table[i]} ]]; then
+ g=${_ble_highlight_layer_syntax2_table[i]}
+ elif [[ ${_ble_highlight_layer_syntax1_table[i]} ]]; then
+ g=${_ble_highlight_layer_syntax1_table[i]}
+ fi
+}
+function ble/highlight/layer:syntax/textarea_render_defer.hook {
+ ble/syntax/wrange#update _ble_syntax_word_ "$_ble_syntax_word_defer_umin" "$_ble_syntax_word_defer_umax"
+ _ble_syntax_word_defer_umin=-1
+ _ble_syntax_word_defer_umax=-1
+}
+blehook textarea_render_defer+=ble/highlight/layer:syntax/textarea_render_defer.hook
+function ble/syntax/import { :; }
+blehook/invoke syntax_load
+ble/function#try ble/textarea#invalidate str
+return 0
diff --git a/.local/src/blesh/lib/core-test.sh b/.local/src/blesh/lib/core-test.sh
new file mode 100644
index 0000000..6adda33
--- /dev/null
+++ b/.local/src/blesh/lib/core-test.sh
@@ -0,0 +1,200 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+function ble/test/getdir {
+ dir=$_ble_base_run/$$.test
+ [[ -d $dir ]] || ble/bin/mkdir -p "$dir"
+}
+_ble_test_dir=
+function ble/test/chdir {
+ local dir
+ ble/test/getdir
+ ble/util/getpid
+ _ble_test_dir=$dir/$BASHPID.d
+ [[ -d $_ble_test_dir ]] ||
+ ble/bin/mkdir -p "$_ble_test_dir"
+ cd "$_ble_test_dir"
+}
+function ble/test/rmdir {
+ [[ -d $_ble_test_dir ]] &&
+ ble/bin/rm -rf "$_ble_test_dir"
+ return 0
+}
+_ble_test_logfile_fd=
+function ble/test/log {
+ if [[ $_ble_test_logfile_fd ]]; then
+ ble/util/print "$1" >&$_ble_test_logfile_fd
+ fi
+ ble/util/print "$1"
+}
+function ble/test/log#open {
+ local file=$1
+ if ble/fd#alloc _ble_test_logfile_fd '>>$file'; then
+ local h10=----------
+ [[ -s $file ]] &&
+ ble/util/print "$h10$h10$h10$h10$h10$h10$h10" >&$_ble_test_logfile_fd
+ ble/util/print "[$(date +'%F %T %Z')] test: start logging" >&$_ble_test_logfile_fd
+ fi
+}
+function ble/test/log#close {
+ if [[ $_ble_test_logfile_fd ]]; then
+ ble/util/print "[$(date +'%F %T %Z')] test: end logging" >&$_ble_test_logfile_fd
+ ble/fd#close _ble_test_logfile_fd
+ _ble_test_logfile_fd=
+ fi
+}
+if ble/bin/.freeze-utility-path colored; then
+ function ble/test/diff.impl {
+ ble/bin/colored diff -u "$@"
+ }
+else
+ function ble/test/diff.impl {
+ diff -u "$@"
+ }
+fi
+function ble/test/diff {
+ local dir
+ ble/test/getdir
+ ble/util/getpid
+ local f1=$BASHPID.$1.expect
+ local f2=$BASHPID.$1.result
+ (
+ cd "$dir"
+ ble/util/print "$2" >| "$f1"
+ ble/util/print "$3" >| "$f2"
+ ble/util/assign ret 'ble/test/diff.impl "$f1" "$f2"'
+ ble/test/log "$ret"
+ >| "$f1" >| "$f2"
+ )
+}
+_ble_test_section_fd=
+_ble_test_section_file=
+_ble_test_section_title=section
+_ble_test_section_count=0
+function ble/test/start-section {
+ [[ $_ble_test_section_fd ]] && ble/test/end-section
+ _ble_test_section_title=$1
+ _ble_test_section_count=$2
+ local dir
+ ble/test/getdir
+ ble/util/getpid
+ _ble_test_section_file=$dir/$BASHPID
+ ble/fd#alloc _ble_test_section_fd '> "$_ble_test_section_file"'
+}
+function ble/test/end-section {
+ [[ $_ble_test_section_fd ]] || return 1
+ ble/fd#close _ble_test_section_fd
+ _ble_test_section_fd=
+ local ntest npass count=$_ble_test_section_count
+ local ntest nfail npass
+ builtin eval -- $(
+ ble/bin/awk '
+ BEGIN{test=0;fail=0;pass=0;}
+ /^test /{test++}
+ /^fail /{fail++}
+ /^pass /{pass++}
+ END{print "ntest="test" nfail="fail" npass="pass;}
+ ' "$_ble_test_section_file")
+ local sgr=$'\e[32m' sgr0=$'\e[m'
+ ((npass==ntest)) || sgr=$'\e[31m'
+ local ncrash=$((ntest-nfail-npass))
+ local nskip=$((count-ntest))
+ if ((ntest)); then
+ local percentage=$((npass*1000/ntest)) # Note: 切り捨て
+ ble/util/sprintf percentage '%6s' "$((percentage/10)).$((percentage%10))%" # "XXX.X%"
+ else
+ local percentage=---.-%
+ fi
+ ble/test/log "$sgr$percentage$sgr0 [section] $_ble_test_section_title: $sgr$npass/$ntest$sgr0 ($nfail fail, $ncrash crash, $nskip skip)"
+ ((npass==ntest))
+}
+function ble/test/section#incr {
+ local title=$1
+ [[ $_ble_test_section_fd ]] || return 1
+ ble/util/print "test $title" >&$_ble_test_section_fd
+}
+function ble/test/section#report {
+ local ext=$? title=$1
+ [[ $_ble_test_section_fd ]] || return 1
+ local code=fail; ((ext==0)) && code=pass
+ ble/util/print "$code $title" >&$_ble_test_section_fd
+}
+function ble/test/.read-arguments {
+ local _stdout _stderr _exit _ret
+ local qstdout qstderr qexit qret
+ local -a buff=()
+ while (($#)); do
+ local arg=$1; shift
+ case $arg in
+ ('#'*)
+ local ret; ble/string#trim "${arg#'#'}"
+ title=$ret ;;
+ (stdout[:=]*)
+ [[ $qstdout ]] && _stdout=$_stdout$'\n'
+ qstdout=1
+ _stdout=$_stdout${arg#*[:=]} ;;
+ (stderr[:=]*)
+ [[ $qstderr ]] && _stderr=$_stderr$'\n'
+ qstderr=1
+ _stderr=$_stderr${arg#*[:=]} ;;
+ (ret[:=]*)
+ qret=1
+ _ret=${arg#*[:=]} ;;
+ (exit[:=]*)
+ qexit=1
+ _exit=${arg#*[:=]} ;;
+ (code[:=]*)
+ ((${#buff[@]})) && ble/array#push buff $'\n'
+ ble/array#push buff "${arg#*[:=]}" ;;
+ (--depth=*)
+ caller_depth=${arg#*=} ;;
+ (--display-code=*)
+ display_code=${arg#*=} ;;
+ (*)
+ ((${#buff[@]})) && ble/array#push buff ' '
+ ble/array#push buff "$arg" ;;
+ esac
+ done
+ [[ $qstdout ]] && item_expect[0]=$_stdout
+ [[ $qstderr ]] && item_expect[1]=$_stderr
+ [[ $qexit ]] && item_expect[2]=$_exit
+ [[ $qret ]] && item_expect[3]=$_ret
+ ((${#item_expect[@]})) || item_expect[2]=0
+ IFS= builtin eval 'code="${buff[*]}"'
+}
+function ble/test {
+ local -a item_name=(stdout stderr exit ret)
+ local code title
+ local caller_depth=0 display_code=
+ local -a item_expect=()
+ ble/test/.read-arguments "$@"
+ local caller_lineno=${BASH_LINENO[caller_depth+0]}
+ local caller_source=${BASH_SOURCE[caller_depth+1]}
+ title="$caller_source:$caller_lineno${title+ ($title)}"
+ ble/test/section#incr "$title"
+ ble/util/assign stderr '
+ ble/util/assign stdout "$code" 2>&1'; exit=$?
+ local -a item_result=()
+ item_result[0]=$stdout
+ item_result[1]=$stderr
+ item_result[2]=$exit
+ item_result[3]=$ret
+ local i flag_error=
+ for i in "${!item_expect[@]}"; do
+ [[ ${item_result[i]} == "${item_expect[i]}" ]] && continue
+ if [[ ! $flag_error ]]; then
+ flag_error=1
+ ble/test/log $'\e[1m'"$title"$'\e[m: \e[91m'"${display_code:-$code}"$'\e[m'
+ fi
+ ble/test/diff "${item_name[i]}" "${item_expect[i]}" "${item_result[i]}"
+ done
+ if [[ $flag_error ]]; then
+ if [[ ! ${item_expect[1]+set} && $stderr ]]; then
+ ble/test/log "<STDERR>"
+ ble/test/log "$stderr"
+ ble/test/log "</STDERR>"
+ fi
+ ble/test/log
+ fi
+ [[ ! $flag_error ]]
+ ble/test/section#report "$title"
+ return 0
+}
diff --git a/.local/src/blesh/lib/init-bind.sh b/.local/src/blesh/lib/init-bind.sh
new file mode 100644
index 0000000..056654b
--- /dev/null
+++ b/.local/src/blesh/lib/init-bind.sh
@@ -0,0 +1,92 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+function ble/init:bind/append {
+ local xarg="\"$1\":ble-decode/.hook $2; builtin eval -- \"\$_ble_decode_bind_hook\""
+ local rarg=$1 condition=$3${3:+' && '}
+ ble/util/print "${condition}builtin bind -x '${xarg//$q/$Q}'" >> "$fbind1"
+ ble/util/print "${condition}builtin bind -r '${rarg//$q/$Q}'" >> "$fbind2"
+}
+function ble/init:bind/append-macro {
+ local kseq1=$1 kseq2=$2 condition=$3${3:+' && '}
+ local sarg="\"$kseq1\":\"$kseq2\"" rarg=$kseq1
+ ble/util/print "${condition}builtin bind '${sarg//$q/$Q}'" >> "$fbind1"
+ ble/util/print "${condition}builtin bind -r '${rarg//$q/$Q}'" >> "$fbind2"
+}
+function ble/init:bind/generate-binder {
+ local fbind1=$_ble_base_cache/decode.bind.$_ble_bash.$bleopt_input_encoding.bind
+ local fbind2=$_ble_base_cache/decode.bind.$_ble_bash.$bleopt_input_encoding.unbind
+ ble/edit/info/show text "ble.sh: updating binders..."
+ : >| "$fbind1"
+ : >| "$fbind2"
+ local q=\' Q="'\\''"
+ local altdqs24='\xC0\x98'
+ local altdqs27='\xC0\x9B'
+ local esc00=$((40300<=_ble_bash&&_ble_bash<50000))
+ local bind18XX=0
+ if ((40400<=_ble_bash&&_ble_bash<50000)); then
+ ble/util/print "[[ -o emacs ]] && builtin bind 'set keyseq-timeout 1'" >> "$fbind1"
+ fbind2=$fbind1 ble/init:bind/append '\C-x\C-x' 24 '[[ -o emacs ]]'
+ elif ((_ble_bash<40300)); then
+ bind18XX=1
+ fi
+ local esc1B=3
+ local esc1B5B=1 bindAllSeq=0
+ local esc1B1B=$((40100<=_ble_bash&&_ble_bash<40300))
+ local i
+ for i in {128..255} {0..127}; do
+ local ret; ble/decode/c2dqs "$i"
+ if ((i==0)); then
+ if ((esc00)); then
+ ble/init:bind/append-macro '\C-@' '\xC0\x80'
+ else
+ ble/init:bind/append "$ret" "$i"
+ fi
+ elif ((i==24)); then
+ if ((bind18XX)); then
+ ble/init:bind/append "$ret" "$i" '[[ ! -o emacs ]]'
+ else
+ ble/init:bind/append "$ret" "$i"
+ fi
+ elif ((i==27)); then
+ if ((esc1B==0)); then
+ ble/init:bind/append "$ret" "$i"
+ elif ((esc1B==2)); then
+ ble/init:bind/append-macro '\e' "$altdqs27"
+ elif ((esc1B==3)); then
+ ble/init:bind/append-macro '\e' '\xDF\xBF' # C-[
+ fi
+ else
+ ((i==28&&_ble_bash>=50000)) && ret='\x1C'
+ ble/init:bind/append "$ret" "$i"
+ fi
+ if ((bind18XX)); then
+ if ((i==24)); then
+ ble/init:bind/append-macro "\C-x$ret" "$altdqs24$altdqs24" '[[ -o emacs ]]'
+ else
+ ble/init:bind/append-macro "\C-x$ret" "$altdqs24$ret" '[[ -o emacs ]]'
+ fi
+ fi
+ if ((esc1B==3)); then
+ ble/init:bind/append-macro '\e'"$ret" "$altdqs27$ret"
+ else
+ if ((esc1B==1)); then
+ if ((i==91&&esc1B5B)); then
+ ble/init:bind/append-macro '\e[' "$altdqs27["
+ else
+ ble/init:bind/append "\\e$ret" "27 $i"
+ fi
+ fi
+ if ((i==27&&esc1B1B)); then
+ ble/init:bind/append-macro '\e\e' '\e[^'
+ ble/util/print "ble-bind -k 'ESC [ ^' __esc__" >> "$fbind1"
+ ble/util/print "ble-bind -f __esc__ '.CHARS 27 27'" >> "$fbind1"
+ fi
+ fi
+ done
+ if ((bindAllSeq)); then
+ ble/util/print 'source "$_ble_decode_bind_fbinder.bind"' >> "$fbind1"
+ ble/util/print 'source "$_ble_decode_bind_fbinder.unbind"' >> "$fbind2"
+ fi
+ ble/function#try ble/encoding:"$bleopt_input_encoding"/generate-binder
+ ble/edit/info/immediate-show text "ble.sh: updating binders... done"
+}
+ble/init:bind/generate-binder
diff --git a/.local/src/blesh/lib/init-cmap.sh b/.local/src/blesh/lib/init-cmap.sh
new file mode 100644
index 0000000..1a2b4ef
--- /dev/null
+++ b/.local/src/blesh/lib/init-cmap.sh
@@ -0,0 +1,186 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+function ble/init:cmap/bind-single-csi {
+ ble-bind -k "ESC [ $1" "$2"
+ ble-bind -k "CSI $1" "$2"
+}
+function ble/init:cmap/bind-single-ss3 {
+ ble-bind -k "ESC O $1" "$2"
+ ble-bind -k "SS3 $1" "$2"
+}
+function ble/init:cmap/bind-keypad-key {
+ local Ft=$1 name=$2
+ (($3&4)) && ble-bind --csi "$Ft" "$name"
+ (($3&1)) && ble/init:cmap/bind-single-ss3 "$Ft" "$name"
+ (($3&2)) && ble-bind -k "ESC ? $Ft" "$name"
+}
+function ble/init:cmap/initialize {
+ ble/edit/info/immediate-show text "ble/lib/init-cmap.sh: updating key sequences..."
+ ble-decode-kbd/generate-keycode insert
+ ble-decode-kbd/generate-keycode home
+ ble-decode-kbd/generate-keycode prior
+ ble-decode-kbd/generate-keycode delete
+ ble-decode-kbd/generate-keycode end
+ ble-decode-kbd/generate-keycode next
+ ble-decode-kbd/generate-keycode find
+ ble-decode-kbd/generate-keycode select
+ local kend; ble/util/assign kend 'tput @7 2>/dev/null || tput kend 2>/dev/null'
+ if [[ $kend == $'\e[5~' ]]; then
+ ble-bind --csi '1~' insert
+ ble-bind --csi '2~' home
+ ble-bind --csi '3~' prior
+ ble-bind --csi '4~' delete
+ ble-bind --csi '5~' end
+ ble-bind --csi '6~' next
+ else
+ if [[ $kend == $'\e[F' && ( $TERM == xterm || $TERM == xterm-* || $TERM == kvt ) ]]; then
+ ble-bind --csi '1~' find
+ ble-bind --csi '4~' select
+ else
+ ble-bind --csi '1~' home
+ ble-bind --csi '4~' end
+ fi
+ ble-bind --csi '2~' insert
+ ble-bind --csi '3~' delete
+ ble-bind --csi '5~' prior
+ ble-bind --csi '6~' next
+ fi
+ ble-bind --csi '7~' home
+ ble-bind --csi '8~' end
+ local kdch1; ble/util/assign kdch1 'tput kD 2>/dev/null || tput kdch1 2>/dev/null'
+ [[ $kdch1 == $'\x7F' || $TERM == sun* ]] && ble-bind -k 'DEL' delete
+ ble-bind --csi '11~' f1
+ ble-bind --csi '12~' f2
+ ble-bind --csi '13~' f3
+ ble-bind --csi '14~' f4
+ ble-bind --csi '15~' f5
+ ble-bind --csi '17~' f6
+ ble-bind --csi '18~' f7
+ ble-bind --csi '19~' f8
+ ble-bind --csi '20~' f9
+ ble-bind --csi '21~' f10
+ ble-bind --csi '23~' f11
+ ble-bind --csi '24~' f12
+ ble-bind --csi '25~' f13
+ ble-bind --csi '26~' f14
+ ble-bind --csi '28~' f15
+ ble-bind --csi '29~' f16
+ ble-bind --csi '31~' f17
+ ble-bind --csi '32~' f18
+ ble-bind --csi '33~' f19
+ ble-bind --csi '34~' f20
+ ble-bind --csi '200~' paste_begin
+ ble-bind --csi '201~' paste_end
+ ble/init:cmap/bind-keypad-key 'SP' SP 3 # kpspace
+ ble/init:cmap/bind-keypad-key 'A' up 5
+ ble/init:cmap/bind-keypad-key 'B' down 5
+ ble/init:cmap/bind-keypad-key 'C' right 5
+ ble/init:cmap/bind-keypad-key 'D' left 5
+ ble/init:cmap/bind-keypad-key 'E' begin 5
+ ble/init:cmap/bind-keypad-key 'F' end 5
+ ble/init:cmap/bind-keypad-key 'H' home 5
+ ble/init:cmap/bind-keypad-key 'I' TAB 3 # kptab (Note: CSI I は xterm SM(?1004) focus と重複)
+ ble/init:cmap/bind-keypad-key 'M' RET 7 # kpent
+ ble/init:cmap/bind-keypad-key 'P' f1 5 # kpf1 # Note: 普通の f1-f4
+ ble/init:cmap/bind-keypad-key 'Q' f2 5 # kpf2 # に対してこれらの
+ ble/init:cmap/bind-keypad-key 'R' f3 5 # kpf3 # シーケンスを送る
+ ble/init:cmap/bind-keypad-key 'S' f4 5 # kpf4 # 端末もある。
+ ble/init:cmap/bind-keypad-key 'j' '*' 7 # kpmul
+ ble/init:cmap/bind-keypad-key 'k' '+' 7 # kpadd
+ ble/init:cmap/bind-keypad-key 'l' ',' 7 # kpsep
+ ble/init:cmap/bind-keypad-key 'm' '-' 7 # kpsub
+ ble/init:cmap/bind-keypad-key 'n' '.' 7 # kpdec
+ ble/init:cmap/bind-keypad-key 'o' '/' 7 # kpdiv
+ ble/init:cmap/bind-keypad-key 'p' '0' 7 # kp0
+ ble/init:cmap/bind-keypad-key 'q' '1' 7 # kp1
+ ble/init:cmap/bind-keypad-key 'r' '2' 7 # kp2
+ ble/init:cmap/bind-keypad-key 's' '3' 7 # kp3
+ ble/init:cmap/bind-keypad-key 't' '4' 7 # kp4
+ ble/init:cmap/bind-keypad-key 'u' '5' 7 # kp5
+ ble/init:cmap/bind-keypad-key 'v' '6' 7 # kp6
+ ble/init:cmap/bind-keypad-key 'w' '7' 7 # kp7
+ ble/init:cmap/bind-keypad-key 'x' '8' 7 # kp8
+ ble/init:cmap/bind-keypad-key 'y' '9' 7 # kp9
+ ble/init:cmap/bind-keypad-key 'X' '=' 7 # kpeq
+ ble/init:cmap/bind-keypad-key 'I' focus 4 # Note: 1 (= SS3) は TAB と重複するので設定しない
+ ble/init:cmap/bind-keypad-key 'O' blur 5
+ ble/init:cmap/bind-single-csi 'Z' S-TAB
+ ble/init:cmap/bind-single-ss3 'a' C-up
+ ble/init:cmap/bind-single-csi 'a' S-up
+ ble/init:cmap/bind-single-ss3 'b' C-down
+ ble/init:cmap/bind-single-csi 'b' S-down
+ ble/init:cmap/bind-single-ss3 'c' C-right
+ ble/init:cmap/bind-single-csi 'c' S-right
+ ble/init:cmap/bind-single-ss3 'd' C-left
+ ble/init:cmap/bind-single-csi 'd' S-left
+ ble/init:cmap/bind-single-csi '2 $' S-insert # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '3 $' S-delete # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '5 $' S-prior # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '6 $' S-next # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '7 $' S-home # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '8 $' S-end # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '2 3 $' S-f11 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '2 4 $' S-f12 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '2 5 $' S-f13 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '2 6 $' S-f14 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '2 8 $' S-f15 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '2 9 $' S-f16 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '3 1 $' S-f17 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '3 2 $' S-f18 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '3 3 $' S-f19 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '3 4 $' S-f20 # ECMA-48 違反
+ ble/init:cmap/bind-single-csi '[ A' f1
+ ble/init:cmap/bind-single-csi '[ B' f2
+ ble/init:cmap/bind-single-csi '[ C' f3
+ ble/init:cmap/bind-single-csi '[ D' f4
+ ble/init:cmap/bind-single-csi '[ E' f5
+ ble/init:cmap/bind-single-csi '2 4 7 z' insert
+ ble/init:cmap/bind-single-csi '2 1 4 z' home
+ ble/init:cmap/bind-single-csi '2 2 0 z' end
+ ble/init:cmap/bind-single-csi '2 2 2 z' prior
+ ble/init:cmap/bind-single-csi '2 1 6 z' next
+ ble/init:cmap/bind-single-csi '2 2 4 z' f1
+ ble/init:cmap/bind-single-csi '2 2 5 z' f2
+ ble/init:cmap/bind-single-csi '2 2 6 z' f3
+ ble/init:cmap/bind-single-csi '2 2 7 z' f4
+ ble/init:cmap/bind-single-csi '2 2 8 z' f5
+ ble/init:cmap/bind-single-csi '2 2 9 z' f6
+ ble/init:cmap/bind-single-csi '2 3 0 z' f7
+ ble/init:cmap/bind-single-csi '2 3 1 z' f8
+ ble/init:cmap/bind-single-csi '2 3 2 z' f9
+ ble/init:cmap/bind-single-csi '2 3 3 z' f10
+ ble/init:cmap/bind-single-csi '2 3 4 z' f11
+ ble/init:cmap/bind-single-csi '2 3 5 z' f12
+ ble/init:cmap/bind-single-csi '1 z' find # from xterm ctlseqs
+ ble/init:cmap/bind-single-csi '4 z' select # from xterm ctlseqs
+ ble/init:cmap/bind-single-csi '2 J' S-home
+ ble/init:cmap/bind-single-csi 'J' C-end
+ ble/init:cmap/bind-single-csi 'K' S-end
+ ble/init:cmap/bind-single-csi '4 l' S-insert
+ ble/init:cmap/bind-single-csi 'L' C-insert
+ ble/init:cmap/bind-single-csi '4 h' insert
+ ble/init:cmap/bind-single-csi '2 K' S-delete
+ ble/init:cmap/bind-single-csi 'P' delete
+ _ble_decode_csimap_kitty_u=(
+ [57358]=capslock [57359]=scrolllock [57360]=numlock [57361]=print [57362]=pause [57363]=menu
+ [57376]=f13 [57377]=f14 [57378]=f15 [57379]=f16 [57380]=f17 [57381]=f18 [57382]=f19 [57383]=f20
+ [57384]=f21 [57385]=f22 [57386]=f23 [57387]=f24 [57388]=f25 [57389]=f26 [57390]=f27 [57391]=f28
+ [57392]=f29 [57393]=f30 [57394]=f31 [57395]=f32 [57396]=f33 [57397]=f34 [57398]=f35
+ [57399]=0 [57400]=1 [57401]=2 [57402]=3 [57403]=4 [57404]=5 [57405]=6 [57406]=7 [57407]=8 [57408]=9
+ [57409]='.' [57410]='/' [57411]='*' [57412]='-' [57413]='+' [57414]=RET [57415]='=' [57416]=','
+ [57417]=left [57418]=right [57419]=up [57420]=down
+ [57421]=prior [57422]=next [57423]=home [57424]=end [57425]=insert [57426]=delete [57427]=begin
+ [57428]=media_play [57429]=media_pause [57430]=media_play_pause [57431]=media_reverse
+ [57432]=media_stop [57433]=media_fast_forward [57434]=media_rewind [57435]=media_track_next
+ [57436]=media_track_prev [57437]=media_record [57438]=lower_volume [57439]=raise_volume
+ [57440]=mute_volume
+ [57441]=lshift [57442]=lcontrol [57443]=lalter [57444]=lsuper [57445]=lhyper [57446]=lmeta
+ [57447]=rshift [57448]=rcontrol [57449]=ralter [57450]=rsuper [57451]=rhyper [57452]=rmeta
+ [57453]=iso_shift3 [57454]=iso_shift5
+ )
+ local keyname
+ for keyname in "${_ble_decode_csimap_kitty_u[@]}"; do
+ ble-decode-kbd/generate-keycode "$keyname"
+ done
+ ble/edit/info/immediate-show text "ble/lib/init-cmap.sh: updating key sequences... done"
+}
+ble/init:cmap/initialize
diff --git a/.local/src/blesh/lib/init-msys1.sh b/.local/src/blesh/lib/init-msys1.sh
new file mode 100644
index 0000000..596ef8f
--- /dev/null
+++ b/.local/src/blesh/lib/init-msys1.sh
@@ -0,0 +1,130 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+function ble-edit/io:msys1/is-msys1 {
+ local cr; cr=$'\r'
+ [[ $OSTYPE == msys && ! $cr ]]
+}
+function ble-edit/io:msys1/get-winpid.proc {
+ /usr/bin/ps | /usr/bin/gawk -v pid="$1" '
+ BEGIN {
+ cygpid_len = 9;
+ winpid_len = 36;
+ }
+ NR == 1 {
+ line = $0;
+ if (!match(line, /.*\yPID\y/)) next;
+ cygpid_end = RLENGTH;
+ if (!match(line, /.*\yWINPID\y/)) next;
+ winpid_end = RLENGTH;
+ next;
+ }
+ function get_last_number(line, limit, _, head, i) {
+ head = substr(line, 1, limit);
+ if (i = match(head, /[0-9]+$/))
+ return substr(head, i, RLENGTH);
+ return -1;
+ }
+ {
+ cygpid = get_last_number($0, cygpid_end);
+ if (cygpid != pid) next;
+ print get_last_number($0, winpid_end);
+ exit
+ }
+ '
+}
+function ble-edit/io:msys1/compile-helper {
+ local helper=$1
+ [[ -x $helper && -s $helper && $helper -nt $_ble_base/lib/init-msys1.sh ]] && return 0
+ gcc -O2 -s -o "$helper" -xc - << EOF || return 1
+// For MSYS 1.0
+#include <stdio.h>
+#include <windows.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+BOOL is_process_alive(HANDLE handle) {
+ DWORD result;
+ return GetExitCodeProcess(handle, &result) && result == STILL_ACTIVE;
+}
+
+BOOL is_file(const char* filename) {
+ struct stat st;
+ return stat(filename, &st) == 0 && S_ISREG(st.st_mode);
+}
+
+int main(int argc, char** argv) {
+ const char* winpid = argv[1];
+ const char* fname_buff = argv[2];
+ const char* fname_read = argv[3];
+
+ signal(SIGINT, SIG_IGN);
+ //signal(SIGQUIT, SIG_IGN);
+
+ int ppid = atoi(winpid);
+ if (!ppid) {
+ fprintf(stderr, "ble.sh (msys1): invalid process ID '%s'\n", winpid);
+ return 1;
+ }
+ HANDLE parent_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ppid);
+ if (parent_process == NULL) {
+ fprintf(stderr, "ble.sh (msys1): failed to open the parent process '%s'\n", winpid);
+ return 1;
+ }
+
+ int exit_code = 0;
+ BOOL terminate = FALSE;
+ while (!terminate) {
+ unlink(fname_read);
+ if (rename(fname_buff, fname_read) != 0) {
+ perror("ble.sh (msys1)");
+ fprintf(stderr, "ble.sh (msys1): failed to move the file '%s' -> '%s'\n", fname_buff, fname_read);
+ terminate = TRUE;
+ exit_code = 1;
+ break;
+ }
+
+ FILE* f = fopen(fname_read, "r");
+ if (!f) {
+ fprintf(stderr, "ble.sh (msys1): failed to open the file '%s'\n", fname_read);
+ terminate = TRUE;
+ exit_code = 1;
+ break;
+ }
+
+ for (;;) {
+ if (!is_process_alive(parent_process)) {
+ terminate = TRUE;
+ break;
+ }
+ if (is_file(fname_buff)) break;
+
+ int count = 0;
+ char buff[4096];
+ while (count = fread(&buff, 1, sizeof buff, f))
+ fwrite(buff, 1, count, stdout);
+ fflush(stdout);
+ Sleep(20);
+ }
+ fclose(f);
+ }
+
+ CloseHandle(parent_process);
+ return exit_code;
+}
+EOF
+ [[ -x $helper ]]
+}
+function ble-edit/io:msys1/start-background {
+ local basename=$_ble_edit_io_fname2
+ local fname_buff=$basename.buff
+ ble-edit/io:msys1/is-msys1 || return 1
+ local helper=$_ble_base_cache/init-msys1-helper.exe
+ local helper2=$_ble_base_run/$$.init-msys1-helper.exe
+ ble-edit/io:msys1/compile-helper "$helper" &&
+ /usr/bin/cp "$helper" "$helper2" || return 1
+ local winpid
+ ble/util/assign winpid 'ble-edit/io:msys1/get-winpid.proc $$'
+ [[ $winpid ]] || return 1
+ : >| "$fname_buff"
+ ble/fd#alloc _ble_edit_io_fd2 '> "$fname_buff"'
+ "$helper2" "$winpid" "$fname_buff" "${fname_buff%.buff}.read" | ble-edit/io/check-ignoreeof-loop & disown
+} &>/dev/null
diff --git a/.local/src/blesh/lib/init-term.sh b/.local/src/blesh/lib/init-term.sh
new file mode 100644
index 0000000..cd9647b
--- /dev/null
+++ b/.local/src/blesh/lib/init-term.sh
@@ -0,0 +1,228 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+_ble_term_tput=
+function ble/init:term/tput { return 1; }
+if ble/bin/.freeze-utility-path tput; then
+ ble/bin/tput cuu 1 &>/dev/null && _ble_term_tput=${_ble_term_tput}i
+ ble/bin/tput UP 1 &>/dev/null && _ble_term_tput=${_ble_term_tput}c
+ if [[ $_ble_term_tput ]]; then
+ function ble/init:term/tput {
+ local type=$_ble_term_tput
+ if [[ $1 == -c ]]; then # termcap 優先
+ shift
+ [[ $type == ic ]] && type=c
+ fi
+ if [[ $type != c ]]; then
+ ble/bin/tput "${1%%:*}" "${@:2}" 2>/dev/null
+ else
+ ble/bin/tput "${1#*:}" "${@:2}" 2>/dev/null
+ fi
+ }
+ fi
+fi
+function ble/init:term/register-varname {
+ local name=$1
+ varnames[${#varnames[@]}]=$name
+}
+function ble/init:term/define-cap {
+ local IFS=$_ble_term_IFS
+ local name=$1 def=$2
+ shift 2
+ ble/util/assign "$name" "ble/init:term/tput $* || ble/util/put \"\$def\""
+ ble/init:term/register-varname "$name"
+}
+function ble/init:term/define-cap.2 {
+ local IFS=$_ble_term_IFS
+ local name=$1 def=$2
+ shift 2
+ ble/util/assign "$name" "ble/util/put x; ble/init:term/tput $* || ble/util/put \"\$def\"; ble/util/put x"
+ builtin eval "$name=\${$name#x}; $name=\${$name%x}"
+ ble/init:term/register-varname "$name"
+}
+_ble_term_sgr_term2ansi=()
+ble/init:term/register-varname _ble_term_sgr_term2ansi
+_ble_term_rex_sgr=$'\e''\[([0-9;:]+)m'
+function ble/init:term/define-sgr-param {
+ local name=$1 seq=$2 ansi=$3
+ if [[ $seq =~ $_ble_term_rex_sgr ]]; then
+ local rematch1=${BASH_REMATCH[1]}
+ builtin eval "$name=\$rematch1"
+ if [[ $ansi ]]; then
+ local rex='^[0-9]+$'
+ [[ $rematch1 =~ $rex ]] &&
+ [[ ! ${_ble_term_sgr_term2ansi[rematch1]} ]] &&
+ _ble_term_sgr_term2ansi[rematch1]=$ansi
+ fi
+ else
+ builtin eval "$name="
+ fi
+ if [[ $name =~ ^[a-zA-Z_][a-zA-Z_0-9]*$ ]]; then
+ ble/init:term/register-varname "$name"
+ fi
+}
+function ble/init:term/initialize {
+ local -a varnames=()
+ _ble_term_xenl=1
+ [[ $_ble_term_tput ]] &&
+ ! ble/init:term/tput xenl:xn &>/dev/null &&
+ _ble_term_xenl=
+ [[ $TERM == sun* ]] && _ble_term_xenl=
+ ble/init:term/register-varname _ble_term_xenl
+ _ble_term_bce=
+ [[ $_ble_term_tput ]] &&
+ ble/init:term/tput bce:ut &>/dev/null &&
+ _ble_term_bce=1
+ ble/init:term/register-varname _ble_term_bce
+ _ble_term_it=8
+ if [[ $_ble_term_tput ]]; then
+ ble/util/assign _ble_term_it 'ble/init:term/tput it:it'
+ _ble_term_it=${_ble_term_it:-8}
+ fi
+ ble/init:term/register-varname _ble_term_it
+ ble/init:term/define-cap.2 _ble_term_ind $'\n' ind:sf # $'\eD'
+ ble/init:term/define-cap _ble_term_ri '' ri:sr # $'\eM'
+ ble/init:term/define-cap _ble_term_cr $'\r' cr:cr
+ if [[ $OSTYPE == msys && ! $_ble_term_CR ]]; then # msys-1.0
+ [[ $_ble_term_cr ]] || _ble_term_cr=$'\e[G'
+ if [[ $TERM == cygwin ]]; then
+ [[ $_ble_term_ind == $'\eD' ]] && _ble_term_ind=$'\n'
+ _ble_term_xenl=
+ fi
+ fi
+ ble/init:term/define-cap _ble_term_cuu $'\e[%dA' cuu:UP 123
+ ble/init:term/define-cap _ble_term_cud $'\e[%dB' cud:DO 123
+ ble/init:term/define-cap _ble_term_cuf $'\e[%dC' cuf:RI 123
+ ble/init:term/define-cap _ble_term_cub $'\e[%dD' cub:LE 123
+ _ble_term_cuu=${_ble_term_cuu//123/%d}
+ _ble_term_cud=${_ble_term_cud//123/%d}
+ _ble_term_cuf=${_ble_term_cuf//123/%d}
+ _ble_term_cub=${_ble_term_cub//123/%d}
+ _ble_term_ri_or_cuu1=${_ble_term_ri:-${_ble_term_cuu//'%d'/1}}
+ ble/init:term/register-varname _ble_term_ri_or_cuu1
+ ble/init:term/define-cap _ble_term_cup $'\e[13;35H' cup:cm 12 34
+ _ble_term_cup=${_ble_term_cup//13/%l}
+ _ble_term_cup=${_ble_term_cup//35/%c}
+ _ble_term_cup=${_ble_term_cup//12/%y}
+ _ble_term_cup=${_ble_term_cup//34/%x}
+ ble/init:term/define-cap _ble_term_hpa "$_ble_term_cr${_ble_term_cuf//'%d'/123}" hpa:ch 123
+ _ble_term_hpa=${_ble_term_hpa//123/%x}
+ _ble_term_hpa=${_ble_term_hpa//124/%c}
+ ble/init:term/define-cap _ble_term_vpa "${_ble_term_cuu//'%d'/199}${_ble_term_cud//'%d'/123}" vpa:cv 123
+ _ble_term_vpa=${_ble_term_vpa//123/%y}
+ _ble_term_vpa=${_ble_term_vpa//124/%l}
+ ble/init:term/define-cap _ble_term_clear $'\e[H\e[2J' clear:cl
+ ble/init:term/define-cap _ble_term_il $'\e[%dL' il:AL 123
+ ble/init:term/define-cap _ble_term_dl $'\e[%dM' -c dl:DL 123
+ _ble_term_il=${_ble_term_il//123/%d}
+ _ble_term_dl=${_ble_term_dl//123/%d}
+ ble/init:term/define-cap _ble_term_el $'\e[K' el:ce
+ ble/init:term/define-cap _ble_term_el1 $'\e[1K' el1:cb
+ if [[ $_ble_term_el == $'\e[K' && $_ble_term_el1 == $'\e[1K' ]]; then
+ _ble_term_el2=$'\e[2K'
+ else
+ _ble_term_el2=$_ble_term_el1$_ble_term_el
+ fi
+ ble/init:term/register-varname _ble_term_el2
+ ble/init:term/define-cap _ble_term_ed $'\e[J' -c ed:cd
+ ble/init:term/define-cap _ble_term_ich '' ich:IC 123 # CSI @
+ ble/init:term/define-cap _ble_term_dch '' dch:DC 123 # CSI P
+ ble/init:term/define-cap _ble_term_ech '' ech:ec 123 # CSI X
+ _ble_term_ich=${_ble_term_ich//123/%d}
+ _ble_term_dch=${_ble_term_dch//123/%d}
+ _ble_term_ech=${_ble_term_ech//123/%d}
+ ble/init:term/define-cap _ble_term_sc $'\e7' sc:sc # \e[s
+ ble/init:term/define-cap _ble_term_rc $'\e8' rc:rc # \e[u
+ [[ $TERM == minix ]] && _ble_term_sc= _ble_term_rc=
+ ble/init:term/define-cap _ble_term_Ss '' Ss:Ss 123 # DECSCUSR
+ _ble_term_Ss=${_ble_term_Ss//123/@1}
+ ble/init:term/define-cap _ble_term_cvvis $'\e[?25h' cvvis:vs
+ ble/init:term/define-cap _ble_term_civis $'\e[?25l' civis:vi
+ [[ $TERM == minix ]] && _ble_term_cvvis= _ble_term_civis=
+ [[ $_ble_term_cvvis == $'\e[?12;25h' || $_ble_term_cvvis == $'\e[?25;12h' ]] &&
+ _ble_term_cvvis=$'\e[?25h'
+ [[ $_ble_term_cvvis == $'\e[34l'* && $_ble_term_civis != *$'\e[34h'* ]] &&
+ _ble_term_civis=$_ble_term_civis$'\e[34h'
+ [[ $_ble_term_civis == $'\e[?25l'* && $_ble_term_cvvis != *$'\e[?25h'* ]] &&
+ _ble_term_cvvis=$_ble_term_cvvis$'\e[?25h'
+ ble/init:term/define-cap _ble_term_smcup '' smcup:ti # \e[?1049h
+ ble/init:term/define-cap _ble_term_rmcup '' rmcup:te # \e[?1049l
+ ble/init:term/define-cap _ble_term_tsl '' tsl:ts
+ ble/init:term/define-cap _ble_term_fsl '' fsl:fs
+ ble/init:term/define-cap _ble_term_dsl '' dsl:ds
+ [[ ! $_ble_term_dsl && $_ble_term_fsl ]] &&
+ _ble_term_dsl=$_ble_term_tsl$_ble_term_fsl
+ ble/init:term/define-cap _ble_term_sgr0 $'\e[m' sgr0:me
+ ble/init:term/define-cap _ble_term_bold $'\e[1m' bold:md
+ ble/init:term/define-cap _ble_term_blink $'\e[5m' blink:mb
+ ble/init:term/define-cap _ble_term_rev $'\e[7m' rev:mr
+ ble/init:term/define-cap _ble_term_invis $'\e[8m' invis:mk
+ ble/init:term/define-sgr-param _ble_term_sgr_bold "$_ble_term_bold" 1
+ ble/init:term/define-sgr-param _ble_term_sgr_blink "$_ble_term_blink" 5
+ ble/init:term/define-sgr-param _ble_term_sgr_rev "$_ble_term_rev" 7
+ ble/init:term/define-sgr-param _ble_term_sgr_invis "$_ble_term_invis" 8
+ ble/init:term/define-cap _ble_term_sitm $'\e[3m' sitm:ZH
+ ble/init:term/define-cap _ble_term_ritm $'\e[23m' ritm:ZR
+ ble/init:term/define-cap _ble_term_smul $'\e[4m' smul:us
+ ble/init:term/define-cap _ble_term_rmul $'\e[24m' rmul:ue
+ ble/init:term/define-cap _ble_term_smso $'\e[7m' smso:so
+ ble/init:term/define-cap _ble_term_rmso $'\e[27m' rmso:se
+ ble/init:term/define-sgr-param _ble_term_sgr_sitm "$_ble_term_sitm" 3
+ ble/init:term/define-sgr-param _ble_term_sgr_ritm "$_ble_term_ritm" 23
+ ble/init:term/define-sgr-param _ble_term_sgr_smul "$_ble_term_smul" 4
+ ble/init:term/define-sgr-param _ble_term_sgr_rmul "$_ble_term_rmul" 24
+ ble/init:term/define-sgr-param _ble_term_sgr_smso "$_ble_term_smso" 7
+ ble/init:term/define-sgr-param _ble_term_sgr_rmso "$_ble_term_rmso" 27
+ ble/init:term/register-varname _ble_term_sgr_rev_reset
+ if [[ $_ble_term_sgr_smso && $_ble_term_sgr_smso == "$_ble_term_sgr_rev" ]]; then
+ _ble_term_sgr_rev_reset=$_ble_term_sgr_rmso
+ else
+ _ble_term_sgr_rev_reset=
+ fi
+ ble/init:term/define-cap _ble_term_colors 256 colors:Co
+ local i
+ _ble_term_setaf=()
+ _ble_term_setab=()
+ _ble_term_sgr_af=()
+ _ble_term_sgr_ab=()
+ for ((i=0;i<16;i++)); do
+ local i1=$((i%8)) af= ab=
+ if [[ $TERM == *-direct ]]; then
+ if ((i<8)); then
+ af=$'\e[3'$i'm'
+ ab=$'\e[4'$i'm'
+ else
+ af=$'\e[38;5;'$i'm'
+ ab=$'\e[48;5;'$i'm'
+ fi
+ else
+ if ((i<_ble_term_colors)); then
+ local j1
+ ((j1=(i1==3?6:
+ (i1==6?3:
+ (i1==1?4:
+ (i1==4?1:i1))))))
+ local j=$((i-i1+j1))
+ ble/util/assign af 'ble/init:term/tput setaf:AF "$i" 2>/dev/null'
+ [[ $af ]] || ble/util/assign af 'ble/init:term/tput setf:Sf "$j" 2>/dev/null'
+ ble/util/assign ab 'ble/init:term/tput setab:AB "$i" 2>/dev/null'
+ [[ $ab ]] || ble/util/assign ab 'ble/init:term/tput setb:Sb "$j" 2>/dev/null'
+ fi
+ fi
+ [[ $af ]] || af=$'\e[3'$i1'm'
+ [[ $ab ]] || ab=$'\e[4'$i1'm'
+ _ble_term_setaf[i]=$af
+ _ble_term_setab[i]=$ab
+ local ansi_sgr_af=3$i1 ansi_sgr_ab=4$i1
+ ((i>=8)) && ansi_sgr_af=9$i1 ansi_sgr_ab=10$i1
+ ble/init:term/define-sgr-param "_ble_term_sgr_af[i]" "$af" "$ansi_sgr_af"
+ ble/init:term/define-sgr-param "_ble_term_sgr_ab[i]" "$ab" "$ansi_sgr_ab"
+ done
+ ble/init:term/register-varname "_ble_term_setaf"
+ ble/init:term/register-varname "_ble_term_setab"
+ ble/init:term/register-varname "_ble_term_sgr_af"
+ ble/init:term/register-varname "_ble_term_sgr_ab"
+ ble/util/declare-print-definitions "${varnames[@]}" >| "$_ble_base_cache/term.$TERM"
+}
+ble/util/put "ble/term.sh: updating tput cache for TERM=$TERM... " >&2
+ble/init:term/initialize
+ble/util/print $'\r'"ble/term.sh: updating tput cache for TERM=$TERM... done" >&2
+return 0
diff --git a/.local/src/blesh/lib/test-canvas.sh b/.local/src/blesh/lib/test-canvas.sh
new file mode 100644
index 0000000..6d329ea
--- /dev/null
+++ b/.local/src/blesh/lib/test-canvas.sh
@@ -0,0 +1,479 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import lib/core-test
+_ble_test_canvas_contra=
+if [[ -x ext/contra ]]; then
+ _ble_test_canvas_contra=ext/contra
+elif [[ $(printf 'hello world' | contra test 5 2 2>/dev/null) == $' worl\nd ' ]]; then
+ _ble_test_canvas_contra=contra
+fi
+function ble/test:canvas/trace.contra {
+ [[ $_ble_test_canvas_contra ]] || return 0 # skip
+ local w=${1%%:*} h=${1#*:} esc=$2 opts=$3 test_opts=$4
+ local expect=$(sed 's/\$$//')
+ local ret x=0 y=0 g=0 rex termw=$w termh=$h
+ rex=':x=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((x=BASH_REMATCH[1]))
+ rex=':y=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((y=BASH_REMATCH[1]))
+ rex=':termw=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((termw=BASH_REMATCH[1]))
+ rex=':termh=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((termh=BASH_REMATCH[1]))
+ local x0=$x y0=$y
+ LINES=$h COLUMNS=$w ble/canvas/trace "$esc" "$opts"
+ local out=$ret
+ ble/string#quote-word "$esc"; local q_esc=$ret
+ ble/string#quote-word "$opts"; local q_opts=$ret
+ ble/test --depth=1 --display-code="trace $q_esc $q_opts" \
+ '{ printf "\e['$((y0+1))';'$((x0+1))'H"; ble/util/put "$out";} | "$_ble_test_canvas_contra" test "$termw" "$termh"' \
+ stdout="$expect"
+}
+ble/test/start-section 'ble/canvas/trace (relative:confine:measure-bbox)' 17
+ble/test:canvas/trace.contra 10:10 'hello world this is a flow world' relative x=3:y=3:termw=20 << EOF
+ $
+ $
+ $
+ hello w $
+orld this $
+is a flow $
+world $
+ $
+ $
+ $
+EOF
+ble/test:canvas/trace.contra 20:1 '12345678901234567890hello' confine << EOF
+12345678901234567890$
+EOF
+ble/test:canvas/trace.contra 10:1 $'hello\nworld' confine << EOF
+helloworld$
+EOF
+ble/test:canvas/trace.contra 10:2 $'hello\nworld check' confine << EOF
+hello $
+world chec$
+EOF
+ble/test:canvas/trace.contra 10:6 $'hello\e[B\e[4D123' measure-bbox x=3:y=2 << EOF
+ $
+ $
+ hello $
+ 123 $
+ $
+ $
+EOF
+[[ $_ble_test_canvas_contra ]] &&
+ ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='3-8:2-4'
+ble/test:canvas/trace.contra 10:2 日本語 measure-bbox << EOF
+日本語 $
+ $
+EOF
+[[ $_ble_test_canvas_contra ]] &&
+ ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-6:0-1'
+ble/test:canvas/trace.contra 10:2 $'hello\eDworld' measure-bbox << EOF
+hello $
+ world$
+EOF
+[[ $_ble_test_canvas_contra ]] &&
+ ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-10:0-2'
+ble/test:canvas/trace.contra 10:2 $'hello\eMworld' measure-bbox << EOF
+ world$
+hello $
+EOF
+[[ $_ble_test_canvas_contra ]] &&
+ ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-10:-1-1'
+(
+ LINES=10 COLUMNS=10 _ble_term_xenl=1
+ ble/test 'x=0 y=0; ble/canvas/trace "HelloWorld"; ret=$x,$y' ret=10,0
+ ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldH"; ret=$x,$y' ret=1,1
+ ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHello"; ret=$x,$y' ret=5,1
+ ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHelloWorldHello"; ret=$x,$y' ret=5,2
+ ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHelloWorldHelloWorldHello"; ret=$x,$y' ret=5,3
+)
+ble/test/start-section 'ble/canvas/trace (cfuncs)' 18
+function ble/test:canvas/check-trace-1 {
+ local input=$1 ex=$2 ey=$3
+ ble/canvas/trace.draw "$input"
+ ble/test --depth=1 '((x==ex&&y==ey))'
+}
+function ble/test:canvas/check-trace {
+ local -a DRAW_BUFF=()
+ ble/canvas/put.draw "$_ble_term_clear"
+ local x=0 y=0
+ ble/test:canvas/check-trace-1 "abc" 3 0
+ ble/test:canvas/check-trace-1 $'\n\n\nn' 1 3
+ ble/test:canvas/check-trace-1 $'\e[3BB' 2 6
+ ble/test:canvas/check-trace-1 $'\e[2AA' 3 4
+ ble/test:canvas/check-trace-1 $'\e[20CC' 24 4
+ ble/test:canvas/check-trace-1 $'\e[8DD' 17 4
+ ble/test:canvas/check-trace-1 $'\e[9EE' 1 13
+ ble/test:canvas/check-trace-1 $'\e[6FF' 1 7
+ ble/test:canvas/check-trace-1 $'\e[28GG' 28 7
+ ble/test:canvas/check-trace-1 $'\e[II' 33 7
+ ble/test:canvas/check-trace-1 $'\e[3ZZ' 17 7
+ ble/test:canvas/check-trace-1 $'\eDD' 18 8
+ ble/test:canvas/check-trace-1 $'\eMM' 19 7
+ ble/test:canvas/check-trace-1 $'\e77\e[3;3Hexcur\e8\e[C8' 21 7
+ ble/test:canvas/check-trace-1 $'\eEE' 1 8
+ ble/test:canvas/check-trace-1 $'\e[10;24HH' 24 9
+ ble/test:canvas/check-trace-1 $'\e[1;94mb\e[m' 25 9
+ local expect=$(sed 's/\$$//' << EOF
+abc $
+ $
+ excur $
+n $
+ A D C $
+ $
+ B $
+F Z M78 G I $
+E D $
+ Hb $
+ $
+ $
+ $
+E $
+ $
+EOF
+)
+ [[ $_ble_test_canvas_contra ]] &&
+ ble/test --depth=1 \
+ 'ble/canvas/flush.draw | $_ble_test_canvas_contra test 40 15' \
+ stdout="$expect"
+}
+ble/test:canvas/check-trace
+ble/test/start-section 'ble/canvas/trace (justify)' 24
+ble/test:canvas/trace.contra 30:1 'a b c' justify << EOF
+a b c$
+EOF
+ble/test:canvas/trace.contra 30:1 ' center ' justify << EOF
+ center $
+EOF
+ble/test:canvas/trace.contra 30:1 ' right-aligned' justify << EOF
+ right-aligned$
+EOF
+ble/test:canvas/trace.contra 30:1 'left-aligned' justify << EOF
+left-aligned $
+EOF
+ble/test:canvas/trace.contra 30:1 ' 日本語' justify << EOF
+ 日本語$
+EOF
+ble/test:canvas/trace.contra 30:1 'a b c d e f' justify << EOF
+a b c d e f$
+EOF
+ble/test:canvas/trace.contra 30:2 $'hello center world\na b c d e f' justify << EOF
+hello center world$
+a b c d e f$
+EOF
+ble/test:canvas/trace.contra 30:3 'A brown fox jumped over the lazy dog. A brown fox jumped over the lazy dog.' justify << EOF
+A brown fox jumped over the la$
+zy dog. A brown fox jumped ove$
+r the lazy dog.$
+EOF
+ble/test:canvas/trace.contra 30:2 $'hello blesh world\rHELLO WORLD\nhello world HELLO BLESH WORLD' justify=$' \r' << EOF
+hello blesh worldHELLO WORLD$
+hello world HELLO BLESH WORLD$
+EOF
+COLUMNS=10 LINES=10 x=3 y=2 ble/canvas/trace $'a b c\n' justify:measure-bbox
+ble/test 'echo "$x1,$y1:$x2,$y2"' stdout:'0,2:10,4'
+COLUMNS=10 LINES=10 x=3 y=2 ble/canvas/trace $' hello ' justify:measure-bbox
+ble/test 'echo "$x1,$y1:$x2,$y2"' stdout:'2,2:7,3'
+ble/test:canvas/trace.contra 30:1 $'\e[3Dhello\rblesh\rworld\e[1D' justify=$'\r' x=5 << EOF
+hello blesh world$
+EOF
+ble/test:canvas/trace.contra \
+ 30:5 $'hello world\nfoo bar buzz\nA quick brown fox\nLorem ipsum\n1 1 2 3 5 8 13 21 34 55 89 144' \
+ justify:clip=2,1+24,5 << EOF
+o bar $
+ quick brown $
+rem i $
+1 2 3 5 8 13 21 34 55 89 $
+ $
+EOF
+ble/test:canvas/trace.contra 30:1 $'hello1 world long long word quick brown' justify:confine << EOF
+hello1 world long long word qu$
+EOF
+ble/test:canvas/trace.contra 30:1 $'hello2 world long long word quick brown' justify:truncate << EOF
+hello2 world long long word qu$
+EOF
+ble/test:canvas/trace.contra 60:2 $'-- INSERT --\r/home/murase\r2021-01-01 00:00:00' justify << EOF
+-- INSERT 2021-01-01 00:00:00$
+ $
+EOF
+ble/test:canvas/trace.contra 30:3 $'hello\r\vquick check\v\rtest \e[2Afoo\r\vbar' justify:truncate << EOF
+hello foo$
+quick check bar$
+ test $
+EOF
+ble/test:canvas/trace.contra 30:3 $'hello\n2021-01-01\nA' right:measure-bbox:measure-gbox << EOF
+ hello$
+ 2021-01-01$
+ A$
+EOF
+if [[ $_ble_test_canvas_contra ]]; then
+ ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-30,3'
+ ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:20,0-30,3'
+fi
+ble/test:canvas/trace.contra 30:3 $'hello\n2021-01-01\nA' center:measure-bbox:measure-gbox << EOF
+ hello $
+ 2021-01-01 $
+ A $
+EOF
+if [[ $_ble_test_canvas_contra ]]; then
+ ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-20,3'
+ ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:10,0-20,3'
+fi
+ble/test:canvas/trace.contra 10:1 $'xyz\e[4Daxyz' relative:measure-bbox x=3 << EOF
+ axyz $
+EOF
+if [[ $_ble_test_canvas_contra ]]; then
+ ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:2,0-6,1'
+fi
+ble/test/start-section 'ble/canvas/trace-text' 11
+(
+ sgr0= sgr1=
+ lines=1 cols=10 _ble_term_xenl=1 x=0 y=0
+ ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='10,0,Hello Worl'
+ lines=1 cols=10 _ble_term_xenl= x=0 y=0
+ ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='9,0,Hello Wor'
+ lines=1 cols=10 _ble_term_xenl=1 x=3 y=0
+ ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='10,0,Hello W'
+ lines=3 cols=10 _ble_term_xenl=1 x=3 y=0
+ ble/test 'ble/canvas/trace-text "Hello Bash World";ret="$x,$y,$ret"' ret='9,1,Hello Bash World'
+ lines=3 cols=10 _ble_term_xenl=1 x=3 y=0
+ ble/test 'ble/canvas/trace-text "これは日本語の文章";ret="$x,$y,$ret"' ret=$'2,2,これは\n日本語の文章'
+ lines=3 cols=10 _ble_term_xenl=1 x=3 y=0
+ ble/test 'ble/canvas/trace-text "これは日本語の文章" nonewline;ret="$x,$y,$ret"' ret='2,2,これは 日本語の文章'
+ lines=3 cols=10 _ble_term_xenl=1 x=0 y=0
+ ble/test 'ble/canvas/trace-text "これは日本";ret="$x,$y,$ret"' ret=$'0,1,これは日本\n'
+ lines=3 cols=10 _ble_term_xenl=0 x=0 y=0
+ ble/test 'ble/canvas/trace-text "これは日本";ret="$x,$y,$ret"' ret=$'0,1,これは日本'
+ lines=3 cols=10 _ble_term_xenl=1 x=0 y=0
+ ble/test 'ble/canvas/trace-text "これは日本" nonewline;ret="$x,$y,$ret"' ret=$'10,0,これは日本'
+ lines=3 cols=10 _ble_term_xenl=0 x=0 y=0
+ ble/test 'ble/canvas/trace-text "これは日本" nonewline;ret="$x,$y,$ret"' ret=$'0,1,これは日本'
+ lines=1 cols=12 _ble_term_xenl=1 x=0 y=0
+ ble/test $'ble/canvas/trace-text "あ\nい\nう" external-sgr;ret="$x,$y,$ret"' ret=$'10,0,あ^Jい^Jう'
+)
+ble/test/end-section
+ble/test/start-section 'ble/textmap#update' 5
+function ble/test:canvas/textmap {
+ local text=$1
+ x=0 y=0
+ _ble_textmap_length=
+ _ble_textmap_pos=()
+ _ble_textmap_glyph=()
+ _ble_textmap_ichg=()
+ _ble_textmap_dbeg=0
+ _ble_textmap_dend=${#text}
+ _ble_textmap_dend0=0
+ ble/textmap#update "$text"
+ [[ :$opts: == *:stderr:* ]] &&
+ declare -p _ble_textmap_pos >&2
+}
+(
+ ble/test:canvas/textmap $'hello\nworld\ncheck'
+ ble/test 'ble/textmap#getxy.out 5; ret=$x,$y' ret='5,0'
+ ble/test 'ble/textmap#getxy.out 6; ret=$x,$y' ret='0,1'
+ ble/test 'ble/textmap#getxy.out 11; ret=$x,$y' ret='5,1'
+ ble/test 'ble/textmap#getxy.out 12; ret=$x,$y' ret='0,2'
+ ble/test 'ble/textmap#getxy.out 17; ret=$x,$y' ret='5,2'
+)
+ble/test/start-section 'ble/unicode/GraphemeCluster/c2break' 72
+(
+ bleopt emoji_opts=ri:tpvs:epvs:zwj
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x20))' ret="$_ble_unicode_GraphemeClusterBreak_Other"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x41))' ret="$_ble_unicode_GraphemeClusterBreak_Other"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x7E))' ret="$_ble_unicode_GraphemeClusterBreak_Other"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x00))' ret="$_ble_unicode_GraphemeClusterBreak_Control"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0d))' ret="$_ble_unicode_GraphemeClusterBreak_Control"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0a))' ret="$_ble_unicode_GraphemeClusterBreak_Control"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F))' ret="$_ble_unicode_GraphemeClusterBreak_Control"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x80))' ret="$_ble_unicode_GraphemeClusterBreak_Control"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x9F))' ret="$_ble_unicode_GraphemeClusterBreak_Control"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0308))' ret="$_ble_unicode_GraphemeClusterBreak_Extend"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x200C))' ret="$_ble_unicode_GraphemeClusterBreak_Extend" # ZWNJ
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x200D))' ret="$_ble_unicode_GraphemeClusterBreak_ZWJ" # ZWJ
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0600))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0605))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x06DD))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x110BD))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xE33))' ret="$_ble_unicode_GraphemeClusterBreak_SpacingMark" # THAI CHARACTER SARA AM
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xEB3))' ret="$_ble_unicode_GraphemeClusterBreak_SpacingMark" # LAO VOWEL SIGN AM
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1100))' ret="$_ble_unicode_GraphemeClusterBreak_L"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x115F))' ret="$_ble_unicode_GraphemeClusterBreak_L"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xA960))' ret="$_ble_unicode_GraphemeClusterBreak_L"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xA97C))' ret="$_ble_unicode_GraphemeClusterBreak_L"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1160))' ret="$_ble_unicode_GraphemeClusterBreak_V"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x11A2))' ret="$_ble_unicode_GraphemeClusterBreak_V"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7B0))' ret="$_ble_unicode_GraphemeClusterBreak_V"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7C6))' ret="$_ble_unicode_GraphemeClusterBreak_V"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x11A8))' ret="$_ble_unicode_GraphemeClusterBreak_T"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x11F9))' ret="$_ble_unicode_GraphemeClusterBreak_T"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7CB))' ret="$_ble_unicode_GraphemeClusterBreak_T"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7FB))' ret="$_ble_unicode_GraphemeClusterBreak_T"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC00))' ret="$_ble_unicode_GraphemeClusterBreak_LV"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC1C))' ret="$_ble_unicode_GraphemeClusterBreak_LV"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC38))' ret="$_ble_unicode_GraphemeClusterBreak_LV"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC01))' ret="$_ble_unicode_GraphemeClusterBreak_LVT"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC04))' ret="$_ble_unicode_GraphemeClusterBreak_LVT"
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F1E6))' ret="$_ble_unicode_GraphemeClusterBreak_Regional_Indicator" # RI A
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F1FF))' ret="$_ble_unicode_GraphemeClusterBreak_Regional_Indicator" # RI Z
+ ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F32B))' ret="$_ble_unicode_GraphemeClusterBreak_Pictographic"
+ if ((_ble_bash>=40200)); then
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 1' ret="0"
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 2' ret="0"
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 3' ret="2"
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 4' ret="2"
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 5' ret="4"
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 2' ret=1
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 3' ret=1
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 4' ret=3
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 5' ret=3
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 6' ret=5
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 7' ret=6
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6Z" 7' ret=6
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 7' ret=1
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 6' ret=1
+ ble/test $'bleopt_grapheme_cluster=legacy ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 7' ret=5
+ ble/test $'bleopt_grapheme_cluster=legacy ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 6' ret=5
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 1' ret=0
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 2' ret=0
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 3' ret=0
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 4' ret=0
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 5' ret=4
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 2' ret=1
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 3' ret=1
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 4' ret=1
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 5' ret=1
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 6' ret=5
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 2' ret=0
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 3' ret=2
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 4' ret=2
+ ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 5' ret=4
+ ble/test "ble/test:canvas/textmap \$'@@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=1
+ ble/test "ble/test:canvas/textmap \$'@\u0308@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=2
+ ble/test "ble/test:canvas/textmap \$'@\u0308\u0308@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=3
+ ble/test "ble/test:canvas/textmap \$'@\u0308\u0308\u0308@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=4
+ fi
+)
+ble/test/start-section 'ble/unicode/GraphemeCluster/c2break (GraphemeBreakTest.txt)' 3251
+(
+ bleopt emoji_opts=ri:tpvs:epvs:zwj
+ tests_cases=(
+ 0,1,2:'\U0020\U0020' 0,0,2,3:'\U0020\U0308\U0020' 0,1,2:'\U0020\U000D' 0,0,2,3:'\U0020\U0308\U000D' 0,1,2:'\U0020\U000A' 0,0,2,3:'\U0020\U0308\U000A'
+ 0,1,2:'\U0020\U0001' 0,0,2,3:'\U0020\U0308\U0001' 0,0,2:'\U0020\U034F' 0,0,0,3:'\U0020\U0308\U034F' 0,1,2:'\U0020\U1F1E6' 0,0,2,3:'\U0020\U0308\U1F1E6'
+ 0,1,2:'\U0020\U0600' 0,0,2,3:'\U0020\U0308\U0600' 0,0,2:'\U0020\U0903' 0,0,0,3:'\U0020\U0308\U0903' 0,1,2:'\U0020\U1100' 0,0,2,3:'\U0020\U0308\U1100'
+ 0,1,2:'\U0020\U1160' 0,0,2,3:'\U0020\U0308\U1160' 0,1,2:'\U0020\U11A8' 0,0,2,3:'\U0020\U0308\U11A8' 0,1,2:'\U0020\UAC00' 0,0,2,3:'\U0020\U0308\UAC00'
+ 0,1,2:'\U0020\UAC01' 0,0,2,3:'\U0020\U0308\UAC01' 0,1,2:'\U0020\U231A' 0,0,2,3:'\U0020\U0308\U231A' 0,0,2:'\U0020\U0300' 0,0,0,3:'\U0020\U0308\U0300'
+ 0,0,2:'\U0020\U200D' 0,0,0,3:'\U0020\U0308\U200D' 0,1,2:'\U0020\U0378' 0,0,2,3:'\U0020\U0308\U0378' 0,1,2:'\U000D\U0020' 0,1,2,3:'\U000D\U0308\U0020'
+ 0,1,2:'\U000D\U000D' 0,1,2,3:'\U000D\U0308\U000D' 0,1,2:'\U000D\U000A' 0,1,2,3:'\U000D\U0308\U000A' 0,1,2:'\U000D\U0001' 0,1,2,3:'\U000D\U0308\U0001'
+ 0,1,2:'\U000D\U034F' 0,1,1,3:'\U000D\U0308\U034F' 0,1,2:'\U000D\U1F1E6' 0,1,2,3:'\U000D\U0308\U1F1E6' 0,1,2:'\U000D\U0600' 0,1,2,3:'\U000D\U0308\U0600'
+ 0,1,2:'\U000D\U0903' 0,1,1,3:'\U000D\U0308\U0903' 0,1,2:'\U000D\U1100' 0,1,2,3:'\U000D\U0308\U1100' 0,1,2:'\U000D\U1160' 0,1,2,3:'\U000D\U0308\U1160'
+ 0,1,2:'\U000D\U11A8' 0,1,2,3:'\U000D\U0308\U11A8' 0,1,2:'\U000D\UAC00' 0,1,2,3:'\U000D\U0308\UAC00' 0,1,2:'\U000D\UAC01' 0,1,2,3:'\U000D\U0308\UAC01'
+ 0,1,2:'\U000D\U231A' 0,1,2,3:'\U000D\U0308\U231A' 0,1,2:'\U000D\U0300' 0,1,1,3:'\U000D\U0308\U0300' 0,1,2:'\U000D\U200D' 0,1,1,3:'\U000D\U0308\U200D'
+ 0,1,2:'\U000D\U0378' 0,1,2,3:'\U000D\U0308\U0378' 0,1,2:'\U000A\U0020' 0,1,2,3:'\U000A\U0308\U0020' 0,1,2:'\U000A\U000D' 0,1,2,3:'\U000A\U0308\U000D'
+ 0,1,2:'\U000A\U000A' 0,1,2,3:'\U000A\U0308\U000A' 0,1,2:'\U000A\U0001' 0,1,2,3:'\U000A\U0308\U0001' 0,1,2:'\U000A\U034F' 0,1,1,3:'\U000A\U0308\U034F'
+ 0,1,2:'\U000A\U1F1E6' 0,1,2,3:'\U000A\U0308\U1F1E6' 0,1,2:'\U000A\U0600' 0,1,2,3:'\U000A\U0308\U0600' 0,1,2:'\U000A\U0903' 0,1,1,3:'\U000A\U0308\U0903'
+ 0,1,2:'\U000A\U1100' 0,1,2,3:'\U000A\U0308\U1100' 0,1,2:'\U000A\U1160' 0,1,2,3:'\U000A\U0308\U1160' 0,1,2:'\U000A\U11A8' 0,1,2,3:'\U000A\U0308\U11A8'
+ 0,1,2:'\U000A\UAC00' 0,1,2,3:'\U000A\U0308\UAC00' 0,1,2:'\U000A\UAC01' 0,1,2,3:'\U000A\U0308\UAC01' 0,1,2:'\U000A\U231A' 0,1,2,3:'\U000A\U0308\U231A'
+ 0,1,2:'\U000A\U0300' 0,1,1,3:'\U000A\U0308\U0300' 0,1,2:'\U000A\U200D' 0,1,1,3:'\U000A\U0308\U200D' 0,1,2:'\U000A\U0378' 0,1,2,3:'\U000A\U0308\U0378'
+ 0,1,2:'\U0001\U0020' 0,1,2,3:'\U0001\U0308\U0020' 0,1,2:'\U0001\U000D' 0,1,2,3:'\U0001\U0308\U000D' 0,1,2:'\U0001\U000A' 0,1,2,3:'\U0001\U0308\U000A'
+ 0,1,2:'\U0001\U0001' 0,1,2,3:'\U0001\U0308\U0001' 0,1,2:'\U0001\U034F' 0,1,1,3:'\U0001\U0308\U034F' 0,1,2:'\U0001\U1F1E6' 0,1,2,3:'\U0001\U0308\U1F1E6'
+ 0,1,2:'\U0001\U0600' 0,1,2,3:'\U0001\U0308\U0600' 0,1,2:'\U0001\U0903' 0,1,1,3:'\U0001\U0308\U0903' 0,1,2:'\U0001\U1100' 0,1,2,3:'\U0001\U0308\U1100'
+ 0,1,2:'\U0001\U1160' 0,1,2,3:'\U0001\U0308\U1160' 0,1,2:'\U0001\U11A8' 0,1,2,3:'\U0001\U0308\U11A8' 0,1,2:'\U0001\UAC00' 0,1,2,3:'\U0001\U0308\UAC00'
+ 0,1,2:'\U0001\UAC01' 0,1,2,3:'\U0001\U0308\UAC01' 0,1,2:'\U0001\U231A' 0,1,2,3:'\U0001\U0308\U231A' 0,1,2:'\U0001\U0300' 0,1,1,3:'\U0001\U0308\U0300'
+ 0,1,2:'\U0001\U200D' 0,1,1,3:'\U0001\U0308\U200D' 0,1,2:'\U0001\U0378' 0,1,2,3:'\U0001\U0308\U0378' 0,1,2:'\U034F\U0020' 0,0,2,3:'\U034F\U0308\U0020'
+ 0,1,2:'\U034F\U000D' 0,0,2,3:'\U034F\U0308\U000D' 0,1,2:'\U034F\U000A' 0,0,2,3:'\U034F\U0308\U000A' 0,1,2:'\U034F\U0001' 0,0,2,3:'\U034F\U0308\U0001'
+ 0,0,2:'\U034F\U034F' 0,0,0,3:'\U034F\U0308\U034F' 0,1,2:'\U034F\U1F1E6' 0,0,2,3:'\U034F\U0308\U1F1E6' 0,1,2:'\U034F\U0600' 0,0,2,3:'\U034F\U0308\U0600'
+ 0,0,2:'\U034F\U0903' 0,0,0,3:'\U034F\U0308\U0903' 0,1,2:'\U034F\U1100' 0,0,2,3:'\U034F\U0308\U1100' 0,1,2:'\U034F\U1160' 0,0,2,3:'\U034F\U0308\U1160'
+ 0,1,2:'\U034F\U11A8' 0,0,2,3:'\U034F\U0308\U11A8' 0,1,2:'\U034F\UAC00' 0,0,2,3:'\U034F\U0308\UAC00' 0,1,2:'\U034F\UAC01' 0,0,2,3:'\U034F\U0308\UAC01'
+ 0,1,2:'\U034F\U231A' 0,0,2,3:'\U034F\U0308\U231A' 0,0,2:'\U034F\U0300' 0,0,0,3:'\U034F\U0308\U0300' 0,0,2:'\U034F\U200D' 0,0,0,3:'\U034F\U0308\U200D'
+ 0,1,2:'\U034F\U0378' 0,0,2,3:'\U034F\U0308\U0378' 0,1,2:'\U1F1E6\U0020' 0,0,2,3:'\U1F1E6\U0308\U0020' 0,1,2:'\U1F1E6\U000D' 0,0,2,3:'\U1F1E6\U0308\U000D'
+ 0,1,2:'\U1F1E6\U000A' 0,0,2,3:'\U1F1E6\U0308\U000A' 0,1,2:'\U1F1E6\U0001' 0,0,2,3:'\U1F1E6\U0308\U0001' 0,0,2:'\U1F1E6\U034F' 0,0,0,3:'\U1F1E6\U0308\U034F'
+ 0,0,2:'\U1F1E6\U1F1E6' 0,0,2,3:'\U1F1E6\U0308\U1F1E6' 0,1,2:'\U1F1E6\U0600' 0,0,2,3:'\U1F1E6\U0308\U0600' 0,0,2:'\U1F1E6\U0903'
+ 0,0,0,3:'\U1F1E6\U0308\U0903' 0,1,2:'\U1F1E6\U1100' 0,0,2,3:'\U1F1E6\U0308\U1100' 0,1,2:'\U1F1E6\U1160' 0,0,2,3:'\U1F1E6\U0308\U1160' 0,1,2:'\U1F1E6\U11A8'
+ 0,0,2,3:'\U1F1E6\U0308\U11A8' 0,1,2:'\U1F1E6\UAC00' 0,0,2,3:'\U1F1E6\U0308\UAC00' 0,1,2:'\U1F1E6\UAC01' 0,0,2,3:'\U1F1E6\U0308\UAC01' 0,1,2:'\U1F1E6\U231A'
+ 0,0,2,3:'\U1F1E6\U0308\U231A' 0,0,2:'\U1F1E6\U0300' 0,0,0,3:'\U1F1E6\U0308\U0300' 0,0,2:'\U1F1E6\U200D' 0,0,0,3:'\U1F1E6\U0308\U200D' 0,1,2:'\U1F1E6\U0378'
+ 0,0,2,3:'\U1F1E6\U0308\U0378' 0,0,2:'\U0600\U0020' 0,0,2,3:'\U0600\U0308\U0020' 0,1,2:'\U0600\U000D' 0,0,2,3:'\U0600\U0308\U000D' 0,1,2:'\U0600\U000A'
+ 0,0,2,3:'\U0600\U0308\U000A' 0,1,2:'\U0600\U0001' 0,0,2,3:'\U0600\U0308\U0001' 0,0,2:'\U0600\U034F' 0,0,0,3:'\U0600\U0308\U034F' 0,0,2:'\U0600\U1F1E6'
+ 0,0,2,3:'\U0600\U0308\U1F1E6' 0,0,2:'\U0600\U0600' 0,0,2,3:'\U0600\U0308\U0600' 0,0,2:'\U0600\U0903' 0,0,0,3:'\U0600\U0308\U0903' 0,0,2:'\U0600\U1100'
+ 0,0,2,3:'\U0600\U0308\U1100' 0,0,2:'\U0600\U1160' 0,0,2,3:'\U0600\U0308\U1160' 0,0,2:'\U0600\U11A8' 0,0,2,3:'\U0600\U0308\U11A8' 0,0,2:'\U0600\UAC00'
+ 0,0,2,3:'\U0600\U0308\UAC00' 0,0,2:'\U0600\UAC01' 0,0,2,3:'\U0600\U0308\UAC01' 0,0,2:'\U0600\U231A' 0,0,2,3:'\U0600\U0308\U231A' 0,0,2:'\U0600\U0300'
+ 0,0,0,3:'\U0600\U0308\U0300' 0,0,2:'\U0600\U200D' 0,0,0,3:'\U0600\U0308\U200D' 0,0,2:'\U0600\U0378' 0,0,2,3:'\U0600\U0308\U0378' 0,1,2:'\U0903\U0020'
+ 0,0,2,3:'\U0903\U0308\U0020' 0,1,2:'\U0903\U000D' 0,0,2,3:'\U0903\U0308\U000D' 0,1,2:'\U0903\U000A' 0,0,2,3:'\U0903\U0308\U000A' 0,1,2:'\U0903\U0001'
+ 0,0,2,3:'\U0903\U0308\U0001' 0,0,2:'\U0903\U034F' 0,0,0,3:'\U0903\U0308\U034F' 0,1,2:'\U0903\U1F1E6' 0,0,2,3:'\U0903\U0308\U1F1E6' 0,1,2:'\U0903\U0600'
+ 0,0,2,3:'\U0903\U0308\U0600' 0,0,2:'\U0903\U0903' 0,0,0,3:'\U0903\U0308\U0903' 0,1,2:'\U0903\U1100' 0,0,2,3:'\U0903\U0308\U1100' 0,1,2:'\U0903\U1160'
+ 0,0,2,3:'\U0903\U0308\U1160' 0,1,2:'\U0903\U11A8' 0,0,2,3:'\U0903\U0308\U11A8' 0,1,2:'\U0903\UAC00' 0,0,2,3:'\U0903\U0308\UAC00' 0,1,2:'\U0903\UAC01'
+ 0,0,2,3:'\U0903\U0308\UAC01' 0,1,2:'\U0903\U231A' 0,0,2,3:'\U0903\U0308\U231A' 0,0,2:'\U0903\U0300' 0,0,0,3:'\U0903\U0308\U0300' 0,0,2:'\U0903\U200D'
+ 0,0,0,3:'\U0903\U0308\U200D' 0,1,2:'\U0903\U0378' 0,0,2,3:'\U0903\U0308\U0378' 0,1,2:'\U1100\U0020' 0,0,2,3:'\U1100\U0308\U0020' 0,1,2:'\U1100\U000D'
+ 0,0,2,3:'\U1100\U0308\U000D' 0,1,2:'\U1100\U000A' 0,0,2,3:'\U1100\U0308\U000A' 0,1,2:'\U1100\U0001' 0,0,2,3:'\U1100\U0308\U0001' 0,0,2:'\U1100\U034F'
+ 0,0,0,3:'\U1100\U0308\U034F' 0,1,2:'\U1100\U1F1E6' 0,0,2,3:'\U1100\U0308\U1F1E6' 0,1,2:'\U1100\U0600' 0,0,2,3:'\U1100\U0308\U0600' 0,0,2:'\U1100\U0903'
+ 0,0,0,3:'\U1100\U0308\U0903' 0,0,2:'\U1100\U1100' 0,0,2,3:'\U1100\U0308\U1100' 0,0,2:'\U1100\U1160' 0,0,2,3:'\U1100\U0308\U1160' 0,1,2:'\U1100\U11A8'
+ 0,0,2,3:'\U1100\U0308\U11A8' 0,0,2:'\U1100\UAC00' 0,0,2,3:'\U1100\U0308\UAC00' 0,0,2:'\U1100\UAC01' 0,0,2,3:'\U1100\U0308\UAC01' 0,1,2:'\U1100\U231A'
+ 0,0,2,3:'\U1100\U0308\U231A' 0,0,2:'\U1100\U0300' 0,0,0,3:'\U1100\U0308\U0300' 0,0,2:'\U1100\U200D' 0,0,0,3:'\U1100\U0308\U200D' 0,1,2:'\U1100\U0378'
+ 0,0,2,3:'\U1100\U0308\U0378' 0,1,2:'\U1160\U0020' 0,0,2,3:'\U1160\U0308\U0020' 0,1,2:'\U1160\U000D' 0,0,2,3:'\U1160\U0308\U000D' 0,1,2:'\U1160\U000A'
+ 0,0,2,3:'\U1160\U0308\U000A' 0,1,2:'\U1160\U0001' 0,0,2,3:'\U1160\U0308\U0001' 0,0,2:'\U1160\U034F' 0,0,0,3:'\U1160\U0308\U034F' 0,1,2:'\U1160\U1F1E6'
+ 0,0,2,3:'\U1160\U0308\U1F1E6' 0,1,2:'\U1160\U0600' 0,0,2,3:'\U1160\U0308\U0600' 0,0,2:'\U1160\U0903' 0,0,0,3:'\U1160\U0308\U0903' 0,1,2:'\U1160\U1100'
+ 0,0,2,3:'\U1160\U0308\U1100' 0,0,2:'\U1160\U1160' 0,0,2,3:'\U1160\U0308\U1160' 0,0,2:'\U1160\U11A8' 0,0,2,3:'\U1160\U0308\U11A8' 0,1,2:'\U1160\UAC00'
+ 0,0,2,3:'\U1160\U0308\UAC00' 0,1,2:'\U1160\UAC01' 0,0,2,3:'\U1160\U0308\UAC01' 0,1,2:'\U1160\U231A' 0,0,2,3:'\U1160\U0308\U231A' 0,0,2:'\U1160\U0300'
+ 0,0,0,3:'\U1160\U0308\U0300' 0,0,2:'\U1160\U200D' 0,0,0,3:'\U1160\U0308\U200D' 0,1,2:'\U1160\U0378' 0,0,2,3:'\U1160\U0308\U0378' 0,1,2:'\U11A8\U0020'
+ 0,0,2,3:'\U11A8\U0308\U0020' 0,1,2:'\U11A8\U000D' 0,0,2,3:'\U11A8\U0308\U000D' 0,1,2:'\U11A8\U000A' 0,0,2,3:'\U11A8\U0308\U000A' 0,1,2:'\U11A8\U0001'
+ 0,0,2,3:'\U11A8\U0308\U0001' 0,0,2:'\U11A8\U034F' 0,0,0,3:'\U11A8\U0308\U034F' 0,1,2:'\U11A8\U1F1E6' 0,0,2,3:'\U11A8\U0308\U1F1E6' 0,1,2:'\U11A8\U0600'
+ 0,0,2,3:'\U11A8\U0308\U0600' 0,0,2:'\U11A8\U0903' 0,0,0,3:'\U11A8\U0308\U0903' 0,1,2:'\U11A8\U1100' 0,0,2,3:'\U11A8\U0308\U1100' 0,1,2:'\U11A8\U1160'
+ 0,0,2,3:'\U11A8\U0308\U1160' 0,0,2:'\U11A8\U11A8' 0,0,2,3:'\U11A8\U0308\U11A8' 0,1,2:'\U11A8\UAC00' 0,0,2,3:'\U11A8\U0308\UAC00' 0,1,2:'\U11A8\UAC01'
+ 0,0,2,3:'\U11A8\U0308\UAC01' 0,1,2:'\U11A8\U231A' 0,0,2,3:'\U11A8\U0308\U231A' 0,0,2:'\U11A8\U0300' 0,0,0,3:'\U11A8\U0308\U0300' 0,0,2:'\U11A8\U200D'
+ 0,0,0,3:'\U11A8\U0308\U200D' 0,1,2:'\U11A8\U0378' 0,0,2,3:'\U11A8\U0308\U0378' 0,1,2:'\UAC00\U0020' 0,0,2,3:'\UAC00\U0308\U0020' 0,1,2:'\UAC00\U000D'
+ 0,0,2,3:'\UAC00\U0308\U000D' 0,1,2:'\UAC00\U000A' 0,0,2,3:'\UAC00\U0308\U000A' 0,1,2:'\UAC00\U0001' 0,0,2,3:'\UAC00\U0308\U0001' 0,0,2:'\UAC00\U034F'
+ 0,0,0,3:'\UAC00\U0308\U034F' 0,1,2:'\UAC00\U1F1E6' 0,0,2,3:'\UAC00\U0308\U1F1E6' 0,1,2:'\UAC00\U0600' 0,0,2,3:'\UAC00\U0308\U0600' 0,0,2:'\UAC00\U0903'
+ 0,0,0,3:'\UAC00\U0308\U0903' 0,1,2:'\UAC00\U1100' 0,0,2,3:'\UAC00\U0308\U1100' 0,0,2:'\UAC00\U1160' 0,0,2,3:'\UAC00\U0308\U1160' 0,0,2:'\UAC00\U11A8'
+ 0,0,2,3:'\UAC00\U0308\U11A8' 0,1,2:'\UAC00\UAC00' 0,0,2,3:'\UAC00\U0308\UAC00' 0,1,2:'\UAC00\UAC01' 0,0,2,3:'\UAC00\U0308\UAC01' 0,1,2:'\UAC00\U231A'
+ 0,0,2,3:'\UAC00\U0308\U231A' 0,0,2:'\UAC00\U0300' 0,0,0,3:'\UAC00\U0308\U0300' 0,0,2:'\UAC00\U200D' 0,0,0,3:'\UAC00\U0308\U200D' 0,1,2:'\UAC00\U0378'
+ 0,0,2,3:'\UAC00\U0308\U0378' 0,1,2:'\UAC01\U0020' 0,0,2,3:'\UAC01\U0308\U0020' 0,1,2:'\UAC01\U000D' 0,0,2,3:'\UAC01\U0308\U000D' 0,1,2:'\UAC01\U000A'
+ 0,0,2,3:'\UAC01\U0308\U000A' 0,1,2:'\UAC01\U0001' 0,0,2,3:'\UAC01\U0308\U0001' 0,0,2:'\UAC01\U034F' 0,0,0,3:'\UAC01\U0308\U034F' 0,1,2:'\UAC01\U1F1E6'
+ 0,0,2,3:'\UAC01\U0308\U1F1E6' 0,1,2:'\UAC01\U0600' 0,0,2,3:'\UAC01\U0308\U0600' 0,0,2:'\UAC01\U0903' 0,0,0,3:'\UAC01\U0308\U0903' 0,1,2:'\UAC01\U1100'
+ 0,0,2,3:'\UAC01\U0308\U1100' 0,1,2:'\UAC01\U1160' 0,0,2,3:'\UAC01\U0308\U1160' 0,0,2:'\UAC01\U11A8' 0,0,2,3:'\UAC01\U0308\U11A8' 0,1,2:'\UAC01\UAC00'
+ 0,0,2,3:'\UAC01\U0308\UAC00' 0,1,2:'\UAC01\UAC01' 0,0,2,3:'\UAC01\U0308\UAC01' 0,1,2:'\UAC01\U231A' 0,0,2,3:'\UAC01\U0308\U231A' 0,0,2:'\UAC01\U0300'
+ 0,0,0,3:'\UAC01\U0308\U0300' 0,0,2:'\UAC01\U200D' 0,0,0,3:'\UAC01\U0308\U200D' 0,1,2:'\UAC01\U0378' 0,0,2,3:'\UAC01\U0308\U0378' 0,1,2:'\U231A\U0020'
+ 0,0,2,3:'\U231A\U0308\U0020' 0,1,2:'\U231A\U000D' 0,0,2,3:'\U231A\U0308\U000D' 0,1,2:'\U231A\U000A' 0,0,2,3:'\U231A\U0308\U000A' 0,1,2:'\U231A\U0001'
+ 0,0,2,3:'\U231A\U0308\U0001' 0,0,2:'\U231A\U034F' 0,0,0,3:'\U231A\U0308\U034F' 0,1,2:'\U231A\U1F1E6' 0,0,2,3:'\U231A\U0308\U1F1E6' 0,1,2:'\U231A\U0600'
+ 0,0,2,3:'\U231A\U0308\U0600' 0,0,2:'\U231A\U0903' 0,0,0,3:'\U231A\U0308\U0903' 0,1,2:'\U231A\U1100' 0,0,2,3:'\U231A\U0308\U1100' 0,1,2:'\U231A\U1160'
+ 0,0,2,3:'\U231A\U0308\U1160' 0,1,2:'\U231A\U11A8' 0,0,2,3:'\U231A\U0308\U11A8' 0,1,2:'\U231A\UAC00' 0,0,2,3:'\U231A\U0308\UAC00' 0,1,2:'\U231A\UAC01'
+ 0,0,2,3:'\U231A\U0308\UAC01' 0,1,2:'\U231A\U231A' 0,0,2,3:'\U231A\U0308\U231A' 0,0,2:'\U231A\U0300' 0,0,0,3:'\U231A\U0308\U0300' 0,0,2:'\U231A\U200D'
+ 0,0,0,3:'\U231A\U0308\U200D' 0,1,2:'\U231A\U0378' 0,0,2,3:'\U231A\U0308\U0378' 0,1,2:'\U0300\U0020' 0,0,2,3:'\U0300\U0308\U0020' 0,1,2:'\U0300\U000D'
+ 0,0,2,3:'\U0300\U0308\U000D' 0,1,2:'\U0300\U000A' 0,0,2,3:'\U0300\U0308\U000A' 0,1,2:'\U0300\U0001' 0,0,2,3:'\U0300\U0308\U0001' 0,0,2:'\U0300\U034F'
+ 0,0,0,3:'\U0300\U0308\U034F' 0,1,2:'\U0300\U1F1E6' 0,0,2,3:'\U0300\U0308\U1F1E6' 0,1,2:'\U0300\U0600' 0,0,2,3:'\U0300\U0308\U0600' 0,0,2:'\U0300\U0903'
+ 0,0,0,3:'\U0300\U0308\U0903' 0,1,2:'\U0300\U1100' 0,0,2,3:'\U0300\U0308\U1100' 0,1,2:'\U0300\U1160' 0,0,2,3:'\U0300\U0308\U1160' 0,1,2:'\U0300\U11A8'
+ 0,0,2,3:'\U0300\U0308\U11A8' 0,1,2:'\U0300\UAC00' 0,0,2,3:'\U0300\U0308\UAC00' 0,1,2:'\U0300\UAC01' 0,0,2,3:'\U0300\U0308\UAC01' 0,1,2:'\U0300\U231A'
+ 0,0,2,3:'\U0300\U0308\U231A' 0,0,2:'\U0300\U0300' 0,0,0,3:'\U0300\U0308\U0300' 0,0,2:'\U0300\U200D' 0,0,0,3:'\U0300\U0308\U200D' 0,1,2:'\U0300\U0378'
+ 0,0,2,3:'\U0300\U0308\U0378' 0,1,2:'\U200D\U0020' 0,0,2,3:'\U200D\U0308\U0020' 0,1,2:'\U200D\U000D' 0,0,2,3:'\U200D\U0308\U000D' 0,1,2:'\U200D\U000A'
+ 0,0,2,3:'\U200D\U0308\U000A' 0,1,2:'\U200D\U0001' 0,0,2,3:'\U200D\U0308\U0001' 0,0,2:'\U200D\U034F' 0,0,0,3:'\U200D\U0308\U034F' 0,1,2:'\U200D\U1F1E6'
+ 0,0,2,3:'\U200D\U0308\U1F1E6' 0,1,2:'\U200D\U0600' 0,0,2,3:'\U200D\U0308\U0600' 0,0,2:'\U200D\U0903' 0,0,0,3:'\U200D\U0308\U0903' 0,1,2:'\U200D\U1100'
+ 0,0,2,3:'\U200D\U0308\U1100' 0,1,2:'\U200D\U1160' 0,0,2,3:'\U200D\U0308\U1160' 0,1,2:'\U200D\U11A8' 0,0,2,3:'\U200D\U0308\U11A8' 0,1,2:'\U200D\UAC00'
+ 0,0,2,3:'\U200D\U0308\UAC00' 0,1,2:'\U200D\UAC01' 0,0,2,3:'\U200D\U0308\UAC01' 0,1,2:'\U200D\U231A' 0,0,2,3:'\U200D\U0308\U231A' 0,0,2:'\U200D\U0300'
+ 0,0,0,3:'\U200D\U0308\U0300' 0,0,2:'\U200D\U200D' 0,0,0,3:'\U200D\U0308\U200D' 0,1,2:'\U200D\U0378' 0,0,2,3:'\U200D\U0308\U0378' 0,1,2:'\U0378\U0020'
+ 0,0,2,3:'\U0378\U0308\U0020' 0,1,2:'\U0378\U000D' 0,0,2,3:'\U0378\U0308\U000D' 0,1,2:'\U0378\U000A' 0,0,2,3:'\U0378\U0308\U000A' 0,1,2:'\U0378\U0001'
+ 0,0,2,3:'\U0378\U0308\U0001' 0,0,2:'\U0378\U034F' 0,0,0,3:'\U0378\U0308\U034F' 0,1,2:'\U0378\U1F1E6' 0,0,2,3:'\U0378\U0308\U1F1E6' 0,1,2:'\U0378\U0600'
+ 0,0,2,3:'\U0378\U0308\U0600' 0,0,2:'\U0378\U0903' 0,0,0,3:'\U0378\U0308\U0903' 0,1,2:'\U0378\U1100' 0,0,2,3:'\U0378\U0308\U1100' 0,1,2:'\U0378\U1160'
+ 0,0,2,3:'\U0378\U0308\U1160' 0,1,2:'\U0378\U11A8' 0,0,2,3:'\U0378\U0308\U11A8' 0,1,2:'\U0378\UAC00' 0,0,2,3:'\U0378\U0308\UAC00' 0,1,2:'\U0378\UAC01'
+ 0,0,2,3:'\U0378\U0308\UAC01' 0,1,2:'\U0378\U231A' 0,0,2,3:'\U0378\U0308\U231A' 0,0,2:'\U0378\U0300' 0,0,0,3:'\U0378\U0308\U0300' 0,0,2:'\U0378\U200D'
+ 0,0,0,3:'\U0378\U0308\U200D' 0,1,2:'\U0378\U0378' 0,0,2,3:'\U0378\U0308\U0378' 0,1,2,3,4,5:'\U000D\U000A\U0061\U000A\U0308' 0,0,2:'\U0061\U0308'
+ 0,0,2,3:'\U0020\U200D\U0646' 0,0,2,3:'\U0646\U200D\U0020' 0,0,2:'\U1100\U1100' 0,0,2,3:'\UAC00\U11A8\U1100' 0,0,2,3:'\UAC01\U11A8\U1100'
+ 0,0,2,3,4:'\U1F1E6\U1F1E7\U1F1E8\U0062' 0,1,1,3,4,5:'\U0061\U1F1E6\U1F1E7\U1F1E8\U0062' 0,1,1,1,4,5,6:'\U0061\U1F1E6\U1F1E7\U200D\U1F1E8\U0062'
+ 0,1,1,3,3,5,6:'\U0061\U1F1E6\U200D\U1F1E7\U1F1E8\U0062' 0,1,1,3,3,5,6:'\U0061\U1F1E6\U1F1E7\U1F1E8\U1F1E9\U0062' 0,0,2:'\U0061\U200D'
+ 0,0,2,3:'\U0061\U0308\U0062' 0,0,2,3:'\U0061\U0903\U0062' 0,1,1,3:'\U0061\U0600\U0062' 0,0,2,3:'\U1F476\U1F3FF\U1F476' 0,0,2,3:'\U0061\U1F3FF\U1F476'
+ 0,0,2,2,2,5:'\U0061\U1F3FF\U1F476\U200D\U1F6D1' 0,0,0,0,0,0,6:'\U1F476\U1F3FF\U0308\U200D\U1F476\U1F3FF' 0,0,0,3:'\U1F6D1\U200D\U1F6D1'
+ 0,0,2,3:'\U0061\U200D\U1F6D1' 0,0,0,3:'\U2701\U200D\U2701' 0,0,2,3:'\U0061\U200D\U2701'
+ )
+ function ble/test:canvas/GraphemeClusterBreak/find-previous-boundary {
+ local ans=${1%%:*} str=${1#*:}
+ ble/string#split ans , "$ans"
+ local i=0 b=0
+ for k in "${!ans[@]}"; do
+ ble/test "ble/unicode/GraphemeCluster/find-previous-boundary \$'$str' $((k+1))" ret=${ans[k]}
+ if ((ans[k]>b)); then
+ local ret= c= w= cs= extend=
+ ble/test "ble/unicode/GraphemeCluster/match \$'$str' $b && ((ret=b+1+extend))" ret=${ans[k]}
+ ((b=ans[k]))
+ fi
+ done
+ }
+ if ((_ble_bash>=40200)); then
+ for spec in "${tests_cases[@]}"; do
+ ble/test:canvas/GraphemeClusterBreak/find-previous-boundary "$spec"
+ done
+ fi
+)
+ble/test/end-section
diff --git a/.local/src/blesh/lib/test-complete.sh b/.local/src/blesh/lib/test-complete.sh
new file mode 100644
index 0000000..cd7c0e1
--- /dev/null
+++ b/.local/src/blesh/lib/test-complete.sh
@@ -0,0 +1,28 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import lib/core-complete
+ble-import lib/core-test
+ble/test/start-section 'ble/complete' 7
+(
+ function _collect {
+ local text=${args[1]} p0=0 i out=
+ for ((i=0;i<${#ret[@]};i++)); do
+ ((p=ret[i]))
+ if ((i%2==0)); then
+ out=$out${text:p0:p-p0}'['
+ else
+ out=$out${text:p0:p-p0}']'
+ fi
+ p0=$p
+ done
+ ((p0<${#text})) && out=$out${text:p0}
+ ret=$out
+ }
+ ble/test 'args=(akf Makefile 0); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='M[ak]e[f]ile'
+ ble/test 'args=(akf Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='Makefile'
+ ble/test 'args=(Mkf Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='[M]a[k]e[f]ile'
+ ble/test 'args=(Maf Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='[Ma]ke[f]ile'
+ ble/test 'args=(Mak Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='[Mak]efile'
+ ble/test 'args=(ake Makefile 0); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='M[ake]file'
+ ble/test 'args=(afe Makefile 0); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='M[a]ke[f]il[e]'
+)
+ble/test/end-section
diff --git a/.local/src/blesh/lib/test-decode.sh b/.local/src/blesh/lib/test-decode.sh
new file mode 100644
index 0000000..712b218
--- /dev/null
+++ b/.local/src/blesh/lib/test-decode.sh
@@ -0,0 +1,39 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import lib/core-test
+ble/test/start-section 'ble/decode' 33
+(
+ ble/test 'ble/builtin/bind/.parse-keyname tab ; ret=${chars[0]}' ret=9
+ ble/test 'ble/builtin/bind/.parse-keyname TAB ; ret=${chars[0]}' ret=9
+ ble/test 'ble/builtin/bind/.parse-keyname newline; ret=${chars[0]}' ret=10
+ ble/test 'ble/builtin/bind/.parse-keyname LFD ; ret=${chars[0]}' ret=10
+ ble/test 'ble/builtin/bind/.parse-keyname Return ; ret=${chars[0]}' ret=13
+ ble/test 'ble/builtin/bind/.parse-keyname RET ; ret=${chars[0]}' ret=13
+ ble/test 'ble/builtin/bind/.parse-keyname Space ; ret=${chars[0]}' ret=32
+ ble/test 'ble/builtin/bind/.parse-keyname SPC ; ret=${chars[0]}' ret=32
+ ble/test 'ble/builtin/bind/.parse-keyname Rubout ; ret=${chars[0]}' ret=127
+ ble/test 'ble/builtin/bind/.parse-keyname DEL ; ret=${chars[0]}' ret=127
+ ble/test 'ble/builtin/bind/.parse-keyname Escape ; ret=${chars[0]}' ret=27
+ ble/test 'ble/builtin/bind/.parse-keyname ESC ; ret=${chars[0]}' ret=27
+ ble/test 'ble/builtin/bind/.parse-keyname C-Space; ret=${chars[0]}' ret=0
+ ble/test 'ble/builtin/bind/.parse-keyname s ; ret=${chars[0]}' ret=115
+ ble/test 'ble/builtin/bind/.parse-keyname S ; ret=${chars[0]}' ret=83
+ ble/test "ble/builtin/bind/.parse-keyname '\C-x\C-y' ; ret=\${chars[0]}" ret=25 # C-y
+ ble/test "ble/builtin/bind/.parse-keyname 'xyz' ; ret=\${chars[0]}" ret=120 # x
+ ble/test "ble/builtin/bind/.parse-keyname '\a' ; ret=\${chars[0]}" ret=92 # \ (backslash)
+ ble/test "ble/builtin/bind/.parse-keyname '\C-nop' ; ret=\${chars[0]}" ret=14 # C-n
+ ble/test "ble/builtin/bind/.parse-keyname '\C-xC-y' ; ret=\${chars[0]}" ret=25 # C-y
+ ble/test "ble/builtin/bind/.parse-keyname '\C-axC-b' ; ret=\${chars[0]}" ret=2 # C-b
+ ble/test "ble/builtin/bind/.parse-keyname 'helloC-b' ; ret=\${chars[0]}" ret=2 # C-b
+ ble/test "ble/builtin/bind/.parse-keyname 'helloC-x,TAB' ; ret=\${chars[0]}" ret=24 # C-x
+ ble/test "ble/builtin/bind/.parse-keyname 'C-xTAB' ; ret=\${chars[0]}" ret=24 # C-x
+ ble/test "ble/builtin/bind/.parse-keyname 'TABC-x' ; ret=\${chars[0]}" ret=24 # C-x
+ ble/test "ble/builtin/bind/.parse-keyname 'BC-' ; ret=\${chars[0]}" ret=0 # C-@
+ ble/test "ble/builtin/bind/.parse-keyname 'C-M-a' ; ret=\${chars[0]}" ret=129 # C-M-a
+ ble/test "ble/builtin/bind/.parse-keyname 'M-C-a' ; ret=\${chars[0]}" ret=129 # C-M-a
+ ble/test "ble/builtin/bind/.parse-keyname 'C-aalpha-beta'; ret=\${chars[0]}" ret=2 # C-b
+ ble/test "ble/builtin/bind/.parse-keyname '\C-a\M-c' ; ret=\${chars[0]}" ret=131 # C-M-c
+ ble/test "ble/builtin/bind/.parse-keyname 'panic-trim-c' ; ret=\${chars[0]}" ret=131 # C-M-c
+ ble/test "ble/builtin/bind/.parse-keyname 'C--' ; ret=\${chars[0]}" ret=0 # C-@
+ ble/test "ble/builtin/bind/.parse-keyname 'C--x' ; ret=\${chars[0]}" ret=24 # C-x
+)
+ble/test/end-section
diff --git a/.local/src/blesh/lib/test-edit.sh b/.local/src/blesh/lib/test-edit.sh
new file mode 100644
index 0000000..f9d8211
--- /dev/null
+++ b/.local/src/blesh/lib/test-edit.sh
@@ -0,0 +1,8 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import lib/core-test
+ble/test/start-section 'ble/edit' 2
+(
+ ble/test "_ble_edit_str=$'echo\nhello\nworld' ble-edit/content/find-logical-eol 13 -1" exit=0 ret=10
+ ble/test "_ble_edit_str=$'echo\nhello\nworld' ble-edit/content/find-logical-bol 13 -1" exit=0 ret=5
+)
+ble/test/end-section
diff --git a/.local/src/blesh/lib/test-main.sh b/.local/src/blesh/lib/test-main.sh
new file mode 100644
index 0000000..dc6cb57
--- /dev/null
+++ b/.local/src/blesh/lib/test-main.sh
@@ -0,0 +1,79 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import lib/core-test
+ble/test/start-section 'ble/main' 19
+(
+ ble/test ble/util/put a stdout=a
+ ble/test ble/util/print a stdout=a
+ ble/test 'ble/util/put "a b"' stdout='a b'
+ ble/test 'ble/util/print "a b"' stdout='a b'
+ ble/test 'ble/util/put "a b"; ble/util/put "c d"' \
+ stdout='a bc d'
+ ble/test 'ble/util/print "a b"; ble/util/print "c d"' \
+ stdout='a b' \
+ stdout='c d'
+)
+(
+ function ble/test/dummy-1 { true; }
+ function ble/test/dummy-2 { true; }
+ function ble/test/dummy-3 { true; }
+ ble/test ble/bin#has ble/test/dummy-1
+ ble/test ble/bin#has ble/test/dummy-{1..3}
+ ble/test ble/bin#has ble/test/dummy-0 exit=1
+ ble/test ble/bin#has ble/test/dummy-{0..2} exit=1
+)
+(
+ ble/bin/.freeze-utility-path readlink ls
+ function ble/test:readlink.impl1 {
+ ret=$1
+ ble/util/readlink/.resolve-loop
+ }
+ function ble/test:readlink.impl2 {
+ ret=$1
+ ble/function#push ble/bin/readlink
+ ble/util/readlink/.resolve-loop
+ ble/function#pop ble/bin/readlink
+ }
+ ble/test/chdir
+ mkdir -p ab/cd/ef
+ touch ab/cd/ef/file.txt
+ ln -s ef/file.txt ab/cd/link1
+ ln -s ab link.d
+ ln -s link.d/cd/link1 f.txt
+ ble/test '
+ ble/util/readlink f.txt
+ [[ $ret != /* ]] && ret=${PWD%/}/$ret' \
+ ret="${PWD%/}/ab/cd/ef/file.txt"
+ ln -s loop1.sh loop0.sh
+ ln -s loop2.sh loop1.sh
+ ln -s loop3.sh loop2.sh
+ ln -s loop1.sh loop3.sh
+ for impl in impl1 impl2; do
+ ble/test "ble/test:readlink.$impl loop0.sh" ret='loop1.sh'
+ done
+ mkdir -p phys.dir
+ touch phys.dir/1.txt
+ ln -s ../../../phys.dir ab/cd/ef/phys.link
+ ln -s ab/cd/ef/phys.link phys.link
+ local pwd=$PWD xpath=
+ ble/test code:'
+ path=phys.link/1.txt
+ ble/util/readlink/.resolve-physical-directory
+ declare -p path PWD >&2
+ [[ $path == */phys.dir/1.txt && $PWD == "$pwd" ]]'
+ ble/test/rmdir
+)
+(
+ ble/test '[[ -d $_ble_base ]]'
+ ble/test '[[ -d $_ble_base_run ]]'
+ ble/test '[[ -d $_ble_base_cache ]]'
+)
+(
+ qnl="\$'\n'"
+ value=$'\nxxx is a function\nhello\nyyy is a function\n'
+ pattern=$'\n+([][{}:[:alnum:]]) is a function\n'
+ shopt -s extglob
+ ble/test '[[ ${value//$pattern/'"$qnl"'} == '"$qnl"'hello'"$qnl"' ]]'
+ shopt -u extglob
+ ble/test '[[ ${value//$pattern/'"$qnl"'} != '"$qnl"'hello'"$qnl"' ]]'
+)
+ble/test/end-section
diff --git a/.local/src/blesh/lib/test-syntax.sh b/.local/src/blesh/lib/test-syntax.sh
new file mode 100644
index 0000000..4e339a7
--- /dev/null
+++ b/.local/src/blesh/lib/test-syntax.sh
@@ -0,0 +1,39 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import lib/core-syntax
+ble-import lib/core-test
+ble/test/start-section 'ble/syntax' 22
+(
+ _func=ble/syntax:bash/simple-word/evaluate-last-brace-expansion
+ _collect='ret=$simple_ibrace/$ret'
+ ble/test "$_func 'a{b,c}x' ; $_collect" ret='6:2/acx'
+ ble/test "$_func 'a{b,{c,d}x' ; $_collect" ret='9:2/adx'
+ ble/test "$_func 'a{b,{c,d}}x'; $_collect" ret='10:2/adx'
+ ble/test "$_func 'a{{c,dx' ; $_collect" ret='5:1/adx'
+ ble/test "$_func 'a{b{c,dx' ; $_collect" ret='6:2/abdx'
+ ble/test "$_func 'a{b,c}{d}x' ; $_collect" ret='7:2/acd}x'
+)
+(
+ _func=ble/syntax:bash/simple-word/reconstruct-incomplete-word
+ _collect='ret=$?:$simple_flags:[$simple_ibrace]:$ret'
+ ble/test "$_func 'hello-word' ; $_collect" ret='0::[0:0]:hello-word'
+ ble/test "$_func 'hello word' ; $_collect" ret='1::[0:0]:hello'
+ ble/test "$_func 'hello-word\"a' ; $_collect" ret='0:D:[0:0]:hello-word"a"'
+ ble/test "$_func 'a{b,c}x' ; $_collect" ret='0::[6:2]:acx'
+ ble/test "$_func 'a{b,{c,d}x' ; $_collect" ret='0::[9:2]:adx'
+ ble/test "$_func 'a{b,{c,d}}x' ; $_collect" ret='0::[10:2]:adx'
+ ble/test "$_func 'a{{c,dx' ; $_collect" ret='0::[5:1]:adx'
+ ble/test "$_func 'a{b{c,dx' ; $_collect" ret='0::[6:2]:abdx'
+ ble/test "$_func 'a{b,c}{d}x' ; $_collect" ret='0::[7:2]:acd}x'
+ ble/test "$_func 'a{b,c}x\"hello, world'; $_collect" ret='0:D:[6:2]:acx"hello, world"'
+ ble/test "$_func 'a{b,{c,d}x'\''a' ; $_collect" ret='0:S:[9:2]:adx'\''a'\'
+ ble/test "$_func 'a{b,{c,d}}x\$'\''\e[m'; $_collect" ret='0:E:[10:2]:adx$'\''\e[m'\'
+ ble/test "$_func 'a{{c,dx\$\"aa' ; $_collect" ret='0:I:[5:1]:adx$"aa"'
+)
+(
+ _func=ble/syntax:bash/simple-word/evaluate-path-spec
+ _collect='ret="${spec[*]} >>> ${path[*]}"'
+ ble/test "$_func '~/a/b/c' ; $_collect" ret="~ ~/a ~/a/b ~/a/b/c >>> $HOME $HOME/a $HOME/a/b $HOME/a/b/c"
+ ble/test "$_func '~/a/b/c' / after-sep; $_collect" ret="~/ ~/a/ ~/a/b/ ~/a/b/c >>> $HOME/ $HOME/a/ $HOME/a/b/ $HOME/a/b/c"
+ ble/test "$_func '/x/y/z' / after-sep ; $_collect" ret="/ /x/ /x/y/ /x/y/z >>> / /x/ /x/y/ /x/y/z"
+)
+ble/test/end-section
diff --git a/.local/src/blesh/lib/test-util.sh b/.local/src/blesh/lib/test-util.sh
new file mode 100644
index 0000000..4ec1155
--- /dev/null
+++ b/.local/src/blesh/lib/test-util.sh
@@ -0,0 +1,1555 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import lib/core-test
+ble/test/start-section 'ble/util' 1198
+(
+ ble/test 'bleopt a=1' \
+ exit=2
+ ble/test 'bleopt a' \
+ stdout= exit=2
+ ble/test 'bleopt a:=2'
+ ble/test 'bleopt a' \
+ stdout="bleopt a=2"
+ ble/test '[[ $bleopt_a == 2 ]]'
+ ble/test "bleopt | grep 'bleopt a='" \
+ stdout="bleopt a=2"
+ ble/test 'bleopt a=3'
+ ble/test 'bleopt a' \
+ stdout="bleopt a=3"
+ function bleopt/check:a { value=123; }
+ ble/test 'bleopt a=4 && bleopt a'
+ stdout="bleopt a=123"
+ function bleopt/check:a { false; }
+ ble/test 'bleopt a=5' \
+ exit=1
+ ble/test 'bleopt a' \
+ stdout="bleopt a=123"
+ ble/test bleopt f:=10 g:=11
+ ble/test bleopt f g \
+ stdout="bleopt f=10${_ble_term_nl}bleopt g=11"
+ ble/test bleopt f=12 g=13
+ ble/test bleopt f g \
+ stdout="bleopt f=12${_ble_term_nl}bleopt g=13"
+ ble/test bleopt/declare -v b 6
+ ble/test bleopt b stdout="bleopt b=6"
+ ble/test bleopt/declare -n c 7
+ ble/test bleopt c stdout="bleopt c=7"
+ ble/test bleopt d:= e:=
+ ble/test bleopt/declare -v d 8
+ ble/test bleopt/declare -n e 9
+ ble/test bleopt d stdout="bleopt d="
+ ble/test bleopt e stdout="bleopt e=9"
+)
+ble/test ble/util/setexit 0 exit=0
+ble/test ble/util/setexit 1 exit=1
+ble/test ble/util/setexit 9 exit=9
+ble/test ble/util/setexit 128 exit=128
+ble/test ble/util/setexit 255 exit=255
+(
+ a=1
+ function f1 {
+ echo g:$a
+ local a=2
+ echo l:$a
+ ble/util/unlocal a
+ echo g:$a
+ a=3
+ }
+ ble/test 'f1; echo g:$a' \
+ stdout=g:1 \
+ stdout=l:2 \
+ stdout=g:1 \
+ stdout=g:3
+ function f2 {
+ echo f1:$a@f2
+ local a=3
+ echo f2:$a@f2
+ ble/util/unlocal a
+ echo f1:$a@f2
+ a=$a+
+ }
+ function f1 {
+ echo g:$a@f1
+ local a=2
+ echo f1:$a@f1
+ f2
+ echo f1:$a@f1
+ ble/util/unlocal a
+ echo g:$a@f1
+ a=$a+
+ }
+ ble/test 'a=1; f1; echo g:$a@g' \
+ stdout=g:1@f1 \
+ stdout=f1:2@f1 \
+ stdout=f1:2@f2 \
+ stdout=f2:3@f2 \
+ stdout=f1:2@f2 \
+ stdout=f1:2+@f1 \
+ stdout=g:1@f1 \
+ stdout=g:1+@g
+)
+(
+ function f1 {
+ local a=1 b=2
+ local result=$((a+b))
+ local "$1" && ble/util/upvar "$1" "$result"
+ }
+ ble/test 'f1 x; ret=$x' ret=3
+ ble/test 'f1 a; ret=$a' ret=3
+ ble/test 'f1 result; ret=$result' ret=3
+ function f2 {
+ local a=1
+ local -a b=(2)
+ local -a result=($((a+b[0])) y z)
+ local "$1" && ble/util/uparr "$1" "${result[@]}"
+ }
+ ble/test 'f2 x; ret="(${x[*]})"' ret='(3 y z)'
+ ble/test 'f2 a; ret="(${a[*]})"' ret='(3 y z)'
+ ble/test 'f2 b; ret="(${b[*]})"' ret='(3 y z)'
+ ble/test 'f2 result; ret="(${result[*]})"' ret='(3 y z)'
+)
+(
+ VARNAMES=(name x y count data)
+ function print-status {
+ echo "name=$name x=$x y=$y count=$count data=(${data[*]})"
+ }
+ function f1 {
+ local "${VARNAMES[@]/%/=}" # WA #D1570 checked
+ name=1 x=2 y=3 count=4 data=(aa bb cc dd)
+ print-status
+ ble/util/save-vars save1_ "${VARNAMES[@]}"
+ name=one x= y=A count=1 data=(Q)
+ print-status
+ ble/util/save-vars save2_ "${VARNAMES[@]}"
+ ble/util/restore-vars save1_ "${VARNAMES[@]}"
+ print-status
+ ble/util/restore-vars save2_ "${VARNAMES[@]}"
+ print-status
+ }
+ ble/test f1 \
+ stdout='name=1 x=2 y=3 count=4 data=(aa bb cc dd)' \
+ stdout='name=one x= y=A count=1 data=(Q)' \
+ stdout='name=1 x=2 y=3 count=4 data=(aa bb cc dd)' \
+ stdout='name=one x= y=A count=1 data=(Q)'
+)
+(
+ declare v=1
+ declare -i i=1
+ export x=2
+ readonly r=3
+ declare -a a=()
+ if ((_ble_bash>=40000)); then
+ declare -A A=()
+ declare -u u=a
+ declare -l l=B
+ declare -c c=c
+ fi
+ if ((_ble_bash>=40300)); then
+ declare -n n=r
+ fi
+ ble/test 'ble/variable#get-attr v; ret=$attr' ret=
+ ble/test 'ble/variable#get-attr i; ret=$attr' ret=i
+ ble/test 'ble/variable#get-attr x; ret=$attr' ret=x
+ ble/test 'ble/variable#get-attr r; ret=$attr' ret=r
+ ble/test 'ble/variable#get-attr a; ret=$attr' ret=a
+ if ((_ble_bash>=40000)); then
+ ble/test 'ble/variable#get-attr u; ret=$attr' ret=u
+ ble/test 'ble/variable#get-attr l; ret=$attr' ret=l
+ ble/test 'ble/variable#get-attr c; ret=$attr' ret=c
+ ble/test 'ble/variable#get-attr A; ret=$attr' ret=A
+ fi
+ ble/test 'ble/variable#has-attr i i'
+ ble/test 'ble/variable#has-attr x x'
+ ble/test 'ble/variable#has-attr r r'
+ ble/test 'ble/variable#has-attr a a'
+ ble/test 'ble/variable#has-attr v i' exit=1
+ ble/test 'ble/variable#has-attr v x' exit=1
+ ble/test 'ble/variable#has-attr v r' exit=1
+ ble/test 'ble/variable#has-attr v a' exit=1
+ if ((_ble_bash>=40000)); then
+ ble/test 'ble/variable#has-attr u u'
+ ble/test 'ble/variable#has-attr l l'
+ ble/test 'ble/variable#has-attr c c'
+ ble/test 'ble/variable#has-attr A A'
+ ble/test 'ble/variable#has-attr v u' exit=1
+ ble/test 'ble/variable#has-attr v l' exit=1
+ ble/test 'ble/variable#has-attr v c' exit=1
+ ble/test 'ble/variable#has-attr v A' exit=1
+ fi
+ ble/test 'ble/is-inttype i'
+ ble/test 'ble/is-inttype v' exit=1
+ ble/test 'ble/is-readonly r'
+ ble/test 'ble/is-readonly v' exit=1
+ if ((_ble_bash>=40000)); then
+ ble/test 'ble/is-transformed u'
+ ble/test 'ble/is-transformed l'
+ ble/test 'ble/is-transformed c'
+ ble/test 'ble/is-transformed v' exit=1
+ fi
+)
+function is-global() (readonly "$1"; ! local "$1" 2>/dev/null)
+(
+ v1=1 v2=2
+ ((_ble_bash>=40200)) &&
+ declare -g v1u v2u
+ function f1 {
+ local v2=22 v3=33
+ local v2u v3u
+ f2
+ }
+ function f2 {
+ local v4=444 v4u
+ ble/test 'is-global v0'
+ ble/test 'is-global v1'
+ ble/test 'is-global v2' exit=1
+ ble/test 'is-global v3' exit=1
+ ble/test 'is-global v4' exit=1
+ ble/test 'ble/variable#is-global v0'
+ ble/test 'ble/variable#is-global v1'
+ ble/test 'ble/variable#is-global v2' exit=1
+ ble/test 'ble/variable#is-global v3' exit=1
+ ble/test 'ble/variable#is-global v4' exit=1
+ ble/test 'ble/variable#is-global v0u'
+ if ((_ble_bash>=40200)); then
+ ble/test 'ble/variable#is-global v1u'
+ ble/test 'ble/variable#is-global v2u' exit=1
+ fi
+ ble/test 'ble/variable#is-global v3u' exit=1
+ ble/test 'ble/variable#is-global v4u' exit=1
+ }
+ f1
+)
+(
+ _ble_array_prototype=()
+ ble/test 'echo ${#_ble_array_prototype[@]}' stdout=0
+ ble/array#reserve-prototype 10
+ ble/test 'echo ${#_ble_array_prototype[@]}' stdout=10
+ ble/test 'x=("${_ble_array_prototype[@]::10}"); echo ${#x[@]}' stdout=10
+ ble/array#reserve-prototype 3
+ ble/test 'echo ${#_ble_array_prototype[@]}' stdout=10
+ ble/test 'x=("${_ble_array_prototype[@]::3}"); echo ${#x[@]}' stdout=3
+)
+(
+ declare -a a=()
+ declare b=
+ ble/test 'ble/is-array a'
+ ble/test 'ble/is-array b' exit=1
+ ble/test 'ble/is-array c' exit=1
+ if ((_ble_bash>=40000)); then
+ declare -A A=()
+ ble/test 'ble/is-array A' exit=1
+ ble/test 'ble/is-assoc a' exit=1
+ ble/test 'ble/is-assoc A'
+ ble/test 'ble/is-assoc b' exit=1
+ ble/test 'ble/is-assoc c' exit=1
+ fi
+)
+(
+ ble/test 'ble/array#set a; echo "${#a[@]}:(${a[*]})"' stdout='0:()'
+ ble/test 'ble/array#set a Q; echo "${#a[@]}:(${a[*]})"' stdout='1:(Q)'
+ ble/test 'ble/array#set a 1 2 3; echo "${#a[@]}:(${a[*]})"' stdout='3:(1 2 3)'
+ ble/test 'ble/array#set a; echo "${#a[@]}:(${a[*]})"' stdout='0:()'
+)
+(
+ declare -a a=()
+ ble/array#push a
+ ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='0:()'
+ ble/array#push a A
+ ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='1:(A)'
+ ble/array#push a B C
+ ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='3:(A B C)'
+ ble/array#push a
+ ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='3:(A B C)'
+)
+(
+ function result { echo "$ret:${#arr[*]}:(${arr[*]})"; }
+ ble/test 'arr=() ; ble/array#pop arr; result' stdout=':0:()'
+ ble/test 'arr=(1) ; ble/array#pop arr; result' stdout='1:0:()'
+ ble/test 'arr=(1 2) ; ble/array#pop arr; result' stdout='2:1:(1)'
+ ble/test 'arr=(0 0 0); ble/array#pop arr; result' stdout='0:2:(0 0)'
+ ble/test 'arr=(1 2 3); ble/array#pop arr; result' stdout='3:2:(1 2)'
+ ble/test 'arr=(" a a " " b b " " c c "); ble/array#pop arr; result' \
+ stdout=' c c :2:( a a b b )'
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ a=()
+ ble/array#unshift a
+ ble/test status stdout='0:()'
+ ble/array#unshift a A
+ ble/test status stdout='1:(A)'
+ ble/array#unshift a
+ ble/test status stdout='1:(A)'
+ ble/array#unshift a B
+ ble/test status stdout='2:(B A)'
+ ble/array#unshift a C D E
+ ble/test status stdout='5:(C D E B A)'
+ a=()
+ ble/array#unshift a A B
+ ble/test status stdout='2:(A B)'
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ a=(); ble/array#reverse a
+ ble/test status stdout='0:()'
+ a=(1); ble/array#reverse a
+ ble/test status stdout='1:(1)'
+ a=(xy zw); ble/array#reverse a
+ ble/test status stdout='2:(zw xy)'
+ a=(a 3 x); ble/array#reverse a
+ ble/test status stdout='3:(x 3 a)'
+ a=({1..10}) b=({10..1}); ble/array#reverse a
+ ble/test status stdout="10:(${b[*]})"
+ a=({1..9}) b=({9..1}); ble/array#reverse a
+ ble/test status stdout="9:(${b[*]})"
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ a=(); ble/array#insert-at a 0 A B C
+ ble/test status stdout='3:(A B C)'
+ a=(); ble/array#insert-at a 1 A B C
+ ble/test status stdout='3:(A B C)'
+ a=(x y z); ble/array#insert-at a 0 A
+ ble/test status stdout='4:(A x y z)'
+ a=(x y z); ble/array#insert-at a 1 A
+ ble/test status stdout='4:(x A y z)'
+ a=(x y z); ble/array#insert-at a 3 A
+ ble/test status stdout='4:(x y z A)'
+ a=(x y z); ble/array#insert-at a 0 A B C
+ ble/test status stdout='6:(A B C x y z)'
+ a=(x y z); ble/array#insert-at a 1 A B C
+ ble/test status stdout='6:(x A B C y z)'
+ a=(x y z); ble/array#insert-at a 3 A B C
+ ble/test status stdout='6:(x y z A B C)'
+ a=(x y z); ble/array#insert-at a 0
+ ble/test status stdout='3:(x y z)'
+ a=(x y z); ble/array#insert-at a 1
+ ble/test status stdout='3:(x y z)'
+ a=(x y z); ble/array#insert-at a 3
+ ble/test status stdout='3:(x y z)'
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ a=(hello world hello world)
+ ble/array#insert-after a hello 1 2 3
+ ble/test status stdout='7:(hello 1 2 3 world hello world)'
+ a=(heart world hello world)
+ ble/array#insert-after a hello 1 2 3
+ ble/test status stdout='7:(heart world hello 1 2 3 world)'
+ a=(hello world hello world)
+ ble/test 'ble/array#insert-after a check 1 2 3' exit=1
+ ble/test status stdout='4:(hello world hello world)'
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ a=(hello world this)
+ ble/array#insert-before a this with check
+ ble/test status stdout='5:(hello world with check this)'
+ a=(hello world this)
+ ble/test 'ble/array#insert-before a haystack kick check' exit=1
+ ble/test status stdout='3:(hello world this)'
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ a=(xxx yyy xxx yyy yyy xxx fdsa fdsa)
+ ble/array#remove a xxx
+ ble/test status stdout='5:(yyy yyy yyy fdsa fdsa)'
+ a=(aa aa aa aa aa)
+ ble/array#remove a bb
+ ble/test status stdout='5:(aa aa aa aa aa)'
+ ble/array#remove a aa
+ ble/test status stdout='0:()'
+ ble/array#remove a cc
+ ble/test status stdout='0:()'
+)
+(
+ a=(hello world this hello world)
+ ble/test 'ble/array#index a hello' ret=0
+ a=(world hep this hello world)
+ ble/test 'ble/array#index a hello' ret=3
+ a=(hello world this hello world)
+ ble/test 'ble/array#index a check' ret=-1
+)
+(
+ a=(hello world this hello world)
+ ble/test 'ble/array#last-index a hello' ret=3
+ a=(world hep this hello world)
+ ble/test 'ble/array#last-index a hello' ret=3
+ a=(hello world this hello world)
+ ble/test 'ble/array#last-index a check' ret=-1
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ a=()
+ ble/test 'ble/array#remove-at a 0; status' stdout='0:()'
+ ble/test 'ble/array#remove-at a 10; status' stdout='0:()'
+ a=(x y z)
+ ble/test 'ble/array#remove-at a 4; status' stdout='3:(x y z)'
+ ble/test 'ble/array#remove-at a 3; status' stdout='3:(x y z)'
+ ble/test 'ble/array#remove-at a 1; status' stdout='2:(x z)'
+ ble/test 'ble/array#remove-at a 0; status' stdout='1:(z)'
+ ble/test 'ble/array#remove-at a 0; status' stdout='0:()'
+ a=({a..z}) a1=({a..y}) a2=({b..y}) a3=({b..h} {j..y})
+ ble/test 'ble/array#remove-at a 25; status' stdout="25:(${a1[*]})"
+ ble/test 'ble/array#remove-at a 0; status' stdout="24:(${a2[*]})"
+ ble/test 'ble/array#remove-at a 7; status' stdout="23:(${a3[*]})"
+)
+(
+ _ble_string_prototype=' '
+ ble/test 'echo ${#_ble_string_prototype}' stdout=8
+ ble/string#reserve-prototype 10
+ ble/test 'echo ${#_ble_string_prototype}' stdout=16
+ ble/test 'x=${_ble_string_prototype::10}; echo ${#x}' stdout=10
+ ble/string#reserve-prototype 3
+ ble/test 'echo ${#_ble_string_prototype}' stdout=16
+ ble/test 'x=${_ble_string_prototype::3}; echo ${#x}' stdout=3
+ ble/string#reserve-prototype 77
+ ble/test 'echo ${#_ble_string_prototype}' stdout=128
+ ble/test 'x=${_ble_string_prototype::77}; echo ${#x}' stdout=77
+)
+(
+ ble/test 'ble/string#repeat' ret=
+ ble/test 'ble/string#repeat ""' ret=
+ ble/test 'ble/string#repeat a' ret=
+ ble/test 'ble/string#repeat abc' ret=
+ ble/test 'ble/string#repeat "" ""' ret=
+ ble/test 'ble/string#repeat a ""' ret=
+ ble/test 'ble/string#repeat abc ""' ret=
+ ble/test 'ble/string#repeat "" 0' ret=
+ ble/test 'ble/string#repeat a 0' ret=
+ ble/test 'ble/string#repeat abc 0' ret=
+ ble/test 'ble/string#repeat "" 1' ret=
+ ble/test 'ble/string#repeat "" 10' ret=
+ ble/test 'ble/string#repeat a 1' ret=a
+ ble/test 'ble/string#repeat a 2' ret=aa
+ ble/test 'ble/string#repeat a 5' ret=aaaaa
+ ble/test 'ble/string#repeat abc 1' ret=abc
+ ble/test 'ble/string#repeat abc 2' ret=abcabc
+ ble/test 'ble/string#repeat abc 5' ret=abcabcabcabcabc
+ ble/test 'ble/string#repeat ";&|<>" 5' ret=';&|<>;&|<>;&|<>;&|<>;&|<>'
+)
+(
+ ble/test 'ble/string#common-prefix' ret=
+ ble/test 'ble/string#common-prefix ""' ret=
+ ble/test 'ble/string#common-prefix a' ret=
+ ble/test 'ble/string#common-prefix "" ""' ret=
+ ble/test 'ble/string#common-prefix a ""' ret=
+ ble/test 'ble/string#common-prefix a b' ret=
+ ble/test 'ble/string#common-prefix a a' ret=a
+ ble/test 'ble/string#common-prefix abc abc' ret=abc
+ ble/test 'ble/string#common-prefix abc aaa' ret=a
+ ble/test 'ble/string#common-prefix abc ccc' ret=
+ ble/test 'ble/string#common-prefix abc xyz' ret=
+)
+(
+ ble/test 'ble/string#common-suffix' ret=
+ ble/test 'ble/string#common-suffix ""' ret=
+ ble/test 'ble/string#common-suffix a' ret=
+ ble/test 'ble/string#common-suffix "" ""' ret=
+ ble/test 'ble/string#common-suffix a ""' ret=
+ ble/test 'ble/string#common-suffix a b' ret=
+ ble/test 'ble/string#common-suffix a a' ret=a
+ ble/test 'ble/string#common-suffix abc abc' ret=abc
+ ble/test 'ble/string#common-suffix abc aaa' ret=
+ ble/test 'ble/string#common-suffix abc ccc' ret=c
+ ble/test 'ble/string#common-suffix abc xyz' ret=
+)
+(
+ function status { echo "${#a[@]}:(""${a[*]}"")"; }
+ nl=$'\n'
+ ble/test 'ble/string#split a , "" ; status' stdout='1:()'
+ ble/test 'ble/string#split a , "1" ; status' stdout='1:(1)'
+ ble/test 'ble/string#split a , "," ; status' stdout='2:( )'
+ ble/test 'ble/string#split a , "1," ; status' stdout='2:(1 )'
+ ble/test 'ble/string#split a , ",2" ; status' stdout='2:( 2)'
+ ble/test 'ble/string#split a , "1,,3" ; status' stdout='3:(1 3)'
+ ble/test 'ble/string#split a , "1,2,3" ; status' stdout='3:(1 2 3)'
+ ble/test 'ble/string#split a " " "1 2 3"; status' stdout='3:(1 2 3)'
+ ble/test 'ble/string#split a " " "1 2 3"; status' stdout='1:(1 2 3)'
+ ble/test 'ble/string#split a " " "1'"$nl"'2'"$nl"'3"; status' stdout="1:(1${nl}2${nl}3)"
+)
+(
+ function status { echo "${#a[@]}:(${a[*]})"; }
+ nl=$'\n' ht=$'\t'
+ ble/test 'ble/string#split-words a "" ; status' stdout='0:()'
+ ble/test 'ble/string#split-words a "1" ; status' stdout='1:(1)'
+ ble/test 'ble/string#split-words a " " ; status' stdout='0:()'
+ ble/test 'ble/string#split-words a "1 " ; status' stdout='1:(1)'
+ ble/test 'ble/string#split-words a " 2" ; status' stdout='1:(2)'
+ ble/test 'ble/string#split-words a "1 3" ; status' stdout='2:(1 3)'
+ ble/test 'ble/string#split-words a "1 2 3"; status' stdout='3:(1 2 3)'
+ ble/test 'ble/string#split-words a " 1'"$ht"'2'"$ht"'3 "; status' stdout='3:(1 2 3)'
+ ble/test 'ble/string#split-words a " 1'"$nl"'2'"$nl"'3 "; status' stdout='3:(1 2 3)'
+)
+(
+ function status { echo "${#a[@]}:(""${a[*]}"")"; }
+ nl=$'\n' ht=$'\t'
+ ble/test 'ble/string#split-lines a "" ; status' stdout='1:()'
+ ble/test 'ble/string#split-lines a "1" ; status' stdout='1:(1)'
+ ble/test 'ble/string#split-lines a "'"$nl"'" ; status' stdout='2:( )'
+ ble/test 'ble/string#split-lines a "1'"$nl"'" ; status' stdout='2:(1 )'
+ ble/test 'ble/string#split-lines a "'"$nl"'2" ; status' stdout='2:( 2)'
+ ble/test 'ble/string#split-lines a "1'"$nl$nl"'3" ; status' stdout='3:(1 3)'
+ ble/test 'ble/string#split-lines a "1'"$nl"'2'"$nl"'3"; status' stdout='3:(1 2 3)'
+ ble/test 'ble/string#split-lines a "1'"$ht"'2'"$ht"'3"; status' stdout="1:(1${ht}2${ht}3)"
+ ble/test 'ble/string#split-lines a "1 2 3"; status' stdout="1:(1 2 3)"
+)
+(
+ ble/test 'ble/string#count-char hello a' ret=0
+ ble/test 'ble/string#count-char hello あ' ret=0
+ ble/test 'ble/string#count-char hello e' ret=1
+ ble/test 'ble/string#count-char hello l' ret=2
+ ble/test 'ble/string#count-char hello olh' ret=4
+ ble/test 'ble/string#count-char hello hello' ret=5
+ ble/test 'ble/string#count-char "" a' ret=0
+ ble/test 'ble/string#count-char "" ab' ret=0
+)
+(
+ ble/test 'ble/string#count-string hello a' ret=0
+ ble/test 'ble/string#count-string hello あ' ret=0
+ ble/test 'ble/string#count-string hello ee' ret=0
+ ble/test 'ble/string#count-string hello e' ret=1
+ ble/test 'ble/string#count-string hello l' ret=2
+ ble/test 'ble/string#count-string hello ll' ret=1
+ ble/test 'ble/string#count-string hello hello' ret=1
+ ble/test 'ble/string#count-string "" a' ret=0
+ ble/test 'ble/string#count-string "" ab' ret=0
+ ble/test 'ble/string#count-string ababababa aba' ret=2
+)
+(
+ ble/test 'ble/string#index-of hello a' ret=-1
+ ble/test 'ble/string#index-of hello あ' ret=-1
+ ble/test 'ble/string#index-of hello ee' ret=-1
+ ble/test 'ble/string#index-of hello e' ret=1
+ ble/test 'ble/string#index-of hello l' ret=2
+ ble/test 'ble/string#index-of hello ll' ret=2
+ ble/test 'ble/string#index-of hello hello' ret=0
+ ble/test 'ble/string#index-of "" a' ret=-1
+ ble/test 'ble/string#index-of "" ab' ret=-1
+ ble/test 'ble/string#index-of ababababa aba' ret=0
+)
+(
+ ble/test 'ble/string#last-index-of hello a' ret=-1
+ ble/test 'ble/string#last-index-of hello あ' ret=-1
+ ble/test 'ble/string#last-index-of hello ee' ret=-1
+ ble/test 'ble/string#last-index-of hello e' ret=1
+ ble/test 'ble/string#last-index-of hello l' ret=3
+ ble/test 'ble/string#last-index-of hello ll' ret=2
+ ble/test 'ble/string#last-index-of hello hello' ret=0
+ ble/test 'ble/string#last-index-of "" a' ret=-1
+ ble/test 'ble/string#last-index-of "" ab' ret=-1
+ ble/test 'ble/string#last-index-of ababababa aba' ret=6
+)
+(
+ ble/test 'ble/string#toggle-case' ret=
+ ble/test 'ble/string#tolower ' ret=
+ ble/test 'ble/string#toupper ' ret=
+ ble/test 'ble/string#capitalize ' ret=
+ ble/test 'ble/string#toggle-case ""' ret=
+ ble/test 'ble/string#tolower ""' ret=
+ ble/test 'ble/string#toupper ""' ret=
+ ble/test 'ble/string#capitalize ""' ret=
+ ble/test 'ble/string#toggle-case a' ret=A
+ ble/test 'ble/string#tolower a' ret=a
+ ble/test 'ble/string#toupper a' ret=A
+ ble/test 'ble/string#capitalize a' ret=A
+ ble/test 'ble/string#toggle-case あ' ret=あ
+ ble/test 'ble/string#tolower あ' ret=あ
+ ble/test 'ble/string#toupper あ' ret=あ
+ ble/test 'ble/string#capitalize あ' ret=あ
+ ble/test 'ble/string#toggle-case +' ret=+
+ ble/test 'ble/string#tolower +' ret=+
+ ble/test 'ble/string#toupper +' ret=+
+ ble/test 'ble/string#capitalize +' ret=+
+ ble/test 'ble/string#toggle-case abc' ret=ABC
+ ble/test 'ble/string#tolower abc' ret=abc
+ ble/test 'ble/string#toupper abc' ret=ABC
+ ble/test 'ble/string#capitalize abc' ret=Abc
+ ble/test 'ble/string#toggle-case ABC' ret=abc
+ ble/test 'ble/string#tolower ABC' ret=abc
+ ble/test 'ble/string#toupper ABC' ret=ABC
+ ble/test 'ble/string#capitalize ABC' ret=Abc
+ ble/test 'ble/string#toggle-case aBc' ret=AbC
+ ble/test 'ble/string#tolower aBc' ret=abc
+ ble/test 'ble/string#toupper aBc' ret=ABC
+ ble/test 'ble/string#capitalize aBc' ret=Abc
+ ble/test 'ble/string#toggle-case +aBc' ret=+AbC
+ ble/test 'ble/string#tolower +aBc' ret=+abc
+ ble/test 'ble/string#toupper +aBc' ret=+ABC
+ ble/test 'ble/string#capitalize +aBc' ret=+Abc
+ ble/test 'ble/string#capitalize "hello world"' ret='Hello World'
+ LC_ALL=en_US.utf8
+ ble/test 'ble/string#toggle-case +aBc' ret=+AbC
+ ble/test 'ble/string#tolower +aBc' ret=+abc
+ ble/test 'ble/string#toupper +aBc' ret=+ABC
+ ble/test 'ble/string#capitalize +aBc' ret=+Abc
+ ble/test 'ble/string#capitalize "hello world"' ret='Hello World'
+)
+(
+ ble/test 'ble/string#trim ' ret=
+ ble/test 'ble/string#ltrim' ret=
+ ble/test 'ble/string#rtrim' ret=
+ ble/test 'ble/string#trim ""' ret=
+ ble/test 'ble/string#ltrim ""' ret=
+ ble/test 'ble/string#rtrim ""' ret=
+ ble/test 'ble/string#trim "a"' ret=a
+ ble/test 'ble/string#ltrim "a"' ret=a
+ ble/test 'ble/string#rtrim "a"' ret=a
+ ble/test 'ble/string#trim " a "' ret=a
+ ble/test 'ble/string#ltrim " a "' ret='a '
+ ble/test 'ble/string#rtrim " a "' ret=' a'
+ ble/test 'ble/string#trim " a b "' ret='a b'
+ ble/test 'ble/string#ltrim " a b "' ret='a b '
+ ble/test 'ble/string#rtrim " a b "' ret=' a b'
+ ble/test 'ble/string#trim "abc"' ret='abc'
+ ble/test 'ble/string#ltrim "abc"' ret='abc'
+ ble/test 'ble/string#rtrim "abc"' ret='abc'
+ ble/test 'ble/string#trim " abc "' ret='abc'
+ ble/test 'ble/string#ltrim " abc "' ret='abc '
+ ble/test 'ble/string#rtrim " abc "' ret=' abc'
+ for pad in $' \t\n \t\n' $'\t\t\t' $'\n\n\n'; do
+ ble/test 'ble/string#trim "'"$pad"'abc'"$pad"'"' ret='abc'
+ ble/test 'ble/string#ltrim "'"$pad"'abc'"$pad"'"' ret="abc${pad}"
+ ble/test 'ble/string#rtrim "'"$pad"'abc'"$pad"'"' ret="${pad}abc"
+ done
+)
+(
+ ble/test 'ble/string#escape-characters hello' ret=hello
+ ble/test 'ble/string#escape-characters hello ""' ret=hello
+ ble/test 'ble/string#escape-characters hello xyz' ret=hello
+ ble/test 'ble/string#escape-characters hello el' ret='h\e\l\lo'
+ ble/test 'ble/string#escape-characters hello hl XY' ret='\Xe\Y\Yo'
+ ble/test 'ble/string#escape-for-sed-regex "A\.[*?+|^\$(){}/"' \
+ ret='A\\\.\[\*?+|\^\$(){}\/'
+ ble/test 'ble/string#escape-for-awk-regex "A\.[*?+|^\$(){}/"' \
+ ret='A\\\.\[\*\?\+\|\^\$\(\)\{\}\/'
+ ble/test 'ble/string#escape-for-extended-regex "A\.[*?+|^\$(){}/"' \
+ ret='A\\\.\[\*\?\+\|\^\$\(\)\{\}/'
+ ble/test 'ble/string#escape-for-bash-glob "A\*?[("' ret='A\\\*\?\[\('
+ ble/test 'ble/string#escape-for-bash-single-quote "A'\''B"' ret="A'\''B"
+ ble/test 'ble/string#escape-for-bash-double-quote "hello \$ \` \\ ! world"' ret='hello \$ \` \\ "\!" world'
+ input=A$'\\\a\b\e\f\n\r\t\v'\'B output=A'\\\a\b\e\f\n\r\t\v\'\'B
+ ble/test 'ble/string#escape-for-bash-escape-string "$input"' ret="$output"
+ ble/test 'ble/string#escape-for-bash-specialchars "[hello] (world) {this,is} <test>"' \
+ ret='\[hello\]\ \(world\)\ {this,is}\ \<test\>'
+ ble/test 'ble/string#escape-for-bash-specialchars "[hello] (world) {this,is} <test>" b' \
+ ret='\[hello\]\ \(world\)\ \{this\,is\}\ \<test\>'
+ ble/test 'ble/string#escape-for-bash-specialchars "a=b:c:d" c' \
+ ret='a\=b\:c\:d'
+ ble/test $'ble/string#escape-for-bash-specialchars "a\tb\tc"' \
+ ret=$'a\\\tb\\\tc'
+)
+(
+ ble/test 'ble/string#quote-command' ret=
+ ble/test 'ble/string#quote-command echo' ret='echo'
+ ble/test 'ble/string#quote-command echo hello world' ret="echo 'hello' 'world'"
+ ble/test 'ble/string#quote-command echo "hello world"' ret="echo 'hello world'"
+ ble/test 'ble/string#quote-command echo "'\''test'\''"' ret="echo ''\''test'\'''"
+ ble/test 'ble/string#quote-command echo "" "" ""' ret="echo '' '' ''"
+ ble/test 'ble/string#quote-command echo a{1..4}' ret="echo 'a1' 'a2' 'a3' 'a4'"
+ ble/test 'ble/util/print-quoted-command' stdout=
+ ble/test 'ble/util/print-quoted-command echo' stdout='echo'
+ ble/test 'ble/util/print-quoted-command echo hello world' stdout="echo 'hello' 'world'"
+ ble/test 'ble/util/print-quoted-command echo "hello world"' stdout="echo 'hello world'"
+ ble/test 'ble/util/print-quoted-command echo "'\''test'\''"' stdout="echo ''\''test'\'''"
+ ble/test 'ble/util/print-quoted-command echo "" "" ""' stdout="echo '' '' ''"
+ ble/test 'ble/util/print-quoted-command echo a{1..4}' stdout="echo 'a1' 'a2' 'a3' 'a4'"
+)
+(
+ ble/test 'ble/string#quote-word' ret=
+ ble/test 'ble/string#quote-word echo' ret='echo'
+ ble/test 'ble/string#quote-word "hello world"' ret="'hello world'"
+ ble/test 'ble/string#quote-word "'\''test'\''"' ret="\'test\'"
+ ble/test 'ble/string#quote-word "a'\''b'\''c"' ret="a\'b\'c"
+)
+(
+ ble/test 'ble/string#create-unicode-progress-bar 0 24 3' ret=' '
+ ble/test 'ble/string#create-unicode-progress-bar 1 24 3' ret='▏ '
+ ble/test 'ble/string#create-unicode-progress-bar 2 24 3' ret='▎ '
+ ble/test 'ble/string#create-unicode-progress-bar 3 24 3' ret='▍ '
+ ble/test 'ble/string#create-unicode-progress-bar 4 24 3' ret='▌ '
+ ble/test 'ble/string#create-unicode-progress-bar 5 24 3' ret='▋ '
+ ble/test 'ble/string#create-unicode-progress-bar 6 24 3' ret='▊ '
+ ble/test 'ble/string#create-unicode-progress-bar 7 24 3' ret='▉ '
+ ble/test 'ble/string#create-unicode-progress-bar 8 24 3' ret='█ '
+ ble/test 'ble/string#create-unicode-progress-bar 9 24 3' ret='█▏ '
+ ble/test 'ble/string#create-unicode-progress-bar 15 24 3' ret='█▉ '
+ ble/test 'ble/string#create-unicode-progress-bar 16 24 3' ret='██ '
+ ble/test 'ble/string#create-unicode-progress-bar 17 24 3' ret='██▏'
+ ble/test 'ble/string#create-unicode-progress-bar 24 24 3' ret='███'
+ ble/test 'ble/string#create-unicode-progress-bar 0 24 4 unlimited' ret=$'█ '
+ ble/test 'ble/string#create-unicode-progress-bar 1 24 4 unlimited' ret=$'\e[7m▏\e[27m▏ '
+ ble/test 'ble/string#create-unicode-progress-bar 2 24 4 unlimited' ret=$'\e[7m▎\e[27m▎ '
+ ble/test 'ble/string#create-unicode-progress-bar 3 24 4 unlimited' ret=$'\e[7m▍\e[27m▍ '
+ ble/test 'ble/string#create-unicode-progress-bar 4 24 4 unlimited' ret=$'\e[7m▌\e[27m▌ '
+ ble/test 'ble/string#create-unicode-progress-bar 5 24 4 unlimited' ret=$'\e[7m▋\e[27m▋ '
+ ble/test 'ble/string#create-unicode-progress-bar 6 24 4 unlimited' ret=$'\e[7m▊\e[27m▊ '
+ ble/test 'ble/string#create-unicode-progress-bar 7 24 4 unlimited' ret=$'\e[7m▉\e[27m▉ '
+ ble/test 'ble/string#create-unicode-progress-bar 8 24 4 unlimited' ret=$' █ '
+ ble/test 'ble/string#create-unicode-progress-bar 9 24 4 unlimited' ret=$' \e[7m▏\e[27m▏ '
+ ble/test 'ble/string#create-unicode-progress-bar 15 24 4 unlimited' ret=$' \e[7m▉\e[27m▉ '
+ ble/test 'ble/string#create-unicode-progress-bar 16 24 4 unlimited' ret=$' █ '
+ ble/test 'ble/string#create-unicode-progress-bar 17 24 4 unlimited' ret=$' \e[7m▏\e[27m▏'
+ ble/test 'ble/string#create-unicode-progress-bar 24 24 4 unlimited' ret=$'█ '
+)
+(
+ ble/test 'ble/util/strlen' ret=0
+ ble/test 'ble/util/strlen ""' ret=0
+ ble/test 'ble/util/strlen a' ret=1
+ ble/test 'ble/util/strlen abc' ret=3
+ ble/test 'ble/util/strlen α' ret=2
+ ble/test 'ble/util/strlen αβγ' ret=6
+ ble/test 'ble/util/strlen あ' ret=3
+ ble/test 'ble/util/strlen あいう' ret=9
+ ble/test 'ble/util/strlen aα' ret=3
+ ble/test 'ble/util/strlen aαあ' ret=6
+ LC_ALL=en_US.utf8
+ ble/test 'ble/util/strlen a' ret=1
+ ble/test 'ble/util/strlen α' ret=2
+ ble/test 'ble/util/strlen あ' ret=3
+)
+(
+ ble/test 'ble/util/substr' ret=
+ ble/test 'ble/util/substr ""' ret=
+ ble/test 'ble/util/substr a' ret=
+ ble/test 'ble/util/substr "" 0' ret=
+ ble/test 'ble/util/substr "" 1' ret=
+ ble/test 'ble/util/substr a 0' ret=
+ ble/test 'ble/util/substr a 1' ret=
+ ble/test 'ble/util/substr a 2' ret=
+ ble/test 'ble/util/substr "" 0 0' ret=
+ ble/test 'ble/util/substr "" 0 1' ret=
+ ble/test 'ble/util/substr "" 1 1' ret=
+ ble/test 'ble/util/substr a 0 0' ret=
+ ble/test 'ble/util/substr a 1 0' ret=
+ ble/test 'ble/util/substr a 0 1' ret=a
+ ble/test 'ble/util/substr a 1 1' ret=
+ ble/test 'ble/util/substr abc 1 0' ret=
+ ble/test 'ble/util/substr abc 1 1' ret=b
+ ble/test 'ble/util/substr abc 1 2' ret=bc
+ ble/test 'ble/util/substr abc 0 0' ret=
+ ble/test 'ble/util/substr abc 0 1' ret=a
+ ble/test 'ble/util/substr abc 0 3' ret=abc
+ ble/test 'ble/util/substr abc 0 4' ret=abc
+ ble/test 'ble/util/substr abc 3 0' ret=
+ ble/test 'ble/util/substr abc 3 1' ret=
+ ble/test 'ble/util/substr abc 4 0' ret=
+ ble/test 'ble/util/substr abc 4 1' ret=
+ ble/test 'ble/util/substr あいう 0 3' ret=あ
+ ble/test 'ble/util/substr あいう 3 6' ret=いう
+ ble/test 'ble/util/substr あいう 0 1' ret=$'\xe3'
+ ble/test 'ble/util/substr あいう 1 2' ret=$'\x81\x82'
+ ble/test 'ble/util/substr あいう 1 4' ret=$'\x81\x82\xe3\x81'
+ ble/test 'ble/util/substr あいう 7 5' ret=$'\x81\x86'
+)
+(
+ for cmd in ble/path#{remove,remove-glob}; do
+ ble/test code:'ret=; '$cmd' ret' ret=
+ ble/test code:'ret=; '$cmd' ret ""' ret=
+ ble/test code:'ret=a; '$cmd' ret ""' ret=a
+ ble/test code:'ret=a; '$cmd' ret a' ret=
+ ble/test code:'ret=a; '$cmd' ret b' ret=a
+ ble/test code:'ret=a:a:a; '$cmd' ret a' ret=
+ ble/test code:'ret=aa; '$cmd' ret a' ret=aa
+ ble/test code:'ret=xyz:abc; '$cmd' ret ""' ret=xyz:abc
+ ble/test code:'ret=xyz:abc; '$cmd' ret xyz' ret=abc
+ ble/test code:'ret=xyz:abc; '$cmd' ret abc' ret=xyz
+ ble/test code:'ret=xyz:abc:tuv; '$cmd' ret xyz' ret=abc:tuv
+ ble/test code:'ret=xyz:abc:tuv; '$cmd' ret abc' ret=xyz:tuv
+ ble/test code:'ret=xyz:abc:tuv; '$cmd' ret tuv' ret=xyz:abc
+ ble/test code:'ret=xyz:xyz; '$cmd' ret xyz' ret=
+ ble/test code:'ret=xyz:abc:xyz; '$cmd' ret xyz' ret=abc
+ ble/test code:'ret=xyz:abc:xyz; '$cmd' ret abc' ret=xyz:xyz
+ ble/test code:'ret=xyz:xyz:xyz; '$cmd' ret xyz' ret=
+ done
+ ble/test code:'ret=a; ble/path#remove ret \?' ret=a
+ ble/test code:'ret=aa; ble/path#remove ret \?' ret=aa
+ ble/test code:'ret=a:b; ble/path#remove ret \?' ret=a:b
+ ble/test code:'ret=a:b:c; ble/path#remove ret \?' ret=a:b:c
+ ble/test code:'ret=aa:b:cc; ble/path#remove ret \?' ret=aa:b:cc
+ ble/test code:'ret=stdX:stdY:usrZ; ble/path#remove ret "std[a-zX-Z]"' ret=stdX:stdY:usrZ
+ ble/test code:'ret=stdX:usrZ:stdY; ble/path#remove ret "std[a-zX-Z]"' ret=stdX:usrZ:stdY
+ ble/test code:'ret=usrZ:stdX:stdY; ble/path#remove ret "std[a-zX-Z]"' ret=usrZ:stdX:stdY
+ ble/test code:'ret=a; ble/path#remove-glob ret \?' ret=
+ ble/test code:'ret=aa; ble/path#remove-glob ret \?' ret=aa
+ ble/test code:'ret=a:b; ble/path#remove-glob ret \?' ret=
+ ble/test code:'ret=a:b:c; ble/path#remove-glob ret \?' ret=
+ ble/test code:'ret=aa:b:cc; ble/path#remove-glob ret \?' ret=aa:cc
+ ble/test code:'ret=stdX:stdY:usrZ; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ
+ ble/test code:'ret=stdX:usrZ:stdY; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ
+ ble/test code:'ret=usrZ:stdX:stdY; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ
+)
+(
+ ble/test code:'ret=; ble/path#append ret a' ret=a
+ ble/test code:'ret=a; ble/path#append ret a' ret=a:a
+ ble/test code:'ret=a; ble/path#append ret b' ret=a:b
+ ble/test code:'ret=a:b; ble/path#append ret cd' ret=a:b:cd
+ ble/test code:'ret=; ble/path#prepend ret a' ret=a
+ ble/test code:'ret=a; ble/path#prepend ret a' ret=a:a
+ ble/test code:'ret=a; ble/path#prepend ret b' ret=b:a
+ ble/test code:'ret=a:b; ble/path#prepend ret cd' ret=cd:a:b
+ ble/test code:'ret=a:b:c; ble/path#contains ret a'
+ ble/test code:'ret=a:b:c; ble/path#contains ret b'
+ ble/test code:'ret=a:b:c; ble/path#contains ret c'
+ ble/test code:'ret=a:b:c; ! ble/path#contains ret x'
+ ble/test code:'ret=a:b:c; ! ble/path#contains ret aa'
+ ble/test code:'ret=a:b:c; ! ble/path#contains ret bb'
+ ble/test code:'ret=a:b:c; ! ble/path#contains ret cc'
+ ble/test code:'ret=a:b:c; ! ble/path#contains ret "?"'
+ ble/test code:'ret=a:b:c; ! ble/path#contains ret "*"'
+ ble/test code:'ret=abc:def; ble/path#contains ret abc'
+ ble/test code:'ret=abc:def; ble/path#contains ret def'
+ ble/test code:'ret=abc:def; ! ble/path#contains ret a'
+ ble/test code:'ret=abc:def; ! ble/path#contains ret ab'
+ ble/test code:'ret=abc:def; ! ble/path#contains ret abcdef'
+ ble/test code:'ret=abc:def; ! ble/path#contains ret "???"'
+ ble/test code:'ret=xyz; ble/path#contains ret xyz'
+ ble/test code:'ret=xyz; ! ble/path#contains ret xyz:xyz'
+ ble/test code:'ret=xyz; ! ble/path#contains ret "???"'
+)
+(
+ builtin eval -- "${_ble_util_dict_declare//NAME/dict1}"
+ builtin eval -- "${_ble_util_gdict_declare//NAME/dict2}"
+ builtin eval -- "${_ble_util_adict_declare//NAME/dict3}"
+ index=1
+ for Dict in ble/{,g,a}dict; do
+ dict=dict$((index++))
+ ret=unchanged
+ ble/test '! '$Dict'#has '$dict' banana' ret=unchanged
+ ble/test '! '$Dict'#has '$dict' ""' ret=unchanged
+ $Dict#set $dict apple red
+ $Dict#set $dict banana yellow
+ $Dict#set $dict orange orange
+ $Dict#set $dict melon green
+ ret=unchanged
+ ble/test $Dict'#has '$dict' banana' ret=unchanged # 先頭
+ ble/test $Dict'#has '$dict' apple' ret=unchanged # 中
+ ble/test $Dict'#has '$dict' melon' ret=unchanged # 末尾
+ ble/test '! '$Dict'#has '$dict' pear' ret=unchanged # 存在しない項目
+ ble/test $Dict'#get '$dict' banana' ret=yellow # 先頭
+ ble/test $Dict'#get '$dict' apple' ret=red # 中
+ ble/test $Dict'#get '$dict' melon' ret=green # 末尾
+ ble/test '! '$Dict'#get '$dict' pear' ret= # 存在しない項目
+ ble/test '! '$Dict'#has '$dict' ""' # 末尾空要素で引けるか
+ ble/test '! '$Dict'#get '$dict' ""' # 末尾空要素で引けるか
+ $Dict#set $dict '' transparent
+ ble/test $Dict'#has '$dict' ""' # 末尾空要素で引けるか
+ ble/test $Dict'#get '$dict' ""' ret=transparent # 末尾空要素で引けるか
+ $Dict#set $dict 'alpha beta' pink
+ ble/test $Dict'#has '$dict' ""' # 中央空要素で引けるか
+ ble/test $Dict'#has '$dict' "alpha beta"' # 空白を含む見出し
+ ble/test $Dict'#get '$dict' ""' ret=transparent # 中央空要素で引けるか
+ ble/test $Dict'#get '$dict' "alpha beta"' ret=pink # 空白を含む見出し
+ $Dict#set $dict ' apple ' ' red '
+ ble/test $Dict'#has '$dict' " apple "' # 空白で trim されないか
+ ble/test $Dict'#has '$dict' apple' # 既存項目を破壊していないか
+ ble/test $Dict'#get '$dict' " apple "' ret=' red ' # 空白で trim されないか
+ ble/test $Dict'#get '$dict' apple' ret=red # 既存項目を破壊していないか
+ ble/test '! '$Dict'#has '$dict' "${_ble_term_FS}"' # 単一FS
+ ble/test '! '$Dict'#has '$dict' ":"' # 単一コロン
+ ble/test '! '$Dict'#has '$dict' "apple${_ble_term_FS}banana"' # FSを含む見出し
+ ble/test '! '$Dict'#has '$dict' apple:banana' # コロンを含む見出し
+ ble/test '! '$Dict'#get '$dict' "${_ble_term_FS}"' ret= # 単一FS
+ ble/test '! '$Dict'#get '$dict' ":"' ret= # 単一コロン
+ ble/test '! '$Dict'#get '$dict' "apple${_ble_term_FS}banana"' ret= # FSを含む見出し
+ ble/test '! '$Dict'#get '$dict' apple:banana' ret= # コロンを含む見出し
+ $Dict#set $dict "${_ble_term_FS}" Empty
+ $Dict#set $dict ":" Colon
+ $Dict#set $dict "apple${_ble_term_FS}banana" RedYellow
+ $Dict#set $dict "apple:banana" __red_yellow__
+ ble/test $Dict'#has '$dict' "${_ble_term_FS}"' # 単一FS
+ ble/test $Dict'#has '$dict' ":"' # 単一コロン
+ ble/test $Dict'#has '$dict' "apple${_ble_term_FS}banana"' # FSを含む見出し
+ ble/test $Dict'#has '$dict' apple:banana' # コロンを含む見出し
+ ble/test $Dict'#get '$dict' "${_ble_term_FS}"' ret=Empty # 単一FS
+ ble/test $Dict'#get '$dict' ":"' ret=Colon # 単一コロン
+ ble/test $Dict'#get '$dict' "apple${_ble_term_FS}banana"' ret=RedYellow # FSを含む見出し
+ ble/test $Dict'#get '$dict' apple:banana' ret=__red_yellow__ # コロンを含む見出し
+ $Dict#unset $dict banana
+ $Dict#unset $dict apple
+ $Dict#unset $dict melon
+ ble/test '! '$Dict'#has '$dict' banana'
+ ble/test '! '$Dict'#has '$dict' apple'
+ ble/test '! '$Dict'#has '$dict' melon'
+ $Dict#unset $dict ""
+ $Dict#unset $dict "alpha beta"
+ $Dict#unset $dict " apple "
+ ble/test '! '$Dict'#has '$dict' ""' # 中央空要素で引けるか
+ ble/test '! '$Dict'#has '$dict' "alpha beta"' # 空白を含む見出し
+ ble/test '! '$Dict'#has '$dict' " apple "' # 空白で trim されないか
+ $Dict#unset $dict "${_ble_term_FS}"
+ $Dict#unset $dict ":"
+ $Dict#unset $dict "apple${_ble_term_FS}banana"
+ $Dict#unset $dict apple:banana
+ ble/test '! '$Dict'#has '$dict' "${_ble_term_FS}"' # 単一FS
+ ble/test '! '$Dict'#has '$dict' ":"' # 単一コロン
+ ble/test '! '$Dict'#has '$dict' "apple${_ble_term_FS}banana"' # FSを含む見出し
+ ble/test '! '$Dict'#has '$dict' apple:banana' # コロンを含む見出し
+ done
+)
+(
+ blehook/declare FOO
+ ble/test 'blehook --color=never FOO' stdout='blehook FOO='
+ ble/test 'blehook/has-hook FOO' exit=1
+ blehook FOO+='echo hello'
+ ble/test 'blehook --color=never FOO' \
+ stdout="blehook FOO+='echo hello'"
+ ble/test 'blehook/has-hook FOO'
+ blehook FOO+='echo world'
+ ble/test 'blehook --color=never FOO' \
+ stdout="blehook FOO+='echo hello'" \
+ stdout="blehook FOO+='echo world'"
+ ble/test 'blehook/has-hook FOO'
+ blehook FOO-='echo hello'
+ ble/test 'blehook --color=never FOO' \
+ stdout="blehook FOO+='echo world'"
+ ble/test 'blehook/has-hook FOO'
+ blehook FOO-='echo world'
+ ble/test 'blehook --color=never FOO' \
+ stdout='blehook FOO='
+ ble/test 'blehook/has-hook FOO' exit=1
+ blehook FOO+='echo hello'
+ blehook FOO+='echo world'
+ blehook FOO='echo empty'
+ ble/test 'blehook --color=never FOO' \
+ stdout="blehook FOO+='echo empty'"
+ ble/test 'blehook/has-hook FOO'
+ blehook FOO+='echo hello'
+ blehook FOO+='echo world'
+ blehook FOO=
+ ble/test 'blehook --color=never FOO' \
+ stdout='blehook FOO='
+ ble/test 'blehook/has-hook FOO' exit=1
+ blehook FOO+='echo hello'
+ blehook FOO+='echo world'
+ blehook FOO!='echo hello'
+ ble/test 'blehook --color=never FOO' \
+ stdout="blehook FOO+='echo hello'${_ble_term_nl}blehook FOO+='echo world'"
+ blehook FOO-+='echo hello'
+ ble/test 'blehook --color=never FOO' \
+ stdout="blehook FOO+='echo world'${_ble_term_nl}blehook FOO+='echo hello'"
+ blehook FOO+-='echo hello'
+ ble/test 'blehook --color=never FOO' \
+ stdout="blehook FOO+='echo hello'${_ble_term_nl}blehook FOO+='echo world'"
+ blehook FOO=
+ blehook FOO+='echo hello'
+ blehook FOO+='echo empty'
+ blehook FOO+='echo world'
+ ble/test 'blehook/invoke FOO' \
+ stdout=hello \
+ stdout=empty \
+ stdout=world
+ blehook FOO='echo A$?'
+ blehook FOO+='echo B$?'
+ blehook FOO+='echo C$?'
+ ble/test 'ble/util/setexit 123; blehook/invoke FOO' \
+ stdout=A123 \
+ stdout=B123 \
+ stdout=C123
+ blehook/declare bar_load
+ blehook bar_load='echo bar_load'
+ ble/test 'blehook/eval-after-load bar "echo yes"' stdout=
+ ble/test 'blehook/invoke bar_load' \
+ stdout=bar_load \
+ stdout=yes
+ ble/test 'blehook/eval-after-load bar "echo next"' stdout=next
+ function func { ret="[$1]"; }
+ blehook FOO=func
+ ble/test 'blehook/invoke FOO xQAHbcpMFyFyQ' ret='[xQAHbcpMFyFyQ]'
+)
+(
+ ble/builtin/trap 'echo TRAPEXIT1' 0
+ ble/test 'ble/builtin/trap/invoke 0' stdout=TRAPEXIT1
+ ble/test 'ble/builtin/trap/invoke EXIT' stdout=TRAPEXIT1
+ ble/builtin/trap 0
+ ble/test 'ble/builtin/trap/invoke 0' stdout=
+ ble/builtin/trap 'echo TRAPEXIT2' EXIT
+ ble/test 'ble/builtin/trap/invoke 0' stdout=TRAPEXIT2
+ ble/test 'ble/builtin/trap/invoke EXIT' stdout=TRAPEXIT2
+ ble/builtin/trap EXIT
+ ble/test 'ble/builtin/trap/invoke 0' stdout=
+ ble/builtin/trap 'echo TRAPHUP1' 1
+ ble/test 'ble/builtin/trap/invoke 1' stdout=TRAPHUP1
+ ble/test 'ble/builtin/trap/invoke HUP' stdout=TRAPHUP1
+ ble/test 'ble/builtin/trap/invoke SIGHUP' stdout=TRAPHUP1
+ ble/builtin/trap 1
+ ble/test 'ble/builtin/trap/invoke 1' stdout=
+ ble/builtin/trap 'echo TRAPHUP2' HUP
+ ble/test 'ble/builtin/trap/invoke 1' stdout=TRAPHUP2
+ ble/test 'ble/builtin/trap/invoke HUP' stdout=TRAPHUP2
+ ble/test 'ble/builtin/trap/invoke SIGHUP' stdout=TRAPHUP2
+ ble/builtin/trap HUP
+ ble/test 'ble/builtin/trap/invoke HUP' stdout=
+ ble/builtin/trap 'echo TRAPHUP3' SIGHUP
+ ble/test 'ble/builtin/trap/invoke 1' stdout=TRAPHUP3
+ ble/test 'ble/builtin/trap/invoke HUP' stdout=TRAPHUP3
+ ble/test 'ble/builtin/trap/invoke SIGHUP' stdout=TRAPHUP3
+ ble/builtin/trap SIGHUP
+ ble/test 'ble/builtin/trap/invoke HUP' stdout=
+ ble/builtin/trap/.register 9999 CUSTOM
+ ble/builtin/trap/reserve CUSTOM
+ ble/builtin/trap 'echo custom trap' CUSTOM
+ ble/test 'ble/builtin/trap/invoke CUSTOM' stdout='custom trap'
+ function ble/builtin/trap:CUSTOM { echo "__set_handler__ ($2) $1"; }
+ ble/test 'ble/builtin/trap "echo hello world" CUSTOM' \
+ stdout='__set_handler__ (CUSTOM) echo hello world'
+ ble/test 'ble/builtin/trap/invoke CUSTOM' stdout='hello world'
+)
+(
+ ble/test 'ble/util/readfile ret <(echo hello)' \
+ ret=hello$'\n'
+ ble/test 'ble/util/readfile ret <(echo hello; echo world)' \
+ ret=hello$'\n'world$'\n'
+ ble/test 'ble/util/readfile ret <(echo hello; echo -n world)' \
+ ret=hello$'\n'world
+ ble/test 'ble/util/readfile ret <(:)' ret=
+ function status { echo "${#a[*]}:(""${a[*]}"")"; }
+ ble/test "ble/util/mapfile a < <(echo hello); status" stdout='1:(hello)'
+ ble/test "ble/util/mapfile a < <(echo -n hello); status" stdout='1:(hello)'
+ ble/test "ble/util/mapfile a < <(echo hello; echo world); status" stdout='2:(hello world)'
+ ble/test "ble/util/mapfile a < <(echo hello; echo -n world); status" stdout='2:(hello world)'
+ ble/test "ble/util/mapfile a < <(printf '%s\n' h1 h2 h3 h4); status" stdout='4:(h1 h2 h3 h4)'
+ ble/test "ble/util/mapfile a < <(:); status" stdout='0:()'
+ ble/test "ble/util/mapfile a < <(echo); status" stdout='1:()'
+ ble/test "ble/util/mapfile a < <(echo;echo); status" stdout='2:( )'
+ ble/test "ble/util/mapfile a < <(echo a;echo;echo b); status" stdout='3:(a b)'
+ nl=$'\n'
+ ble/test 'ble/util/assign ret ""' ret=
+ ble/test 'ble/util/assign ret ":"' ret=
+ ble/test 'ble/util/assign ret "echo"' ret=
+ ble/test 'ble/util/assign ret "echo hello"' ret=hello
+ ble/test 'ble/util/assign ret "seq 5"' ret="1${nl}2${nl}3${nl}4${nl}5"
+ function f1 { echo stdout; echo stderr >&2; }
+ function nested-assign {
+ ble/util/assign err 'ble/util/assign out f1 2>&1'
+ echo "out=$out err=$err"
+ }
+ ble/test nested-assign stdout='out=stdout err=stderr'
+ ble/test 'ble/util/assign-array a :; status' stdout='0:()'
+ ble/test 'ble/util/assign-array a echo; status' stdout='1:()'
+ ble/test 'ble/util/assign-array a "echo hello"; status' stdout='1:(hello)'
+ ble/test 'ble/util/assign-array a "seq 5"; status' stdout='5:(1 2 3 4 5)'
+ ble/test 'ble/util/assign-array a "echo; echo; echo"; status' stdout='3:( )'
+ ble/test 'ble/util/assign-array a "echo 1; echo; echo 2"; status' stdout='3:(1 2)'
+)
+(
+ x=($'\177' $'\1' $'\2' $'\32' ' ' $'\a' $'\b' $'\t' $'\n' $'\v' $'\f' $'\r' a \" \' \$ \! \` \~)
+ x[0]=$'\177'
+ x[1]=$'\1'
+ ble/test "ble/util/writearray -d '' x | sha256sum | awk '{print \$1}'" stdout=$(printf '%s\0' "${x[@]}" | sha256sum | awk '{print $1}')
+)
+(
+ var=variable
+ alias ali=fun
+ function fun { echo yes "$*"; }
+ function ble/fun { echo yes "$*"; return 99; }
+ function ble/fun:type { echo yes "$*"; return 100; }
+ function ble/fun#meth { echo yes "$*"; return 101; }
+ ble/test 'ble/is-function' exit=1
+ ble/test 'ble/is-function ""' exit=1
+ ble/test 'ble/is-function fun'
+ ble/test 'ble/is-function ble/fun'
+ ble/test 'ble/is-function ble/fun:type'
+ ble/test 'ble/is-function ble/fun#meth'
+ ble/test 'ble/is-function fun1' exit=1
+ ble/test 'ble/is-function ble/fun1' exit=1
+ ble/test 'ble/is-function ble/fun1:type' exit=1
+ ble/test 'ble/is-function ble/fun1#meth' exit=1
+ ble/test 'ble/is-function ali' exit=1
+ ble/test 'ble/is-function var' exit=1
+ ble/test 'ble/is-function compgen' exit=1
+ ble/test 'ble/is-function declare' exit=1
+ ble/test 'ble/is-function mkfifo' exit=1
+ function compgen { :; }
+ function declare { :; }
+ function mkfifo { :; }
+ ble/test 'ble/is-function compgen'
+ ble/test 'ble/is-function declare'
+ ble/test 'ble/is-function mkfifo'
+ ble/test 'ble/function#try fun 1 2 3' stdout='yes 1 2 3'
+ ble/test 'ble/function#try ble/fun 1 2 3' stdout='yes 1 2 3' exit=99
+ ble/test 'ble/function#try ble/fun:type 1 2 3' stdout='yes 1 2 3' exit=100
+ ble/test 'ble/function#try ble/fun#meth 1 2 3' stdout='yes 1 2 3' exit=101
+ ble/test 'ble/function#try fun1 1 2 3' stdout= exit=127
+ ble/test 'ble/function#try ble/fun1 1 2 3' stdout= exit=127
+ ble/test 'ble/function#try ble/fun1:type 1 2 3' stdout= exit=127
+ ble/test 'ble/function#try ble/fun1#meth 1 2 3' stdout= exit=127
+)
+(
+ function f1 { echo original $*; }
+ ble/test f1 stdout='original'
+ ble/function#advice before f1 'echo pre'
+ ble/test f1 stdout={pre,original}
+ ble/function#advice after f1 'echo post'
+ ble/test f1 stdout={pre,original,post}
+ ble/function#advice before f1 'echo A'
+ ble/test f1 stdout={A,original,post}
+ ble/function#advice after f1 'echo B'
+ ble/test f1 stdout={A,original,B}
+ ble/function#advice around f1 'echo [; ble/function#advice/do; echo ]'
+ ble/test f1 stdout={A,[,original,],B}
+ ble/function#advice around f1 '
+ ADVICE_WORDS[1]=quick
+ echo [; ble/function#advice/do; echo ]
+ ADVICE_EXIT=99'
+ ble/test f1 stdout={A,[,'original quick',],B} exit=99
+ ble/function#advice remove f1
+ ble/test f1 stdout='original' exit=0
+ ble/test 'f1 1' stdout='original 1' exit=0
+)
+(
+ ble/test 'echo 1 2 3' stdout='1 2 3'
+ ble/test 'ble/is-function echo' exit=1
+ ble/function#push echo 'builtin echo "[$*]"'
+ ble/test 'ble/is-function echo'
+ ble/test 'echo 1 2 3' stdout='[1 2 3]'
+ ble/function#push echo 'builtin echo "($*)"'
+ ble/test 'echo 1 2 3' stdout='(1 2 3)'
+ ble/function#push echo 'builtin echo A; ble/function#push/call-top "$@"; builtin echo Z'
+ ble/test 'echo 1 2 3' stdout={A,'(1 2 3)',Z}
+ ble/function#push echo 'builtin echo [; ble/function#push/call-top "$@"; builtin echo ]'
+ ble/test 'echo 1 2 3' stdout={[,A,'(1 2 3)',Z,]}
+ ble/test 'ble/function#pop echo'
+ ble/test 'echo 1 2 3' stdout={A,'(1 2 3)',Z}
+ ble/function#pop echo
+ ble/test 'echo 1 2 3' stdout='(1 2 3)'
+ ble/function#pop echo
+ ble/test 'echo 1 2 3' stdout='[1 2 3]'
+ ble/test 'ble/is-function echo'
+ ble/test 'ble/function#pop echo'
+ ble/test 'ble/is-function echo' exit=1
+ ble/test 'echo 1 2 3' stdout='1 2 3'
+ ble/test 'ble/function#pop echo' exit=1
+ ble/test 'echo 1 2 3' stdout='1 2 3'
+)
+(
+ ble/test 'ble/util/set ret hello' ret='hello'
+ ble/test 'ble/util/set ret "hello world"' ret='hello world'
+ ble/test 'ble/util/set ret ""' ret=''
+ ble/test 'ble/util/set ret " "' ret=' '
+ ble/test 'ble/util/set ret " a"' ret=' a'
+ ble/test 'ble/util/set ret "a "' ret='a '
+ ble/test 'ble/util/set ret $'\''\n'\''' ret=$'\n'
+ ble/test 'ble/util/set ret A$'\''\n'\''' ret=A$'\n'
+ ble/test 'ble/util/set ret A$'\''\n'\''B' ret=A$'\n'B
+)
+(
+ ble/test 'ble/util/sprintf ret "[%s]" 1 2 3' ret='[1][2][3]'
+ ble/test 'ble/util/sprintf ret "[%5s]" 1' ret='[ 1]'
+ ble/test 'ble/util/sprintf ret "[%.2s]" 12345' ret='[12]'
+ ble/test 'ble/util/sprintf ret "[%d,%d]" 1 3' ret='[1,3]'
+ ble/test 'ble/util/sprintf ret "[%x]" 27' ret='[1b]'
+ ble/test 'ble/util/sprintf ret "[%#.2g]" 27' ret='[27.]'
+ ble/test 'ble/util/sprintf ret "[%#.2f]" 27' ret='[27.00]'
+)
+(
+ shopt -s expand_aliases
+ alias aaa=fun
+ function fun { :; }
+ function ble/fun { :; }
+ function ble/fun:type { :; }
+ function ble/fun#meth { :; }
+ ble/test 'ble/util/type ret aaa' ret=alias
+ ble/test 'ble/util/type ret fun' ret=function
+ ble/test 'ble/util/type ret alias' ret=builtin
+ ble/test 'ble/util/type ret mkfifo' ret=file
+ ble/test 'ble/util/type ret for' ret=keyword
+ ble/test 'ble/util/type ret ble/fun' ret=function
+ ble/test 'ble/util/type ret ble/fun:type' ret=function
+ ble/test 'ble/util/type ret ble/fun#meth' ret=function
+ ble/test 'ble/util/type ret fun1' ret=
+ ble/test 'ble/util/type ret ble/fun1' ret=
+ ble/test 'ble/util/type ret ble/fun1:type' ret=
+ ble/test 'ble/util/type ret ble/fun1#meth' ret=
+)
+(
+ shopt -s expand_aliases
+ alias aaa1='aaa2 world'
+ ble/test 'ble/alias#expand aaa1' ret='aaa2 world'
+ alias aaa2='aaa3 hello'
+ ble/test 'ble/alias#expand aaa2' ret='aaa3 hello'
+ ble/test 'ble/alias#expand aaa1' ret='aaa2 world'
+ alias aaa3='aaa4'
+ ble/test 'ble/alias#expand aaa3' ret='aaa4'
+ ble/test 'ble/alias#expand aaa2' ret='aaa3 hello'
+ ble/test 'ble/alias#expand aaa1' ret='aaa2 world'
+ alias aaa4='echo'
+ ble/test 'ble/alias#expand aaa4' ret='echo'
+ ble/test 'ble/alias#expand aaa3' ret='aaa4'
+ ble/test 'ble/alias#expand aaa2' ret='aaa3 hello'
+ ble/test 'ble/alias#expand aaa1' ret='aaa2 world'
+)
+if ((_ble_bash>=40000)); then
+ (
+ ble/test 'echo 1 | { sleep 0.01; ble/util/is-stdin-ready; }'
+ ble/test 'sleep 0.01 | ble/util/is-stdin-ready' exit=1
+ ble/test 'ble/util/is-stdin-ready <<< a'
+ ble/test 'ble/util/is-stdin-ready <<< ""'
+ ble/test ': | { sleep 0.01; ble/util/is-stdin-ready; }'
+ ble/test 'ble/util/is-stdin-ready < /dev/null'
+ )
+fi
+ble/test ble/util/is-running-in-subshell exit=1
+( ble/test ble/util/is-running-in-subshell )
+(
+ ble/test/chdir
+ function getpid {
+ sh -c 'echo -n $PPID' >| a.txt
+ ble/util/readfile ppid a.txt
+ }
+ dummy=modification_to_environment.1
+ ble/util/getpid
+ ble/test '[[ $BASHPID != $$ ]]'
+ getpid
+ ble/test code:'ret=$BASHPID' ret="$ppid"
+ pid1=$BASHPID
+ (
+ dummy=modification_to_environment.2
+ ble/util/getpid
+ ble/test '[[ $BASHPID != $$ && $BASHPID != $pid1 ]]'
+ getpid
+ ble/test '[[ $BASHPID == $ppid ]]'
+ )
+ ble/test/rmdir
+)
+(
+ ble/test 'ble/fd#is-open 1'
+ ble/test 'ble/fd#is-open 2'
+ exec 9>&-
+ ble/test 'ble/fd#is-open 9' exit=1
+ exec 9>/dev/null
+ ble/test 'ble/fd#is-open 9'
+ exec 9>&-
+ ble/test 'ble/fd#is-open 9' exit=1
+)
+(
+ ble/test/chdir
+ ble/fd#alloc fd '> a.txt'
+ echo hello >&$fd
+ echo world >&$fd
+ if ((_ble_bash/100!=301)); then
+ ble/test 'ble/fd#close fd; echo test >&$fd' exit=1
+ ble/test 'cat a.txt' stdout={hello,world}
+ fi
+ ble/test/rmdir
+)
+(
+ xv1=''
+ xv2a='a' xv2b='ab'
+ xv3a=' ' xv3b='a b'
+ xv4a=$'\n' xv4b=$'a\nb'
+ xv5a=$'\r' xv5b=$'a\rb'
+ xv6a=$'\x01' xv6b=a$'\x01'b
+ xv7a=$'\x02' xv7b=a$'\x02'b
+ xv8a=$'\x7F' xv8b=a$'\x7F'b
+ eval -- "$(
+ for name in v1 v{2..8}{a,b}; do
+ eval "$name=\$x$name"
+ done
+ ble/util/declare-print-definitions vn v1 v{2..8}{a,b} 2>/dev/null)"
+ ble/test '[[ ! ${vn+set} ]]'
+ for name in v1 v{2..8}{a,b}; do
+ ble/test "declare -p $name x$name | cat -A >&2; [[ \$$name == \$x$name ]]"
+ done
+ function status { eval 'ret="${#'$1'[*]}:(""${'$1'[*]}"")"'; }
+ xa0=() sa0='0:()'
+ xa1=('') sa1='1:()'
+ for k in {2..8}; do
+ eval "xa$k=(); xa$k[0]=\"\$xv${k}a\"; xa$k[1]=\"\$xv${k}b\""
+ eval "sa$k=\"2:(\$xv${k}a \$xv${k}b)\""
+ done
+ eval -- "$(
+ for name in a0 a1 a{2..8}; do
+ eval "$name=(\"\${x$name[@]}\")"
+ done
+ ble/util/declare-print-definitions a0 a1 a{2..8} 2>/dev/null)"
+ for name in a0 a1 a{2..8}; do
+ stdout_var=s$name
+ ble/test "status $name" ret="${!stdout_var}"
+ done
+)
+(
+ function status { builtin eval 'echo "${#'$1'[*]}:(""${'$1'[*]}"")"'; }
+ v1=123 v2=(1 2 3) v3=bbb v4=ccc
+ function f2 {
+ local v3=x v4=y
+ builtin eval -- "$(ble/util/print-global-definitions v{0..4})"
+ ble/test '[[ ! ${v0+set} ]]'
+ ble/test 'status v1' stdout='1:(123)'
+ ble/test 'status v2' stdout='3:(1 2 3)'
+ ble/test 'status v3' stdout='1:(bbb)'
+ ble/test 'status v4' stdout='1:(ccc)'
+ }
+ function f1 {
+ local v0=1 v1=2 v2=3 v4=5
+ f2
+ ble/test 'status v1' stdout='1:(2)'
+ ble/test 'status v2' stdout='1:(3)'
+ }
+ f1
+ value="hello 'world'"
+ ble/test 'ble/util/print-global-definitions value' stdout="declare value='hello '\''world'\'''"
+)
+(
+ ble/test 'ble/util/has-glob-pattern "a*"'
+ ble/test 'ble/util/has-glob-pattern "a*b"'
+ ble/test 'ble/util/has-glob-pattern "?"'
+ ble/test 'ble/util/has-glob-pattern "a?"'
+ ble/test 'ble/util/has-glob-pattern "a?b"'
+ ble/test 'ble/util/has-glob-pattern "a?b*c"'
+ ble/test 'ble/util/has-glob-pattern "a[a-c]d"'
+ ble/test 'ble/util/has-glob-pattern "a[!a-c]d"'
+ ble/test 'ble/util/has-glob-pattern "*.txt"'
+ ble/test 'ble/util/has-glob-pattern "*.*"'
+ ble/test 'ble/util/has-glob-pattern ""' exit=1
+ ble/test 'ble/util/has-glob-pattern "a"' exit=1
+ ble/test 'ble/util/has-glob-pattern "abc"' exit=1
+ ble/test 'ble/util/has-glob-pattern "/"' exit=1
+ ble/test 'ble/util/has-glob-pattern "a/c"' exit=1
+ ble/test 'ble/util/has-glob-pattern "a:b"' exit=1
+ ble/test 'ble/util/has-glob-pattern "a=b"' exit=1
+ ble/test 'ble/util/has-glob-pattern "\[xyz\]"' exit=1
+)
+ble/util/msleep/.calibrate-loop &>/dev/null
+ble/util/msleep/.calibrate-loop &>/dev/null
+ble/util/msleep/.calibrate-loop &>/dev/null
+(
+ ble/test 'ble-measure -q "ble/util/msleep 100"; echo "$ret usec" >&2; ((msec=ret/1000,90<=msec&&msec<=110))'
+ ble/test 'ble-measure -q "ble/util/sleep 0.1"; echo "$ret usec" >&2; ((msec=ret/1000,90<=msec&&msec<=110))'
+)
+(
+ time=0
+ ble/function#push ble/util/msleep '((time+=$1));echo $time'
+ ble/test "ble/util/conditional-sync 'sleep 10' '((time<1000))' 100" \
+ stdout={1..10}00
+ ble/test "ble/util/conditional-sync 'sleep 10' '((time<1000))' 100 progressive-weight" \
+ stdout={1,3,7,15,31,63,{1..10}27}
+ ble/function#pop ble/util/msleep
+)
+(
+ ble/test ":| ble/util/cat | cat -A" stdout=
+ ble/test "printf a | ble/util/cat | cat -A" stdout=a
+ ble/test "printf '\0' | ble/util/cat | cat -A" stdout=^@
+ ble/test "printf 'hello\nworld\n'| ble/util/cat | cat -A" stdout={hello\$,world\$}
+ ble/test "printf 'hello\nworld'| ble/util/cat | cat -A" stdout={hello\$,world}
+ ble/test "printf 'hello\0world\0'| ble/util/cat | cat -A" stdout=hello^@world^@
+ ble/test "printf 'hello\0world'| ble/util/cat | cat -A" stdout=hello^@world
+)
+(
+ bleopt_pager=xxx PAGER=yyy
+ ble/test 'ble/util/get-pager ret' ret=xxx
+ bleopt_pager=xxx PAGER=
+ ble/test 'ble/util/get-pager ret' ret=xxx
+ bleopt_pager= PAGER=yyy
+ ble/test 'ble/util/get-pager ret' ret=yyy
+ bleopt_pager= PAGER=
+ ble/test 'ble/util/get-pager ret' ret=less
+)
+(
+ bleopt_pager=cat
+ ble/test 'ble/util/pager <<< hello' stdout=hello
+)
+(
+ ble/util/buffer.clear
+ ble/test 'ble/util/buffer.flush' stdout=
+ ble/util/buffer hello
+ ble/util/buffer world
+ ble/test 'ble/util/buffer.flush' stdout=helloworld
+ ble/test 'ble/util/buffer.flush' stdout=
+ ble/util/buffer.print hello
+ ble/util/buffer.print world
+ ble/test 'ble/util/buffer.flush' stdout={hello,world}
+ ble/test 'ble/util/buffer.flush' stdout=
+ ble/util/buffer.print hello
+ ble/util/buffer.print world
+ ble/util/buffer.clear
+ ble/test 'ble/util/buffer.flush' stdout=
+)
+(
+ ubeg=3 uend=10 uend0=5
+ beg=0 end=5 end0=3
+ ble/dirty-range#load --prefix=u
+ ble/test 'echo "$beg:$end:$end0"' stdout=3:10:5
+ ubeg=3 uend=10 uend0=5
+ ble/dirty-range#clear --prefix=u
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=-1:-1:-1
+ ble/dirty-range#update --prefix=u 0 5 2
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=0:5:2
+ ble/dirty-range#update --prefix=u 10 10 12
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=0:10:9
+ ble/dirty-range#clear --prefix=u
+ ble/dirty-range#update --prefix=u 2 2 3
+ ble/dirty-range#update --prefix=u 2 2 3
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=2:2:4
+ ble/dirty-range#clear --prefix=u
+ ble/dirty-range#update --prefix=u 1 5 3
+ ble/dirty-range#update --prefix=u 7 11 9
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=1:11:7
+ ble/dirty-range#clear --prefix=u
+ ble/dirty-range#update --prefix=u 1 7 5
+ ble/dirty-range#update --prefix=u 4 15 11
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=1:15:9
+ ble/dirty-range#clear --prefix=u
+ ble/dirty-range#update --prefix=u 1 7 5
+ ble/dirty-range#update --prefix=u 3 4 5
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=1:6:5
+ ble/dirty-range#clear --prefix=u
+ ble/dirty-range#update --prefix=u 4 8 6
+ ble/dirty-range#update --prefix=u 2 8 10
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=2:8:8
+ ble/dirty-range#clear --prefix=u
+ ble/dirty-range#update --prefix=u 6 12 8
+ ble/dirty-range#update --prefix=u 3 7 8
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=3:11:8
+ ble/dirty-range#clear --prefix=u
+ ble/dirty-range#update --prefix=u 10 13 11
+ ble/dirty-range#update --prefix=u 3 7 8
+ ble/test 'echo "$ubeg:$uend:$uend0"' stdout=3:12:11
+)
+(
+ ble/test $'ble/util/s2c "\n"' ret=10
+ ble/test 'ble/util/c2s 10' ret=$'\n'
+ ble/test $'ble/util/s2c "\x1b"' ret=27
+ ble/test 'ble/util/c2s 27' ret=$'\x1b'
+ ble/test $'ble/util/s2c "\x1F"' ret=31
+ ble/test 'ble/util/c2s 31' ret=$'\x1F'
+ c=$'\x7F' ble/test 'ble/util/s2c $c' ret=127 # bash-3.0 bug WA
+ ble/test 'ble/util/c2s 127' ret=$'\x7F'
+ ble/test 'ble/util/s2c " "' ret=32
+ ble/test 'ble/util/c2s 32' ret=' '
+ ble/test 'ble/util/s2c a' ret=97
+ ble/test 'ble/util/c2s 97' ret=a
+ ble/test 'ble/util/s2c μ' ret=956
+ ble/test 'ble/util/c2s 956' ret=μ
+ ble/test 'ble/util/s2c あ' ret=12354
+ ble/test 'ble/util/c2s 12354' ret=あ
+ ble/test 'ble/util/s2c' ret=0
+ ble/test 'ble/util/s2c abc' ret=97
+ ble/test 'ble/util/s2c μν' ret=956
+ ble/test 'ble/util/s2c あいう' ret=12354
+ ble/test 'ble/util/c2s.cached 32' ret=' '
+ ble/test 'ble/util/c2s.cached 97' ret=a
+ ble/test 'ble/util/c2s.cached 956' ret=μ
+ ble/test 'ble/util/c2s.cached 12354' ret=あ
+ LANG=C
+ ble/test 'ble/util/c2s 97' ret=a
+ ble/test 'ble/util/c2s 956; [[ $ret != μ ]]'
+ ble/test 'ble/util/c2s 12354; [[ $ret != あ ]]'
+)
+(
+ ble/test 'ble/util/c2bc 97' ret=1
+ ble/test 'ble/util/c2bc 956' ret=2
+ ble/test 'ble/util/c2bc 12354' ret=3
+ ble/test 'ble/util/c2bc 0' ret=1
+ ble/test 'ble/util/c2bc 127' ret=1
+ ble/test 'ble/util/c2bc 128' ret=2
+ ble/test 'ble/util/c2bc 2047' ret=2
+ ble/test 'ble/util/c2bc 2048' ret=3
+ ble/test 'ble/util/c2bc 65535' ret=3
+ ble/test 'ble/util/c2bc 65536' ret=4
+)
+(
+ ble/test 'ble/util/s2chars AaBbCc; ret="${ret[*]}"' ret='65 97 66 98 67 99'
+ ble/test 'ble/util/chars2s 65 97 66 98 67 99' ret=AaBbCc
+ ble/test 'ble/util/s2chars あいう; ret="${ret[*]}"' ret='12354 12356 12358'
+ ble/test 'ble/util/chars2s 12354 12356 12358' ret=あいう
+ ble/test 'ble/util/s2chars; ret="${ret[*]}"' ret=
+ ble/test 'ble/util/s2chars 0; ret="${ret[*]}"' ret=48
+ ble/test 'ble/util/s2chars a; ret="${ret[*]}"' ret=97
+ ble/test 'ble/util/s2chars μ; ret="${ret[*]}"' ret=956
+ ble/test 'ble/util/s2chars あ; ret="${ret[*]}"' ret=12354
+ ble/test 'ble/util/chars2s' ret=
+ ble/test 'ble/util/chars2s 48' ret=0
+ ble/test 'ble/util/chars2s 97' ret=a
+ ble/test 'ble/util/chars2s 956' ret=μ
+ ble/test 'ble/util/chars2s 12354' ret=あ
+)
+(
+ check1() {
+ local char=$1 keyseq=$2
+ ble/test "ble/util/c2keyseq $char" ret="$keyseq"
+ ble/test "ble/util/chars2keyseq $char" ret="$keyseq"
+ ble/test "ble/util/keyseq2chars '$keyseq'; ret=\"\${ret[*]}\"" ret="${3:-$char}"
+ ble/test "ble/util/chars2keyseq 98 $char 99" ret="b${keyseq}c"
+ ble/test "ble/util/keyseq2chars 'b${keyseq}c'; ret=\"\${ret[*]}\"" ret="98 ${3:-$char} 99"
+ }
+ check1 '7' '\a'
+ check1 '8' '\b'
+ check1 '9' '\t'
+ check1 '10' '\n'
+ check1 '11' '\v'
+ check1 '12' '\f'
+ check1 '13' '\r'
+ check1 '27' '\e'
+ check1 '127' '\d'
+ check1 '92' '\\'
+ check1 '28' '\x1c' # workaround bashbug \C-\, \C-\\
+ check1 '156' '\x9c' # workaround bashbug \C-\, \C-\\
+ check1 '0' '\C-@'
+ check1 '1' '\C-a'
+ check1 '26' '\C-z'
+ check1 '29' '\C-]'
+ check1 '30' '\C-^'
+ check1 '31' '\C-_'
+ check1 '128' '\M-\C-@' '27 0'
+ check1 '64' '@'
+ check1 '97' 'a'
+ check1 '956' 'μ'
+ check1 '12354' 'あ'
+ ble/test ble/util/c2keyseq ret='\C-@'
+ ble/test ble/util/chars2keyseq ret=
+ ble/test ble/util/keyseq2chars ret=
+)
+(
+ function pack { ret="${bytes[*]}"; }
+ ble/test 'ble/encoding:UTF-8/b2c ' ret=0
+ ble/test 'ble/encoding:UTF-8/b2c 97' ret=97
+ ble/test 'ble/encoding:UTF-8/b2c 97 98 99 99' ret=97
+ ble/test 'ble/encoding:UTF-8/b2c 206 188 99 99' ret=956
+ ble/test 'ble/encoding:UTF-8/b2c 227 129 130 99' ret=12354
+ ble/test 'ble/encoding:UTF-8/c2b 97 ; pack' ret=97
+ ble/test 'ble/encoding:UTF-8/c2b 956 ; pack' ret='206 188'
+ ble/test 'ble/encoding:UTF-8/c2b 12354; pack' ret='227 129 130'
+ ble/test 'ble/encoding:UTF-8/c2b ; pack' ret=0
+ ble/test 'ble/encoding:UTF-8/c2b 0 ; pack' ret=0
+ ble/test 'ble/encoding:UTF-8/c2b 127 ; pack' ret=127
+ ble/test 'ble/encoding:UTF-8/c2b 128 ; pack' ret='194 128'
+ ble/test 'ble/encoding:UTF-8/c2b 2047; pack' ret='223 191'
+ ble/test 'ble/encoding:UTF-8/c2b 2048; pack' ret='224 160 128'
+)
+(
+ function pack { ret="${bytes[*]}"; }
+ ble/test 'ble/encoding:C/b2c ' ret=0
+ ble/test 'ble/encoding:C/b2c 97' ret=97
+ ble/test 'ble/encoding:C/b2c 97 98 99 99' ret=97
+ ble/test 'ble/encoding:C/b2c 206 188 99 99' ret=206
+ ble/test 'ble/encoding:C/b2c 227 129 130 99' ret=227
+ ble/test 'ble/encoding:C/b2c 97 ' ret=97
+ ble/test 'ble/encoding:C/b2c 956 ' ret=188
+ ble/test 'ble/encoding:C/b2c 12354 ' ret=66
+ ble/test 'ble/encoding:C/c2b ; pack' ret=0
+ ble/test 'ble/encoding:C/c2b 0 ; pack' ret=0
+ ble/test 'ble/encoding:C/c2b 127 ; pack' ret=127
+ ble/test 'ble/encoding:C/c2b 128 ; pack' ret=128
+ ble/test 'ble/encoding:C/c2b 2047; pack' ret=255
+ ble/test 'ble/encoding:C/c2b 2048; pack' ret=0
+)
+(
+ clear-locale() { LC_ALL= LANG= LC_CTYPE=; }
+ for lang in {C,en_US,ja{_JP,}}.{UTF-8,utf8} ja_JP.{utf8,UTF-8}@cjk{wide,narrow,single}; do
+ clear-locale
+ ble/test "LANG=$lang; ble/util/is-unicode-output"
+ clear-locale
+ ble/test "LANG=C LC_CTYPE=$lang; ble/util/is-unicode-output"
+ clear-locale
+ ble/test "LC_CTYPE=C LANG=C LC_ALL=$lang; ble/util/is-unicode-output"
+ done
+ for lang in '' C POSIX UTF-8 utf8 ja_JP.eucJP; do
+ clear-locale
+ ble/test "LANG=$lang; ble/util/is-unicode-output" exit=1
+ clear-locale
+ ble/test "LANG=C LC_CTYPE=$lang; ble/util/is-unicode-output" exit=1
+ clear-locale
+ ble/test "LC_CTYPE=C LANG=C LC_ALL=$lang; ble/util/is-unicode-output" exit=1
+ done
+)
+ble/test/end-section
diff --git a/.local/src/blesh/lib/vim-airline.sh b/.local/src/blesh/lib/vim-airline.sh
new file mode 100644
index 0000000..b4d8b6e
--- /dev/null
+++ b/.local/src/blesh/lib/vim-airline.sh
@@ -0,0 +1,306 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+ble-import keymap/vi
+ble-import prompt-git
+bleopt/declare -n vim_airline_theme dark
+function bleopt/check:vim_airline_theme {
+ local init=ble/lib/vim-airline/theme:"$value"/initialize
+ if ! ble/is-function "$init"; then
+ local ret
+ if ! ble/util/import/search "airline/$value"; then
+ ble/util/print "ble/lib/vim-airline: theme '$value' not found." >&2
+ return 1
+ fi
+ ble/util/import "$ret"
+ ble/is-function "$init" || return 1
+ fi
+ "$init"
+ return 0
+}
+bleopt/declare -v vim_airline_section_a '\e[1m\q{lib/vim-airline/mode}'
+bleopt/declare -v vim_airline_section_b '\q{lib/vim-airline/gitstatus}'
+bleopt/declare -v vim_airline_section_c '\w'
+bleopt/declare -v vim_airline_section_x 'bash'
+bleopt/declare -v vim_airline_section_y '$_ble_util_locale_encoding[unix]'
+bleopt/declare -v vim_airline_section_z ' \q{history-percentile} \e[1m!\q{history-index}/\!\e[22m \q{position}'
+bleopt/declare -v vim_airline_left_sep $'\uE0B0'
+bleopt/declare -v vim_airline_left_alt_sep $'\uE0B1'
+bleopt/declare -v vim_airline_right_sep $'\uE0B2'
+bleopt/declare -v vim_airline_right_alt_sep $'\uE0B3'
+bleopt/declare -v vim_airline_symbol_branch $'\uE0A0'
+bleopt/declare -v vim_airline_symbol_dirty $'\u26A1'
+function bleopt/check:vim_airline_left_sep { ble/prompt/unit#clear _ble_prompt_status; }
+function bleopt/check:vim_airline_left_alt_sep { ble/prompt/unit#clear _ble_prompt_status; }
+function bleopt/check:vim_airline_right_sep { ble/prompt/unit#clear _ble_prompt_status; }
+function bleopt/check:vim_airline_right_alt_sep { ble/prompt/unit#clear _ble_prompt_status; }
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_lib_vim_airline_mode_map_default}"
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'i' 'INSERT'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'n' 'NORMAL'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'in' '(INSERT)'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'o' 'OP PENDING'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'R' 'REPLACE'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default '' 'V REPLACE'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'v' 'VISUAL'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'V' 'V-LINE'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default '' 'V-BLOCK'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 's' 'SELECT'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'S' 'S-LINE'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default '' 'S-BLOCK'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default '?' '------'
+ble/gdict#set _ble_lib_vim_airline_mode_map_default 'c' 'COMMAND'
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_lib_vim_airline_mode_map_atomic}"
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'i' 'I'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'n' 'N'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'R' 'R'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'v' 'V'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'V' 'V-L'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic '' 'V-B'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 's' 'S'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'S' 'S-L'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic '' 'S-B'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic '?' '--'
+ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'c' 'C'
+builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_lib_vim_airline_mode_map}"
+ble/gdict#cp _ble_lib_vim_airline_mode_map_default _ble_lib_vim_airline_mode_map
+function ble/lib/vim-airline/initialize-faces {
+ ble/color/defface vim_airline_a fg=17,bg=45
+ ble/color/defface vim_airline_b fg=231,bg=27
+ ble/color/defface vim_airline_c fg=231,bg=18
+ ble/color/defface vim_airline_error fg=16,bg=88 # fg=#000000,bg=#990000
+ ble/color/defface vim_airline_term fg=158,bg=234 # fg=#9cffd3,bg=#202020
+ ble/color/defface vim_airline_warning fg=16,bg=166 # fg=#000000,bg=#df5f00
+ local section map
+ for section in a b c error term warning; do
+ for map in _normal _insert _visual _commandline _inactive; do
+ ble/color/defface "vim_airline_$section$map" ref:"vim_airline_$section"
+ done
+ ble/color/defface "vim_airline_${section}_replace" ref:"vim_airline_${section}_insert"
+ done
+ local map
+ for map in '' _normal _insert _replace _visual _commandline _inactive; do
+ ble/color/defface "vim_airline_x$map" ref:"vim_airline_c$map"
+ ble/color/defface "vim_airline_y$map" ref:"vim_airline_b$map"
+ ble/color/defface "vim_airline_z$map" ref:"vim_airline_a$map"
+ done
+ local name
+ for name in {a,b,c,x,y,z,error,term,warning}{,_normal,_insert,_replace,_visual,_commandline,_inactive}; do
+ ble/color/defface "vim_airline_${name}_modified" ref:"vim_airline_$name"
+ done
+}
+ble/lib/vim-airline/initialize-faces
+function ble/lib/vim-airline/convert-theme/.to-color256 {
+ local R=$((16#${1:1:2}))
+ local G=$((16#${1:3:2}))
+ local B=$((16#${1:5:2}))
+ ble/color/convert-rgb24-to-color256 "$R" "$G" "$B"
+}
+function ble/lib/vim-airline/convert-theme/.setface {
+ local gspec=
+ local ret
+ ble/lib/vim-airline/convert-theme/.to-color256 "$2"; local fg=$ret
+ ble/lib/vim-airline/convert-theme/.to-color256 "$3"; local bg=$ret
+ printf 'ble/color/setface vim_airline_%-13s %-13s # %s\n' "$1" "fg=$fg,bg=$bg" "fg=$2,bg=$3"
+}
+function ble/lib/vim-airline/convert-theme {
+ local file=$1
+ sed -n 's/let s:airline_\([a-zA-Z_0-9]\{1,\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\).*/\1 \2 \3/p' "$file" |
+ while builtin read -r face fg bg; do
+ ble/lib/vim-airline/convert-theme/.setface "$face" "$fg" "$bg"
+ done
+}
+ble/color/setface vim_airline_a_normal fg=17,bg=190 # fg=#00005f,bg=#dfff00
+ble/color/setface vim_airline_b_normal fg=231,bg=238 # fg=#ffffff,bg=#444444
+ble/color/setface vim_airline_c_normal fg=158,bg=234 # fg=#9cffd3,bg=#202020
+ble/color/setface vim_airline_a_insert fg=17,bg=45 # fg=#00005f,bg=#00dfff
+ble/color/setface vim_airline_b_insert fg=231,bg=27 # fg=#ffffff,bg=#005fff
+ble/color/setface vim_airline_c_insert fg=231,bg=18 # fg=#ffffff,bg=#000080
+ble/color/setface vim_airline_a_visual fg=16,bg=214 # fg=#000000,bg=#ffaf00
+ble/color/setface vim_airline_b_visual fg=16,bg=202 # fg=#000000,bg=#ff5f00
+ble/color/setface vim_airline_c_visual fg=231,bg=52 # fg=#ffffff,bg=#5f0000
+ble/color/setface vim_airline_a_inactive fg=239,bg=234 # fg=#4e4e4e,bg=#1c1c1c
+ble/color/setface vim_airline_b_inactive fg=239,bg=235 # fg=#4e4e4e,bg=#262626
+ble/color/setface vim_airline_c_inactive fg=239,bg=236 # fg=#4e4e4e,bg=#303030
+ble/color/setface vim_airline_a_commandline fg=17,bg=40 # fg=#00005f,bg=#00d700
+ble/color/setface vim_airline_b_commandline fg=231,bg=238 # fg=#ffffff,bg=#444444
+ble/color/setface vim_airline_c_commandline fg=158,bg=234 # fg=#9cffd3,bg=#202020
+_ble_lib_vim_airline_mode_data=()
+_ble_lib_vim_airline_keymap=
+_ble_lib_vim_airline_mode=
+_ble_lib_vim_airline_rawmode=
+function ble/prompt/unit:_ble_lib_vim_airline_mode/update {
+ local keymap mode m
+ ble/keymap:vi/script/get-vi-keymap
+ ble/keymap:vi/script/get-mode
+ case $mode in
+ (i*) m='insert' ;;
+ ([R]*) m='replace' ;;
+ (*[vVsS]) m='visual' ;;
+ (*c) m='commandline' ;;
+ (*n) m='normal' ;;
+ (*) m='inactive' ;;
+ esac
+ ble/prompt/unit/add-hash '$_ble_edit_str'
+ ble/prompt/unit/add-hash '$_ble_history_INDEX'
+ local entry
+ ble/history/get-entry "$_ble_history_INDEX"
+ [[ $_ble_edit_str != "$entry" ]] && m=${m}_modified
+ ble/prompt/unit/assign _ble_lib_vim_airline_keymap "$keymap"
+ ble/prompt/unit/assign _ble_lib_vim_airline_mode "$m"
+ ble/prompt/unit/assign _ble_lib_vim_airline_rawmode "$mode"
+ [[ $prompt_unit_changed ]]
+}
+function ble/prompt/backslash:lib/vim-airline/mode/.resolve {
+ local raw=$1
+ if ble/gdict#has _ble_lib_vim_airline_mode_map "$raw"; then
+ ble/gdict#get _ble_lib_vim_airline_mode_map "$raw"
+ else
+ case $raw in
+ (o) ble/prompt/backslash:lib/vim-airline/mode/.resolve "$_ble_lib_vim_airline_rawmode" ;;
+ ([iR]?*) ble/prompt/backslash:lib/vim-airline/mode/.resolve "${raw::1}" ;;
+ (*?[ncvVsS]) ble/prompt/backslash:lib/vim-airline/mode/.resolve "${raw:${#raw}-1}" ;;
+ () ble/prompt/backslash:lib/vim-airline/mode/.resolve R ;;
+ (R) ble/prompt/backslash:lib/vim-airline/mode/.resolve i ;;
+ ([S]) ble/prompt/backslash:lib/vim-airline/mode/.resolve s ;;
+ ([Vs]) ble/prompt/backslash:lib/vim-airline/mode/.resolve v ;;
+ ([ivnc])
+ ret=
+ case $_ble_lib_vim_airline_rawmode in
+ (i*) ret=$bleopt_keymap_vi_mode_name_insert ;;
+ (R*) ret=$bleopt_keymap_vi_mode_name_replace ;;
+ (*) ret=$bleopt_keymap_vi_mode_name_vreplace ;;
+ esac
+ [[ $_ble_lib_vim_airline_rawmode == [iR]?* ]] &&
+ ble/string#tolower "($insert) "
+ case $_ble_lib_vim_airline_rawmode in
+ (*n)
+ if [[ ! $ret ]]; then
+ local rex='[[:alnum:]](.*[[:alnum:]])?'
+ [[ $bleopt_keymap_vi_mode_string_nmap =~ $rex ]]
+ ret=${BASH_REMATCH[0]:-NORMAL}
+ fi ;;
+ (*v) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_visual" ;;
+ (*V) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_visual $bleopt_keymap_vi_mode_name_line" ;;
+ (*) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_visual $bleopt_keymap_vi_mode_name_block" ;;
+ (*s) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_select" ;;
+ (*S) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_select $bleopt_keymap_vi_mode_name_line" ;;
+ (*) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_select $bleopt_keymap_vi_mode_name_block" ;;
+ (*c) ret="${ret}${ret:+ }COMMAND" ;;
+ esac
+ [[ $ret ]] ||
+ ble/prompt/backslash:lib/vim-airline/mode/.resolve '?' ;;
+ (*) ret='?__' ;;
+ esac
+ fi
+}
+function ble/prompt/backslash:lib/vim-airline/mode {
+ local ret
+ if [[ $_ble_lib_vim_airline_keymap == vi_omap ]]; then
+ ble/prompt/backslash:lib/vim-airline/mode/.resolve o
+ else
+ ble/prompt/backslash:lib/vim-airline/mode/.resolve "$_ble_lib_vim_airline_rawmode"
+ fi
+ [[ $ret ]] && ble/prompt/print "$ret"
+}
+function ble/prompt/backslash:lib/vim-airline/gitstatus {
+ local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked
+ if ble/contrib/prompt-git/initialize; then
+ local hash branch
+ ble/contrib/prompt-git/get-head-information
+ if [[ $branch ]]; then
+ ble/prompt/print "$bleopt_vim_airline_symbol_branch$branch"
+ elif [[ $hash ]]; then
+ ble/prompt/print "$bleopt_vim_airline_symbol_branch${hash::7}"
+ else
+ ble/prompt/print '$bleopt_vim_airline_symbol_branch???????'
+ fi
+ ble/contrib/prompt-git/is-dirty &&
+ ble/prompt/print "$bleopt_vim_airline_symbol_dirty"
+ fi
+}
+function ble/prompt/unit:{vim-airline-section}/update {
+ local section=$1
+ local ref_ps=bleopt_vim_airline_section_$section
+ local face=vim_airline_${section}_$_ble_lib_vim_airline_mode
+ local prefix=_ble_lib_vim_airline_section_$section
+ ble/prompt/unit/add-hash '$_ble_lib_vim_airline_mode_data'
+ ble/prompt/unit/add-hash "\$$ref_ps"
+ local trace_opts=confine:relative:noscrc:face0="$face":ansi:measure-bbox:measure-gbox
+ local prompt_rows=1 prompt_cols=$cols # Note: cols は \q{lib/vim-airline} で設定される
+ ble/prompt/unit:{section}/update "$prefix" "${!ref_ps}" "$trace_opts"
+}
+function ble/prompt/unit:_ble_lib_vim_airline_section_a/update { ble/prompt/unit:{vim-airline-section}/update a; }
+function ble/prompt/unit:_ble_lib_vim_airline_section_b/update { ble/prompt/unit:{vim-airline-section}/update b; }
+function ble/prompt/unit:_ble_lib_vim_airline_section_c/update { ble/prompt/unit:{vim-airline-section}/update c; }
+function ble/prompt/unit:_ble_lib_vim_airline_section_x/update { ble/prompt/unit:{vim-airline-section}/update x; }
+function ble/prompt/unit:_ble_lib_vim_airline_section_y/update { ble/prompt/unit:{vim-airline-section}/update y; }
+function ble/prompt/unit:_ble_lib_vim_airline_section_z/update { ble/prompt/unit:{vim-airline-section}/update z; }
+function ble/lib/vim-airline/.print-section {
+ local section=$1
+ local ret g0 bg
+ ble/color/face2g "vim_airline_${section}_$_ble_lib_vim_airline_mode"; g0=$ret
+ ble/color/g#compute-bg "$g0"; bg=$ret
+ if [[ $prev_g0 ]]; then
+ local sep=bleopt_vim_airline gsep
+ if [[ $prev_section == [ab] ]]; then
+ sep=${sep}_left
+ else
+ sep=${sep}_right
+ fi
+ if [[ $prev_bg == $bg ]]; then
+ sep=${sep}_alt_sep
+ if [[ $prev_section == [ab] ]]; then
+ gsep=$prev_g0
+ else
+ gsep=$g0
+ fi
+ ((gsep&=~_ble_color_gflags_DecorationMask|_ble_color_gflags_Revert|_ble_color_gflags_Invisible))
+ else
+ sep=${sep}_sep gsep=0
+ if [[ $sep == *_right_sep ]]; then
+ ble/color/g#setfg gsep "$bg"
+ ble/color/g#setbg gsep "$prev_bg"
+ else
+ ble/color/g#setfg gsep "$prev_bg"
+ ble/color/g#setbg gsep "$bg"
+ fi
+ fi
+ ble/color/g2sgr-ansi "$gsep"
+ ble/prompt/print "$ret${!sep}"
+ fi
+ local ref_show=_ble_lib_vim_airline_section_${section}_show
+ if [[ ${!ref_show} ]]; then
+ ble/prompt/unit:{section}/get "_ble_lib_vim_airline_section_$section"; local esc=$ret
+ ble/color/g2sgr-ansi "$g0"
+ ble/prompt/print "$ret $esc$ret "
+ fi
+ [[ $section == c ]] && ble/prompt/print $'\r'
+ prev_g0=$g0
+ prev_bg=$bg
+ prev_section=$section
+}
+function ble/prompt/backslash:lib/vim-airline {
+ local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked
+ ble/prompt/unit#update _ble_lib_vim_airline_mode
+ local ret bg=0
+ ble/color/face2g "vim_airline_c_$_ble_lib_vim_airline_mode"
+ ble/color/g#getbg "$ret"
+ ble/color/g#setbg bg "$ret"
+ ble/color/setface prompt_status_line "g:$bg"
+ local cols=$COLUMNS; ((_ble_term_xenl||cols--))
+ local unit rest_cols=$((cols-4))
+ for unit in _ble_lib_vim_airline_section_{a,c,z,b,y,x}; do
+ ble/prompt/unit#update "$unit"
+ local gx1=${unit}_gbox[0]; gx1=${!gx1}
+ local x2=${unit}_bbox[2]; x2=${!x2}
+ local show=
+ [[ $gx1 ]] && ((x2+2<=rest_cols)) && ((show=1,rest_cols-=x2+2))
+ builtin eval -- "${unit}_show=\$show"
+ done
+ local section prev_section= prev_g0= prev_bg=
+ for section in a b c x y z; do
+ ble/lib/vim-airline/.print-section "$section"
+ done
+}
+bleopt -I vim_airline_@
+bleopt keymap_vi_mode_show=
+bleopt prompt_status_line='\q{lib/vim-airline}'
+bleopt prompt_status_align=$'justify=\r'
diff --git a/.local/src/blesh/lib/vim-arpeggio.sh b/.local/src/blesh/lib/vim-arpeggio.sh
new file mode 100644
index 0000000..cb59766
--- /dev/null
+++ b/.local/src/blesh/lib/vim-arpeggio.sh
@@ -0,0 +1,48 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+source "$_ble_base/keymap/vi.sh"
+bleopt/declare -v vim_arpeggio_timeoutlen 40
+function ble/lib/vim-arpeggio.sh/bind/.usage {
+ ble/util/print "usage: ble/lib/vim-arpeggio.sh/bind [-m KEYMAP] -[fxcs@] KEYS COMMAND"
+ ble/util/print " KEYS has the form of {mods}{X}{Y}. {mods} are modifiers of the form"
+ ble/util/print " /([CSMAsH]-)*/ and {X} and {Y} are alphabets which specify simultaneous"
+ ble/util/print " keys."
+}
+function ble/lib/vim-arpeggio.sh/bind {
+ local -a opts=()
+ if [[ $1 == -m ]]; then
+ if [[ ! $2 ]]; then
+ ble/util/print "vim-arpeggio.sh: invalid option argument for \`-m'." >&2
+ ble/lib/vim-arpeggio.sh/bind/.usage >&2
+ return 1
+ fi
+ ble/array#push opts -m "$2"
+ shift 2
+ fi
+ local type=$1 keys=$2 cmd=$3
+ if [[ $type == --help ]]; then
+ ble/lib/vim-arpeggio.sh/bind/.usage
+ return 0
+ elif [[ $type != -[fxcs@] ]]; then
+ ble/util/print "vim-arpeggio.sh: invalid bind type." >&2
+ ble/lib/vim-arpeggio.sh/bind/.usage >&2
+ return 1
+ fi
+ local mods=
+ if local rex='^(([CSMAsH]-)+)..'; [[ $keys =~ $rex ]]; then
+ mods=${BASH_REMATCH[1]}
+ keys=${keys:${#mods}}
+ fi
+ local timeout=$((bleopt_vim_arpeggio_timeoutlen))
+ ((timeout<0)) && timeout=
+ if ((${#keys}==2)); then
+ local k1=$mods${keys::1} k2=$mods${keys:1:1}
+ ble-bind "${opts[@]}" "$type" "$k1 $k2" "$cmd"
+ ble-bind "${opts[@]}" "$type" "$k2 $k1" "$cmd"
+ ble-bind "${opts[@]}" -T "$k1" "$timeout"
+ ble-bind "${opts[@]}" -T "$k2" "$timeout"
+ else
+ ble/util/print "vim-arpeggio.sh: sorry only 2-key bindings are supported now." >&2
+ ble/lib/vim-arpeggio.sh/bind/.usage >&2
+ return 1
+ fi
+}
diff --git a/.local/src/blesh/lib/vim-surround.sh b/.local/src/blesh/lib/vim-surround.sh
new file mode 100644
index 0000000..fc5002c
--- /dev/null
+++ b/.local/src/blesh/lib/vim-surround.sh
@@ -0,0 +1,551 @@
+# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license
+source "$_ble_base/keymap/vi.sh"
+bleopt/declare -n vim_surround_45 $'$(\r)' # ysiw-
+bleopt/declare -n vim_surround_61 $'$((\r))' # ysiw=
+bleopt/declare -n vim_surround_q \" # ysiwQ
+bleopt/declare -n vim_surround_Q \' # ysiwq
+bleopt/declare -v vim_surround_omap_bind 1
+function ble/lib/vim-surround.sh/get-char-from-key {
+ local key=$1
+ if ! ble-decode-key/ischar "$key"; then
+ local flag=$((key&_ble_decode_MaskFlag)) code=$((key&_ble_decode_MaskChar))
+ if ((flag==_ble_decode_Ctrl&&63<=code&&code<128&&(code&0x1F)!=0)); then
+ ((key=code==63?127:code&0x1F))
+ else
+ return 1
+ fi
+ fi
+ ble/util/c2s "$key"
+ return 0
+}
+function ble/lib/vim-surround.sh/async-inputtarget.hook {
+ local mode=$1 hook=${@:2:$#-2} key=${@:$#} ret
+ if ! ble/lib/vim-surround.sh/get-char-from-key "$key"; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local c=$ret
+ if [[ :$mode: == *:digit:* && $c == [0-9] ]]; then
+ _ble_edit_arg=$_ble_edit_arg$c
+ _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook digit $hook"
+ return 147
+ elif [[ :$mode: == *:init:* && $c == ' ' ]]; then
+ _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook space $hook"
+ return 147
+ fi
+ if [[ $c == [$'\e\003'] ]]; then # C-[, C-c
+ ble/widget/vi-command/bell
+ return 1
+ else
+ [[ $c == \' ]] && c="'\''"
+ [[ $mode == space ]] && c=' '$c
+ builtin eval -- "$hook '$c'"
+ fi
+}
+function ble/lib/vim-surround.sh/async-inputtarget {
+ local IFS=$_ble_term_IFS
+ _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook init:digit $*"
+ return 147
+}
+function ble/lib/vim-surround.sh/async-inputtarget-noarg {
+ local IFS=$_ble_term_IFS
+ _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook init $*"
+ return 147
+}
+_ble_lib_vim_surround_previous_tag=html
+function ble/lib/vim-surround.sh/load-template {
+ local ins=$1
+ if [[ ${ins//[0-9]} && ! ${ins//[_0-9a-zA-Z]} ]]; then
+ local optname=bleopt_vim_surround_$ins
+ template=${!optname}
+ [[ $template ]] && return 0
+ fi
+ local ret; ble/util/s2c "$ins"
+ local optname=bleopt_vim_surround_$ret
+ template=${!optname}
+ [[ $template ]] && return 0
+ case "$ins" in
+ (['<tT']*)
+ local tag=${ins:1}; tag=${tag//$'\r'/' '}
+ if [[ ! $tag ]]; then
+ tag=$_ble_lib_vim_surround_previous_tag
+ else
+ tag=${tag%'>'}
+ _ble_lib_vim_surround_previous_tag=$tag
+ fi
+ local end_tag=${tag%%["$_ble_term_IFS"]*}
+ template="<$tag>"$'\r'"</$end_tag>" ;;
+ ('(') template=$'( \r )' ;;
+ ('[') template=$'[ \r ]' ;;
+ ('{') template=$'{ \r }' ;;
+ (['b)']) template=$'(\r)' ;;
+ (['r]']) template=$'[\r]' ;;
+ (['B}']) template=$'{\r}' ;;
+ (['a>']) template=$'<\r>' ;;
+ ([a-zA-Z]) return 1 ;;
+ (*) template=$ins ;;
+ esac
+} &>/dev/null
+function ble/lib/vim-surround.sh/surround {
+ local text=$1 ins=$2 opts=$3
+ local instype=
+ [[ $ins == $'\x1D' ]] && ins='}' instype=indent # C-], C-}
+ local has_space=
+ [[ $ins == ' '?* ]] && ins=${ins:1} has_space=1
+ local template=
+ ble/lib/vim-surround.sh/load-template "$ins" || return 1
+ local prefix= suffix=
+ if [[ $template == *$'\r'* ]]; then
+ prefix=${template%%$'\r'*}
+ suffix=${template#*$'\r'}
+ else
+ prefix=$template
+ suffix=$template
+ fi
+ if [[ $prefix == *' ' && $suffix == ' '* ]]; then
+ prefix=${prefix::${#prefix}-1}
+ suffix=${suffix:1}
+ has_space=1
+ fi
+ if [[ $instype == indent || :$opts: == *:linewise:* ]]; then
+ ble-edit/content/find-logical-bol "$beg"; local bol=$ret
+ ble-edit/content/find-non-space "$bol"; local nol=$ret
+ local indent=
+ if [[ $instype == indent ]] || ((bol<nol)); then
+ indent=${_ble_edit_str:bol:nol-bol}
+ elif [[ $has_space ]]; then
+ indent=' '
+ fi
+ text=$indent$text
+ if [[ $instype == indent || :$opts: == *:indent:* ]]; then
+ ble/keymap:vi/string#increase-indent "$text" "$bleopt_indent_offset"; text=$ret
+ fi
+ text=$'\n'$text$'\n'$indent
+ elif [[ $has_space ]]; then
+ text=' '$text' '
+ fi
+ ret=$prefix$text$suffix
+}
+function ble/lib/vim-surround.sh/async-read-tagname {
+ ble/keymap:vi/async-commandline-mode "$1"
+ _ble_edit_PS1='<'
+ _ble_keymap_vi_cmap_before_command=ble/lib/vim-surround.sh/async-read-tagname/.before-command.hook
+ return 147
+}
+function ble/lib/vim-surround.sh/async-read-tagname/.before-command.hook {
+ if [[ ${KEYS[0]} == 62 ]]; then # '>'
+ ble/widget/self-insert
+ ble/widget/vi_cmap/accept
+ ble/decode/widget/suppress-widget
+ fi
+}
+_ble_lib_vim_surround_ys_type= # ys | yS | vS | vgS
+_ble_lib_vim_surround_ys_args=()
+_ble_lib_vim_surround_ys_ranges=()
+function ble/highlight/layer:region/mark:vi_surround/get-selection {
+ local type=$_ble_lib_vim_surround_ys_type
+ local context=${_ble_lib_vim_surround_ys_args[2]}
+ if [[ $context == block ]]; then
+ local -a sub_ranges
+ sub_ranges=("${_ble_lib_vim_surround_ys_ranges[@]}")
+ selection=()
+ local sub
+ for sub in "${sub_ranges[@]}"; do
+ ble/string#split sub : "$sub"
+ ((sub[0]<sub[1])) || continue
+ ble/array#push selection "${sub[0]}" "${sub[1]}"
+ done
+ else
+ selection=("${_ble_lib_vim_surround_ys_args[@]::2}")
+ if [[ $context == char && ( $type == yS || $type == ySS || $type == vgS ) ]]; then
+ local ret
+ ble-edit/content/find-logical-bol "${selection[0]}"; selection[0]=$ret
+ ble-edit/content/find-logical-eol "${selection[1]}"; selection[1]=$ret
+ fi
+ fi
+}
+function ble/highlight/layer:region/mark:vi_surround/get-face {
+ face=region_target
+}
+function ble/lib/vim-surround.sh/operator.impl {
+ _ble_lib_vim_surround_ys_type=$1; shift
+ _ble_lib_vim_surround_ys_args=("$@")
+ [[ $3 == block ]] && _ble_lib_vim_surround_ys_ranges=("${sub_ranges[@]}")
+ _ble_edit_mark_active=vi_surround
+ ble/lib/vim-surround.sh/async-inputtarget-noarg ble/widget/vim-surround.sh/ysurround.hook1
+ ble/lib/vim-surround.sh/ysurround.repeat/entry
+ return 147
+}
+function ble/keymap:vi/operator:yS { ble/lib/vim-surround.sh/operator.impl yS "$@"; }
+function ble/keymap:vi/operator:ys { ble/lib/vim-surround.sh/operator.impl ys "$@"; }
+function ble/keymap:vi/operator:ySS { ble/lib/vim-surround.sh/operator.impl ySS "$@"; }
+function ble/keymap:vi/operator:yss { ble/lib/vim-surround.sh/operator.impl yss "$@"; }
+function ble/keymap:vi/operator:vS { ble/lib/vim-surround.sh/operator.impl vS "$@"; }
+function ble/keymap:vi/operator:vgS { ble/lib/vim-surround.sh/operator.impl vgS "$@"; }
+function ble/widget/vim-surround.sh/ysurround.hook1 {
+ local ins=$1
+ if local rex='^ ?[<tT]$'; [[ $ins =~ $rex ]]; then
+ ble/lib/vim-surround.sh/async-read-tagname "ble/widget/vim-surround.sh/ysurround.hook2 '$ins'"
+ else
+ ble/widget/vim-surround.sh/ysurround.core "$ins"
+ fi
+}
+function ble/widget/vim-surround.sh/ysurround.hook2 {
+ local ins=$1 tagName=$2
+ ble/widget/vim-surround.sh/ysurround.core "$ins$tagName"
+}
+function ble/widget/vim-surround.sh/ysurround.core {
+ local ins=$1
+ _ble_edit_mark_active= # mark:vi_surround を解除
+ local ret
+ local type=$_ble_lib_vim_surround_ys_type
+ local beg=${_ble_lib_vim_surround_ys_args[0]}
+ local end=${_ble_lib_vim_surround_ys_args[1]}
+ local context=${_ble_lib_vim_surround_ys_args[2]}
+ local sub_ranges; sub_ranges=("${_ble_lib_vim_surround_ys_ranges[@]}")
+ _ble_lib_vim_surround_ys_type=
+ _ble_lib_vim_surround_ys_args=()
+ _ble_lib_vim_surround_ys_ranges=()
+ if [[ $context == block ]]; then
+ local isub=${#sub_ranges[@]} sub
+ local smin= smax= slpad= srpad=
+ while ((isub--)); do
+ local sub=${sub_ranges[isub]}
+ local stext=${sub#*:*:*:*:*:}
+ ble/string#split sub : "${sub::${#sub}-${#stext}}"
+ smin=${sub[0]} smax=${sub[1]}
+ slpad=${sub[2]} srpad=${sub[3]}
+ if ! ble/lib/vim-surround.sh/surround "$stext" "$ins"; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ stext=$ret
+ ((slpad)) && { ble/string#repeat ' ' "$slpad"; stext=$ret$stext; }
+ ((srpad)) && { ble/string#repeat ' ' "$srpad"; stext=$stext$ret; }
+ ble/widget/.replace-range "$smin" "$smax" "$stext"
+ done
+ else
+ local text=${_ble_edit_str:beg:end-beg}
+ if [[ $type == ys ]]; then
+ if local rex=$'[ \t\n]+$'; [[ $text =~ $rex ]]; then
+ ((end-=${#BASH_REMATCH}))
+ text=${_ble_edit_str:beg:end-beg}
+ fi
+ fi
+ local opts=
+ if [[ $type == yS || $type == ySS || $context == char && $type == vgS ]]; then
+ opts=linewise:indent
+ elif [[ $context == line ]]; then
+ opts=linewise
+ fi
+ if ! ble/lib/vim-surround.sh/surround "$text" "$ins" "$opts"; then
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ local text=$ret
+ ble/widget/.replace-range "$beg" "$end" "$text"
+ fi
+ _ble_edit_ind=$beg
+ if [[ $context == line ]]; then
+ ble/widget/vi-command/first-non-space
+ else
+ ble/keymap:vi/adjust-command-mode
+ fi
+ ble/keymap:vi/mark/end-edit-area
+ ble/lib/vim-surround.sh/ysurround.repeat/record "$type" "$ins"
+ return 0
+}
+function ble/widget/vim-surround.sh/ysurround-current-line {
+ ble/widget/vi_nmap/linewise-operator yss
+}
+function ble/widget/vim-surround.sh/ySurround-current-line {
+ ble/widget/vi_nmap/linewise-operator ySS
+}
+function ble/widget/vim-surround.sh/vsurround { # vS
+ ble/widget/vi-command/operator vS
+}
+function ble/widget/vim-surround.sh/vgsurround { # vgS
+ [[ $_ble_decode_keymap == vi_xmap ]] &&
+ ble/keymap:vi/xmap/add-eol-extension # 末尾拡張
+ ble/widget/vi-command/operator vgS
+}
+_ble_lib_vim_surround_ys_repeat=()
+function ble/lib/vim-surround.sh/ysurround.repeat/entry {
+ local -a _ble_keymap_vi_repeat _ble_keymap_vi_repeat_irepeat
+ ble/keymap:vi/repeat/record-normal
+ _ble_lib_vim_surround_ys_repeat=("${_ble_keymap_vi_repeat[@]}")
+}
+function ble/lib/vim-surround.sh/ysurround.repeat/record {
+ ble/keymap:vi/repeat/record-special && return 0
+ local type=$1 ins=$2
+ _ble_keymap_vi_repeat=("${_ble_lib_vim_surround_ys_repeat[@]}")
+ _ble_keymap_vi_repeat_irepeat=()
+ _ble_keymap_vi_repeat[10]=$type
+ _ble_keymap_vi_repeat[11]=$ins
+ case $type in
+ (vS|vgS)
+ _ble_keymap_vi_repeat[2]='ble/widget/vi-command/operator ysurround.repeat'
+ _ble_keymap_vi_repeat[4]= ;;
+ (yss|ySS)
+ _ble_keymap_vi_repeat[2]='ble/widget/vi_nmap/linewise-operator ysurround.repeat'
+ _ble_keymap_vi_repeat[4]= ;;
+ (*)
+ _ble_keymap_vi_repeat[4]=ysurround.repeat
+ esac
+}
+function ble/keymap:vi/operator:ysurround.repeat {
+ _ble_lib_vim_surround_ys_type=${_ble_keymap_vi_repeat[10]}
+ _ble_lib_vim_surround_ys_args=("$@")
+ [[ $3 == block ]] && _ble_lib_vim_surround_ys_ranges=("${sub_ranges[@]}")
+ local ins=${_ble_keymap_vi_repeat[11]}
+ ble/widget/vim-surround.sh/ysurround.core "$ins"
+}
+function ble/keymap:vi/operator:surround.record { :; }
+function ble/keymap:vi/operator:surround {
+ local beg=$1 end=$2 context=$3
+ local content=$surround_content ins=$surround_ins trims=$surround_trim
+ local ret
+ if [[ $trims ]]; then
+ ble/string#trim "$content"; content=$ret
+ fi
+ local opts=; [[ $surround_type == cS ]] && opts=linewise
+ if ! ble/lib/vim-surround.sh/surround "$content" "$ins" "$opts"; then
+ ble/widget/vi-command/bell
+ return 0
+ fi
+ content=$ret
+ ble/widget/.replace-range "$beg" "$end" "$content"
+ return 0
+}
+function ble/keymap:vi/operator:surround-extract-region {
+ surround_beg=$beg surround_end=$end
+ return 147 # 強制中断する為
+}
+_ble_lib_vim_surround_cs=()
+function ble/widget/vim-surround.sh/nmap/csurround.initialize {
+ _ble_lib_vim_surround_cs=("${@:1:3}")
+ return 0
+}
+function ble/widget/vim-surround.sh/nmap/csurround.set-delimiter {
+ local type=${_ble_lib_vim_surround_cs[0]}
+ local arg=${_ble_lib_vim_surround_cs[1]}
+ local reg=${_ble_lib_vim_surround_cs[2]}
+ _ble_lib_vim_surround_cs[3]=$1
+ local trim=
+ [[ $del == ' '?* ]] && trim=1 del=${del:1}
+ if [[ $del == a ]]; then
+ del='>'
+ elif [[ $del == r ]]; then
+ del=']'
+ elif [[ $del == T ]]; then
+ del='t' trim=1
+ fi
+ local obj1= obj2=
+ case "$del" in
+ ([wWps]) obj1=i$del obj2=i$del ;;
+ ([\'\"\`]) obj1=i$del obj2=a$del arg=1 ;;
+ (['bB)}>]t']) obj1=i$del obj2=a$del ;;
+ (['({<[']) obj1=i$del obj2=a$del trim=1 ;;
+ ([a-zA-Z]) obj1=i$del obj2=a$del ;;
+ esac
+ local beg end
+ if [[ $obj1 && $obj2 ]]; then
+ local surround_beg=$_ble_edit_ind surround_end=$_ble_edit_ind
+ ble/keymap:vi/text-object.impl "$arg" surround-extract-region '' "$obj2"
+ beg=$surround_beg end=$surround_end
+ elif [[ $del == / ]]; then
+ local rex='(/\*([^/]|/[^*])*/?){1,'$arg'}$'
+ [[ ${_ble_edit_str::_ble_edit_ind+2} =~ $rex ]] || return 1
+ beg=$((_ble_edit_ind+2-${#BASH_REMATCH}))
+ ble/string#index-of "${_ble_edit_str:beg+2}" '*/' || return 1
+ end=$((beg+ret+4))
+ elif [[ $del ]]; then
+ local ret
+ ble-edit/content/find-logical-bol; local bol=$ret
+ ble-edit/content/find-logical-eol; local eol=$ret
+ local line=${_ble_edit_str:bol:eol-bol}
+ local ind=$((_ble_edit_ind-bol))
+ if ble/string#last-index-of "${line::ind}" "$del"; then
+ beg=$ret
+ elif local base=$((ind-(2*${#del}-1))); ((base>=0||(base=0)))
+ ble/string#index-of "${line:base:ind+${#del}-base}" "$del"; then
+ beg=$((base+ret))
+ else
+ return 1
+ fi
+ ble/string#index-of "${line:beg+${#del}}" "$del" || return 1
+ end=$((beg+2*${#del}+ret))
+ ((beg+=bol,end+=bol))
+ fi
+ _ble_lib_vim_surround_cs[11]=$del
+ _ble_lib_vim_surround_cs[12]=$obj1
+ _ble_lib_vim_surround_cs[13]=$obj2
+ _ble_lib_vim_surround_cs[14]=$beg
+ _ble_lib_vim_surround_cs[15]=$end
+ _ble_lib_vim_surround_cs[16]=$arg
+ _ble_lib_vim_surround_cs[17]=$trim
+}
+function ble/widget/vim-surround.sh/nmap/csurround.replace {
+ local ins=$1
+ local type=${_ble_lib_vim_surround_cs[0]}
+ local arg=${_ble_lib_vim_surround_cs[1]}
+ local reg=${_ble_lib_vim_surround_cs[2]}
+ local del=${_ble_lib_vim_surround_cs[3]}
+ local del2=${_ble_lib_vim_surround_cs[11]}
+ local obj1=${_ble_lib_vim_surround_cs[12]}
+ local obj2=${_ble_lib_vim_surround_cs[13]}
+ local beg=${_ble_lib_vim_surround_cs[14]}
+ local end=${_ble_lib_vim_surround_cs[15]}
+ local arg2=${_ble_lib_vim_surround_cs[16]}
+ local surround_ins=$ins
+ local surround_type=$type
+ local surround_trim=${_ble_lib_vim_surround_cs[17]}
+ if [[ $obj1 && $obj2 ]]; then
+ local ind=$_ble_edit_ind
+ local _ble_edit_kill_ring _ble_edit_kill_type
+ ble/keymap:vi/text-object.impl "$arg2" y '' "$obj1"; local ext=$?
+ _ble_edit_ind=$ind
+ ((ext!=0)) && return 1
+ local surround_content=$_ble_edit_kill_ring
+ ble/keymap:vi/text-object.impl "$arg2" surround '' "$obj2" || return 1
+ elif [[ $del2 == / ]]; then
+ local surround_content=${_ble_edit_str:beg+2:end-beg-4}
+ ble/keymap:vi/call-operator surround "$beg" "$end" char '' ''
+ _ble_edit_ind=$beg
+ elif [[ $del2 ]]; then
+ local surround_content=${_ble_edit_str:beg+${#del2}:end-beg-2*${#del2}}
+ ble/keymap:vi/call-operator surround "$beg" "$end" char '' ''
+ _ble_edit_ind=$beg
+ else
+ ble/widget/vi-command/bell
+ return 1
+ fi
+ ble/widget/vim-surround.sh/nmap/csurround.record "$type" "$arg" "$reg" "$del" "$ins"
+ ble/keymap:vi/adjust-command-mode
+ return 0
+}
+function ble/widget/vim-surround.sh/nmap/csurround.record {
+ [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0
+ local type=$1 arg=$2 reg=$3 del=$4 ins=$5
+ local WIDGET=ble/widget/vim-surround.sh/nmap/csurround.repeat ARG=$arg FLAG= REG=$reg
+ ble/keymap:vi/repeat/record
+ if [[ $_ble_decode_keymap == vi_imap ]]; then
+ _ble_keymap_vi_repeat_insert[10]=$type
+ _ble_keymap_vi_repeat_insert[11]=$del
+ _ble_keymap_vi_repeat_insert[12]=$ins
+ else
+ _ble_keymap_vi_repeat[10]=$type
+ _ble_keymap_vi_repeat[11]=$del
+ _ble_keymap_vi_repeat[12]=$ins
+ fi
+}
+function ble/widget/vim-surround.sh/nmap/csurround.repeat {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local type=${_ble_keymap_vi_repeat[10]}
+ local del=${_ble_keymap_vi_repeat[11]}
+ local ins=${_ble_keymap_vi_repeat[12]}
+ ble/widget/vim-surround.sh/nmap/csurround.initialize "$type" "$ARG" "$REG" &&
+ ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del" &&
+ ble/widget/vim-surround.sh/nmap/csurround.replace "$ins" && return 0
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vim-surround.sh/nmap/dsurround {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ ble/widget/vim-surround.sh/nmap/csurround.initialize ds "$ARG" "$REG"
+ ble/lib/vim-surround.sh/async-inputtarget ble/widget/vim-surround.sh/nmap/dsurround.hook
+}
+function ble/widget/vim-surround.sh/nmap/dsurround.hook {
+ local del=$1
+ ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del" &&
+ ble/widget/vim-surround.sh/nmap/csurround.replace '' && return 0
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/highlight/layer:region/mark:vi_csurround/get-selection {
+ local beg=${_ble_lib_vim_surround_cs[14]}
+ local end=${_ble_lib_vim_surround_cs[15]}
+ selection=("$beg" "$end")
+}
+function ble/highlight/layer:region/mark:vi_csurround/get-face {
+ face=region_target
+}
+function ble/widget/vim-surround.sh/nmap/csurround {
+ ble/widget/vim-surround.sh/nmap/csurround.impl cs
+}
+function ble/widget/vim-surround.sh/nmap/cSurround {
+ ble/widget/vim-surround.sh/nmap/csurround.impl cS
+}
+function ble/widget/vim-surround.sh/nmap/csurround.impl {
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ local type=$1
+ ble/widget/vim-surround.sh/nmap/csurround.initialize "$type" "$ARG" "$REG"
+ ble/lib/vim-surround.sh/async-inputtarget ble/widget/vim-surround.sh/nmap/csurround.hook1
+}
+function ble/widget/vim-surround.sh/nmap/csurround.hook1 {
+ local del=$1
+ if [[ $del ]] && ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del"; then
+ _ble_edit_mark_active=vi_csurround
+ ble/lib/vim-surround.sh/async-inputtarget-noarg ble/widget/vim-surround.sh/nmap/csurround.hook2
+ return "$?"
+ fi
+ _ble_lib_vim_surround_cs=()
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vim-surround.sh/nmap/csurround.hook2 {
+ local ins=$1
+ if local rex='^ ?[<tT]$'; [[ $ins =~ $rex ]]; then
+ ble/lib/vim-surround.sh/async-read-tagname "ble/widget/vim-surround.sh/nmap/csurround.hook3 '$ins'"
+ else
+ ble/widget/vim-surround.sh/nmap/csurround.hook3 "$ins"
+ fi
+}
+function ble/widget/vim-surround.sh/nmap/csurround.hook3 {
+ local ins=$1 tagName=$2
+ _ble_edit_mark_active= # clear mark:vi_csurround
+ ble/widget/vim-surround.sh/nmap/csurround.replace "$ins$tagName" && return 0
+ ble/widget/vi-command/bell
+ return 1
+}
+function ble/widget/vim-surround.sh/omap {
+ local ret n=${#KEYS[@]}
+ if ! ble/keymap:vi/k2c "${KEYS[n?n-1:0]}"; then
+ ble/widget/.bell
+ return 1
+ fi
+ ble/util/c2s "$ret"; local s=$ret
+ local opfunc=${_ble_keymap_vi_opfunc%%:*}$s
+ local opflags=${_ble_keymap_vi_opfunc#*:}
+ case "$opfunc" in
+ (y[sS])
+ local ARG FLAG REG; ble/keymap:vi/get-arg 1
+ _ble_edit_arg=$ARG
+ _ble_keymap_vi_reg=$REG
+ ble/decode/keymap/pop
+ ble/widget/vi-command/operator "$opfunc:$opflags" ;;
+ (yss)
+ ble/widget/vi_nmap/linewise-operator "yss:$opflags" ;;
+ (yS[sS])
+ ble/widget/vi_nmap/linewise-operator "ySS:$opflags" ;;
+ (ds) ble/widget/vim-surround.sh/nmap/dsurround ;;
+ (cs) ble/widget/vim-surround.sh/nmap/csurround ;;
+ (cS) ble/widget/vim-surround.sh/nmap/cSurround ;;
+ (*) ble/widget/.bell ;;
+ esac
+}
+ble-bind -m vi_xmap -f 'S' vim-surround.sh/vsurround
+ble-bind -m vi_xmap -f 'g S' vim-surround.sh/vgsurround
+if [[ $bleopt_vim_surround_omap_bind ]]; then
+ ble-bind -m vi_omap -f s 'vim-surround.sh/omap'
+ ble-bind -m vi_omap -f S 'vim-surround.sh/omap'
+else
+ ble-bind -m vi_nmap -f 'y s' 'vi-command/operator ys'
+ ble-bind -m vi_nmap -f 'y s s' 'vim-surround.sh/ysurround-current-line'
+ ble-bind -m vi_nmap -f 'y S' 'vi-command/operator yS'
+ ble-bind -m vi_nmap -f 'y S s' 'vim-surround.sh/ySurround-current-line'
+ ble-bind -m vi_nmap -f 'y S S' 'vim-surround.sh/ySurround-current-line'
+ ble-bind -m vi_nmap -f 'd s' 'vim-surround.sh/nmap/dsurround'
+ ble-bind -m vi_nmap -f 'c s' 'vim-surround.sh/nmap/csurround'
+ ble-bind -m vi_nmap -f 'c S' 'vim-surround.sh/nmap/cSurround'
+fi