summaryrefslogtreecommitdiff
path: root/.local/src/blesh/lib
diff options
context:
space:
mode:
authorSaumit Dinesan <justsaumit@protonmail.com>2022-05-22 00:37:40 +0530
committerSaumit Dinesan <justsaumit@protonmail.com>2022-05-22 00:37:40 +0530
commitc3362aefa2e762211409923cfff065541bebf9e7 (patch)
treee48e225190fc0bb1a2db18ae2510a89a6f0d8653 /.local/src/blesh/lib
parent4df17a688ba54d710a1d46ee47cb65b5c9e75764 (diff)
ble.sh & z4h addition
Diffstat (limited to '.local/src/blesh/lib')
-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
22 files changed, 16257 insertions, 0 deletions
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