summaryrefslogtreecommitdiff
path: root/.local/src/blesh/lib/core-complete.sh
diff options
context:
space:
mode:
Diffstat (limited to '.local/src/blesh/lib/core-complete.sh')
-rw-r--r--.local/src/blesh/lib/core-complete.sh6327
1 files changed, 6327 insertions, 0 deletions
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